我正在使用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);
}
}
同样任何图像处理软件,我希望改变jpeg文件的压缩级别。但是,我正在搜索ImageIO
中似乎缺少的此选项。
我可以设置压缩级别以及如何设置?
答案 0 :(得分:54)
更简洁的方法是直接从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.class
的单元素数组,以指示它们仅接受ImageOutputStream
。
大多数情况应由这两个类处理:
FileImageOutputStream
- ImageOutputStream
的实施,将其输出直接写入File
或RandomAccessFile
。MemoryCacheImageOutputStream
- ImageOutputStream
的实现,将其输出写入常规OutputStream
。通常与ByteArrayOutputStream
一起使用(感谢提示,@lmiguelmh!)。答案 1 :(得分:42)
您必须使用JPEGImageWriteParam
,然后使用ImageWriter.write()
保存图像。在编写之前,请通过ImageWriter.setOutput
设置输出。
按如下方式设置压缩级别:
JPEGImageWriteParam jpegParams = new JPEGImageWriteParam(null);
jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
jpegParams.setCompressionQuality(1f);
其中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);
或更长的方式
// 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);
答案 2 :(得分:0)
更通用的方法是(来自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();
}
答案 3 :(得分:0)
在我的古代图书馆中发现了相同的方法:
/**
* Work method.
* Reads the jpeg image in rendImage, compresses the image, and writes it back out to outfile.
* JPEGQuality ranges between 0.0F and 1.0F, 0-lowest, 1-highest. ios is closed internally
*
* @param rendImage [@link RenderedImage} instance with an Rendered Image
* @param ios {@link ImageOutputStream} instance,
* note that it is disposed in this method
* @param JPEGQuality float value for the JPEG compression quality (0..1(max))
* @return {@code true} if image was successfully compressed
* else {@code false} on any error, e.g. bad (null) parameters
*/
public static boolean compressJpegFile( RenderedImage rendImage, ImageOutputStream ios, float JPEGQuality )
{
if ( rendImage == null )
return false;
if ( ios == null )
return false;
if ( ( JPEGQuality <= 0.0F ) || ( JPEGQuality > 1.0F ) )
return false;
ImageWriter writer = null;
try
{
// Find a jpeg writer
Iterator iter = ImageIO.getImageWritersByFormatName( "jpg" );
if ( iter.hasNext() )
writer = (ImageWriter) iter.next();
if ( writer == null )
throw new IllegalArgumentException( "jpg writer not found by call to ImageIO.getImageWritersByFormatName( \"jpg\" )" );
writer.setOutput( ios );
// Set the compression quality
ImageWriteParam iwparam = new MyImageWriteParam();
iwparam.setCompressionMode( ImageWriteParam.MODE_EXPLICIT );
iwparam.setCompressionQuality( JPEGQuality );
// float res = iwparam.getCompressionQuality();
// Write the image
writer.write( null, new IIOImage( rendImage, null, null ), iwparam );
return true;
}
catch ( Exception e )
{
return false;
}
finally
{
if ( writer != null )
writer.dispose();
// Cleanup
try
{
ios.flush();
ios.close();
}
catch ( IOException e )
{
}
}
}
答案 4 :(得分:0)
如果您需要字节[]输出,请参见下面的@ user_3pij答案的修改版本:
private static byte[] compressImageToByteArray(BufferedImage image, 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);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageOutputStream ios = ImageIO.createImageOutputStream(bos);
jpgWriter.setOutput(ios);
IIOImage outputImage = new IIOImage(image, null, null);
jpgWriter.write(null, outputImage, jpgWriteParam);
byte[] result = bos.toByteArray();
jpgWriter.dispose();
return result;
}