web-dev-qa-db-ja.com

JavaでImageIOを使用してjpg圧縮レベルを設定する

私は javax.imageio.ImageIOBufferedImageをjpegファイルとして保存します。特に、次のJava関数を作成しました:

public static void getScreenShot(BufferedImage capture, Path folder, String filename) {
        try {
            ImageIO.write(capture, "jpeg", new File(folder.toString()+"/"+filename+".jpg"));
        } catch (AWTException | IOException ex) {
            Logger.getLogger(ScreenShotMaker.class.getName()).log(Level.SEVERE, null, ex);
        }
}

同様に、あらゆる画像操作ソフトウェアで、jpegファイルの圧縮レベルを変更したいと思います。ただし、ImageIOにないように見えるこのオプションを探しています。

圧縮レベルとその方法を設定できますか?

42
mat_boy

JPEGImageWriteParam を使用してから、 ImageWriter.write() で画像を保存する必要があります。書き込む前に、 ImageWriter.setOutput を介して出力を設定します。

圧縮レベルを次のように設定します。

JPEGImageWriteParam jpegParams = new JPEGImageWriteParam(null);
jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
jpegParams.setCompressionQuality(1f);

ここで、1fは、100%の品質を表す浮動小数点数です。間違ったことを覚えていない場合、デフォルト値はaround 70%です。

[〜#〜] edit [〜#〜]

その後、次のようにしてImageWriterのインスタンスを取得する必要があります。短い方法と長い方法の2つの方法があります(念のため、両方とも保持します)。

short way(1つのコメントで lapo で提案):

final ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next();
// specifies where the jpg image has to be written
writer.setOutput(new FileImageOutputStream(
  new File(folder.toString() + "/" + filename + ".jpg")));

// writes the file with given compression level 
// from your JPEGImageWriteParam instance
writer.write(null, new IIOImage(capture, null, null), jpegParams);

またはlonger way

// use IIORegistry to get the available services
IIORegistry registry = IIORegistry.getDefaultInstance();
// return an iterator for the available ImageWriterSpi for jpeg images
Iterator<ImageWriterSpi> services = registry.getServiceProviders(ImageWriterSpi.class,
                                                 new ServiceRegistry.Filter() {   
        @Override
        public boolean filter(Object provider) {
            if (!(provider instanceof ImageWriterSpi)) return false;

            ImageWriterSpi writerSPI = (ImageWriterSpi) provider;
            String[] formatNames = writerSPI.getFormatNames();
            for (int i = 0; i < formatNames.length; i++) {
                if (formatNames[i].equalsIgnoreCase("JPEG")) {
                    return true;
                }
            }

            return false;
        }
    },
   true);
//...assuming that servies.hasNext() == true, I get the first available service.
ImageWriterSpi writerSpi = services.next();
ImageWriter writer = writerSpi.createWriterInstance();

// specifies where the jpg image has to be written
writer.setOutput(new FileImageOutputStream(
  new File(folder.toString() + "/" + filename + ".jpg")));

// writes the file with given compression level 
// from your JPEGImageWriteParam instance
writer.write(null, new IIOImage(capture, null, null), jpegParams);
46
JeanValjean

より簡潔な方法は、ImageWriterからImageIOを直接取得することです。

_ImageWriter jpgWriter = ImageIO.getImageWritersByFormatName("jpg").next();
ImageWriteParam jpgWriteParam = jpgWriter.getDefaultWriteParam();
jpgWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
jpgWriteParam.setCompressionQuality(0.7f);

ImageOutputStream outputStream = createOutputStream(); // For example implementations see below
jpgWriter.setOutput(outputStream);
IIOImage outputImage = new IIOImage(image, null, null);
jpgWriter.write(null, outputImage, jpgWriteParam);
jpgWriter.dispose();
_

ImageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT)の呼び出しは、圧縮のレベル(品質)を明示的に設定するために必要です。

ImageWriteParam.setCompressionQuality()で_1.0f_は最大品質、最小圧縮であり、_0.0f_は最小品質、最大圧縮です。

_ImageWriter.setOutput_には ImageOutputStream を渡す必要があります。メソッドはObjectを受け入れますが、ドキュメントによると、通常サポートされていません:

Object以外の一般的なImageOutputStreamの使用は、出力デバイスまたはイメージングプロトコルと直接対話するライター向けです。正当なクラスのセットは、ライターのサービスプロバイダーのgetOutputTypesメソッドによって通知されます。ほとんどのライターは、ImageOutputStreamのみを受け入れることを示す_ImageOutputStream.class_のみを含む単一要素配列を返します。

ほとんどの場合、次の2つのクラスで処理する必要があります。

  • FileImageOutputStream -ImageOutputStreamまたはFileに出力を直接書き込むRandomAccessFileの実装。
  • MemoryCacheImageOutputStream -出力を通常のImageOutputStreamに書き込むOutputStreamの実装。通常、ByteArrayOutputStreamとともに使用します(ヒントをありがとう、 @ lmiguelmh !)。
55
Igor Klimer

より一般的な方法は(from Igor's answer )です:

static void saveImage(BufferedImage image,File jpegFiletoSave,float quality) throws IOException{
    // save jpeg image with specific quality. "1f" corresponds to 100% , "0.7f" corresponds to 70%

        ImageWriter jpgWriter = ImageIO.getImageWritersByFormatName("jpg").next();
        ImageWriteParam jpgWriteParam = jpgWriter.getDefaultWriteParam();
        jpgWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
        jpgWriteParam.setCompressionQuality(quality);

        jpgWriter.setOutput(ImageIO.createImageOutputStream(jpegFiletoSave));
        IIOImage outputImage = new IIOImage(image, null, null);
        jpgWriter.write(null, outputImage, jpgWriteParam);
        jpgWriter.dispose();

    }
0
Naeem