(I'll explain how to do the following in Clojure as well.)
And the upshot is that this way, it seems you get to preserve the metadata from the original JPEG file — at least it did for me!
You will need these imports:
import java.io.File;
import javax.imageio.*;
import javax.imageio.stream.*;
First, we're going to need the default JPEG ImageReader and ImageWriter:
ImageReader imgRdr = ImageIO.getImageReadersByFormatName("jpg").next();
ImageWriter imgWrtr = ImageIO.getImageWritersByFormatName("jpg").next();
Next we'll need an ImageInputStream, wrapping around the JPEG File you want to convert the compression level of, and an ImageOutputStream, wrapping around the File location you want to save the re-compressed JPEG to:
ImageInputStream imgInStrm = ImageIO.createImageInputStream(inputJpegFile);
ImageOutputStream imgOutStrm = ImageIO.createImageInputStream(outputFile);
I assume you know how to create a File object to supply the parameters inputJpegFile and outputFile.
Now we mate the streams to the reader/writer:
imgRdr.setInput(imgInStrm);
imgWrtr.setOutput(imgOutStrm);
We're going to read in the JPEG file now and store it into the IIOImage container — this will contain the metadata of the original JPEG:
IIOImage iioImg = IIOImage(imgRdr.read(0), null, imgRdr.getImageMetadata(0));
Now here's the part where we select the compression quality. The quality number must be between 0 and 1, where 1 means least-compression/highest-quality and 0 means max-compression/lowest-quality (here I use 0.8):
ImageWriteParam jpgWrtPrm = imgWrtr.getDefaultWriteParam();
jpgWrtPrm.setCompressionMode(JPEGImageWriteParam/MODE_EXPLICIT);
jpgWrtPrm.setCompressionQuality(0.8);
Finally we can write the image out!
imgWrtr.write(null, iioImg, jpgWrtPrm);
Before we go, we have to clean up all the resources used:
imgInStrm.close();
imgOutStrm.close();
imgWrtr.dispose();
imgRdr.dispose();
And that's it! So here's the recap:
import java.io.File;
import javax.imageio.*;
import javax.imageio.stream.*;
File inputJpegFile = ... // your input JPEG file to re-compress at a different quality
File outputFile = ... // where you want the new JPEG file to be written to
// set up reader/writer to wrap around files
ImageReader imgRdr = ImageIO.getImageReadersByFormatName("jpg").next();
ImageWriter imgWrtr = ImageIO.getImageWritersByFormatName("jpg").next();
ImageInputStream imgInStrm = ImageIO.createImageInputStream(inputJpegFile);
ImageOutputStream imgOutStrm = ImageIO.createImageInputStream(outputFile);
imgRdr.setInput(imgInStrm);
imgWrtr.setOutput(imgOutStrm);
// read in JPEG into IIOImage container
IIOImage iioImg = IIOImage(imgRdr.read(0), null, imgRdr.getImageMetadata(0));
// set compression level
ImageWriteParam jpgWrtPrm = imgWrtr.getDefaultWriteParam();
jpgWrtPrm.setCompressionMode(JPEGImageWriteParam/MODE_EXPLICIT);
jpgWrtPrm.setCompressionQuality(0.8);
// write out JPEG
imgWrtr.write(null, iioImg, jpgWrtPrm);
// clean up
imgInStrm.close();
imgOutStrm.close();
imgWrtr.dispose();
imgRdr.dispose();
I should note that the above is untested Java code — I wrote the equivalent of the above in Clojure instead.
Also, I spent so much time looking around the internet for clues as to how to do this, I figure I should dump the links I found useful here too, for my own sake:
- javax.imageio - "The main package of the Java Image I/O API."
- Reading and changing jpeg metadata
- Java and Jpeg Metadata
- What's the best library for manipulating JPEG metadata?
- Write dpi metadata to a jpeg image in Java
- Adjust JPEG image compression quality when saving images in Java
- Compressing a JPEG File
No comments:
Post a Comment