Giter VIP home page Giter VIP logo

rust-lcms2's Introduction

Little CMS wrapper for Rust

Convert and apply color profiles with a safe abstraction layer for the LCMS library. LCMS2 is a mature, fully-featured color management engine. These bindings have been stable for years, and used in production at scale.

See the API reference for the Rust functions, and the LCMS2 documentation in HTML/or the original PDF for more background information about the functions.

use lcms2::*;

fn example() -> Result<(), std::io::Error> {
    let icc_file = include_bytes!("custom_profile.icc"); // You can use Profile::new_file("path"), too
    let custom_profile = Profile::new_icc(icc_file)?;

    let srgb_profile = Profile::new_srgb();

    let t = Transform::new(&custom_profile, PixelFormat::RGB_8, &srgb_profile, PixelFormat::RGB_8, Intent::Perceptual);

    // Pixel struct must have layout compatible with PixelFormat specified in new()
    let source_pixels: &[rgb::RGB<u8>] = …;
    t.transform_pixels(source_pixels, destination_pixels);

    // If input and output pixel formats are the same, you can overwrite them instead of copying
    t.transform_in_place(source_and_dest_pixels);

    Ok(())
}

To apply an ICC profile from a JPEG:

if b"ICC_PROFILE\0" == &app2_marker_data[0..12] {
   let icc = &app2_marker_data[14..]; // Lazy assumption that the profile is smaller than 64KB
   let profile = Profile::new_icc(icc)?;
   let t = Transform::new(&profile, PixelFormat::RGB_8,
       &Profile::new_srgb(), PixelFormat::RGB_8, Intent::Perceptual);
   t.transform_in_place(&mut rgb);
}

There's more in the examples directory.

This crate requires Rust 1.64 or later. It's up to date with LCMS 2.15, and should work with a wide range of versions.

Threads

