在Java中使用ImageIO设置jpg压缩级别
我正在使用javax.imageio.ImageIO
将BufferedImage
保存为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
– 将输出直接写入File
或RandomAccessFile
的ImageOutputStream
实现。 -
MemoryCacheImageOutputStream
– 将输出写入常规OutputStream
的ImageOutputStream
实现。 通常与ByteArrayOutputStream
(感谢提示, @lmiguelmh !)。