ming について

2005/06/29 更新

JPEG について

ming だけが悪いわけではなくて, どちらかというと FlashLite(てか Flash)の変態仕様の話になります。

現象

swf ファイルで JPEG 画像を使用すると, DefineBitsJPEG2(3) というリソースがファイルに埋め込まれます。 このコマンドの JPEGData という部分は,ほぼ JPEG ファイルの構造そのものです。
…といいたいところなんですが, そのような JPEG ファイルそのままの形でリソースを埋め込むと, PC 上の Flash Player からはきちんとみえるのに, au W21CA 系の携帯では画像が表示される部分が赤いボックス (デコード失敗)になってしまいます。 他の機種(できればカシオ日立製以外の端末)でも そのような現象が見られるという方はご報告頂けると幸いです。

追記 鳥取三洋の au 端末や DoCoMo の端末, DoCoMo の i-mode シミュレータ等でも赤ベタは発生するそうな。 報告dクスです。

原理

JPEG ファイルは,一般的に以下のような構造をとります (ある程度柔軟な構造なので必ずしも順番等が以下と一致するとは限りません)

SOI APP0 DQT DHT SOF0 SOS EOI

細かい定義は JPEG の仕様書等を参照していただくとして, おおまかには,

を示すことをつかんでください。

さて,swf ファイルでは実際にどのようにこの情報が格納されているかというと,

SOI DQT DHT EOI SOI APP0 SOF0 SOS EOI

のように,一度圧縮用テーブルが格納された後に EOI マーカが入り, その直後にSOI マーカとともに 実際の圧縮データ等が並ぶことになっています。

なぜこのようになっているかについてですが。 Flash の前身の Future Splash 時代には JPEGTable というコマンドと DefineBits というコマンドで, 圧縮テーブルと圧縮データを別々に格納していました。 その名残だと思われます。

ともかく,前者の swf 的に正しくない JPEG データを埋め込むと, PC 上ではきちんとデコードしてくれるのですが, 少なくとも W21CA ではデコードしてくれず不正なデータとなってしまうのです。

原理 追記

その後ちょっと確かめててわかったんだけど, SOIEOI のブロックが2回あればいいっぽい。 実際,別の jpeg データを含む swf ファイルを作ったところ,

EOI SOI SOI APP0 DQT SOF0 DHT SOS EOI

こんな変な並びのものが生成された (通常の JPEG の先頭に EOI SOI がくっついたもの)。 これも W21CA で正常にデコードできた。 先頭の EOI SOISOI EOI にしても オッケー。 なんか苦労してエンコーダ書いただけ馬鹿を見たな。

ちなみに Flash で自力でエンコードさせると, 先に書いたように,テーブルと実データが別々のブロックにわかれるので, 安全のためには先に挙げたような並び順にするのが無難。

パッチ

ということで,原理はともかく ming 0.3 beta 1 に対するパッチ jpeg.c.diff です。 src/blocks の jpeg.c だけ修正します。 直接 src/blocks に放り込むなどして patch 当てしてください。

個人的には newSWFJpegWithAlpha の仕様も使いづらいので 自力で alpha データを zlib 圧縮するようにさらに改変していますが, 仕様そのものが変わってしまうので上記パッチには含めていません。

サンプルプログラム

ming 非依存で JPEG から SWF ファイルに変換するプログラムを 作ってみました (jpg2swf4.zip)。 いちおう Win32 のバイナリも同梱してあります。 コマンドラインで JPEG のファイルを指定すると, 指定されたファイル名の拡張子を「.swf」に変えたファイルに吐き出します。 大事なファイルを上書きしないよう気を付けてください。

サーバサイドでダイナミックコンテンツとして生成するなら このプログラムを使うより, 上のパッチをあてた ming を使って PHP 等で処理する方がレスポンスは早いでしょう。