DATE : 2006/08/30 (Wed)
(前回の記事)
BufferedImage にアルファチャンネルを追加するコード(一部)は、次のようになります。(import 文などは省略してあります)。
ここで、image はアルファチャンネルを追加する対象の画像(RenderedImage)、最後の return 文で返されるオブジェクトが、アルファチャンネルが追加された画像(BufferedImage)です。
// 1 ColorModel destColorModel = createColorModelWithAlpha(image.getColorModel()); // 2 WritableRaster destRaster = destColorModel. createCompatibleWritableRaster( image.getWidth(), image.getHeight()); // 3 setColorSamples(destRaster, image.getData()); // 4 setAlphaSamples(destRaster); // 5 return new BufferedImage(destColorModel, destRaster, destColorModel.isAlphaPremultiplied(), null);
コメントで示したとおり、上のコードは5つの手順に分かれています。ここからは、それぞれの手順を細かく見ていくことにします。
1. BufferedImage 用に、アルファチャンネル付きの java.awt.image.ColorModel を生成する
ColorModel destColorModel = createColorModelWithAlpha(image.getColorModel());
ここでは、createColorModelWithAlpha メソッドに、対象となる画像のカラーモデルを渡すことでアルファチャンネル付きのカラーモデルを生成しています。
createColorModelWithAlpha メソッドは、次のようなメソッドです。
private static ColorModel createColorModelWithAlpha(ColorModel src) { return new ComponentColorModel(src.getColorSpace(), true, src.isAlphaPremultiplied(), Transparency.BITMASK, src.getTransferType()); }
渡されたカラーモデルと同じ色空間、アルファ値の乗算状態、サンプルの型で、それでいてアルファ値をもつようなカラーモデルを生成しています。
なお、「Transparency.BITMASK」は、透明部分が「完全に不透明、もしくは完全に透明」であることを表します。つまり、アルファ値が1(不透明)か0(透明)かに限定されるわけです。もしも、任意の透明度を設定したい場合は、「Transparency.TRANSLUCENT」にします。(Transparency インタフェースは、java.awt パッケージにあります)
2. BufferedImage 用に、上の ColorModel が扱える java.awt.image.WritableRaster を生成する
WritableRaster destRaster = destColorModel. createCompatibleWritableRaster( image.getWidth(), image.getHeight());
java.awt.image.ColorModel には、そのカラーモデルが扱える WritableRaster を生成するメソッドがあります。
そのため、ここではそのメソッドを利用することで、生成したカラーモデルが扱える WritableRaster を生成しています。
(つづきます)
DATE : 2006/08/23 (Wed)
java.awt.image.BufferedImage などの java.awt.image.RenderedImage にアルファチャンネルを追加した BufferedImage を作るには、次のような手順で処理を行います。
以下の手順では、「RenderedImage」がアルファチャンネルを追加する対象の画像オブジェクト、「BufferedImage」がアルファチャンネルを追加した画像オブジェクトとします。
- BufferedImage 用に、アルファチャンネル付きの java.awt.image.ColorModel を生成する。
- BufferedImage 用に、上の ColorModel が扱える java.awt.image.WritableRaster を生成する。
- BufferedImage 用の WritableRaster の色成分(アルファチャンネルを除いた成分)部分に、RenderedImage の画素値をコピーする。
- BufferedImage 用の WritableRaster にアルファチャンネル部分の値を設定する。
- BufferedImage 用に生成した ColorModel と WritableRaster から、BufferedImage を生成する。
サンプルコードは少々長いので、次の記事に掲載しようと思います。
(つづきます)
DATE : 2006/08/22 (Tue)
java.awt.image.BufferedImage のあるコンストラクタが少々わかりづらいのでメモしておきます。
BufferedImage には、BufferedImage(java.awt.image.ColorModel, java.awt.image.WritableRaster, boolean, java.util.Hashtable) というコンストラクタがあります。
初めの ColorModel や WritableRaster は画像内のデータの解釈方法(ColorModel)と画像のデータ(Raster)であることは分かります。しかし、その後の boolean と Hashtable が謎です。
ちなみに、日本語版 API ドキュメントには、次のように書かれています。
public BufferedImage(ColorModel cm, WritableRaster raster, boolean isRasterPremultiplied, Hashtable,?> properties)
ColorModel および Raster を指定して、新しい BufferedImage を構築します。Raster の SampleModel のバンドの数および型が、色成分およびアルファ成分を表すために ColorModel によって要求される数および型と一致しない場合は、 RasterFormatException がスローされます。このメソッドは、ColorModel の alphaPremultiplied 状態と一致させるために色 Raster データをアルファで乗算または除算できます。この BufferedImage のプロパティは、String と Object のペアの Hashtable を渡すことによって確立できます。
- パラメータ:
- cm - 新しいイメージの ColorModel
- raster - イメージデータの Raster
- isRasterPremultiplied - true の場合、ラスタのデータはアルファによってあらかじめ乗算されている
- properties - String と Object のペアの Hashtable
この引用によると、boolean は『true の場合、ラスタのデータはアルファによってあらかじめ乗算されている』ことを、Hashtable は『BufferedImage のプロパティ』を表すようです。
Hashtable については、ドキュメントを調べるうちに解決できました。BufferedImage のスーパークラスである java.awt.Image を見る(Image#getProperty(String, java.awt.image.ImageObserver))と、次のように書かれていました。
プロパティ名「comment」を使用すると、イメージ、そのソース、またはその作成者の記述としてアプリケーションに提示できるオプションのコメントを格納できます。
どうも、画像に対する付加情報が Hashtable で設定できるようです。例えば、javax.swing.ImageIcon では、「comment」と設定したプロパティをアイコンの説明に使用するようです。(ImageIcon(java.awt.Image)
しかし、この付加情報はあくまでも「画像オブジェクト」に対するものであり、「画像ファイル」の付加情報ではありません。「画像ファイル」に対して、作者やコメントなどの付加情報を付ける場合は、ImageIO であれば javax.imageio.metadata.IIOMetadata を使わなければなりません。
次に boolean です。正直なところ、ドキュメントからはいまひとつ意味がつかめません。『ColorModel の alphaPremultiplied 状態と一致させるために色 Raster データをアルファで乗算または除算できます』という部分から、ColorModel#isAlphaPremultiplied() との関係がうかがえます。しかし、『Raster の SampleModel のバンドの数および型が、色成分およびアルファ成分を表すために ColorModel によって要求される数および型と一致しない場合は、RasterFormatException がスローされます。』という部分には、Raster と ColorModel とが対応しない場合は例外が発生すると書かれているので、alphaPremultiplied 状態が合っていないと例外が発生するようにも受け取れます。しかし、ColorModel#isAlphaPremultiplied() から alphaPremultiplied 状態は取得できるので、あえて引数として alphaPremultiplied を受け取る理由が分かりません。
そこで、BufferedImage(ColorModel, WritableRaster, boolean, Hashtable) のソースコードを調べてみました。すると、次の1行が見つかりました。
coerceData(isRasterPremultiplied);
上のコードは、次のメソッドを呼び出しています。(BufferedImage#coerceData(boolean))。
public void coerceData (boolean isAlphaPremultiplied) { if (colorModel.hasAlpha() && colorModel.isAlphaPremultiplied() != isAlphaPremultiplied) { // Make the color model do the conversion colorModel = colorModel.coerceData ( raster, isAlphaPremultiplied); } }
コンストラクタで指定された ColorModel (フィールドの colorModel)のalphaPremultiplied 状態と isAlphaPremultiplied とを比較して、異なる場合は引数に指定されたものと同じ状態の ColorModel を生成しています。また、ラスタのデータの計算も行っています。
ここから、BufferedImage(ColorModel, WritableRaster, boolean, Hashtable) の boolean は、BufferedImage の ColorModel の alphaPremultiplied 状態を設定する引数と言えます。
参考文献
DATE : 2006/08/21 (Mon)
java.awt.image.RenderedImage から java.awt.image.BufferedImage を生成するには、次のような手順で行います。
- RenderedImage からカラーモデル(java.awt.image.ColorModel)とラスター(java.awt.image.Raster)を取得する。
- ラスターは読み取り専用なので、書き換え可能なラスター(java.awt.image.WritableRaster )を取得する。
- WritableRaster と ColorModel から、BufferedImage を生成する。
コードにすると、次のようになります。ここで、source は BufferedImage を生成するための RenderedImage です。(import 文などは省略してあります)
ColorModel colorModel = source.getColorModel();
WritableRaster raster = source.getData().
createCompatibleWritableRaster();
BufferedImage image = new BufferedImage(colorModel, raster,
colorModel.isAlphaPremultiplied(), null);
コードに示したとおり、BufferedImage には、WritableRaster や ColorModel からインスタンスを生成できるコンストラクタがあります。
その最後から2番目の引数は、アルファ値を Raster のデータにあらかじめ乗算しておくかどうかを指定します。ここでは特にこだわらないため、ColorModel の設定どおりにしました。
また最後の引数は java.util.Hashtable で、画像のプロパティを設定できます。ただし、今回はプロパティがないので null にしました。(BufferedImage のソースコードを見たところ、null に対応するコードがあったので、特に問題はないと思います)
参考文献
DATE : 2006/08/19 (Sat)
「分割画像の作りかた」や「分割画像の作りかた 2」で生成した分割画像片を BufferedImage に取り出すには、次のようなコードを記述します。
なお、tileX は分割画像の水平方向での番号、tileY は垂直方向での番号です。また、対象の分割画像を格納する source は javax.media.jai.PlanarImage です(RenderedOp や TiledImage も PlanarImage です)。(import 文などは省略してあります)
Rectangle tileRect = source.getTileRect(tileX, tileY);
BufferedImage tile = source.getAsBufferedImage(tileRect,
source.getColorModel());
getTileRect メソッドで画像片の領域を取得し、その領域内の内容を BufferedImage として取得します。
簡単なコードですが、API ドキュメントの中に埋もれていたので取り上げてみました。
((´・ω・)実際、気付くまではちょっと非効率なコードを書いていました)