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

mat*_*boy 43 java jpeg image-compression javax.imageio

我正在使用javax.imageio.ImageIO保存BufferedImage为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);
        }
}
Run Code Online (Sandbox Code Playgroud)

同样任何图像处理软件,我希望改变jpeg文件的压缩级别.但是,我正在寻找似乎缺少的这个选项ImageIO.

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

Igo*_*mer 55

更简洁的方法是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();
Run Code Online (Sandbox Code Playgroud)

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

In ImageWriteParam.setCompressionQuality() 1.0f是最高质量,最小压缩,同时0.0f是最低质量,最大压缩.

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

Object除了a之外的通用的使用ImageOutputStream是针对与输出设备或成像协议直接交互的编写者.法律类的集合由作者的服务提供者的getOutputTypes方法公布; 大多数编写器将返回一个单元素数组,仅包含ImageOutputStream.class表示它们只接受一个ImageOutputStream.

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

  • 对于那些不想写入磁盘的人:`ByteArrayOutputStream baos = new ByteArrayOutputStream(); writer.setOutput(new MemoryCacheImageOutputStream(baos)); ... baos.flush(); byte [] returnImage = baos.toByteArray(); baos.close();` (8认同)
  • +1,我想知道为什么手动过滤更复杂的是1.发布,2.接受和3.没有改进这么长时间... (4认同)
  • 让我感到惊讶的是,我回到了同样的问题,我现在无法编辑我的评论.如果你没有按照我之前的说法直接使用`ByteArrayOutputStream`你会得到`java.lang.IllegalArgumentException:非法输出类型! (3认同)

Jea*_*ean 47

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

设置压缩级别如下:

JPEGImageWriteParam jpegParams = new JPEGImageWriteParam(null);
jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
jpegParams.setCompressionQuality(1f);
Run Code Online (Sandbox Code Playgroud)

1f浮点数在哪里代表100%的质量.如果我不记得错误,默认值约为70%.

编辑

然后,您必须按以下步骤获取一个实例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);
Run Code Online (Sandbox Code Playgroud)

更长的路

// 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);
Run Code Online (Sandbox Code Playgroud)

  • `ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next();` (4认同)
  • 不要忘记关闭FileImageOutputStream或处理ImageWriter (4认同)
  • @brad使用`jpegParams.getCompressionQuality()`而不设置它.(你仍然需要先设置`jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT)`.默认情况下,至少对我来说是0.75. (4认同)