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

我正在使用javax.imageio.ImageIOBufferedImage保存为jpeg文件。 特别是,我创build了以下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); } } 

同样任何image processing软件,我希望改变jpeg文件的压缩级别。 但是,我正在寻找ImageIO中似乎缺less的这个选项。

我可以设置压缩级别吗?

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

设置压缩级别如下:

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

其中1f是代表100%质量的浮点数。 如果我没有记错,默认值是70%左右

编辑

然后,您必须按照以下步骤获取ImageWriter的实例。 有两种方式,一种是短的,另一种是长的(为了以防万一)。

简短的说法 ( lapo在一个评论中build议)是:

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

更简洁的方法是直接从ImageIO获取ImageWriter

 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 ,但根据文档通常不支持:

使用除ImageOutputStream以外的通用Object适用于直接与输出设备或映像协议交互的作者。 合法类的集合由作者的服务提供者的getOutputTypes方法通告; 大多数编写者将返回一个只包含ImageOutputStream.class的单元素数组,以表明他们只接受一个ImageOutputStream

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

  • FileImageOutputStream – 将输出直接写入FileRandomAccessFileImageOutputStream实现。
  • MemoryCacheImageOutputStream – 将输出写入常规OutputStreamImageOutputStream实现。 通常与ByteArrayOutputStream (感谢提示, @lmiguelmh !)。
Interesting Posts