MagickCore 6.9.13
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 "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*/
86MagickExport 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*/
179MagickExport 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*/
284MagickExport 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*/
387MagickExport 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*/
460MagickExport 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*/
565MagickExport 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*/
667MagickExport 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
743static 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
750MagickExport 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
796static 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
803MagickExport 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*/
849MagickExport 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*/
916MagickExport 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*/
983MagickExport 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*/
1059MagickExport 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*/
1119MagickExport 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*/
1191MagickExport 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*/
1260MagickExport 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*/
1325static 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
1339MagickExport 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
1386static 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
1400MagickExport 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*/
1445MagickExport 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*/
1481MagickExport 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*/
1617MagickExport 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
1657MagickExport 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
1699MagickExport size_t GetOptimalKernelWidth(const double radius,
1700 const double sigma)
1701{
1702 return(GetOptimalKernelWidth1D(radius,sigma));
1703}