blob: 3ae8979b0a77eb18da1ccc32e3178ffdd241ef3c [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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% John Cristy %
17% August 1996 %
18% %
19% %
cristy45ef08f2012-12-07 13:13:34 +000020% Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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% http://www.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*/
cristy4c08aed2011-07-01 19:47:50 +000043#include "MagickCore/studio.h"
44#include "MagickCore/color-private.h"
45#include "MagickCore/draw.h"
46#include "MagickCore/gem.h"
cristyd1dd6e42011-09-04 01:46:08 +000047#include "MagickCore/gem-private.h"
cristy4c08aed2011-07-01 19:47:50 +000048#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"
cristy35f15302012-06-07 14:59:02 +000053#include "MagickCore/pixel-private.h"
cristy4c08aed2011-07-01 19:47:50 +000054#include "MagickCore/quantum.h"
55#include "MagickCore/quantum-private.h"
56#include "MagickCore/random_.h"
57#include "MagickCore/resize.h"
58#include "MagickCore/transform.h"
59#include "MagickCore/signature-private.h"
cristy3ed852e2009-09-05 21:47:34 +000060
61/*
62%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
63% %
64% %
65% %
cristy722fc0c2012-08-04 23:15:43 +000066% C o n v e r t H C L T o R G B %
67% %
68% %
69% %
70%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
71%
72% ConvertHCLToRGB() transforms a (hue, chroma, luma) to a (red, green,
73% blue) triple.
74%
75% The format of the ConvertHCLToRGBImage method is:
76%
77% void ConvertHCLToRGB(const double hue,const double chroma,
78% const double luma,double *red,double *green,double *blue)
79%
80% A description of each parameter follows:
81%
cristy9e2436a2013-05-02 20:35:59 +000082% o hue, chroma, luma: A double value representing a component of the
83% HCL color space.
cristy722fc0c2012-08-04 23:15:43 +000084%
85% o red, green, blue: A pointer to a pixel component of type Quantum.
86%
87*/
88MagickPrivate void ConvertHCLToRGB(const double hue,const double chroma,
89 const double luma,double *red,double *green,double *blue)
90{
91 double
cristy5756d822013-04-09 01:14:34 +000092 b,
93 c,
94 g,
95 h,
96 m,
97 r,
cristy9e2436a2013-05-02 20:35:59 +000098 x;
cristy722fc0c2012-08-04 23:15:43 +000099
100 /*
101 Convert HCL to RGB colorspace.
102 */
103 assert(red != (double *) NULL);
104 assert(green != (double *) NULL);
105 assert(blue != (double *) NULL);
cristy5756d822013-04-09 01:14:34 +0000106 h=6.0*hue;
107 c=chroma;
108 x=c*(1.0-fabs(fmod(h,2.0)-1.0));
109 r=0.0;
110 g=0.0;
111 b=0.0;
112 if ((0.0 <= h) && (h < 1.0))
113 {
114 r=c;
115 g=x;
116 }
117 else
118 if ((1.0 <= h) && (h < 2.0))
119 {
120 r=x;
121 g=c;
122 }
123 else
124 if ((2.0 <= h) && (h < 3.0))
125 {
126 g=c;
127 b=x;
128 }
129 else
130 if ((3.0 <= h) && (h < 4.0))
131 {
132 g=x;
133 b=c;
134 }
135 else
136 if ((4.0 <= h) && (h < 5.0))
137 {
138 r=x;
139 b=c;
140 }
141 else
142 if ((5.0 <= h) && (h < 6.0))
143 {
144 r=c;
145 b=x;
146 }
cristy9e2436a2013-05-02 20:35:59 +0000147 m=luma-(0.298839*r+0.586811*g+0.114350*b);
148 *red=QuantumRange*(r+m);
149 *green=QuantumRange*(g+m);
150 *blue=QuantumRange*(b+m);
151}
152
153/*
154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
155% %
156% %
157% %
158% C o n v e r t H C L p T o R G B %
159% %
160% %
161% %
162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163%
164% ConvertHCLpToRGB() transforms a (hue, chroma, luma) to a (red, green,
165% blue) triple. Since HCL colorspace is wider than RGB, we instead choose a
166% saturation strategy to project it on the RGB cube.
167%
168% The format of the ConvertHCLpToRGBImage method is:
169%
170% void ConvertHCLpToRGB(const double hue,const double chroma,
171% const double luma,double *red,double *green,double *blue)
172%
173% A description of each parameter follows:
174%
175% o hue, chroma, luma: A double value representing a componenet of the
176% HCLp color space.
177%
178% o red, green, blue: A pointer to a pixel component of type Quantum.
179%
180*/
181MagickPrivate void ConvertHCLpToRGB(const double hue,const double chroma,
182 const double luma,double *red,double *green,double *blue)
183{
184 double
185 b,
186 c,
187 g,
188 h,
189 m,
190 r,
191 x,
192 z;
193
194 /*
195 Convert HCLp to RGB colorspace.
196 */
197 assert(red != (double *) NULL);
198 assert(green != (double *) NULL);
199 assert(blue != (double *) NULL);
200 h=6.0*hue;
201 c=chroma;
202 x=c*(1.0-fabs(fmod(h,2.0)-1.0));
203 r=0.0;
204 g=0.0;
205 b=0.0;
206 if ((0.0 <= h) && (h < 1.0))
207 {
208 r=c;
209 g=x;
210 }
211 else
212 if ((1.0 <= h) && (h < 2.0))
213 {
214 r=x;
215 g=c;
216 }
217 else
218 if ((2.0 <= h) && (h < 3.0))
219 {
220 g=c;
221 b=x;
222 }
223 else
224 if ((3.0 <= h) && (h < 4.0))
225 {
226 g=x;
227 b=c;
228 }
229 else
230 if ((4.0 <= h) && (h < 5.0))
231 {
232 r=x;
233 b=c;
234 }
235 else
236 if ((5.0 <= h) && (h < 6.0))
237 {
238 r=c;
239 b=x;
240 }
241 m=luma-(0.298839*r+0.586811*g+0.114350*b);
cristyc41e5fa2013-05-01 01:24:25 +0000242 z=1.0;
243 if (m < 0.0)
244 {
245 z=luma/(luma-m);
246 m=0.0;
247 }
248 else
249 if (m+c > 1.0)
250 {
251 z=(1.0-luma)/(m+c-luma);
252 m=1.0-z*c;
253 }
cristya5a45a72013-05-02 16:06:57 +0000254 *red=QuantumRange*(z*r+m);
255 *green=QuantumRange*(z*g+m);
256 *blue=QuantumRange*(z*b+m);
cristy722fc0c2012-08-04 23:15:43 +0000257}
258
259/*
260%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
261% %
262% %
263% %
cristy0a39a5c2012-06-27 12:51:45 +0000264% C o n v e r t H S B T o R G B %
cristy3ed852e2009-09-05 21:47:34 +0000265% %
266% %
267% %
268%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
269%
cristy0a39a5c2012-06-27 12:51:45 +0000270% ConvertHSBToRGB() transforms a (hue, saturation, brightness) to a (red,
cristy3ed852e2009-09-05 21:47:34 +0000271% green, blue) triple.
272%
cristy0a39a5c2012-06-27 12:51:45 +0000273% The format of the ConvertHSBToRGBImage method is:
cristy3ed852e2009-09-05 21:47:34 +0000274%
cristy0a39a5c2012-06-27 12:51:45 +0000275% void ConvertHSBToRGB(const double hue,const double saturation,
cristy3094b7f2011-10-01 23:18:02 +0000276% const double brightness,double *red,double *green,double *blue)
cristy3ed852e2009-09-05 21:47:34 +0000277%
278% A description of each parameter follows:
279%
280% o hue, saturation, brightness: A double value representing a
281% component of the HSB color space.
282%
283% o red, green, blue: A pointer to a pixel component of type Quantum.
284%
285*/
cristy0a39a5c2012-06-27 12:51:45 +0000286MagickPrivate void ConvertHSBToRGB(const double hue,const double saturation,
cristy3094b7f2011-10-01 23:18:02 +0000287 const double brightness,double *red,double *green,double *blue)
cristy3ed852e2009-09-05 21:47:34 +0000288{
cristycaf45802012-06-16 18:28:54 +0000289 double
cristy3ed852e2009-09-05 21:47:34 +0000290 f,
291 h,
292 p,
293 q,
294 t;
295
296 /*
297 Convert HSB to RGB colorspace.
298 */
cristy3094b7f2011-10-01 23:18:02 +0000299 assert(red != (double *) NULL);
300 assert(green != (double *) NULL);
301 assert(blue != (double *) NULL);
cristy98a65d52010-04-14 02:12:38 +0000302 if (saturation == 0.0)
cristy3ed852e2009-09-05 21:47:34 +0000303 {
cristycaf45802012-06-16 18:28:54 +0000304 *red=QuantumRange*brightness;
cristy3ed852e2009-09-05 21:47:34 +0000305 *green=(*red);
306 *blue=(*red);
307 return;
308 }
cristy98a65d52010-04-14 02:12:38 +0000309 h=6.0*(hue-floor(hue));
310 f=h-floor((double) h);
311 p=brightness*(1.0-saturation);
312 q=brightness*(1.0-saturation*f);
313 t=brightness*(1.0-(saturation*(1.0-f)));
cristy3ed852e2009-09-05 21:47:34 +0000314 switch ((int) h)
315 {
316 case 0:
317 default:
318 {
cristy0a39a5c2012-06-27 12:51:45 +0000319 *red=QuantumRange*brightness;
320 *green=QuantumRange*t;
321 *blue=QuantumRange*p;
cristy3ed852e2009-09-05 21:47:34 +0000322 break;
323 }
324 case 1:
325 {
cristy0a39a5c2012-06-27 12:51:45 +0000326 *red=QuantumRange*q;
327 *green=QuantumRange*brightness;
328 *blue=QuantumRange*p;
cristy3ed852e2009-09-05 21:47:34 +0000329 break;
330 }
331 case 2:
332 {
cristy0a39a5c2012-06-27 12:51:45 +0000333 *red=QuantumRange*p;
334 *green=QuantumRange*brightness;
335 *blue=QuantumRange*t;
cristy3ed852e2009-09-05 21:47:34 +0000336 break;
337 }
338 case 3:
339 {
cristy0a39a5c2012-06-27 12:51:45 +0000340 *red=QuantumRange*p;
341 *green=QuantumRange*q;
342 *blue=QuantumRange*brightness;
cristy3ed852e2009-09-05 21:47:34 +0000343 break;
344 }
345 case 4:
346 {
cristy0a39a5c2012-06-27 12:51:45 +0000347 *red=QuantumRange*t;
348 *green=QuantumRange*p;
349 *blue=QuantumRange*brightness;
cristy3ed852e2009-09-05 21:47:34 +0000350 break;
351 }
352 case 5:
353 {
cristy0a39a5c2012-06-27 12:51:45 +0000354 *red=QuantumRange*brightness;
355 *green=QuantumRange*p;
356 *blue=QuantumRange*q;
cristy3ed852e2009-09-05 21:47:34 +0000357 break;
358 }
359 }
360}
361
362/*
363%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
364% %
365% %
366% %
cristyaf64eb22013-05-02 14:07:10 +0000367% C o n v e r t H S I T o R G B %
368% %
369% %
370% %
371%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
372%
373% ConvertHSIToRGB() transforms a (hue, saturation, intensity) to a (red,
374% green, blue) triple.
375%
376% The format of the ConvertHSIToRGBImage method is:
377%
378% void ConvertHSIToRGB(const double hue,const double saturation,
379% const double intensity,double *red,double *green,double *blue)
380%
381% A description of each parameter follows:
382%
383% o hue, saturation, intensity: A double value representing a
384% component of the HSI color space.
385%
386% o red, green, blue: A pointer to a pixel component of type Quantum.
387%
388*/
389MagickPrivate void ConvertHSIToRGB(const double hue,const double saturation,
390 const double intensity,double *red,double *green,double *blue)
391{
392 double
393 h;
394
395 /*
396 Convert HSI to RGB colorspace.
397 */
398 assert(red != (double *) NULL);
399 assert(green != (double *) NULL);
400 assert(blue != (double *) NULL);
401 h=360.0*hue;
402 h-=360.0*floor(h/360.0);
403 if (h < 120.0)
404 {
405 *blue=intensity*(1.0-saturation);
406 *red=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
407 (MagickPI/180.0)));
408 *green=3.0*intensity-*red-*blue;
409 }
410 else
411 if (h < 240.0)
412 {
413 h-=120.0;
414 *red=intensity*(1.0-saturation);
415 *green=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
416 (MagickPI/180.0)));
417 *blue=3.0*intensity-*red-*green;
418 }
419 else
420 {
421 h-=240.0;
422 *green=intensity*(1.0-saturation);
423 *blue=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
424 (MagickPI/180.0)));
425 *red=3.0*intensity-*green-*blue;
426 }
427 *red*=QuantumRange;
428 *green*=QuantumRange;
429 *blue*=QuantumRange;
430}
431
432/*
433%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
434% %
435% %
436% %
cristy0a39a5c2012-06-27 12:51:45 +0000437% C o n v e r t H S L T o R G B %
cristy3ed852e2009-09-05 21:47:34 +0000438% %
439% %
440% %
441%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
442%
cristy0a39a5c2012-06-27 12:51:45 +0000443% ConvertHSLToRGB() transforms a (hue, saturation, lightness) to a (red,
cristy3ed852e2009-09-05 21:47:34 +0000444% green, blue) triple.
445%
cristy0a39a5c2012-06-27 12:51:45 +0000446% The format of the ConvertHSLToRGBImage method is:
cristy3ed852e2009-09-05 21:47:34 +0000447%
cristy0a39a5c2012-06-27 12:51:45 +0000448% void ConvertHSLToRGB(const double hue,const double saturation,
cristy3094b7f2011-10-01 23:18:02 +0000449% const double lightness,double *red,double *green,double *blue)
cristy3ed852e2009-09-05 21:47:34 +0000450%
451% A description of each parameter follows:
452%
453% o hue, saturation, lightness: A double value representing a
454% component of the HSL color space.
455%
456% o red, green, blue: A pointer to a pixel component of type Quantum.
457%
458*/
cristy0a39a5c2012-06-27 12:51:45 +0000459MagickExport void ConvertHSLToRGB(const double hue,const double saturation,
cristy3094b7f2011-10-01 23:18:02 +0000460 const double lightness,double *red,double *green,double *blue)
cristy3ed852e2009-09-05 21:47:34 +0000461{
cristycaf45802012-06-16 18:28:54 +0000462 double
cristya5a45a72013-05-02 16:06:57 +0000463 c,
464 h,
465 min,
466 x;
cristy3ed852e2009-09-05 21:47:34 +0000467
468 /*
469 Convert HSL to RGB colorspace.
470 */
cristy3094b7f2011-10-01 23:18:02 +0000471 assert(red != (double *) NULL);
472 assert(green != (double *) NULL);
473 assert(blue != (double *) NULL);
cristya5a45a72013-05-02 16:06:57 +0000474 h=hue*360.0;
475 if (lightness <= 0.5)
476 c=2.0*lightness*saturation;
cristy98a65d52010-04-14 02:12:38 +0000477 else
cristya5a45a72013-05-02 16:06:57 +0000478 c=(2.0-2.0*lightness)*saturation;
479 min=lightness-0.5*c;
480 h-=360.0*floor(h/360.0);
481 h/=60.0;
482 x=c*(1.0-fabs(h-2.0*floor(h/2.0)-1.0));
483 switch ((int) floor(h))
484 {
485 case 0:
486 {
487 *red=QuantumRange*(min+c);
488 *green=QuantumRange*(min+x);
489 *blue=QuantumRange*min;
490 break;
491 }
492 case 1:
493 {
494 *red=QuantumRange*(min+x);
495 *green=QuantumRange*(min+c);
496 *blue=QuantumRange*min;
497 break;
498 }
499 case 2:
500 {
501 *red=QuantumRange*min;
502 *green=QuantumRange*(min+c);
503 *blue=QuantumRange*(min+x);
504 break;
505 }
506 case 3:
507 {
508 *red=QuantumRange*min;
509 *green=QuantumRange*(min+x);
510 *blue=QuantumRange*(min+c);
511 break;
512 }
513 case 4:
514 {
515 *red=QuantumRange*(min+x);
516 *green=QuantumRange*min;
517 *blue=QuantumRange*(min+c);
518 break;
519 }
520 case 5:
521 {
522 *red=QuantumRange*(min+c);
523 *green=QuantumRange*min;
524 *blue=QuantumRange*(min+x);
525 break;
526 }
527 default:
528 {
529 *red=0.0;
530 *green=0.0;
531 *blue=0.0;
532 }
533 }
cristy3ed852e2009-09-05 21:47:34 +0000534}
535
536/*
537%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
538% %
539% %
540% %
cristy246c3132013-05-02 16:35:53 +0000541% C o n v e r t H S V T o R G B %
542% %
543% %
544% %
545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
546%
547% ConvertHSVToRGB() transforms a (hue, saturation, value) to a (red,
548% green, blue) triple.
549%
550% The format of the ConvertHSVToRGBImage method is:
551%
552% void ConvertHSVToRGB(const double hue,const double saturation,
553% const double value,double *red,double *green,double *blue)
554%
555% A description of each parameter follows:
556%
557% o hue, saturation, value: A double value representing a
558% component of the HSV color space.
559%
560% o red, green, blue: A pointer to a pixel component of type Quantum.
561%
562*/
563MagickPrivate void ConvertHSVToRGB(const double hue,const double saturation,
564 const double value,double *red,double *green,double *blue)
565{
566 double
567 c,
568 h,
569 min,
570 x;
571
572 /*
573 Convert HSV to RGB colorspace.
574 */
575 assert(red != (double *) NULL);
576 assert(green != (double *) NULL);
577 assert(blue != (double *) NULL);
578 h=hue*360.0;
579 c=value*saturation;
580 min=value-c;
581 h-=360.0*floor(h/360.0);
582 h/=60.0;
583 x=c*(1.0-fabs(h-2.0*floor(h/2.0)-1.0));
584 switch ((int) floor(h))
585 {
586 case 0:
587 {
588 *red=QuantumRange*(min+c);
589 *green=QuantumRange*(min+x);
590 *blue=QuantumRange*min;
591 break;
592 }
593 case 1:
594 {
595 *red=QuantumRange*(min+x);
596 *green=QuantumRange*(min+c);
597 *blue=QuantumRange*min;
598 break;
599 }
600 case 2:
601 {
602 *red=QuantumRange*min;
603 *green=QuantumRange*(min+c);
604 *blue=QuantumRange*(min+x);
605 break;
606 }
607 case 3:
608 {
609 *red=QuantumRange*min;
610 *green=QuantumRange*(min+x);
611 *blue=QuantumRange*(min+c);
612 break;
613 }
614 case 4:
615 {
616 *red=QuantumRange*(min+x);
617 *green=QuantumRange*min;
618 *blue=QuantumRange*(min+c);
619 break;
620 }
621 case 5:
622 {
623 *red=QuantumRange*(min+c);
624 *green=QuantumRange*min;
625 *blue=QuantumRange*(min+x);
626 break;
627 }
628 default:
629 {
630 *red=0.0;
631 *green=0.0;
632 *blue=0.0;
633 }
634 }
635}
636
637/*
638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
639% %
640% %
641% %
cristy0a39a5c2012-06-27 12:51:45 +0000642% C o n v e r t H W B T o R G B %
cristy3ed852e2009-09-05 21:47:34 +0000643% %
644% %
645% %
646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
647%
cristy0a39a5c2012-06-27 12:51:45 +0000648% ConvertHWBToRGB() transforms a (hue, whiteness, blackness) to a (red, green,
cristy3ed852e2009-09-05 21:47:34 +0000649% blue) triple.
650%
cristy0a39a5c2012-06-27 12:51:45 +0000651% The format of the ConvertHWBToRGBImage method is:
cristy3ed852e2009-09-05 21:47:34 +0000652%
cristy0a39a5c2012-06-27 12:51:45 +0000653% void ConvertHWBToRGB(const double hue,const double whiteness,
cristy3094b7f2011-10-01 23:18:02 +0000654% const double blackness,double *red,double *green,double *blue)
cristy3ed852e2009-09-05 21:47:34 +0000655%
656% A description of each parameter follows:
657%
658% o hue, whiteness, blackness: A double value representing a
659% component of the HWB color space.
660%
661% o red, green, blue: A pointer to a pixel component of type Quantum.
662%
663*/
cristy0a39a5c2012-06-27 12:51:45 +0000664MagickPrivate void ConvertHWBToRGB(const double hue,const double whiteness,
cristy3094b7f2011-10-01 23:18:02 +0000665 const double blackness,double *red,double *green,double *blue)
cristy3ed852e2009-09-05 21:47:34 +0000666{
cristycaf45802012-06-16 18:28:54 +0000667 double
cristy3ed852e2009-09-05 21:47:34 +0000668 b,
669 f,
670 g,
671 n,
672 r,
673 v;
674
cristybb503372010-05-27 20:51:26 +0000675 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000676 i;
677
678 /*
679 Convert HWB to RGB colorspace.
680 */
cristy3094b7f2011-10-01 23:18:02 +0000681 assert(red != (double *) NULL);
682 assert(green != (double *) NULL);
683 assert(blue != (double *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000684 v=1.0-blackness;
cristyaf10b112012-04-18 13:25:37 +0000685 if (hue == -1.0)
cristy3ed852e2009-09-05 21:47:34 +0000686 {
cristy0a39a5c2012-06-27 12:51:45 +0000687 *red=QuantumRange*v;
688 *green=QuantumRange*v;
689 *blue=QuantumRange*v;
cristy3ed852e2009-09-05 21:47:34 +0000690 return;
691 }
cristybb503372010-05-27 20:51:26 +0000692 i=(ssize_t) floor(6.0*hue);
cristy3ed852e2009-09-05 21:47:34 +0000693 f=6.0*hue-i;
694 if ((i & 0x01) != 0)
695 f=1.0-f;
696 n=whiteness+f*(v-whiteness); /* linear interpolation */
697 switch (i)
698 {
699 default:
700 case 6:
701 case 0: r=v; g=n; b=whiteness; break;
702 case 1: r=n; g=v; b=whiteness; break;
703 case 2: r=whiteness; g=v; b=n; break;
704 case 3: r=whiteness; g=n; b=v; break;
705 case 4: r=n; g=whiteness; b=v; break;
706 case 5: r=v; g=whiteness; b=n; break;
707 }
cristy0a39a5c2012-06-27 12:51:45 +0000708 *red=QuantumRange*r;
709 *green=QuantumRange*g;
710 *blue=QuantumRange*b;
cristy3ed852e2009-09-05 21:47:34 +0000711}
712
713/*
714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
715% %
716% %
717% %
cristydf42b172013-04-05 13:35:37 +0000718% C o n v e r t L C H a b T o R G B %
cristyb2850952013-04-04 19:00:52 +0000719% %
720% %
721% %
722%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
723%
cristydf42b172013-04-05 13:35:37 +0000724% ConvertLCHabToRGB() transforms a (luma, chroma, hue) to a (red, green,
cristyb2850952013-04-04 19:00:52 +0000725% blue) triple.
726%
cristydf42b172013-04-05 13:35:37 +0000727% The format of the ConvertLCHabToRGBImage method is:
cristyb2850952013-04-04 19:00:52 +0000728%
cristydf42b172013-04-05 13:35:37 +0000729% void ConvertLCHabToRGB(const double luma,const double chroma,
cristyb2850952013-04-04 19:00:52 +0000730% const double hue,double *red,double *green,double *blue)
731%
732% A description of each parameter follows:
733%
cristydf42b172013-04-05 13:35:37 +0000734% o luma, chroma, hue: A double value representing a component of the
735% LCHab color space.
cristyb2850952013-04-04 19:00:52 +0000736%
737% o red, green, blue: A pointer to a pixel component of type Quantum.
738%
739*/
cristy35605e92013-05-06 11:33:57 +0000740
741static inline void ConvertLCHabToXYZ(const double luma,const double chroma,
742 const double hue,double *X,double *Y,double *Z)
743{
744 ConvertLabToXYZ(luma,chroma*cos(hue*MagickPI/180.0),chroma*
745 sin(hue*MagickPI/180.0),X,Y,Z);
746}
747
cristydf42b172013-04-05 13:35:37 +0000748MagickPrivate void ConvertLCHabToRGB(const double luma,const double chroma,
cristyb2850952013-04-04 19:00:52 +0000749 const double hue,double *red,double *green,double *blue)
750{
751 double
cristyb2850952013-04-04 19:00:52 +0000752 X,
753 Y,
754 Z;
755
756 /*
cristydf42b172013-04-05 13:35:37 +0000757 Convert LCHab to RGB colorspace.
cristyb2850952013-04-04 19:00:52 +0000758 */
759 assert(red != (double *) NULL);
760 assert(green != (double *) NULL);
761 assert(blue != (double *) NULL);
cristy35605e92013-05-06 11:33:57 +0000762 ConvertLCHabToXYZ(luma*100.0,255.0*(chroma-0.5),255.0*(hue-0.5),&X,&Y,&Z);
cristyb2850952013-04-04 19:00:52 +0000763 ConvertXYZToRGB(X,Y,Z,red,green,blue);
764}
765
766/*
767%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
768% %
769% %
770% %
cristydf42b172013-04-05 13:35:37 +0000771% C o n v e r t L C H u v T o R G B %
772% %
773% %
774% %
775%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
776%
777% ConvertLCHuvToRGB() transforms a (luma, chroma, hue) to a (red, green,
778% blue) triple.
779%
780% The format of the ConvertLCHuvToRGBImage method is:
781%
782% void ConvertLCHuvToRGB(const double luma,const double chroma,
783% const double hue,double *red,double *green,double *blue)
784%
785% A description of each parameter follows:
786%
787% o luma, chroma, hue: A double value representing a component of the
788% LCHuv color space.
789%
790% o red, green, blue: A pointer to a pixel component of type Quantum.
791%
792*/
cristya8716912013-05-06 12:04:10 +0000793
794static inline void ConvertLCHuvToXYZ(const double luma,const double chroma,
795 const double hue,double *X,double *Y,double *Z)
796{
797 ConvertLuvToXYZ(luma,chroma*cos(hue*MagickPI/180.0),chroma*
798 sin(hue*MagickPI/180.0),X,Y,Z);
799}
800
cristydf42b172013-04-05 13:35:37 +0000801MagickPrivate void ConvertLCHuvToRGB(const double luma,const double chroma,
802 const double hue,double *red,double *green,double *blue)
803{
804 double
cristydf42b172013-04-05 13:35:37 +0000805 X,
806 Y,
807 Z;
808
809 /*
810 Convert LCHuv to RGB colorspace.
811 */
812 assert(red != (double *) NULL);
813 assert(green != (double *) NULL);
814 assert(blue != (double *) NULL);
cristya8716912013-05-06 12:04:10 +0000815 ConvertLCHuvToXYZ(100.0*luma,354.0*chroma-134.0,262.0*hue-140.0,&X,&Y,&Z);
cristydf42b172013-04-05 13:35:37 +0000816 ConvertXYZToRGB(X,Y,Z,red,green,blue);
817}
818
819/*
820%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
821% %
822% %
823% %
cristy722fc0c2012-08-04 23:15:43 +0000824% C o n v e r t R G B T o H C L %
825% %
826% %
827% %
828%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
829%
830% ConvertRGBToHCL() transforms a (red, green, blue) to a (hue, chroma,
831% luma) triple.
832%
833% The format of the ConvertRGBToHCL method is:
834%
835% void ConvertRGBToHCL(const double red,const double green,
836% const double blue,double *hue,double *chroma,double *luma)
837%
838% A description of each parameter follows:
839%
840% o red, green, blue: A Quantum value representing the red, green, and
841% blue component of a pixel.
842%
843% o hue, chroma, luma: A pointer to a double value representing a
844% component of the HCL color space.
845%
846*/
cristy5756d822013-04-09 01:14:34 +0000847
848static inline double MagickMax(const double x,const double y)
849{
850 if (x > y)
851 return(x);
852 return(y);
853}
854
855static inline double MagickMin(const double x,const double y)
856{
857 if (x < y)
858 return(x);
859 return(y);
860}
861
cristy722fc0c2012-08-04 23:15:43 +0000862MagickPrivate void ConvertRGBToHCL(const double red,const double green,
863 const double blue,double *hue,double *chroma,double *luma)
864{
865 double
cristy5756d822013-04-09 01:14:34 +0000866 b,
867 c,
868 g,
869 h,
870 max,
871 r;
cristy722fc0c2012-08-04 23:15:43 +0000872
873 /*
874 Convert RGB to HCL colorspace.
875 */
cristy9427c422013-04-08 12:03:11 +0000876 assert(hue != (double *) NULL);
cristy5756d822013-04-09 01:14:34 +0000877 assert(chroma != (double *) NULL);
878 assert(luma != (double *) NULL);
879 r=red;
880 g=green;
881 b=blue;
882 max=MagickMax(r,MagickMax(g,b));
883 c=max-(double) MagickMin(r,MagickMin(g,b));
884 h=0.0;
885 if (c == 0.0)
886 h=0.0;
887 else
888 if (red == max)
889 h=fmod((g-b)/c+6.0,6.0);
890 else
891 if (green == max)
892 h=((b-r)/c)+2.0;
893 else
894 if (blue == max)
895 h=((r-g)/c)+4.0;
896 *hue=(h/6.0);
897 *chroma=QuantumScale*c;
cristy9e2436a2013-05-02 20:35:59 +0000898 *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
899}
900
901/*
902%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
903% %
904% %
905% %
906% C o n v e r t R G B T o H C L p %
907% %
908% %
909% %
910%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
911%
912% ConvertRGBToHCLp() transforms a (red, green, blue) to a (hue, chroma,
913% luma) triple.
914%
915% The format of the ConvertRGBToHCLp method is:
916%
917% void ConvertRGBToHCLp(const double red,const double green,
918% const double blue,double *hue,double *chroma,double *luma)
919%
920% A description of each parameter follows:
921%
922% o red, green, blue: A Quantum value representing the red, green, and
923% blue component of a pixel.
924%
925% o hue, chroma, luma: A pointer to a double value representing a
926% component of the HCL color space.
927%
928*/
929MagickPrivate void ConvertRGBToHCLp(const double red,const double green,
930 const double blue,double *hue,double *chroma,double *luma)
931{
932 double
933 b,
934 c,
935 g,
936 h,
937 max,
938 r;
939
940 /*
941 Convert RGB to HCL colorspace.
942 */
943 assert(hue != (double *) NULL);
944 assert(chroma != (double *) NULL);
945 assert(luma != (double *) NULL);
946 r=red;
947 g=green;
948 b=blue;
949 max=MagickMax(r,MagickMax(g,b));
950 c=max-(double) MagickMin(r,MagickMin(g,b));
951 h=0.0;
952 if (c == 0.0)
953 h=0.0;
954 else
955 if (red == max)
956 h=fmod((g-b)/c+6.0,6.0);
957 else
958 if (green == max)
959 h=((b-r)/c)+2.0;
960 else
961 if (blue == max)
962 h=((r-g)/c)+4.0;
963 *hue=(h/6.0);
964 *chroma=QuantumScale*c;
965 *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
cristy722fc0c2012-08-04 23:15:43 +0000966}
967
968/*
969%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
970% %
971% %
972% %
cristy0a39a5c2012-06-27 12:51:45 +0000973% C o n v e r t R G B T o H S B %
cristy3ed852e2009-09-05 21:47:34 +0000974% %
975% %
976% %
977%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
978%
cristy0a39a5c2012-06-27 12:51:45 +0000979% ConvertRGBToHSB() transforms a (red, green, blue) to a (hue, saturation,
cristy3ed852e2009-09-05 21:47:34 +0000980% brightness) triple.
981%
cristy0a39a5c2012-06-27 12:51:45 +0000982% The format of the ConvertRGBToHSB method is:
cristy3ed852e2009-09-05 21:47:34 +0000983%
cristy0a39a5c2012-06-27 12:51:45 +0000984% void ConvertRGBToHSB(const double red,const double green,
cristy3094b7f2011-10-01 23:18:02 +0000985% const double blue,double *hue,double *saturation,double *brightness)
cristy3ed852e2009-09-05 21:47:34 +0000986%
987% A description of each parameter follows:
988%
989% o red, green, blue: A Quantum value representing the red, green, and
990% blue component of a pixel..
991%
992% o hue, saturation, brightness: A pointer to a double value representing a
993% component of the HSB color space.
994%
995*/
cristy0a39a5c2012-06-27 12:51:45 +0000996MagickPrivate void ConvertRGBToHSB(const double red,const double green,
cristy3094b7f2011-10-01 23:18:02 +0000997 const double blue,double *hue,double *saturation,double *brightness)
cristy3ed852e2009-09-05 21:47:34 +0000998{
cristycaf45802012-06-16 18:28:54 +0000999 double
1000 b,
cristy3ed852e2009-09-05 21:47:34 +00001001 delta,
cristycaf45802012-06-16 18:28:54 +00001002 g,
cristy3ed852e2009-09-05 21:47:34 +00001003 max,
cristycaf45802012-06-16 18:28:54 +00001004 min,
1005 r;
cristy3ed852e2009-09-05 21:47:34 +00001006
1007 /*
1008 Convert RGB to HSB colorspace.
1009 */
1010 assert(hue != (double *) NULL);
1011 assert(saturation != (double *) NULL);
1012 assert(brightness != (double *) NULL);
1013 *hue=0.0;
1014 *saturation=0.0;
1015 *brightness=0.0;
cristy0a39a5c2012-06-27 12:51:45 +00001016 r=red;
1017 g=green;
1018 b=blue;
cristycaf45802012-06-16 18:28:54 +00001019 min=r < g ? r : g;
1020 if (b < min)
1021 min=b;
1022 max=r > g ? r : g;
1023 if (b > max)
1024 max=b;
cristy3ed852e2009-09-05 21:47:34 +00001025 if (max == 0.0)
1026 return;
1027 delta=max-min;
cristycaf45802012-06-16 18:28:54 +00001028 *saturation=delta/max;
1029 *brightness=QuantumScale*max;
cristy3ed852e2009-09-05 21:47:34 +00001030 if (delta == 0.0)
1031 return;
cristycaf45802012-06-16 18:28:54 +00001032 if (r == max)
1033 *hue=(g-b)/delta;
cristy3ed852e2009-09-05 21:47:34 +00001034 else
cristycaf45802012-06-16 18:28:54 +00001035 if (g == max)
1036 *hue=2.0+(b-r)/delta;
cristy3ed852e2009-09-05 21:47:34 +00001037 else
cristycaf45802012-06-16 18:28:54 +00001038 *hue=4.0+(r-g)/delta;
cristy18b17442009-10-25 18:36:48 +00001039 *hue/=6.0;
cristy3ed852e2009-09-05 21:47:34 +00001040 if (*hue < 0.0)
1041 *hue+=1.0;
1042}
1043
1044/*
1045%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1046% %
1047% %
1048% %
cristyaf64eb22013-05-02 14:07:10 +00001049% C o n v e r t R G B T o H S I %
1050% %
1051% %
1052% %
1053%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1054%
1055% ConvertRGBToHSI() transforms a (red, green, blue) to a (hue, saturation,
1056% intensity) triple.
1057%
1058% The format of the ConvertRGBToHSI method is:
1059%
1060% void ConvertRGBToHSI(const double red,const double green,
1061% const double blue,double *hue,double *saturation,double *intensity)
1062%
1063% A description of each parameter follows:
1064%
1065% o red, green, blue: A Quantum value representing the red, green, and
1066% blue component of a pixel..
1067%
1068% o hue, saturation, intensity: A pointer to a double value representing a
1069% component of the HSI color space.
1070%
1071*/
1072MagickPrivate void ConvertRGBToHSI(const double red,const double green,
1073 const double blue,double *hue,double *saturation,double *intensity)
1074{
1075 double
1076 alpha,
1077 beta;
1078
1079 /*
1080 Convert RGB to HSI colorspace.
1081 */
1082 assert(hue != (double *) NULL);
1083 assert(saturation != (double *) NULL);
1084 assert(intensity != (double *) NULL);
1085 *intensity=(QuantumScale*red+QuantumScale*green+QuantumScale*blue)/3.0;
1086 if (*intensity <= 0.0)
1087 {
1088 *hue=0.0;
1089 *saturation=0.0;
cristya5a45a72013-05-02 16:06:57 +00001090 return;
cristyaf64eb22013-05-02 14:07:10 +00001091 }
cristya5a45a72013-05-02 16:06:57 +00001092 *saturation=1.0-MagickMin(QuantumScale*red,MagickMin(QuantumScale*green,
1093 QuantumScale*blue))/(*intensity);
1094 alpha=0.5*(2.0*QuantumScale*red-QuantumScale*green-QuantumScale*blue);
cristybe708af2013-05-02 23:42:41 +00001095 beta=0.8660254037844385*(QuantumScale*green-QuantumScale*blue);
cristya5a45a72013-05-02 16:06:57 +00001096 *hue=atan2(beta,alpha)*(180.0/MagickPI)/360.0;
1097 if (*hue < 0.0)
1098 *hue+=1.0;
cristyaf64eb22013-05-02 14:07:10 +00001099}
1100
1101/*
1102%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1103% %
1104% %
1105% %
cristy0a39a5c2012-06-27 12:51:45 +00001106% C o n v e r t R G B T o H S L %
cristy3ed852e2009-09-05 21:47:34 +00001107% %
1108% %
1109% %
1110%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1111%
cristy0a39a5c2012-06-27 12:51:45 +00001112% ConvertRGBToHSL() transforms a (red, green, blue) to a (hue, saturation,
cristy3ed852e2009-09-05 21:47:34 +00001113% lightness) triple.
1114%
cristy0a39a5c2012-06-27 12:51:45 +00001115% The format of the ConvertRGBToHSL method is:
cristy3ed852e2009-09-05 21:47:34 +00001116%
cristy0a39a5c2012-06-27 12:51:45 +00001117% void ConvertRGBToHSL(const double red,const double green,
cristy3094b7f2011-10-01 23:18:02 +00001118% const double blue,double *hue,double *saturation,double *lightness)
cristy3ed852e2009-09-05 21:47:34 +00001119%
1120% A description of each parameter follows:
1121%
1122% o red, green, blue: A Quantum value representing the red, green, and
1123% blue component of a pixel..
1124%
1125% o hue, saturation, lightness: A pointer to a double value representing a
1126% component of the HSL color space.
1127%
1128*/
cristy0a39a5c2012-06-27 12:51:45 +00001129MagickExport void ConvertRGBToHSL(const double red,const double green,
cristy3094b7f2011-10-01 23:18:02 +00001130 const double blue,double *hue,double *saturation,double *lightness)
cristy3ed852e2009-09-05 21:47:34 +00001131{
cristycaf45802012-06-16 18:28:54 +00001132 double
cristya5a45a72013-05-02 16:06:57 +00001133 c,
cristy3ed852e2009-09-05 21:47:34 +00001134 max,
cristya5a45a72013-05-02 16:06:57 +00001135 min;
cristy3ed852e2009-09-05 21:47:34 +00001136
1137 /*
1138 Convert RGB to HSL colorspace.
1139 */
1140 assert(hue != (double *) NULL);
1141 assert(saturation != (double *) NULL);
1142 assert(lightness != (double *) NULL);
cristya5a45a72013-05-02 16:06:57 +00001143 max=MagickMax(QuantumScale*red,MagickMax(QuantumScale*green,
1144 QuantumScale*blue));
1145 min=MagickMin(QuantumScale*red,MagickMin(QuantumScale*green,
1146 QuantumScale*blue));
1147 c=max-min;
1148 *lightness=(max+min)/2.0;
1149 if (c <= 0.0)
cristy3ed852e2009-09-05 21:47:34 +00001150 {
1151 *hue=0.0;
1152 *saturation=0.0;
1153 return;
1154 }
cristya5a45a72013-05-02 16:06:57 +00001155 if (max == (QuantumScale*red))
1156 {
1157 *hue=(QuantumScale*green-QuantumScale*blue)/c;
1158 if ((QuantumScale*green) < (QuantumScale*blue))
1159 *hue+=6.0;
1160 }
cristy3ed852e2009-09-05 21:47:34 +00001161 else
cristya5a45a72013-05-02 16:06:57 +00001162 if (max == (QuantumScale*green))
1163 *hue=2.0+(QuantumScale*blue-QuantumScale*red)/c;
cristy3ed852e2009-09-05 21:47:34 +00001164 else
cristya5a45a72013-05-02 16:06:57 +00001165 *hue=4.0+(QuantumScale*red-QuantumScale*green)/c;
1166 *hue*=60.0/360.0;
1167 if (*lightness <= 0.5)
1168 *saturation=c/(2.0*(*lightness));
1169 else
1170 *saturation=c/(2.0-2.0*(*lightness));
cristy3ed852e2009-09-05 21:47:34 +00001171}
1172
1173/*
1174%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1175% %
1176% %
1177% %
cristy246c3132013-05-02 16:35:53 +00001178% C o n v e r t R G B T o H S V %
1179% %
1180% %
1181% %
1182%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1183%
1184% ConvertRGBToHSV() transforms a (red, green, blue) to a (hue, saturation,
1185% value) triple.
1186%
1187% The format of the ConvertRGBToHSV method is:
1188%
1189% void ConvertRGBToHSV(const double red,const double green,
1190% const double blue,double *hue,double *saturation,double *value)
1191%
1192% A description of each parameter follows:
1193%
1194% o red, green, blue: A Quantum value representing the red, green, and
1195% blue component of a pixel..
1196%
1197% o hue, saturation, value: A pointer to a double value representing a
1198% component of the HSV color space.
1199%
1200*/
1201MagickPrivate void ConvertRGBToHSV(const double red,const double green,
1202 const double blue,double *hue,double *saturation,double *value)
1203{
1204 double
1205 c,
1206 max,
1207 min;
1208
1209 /*
1210 Convert RGB to HSV colorspace.
1211 */
1212 assert(hue != (double *) NULL);
1213 assert(saturation != (double *) NULL);
1214 assert(value != (double *) NULL);
1215 max=MagickMax(QuantumScale*red,MagickMax(QuantumScale*green,
1216 QuantumScale*blue));
1217 min=MagickMin(QuantumScale*red,MagickMin(QuantumScale*green,
1218 QuantumScale*blue));
1219 c=max-min;
1220 *value=max;
1221 if (c <= 0.0)
1222 {
1223 *hue=0.0;
1224 *saturation=0.0;
1225 return;
1226 }
1227 if (max == (QuantumScale*red))
1228 {
1229 *hue=(QuantumScale*green-QuantumScale*blue)/c;
1230 if ((QuantumScale*green) < (QuantumScale*blue))
1231 *hue+=6.0;
1232 }
1233 else
1234 if (max == (QuantumScale*green))
1235 *hue=2.0+(QuantumScale*blue-QuantumScale*red)/c;
1236 else
1237 *hue=4.0+(QuantumScale*red-QuantumScale*green)/c;
1238 *hue*=60.0/360.0;
1239 *saturation=c/max;
1240}
1241
1242/*
1243%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1244% %
1245% %
1246% %
cristy0a39a5c2012-06-27 12:51:45 +00001247% C o n v e r t R G B T o H W B %
cristy3ed852e2009-09-05 21:47:34 +00001248% %
1249% %
1250% %
1251%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1252%
cristy0a39a5c2012-06-27 12:51:45 +00001253% ConvertRGBToHWB() transforms a (red, green, blue) to a (hue, whiteness,
cristy3ed852e2009-09-05 21:47:34 +00001254% blackness) triple.
1255%
cristy0a39a5c2012-06-27 12:51:45 +00001256% The format of the ConvertRGBToHWB method is:
cristy3ed852e2009-09-05 21:47:34 +00001257%
cristy0a39a5c2012-06-27 12:51:45 +00001258% void ConvertRGBToHWB(const double red,const double green,
cristy3094b7f2011-10-01 23:18:02 +00001259% const double blue,double *hue,double *whiteness,double *blackness)
cristy3ed852e2009-09-05 21:47:34 +00001260%
1261% A description of each parameter follows:
1262%
1263% o red, green, blue: A Quantum value representing the red, green, and
1264% blue component of a pixel.
1265%
1266% o hue, whiteness, blackness: A pointer to a double value representing a
1267% component of the HWB color space.
1268%
1269*/
cristy0a39a5c2012-06-27 12:51:45 +00001270MagickPrivate void ConvertRGBToHWB(const double red,const double green,
cristy3094b7f2011-10-01 23:18:02 +00001271 const double blue,double *hue,double *whiteness,double *blackness)
cristy3ed852e2009-09-05 21:47:34 +00001272{
cristycaf45802012-06-16 18:28:54 +00001273 double
1274 b,
cristy3ed852e2009-09-05 21:47:34 +00001275 f,
cristycaf45802012-06-16 18:28:54 +00001276 g,
1277 p,
1278 r,
cristy3ed852e2009-09-05 21:47:34 +00001279 v,
1280 w;
1281
cristy3ed852e2009-09-05 21:47:34 +00001282 /*
1283 Convert RGB to HWB colorspace.
1284 */
1285 assert(hue != (double *) NULL);
1286 assert(whiteness != (double *) NULL);
1287 assert(blackness != (double *) NULL);
cristy0a39a5c2012-06-27 12:51:45 +00001288 r=red;
1289 g=green;
1290 b=blue;
cristycaf45802012-06-16 18:28:54 +00001291 w=MagickMin(r,MagickMin(g,b));
1292 v=MagickMax(r,MagickMax(g,b));
cristy3ed852e2009-09-05 21:47:34 +00001293 *blackness=1.0-QuantumScale*v;
1294 *whiteness=QuantumScale*w;
1295 if (v == w)
1296 {
cristyaf10b112012-04-18 13:25:37 +00001297 *hue=(-1.0);
cristy3ed852e2009-09-05 21:47:34 +00001298 return;
1299 }
cristycaf45802012-06-16 18:28:54 +00001300 f=(r == w) ? g-b : ((g == w) ? b-r : r-g);
1301 p=(r == w) ? 3.0 : ((g == w) ? 5.0 : 1.0);
1302 *hue=(p-f/(v-1.0*w))/6.0;
cristy3ed852e2009-09-05 21:47:34 +00001303}
1304
1305/*
1306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1307% %
1308% %
1309% %
cristya83d4c02013-04-19 19:39:30 +00001310% C o n v e r t R G B T o L C H a b %
cristyb2850952013-04-04 19:00:52 +00001311% %
1312% %
1313% %
1314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1315%
cristydf42b172013-04-05 13:35:37 +00001316% ConvertRGBToLCHab() transforms a (red, green, blue) to a (luma, chroma,
cristyb2850952013-04-04 19:00:52 +00001317% hue) triple.
1318%
cristydf42b172013-04-05 13:35:37 +00001319% The format of the ConvertRGBToLCHab method is:
cristyb2850952013-04-04 19:00:52 +00001320%
cristydf42b172013-04-05 13:35:37 +00001321% void ConvertRGBToLCHab(const double red,const double green,
cristyb2850952013-04-04 19:00:52 +00001322% 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*/
cristyc32cb022013-05-06 13:32:31 +00001333
1334static inline void ConvertXYZToLCHab(const double X,const double Y,
1335 const double Z,double *luma,double *chroma,double *hue)
1336{
1337 double
1338 a,
1339 b;
1340
1341 ConvertXYZToLab(X,Y,Z,luma,&a,&b);
cristy9db2dba2013-05-06 14:04:13 +00001342 *chroma=hypot(255.0*(a-0.5),255.0*(b-0.5));
1343 *hue=180.0*atan2(255.0*(b-0.5),255.0*(a-0.5))/MagickPI;
cristyc32cb022013-05-06 13:32:31 +00001344 if (*hue < 0.0)
1345 *hue+=360.0;
cristy9db2dba2013-05-06 14:04:13 +00001346 *chroma=(*chroma)/255.0+0.5;
1347 *hue=(*hue)/255.0+0.5;
cristyc32cb022013-05-06 13:32:31 +00001348}
1349
cristydf42b172013-04-05 13:35:37 +00001350MagickPrivate void ConvertRGBToLCHab(const double red,const double green,
cristyb2850952013-04-04 19:00:52 +00001351 const double blue,double *luma,double *chroma,double *hue)
1352{
1353 double
cristyb2850952013-04-04 19:00:52 +00001354 X,
1355 Y,
1356 Z;
1357
1358 /*
cristy9427c422013-04-08 12:03:11 +00001359 Convert RGB to LCHab colorspace.
cristyb2850952013-04-04 19:00:52 +00001360 */
1361 assert(luma != (double *) NULL);
1362 assert(chroma != (double *) NULL);
1363 assert(hue != (double *) NULL);
1364 ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
cristyc32cb022013-05-06 13:32:31 +00001365 ConvertXYZToLCHab(X,Y,Z,luma,chroma,hue);
cristyb2850952013-04-04 19:00:52 +00001366}
1367
1368/*
1369%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1370% %
1371% %
1372% %
cristya83d4c02013-04-19 19:39:30 +00001373% C o n v e r t R G B T o L C H u v %
cristydf42b172013-04-05 13:35:37 +00001374% %
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*/
cristyc32cb022013-05-06 13:32:31 +00001396
1397static inline void ConvertXYZToLCHuv(const double X,const double Y,
1398 const double Z,double *luma,double *chroma,double *hue)
1399{
1400 double
cristy9db2dba2013-05-06 14:04:13 +00001401 u,
1402 v;
cristyc32cb022013-05-06 13:32:31 +00001403
cristy9db2dba2013-05-06 14:04:13 +00001404 ConvertXYZToLuv(X,Y,Z,luma,&u,&v);
1405 *chroma=hypot(354.0*u-134.0,262.0*v-140.0);
1406 *hue=180.0*atan2(262.0*v-140.0,354.0*u-134.0)/MagickPI;
cristyc32cb022013-05-06 13:32:31 +00001407 if (*hue < 0.0)
1408 *hue+=360.0;
cristy9db2dba2013-05-06 14:04:13 +00001409 *chroma=(*chroma+134.0)/354.0;
1410 *hue=(*hue+140.0)/262.0;
cristyc32cb022013-05-06 13:32:31 +00001411}
1412
cristydf42b172013-04-05 13:35:37 +00001413MagickPrivate void ConvertRGBToLCHuv(const double red,const double green,
1414 const double blue,double *luma,double *chroma,double *hue)
1415{
1416 double
cristydf42b172013-04-05 13:35:37 +00001417 X,
1418 Y,
1419 Z;
1420
1421 /*
cristy9427c422013-04-08 12:03:11 +00001422 Convert RGB to LCHuv colorspace.
cristydf42b172013-04-05 13:35:37 +00001423 */
1424 assert(luma != (double *) NULL);
1425 assert(chroma != (double *) NULL);
1426 assert(hue != (double *) NULL);
1427 ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
cristyc32cb022013-05-06 13:32:31 +00001428 ConvertXYZToLCHuv(X,Y,Z,luma,chroma,hue);
cristydf42b172013-04-05 13:35:37 +00001429}
1430
1431/*
1432%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1433% %
1434% %
1435% %
cristy3ed852e2009-09-05 21:47:34 +00001436% 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%
cristy2d7ffbb2013-04-19 19:43:01 +00001453% o expansion: ExpandAffine returns the affine's expansion factor.
cristy3ed852e2009-09-05 21:47:34 +00001454%
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%
cristy82b15832009-10-06 19:17:37 +00001475% GenerateDifferentialNoise() generates differentual noise.
cristy3ed852e2009-09-05 21:47:34 +00001476%
1477% The format of the GenerateDifferentialNoise method is:
1478%
1479% double GenerateDifferentialNoise(RandomInfo *random_info,
cristy9ed1f812011-10-08 02:00:08 +00001480% const Quantum pixel,const NoiseType noise_type,const double attenuate)
cristy3ed852e2009-09-05 21:47:34 +00001481%
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*/
cristy8ea81222011-09-04 10:33:32 +00001493MagickPrivate double GenerateDifferentialNoise(RandomInfo *random_info,
cristy9ed1f812011-10-08 02:00:08 +00001494 const Quantum pixel,const NoiseType noise_type,const double attenuate)
cristy3ed852e2009-09-05 21:47:34 +00001495{
cristy7118edf2011-10-08 13:33:25 +00001496#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)
cristy4ce9df62011-10-12 12:06:02 +00001501#define SigmaPoisson (attenuate*12.5)
cristy785eb592012-07-08 22:12:15 +00001502#define SigmaRandom (attenuate)
cristy7118edf2011-10-08 13:33:25 +00001503#define TauGaussian (attenuate*0.078125)
cristy3ed852e2009-09-05 21:47:34 +00001504
cristyadb41ca2009-10-22 15:02:28 +00001505 double
cristy3ed852e2009-09-05 21:47:34 +00001506 alpha,
1507 beta,
1508 noise,
1509 sigma;
1510
1511 alpha=GetPseudoRandomValue(random_info);
cristy3ed852e2009-09-05 21:47:34 +00001512 switch (noise_type)
1513 {
1514 case UniformNoise:
1515 default:
1516 {
cristy6bbabe62011-10-09 13:54:18 +00001517 noise=(double) (pixel+QuantumRange*SigmaUniform*(alpha-0.5));
cristy3ed852e2009-09-05 21:47:34 +00001518 break;
1519 }
1520 case GaussianNoise:
1521 {
cristyadb41ca2009-10-22 15:02:28 +00001522 double
cristy62faa602010-02-20 03:36:17 +00001523 gamma,
cristy3ed852e2009-09-05 21:47:34 +00001524 tau;
1525
cristyadb41ca2009-10-22 15:02:28 +00001526 if (alpha == 0.0)
1527 alpha=1.0;
cristy3ed852e2009-09-05 21:47:34 +00001528 beta=GetPseudoRandomValue(random_info);
cristy62faa602010-02-20 03:36:17 +00001529 gamma=sqrt(-2.0*log(alpha));
cristy55a91cd2010-12-01 00:57:40 +00001530 sigma=gamma*cos((double) (2.0*MagickPI*beta));
1531 tau=gamma*sin((double) (2.0*MagickPI*beta));
cristy6bbabe62011-10-09 13:54:18 +00001532 noise=(double) (pixel+sqrt((double) pixel)*SigmaGaussian*sigma+
1533 QuantumRange*TauGaussian*tau);
cristy3ed852e2009-09-05 21:47:34 +00001534 break;
1535 }
1536 case ImpulseNoise:
1537 {
1538 if (alpha < (SigmaImpulse/2.0))
1539 noise=0.0;
cristy37c24072011-10-08 01:26:00 +00001540 else
1541 if (alpha >= (1.0-(SigmaImpulse/2.0)))
1542 noise=(double) QuantumRange;
1543 else
1544 noise=(double) pixel;
cristy3ed852e2009-09-05 21:47:34 +00001545 break;
1546 }
1547 case LaplacianNoise:
1548 {
1549 if (alpha <= 0.5)
1550 {
cristy7118edf2011-10-08 13:33:25 +00001551 if (alpha <= MagickEpsilon)
cristy6bbabe62011-10-09 13:54:18 +00001552 noise=(double) (pixel-QuantumRange);
cristy3ed852e2009-09-05 21:47:34 +00001553 else
cristy785eb592012-07-08 22:12:15 +00001554 noise=(double) (pixel+QuantumRange*SigmaLaplacian*log(2.0*alpha)+
1555 0.5);
cristy3ed852e2009-09-05 21:47:34 +00001556 break;
1557 }
1558 beta=1.0-alpha;
cristy7118edf2011-10-08 13:33:25 +00001559 if (beta <= (0.5*MagickEpsilon))
cristyadb41ca2009-10-22 15:02:28 +00001560 noise=(double) (pixel+QuantumRange);
cristy3ed852e2009-09-05 21:47:34 +00001561 else
cristy6bbabe62011-10-09 13:54:18 +00001562 noise=(double) (pixel-QuantumRange*SigmaLaplacian*log(2.0*beta)+0.5);
cristy7118edf2011-10-08 13:33:25 +00001563 break;
1564 }
1565 case MultiplicativeGaussianNoise:
1566 {
1567 sigma=1.0;
1568 if (alpha > MagickEpsilon)
1569 sigma=sqrt(-2.0*log(alpha));
1570 beta=GetPseudoRandomValue(random_info);
cristy6bbabe62011-10-09 13:54:18 +00001571 noise=(double) (pixel+pixel*SigmaMultiplicativeGaussian*sigma*
1572 cos((double) (2.0*MagickPI*beta))/2.0);
cristy3ed852e2009-09-05 21:47:34 +00001573 break;
1574 }
1575 case PoissonNoise:
1576 {
cristyadb41ca2009-10-22 15:02:28 +00001577 double
cristy3ed852e2009-09-05 21:47:34 +00001578 poisson;
1579
cristybb503372010-05-27 20:51:26 +00001580 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001581 i;
1582
cristy7118edf2011-10-08 13:33:25 +00001583 poisson=exp(-SigmaPoisson*QuantumScale*pixel);
cristy3ed852e2009-09-05 21:47:34 +00001584 for (i=0; alpha > poisson; i++)
1585 {
1586 beta=GetPseudoRandomValue(random_info);
1587 alpha*=beta;
1588 }
cristy6bbabe62011-10-09 13:54:18 +00001589 noise=(double) (QuantumRange*i/SigmaPoisson);
cristy3ed852e2009-09-05 21:47:34 +00001590 break;
1591 }
1592 case RandomNoise:
1593 {
cristy785eb592012-07-08 22:12:15 +00001594 noise=(double) (QuantumRange*SigmaRandom*alpha);
cristy3ed852e2009-09-05 21:47:34 +00001595 break;
1596 }
1597 }
1598 return(noise);
1599}
1600
1601/*
1602%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1603% %
1604% %
1605% %
1606% G e t O p t i m a l K e r n e l W i d t h %
1607% %
1608% %
1609% %
1610%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1611%
1612% GetOptimalKernelWidth() computes the optimal kernel radius for a convolution
1613% filter. Start with the minimum value of 3 pixels and walk out until we drop
1614% below the threshold of one pixel numerical accuracy.
1615%
1616% The format of the GetOptimalKernelWidth method is:
1617%
cristybb503372010-05-27 20:51:26 +00001618% size_t GetOptimalKernelWidth(const double radius,
cristy3ed852e2009-09-05 21:47:34 +00001619% const double sigma)
1620%
1621% A description of each parameter follows:
1622%
cristy2d7ffbb2013-04-19 19:43:01 +00001623% o width: GetOptimalKernelWidth returns the optimal width of a
1624% convolution kernel.
cristy3ed852e2009-09-05 21:47:34 +00001625%
1626% o radius: the radius of the Gaussian, in pixels, not counting the center
1627% pixel.
1628%
1629% o sigma: the standard deviation of the Gaussian, in pixels.
1630%
1631*/
cristy8ea81222011-09-04 10:33:32 +00001632MagickPrivate size_t GetOptimalKernelWidth1D(const double radius,
cristye96405a2010-05-19 02:24:31 +00001633 const double sigma)
cristy3ed852e2009-09-05 21:47:34 +00001634{
cristye96405a2010-05-19 02:24:31 +00001635 double
1636 alpha,
1637 beta,
1638 gamma,
cristy3ed852e2009-09-05 21:47:34 +00001639 normalize,
cristye96405a2010-05-19 02:24:31 +00001640 value;
cristy3ed852e2009-09-05 21:47:34 +00001641
cristybb503372010-05-27 20:51:26 +00001642 register ssize_t
cristy47e00502009-12-17 19:19:57 +00001643 i;
1644
cristybb503372010-05-27 20:51:26 +00001645 size_t
cristy47e00502009-12-17 19:19:57 +00001646 width;
cristy3ed852e2009-09-05 21:47:34 +00001647
cristy9d314ff2011-03-09 01:30:28 +00001648 ssize_t
1649 j;
1650
cristy3ed852e2009-09-05 21:47:34 +00001651 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristy47e00502009-12-17 19:19:57 +00001652 if (radius > MagickEpsilon)
cristybb503372010-05-27 20:51:26 +00001653 return((size_t) (2.0*ceil(radius)+1.0));
cristye96405a2010-05-19 02:24:31 +00001654 gamma=fabs(sigma);
1655 if (gamma <= MagickEpsilon)
anthonyc1061722010-05-14 06:23:49 +00001656 return(3UL);
cristy3e3ec3a2012-11-03 23:11:06 +00001657 alpha=PerceptibleReciprocal(2.0*gamma*gamma);
1658 beta=(double) PerceptibleReciprocal((double) MagickSQ2PI*gamma);
cristy3ed852e2009-09-05 21:47:34 +00001659 for (width=5; ; )
1660 {
1661 normalize=0.0;
cristy35faaa72013-03-08 12:33:42 +00001662 j=(ssize_t) (width-1)/2;
cristy47e00502009-12-17 19:19:57 +00001663 for (i=(-j); i <= j; i++)
cristye96405a2010-05-19 02:24:31 +00001664 normalize+=exp(-((double) (i*i))*alpha)*beta;
1665 value=exp(-((double) (j*j))*alpha)*beta/normalize;
cristy20908da2009-12-02 14:34:11 +00001666 if ((value < QuantumScale) || (value < MagickEpsilon))
cristy3ed852e2009-09-05 21:47:34 +00001667 break;
1668 width+=2;
1669 }
cristybb503372010-05-27 20:51:26 +00001670 return((size_t) (width-2));
cristy3ed852e2009-09-05 21:47:34 +00001671}
1672
cristy8ea81222011-09-04 10:33:32 +00001673MagickPrivate size_t GetOptimalKernelWidth2D(const double radius,
cristye96405a2010-05-19 02:24:31 +00001674 const double sigma)
cristy3ed852e2009-09-05 21:47:34 +00001675{
cristy47e00502009-12-17 19:19:57 +00001676 double
cristye96405a2010-05-19 02:24:31 +00001677 alpha,
1678 beta,
1679 gamma,
cristy3ed852e2009-09-05 21:47:34 +00001680 normalize,
cristye96405a2010-05-19 02:24:31 +00001681 value;
cristy3ed852e2009-09-05 21:47:34 +00001682
cristy9d314ff2011-03-09 01:30:28 +00001683 size_t
1684 width;
1685
cristybb503372010-05-27 20:51:26 +00001686 ssize_t
cristy47e00502009-12-17 19:19:57 +00001687 j,
cristy3ed852e2009-09-05 21:47:34 +00001688 u,
1689 v;
1690
1691 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristy47e00502009-12-17 19:19:57 +00001692 if (radius > MagickEpsilon)
cristybb503372010-05-27 20:51:26 +00001693 return((size_t) (2.0*ceil(radius)+1.0));
cristye96405a2010-05-19 02:24:31 +00001694 gamma=fabs(sigma);
1695 if (gamma <= MagickEpsilon)
anthonyc1061722010-05-14 06:23:49 +00001696 return(3UL);
cristy3e3ec3a2012-11-03 23:11:06 +00001697 alpha=PerceptibleReciprocal(2.0*gamma*gamma);
1698 beta=(double) PerceptibleReciprocal((double) Magick2PI*gamma*gamma);
cristy3ed852e2009-09-05 21:47:34 +00001699 for (width=5; ; )
1700 {
1701 normalize=0.0;
cristy35faaa72013-03-08 12:33:42 +00001702 j=(ssize_t) (width-1)/2;
cristy47e00502009-12-17 19:19:57 +00001703 for (v=(-j); v <= j; v++)
cristy47e00502009-12-17 19:19:57 +00001704 for (u=(-j); u <= j; u++)
cristye96405a2010-05-19 02:24:31 +00001705 normalize+=exp(-((double) (u*u+v*v))*alpha)*beta;
1706 value=exp(-((double) (j*j))*alpha)*beta/normalize;
cristy20908da2009-12-02 14:34:11 +00001707 if ((value < QuantumScale) || (value < MagickEpsilon))
cristy3ed852e2009-09-05 21:47:34 +00001708 break;
1709 width+=2;
1710 }
cristybb503372010-05-27 20:51:26 +00001711 return((size_t) (width-2));
cristy3ed852e2009-09-05 21:47:34 +00001712}
1713
cristy8ea81222011-09-04 10:33:32 +00001714MagickPrivate size_t GetOptimalKernelWidth(const double radius,
cristy3ed852e2009-09-05 21:47:34 +00001715 const double sigma)
1716{
1717 return(GetOptimalKernelWidth1D(radius,sigma));
1718}