Java – ImageIOの画像出力とColorModelとの関係

プログラミング
スポンサーリンク

画像ビューアを開発しているのですが、
画像処理した後にJpegとして保存すると赤っぽくなっていた原因が分かった。
Javaのせいにしてたけど、完全なミスでした。^^;

Java6でImageIOを使ってjpeg,gif,png,bmpと保存できるようになったけど、注意点が必要。

元ソースが「TYPE_INT_ARGB」の場合の話です。

png (32bitフルカラー・インデックスカラーに対応)
どんなカラーモデルでも保存可能
α値つきの32ビットのColorModelでもOK。なんでもOK。
IndexColorModelでも可能。透明色指定も可能。
但しIndexColorModelの場合ビットが8に固定される?
使用されている色が256以下なら、IndexColorModelで保存したほうがいいのかな。

jpg/jpeg (24bitフルカラーのみ対応※・グレイスケール(TYPE_BYTE_GRAY)は試してないです)
TYPE_INT_ARGB の場合、保存できるが赤っぽくなる※。
保存する場合に、ColorConvertOpのfilterを使って、TYPE_INT_RGBに変換が必要。
IndexColorModelは試してないからわからない。
仕様上、透明色の指定は不可能。

bmp (24bitフルカラー・インデックスカラーに対応)
TYPE_INT_ARGB の場合、32ビットってのもbmpとして可能そうなんだけど、保存失敗します。
TYPE_INT_RGBに変換するか、IndexColorModelのBufferedImageを作成する。
仕様上、透明色の指定は不可能。

gif (インデックスカラーのみ対応)
TYPE_INT_ARGB の場合、保存不可能。
TYPE_INT_RGBへ変換すると、自動的に256色に減色してくれる。(但し、α値の透明色は無視される。)
透明色を指定したい場合は、自分で減色して、透明色つきのIndexColorModelのBufferedImageを作成すること。

こんな感じ。

保存するだけなら「TYPE_INT_RGB」に変換することで、
jpeg,gif,png,bmp一応全ての拡張子として保存できるんだけど。

実際に、それぞれ特性をいかした保存形式で保存しようと思うと、
カラーモデルを考えないといけないから結構面倒。

一応、今回の更新で、これらは全て使えるようにしてみました。

ちなみに、BufferedImageのgetType() で、いま「TYPE_INT_RGB」なのか「TYPE_INT_ARGB」なのか、
getColorModel()で、「IndexColorModel」なのか普通の「ColorModel」なのか調べることが出来ます。

おさらい
TYPE_INT_ARGB … 通常こっちかな、透明色・赤・緑・青 の順番
TYPE_INT_RGB … 保存する場合は何も考えなくていいから楽。
TYPE_BYTE_INDEXED … GIF画像とかインデックスカラーの画像を作るときこっち。
TYPE_BYTE_GRAY … 試してないけど、jpegでグレイスケールで保存できるのかな。
TYPE_BYTE_BINARY … 試してないけど、wbmpで保存できるのかな。

もう一度、保存読み込みして、確認してみたんだけど、どうやらImageIOはTYPE_INT_ARGBの場合
透明度情報も含めたjpegで保存してくれることが分かった。
透明度をjpegに含めるって、仕様上やっていいのかな。よくわかんない。Flashは対応してるらしい。
それで、対応していないソフト?は赤っぽく表示してしまったというわけ。
透明度もたせた画像形式って可逆圧縮のpngしかないから、
Javaのゲームとかでフルカラー+透明度の画像を用意したい時は、
アルファチャンネル付きのjpegで保存しておくっていうのも手かもしれない。


2009年7月26日追記

画像の読み書きのサンプルを作ったので、どうぞ利用してみてください。自由に使ってもらって結構です。
画像をファイルとして読み書きする

たぶん、Java1.6には、IndexColorModelで保存するときにバグ?があるかもしれません。
例えば、0番以外を、透明色に指定した場合、うまく画像が保存できません。
また、透明色の黒と、透明色ではない黒が、存在するときもうまく保存できないようです。
あと、IndexColorModelでbmp保存すると、うまく保存できません。
誰か原因分かるかいたら教えてください。


2010年2月26日追記

関連記事を書きました。
「BufferedImage」の TYPE_4BYTE_ABGR から TYPE_INT_ARGB にする方法
「BufferedImage」の TYPE_BYTE_GRAY から TYPE_BYTE_INDEXED にする方法

コメント

タイトルとURLをコピーしました