18-2:Rasterのしくみ

Rasterクラスがどのようにして実現されているのか、 もう少し詳しく見てみましょう。


・ BufferedImageのピクセル情報は、 Rasterのオブジェクトというシステムに依存しない形式でプログラム内に記述されます。 このことを可能にする仕組みについて調べてみることにしましょう。 Rasterクラスは内部に2種類の重要なオブジェクトを持っています。 DataBuffer と SampleModel です。 DataBuffer はメモリ上のデータの実体である原始型の配列の集まりを表します。 SampleModel は、 それらのデータを解釈してピクセル情報を取り出すためのルールを定めます。


Rasterの内部構造。DataBufferとSampleModelには複数のタイプがある。

イメージデータの形式はさまざまな場合があるため、 DataBuffer も SampleModel も複数のタイプを用意しなければなりません。 そのため DataBuffer も SampleModel も抽象クラスで、 実際にオブジェクトとして生成されるのは、これらのサブクラスです。 どんなサブクラスがあるかを下表にまとめておきましょう。

DataBufferのサブクラス
クラス名用途
DataBufferByte1バイト単位のデータ(byte配列)の格納
DataBufferShort2バイト単位のデータ(short配列)の格納
DataBufferInt4バイト単位のデータ(int配列)の格納

SampleModelのサブクラス
クラス名用途
BandedSampleModel ピクセルに関する情報が、複数の配列に分かれ格納されている場合
ComponentSampleModel ピクセルに関する情報が、1つの配列内の連続する配列に格納されている場合
SinglePixelPackedSampleModel 1ピクセルの情報を1個の原始型データに格納し、 それらの集まり(通常は行に対応)をまとめて連続する配列として格納している場合
MultiPixelPackedSampleModel 複数のピクセルの情報を1個の原始型データに格納し、 それらの集まり(通常は行に対応)をまとめて連続する配列として格納している場合

・ Raster内の DataBuffer および SampleModelの情報は、 getDataBuffer() および getSampleModel()メソッドによって得ることができます。 それらが実際にどのサブクラスのオブジェクトになるかは、 BufferedImage もしくは Rasterを生成する時に、 それらのタイプを指定に応じて自動的に選択されます。 たとえば BufferedImage.TYPE_INT_RGB を指定して BufferedImage のオブジェクト を生成した場合には、DataBufferInt と SinglePixelPackedSampleModel が 選択されることになります。 SampleModelの助けを借りずに直接 DataBuffer に値を設定することも可能です。 ただしその際には、DataBufferの構造と データがどんな形式であるのかをきちんと理解していなくてはいけません。 またプログラムが特定のデータ形式に依存しないように注意を払う必要があります。


BufferedImage image
   = new BufferedImage( 2, 2, BufferedImage.TYPE_INT_RGB );
WritableRaster raster = image.getRaster();
DataBufferInt buffer = (DataBufferInt)(raster.getDataBuffer());
buffer.setElem( 0, 0x000000 ); buffer.setElem( 1, 0xff0000 );
buffer.setElem( 2, 0x00ff00 ); buffer.setElem( 3, 0x0000ff );

Raster のピクセル情報の操作は Rasterの setPixel() もしくは setSample() メソッドによっても行えます。 これらのメソッドは Rasterの中の SampleModelのオブジェクトにある データの設定用のメソッドを間接的に呼び出します。 この過程でデータ形式の違いが吸収され、 プログラムは特定のデータ形式に依存しないで記述することが可能となります。 そして通常の場合は DataBuffer や SampleModelの存在を意識する必要もありません。
Rasterの setPixel()メソッドでは ピクセル値は常に RGBの配列で指定できます。 これを int型のデータにまとめて格納する作業は SampleModelのオブジェクトに まかせてしまえばいいわけです。


BufferedImage image
   = new BufferedImage( 2, 2, BufferedImage.TYPE_INT_RGB );
WritableRaster raster = image.getRaster();
data[0]=0; data[1]=0; data[2]=0;     // RGBのデータ
raster.setPixel( 0, 0, data );       // ピクセル値の設定
data[0]=255; data[1]=0; data[2]=0;   // RGBのデータ
raster.setPixel( 1, 0, data );       // ピクセル値の設定
data[0]=0; data[1]=255; data[2]=0;   // RGBのデータ
raster.setPixel( 0, 1, data );       // ピクセル値の設定
data[0]=0; data[1]=0; data[2]=255;   // RGBのデータ
raster.setPixel( 1, 1, data );       // ピクセル値の設定