Graphics::ColorObject - convert between color spaces
Contents
Abstract
Use this module to convert between all the common color spaces. As a pure Perl module, it is not very
fast, and so it you want to convert entire images quickly, this is probably not what you want. The
emphasis is on completeness and accurate conversion.
Supported color spaces are: RGB (including sRGB, Apple, Adobe, CIE Rec 601, CIE Rec 709, CIE ITU, and
about a dozen other RGB spaces), CMY, CMYK, HSL, HSV, XYZ, xyY, Lab, LCHab, Luv, LCHuv, YPbPr, YCbCr,
YUV, YIQ, PhotoYCC.
Conversion between different RGB working spaces, and between different white-points, is fully supported.
Bugs
Backwards compatibility with versions before 0.4 is not very well tested.
This module will produce results that are, in some cases, different from other software. Most of the
time that is not a bug in this module, but rather a case where the other software uses an approximate
(trading accuracy for speed) algorithm. That is particularly true for YUV and related conversions which
are often implemented using integer-math approximations. As far as possible, this module produces
results which are exact according to the definitions in the relevant CIE/ITU or other standards.
Some color transformations are not exactly reversible. In particular, conversions between different
white points are almost but not exactly reversible. This is not a bug.
There is no way to choose any other color-adaptation algorithm than the Bradford algorithm. That is
probably ok since the Bradford algorithm is better than other algorithms (such as Von Kries or simple
scaling).
There is no way to choose a RGB space other than the built-in ones.
Support for CMYK is very basic, it relies on assumptions that completely do not work in the physical
world of subtractive pigment mixtures. If you tried to convert an image to CMYK directly for printing
using these functions, the results will not be very good, to say the least.
Copyright And License
Copyright 2003-2005 by Alex Izvorski
Portions Copyright 2001-2003 by Alfred Reibenschuh
This library is free software; you can redistribute it and/or modify it under the same terms as Perl
itself.
perl v5.36.0 2023-09-29 ColorObject(3pm)
Description
For any supported color space XXX, there is one constructor new_XXX that creates a color using data in
that color space, and one method as_XXX that returns the current color as expressed in that color space.
For example, for RGB there is new_RGB and as_RGB. The color data is always passed as an array reference
to a three-element array (four-element in the case of CMYK). Thus, to convert from RGB to HSL, you can
use:
$color = Graphics::ColorObject->new_RGB([$r, $g, $b]);
($h, $s, $l) = @{ $color->as_HSL() };
The constructor can always take a hash of optional arguments in addition to the color value, namely the
working RGB space and the white point. For example:
$color = Graphics::ColorObject->new_RGB([$r, $g, $b], space=>'Adobe', white_point=>'D65');
For a list of all supported color spaces, call Graphics::ColorObject->list_colorspaces(). For a list of
all RGB working spaces and of all white points that this module supports, call
Graphics::ColorObject->list_rgb_spaces() and Graphics::ColorObject->list_white_points().
If not specified, the working RGB space will be sRGB. Many non-RGB conversions also rely on an implicit
RGB space, and passing an RGB space as an option (either to the constructor or later) will have an effect
on the values.
Methods
$color=Graphics::ColorObject->new_XYZ([$X,$Y,$Z])$color=Graphics::ColorObject->new_xyY([$x,$y,$Y])$color=Graphics::ColorObject->new_RGB([$R,$G,$B])$color=Graphics::ColorObject->new_RGB255([$R,$G,$B])$color=Graphics::ColorObject->new_RGBhex($rgbhex)$color=Graphics::ColorObject->new_Lab([$L,$a,$b])$color=Graphics::ColorObject->new_LCHab([$L,$C,$H])$color=Graphics::ColorObject->new_Luv([$L,$u,$v])$color=Graphics::ColorObject->new_LCHuv([$L,$C,$H])$color=Graphics::ColorObject->new_HSL([$H,$S,$L])$color=Graphics::ColorObject->new_HSV([$H,$S,$V])$color=Graphics::ColorObject->new_CMY([$C,$M,$Y])$color=Graphics::ColorObject->new_CMYK([$C,$M,$Y])$color=Graphics::ColorObject->new_YPbPr([$Y,$Pb,$Pr])$color=Graphics::ColorObject->new_YCbCr([$Y,$Cb,$Cr])$color=Graphics::ColorObject->new_YUV([$Y,$Cb,$Cr])$color=Graphics::ColorObject->new_YIQ([$Y,$I,$Q])$color=Graphics::ColorObject->new_PhotoYCC([$Y,$C1,$C2])($X,$Y,$Z)=@{$color->as_XYZ()}($R,$G,$B)=@{$color->as_RGB()}($R,$G,$B)=@{$color->as_RGB255()}$hex=$color->as_RGBhex()($x,$y,$Y)=@{$color->as_xyY()}($L,$a,$b)=@{$color->as_Lab()}($L,$C,$H)=@{$color->as_LCHab()}($L,$u,$v)=@{$color->as_Luv()}($L,$C,$H)=@{$color->as_LCHuv()}($H,$S,$L)=@{$color->as_HSL()}($H,$S,$V)=@{$color->as_HSV()}($C,$M,$Y)=@{$color->as_CMY()}($C,$M,$Y,$K)=@{$color->as_CMYK()}($Y,$Pb,$Pr)=@{$color->as_YPbPr()}($Y,$Cb,$Cr)=@{$color->as_YCbCr()}($Y,$U,$V)=@{$color->as_YUV()}($Y,$I,$Q)=@{$color->as_YIQ()}($Y,$C1,$C2)=@{$color->as_PhotoYCC()}$white_point=$color->get_white_point()Returnsthenameofthecurrentwhitepoint.Valueisoneoftheentriesreturnedfromlist_white_points,suchas"D65",oracolortemperature.$color->set_white_point("D65")Setsthecurrentwhitepointbyname.Argumentisoneoftheentriesreturnedfromlist_white_points,oratemperaturevaluelike"6800K".Thischangesthecurrentcolorslightlysincewhite-pointadaptationisnotcompletelyreversible.ThisdoesnotaffectthecurrentRGBspace,thusitispossibletouseRGBspacesatwhitepointsotherthanthosetheyweredefinedat.$rgb_space=$color->get_rgb_space()ReturnsthenameofthecurrentRGBcolorspace.Valueisoneoftheentriesreturnedfromlist_rgb_spaces,suchas"NTSC".$color->set_rgb_space("NTSC")SetsthecurrentRGBcolorspacebyname.Argumentisoneoftheentriesreturnedfromlist_rgb_spaces.Thismaychangethecurrentcoloriftheoldandnewspaceshavedifferentwhitepoints.$color2=$color->copy()Createsanexactduplicateofthecurrentcolor.if($color->equals($color2)){...}Checksifanothercoloristhesameasthisone.Optionallytakesanaccuracyparameterwhichisthedistancebetweenthetwocolorsasmeasuredbythecity-blockmetricinXYZspace(defaultaccuracyis0.01%).$d=$color->difference($color2)Calculatesthedifferencebetweenthiscolorandanotherone.Thedifferencemeasureis(approximately)perceptuallyuniform.@colorspaces=&Graphics::ColorObject->list_colorspaces()Returnsalistofallsupportedcolorspaces.@rgb_spaces=&Graphics::ColorObject->list_rgb_spaces()ReturnsalistofallsupportedRGBspaces.Someitemsarealiases,sothesamespacemaybelistedmorethanonceunderdifferentnames.@white_points=&Graphics::ColorObject->list_white_points()Returnsalistofallsupportedwhitepoints.EXPORT
None by default. The 'all' tag causes the non-object-oriented interface to be exported, and you get all
the XXX_to_YYY functions, for example RGB_to_XYZ. Please note that some of these functions need extra
arguments in addition to the color value to be converted.
Name
Graphics::ColorObject - convert between color spaces
Recommendations
Aside from converting from one space to another, what colorspace is the best one to use for a particular
task? This section attempts to answer that question.
For "generic" RGB values, use sRGB (which is the default).
For 2D effects filters, use Lab (or LCHab).
For adjustment of brightness, saturation and hue, use LCHab or LSHab.
For compression, use YCbCr, or use YPbPr and convert to integer values in a way that makes sense in your
application.
For representing data as colors, use Lab (straight lines between points in Lab are more-or-less uniform
gradients, unlike straight lines in RGB, for example).
See Also
The Color FAQ by Charles Poynton is one of the definitive references on the subject:
http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.txt
Bruce Lindbloom's web site contains a tremendous amount of information on color:
http://www.brucelindbloom.com/index.html?Math.html
Synopsis
use Graphics::ColorObject;
# rgb to hsv
$color = Graphics::ColorObject->new_RGB([$r, $g, $b]);
($h, $s, $v) = @{ $color->as_HSV() };
# one rgb space to another (NTSC to PAL)
$color = Graphics::ColorObject->new_RGB([$r, $g, $b], space=>'NTSC');
($r, $g, $b) = @{ $color->as_RGB(space=>'PAL') };
Todo
Add clipping to gamut for every color space.
Choose between several clipping algorithms (nearest, luminance-preserving, hue-preserving).
Add a simpler way to check whether something is within gamut.
Add user-defined RGB spaces.
Calculate RGB matrices from chromaticity coordinates.
Only load non-RGB matrices once at startup.
Add colorspaces: uvw, YOZ, RYB, others?
Add RGB spaces: ROMM, others?
Convert arrays of colors efficiently (maybe someday in C).
Upgrading From 0.3A2 And Older Versions
Version 0.4 and later are a complete rewrite from the previous major version, 0.3a2. The API is
completely changed. The old API should be emulated exactly in all cases. Please test any code that uses
this module when upgrading. If you encounter any strange behavior, please downgrade to 0.3a2 and email me
a bug report. Additionally, the exact values returned by some functions may be slightly different, this
is not a bug - the new values are (more) correct.
Various Notes And Gotchas
Most conversions will return out-of-gamut values if necessary, because that way they are lossless and can
be chained in calculations, or reversed to produce the original values. Many conversion methods will
take an optional boolean "clip" parameter to restrict the returned values to be within gamut:
($r, $g, $b) = @{ $color->as_RGB(space=>'sRGB', clip=>1) };
Currently clipping is supported in RGB, RGB-derived (HSL, CMY) and chroma-luma separated (YUV, etc)
spaces, but not in XYZ-derived spaces. The only way to check whether a value is within gamut is to
convert it with and without the clip option and compare the two results. An RGB value is within gamut
simply if R, G and B are between 0 and 1, but other spaces can be much harder to check.
RGB values are non-linear (gamma-adjusted) floating-point values scaled in the range from 0 to 1. If you
want integer values in the range 0..255, use the new_RGB255/as_RGB255 functions instead. If you want
linear RGB (not gamma-adjusted) use RGB_to_linear_RGB([$r, $g, $b]).
Functions that use an angle value always express it in degrees from 0 to 360. That includes the hue H in
HSL, HSV, LCHab and LCHuv. Use rad2deg and deg2rad from Math::Trig to convert to/from degrees if
necessary.
There is some confusion in the naming of YUV and related (Y-something-something) colorspaces. Most of
the time when "YUV" or "YCC" is used in software, for example in JPEG and MPEG2, that is actually YCbCr,
a chroma-luma separated space with integer values of Y in the range [16..235], Cb and Cr in [16..240].
JPEG uses a modified YCbCr with values in [0..255] (which is not implemented in this module). As used
here, YUV is a floating-point representation of the analog signal in PAL TV, YIQ is the same for NTSC TV,
YPbPr is component analog video, and PhotoYCC or YCC is the Kodak PhotoCD standard.
The set_white_point() function can take arbitrary temperatures as well as the predefined standard
illuminants. The valid range of temperatures is from 4000K to 25000K.
