Ruby用画像処理ライブラリをちょっと改良
Rubyを使ってちょっとした画像処理のアルゴリズムを試したいと思い、(a)PNG形式の画像を読み込み、(b)画素単位で読み書きでき、(c)線と文字が描画できて、(d)結果をPNG形式で保存できる、といった程度の手軽なライブラリを探したところ、NISHIMOTO Keisuke氏のRuby/PureImageというライブラリ見付けました。
さっそく使ってみたところ、私の用途には処理速度的にも充分で、便利に使っていたのですが、ライブラリ付属のサンプル画像を使うと上手くいくものの、自分で用意したPNGファイルでは画像を正しく読めないことに気が付きました。
何でだろうなーと思ってライブラリのコードを見たところ、このライブラリ(バージョン0.1.2)では、画像ファイルの読み込み時にフィルタ処理を端折っているようです。
PNG形式では、圧縮サイズを改善するために、スキャンライン単位で5種類のフィルタ処理(「フィルタ処理なし」を含む)を指定できるのですが、Ruby/PureImageライブラリでは、このフィルタ処理を「フィルタ処理なし」で決め打ちにしており、その結果、フィルタ処理している画像を読み込むと、色が化けます。
Ruby/PureImageライブラリは2006年で更新が止まっているライブラリのようですし、高性能な画像処理ライブラリはたくさんあるのでしょうけれど、シンプルなRuby/PureImageも捨てがたかったので、ちょっと改良してみました。
(速度や機能が必要ならC++ Builderなどを使うので、高性能ライブラリは私がRubyに求めているものとは方向が異なり、使い方を憶える気になれませんでした。Ruby/PureImageライブラリの改良も、探せばどこかで誰かがすでにやっているような気もしますが、たいした手間ではないので…。)
改良点は、pureimage.rbファイルのPNGIOクラスのloadメソッド内で、PNGファイルのイメージ・データをZlibで展開した後、idatから画像を作る「# Create image.」(873行目)の前に、以下のコードを追加します(展開したイメージ・データにスキャンライン単位でフィルタ処理をするコードです)。
これで、自分で用意したPNGファイルも正しく読めるようになりました。よかったよかった。
# Filtering
bpp = (color_type == 2) ? 3 : 4
width_bpp = width * bpp
dat_index = 0
for y in 0...height
filter = idat[dat_index].to_i
dat_index += 1
if filter == 0 then # None
for x in 0...width_bpp
idat[dat_index] = idat[dat_index].to_i
dat_index += 1
end
elsif filter == 1 then # Sub
for x in 0...width_bpp
idat[dat_index] = idat[dat_index].to_i + ((x < bpp) ? 0 : idat[dat_index - bpp])
dat_index += 1
end
elsif filter == 2 then # Up
for x in 0...width_bpp
idat[dat_index] = idat[dat_index].to_i + ((y < 1) ? 0 : idat[dat_index - width_bpp - 1])
dat_index += 1
end
elsif filter == 3 then # Average
for x in 0...width_bpp
average = ((x < bpp) ? 0 : idat[dat_index - bpp])
average += ((y < 1) ? 0 : idat[dat_index - width_bpp - 1])
average /= 2
idat[dat_index] = (idat[dat_index].to_i + average) & 0xff
dat_index += 1
end
elsif filter == 4 then # Paeth
for x in 0...width_bpp
a = (x < bpp) ? 0 : idat[dat_index - bpp]
b = (y < 1) ? 0 : idat[dat_index - width_bpp - 1]
c = ((x < bpp) || (y < 1)) ? 0 : idat[dat_index - width_bpp - 1 - bpp]
pp = a + b - c
pa = (pp - a).abs
pb = (pp - b).abs
pc = (pp - c).abs
if (pa <= pb) && (pa <= pc) then
pp = a
elsif (pb <= pc) then
pp = b
else
pp = c
end
idat[dat_index] = (idat[dat_index].to_i + pp) & 0xff
dat_index += 1
end
else # 未知のフィルタ
raise "Not support scanline filter method: " + filter.to_s
end
end
| 固定リンク
| トラックバック (0)

![I/O編集部[編]: 基礎からのAndroidプログラミング](http://ecx.images-amazon.com/images/I/41-CXSqMJuL._SL75_.jpg)
![I/O編集部[編]: はじめてのiPadプログラミング (I・O BOOKS)](http://ecx.images-amazon.com/images/I/41eimO%2BfO6L._SL75_.jpg)
![I/O編集部[編]: はじめてのiPhoneプログラミング (I・O BOOKS)](http://ecx.images-amazon.com/images/I/51xc-G-fyCL._SL75_.jpg)












