Giter Site home page Giter Site logo

tylerreisinger / prisma Goto Github PK

View Code? Open in Web Editor NEW
21.0 5.0 5.0 470 KB

A powerful color representation, manipulation and conversion library that aims to be easy to use.

License: MIT License

Rust 99.70% HTML 0.30%
rust color conversion cie rgb hsv lab xyz hsi prisma conversion-library lch

prisma's Introduction

Prisma - The Rust Color Library

Build Status

Table of Contents:

Overview:

Prisma is a rust library aimed to be a comprehensive set of color representations, manipulations, conversions and algorithms that are easy to use for projects of all levels. Prisma follows a model of "opt-in" complexity, meaning that if you just want a library to convert from Rgb to Hsv and back, prisma will let you do it with minimal knowledge of color science. If you need to access the CIE spaces or do color space conversions however, prisma also provides that functionality with wrappers to use the type system to enforce validity.

Prisma aims to be the go-to source for color conversions and color science in rust. It is currently a work in progress, and any contributions or feature requests are appreciated.

Color Models:

Currently prisma supports the following color models:

Device Dependent:

  • Rgb - The standard color model for displays
  • Rgi - A chromaticity model constructed from Rgb that decouples chromaticity and lightness
  • Hsv - Hue, saturation, value: a more intuitive polar Rgb model
  • Hsl - Hue, saturation, lightness: an alternate to Hsv fulfilling similar roles
  • Hsi - Hue, saturation, intensity: a hue-based model without distortion
  • eHsi - An extension to Hsi that rescaled saturation to avoid going out of gamut in Rgb
  • Hwb - Hue, whiteness, blackness: a hue-based model made to be easy for users to select colors in
  • YCbCr - A representation of the various YUV and YIQ models used in display and broadcast

Device Independent:

  • Xyz - The "parent" absolute color space other color spaces are defined in terms of
  • Lms - A color space simulating human cone response
  • Lab - A uniform perception color space transformation of XYZ
  • Lchab - A polar transformation of Lab. A uniform perception analog of Hsl
  • Luv - An alternative uniform perception color space useful in lighting calculations
  • Lchuv - A polar transformation of Luv

Prisma also supports these color spaces with an alpha channel via the Alpha type.

Why Prisma?

Currently, there are two main color libraries for rust:

  • color -- color is a very old library that hasn't been updated in several years. While it works for conversion through a few color spaces, and is easy to use, it has a very minimal set of features.

  • palette -- palette has significantly more features and can go into a few of the CIE spaces, but requiring all computations to be done in linear encoding is a serious drawback, as if you just want a nice looking gradient in a game, linear Hsv will not get you that. It also is built on predefined models and doesn't support dynamic configuration. prisma supports considerably more color spaces, as well as multiple encodings and spaces which can be built at runtime. prisma also does not require you to specify a color space, as most applications don't really care and use the device color space or sRgb.

Prisma aims to support all the features of the above libraries, while making it up to the user how much complexity they need.

A Tour by Example:

Converting from Rgb to Hsv, manipulating hue, and converting back
#[macro_use] extern crate approx;
extern crate angular_units as angle;
# extern crate prisma;

use prisma::{Rgb, Hsv, FromColor};
use angle::Deg;

let rgb = Rgb::new(0.5, 0.75, 1.0);
let mut hsv = Hsv::from_color(&rgb);
hsv.set_hue(Deg(180.0));
let rgb = Rgb::from_color(&hsv);
assert_relative_eq!(rgb, Rgb::new(0.5, 1.0, 1.0), epsilon=1e-6);
Interpolating between two colors in Hsl.
#[macro_use] extern crate approx;
extern crate angular_units as angle;
# extern crate prisma;

use prisma::{Rgb, Hsl, FromColor, Lerp};
use angle::Deg;

