Steve on Image Processing

JPEG and PNG – lossy and lossless image compression 7

Posted by Steve Eddins,

I was reviewing enhancement requests recently when I came across this one: Add support for a 'Quality' parameter when using imwrite to write a PNG file, just like you can currently do when writing a JPEG file.

Well, there is actually a pretty good reason why there is no 'Quality' parameter for writing PNG files, but it's not an obvious reason unless you know more about the differences between various image compression methods.

A very important characteristic of a compression method is whether it is lossless or lossy. With a lossless compression method, the original data can be recovered exactly. When you make a "zip" file on your computer, this is what you certainly expect.

Here's an example: I can use gzip to compress the MATLAB script file I'm using for this blog post.

gzip('lossless_lossy.m');
dir('lossless_lossy.*')
lossless_lossy.m     lossless_lossy.m.gz  

Let's compare their sizes to see if the output of gzip is really compressed.

d1 = dir('lossless_lossy.m');
d1.bytes
ans =

        4098

d2 = dir('lossless_lossy.m.gz');
d2.bytes
ans =

        1785

Indeed, the compressed does actually have fewer bytes. Can we get the original file back exactly?

gunzip('lossless_lossy.m.gz','./tmp')
isequal(fileread('lossless_lossy.m'),fileread('./tmp/lossless_lossy.m'))
ans =

     1

Yes.

Let's switch to image formats. The PNG image format uses lossless compression. When you save image data to a PNG file, you can read the file back in and get back the original pixels, unchanged. For a sample image I'll use my imzoneplate function on the MATLAB Central File Exchange.

I = im2uint8(imzoneplate);
imshow(I)

Let's write I out to a PNG file, read it back in, and see if the pixels are the same.

imwrite(I,'zoneplate.png');
I2 = imread('zoneplate.png');
isequal(I,I2)
ans =

     1

OK, now let's try the same experiment using JPEG.

imwrite(I,'zoneplate.jpg')
I2j = imread('zoneplate.jpg');
isequal(I,I2j)
ans =

     0

No, the pixels are not equal! It turns out the JPEG is a lossy image compression format. (Full disclosure: there is a lossless variant of JPEG, but it is rarely used.)

Why in the world would we use a compression format that doesn't preserve the original data? Because by giving up on exact data recovery and by taking advantage of properties of human visual perception, we can make the stored file a lot smaller. Let's compare the file sizes of the PNG file with the JPEG file.

z1 = dir('zoneplate.png');
num_bytes_png = z1.bytes
num_bytes_png =

      218864

z2 = dir('zoneplate.jpg');
num_bytes_jpeg = z2.bytes
num_bytes_jpeg =

       72660

The JPEG file is only one-third the size of the PNG file! But it looks almost exactly the same.

imshow('zoneplate.jpg')

So, what about that 'Quality' parameter that I mentioned at the top of today's post? It turns out that we can make the JPEG file even smaller if we are willing to put up with some visible distortion in the image. Let's try a quality factor of 25. (The default is 75 on a scale of 0 to 100.)

imwrite(I,'zoneplate_25.jpg','Quality',25)
I2j_25 = imread('zoneplate_25.jpg');
imshow(I2j_25)

You can see some distortion, especially around the high-frequency part of the pattern. How about the file size?

z3 = dir('zoneplate_25.jpg');
z3.bytes
ans =

       39544

That's about 54% of the size of the zoneplate.jpg.

Sometimes people think they can get "lossless JPEG" by using a 'Quality' factor of 100, but unfortunately that isn't the case. Let's check it:

imwrite(I,'zoneplate_100.jpg','Quality',100)
I2j_100 = imread('zoneplate_100.jpg');
isequal(I,I2j_100)
ans =

     0

So there you go -- that's why there's no 'Quality' parameter when writing PNG files. PNG files are always perfect!

When I write blog posts, sometimes I use PNG image files and sometimes I use JPEG. My choice is based on what kind of graphics I have in that particular post. And that's a blog topic for another day.


Get the MATLAB code

Published with MATLAB® R2013a

7 CommentsOldest to Newest

Perhaps the original requester was thinking of the time/size compression trade-off for png images? Because the png format is based around general data-compression methods, it is possible to “spend” more computing time to look for smaller encodings of the same image (still lossless, but more efficient).

There are programs like pngcrush that repeatedly try different pre-filters, and spend more time on the DEFLATE step, to try to make smaller files. That kind of option in MATLAB would sometimes be useful – you could choose low compression when saving many temporary images, or highest compression when the image will be published to the web.

For PNG the proper name for such a parameter would not be “quality” but “compression” or something similar. Come to think of it, maybe the JPEG parameter should be called “qualpression” instead!

Is there a method to extract jpeg header, or signature including quantization table and huffman code with matlab?

While PNG in itself is lossless, I believe that it is possible to pre-process the raw input to PNG in such a manner as to reduce the final filesize.

An obvious approach would be to reduce the number of unique colors.

Perhaps this was what the user thought about?

Neo—The imfinfo function returns some metadata information about a JPEG file, but it does not include the quantization table or Huffman code.

These postings are the author's and don't necessarily represent the opinions of MathWorks.