Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting jpg compression level with ImageIO in Java

I'm using javax.imageio.ImageIO to save a BufferedImage as a jpeg file. In particular, I created the following Java function:

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

Likewise any image manipulation software, I wish to change the compression level of the jpeg file. However, I'm searching for this option that seems to be missing in ImageIO.

Can I set the compression level and how?

like image 832
mat_boy Avatar asked Jun 14 '13 12:06

mat_boy


People also ask

Can ImageIO read JPG?

imageio package. Image I/O has built-in support for GIF, PNG, JPEG, BMP, and WBMP. Image I/O is also extensible so that developers or administrators can "plug-in" support for additional formats. For example, plug-ins for TIFF and JPEG 2000 are separately available.

What is ImageIO in Java?

ImageIO. A class containing static convenience methods for locating ImageReader s and ImageWriter s, and performing simple encoding and decoding. ImageReader. An abstract superclass for parsing and decoding of images.

What does ImageIO write do?

The ImageIO. write method calls the code that implements PNG writing a “PNG writer plug-in”. The term plug-in is used since Image I/O is extensible and can support a wide range of formats.


2 Answers

A more succinct way is to get the ImageWriter directly from 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(); 

The call to ImageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT) is needed in order to explicitly set the compression's level (quality).

In ImageWriteParam.setCompressionQuality() 1.0f is maximum quality, minimum compression, while 0.0f is minimum quality, maximum compression.

ImageWriter.setOutput should be passed an ImageOutputStream. While the method accepts Object, according to documentation it's usually not supported:

Use of a general Object other than an ImageOutputStream is intended for writers that interact directly with an output device or imaging protocol. The set of legal classes is advertised by the writer's service provider's getOutputTypes method; most writers will return a single-element array containing only ImageOutputStream.class to indicate that they accept only an ImageOutputStream.

Most cases should be handled by these two classes:

  • FileImageOutputStream - an implementation of ImageOutputStream that writes its output directly to a File or RandomAccessFile.
  • MemoryCacheImageOutputStream - an implementation of ImageOutputStream that writes its output to a regular OutputStream. Usually used with ByteArrayOutputStream (thanks for the tip, @lmiguelmh!).
like image 121
Igor Klimer Avatar answered Sep 20 '22 19:09

Igor Klimer


You have to use JPEGImageWriteParam and then save the image with ImageWriter.write(). Before to write, set the output via ImageWriter.setOutput.

Set the compression level as follows:

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

Where 1f is a float number that stands for 100% quality. Default value is around 70% if I don't remember wrong.

EDIT

Then, you have to do as follows to get an instance of an ImageWriter. There are two ways, a short and a long one (I keep both, just in case).

The short way (suggested by lapo in one comment) is:

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

or longer way

// 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); 
like image 39
JeanValjean Avatar answered Sep 21 '22 19:09

JeanValjean