Lua-GD でのアルファチャンネルの扱い
Lua-GD のアルファチャンネルの扱いでよく失敗するのでまとめました。勘違いしていると、じつは画像が透明だったり、不透明だったり、半透明があるのに思い通りにブレンドされなかったりします。
内容は Lua-GD 2.0.33r2 に準拠しています。他の環境下での挙動は保証しません。
画像の新規作成 (フルカラー)
- フルカラー画像の作成には、
gd.createTrueColor(x, y)
を利用。 - 画像作成後は、全面不透明黒で塗られた状態(透明ではない)
- 画像作成後は、gdImage:alphaBlending(true) の状態。
- 画像作成後は、gdImage:saveAlpha(false) の状態。
- アルファチャンネルの範囲は 0〜127 であり、0〜255 ではないので注意。
- 透明なキャンバスを作成するには透明ピクセルで塗りつぶす必要がある。下記にフルカラー透過画像を作成するコードを示す。
-- create a blank truecolor image gd.createTrueColorBlank = function(x, y) local gdImage = gd.createTrueColor(x, y) if gdImage == nil then return nil end local colorTrans = gdImage:colorAllocateAlpha(255, 255, 255, 127) gdImage:alphaBlending(false) gdImage:filledRectangle(0, 0, gdImage:sizeX() - 1, gdImage:sizeY() - 1, colorTrans) gdImage:alphaBlending(true) gdImage:colorDeallocate(colorTrans) return gdImage end
余談ですが、gd.create(gdImage)
的な関数はありそうでないです。
画像の読込 (PNG)
- PNG画像の読込には、
gd.createFromPng(filename)
を利用。- ファイル内容を文字列をとして読み込んである場合は
gd.createFromPngStr(string)
を利用。
- ファイル内容を文字列をとして読み込んである場合は
- パレットかフルカラーかは入力ファイルに基づく(要注意!)
画像の保存 (PNG)
- PNG画像の保存には、
gdImage:png(filename)
,gdImage:pngEx(filename, compression_level)
を利用。 - 出力ファイルがパレットかフルカラーかは入力画像に基づく。
- アルファチャンネルの保存は
gdImage:saveAlpha(true)
を実行していないと行われない。
画像のコピー・貼り付け
パレットとフルカラー
フルカラーとパレットの混在時には注意を要する場合がある。
- 画像がフルカラーかどうか調べるには、下記のようなメソッドを要する。
gd.isTrueColor = function(gdImage) if gdImage == nil then return nil end local gdStr = gdImage:gdStr() if gdStr == nil then return nil end return (gdStr:byte(2) == 254) end
- パレットの「透過色」とフルカラーの「アルファ」は異なる概念である。それ故か下記の問題がある。
gd.copy()
で パレット→フルカラー のコピーを行うとき、gdImage:alphaBlending(boolean)
に関わらず透過ピクセルが透過コピーされてしまう。ただし、gd.copyResampled()
であればgdImage:alphaBlending(boolean)
を尊重したコピーが行われる。
- 上記を考慮すると、画像をフルカラーに変換する下記のコードが書ける。
-- return a converted image gd.convertToTrueColor = function(srcImage) if srcImage == nil then return nil end if gd.isTrueColor(srcImage) then return srcImage end local gdImage = gd.createTrueColor(srcImage:sizeX(), srcImage:sizeY()) if gdImage == nil then return nil end gdImage:alphaBlending(false) local colorTrans = gdImage:colorAllocateAlpha(255, 255, 255, 127) gdImage:filledRectangle(0, 0, gdImage:sizeX() - 1, gdImage:sizeY() - 1, colorTrans) gdImage:copyResampled(srcImage, 0, 0, 0, 0, gdImage:sizeX(), gdImage:sizeY(), gdImage:sizeX(), gdImage:sizeY()) gdImage:alphaBlending(true) return gdImage end
おまけ:画像の左右反転
- 拡大コピーで負数を指定
- 反転画像の作成は、新しいGDライブラリにはあるが、上記 Lua-GD にはない。ただし下記で代用できる(巨大画像では低速)
-- flip an image about the vertical axis gd.flipVertical = function(gdImage) if gdImage == nil then return nil end gdImage:alphaBlending(false) for x = 0, gdImage:sizeX() do for y = 0, math.floor(gdImage:sizeY()/2) - 1 do local c1, c2 = gdImage:getPixel(x, y), gdImage:getPixel(x, gdImage:sizeY()-1-y) gdImage:setPixel(x, y, c2) gdImage:setPixel(gdImage:sizeX()-1-x, y, c1) end end gdImage:alphaBlending(true) -- TODO: restore the previous value return gdImage end -- flip an image about the horizontal axis gd.flipHorizontal = function(gdImage) if gdImage == nil then return nil end gdImage:alphaBlending(false) for y = 0, gdImage:sizeY() do for x = 0, math.floor(gdImage:sizeX()/2) - 1 do local c1, c2 = gdImage:getPixel(x, y), gdImage:getPixel(gdImage:sizeX()-1-x, y) gdImage:setPixel(x, y, c2) gdImage:setPixel(gdImage:sizeX()-1-x, y, c1) end end gdImage:alphaBlending(true) -- TODO: restore the previous value return gdImage end -- applies vertical and horizontal flip gd.flipBoth = function(gdImage) -- use of gd.copyRotated() can provide the same result? gd.flipVertical(gdImage) gd.flipHorizontal(gdImage) return gdImage end