image icon indicating copy to clipboard operation
image copied to clipboard

Color changed after decode/encode by image-rs

Open Brooooooklyn opened this issue 3 years ago • 6 comments

Expected

Images are identical

Actual behaviour

The green color of texts were changed after decode/encode by image-rs

Reproduction steps

use std::error;
use std::fs;

use image::load_from_memory;

type Result<T> = std::result::Result<T, Box<dyn error::Error>>;

fn main() -> Result<()> {
    let raw_png = fs::read("hulu.png")?;
    let dynamic_image = load_from_memory(&raw_png)?;
    dynamic_image.save_with_format("hulu-image.png", image::ImageFormat::Png)?;
    Ok(())
}
  • clone https://github.com/Brooooooklyn/image-rs-wrong-color
  • cargo run
Raw Decode/Encode by image-rs

Brooooooklyn avatar Jul 07 '22 14:07 Brooooooklyn

Can you be more precise or recheck? The images in the columns contain literally the same pixel matrix:

$ png2pnm /tmp/hulu.png > /tmp/hulu.pnm
$ png2pnm /tmp/hulu-image.png.png > /tmp/hulu-image.pnm
$ diff /tmp/hulu.pnm /tmp/hulu-image.pnm

197g avatar Jul 07 '22 19:07 197g

Oops, messed up paths, I see it now. Probably color profiles which we definitely are not doing properly through the whole chain.

197g avatar Jul 07 '22 19:07 197g

Wait.. Wait.. The initial observation was correct. Pixels are literally the same value. The difference is simply because we're dropping the color profile chunks.

Original chunks:

ChunkType { type: IHDR, critical: true, private: false, reserved: false, safecopy: false }
ChunkType { type: iCCP, critical: false, private: false, reserved: false, safecopy: false }
ChunkType { type: eXIf, critical: false, private: false, reserved: false, safecopy: true }
ChunkType { type: pHYs, critical: false, private: false, reserved: false, safecopy: true }
ChunkType { type: iTXt, critical: false, private: false, reserved: false, safecopy: true }
ChunkType { type: iDOT, critical: false, private: false, reserved: false, safecopy: false }
ChunkType { type: IDAT, critical: true, private: false, reserved: false, safecopy: false }
[… some more IDAT]

After chunks:

ChunkType { type: IHDR, critical: true, private: false, reserved: false, safecopy: false }
ChunkType { type: IDAT, critical: true, private: false, reserved: false, safecopy: false }
OK: /tmp/hulu-image.png (3008x1904, 8-bit RGB+alpha, non-interlaced, 81.5%)

197g avatar Jul 07 '22 20:07 197g

Any workaround for this issue?

Brooooooklyn avatar Jul 13 '22 09:07 Brooooooklyn

Any progress on fixing this issue?

thep0y avatar Dec 06 '23 10:12 thep0y

There actually has been some progress! We've now got an icc_profile method on the ImageDecoder trait which provides the low level API to query the color profile for an image. The next step would be to expose the ability to set a color profile when saving an image

fintelia avatar Dec 11 '23 08:12 fintelia