0

I have an image (147 KB), and I want to downsize it to under 100KB. The code below attempts to do this, however when the image comes out on the other side, the widht and height are scaled down, but the disk space on the image goes from 147 to 250! It's supposed to get smaller not higher...

Can you please tell me why this code isn't doing this?

Thanks

//Save image
        BufferedImage resizeImagePng = resizeImage(originalImage, type, newLargeImageLocation);

    //Resize and save
    ImageIO.write(resizeImagePng, "png", new File(newSmallImageLocation));



//Create new image
    private static BufferedImage resizeImage(BufferedImage originalImage, int type, String newLargeLocation) throws Exception{

            //Get size of image
            File file =new File(newLargeLocation);

            //File size in KBs
            double bytes = file.length();
            double kiloBytes = bytes/1024;

            double smallWidth = originalImage.getWidth();
            double smallHeight = originalImage.getHeight();

            double downMult = 1;

            //If image is too large downsize to fit the size
            if (kiloBytes>MAX_IMAGE_SIZE_IN_KYLOBITES) {

                downMult = MAX_IMAGE_SIZE_IN_KYLOBITES/kiloBytes;

                smallWidth *= downMult;
                smallHeight *= downMult;
            }

            //Final dimensions
            int finalHeight = (int)smallHeight;
            int finalWidth = (int)smallWidth;

            //Init after
            BufferedImage after = new BufferedImage(finalWidth, finalHeight, BufferedImage.TYPE_INT_ARGB);

            //Scale
            AffineTransform at = new AffineTransform();
            at.scale(downMult, downMult);

            //Scale op
            AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
            after = scaleOp.filter(originalImage, after);

            //Return after
            return after;
        }
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
William Falcon
  • 9,813
  • 14
  • 67
  • 110
  • Can you show the code where you write the image? Maybe you're writing to a format that doesn't compress as well as the original format. – dnault Aug 28 '13 at 19:06
  • 2
    The saved size is largely about the image format and settings used for saving. Are you possibly reading JPG and saving in some other format? – kiheru Aug 28 '13 at 19:07
  • Just added the saving code. The File file is an image with a .png ending on disk – William Falcon Aug 28 '13 at 19:14
  • 1
    The `downMult` should even be more like `downMult = Math.sqrt(MAX_IMAGE_SIZE_IN_KYLOBITES/kiloBytes);` but of course guarantees no fit below MAX_IMAGE_SIZE_IN_KB. – Joop Eggen Aug 28 '13 at 19:17
  • 1
    Try saving without rescaling. – Joop Eggen Aug 28 '13 at 19:20
  • 1
    `png` supports multiple modes as well. Compare http://tinypng.org/ – zapl Aug 28 '13 at 20:29
  • tinypng looks great except i have to do this on 40,000+ images (which is why I wrote my own program) – William Falcon Aug 28 '13 at 20:45
  • @zapl *"png supports multiple modes as well. Compare tinypng.org"* `waf` *"tinypng looks great except i have to do this on 40,000+ images"* Huh. If that had ended with *"only have to do this on 3-5 images I control"* the final sentence would have made sense. But at 40,000+, I'd definitely look to an API! – Andrew Thompson Aug 29 '13 at 04:44
  • 2
    Using `BufferedImage.TYPE_INT_ARGB` will result in a PNG with 24 bit color and 8 bit alpha channel. Unless your image was already in this format, chances are you'll have an increase in file size due to this. Also, artifacts introduced by the resizing could make the PNG compression less effective, actual compression ratios will vary between images. – Harald K Aug 29 '13 at 08:44
  • There [several](http://superuser.com/questions/9251/best-png-compression-software) [tools](http://www.raymond.cc/blog/4-free-tools-to-optimize-and-compress-png-images-without-loosing-quality/) that include advanced algorithms to reduce the size. You could use most of them through `Runtime#exec()`. I doubt that you can achieve the same with ImageIO since the largest improvement is result of reducing the image from 4byte per pixel ARGB to 1byte per pixel indexed colors. For that to look good you need some sort of dithering and a good algorithm to find <= 256 colors that can represent your image. – zapl Aug 29 '13 at 09:41

1 Answers1

1

2 issues, I also have a resizing program but I resize the images a bit different:

First I create a Dimension object (not really needed but designwise it seems a bit better) starting from a BufferedImage object called original

final int width = original.getWidth();
final int height = original.getHeight();
final Dimension d = new Dimension(width, height);

In my case it is not about filesize but about maximum width and/or height, so without getting into details I calculate a new Dimension object based upon the one created above. The new Dimension object is called scaled.

This is how I obtain a new scaled buffered image:

public BufferedImage resizeExact(final BufferedImage original, final Dimension scaled, final Dimension offset) {
    final Image newImage = original.getScaledInstance(scaled.width, scaled.height, Image.SCALE_SMOOTH);
    final BufferedImage bufferedImage = new BufferedImage(newImage.getWidth(null),
                                                          newImage.getHeight(null),
                                                          BufferedImage.TYPE_INT_BGR);
    bufferedImage.createGraphics().drawImage(newImage, offset.width, offset.height, null);
    return bufferedImage;
}

Using this code I obtain a BufferedImage called resizedImage that needs to get written to an OutputStream out, for this I use this code:

ImageIO.write(resized, "jpg", out);
out.close();

And here I am about the 2nd issue: I use the standard ImageIO class to write the BufferedImage as a jpeg file. The issue here is that JPEG encoders typically use a compression factor, the higher the factor the smaller the resulting file but the more quality loss in the resulting file. The code uses a default compression factor of 70%. which suits me fine. However if yoy want to change this, this reference explains how to do this: Setting jpg compression level with ImageIO in Java. Note that here changing it to 100% is essentially a lower compression factor.

Your code snippet doesn't show how eventually you create the jpeg file (I assume you use jpeg as well). If your original image is compressed say with a ratio of 40% (unlikely because then you get a lousy image I assume) so un-jpeged you have 100%, if you wanted to reduce the file size to 80% you reduce the image size to 80%, if you then compress it using 70% compression factor your end result will be aroung 56% which is bigger than the 40%.

Hope this helps. But if you specify how you write the jeg image (maybe using another library than the standard of javax.imageio) there might be another way to specify the compression factor.

Community
  • 1
  • 1
GerritCap
  • 1,606
  • 10
  • 9