JDK1.1でJPEGをエンコードする
(Java開発者向け)

背景

 MS支配を叩き潰すために炎を燃やすSunに対し、そうはさせまいとSunに対して欺瞞的な態度をとるMS社。…結局そのとばっちりを最後に食らうのは我々コンシューマーなのであります。
 ということで、MS社が配布しているMSIEには元々JDK1.1対応のJava実行環境しか付属していません。最新のJDK1.3(J2SE1.3)に対応させるためには、雑誌の付録CDからインストールするか、Sunのサイトから巨大なファイルをダウンロードしなければなりません。少々ネットの世界に精通している方のPCには最新のJava環境がインストールされているものですが、JDK1.2やJDK1.3の存在自体が一般には広く知られていないのも事実です。
 またMacOSX以外のMacOS(いわゆるClassicMacOS)ではJDK1.2以降のJava実行環境が用意されていません。
 そのため、お手軽に使えるJavaアプレットはどうしてもJDK1.1以前に対応させる必要があります。(余談ですが、お絵かき系アプレットではpoo版がJDK1.0対応、その他はJDK1.1対応のようです。もちろんBBSPainterはJDK1.1対応です。)
 JDK1.2以降ではJPEGエンコーダとデコーダが付属しています。しかし、JDK1.1ではJPEGを読み込むことはできてもエンコードはできません。
 そこで今回は勉強も兼ねてJPEGエンコーダを作ってみましょう。

参考文書

 インターネットではJPEGエンコーダの詳細について解説された資料はあまり見かけません。私の探し方が悪いのか、それとも日本語以外のページを探せばあるのかも知れませんが、とにかく使えそうなものを見つけることはできませんでした。(余談ですが、Unisysの野望を叩き潰すべく登場しながら、未だ知名度が低いPNGについては詳細な資料を読むことができます。)根性入れて探せば、案外オーストリアかポーランド辺りの怪しげなサイトの奥深くに消し忘れて残っているのを発見(以前ファックスのT.30規格書を探していたらこういうことがあった)できるかも知れませんが、今回はたまたま駅前の本屋でよい本(JPEG概念からC++による実装まで ISBN4-7973-0632-7)を見つけたのでコレを参考にしましょう。

Javaにおけるイメージ

 Javaの設計基盤としてプラットフォーム中立という考えが方があります。それゆえ、java.awt.Imageクラスで定義されているイメージは非常に抽象的で、すぐには理解しづらいものとなっています。ここで、それについて長々と書くと、私の貴重な寝る時間が減るので、とりあえずは最も安易な方法で解決をはかりましょう。
 JavaDocからjava.awt.image.PixelGrabberを見て下さい。これは、java.awt.Imageからint型の配列としてラスタ(Macプログラマはピクセルマップ、Winプログラマはビットマップという言葉を好むようです。癪ですがこれからは長いものに巻かれてビットマップと呼びましょう。)を抽出します。これで、単純にjava.awr.Imageをビットマップとして扱うことができます。

java.awt.Imageの設計をみる限り、このクラスはラスタイメージ以外のイメージも表せるようになっています。おそらく、EPSやPDF等の非ラスタ(大抵はベクタイメージ。最近はフラクタルなどというものもあるらしい)イメージを意識しているのでしょう。さらには、時間とともに刻々と変わるアニメーションGIFの表示も可能です。java.awt.image.PixGrabberはjava.awt.image.ImageConsumerというjava.awt.Imageから各ピクセルの色を取得するインターフェースの実装です。java.awt.image.ImageConsumerを各自でうまく実装すれば、java.awt.image.PixGrabberを使うよりも効率的にJPEGのエンコードが行えるでしょう。(でも考えるのが面倒くさいのでやらない)

JPEG符号化方式の概要

 まず、画像を輝度、色差ごとに8×8ピクセルのブロックに分解し、「離散コサインフーリエ変換」を使ってブロック内に見られる色の変化を波長の違う8つの波に分解します。さらに「量子化」と呼ばれる操作で波長の短い波を中心に情報を切り落とします。最後に「ハフマン符号」を使って圧縮します。
 要はJavaでJPEGを出すのが目的なので、ここであまり詳しい説明はしません。各自専門書等を参照して下さい。フーリエ変換や情報理論の基礎から学びたいなら、大学の電子工学科や情報工学科に潜り込むのが一番でしょう。(ユニクロで買ったオーソドックスでカジュアルな服装で、しかも背中にナップサックをしょってビニール傘を持っていたりすれば簡単に潜り込むことができます。万一の場合は「友達から面白い講義だと聞いて他の大学(学部)から聴きに来た」等の言い訳が有効です。教務係から講義の日程表ももらっておきましょう。)

結果

 次のファイルにソースコードが入っています。コンパイル後、TestAppを実行してください。サンプルとして添付されているJPEGファイルよりさらに質の悪いJPEGファイルが生成されます。TestApp中のsetQFactorの値を変えると生成する画像の画質がどうなるか実験してみましょう。

jpegcoder.lzh

[注意]このプログラムをどこかで使いたい方は使って構いませんが、なんら保証はありません。このプログラムが原因でどのような恐ろしい事態が発生しても作者は関知しないのでご了承下さい。(たぶんめったなことはないと思うけど...)