blob: b82affa2a0f36a9b9851852cfbf829bb95a51d75 [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 %
cristyde984cd2013-12-01 14:49:27 +000016% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000017% August 1996 %
18% %
19% %
cristyb56bb242014-11-25 17:12:48 +000020% Copyright 1999-2015 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
cristybed2d4b2013-05-07 18:41:38 +0000393 b,
cristy6eb18172013-05-07 18:43:59 +0000394 g,
cristybed2d4b2013-05-07 18:41:38 +0000395 h,
396 r;
cristyaf64eb22013-05-02 14:07:10 +0000397
398 /*
399 Convert HSI to RGB colorspace.
400 */
401 assert(red != (double *) NULL);
402 assert(green != (double *) NULL);
403 assert(blue != (double *) NULL);
404 h=360.0*hue;
405 h-=360.0*floor(h/360.0);
406 if (h < 120.0)
407 {
cristybed2d4b2013-05-07 18:41:38 +0000408 b=intensity*(1.0-saturation);
409 r=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
cristyaf64eb22013-05-02 14:07:10 +0000410 (MagickPI/180.0)));
cristybed2d4b2013-05-07 18:41:38 +0000411 g=3.0*intensity-r-b;
cristyaf64eb22013-05-02 14:07:10 +0000412 }
413 else
414 if (h < 240.0)
415 {
416 h-=120.0;
cristybed2d4b2013-05-07 18:41:38 +0000417 r=intensity*(1.0-saturation);
418 g=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
cristyaf64eb22013-05-02 14:07:10 +0000419 (MagickPI/180.0)));
cristybed2d4b2013-05-07 18:41:38 +0000420 b=3.0*intensity-r-g;
cristyaf64eb22013-05-02 14:07:10 +0000421 }
422 else
423 {
424 h-=240.0;
cristybed2d4b2013-05-07 18:41:38 +0000425 g=intensity*(1.0-saturation);
426 b=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
cristyaf64eb22013-05-02 14:07:10 +0000427 (MagickPI/180.0)));
cristybed2d4b2013-05-07 18:41:38 +0000428 r=3.0*intensity-g-b;
cristyaf64eb22013-05-02 14:07:10 +0000429 }
cristybed2d4b2013-05-07 18:41:38 +0000430 *red=QuantumRange*r;
431 *green=QuantumRange*g;
432 *blue=QuantumRange*b;
cristyaf64eb22013-05-02 14:07:10 +0000433}
434
435/*
436%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
437% %
438% %
439% %
cristy0a39a5c2012-06-27 12:51:45 +0000440% C o n v e r t H S L T o R G B %
cristy3ed852e2009-09-05 21:47:34 +0000441% %
442% %
443% %
444%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
445%
cristy0a39a5c2012-06-27 12:51:45 +0000446% ConvertHSLToRGB() transforms a (hue, saturation, lightness) to a (red,
cristy3ed852e2009-09-05 21:47:34 +0000447% green, blue) triple.
448%
cristy0a39a5c2012-06-27 12:51:45 +0000449% The format of the ConvertHSLToRGBImage method is:
cristy3ed852e2009-09-05 21:47:34 +0000450%
cristy0a39a5c2012-06-27 12:51:45 +0000451% void ConvertHSLToRGB(const double hue,const double saturation,
cristy3094b7f2011-10-01 23:18:02 +0000452% const double lightness,double *red,double *green,double *blue)
cristy3ed852e2009-09-05 21:47:34 +0000453%
454% A description of each parameter follows:
455%
456% o hue, saturation, lightness: A double value representing a
457% component of the HSL color space.
458%
459% o red, green, blue: A pointer to a pixel component of type Quantum.
460%
461*/
cristy0a39a5c2012-06-27 12:51:45 +0000462MagickExport void ConvertHSLToRGB(const double hue,const double saturation,
cristy3094b7f2011-10-01 23:18:02 +0000463 const double lightness,double *red,double *green,double *blue)
cristy3ed852e2009-09-05 21:47:34 +0000464{
cristycaf45802012-06-16 18:28:54 +0000465 double
cristya5a45a72013-05-02 16:06:57 +0000466 c,
467 h,
468 min,
469 x;
cristy3ed852e2009-09-05 21:47:34 +0000470
471 /*
472 Convert HSL to RGB colorspace.
473 */
cristy3094b7f2011-10-01 23:18:02 +0000474 assert(red != (double *) NULL);
475 assert(green != (double *) NULL);
476 assert(blue != (double *) NULL);
cristya5a45a72013-05-02 16:06:57 +0000477 h=hue*360.0;
478 if (lightness <= 0.5)
479 c=2.0*lightness*saturation;
cristy98a65d52010-04-14 02:12:38 +0000480 else
cristya5a45a72013-05-02 16:06:57 +0000481 c=(2.0-2.0*lightness)*saturation;
482 min=lightness-0.5*c;
483 h-=360.0*floor(h/360.0);
484 h/=60.0;
485 x=c*(1.0-fabs(h-2.0*floor(h/2.0)-1.0));
486 switch ((int) floor(h))
487 {
488 case 0:
489 {
490 *red=QuantumRange*(min+c);
491 *green=QuantumRange*(min+x);
492 *blue=QuantumRange*min;
493 break;
494 }
495 case 1:
496 {
497 *red=QuantumRange*(min+x);
498 *green=QuantumRange*(min+c);
499 *blue=QuantumRange*min;
500 break;
501 }
502 case 2:
503 {
504 *red=QuantumRange*min;
505 *green=QuantumRange*(min+c);
506 *blue=QuantumRange*(min+x);
507 break;
508 }
509 case 3:
510 {
511 *red=QuantumRange*min;
512 *green=QuantumRange*(min+x);
513 *blue=QuantumRange*(min+c);
514 break;
515 }
516 case 4:
517 {
518 *red=QuantumRange*(min+x);
519 *green=QuantumRange*min;
520 *blue=QuantumRange*(min+c);
521 break;
522 }
523 case 5:
524 {
525 *red=QuantumRange*(min+c);
526 *green=QuantumRange*min;
527 *blue=QuantumRange*(min+x);
528 break;
529 }
530 default:
531 {
532 *red=0.0;
533 *green=0.0;
534 *blue=0.0;
535 }
536 }
cristy3ed852e2009-09-05 21:47:34 +0000537}
538
539/*
540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
541% %
542% %
543% %
cristy246c3132013-05-02 16:35:53 +0000544% C o n v e r t H S V T o R G B %
545% %
546% %
547% %
548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
549%
550% ConvertHSVToRGB() transforms a (hue, saturation, value) to a (red,
551% green, blue) triple.
552%
553% The format of the ConvertHSVToRGBImage method is:
554%
555% void ConvertHSVToRGB(const double hue,const double saturation,
556% const double value,double *red,double *green,double *blue)
557%
558% A description of each parameter follows:
559%
560% o hue, saturation, value: A double value representing a
561% component of the HSV color space.
562%
563% o red, green, blue: A pointer to a pixel component of type Quantum.
564%
565*/
566MagickPrivate void ConvertHSVToRGB(const double hue,const double saturation,
567 const double value,double *red,double *green,double *blue)
568{
569 double
570 c,
571 h,
572 min,
573 x;
574
575 /*
576 Convert HSV to RGB colorspace.
577 */
578 assert(red != (double *) NULL);
579 assert(green != (double *) NULL);
580 assert(blue != (double *) NULL);
581 h=hue*360.0;
582 c=value*saturation;
583 min=value-c;
584 h-=360.0*floor(h/360.0);
585 h/=60.0;
586 x=c*(1.0-fabs(h-2.0*floor(h/2.0)-1.0));
587 switch ((int) floor(h))
588 {
589 case 0:
590 {
591 *red=QuantumRange*(min+c);
592 *green=QuantumRange*(min+x);
593 *blue=QuantumRange*min;
594 break;
595 }
596 case 1:
597 {
598 *red=QuantumRange*(min+x);
599 *green=QuantumRange*(min+c);
600 *blue=QuantumRange*min;
601 break;
602 }
603 case 2:
604 {
605 *red=QuantumRange*min;
606 *green=QuantumRange*(min+c);
607 *blue=QuantumRange*(min+x);
608 break;
609 }
610 case 3:
611 {
612 *red=QuantumRange*min;
613 *green=QuantumRange*(min+x);
614 *blue=QuantumRange*(min+c);
615 break;
616 }
617 case 4:
618 {
619 *red=QuantumRange*(min+x);
620 *green=QuantumRange*min;
621 *blue=QuantumRange*(min+c);
622 break;
623 }
624 case 5:
625 {
626 *red=QuantumRange*(min+c);
627 *green=QuantumRange*min;
628 *blue=QuantumRange*(min+x);
629 break;
630 }
631 default:
632 {
633 *red=0.0;
634 *green=0.0;
635 *blue=0.0;
636 }
637 }
638}
639
640/*
641%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
642% %
643% %
644% %
cristy0a39a5c2012-06-27 12:51:45 +0000645% C o n v e r t H W B T o R G B %
cristy3ed852e2009-09-05 21:47:34 +0000646% %
647% %
648% %
649%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
650%
cristy0a39a5c2012-06-27 12:51:45 +0000651% ConvertHWBToRGB() transforms a (hue, whiteness, blackness) to a (red, green,
cristy3ed852e2009-09-05 21:47:34 +0000652% blue) triple.
653%
cristy0a39a5c2012-06-27 12:51:45 +0000654% The format of the ConvertHWBToRGBImage method is:
cristy3ed852e2009-09-05 21:47:34 +0000655%
cristy0a39a5c2012-06-27 12:51:45 +0000656% void ConvertHWBToRGB(const double hue,const double whiteness,
cristy3094b7f2011-10-01 23:18:02 +0000657% const double blackness,double *red,double *green,double *blue)
cristy3ed852e2009-09-05 21:47:34 +0000658%
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*/
cristy0a39a5c2012-06-27 12:51:45 +0000667MagickPrivate void ConvertHWBToRGB(const double hue,const double whiteness,
cristy3094b7f2011-10-01 23:18:02 +0000668 const double blackness,double *red,double *green,double *blue)
cristy3ed852e2009-09-05 21:47:34 +0000669{
cristycaf45802012-06-16 18:28:54 +0000670 double
cristy3ed852e2009-09-05 21:47:34 +0000671 b,
672 f,
673 g,
674 n,
675 r,
676 v;
677
cristybb503372010-05-27 20:51:26 +0000678 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000679 i;
680
681 /*
682 Convert HWB to RGB colorspace.
683 */
cristy3094b7f2011-10-01 23:18:02 +0000684 assert(red != (double *) NULL);
685 assert(green != (double *) NULL);
686 assert(blue != (double *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000687 v=1.0-blackness;
cristyaf10b112012-04-18 13:25:37 +0000688 if (hue == -1.0)
cristy3ed852e2009-09-05 21:47:34 +0000689 {
cristy0a39a5c2012-06-27 12:51:45 +0000690 *red=QuantumRange*v;
691 *green=QuantumRange*v;
692 *blue=QuantumRange*v;
cristy3ed852e2009-09-05 21:47:34 +0000693 return;
694 }
cristybb503372010-05-27 20:51:26 +0000695 i=(ssize_t) floor(6.0*hue);
cristy3ed852e2009-09-05 21:47:34 +0000696 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 default:
703 case 6:
704 case 0: r=v; g=n; b=whiteness; break;
705 case 1: r=n; g=v; b=whiteness; break;
706 case 2: r=whiteness; g=v; b=n; break;
707 case 3: r=whiteness; g=n; b=v; break;
708 case 4: r=n; g=whiteness; b=v; break;
709 case 5: r=v; g=whiteness; b=n; break;
710 }
cristy0a39a5c2012-06-27 12:51:45 +0000711 *red=QuantumRange*r;
712 *green=QuantumRange*g;
713 *blue=QuantumRange*b;
cristy3ed852e2009-09-05 21:47:34 +0000714}
715
716/*
717%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
718% %
719% %
720% %
cristydf42b172013-04-05 13:35:37 +0000721% C o n v e r t L C H a b T o R G B %
cristyb2850952013-04-04 19:00:52 +0000722% %
723% %
724% %
725%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
726%
cristydf42b172013-04-05 13:35:37 +0000727% ConvertLCHabToRGB() transforms a (luma, chroma, hue) to a (red, green,
cristyb2850952013-04-04 19:00:52 +0000728% blue) triple.
729%
cristydf42b172013-04-05 13:35:37 +0000730% The format of the ConvertLCHabToRGBImage method is:
cristyb2850952013-04-04 19:00:52 +0000731%
cristydf42b172013-04-05 13:35:37 +0000732% void ConvertLCHabToRGB(const double luma,const double chroma,
cristyb2850952013-04-04 19:00:52 +0000733% const double hue,double *red,double *green,double *blue)
734%
735% A description of each parameter follows:
736%
cristydf42b172013-04-05 13:35:37 +0000737% o luma, chroma, hue: A double value representing a component of the
738% LCHab color space.
cristyb2850952013-04-04 19:00:52 +0000739%
740% o red, green, blue: A pointer to a pixel component of type Quantum.
741%
742*/
cristy35605e92013-05-06 11:33:57 +0000743
744static inline void ConvertLCHabToXYZ(const double luma,const double chroma,
745 const double hue,double *X,double *Y,double *Z)
746{
747 ConvertLabToXYZ(luma,chroma*cos(hue*MagickPI/180.0),chroma*
748 sin(hue*MagickPI/180.0),X,Y,Z);
749}
750
cristydf42b172013-04-05 13:35:37 +0000751MagickPrivate void ConvertLCHabToRGB(const double luma,const double chroma,
cristyb2850952013-04-04 19:00:52 +0000752 const double hue,double *red,double *green,double *blue)
753{
754 double
cristyb2850952013-04-04 19:00:52 +0000755 X,
756 Y,
757 Z;
758
759 /*
cristydf42b172013-04-05 13:35:37 +0000760 Convert LCHab to RGB colorspace.
cristyb2850952013-04-04 19:00:52 +0000761 */
762 assert(red != (double *) NULL);
763 assert(green != (double *) NULL);
764 assert(blue != (double *) NULL);
cristy6d897c72013-06-19 19:20:40 +0000765 ConvertLCHabToXYZ(100.0*luma,255.0*(chroma-0.5),360.0*hue,&X,&Y,&Z);
cristyb2850952013-04-04 19:00:52 +0000766 ConvertXYZToRGB(X,Y,Z,red,green,blue);
767}
768
769/*
770%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
771% %
772% %
773% %
cristydf42b172013-04-05 13:35:37 +0000774% C o n v e r t L C H u v T o R G B %
775% %
776% %
777% %
778%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
779%
780% ConvertLCHuvToRGB() transforms a (luma, chroma, hue) to a (red, green,
781% blue) triple.
782%
783% The format of the ConvertLCHuvToRGBImage method is:
784%
785% void ConvertLCHuvToRGB(const double luma,const double chroma,
786% const double hue,double *red,double *green,double *blue)
787%
788% A description of each parameter follows:
789%
790% o luma, chroma, hue: A double value representing a component of the
791% LCHuv color space.
792%
793% o red, green, blue: A pointer to a pixel component of type Quantum.
794%
795*/
cristya8716912013-05-06 12:04:10 +0000796
797static inline void ConvertLCHuvToXYZ(const double luma,const double chroma,
798 const double hue,double *X,double *Y,double *Z)
799{
800 ConvertLuvToXYZ(luma,chroma*cos(hue*MagickPI/180.0),chroma*
801 sin(hue*MagickPI/180.0),X,Y,Z);
802}
803
cristydf42b172013-04-05 13:35:37 +0000804MagickPrivate void ConvertLCHuvToRGB(const double luma,const double chroma,
805 const double hue,double *red,double *green,double *blue)
806{
807 double
cristydf42b172013-04-05 13:35:37 +0000808 X,
809 Y,
810 Z;
811
812 /*
813 Convert LCHuv to RGB colorspace.
814 */
815 assert(red != (double *) NULL);
816 assert(green != (double *) NULL);
817 assert(blue != (double *) NULL);
cristy51199212013-06-19 23:40:01 +0000818 ConvertLCHuvToXYZ(100.0*luma,255.0*(chroma-0.5),360.0*hue,&X,&Y,&Z);
cristydf42b172013-04-05 13:35:37 +0000819 ConvertXYZToRGB(X,Y,Z,red,green,blue);
820}
821
822/*
823%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
824% %
825% %
826% %
cristy722fc0c2012-08-04 23:15:43 +0000827% C o n v e r t R G B T o H C L %
828% %
829% %
830% %
831%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
832%
833% ConvertRGBToHCL() transforms a (red, green, blue) to a (hue, chroma,
834% luma) triple.
835%
836% The format of the ConvertRGBToHCL method is:
837%
838% void ConvertRGBToHCL(const double red,const double green,
839% const double blue,double *hue,double *chroma,double *luma)
840%
841% A description of each parameter follows:
842%
843% o red, green, blue: A Quantum value representing the red, green, and
844% blue component of a pixel.
845%
846% o hue, chroma, luma: A pointer to a double value representing a
847% component of the HCL color space.
848%
849*/
850MagickPrivate void ConvertRGBToHCL(const double red,const double green,
851 const double blue,double *hue,double *chroma,double *luma)
852{
853 double
cristy5756d822013-04-09 01:14:34 +0000854 c,
cristy5756d822013-04-09 01:14:34 +0000855 h,
dirk568ce7a2015-04-11 13:17:06 +0000856 max;
cristy722fc0c2012-08-04 23:15:43 +0000857
858 /*
859 Convert RGB to HCL colorspace.
860 */
cristy9427c422013-04-08 12:03:11 +0000861 assert(hue != (double *) NULL);
cristy5756d822013-04-09 01:14:34 +0000862 assert(chroma != (double *) NULL);
863 assert(luma != (double *) NULL);
dirk568ce7a2015-04-11 13:17:06 +0000864 max=MagickMax(red,MagickMax(green,blue));
865 c=max-(double) MagickMin(red,MagickMin(green,blue));
cristy5756d822013-04-09 01:14:34 +0000866 h=0.0;
867 if (c == 0.0)
868 h=0.0;
869 else
870 if (red == max)
dirk568ce7a2015-04-11 13:17:06 +0000871 h=fmod((green-blue)/c+6.0,6.0);
cristy5756d822013-04-09 01:14:34 +0000872 else
873 if (green == max)
dirk568ce7a2015-04-11 13:17:06 +0000874 h=((blue-red)/c)+2.0;
cristy5756d822013-04-09 01:14:34 +0000875 else
876 if (blue == max)
dirk568ce7a2015-04-11 13:17:06 +0000877 h=((red-green)/c)+4.0;
cristy5756d822013-04-09 01:14:34 +0000878 *hue=(h/6.0);
879 *chroma=QuantumScale*c;
dirk568ce7a2015-04-11 13:17:06 +0000880 *luma=QuantumScale*(0.298839*red+0.586811*green+0.114350*blue);
cristy9e2436a2013-05-02 20:35:59 +0000881}
882
883/*
884%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
885% %
886% %
887% %
888% C o n v e r t R G B T o H C L p %
889% %
890% %
891% %
892%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
893%
894% ConvertRGBToHCLp() transforms a (red, green, blue) to a (hue, chroma,
895% luma) triple.
896%
897% The format of the ConvertRGBToHCLp method is:
898%
899% void ConvertRGBToHCLp(const double red,const double green,
900% const double blue,double *hue,double *chroma,double *luma)
901%
902% A description of each parameter follows:
903%
904% o red, green, blue: A Quantum value representing the red, green, and
905% blue component of a pixel.
906%
907% o hue, chroma, luma: A pointer to a double value representing a
908% component of the HCL color space.
909%
910*/
911MagickPrivate void ConvertRGBToHCLp(const double red,const double green,
912 const double blue,double *hue,double *chroma,double *luma)
913{
914 double
cristy9e2436a2013-05-02 20:35:59 +0000915 c,
cristy9e2436a2013-05-02 20:35:59 +0000916 h,
dirk568ce7a2015-04-11 13:17:06 +0000917 max;
cristy9e2436a2013-05-02 20:35:59 +0000918
919 /*
920 Convert RGB to HCL colorspace.
921 */
922 assert(hue != (double *) NULL);
923 assert(chroma != (double *) NULL);
924 assert(luma != (double *) NULL);
dirk568ce7a2015-04-11 13:17:06 +0000925 max=MagickMax(red,MagickMax(green,blue));
926 c=max-MagickMin(red,MagickMin(green,blue));
cristy9e2436a2013-05-02 20:35:59 +0000927 h=0.0;
928 if (c == 0.0)
929 h=0.0;
930 else
931 if (red == max)
dirk568ce7a2015-04-11 13:17:06 +0000932 h=fmod((green-blue)/c+6.0,6.0);
cristy9e2436a2013-05-02 20:35:59 +0000933 else
934 if (green == max)
dirk568ce7a2015-04-11 13:17:06 +0000935 h=((blue-red)/c)+2.0;
cristy9e2436a2013-05-02 20:35:59 +0000936 else
937 if (blue == max)
dirk568ce7a2015-04-11 13:17:06 +0000938 h=((red-green)/c)+4.0;
cristy9e2436a2013-05-02 20:35:59 +0000939 *hue=(h/6.0);
940 *chroma=QuantumScale*c;
dirk568ce7a2015-04-11 13:17:06 +0000941 *luma=QuantumScale*(0.298839*red+0.586811*green+0.114350*blue);
cristy722fc0c2012-08-04 23:15:43 +0000942}
943
944/*
945%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
946% %
947% %
948% %
cristy0a39a5c2012-06-27 12:51:45 +0000949% C o n v e r t R G B T o H S B %
cristy3ed852e2009-09-05 21:47:34 +0000950% %
951% %
952% %
953%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
954%
cristy0a39a5c2012-06-27 12:51:45 +0000955% ConvertRGBToHSB() transforms a (red, green, blue) to a (hue, saturation,
cristy3ed852e2009-09-05 21:47:34 +0000956% brightness) triple.
957%
cristy0a39a5c2012-06-27 12:51:45 +0000958% The format of the ConvertRGBToHSB method is:
cristy3ed852e2009-09-05 21:47:34 +0000959%
cristy0a39a5c2012-06-27 12:51:45 +0000960% void ConvertRGBToHSB(const double red,const double green,
cristy3094b7f2011-10-01 23:18:02 +0000961% const double blue,double *hue,double *saturation,double *brightness)
cristy3ed852e2009-09-05 21:47:34 +0000962%
963% A description of each parameter follows:
964%
965% o red, green, blue: A Quantum value representing the red, green, and
966% blue component of a pixel..
967%
968% o hue, saturation, brightness: A pointer to a double value representing a
969% component of the HSB color space.
970%
971*/
cristy0a39a5c2012-06-27 12:51:45 +0000972MagickPrivate void ConvertRGBToHSB(const double red,const double green,
cristy3094b7f2011-10-01 23:18:02 +0000973 const double blue,double *hue,double *saturation,double *brightness)
cristy3ed852e2009-09-05 21:47:34 +0000974{
cristycaf45802012-06-16 18:28:54 +0000975 double
cristy3ed852e2009-09-05 21:47:34 +0000976 delta,
977 max,
dirk568ce7a2015-04-11 13:17:06 +0000978 min;
cristy3ed852e2009-09-05 21:47:34 +0000979
980 /*
981 Convert RGB to HSB colorspace.
982 */
983 assert(hue != (double *) NULL);
984 assert(saturation != (double *) NULL);
985 assert(brightness != (double *) NULL);
986 *hue=0.0;
987 *saturation=0.0;
988 *brightness=0.0;
dirk568ce7a2015-04-11 13:17:06 +0000989 min=red < green ? red : green;
990 if (blue < min)
991 min=blue;
992 max=red > green ? red : green;
993 if (blue > max)
994 max=blue;
cristy3ed852e2009-09-05 21:47:34 +0000995 if (max == 0.0)
996 return;
997 delta=max-min;
cristycaf45802012-06-16 18:28:54 +0000998 *saturation=delta/max;
999 *brightness=QuantumScale*max;
cristy3ed852e2009-09-05 21:47:34 +00001000 if (delta == 0.0)
1001 return;
dirk568ce7a2015-04-11 13:17:06 +00001002 if (red == max)
1003 *hue=(green-blue)/delta;
cristy3ed852e2009-09-05 21:47:34 +00001004 else
dirk568ce7a2015-04-11 13:17:06 +00001005 if (green == max)
1006 *hue=2.0+(blue-red)/delta;
cristy3ed852e2009-09-05 21:47:34 +00001007 else
dirk568ce7a2015-04-11 13:17:06 +00001008 *hue=4.0+(red-green)/delta;
cristy18b17442009-10-25 18:36:48 +00001009 *hue/=6.0;
cristy3ed852e2009-09-05 21:47:34 +00001010 if (*hue < 0.0)
1011 *hue+=1.0;
1012}
1013
1014/*
1015%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1016% %
1017% %
1018% %
cristyaf64eb22013-05-02 14:07:10 +00001019% C o n v e r t R G B T o H S I %
1020% %
1021% %
1022% %
1023%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1024%
1025% ConvertRGBToHSI() transforms a (red, green, blue) to a (hue, saturation,
1026% intensity) triple.
1027%
1028% The format of the ConvertRGBToHSI method is:
1029%
1030% void ConvertRGBToHSI(const double red,const double green,
1031% const double blue,double *hue,double *saturation,double *intensity)
1032%
1033% A description of each parameter follows:
1034%
1035% o red, green, blue: A Quantum value representing the red, green, and
1036% blue component of a pixel..
1037%
1038% o hue, saturation, intensity: A pointer to a double value representing a
1039% component of the HSI color space.
1040%
1041*/
1042MagickPrivate void ConvertRGBToHSI(const double red,const double green,
1043 const double blue,double *hue,double *saturation,double *intensity)
1044{
1045 double
1046 alpha,
1047 beta;
1048
1049 /*
1050 Convert RGB to HSI colorspace.
1051 */
1052 assert(hue != (double *) NULL);
1053 assert(saturation != (double *) NULL);
1054 assert(intensity != (double *) NULL);
1055 *intensity=(QuantumScale*red+QuantumScale*green+QuantumScale*blue)/3.0;
1056 if (*intensity <= 0.0)
1057 {
1058 *hue=0.0;
1059 *saturation=0.0;
cristya5a45a72013-05-02 16:06:57 +00001060 return;
cristyaf64eb22013-05-02 14:07:10 +00001061 }
cristya5a45a72013-05-02 16:06:57 +00001062 *saturation=1.0-MagickMin(QuantumScale*red,MagickMin(QuantumScale*green,
1063 QuantumScale*blue))/(*intensity);
1064 alpha=0.5*(2.0*QuantumScale*red-QuantumScale*green-QuantumScale*blue);
cristybe708af2013-05-02 23:42:41 +00001065 beta=0.8660254037844385*(QuantumScale*green-QuantumScale*blue);
cristya5a45a72013-05-02 16:06:57 +00001066 *hue=atan2(beta,alpha)*(180.0/MagickPI)/360.0;
1067 if (*hue < 0.0)
1068 *hue+=1.0;
cristyaf64eb22013-05-02 14:07:10 +00001069}
1070
1071/*
1072%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1073% %
1074% %
1075% %
cristy0a39a5c2012-06-27 12:51:45 +00001076% C o n v e r t R G B T o H S L %
cristy3ed852e2009-09-05 21:47:34 +00001077% %
1078% %
1079% %
1080%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1081%
cristy0a39a5c2012-06-27 12:51:45 +00001082% ConvertRGBToHSL() transforms a (red, green, blue) to a (hue, saturation,
cristy3ed852e2009-09-05 21:47:34 +00001083% lightness) triple.
1084%
cristy0a39a5c2012-06-27 12:51:45 +00001085% The format of the ConvertRGBToHSL method is:
cristy3ed852e2009-09-05 21:47:34 +00001086%
cristy0a39a5c2012-06-27 12:51:45 +00001087% void ConvertRGBToHSL(const double red,const double green,
cristy3094b7f2011-10-01 23:18:02 +00001088% const double blue,double *hue,double *saturation,double *lightness)
cristy3ed852e2009-09-05 21:47:34 +00001089%
1090% A description of each parameter follows:
1091%
1092% o red, green, blue: A Quantum value representing the red, green, and
1093% blue component of a pixel..
1094%
1095% o hue, saturation, lightness: A pointer to a double value representing a
1096% component of the HSL color space.
1097%
1098*/
cristy0a39a5c2012-06-27 12:51:45 +00001099MagickExport void ConvertRGBToHSL(const double red,const double green,
cristy3094b7f2011-10-01 23:18:02 +00001100 const double blue,double *hue,double *saturation,double *lightness)
cristy3ed852e2009-09-05 21:47:34 +00001101{
cristycaf45802012-06-16 18:28:54 +00001102 double
cristya5a45a72013-05-02 16:06:57 +00001103 c,
cristy3ed852e2009-09-05 21:47:34 +00001104 max,
cristya5a45a72013-05-02 16:06:57 +00001105 min;
cristy3ed852e2009-09-05 21:47:34 +00001106
1107 /*
1108 Convert RGB to HSL colorspace.
1109 */
1110 assert(hue != (double *) NULL);
1111 assert(saturation != (double *) NULL);
1112 assert(lightness != (double *) NULL);
cristya5a45a72013-05-02 16:06:57 +00001113 max=MagickMax(QuantumScale*red,MagickMax(QuantumScale*green,
1114 QuantumScale*blue));
1115 min=MagickMin(QuantumScale*red,MagickMin(QuantumScale*green,
1116 QuantumScale*blue));
1117 c=max-min;
1118 *lightness=(max+min)/2.0;
1119 if (c <= 0.0)
cristy3ed852e2009-09-05 21:47:34 +00001120 {
1121 *hue=0.0;
1122 *saturation=0.0;
1123 return;
1124 }
cristya5a45a72013-05-02 16:06:57 +00001125 if (max == (QuantumScale*red))
1126 {
1127 *hue=(QuantumScale*green-QuantumScale*blue)/c;
1128 if ((QuantumScale*green) < (QuantumScale*blue))
1129 *hue+=6.0;
1130 }
cristy3ed852e2009-09-05 21:47:34 +00001131 else
cristya5a45a72013-05-02 16:06:57 +00001132 if (max == (QuantumScale*green))
1133 *hue=2.0+(QuantumScale*blue-QuantumScale*red)/c;
cristy3ed852e2009-09-05 21:47:34 +00001134 else
cristya5a45a72013-05-02 16:06:57 +00001135 *hue=4.0+(QuantumScale*red-QuantumScale*green)/c;
1136 *hue*=60.0/360.0;
1137 if (*lightness <= 0.5)
1138 *saturation=c/(2.0*(*lightness));
1139 else
1140 *saturation=c/(2.0-2.0*(*lightness));
cristy3ed852e2009-09-05 21:47:34 +00001141}
1142
1143/*
1144%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1145% %
1146% %
1147% %
cristy246c3132013-05-02 16:35:53 +00001148% C o n v e r t R G B T o H S V %
1149% %
1150% %
1151% %
1152%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1153%
1154% ConvertRGBToHSV() transforms a (red, green, blue) to a (hue, saturation,
1155% value) triple.
1156%
1157% The format of the ConvertRGBToHSV method is:
1158%
1159% void ConvertRGBToHSV(const double red,const double green,
1160% const double blue,double *hue,double *saturation,double *value)
1161%
1162% A description of each parameter follows:
1163%
1164% o red, green, blue: A Quantum value representing the red, green, and
1165% blue component of a pixel..
1166%
1167% o hue, saturation, value: A pointer to a double value representing a
1168% component of the HSV color space.
1169%
1170*/
1171MagickPrivate void ConvertRGBToHSV(const double red,const double green,
1172 const double blue,double *hue,double *saturation,double *value)
1173{
1174 double
1175 c,
1176 max,
1177 min;
1178
1179 /*
1180 Convert RGB to HSV colorspace.
1181 */
1182 assert(hue != (double *) NULL);
1183 assert(saturation != (double *) NULL);
1184 assert(value != (double *) NULL);
1185 max=MagickMax(QuantumScale*red,MagickMax(QuantumScale*green,
1186 QuantumScale*blue));
1187 min=MagickMin(QuantumScale*red,MagickMin(QuantumScale*green,
1188 QuantumScale*blue));
1189 c=max-min;
1190 *value=max;
1191 if (c <= 0.0)
1192 {
1193 *hue=0.0;
1194 *saturation=0.0;
1195 return;
1196 }
1197 if (max == (QuantumScale*red))
1198 {
1199 *hue=(QuantumScale*green-QuantumScale*blue)/c;
1200 if ((QuantumScale*green) < (QuantumScale*blue))
1201 *hue+=6.0;
1202 }
1203 else
1204 if (max == (QuantumScale*green))
1205 *hue=2.0+(QuantumScale*blue-QuantumScale*red)/c;
1206 else
1207 *hue=4.0+(QuantumScale*red-QuantumScale*green)/c;
1208 *hue*=60.0/360.0;
1209 *saturation=c/max;
1210}
1211
1212/*
1213%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1214% %
1215% %
1216% %
cristy0a39a5c2012-06-27 12:51:45 +00001217% C o n v e r t R G B T o H W B %
cristy3ed852e2009-09-05 21:47:34 +00001218% %
1219% %
1220% %
1221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1222%
cristy0a39a5c2012-06-27 12:51:45 +00001223% ConvertRGBToHWB() transforms a (red, green, blue) to a (hue, whiteness,
cristy3ed852e2009-09-05 21:47:34 +00001224% blackness) triple.
1225%
cristy0a39a5c2012-06-27 12:51:45 +00001226% The format of the ConvertRGBToHWB method is:
cristy3ed852e2009-09-05 21:47:34 +00001227%
cristy0a39a5c2012-06-27 12:51:45 +00001228% void ConvertRGBToHWB(const double red,const double green,
cristy3094b7f2011-10-01 23:18:02 +00001229% const double blue,double *hue,double *whiteness,double *blackness)
cristy3ed852e2009-09-05 21:47:34 +00001230%
1231% A description of each parameter follows:
1232%
1233% o red, green, blue: A Quantum value representing the red, green, and
1234% blue component of a pixel.
1235%
1236% o hue, whiteness, blackness: A pointer to a double value representing a
1237% component of the HWB color space.
1238%
1239*/
cristy0a39a5c2012-06-27 12:51:45 +00001240MagickPrivate void ConvertRGBToHWB(const double red,const double green,
cristy3094b7f2011-10-01 23:18:02 +00001241 const double blue,double *hue,double *whiteness,double *blackness)
cristy3ed852e2009-09-05 21:47:34 +00001242{
cristycaf45802012-06-16 18:28:54 +00001243 double
cristy3ed852e2009-09-05 21:47:34 +00001244 f,
cristycaf45802012-06-16 18:28:54 +00001245 p,
cristy3ed852e2009-09-05 21:47:34 +00001246 v,
1247 w;
1248
cristy3ed852e2009-09-05 21:47:34 +00001249 /*
1250 Convert RGB to HWB colorspace.
1251 */
1252 assert(hue != (double *) NULL);
1253 assert(whiteness != (double *) NULL);
1254 assert(blackness != (double *) NULL);
dirk568ce7a2015-04-11 13:17:06 +00001255 w=MagickMin(red,MagickMin(green,blue));
1256 v=MagickMax(red,MagickMax(green,blue));
cristy3ed852e2009-09-05 21:47:34 +00001257 *blackness=1.0-QuantumScale*v;
1258 *whiteness=QuantumScale*w;
1259 if (v == w)
1260 {
cristyaf10b112012-04-18 13:25:37 +00001261 *hue=(-1.0);
cristy3ed852e2009-09-05 21:47:34 +00001262 return;
1263 }
dirk568ce7a2015-04-11 13:17:06 +00001264 f=(red == w) ? green-blue : ((green == w) ? blue-red : red-green);
1265 p=(red == w) ? 3.0 : ((green == w) ? 5.0 : 1.0);
cristycaf45802012-06-16 18:28:54 +00001266 *hue=(p-f/(v-1.0*w))/6.0;
cristy3ed852e2009-09-05 21:47:34 +00001267}
1268
1269/*
1270%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1271% %
1272% %
1273% %
cristya83d4c02013-04-19 19:39:30 +00001274% C o n v e r t R G B T o L C H a b %
cristyb2850952013-04-04 19:00:52 +00001275% %
1276% %
1277% %
1278%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1279%
cristydf42b172013-04-05 13:35:37 +00001280% ConvertRGBToLCHab() transforms a (red, green, blue) to a (luma, chroma,
cristyb2850952013-04-04 19:00:52 +00001281% hue) triple.
1282%
cristydf42b172013-04-05 13:35:37 +00001283% The format of the ConvertRGBToLCHab method is:
cristyb2850952013-04-04 19:00:52 +00001284%
cristydf42b172013-04-05 13:35:37 +00001285% void ConvertRGBToLCHab(const double red,const double green,
cristyb2850952013-04-04 19:00:52 +00001286% const double blue,double *luma,double *chroma,double *hue)
1287%
1288% A description of each parameter follows:
1289%
1290% o red, green, blue: A Quantum value representing the red, green, and
1291% blue component of a pixel.
1292%
1293% o luma, chroma, hue: A pointer to a double value representing a
1294% component of the LCH color space.
1295%
1296*/
cristyc32cb022013-05-06 13:32:31 +00001297
1298static inline void ConvertXYZToLCHab(const double X,const double Y,
1299 const double Z,double *luma,double *chroma,double *hue)
1300{
1301 double
1302 a,
1303 b;
1304
1305 ConvertXYZToLab(X,Y,Z,luma,&a,&b);
cristy846740b2013-06-19 18:19:55 +00001306 *chroma=hypot(255.0*(a-0.5),255.0*(b-0.5))/255.0+0.5;
cristy6d897c72013-06-19 19:20:40 +00001307 *hue=180.0*atan2(255.0*(b-0.5),255.0*(a-0.5))/MagickPI/360.0;
cristy89106f82013-05-06 17:04:29 +00001308 if (*hue < 0.0)
1309 *hue+=1.0;
cristyc32cb022013-05-06 13:32:31 +00001310}
1311
cristydf42b172013-04-05 13:35:37 +00001312MagickPrivate void ConvertRGBToLCHab(const double red,const double green,
cristyb2850952013-04-04 19:00:52 +00001313 const double blue,double *luma,double *chroma,double *hue)
1314{
1315 double
cristyb2850952013-04-04 19:00:52 +00001316 X,
1317 Y,
1318 Z;
1319
1320 /*
cristy9427c422013-04-08 12:03:11 +00001321 Convert RGB to LCHab colorspace.
cristyb2850952013-04-04 19:00:52 +00001322 */
1323 assert(luma != (double *) NULL);
1324 assert(chroma != (double *) NULL);
1325 assert(hue != (double *) NULL);
1326 ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
cristyc32cb022013-05-06 13:32:31 +00001327 ConvertXYZToLCHab(X,Y,Z,luma,chroma,hue);
cristyb2850952013-04-04 19:00:52 +00001328}
1329
1330/*
1331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1332% %
1333% %
1334% %
cristya83d4c02013-04-19 19:39:30 +00001335% C o n v e r t R G B T o L C H u v %
cristydf42b172013-04-05 13:35:37 +00001336% %
1337% %
1338% %
1339%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1340%
1341% ConvertRGBToLCHuv() transforms a (red, green, blue) to a (luma, chroma,
1342% hue) triple.
1343%
1344% The format of the ConvertRGBToLCHuv method is:
1345%
1346% void ConvertRGBToLCHuv(const double red,const double green,
1347% const double blue,double *luma,double *chroma,double *hue)
1348%
1349% A description of each parameter follows:
1350%
1351% o red, green, blue: A Quantum value representing the red, green, and
1352% blue component of a pixel.
1353%
1354% o luma, chroma, hue: A pointer to a double value representing a
1355% component of the LCHuv color space.
1356%
1357*/
cristyc32cb022013-05-06 13:32:31 +00001358
1359static inline void ConvertXYZToLCHuv(const double X,const double Y,
1360 const double Z,double *luma,double *chroma,double *hue)
1361{
1362 double
cristy9db2dba2013-05-06 14:04:13 +00001363 u,
1364 v;
cristyc32cb022013-05-06 13:32:31 +00001365
cristy9db2dba2013-05-06 14:04:13 +00001366 ConvertXYZToLuv(X,Y,Z,luma,&u,&v);
cristy846740b2013-06-19 18:19:55 +00001367 *chroma=hypot(354.0*u-134.0,262.0*v-140.0)/255.0+0.5;
cristy6d897c72013-06-19 19:20:40 +00001368 *hue=180.0*atan2(262.0*v-140.0,354.0*u-134.0)/MagickPI/360.0;
cristy14a4e0f2013-05-06 19:53:58 +00001369 if (*hue < 0.0)
1370 *hue+=1.0;
cristyc32cb022013-05-06 13:32:31 +00001371}
1372
cristydf42b172013-04-05 13:35:37 +00001373MagickPrivate void ConvertRGBToLCHuv(const double red,const double green,
1374 const double blue,double *luma,double *chroma,double *hue)
1375{
1376 double
cristydf42b172013-04-05 13:35:37 +00001377 X,
1378 Y,
1379 Z;
1380
1381 /*
cristy9427c422013-04-08 12:03:11 +00001382 Convert RGB to LCHuv colorspace.
cristydf42b172013-04-05 13:35:37 +00001383 */
1384 assert(luma != (double *) NULL);
1385 assert(chroma != (double *) NULL);
1386 assert(hue != (double *) NULL);
1387 ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
cristyc32cb022013-05-06 13:32:31 +00001388 ConvertXYZToLCHuv(X,Y,Z,luma,chroma,hue);
cristydf42b172013-04-05 13:35:37 +00001389}
1390
1391/*
1392%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1393% %
1394% %
1395% %
cristy3ed852e2009-09-05 21:47:34 +00001396% E x p a n d A f f i n e %
1397% %
1398% %
1399% %
1400%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1401%
1402% ExpandAffine() computes the affine's expansion factor, i.e. the square root
1403% of the factor by which the affine transform affects area. In an affine
1404% transform composed of scaling, rotation, shearing, and translation, returns
1405% the amount of scaling.
1406%
1407% The format of the ExpandAffine method is:
1408%
1409% double ExpandAffine(const AffineMatrix *affine)
1410%
1411% A description of each parameter follows:
1412%
cristy2d7ffbb2013-04-19 19:43:01 +00001413% o expansion: ExpandAffine returns the affine's expansion factor.
cristy3ed852e2009-09-05 21:47:34 +00001414%
1415% o affine: A pointer the affine transform of type AffineMatrix.
1416%
1417*/
1418MagickExport double ExpandAffine(const AffineMatrix *affine)
1419{
1420 assert(affine != (const AffineMatrix *) NULL);
1421 return(sqrt(fabs(affine->sx*affine->sy-affine->rx*affine->ry)));
1422}
1423
1424/*
1425%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1426% %
1427% %
1428% %
1429% 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 %
1430% %
1431% %
1432% %
1433%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1434%
cristy82b15832009-10-06 19:17:37 +00001435% GenerateDifferentialNoise() generates differentual noise.
cristy3ed852e2009-09-05 21:47:34 +00001436%
1437% The format of the GenerateDifferentialNoise method is:
1438%
1439% double GenerateDifferentialNoise(RandomInfo *random_info,
cristy9ed1f812011-10-08 02:00:08 +00001440% const Quantum pixel,const NoiseType noise_type,const double attenuate)
cristy3ed852e2009-09-05 21:47:34 +00001441%
1442% A description of each parameter follows:
1443%
1444% o random_info: the random info.
1445%
1446% o pixel: noise is relative to this pixel value.
1447%
1448% o noise_type: the type of noise.
1449%
1450% o attenuate: attenuate the noise.
1451%
1452*/
cristy8ea81222011-09-04 10:33:32 +00001453MagickPrivate double GenerateDifferentialNoise(RandomInfo *random_info,
cristy9ed1f812011-10-08 02:00:08 +00001454 const Quantum pixel,const NoiseType noise_type,const double attenuate)
cristy3ed852e2009-09-05 21:47:34 +00001455{
cristy7118edf2011-10-08 13:33:25 +00001456#define SigmaUniform (attenuate*0.015625)
1457#define SigmaGaussian (attenuate*0.015625)
1458#define SigmaImpulse (attenuate*0.1)
1459#define SigmaLaplacian (attenuate*0.0390625)
1460#define SigmaMultiplicativeGaussian (attenuate*0.5)
cristy4ce9df62011-10-12 12:06:02 +00001461#define SigmaPoisson (attenuate*12.5)
cristy785eb592012-07-08 22:12:15 +00001462#define SigmaRandom (attenuate)
cristy7118edf2011-10-08 13:33:25 +00001463#define TauGaussian (attenuate*0.078125)
cristy3ed852e2009-09-05 21:47:34 +00001464
cristyadb41ca2009-10-22 15:02:28 +00001465 double
cristy3ed852e2009-09-05 21:47:34 +00001466 alpha,
1467 beta,
1468 noise,
1469 sigma;
1470
1471 alpha=GetPseudoRandomValue(random_info);
cristy3ed852e2009-09-05 21:47:34 +00001472 switch (noise_type)
1473 {
1474 case UniformNoise:
1475 default:
1476 {
cristy6bbabe62011-10-09 13:54:18 +00001477 noise=(double) (pixel+QuantumRange*SigmaUniform*(alpha-0.5));
cristy3ed852e2009-09-05 21:47:34 +00001478 break;
1479 }
1480 case GaussianNoise:
1481 {
cristyadb41ca2009-10-22 15:02:28 +00001482 double
cristy62faa602010-02-20 03:36:17 +00001483 gamma,
cristy3ed852e2009-09-05 21:47:34 +00001484 tau;
1485
cristyadb41ca2009-10-22 15:02:28 +00001486 if (alpha == 0.0)
1487 alpha=1.0;
cristy3ed852e2009-09-05 21:47:34 +00001488 beta=GetPseudoRandomValue(random_info);
cristy62faa602010-02-20 03:36:17 +00001489 gamma=sqrt(-2.0*log(alpha));
cristy55a91cd2010-12-01 00:57:40 +00001490 sigma=gamma*cos((double) (2.0*MagickPI*beta));
1491 tau=gamma*sin((double) (2.0*MagickPI*beta));
cristy6bbabe62011-10-09 13:54:18 +00001492 noise=(double) (pixel+sqrt((double) pixel)*SigmaGaussian*sigma+
1493 QuantumRange*TauGaussian*tau);
cristy3ed852e2009-09-05 21:47:34 +00001494 break;
1495 }
1496 case ImpulseNoise:
1497 {
1498 if (alpha < (SigmaImpulse/2.0))
1499 noise=0.0;
cristy37c24072011-10-08 01:26:00 +00001500 else
1501 if (alpha >= (1.0-(SigmaImpulse/2.0)))
1502 noise=(double) QuantumRange;
1503 else
1504 noise=(double) pixel;
cristy3ed852e2009-09-05 21:47:34 +00001505 break;
1506 }
1507 case LaplacianNoise:
1508 {
1509 if (alpha <= 0.5)
1510 {
cristy7118edf2011-10-08 13:33:25 +00001511 if (alpha <= MagickEpsilon)
cristy6bbabe62011-10-09 13:54:18 +00001512 noise=(double) (pixel-QuantumRange);
cristy3ed852e2009-09-05 21:47:34 +00001513 else
cristy785eb592012-07-08 22:12:15 +00001514 noise=(double) (pixel+QuantumRange*SigmaLaplacian*log(2.0*alpha)+
1515 0.5);
cristy3ed852e2009-09-05 21:47:34 +00001516 break;
1517 }
1518 beta=1.0-alpha;
cristy7118edf2011-10-08 13:33:25 +00001519 if (beta <= (0.5*MagickEpsilon))
cristyadb41ca2009-10-22 15:02:28 +00001520 noise=(double) (pixel+QuantumRange);
cristy3ed852e2009-09-05 21:47:34 +00001521 else
cristy6bbabe62011-10-09 13:54:18 +00001522 noise=(double) (pixel-QuantumRange*SigmaLaplacian*log(2.0*beta)+0.5);
cristy7118edf2011-10-08 13:33:25 +00001523 break;
1524 }
1525 case MultiplicativeGaussianNoise:
1526 {
1527 sigma=1.0;
1528 if (alpha > MagickEpsilon)
1529 sigma=sqrt(-2.0*log(alpha));
1530 beta=GetPseudoRandomValue(random_info);
cristy6bbabe62011-10-09 13:54:18 +00001531 noise=(double) (pixel+pixel*SigmaMultiplicativeGaussian*sigma*
1532 cos((double) (2.0*MagickPI*beta))/2.0);
cristy3ed852e2009-09-05 21:47:34 +00001533 break;
1534 }
1535 case PoissonNoise:
1536 {
cristyadb41ca2009-10-22 15:02:28 +00001537 double
cristy3ed852e2009-09-05 21:47:34 +00001538 poisson;
1539
cristybb503372010-05-27 20:51:26 +00001540 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001541 i;
1542
cristy7118edf2011-10-08 13:33:25 +00001543 poisson=exp(-SigmaPoisson*QuantumScale*pixel);
cristy3ed852e2009-09-05 21:47:34 +00001544 for (i=0; alpha > poisson; i++)
1545 {
1546 beta=GetPseudoRandomValue(random_info);
1547 alpha*=beta;
1548 }
cristy6bbabe62011-10-09 13:54:18 +00001549 noise=(double) (QuantumRange*i/SigmaPoisson);
cristy3ed852e2009-09-05 21:47:34 +00001550 break;
1551 }
1552 case RandomNoise:
1553 {
cristy785eb592012-07-08 22:12:15 +00001554 noise=(double) (QuantumRange*SigmaRandom*alpha);
cristy3ed852e2009-09-05 21:47:34 +00001555 break;
1556 }
1557 }
1558 return(noise);
1559}
1560
1561/*
1562%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1563% %
1564% %
1565% %
1566% G e t O p t i m a l K e r n e l W i d t h %
1567% %
1568% %
1569% %
1570%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1571%
1572% GetOptimalKernelWidth() computes the optimal kernel radius for a convolution
1573% filter. Start with the minimum value of 3 pixels and walk out until we drop
1574% below the threshold of one pixel numerical accuracy.
1575%
1576% The format of the GetOptimalKernelWidth method is:
1577%
cristybb503372010-05-27 20:51:26 +00001578% size_t GetOptimalKernelWidth(const double radius,
cristy3ed852e2009-09-05 21:47:34 +00001579% const double sigma)
1580%
1581% A description of each parameter follows:
1582%
cristy2d7ffbb2013-04-19 19:43:01 +00001583% o width: GetOptimalKernelWidth returns the optimal width of a
1584% convolution kernel.
cristy3ed852e2009-09-05 21:47:34 +00001585%
1586% o radius: the radius of the Gaussian, in pixels, not counting the center
1587% pixel.
1588%
1589% o sigma: the standard deviation of the Gaussian, in pixels.
1590%
1591*/
cristy8ea81222011-09-04 10:33:32 +00001592MagickPrivate size_t GetOptimalKernelWidth1D(const double radius,
cristye96405a2010-05-19 02:24:31 +00001593 const double sigma)
cristy3ed852e2009-09-05 21:47:34 +00001594{
cristye96405a2010-05-19 02:24:31 +00001595 double
1596 alpha,
1597 beta,
1598 gamma,
cristy3ed852e2009-09-05 21:47:34 +00001599 normalize,
cristye96405a2010-05-19 02:24:31 +00001600 value;
cristy3ed852e2009-09-05 21:47:34 +00001601
cristybb503372010-05-27 20:51:26 +00001602 register ssize_t
cristy47e00502009-12-17 19:19:57 +00001603 i;
1604
cristybb503372010-05-27 20:51:26 +00001605 size_t
cristy47e00502009-12-17 19:19:57 +00001606 width;
cristy3ed852e2009-09-05 21:47:34 +00001607
cristy9d314ff2011-03-09 01:30:28 +00001608 ssize_t
1609 j;
1610
cristy3ed852e2009-09-05 21:47:34 +00001611 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristy47e00502009-12-17 19:19:57 +00001612 if (radius > MagickEpsilon)
cristybb503372010-05-27 20:51:26 +00001613 return((size_t) (2.0*ceil(radius)+1.0));
cristye96405a2010-05-19 02:24:31 +00001614 gamma=fabs(sigma);
1615 if (gamma <= MagickEpsilon)
anthonyc1061722010-05-14 06:23:49 +00001616 return(3UL);
cristy3e3ec3a2012-11-03 23:11:06 +00001617 alpha=PerceptibleReciprocal(2.0*gamma*gamma);
1618 beta=(double) PerceptibleReciprocal((double) MagickSQ2PI*gamma);
cristy3ed852e2009-09-05 21:47:34 +00001619 for (width=5; ; )
1620 {
1621 normalize=0.0;
cristy35faaa72013-03-08 12:33:42 +00001622 j=(ssize_t) (width-1)/2;
cristy47e00502009-12-17 19:19:57 +00001623 for (i=(-j); i <= j; i++)
cristye96405a2010-05-19 02:24:31 +00001624 normalize+=exp(-((double) (i*i))*alpha)*beta;
1625 value=exp(-((double) (j*j))*alpha)*beta/normalize;
cristy20908da2009-12-02 14:34:11 +00001626 if ((value < QuantumScale) || (value < MagickEpsilon))
cristy3ed852e2009-09-05 21:47:34 +00001627 break;
1628 width+=2;
1629 }
cristybb503372010-05-27 20:51:26 +00001630 return((size_t) (width-2));
cristy3ed852e2009-09-05 21:47:34 +00001631}
1632
cristy8ea81222011-09-04 10:33:32 +00001633MagickPrivate size_t GetOptimalKernelWidth2D(const double radius,
cristye96405a2010-05-19 02:24:31 +00001634 const double sigma)
cristy3ed852e2009-09-05 21:47:34 +00001635{
cristy47e00502009-12-17 19:19:57 +00001636 double
cristye96405a2010-05-19 02:24:31 +00001637 alpha,
1638 beta,
1639 gamma,
cristy3ed852e2009-09-05 21:47:34 +00001640 normalize,
cristye96405a2010-05-19 02:24:31 +00001641 value;
cristy3ed852e2009-09-05 21:47:34 +00001642
cristy9d314ff2011-03-09 01:30:28 +00001643 size_t
1644 width;
1645
cristybb503372010-05-27 20:51:26 +00001646 ssize_t
cristy47e00502009-12-17 19:19:57 +00001647 j,
cristy3ed852e2009-09-05 21:47:34 +00001648 u,
1649 v;
1650
1651 (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) Magick2PI*gamma*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 (v=(-j); v <= j; v++)
cristy47e00502009-12-17 19:19:57 +00001664 for (u=(-j); u <= j; u++)
cristye96405a2010-05-19 02:24:31 +00001665 normalize+=exp(-((double) (u*u+v*v))*alpha)*beta;
1666 value=exp(-((double) (j*j))*alpha)*beta/normalize;
cristy20908da2009-12-02 14:34:11 +00001667 if ((value < QuantumScale) || (value < MagickEpsilon))
cristy3ed852e2009-09-05 21:47:34 +00001668 break;
1669 width+=2;
1670 }
cristybb503372010-05-27 20:51:26 +00001671 return((size_t) (width-2));
cristy3ed852e2009-09-05 21:47:34 +00001672}
1673
cristy8ea81222011-09-04 10:33:32 +00001674MagickPrivate size_t GetOptimalKernelWidth(const double radius,
cristy3ed852e2009-09-05 21:47:34 +00001675 const double sigma)
1676{
1677 return(GetOptimalKernelWidth1D(radius,sigma));
1678}