image-png icon indicating copy to clipboard operation
image-png copied to clipboard

PNG image is erroneously blank when loaded by `image`

Open Shnatsel opened this issue 2 years ago • 6 comments

This happens in image v0.24.2

Expected

PNG image loaded and saved right back should have the same content (ignoring color space differences)

Actual behaviour

The attached image is completely transparent after being loaded and saved by image: 4f14b7aab3a41855378c5517342598b9

Reproduction steps

use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    use image::io::Reader as ImageReader;
    let input = std::env::args().nth(1).unwrap();
    let output = std::env::args().nth(2).unwrap();
    
    let img = ImageReader::open(input)?.decode()?;
    img.save(output)?;
    Ok(())
}

invoked with image-convert in.png out.png

Shnatsel avatar Jul 03 '22 23:07 Shnatsel

This sample aside, I am astonished how few divergences from other decoders I have found.

The entirety of my imageboard dataset (10,000 images, jpeg/gif/png) and a chunk of the wallhaven dataset (3k images, jpeg) decoded without a single divergence from imagemagick.

You all did an amazing job on this crate :+1:

Shnatsel avatar Jul 03 '22 23:07 Shnatsel

emulsion also displays the image as blank, so I think the saving step can be ruled out. It's the loading step that's the culprit.

Shnatsel avatar Jul 03 '22 23:07 Shnatsel

pngcheck reports an issue with the image:

$ pngcheck in.png 
in.png  invalid tRNS length for palette image
ERROR: in.png

fintelia avatar Jul 04 '22 01:07 fintelia

I suspect what is happening is that when encountering invalid alpha information, we default to alpha=0 while other decoders default to alpha=255.

fintelia avatar Jul 04 '22 01:07 fintelia

The tRNS chunk shall not contain more alpha values than there are palette entries, but a tRNS chunk may contain fewer values than there are palette entries. In this case, the alpha value for all remaining palette entries is assumed to be 255.

It seems that color palettes aren't handled properly in expand_paletted.

HeroicKatora avatar Jul 04 '22 06:07 HeroicKatora

That actually all seems to be handled as best as possible, as far as I can tell. tRNS consists of 174 nul-bytes.

(ChunkType { type: tRNS, critical: false, private: false, reserved: false, safecopy: false }, 174)

However, the palette only holds 173 entries! Hence, the detection of an invalid tRNS by pngcheck. Subsequently the whole chunk is most likely ignored by most other decoders.

HeroicKatora avatar Jul 04 '22 06:07 HeroicKatora