ExcelでWebの挿絵を書く
はじめに
Webに載せる挿絵を書く時、みなさんはどんなツールを使ってますか?
私はExcelを使ってます。こんな仕組みになってます。
- Excelのワークシートに図を描き、グルーピングして名前をつけておく
- HTML形式で保存すると、図はPNGやJPEGに変換され、図につけた名前と図ファイル名の対応はHTMLファイルの中に書かれている
- 図の名前を指定すればイメージデータを渡してくれるCGIを用意すれば、Webの挿絵として使用できる
- HTML形式で保存したファイルは、再度Excelで開きなおすことができるので、挿絵を手直しして保存すればそのままビットマップ ファイルにも変更が反映される。
このシステムの利点は、ビットマップ系のファイルとDraw系のファイルがいつも一緒に関連付けられて管理されていることだと思う。 Webの挿絵を手直ししたくても、Draw系のファイルが残ってないというような悲劇が起きない。
ExcelのHTML形式で保存した時のファイル群をさぐる
まずは、ExcelファイルをHTML形式で保存した時のファイルの構成を見てみよう。
- 試しに、Excelでちょっとした図を描いて、グルーピングしておく。
- そのグループ化した図に"image_sample01"という名前をつけておく。 図形に名前をつけるときは、図のプロパティを出し、「Webタグ」の「代わりに表示する文字列」に名前を入れておく。
別のワークシートにも同じような図を描いておく。こちらにも別の名前をつけておく*1。
このファイルをHTML形式で保存する。ファイル名はsample.htmlとしよう。保存すると、こんなファイル構成になる。
画像ファイルへの道筋
さきほどのファイル群から画像ファイルへ至る方法を説明しよう。
- トップのHTMLファイルの中を探してみると、各ワークシートを示すサブHTMLファイルへのリンクが含まれている。
- そのリンク先のファイルを開くと、<img src=image002.png alt="image_sample">のようなタグが見つかる
- これで図形につけた名前と実際の画像ファイル名の対応がわかるわけだ
というわけで、HTMLファイルから各ワークシートへのリンクと<img>タグを見つけるスクリプトが必要だ。まず、これを作ってみよう。
HTMLファイルから必要な情報を得るスクリプト
正規表現を使えば簡単に情報は取り出せる。
まずはライブラリ。
# excel_images.rb
def get_subhtml_list(html_text)
subhtml_list = []
tag_list = html_text.gsub(/\r|\n/,"").scan(/<link\s+.*?>/)
tag_list.each {|linktag|
if linktag =~ /id=\"shLink\"/
if linktag =~ /href=\"(.*?)\"/
subhtml_list.push $1
end
end
}
return subhtml_list
end
def get_imgtag_list(html_text, dirname)
imgtag_list = []
tag_list = html_text.gsub(/\r|\n/,"").scan(/<img\s+.*?>/)
tag_list.each {|imgtag|
if (imgtag =~ /src=(.+?)\s/) and (imgtag =~ /alt=\"(.+?)\"\s/)
(imgtag =~ /src=(.+?)\s/)
img_filename = File.join(dirname, $1)
(imgtag =~ /alt=\"(.+?)\"\s/)
img_keyname = $1
imgtag_list.push [img_keyname, img_filename]
end
}
return imgtag_list
end
実行スクリプト。
# analize_excel_html.rb
require 'excel_images'
filename = ARGV.shift
html_text = open(filename).read
subhtml_list = get_subhtml_list(html_text)
subhtml_list.each {|sub_html_filename|
puts "**** #{sub_html_filename}"
dirname = File.dirname(sub_html_filename)
html_text = open(sub_html_filename).read
imgtag_list = get_imgtag_list(html_text, dirname)
p imgtag_list
}
これを実行すると、こんな結果になる。sample.htmは先ほどExcelで作ったサンプルファイル。
$ ruby analize_excel_html.rb sample.htm **** sample.files/sheet001.htm [["image_sample", "sample.files/image002.png"]] **** sample.files/sheet002.htm [["image_sample2", "sample.files/image003.png"]] **** sample.files/sheet003.htm []
画像を取り出すスクリプト
今回、目標としているのはCGIで画像を取り出すことだが、そのためには、WebサーバでRubyのCGIが利用できる必要がある。 さらに、Webサーバに直接Excelからファイルが保存できる必要もある。
このような環境は、イントラネットや自宅サーバでないとなかなか用意できないだろうから、まずExcelの保存フォルダから 画像ファイルを別フォルダに移すスクリプトを書いてみる。保存時のファイル名はExcel上で画像につけた名前を使う。
先ほど作ったexcel_images.rbも使う。 このスクリプトを使うと、ExcelImageFilePathに保存されているExcelファイルで示される画像ファイルをEXT_DIRNAMEに保存できる。
#Ruby -Ks
# ext_imgfiles.rb
require 'excel_images.rb'
def extract_file(img_name, source_filename)
source_filename =~ /\.(\w+?)$/
extname = $1
#extname = File.extname(source_filename)
basename = File.basename(source_filename)
dest_filename = File.join(EXT_DIRNAME, img_name+"."+extname)
source_file = open(source_filename)
dest_file = open(dest_filename, "w")
dest_file << source_file.read
dest_file.close
source_file.close
end
EXT_DIRNAME = "/home/www/html/images" # 画像ファイルの出力先
ExcelImageFilePath = "/home/www/html/xxxxx" # Excelファイルの置き場
excel_filelist = Dir.glob(File.join(ExcelImageFilePath,"*.htm"))
excel_filelist.each {|filename|
p filename
html_text = open(filename).read
subhtml_list = get_subhtml_list(html_text)
subhtml_list.each {|sub_html_filename|
dirname = File.dirname(sub_html_filename)
html_text = open(sub_html_filename).read
imgtag_list = get_imgtag_list(html_text, dirname)
imgtag_list.each {|imgtag|
img_name = imgtag[0]
excel_imgfilepath = imgtag[1]
extract_file(img_name, excel_imgfilepath)
}
}
}
CGIで画像を参照するスクリプト
CGIを使って、直接Excelの保存先フォルダから画像を抜き出し、Webブラウザに画像データを渡してみよう。
CGIにはパラメータとして、画像につけた名前を指定する。それを元に、Excelが出力した画像ファイルを探し出し、ファイル内容を そのままブラウザに返してやれば画像が表示されるようだ。
このCGIを利用するには、CGIからExcelが出力したファイル群にアクセスする必要があるため、Sambaも動作させておく必要がある。 ExcelImageFilePathにExcelファイルの保存ディレクトリ名を入れておき、以下のような<img>タグで挿絵を読み出せる。
<img src="/cgi-bin/imageref.rb?tag=excel_img_flow" alt="Excel挿絵システム" />
もちろん、この例ではexcel_img_flowが画像につけられた名前である。
- 以下のスクリプトをimageref.rb という名前でCGIとして動作できる場所に保存
- 先ほど紹介したexcel_images.rbもCGIと同じフォルダに保存
- ExcelImageFilePath を自分の環境に合わせて変更
- <img src="/cgi-bin/imageref.rb?tag=excel_img_flow" /> のようなHTMLで画像を挿入する
このCGIの欠点は、リクエストがあるたびに毎回、Excelが出力したHTMLファイルを渡り歩いて画像ファイルを探すため、絵が 増えてくると動作が遅くなる、ということか。
まぁ、これは先に対応テーブルを作っておき、CGI実行時には対応テーブルを使って画像ファイルを探すようにすればいい。これは またの機会に。
#!/usr/local/bin/ruby
require "cgi"
require 'excel_images'
def show_image(excel_imgfilepath)
excel_imgfilepath =~ /\.(\w+?)$/
extname = $1.downcase
case extname
when "jpg"
output_data = "Content-type: image/jpeg\n\n"
when "png"
output_data = "Content-type: image/png\n\n"
when "gif"
output_data = "Content-type: image/gif\n\n"
when "tiff"
output_data = "Content-type: image/tiff\n\n"
else
output_data = "Content-type: image/jpeg\n\n"
end
fn = open(excel_imgfilepath)
img_dat = fn.read
fn.close
output_data << img_dat
return output_data
end
def find_image(tagname)
excel_filelist = Dir.glob(File.join(ExcelImageFilePath,"*.htm"))
excel_filelist.each {|filename|
html_text = open(filename).read
subhtml_list = get_subhtml_list(html_text)
subhtml_list.each {|sub_html_filename|
sub_html_filename = File.join(ExcelImageFilePath, sub_html_filename)
dirname = File.dirname(sub_html_filename)
html_text = open(sub_html_filename).read
imgtag_list = get_imgtag_list(html_text, dirname)
imgtag_list.each {|imgtag|
img_name = imgtag[0]
excel_imgfilepath = imgtag[1]
if img_name == tagname
return show_image(excel_imgfilepath)
end
}
}
}
return nil
end
ExcelImageFilePath = "/home/www/html/xxxx" # Excelファイルの置き場
input = CGI.new
tagname = input["tag"].shift
if tagname then
print find_image(tagname)
end
ライセンス
ライセンスはRubyのライセンスに従います。
Copyright (C) 2003 Oka Yasushi <yac@tech-notes.dyndns.org>
You may redistribute it and/or modify it under the same license terms as Ruby.
免責事項
本プログラムは無保証です。作者は、プログラム自身のバグ、あるいは、本プログラムの実行など から発生するいかなる損害に対しても責任を持ちません。
変更履歴
Initial Release
*1複数のワークシートに図がないと、結果がかなり 違ってきてしまうんです。