Solved

JPEGImageEncoder: Reducing the size of the JPEG without resizing the Image

Posted on 2007-04-02
7
1,639 Views
Last Modified: 2012-06-27
I am using JPEGImageEncoder in order to encode a BufferedImage into a JPEG file.
The problem is that I would like to restrict the files size to a maximum of 200KB, without affecting the height/widht of the image. So I guess that the only option that is left is quality.

The code I am using is something like:

BufferedImage thumbImage = new BufferedImage(
image.getWidth(),
image.getHeight(),
BufferedImage.TYPE_INT_RGB);

Graphics2D graphics2D = thumbImage.createGraphics();
graphics2D.setRenderingHint(
                 RenderingHints.KEY_INTERPOLATION,
                 RenderingHints.VALUE_INTERPOLATION_BILINEAR);
      graphics2D.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);

      imageOut = new FileOutputStream(yetAnOtherFile);
      out = new BufferedOutputStream(imageOut);
      encoder = JPEGCodec.createJPEGEncoder(imageOut);
      enparam = encoder.getDefaultJPEGEncodeParam(thumbImage);
      int quality = 100;
      enparam.setXDensity(100);
      enparam.setYDensity(100);

        enparam.setQuality( (float) quality / 100.0f, false);
        encoder.setJPEGEncodeParam(enparam);
        encoder.encode(thumbImage);


I also tried a do/while loop till the out file gets an accepted size, decreasing the quality in each step. It didn't work as expected. Is there an other solution to the problem ?
0
Comment
Question by:Nellios
  • 4
  • 3
7 Comments
 
LVL 92

Expert Comment

by:objects
ID: 18835109
that approach should work, what problem were u having?
btw, u probably should start quality at 80 max, theres no real value going any higher.
0
 
LVL 92

Expert Comment

by:objects
ID: 18835111
be better off wrting it to a ByteArrayOutputStream rather than a file.
0
 
LVL 10

Author Comment

by:Nellios
ID: 18835117
The problem was that I ended up in an infinite loop. I didn't like the approach anyway so I stoped working on it. If there isn't a better one, then I guess I will work on this one.
0
Live: Real-Time Solutions, Start Here

Receive instant 1:1 support from technology experts, using our real-time conversation and whiteboard interface. Your first 5 minutes are always free.

 
LVL 92

Accepted Solution

by:
objects earned 500 total points
ID: 18835128
can't think of one, the size of the file will depend on the actual contents of the image and how much it can be compressed.

the loop would be something like:

byte[] bytes = null;
int quality = 80;
while (bytes==null && quality>0)
{
   bytes = encode(image, quality);
   if (bytes.length>maxsize)
   {
       bytes = null;
   }
   else
   {
       quality -= 10;
   }
}
0
 
LVL 10

Author Comment

by:Nellios
ID: 18916802
I am accepting objects proposal as a solution to this, since its the only feasible way to solve the problem that I am aware of.

I am not very fond of that solution, neither I applied it to my problem yet. I will provide further feedback in this thread as soon as I do so.
0
 
LVL 10

Author Comment

by:Nellios
ID: 18945579
I promised you feedback didn't I?

So here's exactly what worked for me:

 int size = 1024000;
     for (int quality = 80; size > 921600; quality -= 2) {

        imageOut = new FileOutputStream(new File(tmpdir + "tmpImageName.jpg"));
        out = new BufferedOutputStream(imageOut);
        encoder = JPEGCodec.createJPEGEncoder(imageOut);
        enparam = encoder.getDefaultJPEGEncodeParam(thumbImage);

          enparam.setXDensity(100);
          enparam.setYDensity(100);
          enparam.setQuality( (float) quality / 100.0f, false);
          encoder.setJPEGEncodeParam(enparam);
          encoder.encode(thumbImage);
          out.close();
          imageIn = new FileInputStream(new File(tmpdir + "tmpImageName.jpg"));
          this.in = new BufferedInputStream(imageIn);
          size = in.available();
       }

with this for loop the image quality will gradually decrease till the output file is less than the maximum allowed size.

This is the implementation of my original idea influenced by Objects. Currently I am using temporary files to do so. It would also work with Piped Streams, though it would involve threads and would make things a bit more complicated :-D
0
 
LVL 92

Expert Comment

by:objects
ID: 18945596
you can avoid using a file by writing the image to a ByteArrayOutputStream.
0

Featured Post

Live: Real-Time Solutions, Start Here

Receive instant 1:1 support from technology experts, using our real-time conversation and whiteboard interface. Your first 5 minutes are always free.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Java contains several comparison operators (e.g., <, <=, >, >=, ==, !=) that allow you to compare primitive values. However, these operators cannot be used to compare the contents of objects. Interface Comparable is used to allow objects of a cl…
Introduction This article is the first of three articles that explain why and how the Experts Exchange QA Team does test automation for our web site. This article explains our test automation goals. Then rationale is given for the tools we use to a…
Viewers learn how to read error messages and identify possible mistakes that could cause hours of frustration. Coding is as much about debugging your code as it is about writing it. Define Error Message: Line Numbers: Type of Error: Break Down…
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.

816 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

8 Experts available now in Live!

Get 1:1 Help Now