2022/08/20(土) [n年前の日記]
#1 [ruby] Rubyスクリプトに画像ファイルを含める
Ruby/SDL を使ったスクリプト内に、png画像を含めてしまいたい。
exerbを使って Rubyスクリプトをexe化する際、画像ファイルもRubyスクリプト内に含めてしまったほうが都合がいいのかなと思ってしまったので、そういうことができるかどうか試してみた。
まあ、Ruby/SDLを使用しているスクリプトを、exerbでexe化するのは _色々問題があって無理だった のだけど。せっかく実験したので、一応メモしておく。
動作確認環境は以下。
昔、似たようなことをやった記憶がある。日記を検索してみたら、DXRuby を使ってそういうことをしていた。
_Rubyスクリプトの中に画像を仕込むソレ
要するに、png画像を base64文字列に変換してスクリプト内に記述しておけば目的は果たせそう。
_Base64 - Wikipedia
exerbを使って Rubyスクリプトをexe化する際、画像ファイルもRubyスクリプト内に含めてしまったほうが都合がいいのかなと思ってしまったので、そういうことができるかどうか試してみた。
まあ、Ruby/SDLを使用しているスクリプトを、exerbでexe化するのは _色々問題があって無理だった のだけど。せっかく実験したので、一応メモしておく。
動作確認環境は以下。
- Windows10 x64 21H2
- Ruby 1.8.7 p330 i386-mingw32 + Ruby/SDL 1.3.1.1
- Ruby 1.9.3 p330 i386-mingw32 + Ruby/SDL 2.1.1.1
昔、似たようなことをやった記憶がある。日記を検索してみたら、DXRuby を使ってそういうことをしていた。
_Rubyスクリプトの中に画像を仕込むソレ
要するに、png画像を base64文字列に変換してスクリプト内に記述しておけば目的は果たせそう。
_Base64 - Wikipedia
◎ base64への変換スクリプト。 :
png画像等をbase64に変換するスクリプトは以下。
_image2base64.rb
注意点。Ruby 1.9.3 なら動いたけれど、Ruby 1.8.7 では動かなかった。Ruby 1.8.7 には File.binread() が無かった。
実行は以下。hoge.png を読み込んで、tmp.txt に base64 の形で出力する例。
これで得られた base64文字列を、Rubyスクリプトのどこかにコピペしてしまえばいい。
_image2base64.rb
infile = ARGV[0] bin_data = File.binread(infile) base64_text = [bin_data].pack("m") puts base64_text
注意点。Ruby 1.9.3 なら動いたけれど、Ruby 1.8.7 では動かなかった。Ruby 1.8.7 には File.binread() が無かった。
実行は以下。hoge.png を読み込んで、tmp.txt に base64 の形で出力する例。
ruby image2base64.rb hoge.png > tmp.txt
これで得られた base64文字列を、Rubyスクリプトのどこかにコピペしてしまえばいい。
◎ base64を読み出して使うスクリプト。 :
base64文字列を読み出して、Ruby/SDLのウインドウに描画してみる。
_03_imgdisp_rubysdl.rb
実行すると以下のようなウインドウが開く。画像を描画できている。
少し解説。
base64文字列を読み込んで、バイナリデータに変換して、それを StringIO に渡している部分は以下。
StringIO というのは、文字列をファイル(IOオブジェクト)のような感覚で利用できるオブジェクトらしい。
_class StringIO (Ruby 1.8.7)
StringIO を渡して、Ruby/SDL で利用できる画像データ(Surface) に変換している部分は以下。
一般的に、Ruby/SDL で画像ファイルを読み込むなら SDL::Surface.load(filename) を使うけれど、SDL::Surface.loadFromIO(io) を使えば Ruby のIOオブジェクトから画像を読み込める。
_Ruby/SDL Reference Manual (2.x)
_03_imgdisp_rubysdl.rb
require "sdl" require "stringio" SCRW, SCRH = 512, 288 # SDL init SDL.init(SDL::INIT_EVERYTHING) screen = SDL::Screen.open(SCRW, SCRH, 0, SDL::SWSURFACE) # read base64 text base64_text = "" DATA.each { |l| base64_text += l.chomp } bin_data_io = StringIO.new(base64_text.unpack("m")[0], "rb") # load image from StringIO img = SDL::Surface.loadFromIO(bin_data_io).display_format # main loop loop do while event = SDL::Event2.poll case event when SDL::Event2::Quit exit when SDL::Event2::KeyDown exit if event.sym == SDL::Key::ESCAPE end end screen.fill_rect(0, 0, SCRW, SCRH, [0, 100, 200]) # fill bg screen.put(img, 32, 32) # draw sprite screen.update_rect(0, 0, 0, 0) # update screen SDL.delay(16.6) # wait end __END__ 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
実行すると以下のようなウインドウが開く。画像を描画できている。
ruby 03_imgdisp_rubysdl.rb
少し解説。
- このスクリプトは、「__END__」と書かれた行の下に、画像ファイルを変換したbase64文字列を列挙している。
- Ruby は、「__END__」と書いてある行より下に書かれた行に対して、「DATA」というシンボルでアクセスすることができる。
base64文字列を読み込んで、バイナリデータに変換して、それを StringIO に渡している部分は以下。
base64_text = "" DATA.each { |l| base64_text += l.chomp } bin_data_io = StringIO.new(base64_text.unpack("m")[0], "rb")
StringIO というのは、文字列をファイル(IOオブジェクト)のような感覚で利用できるオブジェクトらしい。
_class StringIO (Ruby 1.8.7)
StringIO を渡して、Ruby/SDL で利用できる画像データ(Surface) に変換している部分は以下。
img = SDL::Surface.loadFromIO(bin_data_io).display_format
一般的に、Ruby/SDL で画像ファイルを読み込むなら SDL::Surface.load(filename) を使うけれど、SDL::Surface.loadFromIO(io) を使えば Ruby のIOオブジェクトから画像を読み込める。
_Ruby/SDL Reference Manual (2.x)
◎ 別の書き方。 :
「__END__」以下の行を読み込もうとすると1種類のデータしか読み込めなかったりするし、exerb が DATAシンボルに非対応だったりもするので、ちょっと違う書き方をしてみた。
_04_imgdisp_rubysdl_2.rb
base64 をバイナリ化するあたりは、ちょっとだけ記述が減ってくれた。
_04_imgdisp_rubysdl_2.rb
require "sdl" require "stringio" SCRW, SCRH = 512, 288 BASE64_STRINGS = [ "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", ] # SDL init SDL.init(SDL::INIT_EVERYTHING) screen = SDL::Screen.open(SCRW, SCRH, 0, SDL::SWSURFACE) # read base64 text base64_text = BASE64_STRINGS.join bin_data_io = StringIO.new(base64_text.unpack("m")[0], "rb") # load image from StringIO img = SDL::Surface.loadFromIO(bin_data_io).display_format # main loop loop do while event = SDL::Event2.poll case event when SDL::Event2::Quit exit when SDL::Event2::KeyDown exit if event.sym == SDL::Key::ESCAPE end end screen.fill_rect(0, 0, SCRW, SCRH, [0, 100, 200]) # fill bg screen.put(img, 32, 32) # draw sprite screen.update_rect(0, 0, 0, 0) # update screen SDL.delay(16.6) # wait end
base64 をバイナリ化するあたりは、ちょっとだけ記述が減ってくれた。
base64_text = BASE64_STRINGS.join bin_data_io = StringIO.new(base64_text.unpack("m")[0], "rb")
[ ツッコむ ]
以上です。