Edited at

RMagickを使ってGIF生成

More than 1 year has passed since last update.


ビジュアライズしたい。

ライフゲーム

これをアニメーションするのにターミナルを使い、

それをttyrecで録画。ttygifでgif生成したのだけど、

イマイチかくかく。

ビジュアライズに限れば適当なplotを使えば良いのだろうけど、

gifも欲しい。ttygifの中身はImageMagickなわけだから、

直接使ってしまおうと。


RMagick

ImageMagickのRuby binding


追記 new_imageを使おう

自前でtempfile使うより簡潔です。

new_imageしていくだけでGIFのワンフレーム追加できます。

def make_gif(name = "", x = 0, y = 0, fps = 0, &d)

m = Magick::ImageList.new
(0..fps).each { |n|
m.new_image(x,y)
d.call(m,n)
}

m.write(name)
end


make_gif

一時ファイルにワンフレームごと書き出し、

最後にそれらをひとつのGIFにまとめる。

非効率臭い。


rmagick_make_gif

require "RMagick"

require "tempfile"

def make_gif(name = "", x = 0, y = 0, fps = 0, &d)
tfs = (0..fps).map { |n|
mi = Magick::Image.new(x,y)

d.call(mi,n)
tf = Tempfile.new(["draw_gif",".gif"])
mi.write(tf.path)
tf
}

Magick::ImageList.new(*tfs.map(&:path)).tap { |mil|
mil.iterations = 10
mil.write(name)
tfs.each(&:close)
}
end



lifegame.rb

require "./lifegame.rb"

require "./rmagick_make_gif.rb"

lg = Lifegame.new(300,300)
lg.random { (rand(2) + rand(2) + rand(2)) / 3 }

make_gif("lifegame.gif",300,300,100) { |m,n|
lg.cells.each_with_index { |cy,iy|
cy.each_with_index { |cx,ix|
m.pixel_color(ix,iy,"black") if cx == 1
}
}
lg.apply
}

lifegame.gif


cells

一次元セルオートマトンもついでに。

ルール90です。

require "./cells.rb"

require "./rmagick_make_gif.rb"

cs = Cells.new
bs = []
make_gif("cells.gif", 200,100,100) { |m,n|
y = 0
bs.push(cs.dup)
bs.each { |cy|
x = 0
cy.cells.each { |cx|
m.pixel_color(x,y,"black") if cx == 1
x += 1
}
y += 1
}
cs.apply 90
}

cells.gif


end

ターミナルのテキスト表現のボリュームとは桁違いに多く出力できるので、

この例の場合はこちらを使う方が良いですね。