Memorandums?

This blog is written about technical-discoveries and daily-events.

ImageIO#readのBugSolver(代替方法)

画像送信プログラムを作製中、、

Bug ID: JDK-4821108 IIOException thrown when reading PNG images

このバグ報告が出ていることに暫く気づかず、ずっとImageIOクラスで戦っていました。
しかしながら、Bugにより、ImageIO#readを使用しての画像送信は無理です。

そこで様々な解決策を考えました。
真っ先に思いつくのが、画像をByte配列に変換し、送信し、デコードして復元する。
ByteArrayOutputStreamなどを使用すれば、変換することはできます。
しかし、複雑で送信に時間がかかったため、非採用としました。

もうひとつの方法として、ObjectOutputStreamを使用し、オブジェクトとして送信することです。
Imageオブジェクトを送信しても、読み込み側でImageIOを使用しなくてはいけないため意味がありません。
そこで、BufferedImageオブジェクトをObjectOutputStream#writeObjectに乗せて送信することを思いつきました。
しかし、まだ問題はあります。
それは、ObjectOutputStreamは直列化(serialize)されたオブジェクトしか扱えないということです。
BufferedImageはSerializeされていないため、そのまま送ることは不可能です。
そこで、自作クラスでラップし、そのクラスをSerializeしてみます。

Serializeする独自クラスは以下のようになります。

import java.awt.image.BufferedImage;
import java.io.Serializable;

public class BufferedImageSerializer implements Serializable {

	private static final long serialVersionUID = 1L;
	
	private int width, height;
	private int[] pixels;
	
	/**
	 * 受け取ったBufferedImageクラスのインスタンスの情報を収集します。
	 * @param image 送信したいBufferedImageクラスインスタンス
	 */
	public BufferedImageSerializer(BufferedImage image) {
		width = image.getWidth();
		height = image.getHeight();
		pixels = new int[width * height];
		image.getRGB(0, 0, width, height, pixels, 0, width);
	}
	
	/**
	 * BufferedImageクラスのインスタンスを受け取ります。
	 * 画像受信元にて使用します。
	 * @return 送信されたBufferedImageインスタンス
	 */
	public BufferedImage getImage() {
		BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		image.setRGB(0, 0, width, height, pixels, 0, width);
		return image;
	}
	
}

利用方法はコードを示すまでもなく、
画像を送信する側は、コンストラクタにBufferedImageのインスタンスを指定する。
画像を受信する側は、getImageで取得する。
これでOKです。

サーバークライアントソフトウェアはこの問題を最後についにリリース版となりました!!
これからもバージョンアップを重ねていきます。