このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。
昨日の続き。encodeRawPixels の実装を行う。
RAW 符号化は、ピクセルの画素表現をそのまま使う。
1 画素のサイズは、PixelFormat#getBitPerPixel、
画素のバイト表現は PixelFormat#isBigEndian、
そして、画素は左から右、上から下の順で並べられる。
========== RFBCanvas#encodeRawPixels ==========
private byte[] encodeRawPixels(Rectangle rect) throws IOException {
// まずは画素の配列を取得
WritableRaster raster = displayBuffer.getRaster();
Object data = raster.getDataElements(rect.x, rect.y,
rect.width, rect.height, null);
PixelFormat format = context.getPixelFormat();
// 画素あたり 1 バイトならバイト配列なのでそのまま返す
if (format.getBitPerPixel() == 8) {
return (byte[])data;
}
// それ以外の場合、エンディアンに応じて変換が必要
int count = rect.width * rect.height;
int bytes = count * (format.getBitPerPixel() / 8);
ByteBuffer buffer = ByteBuffer.allocate(bytes);
if (format.isBigEndian()) {
buffer.order(ByteOrder.BIG_ENDIAN);
} else {
buffer.order(ByteOrder.LITTLE_ENDIAN);
}
switch (format.getBitPerPixel()) {
case 16:
{
short[] pixels = (short[])data;
for (int i = 0; i < count; ++i) {
buffer.putShort(pixels[i]);
}
}
break;
case 32:
{
int[] pixels = (int[])data;
for (int i = 0; i < count; ++i) {
buffer.putInt(pixels[i]);
}
}
break;
default:
throw new IOException();
}
return buffer.array();
}
========== end of RFBCanvas#encodeRawPixels ==========
画面データは BufferedImage に格納されており、
BufferedImage は内部的に WritableRaster を持つ。
その WritableRaster の getDataElements を使うと、
画像の一部領域のデータを取得することができる。
これは非常に便利なメソッドで、指定範囲の画素データを、
SampleModel#getTransferType(転送型)が示す、
プリミティブ形の配列として取得することができる。
転送型に対応するプリミティブは決まっており、
8 ビットの場合は byte、16 ビットの場合は short、
32 ビットの場合は int である。
RFBCanvas の場合、転送型は間接的に、
PixelFormat#getBitPerPixel によって決まる。
後は、RAW 符号化を行うためには、
転送型で表現された配列を、
byte 配列に変換する必要がある。
PixelFormat#getBitPerPixel が 8 ならば、
転送型 = byte なので、そのまま使えるのだが、
16 や 32 であれば、そのエンディアンを考慮して、
byte 配列に格納しなおす必要がある。
そういった変換は、java.nio パッケージにある、
ByteBuffer クラスを使えば簡単に実現できるのである。