let rgb1 = Rgb::new(0.8, 0.25, 0.0f32);
let rgb2 = Rgb::new(0.5, 0.66, 1.0);
// Specify the hue channel should use degrees
let hsl1: Hsl<_, Deg<f32>> = Hsl::from_color(&rgb1);
let hsl2 = Hsl::from_color(&rgb2);
// Note that hue channels will interpolate in the shortest direction. This is usually
// the expected behavior, but you can always go forward with `lerp_flat`.
let rgb_out = Rgb::from_color(&hsl1.lerp(&hsl2, 0.35));
assert_relative_eq!(rgb_out, Rgb::new(1.0, 0.045, 0.62648), epsilon=1e-4);
Converting from Rgb to Rgb
#[macro_use] extern crate approx;
# extern crate prisma;

use prisma::Rgb;

let rgb_in = Rgb::new(100, 200, 255u8);
let rgb_out: Rgb<f32> = rgb_in.color_cast();
assert_relative_eq!(rgb_out, Rgb::new(0.39216, 0.78431, 1.0), epsilon=1e-4);
Convert from sRgb encoded to linear encoded Rgb
#[macro_use] extern crate approx;
# extern crate prisma;

use prisma::Rgb;
use prisma::encoding::{EncodableColor, TranscodableColor, SrgbEncoding};

// This returns a `EncodedColor<Rgb<f32>, SrgbEncoding>`
// Note: no encodind is done. `srgb_encoded` says that this value is already in sRgb encoding.
let rgb_srgb = Rgb::new(0.5, 1.0, 0.25f32).srgb_encoded();
// Decode goes from an encoding to linear.
let rgb_linear = rgb_srgb.clone().decode();
assert_relative_eq!(rgb_linear, Rgb::new(0.21404, 1.0, 0.05088).linear(), epsilon=1e-4);
// We can then go back with `encode`
let rgb_out = rgb_linear.encode(SrgbEncoding);
assert_relative_eq!(rgb_out, rgb_srgb, epsilon=1e-6);
Going to XYZ
#[macro_use] extern crate approx;
# extern crate prisma;

use prisma::{Rgb, Xyz};
use prisma::encoding::{EncodableColor, TranscodableColor};
use prisma::color_space::{ColorSpace, EncodedColorSpace, NamedColorSpace, ConvertToXyz};
use prisma::color_space::presets::sRgb;

let rgb = Rgb::new(0.25, 0.5, 0.75f32).srgb_encoded();
let color_space = sRgb::get_color_space();
// In this case, since rgb and color_space know their own encodings, the conversion to linear
// is automatic.
let xyz = color_space.convert_to_xyz(&rgb);
assert_relative_eq!(xyz, Xyz::new(0.191803, 0.201605, 0.523050), epsilon=1e-5);

prisma's People

Contributors

tylerreisinger avatar

Stargazers

 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  avatar

prisma's Issues

Inline all the things

Many functions are trivial and should be inlined. Do an inlining pass over the code.

Support f16 "half-precision" using the half crate

Half-precision floating point has 11 bits of precision, which is more than enough for most display-oriented colors. Implementing an optional feature supporting them in prisma could be beneficial to some applications.

Implement CIE UVW

While UVW is technically an obsolete color space, it is still used in the computation of correlated color temperature.

Implement a mean computation for all relevant colors

The mean of Rgb is a very simple process, but the mean of polar colors is a bit more involved, as is the mean of xyY. It would be nice to have a trait to allow means to be computed from an iterator of color values.

Implement a preamble module

Prisma contains many traits. Usability may be improved by re-exporting the most commonly used into a preamble module that can then be glob imported.

Implement chromatic adaptation

Chromatic adaptation allows changing white points and color spaces, which is useful in photography and many other fields

HDR

Right now, the documentation says that RGB components can only be in the 0..1 range. I'm currently doing "Ray Tracing In One Weekend" and I wanted to do HDR with a proper color library, but it doesn't look like Prisma allows that. :/

3 PRs

@tylerreisinger thanks for the prisma crate! I really prefer it compared to the alternatives.

I created three PRs that should be very clean and easy to merge. They don't touch any of the current features so no need to worry about regressions.

Thanks

Implement `lerp_flat` for all colors.

Lerp always takes the shortest path on angular channels. Sometimes, it might be desirable to take the other path, and so there should be a method to support that. Non-angular channels will behave identically for both lerp methods.

Re-export dependencies such as angular-units

