5

I want to compress a jpeg image, that is, decrease its resolution, without resizing it in any way. Is there any good Java library that will help me doing it? There are lots of similar posts in SO, but most of them end up resizing the image as well.

If not, how can I do it programatically? Say, for an argument of 0.9, the image's resolution will decrease by a factor of 0.1...

SexyBeast
  • 7,913
  • 28
  • 108
  • 196

2 Answers2

6

Typically "resolution" means size. Do you mean the JPEG quality instead? That is the only way I can think of to compress it without resizing it.

If so, you can use the Java2D ImageIO API. Something like the following would work (adapted from this page):

BufferedImage bufferedImage = ImageIO.read(...);

ImageWriter writer = (ImageWriter)ImageIO.getImageWritersByFormatName("jpeg").next();
ImageWriteParam iwp = writer.getDefaultWriteParam();
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwp.setCompressionQuality(...);

File file = new File(...);
FileImageOutputStream output = new FileImageOutputStream(file);
writer.setOutput(output);
IIOImage image = new IIOImage(bufferedImage, null, null);
writer.write(null, image, iwp);
writer.dispose();

Unfortunately, I don't think there's a way to get the existing JPEG quality of an image, so you'll have to use some fixed value for the compression quality.

Eric Galluzzo
  • 3,191
  • 1
  • 20
  • 20
  • I am actually concerned with the image size (which roughly translates to its quality). So if the size is say, 30 kB, I want it to change to 25 kB while maintaining the same dimensions.. – SexyBeast Feb 14 '13 at 19:35
  • I don't know of a way to guarantee file size. One approach you could take, if you have a fair bit of processing time per image on your hands, is to use a binary search on quality between 0 and 1 to save each image. When your resulting file size is within a certain threshold of (say) 25kB, you would stop. – Eric Galluzzo Feb 14 '13 at 19:41
  • How about the answer given by iTech? – SexyBeast Feb 14 '13 at 19:42
  • Sure -- his answer is very similar to mine. His code is more robust, though, which is good! However, neither his nor my answer will guarantee you a file of a certain size. – Eric Galluzzo Feb 14 '13 at 19:46
  • I am not exactly looking for a given file size. I have to render images as base64. IE8 doesn't support base64 strings longer than 32k, so I will have to progressively reduce the image quality until its base64 is less than 32K... – SexyBeast Feb 14 '13 at 19:56
1

You can do this by using Java2D API and set the compression quality for the output image, which will reduce the image quality and file size but will maintain the same width and height of the original image

    File imageFile = new File("original.jpg");
    File compressedImageFile = new File("compressed.jpg");

    InputStream is = new FileInputStream(imageFile);
    OutputStream os = new FileOutputStream(compressedImageFile);

    float quality = 0.7f; // Change this as needed

    BufferedImage image = ImageIO.read(is);

    // get all image writers for JPG format
    Iterator<ImageWriter> writers = ImageIO
            .getImageWritersByFormatName("jpg");

    if (!writers.hasNext())
        throw new IllegalStateException("No writers found");

    ImageWriter writer = (ImageWriter) writers.next();
    ImageOutputStream ios = ImageIO.createImageOutputStream(os);
    writer.setOutput(ios);

    // set compression quality
    ImageWriteParam param = writer.getDefaultWriteParam();

    param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
    param.setCompressionQuality(quality);

    writer.write(null, new IIOImage(image, null, null), param);

    // clean resources e.g. close streams

If you want something more advanced, check imageJ and [Fiji][2] they are very powerful image processing libraries in Java with easy to use APIs.

iTech
  • 18,192
  • 4
  • 57
  • 80
  • Thanks iTech. Can you explain what is meant in the comment `// set compression quality`? – SexyBeast Feb 14 '13 at 20:17
  • This code particularly `param.setCompressionQuality(quality);` specify the compression quality of the output `JPEG` that takes a value between `0 and 1` where `0` is worst quality but smaller file size – iTech Feb 14 '13 at 20:26