BufferedImageを画素加工処理付きで高速描画

イメージに明度の変更など加工処理を加えた上で高速転送する方法の備忘録。
まずBufferedImageのgetRaster().getDataBuffer()メソッドを呼び、イメージのラスタデータを取得します。次に、そのラスタ配列要素から順に画素を取り出し、演算を行っていきます。getRGB/setRGBとは比較にならない速さです。

以下は、イメージを50%明るくして描画する例です。コードを見やすくするために演算部分をbrightenメソッドに切り出していますが、ここをインライン化することでさらに高速化できます。

  • この例は、転送元と転送先のBufferedImageが両方ともTYPE_INT_BGRタイプで作成されていることが前提です。
  • クリッピング処理を省略しているので、画像サイズをはみ出す座標を渡すとエラーになります。
public void drawBrightenedImage(
        BufferedImage dest, int dx, int dy, int dw, int dh,
        BufferedImage src, int sx, int sy) {
    DataBufferInt destBuf = (DataBufferInt)dest.getRaster().getDataBuffer();
    DataBufferInt srcBuf = (DataBufferInt)src.getRaster().getDataBuffer();
    int[] destPixels = destBuf.getData();
    int[] srcPixels = srcBuf.getData();

    int dp = dest.getWidth() * dy + dx;
    int sp = src.getWidth() * sy + sx;
    int da = dest.getWidth() - dw;
    int sa = src.getWidth() - dw;

    for(int y = 0; y < dh; y++, dp += da, sp += sa) {
        for(int x = 0; x < dw; x++) {
            destPixels[dp++] = brighten(srcPixels[sp++]);
        }
    }
}

private int brighten(int bgr) {
    // RGB値に分割
    int b1 = (bgr >> 16) & 0xff;
    int g1 = (bgr >> 8) & 0xff;
    int r1 = bgr & 0xff;
    // 演算処理
    int b2 = b1 > 127 ? 255 : b1 + 128;
    int g2 = g1 > 127 ? 255 : g1 + 128;
    int r2 = r1 > 127 ? 255 : r1 + 128;
    // RGB値を再結合
    return b2 << 16 | g2 << 8 | r2;
}