File Coverage

color_space.pd
Criterion Covered Total %
statement 45 45 100.0
branch 1 2 50.0
condition n/a
subroutine 13 13 100.0
pod 0 8 0.0
total 59 68 86.7


line stmt bran cond sub pod time code
1             pp_add_exported(
2             'rgb_to_xyz', 'xyz_to_rgb',
3             'xyz_to_lab', 'lab_to_xyz',
4             'rgb_to_lch', 'lch_to_rgb',
5             'rgb_to_lab', 'lab_to_rgb',
6             'add_rgb_space',
7             );
8              
9             $PDL::Graphics::ColorSpace::VERSION = '0.206';
10              
11             pp_setversion("'$PDL::Graphics::ColorSpace::VERSION'");
12              
13             pp_addpm({At=>'Top'}, <<'EOD');
14              
15             =encoding utf8
16              
17             =head1 NAME
18              
19             PDL::Graphics::ColorSpace - colour-space conversions for PDL
20              
21             =head1 SYNOPSIS
22              
23             use PDL::LiteF;
24             use PDL::IO::Pic;
25             use PDL::Graphics::ColorSpace;
26              
27             my $image_rgb = PDL->rpic('photo.jpg') if PDL->rpiccan('JPEG');
28              
29             # convert RGB value from [0,255] to [0,1]
30             $image_rgb = $image_rgb->double / 255;
31              
32             my $image_xyz = $image_rgb->rgb_to_xyz( 'sRGB' );
33              
34             Or
35              
36             my $image_xyz = rgb_to_xyz( $image_rgb, 'sRGB' );
37              
38             =head1 DESCRIPTION
39              
40             Does image color space conversions such as RGB to XYZ and Lab to LCH. Derived from Graphics::ColorObject (Izvorski & Reibenschuh, 2005) but since it's implemented in C and PDL, it runs *much* faster.
41              
42             Often the conversion will return out-of-gamut values. Retaining out-of-gamut values allows chained conversions to be lossless and reverse conversions to produce the original values. You can clip the values to be within-gamut if necessary. Please check the specific color space for the gamut range.
43              
44             =head1 COLOR SPACES
45              
46             =head2 RGB
47              
48             An RGB color space is any additive color space based on the RGB color model. A particular RGB color space is defined by the three chromaticities of the red, green, and blue additive primaries, and can produce any chromaticity that is the triangle defined by those primary colors. The complete specification of an RGB color space also requires a white point chromaticity and a gamma correction curve.
49              
50             For more info on the RGB color space, see L.
51              
52             This module expects and produces RGB values normalized to be in the range of [0,1]. If you have / need integer value between [0,255], divide or multiply the values by 255.
53              
54             =head2 CMYK
55              
56             CMYK refers to the four inks used in some color printing: cyan, magenta, yellow, and key (black). The CMYK model works by partially or entirely masking colors on a lighter, usually white, background. The ink reduces the light that would otherwise be reflected. Such a model is called subtractive because inks "subtract" brightness from white.
57              
58             In additive color models such as RGB, white is the "additive" combination of all primary colored lights, while black is the absence of light. In the CMYK model, it is the opposite: white is the natural color of the paper or other background, while black results from a full combination of colored inks. To save money on ink, and to produce deeper black tones, unsaturated and dark colors are produced by using black ink instead of the combination of cyan, magenta and yellow.
59              
60             For more info, see L.
61              
62             =head2 HSL
63              
64             Hue, Saturation and Luminance (or brightness).
65              
66             The HSL color space defines colors more naturally: Hue specifies the base color, the other two values then let you specify the saturation of that color and how bright the color should be.
67              
68             Hue is specified here as degrees ranging from 0 to 360. There are 6 base colors:
69              
70             0 red
71             60 yellow
72             120 green
73             180 cyan
74             240 blue
75             300 magenta
76             360 red
77              
78             Saturation specifies the distance from the middle of the color wheel. So a saturation value of 0 (0%) means "center of the wheel", i.e. a grey value, whereas a saturation value of 1 (100%) means "at the border of the wheel", where the color is fully saturated.
79              
80             Luminance describes how "bright" the color is. 0 (0%) means 0 brightness and the color is black. 1 (100%) means maximum brightness and the color is white.
81              
82             For more info, see L.
83              
84             =head2 XYZ and xyY
85              
86             The CIE XYZ color space was derived the CIE RGB color space. XYZ are three hypothetical primaries. Y means brightness, Z is quasi-equal to blue stimulation, and X is a mix which looks like red sensitivity curve of cones. All visible colors can be represented by using only positive values of X, Y, and Z. The main advantage of the CIE XYZ space (and any color space based on it) is that this space is completely device-independent.
87              
88             For more info, see L.
89              
90             =head2 Lab
91              
92             A Lab color space is a color-opponent space with dimension L for lightness and a and b for the color-opponent dimensions, based on nonlinearly compressed CIE XYZ color space coordinates. It's derived from the "master" space CIE 1931 XYZ color space but is more perceptually uniform than XYZ. The Lab space is relative to the white point of the XYZ data they were converted from. Lab values do not define absolute colors unless the white point is also specified.
93              
94             For more info, see L.
95              
96             =head2 LCH
97              
98             This is possibly a little easier to comprehend than the Lab colour space, with which it shares several features. It is more correctly known as L*C*H*. Essentially it is in the form of a sphere. There are three axes; L* and C* and H°.
99              
100             The L* axis represents Lightness. This is vertical; from 0, which has no lightness (i.e. absolute black), at the bottom; through 50 in the middle, to 100 which is maximum lightness (i.e. absolute white) at the top.
101              
102             The C* axis represents Chroma or "saturation". This ranges from 0 at the centre of the circle, which is completely unsaturated (i.e. a neutral grey, black or white) to 100 or more at the edge of the circle for very high Chroma (saturation) or "colour purity".
103              
104             If we take a horizontal slice through the centre, we see a coloured circle. Around the edge of the circle we see every possible saturated colour, or Hue. This circular axis is known as H° for Hue. The units are in the form of degrees° (or angles), ranging from 0 (red) through 90 (yellow), 180 (green), 270 (blue) and back to 0.
105              
106             For more info, see L.
107              
108             =head1 OPTIONS
109              
110             Some conversions require specifying the RGB space which includes gamma curve and white point definitions. Supported RGB spaces include (aliases in square brackets):
111              
112             Adobe RGB (1998) [Adobe]
113             Apple RGB [Apple]
114             BestRGB
115             Beta RGB
116             BruceRGB
117             CIE
118             ColorMatch
119             DonRGB4
120             ECI
121             Ekta Space PS5
122             NTSC [601] [CIE Rec 601]
123             PAL/SECAM [PAL] [CIE ITU]
124             ProPhoto
125             SMPTE-C [SMPTE]
126             WideGamut
127             sRGB [709] [CIE Rec 709]
128             lsRGB
129              
130             You can also add custom RGB space definitions via the function add_rgb_space.
131             Alternatively, as of 0.202 you can directly supply the function with a
132             hash-ref in the same format.
133              
134             =head1 CONVERSIONS
135              
136             Some conversions, if not already included as functions, can be achieved
137             by chaining existing functions. For example, LCH to HSV conversion can
138             be achieved by chaining lch_to_rgb and rgb_to_hsv:
139              
140             my $hsv = rgb_to_hsv( lch_to_rgb( $lch, 'sRGB' ), 'sRGB' );
141              
142             To generate a local diagram of what conversions are available between
143             formats, using GraphViz, you can use this script:
144              
145             use blib;
146             use PDL::Graphics::ColorSpace;
147             print "digraph {\n";
148             print join(' -> ', split /_to_/), "\n"
149             for grep !/^_/ && /_to_/, @PDL::Graphics::ColorSpace::EXPORT_OK;
150             print "}\n";
151             # then:
152             perl scriptname >d.dot; dot -Tsvg d.dot >d.svg; display d.svg
153              
154             (As of 0.202, this is everything to and from C, plus C <->
155             C <-> C)
156              
157             =cut
158 1     1   10  
  1         2  
  1         47  
