Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

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

Posted on 2007-04-02
7
Medium Priority
?
1,696 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 92

Accepted Solution

by:
objects earned 1000 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

The top UI technologies you need to be aware of

An important part of the job as a front-end developer is to stay up to date and in contact with new tools, trends and workflows. That’s why you cannot miss this upcoming webinar to explore the latest trends in UI technologies!

Question has a verified solution.

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

Introduction Java can be integrated with native programs using an interface called JNI(Java Native Interface). Native programs are programs which can directly run on the processor. JNI is simply a naming and calling convention so that the JVM (Java…
In this post we will learn how to connect and configure Android Device (Smartphone etc.) with Android Studio. After that we will run a simple Hello World Program.
This video teaches viewers about errors in exception handling.
Viewers will learn how to properly install Eclipse with the necessary JDK, and will take a look at an introductory Java program. Download Eclipse installation zip file: Extract files from zip file: Download and install JDK 8: Open Eclipse and …
Suggested Courses

688 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