| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 1 | /* | 
|  | 2 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
|  | 3 | %                                                                             % | 
|  | 4 | %                                                                             % | 
|  | 5 | %                                                                             % | 
|  | 6 | %                              GGGG  EEEEE  M   M                             % | 
|  | 7 | %                             G      E      MM MM                             % | 
|  | 8 | %                             G GG   EEE    M M M                             % | 
|  | 9 | %                             G   G  E      M   M                             % | 
|  | 10 | %                              GGGG  EEEEE  M   M                             % | 
|  | 11 | %                                                                             % | 
|  | 12 | %                                                                             % | 
|  | 13 | %                    Graphic Gems - Graphic Support Methods                   % | 
|  | 14 | %                                                                             % | 
|  | 15 | %                               Software Design                               % | 
|  | 16 | %                                 John Cristy                                 % | 
|  | 17 | %                                 August 1996                                 % | 
|  | 18 | %                                                                             % | 
|  | 19 | %                                                                             % | 
| cristy | 1454be7 | 2011-12-19 01:52:48 +0000 | [diff] [blame] | 20 | %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      % | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 21 | %  dedicated to making software imaging solutions freely available.           % | 
|  | 22 | %                                                                             % | 
|  | 23 | %  You may not use this file except in compliance with the License.  You may  % | 
|  | 24 | %  obtain a copy of the License at                                            % | 
|  | 25 | %                                                                             % | 
|  | 26 | %    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 | */ | 
| cristy | 4c08aed | 2011-07-01 19:47:50 +0000 | [diff] [blame] | 43 | #include "MagickCore/studio.h" | 
|  | 44 | #include "MagickCore/color-private.h" | 
|  | 45 | #include "MagickCore/draw.h" | 
|  | 46 | #include "MagickCore/gem.h" | 
| cristy | d1dd6e4 | 2011-09-04 01:46:08 +0000 | [diff] [blame] | 47 | #include "MagickCore/gem-private.h" | 
| cristy | 4c08aed | 2011-07-01 19:47:50 +0000 | [diff] [blame] | 48 | #include "MagickCore/image.h" | 
|  | 49 | #include "MagickCore/image-private.h" | 
|  | 50 | #include "MagickCore/log.h" | 
|  | 51 | #include "MagickCore/memory_.h" | 
|  | 52 | #include "MagickCore/pixel-accessor.h" | 
| cristy | 35f1530 | 2012-06-07 14:59:02 +0000 | [diff] [blame] | 53 | #include "MagickCore/pixel-private.h" | 
| cristy | 4c08aed | 2011-07-01 19:47:50 +0000 | [diff] [blame] | 54 | #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" | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 60 |  | 
|  | 61 | /* | 
|  | 62 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
|  | 63 | %                                                                             % | 
|  | 64 | %                                                                             % | 
|  | 65 | %                                                                             % | 
| cristy | bd0e548 | 2012-06-14 11:51:00 +0000 | [diff] [blame] | 66 | %   C o n v e r t H S B T o s R G B                                           % | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 67 | %                                                                             % | 
|  | 68 | %                                                                             % | 
|  | 69 | %                                                                             % | 
|  | 70 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
|  | 71 | % | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 72 | %  ConvertHSBTosRGB() transforms a (hue, saturation, brightness) to a (red, | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 73 | %  green, blue) triple. | 
|  | 74 | % | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 75 | %  The format of the ConvertHSBTosRGBImage method is: | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 76 | % | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 77 | %      void ConvertHSBTosRGB(const double hue,const double saturation, | 
| cristy | 3094b7f | 2011-10-01 23:18:02 +0000 | [diff] [blame] | 78 | %        const double brightness,double *red,double *green,double *blue) | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 79 | % | 
|  | 80 | %  A description of each parameter follows: | 
|  | 81 | % | 
|  | 82 | %    o hue, saturation, brightness: A double value representing a | 
|  | 83 | %      component of the HSB color space. | 
|  | 84 | % | 
|  | 85 | %    o red, green, blue: A pointer to a pixel component of type Quantum. | 
|  | 86 | % | 
|  | 87 | */ | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 88 | MagickPrivate void ConvertHSBTosRGB(const double hue,const double saturation, | 
| cristy | 3094b7f | 2011-10-01 23:18:02 +0000 | [diff] [blame] | 89 | const double brightness,double *red,double *green,double *blue) | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 90 | { | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 91 | double | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 92 | f, | 
|  | 93 | h, | 
|  | 94 | p, | 
|  | 95 | q, | 
|  | 96 | t; | 
|  | 97 |  | 
|  | 98 | /* | 
|  | 99 | Convert HSB to RGB colorspace. | 
|  | 100 | */ | 
| cristy | 3094b7f | 2011-10-01 23:18:02 +0000 | [diff] [blame] | 101 | assert(red != (double *) NULL); | 
|  | 102 | assert(green != (double *) NULL); | 
|  | 103 | assert(blue != (double *) NULL); | 
| cristy | 98a65d5 | 2010-04-14 02:12:38 +0000 | [diff] [blame] | 104 | if (saturation == 0.0) | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 105 | { | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 106 | *red=QuantumRange*brightness; | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 107 | *green=(*red); | 
|  | 108 | *blue=(*red); | 
|  | 109 | return; | 
|  | 110 | } | 
| cristy | 98a65d5 | 2010-04-14 02:12:38 +0000 | [diff] [blame] | 111 | h=6.0*(hue-floor(hue)); | 
|  | 112 | f=h-floor((double) h); | 
|  | 113 | p=brightness*(1.0-saturation); | 
|  | 114 | q=brightness*(1.0-saturation*f); | 
|  | 115 | t=brightness*(1.0-(saturation*(1.0-f))); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 116 | switch ((int) h) | 
|  | 117 | { | 
|  | 118 | case 0: | 
|  | 119 | default: | 
|  | 120 | { | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 121 | *red=QuantumRange*sRGBCompanding(brightness); | 
|  | 122 | *green=QuantumRange*sRGBCompanding(t); | 
|  | 123 | *blue=QuantumRange*sRGBCompanding(p); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 124 | break; | 
|  | 125 | } | 
|  | 126 | case 1: | 
|  | 127 | { | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 128 | *red=QuantumRange*sRGBCompanding(q); | 
|  | 129 | *green=QuantumRange*sRGBCompanding(brightness); | 
|  | 130 | *blue=QuantumRange*sRGBCompanding(p); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 131 | break; | 
|  | 132 | } | 
|  | 133 | case 2: | 
|  | 134 | { | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 135 | *red=QuantumRange*sRGBCompanding(p); | 
|  | 136 | *green=QuantumRange*sRGBCompanding(brightness); | 
|  | 137 | *blue=QuantumRange*sRGBCompanding(t); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 138 | break; | 
|  | 139 | } | 
|  | 140 | case 3: | 
|  | 141 | { | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 142 | *red=QuantumRange*sRGBCompanding(p); | 
|  | 143 | *green=QuantumRange*sRGBCompanding(q); | 
|  | 144 | *blue=QuantumRange*sRGBCompanding(brightness); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 145 | break; | 
|  | 146 | } | 
|  | 147 | case 4: | 
|  | 148 | { | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 149 | *red=QuantumRange*sRGBCompanding(t); | 
|  | 150 | *green=QuantumRange*sRGBCompanding(p); | 
|  | 151 | *blue=QuantumRange*sRGBCompanding(brightness); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 152 | break; | 
|  | 153 | } | 
|  | 154 | case 5: | 
|  | 155 | { | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 156 | *red=QuantumRange*sRGBCompanding(brightness); | 
|  | 157 | *green=QuantumRange*sRGBCompanding(p); | 
|  | 158 | *blue=QuantumRange*sRGBCompanding(q); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 159 | break; | 
|  | 160 | } | 
|  | 161 | } | 
|  | 162 | } | 
|  | 163 |  | 
|  | 164 | /* | 
|  | 165 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
|  | 166 | %                                                                             % | 
|  | 167 | %                                                                             % | 
|  | 168 | %                                                                             % | 
| cristy | bd0e548 | 2012-06-14 11:51:00 +0000 | [diff] [blame] | 169 | %   C o n v e r t H S L T o s R G B                                           % | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 170 | %                                                                             % | 
|  | 171 | %                                                                             % | 
|  | 172 | %                                                                             % | 
|  | 173 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
|  | 174 | % | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 175 | %  ConvertHSLTosRGB() transforms a (hue, saturation, lightness) to a (red, | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 176 | %  green, blue) triple. | 
|  | 177 | % | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 178 | %  The format of the ConvertHSLTosRGBImage method is: | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 179 | % | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 180 | %      void ConvertHSLTosRGB(const double hue,const double saturation, | 
| cristy | 3094b7f | 2011-10-01 23:18:02 +0000 | [diff] [blame] | 181 | %        const double lightness,double *red,double *green,double *blue) | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 182 | % | 
|  | 183 | %  A description of each parameter follows: | 
|  | 184 | % | 
|  | 185 | %    o hue, saturation, lightness: A double value representing a | 
|  | 186 | %      component of the HSL color space. | 
|  | 187 | % | 
|  | 188 | %    o red, green, blue: A pointer to a pixel component of type Quantum. | 
|  | 189 | % | 
|  | 190 | */ | 
|  | 191 |  | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 192 | static inline double ConvertHueTosRGB(double m1,double m2,double hue) | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 193 | { | 
|  | 194 | if (hue < 0.0) | 
|  | 195 | hue+=1.0; | 
|  | 196 | if (hue > 1.0) | 
|  | 197 | hue-=1.0; | 
|  | 198 | if ((6.0*hue) < 1.0) | 
| cristy | a163b0c | 2010-04-13 01:04:49 +0000 | [diff] [blame] | 199 | return(m1+6.0*(m2-m1)*hue); | 
|  | 200 | if ((2.0*hue) < 1.0) | 
|  | 201 | return(m2); | 
|  | 202 | if ((3.0*hue) < 2.0) | 
|  | 203 | return(m1+6.0*(m2-m1)*(2.0/3.0-hue)); | 
|  | 204 | return(m1); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 205 | } | 
|  | 206 |  | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 207 | MagickExport void ConvertHSLTosRGB(const double hue,const double saturation, | 
| cristy | 3094b7f | 2011-10-01 23:18:02 +0000 | [diff] [blame] | 208 | const double lightness,double *red,double *green,double *blue) | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 209 | { | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 210 | double | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 211 | b, | 
|  | 212 | g, | 
|  | 213 | r, | 
|  | 214 | m1, | 
|  | 215 | m2; | 
|  | 216 |  | 
|  | 217 | /* | 
|  | 218 | Convert HSL to RGB colorspace. | 
|  | 219 | */ | 
| cristy | 3094b7f | 2011-10-01 23:18:02 +0000 | [diff] [blame] | 220 | assert(red != (double *) NULL); | 
|  | 221 | assert(green != (double *) NULL); | 
|  | 222 | assert(blue != (double *) NULL); | 
| cristy | 98a65d5 | 2010-04-14 02:12:38 +0000 | [diff] [blame] | 223 | if (saturation == 0) | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 224 | { | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 225 | *red=QuantumRange*lightness; | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 226 | *green=(*red); | 
|  | 227 | *blue=(*red); | 
|  | 228 | return; | 
|  | 229 | } | 
| cristy | 27cabb8 | 2010-04-14 11:33:57 +0000 | [diff] [blame] | 230 | if (lightness < 0.5) | 
| cristy | 98a65d5 | 2010-04-14 02:12:38 +0000 | [diff] [blame] | 231 | m2=lightness*(saturation+1.0); | 
|  | 232 | else | 
|  | 233 | m2=(lightness+saturation)-(lightness*saturation); | 
|  | 234 | m1=2.0*lightness-m2; | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 235 | r=ConvertHueTosRGB(m1,m2,hue+1.0/3.0); | 
|  | 236 | g=ConvertHueTosRGB(m1,m2,hue); | 
|  | 237 | b=ConvertHueTosRGB(m1,m2,hue-1.0/3.0); | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 238 | *red=QuantumRange*sRGBCompanding(r); | 
|  | 239 | *green=QuantumRange*sRGBCompanding(g); | 
|  | 240 | *blue=QuantumRange*sRGBCompanding(b); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 241 | } | 
|  | 242 |  | 
|  | 243 | /* | 
|  | 244 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
|  | 245 | %                                                                             % | 
|  | 246 | %                                                                             % | 
|  | 247 | %                                                                             % | 
| cristy | bd0e548 | 2012-06-14 11:51:00 +0000 | [diff] [blame] | 248 | %   C o n v e r t H W B T o s R G B                                           % | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 249 | %                                                                             % | 
|  | 250 | %                                                                             % | 
|  | 251 | %                                                                             % | 
|  | 252 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
|  | 253 | % | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 254 | %  ConvertHWBTosRGB() transforms a (hue, whiteness, blackness) to a (red, green, | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 255 | %  blue) triple. | 
|  | 256 | % | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 257 | %  The format of the ConvertHWBTosRGBImage method is: | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 258 | % | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 259 | %      void ConvertHWBTosRGB(const double hue,const double whiteness, | 
| cristy | 3094b7f | 2011-10-01 23:18:02 +0000 | [diff] [blame] | 260 | %        const double blackness,double *red,double *green,double *blue) | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 261 | % | 
|  | 262 | %  A description of each parameter follows: | 
|  | 263 | % | 
|  | 264 | %    o hue, whiteness, blackness: A double value representing a | 
|  | 265 | %      component of the HWB color space. | 
|  | 266 | % | 
|  | 267 | %    o red, green, blue: A pointer to a pixel component of type Quantum. | 
|  | 268 | % | 
|  | 269 | */ | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 270 | MagickPrivate void ConvertHWBTosRGB(const double hue,const double whiteness, | 
| cristy | 3094b7f | 2011-10-01 23:18:02 +0000 | [diff] [blame] | 271 | const double blackness,double *red,double *green,double *blue) | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 272 | { | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 273 | double | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 274 | b, | 
|  | 275 | f, | 
|  | 276 | g, | 
|  | 277 | n, | 
|  | 278 | r, | 
|  | 279 | v; | 
|  | 280 |  | 
| cristy | bb50337 | 2010-05-27 20:51:26 +0000 | [diff] [blame] | 281 | register ssize_t | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 282 | i; | 
|  | 283 |  | 
|  | 284 | /* | 
|  | 285 | Convert HWB to RGB colorspace. | 
|  | 286 | */ | 
| cristy | 3094b7f | 2011-10-01 23:18:02 +0000 | [diff] [blame] | 287 | assert(red != (double *) NULL); | 
|  | 288 | assert(green != (double *) NULL); | 
|  | 289 | assert(blue != (double *) NULL); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 290 | v=1.0-blackness; | 
| cristy | af10b11 | 2012-04-18 13:25:37 +0000 | [diff] [blame] | 291 | if (hue == -1.0) | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 292 | { | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 293 | *red=QuantumRange*sRGBCompanding(v); | 
|  | 294 | *green=QuantumRange*sRGBCompanding(v); | 
|  | 295 | *blue=QuantumRange*sRGBCompanding(v); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 296 | return; | 
|  | 297 | } | 
| cristy | bb50337 | 2010-05-27 20:51:26 +0000 | [diff] [blame] | 298 | i=(ssize_t) floor(6.0*hue); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 299 | f=6.0*hue-i; | 
|  | 300 | if ((i & 0x01) != 0) | 
|  | 301 | f=1.0-f; | 
|  | 302 | n=whiteness+f*(v-whiteness);  /* linear interpolation */ | 
|  | 303 | switch (i) | 
|  | 304 | { | 
|  | 305 | default: | 
|  | 306 | case 6: | 
|  | 307 | case 0: r=v; g=n; b=whiteness; break; | 
|  | 308 | case 1: r=n; g=v; b=whiteness; break; | 
|  | 309 | case 2: r=whiteness; g=v; b=n; break; | 
|  | 310 | case 3: r=whiteness; g=n; b=v; break; | 
|  | 311 | case 4: r=n; g=whiteness; b=v; break; | 
|  | 312 | case 5: r=v; g=whiteness; b=n; break; | 
|  | 313 | } | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 314 | *red=QuantumRange*sRGBCompanding(r); | 
|  | 315 | *green=QuantumRange*sRGBCompanding(g); | 
|  | 316 | *blue=QuantumRange*sRGBCompanding(b); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 317 | } | 
|  | 318 |  | 
|  | 319 | /* | 
|  | 320 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
|  | 321 | %                                                                             % | 
|  | 322 | %                                                                             % | 
|  | 323 | %                                                                             % | 
| cristy | bd0e548 | 2012-06-14 11:51:00 +0000 | [diff] [blame] | 324 | %   C o n v e r t s R G B T o H S B                                           % | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 325 | %                                                                             % | 
|  | 326 | %                                                                             % | 
|  | 327 | %                                                                             % | 
|  | 328 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
|  | 329 | % | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 330 | %  ConvertsRGBToHSB() transforms a (red, green, blue) to a (hue, saturation, | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 331 | %  brightness) triple. | 
|  | 332 | % | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 333 | %  The format of the ConvertsRGBToHSB method is: | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 334 | % | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 335 | %      void ConvertsRGBToHSB(const double red,const double green, | 
| cristy | 3094b7f | 2011-10-01 23:18:02 +0000 | [diff] [blame] | 336 | %        const double blue,double *hue,double *saturation,double *brightness) | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 337 | % | 
|  | 338 | %  A description of each parameter follows: | 
|  | 339 | % | 
|  | 340 | %    o red, green, blue: A Quantum value representing the red, green, and | 
|  | 341 | %      blue component of a pixel.. | 
|  | 342 | % | 
|  | 343 | %    o hue, saturation, brightness: A pointer to a double value representing a | 
|  | 344 | %      component of the HSB color space. | 
|  | 345 | % | 
|  | 346 | */ | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 347 | MagickPrivate void ConvertsRGBToHSB(const double red,const double green, | 
| cristy | 3094b7f | 2011-10-01 23:18:02 +0000 | [diff] [blame] | 348 | const double blue,double *hue,double *saturation,double *brightness) | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 349 | { | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 350 | double | 
|  | 351 | b, | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 352 | delta, | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 353 | g, | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 354 | max, | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 355 | min, | 
|  | 356 | r; | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 357 |  | 
|  | 358 | /* | 
|  | 359 | Convert RGB to HSB colorspace. | 
|  | 360 | */ | 
|  | 361 | assert(hue != (double *) NULL); | 
|  | 362 | assert(saturation != (double *) NULL); | 
|  | 363 | assert(brightness != (double *) NULL); | 
|  | 364 | *hue=0.0; | 
|  | 365 | *saturation=0.0; | 
|  | 366 | *brightness=0.0; | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 367 | r=QuantumRange*sRGBDecompanding(QuantumScale*red); | 
|  | 368 | g=QuantumRange*sRGBDecompanding(QuantumScale*green); | 
|  | 369 | b=QuantumRange*sRGBDecompanding(QuantumScale*blue); | 
|  | 370 | min=r < g ? r : g; | 
|  | 371 | if (b < min) | 
|  | 372 | min=b; | 
|  | 373 | max=r > g ? r : g; | 
|  | 374 | if (b > max) | 
|  | 375 | max=b; | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 376 | if (max == 0.0) | 
|  | 377 | return; | 
|  | 378 | delta=max-min; | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 379 | *saturation=delta/max; | 
|  | 380 | *brightness=QuantumScale*max; | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 381 | if (delta == 0.0) | 
|  | 382 | return; | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 383 | if (r == max) | 
|  | 384 | *hue=(g-b)/delta; | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 385 | else | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 386 | if (g == max) | 
|  | 387 | *hue=2.0+(b-r)/delta; | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 388 | else | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 389 | *hue=4.0+(r-g)/delta; | 
| cristy | 18b1744 | 2009-10-25 18:36:48 +0000 | [diff] [blame] | 390 | *hue/=6.0; | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 391 | if (*hue < 0.0) | 
|  | 392 | *hue+=1.0; | 
|  | 393 | } | 
|  | 394 |  | 
|  | 395 | /* | 
|  | 396 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
|  | 397 | %                                                                             % | 
|  | 398 | %                                                                             % | 
|  | 399 | %                                                                             % | 
| cristy | bd0e548 | 2012-06-14 11:51:00 +0000 | [diff] [blame] | 400 | %   C o n v e r t s R G B T o H S L                                           % | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 401 | %                                                                             % | 
|  | 402 | %                                                                             % | 
|  | 403 | %                                                                             % | 
|  | 404 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
|  | 405 | % | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 406 | %  ConvertsRGBToHSL() transforms a (red, green, blue) to a (hue, saturation, | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 407 | %  lightness) triple. | 
|  | 408 | % | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 409 | %  The format of the ConvertsRGBToHSL method is: | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 410 | % | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 411 | %      void ConvertsRGBToHSL(const double red,const double green, | 
| cristy | 3094b7f | 2011-10-01 23:18:02 +0000 | [diff] [blame] | 412 | %        const double blue,double *hue,double *saturation,double *lightness) | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 413 | % | 
|  | 414 | %  A description of each parameter follows: | 
|  | 415 | % | 
|  | 416 | %    o red, green, blue: A Quantum value representing the red, green, and | 
|  | 417 | %      blue component of a pixel.. | 
|  | 418 | % | 
|  | 419 | %    o hue, saturation, lightness: A pointer to a double value representing a | 
|  | 420 | %      component of the HSL color space. | 
|  | 421 | % | 
|  | 422 | */ | 
|  | 423 |  | 
|  | 424 | static inline double MagickMax(const double x,const double y) | 
|  | 425 | { | 
|  | 426 | if (x > y) | 
|  | 427 | return(x); | 
|  | 428 | return(y); | 
|  | 429 | } | 
|  | 430 |  | 
|  | 431 | static inline double MagickMin(const double x,const double y) | 
|  | 432 | { | 
|  | 433 | if (x < y) | 
|  | 434 | return(x); | 
|  | 435 | return(y); | 
|  | 436 | } | 
|  | 437 |  | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 438 | MagickExport void ConvertsRGBToHSL(const double red,const double green, | 
| cristy | 3094b7f | 2011-10-01 23:18:02 +0000 | [diff] [blame] | 439 | const double blue,double *hue,double *saturation,double *lightness) | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 440 | { | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 441 | double | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 442 | b, | 
|  | 443 | delta, | 
|  | 444 | g, | 
|  | 445 | max, | 
|  | 446 | min, | 
|  | 447 | r; | 
|  | 448 |  | 
|  | 449 | /* | 
|  | 450 | Convert RGB to HSL colorspace. | 
|  | 451 | */ | 
|  | 452 | assert(hue != (double *) NULL); | 
|  | 453 | assert(saturation != (double *) NULL); | 
|  | 454 | assert(lightness != (double *) NULL); | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 455 | r=sRGBDecompanding(QuantumScale*red); | 
|  | 456 | g=sRGBDecompanding(QuantumScale*green); | 
|  | 457 | b=sRGBDecompanding(QuantumScale*blue); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 458 | max=MagickMax(r,MagickMax(g,b)); | 
|  | 459 | min=MagickMin(r,MagickMin(g,b)); | 
|  | 460 | *lightness=(double) ((min+max)/2.0); | 
|  | 461 | delta=max-min; | 
|  | 462 | if (delta == 0.0) | 
|  | 463 | { | 
|  | 464 | *hue=0.0; | 
|  | 465 | *saturation=0.0; | 
|  | 466 | return; | 
|  | 467 | } | 
|  | 468 | if (*lightness < 0.5) | 
|  | 469 | *saturation=(double) (delta/(min+max)); | 
|  | 470 | else | 
|  | 471 | *saturation=(double) (delta/(2.0-max-min)); | 
|  | 472 | if (r == max) | 
|  | 473 | *hue=((((max-b)/6.0)+(delta/2.0))-(((max-g)/6.0)+(delta/2.0)))/delta; | 
|  | 474 | else | 
|  | 475 | if (g == max) | 
|  | 476 | *hue=(1.0/3.0)+((((max-r)/6.0)+(delta/2.0))-(((max-b)/6.0)+(delta/2.0)))/ | 
|  | 477 | delta; | 
|  | 478 | else | 
|  | 479 | if (b == max) | 
|  | 480 | *hue=(2.0/3.0)+((((max-g)/6.0)+(delta/2.0))-(((max-r)/6.0)+ | 
|  | 481 | (delta/2.0)))/delta; | 
|  | 482 | if (*hue < 0.0) | 
|  | 483 | *hue+=1.0; | 
|  | 484 | if (*hue > 1.0) | 
|  | 485 | *hue-=1.0; | 
|  | 486 | } | 
|  | 487 |  | 
|  | 488 | /* | 
|  | 489 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
|  | 490 | %                                                                             % | 
|  | 491 | %                                                                             % | 
|  | 492 | %                                                                             % | 
| cristy | bd0e548 | 2012-06-14 11:51:00 +0000 | [diff] [blame] | 493 | %   C o n v e r t s R G B T o H W B                                           % | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 494 | %                                                                             % | 
|  | 495 | %                                                                             % | 
|  | 496 | %                                                                             % | 
|  | 497 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
|  | 498 | % | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 499 | %  ConvertsRGBToHWB() transforms a (red, green, blue) to a (hue, whiteness, | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 500 | %  blackness) triple. | 
|  | 501 | % | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 502 | %  The format of the ConvertsRGBToHWB method is: | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 503 | % | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 504 | %      void ConvertsRGBToHWB(const double red,const double green, | 
| cristy | 3094b7f | 2011-10-01 23:18:02 +0000 | [diff] [blame] | 505 | %        const double blue,double *hue,double *whiteness,double *blackness) | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 506 | % | 
|  | 507 | %  A description of each parameter follows: | 
|  | 508 | % | 
|  | 509 | %    o red, green, blue: A Quantum value representing the red, green, and | 
|  | 510 | %      blue component of a pixel. | 
|  | 511 | % | 
|  | 512 | %    o hue, whiteness, blackness: A pointer to a double value representing a | 
|  | 513 | %      component of the HWB color space. | 
|  | 514 | % | 
|  | 515 | */ | 
| cristy | cf12ee4 | 2012-06-14 11:02:23 +0000 | [diff] [blame] | 516 | MagickPrivate void ConvertsRGBToHWB(const double red,const double green, | 
| cristy | 3094b7f | 2011-10-01 23:18:02 +0000 | [diff] [blame] | 517 | const double blue,double *hue,double *whiteness,double *blackness) | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 518 | { | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 519 | double | 
|  | 520 | b, | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 521 | f, | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 522 | g, | 
|  | 523 | p, | 
|  | 524 | r, | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 525 | v, | 
|  | 526 | w; | 
|  | 527 |  | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 528 | /* | 
|  | 529 | Convert RGB to HWB colorspace. | 
|  | 530 | */ | 
|  | 531 | assert(hue != (double *) NULL); | 
|  | 532 | assert(whiteness != (double *) NULL); | 
|  | 533 | assert(blackness != (double *) NULL); | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 534 | r=QuantumRange*sRGBDecompanding(QuantumScale*red); | 
|  | 535 | g=QuantumRange*sRGBDecompanding(QuantumScale*green); | 
|  | 536 | b=QuantumRange*sRGBDecompanding(QuantumScale*blue); | 
|  | 537 | w=MagickMin(r,MagickMin(g,b)); | 
|  | 538 | v=MagickMax(r,MagickMax(g,b)); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 539 | *blackness=1.0-QuantumScale*v; | 
|  | 540 | *whiteness=QuantumScale*w; | 
|  | 541 | if (v == w) | 
|  | 542 | { | 
| cristy | af10b11 | 2012-04-18 13:25:37 +0000 | [diff] [blame] | 543 | *hue=(-1.0); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 544 | return; | 
|  | 545 | } | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 546 | f=(r == w) ? g-b : ((g == w) ? b-r : r-g); | 
|  | 547 | p=(r == w) ? 3.0 : ((g == w) ? 5.0 : 1.0); | 
|  | 548 | *hue=(p-f/(v-1.0*w))/6.0; | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 549 | } | 
|  | 550 |  | 
|  | 551 | /* | 
|  | 552 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
|  | 553 | %                                                                             % | 
|  | 554 | %                                                                             % | 
|  | 555 | %                                                                             % | 
|  | 556 | %   E x p a n d A f f i n e                                                   % | 
|  | 557 | %                                                                             % | 
|  | 558 | %                                                                             % | 
|  | 559 | %                                                                             % | 
|  | 560 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
|  | 561 | % | 
|  | 562 | %  ExpandAffine() computes the affine's expansion factor, i.e. the square root | 
|  | 563 | %  of the factor by which the affine transform affects area. In an affine | 
|  | 564 | %  transform composed of scaling, rotation, shearing, and translation, returns | 
|  | 565 | %  the amount of scaling. | 
|  | 566 | % | 
|  | 567 | %  The format of the ExpandAffine method is: | 
|  | 568 | % | 
|  | 569 | %      double ExpandAffine(const AffineMatrix *affine) | 
|  | 570 | % | 
|  | 571 | %  A description of each parameter follows: | 
|  | 572 | % | 
|  | 573 | %    o expansion: Method ExpandAffine returns the affine's expansion factor. | 
|  | 574 | % | 
|  | 575 | %    o affine: A pointer the affine transform of type AffineMatrix. | 
|  | 576 | % | 
|  | 577 | */ | 
|  | 578 | MagickExport double ExpandAffine(const AffineMatrix *affine) | 
|  | 579 | { | 
|  | 580 | assert(affine != (const AffineMatrix *) NULL); | 
|  | 581 | return(sqrt(fabs(affine->sx*affine->sy-affine->rx*affine->ry))); | 
|  | 582 | } | 
|  | 583 |  | 
|  | 584 | /* | 
|  | 585 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
|  | 586 | %                                                                             % | 
|  | 587 | %                                                                             % | 
|  | 588 | %                                                                             % | 
|  | 589 | %   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                         % | 
|  | 590 | %                                                                             % | 
|  | 591 | %                                                                             % | 
|  | 592 | %                                                                             % | 
|  | 593 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
|  | 594 | % | 
| cristy | 82b1583 | 2009-10-06 19:17:37 +0000 | [diff] [blame] | 595 | %  GenerateDifferentialNoise() generates differentual noise. | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 596 | % | 
|  | 597 | %  The format of the GenerateDifferentialNoise method is: | 
|  | 598 | % | 
|  | 599 | %      double GenerateDifferentialNoise(RandomInfo *random_info, | 
| cristy | 9ed1f81 | 2011-10-08 02:00:08 +0000 | [diff] [blame] | 600 | %        const Quantum pixel,const NoiseType noise_type,const double attenuate) | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 601 | % | 
|  | 602 | %  A description of each parameter follows: | 
|  | 603 | % | 
|  | 604 | %    o random_info: the random info. | 
|  | 605 | % | 
|  | 606 | %    o pixel: noise is relative to this pixel value. | 
|  | 607 | % | 
|  | 608 | %    o noise_type: the type of noise. | 
|  | 609 | % | 
|  | 610 | %    o attenuate:  attenuate the noise. | 
|  | 611 | % | 
|  | 612 | */ | 
| cristy | 8ea8122 | 2011-09-04 10:33:32 +0000 | [diff] [blame] | 613 | MagickPrivate double GenerateDifferentialNoise(RandomInfo *random_info, | 
| cristy | 9ed1f81 | 2011-10-08 02:00:08 +0000 | [diff] [blame] | 614 | const Quantum pixel,const NoiseType noise_type,const double attenuate) | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 615 | { | 
| cristy | 7118edf | 2011-10-08 13:33:25 +0000 | [diff] [blame] | 616 | #define SigmaUniform  (attenuate*0.015625) | 
|  | 617 | #define SigmaGaussian  (attenuate*0.015625) | 
|  | 618 | #define SigmaImpulse  (attenuate*0.1) | 
|  | 619 | #define SigmaLaplacian (attenuate*0.0390625) | 
|  | 620 | #define SigmaMultiplicativeGaussian  (attenuate*0.5) | 
| cristy | 4ce9df6 | 2011-10-12 12:06:02 +0000 | [diff] [blame] | 621 | #define SigmaPoisson  (attenuate*12.5) | 
| cristy | 7118edf | 2011-10-08 13:33:25 +0000 | [diff] [blame] | 622 | #define TauGaussian  (attenuate*0.078125) | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 623 |  | 
| cristy | adb41ca | 2009-10-22 15:02:28 +0000 | [diff] [blame] | 624 | double | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 625 | alpha, | 
|  | 626 | beta, | 
|  | 627 | noise, | 
|  | 628 | sigma; | 
|  | 629 |  | 
|  | 630 | alpha=GetPseudoRandomValue(random_info); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 631 | switch (noise_type) | 
|  | 632 | { | 
|  | 633 | case UniformNoise: | 
|  | 634 | default: | 
|  | 635 | { | 
| cristy | 6bbabe6 | 2011-10-09 13:54:18 +0000 | [diff] [blame] | 636 | noise=(double) (pixel+QuantumRange*SigmaUniform*(alpha-0.5)); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 637 | break; | 
|  | 638 | } | 
|  | 639 | case GaussianNoise: | 
|  | 640 | { | 
| cristy | adb41ca | 2009-10-22 15:02:28 +0000 | [diff] [blame] | 641 | double | 
| cristy | 62faa60 | 2010-02-20 03:36:17 +0000 | [diff] [blame] | 642 | gamma, | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 643 | tau; | 
|  | 644 |  | 
| cristy | adb41ca | 2009-10-22 15:02:28 +0000 | [diff] [blame] | 645 | if (alpha == 0.0) | 
|  | 646 | alpha=1.0; | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 647 | beta=GetPseudoRandomValue(random_info); | 
| cristy | 62faa60 | 2010-02-20 03:36:17 +0000 | [diff] [blame] | 648 | gamma=sqrt(-2.0*log(alpha)); | 
| cristy | 55a91cd | 2010-12-01 00:57:40 +0000 | [diff] [blame] | 649 | sigma=gamma*cos((double) (2.0*MagickPI*beta)); | 
|  | 650 | tau=gamma*sin((double) (2.0*MagickPI*beta)); | 
| cristy | 6bbabe6 | 2011-10-09 13:54:18 +0000 | [diff] [blame] | 651 | noise=(double) (pixel+sqrt((double) pixel)*SigmaGaussian*sigma+ | 
|  | 652 | QuantumRange*TauGaussian*tau); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 653 | break; | 
|  | 654 | } | 
|  | 655 | case ImpulseNoise: | 
|  | 656 | { | 
|  | 657 | if (alpha < (SigmaImpulse/2.0)) | 
|  | 658 | noise=0.0; | 
| cristy | 37c2407 | 2011-10-08 01:26:00 +0000 | [diff] [blame] | 659 | else | 
|  | 660 | if (alpha >= (1.0-(SigmaImpulse/2.0))) | 
|  | 661 | noise=(double) QuantumRange; | 
|  | 662 | else | 
|  | 663 | noise=(double) pixel; | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 664 | break; | 
|  | 665 | } | 
|  | 666 | case LaplacianNoise: | 
|  | 667 | { | 
|  | 668 | if (alpha <= 0.5) | 
|  | 669 | { | 
| cristy | 7118edf | 2011-10-08 13:33:25 +0000 | [diff] [blame] | 670 | if (alpha <= MagickEpsilon) | 
| cristy | 6bbabe6 | 2011-10-09 13:54:18 +0000 | [diff] [blame] | 671 | noise=(double) (pixel-QuantumRange); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 672 | else | 
| cristy | 6bbabe6 | 2011-10-09 13:54:18 +0000 | [diff] [blame] | 673 | noise=(double) (pixel+QuantumRange*SigmaLaplacian* | 
|  | 674 | log(2.0*alpha)+0.5); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 675 | break; | 
|  | 676 | } | 
|  | 677 | beta=1.0-alpha; | 
| cristy | 7118edf | 2011-10-08 13:33:25 +0000 | [diff] [blame] | 678 | if (beta <= (0.5*MagickEpsilon)) | 
| cristy | adb41ca | 2009-10-22 15:02:28 +0000 | [diff] [blame] | 679 | noise=(double) (pixel+QuantumRange); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 680 | else | 
| cristy | 6bbabe6 | 2011-10-09 13:54:18 +0000 | [diff] [blame] | 681 | noise=(double) (pixel-QuantumRange*SigmaLaplacian*log(2.0*beta)+0.5); | 
| cristy | 7118edf | 2011-10-08 13:33:25 +0000 | [diff] [blame] | 682 | break; | 
|  | 683 | } | 
|  | 684 | case MultiplicativeGaussianNoise: | 
|  | 685 | { | 
|  | 686 | sigma=1.0; | 
|  | 687 | if (alpha > MagickEpsilon) | 
|  | 688 | sigma=sqrt(-2.0*log(alpha)); | 
|  | 689 | beta=GetPseudoRandomValue(random_info); | 
| cristy | 6bbabe6 | 2011-10-09 13:54:18 +0000 | [diff] [blame] | 690 | noise=(double) (pixel+pixel*SigmaMultiplicativeGaussian*sigma* | 
|  | 691 | cos((double) (2.0*MagickPI*beta))/2.0); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 692 | break; | 
|  | 693 | } | 
|  | 694 | case PoissonNoise: | 
|  | 695 | { | 
| cristy | adb41ca | 2009-10-22 15:02:28 +0000 | [diff] [blame] | 696 | double | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 697 | poisson; | 
|  | 698 |  | 
| cristy | bb50337 | 2010-05-27 20:51:26 +0000 | [diff] [blame] | 699 | register ssize_t | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 700 | i; | 
|  | 701 |  | 
| cristy | 7118edf | 2011-10-08 13:33:25 +0000 | [diff] [blame] | 702 | poisson=exp(-SigmaPoisson*QuantumScale*pixel); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 703 | for (i=0; alpha > poisson; i++) | 
|  | 704 | { | 
|  | 705 | beta=GetPseudoRandomValue(random_info); | 
|  | 706 | alpha*=beta; | 
|  | 707 | } | 
| cristy | 6bbabe6 | 2011-10-09 13:54:18 +0000 | [diff] [blame] | 708 | noise=(double) (QuantumRange*i/SigmaPoisson); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 709 | break; | 
|  | 710 | } | 
|  | 711 | case RandomNoise: | 
|  | 712 | { | 
| cristy | 6bbabe6 | 2011-10-09 13:54:18 +0000 | [diff] [blame] | 713 | noise=(double) (QuantumRange*alpha); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 714 | break; | 
|  | 715 | } | 
|  | 716 | } | 
|  | 717 | return(noise); | 
|  | 718 | } | 
|  | 719 |  | 
|  | 720 | /* | 
|  | 721 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
|  | 722 | %                                                                             % | 
|  | 723 | %                                                                             % | 
|  | 724 | %                                                                             % | 
|  | 725 | %   G e t O p t i m a l K e r n e l W i d t h                                 % | 
|  | 726 | %                                                                             % | 
|  | 727 | %                                                                             % | 
|  | 728 | %                                                                             % | 
|  | 729 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
|  | 730 | % | 
|  | 731 | %  GetOptimalKernelWidth() computes the optimal kernel radius for a convolution | 
|  | 732 | %  filter.  Start with the minimum value of 3 pixels and walk out until we drop | 
|  | 733 | %  below the threshold of one pixel numerical accuracy. | 
|  | 734 | % | 
|  | 735 | %  The format of the GetOptimalKernelWidth method is: | 
|  | 736 | % | 
| cristy | bb50337 | 2010-05-27 20:51:26 +0000 | [diff] [blame] | 737 | %      size_t GetOptimalKernelWidth(const double radius, | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 738 | %        const double sigma) | 
|  | 739 | % | 
|  | 740 | %  A description of each parameter follows: | 
|  | 741 | % | 
|  | 742 | %    o width: Method GetOptimalKernelWidth returns the optimal width of | 
|  | 743 | %      a convolution kernel. | 
|  | 744 | % | 
|  | 745 | %    o radius: the radius of the Gaussian, in pixels, not counting the center | 
|  | 746 | %      pixel. | 
|  | 747 | % | 
|  | 748 | %    o sigma: the standard deviation of the Gaussian, in pixels. | 
|  | 749 | % | 
|  | 750 | */ | 
| cristy | 8ea8122 | 2011-09-04 10:33:32 +0000 | [diff] [blame] | 751 | MagickPrivate size_t GetOptimalKernelWidth1D(const double radius, | 
| cristy | e96405a | 2010-05-19 02:24:31 +0000 | [diff] [blame] | 752 | const double sigma) | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 753 | { | 
| cristy | e96405a | 2010-05-19 02:24:31 +0000 | [diff] [blame] | 754 | double | 
|  | 755 | alpha, | 
|  | 756 | beta, | 
|  | 757 | gamma, | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 758 | normalize, | 
| cristy | e96405a | 2010-05-19 02:24:31 +0000 | [diff] [blame] | 759 | value; | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 760 |  | 
| cristy | bb50337 | 2010-05-27 20:51:26 +0000 | [diff] [blame] | 761 | register ssize_t | 
| cristy | 47e0050 | 2009-12-17 19:19:57 +0000 | [diff] [blame] | 762 | i; | 
|  | 763 |  | 
| cristy | bb50337 | 2010-05-27 20:51:26 +0000 | [diff] [blame] | 764 | size_t | 
| cristy | 47e0050 | 2009-12-17 19:19:57 +0000 | [diff] [blame] | 765 | width; | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 766 |  | 
| cristy | 9d314ff | 2011-03-09 01:30:28 +0000 | [diff] [blame] | 767 | ssize_t | 
|  | 768 | j; | 
|  | 769 |  | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 770 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); | 
| cristy | 47e0050 | 2009-12-17 19:19:57 +0000 | [diff] [blame] | 771 | if (radius > MagickEpsilon) | 
| cristy | bb50337 | 2010-05-27 20:51:26 +0000 | [diff] [blame] | 772 | return((size_t) (2.0*ceil(radius)+1.0)); | 
| cristy | e96405a | 2010-05-19 02:24:31 +0000 | [diff] [blame] | 773 | gamma=fabs(sigma); | 
|  | 774 | if (gamma <= MagickEpsilon) | 
| anthony | c106172 | 2010-05-14 06:23:49 +0000 | [diff] [blame] | 775 | return(3UL); | 
| cristy | 35f1530 | 2012-06-07 14:59:02 +0000 | [diff] [blame] | 776 | alpha=MagickEpsilonReciprocal(2.0*gamma*gamma); | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 777 | beta=(double) MagickEpsilonReciprocal((MagickRealType) MagickSQ2PI*gamma); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 778 | for (width=5; ; ) | 
|  | 779 | { | 
|  | 780 | normalize=0.0; | 
| cristy | bb50337 | 2010-05-27 20:51:26 +0000 | [diff] [blame] | 781 | j=(ssize_t) width/2; | 
| cristy | 47e0050 | 2009-12-17 19:19:57 +0000 | [diff] [blame] | 782 | for (i=(-j); i <= j; i++) | 
| cristy | e96405a | 2010-05-19 02:24:31 +0000 | [diff] [blame] | 783 | normalize+=exp(-((double) (i*i))*alpha)*beta; | 
|  | 784 | value=exp(-((double) (j*j))*alpha)*beta/normalize; | 
| cristy | 20908da | 2009-12-02 14:34:11 +0000 | [diff] [blame] | 785 | if ((value < QuantumScale) || (value < MagickEpsilon)) | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 786 | break; | 
|  | 787 | width+=2; | 
|  | 788 | } | 
| cristy | bb50337 | 2010-05-27 20:51:26 +0000 | [diff] [blame] | 789 | return((size_t) (width-2)); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 790 | } | 
|  | 791 |  | 
| cristy | 8ea8122 | 2011-09-04 10:33:32 +0000 | [diff] [blame] | 792 | MagickPrivate size_t GetOptimalKernelWidth2D(const double radius, | 
| cristy | e96405a | 2010-05-19 02:24:31 +0000 | [diff] [blame] | 793 | const double sigma) | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 794 | { | 
| cristy | 47e0050 | 2009-12-17 19:19:57 +0000 | [diff] [blame] | 795 | double | 
| cristy | e96405a | 2010-05-19 02:24:31 +0000 | [diff] [blame] | 796 | alpha, | 
|  | 797 | beta, | 
|  | 798 | gamma, | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 799 | normalize, | 
| cristy | e96405a | 2010-05-19 02:24:31 +0000 | [diff] [blame] | 800 | value; | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 801 |  | 
| cristy | 9d314ff | 2011-03-09 01:30:28 +0000 | [diff] [blame] | 802 | size_t | 
|  | 803 | width; | 
|  | 804 |  | 
| cristy | bb50337 | 2010-05-27 20:51:26 +0000 | [diff] [blame] | 805 | ssize_t | 
| cristy | 47e0050 | 2009-12-17 19:19:57 +0000 | [diff] [blame] | 806 | j, | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 807 | u, | 
|  | 808 | v; | 
|  | 809 |  | 
|  | 810 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); | 
| cristy | 47e0050 | 2009-12-17 19:19:57 +0000 | [diff] [blame] | 811 | if (radius > MagickEpsilon) | 
| cristy | bb50337 | 2010-05-27 20:51:26 +0000 | [diff] [blame] | 812 | return((size_t) (2.0*ceil(radius)+1.0)); | 
| cristy | e96405a | 2010-05-19 02:24:31 +0000 | [diff] [blame] | 813 | gamma=fabs(sigma); | 
|  | 814 | if (gamma <= MagickEpsilon) | 
| anthony | c106172 | 2010-05-14 06:23:49 +0000 | [diff] [blame] | 815 | return(3UL); | 
| cristy | 35f1530 | 2012-06-07 14:59:02 +0000 | [diff] [blame] | 816 | alpha=MagickEpsilonReciprocal(2.0*gamma*gamma); | 
| cristy | caf4580 | 2012-06-16 18:28:54 +0000 | [diff] [blame^] | 817 | beta=(double) MagickEpsilonReciprocal((MagickRealType) Magick2PI*gamma*gamma); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 818 | for (width=5; ; ) | 
|  | 819 | { | 
|  | 820 | normalize=0.0; | 
| cristy | bb50337 | 2010-05-27 20:51:26 +0000 | [diff] [blame] | 821 | j=(ssize_t) width/2; | 
| cristy | 47e0050 | 2009-12-17 19:19:57 +0000 | [diff] [blame] | 822 | for (v=(-j); v <= j; v++) | 
| cristy | 47e0050 | 2009-12-17 19:19:57 +0000 | [diff] [blame] | 823 | for (u=(-j); u <= j; u++) | 
| cristy | e96405a | 2010-05-19 02:24:31 +0000 | [diff] [blame] | 824 | normalize+=exp(-((double) (u*u+v*v))*alpha)*beta; | 
|  | 825 | value=exp(-((double) (j*j))*alpha)*beta/normalize; | 
| cristy | 20908da | 2009-12-02 14:34:11 +0000 | [diff] [blame] | 826 | if ((value < QuantumScale) || (value < MagickEpsilon)) | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 827 | break; | 
|  | 828 | width+=2; | 
|  | 829 | } | 
| cristy | bb50337 | 2010-05-27 20:51:26 +0000 | [diff] [blame] | 830 | return((size_t) (width-2)); | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 831 | } | 
|  | 832 |  | 
| cristy | 8ea8122 | 2011-09-04 10:33:32 +0000 | [diff] [blame] | 833 | MagickPrivate size_t  GetOptimalKernelWidth(const double radius, | 
| cristy | 3ed852e | 2009-09-05 21:47:34 +0000 | [diff] [blame] | 834 | const double sigma) | 
|  | 835 | { | 
|  | 836 | return(GetOptimalKernelWidth1D(radius,sigma)); | 
|  | 837 | } |