pbrubaker / Nanocolor

Nanocolor, a lightweight color transformation library

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Nanocolor

A very small color transform library

Pixar Animation Studios

Introduction

Color management and transformation is a complex domain. Values are captured by cameras or generated by renderers, transferred to a storage medium, combined into frame buffers to make new images, transformed for display, and projected by devices. During each step, the color values may be transformed by photochemical, electro-optical, and digital processes.

A renderer's input working space to output working space is an interesting subset of that domain, and it's the subset that Nanocolor concerns itself with.

OpenEXR goes so far as to restrict itself to linear working spaces, and describes them completed by specifying chromaticities and an adapted whitepoint in the CIEXYZ 1931 space. Nanocolor takes inspiration from this, and uses the equations in SMPTE document RP177-1993 (reaffirmed in 2002) ~ SMPTE Recommended Practice: Derivation of Basic Television Equations.

Interesting colors do not just come from OpenEXR however, but may originate as properties in a MaterialX shade graph, vertex attributes in an OpenUSD file, or PNG or TIFF textures, to name a few common sources.

Amongst all these sources, only OpenEXR specifies colors in terms of chromaticities and whitepoint. Some sources specify the color space in documentation, whereas others name color spaces in the data itself, or refer to site specific configuration files in the OpenColorIO format, and other alternatives. This lack of broad agreement on such things as what the name of a colorspace actually refers to makes accurate and reproducible color calculations between software packages and studios challenging.

MaterialX takes an interesting perspective; it names a bakers' dozen of color spaces and defines them as OpenEXR does, and also introduces a notion of being able to remove an input transform from a color in order to accomodate image formats commonly used as texture sources for shader graphs.

Nanocolor follows this idea, and also introduces that all the color spaces must be invertible, in the sense that a value can have its input transform removed to make it a linear color value, linear values may be transformed as desired through matrix multiplication, and an output transform may be re-applied. This allows Nanocolor to transform any color space with this invertible property to any other with the invertible property.


Definitions

Nomenclature shall be as per ISO 22028-1 terminology, and will occassionally spell colour with a u per common usage.

Colour space

A geometric representation of colors in a metrical space.

Colorimetric colour space

A colour space having an exact and simple relationship to CIE colorimetric values.

Adopted white

A “spectral radiance distribution” that converts to perfectly achromatic colour signals that have a value of unity “(i.e. colour signals that are considered to correspond to a perfect white diffuser)”

Additive RGB colour space

colorimetric colour space with three primary chromaticities, adopted white chromaticity, transfer function

Colour space encoding

“digital encoding of a colour space, including ... digital encoding method, and ... value range”

Colour image encoding

Colour space encoding plus context, including image state, intended viewing environment, and for print, reference medium


Scope

Colour space encoding is in scope.

Colour image encoding is out of scope.

Camera vendor specific colour spaces are out of scope.

Colour spaces relative to a particular encoded white (cf. LAB, LUV, etc but also IPT and other spaces optimized for gamut mapping) are out of scope.

Hybrid Log Gamma encoding is to be discussed as to whether it is in or out of scope.


Nanocolor API

For a description of data types, please refer to Nanocolor.h

NcColorSpace     NcGetNamedColorSpace(const char* name);
NcM33f           NcGetRGBToCIEXYZMatrix(NcColorSpace* cs);
NcM33f           NcGetCIEXYZToRGBMatrix(NcColorSpace* cs);
NcM33f           NcGetRGBToRGBTransform(NcColorSpace* src, NcColorSpace* dst);
NcRGB            NcTransformColor(NcColorSpace* dst, NcColorSpace* src, NcRGB rgb);
NcCIEXYZ         NcRGBToXYZ(NcColorSpace* cs, NcRGB rgb);
NcRGB            NcXYZToRGB(NcColorSpace* cs, NcCIEXYZ xyz);
void             NcInitColorSpace(NcColorSpace* cs);
const char**     NcRegisteredColorSpaceNames();

NcGetNamedColorSpace ~ returns a named color space, if it is known by Nanocolor

NcGetRGBToCIEXYZMatrix ~ given a color space compute the corresponding RP177-1993 3x3 matrix

