image icon indicating copy to clipboard operation
image copied to clipboard

Wrong byte-order when encoding DynamicImage with 16-bit depth

Open demurgos opened this issue 2 years ago • 1 comments

If I create a strongly typed image buffer ImageBuffer<Rgba<u16>, Vec<u16>> with a single pixel with RGBA color [0x57d8, 0x48c9, 0xd555, 0x7eff] (purple), I can encode it into a PNG file img16.png and will have a purple image.

However, if I wrap my buffer inside a DynamicImage and encode it into img_dyn.png, I will get a yellow image.

Expected

Both img16.png and img_dyn.png should be purple images.

Actual behaviour

  • img16.png is a purple image
  • img_dyn.png is a yellow image, more specifically it has RGBA [0xd857, 0xc948, 0x55d5, 0xff7e] (swapped byte order)

Reproduction steps

let img16: ImageBuffer<Rgba<u16>, Vec<u16>> = ImageBuffer::from_raw(1, 1, vec![0x57d8, 0x48c9, 0xd555, 0x7eff]).unwrap();
img16.write_to(&mut std::fs::File::create("img16.png").unwrap(), ImageOutputFormat::Png).unwrap();
let img_dyn = DynamicImage::ImageRgba16(img16);
img_dyn.write_to(&mut std::fs::File::create("img_dyn.png").unwrap(), ImageOutputFormat::Png).unwrap();

Details

This happens on an x86_64 Linux system. This architecture uses a little-endian number representation but PNG expects a big endian ("network order") encoding; maybe it's related (I see some casts).

I am still investigating why the issue happens.

demurgos avatar Jul 05 '22 12:07 demurgos

Okay, I found the issue:

  • When using a typed image buffer, the encoding goes through PngEncoder::write_image which fixes the ordering before calling encode_inner.
  • When using a dynamic image, it goes through the deprecated PngEncoder::encode which does NOT handle byte order before calling encode_inner.

demurgos avatar Jul 05 '22 12:07 demurgos

Shall this be fixed for future major releases? Like replacing PngEncoder::encode with PngEncoder::write_image?

VolkerFelix avatar Oct 29 '22 17:10 VolkerFelix