159 1     1   6 use strict;
  1         2  
  1         92  
160             use warnings;
161 1     1   6  
  1         2  
  1         80  
162 1     1   8 use Carp;
  1         1  
  1         8  
163 1     1   3489 use PDL::LiteF;
  1         4  
  1         1315  
164             use PDL::Graphics::ColorSpace::RGBSpace;
165              
166             my $RGB_SPACE = $PDL::Graphics::ColorSpace::RGBSpace::RGB_SPACE;
167              
168             EOD
169              
170             pp_addhdr('
171             #include
172             #include "color_space.h" /* Local decs */
173             '
174             );
175              
176             pp_def('rgb_to_cmyk',
177             Pars => 'rgb(c=3); [o]cmyk(d=4)',
178             HandleBad => 1,
179             GenericTypes=>['D'],
180             Code => '
181             /* First check for bad values */
182             PDL_IF_BAD(if ($ISBAD(rgb(c=>0)) || $ISBAD(rgb(c=>1)) || $ISBAD(rgb(c=>2))) {
183             loop (d) %{
184             $SETBAD(cmyk());
185             %}
186             /* skip to the next cmyk triple */
187             }
188             else,) {
189             rgb2cmyk($P(rgb), $P(cmyk));
190             }
191             ',
192              
193             Doc => <<'DOCUMENTATION',
194              
195             =pod
196              
197             =for ref
198              
199             Converts an RGB color triple to an CMYK color quadruple.
200              
201             The first dimension of the ndarrays holding the rgb values must be size 3, i.e. the dimensions must look like (3, m, n, ...). The first dimension of the ndarrays holding the cmyk values must be size 4.
202              
203             =for usage
204              
205             Usage:
206              
207             my $cmyk = rgb_to_cmyk( $rgb );
208              
209             =cut
210              
211             DOCUMENTATION
212             BadDoc => <
213              
214             =for bad
215              
216             If C encounters a bad value in any of the R, G, or B values the output ndarray will be marked as bad and the associated C, M, Y, and K values will all be marked as bad.
217              
218             =cut
219              
220             BADDOC
221             );
222              
223              
224             pp_def('cmyk_to_rgb',
225             Pars => 'cmyk(d=4); [o]rgb(c=3)',
226             HandleBad => 1,
227             GenericTypes=>['D'],
228             Code => '
229             /* First check for bad values */
230             PDL_IF_BAD(if ($ISBAD(cmyk(d=>0)) || $ISBAD(cmyk(d=>1)) || $ISBAD(cmyk(d=>2)) || $ISBAD(cmyk(d=>3))) {
231             loop (c) %{
232             $SETBAD(rgb());
233             %}
234             /* skip to the next cmyk triple */
235             }
236             else,) {
237             cmyk2rgb($P(cmyk), $P(rgb));
238             }
239             ',
240             Doc => <<'DOCUMENTATION',
241              
242             =pod
243              
244             =for ref
245              
246             Converts an CMYK color quadruple to an RGB color triple
247              
248             The first dimension of the ndarrays holding the cmyk values must be size 4, i.e. the dimensions must look like (4, m, n, ...). The first dimension of the ndarray holding the rgb values must be 3.
249              
250             =for usage
251              
252             Usage:
253              
254             my $rgb = cmyk_to_rgb( $cmyk );
255              
256             =cut
257              
258             DOCUMENTATION
259             BadDoc => <
260              
261             =for bad
262              
263             If C encounters a bad value in any of the C, M, Y, or K quantities, the output ndarray will be marked as bad and the associated R, G, and B color values will all be marked as bad.
264              
265             =cut
266              
267             BADDOC
268             );
269              
270              
271             pp_def('rgb_to_hsl',
272             Pars => 'rgb(c=3); [o]hsl(c=3)',
273             HandleBad => 1,
274             Inplace => 1,
275             GenericTypes=>['D'],
276             Code => '
277             /* First check for bad values */
278             PDL_IF_BAD(if ($ISBAD(rgb(c=>0)) || $ISBAD(rgb(c=>1)) || $ISBAD(rgb(c=>2))) {
279             loop (c) %{
280             $SETBAD(hsl());
281             %}
282             /* skip to the next hsl triple */
283             }
284             else,) {
285             rgb2hsl($P(rgb), $P(hsl));
286             }
287             ',
288              
289             Doc => <<'DOCUMENTATION',
290              
291             =pod
292              
293             =for ref
294              
295             Converts an RGB color triple to an HSL color triple.
296              
297             The first dimension of the ndarrays holding the hsl and rgb values must be size 3, i.e. the dimensions must look like (3, m, n, ...).
298              
299             =for usage
300              
301             Usage:
302              
303             my $hsl = rgb_to_hsl( $rgb );
304              
305             =cut
306              
307             DOCUMENTATION
308             BadDoc => <
309              
310             =for bad
311              
312             If C encounters a bad value in any of the R, G, or B values the output ndarray will be marked as bad and the associated H, S, and L values will all be marked as bad.
313              
314             =cut
315              
316             BADDOC
317             );
318              
319              
320             pp_def('hsl_to_rgb',
321             Pars => 'hsl(c=3); [o]rgb(c=3)',
322             HandleBad => 1,
323             Inplace => 1,
324             GenericTypes=>['D'],
325             Code => '
326             /* First check for bad values */
327             PDL_IF_BAD(if ($ISBAD(hsl(c=>0)) || $ISBAD(hsl(c=>1)) || $ISBAD(hsl(c=>2))) {
328             loop (c) %{
329             $SETBAD(rgb());
330             %}
331             /* skip to the next hsl triple */
332             }
333             else,) {
334             hsl2rgb($P(hsl), $P(rgb));
335             }
336             ',
337             Doc => <<'DOCUMENTATION',
338              
339             =pod
340              
341             =for ref
342              
343             Converts an HSL color triple to an RGB color triple
344              
345             The first dimension of the ndarrays holding the hsl and rgb values must be size 3, i.e. the dimensions must look like (3, m, n, ...).
346              
347             =for usage
348              
349             Usage:
350              
351             my $rgb = hsl_to_rgb( $hsl );
352              
353             =cut
354              
355             DOCUMENTATION
356             BadDoc => <
357              
358             =for bad
359              
360             If C encounters a bad value in any of the H, S, or V quantities, the output ndarray will be marked as bad and the associated R, G, and B color values will all be marked as bad.
361              
362             =cut
363              
364             BADDOC
365             );
366              
367              
368             pp_def('rgb_to_hsv',
369             Pars => 'rgb(c=3); [o]hsv(c=3)',
370             HandleBad => 1,
371             Inplace => 1,
372             GenericTypes=>['D'],
373             Code => '
374             /* First check for bad values */
375             PDL_IF_BAD(if ($ISBAD(rgb(c=>0)) || $ISBAD(rgb(c=>1)) || $ISBAD(rgb(c=>2))) {
376             loop (c) %{
377             $SETBAD(hsv());
378             %}
379             /* skip to the next hsv triple */
380             }
381             else,) {
382             rgb2hsv($P(rgb), $P(hsv));
383             }
384             ',
385              
386             Doc => <<'DOCUMENTATION',
387              
388             =pod
389              
390             =for ref
391              
392             Converts an RGB color triple to an HSV color triple.
393              
394             The first dimension of the ndarrays holding the hsv and rgb values must be size 3, i.e. the dimensions must look like (3, m, n, ...).
395              
396             =for usage
397              
398             Usage:
399              
400             my $hsv = rgb_to_hsv( $rgb );
401              
402             =cut
403              
404             DOCUMENTATION
405             BadDoc => <
406              
407             =for bad
408              
409             If C encounters a bad value in any of the R, G, or B values the output ndarray will be marked as bad and the associated H, S, and V values will all be marked as bad.
410              
411             =cut
412              
413             BADDOC
414             );
415              
416              
417             pp_def('hsv_to_rgb',
418             Pars => 'hsv(c=3); [o]rgb(c=3)',
419             HandleBad => 1,
420             Inplace => 1,
421             GenericTypes=>['D'],
422             Code => '
423             /* First check for bad values */
424             PDL_IF_BAD(if ($ISBAD(hsv(c=>0)) || $ISBAD(hsv(c=>1)) || $ISBAD(hsv(c=>2))) {
425             loop (c) %{
426             $SETBAD(rgb());
427             %}
428             /* skip to the next rgb triple */
429             }
430             else,) {
431             hsv2rgb($P(hsv), $P(rgb));
432             }
433             ',
434              
435             Doc => <<'DOCUMENTATION',
436              
437             =pod
438              
439             =for ref
440              
441             Converts an HSV color triple to an RGB color triple
442              
443             The first dimension of the ndarrays holding the hsv and rgb values must be size 3, i.e. the dimensions must look like (3, m, n, ...).
444              
445             =for usage
446              
447             Usage:
448              
449             my $rgb = hsv_to_rgb( $hsv );
450              
451             =cut
452              
453             DOCUMENTATION
454             BadDoc => <
455              
456             =for bad
457              
458             If C encounters a bad value in any of the H, S, or V quantities, the output ndarray will be marked as bad and the associated R, G, and B color values will all be marked as bad.
459              
460             =cut
461              
462             BADDOC
463             );
464              
465              
466             pp_def('xyY_to_xyz',
467             Pars => 'xyY(c=3); [o]xyz(c=3)',
468             Doc => 'Internal function for white point calculation. Use it if you must.',
469             HandleBad => 1,
470             Inplace => 1,
471             GenericTypes=>['D'],
472             Code => '
473             /* First check for bad values */
474             PDL_IF_BAD(if ($ISBAD(xyY(c=>0)) || $ISBAD(xyY(c=>1)) || $ISBAD(xyY(c=>2))) {
475             loop (c) %{
476             $SETBAD(xyz());
477             %}
478             /* skip to the next hsl triple */
479             }
480             else,) {
481             xyY2xyz($P(xyY), $P(xyz));
482             }
483             ',
484             );
485              
486              
487             pp_def('_rgb_to_xyz',
488             Pars => 'rgb(c=3); gamma(); m(i=3,rows=3); [o]xyz(c=3)',
489             HandleBad => 1,
490             Inplace => ['rgb'],
491             GenericTypes=>['D'],
492             Code => '
493             /* First check for bad values */
494             PDL_IF_BAD(if ($ISBAD(rgb(c=>0)) || $ISBAD(rgb(c=>1)) || $ISBAD(rgb(c=>2))) {
495             loop (c) %{
496             $SETBAD(xyz());
497             %}
498             /* skip to the next xyz triple */
499             }
500             else,) {
501             rgb2xyz($P(rgb), $gamma(), &$m(i=>0,rows=>0), &$m(i=>0,rows=>1), &$m(i=>0,rows=>2), $P(xyz));
502             }
503             ',
504             Doc => undef,
505             );
506              
507              
508             pp_def('_xyz_to_rgb',
509             Pars => 'xyz(c=3); gamma(); mstar(i=3,rows=3); [o]rgb(c=3)',
510             HandleBad => 1,
511             Inplace => ['xyz'],
512             GenericTypes=>['D'],
513             Code => '
514             /* First check for bad values */
515             PDL_IF_BAD(if ($ISBAD(xyz(c=>0)) || $ISBAD(xyz(c=>1)) || $ISBAD(xyz(c=>2))) {
516             loop (c) %{
517             $SETBAD(rgb());
518             %}
519             /* skip to the next rgb triple */
520             }
521             else,) {
522             xyz2rgb($P(xyz), $gamma(), &$mstar(i=>0,rows=>0), &$mstar(i=>0,rows=>1), &$mstar(i=>0,rows=>2), $P(rgb));
523             }
524             ',
525             Doc => undef,
526             );
527              
528              
529             pp_def('_xyz_to_lab',
530             Pars => 'xyz(c=3); w(d=2); [o]lab(c=3)',
531             Doc => undef,
532             HandleBad => 1,
533             Inplace => ['xyz'],
534             GenericTypes=>['D'],
535             Code => '
536             /* construct white point */
537             double xyY[3] = { $w(d=>0), $w(d=>1), 1.0 };
538             double xyz_white[3];
539             xyY2xyz( &xyY[0], &xyz_white[0] );
540              
541             threadloop %{
542             /* First check for bad values */
543             PDL_IF_BAD(if ($ISBAD(xyz(c=>0)) || $ISBAD(xyz(c=>1)) || $ISBAD(xyz(c=>2))) {
544             loop (c) %{
545             $SETBAD(lab());
546             %}
547             /* skip to the next xyz triple */
548             }
549             else,) {
550             xyz2lab( $P(xyz), &xyz_white[0], $P(lab) );
551             }
552             %}
553             ',
554             );
555              
556              
557             pp_def('_lab_to_xyz',
558             Pars => 'lab(c=3); w(d=2); [o]xyz(c=3)',
559             Doc => undef,
560              
561             HandleBad => 1,
562             Inplace => ['lab'],
563             GenericTypes=>['D'],
564             Code => '
565             /* construct white point */
566             double xyY[3] = { $w(d=>0), $w(d=>1), 1.0 };
567             double xyz_white[3];
568             xyY2xyz( &xyY[0], &xyz_white[0] );
569              
570             threadloop %{
571             /* First check for bad values */
572             PDL_IF_BAD(if ($ISBAD(lab(c=>0)) || $ISBAD(lab(c=>1)) || $ISBAD(lab(c=>2))) {
573             loop (c) %{
574             $SETBAD(xyz());
575             %}
576             /* skip to the next lab triple */
577             }
578             else,) {
579             lab2xyz( $P(lab), &xyz_white[0], $P(xyz) );
580             }
581             %}
582             ',
583             );
584              
585              
586             pp_def('lab_to_lch',
587             Pars => 'lab(c=3); [o]lch(c=3)',
588             HandleBad => 1,
589             Inplace => 1,
590             GenericTypes=>['D'],
591             Code => '
592             /* First check for bad values */
593             PDL_IF_BAD(if ($ISBAD(lab(c=>0)) || $ISBAD(lab(c=>1)) || $ISBAD(lab(c=>2))) {
594             loop (c) %{
595             $SETBAD(lch());
596             %}
597             /* skip to the next lch triple */
598             }
599             else,) {
600             lab2lch( $P(lab), $P(lch) );
601             }
602             ',
603             Doc => <<'DOCUMENTATION',
604              
605             =pod
606              
607             =for ref
608              
609             Converts an Lab color triple to an LCH color triple.
610              
611             The first dimension of the ndarrays holding the lab values must be size 3, i.e. the dimensions must look like (3, m, n, ...).
612              
613             =for usage
614              
615             Usage:
616              
617             my $lch = lab_to_lch( $lab );
618              
619             =cut
620              
621             DOCUMENTATION
622             BadDoc => <
623              
624             =for bad
625              
626             If C encounters a bad value in any of the L, a, or b values the output ndarray will be marked as bad and the associated L, C, and H values will all be marked as bad.
627              
628             =cut
629              
630             BADDOC
631             );
632              
633              
634             pp_def('lch_to_lab',
635             Pars => 'lch(c=3); [o]lab(c=3)',
636             HandleBad => 1,
637             Inplace => 1,
638             GenericTypes=>['D'],
639             Code => '
640             /* First check for bad values */
641             PDL_IF_BAD(if ($ISBAD(lch(c=>0)) || $ISBAD(lch(c=>1)) || $ISBAD(lch(c=>2))) {
642             loop (c) %{
643             $SETBAD(lab());
644             %}
645             /* skip to the next lab triple */
646             }
647             else,) {
648             lch2lab( $P(lch), $P(lab) );
649             }
650             ',
651             Doc => <<'DOCUMENTATION',
652              
653             =pod
654              
655             =for ref
656              
657             Converts an LCH color triple to an Lab color triple.
658              
659             The first dimension of the ndarrays holding the lch values must be size 3, i.e. the dimensions must look like (3, m, n, ...).
660              
661             =for usage
662              
663             Usage:
664              
665             my $lab = lch_to_lab( $lch );
666              
667             =cut
668              
669             DOCUMENTATION
670             BadDoc => <
671              
672             =for bad
673              
674             If C encounters a bad value in any of the L, C, or H values the output ndarray will be marked as bad and the associated L, a, and b values will all be marked as bad.
675              
676             =cut
677              
678             BADDOC
679             );
680              
681              
682             pp_def('rgb_to_linear',
683             Pars => 'rgb(c=3); gamma(); [o]out(c=3)',
684             HandleBad => 1,
685             Inplace => ['rgb'],
686             GenericTypes=>['D'],
687             Code => '
688             PDL_IF_BAD(if ($ISBAD(rgb(c=>0)) || $ISBAD(rgb(c=>1)) || $ISBAD(rgb(c=>2))) {
689             loop (c) %{ $SETBAD(out()); %}
690             }
691             else,) {
692             rgb2linear( $P(rgb), $gamma(), $P(out) );
693             }
694             ',
695             Doc => <<'DOCUMENTATION',
696             =for ref
697              
698             Converts an RGB color triple (presumably with gamma) to an RGB color triple
699             with linear values.
700              
701             =for usage
702              
703             Usage:
704              
705             my $rgb_linear = rgb_to_linear( $gammaed, 2.2 );
706             DOCUMENTATION
707             BadDoc => <
708             =for bad
709              
710             If C encounters a bad value in any of the R, G, or B
711             values the output ndarray will be marked as bad and the associated R,
712             G, and B values will all be marked as bad.
713             BADDOC
714             );
715              
716              
717             pp_def('rgb_from_linear',
718             Pars => 'rgb(c=3); gamma(); [o]out(c=3)',
719             HandleBad => 1,
720             Inplace => ['rgb'],
721             GenericTypes=>['D'],
722             Code => '
723             PDL_IF_BAD(if ($ISBAD(rgb(c=>0)) || $ISBAD(rgb(c=>1)) || $ISBAD(rgb(c=>2))) {
724             loop (c) %{ $SETBAD(out()); %}
725             }
726             else,) {
727             rgb2gamma( $P(rgb), $gamma(), $P(out) );
728             }
729             ',
730             Doc => <<'DOCUMENTATION',
731             =for ref
732              
733             Converts an RGB color triple (presumably linear) to an RGB color triple
734             with the specified gamma.
735              
736             =for usage
737              
738             Usage:
739              
740             my $gammaed = rgb_from_linear( $rgb_linear, 2.2 );
741             DOCUMENTATION
742             BadDoc => <
743             =for bad
744              
745             If C encounters a bad value in any of the R, G, or B
746             values the output ndarray will be marked as bad and the associated R,
747             G, and B values will all be marked as bad.
748             BADDOC
749             );
750              
751              
752             pp_addpm(<<'EOD');
753              
754              
755             =head2 rgb_to_xyz
756              
757             =for ref
758              
759             Converts an RGB color triple to an XYZ color triple.
760              
761             The first dimension of the ndarrays holding the rgb values must be size 3, i.e. the dimensions must look like (3, m, n, ...).
762              
763             =for bad
764              
765             If C encounters a bad value in any of the R, G, or B values the output ndarray will be marked as bad and the associated X, Y, and Z values will all be marked as bad.
766              
767             =for usage
768              
769             Usage:
770              
771             my $xyz = rgb_to_xyz( $rgb, 'sRGB' );
772             my $xyz = rgb_to_xyz( $rgb, \%rgb_spec );
773              
774             =cut
775              
776 10     10 0 276006 *rgb_to_xyz = \&PDL::rgb_to_xyz;
777 10         30 sub PDL::rgb_to_xyz {
778 10         26 my ($rgb, $space) = @_;
779 10         166 my $spec = get_space($space);
780             my $m = PDL->topdl( $spec->{m} );
781             return _rgb_to_xyz( $rgb, $spec->{gamma}, $m );
782             }
783              
784              
785             =head2 xyz_to_rgb
786              
787             =for ref
788              
789             Converts an XYZ color triple to an RGB color triple.
790              
791             The first dimension of the ndarrays holding the xyz and rgb values must be size 3, i.e. the dimensions must look like (3, m, n, ...).
792              
793             =for bad
794              
795             If C encounters a bad value in any of the X, Y, or Z values the output ndarray will be marked as bad and the associated R, G, and B values will all be marked as bad.
796              
797             =for usage
798              
799             Usage:
800              
801             my $rgb = xyz_to_rgb( $xyz, 'sRGB' );
802             my $rgb = xyz_to_rgb( $xyz, \%rgb_spec );
803              
804             =cut
805 5     5 0 8  
806 5         8 *xyz_to_rgb = \&PDL::xyz_to_rgb;
807 5 50       15 sub PDL::xyz_to_rgb {
808 5         78 my ($xyz, $space) = @_;
809             my $spec = get_space($space);
810             my $mstar = exists $spec->{mstar} ? PDL->topdl( $spec->{mstar} ) : PDL->topdl( $spec->{m} )->inv;
811             return _xyz_to_rgb( $xyz, $spec->{gamma}, $mstar );
812             }
813              
814              
815             =head2 xyz_to_lab
816              
817             =for ref
818              
819             Converts an XYZ color triple to an Lab color triple.
820              
821             The first dimension of the ndarrays holding the xyz values must be size 3, i.e. the dimensions must look like (3, m, n, ...).
822              
823             =for bad
824              
825             If C encounters a bad value in any of the X, Y, or Z values the output ndarray will be marked as bad and the associated L, a, and b values will all be marked as bad.
826              
827             =for usage
828              
829             Usage:
830              
831             my $lab = xyz_to_lab( $xyz, 'sRGB' );
832             my $lab = xyz_to_lab( $xyz, \%rgb_spec );
833              
834 8     8 0 889 =cut
835 8         11  
836 8         13 *xyz_to_lab = \&PDL::xyz_to_lab;
837 8         72 sub PDL::xyz_to_lab {
838             my ($xyz, $space) = @_;
839             my $spec = get_space($space);
840             my $w = PDL->topdl($spec->{white_point});
841             return _xyz_to_lab( $xyz, $w );
842             }
843              
844              
845             =head2 lab_to_xyz
846              
847             =for ref
848              
849             Converts an Lab color triple to an XYZ color triple.
850              
851             The first dimension of the ndarrays holding the lab values must be size 3, i.e. the dimensions must look like (3, m, n, ...).
852              
853             =for bad
854              
855             If C encounters a bad value in any of the L, a, or b values the output ndarray will be marked as bad and the associated X, Y, and Z values will all be marked as bad.
856              
857             =for usage
858              
859             Usage:
860              
861             my $xyz = lab_to_xyz( $lab, 'sRGB' );
862             my $xyz = lab_to_xyz( $lab, \%rgb_spec );
863 7     7 0 783  
864 7         12 =cut
865 7         17  
866 7         103 *lab_to_xyz = \&PDL::lab_to_xyz;
867             sub PDL::lab_to_xyz {
868             my ($lab, $space) = @_;
869             my $spec = get_space($space);
870             my $w = PDL->topdl($spec->{white_point});
871             return _lab_to_xyz( $lab, $w );
872             }
873              
874              
875             =head2 rgb_to_lch
876              
877             =for ref
878              
879             Converts an RGB color triple to an LCH color triple.
880              
881             The first dimension of the ndarrays holding the rgb values must be size 3, i.e. the dimensions must look like (3, m, n, ...).
882              
883             =for bad
884              
885             If C encounters a bad value in any of the R, G, or B values the output ndarray will be marked as bad and the associated L, C, and H values will all be marked as bad.
886              
887             =for usage
888              
889             Usage:
890              
891             my $lch = rgb_to_lch( $rgb, 'sRGB' );
892 4     4 0 2826 my $lch = rgb_to_lch( $rgb, \%rgb_spec );
893 4         9  
894 4         7 =cut
895 4         37  
896             *rgb_to_lch = \&PDL::rgb_to_lch;
897             sub PDL::rgb_to_lch {
898             my ($rgb, $space) = @_;
899             my $spec = get_space($space);
900             my $lab = xyz_to_lab( rgb_to_xyz( $rgb, $spec ), $spec );
901             return lab_to_lch( $lab );
902             }
903              
904              
905             =head2 lch_to_rgb
906              
907             =for ref
908              
909             Converts an LCH color triple to an RGB color triple.
910              
911             The first dimension of the ndarrays holding the lch values must be size 3, i.e. the dimensions must look like (3, m, n, ...).
912              
913             =for bad
914              
915             If C encounters a bad value in any of the L, C, or H values the output ndarray will be marked as bad and the associated R, G, and B values will all be marked as bad.
916              
917             =for usage
918              
919             Usage:
920              
921 2     2 0 804 my $rgb = lch_to_rgb( $lch, 'sRGB' );
922 2         5 my $rgb = lch_to_rgb( $lch, \%rgb_spec );
923 2         40  
924 2         7 =cut
925              
926             *lch_to_rgb = \&PDL::lch_to_rgb;
927             sub PDL::lch_to_rgb {
928             my ($lch, $space) = @_;
929             my $spec = get_space($space);
930             my $xyz = lab_to_xyz( lch_to_lab( $lch ), $spec );
931             return xyz_to_rgb( $xyz, $spec );
932             }
933              
934              
935             =head2 rgb_to_lab
936              
937             =for ref
938              
939             Converts an RGB color triple to an LAB color triple.
940              
941             The first dimension of the ndarrays holding the rgb values must be size 3, i.e. the dimensions must look like (3, m, n, ...).
942              
943             =for bad
944              
945             If C encounters a bad value in any of the R, G, or B values the output ndarray will be marked as bad and the associated L, A, and B values will all be marked as bad.
946              
947             =for usage
948              
949             Usage:
950 2     2 0 932  
951 2         6 my $lab = rgb_to_lab( $rgb, 'sRGB' );
952 2         4 my $lab = rgb_to_lab( $rgb, \%rgb_spec );
953              
954             =cut
955              
956             *rgb_to_lab = \&PDL::rgb_to_lab;
957             sub PDL::rgb_to_lab {
958             my ($rgb, $space) = @_;
959             my $spec = get_space($space);
960             return xyz_to_lab( rgb_to_xyz( $rgb, $spec ), $spec );
961             }
962              
963              
964             =head2 lab_to_rgb
965              
966             =for ref
967              
968             Converts an LAB color triple to an RGB color triple.
969              
970             The first dimension of the ndarrays holding the lab values must be size 3, i.e. the dimensions must look like (3, m, n, ...).
971              
972             =for bad
973              
974             If C encounters a bad value in any of the L, A, or B values the output ndarray will be marked as bad and the associated R, G, and B values will all be marked as bad.
975              
976             =for usage
977              
978 2     2 0 797 Usage:
979 2         6  
980 2         4 my $rgb = lab_to_rgb( $lab, 'sRGB' );
981             my $rgb = lab_to_rgb( $lab, \%rgb_spec );
982              
983             =cut
984              
985             *lab_to_rgb = \&PDL::lab_to_rgb;
986             sub PDL::lab_to_rgb {
987             my ($lab, $space) = @_;
988             my $spec = get_space($space);
989             return xyz_to_rgb( lab_to_xyz( $lab, $spec ), $spec );
990             }
991              
992              
993             =head2 add_rgb_space
994              
995             Supports adding custom RGB space definitions. The C and C
996             can be supplied as PDL ndarrays if desired. As of 0.202, you don't need
997             to provide an C since the inverse of the C will be calculated
998             (once) as a default.
999              
1000             Usage:
1001              
1002             my %custom_space = (
1003             custom_1 => {
1004             'gamma' => '2.2',
1005             'm' => [
1006             [
1007             '0.467384242424242',
1008             '0.240995',
1009             '0.0219086363636363'
1010             ],
1011             [
1012             '0.294454030769231',
1013             '0.683554',
1014             '0.0736135076923076'
1015             ],
1016             [
1017             '0.18863',
1018             '0.075452',
1019             '0.993451333333334'
1020             ]
1021             ],
1022             'white_point' => [
1023             '0.312713',
1024             '0.329016'
1025             ],
1026             },
1027             custom_2 => { ... },
1028             );
1029              
1030             add_rgb_space( \%custom_space );
1031              
1032             my $rgb = lch_to_rgb( $lch, 'custom_1' );
1033              
1034             =cut
1035              
1036             *add_rgb_space = \&PDL::Graphics::ColorSpace::RGBSpace::add_rgb_space;
1037             *get_space = \&PDL::Graphics::ColorSpace::RGBSpace::get_space;
1038              
1039              
1040             =head1 SEE ALSO
1041              
1042             Graphics::ColorObject
1043              
1044             =head1 AUTHOR
1045              
1046             ~~~~~~~~~~~~ ~~~~~ ~~~~~~~~ ~~~~~ ~~~ `` ><(((">
1047              
1048             Copyright (C) 2012 Maggie J. Xiong
1049              
1050             Original work sponsored by Shutterstock, LLC L
1051              
1052             All rights reserved. There is no warranty. You are allowed to redistribute this software / documentation as described in the file COPYING in the PDL distribution.
1053              
1054             =cut
1055              
1056             EOD
1057              
1058             pp_done();