In LCMS all functions are in 2 flavors: global and *THR() functions. In this crate this is represented by having functions with GlobalContext and ThreadContext. Create profiles, transforms, etc. using *_context() constructors to give them their private context, which makes them sendable between threads (i.e. they're Send).

By default Transform does not implement Sync, because LCMS2 has a thread-unsafe cache in the transform. You can set Flags::NO_CACHE to make it safe (this is checked at compile time).

Upgrading from v5

If you're using a custom RGB type with Transform, implement bytemuck::Pod and Zeroable for it. Make sure you use arrays or #[repr(C)] struct types for pixels. Rust tuples have a technically undefined layout, and can't be used as as a pixel format.

unsafe impl Pod for RGB {}
unsafe impl Zeroable for RGB {}

You don't need to do this if you use the rgb crate.

rust-lcms2's People

Contributors

decathorpe avatar drakulix avatar ezhz avatar fxthomas avatar icmccorm avatar jrmuizel avatar kornelski avatar lilith avatar paolobarbolini avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

rust-lcms2's Issues

Segfault since 6.0 on 32bit

My CI tests have failed with segfault since version 6.0.0.

I found that commit 662598e is still okay and the problem was introduced with 579182f

So sadly with a nice convenient feature that you have implemented based on my suggestion 🙈

The segfault is also triggered with the new &[u8] feature. All tests pass on 64-bit.

Support &mut [u8] for transforms

If I understand the library correctly, only formats of the form [[u8,u8,u8]] etc., are supported for RGB values.

I currently have 27 different memory layouts in my image library with formats like RGBA_16. Internally, all image data are just [u8]. It would be quite a hassle to transmute them all into specific rust types for all 27 memory layouts. Would it be possible to let transform_in_place also support [u8]? It should still be possible to check if the buffer length is aligned with the pixel format.

Please add a license file

Cargo.toml says that the license of the project is MIT, but there is no corresponding license file with the license text. Could you add one, please?

The MIT license is one of the licenses that requires redistributed sources to contain a copy of the license text ("The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.")

For reference, I'm packaging rust-lcms2 for Fedora and one of the requirements is that for licenses that contain a clause like above we need to include the full license text.

[Bug] Build failure on various arches

Hi, I packaged lcms2 for debian. That's when I noticed it fails to build on some arches:
arm(64,el,hf) (aarch64 and arm in rust), ppc(64, el) and s390x.

Log:

   Compiling lcms2 v5.6.0 (/<<PKGBUILDDIR>>)
     Running `CARGO=/usr/bin/cargo CARGO_CRATE_NAME=lcms2 CARGO_MANIFEST_DIR=/<<PKGBUILDDIR>> CARGO_PKG_AUTHORS='Kornel Lesiński <[email protected]>' CARGO_PKG_DESCRIPTION='ICC color profile handling. Rusty wrapper for Little CMS' CARGO_PKG_HOMEPAGE='https://lib.rs/crates/lcms2' CARGO_PKG_LICENSE=MIT CARGO_PKG_LICENSE_FILE='' CARGO_PKG_NAME=lcms2 CARGO_PKG_REPOSITORY='https://github.com/kornelski/rust-lcms2.git' CARGO_PKG_RUST_VERSION='' CARGO_PKG_VERSION=5.6.0 CARGO_PKG_VERSION_MAJOR=5 CARGO_PKG_VERSION_MINOR=6 CARGO_PKG_VERSION_PATCH=0 CARGO_PKG_VERSION_PRE='' CARGO_PRIMARY_PACKAGE=1 LD_LIBRARY_PATH='/<<PKGBUILDDIR>>/target/debug/deps:/usr/lib' rustc --crate-name lcms2 --edition=2021 src/lib.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --crate-type lib --emit=dep-info,metadata,link -C embed-bitcode=no -C debuginfo=2 -C metadata=36d5841e2cf2094e -C extra-filename=-36d5841e2cf2094e --out-dir /<<PKGBUILDDIR>>/target/aarch64-unknown-linux-gnu/debug/deps --target aarch64-unknown-linux-gnu -C incremental=/<<PKGBUILDDIR>>/target/aarch64-unknown-linux-gnu/debug/incremental -L dependency=/<<PKGBUILDDIR>>/target/aarch64-unknown-linux-gnu/debug/deps -L dependency=/<<PKGBUILDDIR>>/target/debug/deps --extern foreign_types=/<<PKGBUILDDIR>>/target/aarch64-unknown-linux-gnu/debug/deps/libforeign_types-7ab08a8936ed771c.rmeta --extern lcms2_sys=/<<PKGBUILDDIR>>/target/aarch64-unknown-linux-gnu/debug/deps/liblcms2_sys-7deb6ee05bdb0abf.rmeta -C debuginfo=2 --cap-lints warn -C linker=aarch64-linux-gnu-gcc -C link-arg=-Wl,-z,relro --remap-path-prefix /<<PKGBUILDDIR>>=/usr/share/cargo/registry/lcms2-5.6.0 --remap-path-prefix /<<PKGBUILDDIR>>/debian/cargo_registry=/usr/share/cargo/registry -L native=/usr/lib/aarch64-linux-gnu`
     Running `CARGO=/usr/bin/cargo CARGO_CRATE_NAME=lcms2 CARGO_MANIFEST_DIR=/<<PKGBUILDDIR>> CARGO_PKG_AUTHORS='Kornel Lesiński <[email protected]>' CARGO_PKG_DESCRIPTION='ICC color profile handling. Rusty wrapper for Little CMS' CARGO_PKG_HOMEPAGE='https://lib.rs/crates/lcms2' CARGO_PKG_LICENSE=MIT CARGO_PKG_LICENSE_FILE='' CARGO_PKG_NAME=lcms2 CARGO_PKG_REPOSITORY='https://github.com/kornelski/rust-lcms2.git' CARGO_PKG_RUST_VERSION='' CARGO_PKG_VERSION=5.6.0 CARGO_PKG_VERSION_MAJOR=5 CARGO_PKG_VERSION_MINOR=6 CARGO_PKG_VERSION_PATCH=0 CARGO_PKG_VERSION_PRE='' CARGO_PRIMARY_PACKAGE=1 LD_LIBRARY_PATH='/<<PKGBUILDDIR>>/target/debug/deps:/usr/lib' rustc --crate-name lcms2 --edition=2021 src/lib.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 --test -C metadata=ceed8e51efa4ba21 -C extra-filename=-ceed8e51efa4ba21 --out-dir /<<PKGBUILDDIR>>/target/aarch64-unknown-linux-gnu/debug/deps --target aarch64-unknown-linux-gnu -C incremental=/<<PKGBUILDDIR>>/target/aarch64-unknown-linux-gnu/debug/incremental -L dependency=/<<PKGBUILDDIR>>/target/aarch64-unknown-linux-gnu/debug/deps -L dependency=/<<PKGBUILDDIR>>/target/debug/deps --extern foreign_types=/<<PKGBUILDDIR>>/target/aarch64-unknown-linux-gnu/debug/deps/libforeign_types-7ab08a8936ed771c.rlib --extern lcms2_sys=/<<PKGBUILDDIR>>/target/aarch64-unknown-linux-gnu/debug/deps/liblcms2_sys-7deb6ee05bdb0abf.rlib -C debuginfo=2 --cap-lints warn -C linker=aarch64-linux-gnu-gcc -C link-arg=-Wl,-z,relro --remap-path-prefix /<<PKGBUILDDIR>>=/usr/share/cargo/registry/lcms2-5.6.0 --remap-path-prefix /<<PKGBUILDDIR>>/debian/cargo_registry=/usr/share/cargo/registry -L native=/usr/lib/aarch64-linux-gnu`
error[E0277]: can't compare `i8` with `u8`
  --> src/locale.rs:91:5
   |
91 |     assert_eq!([0i8; 3], l.language);
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i8 == u8`
   |
   = help: the trait `PartialEq<u8>` is not implemented for `i8`
   = help: the following other types implement trait `PartialEq<Rhs>`:
             f32
             f64
             i128
             i16
             i32
             i64
             i8
             isize
           and 6 others
   = note: required for `[i8; 3]` to implement `PartialEq<[u8; 3]>`
   = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: can't compare `i8` with `u8`
  --> src/locale.rs:92:5
   |
92 |     assert_eq!([0i8; 3], l.country);
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i8 == u8`
   |
   = help: the trait `PartialEq<u8>` is not implemented for `i8`
   = help: the following other types implement trait `PartialEq<Rhs>`:
             f32
             f64
             i128
             i16
             i32
             i64
             i8
             isize
           and 6 others
   = note: required for `[i8; 3]` to implement `PartialEq<[u8; 3]>`
   = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: can't compare `i8` with `u8`
  --> src/locale.rs:95:5
   |
95 |     assert_eq!([0i8; 3], l.language);
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i8 == u8`
   |
   = help: the trait `PartialEq<u8>` is not implemented for `i8`
   = help: the following other types implement trait `PartialEq<Rhs>`:
             f32
             f64
             i128
             i16
             i32
             i64
             i8
             isize
           and 6 others
   = note: required for `[i8; 3]` to implement `PartialEq<[u8; 3]>`
   = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: can't compare `i8` with `u8`
  --> src/locale.rs:96:5
   |
96 |     assert_eq!([0i8; 3], l.country);
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i8 == u8`
   |
   = help: the trait `PartialEq<u8>` is not implemented for `i8`
   = help: the following other types implement trait `PartialEq<Rhs>`:
             f32
             f64
             i128
             i16
             i32
             i64
             i8
             isize
           and 6 others
   = note: required for `[i8; 3]` to implement `PartialEq<[u8; 3]>`
   = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: can't compare `i8` with `u8`
   --> src/locale.rs:100:5
    |
100 |     assert_eq!([0i8; 3], l.country);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i8 == u8`
    |
    = help: the trait `PartialEq<u8>` is not implemented for `i8`
    = help: the following other types implement trait `PartialEq<Rhs>`:
              f32
              f64
              i128
              i16
              i32
              i64
              i8
              isize
            and 6 others
    = note: required for `[i8; 3]` to implement `PartialEq<[u8; 3]>`
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0277`.
error: could not compile `lcms2` due to 5 previous errors

Caused by:
...




Transform doesn't implement Sync

From the lcms mailing lists I thought that Transform and Profile could be used from multiple threads. Is there a reason Transform doesn't implement Sync?

Double-precision `PixelFormat` values report incorrect bytes per channel

PixelFormat::bytes_per_channel incorrectly returns a size of 0 instead of the expected 8 if the pixel format is one of the double-precision pixel format constants (XYZ_DBL, Lab_DBL, GRAY_DBL, RGB_DBL, BGR_DBL, and CMYK_DBL).

This problem occurs in lcms2 version 5.3.0-alpha and 5.2.0. I am running Windows 1809 and compiling with stable Rust MSVC 1.44.0.

Example code:

use lcms2::PixelFormat;

fn main() {
    println!("{}", PixelFormat::XYZ_DBL.bytes_per_channel());
    println!("{}", PixelFormat::Lab_DBL.bytes_per_channel());
    println!("{}", PixelFormat::GRAY_DBL.bytes_per_channel());
    println!("{}", PixelFormat::RGB_DBL.bytes_per_channel());
    println!("{}", PixelFormat::BGR_DBL.bytes_per_channel());
    println!("{}", PixelFormat::CMYK_DBL.bytes_per_channel());
}

I expect the code above to output:

8
8
8
8
8
8

But instead the result is:

0
0
0
0
0
0

MHC2 support

I was unable to find how to write MHC2 tags. It seems that while the tag signature lcms2::TagSignature::MHC2Tag exists, there is no tag type associated with it. If I'm not just doing something wrong and the support isn't there, is it planned?

STATUS_ACCESS_VIOLATION when writing vcgt tag

I tried using this library to create a custom ICC profile with a custom VCGT. I have no clue if I'm using this library correctly, but I managed to produce a very confusing error with the following code:

use std::path::Path;

use lcms2::{Locale, Profile, Tag, ToneCurve, MLU};

fn main() {
    let mut icc = Profile::new_srgb();

    icc.remove_tag(lcms2::TagSignature::ProfileDescriptionTag);

    let mut desc = MLU::new(1);
    desc.set_text("Test ICC", Locale::none());
    icc.write_tag(lcms2::TagSignature::ProfileDescriptionTag, Tag::MLU(&desc));

    let tc = ToneCurve::new(2.0);

    let tc_refs: [&lcms2::ToneCurveRef; 3] = [&tc, &tc, &tc];
    let vcgt_tag = Tag::VcgtCurves(tc_refs);
    icc.write_tag(lcms2::TagSignature::VcgtTag, vcgt_tag);

    println!("saving profile to out.icc...");
    icc.save_profile_to_file(Path::new("out.icc")).expect("error while saving profile");
}

Running the program with lcms2 = 6.0.3 results in: error: process didn't exit successfully: 'target\debug\rs-lcms-test.exe' (exit code: 0xc0000005, STATUS_ACCESS_VIOLATION).

While I have no clue what I'm doing, I feel like the intent is not to crash in a way like this?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.