java.awt.Image を BufferedImage や byte 配列に変換する方法

2007/04/03 12:18pm

Java ImageIO で Flickr 並みのサムネイル画像をつくるという記事で、

java.awt.Image を BufferedImage や byte 配列に変換する方法は次回。

と書いたにも関わらず、そのまま放置になっていた(コメントで指摘されているのに気づいたのも今日だ。すまん)。

概要

まずは java.awt.image.BufferedImagebyte 配列に変換する方法を紹介する。

そのあと、java.awt.Imagejava.awt.image.BufferedImage に変換する方法を紹介するので、このふたつを組み合わせれば、

Image --> BufferedImage --> byte[]

が実現できるわけだ。

BufferedImage を byte[] に変換する

BufferedImage から byte 配列の変換は、javax.imageio.ImageWriter でわりかし素直に実装できる。

BufferedImage image = ...;
ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
ImageWriter writer = ImageIOKit.getImageWritersByFormatName(formatName);
ImageOutputStream stream = ImageIO.createImageOutputStream(bytesOut);

try {
  writer.setOutput(stream);
  writer.write(image);
  stream.flush();
} finally {
  writer.dispose();
  if (stream != null) try { stream.close(); } catch (Throwable t) {;}
}

byte[] bytes = bytesOut.toByteArray();
...

ImageWriteParam も組み合わせれば、圧縮率などの設定ができる。

Image を BufferedImage をに変換する

一筋縄ではいかないのが、Image を BufferedImage をに変換する方法だ。

以下では、image 変数が java.awt.Image のインスタンスであるとして、順を追って説明する。

まず、imageBufferedImage のインスタンスなら、以降は何もする必要がない。

if (image instanceof BufferedImage) {
  ...
}

次に、java.awt.Image のインスタンスは、実際のデータが非同期でロードされているかもしれないので、変換処理を行う前に、java.awt.MediaTracker でロードが完了するまで待機する。

// java.awt.MediaTracker でロードを待機
MediaTracker tracker = new MediaTracker(new Component(){});
tracker.addImage(image, 0);
tracker.waitForAll();

ここからが実際の変換処理になるが、基本的に、

  1. 新規に BufferedImage を生成
  2. 生成した BufferedImageImage のピクセルをコピー

という処理になる。

PixelGrabber pixelGrabber = new PixelGrabber(image, 0, 0, -1, -1, false);
pixelGrabber.grabPixels();
ColorModel cm = pixelGrabber.getColorModel();

final int w = pixelGrabber.getWidth();
final int h = pixelGrabber.getHeight();
WritableRaster raster = cm.createCompatibleWritableRaster(w, h);
BufferedImage renderedImage =
  new BufferedImage(
    cm,
    raster,
    cm.isAlphaPremultiplied(),
    new Hashtable());
renderedImage.getRaster().setDataElements(0, 0, w, h, pixelGrabber.getPixels());

上記のコードでは、元の ColorModel もサポートするために、PixelGrabber を使っている。

あとは、ここで生成した BufferedImagebyte 配列に変換してやればよい。