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")
[ ツッコむ ]
#2 [zatta] スクリーンセーバ作成に対する憧れ
自分語り。思考メモ。スクリーンセーバにまつわるアレコレを脈絡なくメモ。
ここ最近、スクリーンセーバ作成についてアレコレ実験しているけれど。「ちょwwwおまwww今時スクリーンセーバ作成ってwww」と笑われそうだなと不安になりながら作業メモを書き残してる状態で。
でも、仕方ない。スクリーンセーバ作成というお題は、自分の中ではずっと気になってるお題でして…。
大昔、Windows95 が普及し始めて、CD-ROMに入ったデスクトップアクセサリー云々が店頭販売されてた当時。「スクリーンセーバって面白いな。見ていて楽しい」「自分も作れないものかなあ」と気になったのですが。しかし、作り方がさっぱり分からない。一体何をどうすればいいんだろう。そんなもやもやが、喉に刺さった魚の小骨のように自分の中ではずっと残っていて。プログラマーとしてはフツーに悔しいじゃないですか。作り方の概要すら知らないなんて…。少なくとも自分は、その状態ってちょっと恥ずかしいし情けない状態だなと感じてしまって。そこにはプログラマーとしての敗北感があるわけですよ。
あれから四半世紀。さすがに今なら簡単に作れるようになってるんじゃないかと、時々思い出したように関連情報をググってみたりして。仕様その他がなんとなく分かってきたような気分になってきたので、こうして実験を始めちゃったという。まあ、使った言語やライブラリはアレだけど、一応作れることは分かってきて、多少は気分的にスッキリ…。
いや、スッキリしてない。四半世紀も経ってるのに、まだこんなに作成が難しいのかと、正直ガッカリした面もあるなと。
もっと簡単に作れないものかなあ…。
ここ最近、スクリーンセーバ作成についてアレコレ実験しているけれど。「ちょwwwおまwww今時スクリーンセーバ作成ってwww」と笑われそうだなと不安になりながら作業メモを書き残してる状態で。
でも、仕方ない。スクリーンセーバ作成というお題は、自分の中ではずっと気になってるお題でして…。
大昔、Windows95 が普及し始めて、CD-ROMに入ったデスクトップアクセサリー云々が店頭販売されてた当時。「スクリーンセーバって面白いな。見ていて楽しい」「自分も作れないものかなあ」と気になったのですが。しかし、作り方がさっぱり分からない。一体何をどうすればいいんだろう。そんなもやもやが、喉に刺さった魚の小骨のように自分の中ではずっと残っていて。プログラマーとしてはフツーに悔しいじゃないですか。作り方の概要すら知らないなんて…。少なくとも自分は、その状態ってちょっと恥ずかしいし情けない状態だなと感じてしまって。そこにはプログラマーとしての敗北感があるわけですよ。
あれから四半世紀。さすがに今なら簡単に作れるようになってるんじゃないかと、時々思い出したように関連情報をググってみたりして。仕様その他がなんとなく分かってきたような気分になってきたので、こうして実験を始めちゃったという。まあ、使った言語やライブラリはアレだけど、一応作れることは分かってきて、多少は気分的にスッキリ…。
いや、スッキリしてない。四半世紀も経ってるのに、まだこんなに作成が難しいのかと、正直ガッカリした面もあるなと。
もっと簡単に作れないものかなあ…。
◎ 余談。 :
スクリーンセーバ作成の民主化だの、スクリーンセーバはCGアートだの、普段考えてたことをメモしてたのだけど、ふと日記を検索したらまるっきり同じことを以前メモしてあった…。
_スクリーンセーバの作り方を調べてる
_スクリーンセーバの作り方を調べてる
[ ツッコむ ]
以上、1 日分です。
