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

次回未定

  • DefineEdit(テキストボックス), DefineShape(ベクター画像), DefineSprite(シンボル)、DoAction(AcrionScript2.0 ByteCode)等、ご要望があれば続きます。

*1: SWF 8 以降では DefineBitsJPEG 系のタグに PNG データを格納できるようですが、それには触れません

*2: PNG は R,G,B 各々を 16bit で表現する 48bit フルカラーも表現出来ますが、その説明は省きます

*3: alpha値や opaque 等と呼ばれる事が多いです