PIL: converting an image with mode "I" to "RGB" results in a fully white image - png

The image at the end of this question is a PNG with mode I, which stands for Indexed, as far as I can tell.
I'm trying to create a thumbnail out of it, and save it as JPG with PIL.
However, is I leave the mode alone, PIL won't let me resize it with error unable to generate thumbnail: cannot write mode I as JPEG.
If I convert it to RGB, the result will be a fully white image.
Is there a way to fix this?
https://www.dropbox.com/s/2d1edk2iu4ixk25/NGC281.png

The input image is a 16-bit grayscale PNG, and it appears PIL has a problem with this. Manually converting it to an 8-bit image before further processing makes it work again.
The problem may originate inside PIL itself. The PyPNG homepage asserts
..PIL only has internal representations (PIL mode) for 1-bit and 8-bit channel values. This makes me wonder if PIL can read PNG files with bit depth 2 or 4 (greyscale or palette), and also bit depth 16 (which PNG supports for greyscale and RGB images).
Then again, that page is from 2009. It could be worth tracking down where PIL is maintained from, and report this as a bug (? Or possibly a feature request?).

Related

Load PNG RGBA channels like interleaved JPG RGB channels

Can a PNG file's data be loaded in a certain order, say beginning with one RGBA channel, then the rest?
Perhaps similar to how JPG files can, sometimes using custom codecs, store their data as "scans" or "slices", that are loaded progressively, sequentially or interleaved, at first displaying black and white, followed by red, green, and finally blue.
It seems very unlikely, but can PNG files have a way of behaving like this?
References:
https://cloudinary.com/blog/progressive_jpegs_and_green_martians
Besides standard/progressive, the 3rd kind of JPEG compression: load by channel?
https://graphicdesign.stackexchange.com/a/55570/97317
PNG's equivalent to JPEG's progressive display is interlacing. Rather than interlacing lines, it interlaces pixels using a pattern the PNG standard calls ADAM7.

Does an image loses quality when it is converted from jpg to png?

We all know that converting from jpg to jpg makes an image lose quality, and that the same doesn't happen when it's png to png, but what about jpg to png ?
In my mind it makes sense that it doesn't, but still I'm not sure.
I think that good answer to this question probably would be an article in which there would be a good explanation of why it happens or not. Do you now of any ? I couldn't find such article.
It doesn't, but it's complicated.
Reading of JPEG is not a precisely defined process. Different JPEG decoders are allowed to produce slightly different results from the same file.
Converting JPEG to PNG makes pixels forever represent the particular method that was used to decode the JPEG, even if it wasn't the best one. If you use a "bad" JPEG decoder for the conversion you lose ability to use a "better" JPEG decoder later.
The differences are:
Chroma upsampling. JPEG may store chroma (~color) at lower resolution than luma (~brightness) of the image. The spec doesn't say how the chroma channel should be resized, so some decoders use blocky nearest-neighbor scaling, some use bilinear scaling, some do even weirder things.
Numeric precision. JPEG requires calculations to be done to convert image from DCT and YCbCr representation to RGB. This can be done quickly and cheaply using integer math and 8-bit color, or a tiny bit better using floating-point math and higher-depth color.
Color profiles and CMYK. Conversion may change color space (in case of CMYK it has to convert to RGB), which is easy to get wrong.
There are other reasons to avoid the conversion:
The file will almost certainly become much larger. JPEG compression artifacts are the worst case for PNG.
The file will lose metadata (like camera info, GPS). While in theory PNG could carry the same metadata, in practice converters rarely preserve it.
And a case for conversion: jpeg2png project, which doesn't merely convert the file, but also uses quite advanced post-processing to smooth out JPEG compression distortions. In that case you might salvage a low-quality blocky JPEG and get a smoother image instead.
The process you describe is:
JPEG Stream => JPEG DECODER => BITMAP
=> PNG ENCODER => PNG Stream
There is no change in step #2. Step #1 might have rounding errors inherent in JPEG.

