blob: 36fbdf806b74cae903c2aecff7606599bd6cb87c [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
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);
cristy0c125412013-05-06 16:54:07 +0000765 ConvertLCHabToXYZ(100.0*luma,255.0*(chroma-0.5),255.0*(hue-0.5),&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);
cristya8716912013-05-06 12:04:10 +0000818 ConvertLCHuvToXYZ(100.0*luma,354.0*chroma-134.0,262.0*hue-140.0,&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*/
cristy5756d822013-04-09 01:14:34 +0000850
851static inline double MagickMax(const double x,const double y)
852{
853 if (x > y)
854 return(x);
855 return(y);
856}
857
858static inline double MagickMin(const double x,const double y)
859{
860 if (x < y)
861 return(x);
862 return(y);
863}
864
cristy722fc0c2012-08-04 23:15:43 +0000865MagickPrivate void ConvertRGBToHCL(const double red,const double green,
866 const double blue,double *hue,double *chroma,double *luma)
867{
868 double
cristy5756d822013-04-09 01:14:34 +0000869 b,
870 c,
871 g,
872 h,
873 max,
874 r;
cristy722fc0c2012-08-04 23:15:43 +0000875
876 /*
877 Convert RGB to HCL colorspace.
878 */
cristy9427c422013-04-08 12:03:11 +0000879 assert(hue != (double *) NULL);
cristy5756d822013-04-09 01:14:34 +0000880 assert(chroma != (double *) NULL);
881 assert(luma != (double *) NULL);
882 r=red;
883 g=green;
884 b=blue;
885 max=MagickMax(r,MagickMax(g,b));
886 c=max-(double) MagickMin(r,MagickMin(g,b));
887 h=0.0;
888 if (c == 0.0)
889 h=0.0;
890 else
891 if (red == max)
892 h=fmod((g-b)/c+6.0,6.0);
893 else
894 if (green == max)
895 h=((b-r)/c)+2.0;
896 else
897 if (blue == max)
898 h=((r-g)/c)+4.0;
899 *hue=(h/6.0);
900 *chroma=QuantumScale*c;
cristy9e2436a2013-05-02 20:35:59 +0000901 *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
902}
903
904/*
905%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
906% %
907% %
908% %
909% C o n v e r t R G B T o H C L p %
910% %
911% %
912% %
913%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
914%
915% ConvertRGBToHCLp() transforms a (red, green, blue) to a (hue, chroma,
916% luma) triple.
917%
918% The format of the ConvertRGBToHCLp method is:
919%
920% void ConvertRGBToHCLp(const double red,const double green,
921% const double blue,double *hue,double *chroma,double *luma)
922%
923% A description of each parameter follows:
924%
925% o red, green, blue: A Quantum value representing the red, green, and
926% blue component of a pixel.
927%
928% o hue, chroma, luma: A pointer to a double value representing a
929% component of the HCL color space.
930%
931*/
932MagickPrivate void ConvertRGBToHCLp(const double red,const double green,
933 const double blue,double *hue,double *chroma,double *luma)
934{
935 double
936 b,
937 c,
938 g,
939 h,
940 max,
941 r;
942
943 /*
944 Convert RGB to HCL colorspace.
945 */
946 assert(hue != (double *) NULL);
947 assert(chroma != (double *) NULL);
948 assert(luma != (double *) NULL);
949 r=red;
950 g=green;
951 b=blue;
952 max=MagickMax(r,MagickMax(g,b));
953 c=max-(double) MagickMin(r,MagickMin(g,b));
954 h=0.0;
955 if (c == 0.0)
956 h=0.0;
957 else
958 if (red == max)
959 h=fmod((g-b)/c+6.0,6.0);
960 else
961 if (green == max)
962 h=((b-r)/c)+2.0;
963 else
964 if (blue == max)
965 h=((r-g)/c)+4.0;
966 *hue=(h/6.0);
967 *chroma=QuantumScale*c;
968 *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
cristy722fc0c2012-08-04 23:15:43 +0000969}
970
971/*
972%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
973% %
974% %
975% %
cristy0a39a5c2012-06-27 12:51:45 +0000976% C o n v e r t R G B T o H S B %
cristy3ed852e2009-09-05 21:47:34 +0000977% %
978% %
979% %
980%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
981%
cristy0a39a5c2012-06-27 12:51:45 +0000982% ConvertRGBToHSB() transforms a (red, green, blue) to a (hue, saturation,
cristy3ed852e2009-09-05 21:47:34 +0000983% brightness) triple.
984%
cristy0a39a5c2012-06-27 12:51:45 +0000985% The format of the ConvertRGBToHSB method is:
cristy3ed852e2009-09-05 21:47:34 +0000986%
cristy0a39a5c2012-06-27 12:51:45 +0000987% void ConvertRGBToHSB(const double red,const double green,
cristy3094b7f2011-10-01 23:18:02 +0000988% const double blue,double *hue,double *saturation,double *brightness)
cristy3ed852e2009-09-05 21:47:34 +0000989%
990% A description of each parameter follows:
991%
992% o red, green, blue: A Quantum value representing the red, green, and
993% blue component of a pixel..
994%
995% o hue, saturation, brightness: A pointer to a double value representing a
996% component of the HSB color space.
997%
998*/
cristy0a39a5c2012-06-27 12:51:45 +0000999MagickPrivate void ConvertRGBToHSB(const double red,const double green,
cristy3094b7f2011-10-01 23:18:02 +00001000 const double blue,double *hue,double *saturation,double *brightness)
cristy3ed852e2009-09-05 21:47:34 +00001001{
cristycaf45802012-06-16 18:28:54 +00001002 double
1003 b,
cristy3ed852e2009-09-05 21:47:34 +00001004 delta,
cristycaf45802012-06-16 18:28:54 +00001005 g,
cristy3ed852e2009-09-05 21:47:34 +00001006 max,
cristycaf45802012-06-16 18:28:54 +00001007 min,
1008 r;
cristy3ed852e2009-09-05 21:47:34 +00001009
1010 /*
1011 Convert RGB to HSB colorspace.
1012 */
1013 assert(hue != (double *) NULL);
1014 assert(saturation != (double *) NULL);
1015 assert(brightness != (double *) NULL);
1016 *hue=0.0;
1017 *saturation=0.0;
1018 *brightness=0.0;
cristy0a39a5c2012-06-27 12:51:45 +00001019 r=red;
1020 g=green;
1021 b=blue;
cristycaf45802012-06-16 18:28:54 +00001022 min=r < g ? r : g;
1023 if (b < min)
1024 min=b;
1025 max=r > g ? r : g;
1026 if (b > max)
1027 max=b;
cristy3ed852e2009-09-05 21:47:34 +00001028 if (max == 0.0)
1029 return;
1030 delta=max-min;
cristycaf45802012-06-16 18:28:54 +00001031 *saturation=delta/max;
1032 *brightness=QuantumScale*max;
cristy3ed852e2009-09-05 21:47:34 +00001033 if (delta == 0.0)
1034 return;
cristycaf45802012-06-16 18:28:54 +00001035 if (r == max)
1036 *hue=(g-b)/delta;
cristy3ed852e2009-09-05 21:47:34 +00001037 else
cristycaf45802012-06-16 18:28:54 +00001038 if (g == max)
1039 *hue=2.0+(b-r)/delta;
cristy3ed852e2009-09-05 21:47:34 +00001040 else
cristycaf45802012-06-16 18:28:54 +00001041 *hue=4.0+(r-g)/delta;
cristy18b17442009-10-25 18:36:48 +00001042 *hue/=6.0;
cristy3ed852e2009-09-05 21:47:34 +00001043 if (*hue < 0.0)
1044 *hue+=1.0;
1045}
1046
1047/*
1048%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1049% %
1050% %
1051% %
cristyaf64eb22013-05-02 14:07:10 +00001052% C o n v e r t R G B T o H S I %
1053% %
1054% %
1055% %
1056%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1057%
1058% ConvertRGBToHSI() transforms a (red, green, blue) to a (hue, saturation,
1059% intensity) triple.
1060%
1061% The format of the ConvertRGBToHSI method is:
1062%
1063% void ConvertRGBToHSI(const double red,const double green,
1064% const double blue,double *hue,double *saturation,double *intensity)
1065%
1066% A description of each parameter follows:
1067%
1068% o red, green, blue: A Quantum value representing the red, green, and
1069% blue component of a pixel..
1070%
1071% o hue, saturation, intensity: A pointer to a double value representing a
1072% component of the HSI color space.
1073%
1074*/
1075MagickPrivate void ConvertRGBToHSI(const double red,const double green,
1076 const double blue,double *hue,double *saturation,double *intensity)
1077{
1078 double
1079 alpha,
1080 beta;
1081
1082 /*
1083 Convert RGB to HSI colorspace.
1084 */
1085 assert(hue != (double *) NULL);
1086 assert(saturation != (double *) NULL);
1087 assert(intensity != (double *) NULL);
1088 *intensity=(QuantumScale*red+QuantumScale*green+QuantumScale*blue)/3.0;
1089 if (*intensity <= 0.0)
1090 {
1091 *hue=0.0;
1092 *saturation=0.0;
cristya5a45a72013-05-02 16:06:57 +00001093 return;
cristyaf64eb22013-05-02 14:07:10 +00001094 }
cristya5a45a72013-05-02 16:06:57 +00001095 *saturation=1.0-MagickMin(QuantumScale*red,MagickMin(QuantumScale*green,
1096 QuantumScale*blue))/(*intensity);
1097 alpha=0.5*(2.0*QuantumScale*red-QuantumScale*green-QuantumScale*blue);
cristybe708af2013-05-02 23:42:41 +00001098 beta=0.8660254037844385*(QuantumScale*green-QuantumScale*blue);
cristya5a45a72013-05-02 16:06:57 +00001099 *hue=atan2(beta,alpha)*(180.0/MagickPI)/360.0;
1100 if (*hue < 0.0)
1101 *hue+=1.0;
cristyaf64eb22013-05-02 14:07:10 +00001102}
1103
1104/*
1105%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1106% %
1107% %
1108% %
cristy0a39a5c2012-06-27 12:51:45 +00001109% C o n v e r t R G B T o H S L %
cristy3ed852e2009-09-05 21:47:34 +00001110% %
1111% %
1112% %
1113%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1114%
cristy0a39a5c2012-06-27 12:51:45 +00001115% ConvertRGBToHSL() transforms a (red, green, blue) to a (hue, saturation,
cristy3ed852e2009-09-05 21:47:34 +00001116% lightness) triple.
1117%
cristy0a39a5c2012-06-27 12:51:45 +00001118% The format of the ConvertRGBToHSL method is:
cristy3ed852e2009-09-05 21:47:34 +00001119%
cristy0a39a5c2012-06-27 12:51:45 +00001120% void ConvertRGBToHSL(const double red,const double green,
cristy3094b7f2011-10-01 23:18:02 +00001121% const double blue,double *hue,double *saturation,double *lightness)
cristy3ed852e2009-09-05 21:47:34 +00001122%
1123% A description of each parameter follows:
1124%
1125% o red, green, blue: A Quantum value representing the red, green, and
1126% blue component of a pixel..
1127%
1128% o hue, saturation, lightness: A pointer to a double value representing a
1129% component of the HSL color space.
1130%
1131*/
cristy0a39a5c2012-06-27 12:51:45 +00001132MagickExport void ConvertRGBToHSL(const double red,const double green,
cristy3094b7f2011-10-01 23:18:02 +00001133 const double blue,double *hue,double *saturation,double *lightness)
cristy3ed852e2009-09-05 21:47:34 +00001134{
cristycaf45802012-06-16 18:28:54 +00001135 double
cristya5a45a72013-05-02 16:06:57 +00001136 c,
cristy3ed852e2009-09-05 21:47:34 +00001137 max,
cristya5a45a72013-05-02 16:06:57 +00001138 min;
cristy3ed852e2009-09-05 21:47:34 +00001139
1140 /*
1141 Convert RGB to HSL colorspace.
1142 */
1143 assert(hue != (double *) NULL);
1144 assert(saturation != (double *) NULL);
1145 assert(lightness != (double *) NULL);
cristya5a45a72013-05-02 16:06:57 +00001146 max=MagickMax(QuantumScale*red,MagickMax(QuantumScale*green,
1147 QuantumScale*blue));
1148 min=MagickMin(QuantumScale*red,MagickMin(QuantumScale*green,
1149 QuantumScale*blue));
1150 c=max-min;
1151 *lightness=(max+min)/2.0;
1152 if (c <= 0.0)
cristy3ed852e2009-09-05 21:47:34 +00001153 {
1154 *hue=0.0;
1155 *saturation=0.0;
1156 return;
1157 }
cristya5a45a72013-05-02 16:06:57 +00001158 if (max == (QuantumScale*red))
1159 {
1160 *hue=(QuantumScale*green-QuantumScale*blue)/c;
1161 if ((QuantumScale*green) < (QuantumScale*blue))
1162 *hue+=6.0;
1163 }
cristy3ed852e2009-09-05 21:47:34 +00001164 else
cristya5a45a72013-05-02 16:06:57 +00001165 if (max == (QuantumScale*green))
1166 *hue=2.0+(QuantumScale*blue-QuantumScale*red)/c;
cristy3ed852e2009-09-05 21:47:34 +00001167 else
cristya5a45a72013-05-02 16:06:57 +00001168 *hue=4.0+(QuantumScale*red-QuantumScale*green)/c;
1169 *hue*=60.0/360.0;
1170 if (*lightness <= 0.5)
1171 *saturation=c/(2.0*(*lightness));
1172 else
1173 *saturation=c/(2.0-2.0*(*lightness));
cristy3ed852e2009-09-05 21:47:34 +00001174}
1175
1176/*
1177%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1178% %
1179% %
1180% %
cristy246c3132013-05-02 16:35:53 +00001181% C o n v e r t R G B T o H S V %
1182% %
1183% %
1184% %
1185%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1186%
1187% ConvertRGBToHSV() transforms a (red, green, blue) to a (hue, saturation,
1188% value) triple.
1189%
1190% The format of the ConvertRGBToHSV method is:
1191%
1192% void ConvertRGBToHSV(const double red,const double green,
1193% const double blue,double *hue,double *saturation,double *value)
1194%
1195% A description of each parameter follows:
1196%
1197% o red, green, blue: A Quantum value representing the red, green, and
1198% blue component of a pixel..
1199%
1200% o hue, saturation, value: A pointer to a double value representing a
1201% component of the HSV color space.
1202%
1203*/
1204MagickPrivate void ConvertRGBToHSV(const double red,const double green,
1205 const double blue,double *hue,double *saturation,double *value)
1206{
1207 double
1208 c,
1209 max,
1210 min;
1211
1212 /*
1213 Convert RGB to HSV colorspace.
1214 */
1215 assert(hue != (double *) NULL);
1216 assert(saturation != (double *) NULL);
1217 assert(value != (double *) NULL);
1218 max=MagickMax(QuantumScale*red,MagickMax(QuantumScale*green,
1219 QuantumScale*blue));
1220 min=MagickMin(QuantumScale*red,MagickMin(QuantumScale*green,
1221 QuantumScale*blue));
1222 c=max-min;
1223 *value=max;
1224 if (c <= 0.0)
1225 {
1226 *hue=0.0;
1227 *saturation=0.0;
1228 return;
1229 }
1230 if (max == (QuantumScale*red))
1231 {
1232 *hue=(QuantumScale*green-QuantumScale*blue)/c;
1233 if ((QuantumScale*green) < (QuantumScale*blue))
1234 *hue+=6.0;
1235 }
1236 else
1237 if (max == (QuantumScale*green))
1238 *hue=2.0+(QuantumScale*blue-QuantumScale*red)/c;
1239 else
1240 *hue=4.0+(QuantumScale*red-QuantumScale*green)/c;
1241 *hue*=60.0/360.0;
1242 *saturation=c/max;
1243}
1244
1245/*
1246%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1247% %
1248% %
1249% %
cristy0a39a5c2012-06-27 12:51:45 +00001250% C o n v e r t R G B T o H W B %
cristy3ed852e2009-09-05 21:47:34 +00001251% %
1252% %
1253% %
1254%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1255%
cristy0a39a5c2012-06-27 12:51:45 +00001256% ConvertRGBToHWB() transforms a (red, green, blue) to a (hue, whiteness,
cristy3ed852e2009-09-05 21:47:34 +00001257% blackness) triple.
1258%
cristy0a39a5c2012-06-27 12:51:45 +00001259% The format of the ConvertRGBToHWB method is:
cristy3ed852e2009-09-05 21:47:34 +00001260%
cristy0a39a5c2012-06-27 12:51:45 +00001261% void ConvertRGBToHWB(const double red,const double green,
cristy3094b7f2011-10-01 23:18:02 +00001262% const double blue,double *hue,double *whiteness,double *blackness)
cristy3ed852e2009-09-05 21:47:34 +00001263%
1264% A description of each parameter follows:
1265%
1266% o red, green, blue: A Quantum value representing the red, green, and
1267% blue component of a pixel.
1268%
1269% o hue, whiteness, blackness: A pointer to a double value representing a
1270% component of the HWB color space.
1271%
1272*/
cristy0a39a5c2012-06-27 12:51:45 +00001273MagickPrivate void ConvertRGBToHWB(const double red,const double green,
cristy3094b7f2011-10-01 23:18:02 +00001274 const double blue,double *hue,double *whiteness,double *blackness)
cristy3ed852e2009-09-05 21:47:34 +00001275{
cristycaf45802012-06-16 18:28:54 +00001276 double
1277 b,
cristy3ed852e2009-09-05 21:47:34 +00001278 f,
cristycaf45802012-06-16 18:28:54 +00001279 g,
1280 p,
1281 r,
cristy3ed852e2009-09-05 21:47:34 +00001282 v,
1283 w;
1284
cristy3ed852e2009-09-05 21:47:34 +00001285 /*
1286 Convert RGB to HWB colorspace.
1287 */
1288 assert(hue != (double *) NULL);
1289 assert(whiteness != (double *) NULL);
1290 assert(blackness != (double *) NULL);
cristy0a39a5c2012-06-27 12:51:45 +00001291 r=red;
1292 g=green;
1293 b=blue;
cristycaf45802012-06-16 18:28:54 +00001294 w=MagickMin(r,MagickMin(g,b));
1295 v=MagickMax(r,MagickMax(g,b));
cristy3ed852e2009-09-05 21:47:34 +00001296 *blackness=1.0-QuantumScale*v;
1297 *whiteness=QuantumScale*w;
1298 if (v == w)
1299 {
cristyaf10b112012-04-18 13:25:37 +00001300 *hue=(-1.0);
cristy3ed852e2009-09-05 21:47:34 +00001301 return;
1302 }
cristycaf45802012-06-16 18:28:54 +00001303 f=(r == w) ? g-b : ((g == w) ? b-r : r-g);
1304 p=(r == w) ? 3.0 : ((g == w) ? 5.0 : 1.0);
1305 *hue=(p-f/(v-1.0*w))/6.0;
cristy3ed852e2009-09-05 21:47:34 +00001306}
1307
1308/*
1309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1310% %
1311% %
1312% %
cristya83d4c02013-04-19 19:39:30 +00001313% C o n v e r t R G B T o L C H a b %
cristyb2850952013-04-04 19:00:52 +00001314% %
1315% %
1316% %
1317%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1318%
cristydf42b172013-04-05 13:35:37 +00001319% ConvertRGBToLCHab() transforms a (red, green, blue) to a (luma, chroma,
cristyb2850952013-04-04 19:00:52 +00001320% hue) triple.
1321%
cristydf42b172013-04-05 13:35:37 +00001322% The format of the ConvertRGBToLCHab method is:
cristyb2850952013-04-04 19:00:52 +00001323%
cristydf42b172013-04-05 13:35:37 +00001324% void ConvertRGBToLCHab(const double red,const double green,
cristyb2850952013-04-04 19:00:52 +00001325% const double blue,double *luma,double *chroma,double *hue)
1326%
1327% A description of each parameter follows:
1328%
1329% o red, green, blue: A Quantum value representing the red, green, and
1330% blue component of a pixel.
1331%
1332% o luma, chroma, hue: A pointer to a double value representing a
1333% component of the LCH color space.
1334%
1335*/
cristyc32cb022013-05-06 13:32:31 +00001336
1337static inline void ConvertXYZToLCHab(const double X,const double Y,
1338 const double Z,double *luma,double *chroma,double *hue)
1339{
1340 double
1341 a,
1342 b;
1343
1344 ConvertXYZToLab(X,Y,Z,luma,&a,&b);
cristycc6d1f42013-06-19 16:13:34 +00001345 *chroma=hypot(255.0*(a-0.5),255.0*(b-0.5))/255.0+0.5;
1346 *hue=180.0*atan2(255.0*(b-0.5),255.0*(a-0.5))/MagickPI/360.0;
cristy89106f82013-05-06 17:04:29 +00001347 if (*hue < 0.0)
1348 *hue+=1.0;
cristycc6d1f42013-06-19 16:13:34 +00001349 *hue+=0.5;
cristyc32cb022013-05-06 13:32:31 +00001350}
1351
cristydf42b172013-04-05 13:35:37 +00001352MagickPrivate void ConvertRGBToLCHab(const double red,const double green,
cristyb2850952013-04-04 19:00:52 +00001353 const double blue,double *luma,double *chroma,double *hue)
1354{
1355 double
cristyb2850952013-04-04 19:00:52 +00001356 X,
1357 Y,
1358 Z;
1359
1360 /*
cristy9427c422013-04-08 12:03:11 +00001361 Convert RGB to LCHab colorspace.
cristyb2850952013-04-04 19:00:52 +00001362 */
1363 assert(luma != (double *) NULL);
1364 assert(chroma != (double *) NULL);
1365 assert(hue != (double *) NULL);
1366 ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
cristyc32cb022013-05-06 13:32:31 +00001367 ConvertXYZToLCHab(X,Y,Z,luma,chroma,hue);
cristyb2850952013-04-04 19:00:52 +00001368}
1369
1370/*
1371%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1372% %
1373% %
1374% %
cristya83d4c02013-04-19 19:39:30 +00001375% C o n v e r t R G B T o L C H u v %
cristydf42b172013-04-05 13:35:37 +00001376% %
1377% %
1378% %
1379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1380%
1381% ConvertRGBToLCHuv() transforms a (red, green, blue) to a (luma, chroma,
1382% hue) triple.
1383%
1384% The format of the ConvertRGBToLCHuv method is:
1385%
1386% void ConvertRGBToLCHuv(const double red,const double green,
1387% const double blue,double *luma,double *chroma,double *hue)
1388%
1389% A description of each parameter follows:
1390%
1391% o red, green, blue: A Quantum value representing the red, green, and
1392% blue component of a pixel.
1393%
1394% o luma, chroma, hue: A pointer to a double value representing a
1395% component of the LCHuv color space.
1396%
1397*/
cristyc32cb022013-05-06 13:32:31 +00001398
1399static inline void ConvertXYZToLCHuv(const double X,const double Y,
1400 const double Z,double *luma,double *chroma,double *hue)
1401{
1402 double
cristy9db2dba2013-05-06 14:04:13 +00001403 u,
1404 v;
cristyc32cb022013-05-06 13:32:31 +00001405
cristy9db2dba2013-05-06 14:04:13 +00001406 ConvertXYZToLuv(X,Y,Z,luma,&u,&v);
cristycc6d1f42013-06-19 16:13:34 +00001407 *chroma=(hypot(354.0*u-134.0,262.0*v-140.0)+134.0)/354.0;
1408 *hue=180.0*atan2(262.0*v-140.0,354.0*u-134.0)/MagickPI/360.0;
cristy14a4e0f2013-05-06 19:53:58 +00001409 if (*hue < 0.0)
1410 *hue+=1.0;
cristycc6d1f42013-06-19 16:13:34 +00001411 *hue=(255.0**hue+140.0)/262.0;
cristyc32cb022013-05-06 13:32:31 +00001412}
1413
cristydf42b172013-04-05 13:35:37 +00001414MagickPrivate void ConvertRGBToLCHuv(const double red,const double green,
1415 const double blue,double *luma,double *chroma,double *hue)
1416{
1417 double
cristydf42b172013-04-05 13:35:37 +00001418 X,
1419 Y,
1420 Z;
1421
1422 /*
cristy9427c422013-04-08 12:03:11 +00001423 Convert RGB to LCHuv colorspace.
cristydf42b172013-04-05 13:35:37 +00001424 */
1425 assert(luma != (double *) NULL);
1426 assert(chroma != (double *) NULL);
1427 assert(hue != (double *) NULL);
1428 ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
cristyc32cb022013-05-06 13:32:31 +00001429 ConvertXYZToLCHuv(X,Y,Z,luma,chroma,hue);
cristydf42b172013-04-05 13:35:37 +00001430}
1431
1432/*
1433%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1434% %
1435% %
1436% %
cristy3ed852e2009-09-05 21:47:34 +00001437% E x p a n d A f f i n e %
1438% %
1439% %
1440% %
1441%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1442%
1443% ExpandAffine() computes the affine's expansion factor, i.e. the square root
1444% of the factor by which the affine transform affects area. In an affine
1445% transform composed of scaling, rotation, shearing, and translation, returns
1446% the amount of scaling.
1447%
1448% The format of the ExpandAffine method is:
1449%
1450% double ExpandAffine(const AffineMatrix *affine)
1451%
1452% A description of each parameter follows:
1453%
cristy2d7ffbb2013-04-19 19:43:01 +00001454% o expansion: ExpandAffine returns the affine's expansion factor.
cristy3ed852e2009-09-05 21:47:34 +00001455%
1456% o affine: A pointer the affine transform of type AffineMatrix.
1457%
1458*/
1459MagickExport double ExpandAffine(const AffineMatrix *affine)
1460{
1461 assert(affine != (const AffineMatrix *) NULL);
1462 return(sqrt(fabs(affine->sx*affine->sy-affine->rx*affine->ry)));
1463}
1464
1465/*
1466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1467% %
1468% %
1469% %
1470% 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 %
1471% %
1472% %
1473% %
1474%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1475%
cristy82b15832009-10-06 19:17:37 +00001476% GenerateDifferentialNoise() generates differentual noise.
cristy3ed852e2009-09-05 21:47:34 +00001477%
1478% The format of the GenerateDifferentialNoise method is:
1479%
1480% double GenerateDifferentialNoise(RandomInfo *random_info,
cristy9ed1f812011-10-08 02:00:08 +00001481% const Quantum pixel,const NoiseType noise_type,const double attenuate)
cristy3ed852e2009-09-05 21:47:34 +00001482%
1483% A description of each parameter follows:
1484%
1485% o random_info: the random info.
1486%
1487% o pixel: noise is relative to this pixel value.
1488%
1489% o noise_type: the type of noise.
1490%
1491% o attenuate: attenuate the noise.
1492%
1493*/
cristy8ea81222011-09-04 10:33:32 +00001494MagickPrivate double GenerateDifferentialNoise(RandomInfo *random_info,
cristy9ed1f812011-10-08 02:00:08 +00001495 const Quantum pixel,const NoiseType noise_type,const double attenuate)
cristy3ed852e2009-09-05 21:47:34 +00001496{
cristy7118edf2011-10-08 13:33:25 +00001497#define SigmaUniform (attenuate*0.015625)
1498#define SigmaGaussian (attenuate*0.015625)
1499#define SigmaImpulse (attenuate*0.1)
1500#define SigmaLaplacian (attenuate*0.0390625)
1501#define SigmaMultiplicativeGaussian (attenuate*0.5)
cristy4ce9df62011-10-12 12:06:02 +00001502#define SigmaPoisson (attenuate*12.5)
cristy785eb592012-07-08 22:12:15 +00001503#define SigmaRandom (attenuate)
cristy7118edf2011-10-08 13:33:25 +00001504#define TauGaussian (attenuate*0.078125)
cristy3ed852e2009-09-05 21:47:34 +00001505
cristyadb41ca2009-10-22 15:02:28 +00001506 double
cristy3ed852e2009-09-05 21:47:34 +00001507 alpha,
1508 beta,
1509 noise,
1510 sigma;
1511
1512 alpha=GetPseudoRandomValue(random_info);
cristy3ed852e2009-09-05 21:47:34 +00001513 switch (noise_type)
1514 {
1515 case UniformNoise:
1516 default:
1517 {
cristy6bbabe62011-10-09 13:54:18 +00001518 noise=(double) (pixel+QuantumRange*SigmaUniform*(alpha-0.5));
cristy3ed852e2009-09-05 21:47:34 +00001519 break;
1520 }
1521 case GaussianNoise:
1522 {
cristyadb41ca2009-10-22 15:02:28 +00001523 double
cristy62faa602010-02-20 03:36:17 +00001524 gamma,
cristy3ed852e2009-09-05 21:47:34 +00001525 tau;
1526
cristyadb41ca2009-10-22 15:02:28 +00001527 if (alpha == 0.0)
1528 alpha=1.0;
cristy3ed852e2009-09-05 21:47:34 +00001529 beta=GetPseudoRandomValue(random_info);
cristy62faa602010-02-20 03:36:17 +00001530 gamma=sqrt(-2.0*log(alpha));
cristy55a91cd2010-12-01 00:57:40 +00001531 sigma=gamma*cos((double) (2.0*MagickPI*beta));
1532 tau=gamma*sin((double) (2.0*MagickPI*beta));
cristy6bbabe62011-10-09 13:54:18 +00001533 noise=(double) (pixel+sqrt((double) pixel)*SigmaGaussian*sigma+
1534 QuantumRange*TauGaussian*tau);
cristy3ed852e2009-09-05 21:47:34 +00001535 break;
1536 }
1537 case ImpulseNoise:
1538 {
1539 if (alpha < (SigmaImpulse/2.0))
1540 noise=0.0;
cristy37c24072011-10-08 01:26:00 +00001541 else
1542 if (alpha >= (1.0-(SigmaImpulse/2.0)))
1543 noise=(double) QuantumRange;
1544 else
1545 noise=(double) pixel;
cristy3ed852e2009-09-05 21:47:34 +00001546 break;
1547 }
1548 case LaplacianNoise:
1549 {
1550 if (alpha <= 0.5)
1551 {
cristy7118edf2011-10-08 13:33:25 +00001552 if (alpha <= MagickEpsilon)
cristy6bbabe62011-10-09 13:54:18 +00001553 noise=(double) (pixel-QuantumRange);
cristy3ed852e2009-09-05 21:47:34 +00001554 else
cristy785eb592012-07-08 22:12:15 +00001555 noise=(double) (pixel+QuantumRange*SigmaLaplacian*log(2.0*alpha)+
1556 0.5);
cristy3ed852e2009-09-05 21:47:34 +00001557 break;
1558 }
1559 beta=1.0-alpha;
cristy7118edf2011-10-08 13:33:25 +00001560 if (beta <= (0.5*MagickEpsilon))
cristyadb41ca2009-10-22 15:02:28 +00001561 noise=(double) (pixel+QuantumRange);
cristy3ed852e2009-09-05 21:47:34 +00001562 else
cristy6bbabe62011-10-09 13:54:18 +00001563 noise=(double) (pixel-QuantumRange*SigmaLaplacian*log(2.0*beta)+0.5);
cristy7118edf2011-10-08 13:33:25 +00001564 break;
1565 }
1566 case MultiplicativeGaussianNoise:
1567 {
1568 sigma=1.0;
1569 if (alpha > MagickEpsilon)
1570 sigma=sqrt(-2.0*log(alpha));
1571 beta=GetPseudoRandomValue(random_info);
cristy6bbabe62011-10-09 13:54:18 +00001572 noise=(double) (pixel+pixel*SigmaMultiplicativeGaussian*sigma*
1573 cos((double) (2.0*MagickPI*beta))/2.0);
cristy3ed852e2009-09-05 21:47:34 +00001574 break;
1575 }
1576 case PoissonNoise:
1577 {
cristyadb41ca2009-10-22 15:02:28 +00001578 double
cristy3ed852e2009-09-05 21:47:34 +00001579 poisson;
1580
cristybb503372010-05-27 20:51:26 +00001581 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001582 i;
1583
cristy7118edf2011-10-08 13:33:25 +00001584 poisson=exp(-SigmaPoisson*QuantumScale*pixel);
cristy3ed852e2009-09-05 21:47:34 +00001585 for (i=0; alpha > poisson; i++)
1586 {
1587 beta=GetPseudoRandomValue(random_info);
1588 alpha*=beta;
1589 }
cristy6bbabe62011-10-09 13:54:18 +00001590 noise=(double) (QuantumRange*i/SigmaPoisson);
cristy3ed852e2009-09-05 21:47:34 +00001591 break;
1592 }
1593 case RandomNoise:
1594 {
cristy785eb592012-07-08 22:12:15 +00001595 noise=(double) (QuantumRange*SigmaRandom*alpha);
cristy3ed852e2009-09-05 21:47:34 +00001596 break;
1597 }
1598 }
1599 return(noise);
1600}
1601
1602/*
1603%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1604% %
1605% %
1606% %
1607% G e t O p t i m a l K e r n e l W i d t h %
1608% %
1609% %
1610% %
1611%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1612%
1613% GetOptimalKernelWidth() computes the optimal kernel radius for a convolution
1614% filter. Start with the minimum value of 3 pixels and walk out until we drop
1615% below the threshold of one pixel numerical accuracy.
1616%
1617% The format of the GetOptimalKernelWidth method is:
1618%
cristybb503372010-05-27 20:51:26 +00001619% size_t GetOptimalKernelWidth(const double radius,
cristy3ed852e2009-09-05 21:47:34 +00001620% const double sigma)
1621%
1622% A description of each parameter follows:
1623%
cristy2d7ffbb2013-04-19 19:43:01 +00001624% o width: GetOptimalKernelWidth returns the optimal width of a
1625% convolution kernel.
cristy3ed852e2009-09-05 21:47:34 +00001626%
1627% o radius: the radius of the Gaussian, in pixels, not counting the center
1628% pixel.
1629%
1630% o sigma: the standard deviation of the Gaussian, in pixels.
1631%
1632*/
cristy8ea81222011-09-04 10:33:32 +00001633MagickPrivate size_t GetOptimalKernelWidth1D(const double radius,
cristye96405a2010-05-19 02:24:31 +00001634 const double sigma)
cristy3ed852e2009-09-05 21:47:34 +00001635{
cristye96405a2010-05-19 02:24:31 +00001636 double
1637 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
cristybb503372010-05-27 20:51:26 +00001643 register ssize_t
cristy47e00502009-12-17 19:19:57 +00001644 i;
1645
cristybb503372010-05-27 20:51:26 +00001646 size_t
cristy47e00502009-12-17 19:19:57 +00001647 width;
cristy3ed852e2009-09-05 21:47:34 +00001648
cristy9d314ff2011-03-09 01:30:28 +00001649 ssize_t
1650 j;
1651
cristy3ed852e2009-09-05 21:47:34 +00001652 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristy47e00502009-12-17 19:19:57 +00001653 if (radius > MagickEpsilon)
cristybb503372010-05-27 20:51:26 +00001654 return((size_t) (2.0*ceil(radius)+1.0));
cristye96405a2010-05-19 02:24:31 +00001655 gamma=fabs(sigma);
1656 if (gamma <= MagickEpsilon)
anthonyc1061722010-05-14 06:23:49 +00001657 return(3UL);
cristy3e3ec3a2012-11-03 23:11:06 +00001658 alpha=PerceptibleReciprocal(2.0*gamma*gamma);
1659 beta=(double) PerceptibleReciprocal((double) MagickSQ2PI*gamma);
cristy3ed852e2009-09-05 21:47:34 +00001660 for (width=5; ; )
1661 {
1662 normalize=0.0;
cristy35faaa72013-03-08 12:33:42 +00001663 j=(ssize_t) (width-1)/2;
cristy47e00502009-12-17 19:19:57 +00001664 for (i=(-j); i <= j; i++)
cristye96405a2010-05-19 02:24:31 +00001665 normalize+=exp(-((double) (i*i))*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 GetOptimalKernelWidth2D(const double radius,
cristye96405a2010-05-19 02:24:31 +00001675 const double sigma)
cristy3ed852e2009-09-05 21:47:34 +00001676{
cristy47e00502009-12-17 19:19:57 +00001677 double
cristye96405a2010-05-19 02:24:31 +00001678 alpha,
1679 beta,
1680 gamma,
cristy3ed852e2009-09-05 21:47:34 +00001681 normalize,
cristye96405a2010-05-19 02:24:31 +00001682 value;
cristy3ed852e2009-09-05 21:47:34 +00001683
cristy9d314ff2011-03-09 01:30:28 +00001684 size_t
1685 width;
1686
cristybb503372010-05-27 20:51:26 +00001687 ssize_t
cristy47e00502009-12-17 19:19:57 +00001688 j,
cristy3ed852e2009-09-05 21:47:34 +00001689 u,
1690 v;
1691
1692 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristy47e00502009-12-17 19:19:57 +00001693 if (radius > MagickEpsilon)
cristybb503372010-05-27 20:51:26 +00001694 return((size_t) (2.0*ceil(radius)+1.0));
cristye96405a2010-05-19 02:24:31 +00001695 gamma=fabs(sigma);
1696 if (gamma <= MagickEpsilon)
anthonyc1061722010-05-14 06:23:49 +00001697 return(3UL);
cristy3e3ec3a2012-11-03 23:11:06 +00001698 alpha=PerceptibleReciprocal(2.0*gamma*gamma);
1699 beta=(double) PerceptibleReciprocal((double) Magick2PI*gamma*gamma);
cristy3ed852e2009-09-05 21:47:34 +00001700 for (width=5; ; )
1701 {
1702 normalize=0.0;
cristy35faaa72013-03-08 12:33:42 +00001703 j=(ssize_t) (width-1)/2;
cristy47e00502009-12-17 19:19:57 +00001704 for (v=(-j); v <= j; v++)
cristy47e00502009-12-17 19:19:57 +00001705 for (u=(-j); u <= j; u++)
cristye96405a2010-05-19 02:24:31 +00001706 normalize+=exp(-((double) (u*u+v*v))*alpha)*beta;
1707 value=exp(-((double) (j*j))*alpha)*beta/normalize;
cristy20908da2009-12-02 14:34:11 +00001708 if ((value < QuantumScale) || (value < MagickEpsilon))
cristy3ed852e2009-09-05 21:47:34 +00001709 break;
1710 width+=2;
1711 }
cristybb503372010-05-27 20:51:26 +00001712 return((size_t) (width-2));
cristy3ed852e2009-09-05 21:47:34 +00001713}
1714
cristy8ea81222011-09-04 10:33:32 +00001715MagickPrivate size_t GetOptimalKernelWidth(const double radius,
cristy3ed852e2009-09-05 21:47:34 +00001716 const double sigma)
1717{
1718 return(GetOptimalKernelWidth1D(radius,sigma));
1719}