jpeg-decoder icon indicating copy to clipboard operation
jpeg-decoder copied to clipboard

color looks wrong when CMYK jpg changed to RGB after opened and saved by image-rs

Open wellitecho opened this issue 4 years ago • 3 comments

This happens when I simply used image-rs to open and save a CMYK jpg file

Expected

I expect the CMYK jpg file stays the same(file size, colorspace, etc.) I did not expect a CMYK jpg be changed to RGB jpg automatically. Because this CMYK jpg is used for printing.

Actual behaviour

the original CMYK jpg file is 12.5Mb, in CMYK; after opened and saved by image-rs, the size was changed to 2.2Mb, color spaced was changed to RGB(found out with Photoshop), and the image color looks different than the original file.

Reproduction steps

Download the original CMYK image file from the link below, and simply run:

use image;
/*
Cargo.toml:
[dependencies]
image = "0.23"
*/
fn main() {
    let img = image::open("cmyk_original.jpg").unwrap();
    img.save("cmyk_open_and_saved.jpg").unwrap();
}

Related Resources

original cmyk image file uploaded to mega.io open and saved by image-rs

wellitecho avatar Feb 26 '21 07:02 wellitecho

It seems like this is caused by not using the ICC profile embedded in the image to do the CMYK to RGB conversion.

jrmuizel avatar Feb 26 '21 12:02 jrmuizel

With the risk of being rude(I don't mean to), I just wanna ask is there any update/progress on this issue? Thanks in advance.

wellitecho avatar May 04 '21 13:05 wellitecho

It's not exactly what you're looking for but qcms now supports doing CMYK to RGB conversions. The following produces an sRGB png file that should have more correct colors.

    use jpeg_decoder::Decoder;
    use std::fs::File;
    use std::io::BufReader;

    let file = File::open("cmyk_original.jpg").expect("failed to open file");
    let mut decoder = Decoder::new(BufReader::new(file));
    let pixels = decoder.decode().expect("failed to decode image");
    let metadata = decoder.info().unwrap();
    let profile = decoder.icc_profile().unwrap();
    let profile = qcms::Profile::new_from_slice(&profile).unwrap();
    let srgb = qcms::Profile::new_sRGB();
    let xfm = qcms::Transform::new_to(&profile, &srgb, qcms::DataType::CMYK, qcms::DataType::RGB8, qcms::Intent::Perceptual).unwrap();
    let mut result = vec![0; pixels.len()/4 * 3];
    xfm.convert(&pixels, &mut result);

    // write the result to a PNG
    let mut encoder = png::Encoder::new(std::fs::File::create("out.png").unwrap(), metadata.width as u32, metadata.height as u32);

    encoder.set_color(png::ColorType::Rgb);
    encoder.set_srgb(png::SrgbRenderingIntent::Perceptual);
    let mut writer = encoder.write_header().unwrap();
    writer.write_image_data(&result).unwrap(); // Save

jrmuizel avatar May 10 '21 15:05 jrmuizel