Javaで画像縮小

Javaで画像をリサイズすることになったので、試した結果を纏めてみます。

Javaで画像処理した人なら、ImageMagickを使えるJMagickやOpenCVを使えるJavaCVを使うかなと思います。
今回はサーバ等にインストールしないで使えるLibrary等を使って軽く検証。

画像ファイルの読み込み書き込みは共通の以下のコード

public static BufferedImage readImageFile(File file) {
	return ImageIO.read(file);
}

public static void writeImageFile(BufferedImage image) {
	try {
		ImageIO.write(image, "JPG", new File("hoge.JPG"));
	} catch (IOException e) {
		e.printStackTrace();
	}
}


リサイズ処理は以下の5パターン。

  • BufferedImage#getScaledInstance()
public static BufferedImage reSize1(BufferedImage image, int width, int height) {
	BufferedImage thumb = new BufferedImage(width, height, image.getType());
	thumb.getGraphics().drawImage(image.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING), 0, 0, width, height, null);
	return thumb;
}
  • Graphics2D#drawImage()
public static BufferedImage reSize2(BufferedImage img, int width, int height) {
	BufferedImage thmb = new BufferedImage(width, height, img.getType());
	Graphics2D g2d = thmb.createGraphics();
	g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
	g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
	g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
	g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
	g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
	g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
	g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
	g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
	g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);
	g2d.drawImage(img, 0, 0, width, height, null);
	return thmb;
}
  • java-image-scaling-0.8.5.jar
public static BufferedImage reSize3(BufferedImage img, int width, int height) {
	ResampleOp resampleOp = new ResampleOp(width, height);
	resampleOp.setFilter(ResampleFilters.getLanczos3Filter());
	resampleOp.setUnsharpenMask(AdvancedResizeOp.UnsharpenMask.VerySharp);
	BufferedImage rescaled = resampleOp.filter(img, null);
	return rescaled;
}
  • img-scalr-lib-4.2.jar
public static BufferedImage reSize4(BufferedImage img, int width, int height) {
	BufferedImage thmb = Scalr.resize(img, Scalr.Method.ULTRA_QUALITY, Scalr.Mode.FIT_EXACT, width, height, Scalr.OP_ANTIALIAS);
	return thmb;
}
  • thumbnailator-0.4.6.jar
public static BufferedImage reSize5(BufferedImage img, int width, int height) {
	BufferedImage thmb = null;
	try {
		thmb = Thumbnails.of(img)
				.size(width, height)
				.outputQuality(1.0f) 
				.rotate(90) // 画像のローテートも可能
				.asBufferedImage();
	} catch (IOException e) {
		e.printStackTrace();
	}
	return thmb;
}


上の5パターンで試した結果java-image-scalingが一番綺麗にリサイズされる。
ただjpgとかだとExifのOrientationからrotateしたいなって時に出来ないのが難点。。。


img-scalr-libはjava-image-scalingには劣るけど、大差はないかな。
また別メソッドでrotate出来るので使い勝手は良さそう!

private static BufferedImage rotate1(BufferedImage img) {
	BufferedImage thmb = Scalr.rotate(img, Scalr.Rotation.CW_90, Scalr.OP_ANTIALIAS);
	return thmb;
}

品質もかなり良い感じ。


thumbnailator-0.4.6.jarは上のコードでも書いてる通りリサイズと同時にrotate出来るのでコード自体は少なくて綺麗に書けます。
他にもOrientationが分かれば簡単にrotateしてくれるメソッドも用意されてる!

private static BufferedImage rotate2(BufferedImage img) {
	BufferedImage thmb = ExifFilterUtils.getFilterForOrientation(Orientation.LEFT_BOTTOM).apply(img);
	return thmb;
}

意外とどのLibraryも簡単!!