jiichan.com

PROGRAMMING

高画質で画像縮小

高画質で画像を縮小するために、PHPやjavascriptなどでいろいろ作ってみました。
以前javaでも作ってみたがどうにも画質が良くありません。
javaにもいくつかの方法があるようで今回はサイトで見た別の方法を試してみました。 これが今までで一番画質が良かったのでメモっておくことにしました。

主なフィールド

画像は長辺と短辺があるので長い方を基準に縮小するようにしています。


public class ResizeImage extends javax.swing.JFrame {
	private int longerSize; //画像の長辺がこのピクセルになるように拡縮する
	private int resizedW;
	private int resizedH;
 

画像縮小のメイン部

実際のアプリでは複数の画像ファイルを縮小できるように、このメイン部をループさせています。


try{
	BufferedImage originalImage = ImageIO.read(new File(元ファイルパス));

	// 新規画像のサイズ計算
	longerSize = 600;	// 長辺のサイズを600pxに縮小
	sizeCalculate(originalImage, longerSize);

	// 画像サイズ変更
	BufferedImage scaleImg = scaleImage(originalImage, resizedW, resizedH); 
	
	// 縮小後の画像を画質を指定してファイルに出力
	// 文{}の終わりでリソース(imageStream)が確実に閉じられるよう try-with-resources文を使う
	try (ImageOutputStream imageStream = 
					ImageIO.createImageOutputStream(new File(縮小ファイルパス)
	)) {
		// imageStreamの画質に利用される(paramをIIOImageに渡す)
		JPEGImageWriteParam param = new JPEGImageWriteParam(Locale.getDefault());
		param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
		param.setCompressionQuality(1f);	// 画質 0f(低) ~ 1f(高)

		// ファイルに出力
		ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next();
		writer.setOutput(imageStream);
		writer.write(null, new IIOImage(scaleImg, null, null), param);
		imageStream.flush();
		writer.dispose();
	}
}catch(Exception e){
	this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR ));
	System.out.println(e);
}
 

縮小後のサイズを計算するメソッド

長辺を基準として縮小後のサイズを計算します。
上記メイン部の9行目で使用しています。


//縮小後のサイズを計算
private void sizeCalculate(BufferedImage bimg, int longerSize) {
	double percentage;
	//長辺を基準として縦横percentageの縮小倍率を求める
	if(bimg.getWidth() >= bimg.getHeight()){
		percentage = ((double)longerSize / bimg.getWidth());
		// 長辺
		resizedW = longerSize;
		// 短辺
		resizedH = (int)(bimg.getHeight() * percentage);
	}else{
		percentage = ((double)longerSize / bimg.getHeight());
		// 短辺
		resizedW = (int)(bimg.getWidth() * percentage);
		// 長辺
		resizedH = longerSize;
	}}

サイズを変更するメソッド

長辺を基準として縮小後のサイズを計算します。
上記の23行目でIIOImageの引数になっています。


// サイズの変更
private BufferedImage scaleImage(Image img, int dw, int dh) {
	// image のサイズを(dw, dh)に変更する
	BufferedImage resizeImage =
		new BufferedImage(dw, dh, BufferedImage.TYPE_3BYTE_BGR);
		resizeImage.createGraphics().drawImage(
			img.getScaledInstance(dw, dh, Image.SCALE_AREA_AVERAGING),
				 0, 0, dw, dh, null);
	return resizeImage;
}  



画質が良い分ファイルサイズは大きめでした。