Compression ratio when writing PNGs with ImageIO

Is it possible to increase the compression ratio for PNG files when using ImageIO?
I can’t find any switch to set the compression level, so …

I’m asking because when I use XnView to save a 32bpp PNG with compression level set to “9” (highest value in Xnview), its PNG file is typically about 20-30% smaller compared to the one of ImageIO.
(The method using ImageIO says “PNG” as name and uses a BufferedImage of type TYPE_INT_ARGB).

Normally I wouldn’t bother, but the PNGs my Java tool writes are going to be used inside my little game… so size matters.

PS: I must be missing something. Because when you write JPEGs with ImageIO how would you specify the compression ratio? :slight_smile:
{This doesn’t mean I want to compare the lossy JPG compression to the lossless PNG compression but the way to say it to ImageIO I mean.}

Normally I wouldn’t bother, but the PNGs my Java tool
writes are going to be used inside my little game… so size matters.

Just use PNGOUT for post processing (like everyone else does). It takes ages but it’s about as small as it can get.

http://advsys.net/ken/utils.htm

(make a batch file and let it run over night) :wink:

[quote]>Normally I wouldn’t bother, but the PNGs my Java tool

writes are going to be used inside my little game… so size matters.

Just use PNGOUT for post processing (like everyone else does). It takes ages but it’s about as small as it can get.
[/quote]
Thanks; for the final step this is probably worth a try, although I think it will take a week for all the PNGs to be re-compressed…

Still I would like to get the PNG size results of the (fast) Xnview with ImageIO. Well, 20%-30% smaller for no extra time. Sounds well.

although I think it will take a week for all the PNGs to be re-compressed…

Uh… you don’t have hundrets of megabytes, do you? It takes 5-30mins for a 800x600 truecolor image on a 500mhz cpu. That should be do-able… and well you can always ask others to donate some cpu power :wink:

Still I would like to get the PNG size results of the (fast)
Xnview with ImageIO. Well, 20%-30% smaller for no extra
time. Sounds well.

Well, you can try irfanview. Press ‘b’ for batchconvert… the compression ratio should be a bit better then (10-20% I gueess) and it’s still very fast (some seconds per image).

[quote]>although I think it will take a week for all the PNGs to be re-compressed…

Uh… you don’t have hundrets of megabytes, do you?
[/quote]
Actually hundrets of megabytes… (It’s for a 2d game in OpenGL.) Output with ImageIO, so Xnview will probably reduce this to 2/3 of the amount.

I performed a few tests and compared the Xnview output with the Pngout one and found Xnview to be very good. As the Pngout’s author writes, you’ve to use the “right” parameters, though.

This is all OK. And thanks Onyx for your help.
The main target of my question has been however how to improve the compression ratio of the Java’s ImageIO class for PNGs within Java. Because it’s the development tool and will be used. It looks like nobody knows an answer to this question so I guess there’s no switch in ImageIO.

Well, anyway, Java rules. Great platform; I love it.

I use this bit of code for JPEGs… the code is generic so it might work for PNGs:


            for (Iterator writers = ImageIO.getImageWritersByFormatName("jpeg"); writers.hasNext(); ) {
                  ImageWriter writer = (ImageWriter) writers.next();
                  ImageWriteParam param = writer.getDefaultWriteParam();
                  IIOImage iio_img = new IIOImage(img, null, null);
                  param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
                  param.setCompressionQuality(0.95f);
                  ImageTypeSpecifier its;
                  writer.setOutput(ios);
                  writer.write(null, iio_img, param);
                  ByteBuffer dest = ByteBuffer.allocate(baos.size());
                  dest.put(baos.toByteArray());
                  dest.flip();
                  return dest;
            }

Might need some hunting through source code to figure out.

Cas :slight_smile:

Actually hundrets of megabytes…

Oh.

Well, I hadn’t found anything you can do on the java side the last time I looked at it (just took another look… if there is something, it’s pretty well hidden).

However, there are still some alternative solutions.

#1 irfanview batch convert.

#2 xnview batch convert… see here

#3 pngcrush - it’s faster than pngout, but usually results in bigger files. Use the -brute switch and let it run over night.

[quote]I use this bit of code for JPEGs… the code is generic so it might work for PNGs:
[/quote]
Thanks Cas for that hint. I think this could point me to what I’m looking for.
So far I don’t understand the code but I’ll dig deeper. :slight_smile:

[quote]>Well, I hadn’t found anything you can do on the java side the last time I looked at it (just took another look… if there is something, it’s pretty well hidden).
[/quote]
Yes if it’s there, it’s hidden - please see Cas’ code snippets for how to set the JPEG compression ratio. I’d never ever come up with such ideas to set the ratio…

[quote]#2 xnview batch convert… see here
[/quote]
Xnview is my favourite and it’s very simple to set up a batch script from within the Xnview GUI.
I’ve run the Pngout for a dozen MB of PNGs and on avarage its about <5% better than Xnview - in some cases it produces larger files. :slight_smile:
So I think Xnview will do the job - in case the ImageIO’s PNG compression ratio can’t be changed that is.

PS: In the Xnview options you’ve to set the compression level of “PNG write” to “9” (max value) in order to get these nice ratios. It’s still lightning fast.

Have a look at the documentation for the javax.imageio.ImageWriteParam class. In particular the getCompressionTypes() and getCompressionQualityDescriptions() methods. That should tell you what control the PNG writer supports.

Thanks for your help.
In addition to the Javadoc I’ve found a Techtip on Javadev: http://java.sun.com/developer/JDCTechTips/2004/tt0217.html
Which explains some bits of what Cas and Mark wrote.

I don’t think there’s something to change the (default) PNG compression, because when I do:

[quote]Iterator it = ImageIO.getImageWritersByFormatName(“PNG”);
ImageWriter writer = (ImageWriter) it.next();
ImageWriteParam iwparam = writer.getDefaultWriteParam();
System.out.println( iwparam.getCompressionType());
-> Exception: Compression not supported.
[/quote]
… an error is being thrown at the last line. (Dito for getCompressionMode, … Quality, etc)

If you install JAI http://java.sun.com/products/java-media/jai/downloads/download-1_1_2.html you will get some additional implementations of the codecs which may support different parameters to those included in J2SE 1.4.2