ICC::Support::PCS - An object oriented module that transforms color values from one colorspace/encoding to another.
use ICC::Support::PCS;
# create a new object
$pcs = ICC::Support::PCS->new(); # empty object
$pcs = ICC::Support::PCS->new($input_array_ref, $output_array_ref, [$tone_compression_linearity]); # input/output parameters
# get/set header hash
$hash = $pcs->header(); # get header hash reference
$hash = $pcs->header($replacement_hash_ref); # set header hash
# get/set clipping flag
$flag = $pcs->clip(); # get clipping flag
$flag = $pcs->clip($replacement_value); # set clipping flag
# get/set tone compression linearity
$lin = $pcs->linearity(); # get tone compression value
$lin = $pcs->linearity($replacement_value); # set tone compression value
# get/set gamut scale factors
($input_gamut_scale_factor, $output_gamut_scale_factor) = $pcs->scale(); # get gamut scale factors
($input_gamut_scale_factor, $output_gamut_scale_factor) = $pcs->scale(($input_gamut_scale_factor, $output_gamut_scale_factor)); # set gamut scale factors
# transform
@list = $pcs->transform(@list, [$hash])
$vector = $pcs->transform($vector, [$hash])
$matrix = $pcs->transform($matrix, [$hash])
$structure = $pcs->transform($structure, [$hash])
Math::Matrix_object = $pcs->transform(Math::Matrix_object, [$hash])
# inverse transform
@list = $pcs->inverse(@list, [$hash])
$vector = $pcs->inverse($vector, [$hash])
$matrix = $pcs->inverse($matrix, [$hash])
$structure = $pcs->inverse($structure, [$hash])
Math::Matrix_object = $pcs->inverse(Math::Matrix_object, [$hash])
# Jacobian matrix
$matrix = $pcs->jacobian($vector, [$hash]);
($matrix, $vector) = $pcs->jacobian($vector, [$hash]);
# compute tone compression coefficients
$pcs->tc_pars();
# dump object
$string = $pcs->sdump([$format]);
$pcs->dump([$format]);
A PCS object transforms color values from one colorspace/encoding to another. The object class, PCS, is an acronym for Profile Connection Space, as defined in the ICC specification. The PCS colorspace may be XYZ or L*a*b*, and is encoded for 8-bit, 16-bit, or floating point values, depending on the tag's construction. All of the various PCS colorspace/encodings defined by the ICC are supported by the PCS object. In addition, other commonly used XYZ and L*a*b* encodings are supported.
A PCS object will transform various color data structures, including arrays, vectors and matrices. The object will identify the input data structure, and convert it to a corresponding output data structure.
An ICC::Support::PCS
object is a blessed array reference. The array contains four elements, the header hash, the parameter array, the tone compression array, and the clipping flag.
# create empty 'PCS' object
my $self = [
{}, # object header
[], # parameter array
[], # tone compression array
0 # clipping flag
];
The header hash contains metadata, and may be used to attach information to the object.
The parameter array contains colorspace, white point, and black point, of the input and output, structured as follows:
[[input_cs, [input_wtpt], [input_bkpt]], [output_cs, [output_wtpt], [output_bkpt]]]
This structure is created by the new
method from the supplied parameters. The white point and black point values are xyz
encoded (see below).
The tone compression array contains constants used by the transform methods. They are calculated by the tc_pars
method, which is called by the new
method.
The clipping flag controls the clipping of output values, which may be necessary to simulate the function of an ICC CMM.
Objects are created using integer parameters to specify the input and output colorspace/encodings, per the following table, which also lists their L*a*b* 100, 0, 0 equivalents:
0 - 8-bit ICC CIELAB (100, 0, 0 -> 255/255, 128/255, 128/255 = 1, 0.50196, 0.50196)
0 - 16-bit ICC CIELAB (100, 0, 0 -> 65535/65535, 32896/65535, 32896/65535 = 1, 0.50196, 0.50196)
1 - 16-bit ICC legacy L*a*b* (100, 0, 0 -> 65280/65535, 32768/65535, 32768/65535 = 0.99611, 0.50001, 0.50001)
2 - 16-bit EFI/Monaco L*a*b* (100, 0, 0 -> 65535/65535, 32768/65535, 32768/65535 = 1, 0.50001, 0.50001)
3 - L*a*b* (100, 0, 0 -> 100, 0, 0)
4 - LxLyLz (100, 0, 0 -> 100, 100, 100)
5 - unit LxLyLz (100, 0, 0 -> 1, 1, 1)
6 - xyY (100, 0, 0 -> 0.34570, 0.35854, 100)
7 - 16-bit ICC XYZ (100, 0, 0 -> 0.9642 * 32768/65535, 32768/65535, 0.8249 * 32768/65535 = 0.48211, 0.50001, 0.41246)
8 - 32-bit ICC XYZNumber (100, 0, 0 -> 0.9642, 1.0, 0.8249)
9 - xyz (100, 0, 0 -> 1, 1, 1)
10 - XYZ (100, 0, 0 -> 96.42, 100, 82.49)
Here is some further explanation,
0 is the 8-bit and 16-bit CIELAB encoding from the ICC v4 specification. it is listed twice to show the equivalence.
1 is the 16-bit L*a*b* encoding from the ICC v2 specification. also applies to mft2 and ncl2 tags within ICC v4 profiles.
2 is a non-standard L*a*b* encoding used in EFI and Monaco profiles.
3 is standard L*a*b* encoding, used in measurement files and floating point tags (e.g. D2Bx, B2Dx).
4 is L* encoding of the xyz channels.
5 is unit L* encoding of the xyz channels.
6 is chromaticity plus Y.
7 is the 16-bit XYZ encoding used by ICC v2 and v4. 8-bit XYZ encoding is undefined by the ICC specification.
8 is the 32-bit format used by XYZ tags, and the format used to set absolute colorimetry when creating PCS objects.
9 is X/Xn, Y/Yn, Z/Zn, as defined in ISO 13655.
10 is standard XYZ encoding, used in measurement files.
In addition to converting from one colorspace/encoding to another, the PCS object may transform the color values based on provided white point and black point values. This capability is used primarily to transform media-relative colorimetry to/from absolute colorimetry, as defined in the ICC specification. It may also be used to scale the color gamut.
When the input white point and black point are different from the output white point and black point, tone values are mapped. When the output tonal range is less than the input, tone compression occurs. By default, this is linear in xyz
space, and contrast is reduced uniformly in all tones.
In some cases, it may be desirable to favor light or dark tones, at the expense of detail in the opposite tone region. This is supported by the PCS object's tone compression algorithm, and controlled by a single linearity parameter.
Tone compression is accomplished with the following math (which uses x
and y
as input/output variables, not to be confused with xyz
color values).
First, we transform the xyz
values with a non-linear function,
t = exp(r * x)
where r
is a parameter called linearity
.
Second, we apply a linear transformation to t
,
t' = a * t + b
where a
and b
are constants.
Third, we apply the inverse transform to t'
,
y = ln(t')/r
This transform is symmetric,
t' = exp(r * y)
t = (t' - b)/a
x = ln(t)/r
The linearity of the overall transform is controlled by r
, which is set to a fixed value. As r
-> 0
, the transform becomes linear. So, we test if r == 0
, and do a simple linear transform for that case.
The default linearity
is 0
(linear). Positive values will favor light tones, and negative values will favor dark tones. The normal range of the linearity
parameter is -5
to +5
.
The constants a
and b
are calculated by the tc_pars()
method.
The PCS object may be set to enlarge or reduce the color gamut of the transformed values. By default, the output black point is set to [0, 0, 0]
. If we changed that to [0.1, 0.1, 0.1]
, the color gamut of the output would be reduced to roughly 90% of its former size, depending on the white point setting.
The scale
method adjusts the black point setting to a reduced level of the white point setting, using the gamut scale factor, which is normally a value near 1
.
If the white point is [x, y, z]
, and the gamut scale factor is gsf
, the black point is computed as,
bkpt = [(1 - gsf) * x, (1 - gsf) * y, (1 - gsf) * z]
When the gsf
is 0
, the black point is the same as the white point; when the gsf
is 1
, the the black point is [0, 0, 0]
, which is the default. The gsf
can be somewhat greater than 1
, which makes the black point values negative. This enlarges the color gamut, but can lead to negative xyz
output values.
The domain and range of the PCS object depends upon the input and output colorspace/encoding. All calculations are done with floating point math, regardless of whether they're encoded as 8-bit or 16-bit. Therefore, calculations will generally be successful, even when the input values are outside the normal range.
This method creates an ICC::Support::PCS
object.
With no parameters, the object contains the empty basic structure (see "Object structure" section).
An object is normally created from input and output array references.
Usage
# create a new object
$pcs = ICC::Support::PCS->new(); # empty object
$pcs = ICC::Support::PCS->new($input_array_ref, $output_array_ref, [$tone_compression_linearity]); # with parameters
Examples
use ICC::Support::PCS;
$pcs = ICC::Support::PCS->new(); # empty object (see note 1)
$wtpt = Lab2XYZ([95, 1, -4], d50); # L*a*b* 95, 1, -4 encoded as XYZNumber (see note 2)
$bkpt = Lab2XYZ([10, 0, 0], d50); # L*a*b* 10, 0, 0 encoded as XYZNumber
$pcs = ICC::Support::PCS->new([0], [3]); # input cs: ICC CIELAB (0), output cs: L*a*b* (3) (see note 3)
$pcs = ICC::Support::PCS->new([0], [3, $wtpt]); # same, but map profile white point to L*a*b* 95, 1, -4
$pcs = ICC::Support::PCS->new([3, $wtpt], [0]); # same, but map L*a*b* 95, 1, -4 to profile white point (see note 4)
$pcs = ICC::Support::PCS->new([0], [3, $wtpt, $bkpt]); # linear tone compression (see note 5)
$pcs = ICC::Support::PCS->new([0], [3, $wtpt, $bkpt], 1); # tone compression favoring light tones (see note 6)
$pcs = ICC::Support::PCS->new([0], [3, $wtpt, $bkpt], -1); # tone compression favoring dark tones (see note 6)
$profile = ICC::Profile->new('/Library/ColorSync/Profiles/GRACoL2013_CRPC6.icc'); # make profile object
$A2B1 = $profile->tag('A2B1'); # make A2B1 tag object
$pcs = ICC::Support::PCS->new([$A2B1->pcs], [3, $A2B1->wtpt]); # make absolute L*a*b* PCS object (see note 7)
print Dumper($pcs->transform($A2B1->transform([0, 0, 0, 0]))); # print the L*a*b* value of the media white point
The empty object cannot transform data.
The white point and black point parameters are encoded as XYZNumbers
using the Lab2XYZ
function. These parameters are converted to xyz
encoding and stored in the parameter array, when the object is created (see "Object structure" section).
Colorspace values are from the "Colorspace table".
The PCS object is symmetrical. Swapping the input and output arrays yields inverse transforms.
The white point is mapped from L*a*b* 100, 0, 0 to 95, 1, -4 and the black point is mapped from L*a*b* 0, 0, 0 to 10, 0, 0. Tone mapping is linear in xyz
space. Note the white point and black point parameters are XYZNumbers
. This is for compatibility with the ICC XYZType
tag, which is used to store the media white point.
Tone compression linearity is is a real value, typically between -3 and +3. By default, the linearity is 0 (linear). Positive values favor light tones, while negative values favor dark tones. Legacy terminology for these effects is 'high-key' and 'low-key' tone reproduction.
This PCS object transforms the encoded media relative color in the A2B1
tag to absolute L*a*b* color. The colorspace and white point of the tag object are obtained using the pcs
and wtpt
methods.
This method returns a reference to the header hash (see "Object structure" section). It may also be used to replace the header hash.
Usage
$hash = $pcs->header(); # get header hash reference
$hash = $pcs->header($replacement_hash_ref); # set header hash
Examples
use ICC::Support::PCS;
$pcs = ICC::Support::PCS->new([0], [3]); # make 'PCS' object
$hash = $pcs->header(); # get header hash reference
$hash->{'key'} = 'value'; # add key/value to header hash
$pcs->header->{'wtpt'} = [1, 1, 1]; # set value
$wtpt = $pcs->header->{'wtpt'}; # get value
$pcs->header({'new' => 'hash'}); # replace header (see note 1)
The parameter is copied to the object.
This method returns the value of the clipping flag (see "Object structure" section). It may also be used to set the flag value.
Usage
$flag = $pcs->clip(); # get clipping flag
$flag = $pcs->clip($replacement_value); # set clipping flag
Examples
use ICC::Support::PCS;
$pcs = ICC::Support::PCS->new([3], [0]); # make 'PCS' object
$clip = $pcs->clip(); # get value of clipping flag
$pcs->clip(1); # enable clipping (see note 1)
$pcs->clip(0); # disable clipping
Setting the clipping flag limits the output values to between 0 and 1, for colorspace/encoding 0, 1, and 2. This is done to simulate the behavior of an ICC CMM, where the output values are 8-bit or 16-bit binary values.
This method returns the tone compression linearity value (see "Tone compression" section). It may also be used to set the linearity value.
Usage
$lin = $pcs->linearity(); # get tone compression linearity value
$lin = $pcs->linearity($replacement_value); # set tone compression linearity value
Examples
use ICC::Support::PCS;
$wtpt = Lab2XYZ([95, 1, -4], d50); # L*a*b* 95, 1, -4 encoded as XYZNumber (see note 1)
$bkpt = Lab2XYZ([10, 0, 0], d50); # L*a*b* 10, 0, 0 encoded as XYZNumber
$pcs = ICC::Support::PCS->new([0], [3, $wtpt, $bkpt], 1); # make PCS object, linearity is 1
$lin = $pcs->linearity(); # get the current linearity
$pcs->linearity(1.5); # set the value to 1.5 (see note 2)
The white point and black point parameters are encoded as XYZNumbers
using the Lab2XYZ
function.
The default linearity is 0 (linear). Positive values will favor light tones, and negative values will favor dark tones. The normal range of the linearity parameter is -5 to +5.
This method returns the gamut scale factor values (see "Gamut scale factor" section). It may also be used to set these values.
Usage
($input_gamut_scale_factor, $output_gamut_scale_factor) = $pcs->scale(); # get gamut scale factors
($input_gamut_scale_factor, $output_gamut_scale_factor) = $pcs->scale(($input_gamut_scale_factor, $output_gamut_scale_factor)); # set gamut scale factors
Examples
use ICC::Support::PCS;
$pcs = ICC::Support::PCS->new([0], [3]); # make PCS object
($gsfi, $gsfo) = $pcs->scale(); # get gamut scale factors
$pcs->scale(0.9, 0); # set input gamut scale factor to 0.9 (output unchanged) (see note 1)
$pcs->scale(0, 0.9); # set output gamut scale factor to 0.9 (input unchanged)
When setting gamut scale factors, a value of 0
leaves that factor unchanged.
This method transforms data of various types, including lists, vectors, matrices, and certain structures. The output type is identical to the input type, which is automatically detected by the method.
Usage
@list = $pcs->transform(@list, [$hash])
$vector = $pcs->transform($vector, [$hash])
$matrix = $pcs->transform($matrix, [$hash])
$structure = $pcs->transform($structure, [$hash])
Math::Matrix_object = $pcs->transform(Math::Matrix_object, [$hash])
Examples
use ICC::Support::PCS;
$pcs = ICC::Support::PCS->new([0], [3]); # make PCS object
@list = $pcs->transform(1, 0.5, 0.5); # transform a list (array) (see note 1)
print "@list\n";
$vector = $pcs->transform([1, 0.5, 0.5]); # transform a vector (array reference) (see note 2)
print Dumper($vector);
$matrix = $pcs->transform([[1, 0.5, 0.5], [0.9, 0.5, 0.5], [0.8, 0.5, 0.5]]); # transform a matrix (see note 3)
print Dumper($matrix);
$structure = $pcs->transform([[1, 0.5, 0.5], [[0.9, 0.5, 0.5], [0.8, 0.5, 0.5]]]); # transform a structure (see note 4)
print Dumper($structure);
$mat_obj = $pcs->transform(Math::Matrix->new([1, 0.5, 0.5], [0.9, 0.5, 0.5], [0.8, 0.5, 0.5])); # transform a matrix obj (see note 5)
print Dumper($mat_obj);
$vector = $pcs->transform([1, 0.5, 0.5], {'key' => 'value'}); # with optional hash (see note 6)
print Dumper($vector);
The list (array) must contain exactly three elements, and be a valid color in the colorspace/encoding of the PCS object.
The vector (array reference) must contain exactly three elements, and be a valid color in the colorspace/encoding of the PCS object.
Each element of the matrix must be a vector containing exactly three elements, and be a valid color in the colorspace/encoding of the PCS object.
Each element of the structure must be a vector containing exactly three elements, and be a valid color in the colorspace/encoding of the PCS object.
Each element of the matrix must be a vector containing exactly three elements, and be a valid color in the colorspace/encoding of the PCS object.
Currently, the optional hash has no function, but that may change in future revisions.
This method transforms data of various types, including lists, vectors, matrices, and certain structures. The output type is identical to the input type, which is automatically detected by the method. This method is the inverse of the "transform" method.
Usage
@list = $pcs->inverse(@list, [$hash])
$vector = $pcs->inverse($vector, [$hash])
$matrix = $pcs->inverse($matrix, [$hash])
$structure = $pcs->inverse($structure, [$hash])
Math::Matrix_object = $pcs->inverse(Math::Matrix_object, [$hash])
Examples
use ICC::Support::PCS;
$pcs = ICC::Support::PCS->new([0], [3]); # make PCS object
@list = $pcs->inverse(100, -0.5, -0.5); # transform a list (array) (see note 1)
print "@list\n";
$vector = $pcs->inverse([100, -0.5, -0.5]); # transform a vector (array reference) (see note 2)
print Dumper($vector);
$matrix = $pcs->inverse([[100, -0.5, -0.5], [90, -0.5, -0.5], [80, -0.5, -0.5]]); # transform a matrix (see note 3)
print Dumper($matrix);
$structure = $pcs->inverse([[100, -0.5, -0.5], [[90, -0.5, -0.5], [80, -0.5, -0.5]]]); # transform a structure (see note 4)
print Dumper($structure);
$mat_obj = $pcs->inverse(Math::Matrix->new([100, -0.5, -0.5], [90, -0.5, -0.5], [80, -0.5, -0.5])); # transform a matrix obj (see note 5)
print Dumper($mat_obj);
$vector = $pcs->inverse([100, -0.5, -0.5], {'key' => 'value'}); # with optional hash (see note 6)
print Dumper($vector);
The list (array) must contain exactly three elements, and be a valid color in the colorspace/encoding of the PCS object.
The vector (array reference) must contain exactly three elements, and be a valid color in the colorspace/encoding of the PCS object.
Each element of the matrix must be a vector containing exactly three elements, and be a valid color in the colorspace/encoding of the PCS object.
Each element of the structure must be a vector containing exactly three elements, and be a valid color in the colorspace/encoding of the PCS object.
Each element of the matrix must be a vector containing exactly three elements, and be a valid color in the colorspace/encoding of the PCS object.
Currently, the optional hash has no function, but that may change in future revisions.
This method returns the Jacobian matrix of the vector transform, and optionally, the "transform" output.
Usage
$matrix = $pcs->jacobian($vector, [$hash]);
($matrix, $vector) = $pcs->jacobian($vector, [$hash]);
Examples
use ICC::Support::PCS;
$pcs = ICC::Support::PCS->new([0], [3]); # make PCS object
$matrix = $pcs->jacobian([1, 0.5, 0.5]); # compute Jacobian matrix (see note 1)
print Dumper($matrix);
($matrix, $vector) = $pcs->jacobian([1, 0.5, 0.5]); # compute Jacobian matrix and transform vector (see notes 1 and 2)
print Dumper($matrix, $vector);
The vector (array reference) must contain exactly three elements, and be a valid color in the colorspace/encoding of the PCS object.
The output vector computed by the transform
method is optionally returned.
This method calculates the internal tone compression parameters used by the transform methods. It is called when making a new PCS object, and also by the linearity
and scale
methods. The user will not normally need to call this method, except when directly modifying the internal parameters.
Usage
$pcs->tc_pars();
This method returns a string showing the structure of the 'PCS' object.
Usage
$string = $pcs->sdump([$format]);
$pcs->dump([$format]);
Examples
use ICC::Support::PCS;
$pcs = ICC::Support::PCS->new([0], [3]); # make PCS object
$string = $pcs->sdump(); # dump to string
$pcs->dump(); # dump to STDOUT
The ICC (International Color Consortium) maintains a web site at http://www.color.org The ICC specification and related materials may be downloaded from this web site.
The ICC specification is also published as ISO 15076-1.
ISO 15076-1 Image technology colour management — Architecture, profile format and data structure — Part 1: Based on ICC.1:2010
Programs in this distribution, authored by William B. Birkett, are licensed under the GNU General Public License, v3.
See https://www.gnu.org/licenses/gpl-3.0.html for license details.
William B. Birkett, <wbirkett@doplganger.com>
Copyright © 2004-2024 by William B. Birkett