三国志大戦の個人的な開発でTwitterにある画像をJavaのプログラム処理でローカルPCへ保存していた。
保存した画像を見てみると、明らかに画質の劣化が見受けられたので色々と調べてみました。
画質劣化はパターンマッチングにおいて致命的になりそうなので、妥協できない点です。
結論から書くと、ImageIOを使用せずにファイルとして取り扱えとなります。
以下、ImageIOを使用してTwitterの画像(mediaUrl)をローカルPCに保存(outputPath)している。
ImageIO.write(ImageIO.read(mediaUrl), "jpg", new File(outputPath));
ブラウザで保存した画像とImageIOを使用して保存した画像をWinMergeで比較してみる。
WinMergeは、いつから画像比較もできるようになったんだ。
WinMergeの進化が止まらない。
差異がある部分が黄色になっている。
やっぱ画質劣化してるやん、詐欺やん。
調べてみると、画像保存時の品質設定がMAXではないらしい。
以下、品質設定MAXで行う処理。
try (FileImageOutputStream output = new FileImageOutputStream(new File(outputPath))) {
BufferedImage readImage = ImageIO.read(mediaUrl);
ImageWriter writeImage = ImageIO.getImageWritersByFormatName("jpeg").next();
ImageWriteParam writeParam = writeImage.getDefaultWriteParam();
writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
writeParam.setCompressionQuality(1.0f);
writeImage.setOutput(output);
writeImage.write(null, new IIOImage(readImage, null, null), writeParam);
writeImage.dispose();
}
その結果。
たいして変わってねぇ。
むしろ差異が増えている?
そもそもJpg画像として保存する事が自体がダメな気がしてきました。
以下、ファイルとして保存する処理。
try (ReadableByteChannel rbc = Channels.newChannel(mediaUrl.openStream());
FileOutputStream fos = new FileOutputStream(outputPath)) {
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
}
その結果。
いけた。
Jpg画像を読み込んでJpg画像を出力すると品質劣化しますね。
Jpg自体、画像を圧縮する技術なので、圧縮処理されたものを、さらに圧縮処理する事になっているのか。
劣化するのは当たり前っちゃ当たり前ですね。
考えればわかりそうな事ですが、パッと思いつかなかったなぁ。
画像といえど、そのまま保存するならファイルとして扱うのがいいですね。
今更ながらの学び、でも大事。