SWFバイナリ編集のススメ第五回 (PNG)
こんにちは。メディア開発のよやです。
今回は、PNG 画像入れ替えについてお話します。
PNG の情報を格納できるタグ
- DefineBitsLossless, DefineBitsLossless2 が利用出来ます。(*1)
- DefineBitsLossless に透明度情報を加えたのが、DefineBitsLossless2 です。
PNG の特徴 (基礎知識)
- 可逆圧縮のフォーマットです。(JPEGと違って画像の細部が潰れません)
- パレット形式とトゥルーカラー形式(24bit(*2)フルカラー)の両方に対応します。
- 色毎、ピクセル毎に透明度(半透明も可)が指定できます。 (GIFは半透明を扱えません)
パレット形式
- 前回の GIF 編の説明と似ていますが、(GIFと異なり)半透明も扱う為、格納方式が異なります。
- 以下のは輪郭の外が透明で、黄色を少しだけ半透明した例です。
- PLTE chunk にカラーパレット(=カラーテーブル)が入り、IDAT chunk に各ピクセルの色インデックス一覧が格納されるのは GIF と実質的に変わりませんが、透明度情報を tRNS chunk に配列で格納します。
- PLTE (カラーパレット)の先頭から順に対応する不透明度(*3)を tRNS に格納します。透明又は半透明な分だけで良くて省略した分は不透明(0xff)として扱われます。
トゥルーカラー形式
- pixel 毎に RGB の 24bit や RGBA の 32bit を並べる格納方法です。
- RGBA を例にとると以下のようになります。
- こちらは pixel毎に透明度を指定できます。勿論、半透明も表現できます。
DefineBitsLossless タグ
以下に、DefineBitsLossless, DefineBitsLossless2 のタグを種類毎に図で示します。DefineBitsLossless の方には format=4 (15bit RGB 形式)も存在して、RGB 各々を 4 bit で表す 12bit カラーを格納するのに便利ですが、説明を省略します。
DefineBitsLossless (透明色なし)
format=3 (カラーマップ形式= パレット形式)
- このパターンでは 4 の倍数での padding 処理が必要です。(format=5 や DefineBitsLossless2 では padding は不要)
- GIF とほぼ同じですので詳細は前回の記事を参考にして下さい。 > http://labs.gree.jp/blog/2010/10/1263/
format=5 (24bit RGB形式)
- カラーマップ無しで画像上の各 pixel の RGB をそのまま並べて格納します。
- RGB の頭に 00(=X) を付けて、XRGB で並べます。
DefineBitsLossless2 (透明色情報つき)
- DefineBitsLossless とほぼ同じで、色の並びについて、カラーマップの RGB が RGBA に、(24Bit) RGB の XRGB が ARGB に変わります。
format=3 (カラーマップ形式= パレット形式)
- カラーマップに透明度情報も付加します。
- カラーマップ上の並びは RGBA です。format=5 は ARGB なのでご注意下さい。
format=5 (32bit ARGB形式)
- 各pixel 毎に透明度を含めた ARGB 32bit を単純に並べる形式です。
注意点
- RGB(24bit)のカラーマップ形式では横のライン毎に 4byte 境界に合うように padding を入れます。前回のGIF編を参考にして下さい。
- GD で抽出した A(alpha値)は 0(不透明)=>127(透明)で、SWF の方は 0(透明)=>255(不透明)なので、変換する必要があります。
- ARGB, RGBA 表現は、A に応じて以下の式で RGB を補正します。
PNG 差し替え処理
- 素材Flash (grayorz.swf)
- 尚、これから説明するコードは以下のファイルから切り出したものです。
- SWF 編集に使う IO_SWF_Editor は openpear で公開しています。pear の入っている環境では、以下のコマンドでインストールできます。
パレット形式の PNG
GD を使うと以下のように吸い出せます。
- パレットを吸い出す
- パレットを指すピクセルデータを吸い出す (横一列毎に 4 の倍数になるように)
- 吸い出した画像データを DefineBitsLossless の形式に変換する
- SWF 内の画像を入れ替える
- PNG画像 (GREElabs-palette.png)
- コマンド実行
- 結果(GREElabs-palette.swf)
32Bit RGBA形式のPNG画像(透明度付き)
- 32Bit RGBA を吸い出して ARGB で並べる (RGB は A に応じて補正)
- GD library の alpha 値は特殊なので 127~0 を 0~254 に変換。
- 吸い出した画像データを DefineBitsLossless2 の形式に変換する
- SWF 内の画像を入れ替える
- PNG画像 (GREElabs-rgba.png)
- コマンド実行
- 結果(GREElabs-rgba.swf)
簡単ですね!
備考
- SWF 仕様書には、DefineLossless2 の format = 3 (カラーマップ形式) に対する A 値による RGB 補正が書かれていませんが、実際には format = 5 同様に補正が必要なようです。(経験談)
- ColormapNum は色数を -1 した値が入っているので注意。1byte で 1色~256色を表現する為だと思われます。(そのままだと 255色で打ち止めなので)
- 画像データを圧縮する際に使用する gzcompress は第二引数で圧縮レベルを指定できます。指定しない場合は Zlib ライブラリのデフォルト値 6 が適用され、CS2,3,4 等が出力する SWF の Zlib圧縮も 6 相当です。CPU とファイルサイズのトレードオフで、この値を調整するのも手です。
参考URL
- http://www.adobe.com/devnet/swf.html
- http://www.m2osw.com/swf_tag_definebitslossless
- http://pwiki.awm.jp/~yoya/?Flash/SWF/format/Lossless
- http://www.w3.org/TR/PNG/
- http://www.geocities.co.jp/Playtown-Knight/6845/sd_doc/format_png.html
- http://homepage2.nifty.com/sophia0/png.html
- http://bb.watch.impress.co.jp/cda/bbword/15612.html
次回未定
- DefineEdit(テキストボックス), DefineShape(ベクター画像), DefineSprite(シンボル)、DoAction(AcrionScript2.0 ByteCode)等、ご要望があれば続きます。
*1: SWF 8 以降では DefineBitsJPEG 系のタグに PNG データを格納できるようですが、それには触れません
*2: PNG は R,G,B 各々を 16bit で表現する 48bit フルカラーも表現出来ますが、その説明は省きます
*3: alpha値や opaque 等と呼ばれる事が多いです
0