MagickCore  7.1.1-43
Convert, Edit, Or Compose Bitmap Images
colorspace-private.h
1 /*
2  Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization
3  dedicated to making software imaging solutions freely available.
4 
5  You may not use this file except in compliance with the License. You may
6  obtain a copy of the License at
7 
8  https://imagemagick.org/script/license.php
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 
16  MagickCore image colorspace private methods.
17 */
18 #ifndef MAGICKCORE_COLORSPACE_PRIVATE_H
19 #define MAGICKCORE_COLORSPACE_PRIVATE_H
20 
21 #include "MagickCore/image.h"
22 #include "MagickCore/image-private.h"
23 #include "MagickCore/pixel.h"
24 #include "MagickCore/pixel-accessor.h"
25 
26 #define IlluminantX 0.95047
27 #define IlluminantY 1.0
28 #define IlluminantZ 1.08883
29 #define CIEEpsilon (216.0/24389.0)
30 #define CIEK (24389.0/27.0)
31 
32 static const PrimaryInfo
33  illuminant_tristimulus[] =
34  {
35  { 1.09850, 1.00000, 0.35585 }, /* A */
36  { 0.99072, 1.00000, 0.85223 }, /* B */
37  { 0.98074, 1.00000, 1.18232 }, /* C */
38  { 0.96422, 1.00000, 0.82521 }, /* D50 */
39  { 0.95682, 1.00000, 0.92149 }, /* D55 */
40  { 0.95047, 1.00000, 1.08883 }, /* D65 */
41  { 0.94972, 1.00000, 1.22638 }, /* D75 */
42  { 1.00000, 1.00000, 1.00000 }, /* E */
43  { 0.99186, 1.00000, 0.67393 }, /* F2 */
44  { 0.95041, 1.00000, 1.08747 }, /* F7 */
45  { 1.00962, 1.00000, 0.64350 } /* F11 */
46  };
47 
48 #if defined(__cplusplus) || defined(c_plusplus)
49 extern "C" {
50 #endif
51 
52 
53 static inline void ConvertAdobe98ToXYZ(const double red,const double green,
54  const double blue,double *X,double *Y,double *Z)
55 {
56  double
57  b,
58  g,
59  r;
60 
61  /*
62  Convert Adobe '98 to XYZ colorspace.
63  */
64  r=QuantumScale*DecodePixelGamma((double) QuantumRange*red);
65  g=QuantumScale*DecodePixelGamma((double) QuantumRange*green);
66  b=QuantumScale*DecodePixelGamma((double) QuantumRange*blue);
67  *X=0.57666904291013050*r+0.18555823790654630*g+0.18822864623499470*b;
68  *Y=0.29734497525053605*r+0.62736356625546610*g+0.07529145849399788*b;
69  *Z=0.02703136138641234*r+0.07068885253582723*g+0.99133753683763880*b;
70 }
71 
72 static inline void ConvertXYZToRGB(const double X,const double Y,const double Z,
73  double *red,double *green,double *blue)
74 {
75  double
76  b,
77  g,
78  r;
79 
80  r=3.2404542*X-1.5371385*Y-0.4985314*Z;
81  g=(-0.9692660)*X+1.8760108*Y+0.0415560*Z;
82  b=0.0556434*X-0.2040259*Y+1.0572252*Z;
83  *red=EncodePixelGamma((double) QuantumRange*r);
84  *green=EncodePixelGamma((double) QuantumRange*g);
85  *blue=EncodePixelGamma((double) QuantumRange*b);
86 }
87 
88 static inline void ConvertAdobe98ToRGB(const double r,const double g,
89  const double b,double *red,double *green,double *blue)
90 {
91  double
92  X,
93  Y,
94  Z;
95 
96  ConvertAdobe98ToXYZ(r,g,b,&X,&Y,&Z);
97  ConvertXYZToRGB(X,Y,Z,red,green,blue);
98 }
99 
100 static inline void ConvertCMYKToRGB(PixelInfo *pixel)
101 {
102  pixel->red=(((double) QuantumRange-(QuantumScale*pixel->red*
103  ((double) QuantumRange-pixel->black)+pixel->black)));
104  pixel->green=(((double) QuantumRange-(QuantumScale*pixel->green*
105  ((double) QuantumRange-pixel->black)+pixel->black)));
106  pixel->blue=(((double) QuantumRange-(QuantumScale*pixel->blue*
107  ((double) QuantumRange-pixel->black)+pixel->black)));
108 }
109 
110 static inline void ConvertCMYToRGB(const double cyan,const double magenta,
111  const double yellow,double *red,double *green,double *blue)
112 {
113  *red=(double) QuantumRange*(1.0-cyan);
114  *green=(double) QuantumRange*(1.0-magenta);
115  *blue=(double) QuantumRange*(1.0-yellow);
116 }
117 
118 static inline void ConvertHCLToRGB(const double hue,const double chroma,
119  const double luma,double *red,double *green,double *blue)
120 {
121  double
122  b,
123  c,
124  g,
125  h,
126  m,
127  r,
128  x;
129 
130  /*
131  Convert HCL to RGB colorspace.
132  */
133  assert(red != (double *) NULL);
134  assert(green != (double *) NULL);
135  assert(blue != (double *) NULL);
136  h=6.0*hue;
137  c=chroma;
138  x=c*(1.0-fabs(fmod(h,2.0)-1.0));
139  r=0.0;
140  g=0.0;
141  b=0.0;
142  if ((0.0 <= h) && (h < 1.0))
143  {
144  r=c;
145  g=x;
146  }
147  else
148  if ((1.0 <= h) && (h < 2.0))
149  {
150  r=x;
151  g=c;
152  }
153  else
154  if ((2.0 <= h) && (h < 3.0))
155  {
156  g=c;
157  b=x;
158  }
159  else
160  if ((3.0 <= h) && (h < 4.0))
161  {
162  g=x;
163  b=c;
164  }
165  else
166  if ((4.0 <= h) && (h < 5.0))
167  {
168  r=x;
169  b=c;
170  }
171  else
172  if ((5.0 <= h) && (h < 6.0))
173  {
174  r=c;
175  b=x;
176  }
177  m=luma-(0.298839*r+0.586811*g+0.114350*b);
178  *red=(double) QuantumRange*(r+m);
179  *green=(double) QuantumRange*(g+m);
180  *blue=(double) QuantumRange*(b+m);
181 }
182 
183 static inline void ConvertHCLpToRGB(const double hue,const double chroma,
184  const double luma,double *red,double *green,double *blue)
185 {
186  double
187  b,
188  c,
189  g,
190  h,
191  m,
192  r,
193  x,
194  z;
195 
196  /*
197  Convert HCLp to RGB colorspace.
198  */
199  assert(red != (double *) NULL);
200  assert(green != (double *) NULL);
201  assert(blue != (double *) NULL);
202  h=6.0*hue;
203  c=chroma;
204  x=c*(1.0-fabs(fmod(h,2.0)-1.0));
205  r=0.0;
206  g=0.0;
207  b=0.0;
208  if ((0.0 <= h) && (h < 1.0))
209  {
210  r=c;
211  g=x;
212  }
213  else
214  if ((1.0 <= h) && (h < 2.0))
215  {
216  r=x;
217  g=c;
218  }
219  else
220  if ((2.0 <= h) && (h < 3.0))
221  {
222  g=c;
223  b=x;
224  }
225  else
226  if ((3.0 <= h) && (h < 4.0))
227  {
228  g=x;
229  b=c;
230  }
231  else
232  if ((4.0 <= h) && (h < 5.0))
233  {
234  r=x;
235  b=c;
236  }
237  else
238  if ((5.0 <= h) && (h < 6.0))
239  {
240  r=c;
241  b=x;
242  }
243  m=luma-(0.298839*r+0.586811*g+0.114350*b);
244  z=1.0;
245  if (m < 0.0)
246  {
247  z=luma/(luma-m);
248  m=0.0;
249  }
250  else
251  if (m+c > 1.0)
252  {
253  z=(1.0-luma)/(m+c-luma);
254  m=1.0-z*c;
255  }
256  *red=(double) QuantumRange*(z*r+m);
257  *green=(double) QuantumRange*(z*g+m);
258  *blue=(double) QuantumRange*(z*b+m);
259 }
260 
261 static inline void ConvertHSBToRGB(const double hue,const double saturation,
262  const double brightness,double *red,double *green,double *blue)
263 {
264  double
265  f,
266  h,
267  p,
268  q,
269  t;
270 
271  /*
272  Convert HSB to RGB colorspace.
273  */
274  assert(red != (double *) NULL);
275  assert(green != (double *) NULL);
276  assert(blue != (double *) NULL);
277  if (fabs(saturation) < MagickEpsilon)
278  {
279  *red=(double) QuantumRange*brightness;
280  *green=(*red);
281  *blue=(*red);
282  return;
283  }
284  h=6.0*(hue-floor(hue));
285  f=h-floor((double) h);
286  p=brightness*(1.0-saturation);
287  q=brightness*(1.0-saturation*f);
288  t=brightness*(1.0-(saturation*(1.0-f)));
289  switch ((int) h)
290  {
291  case 0:
292  default:
293  {
294  *red=(double) QuantumRange*brightness;
295  *green=(double) QuantumRange*t;
296  *blue=(double) QuantumRange*p;
297  break;
298  }
299  case 1:
300  {
301  *red=(double) QuantumRange*q;
302  *green=(double) QuantumRange*brightness;
303  *blue=(double) QuantumRange*p;
304  break;
305  }
306  case 2:
307  {
308  *red=(double) QuantumRange*p;
309  *green=(double) QuantumRange*brightness;
310  *blue=(double) QuantumRange*t;
311  break;
312  }
313  case 3:
314  {
315  *red=(double) QuantumRange*p;
316  *green=(double) QuantumRange*q;
317  *blue=(double) QuantumRange*brightness;
318  break;
319  }
320  case 4:
321  {
322  *red=(double) QuantumRange*t;
323  *green=(double) QuantumRange*p;
324  *blue=(double) QuantumRange*brightness;
325  break;
326  }
327  case 5:
328  {
329  *red=(double) QuantumRange*brightness;
330  *green=(double) QuantumRange*p;
331  *blue=(double) QuantumRange*q;
332  break;
333  }
334  }
335 }
336 
337 static inline void ConvertHSIToRGB(const double hue,const double saturation,
338  const double intensity,double *red,double *green,double *blue)
339 {
340  double
341  b,
342  g,
343  h,
344  r;
345 
346  /*
347  Convert HSI to RGB colorspace.
348  */
349  assert(red != (double *) NULL);
350  assert(green != (double *) NULL);
351  assert(blue != (double *) NULL);
352  h=360.0*hue;
353  h-=360.0*floor(h/360.0);
354  if (h < 120.0)
355  {
356  b=intensity*(1.0-saturation);
357  r=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
358  (MagickPI/180.0)));
359  g=3.0*intensity-r-b;
360  }
361  else
362  if (h < 240.0)
363  {
364  h-=120.0;
365  r=intensity*(1.0-saturation);
366  g=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
367  (MagickPI/180.0)));
368  b=3.0*intensity-r-g;
369  }
370  else
371  {
372  h-=240.0;
373  g=intensity*(1.0-saturation);
374  b=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
375  (MagickPI/180.0)));
376  r=3.0*intensity-g-b;
377  }
378  *red=(double) QuantumRange*r;
379  *green=(double) QuantumRange*g;
380  *blue=(double) QuantumRange*b;
381 }
382 
383 static inline void ConvertHSVToRGB(const double hue,const double saturation,
384  const double value,double *red,double *green,double *blue)
385 {
386  double
387  c,
388  h,
389  min,
390  x;
391 
392  /*
393  Convert HSV to RGB colorspace.
394  */
395  assert(red != (double *) NULL);
396  assert(green != (double *) NULL);
397  assert(blue != (double *) NULL);
398  h=hue*360.0;
399  c=value*saturation;
400  min=value-c;
401  h-=360.0*floor(h/360.0);
402  h/=60.0;
403  x=c*(1.0-fabs(h-2.0*floor(h/2.0)-1.0));
404  switch ((int) floor(h))
405  {
406  case 0:
407  default:
408  {
409  *red=(double) QuantumRange*(min+c);
410  *green=(double) QuantumRange*(min+x);
411  *blue=(double) QuantumRange*min;
412  break;
413  }
414  case 1:
415  {
416  *red=(double) QuantumRange*(min+x);
417  *green=(double) QuantumRange*(min+c);
418  *blue=(double) QuantumRange*min;
419  break;
420  }
421  case 2:
422  {
423  *red=(double) QuantumRange*min;
424  *green=(double) QuantumRange*(min+c);
425  *blue=(double) QuantumRange*(min+x);
426  break;
427  }
428  case 3:
429  {
430  *red=(double) QuantumRange*min;
431  *green=(double) QuantumRange*(min+x);
432  *blue=(double) QuantumRange*(min+c);
433  break;
434  }
435  case 4:
436  {
437  *red=(double) QuantumRange*(min+x);
438  *green=(double) QuantumRange*min;
439  *blue=(double) QuantumRange*(min+c);
440  break;
441  }
442  case 5:
443  {
444  *red=(double) QuantumRange*(min+c);
445  *green=(double) QuantumRange*min;
446  *blue=(double) QuantumRange*(min+x);
447  break;
448  }
449  }
450 }
451 
452 static inline void ConvertHWBToRGB(const double hue,const double whiteness,
453  const double blackness,double *red,double *green,double *blue)
454 {
455  double
456  b,
457  f,
458  g,
459  n,
460  r,
461  v;
462 
463  ssize_t
464  i;
465 
466  /*
467  Convert HWB to RGB colorspace.
468  */
469  assert(red != (double *) NULL);
470  assert(green != (double *) NULL);
471  assert(blue != (double *) NULL);
472  v=1.0-blackness;
473  if (fabs(hue-(-1.0)) < MagickEpsilon)
474  {
475  *red=(double) QuantumRange*v;
476  *green=(double) QuantumRange*v;
477  *blue=(double) QuantumRange*v;
478  return;
479  }
480  i=CastDoubleToLong(floor(6.0*hue));
481  f=6.0*hue-i;
482  if ((i & 0x01) != 0)
483  f=1.0-f;
484  n=whiteness+f*(v-whiteness); /* linear interpolation */
485  switch (i)
486  {
487  case 0:
488  default: r=v; g=n; b=whiteness; break;
489  case 1: r=n; g=v; b=whiteness; break;
490  case 2: r=whiteness; g=v; b=n; break;
491  case 3: r=whiteness; g=n; b=v; break;
492  case 4: r=n; g=whiteness; b=v; break;
493  case 5: r=v; g=whiteness; b=n; break;
494  }
495  *red=(double) QuantumRange*r;
496  *green=(double) QuantumRange*g;
497  *blue=(double) QuantumRange*b;
498 }
499 
500 static inline void ConvertLabToXYZ(const double L,const double a,const double b,
501  const IlluminantType illuminant,double *X,double *Y,double *Z)
502 {
503  double
504  x,
505  y,
506  z;
507 
508  y=(L+16.0)/116.0;
509  x=y+a/500.0;
510  z=y-b/200.0;
511  if ((x*x*x) > CIEEpsilon)
512  x=(x*x*x);
513  else
514  x=(116.0*x-16.0)/CIEK;
515  if (L > (CIEK*CIEEpsilon))
516  y=(y*y*y);
517  else
518  y=L/CIEK;
519  if ((z*z*z) > CIEEpsilon)
520  z=(z*z*z);
521  else
522  z=(116.0*z-16.0)/CIEK;
523  *X=illuminant_tristimulus[illuminant].x*x;
524  *Y=illuminant_tristimulus[illuminant].y*y;
525  *Z=illuminant_tristimulus[illuminant].z*z;
526 }
527 
528 static inline void ConvertLabToRGB(const double L,const double a,
529  const double b,const IlluminantType illuminant,double *red,double *green,
530  double *blue)
531 {
532  double
533  X,
534  Y,
535  Z;
536 
537  ConvertLabToXYZ(100.0*L,255.0*(a-0.5),255.0*(b-0.5),illuminant,&X,&Y,&Z);
538  ConvertXYZToRGB(X,Y,Z,red,green,blue);
539 }
540 
541 static inline void ConvertLCHabToXYZ(const double luma,const double chroma,
542  const double hue,const IlluminantType illuminant,double *X,double *Y,
543  double *Z)
544 {
545  ConvertLabToXYZ(luma,chroma*cos(DegreesToRadians(hue)),chroma*
546  sin(DegreesToRadians(hue)),illuminant,X,Y,Z);
547 }
548 
549 static inline void ConvertLCHabToRGB(const double luma,const double chroma,
550  const double hue,const IlluminantType illuminant,double *red,double *green,
551  double *blue)
552 {
553  double
554  X,
555  Y,
556  Z;
557 
558  /*
559  Convert LCHab to RGB colorspace.
560  */
561  assert(red != (double *) NULL);
562  assert(green != (double *) NULL);
563  assert(blue != (double *) NULL);
564  ConvertLCHabToXYZ(100.0*luma,255.0*(chroma-0.5),360.0*hue,illuminant,
565  &X,&Y,&Z);
566  ConvertXYZToRGB(X,Y,Z,red,green,blue);
567 }
568 
569 static inline void ConvertLuvToXYZ(const double L,const double u,const double v,
570  const IlluminantType illuminant,double *X,double *Y,double *Z)
571 {
572  double
573  gamma;
574 
575  if (L > (CIEK*CIEEpsilon))
576  *Y=(double) pow((L+16.0)/116.0,3.0);
577  else
578  *Y=L/CIEK;
579  gamma=PerceptibleReciprocal((((52.0*L*PerceptibleReciprocal(u+13.0*L*
580  (4.0*illuminant_tristimulus[illuminant].x/
581  (illuminant_tristimulus[illuminant].x+15.0*
582  illuminant_tristimulus[illuminant].y+3.0*
583  illuminant_tristimulus[illuminant].z))))-1.0)/3.0)-(-1.0/3.0));
584  *X=gamma*((*Y*((39.0*L*PerceptibleReciprocal(v+13.0*L*(9.0*
585  illuminant_tristimulus[illuminant].y/
586  (illuminant_tristimulus[illuminant].x+15.0*
587  illuminant_tristimulus[illuminant].y+3.0*
588  illuminant_tristimulus[illuminant].z))))-5.0))+5.0*(*Y));
589  *Z=(*X*(((52.0*L*PerceptibleReciprocal(u+13.0*L*(4.0*
590  illuminant_tristimulus[illuminant].x/
591  (illuminant_tristimulus[illuminant].x+15.0*
592  illuminant_tristimulus[illuminant].y+3.0*
593  illuminant_tristimulus[illuminant].z))))-1.0)/3.0))-5.0*(*Y);
594 }
595 
596 static inline void ConvertLCHuvToXYZ(const double luma,const double chroma,
597  const double hue,const IlluminantType illuminant,double *X,double *Y,
598  double *Z)
599 {
600  ConvertLuvToXYZ(luma,chroma*cos(DegreesToRadians(hue)),chroma*
601  sin(DegreesToRadians(hue)),illuminant,X,Y,Z);
602 }
603 
604 static inline void ConvertLCHuvToRGB(const double luma,const double chroma,
605  const double hue,const IlluminantType illuminant,double *red,double *green,
606  double *blue)
607 {
608  double
609  X,
610  Y,
611  Z;
612 
613  /*
614  Convert LCHuv to RGB colorspace.
615  */
616  assert(red != (double *) NULL);
617  assert(green != (double *) NULL);
618  assert(blue != (double *) NULL);
619  ConvertLCHuvToXYZ(100.0*luma,255.0*(chroma-0.5),360.0*hue,illuminant,
620  &X,&Y,&Z);
621  ConvertXYZToRGB(X,Y,Z,red,green,blue);
622 }
623 
624 static inline void ConvertLMSToXYZ(const double L,const double M,const double S,
625  double *X,double *Y,double *Z)
626 {
627  *X=1.096123820835514*L-0.278869000218287*M+0.182745179382773*S;
628  *Y=0.454369041975359*L+0.473533154307412*M+0.072097803717229*S;
629  *Z=(-0.009627608738429)*L-0.005698031216113*M+1.015325639954543*S;
630 }
631 
632 static inline void ConvertLMSToRGB(const double L,const double M,
633  const double S,double *red,double *green,double *blue)
634 {
635  double
636  X,
637  Y,
638  Z;
639 
640  ConvertLMSToXYZ(L,M,S,&X,&Y,&Z);
641  ConvertXYZToRGB(X,Y,Z,red,green,blue);
642 }
643 
644 static inline void ConvertDisplayP3ToXYZ(const double red,const double green,
645  const double blue,double *X,double *Y,double *Z)
646 {
647  double
648  b,
649  g,
650  r;
651 
652  /*
653  Convert Display P3 to XYZ colorspace.
654  */
655  r=QuantumScale*DecodePixelGamma((double) QuantumRange*red);
656  g=QuantumScale*DecodePixelGamma((double) QuantumRange*green);
657  b=QuantumScale*DecodePixelGamma((double) QuantumRange*blue);
658  *X=0.4865709486482162*r+0.26566769316909306*g+0.1982172852343625*b;
659  *Y=0.2289745640697488*r+0.69173852183650640*g+0.0792869140937450*b;
660  *Z=0.0000000000000000*r+0.04511338185890264*g+1.0439443689009760*b;
661 }
662 
663 static inline void ConvertDisplayP3ToRGB(const double r,const double g,
664  const double b,double *red,double *green,double *blue)
665 {
666  double
667  X,
668  Y,
669  Z;
670 
671  ConvertDisplayP3ToXYZ(r,g,b,&X,&Y,&Z);
672  ConvertXYZToRGB(X,Y,Z,red,green,blue);
673 }
674 
675 static inline void ConvertLuvToRGB(const double L,const double u,
676  const double v,const IlluminantType illuminant,double *red,double *green,
677  double *blue)
678 {
679  double
680  X,
681  Y,
682  Z;
683 
684  ConvertLuvToXYZ(100.0*L,354.0*u-134.0,262.0*v-140.0,illuminant,&X,&Y,&Z);
685  ConvertXYZToRGB(X,Y,Z,red,green,blue);
686 }
687 
688 static inline void ConvertProPhotoToXYZ(const double red,const double green,
689  const double blue,double *X,double *Y,double *Z)
690 {
691  double
692  b,
693  g,
694  r;
695 
696  /*
697  Convert ProPhoto to XYZ colorspace.
698  */
699  r=QuantumScale*DecodePixelGamma((double) QuantumRange*red);
700  g=QuantumScale*DecodePixelGamma((double) QuantumRange*green);
701  b=QuantumScale*DecodePixelGamma((double) QuantumRange*blue);
702  *X=0.4865709486482162*r+0.26566769316909306*g+0.1982172852343625*b;
703  *X=0.7977604896723027*r+0.13518583717574031*g+0.03134934958152480000*b;
704  *Y=0.2880711282292934*r+0.71184321781010140*g+0.00008565396060525902*b;
705  *Z=0.0000000000000000*r+0.00000000000000000*g+0.82510460251046010000*b;
706 }
707 
708 static inline void ConvertProPhotoToRGB(const double r,const double g,
709  const double b,double *red,double *green,double *blue)
710 {
711  double
712  X,
713  Y,
714  Z;
715 
716  ConvertProPhotoToXYZ(r,g,b,&X,&Y,&Z);
717  ConvertXYZToRGB(X,Y,Z,red,green,blue);
718 }
719 
720 static inline void ConvertRGBToCMY(const double red,const double green,
721  const double blue,double *cyan,double *magenta,double *yellow)
722 {
723  *cyan=QuantumScale*((double) QuantumRange-red);
724  *magenta=QuantumScale*((double) QuantumRange-green);
725  *yellow=QuantumScale*((double) QuantumRange-blue);
726 }
727 
728 static inline void ConvertRGBToHCL(const double red,const double green,
729  const double blue,double *hue,double *chroma,double *luma)
730 {
731  double
732  c,
733  h,
734  max;
735 
736  /*
737  Convert RGB to HCL colorspace.
738  */
739  assert(hue != (double *) NULL);
740  assert(chroma != (double *) NULL);
741  assert(luma != (double *) NULL);
742  max=MagickMax(red,MagickMax(green,blue));
743  c=max-(double) MagickMin(red,MagickMin(green,blue));
744  h=0.0;
745  if (fabs(c) < MagickEpsilon)
746  h=0.0;
747  else
748  if (fabs(red-max) < MagickEpsilon)
749  h=fmod((green-blue)/c+6.0,6.0);
750  else
751  if (fabs(green-max) < MagickEpsilon)
752  h=((blue-red)/c)+2.0;
753  else
754  if (fabs(blue-max) < MagickEpsilon)
755  h=((red-green)/c)+4.0;
756  *hue=(h/6.0);
757  *chroma=QuantumScale*c;
758  *luma=QuantumScale*(0.298839*red+0.586811*green+0.114350*blue);
759 }
760 
761 static inline void ConvertRGBToHCLp(const double red,const double green,
762  const double blue,double *hue,double *chroma,double *luma)
763 {
764  double
765  c,
766  h,
767  max;
768 
769  /*
770  Convert RGB to HCL colorspace.
771  */
772  assert(hue != (double *) NULL);
773  assert(chroma != (double *) NULL);
774  assert(luma != (double *) NULL);
775  max=MagickMax(red,MagickMax(green,blue));
776  c=max-MagickMin(red,MagickMin(green,blue));
777  h=0.0;
778  if (fabs(c) < MagickEpsilon)
779  h=0.0;
780  else
781  if (fabs(red-max) < MagickEpsilon)
782  h=fmod((green-blue)/c+6.0,6.0);
783  else
784  if (fabs(green-max) < MagickEpsilon)
785  h=((blue-red)/c)+2.0;
786  else
787  if (fabs(blue-max) < MagickEpsilon)
788  h=((red-green)/c)+4.0;
789  *hue=(h/6.0);
790  *chroma=QuantumScale*c;
791  *luma=QuantumScale*(0.298839*red+0.586811*green+0.114350*blue);
792 }
793 
794 static inline void ConvertRGBToHSB(const double red,const double green,
795  const double blue,double *hue,double *saturation,double *brightness)
796 {
797  double
798  delta,
799  max,
800  min;
801 
802  /*
803  Convert RGB to HSB colorspace.
804  */
805  assert(hue != (double *) NULL);
806  assert(saturation != (double *) NULL);
807  assert(brightness != (double *) NULL);
808  *hue=0.0;
809  *saturation=0.0;
810  *brightness=0.0;
811  min=red < green ? red : green;
812  if (blue < min)
813  min=blue;
814  max=red > green ? red : green;
815  if (blue > max)
816  max=blue;
817  if (fabs(max) < MagickEpsilon)
818  return;
819  delta=max-min;
820  *saturation=delta/max;
821  *brightness=QuantumScale*max;
822  if (fabs(delta) < MagickEpsilon)
823  return;
824  if (fabs(red-max) < MagickEpsilon)
825  *hue=(green-blue)/delta;
826  else
827  if (fabs(green-max) < MagickEpsilon)
828  *hue=2.0+(blue-red)/delta;
829  else
830  *hue=4.0+(red-green)/delta;
831  *hue/=6.0;
832  if (*hue < 0.0)
833  *hue+=1.0;
834 }
835 
836 static inline void ConvertRGBToHSI(const double red,const double green,
837  const double blue,double *hue,double *saturation,double *intensity)
838 {
839  double
840  alpha,
841  beta;
842 
843  /*
844  Convert RGB to HSI colorspace.
845  */
846  assert(hue != (double *) NULL);
847  assert(saturation != (double *) NULL);
848  assert(intensity != (double *) NULL);
849  *intensity=(QuantumScale*red+QuantumScale*green+QuantumScale*blue)/3.0;
850  if (*intensity <= 0.0)
851  {
852  *hue=0.0;
853  *saturation=0.0;
854  return;
855  }
856  *saturation=1.0-MagickMin(QuantumScale*red,MagickMin(QuantumScale*green,
857  QuantumScale*blue))/(*intensity);
858  alpha=0.5*(2.0*QuantumScale*red-QuantumScale*green-QuantumScale*blue);
859  beta=0.8660254037844385*(QuantumScale*green-QuantumScale*blue);
860  *hue=atan2(beta,alpha)*(180.0/MagickPI)/360.0;
861  if (*hue < 0.0)
862  *hue+=1.0;
863 }
864 
865 static inline void ConvertRGBToXYZ(const double red,const double green,
866  const double blue,double *X,double *Y,double *Z)
867 {
868  double
869  b,
870  g,
871  r;
872 
873  /*
874  Convert RGB to XYZ colorspace.
875  */
876  r=QuantumScale*DecodePixelGamma(red);
877  g=QuantumScale*DecodePixelGamma(green);
878  b=QuantumScale*DecodePixelGamma(blue);
879  *X=0.4124564*r+0.3575761*g+0.1804375*b;
880  *Y=0.2126729*r+0.7151522*g+0.0721750*b;
881  *Z=0.0193339*r+0.1191920*g+0.9503041*b;
882 }
883 
884 static inline void ConvertXYZToAdobe98(const double X,const double Y,
885  const double Z,double *red,double *green,double *blue)
886 {
887  double
888  b,
889  g,
890  r;
891 
892  r=2.041587903810746500*X-0.56500697427885960*Y-0.34473135077832956*Z;
893  g=(-0.969243636280879500)*X+1.87596750150772020*Y+0.04155505740717557*Z;
894  b=0.013444280632031142*X-0.11836239223101838*Y+1.01517499439120540*Z;
895  *red=QuantumScale*EncodePixelGamma((double) QuantumRange*r);
896  *green=QuantumScale*EncodePixelGamma((double) QuantumRange*g);
897  *blue=QuantumScale*EncodePixelGamma((double) QuantumRange*b);
898 }
899 
900 static inline void ConvertRGBToAdobe98(const double red,const double green,
901  const double blue,double *r,double *g,double *b)
902 {
903  double
904  X,
905  Y,
906  Z;
907 
908  ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
909  ConvertXYZToAdobe98(X,Y,Z,r,g,b);
910 }
911 
912 static inline void ConvertXYZToDisplayP3(const double X,const double Y,
913  const double Z,double *red,double *green,double *blue)
914 {
915  double
916  b,
917  g,
918  r;
919 
920  r=2.49349691194142500*X-0.93138361791912390*Y-0.402710784450716840*Z;
921  g=(-0.82948896956157470)*X+1.76266406031834630*Y+0.023624685841943577*Z;
922  b=0.03584583024378447*X-0.07617238926804182*Y+0.956884524007687200*Z;
923  *red=QuantumScale*EncodePixelGamma((double) QuantumRange*r);
924  *green=QuantumScale*EncodePixelGamma((double) QuantumRange*g);
925  *blue=QuantumScale*EncodePixelGamma((double) QuantumRange*b);
926 }
927 
928 static inline void ConvertRGBToDisplayP3(const double red,const double green,
929  const double blue,double *r,double *g,double *b)
930 {
931  double
932  X,
933  Y,
934  Z;
935 
936  ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
937  ConvertXYZToDisplayP3(X,Y,Z,r,g,b);
938 }
939 
940 static inline void ConvertRGBToHSV(const double red,const double green,
941  const double blue,double *hue,double *saturation,double *value)
942 {
943  double
944  c,
945  max,
946  min;
947 
948  /*
949  Convert RGB to HSV colorspace.
950  */
951  assert(hue != (double *) NULL);
952  assert(saturation != (double *) NULL);
953  assert(value != (double *) NULL);
954  max=MagickMax(QuantumScale*red,MagickMax(QuantumScale*green,
955  QuantumScale*blue));
956  min=MagickMin(QuantumScale*red,MagickMin(QuantumScale*green,
957  QuantumScale*blue));
958  c=max-min;
959  *value=max;
960  if (c <= 0.0)
961  {
962  *hue=0.0;
963  *saturation=0.0;
964  return;
965  }
966  if (fabs(max-QuantumScale*red) < MagickEpsilon)
967  {
968  *hue=(QuantumScale*green-QuantumScale*blue)/c;
969  if ((QuantumScale*green) < (QuantumScale*blue))
970  *hue+=6.0;
971  }
972  else
973  if (fabs(max-QuantumScale*green) < MagickEpsilon)
974  *hue=2.0+(QuantumScale*blue-QuantumScale*red)/c;
975  else
976  *hue=4.0+(QuantumScale*red-QuantumScale*green)/c;
977  *hue*=60.0/360.0;
978  *saturation=c*PerceptibleReciprocal(max);
979 }
980 
981 static inline void ConvertRGBToHWB(const double red,const double green,
982  const double blue,double *hue,double *whiteness,double *blackness)
983 {
984  double
985  f,
986  p,
987  v,
988  w;
989 
990  /*
991  Convert RGB to HWB colorspace.
992  */
993  assert(hue != (double *) NULL);
994  assert(whiteness != (double *) NULL);
995  assert(blackness != (double *) NULL);
996  w=MagickMin(red,MagickMin(green,blue));
997  v=MagickMax(red,MagickMax(green,blue));
998  *blackness=1.0-QuantumScale*v;
999  *whiteness=QuantumScale*w;
1000  if (fabs(v-w) < MagickEpsilon)
1001  {
1002  *hue=(-1.0);
1003  return;
1004  }
1005  f=(fabs(red-w) < MagickEpsilon) ? green-blue :
1006  ((fabs(green-w) < MagickEpsilon) ? blue-red : red-green);
1007  p=(fabs(red-w) < MagickEpsilon) ? 3.0 :
1008  ((fabs(green-w) < MagickEpsilon) ? 5.0 : 1.0);
1009  *hue=(p-f/(v-1.0*w))/6.0;
1010 }
1011 
1012 static inline void ConvertXYZToLab(const double X,const double Y,const double Z,
1013  const IlluminantType illuminant,double *L,double *a,double *b)
1014 {
1015  double
1016  x,
1017  y,
1018  z;
1019 
1020  if ((X/illuminant_tristimulus[illuminant].x) > CIEEpsilon)
1021  x=pow(X/illuminant_tristimulus[illuminant].x,1.0/3.0);
1022  else
1023  x=(CIEK*X/illuminant_tristimulus[illuminant].x+16.0)/116.0;
1024  if ((Y/illuminant_tristimulus[illuminant].y) > CIEEpsilon)
1025  y=pow(Y/illuminant_tristimulus[illuminant].y,1.0/3.0);
1026  else
1027  y=(CIEK*Y/illuminant_tristimulus[illuminant].y+16.0)/116.0;
1028  if ((Z/illuminant_tristimulus[illuminant].z) > CIEEpsilon)
1029  z=pow(Z/illuminant_tristimulus[illuminant].z,1.0/3.0);
1030  else
1031  z=(CIEK*Z/illuminant_tristimulus[illuminant].z+16.0)/116.0;
1032  *L=((116.0*y)-16.0)/100.0;
1033  *a=(500.0*(x-y))/255.0+0.5;
1034  *b=(200.0*(y-z))/255.0+0.5;
1035 }
1036 
1037 static inline void ConvertRGBToLab(const double red,const double green,
1038  const double blue,const IlluminantType illuminant,double *L,double *a,
1039  double *b)
1040 {
1041  double
1042  X,
1043  Y,
1044  Z;
1045 
1046  ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
1047  ConvertXYZToLab(X,Y,Z,illuminant,L,a,b);
1048 }
1049 
1050 static inline void ConvertXYZToLCHab(const double X,const double Y,
1051  const double Z,const IlluminantType illuminant,double *luma,double *chroma,
1052  double *hue)
1053 {
1054  double
1055  a,
1056  b;
1057 
1058  ConvertXYZToLab(X,Y,Z,illuminant,luma,&a,&b);
1059  *chroma=hypot(a-0.5,b-0.5)/1.0+0.5;
1060  *hue=180.0*atan2(b-0.5,a-0.5)/MagickPI/360.0;
1061  if (*hue < 0.0)
1062  *hue+=1.0;
1063 }
1064 
1065 static inline void ConvertRGBToLCHab(const double red,const double green,
1066  const double blue,const IlluminantType illuminant,double *luma,double *chroma,
1067  double *hue)
1068 {
1069  double
1070  X,
1071  Y,
1072  Z;
1073 
1074  /*
1075  Convert RGB to LCHab colorspace.
1076  */
1077  assert(luma != (double *) NULL);
1078  assert(chroma != (double *) NULL);
1079  assert(hue != (double *) NULL);
1080  ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
1081  ConvertXYZToLCHab(X,Y,Z,illuminant,luma,chroma,hue);
1082 }
1083 
1084 static inline void ConvertXYZToLuv(const double X,const double Y,const double Z,
1085  const IlluminantType illuminant,double *L,double *u,double *v)
1086 {
1087  double
1088  alpha;
1089 
1090  if ((Y/illuminant_tristimulus[illuminant].y) > CIEEpsilon)
1091  *L=(double) (116.0*pow(Y/illuminant_tristimulus[illuminant].y,
1092  1.0/3.0)-16.0);
1093  else
1094  *L=CIEK*(Y/illuminant_tristimulus[illuminant].y);
1095  alpha=PerceptibleReciprocal(X+15.0*Y+3.0*Z);
1096  *u=13.0*(*L)*((4.0*alpha*X)-(4.0*illuminant_tristimulus[illuminant].x/
1097  (illuminant_tristimulus[illuminant].x+15.0*
1098  illuminant_tristimulus[illuminant].y+3.0*
1099  illuminant_tristimulus[illuminant].z)));
1100  *v=13.0*(*L)*((9.0*alpha*Y)-(9.0*illuminant_tristimulus[illuminant].y/
1101  (illuminant_tristimulus[illuminant].x+15.0*
1102  illuminant_tristimulus[illuminant].y+3.0*
1103  illuminant_tristimulus[illuminant].z)));
1104  *L/=100.0;
1105  *u=(*u+134.0)/354.0;
1106  *v=(*v+140.0)/262.0;
1107 }
1108 
1109 static inline void ConvertXYZToLCHuv(const double X,const double Y,
1110  const double Z,const IlluminantType illuminant,double *luma,double *chroma,
1111  double *hue)
1112 {
1113  double
1114  u,
1115  v;
1116 
1117  ConvertXYZToLuv(X,Y,Z,illuminant,luma,&u,&v);
1118  *chroma=hypot(354.0*u-134.0,262.0*v-140.0)/255.0+0.5;
1119  *hue=180.0*atan2(262.0*v-140.0,354.0*u-134.0)/MagickPI/360.0;
1120  if (*hue < 0.0)
1121  *hue+=1.0;
1122 }
1123 
1124 static inline void ConvertRGBToLCHuv(const double red,const double green,
1125  const double blue,const IlluminantType illuminant,double *luma,double *chroma,
1126  double *hue)
1127 {
1128  double
1129  X,
1130  Y,
1131  Z;
1132 
1133  /*
1134  Convert RGB to LCHuv colorspace.
1135  */
1136  assert(luma != (double *) NULL);
1137  assert(chroma != (double *) NULL);
1138  assert(hue != (double *) NULL);
1139  ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
1140  ConvertXYZToLCHuv(X,Y,Z,illuminant,luma,chroma,hue);
1141 }
1142 
1143 static inline void ConvertXYZToProPhoto(const double X,const double Y,
1144  const double Z,double *red,double *green,double *blue)
1145 {
1146  double
1147  b,
1148  g,
1149  r;
1150 
1151  r=1.3457989731028281*X-0.25558010007997534*Y-0.05110628506753401*Z;
1152  g=(-0.5446224939028347)*X+1.50823274131327810*Y+0.02053603239147973*Z;
1153  b=0.0000000000000000*X+0.0000000000000000*Y+1.21196754563894540*Z;
1154  *red=QuantumScale*EncodePixelGamma((double) QuantumRange*r);
1155  *green=QuantumScale*EncodePixelGamma((double) QuantumRange*g);
1156  *blue=QuantumScale*EncodePixelGamma((double) QuantumRange*b);
1157 }
1158 
1159 static inline void ConvertRGBToProPhoto(const double red,const double green,
1160  const double blue,double *r,double *g,double *b)
1161 {
1162  double
1163  X,
1164  Y,
1165  Z;
1166 
1167  ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
1168  ConvertXYZToProPhoto(X,Y,Z,r,g,b);
1169 }
1170 
1171 static inline void ConvertXYZToLMS(const double x,const double y,
1172  const double z,double *L,double *M,double *S)
1173 {
1174  *L=0.7328*x+0.4296*y-0.1624*z;
1175  *M=(-0.7036*x+1.6975*y+0.0061*z);
1176  *S=0.0030*x+0.0136*y+0.9834*z;
1177 }
1178 
1179 static inline void ConvertRGBToLMS(const double red,const double green,
1180  const double blue,double *L,double *M,double *S)
1181 {
1182  double
1183  X,
1184  Y,
1185  Z;
1186 
1187  ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
1188  ConvertXYZToLMS(X,Y,Z,L,M,S);
1189 }
1190 
1191 static inline void ConvertRGBToLuv(const double red,const double green,
1192  const double blue,const IlluminantType illuminant,double *L,double *u,
1193  double *v)
1194 {
1195  double
1196  X,
1197  Y,
1198  Z;
1199 
1200  ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
1201  ConvertXYZToLuv(X,Y,Z,illuminant,L,u,v);
1202 }
1203 
1204 static inline void ConvertRGBToxyY(const double red,const double green,
1205  const double blue,double *low_x,double *low_y,double *cap_Y)
1206 {
1207  double
1208  gamma,
1209  X,
1210  Y,
1211  Z;
1212 
1213  ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
1214  gamma=PerceptibleReciprocal(X+Y+Z);
1215  *low_x=gamma*X;
1216  *low_y=gamma*Y;
1217  *cap_Y=Y;
1218 }
1219 
1220 static inline void ConvertXYZToJzazbz(const double X,const double Y,
1221  const double Z,const double white_luminance,double *Jz,double *az,double *bz)
1222 {
1223 #define Jzazbz_b 1.15 /* https://observablehq.com/@jrus/jzazbz */
1224 #define Jzazbz_g 0.66
1225 #define Jzazbz_c1 (3424.0/4096.0)
1226 #define Jzazbz_c2 (2413.0/128.0)
1227 #define Jzazbz_c3 (2392.0/128.0)
1228 #define Jzazbz_n (2610.0/16384.0)
1229 #define Jzazbz_p (1.7*2523.0/32.0)
1230 #define Jzazbz_d (-0.56)
1231 #define Jzazbz_d0 (1.6295499532821566e-11)
1232 
1233  double
1234  gamma,
1235  Iz,
1236  L,
1237  Lp,
1238  M,
1239  Mp,
1240  S,
1241  Sp,
1242  Xp,
1243  Yp,
1244  Zp;
1245 
1246  Xp=(Jzazbz_b*X-(Jzazbz_b-1)*Z);
1247  Yp=(Jzazbz_g*Y-(Jzazbz_g-1)*X);
1248  Zp=Z;
1249  L=0.41478972*Xp+0.579999*Yp+0.0146480*Zp;
1250  M=(-0.2015100)*Xp+1.120649*Yp+0.0531008*Zp;
1251  S=(-0.0166008)*Xp+0.264800*Yp+0.6684799*Zp;
1252  gamma=pow(L*PerceptibleReciprocal(white_luminance),Jzazbz_n);
1253  Lp=pow((Jzazbz_c1+Jzazbz_c2*gamma)/(1.0+Jzazbz_c3*gamma),Jzazbz_p);
1254  gamma=pow(M*PerceptibleReciprocal(white_luminance),Jzazbz_n);
1255  Mp=pow((Jzazbz_c1+Jzazbz_c2*gamma)/(1.0+Jzazbz_c3*gamma),Jzazbz_p);
1256  gamma=pow(S*PerceptibleReciprocal(white_luminance),Jzazbz_n);
1257  Sp=pow((Jzazbz_c1+Jzazbz_c2*gamma)/(1.0+Jzazbz_c3*gamma),Jzazbz_p);
1258  Iz=0.5*Lp+0.5*Mp;
1259  *az=3.52400*Lp-4.066708*Mp+0.542708*Sp+0.5;
1260  *bz=0.199076*Lp+1.096799*Mp-1.295875*Sp+0.5;
1261  *Jz=((Jzazbz_d+1.0)*Iz)/(Jzazbz_d*Iz+1.0)-Jzazbz_d0;
1262 }
1263 
1264 static inline void ConvertJzazbzToXYZ(const double Jz,const double az,
1265  const double bz,const double white_luminance,double *X,double *Y,double *Z)
1266 {
1267  double
1268  azz,
1269  bzz,
1270  gamma,
1271  Iz,
1272  L,
1273  Lp,
1274  M,
1275  Mp,
1276  S,
1277  Sp,
1278  Xp,
1279  Yp,
1280  Zp;
1281 
1282  gamma=Jz+Jzazbz_d0;
1283  Iz=gamma/(Jzazbz_d-Jzazbz_d*gamma+1.0);
1284  azz=az-0.5;
1285  bzz=bz-0.5;
1286  Lp=Iz+0.138605043271539*azz+0.0580473161561189*bzz;
1287  Mp=Iz-0.138605043271539*azz-0.0580473161561189*bzz;
1288  Sp=Iz-0.0960192420263189*azz-0.811891896056039*bzz;
1289  gamma=pow(Lp,1.0/Jzazbz_p);
1290  L=white_luminance*pow((Jzazbz_c1-gamma)/(Jzazbz_c3*gamma-Jzazbz_c2),1.0/
1291  Jzazbz_n);
1292  gamma=pow(Mp,1.0/Jzazbz_p);
1293  M=white_luminance*pow((Jzazbz_c1-gamma)/(Jzazbz_c3*gamma-Jzazbz_c2),1.0/
1294  Jzazbz_n);
1295  gamma=pow(Sp,1.0/Jzazbz_p);
1296  S=white_luminance*pow((Jzazbz_c1-gamma)/(Jzazbz_c3*gamma-Jzazbz_c2),1.0/
1297  Jzazbz_n);
1298  Xp=1.92422643578761*L-1.00479231259537*M+0.037651404030618*S;
1299  Yp=0.350316762094999*L+0.726481193931655*M-0.065384422948085*S;
1300  Zp=(-0.0909828109828476)*L-0.312728290523074*M+1.52276656130526*S;
1301  *X=(Xp+(Jzazbz_b-1.0)*Zp)/Jzazbz_b;
1302  *Y=(Yp+(Jzazbz_g-1.0)**X)/Jzazbz_g;
1303  *Z=Zp;
1304 }
1305 
1306 static inline void ConvertRGBToJzazbz(const double red,const double green,
1307  const double blue,const double white_luminance,double *Jz,double *az,
1308  double *bz)
1309 {
1310  double
1311  X,
1312  Y,
1313  Z;
1314 
1315  ConvertRGBToXYZ(red,blue,green,&X,&Y,&Z);
1316  ConvertXYZToJzazbz(X,Y,Z,white_luminance,Jz,az,bz);
1317 }
1318 
1319 static inline void ConvertJzazbzToRGB(const double Jz,const double az,
1320  const double bz,const double white_luminance,double *red,double *green,
1321  double *blue)
1322 {
1323  double
1324  X,
1325  Y,
1326  Z;
1327 
1328  ConvertJzazbzToXYZ(Jz,az,bz,white_luminance,&X,&Y,&Z);
1329  ConvertXYZToRGB(X,Y,Z,red,blue,green);
1330 }
1331 
1332 static inline void ConvertOklabToRGB(const double L,const double a,
1333  const double b,double *red,double *green,double *blue)
1334 {
1335  double
1336  B,
1337  G,
1338  l,
1339  m,
1340  R,
1341  s;
1342 
1343  l=L+0.3963377774*(a-0.5)+0.2158037573*(b-0.5);
1344  m=L-0.1055613458*(a-0.5)-0.0638541728*(b-0.5);
1345  s=L-0.0894841775*(a-0.5)-1.2914855480*(b-0.5);
1346  l*=l*l;
1347  m*=m*m;
1348  s*=s*s;
1349  R=4.0767416621*l-3.3077115913*m+0.2309699292*s;
1350  G=(-1.2684380046)*l+2.6097574011*m-0.3413193965*s;
1351  B=(-0.0041960863)*l-0.7034186147*m+1.7076147010*s;
1352  *red=EncodePixelGamma((double) QuantumRange*R);
1353  *green=EncodePixelGamma((double) QuantumRange*G);
1354  *blue=EncodePixelGamma((double) QuantumRange*B);
1355 }
1356 
1357 static inline void ConvertRGBToOklab(const double red,const double green,
1358  const double blue,double *L,double *a,double *b)
1359 {
1360  double
1361  B,
1362  G,
1363  l,
1364  m,
1365  R,
1366  s;
1367 
1368  R=QuantumScale*DecodePixelGamma(red);
1369  G=QuantumScale*DecodePixelGamma(green);
1370  B=QuantumScale*DecodePixelGamma(blue);
1371  l=cbrt(0.4122214708*R+0.5363325363*G+0.0514459929*B);
1372  m=cbrt(0.2119034982*R+0.6806995451*G+0.1073969566*B);
1373  s=cbrt(0.0883024619*R+0.2817188376*G+0.6299787005*B);
1374  *L=0.2104542553*l+0.7936177850*m-0.0040720468*s;
1375  *a=1.9779984951*l-2.4285922050*m+0.4505937099*s+0.5;
1376  *b=0.0259040371*l+0.7827717662*m-0.8086757660*s+0.5;
1377 }
1378 
1379 static inline void ConvertOklchToRGB(const double L,const double C,
1380  const double h,double *red,double *green,double *blue)
1381 {
1382  double
1383  a,
1384  b;
1385 
1386  a=C*cos(2.0*MagickPI*h);
1387  b=C*sin(2.0*MagickPI*h);
1388  ConvertOklabToRGB(L,a,b,red,green,blue);
1389 }
1390 
1391 static inline void ConvertRGBToOklch(const double red,const double green,
1392  const double blue,double *L,double *C,double *h)
1393 {
1394  double
1395  a,
1396  b;
1397 
1398  ConvertRGBToOklab(red,green,blue,L,&a,&b);
1399  *C=sqrt(a*a+b*b);
1400  *h=0.5+0.5*atan2(-b,-a)/MagickPI;
1401 }
1402 
1403 static inline void ConvertRGBToYDbDr(const double red,const double green,
1404  const double blue,double *Y,double *Db,double *Dr)
1405 {
1406  *Y=QuantumScale*(0.298839*red+0.586811*green+0.114350*blue);
1407  *Db=QuantumScale*(-0.450*red-0.883*green+1.333*blue)+0.5;
1408  *Dr=QuantumScale*(-1.333*red+1.116*green+0.217*blue)+0.5;
1409 }
1410 
1411 static inline void ConvertRGBToYIQ(const double red,const double green,
1412  const double blue,double *Y,double *I,double *Q)
1413 {
1414  *Y=QuantumScale*(0.298839*red+0.586811*green+0.114350*blue);
1415  *I=QuantumScale*(0.595716*red-0.274453*green-0.321263*blue)+0.5;
1416  *Q=QuantumScale*(0.211456*red-0.522591*green+0.311135*blue)+0.5;
1417 }
1418 
1419 static inline void ConvertRGBToYPbPr(const double red,const double green,
1420  const double blue,double *Y,double *Pb,double *Pr)
1421 {
1422  *Y=QuantumScale*(0.298839*red+0.586811*green+0.114350*blue);
1423  *Pb=QuantumScale*((-0.1687367)*red-0.331264*green+0.5*blue)+0.5;
1424  *Pr=QuantumScale*(0.5*red-0.418688*green-0.081312*blue)+0.5;
1425 }
1426 
1427 static inline void ConvertRGBToYCbCr(const double red,const double green,
1428  const double blue,double *Y,double *Cb,double *Cr)
1429 {
1430  ConvertRGBToYPbPr(red,green,blue,Y,Cb,Cr);
1431 }
1432 
1433 static inline void ConvertRGBToYUV(const double red,const double green,
1434  const double blue,double *Y,double *U,double *V)
1435 {
1436  *Y=QuantumScale*(0.298839*red+0.586811*green+0.114350*blue);
1437  *U=QuantumScale*((-0.147)*red-0.289*green+0.436*blue)+0.5;
1438  *V=QuantumScale*(0.615*red-0.515*green-0.100*blue)+0.5;
1439 }
1440 
1441 static inline void ConvertRGBToCMYK(PixelInfo *pixel)
1442 {
1443  MagickRealType
1444  black,
1445  blue,
1446  cyan,
1447  green,
1448  magenta,
1449  red,
1450  yellow;
1451 
1452  if (pixel->colorspace != sRGBColorspace)
1453  {
1454  red=QuantumScale*pixel->red;
1455  green=QuantumScale*pixel->green;
1456  blue=QuantumScale*pixel->blue;
1457  }
1458  else
1459  {
1460  red=QuantumScale*DecodePixelGamma(pixel->red);
1461  green=QuantumScale*DecodePixelGamma(pixel->green);
1462  blue=QuantumScale*DecodePixelGamma(pixel->blue);
1463  }
1464  if ((fabs((double) red) < MagickEpsilon) &&
1465  (fabs((double) green) < MagickEpsilon) &&
1466  (fabs((double) blue) < MagickEpsilon))
1467  {
1468  pixel->black=(MagickRealType) QuantumRange;
1469  return;
1470  }
1471  cyan=(MagickRealType) (1.0-red);
1472  magenta=(MagickRealType) (1.0-green);
1473  yellow=(MagickRealType) (1.0-blue);
1474  black=cyan;
1475  if (magenta < black)
1476  black=magenta;
1477  if (yellow < black)
1478  black=yellow;
1479  cyan=(MagickRealType) (PerceptibleReciprocal(1.0-black)*(cyan-black));
1480  magenta=(MagickRealType) (PerceptibleReciprocal(1.0-black)*(magenta-black));
1481  yellow=(MagickRealType) (PerceptibleReciprocal(1.0-black)*(yellow-black));
1482  pixel->colorspace=CMYKColorspace;
1483  pixel->red=(MagickRealType) QuantumRange*cyan;
1484  pixel->green=(MagickRealType) QuantumRange*magenta;
1485  pixel->blue=(MagickRealType) QuantumRange*yellow;
1486  pixel->black=(MagickRealType) QuantumRange*black;
1487 }
1488 
1489 static inline void ConvertYPbPrToRGB(const double Y,const double Pb,
1490  const double Pr,double *red,double *green,double *blue)
1491 {
1492  *red=(double) QuantumRange*(0.99999999999914679361*Y-1.2188941887145875e-06*
1493  (Pb-0.5)+1.4019995886561440468*(Pr-0.5));
1494  *green=(double) QuantumRange*(0.99999975910502514331*Y-0.34413567816504303521*
1495  (Pb-0.5)-0.71413649331646789076*(Pr-0.5));
1496  *blue=(double) QuantumRange*(1.00000124040004623180*Y+1.77200006607230409200*
1497  (Pb-0.5)+2.1453384174593273e-06*(Pr-0.5));
1498 }
1499 
1500 static inline void ConvertYCbCrToRGB(const double Y,const double Cb,
1501  const double Cr,double *red,double *green,double *blue)
1502 {
1503  ConvertYPbPrToRGB(Y,Cb,Cr,red,green,blue);
1504 }
1505 
1506 static inline void ConvertYDbDrToRGB(const double Y,const double Db,
1507  const double Dr,double *red,double *green,double *blue)
1508 {
1509  *red=(double) QuantumRange*(Y+9.2303716147657e-05*(Db-0.5)-
1510  0.52591263066186533*(Dr-0.5));
1511  *green=(double) QuantumRange*(Y-0.12913289889050927*(Db-0.5)+
1512  0.26789932820759876*(Dr-0.5));
1513  *blue=(double) QuantumRange*(Y+0.66467905997895482*(Db-0.5)-
1514  7.9202543533108e-05*(Dr-0.5));
1515 }
1516 
1517 static inline void ConvertYIQToRGB(const double Y,const double I,const double Q,
1518  double *red,double *green,double *blue)
1519 {
1520  *red=(double) QuantumRange*(Y+0.9562957197589482261*(I-0.5)+
1521  0.6210244164652610754*(Q-0.5));
1522  *green=(double) QuantumRange*(Y-0.2721220993185104464*(I-0.5)-
1523  0.6473805968256950427*(Q-0.5));
1524  *blue=(double) QuantumRange*(Y-1.1069890167364901945*(I-0.5)+
1525  1.7046149983646481374*(Q-0.5));
1526 }
1527 
1528 static inline void ConvertxyYToRGB(const double low_x,const double low_y,
1529  const double cap_Y,double *red,double *green,double *blue)
1530 {
1531  double
1532  gamma,
1533  X,
1534  Y,
1535  Z;
1536 
1537  gamma=PerceptibleReciprocal(low_y);
1538  X=gamma*cap_Y*low_x;
1539  Y=cap_Y;
1540  Z=gamma*cap_Y*(1.0-low_x-low_y);
1541  ConvertXYZToRGB(X,Y,Z,red,green,blue);
1542 }
1543 
1544 static inline void ConvertYUVToRGB(const double Y,const double U,const double V,
1545  double *red,double *green,double *blue)
1546 {
1547  *red=(double) QuantumRange*(Y-3.945707070708279e-05*(U-0.5)+
1548  1.1398279671717170825*(V-0.5));
1549  *green=(double) QuantumRange*(Y-0.3946101641414141437*(U-0.5)-
1550  0.5805003156565656797*(V-0.5));
1551  *blue=(double) QuantumRange*(Y+2.0319996843434342537*(U-0.5)-
1552  4.813762626262513e-04*(V-0.5));
1553 }
1554 
1555 static inline MagickBooleanType IsCMYKColorspace(
1556  const ColorspaceType colorspace)
1557 {
1558  if (colorspace == CMYKColorspace)
1559  return(MagickTrue);
1560  return(MagickFalse);
1561 }
1562 
1563 static inline MagickBooleanType IsGrayColorspace(
1564  const ColorspaceType colorspace)
1565 {
1566  if ((colorspace == LinearGRAYColorspace) || (colorspace == GRAYColorspace))
1567  return(MagickTrue);
1568  return(MagickFalse);
1569 }
1570 
1571 static inline MagickBooleanType IsGrayImageType(const ImageType type)
1572 {
1573  if ((type == GrayscaleType) || (type == GrayscaleAlphaType) ||
1574  (type == BilevelType))
1575  return(MagickTrue);
1576  return(MagickFalse);
1577 }
1578 
1579 static inline MagickBooleanType IsHueCompatibleColorspace(
1580  const ColorspaceType colorspace)
1581 {
1582  if ((colorspace == HCLColorspace) || (colorspace == HCLpColorspace) ||
1583  (colorspace == HSBColorspace) || (colorspace == HSIColorspace) ||
1584  (colorspace == HSLColorspace) || (colorspace == HSVColorspace))
1585  return(MagickTrue);
1586  return(MagickFalse);
1587 }
1588 
1589 static inline MagickBooleanType IsLabCompatibleColorspace(
1590  const ColorspaceType colorspace)
1591 {
1592  if ((colorspace == LabColorspace) || (colorspace == LCHColorspace) ||
1593  (colorspace == LCHabColorspace) || (colorspace == LCHuvColorspace) ||
1594  (colorspace == OklabColorspace) || (colorspace == OklchColorspace))
1595  return(MagickTrue);
1596  return(MagickFalse);
1597 }
1598 
1599 static inline MagickBooleanType IsRGBColorspace(const ColorspaceType colorspace)
1600 {
1601  if ((colorspace == RGBColorspace) || (colorspace == scRGBColorspace) ||
1602  (colorspace == LinearGRAYColorspace))
1603  return(MagickTrue);
1604  return(MagickFalse);
1605 }
1606 
1607 static inline MagickBooleanType IssRGBColorspace(
1608  const ColorspaceType colorspace)
1609 {
1610  if ((colorspace == sRGBColorspace) || (colorspace == TransparentColorspace))
1611  return(MagickTrue);
1612  return(MagickFalse);
1613 }
1614 
1615 static inline MagickBooleanType IssRGBCompatibleColorspace(
1616  const ColorspaceType colorspace)
1617 {
1618  if ((colorspace == sRGBColorspace) || (colorspace == RGBColorspace) ||
1619  (colorspace == Adobe98Colorspace) || (colorspace == ProPhotoColorspace) ||
1620  (colorspace == DisplayP3Colorspace) || (colorspace == scRGBColorspace) ||
1621  (colorspace == TransparentColorspace) || (colorspace == GRAYColorspace) ||
1622  (colorspace == LinearGRAYColorspace))
1623  return(MagickTrue);
1624  return(MagickFalse);
1625 }
1626 
1627 static inline MagickBooleanType IsYCbCrCompatibleColorspace(
1628  const ColorspaceType colorspace)
1629 {
1630  if ((colorspace == YCbCrColorspace) ||
1631  (colorspace == Rec709YCbCrColorspace) ||
1632  (colorspace == Rec601YCbCrColorspace))
1633  return(MagickTrue);
1634  return(MagickFalse);
1635 }
1636 
1637 extern MagickPrivate void
1638  ConvertGenericToRGB(const ColorspaceType,const double,const double,
1639  const double,const double,const IlluminantType,double *,double *,double *),
1640  ConvertRGBToGeneric(const ColorspaceType,const double,const double,
1641  const double,const double,const IlluminantType,double *,double *,double *);
1642 
1643 #if defined(__cplusplus) || defined(c_plusplus)
1644 }
1645 #endif
1646 
1647 #endif
_PixelInfo
Definition: pixel.h:181
_PrimaryInfo
Definition: image.h:76