Solved

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

Posted on 2007-04-02
7
1,609 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
Comment Utility
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
Comment Utility
be better off wrting it to a ByteArrayOutputStream rather than a file.
0
 
LVL 10

Author Comment

by:Nellios
Comment Utility
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
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 92

Accepted Solution

by:
objects earned 500 total points
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
you can avoid using a file by writing the image to a ByteArrayOutputStream.
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Suggested Solutions

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.
Viewers learn about the scanner class in this video and are introduced to receiving user input for their programs. Additionally, objects, conditional statements, and loops are used to help reinforce the concepts. Introduce Scanner class: Importing…
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…

744 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

17 Experts available now in Live!

Get 1:1 Help Now