1 /*
2 Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization
3 dedicated to making software imaging solutions freely available.
4
5 You may not use this file except in compliance with the License. You may
6 obtain a copy of the License at
7
8 https://imagemagick.org/script/license.php
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15
16 MagickCore private graphic gems methods.
17 */
18 #ifndef MAGICKCORE_GEM_PRIVATE_H
19 #define MAGICKCORE_GEM_PRIVATE_H
20
21 #include "MagickCore/pixel-accessor.h"
22 #include "MagickCore/visual-effects.h"
23
24 #if defined(__cplusplus) || defined(c_plusplus)
25 extern "C" {
26 #endif
27
28 #define IlluminantX 0.95047
29 #define IlluminantY 1.0
30 #define IlluminantZ 1.08883
31 #define CIEEpsilon (216.0/24389.0)
32 #define CIEK (24389.0/27.0)
33
34 static const PrimaryInfo
35 illuminant_tristimulus[] =
36 {
37 { 1.09850, 1.00000, 0.35585 }, /* A */
38 { 0.99072, 1.00000, 0.85223 }, /* B */
39 { 0.98074, 1.00000, 1.18232 }, /* C */
40 { 0.96422, 1.00000, 0.82521 }, /* D50 */
41 { 0.95682, 1.00000, 0.92149 }, /* D55 */
42 { 0.95047, 1.00000, 1.08883 }, /* D65 */
43 { 0.94972, 1.00000, 1.22638 }, /* D75 */
44 { 1.00000, 1.00000, 1.00000 }, /* E */
45 { 0.99186, 1.00000, 0.67393 }, /* F2 */
46 { 0.95041, 1.00000, 1.08747 }, /* F7 */
47 { 1.00962, 1.00000, 0.64350 } /* F11 */
48 };
49
50 extern MagickPrivate double
51 GenerateDifferentialNoise(RandomInfo *,const Quantum,const NoiseType,
52 const double);
53
54 extern MagickPrivate size_t
55 GetOptimalKernelWidth(const double,const double),
56 GetOptimalKernelWidth1D(const double,const double),
57 GetOptimalKernelWidth2D(const double,const double);
58
59 extern MagickPrivate void
60 ConvertHCLToRGB(const double,const double,const double,double *,double *,
61 double *),
62 ConvertHCLpToRGB(const double,const double,const double,double *,double *,
63 double *),
64 ConvertHSBToRGB(const double,const double,const double,double *,double *,
65 double *),
66 ConvertHSIToRGB(const double,const double,const double,double *,double *,
67 double *),
68 ConvertHSVToRGB(const double,const double,const double,double *,double *,
69 double *),
70 ConvertHWBToRGB(const double,const double,const double,double *,double *,
71 double *),
72 ConvertLCHabToRGB(const double,const double,const double,const IlluminantType,
73 double *,double *,double *),
74 ConvertLCHuvToRGB(const double,const double,const double,const IlluminantType,
75 double *,double *,double *),
76 ConvertRGBToHCL(const double,const double,const double,double *,double *,
77 double *),
78 ConvertRGBToHCLp(const double,const double,const double,double *,double *,
79 double *),
80 ConvertRGBToHSB(const double,const double,const double,double *,double *,
81 double *),
82 ConvertRGBToHSI(const double,const double,const double,double *,double *,
83 double *),
84 ConvertRGBToHSV(const double,const double,const double,double *,double *,
85 double *),
86 ConvertRGBToHWB(const double,const double,const double,double *,double *,
87 double *),
88 ConvertRGBToLab(const double,const double,const double,const IlluminantType,
89 double *,double *,double *),
90 ConvertRGBToLCHab(const double,const double,const double,const IlluminantType,
91 double *,double *,double *),
92 ConvertRGBToLCHuv(const double,const double,const double,const IlluminantType,
93 double *,double *,double *);
94
ConvertAdobe98ToXYZ(const double red,const double green,const double blue,double * X,double * Y,double * Z)95 static inline void ConvertAdobe98ToXYZ(const double red,const double green,
96 const double blue,double *X,double *Y,double *Z)
97 {
98 double
99 b,
100 g,
101 r;
102
103 /*
104 Convert Adobe '98 to XYZ colorspace.
105 */
106 assert(X != (double *) NULL);
107 assert(Y != (double *) NULL);
108 assert(Z != (double *) NULL);
109 r=QuantumScale*DecodePixelGamma(red);
110 g=QuantumScale*DecodePixelGamma(green);
111 b=QuantumScale*DecodePixelGamma(blue);
112 *X=0.57666904291013050*r+0.18555823790654630*g+0.18822864623499470*b;
113 *Y=0.29734497525053605*r+0.62736356625546610*g+0.07529145849399788*b;
114 *Z=0.02703136138641234*r+0.07068885253582723*g+0.99133753683763880*b;
115 }
116
ConvertDisplayP3ToXYZ(const double red,const double green,const double blue,double * X,double * Y,double * Z)117 static inline void ConvertDisplayP3ToXYZ(const double red,const double green,
118 const double blue,double *X,double *Y,double *Z)
119 {
120 double
121 b,
122 g,
123 r;
124
125 /*
126 Convert Display P3 to XYZ colorspace.
127 */
128 assert(X != (double *) NULL);
129 assert(Y != (double *) NULL);
130 assert(Z != (double *) NULL);
131 r=QuantumScale*DecodePixelGamma(red);
132 g=QuantumScale*DecodePixelGamma(green);
133 b=QuantumScale*DecodePixelGamma(blue);
134 *X=0.4865709486482162*r+0.26566769316909306*g+0.1982172852343625*b;
135 *Y=0.2289745640697488*r+0.69173852183650640*g+0.0792869140937450*b;
136 *Z=0.0000000000000000*r+0.04511338185890264*g+1.0439443689009760*b;
137 }
138
ConvertLabToXYZ(const double L,const double a,const double b,const IlluminantType illuminant,double * X,double * Y,double * Z)139 static inline void ConvertLabToXYZ(const double L,const double a,const double b,
140 const IlluminantType illuminant,double *X,double *Y,double *Z)
141 {
142 double
143 x,
144 y,
145 z;
146
147 assert(X != (double *) NULL);
148 assert(Y != (double *) NULL);
149 assert(Z != (double *) NULL);
150 y=(L+16.0)/116.0;
151 x=y+a/500.0;
152 z=y-b/200.0;
153 if ((x*x*x) > CIEEpsilon)
154 x=(x*x*x);
155 else
156 x=(116.0*x-16.0)/CIEK;
157 if (L > (CIEK*CIEEpsilon))
158 y=(y*y*y);
159 else
160 y=L/CIEK;
161 if ((z*z*z) > CIEEpsilon)
162 z=(z*z*z);
163 else
164 z=(116.0*z-16.0)/CIEK;
165 *X=illuminant_tristimulus[illuminant].x*x;
166 *Y=illuminant_tristimulus[illuminant].y*y;
167 *Z=illuminant_tristimulus[illuminant].z*z;
168 }
169
ConvertLuvToXYZ(const double L,const double u,const double v,const IlluminantType illuminant,double * X,double * Y,double * Z)170 static inline void ConvertLuvToXYZ(const double L,const double u,const double v,
171 const IlluminantType illuminant,double *X,double *Y,double *Z)
172 {
173 double
174 gamma;
175
176 assert(X != (double *) NULL);
177 assert(Y != (double *) NULL);
178 assert(Z != (double *) NULL);
179 if (L > (CIEK*CIEEpsilon))
180 *Y=(double) pow((L+16.0)/116.0,3.0);
181 else
182 *Y=L/CIEK;
183 gamma=PerceptibleReciprocal((((52.0*L*PerceptibleReciprocal(u+13.0*L*
184 (4.0*illuminant_tristimulus[illuminant].x/
185 (illuminant_tristimulus[illuminant].x+15.0*
186 illuminant_tristimulus[illuminant].y+3.0*
187 illuminant_tristimulus[illuminant].z))))-1.0)/3.0)-(-1.0/3.0));
188 *X=gamma*((*Y*((39.0*L*PerceptibleReciprocal(v+13.0*L*(9.0*
189 illuminant_tristimulus[illuminant].y/
190 (illuminant_tristimulus[illuminant].x+15.0*
191 illuminant_tristimulus[illuminant].y+3.0*
192 illuminant_tristimulus[illuminant].z))))-5.0))+5.0*(*Y));
193 *Z=(*X*(((52.0*L*PerceptibleReciprocal(u+13.0*L*(4.0*
194 illuminant_tristimulus[illuminant].x/
195 (illuminant_tristimulus[illuminant].x+15.0*
196 illuminant_tristimulus[illuminant].y+3.0*
197 illuminant_tristimulus[illuminant].z))))-1.0)/3.0))-5.0*(*Y);
198 }
199
ConvertProPhotoToXYZ(const double red,const double green,const double blue,double * X,double * Y,double * Z)200 static inline void ConvertProPhotoToXYZ(const double red,const double green,
201 const double blue,double *X,double *Y,double *Z)
202 {
203 double
204 b,
205 g,
206 r;
207
208 /*
209 Convert ProPhoto to XYZ colorspace.
210 */
211 assert(X != (double *) NULL);
212 assert(Y != (double *) NULL);
213 assert(Z != (double *) NULL);
214 r=QuantumScale*DecodePixelGamma(red);
215 g=QuantumScale*DecodePixelGamma(green);
216 b=QuantumScale*DecodePixelGamma(blue);
217 *X=0.7977604896723027*r+0.13518583717574031*g+0.03134934958152480000*b;
218 *Y=0.2880711282292934*r+0.71184321781010140*g+0.00008565396060525902*b;
219 *Z=0.0000000000000000*r+0.00000000000000000*g+0.82510460251046010000*b;
220 }
221
ConvertRGBToXYZ(const double red,const double green,const double blue,double * X,double * Y,double * Z)222 static inline void ConvertRGBToXYZ(const double red,const double green,
223 const double blue,double *X,double *Y,double *Z)
224 {
225 double
226 b,
227 g,
228 r;
229
230 /*
231 Convert RGB to XYZ colorspace.
232 */
233 assert(X != (double *) NULL);
234 assert(Y != (double *) NULL);
235 assert(Z != (double *) NULL);
236 r=QuantumScale*DecodePixelGamma(red);
237 g=QuantumScale*DecodePixelGamma(green);
238 b=QuantumScale*DecodePixelGamma(blue);
239 *X=0.4124564*r+0.3575761*g+0.1804375*b;
240 *Y=0.2126729*r+0.7151522*g+0.0721750*b;
241 *Z=0.0193339*r+0.1191920*g+0.9503041*b;
242 }
243
ConvertXYZToAdobe98(const double X,const double Y,const double Z,double * red,double * green,double * blue)244 static inline void ConvertXYZToAdobe98(const double X,const double Y,
245 const double Z,double *red,double *green,double *blue)
246 {
247 double
248 b,
249 g,
250 r;
251
252 assert(red != (double *) NULL);
253 assert(green != (double *) NULL);
254 assert(blue != (double *) NULL);
255 r=2.041587903810746500*X-0.56500697427885960*Y-0.34473135077832956*Z;
256 g=(-0.969243636280879500)*X+1.87596750150772020*Y+0.04155505740717557*Z;
257 b=0.013444280632031142*X-0.11836239223101838*Y+1.01517499439120540*Z;
258 *red=EncodePixelGamma(QuantumRange*r);
259 *green=EncodePixelGamma(QuantumRange*g);
260 *blue=EncodePixelGamma(QuantumRange*b);
261 }
262
ConvertXYZToDisplayP3(const double X,const double Y,const double Z,double * red,double * green,double * blue)263 static inline void ConvertXYZToDisplayP3(const double X,const double Y,
264 const double Z,double *red,double *green,double *blue)
265 {
266 double
267 b,
268 g,
269 r;
270
271 assert(red != (double *) NULL);
272 assert(green != (double *) NULL);
273 assert(blue != (double *) NULL);
274 r=2.49349691194142500*X-0.93138361791912390*Y-0.402710784450716840*Z;
275 g=(-0.82948896956157470)*X+1.76266406031834630*Y+0.023624685841943577*Z;
276 b=0.03584583024378447*X-0.07617238926804182*Y+0.956884524007687200*Z;
277 *red=EncodePixelGamma(QuantumRange*r);
278 *green=EncodePixelGamma(QuantumRange*g);
279 *blue=EncodePixelGamma(QuantumRange*b);
280 }
281
ConvertXYZToLab(const double X,const double Y,const double Z,const IlluminantType illuminant,double * L,double * a,double * b)282 static inline void ConvertXYZToLab(const double X,const double Y,const double Z,
283 const IlluminantType illuminant,double *L,double *a,double *b)
284 {
285 double
286 x,
287 y,
288 z;
289
290 assert(L != (double *) NULL);
291 assert(a != (double *) NULL);
292 assert(b != (double *) NULL);
293 if ((X/illuminant_tristimulus[illuminant].x) > CIEEpsilon)
294 x=pow(X/illuminant_tristimulus[illuminant].x,1.0/3.0);
295 else
296 x=(CIEK*X/illuminant_tristimulus[illuminant].x+16.0)/116.0;
297 if ((Y/illuminant_tristimulus[illuminant].y) > CIEEpsilon)
298 y=pow(Y/illuminant_tristimulus[illuminant].y,1.0/3.0);
299 else
300 y=(CIEK*Y/illuminant_tristimulus[illuminant].y+16.0)/116.0;
301 if ((Z/illuminant_tristimulus[illuminant].z) > CIEEpsilon)
302 z=pow(Z/illuminant_tristimulus[illuminant].z,1.0/3.0);
303 else
304 z=(CIEK*Z/illuminant_tristimulus[illuminant].z+16.0)/116.0;
305 *L=((116.0*y)-16.0)/100.0;
306 *a=(500.0*(x-y))/255.0+0.5;
307 *b=(200.0*(y-z))/255.0+0.5;
308 }
309
ConvertXYZToLuv(const double X,const double Y,const double Z,const IlluminantType illuminant,double * L,double * u,double * v)310 static inline void ConvertXYZToLuv(const double X,const double Y,const double Z,
311 const IlluminantType illuminant,double *L,double *u,double *v)
312 {
313 double
314 alpha;
315
316 assert(L != (double *) NULL);
317 assert(u != (double *) NULL);
318 assert(v != (double *) NULL);
319 if ((Y/illuminant_tristimulus[illuminant].y) > CIEEpsilon)
320 *L=(double) (116.0*pow(Y/illuminant_tristimulus[illuminant].y,
321 1.0/3.0)-16.0);
322 else
323 *L=CIEK*(Y/illuminant_tristimulus[illuminant].y);
324 alpha=PerceptibleReciprocal(X+15.0*Y+3.0*Z);
325 *u=13.0*(*L)*((4.0*alpha*X)-(4.0*illuminant_tristimulus[illuminant].x/
326 (illuminant_tristimulus[illuminant].x+15.0*
327 illuminant_tristimulus[illuminant].y+3.0*
328 illuminant_tristimulus[illuminant].z)));
329 *v=13.0*(*L)*((9.0*alpha*Y)-(9.0*illuminant_tristimulus[illuminant].y/
330 (illuminant_tristimulus[illuminant].x+15.0*
331 illuminant_tristimulus[illuminant].y+3.0*
332 illuminant_tristimulus[illuminant].z)));
333 *L/=100.0;
334 *u=(*u+134.0)/354.0;
335 *v=(*v+140.0)/262.0;
336 }
337
ConvertXYZToProPhoto(const double X,const double Y,const double Z,double * red,double * green,double * blue)338 static inline void ConvertXYZToProPhoto(const double X,const double Y,
339 const double Z,double *red,double *green,double *blue)
340 {
341 double
342 b,
343 g,
344 r;
345
346 assert(red != (double *) NULL);
347 assert(green != (double *) NULL);
348 assert(blue != (double *) NULL);
349 r=1.3457989731028281*X-0.25558010007997534*Y-0.05110628506753401*Z;
350 g=(-0.5446224939028347)*X+1.50823274131327810*Y+0.02053603239147973*Z;
351 b=0.0000000000000000*X+0.0000000000000000*Y+1.21196754563894540*Z;
352 *red=EncodePixelGamma(QuantumRange*r);
353 *green=EncodePixelGamma(QuantumRange*g);
354 *blue=EncodePixelGamma(QuantumRange*b);
355 }
356
ConvertXYZToRGB(const double X,const double Y,const double Z,double * red,double * green,double * blue)357 static inline void ConvertXYZToRGB(const double X,const double Y,const double Z,
358 double *red,double *green,double *blue)
359 {
360 double
361 b,
362 g,
363 r;
364
365 assert(red != (double *) NULL);
366 assert(green != (double *) NULL);
367 assert(blue != (double *) NULL);
368 r=3.2404542*X-1.5371385*Y-0.4985314*Z;
369 g=(-0.9692660)*X+1.8760108*Y+0.0415560*Z;
370 b=0.0556434*X-0.2040259*Y+1.0572252*Z;
371 *red=EncodePixelGamma(QuantumRange*r);
372 *green=EncodePixelGamma(QuantumRange*g);
373 *blue=EncodePixelGamma(QuantumRange*b);
374 }
375
376 #if defined(__cplusplus) || defined(c_plusplus)
377 }
378 #endif
379
380 #endif
381