cmx 0.1.0

Rust Spectral Color Management Library
Documentation
// Creates four small png images, with horizontally stacked blocks,
// each 100 by 100 pixels wide, with repectively a fully satured red, green,
// and blue color with RGB coordinates of [255, 0, 0], [0, 255, 0], and [0, 0, 255].
//
// * The first image, written to "tmp/srgb_test.png" contains no color profile. If no profile is
//   embedded, color management systems will assume the image is in the sRGB color space.
// * The second image, written to "tmp/srgb_profile_test.png" contains an sRGB based display profile, set with
//   relative colorimetric intent.
// * The third contains a Display P3 display profile, also with relative colorimetric intent,
//   and is written to "tmp/display_p3_test.png".
// * The fourth contains an Adobe RGB display profile, also with relative colorimetric intent,
//   and is written to "tmp/display_p3_test.png".
//
// The purpose of these images is to check if an application, rendering the images, interprets the
// color profiles correctly. This is a visual test, and you can view the images in different applications and on
// different screens, and try to make sense of what you see, and the pixel values you read with an
// applications such as Apple's Digital Color Meter.
//
// I have also included a primaries.html file, that uses the same images, and
// displays them in a browser, using the HTML `<img>` tag. Modern browsers
// such as Safari, Firefox, and Chrome, support color managed rendering of images,
// so if you view the primaries.html file in such a browser, you should see
// the correct colors, if your display supports wide gamut rendering.
// If your display is a standard gamut sRGB display, you will see the same colors
// for all three images, as the display cannot show the wider gamut colors of
// the Display P3 image.

use cmx::{profile::DisplayProfile, tag::RenderingIntent};
use image::{codecs::png::PngEncoder, ExtendedColorType, ImageEncoder, Rgb, RgbImage};

pub fn main() -> Result<(), Box<dyn std::error::Error>> {
    let width = 300;
    let height = 100;
    let mut image = RgbImage::new(width, height);
    for (x, _y, pixel) in image.enumerate_pixels_mut() {
        if x < 100 {
            *pixel = Rgb([255, 0, 0]); // Red block
        } else if x < 200 {
            *pixel = Rgb([0, 255, 0]); // Green block
        } else {
            *pixel = Rgb([0, 0, 255]); // Blue block
        }
    }
    // Save the image without a color profile
    image.save("examples/srgb_test.png")?;
    println!("Saved examples/srgb_test.png without color profile");

    // Save the image with an sRGB color profile
    let srgb_profile = DisplayProfile::cmx_srgb(RenderingIntent::RelativeColorimetric);
    let mut srgb_png_data = Vec::new();
    let mut encoder = PngEncoder::new(&mut srgb_png_data);
    encoder.set_icc_profile(srgb_profile.to_bytes()?)?;
    encoder.write_image(image.as_raw(), width, height, ExtendedColorType::Rgb8)?;
    std::fs::write("examples/srgb_profile_test.png", &srgb_png_data)?;
    println!("Saved examples/srgb_profile_test.png with sRGB color profile");

    // Save the image with a Display P3 color profile
    let display_p3_profile = DisplayProfile::cmx_display_p3(RenderingIntent::RelativeColorimetric);
    display_p3_profile
        .clone()
        .write("examples/display_p3.icc")?;
    let mut display_p3_png_data = Vec::new();
    let mut encoder = PngEncoder::new(&mut display_p3_png_data);
    encoder.set_icc_profile(display_p3_profile.to_bytes()?)?;
    encoder.write_image(image.as_raw(), width, height, ExtendedColorType::Rgb8)?;
    std::fs::write("examples/display_p3_test.png", &display_p3_png_data)?;
    println!("Saved examples/display_p3_test.png with Display P3 color profile");

    // Save the image with a Adobe color profile
    let adobe_rgb = DisplayProfile::cmx_adobe_rgb(RenderingIntent::RelativeColorimetric);
    adobe_rgb.clone().write("examples/display_p3.icc")?;
    let mut adobe_rgb_png_data = Vec::new();
    let mut encoder = PngEncoder::new(&mut adobe_rgb_png_data);
    encoder.set_icc_profile(adobe_rgb.to_bytes()?)?;
    encoder.write_image(image.as_raw(), width, height, ExtendedColorType::Rgb8)?;
    std::fs::write("examples/adobe_rgb_test.png", &adobe_rgb_png_data)?;
    println!("Saved examples/adobe_rgb_test.png with Adobe RGB color profile");

    Ok(())
}