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