2020/01/20(月) [n年前の日記]
#1 [love2d] Love2Dのウインドウにドロップされたpng画像を表示
任意の場所に置いてある png画像を、エクスプローラ等のファイラーから Love2Dのウインドウにドラッグアンドドロップ(D&D)して表示することができそうか実験してみたり。環境は、Windows10 x64 1909 + Love2D 11.3。
◎ 実験の動機。 :
Love2D を使って何かしらのツールを作成するとして、どうやって画像ファイルその他を渡してやればいいのか、ちょっと悩んでしまった。もしかすると、Love2D は、ファイル選択ダイアログの類は持っていない・利用できないのではないか…。
まあ、エクスプローラから画像ファイルを、そのウインドウにD&Dしてやれば、ひとまずどうにかなるんじゃないか。でも、そんなこと、Love2D はできるのだろうか。ということで、ちょっと実験。
まあ、エクスプローラから画像ファイルを、そのウインドウにD&Dしてやれば、ひとまずどうにかなるんじゃないか。でも、そんなこと、Love2D はできるのだろうか。ということで、ちょっと実験。
◎ 結果。 :
一応出来た。と思う。たぶん。
png画像をD&Dして、表示される画像を変更できた。
ただ、今回のソースは png画像にしか対応させてないので、gif画像を渡すとエラーを出して停止する…。仕様です。
png画像をD&Dして、表示される画像を変更できた。
ただ、今回のソースは png画像にしか対応させてないので、gif画像を渡すとエラーを出して停止する…。仕様です。
◎ ソース。 :
_conf.lua
_main.lua
function love.conf(t) t.version = "11.3" -- love2d version t.window.title = "File Dropped - love2d" t.window.vsync = 1 t.window.width = 640 t.window.height = 480 t.window.msaa = 8 -- t.window.fullscreen = true -- t.window.fullscreentype = "exclusive" end
_main.lua
function love.load() font = love.graphics.newFont(12) filepath = "" loadreq = false img = nil scalev = 0 angle = 0 end function love.update(dt) if loadreq then -- load png image loadreq = false local f = io.open(filepath, "rb") local contents = f:read("*all") local data = love.filesystem.newFileData(contents, "temp.png") local imgdata = love.image.newImageData(data) f:close() img = love.graphics.newImage(imgdata) end scalev = 0.1 * math.sin(math.rad(angle)) angle = (angle + 540 * dt) % 360.0 end function love.draw() -- clear canvas love.graphics.clear(0.2, 0.2, 0.2, 1.0) -- draw image love.graphics.setColor(1.0, 1.0, 1.0, 1.0) if img ~= nil then local scrw, scrh = love.graphics.getDimensions() local w = img:getWidth() local h = img:getHeight() local x = scrw / 2 local y = scrh - 16 local ox = w / 2 local oy = h local yscale = 1.0 + scalev local xscale = (w * h) / (h * yscale) / w love.graphics.draw(img, x, y, 0, xscale, yscale, ox, oy) end -- draw text love.graphics.setFont(font) love.graphics.setColor(1, 1, 1, 1) love.graphics.print("Please drop the png image file", 220, 2) love.graphics.print(filepath, 2, 40) love.graphics.print("FPS: " .. tostring(love.timer.getFPS()), 2, 2) end function love.keypressed(key, isrepeat) if key == "escape" then -- ESC key to exit love.event.quit() end end function love.filedropped(file) filepath = file:getFilename() loadreq = true end
◎ 少し解説。 :
Love2D のウインドウに、何かがドラッグアンドドロップされた時は、love.filedropped() というメソッドを(もし用意してあるのなら)呼んでくれるらしい。渡された変数から、ファイルのパス(C:\hoge\fuga\piyo.png みたいな文字列)も得られるので、どの場所の、何のファイルがドロップされたのかを知ることができる。
であれば、渡されたそのファイルを開いてしまえばあっさりOK ―― というわけにはいかないようで。
Love2D は、ファイルアクセスに関して、セキュリティ面を意識して制限が設けられているのだとか。なんでも、以下の2種類のフォルダにしかアクセスできないそうで。
例えば、「画像ファイルを読み込んでウインドウ内に表示したい」場合は…。その画像ファイルは、えてして、ソースフォルダ以下(ソースフォルダ内に作ったサブフォルダも含む)に置いておかないといけない。他の場所に置いてあると、「そんなファイルは存在しねえよ!(だって俺そんな場所にアクセスできないもん、あるかどうかを調べることすらできないもん)」とエラーを出してしまう。
しかし、そんな仕様では、ツールの類を作りたい時に困ってしまうわけで…。ユーザは、自分の把握しやすい場所に、作業用のファイルを置いておきたいはずなので…。「この場所に絶対置け!」と強制されちゃうツールなんて、不便極まりないわけで…。
そこで、一応抜け道モドキが用意されているらしい。Love2D が持っているファイル関係APIではなく、Lua が持ってる標準的なファイル関係APIを使えば、任意の場所からファイルを読み込めるそうで。
コミュニティの掲示板を眺めた感じでは、「セキュリティ上推奨できないけれど、どうしてもそういうことをしたかったら、こういうやり方でどうにかするしかないだろうねえ」みたいな雰囲気を感じたり。
具体的な手順としては…。一例として、png画像を読み込んで画像描画に使う Image に変換したい場合、以下のような流れになる模様。
上記のソースでは、love.update(dt) の中で、この手順を使ってpng画像を読み込んでいる。
ただ、この場合、ドロップされるファイルは png画像のはず、と決め打ちして書いてある。例えば gif画像をドロップすると、「コレ、png画像のフォーマットじゃないから開けないよ」とエラーを出して止まってしまう。
本来なら、せめてファイルの拡張子をチェックして、Love2D が扱えるファイル種類かどうか判定して、扱えるファイル種類なら対応した仮画像ファイル名を渡して処理をすべき、なのだろうなと…。今回はそこまでやってないけど。
であれば、渡されたそのファイルを開いてしまえばあっさりOK ―― というわけにはいかないようで。
Love2D は、ファイルアクセスに関して、セキュリティ面を意識して制限が設けられているのだとか。なんでも、以下の2種類のフォルダにしかアクセスできないそうで。
- main.lua等のソースファイルが置かれているフォルダ。
- ゲームのセーブデータを保存できる特定のフォルダ。
例えば、「画像ファイルを読み込んでウインドウ内に表示したい」場合は…。その画像ファイルは、えてして、ソースフォルダ以下(ソースフォルダ内に作ったサブフォルダも含む)に置いておかないといけない。他の場所に置いてあると、「そんなファイルは存在しねえよ!(だって俺そんな場所にアクセスできないもん、あるかどうかを調べることすらできないもん)」とエラーを出してしまう。
しかし、そんな仕様では、ツールの類を作りたい時に困ってしまうわけで…。ユーザは、自分の把握しやすい場所に、作業用のファイルを置いておきたいはずなので…。「この場所に絶対置け!」と強制されちゃうツールなんて、不便極まりないわけで…。
そこで、一応抜け道モドキが用意されているらしい。Love2D が持っているファイル関係APIではなく、Lua が持ってる標準的なファイル関係APIを使えば、任意の場所からファイルを読み込めるそうで。
コミュニティの掲示板を眺めた感じでは、「セキュリティ上推奨できないけれど、どうしてもそういうことをしたかったら、こういうやり方でどうにかするしかないだろうねえ」みたいな雰囲気を感じたり。
具体的な手順としては…。一例として、png画像を読み込んで画像描画に使う Image に変換したい場合、以下のような流れになる模様。
- Lua の io.open() を使って、ファイルを開く。
- Lua の File.read() を使って、ファイルの中身を全部読み込む。
- Love2D が持っている仮想ファイルシステム上で、ファイルの中身を使って、仮ファイル(?)を生成する。
- 仮ファイルから、ImageData を作る。
- ImageData から、Image を作る。
上記のソースでは、love.update(dt) の中で、この手順を使ってpng画像を読み込んでいる。
local f = io.open(filepath, "rb") local contents = f:read("*all") local data = love.filesystem.newFileData(contents, "temp.png") local imgdata = love.image.newImageData(data) f:close() img = love.graphics.newImage(imgdata)
ただ、この場合、ドロップされるファイルは png画像のはず、と決め打ちして書いてある。例えば gif画像をドロップすると、「コレ、png画像のフォーマットじゃないから開けないよ」とエラーを出して止まってしまう。
本来なら、せめてファイルの拡張子をチェックして、Love2D が扱えるファイル種類かどうか判定して、扱えるファイル種類なら対応した仮画像ファイル名を渡して処理をすべき、なのだろうなと…。今回はそこまでやってないけど。
◎ 参考ページ。 :
_love.filedropped (日本語) - LOVE
_DroppedFile (日本語) - LOVE
_love.filesystem (日本語) - LOVE
_love.filesystem.newFileData (日本語) - LOVE
_Load image from different directory - LOVE
_Using love.graphics.newImage() with png files in an external directory - LOVE
_[SOLVED] Loading image from absolute directory using IO.Open - LOVE
_Why can't I open an image? - LOVE
_Is there a way of saving and loading files from anywhere? - LOVE
_DroppedFile (日本語) - LOVE
_love.filesystem (日本語) - LOVE
_love.filesystem.newFileData (日本語) - LOVE
_Load image from different directory - LOVE
_Using love.graphics.newImage() with png files in an external directory - LOVE
_[SOLVED] Loading image from absolute directory using IO.Open - LOVE
_Why can't I open an image? - LOVE
_Is there a way of saving and loading files from anywhere? - LOVE
[ ツッコむ ]
以上です。