MagickCore  6.9.13-11
Convert, Edit, Or Compose Bitmap Images
gem.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % GGGG EEEEE M M %
7 % G E MM MM %
8 % G GG EEE M M M %
9 % G G E M M %
10 % GGGG EEEEE M M %
11 % %
12 % %
13 % Graphic Gems - Graphic Support Methods %
14 % %
15 % Software Design %
16 % Cristy %
17 % August 1996 %
18 % %
19 % %
20 % Copyright 1999 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 %
38 */
39 
40 /*
41  Include declarations.
42 */
43 #include "magick/studio.h"
44 #include "magick/color-private.h"
45 #include "magick/draw.h"
46 #include "magick/gem.h"
47 #include "magick/gem-private.h"
48 #include "magick/image.h"
49 #include "magick/image-private.h"
50 #include "magick/log.h"
51 #include "magick/memory_.h"
52 #include "magick/pixel-private.h"
53 #include "magick/quantum.h"
54 #include "magick/random_.h"
55 #include "magick/resize.h"
56 #include "magick/transform.h"
57 #include "magick/signature-private.h"
58 
59 /*
60 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
61 % %
62 % %
63 % %
64 % C o n v e r t H C L T o R G B %
65 % %
66 % %
67 % %
68 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
69 %
70 % ConvertHCLToRGB() transforms a (hue, chroma, luma) to a (red, green,
71 % blue) triple.
72 %
73 % The format of the ConvertHCLToRGBImage method is:
74 %
75 % void ConvertHCLToRGB(const double hue,const double chroma,
76 % const double luma,Quantum *red,Quantum *green,Quantum *blue)
77 %
78 % A description of each parameter follows:
79 %
80 % o hue, chroma, luma: A double value representing a component of the
81 % HCL color space.
82 %
83 % o red, green, blue: A pointer to a pixel component of type Quantum.
84 %
85 */
86 MagickExport void ConvertHCLToRGB(const double hue,const double chroma,
87  const double luma,Quantum *red,Quantum *green,Quantum *blue)
88 {
89  double
90  b,
91  c,
92  g,
93  h,
94  m,
95  r,
96  x;
97 
98  /*
99  Convert HCL to RGB colorspace.
100  */
101  assert(red != (Quantum *) NULL);
102  assert(green != (Quantum *) NULL);
103  assert(blue != (Quantum *) NULL);
104  h=6.0*hue;
105  c=chroma;
106  x=c*(1.0-fabs(fmod(h,2.0)-1.0));
107  r=0.0;
108  g=0.0;
109  b=0.0;
110  if ((0.0 <= h) && (h < 1.0))
111  {
112  r=c;
113  g=x;
114  }
115  else
116  if ((1.0 <= h) && (h < 2.0))
117  {
118  r=x;
119  g=c;
120  }
121  else
122  if ((2.0 <= h) && (h < 3.0))
123  {
124  g=c;
125  b=x;
126  }
127  else
128  if ((3.0 <= h) && (h < 4.0))
129  {
130  g=x;
131  b=c;
132  }
133  else
134  if ((4.0 <= h) && (h < 5.0))
135  {
136  r=x;
137  b=c;
138  }
139  else
140  if ((5.0 <= h) && (h < 6.0))
141  {
142  r=c;
143  b=x;
144  }
145  m=luma-(0.298839*r+0.586811*g+0.114350*b);
146  *red=ClampToQuantum((MagickRealType) QuantumRange*(r+m));
147  *green=ClampToQuantum((MagickRealType) QuantumRange*(g+m));
148  *blue=ClampToQuantum((MagickRealType) QuantumRange*(b+m));
149 }
150 
151 /*
152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
153 % %
154 % %
155 % %
156 % C o n v e r t H C L p T o R G B %
157 % %
158 % %
159 % %
160 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
161 %
162 % ConvertHCLpToRGB() transforms a (hue, chroma, luma) to a (red, green,
163 % blue) triple. Since HCL colorspace is wider than RGB, we instead choose a
164 % saturation strategy to project it on the RGB cube.
165 %
166 % The format of the ConvertHCLpToRGBImage method is:
167 %
168 % void ConvertHCLpToRGB(const double hue,const double chroma,
169 % const double luma,Quantum *red,Quantum *green,Quantum *blue)
170 %
171 % A description of each parameter follows:
172 %
173 % o hue, chroma, luma: A double value representing a component of the
174 % HCLp color space.
175 %
176 % o red, green, blue: A pointer to a pixel component of type Quantum.
177 %
178 */
179 MagickExport void ConvertHCLpToRGB(const double hue,const double chroma,
180  const double luma,Quantum *red,Quantum *green,Quantum *blue)
181 {
182  double
183  b,
184  c,
185  g,
186  h,
187  m,
188  r,
189  x,
190  z;
191 
192  /*
193  Convert HCLp to RGB colorspace.
194  */
195  assert(red != (Quantum *) NULL);
196  assert(green != (Quantum *) NULL);
197  assert(blue != (Quantum *) NULL);
198  h=6.0*hue;
199  c=chroma;
200  x=c*(1.0-fabs(fmod(h,2.0)-1.0));
201  r=0.0;
202  g=0.0;
203  b=0.0;
204  if ((0.0 <= h) && (h < 1.0))
205  {
206  r=c;
207  g=x;
208  }
209  else
210  if ((1.0 <= h) && (h < 2.0))
211  {
212  r=x;
213  g=c;
214  }
215  else
216  if ((2.0 <= h) && (h < 3.0))
217  {
218  g=c;
219  b=x;
220  }
221  else
222  if ((3.0 <= h) && (h < 4.0))
223  {
224  g=x;
225  b=c;
226  }
227  else
228  if ((4.0 <= h) && (h < 5.0))
229  {
230  r=x;
231  b=c;
232  }
233  else
234  if ((5.0 <= h) && (h < 6.0))
235  {
236  r=c;
237  b=x;
238  }
239  m=luma-(0.298839*r+0.586811*g+0.114350*b);
240  z=1.0;
241  if (m < 0.0)
242  {
243  z=luma/(luma-m);
244  m=0.0;
245  }
246  else
247  if (m+c > 1.0)
248  {
249  z=(1.0-luma)/(m+c-luma);
250  m=1.0-z*c;
251  }
252  *red=ClampToQuantum((MagickRealType) QuantumRange*(z*r+m));
253  *green=ClampToQuantum((MagickRealType) QuantumRange*(z*g+m));
254  *blue=ClampToQuantum((MagickRealType) QuantumRange*(z*b+m));
255 }
256 
257 /*
258 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
259 % %
260 % %
261 % %
262 % C o n v e r t H S B T o R G B %
263 % %
264 % %
265 % %
266 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
267 %
268 % ConvertHSBToRGB() transforms a (hue, saturation, brightness) to a (red,
269 % green, blue) triple.
270 %
271 % The format of the ConvertHSBToRGBImage method is:
272 %
273 % void ConvertHSBToRGB(const double hue,const double saturation,
274 % const double brightness,Quantum *red,Quantum *green,Quantum *blue)
275 %
276 % A description of each parameter follows:
277 %
278 % o hue, saturation, brightness: A double value representing a
279 % component of the HSB color space.
280 %
281 % o red, green, blue: A pointer to a pixel component of type Quantum.
282 %
283 */
284 MagickExport void ConvertHSBToRGB(const double hue,const double saturation,
285  const double brightness,Quantum *red,Quantum *green,Quantum *blue)
286 {
287  double
288  f,
289  h,
290  p,
291  q,
292  t;
293 
294  /*
295  Convert HSB to RGB colorspace.
296  */
297  assert(red != (Quantum *) NULL);
298  assert(green != (Quantum *) NULL);
299  assert(blue != (Quantum *) NULL);
300  if (fabs(saturation) < MagickEpsilon)
301  {
302  *red=ClampToQuantum((MagickRealType) QuantumRange*brightness);
303  *green=(*red);
304  *blue=(*red);
305  return;
306  }
307  h=6.0*(hue-floor(hue));
308  f=h-floor((double) h);
309  p=brightness*(1.0-saturation);
310  q=brightness*(1.0-saturation*f);
311  t=brightness*(1.0-(saturation*(1.0-f)));
312  switch ((int) h)
313  {
314  case 0:
315  default:
316  {
317  *red=ClampToQuantum((MagickRealType) QuantumRange*brightness);
318  *green=ClampToQuantum((MagickRealType) QuantumRange*t);
319  *blue=ClampToQuantum((MagickRealType) QuantumRange*p);
320  break;
321  }
322  case 1:
323  {
324  *red=ClampToQuantum((MagickRealType) QuantumRange*q);
325  *green=ClampToQuantum((MagickRealType) QuantumRange*brightness);
326  *blue=ClampToQuantum((MagickRealType) QuantumRange*p);
327  break;
328  }
329  case 2:
330  {
331  *red=ClampToQuantum((MagickRealType) QuantumRange*p);
332  *green=ClampToQuantum((MagickRealType) QuantumRange*brightness);
333  *blue=ClampToQuantum((MagickRealType) QuantumRange*t);
334  break;
335  }
336  case 3:
337  {
338  *red=ClampToQuantum((MagickRealType) QuantumRange*p);
339  *green=ClampToQuantum((MagickRealType) QuantumRange*q);
340  *blue=ClampToQuantum((MagickRealType) QuantumRange*brightness);
341  break;
342  }
343  case 4:
344  {
345  *red=ClampToQuantum((MagickRealType) QuantumRange*t);
346  *green=ClampToQuantum((MagickRealType) QuantumRange*p);
347  *blue=ClampToQuantum((MagickRealType) QuantumRange*brightness);
348  break;
349  }
350  case 5:
351  {
352  *red=ClampToQuantum((MagickRealType) QuantumRange*brightness);
353  *green=ClampToQuantum((MagickRealType) QuantumRange*p);
354  *blue=ClampToQuantum((MagickRealType) QuantumRange*q);
355  break;
356  }
357  }
358 }
359 
360 /*
361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
362 % %
363 % %
364 % %
365 % C o n v e r t H S I T o R G B %
366 % %
367 % %
368 % %
369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370 %
371 % ConvertHSIToRGB() transforms a (hue, saturation, intensity) to a (red,
372 % green, blue) triple.
373 %
374 % The format of the ConvertHSIToRGBImage method is:
375 %
376 % void ConvertHSIToRGB(const double hue,const double saturation,
377 % const double intensity,Quantum *red,Quantum *green,Quantum *blue)
378 %
379 % A description of each parameter follows:
380 %
381 % o hue, saturation, intensity: A double value representing a
382 % component of the HSI color space.
383 %
384 % o red, green, blue: A pointer to a pixel component of type Quantum.
385 %
386 */
387 MagickExport void ConvertHSIToRGB(const double hue,const double saturation,
388  const double intensity,Quantum *red,Quantum *green,Quantum *blue)
389 {
390  double
391  b,
392  g,
393  h,
394  r;
395 
396  /*
397  Convert HSI to RGB colorspace.
398  */
399  assert(red != (Quantum *) NULL);
400  assert(green != (Quantum *) NULL);
401  assert(blue != (Quantum *) NULL);
402  h=360.0*hue;
403  h-=360.0*floor(h/360.0);
404  if (h < 120.0)
405  {
406  b=intensity*(1.0-saturation);
407  r=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
408  (MagickPI/180.0)));
409  g=3.0*intensity-r-b;
410  }
411  else
412  if (h < 240.0)
413  {
414  h-=120.0;
415  r=intensity*(1.0-saturation);
416  g=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
417  (MagickPI/180.0)));
418  b=3.0*intensity-r-g;
419  }
420  else
421  {
422  h-=240.0;
423  g=intensity*(1.0-saturation);
424  b=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
425  (MagickPI/180.0)));
426  r=3.0*intensity-g-b;
427  }
428  *red=ClampToQuantum((MagickRealType) QuantumRange*r);
429  *green=ClampToQuantum((MagickRealType) QuantumRange*g);
430  *blue=ClampToQuantum((MagickRealType) QuantumRange*b);
431 }
432 
433 /*
434 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
435 % %
436 % %
437 % %
438 % C o n v e r t H S L T o R G B %
439 % %
440 % %
441 % %
442 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
443 %
444 % ConvertHSLToRGB() transforms a (hue, saturation, lightness) to a (red,
445 % green, blue) triple.
446 %
447 % The format of the ConvertHSLToRGBImage method is:
448 %
449 % void ConvertHSLToRGB(const double hue,const double saturation,
450 % const double lightness,Quantum *red,Quantum *green,Quantum *blue)
451 %
452 % A description of each parameter follows:
453 %
454 % o hue, saturation, lightness: A double value representing a
455 % component of the HSL color space.
456 %
457 % o red, green, blue: A pointer to a pixel component of type Quantum.
458 %
459 */
460 MagickExport void ConvertHSLToRGB(const double hue,const double saturation,
461  const double lightness,Quantum *red,Quantum *green,Quantum *blue)
462 {
463  double
464  b,
465  c,
466  g,
467  h,
468  min,
469  r,
470  x;
471 
472  /*
473  Convert HSL to RGB colorspace.
474  */
475  assert(red != (Quantum *) NULL);
476  assert(green != (Quantum *) NULL);
477  assert(blue != (Quantum *) NULL);
478  h=hue*360.0;
479  if (lightness <= 0.5)
480  c=2.0*lightness*saturation;
481  else
482  c=(2.0-2.0*lightness)*saturation;
483  min=lightness-0.5*c;
484  h-=360.0*floor(h/360.0);
485  h/=60.0;
486  x=c*(1.0-fabs(h-2.0*floor(h/2.0)-1.0));
487  switch ((int) floor(h))
488  {
489  case 0:
490  default:
491  {
492  r=min+c;
493  g=min+x;
494  b=min;
495  break;
496  }
497  case 1:
498  {
499  r=min+x;
500  g=min+c;
501  b=min;
502  break;
503  }
504  case 2:
505  {
506  r=min;
507  g=min+c;
508  b=min+x;
509  break;
510  }
511  case 3:
512  {
513  r=min;
514  g=min+x;
515  b=min+c;
516  break;
517  }
518  case 4:
519  {
520  r=min+x;
521  g=min;
522  b=min+c;
523  break;
524  }
525  case 5:
526  {
527  r=min+c;
528  g=min;
529  b=min+x;
530  break;
531  }
532  }
533  *red=ClampToQuantum((MagickRealType) QuantumRange*r);
534  *green=ClampToQuantum((MagickRealType) QuantumRange*g);
535  *blue=ClampToQuantum((MagickRealType) QuantumRange*b);
536 }
537 
538 /*
539 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
540 % %
541 % %
542 % %
543 % C o n v e r t H S V T o R G B %
544 % %
545 % %
546 % %
547 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
548 %
549 % ConvertHSVToRGB() transforms a (hue, saturation, value) to a (red,
550 % green, blue) triple.
551 %
552 % The format of the ConvertHSVToRGBImage method is:
553 %
554 % void ConvertHSVToRGB(const double hue,const double saturation,
555 % const double value,Quantum *red,Quantum *green,Quantum *blue)
556 %
557 % A description of each parameter follows:
558 %
559 % o hue, saturation, value: A double value representing a
560 % component of the HSV color space.
561 %
562 % o red, green, blue: A pointer to a pixel component of type Quantum.
563 %
564 */
565 MagickExport void ConvertHSVToRGB(const double hue,const double saturation,
566  const double value,Quantum *red,Quantum *green,Quantum *blue)
567 {
568  double
569  b,
570  c,
571  g,
572  h,
573  min,
574  r,
575  x;
576 
577  /*
578  Convert HSV to RGB colorspace.
579  */
580  assert(red != (Quantum *) NULL);
581  assert(green != (Quantum *) NULL);
582  assert(blue != (Quantum *) NULL);
583  h=hue*360.0;
584  c=value*saturation;
585  min=value-c;
586  h-=360.0*floor(h/360.0);
587  h/=60.0;
588  x=c*(1.0-fabs(h-2.0*floor(h/2.0)-1.0));
589  switch ((int) floor(h))
590  {
591  case 0:
592  default:
593  {
594  r=min+c;
595  g=min+x;
596  b=min;
597  break;
598  }
599  case 1:
600  {
601  r=min+x;
602  g=min+c;
603  b=min;
604  break;
605  }
606  case 2:
607  {
608  r=min;
609  g=min+c;
610  b=min+x;
611  break;
612  }
613  case 3:
614  {
615  r=min;
616  g=min+x;
617  b=min+c;
618  break;
619  }
620  case 4:
621  {
622  r=min+x;
623  g=min;
624  b=min+c;
625  break;
626  }
627  case 5:
628  {
629  r=min+c;
630  g=min;
631  b=min+x;
632  break;
633  }
634  }
635  *red=ClampToQuantum((MagickRealType) QuantumRange*r);
636  *green=ClampToQuantum((MagickRealType) QuantumRange*g);
637  *blue=ClampToQuantum((MagickRealType) QuantumRange*b);
638 }
639 
640 /*
641 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
642 % %
643 % %
644 % %
645 % C o n v e r t H W B T o R G B %
646 % %
647 % %
648 % %
649 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
650 %
651 % ConvertHWBToRGB() transforms a (hue, whiteness, blackness) to a (red, green,
652 % blue) triple.
653 %
654 % The format of the ConvertHWBToRGBImage method is:
655 %
656 % void ConvertHWBToRGB(const double hue,const double whiteness,
657 % const double blackness,Quantum *red,Quantum *green,Quantum *blue)
658 %
659 % A description of each parameter follows:
660 %
661 % o hue, whiteness, blackness: A double value representing a
662 % component of the HWB color space.
663 %
664 % o red, green, blue: A pointer to a pixel component of type Quantum.
665 %
666 */
667 MagickExport void ConvertHWBToRGB(const double hue,const double whiteness,
668  const double blackness,Quantum *red,Quantum *green,Quantum *blue)
669 {
670  double
671  b,
672  f,
673  g,
674  n,
675  r,
676  v;
677 
678  ssize_t
679  i;
680 
681  /*
682  Convert HWB to RGB colorspace.
683  */
684  assert(red != (Quantum *) NULL);
685  assert(green != (Quantum *) NULL);
686  assert(blue != (Quantum *) NULL);
687  v=1.0-blackness;
688  if (fabs(hue-(-1.0)) < MagickEpsilon)
689  {
690  *red=ClampToQuantum((MagickRealType) QuantumRange*v);
691  *green=ClampToQuantum((MagickRealType) QuantumRange*v);
692  *blue=ClampToQuantum((MagickRealType) QuantumRange*v);
693  return;
694  }
695  i=CastDoubleToLong(floor(6.0*hue));
696  f=6.0*hue-i;
697  if ((i & 0x01) != 0)
698  f=1.0-f;
699  n=whiteness+f*(v-whiteness); /* linear interpolation */
700  switch (i)
701  {
702  case 0:
703  default: r=v; g=n; b=whiteness; break;
704  case 1: r=n; g=v; b=whiteness; break;
705  case 2: r=whiteness; g=v; b=n; break;
706  case 3: r=whiteness; g=n; b=v; break;
707  case 4: r=n; g=whiteness; b=v; break;
708  case 5: r=v; g=whiteness; b=n; break;
709  }
710  *red=ClampToQuantum((MagickRealType) QuantumRange*r);
711  *green=ClampToQuantum((MagickRealType) QuantumRange*g);
712  *blue=ClampToQuantum((MagickRealType) QuantumRange*b);
713 }
714 
715 /*
716 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
717 % %
718 % %
719 % %
720 % C o n v e r t L C H a b T o R G B %
721 % %
722 % %
723 % %
724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
725 %
726 % ConvertLCHabToRGB() transforms a (luma, chroma, hue) to a (red, green,
727 % blue) triple.
728 %
729 % The format of the ConvertLCHabToRGBImage method is:
730 %
731 % void ConvertLCHabToRGB(const double luma,const double chroma,
732 % const double hue,Quantum *red,Quantum *green,Quantum *blue)
733 %
734 % A description of each parameter follows:
735 %
736 % o luma, chroma, hue: A double value representing a component of the LCHab
737 % color space.
738 %
739 % o red, green, blue: A pointer to a pixel component of type Quantum.
740 %
741 */
742 
743 static inline void ConvertLCHabToXYZ(const double luma,const double chroma,
744  const double hue,double *X,double *Y,double *Z)
745 {
746  ConvertLabToXYZ(luma,chroma*cos(DegreesToRadians(hue)),chroma*
747  sin(DegreesToRadians(hue)),X,Y,Z);
748 }
749 
750 MagickExport void ConvertLCHabToRGB(const double luma,const double chroma,
751  const double hue,Quantum *red,Quantum *green,Quantum *blue)
752 {
753  double
754  X,
755  Y,
756  Z;
757 
758  /*
759  Convert LCHab to RGB colorspace.
760  */
761  assert(red != (Quantum *) NULL);
762  assert(green != (Quantum *) NULL);
763  assert(blue != (Quantum *) NULL);
764  ConvertLCHabToXYZ(100.0*luma,255.0*(chroma-0.5),360.0*hue,&X,&Y,&Z);
765  ConvertXYZToRGB(X,Y,Z,red,green,blue);
766 }
767 
768 /*
769 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
770 % %
771 % %
772 % %
773 % C o n v e r t L C H u v T o R G B %
774 % %
775 % %
776 % %
777 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
778 %
779 % ConvertLCHuvToRGB() transforms a (luma, chroma, hue) to a (red, green,
780 % blue) triple.
781 %
782 % The format of the ConvertLCHuvToRGBImage method is:
783 %
784 % void ConvertLCHuvToRGB(const double luma,const double chroma,
785 % const double hue,Quantum *red,Quantum *green,Quantum *blue)
786 %
787 % A description of each parameter follows:
788 %
789 % o luma, chroma, hue: A double value representing a component of the LCHuv
790 % color space.
791 %
792 % o red, green, blue: A pointer to a pixel component of type Quantum.
793 %
794 */
795 
796 static inline void ConvertLCHuvToXYZ(const double luma,const double chroma,
797  const double hue,double *X,double *Y,double *Z)
798 {
799  ConvertLuvToXYZ(luma,chroma*cos(DegreesToRadians(hue)),chroma*
800  sin(DegreesToRadians(hue)),X,Y,Z);
801 }
802 
803 MagickExport void ConvertLCHuvToRGB(const double luma,const double chroma,
804  const double hue,Quantum *red,Quantum *green,Quantum *blue)
805 {
806  double
807  X,
808  Y,
809  Z;
810 
811  /*
812  Convert LCHuv to RGB colorspace.
813  */
814  assert(red != (Quantum *) NULL);
815  assert(green != (Quantum *) NULL);
816  assert(blue != (Quantum *) NULL);
817  ConvertLCHuvToXYZ(100.0*luma,255.0*(chroma-0.5),360.0*hue,&X,&Y,&Z);
818  ConvertXYZToRGB(X,Y,Z,red,green,blue);
819 }
820 
821 /*
822 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
823 % %
824 % %
825 % %
826 % C o n v e r t R G B T o H C L %
827 % %
828 % %
829 % %
830 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
831 %
832 % ConvertRGBToHCL() transforms a (red, green, blue) to a (hue, chroma,
833 % luma) triple.
834 %
835 % The format of the ConvertRGBToHCL method is:
836 %
837 % void ConvertRGBToHCL(const Quantum red,const Quantum green,
838 % const Quantum blue,double *hue,double *chroma,double *luma)
839 %
840 % A description of each parameter follows:
841 %
842 % o red, green, blue: A Quantum value representing the red, green, and
843 % blue component of a pixel.
844 %
845 % o hue, chroma, luma: A pointer to a double value representing a
846 % component of the HCL color space.
847 %
848 */
849 MagickExport void ConvertRGBToHCL(const Quantum red,const Quantum green,
850  const Quantum blue,double *hue,double *chroma,double *luma)
851 {
852  double
853  b,
854  c,
855  g,
856  h,
857  max,
858  r;
859 
860  /*
861  Convert RGB to HCL colorspace.
862  */
863  assert(hue != (double *) NULL);
864  assert(chroma != (double *) NULL);
865  assert(luma != (double *) NULL);
866  r=(double) red;
867  g=(double) green;
868  b=(double) blue;
869  max=MagickMax(r,MagickMax(g,b));
870  c=max-(double) MagickMin(r,MagickMin(g,b));
871  h=0.0;
872  if (fabs(c) < MagickEpsilon)
873  h=0.0;
874  else
875  if (red == (Quantum) max)
876  h=fmod((g-b)/c+6.0,6.0);
877  else
878  if (green == (Quantum) max)
879  h=((b-r)/c)+2.0;
880  else
881  if (blue == (Quantum) max)
882  h=((r-g)/c)+4.0;
883  *hue=(h/6.0);
884  *chroma=QuantumScale*c;
885  *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
886 }
887 
888 /*
889 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
890 % %
891 % %
892 % %
893 % C o n v e r t R G B T o H C L p %
894 % %
895 % %
896 % %
897 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
898 %
899 % ConvertRGBToHCLp() transforms a (red, green, blue) to a (hue, chroma,
900 % luma) triple.
901 %
902 % The format of the ConvertRGBToHCLp method is:
903 %
904 % void ConvertRGBToHCLp(const Quantum red,const Quantum green,
905 % const Quantum blue,double *hue,double *chroma,double *luma)
906 %
907 % A description of each parameter follows:
908 %
909 % o red, green, blue: A Quantum value representing the red, green, and
910 % blue component of a pixel.
911 %
912 % o hue, chroma, luma: A pointer to a double value representing a
913 % component of the HCLp color space.
914 %
915 */
916 MagickExport void ConvertRGBToHCLp(const Quantum red,const Quantum green,
917  const Quantum blue,double *hue,double *chroma,double *luma)
918 {
919  double
920  b,
921  c,
922  g,
923  h,
924  max,
925  r;
926 
927  /*
928  Convert RGB to HCLp colorspace.
929  */
930  assert(hue != (double *) NULL);
931  assert(chroma != (double *) NULL);
932  assert(luma != (double *) NULL);
933  r=(double) red;
934  g=(double) green;
935  b=(double) blue;
936  max=MagickMax(r,MagickMax(g,b));
937  c=max-(double) MagickMin(r,MagickMin(g,b));
938  h=0.0;
939  if (fabs(c) < MagickEpsilon)
940  h=0.0;
941  else
942  if (red == (Quantum) max)
943  h=fmod((g-b)/c+6.0,6.0);
944  else
945  if (green == (Quantum) max)
946  h=((b-r)/c)+2.0;
947  else
948  if (blue == (Quantum) max)
949  h=((r-g)/c)+4.0;
950  *hue=(h/6.0);
951  *chroma=QuantumScale*c;
952  *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
953 }
954 
955 /*
956 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
957 % %
958 % %
959 % %
960 % C o n v e r t R G B T o H S B %
961 % %
962 % %
963 % %
964 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
965 %
966 % ConvertRGBToHSB() transforms a (red, green, blue) to a (hue, saturation,
967 % brightness) triple.
968 %
969 % The format of the ConvertRGBToHSB method is:
970 %
971 % void ConvertRGBToHSB(const Quantum red,const Quantum green,
972 % const Quantum blue,double *hue,double *saturation,double *brightness)
973 %
974 % A description of each parameter follows:
975 %
976 % o red, green, blue: A Quantum value representing the red, green, and
977 % blue component of a pixel..
978 %
979 % o hue, saturation, brightness: A pointer to a double value representing a
980 % component of the HSB color space.
981 %
982 */
983 MagickExport void ConvertRGBToHSB(const Quantum red,const Quantum green,
984  const Quantum blue,double *hue,double *saturation,double *brightness)
985 {
986  double
987  b,
988  delta,
989  g,
990  max,
991  min,
992  r;
993 
994  /*
995  Convert RGB to HSB colorspace.
996  */
997  assert(hue != (double *) NULL);
998  assert(saturation != (double *) NULL);
999  assert(brightness != (double *) NULL);
1000  *hue=0.0;
1001  *saturation=0.0;
1002  *brightness=0.0;
1003  r=(double) red;
1004  g=(double) green;
1005  b=(double) blue;
1006  min=r < g ? r : g;
1007  if (b < min)
1008  min=b;
1009  max=r > g ? r : g;
1010  if (b > max)
1011  max=b;
1012  if (fabs(max) < MagickEpsilon)
1013  return;
1014  delta=max-min;
1015  *saturation=delta/max;
1016  *brightness=QuantumScale*max;
1017  if (fabs(delta) < MagickEpsilon)
1018  return;
1019  if (fabs(r-max) < MagickEpsilon)
1020  *hue=(g-b)/delta;
1021  else
1022  if (fabs(g-max) < MagickEpsilon)
1023  *hue=2.0+(b-r)/delta;
1024  else
1025  *hue=4.0+(r-g)/delta;
1026  *hue/=6.0;
1027  if (*hue < 0.0)
1028  *hue+=1.0;
1029 }
1030 
1031 /*
1032 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1033 % %
1034 % %
1035 % %
1036 % C o n v e r t R G B T o H S I %
1037 % %
1038 % %
1039 % %
1040 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1041 %
1042 % ConvertRGBToHSI() transforms a (red, green, blue) to a (hue, saturation,
1043 % intensity) triple.
1044 %
1045 % The format of the ConvertRGBToHSI method is:
1046 %
1047 % void ConvertRGBToHSI(const Quantum red,const Quantum green,
1048 % const Quantum blue,double *hue,double *saturation,double *intensity)
1049 %
1050 % A description of each parameter follows:
1051 %
1052 % o red, green, blue: A Quantum value representing the red, green, and
1053 % blue component of a pixel..
1054 %
1055 % o hue, saturation, intensity: A pointer to a double value representing a
1056 % component of the HSI color space.
1057 %
1058 */
1059 MagickExport void ConvertRGBToHSI(const Quantum red,const Quantum green,
1060  const Quantum blue,double *hue,double *saturation,double *intensity)
1061 {
1062  double
1063  alpha,
1064  beta;
1065 
1066  /*
1067  Convert RGB to HSI colorspace.
1068  */
1069  assert(hue != (double *) NULL);
1070  assert(saturation != (double *) NULL);
1071  assert(intensity != (double *) NULL);
1072  *intensity=(QuantumScale*(double) red+QuantumScale*(double) green+
1073  QuantumScale*(double) blue)/3.0;
1074  if (*intensity <= 0.0)
1075  {
1076  *hue=0.0;
1077  *saturation=0.0;
1078  return;
1079  }
1080  *saturation=1.0-MagickMin(QuantumScale*(double) red,MagickMin(QuantumScale*
1081  (double) green,QuantumScale*(double) blue))/(*intensity);
1082  alpha=0.5*(2.0*QuantumScale*(double) red-QuantumScale*(double) green-
1083  QuantumScale*(double) blue);
1084  beta=0.8660254037844385*(QuantumScale*(double) green-QuantumScale*(double)
1085  blue);
1086  *hue=atan2(beta,alpha)*(180.0/MagickPI)/360.0;
1087  if (*hue < 0.0)
1088  *hue+=1.0;
1089 }
1090 
1091 /*
1092 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1093 % %
1094 % %
1095 % %
1096 % C o n v e r t R G B T o H S L %
1097 % %
1098 % %
1099 % %
1100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1101 %
1102 % ConvertRGBToHSL() transforms a (red, green, blue) to a (hue, saturation,
1103 % lightness) triple.
1104 %
1105 % The format of the ConvertRGBToHSL method is:
1106 %
1107 % void ConvertRGBToHSL(const Quantum red,const Quantum green,
1108 % const Quantum blue,double *hue,double *saturation,double *lightness)
1109 %
1110 % A description of each parameter follows:
1111 %
1112 % o red, green, blue: A Quantum value representing the red, green, and
1113 % blue component of a pixel..
1114 %
1115 % o hue, saturation, lightness: A pointer to a double value representing a
1116 % component of the HSL color space.
1117 %
1118 */
1119 MagickExport void ConvertRGBToHSL(const Quantum red,const Quantum green,
1120  const Quantum blue,double *hue,double *saturation,double *lightness)
1121 {
1122  double
1123  c,
1124  max,
1125  min;
1126 
1127  /*
1128  Convert RGB to HSL colorspace.
1129  */
1130  assert(hue != (double *) NULL);
1131  assert(saturation != (double *) NULL);
1132  assert(lightness != (double *) NULL);
1133  max=MagickMax(QuantumScale*(double) red,MagickMax(QuantumScale*(double) green,
1134  QuantumScale*(double) blue));
1135  min=MagickMin(QuantumScale*(double) red,MagickMin(QuantumScale*(double) green,
1136  QuantumScale*(double) blue));
1137  c=max-min;
1138  *lightness=(max+min)/2.0;
1139  if (c <= 0.0)
1140  {
1141  *hue=0.0;
1142  *saturation=0.0;
1143  return;
1144  }
1145  if (fabs(max-QuantumScale*(double) red) < MagickEpsilon)
1146  {
1147  *hue=(QuantumScale*(double) green-QuantumScale*(double) blue)/c;
1148  if ((QuantumScale*(double) green) < (QuantumScale*(double) blue))
1149  *hue+=6.0;
1150  }
1151  else
1152  if (fabs(max-QuantumScale*(double) green) < MagickEpsilon)
1153  *hue=2.0+(QuantumScale*(double) blue-QuantumScale*(double) red)/c;
1154  else
1155  *hue=4.0+(QuantumScale*(double) red-QuantumScale*(double) green)/c;
1156  *hue*=60.0/360.0;
1157  if (*lightness <= 0.5)
1158  *saturation=c*PerceptibleReciprocal(2.0*(*lightness));
1159  else
1160  *saturation=c*PerceptibleReciprocal(2.0-2.0*(*lightness));
1161 }
1162 
1163 /*
1164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1165 % %
1166 % %
1167 % %
1168 % C o n v e r t R G B T o H S V %
1169 % %
1170 % %
1171 % %
1172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1173 %
1174 % ConvertRGBToHSV() transforms a (red, green, blue) to a (hue, saturation,
1175 % value) triple.
1176 %
1177 % The format of the ConvertRGBToHSV method is:
1178 %
1179 % void ConvertRGBToHSV(const Quantum red,const Quantum green,
1180 % const Quantum blue,double *hue,double *saturation,double *value)
1181 %
1182 % A description of each parameter follows:
1183 %
1184 % o red, green, blue: A Quantum value representing the red, green, and
1185 % blue component of a pixel..
1186 %
1187 % o hue, saturation, value: A pointer to a double value representing a
1188 % component of the HSV color space.
1189 %
1190 */
1191 MagickExport void ConvertRGBToHSV(const Quantum red,const Quantum green,
1192  const Quantum blue,double *hue,double *saturation,double *value)
1193 {
1194  double
1195  c,
1196  max,
1197  min;
1198 
1199  /*
1200  Convert RGB to HSV colorspace.
1201  */
1202  assert(hue != (double *) NULL);
1203  assert(saturation != (double *) NULL);
1204  assert(value != (double *) NULL);
1205  max=MagickMax(QuantumScale*(double) red,MagickMax(QuantumScale*(double) green,
1206  QuantumScale*(double) blue));
1207  min=MagickMin(QuantumScale*(double) red,MagickMin(QuantumScale*(double) green,
1208  QuantumScale*(double) blue));
1209  c=max-min;
1210  *value=max;
1211  if (c <= 0.0)
1212  {
1213  *hue=0.0;
1214  *saturation=0.0;
1215  return;
1216  }
1217  if (fabs(max-QuantumScale*(double) red) < MagickEpsilon)
1218  {
1219  *hue=(QuantumScale*(double) green-QuantumScale*(double) blue)/c;
1220  if ((QuantumScale*(double) green) < (QuantumScale*(double) blue))
1221  *hue+=6.0;
1222  }
1223  else
1224  if (fabs(max-QuantumScale*(double) green) < MagickEpsilon)
1225  *hue=2.0+(QuantumScale*(double) blue-QuantumScale*(double) red)/c;
1226  else
1227  *hue=4.0+(QuantumScale*(double) red-QuantumScale*(double) green)/c;
1228  *hue*=60.0/360.0;
1229  *saturation=c*PerceptibleReciprocal(max);
1230 }
1231 
1232 /*
1233 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1234 % %
1235 % %
1236 % %
1237 % C o n v e r t R G B T o H W B %
1238 % %
1239 % %
1240 % %
1241 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1242 %
1243 % ConvertRGBToHWB() transforms a (red, green, blue) to a (hue, whiteness,
1244 % blackness) triple.
1245 %
1246 % The format of the ConvertRGBToHWB method is:
1247 %
1248 % void ConvertRGBToHWB(const Quantum red,const Quantum green,
1249 % const Quantum blue,double *hue,double *whiteness,double *blackness)
1250 %
1251 % A description of each parameter follows:
1252 %
1253 % o red, green, blue: A Quantum value representing the red, green, and
1254 % blue component of a pixel.
1255 %
1256 % o hue, whiteness, blackness: A pointer to a double value representing a
1257 % component of the HWB color space.
1258 %
1259 */
1260 MagickExport void ConvertRGBToHWB(const Quantum red,const Quantum green,
1261  const Quantum blue,double *hue,double *whiteness,double *blackness)
1262 {
1263  double
1264  b,
1265  f,
1266  g,
1267  p,
1268  r,
1269  v,
1270  w;
1271 
1272  /*
1273  Convert RGB to HWB colorspace.
1274  */
1275  assert(hue != (double *) NULL);
1276  assert(whiteness != (double *) NULL);
1277  assert(blackness != (double *) NULL);
1278  r=(double) red;
1279  g=(double) green;
1280  b=(double) blue;
1281  w=MagickMin(r,MagickMin(g,b));
1282  v=MagickMax(r,MagickMax(g,b));
1283  *blackness=1.0-QuantumScale*v;
1284  *whiteness=QuantumScale*w;
1285  if (fabs(v-w) < MagickEpsilon)
1286  {
1287  *hue=(-1.0);
1288  return;
1289  }
1290  f=(fabs(r-w) < MagickEpsilon) ? g-b : ((fabs(g-w) < MagickEpsilon) ? b-r :
1291  r-g);
1292  p=(fabs(r-w) < MagickEpsilon) ? 3.0 : ((fabs(g-w) < MagickEpsilon) ? 5.0 :
1293  1.0);
1294  *hue=(p-f/(v-1.0*w))/6.0;
1295 }
1296 
1297 /*
1298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1299 % %
1300 % %
1301 % %
1302 % C o n v e r t R G B T o L C H a b %
1303 % %
1304 % %
1305 % %
1306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1307 %
1308 % ConvertRGBToLCHab() transforms a (red, green, blue) to a (luma, chroma,
1309 % hue) triple.
1310 %
1311 % The format of the ConvertRGBToLCHab method is:
1312 %
1313 % void ConvertRGBToLCHab(const Quantum red,const Quantum green,
1314 % const Quantum blue,double *luma,double *chroma,double *hue)
1315 %
1316 % A description of each parameter follows:
1317 %
1318 % o red, green, blue: A Quantum value representing the red, green, and
1319 % blue component of a pixel.
1320 %
1321 % o hue, chroma, luma: A pointer to a double value representing a
1322 % component of the LCHab color space.
1323 %
1324 */
1325 static inline void ConvertXYZToLCHab(const double X,const double Y,
1326  const double Z,double *luma,double *chroma,double *hue)
1327 {
1328  double
1329  a,
1330  b;
1331 
1332  ConvertXYZToLab(X,Y,Z,luma,&a,&b);
1333  *chroma=hypot(a-0.5,b-0.5)/255.0+0.5;
1334  *hue=180.0*atan2(b-0.5,a-0.5)/MagickPI/360.0;
1335  if (*hue < 0.0)
1336  *hue+=1.0;
1337 }
1338 
1339 MagickExport void ConvertRGBToLCHab(const Quantum red,const Quantum green,
1340  const Quantum blue,double *luma,double *chroma,double *hue)
1341 {
1342  double
1343  X,
1344  Y,
1345  Z;
1346 
1347  /*
1348  Convert RGB to LCHab colorspace.
1349  */
1350  assert(luma != (double *) NULL);
1351  assert(chroma != (double *) NULL);
1352  assert(hue != (double *) NULL);
1353  ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
1354  ConvertXYZToLCHab(X,Y,Z,luma,chroma,hue);
1355 }
1356 
1357 /*
1358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1359 % %
1360 % %
1361 % %
1362 % C o n v e r t R G B T o L C H u v %
1363 % %
1364 % %
1365 % %
1366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1367 %
1368 % ConvertRGBToLCHuv() transforms a (red, green, blue) to a (luma, chroma,
1369 % hue) triple.
1370 %
1371 % The format of the ConvertRGBToLCHuv method is:
1372 %
1373 % void ConvertRGBToLCHuv(const Quantum red,const Quantum green,
1374 % const Quantum blue,double *luma,double *chroma,double *hue)
1375 %
1376 % A description of each parameter follows:
1377 %
1378 % o red, green, blue: A Quantum value representing the red, green, and
1379 % blue component of a pixel.
1380 %
1381 % o hue, chroma, luma: A pointer to a double value representing a
1382 % component of the LCHuv color space.
1383 %
1384 */
1385 
1386 static inline void ConvertXYZToLCHuv(const double X,const double Y,
1387  const double Z,double *luma,double *chroma,double *hue)
1388 {
1389  double
1390  u,
1391  v;
1392 
1393  ConvertXYZToLuv(X,Y,Z,luma,&u,&v);
1394  *chroma=hypot(354.0*u-134.0,262.0*v-140.0)/255.0+0.5;
1395  *hue=180.0*atan2(262.0*v-140.0,354.0*u-134.0)/MagickPI/360.0;
1396  if (*hue < 0.0)
1397  *hue+=1.0;
1398 }
1399 
1400 MagickExport void ConvertRGBToLCHuv(const Quantum red,const Quantum green,
1401  const Quantum blue,double *luma,double *chroma,double *hue)
1402 {
1403  double
1404  X,
1405  Y,
1406  Z;
1407 
1408  /*
1409  Convert RGB to LCHuv colorspace.
1410  */
1411  assert(luma != (double *) NULL);
1412  assert(chroma != (double *) NULL);
1413  assert(hue != (double *) NULL);
1414  ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
1415  ConvertXYZToLCHuv(X,Y,Z,luma,chroma,hue);
1416 }
1417 
1418 /*
1419 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1420 % %
1421 % %
1422 % %
1423 % E x p a n d A f f i n e %
1424 % %
1425 % %
1426 % %
1427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1428 %
1429 % ExpandAffine() computes the affine's expansion factor, i.e. the square root
1430 % of the factor by which the affine transform affects area. In an affine
1431 % transform composed of scaling, rotation, shearing, and translation, returns
1432 % the amount of scaling.
1433 %
1434 % The format of the ExpandAffine method is:
1435 %
1436 % double ExpandAffine(const AffineMatrix *affine)
1437 %
1438 % A description of each parameter follows:
1439 %
1440 % o expansion: ExpandAffine returns the affine's expansion factor.
1441 %
1442 % o affine: A pointer the affine transform of type AffineMatrix.
1443 %
1444 */
1445 MagickExport double ExpandAffine(const AffineMatrix *affine)
1446 {
1447  assert(affine != (const AffineMatrix *) NULL);
1448  return(sqrt(fabs(affine->sx*affine->sy-affine->rx*affine->ry)));
1449 }
1450 
1451 /*
1452 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1453 % %
1454 % %
1455 % %
1456 % G e n e r a t e D i f f e r e n t i a l N o i s e %
1457 % %
1458 % %
1459 % %
1460 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1461 %
1462 % GenerateDifferentialNoise() generates differential noise.
1463 %
1464 % The format of the GenerateDifferentialNoise method is:
1465 %
1466 % double GenerateDifferentialNoise(RandomInfo *random_info,
1467 % const Quantum pixel,const NoiseType noise_type,
1468 % const MagickRealType attenuate)
1469 %
1470 % A description of each parameter follows:
1471 %
1472 % o random_info: the random info.
1473 %
1474 % o pixel: noise is relative to this pixel value.
1475 %
1476 % o noise_type: the type of noise.
1477 %
1478 % o attenuate: attenuate the noise.
1479 %
1480 */
1481 MagickExport double GenerateDifferentialNoise(RandomInfo *random_info,
1482  const Quantum pixel,const NoiseType noise_type,const MagickRealType attenuate)
1483 {
1484 #define SigmaUniform (attenuate*0.015625)
1485 #define SigmaGaussian (attenuate*0.015625)
1486 #define SigmaImpulse (attenuate*0.1)
1487 #define SigmaLaplacian (attenuate*0.0390625)
1488 #define SigmaMultiplicativeGaussian (attenuate*0.5)
1489 #define SigmaPoisson (attenuate*12.5)
1490 #define SigmaRandom (attenuate)
1491 #define TauGaussian (attenuate*0.078125)
1492 
1493  double
1494  alpha,
1495  beta,
1496  noise,
1497  sigma;
1498 
1499  alpha=GetPseudoRandomValue(random_info);
1500  switch (noise_type)
1501  {
1502  case UniformNoise:
1503  default:
1504  {
1505  noise=(double) pixel+(double) QuantumRange*SigmaUniform*(alpha-0.5);
1506  break;
1507  }
1508  case GaussianNoise:
1509  {
1510  double
1511  gamma,
1512  tau;
1513 
1514  if (fabs(alpha) < MagickEpsilon)
1515  alpha=1.0;
1516  beta=GetPseudoRandomValue(random_info);
1517  gamma=sqrt(-2.0*log(alpha));
1518  sigma=gamma*cos((double) (2.0*MagickPI*beta));
1519  tau=gamma*sin((double) (2.0*MagickPI*beta));
1520  noise=(double) pixel+sqrt((double) pixel)*SigmaGaussian*sigma+
1521  (double) QuantumRange*TauGaussian*tau;
1522  break;
1523  }
1524  case ImpulseNoise:
1525  {
1526  if (alpha < (SigmaImpulse/2.0))
1527  noise=0.0;
1528  else
1529  if (alpha >= (1.0-(SigmaImpulse/2.0)))
1530  noise=(double) QuantumRange;
1531  else
1532  noise=(double) pixel;
1533  break;
1534  }
1535  case LaplacianNoise:
1536  {
1537  if (alpha <= 0.5)
1538  {
1539  if (alpha <= MagickEpsilon)
1540  noise=(double) (pixel-QuantumRange);
1541  else
1542  noise=(double) pixel+(double) QuantumRange*SigmaLaplacian*
1543  log(2.0*alpha)+0.5;
1544  break;
1545  }
1546  beta=1.0-alpha;
1547  if (beta <= (0.5*MagickEpsilon))
1548  noise=(double) (pixel+QuantumRange);
1549  else
1550  noise=(double) pixel-(double) QuantumRange*SigmaLaplacian*
1551  log(2.0*beta)+0.5;
1552  break;
1553  }
1554  case MultiplicativeGaussianNoise:
1555  {
1556  sigma=1.0;
1557  if (alpha > MagickEpsilon)
1558  sigma=sqrt(-2.0*log(alpha));
1559  beta=GetPseudoRandomValue(random_info);
1560  noise=(double) pixel+(double) pixel*SigmaMultiplicativeGaussian*sigma*
1561  cos((double) (2.0*MagickPI*beta))/2.0;
1562  break;
1563  }
1564  case PoissonNoise:
1565  {
1566  double
1567  poisson;
1568 
1569  ssize_t
1570  i;
1571 
1572  poisson=exp(-SigmaPoisson*QuantumScale*(double) pixel);
1573  for (i=0; alpha > poisson; i++)
1574  {
1575  beta=GetPseudoRandomValue(random_info);
1576  alpha*=beta;
1577  }
1578  noise=(double) QuantumRange*i*PerceptibleReciprocal(SigmaPoisson);
1579  break;
1580  }
1581  case RandomNoise:
1582  {
1583  noise=(double) QuantumRange*SigmaRandom*alpha;
1584  break;
1585  }
1586  }
1587  return(noise);
1588 }
1589 
1590 /*
1591 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1592 % %
1593 % %
1594 % %
1595 % G e t O p t i m a l K e r n e l W i d t h %
1596 % %
1597 % %
1598 % %
1599 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1600 %
1601 % GetOptimalKernelWidth() computes the optimal kernel radius for a convolution
1602 % filter. Start with the minimum value of 3 pixels and walk out until we drop
1603 % below the threshold of one pixel numerical accuracy.
1604 %
1605 % The format of the GetOptimalKernelWidth method is:
1606 %
1607 % size_t GetOptimalKernelWidth(const double radius,const double sigma)
1608 %
1609 % A description of each parameter follows:
1610 %
1611 % o radius: the radius of the Gaussian, in pixels, not counting the center
1612 % pixel.
1613 %
1614 % o sigma: the standard deviation of the Gaussian, in pixels.
1615 %
1616 */
1617 MagickExport size_t GetOptimalKernelWidth1D(const double radius,
1618  const double sigma)
1619 {
1620  double
1621  alpha,
1622  beta,
1623  gamma,
1624  normalize,
1625  value;
1626 
1627  size_t
1628  width;
1629 
1630  ssize_t
1631  i,
1632  j;
1633 
1634  if (IsEventLogging() != MagickFalse)
1635  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1636  if (radius > MagickEpsilon)
1637  return((size_t) (2.0*ceil(radius)+1.0));
1638  gamma=fabs(sigma);
1639  if (gamma <= MagickEpsilon)
1640  return(3UL);
1641  alpha=PerceptibleReciprocal(2.0*gamma*gamma);
1642  beta=(double) PerceptibleReciprocal((double) MagickSQ2PI*gamma);
1643  for (width=5; ; )
1644  {
1645  normalize=0.0;
1646  j=(ssize_t) (width-1)/2;
1647  for (i=(-j); i <= j; i++)
1648  normalize+=exp(-((double) (i*i))*alpha)*beta;
1649  value=exp(-((double) (j*j))*alpha)*beta/normalize;
1650  if ((value < QuantumScale) || (value < MagickEpsilon))
1651  break;
1652  width+=2;
1653  }
1654  return((size_t) (width-2));
1655 }
1656 
1657 MagickExport size_t GetOptimalKernelWidth2D(const double radius,
1658  const double sigma)
1659 {
1660  double
1661  alpha,
1662  beta,
1663  gamma,
1664  normalize,
1665  value;
1666 
1667  size_t
1668  width;
1669 
1670  ssize_t
1671  j,
1672  u,
1673  v;
1674 
1675  if (IsEventLogging() != MagickFalse)
1676  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1677  if (radius > MagickEpsilon)
1678  return((size_t) (2.0*ceil(radius)+1.0));
1679  gamma=fabs(sigma);
1680  if (gamma <= MagickEpsilon)
1681  return(3UL);
1682  alpha=PerceptibleReciprocal(2.0*gamma*gamma);
1683  beta=(double) PerceptibleReciprocal((double) Magick2PI*gamma*gamma);
1684  for (width=5; ; )
1685  {
1686  normalize=0.0;
1687  j=(ssize_t) (width-1)/2;
1688  for (v=(-j); v <= j; v++)
1689  for (u=(-j); u <= j; u++)
1690  normalize+=exp(-((double) (u*u+v*v))*alpha)*beta;
1691  value=exp(-((double) (j*j))*alpha)*beta/normalize;
1692  if ((value < QuantumScale) || (value < MagickEpsilon))
1693  break;
1694  width+=2;
1695  }
1696  return((size_t) (width-2));
1697 }
1698 
1699 MagickExport size_t GetOptimalKernelWidth(const double radius,
1700  const double sigma)
1701 {
1702  return(GetOptimalKernelWidth1D(radius,sigma));
1703 }