在 Java 中使用 ImageIO 设置 jpg 压缩级别

我正在使用javax.imageio.ImageIO将一个保存为jpeg文件。特别是,我创建了以下Java函数:BufferedImage

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

我可以设置压缩级别以及如何设置?


答案 1

一种更简洁的方法是直接从中获取:ImageWriterImageIO

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();

需要调用 to 才能显式设置压缩的级别(质量)。ImageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT)

In是最高质量,最小压缩,而最低质量,最大压缩。ImageWriteParam.setCompressionQuality()1.0f0.0f

ImageWriter.setOutput应该传递一个 ImageOutputStream。虽然该方法接受 ,但根据文档,它通常不受支持:Object

使用除 非 常规适用于直接与输出设备或映像协议交互的编写器。法律类集由作者的服务提供商的方法公布;大多数编写器将返回一个单元素数组,该数组仅包含以指示它们仅接受 .ObjectImageOutputStreamgetOutputTypesImageOutputStream.classImageOutputStream

大多数情况应由以下两个类处理:


答案 2

您必须使用JPEGImageWriteParam,然后使用ImageWriter.write()保存图像。在写入之前,请通过 ImageWriter.setOutput 设置输出。

按如下方式设置压缩级别:

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

其中是代表100%质量的浮动数字。如果我不记得错误,默认值约为70%1f

编辑

然后,您必须执行以下操作才能获得 .有两种方式,一种是短的,一种是长方法(为了以防万一,我都保留两种方法)。ImageWriter

最短的方法由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);

更长的路程

// 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);

推荐