Angular-units is a dependency of the crate, but since prisma doesn't re-export it, users need to add angular-units to their own dependencies in order to use things like prisma::Hsv.
I think it'd help usability to add a re-export.

"entered unreachable code" panic on converting HSL color to RGB with hue outside range 0โ€ฆ360

Running with Rust 1.77.2 on Windows 10, I ran this code :

let color = [r, g, b];
let color = prisma::Rgb::new(color[0], color[1], color[2]);
let mut color = prisma::Hsv::<f32,angular_units::Deg<_>>::from_color(&color);
color.set_hue( color.hue() + angular_units::Deg(90.0) );
let color = prisma::Rgb::from_color(&color);
let color = [color.red(), color.green(), color.blue()];

In other words, I created a color from existing r,g,b values and then attempted to rotate its hue 90 degrees.

On the line let color = prisma::Rgb::from_color(&color); I got:

thread 'main' panicked at C:\Users\Andi\.cargo\registry\src\index.crates.io-6f17d22bba15001f\prisma-0.1.1\src\hsv.rs:29
1:18:
internal error: entered unreachable code
stack backtrace:
   0: std::panicking::begin_panic_handler
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library\std\src\panicking.rs:647
   1: core::panicking::panic_fmt
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library\core\src\panicking.rs:72
   2: core::panicking::panic
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library\core\src\panicking.rs:144
   3: prisma::hsv::impl$15::from_color<f32,angular_units::Deg<f32> >
   3: prisma::hsv::impl$15::from_color<f32,angular_units::Deg<f32> >
             at C:\Users\Andi\.cargo\registry\src\index.crates.io-6f17d22bba15001f\prisma-0.1.1\src\hsv.rs:291         3: prisma::hsv::impl$15::from_color<f32,angular_units::Deg<f32> >
             at C:\Users\Andi\.cargo\registry\src\index.crates.io-6f17d22bba15001f\prisma-0.1.1\src\hsv.rs:291         3: prisma::hsv::impl$15::from_color<f32,angular_units::Deg<f32> >
             at C:\Users\Andi\.cargo\registry\src\index.crates.io-6f17d22bba15001f\prisma-0.1.1\src\hsv.rs:291       3: prisma::hsv::impl$15::from_color<f32,angular_units::Deg<f32> >
             at C:\Users\Andi\.cargo\registry\src\index.crates.io-6f17d22bba15001f\prisma-0.1.1\src\hsv.rs:291       3: prisma::hsv::impl$15::from_color<f32,angular_units::Deg<f32> >
             at C:\Users\Andi\.cargo\registry\src\index.crates.io-6f17d22bba15001f\prisma-0.1.1\src\hsv.rs:291     3: prisma::hsv::impl$15::from_color<f32,angular_units::Deg<f32> >
             at C:\Users\Andi\.cargo\registry\src\index.crates.io-6f17d22bba15001f\prisma-0.1.1\src\hsv.rs:291     3: prisma::hsv::impl$15::from_color<f32,angular_units::Deg<f32> >
             at C:\Users\Andi\.cargo\registry\src\index.crates.io-6f17d22bba15001f\prisma-0.1.1\src\hsv.rs:291    3: prisma::hsv::impl$15::from_color<f32,angular_units::Deg<f32> >
             at C:\Users\Andi\.cargo\registry\src\index.crates.io-6f17d22bba15001f\prisma-0.1.1\src\hsv.rs:291 
   4: video::main
             at .\src\main.rs:188
   5: core::ops::function::FnOnce::call_once<void (*)(),tuple$<> >
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04\library\core\src\ops\function.rs:250
   6: core::hint::black_box
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04\library\core\src\hint.rs:334
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

However, if I change the rotation line to:

color.set_hue( ( color.hue() + angular_units::Deg(90.0) ) % angular_units::Deg(360.0) )

It runs without problems.

Expected behavior

  • It would be reasonable to expect that "450 degrees" is a valid hue, since mathematically that would be equal to 90 degrees.
  • If I have actually specified an impossible color, I would expect the failure on conversion to come in the form of a recoverable error (such as a Result) rather than a panic. (I do not know whether TryInto provides this with Prisma.)
  • If panic on converting is intentionally the interface, I would expect a clearer error message.

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.