Artifacts appear using imread function from opencv

I use imread function to read one jpeg file and save the rgb image in bmp format. Comparing the two files, I found artifacts appear and use green circle to denote artifacts. The version of OpenCV is 3.0. I compile the libraries by myself with SSE, SSE2 and SSE3 switchd on (default setting). My OS is windows 7 professional. You can use the following image to check.
original jpeg image
saved bmp file
If I read the jpeg file in Matlab, the rgb image is correct. I save rgb image in png format in Matlab, read the png file using opencv and save the loaded image in bmp file. Everything is OK. It seems that there is a problem with jpeg decoder. The jpeg library used is libjpeg.lib.
Due to the size limit, I cut the patch from the second image.
You're always going to get some artifacts in JPEG. You can reduce the appearance of such artifacts by changing the quantization tables used (usually with loss of compression).
JPEG encoders often use a "quality" setting to change the quantization tables.

Transparency with JPEGs

JPEGs are smaller in size than PNGs. So, I thought that if I can make a specific region in a JPEG-file transparent, with some code, maybe I can save some bytes.
So does anyone know how to achieve this with for example PHP or JavaScript?
No. You can't do this. JPGs do not support alpha channels and have no capacity to designate certain colors as transparent either (GIF-style).
There's several issues with this, all of them have to do with that JPEG is a lossy compression format. The JPEG format is optimized for natural images and sharp edges will get blurred. If you intend that a specific pixel should have the value #d67fff there's no guarantee that after color conversion, FDCT, quantization, IDCT and color conversion, the pixel still will have that value. There's also a strong possibility that that pixel value will occur in areas that you don't want.
No. JPEG does not support transparency and is not likely to do so any time
soon. http://www.faqs.org/faqs/jpeg-faq/part1/section-12.html
You cannot do that, the client renders the image and doesn't know that you want it to treat that color as transparent (plus various compression methods on jpeg wouldn't work well with transparencies anyway).
I believe you can go with an 8-bit custom-pallet png, should save you a lot of space. Otherwise 24-bit PNG is your only high color option.
You can convert your image to SVG containing a color information as JPEG and an alpha channel as grayscale mask. Here is a tool I wrote to do it https://github.com/igrmk/transpeg

Best practice for PNG optimization?

I 'd like to prepare my PNGs for the best optimization, so I can get the best image quality (lossless if possible) and the smallest size.
From what I understand, I should use: PNG, 72 dpi, RGB, but what else?
Here is what we find in the iPhone HIG:
Note:*The standard bit depth for icons and images is 24 bits (8 bits each for red, green, and blue), plus an 8-bit alpha channel. The PNG format is recommended, because it preserves color depth and supports an embedded alpha channel.
I guess this mean we should save the image as PNG 24 and create them in 8 bits mode? But I also read about 32 bits for best quality ?
The interlacing scheme (witch add to the file size) allows for the PNGs to display faster. Does this applies to the iPhone?
Thanks.
I suggest using ImageAlpha (lossy) on as many images as you can, because it greatly reduces their size.
Optimize all images with ImageOptim — it will remove all invisible junk and re-compress the data.
Disable Xcode conversion, because it undoes other optimisations and can make images much slower to load.
24 bit is red, green and blue with 8 bits each. 32 bits is RGB plus an 8-bit alpha channel. So if you need (semi-)transparent images, you should go for 32bit PNG, otherwise 24bit.
You don't have to compress/crush the PNGs yourself, Xcode's build steps will automatically use pngcrush and re-order the color channels for the iPhone's BGR memory alignment.
For my background app I am using JPEG (Export for web in photoshop) with quality 70.
Last day I heard about pngcrunch, tried it but file size is the same...
http://pmt.sourceforge.net/pngcrush/
Take a look at this previous post :
Understanding 24 bit PNG generated with Photoshop