NcGetCIEXYZToRGBMatrix ~ given a color space compute the corresponding RP177-1993 3x3 matrix

NcGetRGBToRGBTransform ~ given two color spaces, compute a color transform that moves a color from the source color space to a destination

NcTransformColor ~ a convience function, that given a color and two color spaces, transforms the color and returns it. Note that if many values must be transformed it's far more efficient to reuse a color transform object.

NcRGBToXYZ ~ return the CIEXYZ coordinates for an RGB color

NcXYZToRGB ~ return an RGB color given CIEXYZ coordinates

NcInitColorSpace ~ create an identity color space which can be further modified to create a color space object compatible with the other functions

NanocolorUtils API

NanocolorUtils.h declares a number of useful functions such as might be used by test programs and the like. It is an optional component, and you may choose to omit it from your project.

NcCIEXYZ NcKelvinToXYZ(float temperature, float luminosity);
NcRGB*   NcISO17321_AP0_ColorChips();
NCAPI    NcCIEXYZ* NcISO17321_ColorChips_xyY(void);
NCAPI    const char** NcISO17321_ColorChips_Names(void);
NcCIEXYZ NcProjectToChromaticities(NcCIEXYZ c);
NcCIEXYZ NcNormalizeXYZ(NcCIEXYZ c);
NcRGB    NcRGBFromYxy(NcColorSpace* cs, NcCIEXYZ c);
NcCIEXYZ NcCIE1931ColorFromWavelength(float lambda, bool approx);
NCAPI const char* NcMatchLinearColorSpace(NcCIEXYZ redPrimary, 
                                          NcCIEXYZ greenPrimary,
                                          NcCIEXYZ bluePrimary,
                                          NcXYChromaticity  whitePoint, 
                                          float epsilon);

NcKelvinToXYZ ~ returns an XYZ coordinate for the blackbody emission spectrum for values between 1667 and 25000K

NcISO17321_AP0_ColorChips ~ return a pointer to 24 color values in the ap0 gamut corresponding to the 24 color chips in ISO standard chart 17321

NcISO17321_AP0_ColorChips ~ common names for those chips

NcISO17321_ColorChips_xyY ~ the same but as xyY values

NcISO17321_ColorChips_SRGB ~ an alternative set of values commonly in use despite not strictly matching the specification

NcProjectToChromaticities ~ given a CIEXYZ 1931 color coordinate, project it to the regularized chromaticity coordinate

NcNormalizeXYZ ~ given a CIEXYZ 1931 color coordinate, normalize it to a unit luminance

NcRGBFromYxy ~ given a CIEXY coordinate, and a luminace, compute an RGB value for the given color space

NcCIE1931ColorFromWavelength ~ compute a CIEXYZ coordinate for a given wavelength. If plotted, the values will land on the boundary of the familiar color gamut diagram.

NcMatchLinearColorSpace ~ given primaries and whitepoint, return a corresponding nanocolor named colorspace if one matches.

Building

The interface types are expected to be stable, and to be compatible between all versions of Nanocolor. If the types need to be revised, new ones will be introduced with a new name. The functions however may change, and may be locally modified, and it's expected that more than one copy of Nanocolor may be linked. Therefore, they are namespaced via a macro, even though the names appear to be simply prefixed with Nc. When building Nanocolor, you may provide your own preprocessor macro to distinguish your copy of it.

#ifndef NCNAMESPACE
#define NCNAMESPACE pxr_nc_1_0_
#endif

There are no build scripts included with Nanocolor. You may build it as a library if you wish, or you may include Nanocolor.cpp, and optionally NanocolorUtils.cpp in your project.

License and Copyright

//
// Copyright 2024 Pixar
//
// Licensed under the Apache License, Version 2.0 (the "Apache License")
//
// You may obtain a copy of the Apache License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the Apache License with the above modification is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the Apache License for the specific
// language governing permissions and limitations under the Apache License.
//

Acknowledgements

Thanks to the scientists at Pixar, OpenColorIO, OpenEXR, OpenUSD, and MaterialX for the fruitful advice and feedback that helped guide the creation of Nanocolor.

About

Nanocolor, a lightweight color transformation library

License:Apache License 2.0


Languages

Language:C++ 84.5%Language:C 15.5%