MagickCore 7.1.1
Convert, Edit, Or Compose Bitmap Images
Loading...
Searching...
No Matches
colorspace.c
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC OOO L OOO RRRR SSSSS PPPP AAA CCCC EEEEE %
7% C O O L O O R R SS P P A A C E %
8% C O O L O O RRRR SSS PPPP AAAAA C EEE %
9% C O O L O O R R SS P A A C E %
10% CCCC OOO LLLLL OOO R R SSSSS P A A CCCC EEEEE %
11% %
12% %
13% MagickCore Image Colorspace Methods %
14% %
15% Software Design %
16% Cristy %
17% July 1992 %
18% %
19% %
20% Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization %
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% https://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 Include declarations.
41*/
42#include "MagickCore/studio.h"
43#include "MagickCore/artifact.h"
44#include "MagickCore/attribute.h"
45#include "MagickCore/property.h"
46#include "MagickCore/cache.h"
47#include "MagickCore/cache-private.h"
48#include "MagickCore/cache-view.h"
49#include "MagickCore/color.h"
50#include "MagickCore/color-private.h"
51#include "MagickCore/colorspace.h"
52#include "MagickCore/colorspace-private.h"
53#include "MagickCore/exception.h"
54#include "MagickCore/exception-private.h"
55#include "MagickCore/enhance.h"
56#include "MagickCore/image.h"
57#include "MagickCore/image-private.h"
58#include "MagickCore/gem.h"
59#include "MagickCore/gem-private.h"
60#include "MagickCore/memory_.h"
61#include "MagickCore/monitor.h"
62#include "MagickCore/monitor-private.h"
63#include "MagickCore/option.h"
64#include "MagickCore/pixel-accessor.h"
65#include "MagickCore/quantize.h"
66#include "MagickCore/quantum.h"
67#include "MagickCore/quantum-private.h"
68#include "MagickCore/resource_.h"
69#include "MagickCore/string_.h"
70#include "MagickCore/string-private.h"
71#include "MagickCore/utility.h"
72
73/*
74 Typedef declarations.
75*/
76typedef struct _TransformPacket
77{
78 MagickRealType
79 x,
80 y,
81 z;
83
84/*
85 Forward declarations.
86*/
87static MagickBooleanType
88 TransformsRGBImage(Image *,ExceptionInfo *);
89
90/*
91%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
92% %
93% %
94% %
95% G e t I m a g e C o l o r s p a c e T y p e %
96% %
97% %
98% %
99%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
100%
101% GetImageColorspaceType() returns the potential type of image:
102% sRGBColorspaceType, RGBColorspaceType, GRAYColorspaceType, etc.
103%
104% To ensure the image type matches its potential, use SetImageColorspaceType():
105%
106% (void) SetImageColorspaceType(image,GetImageColorspaceType(image),
107% exception);
108%
109% The format of the GetImageColorspaceType method is:
110%
111% ColorspaceType GetImageColorspaceType(const Image *image,
112% ExceptionInfo *exception)
113%
114% A description of each parameter follows:
115%
116% o image: the image.
117%
118% o exception: return any errors or warnings in this structure.
119%
120*/
121MagickExport ColorspaceType GetImageColorspaceType(const Image *image,
122 ExceptionInfo *exception)
123{
124 ColorspaceType
125 colorspace;
126
127 ImageType
128 type;
129
130 assert(image != (Image *) NULL);
131 assert(image->signature == MagickCoreSignature);
132 if (IsEventLogging() != MagickFalse)
133 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
134 colorspace=image->colorspace;
135 type=IdentifyImageType(image,exception);
136 if (IsGrayImageType(type))
137 colorspace=GRAYColorspace;
138 return(colorspace);
139}
140
141/*
142%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143% %
144% %
145% %
146+ s R G B T r a n s f o r m I m a g e %
147% %
148% %
149% %
150%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
151%
152% sRGBTransformImage() converts the reference image from sRGB to an alternate
153% colorspace. The transformation matrices are not the standard ones: the
154% weights are rescaled to normalized the range of the transformed values to
155% be [0..QuantumRange].
156%
157% The format of the sRGBTransformImage method is:
158%
159% MagickBooleanType sRGBTransformImage(Image *image,
160% const ColorspaceType colorspace,ExceptionInfo *exception)
161%
162% A description of each parameter follows:
163%
164% o image: the image.
165%
166% o colorspace: the colorspace to transform the image to.
167%
168% o exception: return any errors or warnings in this structure.
169%
170*/
171
172static inline void ConvertAdobe98ToRGB(const double r,const double g,
173 const double b,double *red,double *green,double *blue)
174{
175 double
176 X,
177 Y,
178 Z;
179
180 ConvertAdobe98ToXYZ(r,g,b,&X,&Y,&Z);
181 ConvertXYZToRGB(X,Y,Z,red,green,blue);
182}
183
184static inline void ConvertDisplayP3ToRGB(const double r,const double g,
185 const double b,double *red,double *green,double *blue)
186{
187 double
188 X,
189 Y,
190 Z;
191
192 ConvertDisplayP3ToXYZ(r,g,b,&X,&Y,&Z);
193 ConvertXYZToRGB(X,Y,Z,red,green,blue);
194}
195
196static inline void ConvertProPhotoToRGB(const double r,const double g,
197 const double b,double *red,double *green,double *blue)
198{
199 double
200 X,
201 Y,
202 Z;
203
204 ConvertProPhotoToXYZ(r,g,b,&X,&Y,&Z);
205 ConvertXYZToRGB(X,Y,Z,red,green,blue);
206}
207
208static inline void ConvertRGBToCMY(const double red,const double green,
209 const double blue,double *cyan,double *magenta,double *yellow)
210{
211 *cyan=QuantumScale*((double) QuantumRange-red);
212 *magenta=QuantumScale*((double) QuantumRange-green);
213 *yellow=QuantumScale*((double) QuantumRange-blue);
214}
215
216static void ConvertRGBToAdobe98(const double red,const double green,
217 const double blue,double *r,double *g,double *b)
218{
219 double
220 X,
221 Y,
222 Z;
223
224 ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
225 ConvertXYZToAdobe98(X,Y,Z,r,g,b);
226}
227
228static void ConvertRGBToDisplayP3(const double red,const double green,
229 const double blue,double *r,double *g,double *b)
230{
231 double
232 X,
233 Y,
234 Z;
235
236 ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
237 ConvertXYZToDisplayP3(X,Y,Z,r,g,b);
238}
239
240static void ConvertRGBToProPhoto(const double red,const double green,
241 const double blue,double *r,double *g,double *b)
242{
243 double
244 X,
245 Y,
246 Z;
247
248 ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
249 ConvertXYZToProPhoto(X,Y,Z,r,g,b);
250}
251
252static inline void ConvertXYZToLMS(const double x,const double y,
253 const double z,double *L,double *M,double *S)
254{
255 *L=0.7328*x+0.4296*y-0.1624*z;
256 *M=(-0.7036*x+1.6975*y+0.0061*z);
257 *S=0.0030*x+0.0136*y+0.9834*z;
258}
259
260static void ConvertRGBToLMS(const double red,const double green,
261 const double blue,double *L,double *M,double *S)
262{
263 double
264 X,
265 Y,
266 Z;
267
268 ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
269 ConvertXYZToLMS(X,Y,Z,L,M,S);
270}
271
272static void ConvertRGBToLuv(const double red,const double green,
273 const double blue,const IlluminantType illuminant,double *L,double *u,
274 double *v)
275{
276 double
277 X,
278 Y,
279 Z;
280
281 ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
282 ConvertXYZToLuv(X,Y,Z,illuminant,L,u,v);
283}
284
285static void ConvertRGBToxyY(const double red,const double green,
286 const double blue,double *low_x,double *low_y,double *cap_Y)
287{
288 double
289 gamma,
290 X,
291 Y,
292 Z;
293
294 ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
295 gamma=PerceptibleReciprocal(X+Y+Z);
296 *low_x=gamma*X;
297 *low_y=gamma*Y;
298 *cap_Y=Y;
299}
300
301static inline void ConvertXYZToJzazbz(const double X,const double Y,
302 const double Z,const double white_luminance,double *Jz,double *az,double *bz)
303{
304#define Jzazbz_b 1.15 /* https://observablehq.com/@jrus/jzazbz */
305#define Jzazbz_g 0.66
306#define Jzazbz_c1 (3424.0/4096.0)
307#define Jzazbz_c2 (2413.0/128.0)
308#define Jzazbz_c3 (2392.0/128.0)
309#define Jzazbz_n (2610.0/16384.0)
310#define Jzazbz_p (1.7*2523.0/32.0)
311#define Jzazbz_d (-0.56)
312#define Jzazbz_d0 (1.6295499532821566e-11)
313
314 double
315 gamma,
316 Iz,
317 L,
318 Lp,
319 M,
320 Mp,
321 S,
322 Sp,
323 Xp,
324 Yp,
325 Zp;
326
327 Xp=(Jzazbz_b*X-(Jzazbz_b-1)*Z);
328 Yp=(Jzazbz_g*Y-(Jzazbz_g-1)*X);
329 Zp=Z;
330 L=0.41478972*Xp+0.579999*Yp+0.0146480*Zp;
331 M=(-0.2015100)*Xp+1.120649*Yp+0.0531008*Zp;
332 S=(-0.0166008)*Xp+0.264800*Yp+0.6684799*Zp;
333 gamma=pow(L*PerceptibleReciprocal(white_luminance),Jzazbz_n);
334 Lp=pow((Jzazbz_c1+Jzazbz_c2*gamma)/(1.0+Jzazbz_c3*gamma),Jzazbz_p);
335 gamma=pow(M*PerceptibleReciprocal(white_luminance),Jzazbz_n);
336 Mp=pow((Jzazbz_c1+Jzazbz_c2*gamma)/(1.0+Jzazbz_c3*gamma),Jzazbz_p);
337 gamma=pow(S*PerceptibleReciprocal(white_luminance),Jzazbz_n);
338 Sp=pow((Jzazbz_c1+Jzazbz_c2*gamma)/(1.0+Jzazbz_c3*gamma),Jzazbz_p);
339 Iz=0.5*Lp+0.5*Mp;
340 *az=3.52400*Lp-4.066708*Mp+0.542708*Sp+0.5;
341 *bz=0.199076*Lp+1.096799*Mp-1.295875*Sp+0.5;
342 *Jz=((Jzazbz_d+1.0)*Iz)/(Jzazbz_d*Iz+1.0)-Jzazbz_d0;
343}
344
345static inline void ConvertJzazbzToXYZ(const double Jz,const double az,
346 const double bz,const double white_luminance,double *X,double *Y,double *Z)
347{
348 double
349 azz,
350 bzz,
351 gamma,
352 Iz,
353 L,
354 Lp,
355 M,
356 Mp,
357 S,
358 Sp,
359 Xp,
360 Yp,
361 Zp;
362
363 gamma=Jz+Jzazbz_d0;
364 Iz=gamma/(Jzazbz_d-Jzazbz_d*gamma+1.0);
365 azz=az-0.5;
366 bzz=bz-0.5;
367 Lp=Iz+0.138605043271539*azz+0.0580473161561189*bzz;
368 Mp=Iz-0.138605043271539*azz-0.0580473161561189*bzz;
369 Sp=Iz-0.0960192420263189*azz-0.811891896056039*bzz;
370 gamma=pow(Lp,1.0/Jzazbz_p);
371 L=white_luminance*pow((Jzazbz_c1-gamma)/(Jzazbz_c3*gamma-Jzazbz_c2),1.0/
372 Jzazbz_n);
373 gamma=pow(Mp,1.0/Jzazbz_p);
374 M=white_luminance*pow((Jzazbz_c1-gamma)/(Jzazbz_c3*gamma-Jzazbz_c2),1.0/
375 Jzazbz_n);
376 gamma=pow(Sp,1.0/Jzazbz_p);
377 S=white_luminance*pow((Jzazbz_c1-gamma)/(Jzazbz_c3*gamma-Jzazbz_c2),1.0/
378 Jzazbz_n);
379 Xp=1.92422643578761*L-1.00479231259537*M+0.037651404030618*S;
380 Yp=0.350316762094999*L+0.726481193931655*M-0.065384422948085*S;
381 Zp=(-0.0909828109828476)*L-0.312728290523074*M+1.52276656130526*S;
382 *X=(Xp+(Jzazbz_b-1.0)*Zp)/Jzazbz_b;
383 *Y=(Yp+(Jzazbz_g-1.0)**X)/Jzazbz_g;
384 *Z=Zp;
385}
386
387static void ConvertRGBToJzazbz(const double red,const double green,
388 const double blue,const double white_luminance,double *Jz,double *az,
389 double *bz)
390{
391 double
392 X,
393 Y,
394 Z;
395
396 ConvertRGBToXYZ(red,blue,green,&X,&Y,&Z);
397 ConvertXYZToJzazbz(X,Y,Z,white_luminance,Jz,az,bz);
398}
399
400static void ConvertJzazbzToRGB(const double Jz,const double az,
401 const double bz,const double white_luminance,double *red,double *green,
402 double *blue)
403{
404 double
405 X,
406 Y,
407 Z;
408
409 ConvertJzazbzToXYZ(Jz,az,bz,white_luminance,&X,&Y,&Z);
410 ConvertXYZToRGB(X,Y,Z,red,blue,green);
411}
412
413static inline void ConvertOklabToRGB(const double L,const double a,
414 const double b,double *red,double *green,double *blue)
415{
416 double
417 B,
418 G,
419 l,
420 m,
421 R,
422 s;
423
424 l=L+0.3963377774*(a-0.5)+0.2158037573*(b-0.5);
425 m=L-0.1055613458*(a-0.5)-0.0638541728*(b-0.5);
426 s=L-0.0894841775*(a-0.5)-1.2914855480*(b-0.5);
427 l*=l*l;
428 m*=m*m;
429 s*=s*s;
430 R=4.0767416621*l-3.3077115913*m+0.2309699292*s;
431 G=(-1.2684380046)*l+2.6097574011*m-0.3413193965*s;
432 B=(-0.0041960863)*l-0.7034186147*m+1.7076147010*s;
433 *red=EncodePixelGamma((double) QuantumRange*R);
434 *green=EncodePixelGamma((double) QuantumRange*G);
435 *blue=EncodePixelGamma((double) QuantumRange*B);
436}
437
438static void ConvertRGBToOklab(const double red,const double green,
439 const double blue,double *L,double *a,double *b)
440{
441 double
442 B,
443 G,
444 l,
445 m,
446 R,
447 s;
448
449 R=QuantumScale*DecodePixelGamma(red);
450 G=QuantumScale*DecodePixelGamma(green);
451 B=QuantumScale*DecodePixelGamma(blue);
452 l=cbrt(0.4122214708*R+0.5363325363*G+0.0514459929*B);
453 m=cbrt(0.2119034982*R+0.6806995451*G+0.1073969566*B);
454 s=cbrt(0.0883024619*R+0.2817188376*G+0.6299787005*B);
455 *L=0.2104542553*l+0.7936177850*m-0.0040720468*s;
456 *a=1.9779984951*l-2.4285922050*m+0.4505937099*s+0.5;
457 *b=0.0259040371*l+0.7827717662*m-0.8086757660*s+0.5;
458}
459
460static inline void ConvertOklchToRGB(const double L,const double C,
461 const double h,double *red,double *green,double *blue)
462{
463 double
464 a,
465 b;
466
467 a=C*cos(2.0*MagickPI*h);
468 b=C*sin(2.0*MagickPI*h);
469 ConvertOklabToRGB(L,a,b,red,green,blue);
470}
471
472static void ConvertRGBToOklch(const double red,const double green,
473 const double blue,double *L,double *C,double *h)
474{
475 double
476 a,
477 b;
478
479 ConvertRGBToOklab(red,green,blue,L,&a,&b);
480 *C=sqrt(a*a+b*b);
481 *h=0.5+0.5*atan2(-b,-a)/MagickPI;
482}
483
484static void ConvertRGBToYDbDr(const double red,const double green,
485 const double blue,double *Y,double *Db,double *Dr)
486{
487 *Y=QuantumScale*(0.298839*red+0.586811*green+0.114350*blue);
488 *Db=QuantumScale*(-0.450*red-0.883*green+1.333*blue)+0.5;
489 *Dr=QuantumScale*(-1.333*red+1.116*green+0.217*blue)+0.5;
490}
491
492static void ConvertRGBToYIQ(const double red,const double green,
493 const double blue,double *Y,double *I,double *Q)
494{
495 *Y=QuantumScale*(0.298839*red+0.586811*green+0.114350*blue);
496 *I=QuantumScale*(0.595716*red-0.274453*green-0.321263*blue)+0.5;
497 *Q=QuantumScale*(0.211456*red-0.522591*green+0.311135*blue)+0.5;
498}
499
500static void ConvertRGBToYPbPr(const double red,const double green,
501 const double blue,double *Y,double *Pb,double *Pr)
502{
503 *Y=QuantumScale*(0.298839*red+0.586811*green+0.114350*blue);
504 *Pb=QuantumScale*((-0.1687367)*red-0.331264*green+0.5*blue)+0.5;
505 *Pr=QuantumScale*(0.5*red-0.418688*green-0.081312*blue)+0.5;
506}
507
508static void ConvertRGBToYCbCr(const double red,const double green,
509 const double blue,double *Y,double *Cb,double *Cr)
510{
511 ConvertRGBToYPbPr(red,green,blue,Y,Cb,Cr);
512}
513
514static void ConvertRGBToYUV(const double red,const double green,
515 const double blue,double *Y,double *U,double *V)
516{
517 *Y=QuantumScale*(0.298839*red+0.586811*green+0.114350*blue);
518 *U=QuantumScale*((-0.147)*red-0.289*green+0.436*blue)+0.5;
519 *V=QuantumScale*(0.615*red-0.515*green-0.100*blue)+0.5;
520}
521
522static MagickBooleanType sRGBTransformImage(Image *image,
523 const ColorspaceType colorspace,ExceptionInfo *exception)
524{
525#define sRGBTransformImageTag "RGBTransform/Image"
526
528 *image_view;
529
530 const char
531 *artifact;
532
533 IlluminantType
534 illuminant = D65Illuminant;
535
536 MagickBooleanType
537 status;
538
539 MagickOffsetType
540 progress;
541
543 primary_info;
544
545 ssize_t
546 i,
547 y;
548
550 *x_map,
551 *y_map,
552 *z_map;
553
554 assert(image != (Image *) NULL);
555 assert(image->signature == MagickCoreSignature);
556 assert(colorspace != sRGBColorspace);
557 assert(colorspace != TransparentColorspace);
558 assert(colorspace != UndefinedColorspace);
559 if (IsEventLogging() != MagickFalse)
560 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
561 artifact=GetImageArtifact(image,"color:illuminant");
562 if (artifact != (const char *) NULL)
563 {
564 ssize_t
565 illuminant_type;
566
567 illuminant_type=ParseCommandOption(MagickIlluminantOptions,MagickFalse,
568 artifact);
569 if (illuminant_type < 0)
570 illuminant=UndefinedIlluminant;
571 else
572 illuminant=(IlluminantType) illuminant_type;
573 }
574 status=MagickTrue;
575 progress=0;
576 switch (colorspace)
577 {
578 case CMYKColorspace:
579 {
581 zero;
582
583 /*
584 Convert RGB to CMYK colorspace.
585 */
586 if (image->storage_class == PseudoClass)
587 {
588 if (SyncImage(image,exception) == MagickFalse)
589 return(MagickFalse);
590 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
591 return(MagickFalse);
592 }
593 if (SetImageColorspace(image,colorspace,exception) == MagickFalse)
594 return(MagickFalse);
595 GetPixelInfo(image,&zero);
596 image_view=AcquireAuthenticCacheView(image,exception);
597#if defined(MAGICKCORE_OPENMP_SUPPORT)
598 #pragma omp parallel for schedule(static) shared(status) \
599 magick_number_threads(image,image,image->rows,2)
600#endif
601 for (y=0; y < (ssize_t) image->rows; y++)
602 {
603 MagickBooleanType
604 sync;
605
607 pixel;
608
609 Quantum
610 *magick_restrict q;
611
612 ssize_t
613 x;
614
615 if (status == MagickFalse)
616 continue;
617 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
618 exception);
619 if (q == (Quantum *) NULL)
620 {
621 status=MagickFalse;
622 continue;
623 }
624 pixel=zero;
625 for (x=0; x < (ssize_t) image->columns; x++)
626 {
627 GetPixelInfoPixel(image,q,&pixel);
628 ConvertRGBToCMYK(&pixel);
629 SetPixelViaPixelInfo(image,&pixel,q);
630 q+=GetPixelChannels(image);
631 }
632 sync=SyncCacheViewAuthenticPixels(image_view,exception);
633 if (sync == MagickFalse)
634 status=MagickFalse;
635 }
636 image_view=DestroyCacheView(image_view);
637 image->type=image->alpha_trait == UndefinedPixelTrait ?
638 ColorSeparationType : ColorSeparationAlphaType;
639 if (SetImageColorspace(image,colorspace,exception) == MagickFalse)
640 return(MagickFalse);
641 return(status);
642 }
643 case LinearGRAYColorspace:
644 {
645 /*
646 Transform image from sRGB to GRAY.
647 */
648 if (image->storage_class == PseudoClass)
649 {
650 if (SyncImage(image,exception) == MagickFalse)
651 return(MagickFalse);
652 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
653 return(MagickFalse);
654 }
655 image_view=AcquireAuthenticCacheView(image,exception);
656#if defined(MAGICKCORE_OPENMP_SUPPORT)
657 #pragma omp parallel for schedule(static) shared(status) \
658 magick_number_threads(image,image,image->rows,2)
659#endif
660 for (y=0; y < (ssize_t) image->rows; y++)
661 {
662 MagickBooleanType
663 sync;
664
665 ssize_t
666 x;
667
668 Quantum
669 *magick_restrict q;
670
671 if (status == MagickFalse)
672 continue;
673 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
674 exception);
675 if (q == (Quantum *) NULL)
676 {
677 status=MagickFalse;
678 continue;
679 }
680 for (x=0; x < (ssize_t) image->columns; x++)
681 {
682 MagickRealType
683 gray;
684
685 gray=0.212656*DecodePixelGamma(GetPixelRed(image,q))+0.715158*
686 DecodePixelGamma(GetPixelGreen(image,q))+0.072186*
687 DecodePixelGamma(GetPixelBlue(image,q));
688 SetPixelGray(image,ClampToQuantum(gray),q);
689 q+=GetPixelChannels(image);
690 }
691 sync=SyncCacheViewAuthenticPixels(image_view,exception);
692 if (sync == MagickFalse)
693 status=MagickFalse;
694 }
695 image_view=DestroyCacheView(image_view);
696 if (SetImageColorspace(image,colorspace,exception) == MagickFalse)
697 return(MagickFalse);
698 image->type=GrayscaleType;
699 return(status);
700 }
701 case GRAYColorspace:
702 {
703 /*
704 Transform image from sRGB to GRAY.
705 */
706 if (image->storage_class == PseudoClass)
707 {
708 if (SyncImage(image,exception) == MagickFalse)
709 return(MagickFalse);
710 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
711 return(MagickFalse);
712 }
713 image_view=AcquireAuthenticCacheView(image,exception);
714#if defined(MAGICKCORE_OPENMP_SUPPORT)
715 #pragma omp parallel for schedule(static) shared(status) \
716 magick_number_threads(image,image,image->rows,2)
717#endif
718 for (y=0; y < (ssize_t) image->rows; y++)
719 {
720 MagickBooleanType
721 sync;
722
723 ssize_t
724 x;
725
726 Quantum
727 *magick_restrict q;
728
729 if (status == MagickFalse)
730 continue;
731 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
732 exception);
733 if (q == (Quantum *) NULL)
734 {
735 status=MagickFalse;
736 continue;
737 }
738 for (x=0; x < (ssize_t) image->columns; x++)
739 {
740 MagickRealType
741 gray;
742
743 gray=0.212656*(double) GetPixelRed(image,q)+0.715158*(double)
744 GetPixelGreen(image,q)+0.072186*(double) GetPixelBlue(image,q);
745 SetPixelGray(image,ClampToQuantum(gray),q);
746 q+=GetPixelChannels(image);
747 }
748 sync=SyncCacheViewAuthenticPixels(image_view,exception);
749 if (sync == MagickFalse)
750 status=MagickFalse;
751 }
752 image_view=DestroyCacheView(image_view);
753 if (SetImageColorspace(image,colorspace,exception) == MagickFalse)
754 return(MagickFalse);
755 image->type=GrayscaleType;
756 return(status);
757 }
758 case CMYColorspace:
759 case Adobe98Colorspace:
760 case DisplayP3Colorspace:
761 case HCLColorspace:
762 case HCLpColorspace:
763 case HSBColorspace:
764 case HSIColorspace:
765 case HSLColorspace:
766 case HSVColorspace:
767 case HWBColorspace:
768 case JzazbzColorspace:
769 case LabColorspace:
770 case LCHColorspace:
771 case LCHabColorspace:
772 case LCHuvColorspace:
773 case LMSColorspace:
774 case LuvColorspace:
775 case OklabColorspace:
776 case OklchColorspace:
777 case ProPhotoColorspace:
778 case xyYColorspace:
779 case XYZColorspace:
780 case YCbCrColorspace:
781 case YDbDrColorspace:
782 case YIQColorspace:
783 case YPbPrColorspace:
784 case YUVColorspace:
785 {
786 const char
787 *value;
788
789 double
790 white_luminance;
791
792 /*
793 Transform image from sRGB to target colorspace.
794 */
795 white_luminance=10000.0;
796 value=GetImageProperty(image,"white-luminance",exception);
797 if (value != (const char *) NULL)
798 white_luminance=StringToDouble(value,(char **) NULL);
799 if (image->storage_class == PseudoClass)
800 {
801 if (SyncImage(image,exception) == MagickFalse)
802 return(MagickFalse);
803 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
804 return(MagickFalse);
805 }
806 image_view=AcquireAuthenticCacheView(image,exception);
807#if defined(MAGICKCORE_OPENMP_SUPPORT)
808 #pragma omp parallel for schedule(static) shared(status) \
809 magick_number_threads(image,image,image->rows,2)
810#endif
811 for (y=0; y < (ssize_t) image->rows; y++)
812 {
813 MagickBooleanType
814 sync;
815
816 ssize_t
817 x;
818
819 Quantum
820 *magick_restrict q;
821
822 if (status == MagickFalse)
823 continue;
824 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
825 exception);
826 if (q == (Quantum *) NULL)
827 {
828 status=MagickFalse;
829 continue;
830 }
831 for (x=0; x < (ssize_t) image->columns; x++)
832 {
833 double
834 blue,
835 green,
836 red,
837 X,
838 Y,
839 Z;
840
841 red=(double) GetPixelRed(image,q);
842 green=(double) GetPixelGreen(image,q);
843 blue=(double) GetPixelBlue(image,q);
844 switch (colorspace)
845 {
846 case Adobe98Colorspace:
847 {
848 ConvertRGBToAdobe98(red,green,blue,&X,&Y,&Z);
849 break;
850 }
851 case CMYColorspace:
852 {
853 ConvertRGBToCMY(red,green,blue,&X,&Y,&Z);
854 break;
855 }
856 case DisplayP3Colorspace:
857 {
858 ConvertRGBToDisplayP3(red,green,blue,&X,&Y,&Z);
859 break;
860 }
861 case HCLColorspace:
862 {
863 ConvertRGBToHCL(red,green,blue,&X,&Y,&Z);
864 break;
865 }
866 case HCLpColorspace:
867 {
868 ConvertRGBToHCLp(red,green,blue,&X,&Y,&Z);
869 break;
870 }
871 case HSBColorspace:
872 {
873 ConvertRGBToHSB(red,green,blue,&X,&Y,&Z);
874 break;
875 }
876 case HSIColorspace:
877 {
878 ConvertRGBToHSI(red,green,blue,&X,&Y,&Z);
879 break;
880 }
881 case HSLColorspace:
882 {
883 ConvertRGBToHSL(red,green,blue,&X,&Y,&Z);
884 break;
885 }
886 case HSVColorspace:
887 {
888 ConvertRGBToHSV(red,green,blue,&X,&Y,&Z);
889 break;
890 }
891 case HWBColorspace:
892 {
893 ConvertRGBToHWB(red,green,blue,&X,&Y,&Z);
894 break;
895 }
896 case JzazbzColorspace:
897 {
898 ConvertRGBToJzazbz(red,green,blue,white_luminance,&X,&Y,&Z);
899 break;
900 }
901 case LabColorspace:
902 {
903 ConvertRGBToLab(red,green,blue,illuminant,&X,&Y,&Z);
904 break;
905 }
906 case LCHColorspace:
907 case LCHabColorspace:
908 {
909 ConvertRGBToLCHab(red,green,blue,illuminant,&X,&Y,&Z);
910 break;
911 }
912 case LCHuvColorspace:
913 {
914 ConvertRGBToLCHuv(red,green,blue,illuminant,&X,&Y,&Z);
915 break;
916 }
917 case LMSColorspace:
918 {
919 ConvertRGBToLMS(red,green,blue,&X,&Y,&Z);
920 break;
921 }
922 case LuvColorspace:
923 {
924 ConvertRGBToLuv(red,green,blue,illuminant,&X,&Y,&Z);
925 break;
926 }
927 case OklabColorspace:
928 {
929 ConvertRGBToOklab(red,green,blue,&X,&Y,&Z);
930 break;
931 }
932 case OklchColorspace:
933 {
934 ConvertRGBToOklch(red,green,blue,&X,&Y,&Z);
935 break;
936 }
937 case ProPhotoColorspace:
938 {
939 ConvertRGBToProPhoto(red,green,blue,&X,&Y,&Z);
940 break;
941 }
942 case xyYColorspace:
943 {
944 ConvertRGBToxyY(red,green,blue,&X,&Y,&Z);
945 break;
946 }
947 case XYZColorspace:
948 {
949 ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
950 break;
951 }
952 case YCbCrColorspace:
953 {
954 ConvertRGBToYCbCr(red,green,blue,&X,&Y,&Z);
955 break;
956 }
957 case YDbDrColorspace:
958 {
959 ConvertRGBToYDbDr(red,green,blue,&X,&Y,&Z);
960 break;
961 }
962 case YIQColorspace:
963 {
964 ConvertRGBToYIQ(red,green,blue,&X,&Y,&Z);
965 break;
966 }
967 case YPbPrColorspace:
968 {
969 ConvertRGBToYPbPr(red,green,blue,&X,&Y,&Z);
970 break;
971 }
972 case YUVColorspace:
973 {
974 ConvertRGBToYUV(red,green,blue,&X,&Y,&Z);
975 break;
976 }
977 default:
978 {
979 X=QuantumScale*red;
980 Y=QuantumScale*green;
981 Z=QuantumScale*blue;
982 break;
983 }
984 }
985 SetPixelRed(image,ClampToQuantum((double) QuantumRange*X),q);
986 SetPixelGreen(image,ClampToQuantum((double) QuantumRange*Y),q);
987 SetPixelBlue(image,ClampToQuantum((double) QuantumRange*Z),q);
988 q+=GetPixelChannels(image);
989 }
990 sync=SyncCacheViewAuthenticPixels(image_view,exception);
991 if (sync == MagickFalse)
992 status=MagickFalse;
993 }
994 image_view=DestroyCacheView(image_view);
995 if (SetImageColorspace(image,colorspace,exception) == MagickFalse)
996 return(MagickFalse);
997 return(status);
998 }
999 case LogColorspace:
1000 {
1001#define DisplayGamma (1.0/1.7)
1002#define FilmGamma 0.6
1003#define ReferenceBlack 95.0
1004#define ReferenceWhite 685.0
1005
1006 const char
1007 *value;
1008
1009 double
1010 black,
1011 density,
1012 film_gamma,
1013 gamma,
1014 reference_black,
1015 reference_white;
1016
1017 Quantum
1018 *logmap;
1019
1020 /*
1021 Transform RGB to Log colorspace.
1022 */
1023 density=DisplayGamma;
1024 gamma=DisplayGamma;
1025 value=GetImageProperty(image,"gamma",exception);
1026 if (value != (const char *) NULL)
1027 gamma=PerceptibleReciprocal(StringToDouble(value,(char **) NULL));
1028 film_gamma=FilmGamma;
1029 value=GetImageProperty(image,"film-gamma",exception);
1030 if (value != (const char *) NULL)
1031 film_gamma=StringToDouble(value,(char **) NULL);
1032 reference_black=ReferenceBlack;
1033 value=GetImageProperty(image,"reference-black",exception);
1034 if (value != (const char *) NULL)
1035 reference_black=StringToDouble(value,(char **) NULL);
1036 reference_white=ReferenceWhite;
1037 value=GetImageProperty(image,"reference-white",exception);
1038 if (value != (const char *) NULL)
1039 reference_white=StringToDouble(value,(char **) NULL);
1040 logmap=(Quantum *) AcquireQuantumMemory((size_t) MaxMap+1UL,
1041 sizeof(*logmap));
1042 if (logmap == (Quantum *) NULL)
1043 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1044 image->filename);
1045 black=pow(10.0,(reference_black-reference_white)*(gamma/density)*0.002*
1046 PerceptibleReciprocal(film_gamma));
1047#if defined(MAGICKCORE_OPENMP_SUPPORT)
1048 #pragma omp parallel for schedule(static)
1049#endif
1050 for (i=0; i <= (ssize_t) MaxMap; i++)
1051 logmap[i]=ScaleMapToQuantum(((double) MaxMap*(reference_white+
1052 log10(black+(1.0*i/MaxMap)*(1.0-black))/((gamma/density)*0.002*
1053 PerceptibleReciprocal(film_gamma)))/1024.0));
1054 image_view=AcquireAuthenticCacheView(image,exception);
1055#if defined(MAGICKCORE_OPENMP_SUPPORT)
1056 #pragma omp parallel for schedule(static) shared(status) \
1057 magick_number_threads(image,image,image->rows,2)
1058#endif
1059 for (y=0; y < (ssize_t) image->rows; y++)
1060 {
1061 MagickBooleanType
1062 sync;
1063
1064 ssize_t
1065 x;
1066
1067 Quantum
1068 *magick_restrict q;
1069
1070 if (status == MagickFalse)
1071 continue;
1072 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1073 exception);
1074 if (q == (Quantum *) NULL)
1075 {
1076 status=MagickFalse;
1077 continue;
1078 }
1079 for (x=(ssize_t) image->columns; x != 0; x--)
1080 {
1081 double
1082 blue,
1083 green,
1084 red;
1085
1086 red=(double) DecodePixelGamma((MagickRealType)
1087 GetPixelRed(image,q));
1088 green=(double) DecodePixelGamma((MagickRealType)
1089 GetPixelGreen(image,q));
1090 blue=(double) DecodePixelGamma((MagickRealType)
1091 GetPixelBlue(image,q));
1092 SetPixelRed(image,logmap[ScaleQuantumToMap(ClampToQuantum(red))],q);
1093 SetPixelGreen(image,logmap[ScaleQuantumToMap(ClampToQuantum(green))],
1094 q);
1095 SetPixelBlue(image,logmap[ScaleQuantumToMap(ClampToQuantum(blue))],q);
1096 q+=GetPixelChannels(image);
1097 }
1098 sync=SyncCacheViewAuthenticPixels(image_view,exception);
1099 if (sync == MagickFalse)
1100 status=MagickFalse;
1101 }
1102 image_view=DestroyCacheView(image_view);
1103 logmap=(Quantum *) RelinquishMagickMemory(logmap);
1104 if (SetImageColorspace(image,colorspace,exception) == MagickFalse)
1105 return(MagickFalse);
1106 return(status);
1107 }
1108 case RGBColorspace:
1109 case scRGBColorspace:
1110 {
1111 /*
1112 Transform image from sRGB to linear RGB.
1113 */
1114 if (image->storage_class == PseudoClass)
1115 {
1116 if (SyncImage(image,exception) == MagickFalse)
1117 return(MagickFalse);
1118 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1119 return(MagickFalse);
1120 }
1121 image_view=AcquireAuthenticCacheView(image,exception);
1122#if defined(MAGICKCORE_OPENMP_SUPPORT)
1123 #pragma omp parallel for schedule(static) shared(status) \
1124 magick_number_threads(image,image,image->rows,2)
1125#endif
1126 for (y=0; y < (ssize_t) image->rows; y++)
1127 {
1128 MagickBooleanType
1129 sync;
1130
1131 ssize_t
1132 x;
1133
1134 Quantum
1135 *magick_restrict q;
1136
1137 if (status == MagickFalse)
1138 continue;
1139 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1140 exception);
1141 if (q == (Quantum *) NULL)
1142 {
1143 status=MagickFalse;
1144 continue;
1145 }
1146 for (x=0; x < (ssize_t) image->columns; x++)
1147 {
1148 double
1149 blue,
1150 green,
1151 red;
1152
1153 red=DecodePixelGamma((MagickRealType) GetPixelRed(image,q));
1154 green=DecodePixelGamma((MagickRealType) GetPixelGreen(image,q));
1155 blue=DecodePixelGamma((MagickRealType) GetPixelBlue(image,q));
1156 SetPixelRed(image,ClampToQuantum(red),q);
1157 SetPixelGreen(image,ClampToQuantum(green),q);
1158 SetPixelBlue(image,ClampToQuantum(blue),q);
1159 q+=GetPixelChannels(image);
1160 }
1161 sync=SyncCacheViewAuthenticPixels(image_view,exception);
1162 if (sync == MagickFalse)
1163 status=MagickFalse;
1164 }
1165 image_view=DestroyCacheView(image_view);
1166 if (SetImageColorspace(image,colorspace,exception) == MagickFalse)
1167 return(MagickFalse);
1168 return(status);
1169 }
1170 default:
1171 break;
1172 }
1173 /*
1174 Allocate the tables.
1175 */
1176 x_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
1177 sizeof(*x_map));
1178 y_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
1179 sizeof(*y_map));
1180 z_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
1181 sizeof(*z_map));
1182 if ((x_map == (TransformPacket *) NULL) ||
1183 (y_map == (TransformPacket *) NULL) ||
1184 (z_map == (TransformPacket *) NULL))
1185 {
1186 if (x_map != (TransformPacket *) NULL)
1187 x_map=(TransformPacket *) RelinquishMagickMemory(x_map);
1188 if (y_map != (TransformPacket *) NULL)
1189 y_map=(TransformPacket *) RelinquishMagickMemory(y_map);
1190 if (z_map != (TransformPacket *) NULL)
1191 z_map=(TransformPacket *) RelinquishMagickMemory(z_map);
1192 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1193 image->filename);
1194 }
1195 (void) memset(&primary_info,0,sizeof(primary_info));
1196 switch (colorspace)
1197 {
1198 case OHTAColorspace:
1199 {
1200 /*
1201 Initialize OHTA tables:
1202
1203 I1 = 0.33333*R+0.33334*G+0.33333*B
1204 I2 = 0.50000*R+0.00000*G-0.50000*B
1205 I3 =-0.25000*R+0.50000*G-0.25000*B
1206
1207 I and Q, normally -0.5 through 0.5, are normalized to the range 0
1208 through QuantumRange.
1209 */
1210 primary_info.y=(MagickRealType) ((MaxMap+1)/2);
1211 primary_info.z=(MagickRealType) ((MaxMap+1)/2);
1212#if defined(MAGICKCORE_OPENMP_SUPPORT)
1213 #pragma omp parallel for schedule(static)
1214#endif
1215 for (i=0; i <= (ssize_t) MaxMap; i++)
1216 {
1217 x_map[i].x=(MagickRealType) (0.33333*(double) i);
1218 x_map[i].y=(MagickRealType) (0.50000*(double) i);
1219 x_map[i].z=(MagickRealType) (-0.25000*(double) i);
1220 y_map[i].x=(MagickRealType) (0.33334*(double) i);
1221 y_map[i].y=(MagickRealType) (0.00000*(double) i);
1222 y_map[i].z=(MagickRealType) (0.50000*(double) i);
1223 z_map[i].x=(MagickRealType) (0.33333*(double) i);
1224 z_map[i].y=(MagickRealType) (-0.50000*(double) i);
1225 z_map[i].z=(MagickRealType) (-0.25000*(double) i);
1226 }
1227 break;
1228 }
1229 case Rec601YCbCrColorspace:
1230 {
1231 /*
1232 Initialize YCbCr tables (ITU-R BT.601):
1233
1234 Y = 0.2988390*R+0.5868110*G+0.1143500*B
1235 Cb= -0.1687367*R-0.3312640*G+0.5000000*B
1236 Cr= 0.5000000*R-0.4186880*G-0.0813120*B
1237
1238 Cb and Cr, normally -0.5 through 0.5, are normalized to the range 0
1239 through QuantumRange.
1240 */
1241 primary_info.y=(MagickRealType) ((MaxMap+1)/2);
1242 primary_info.z=(MagickRealType) ((MaxMap+1)/2);
1243#if defined(MAGICKCORE_OPENMP_SUPPORT)
1244 #pragma omp parallel for schedule(static)
1245#endif
1246 for (i=0; i <= (ssize_t) MaxMap; i++)
1247 {
1248 x_map[i].x=(MagickRealType) (0.298839*(double) i);
1249 x_map[i].y=(MagickRealType) (-0.1687367*(double) i);
1250 x_map[i].z=(MagickRealType) (0.500000*(double) i);
1251 y_map[i].x=(MagickRealType) (0.586811*(double) i);
1252 y_map[i].y=(MagickRealType) (-0.331264*(double) i);
1253 y_map[i].z=(MagickRealType) (-0.418688*(double) i);
1254 z_map[i].x=(MagickRealType) (0.114350*(double) i);
1255 z_map[i].y=(MagickRealType) (0.500000*(double) i);
1256 z_map[i].z=(MagickRealType) (-0.081312*(double) i);
1257 }
1258 break;
1259 }
1260 case Rec709YCbCrColorspace:
1261 {
1262 /*
1263 Initialize YCbCr tables (ITU-R BT.709):
1264
1265 Y = 0.212656*R+0.715158*G+0.072186*B
1266 Cb= -0.114572*R-0.385428*G+0.500000*B
1267 Cr= 0.500000*R-0.454153*G-0.045847*B
1268
1269 Cb and Cr, normally -0.5 through 0.5, are normalized to the range 0
1270 through QuantumRange.
1271 */
1272 primary_info.y=(double) ((MaxMap+1)/2);
1273 primary_info.z=(double) ((MaxMap+1)/2);
1274#if defined(MAGICKCORE_OPENMP_SUPPORT)
1275 #pragma omp parallel for schedule(static)
1276#endif
1277 for (i=0; i <= (ssize_t) MaxMap; i++)
1278 {
1279 x_map[i].x=(MagickRealType) (0.212656*(double) i);
1280 x_map[i].y=(MagickRealType) (-0.114572*(double) i);
1281 x_map[i].z=(MagickRealType) (0.500000*(double) i);
1282 y_map[i].x=(MagickRealType) (0.715158*(double) i);
1283 y_map[i].y=(MagickRealType) (-0.385428*(double) i);
1284 y_map[i].z=(MagickRealType) (-0.454153*(double) i);
1285 z_map[i].x=(MagickRealType) (0.072186*(double) i);
1286 z_map[i].y=(MagickRealType) (0.500000*(double) i);
1287 z_map[i].z=(MagickRealType) (-0.045847*(double) i);
1288 }
1289 break;
1290 }
1291 case YCCColorspace:
1292 {
1293 /*
1294 Initialize YCC tables:
1295
1296 Y = 0.298839*R+0.586811*G+0.114350*B
1297 C1= -0.298839*R-0.586811*G+0.88600*B
1298 C2= 0.70100*R-0.586811*G-0.114350*B
1299
1300 YCC is scaled by 1.3584. C1 zero is 156 and C2 is at 137.
1301 */
1302 primary_info.y=(MagickRealType) ScaleQuantumToMap(
1303 ScaleCharToQuantum(156));
1304 primary_info.z=(MagickRealType) ScaleQuantumToMap(
1305 ScaleCharToQuantum(137));
1306 for (i=0; i <= (ssize_t) (0.018*MaxMap); i++)
1307 {
1308 x_map[i].x=0.005382*i;
1309 x_map[i].y=(-0.003296)*i;
1310 x_map[i].z=0.009410*i;
1311 y_map[i].x=0.010566*i;
1312 y_map[i].y=(-0.006471)*i;
1313 y_map[i].z=(-0.007880)*i;
1314 z_map[i].x=0.002052*i;
1315 z_map[i].y=0.009768*i;
1316 z_map[i].z=(-0.001530)*i;
1317 }
1318 for ( ; i <= (ssize_t) MaxMap; i++)
1319 {
1320 x_map[i].x=0.298839*(1.099*i-0.099);
1321 x_map[i].y=(-0.298839)*(1.099*i-0.099);
1322 x_map[i].z=0.70100*(1.099*i-0.099);
1323 y_map[i].x=0.586811*(1.099*i-0.099);
1324 y_map[i].y=(-0.586811)*(1.099*i-0.099);
1325 y_map[i].z=(-0.586811)*(1.099*i-0.099);
1326 z_map[i].x=0.114350*(1.099*i-0.099);
1327 z_map[i].y=0.88600*(1.099*i-0.099);
1328 z_map[i].z=(-0.114350)*(1.099*i-0.099);
1329 }
1330 break;
1331 }
1332 default:
1333 {
1334 /*
1335 Linear conversion tables.
1336 */
1337#if defined(MAGICKCORE_OPENMP_SUPPORT)
1338 #pragma omp parallel for schedule(static)
1339#endif
1340 for (i=0; i <= (ssize_t) MaxMap; i++)
1341 {
1342 x_map[i].x=(MagickRealType) (1.0*(double) i);
1343 x_map[i].y=(MagickRealType) 0.0;
1344 x_map[i].z=(MagickRealType) 0.0;
1345 y_map[i].x=(MagickRealType) 0.0;
1346 y_map[i].y=(MagickRealType) (1.0*(double) i);
1347 y_map[i].z=(MagickRealType) 0.0;
1348 z_map[i].x=(MagickRealType) 0.0;
1349 z_map[i].y=(MagickRealType) 0.0;
1350 z_map[i].z=(MagickRealType) (1.0*(double) i);
1351 }
1352 break;
1353 }
1354 }
1355 /*
1356 Convert from sRGB.
1357 */
1358 switch (image->storage_class)
1359 {
1360 case DirectClass:
1361 default:
1362 {
1363 /*
1364 Convert DirectClass image.
1365 */
1366 image_view=AcquireAuthenticCacheView(image,exception);
1367#if defined(MAGICKCORE_OPENMP_SUPPORT)
1368 #pragma omp parallel for schedule(static) shared(status) \
1369 magick_number_threads(image,image,image->rows,2)
1370#endif
1371 for (y=0; y < (ssize_t) image->rows; y++)
1372 {
1373 MagickBooleanType
1374 sync;
1375
1376 PixelInfo
1377 pixel;
1378
1379 Quantum
1380 *magick_restrict q;
1381
1382 ssize_t
1383 x;
1384
1385 unsigned int
1386 blue,
1387 green,
1388 red;
1389
1390 if (status == MagickFalse)
1391 continue;
1392 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1393 exception);
1394 if (q == (Quantum *) NULL)
1395 {
1396 status=MagickFalse;
1397 continue;
1398 }
1399 for (x=0; x < (ssize_t) image->columns; x++)
1400 {
1401 red=ScaleQuantumToMap(ClampToQuantum((MagickRealType)
1402 GetPixelRed(image,q)));
1403 green=ScaleQuantumToMap(ClampToQuantum((MagickRealType)
1404 GetPixelGreen(image,q)));
1405 blue=ScaleQuantumToMap(ClampToQuantum((MagickRealType)
1406 GetPixelBlue(image,q)));
1407 pixel.red=(x_map[red].x+y_map[green].x+z_map[blue].x)+
1408 primary_info.x;
1409 pixel.green=(x_map[red].y+y_map[green].y+z_map[blue].y)+
1410 primary_info.y;
1411 pixel.blue=(x_map[red].z+y_map[green].z+z_map[blue].z)+
1412 primary_info.z;
1413 SetPixelRed(image,ScaleMapToQuantum(pixel.red),q);
1414 SetPixelGreen(image,ScaleMapToQuantum(pixel.green),q);
1415 SetPixelBlue(image,ScaleMapToQuantum(pixel.blue),q);
1416 q+=GetPixelChannels(image);
1417 }
1418 sync=SyncCacheViewAuthenticPixels(image_view,exception);
1419 if (sync == MagickFalse)
1420 status=MagickFalse;
1421 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1422 {
1423 MagickBooleanType
1424 proceed;
1425
1426#if defined(MAGICKCORE_OPENMP_SUPPORT)
1427 #pragma omp atomic
1428#endif
1429 progress++;
1430 proceed=SetImageProgress(image,sRGBTransformImageTag,progress,
1431 image->rows);
1432 if (proceed == MagickFalse)
1433 status=MagickFalse;
1434 }
1435 }
1436 image_view=DestroyCacheView(image_view);
1437 break;
1438 }
1439 case PseudoClass:
1440 {
1441 unsigned int
1442 blue,
1443 green,
1444 red;
1445
1446 /*
1447 Convert PseudoClass image.
1448 */
1449 for (i=0; i < (ssize_t) image->colors; i++)
1450 {
1451 PixelInfo
1452 pixel;
1453
1454 red=ScaleQuantumToMap(ClampToQuantum(image->colormap[i].red));
1455 green=ScaleQuantumToMap(ClampToQuantum(image->colormap[i].green));
1456 blue=ScaleQuantumToMap(ClampToQuantum(image->colormap[i].blue));
1457 pixel.red=x_map[red].x+y_map[green].x+z_map[blue].x+primary_info.x;
1458 pixel.green=x_map[red].y+y_map[green].y+z_map[blue].y+primary_info.y;
1459 pixel.blue=x_map[red].z+y_map[green].z+z_map[blue].z+primary_info.z;
1460 image->colormap[i].red=(double) ScaleMapToQuantum(pixel.red);
1461 image->colormap[i].green=(double) ScaleMapToQuantum(pixel.green);
1462 image->colormap[i].blue=(double) ScaleMapToQuantum(pixel.blue);
1463 }
1464 (void) SyncImage(image,exception);
1465 break;
1466 }
1467 }
1468 /*
1469 Relinquish resources.
1470 */
1471 z_map=(TransformPacket *) RelinquishMagickMemory(z_map);
1472 y_map=(TransformPacket *) RelinquishMagickMemory(y_map);
1473 x_map=(TransformPacket *) RelinquishMagickMemory(x_map);
1474 if (SetImageColorspace(image,colorspace,exception) == MagickFalse)
1475 return(MagickFalse);
1476 return(status);
1477}
1478
1479/*
1480%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1481% %
1482% %
1483% %
1484% S e t I m a g e C o l o r s p a c e %
1485% %
1486% %
1487% %
1488%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1489%
1490% SetImageColorspace() sets the colorspace member of the Image structure.
1491%
1492% The format of the SetImageColorspace method is:
1493%
1494% MagickBooleanType SetImageColorspace(Image *image,
1495% const ColorspaceType colorspace,ExceptionInfo *exception)
1496%
1497% A description of each parameter follows:
1498%
1499% o image: the image.
1500%
1501% o colorspace: the colorspace.
1502%
1503% o exception: return any errors or warnings in this structure.
1504%
1505*/
1506MagickExport MagickBooleanType SetImageColorspace(Image *image,
1507 const ColorspaceType colorspace,ExceptionInfo *exception)
1508{
1509 ImageType
1510 type;
1511
1512 MagickBooleanType
1513 status;
1514
1515 assert(image != (Image *) NULL);
1516 assert(image->signature == MagickCoreSignature);
1517 assert(exception != (ExceptionInfo *) NULL);
1518 assert(exception->signature == MagickCoreSignature);
1519 if (IsEventLogging() != MagickFalse)
1520 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1521 if (image->colorspace == colorspace)
1522 return(MagickTrue);
1523 image->colorspace=colorspace;
1524 image->rendering_intent=UndefinedIntent;
1525 image->gamma=1.000/2.200;
1526 (void) memset(&image->chromaticity,0,sizeof(image->chromaticity));
1527 type=image->type;
1528 if (IsGrayColorspace(colorspace) != MagickFalse)
1529 {
1530 if (colorspace == LinearGRAYColorspace)
1531 image->gamma=1.000;
1532 type=GrayscaleType;
1533 }
1534 else
1535 if ((IsRGBColorspace(colorspace) != MagickFalse) ||
1536 (colorspace == XYZColorspace) || (colorspace == xyYColorspace))
1537 image->gamma=1.000;
1538 else
1539 {
1540 image->rendering_intent=PerceptualIntent;
1541 image->chromaticity.red_primary.x=0.6400;
1542 image->chromaticity.red_primary.y=0.3300;
1543 image->chromaticity.red_primary.z=0.0300;
1544 image->chromaticity.green_primary.x=0.3000;
1545 image->chromaticity.green_primary.y=0.6000;
1546 image->chromaticity.green_primary.z=0.1000;
1547 image->chromaticity.blue_primary.x=0.1500;
1548 image->chromaticity.blue_primary.y=0.0600;
1549 image->chromaticity.blue_primary.z=0.7900;
1550 image->chromaticity.white_point.x=0.3127;
1551 image->chromaticity.white_point.y=0.3290;
1552 image->chromaticity.white_point.z=0.3583;
1553 }
1554 status=SyncImagePixelCache(image,exception);
1555 image->type=type;
1556 return(status);
1557}
1558
1559/*
1560%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1561% %
1562% %
1563% %
1564% S e t I m a g e G r a y %
1565% %
1566% %
1567% %
1568%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1569%
1570% SetImageGray() returns MagickTrue if all the pixels in the image have the
1571% same red, green, and blue intensities and changes the type of the image to
1572% bi-level or grayscale.
1573%
1574% The format of the SetImageGray method is:
1575%
1576% MagickBooleanType SetImageGray(const Image *image,
1577% ExceptionInfo *exception)
1578%
1579% A description of each parameter follows:
1580%
1581% o image: the image.
1582%
1583% o exception: return any errors or warnings in this structure.
1584%
1585*/
1586MagickExport MagickBooleanType SetImageGray(Image *image,
1587 ExceptionInfo *exception)
1588{
1589 const char
1590 *value;
1591
1592 ImageType
1593 type;
1594
1595 assert(image != (Image *) NULL);
1596 assert(image->signature == MagickCoreSignature);
1597 if (IsEventLogging() != MagickFalse)
1598 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1599 if (IsImageGray(image) != MagickFalse)
1600 return(MagickTrue);
1601 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
1602 return(MagickFalse);
1603 value=GetImageProperty(image,"colorspace:auto-grayscale",exception);
1604 if (IsStringFalse(value) != MagickFalse)
1605 return(MagickFalse);
1606 type=IdentifyImageGray(image,exception);
1607 if (type == UndefinedType)
1608 return(MagickFalse);
1609 image->colorspace=GRAYColorspace;
1610 if (SyncImagePixelCache(image,exception) == MagickFalse)
1611 return(MagickFalse);
1612 image->type=type;
1613 return(MagickTrue);
1614}
1615
1616/*
1617%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1618% %
1619% %
1620% %
1621% S e t I m a g e M o n o c h r o m e %
1622% %
1623% %
1624% %
1625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1626%
1627% SetImageMonochrome() returns MagickTrue if all the pixels in the image have
1628% the same red, green, and blue intensities and the intensity is either
1629% 0 or QuantumRange and changes the type of the image to bi-level.
1630%
1631% The format of the SetImageMonochrome method is:
1632%
1633% MagickBooleanType SetImageMonochrome(Image *image,
1634% ExceptionInfo *exception)
1635%
1636% A description of each parameter follows:
1637%
1638% o image: the image.
1639%
1640% o exception: return any errors or warnings in this structure.
1641%
1642*/
1643MagickExport MagickBooleanType SetImageMonochrome(Image *image,
1644 ExceptionInfo *exception)
1645{
1646 MagickBooleanType
1647 is_bilevel;
1648
1649 assert(image != (Image *) NULL);
1650 assert(image->signature == MagickCoreSignature);
1651 if (IsEventLogging() != MagickFalse)
1652 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1653 if (IsImageMonochrome(image) != MagickFalse)
1654 return(MagickTrue);
1655 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
1656 return(MagickFalse);
1657 is_bilevel=IdentifyImageMonochrome(image,exception);
1658 if (is_bilevel == MagickFalse)
1659 return(MagickFalse);
1660 image->colorspace=GRAYColorspace;
1661 if (SyncImagePixelCache((Image *) image,exception) == MagickFalse)
1662 return(MagickFalse);
1663 image->type=BilevelType;
1664 return(MagickTrue);
1665}
1666
1667/*
1668%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1669% %
1670% %
1671% %
1672% T r a n s f o r m I m a g e C o l o r s p a c e %
1673% %
1674% %
1675% %
1676%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1677%
1678% TransformImageColorspace() transforms an image colorspace, changing the
1679% image data to reflect the new colorspace.
1680%
1681% The format of the TransformImageColorspace method is:
1682%
1683% MagickBooleanType TransformImageColorspace(Image *image,
1684% const ColorspaceType colorspace,ExceptionInfo *exception)
1685%
1686% A description of each parameter follows:
1687%
1688% o image: the image.
1689%
1690% o colorspace: the colorspace.
1691%
1692% o exception: return any errors or warnings in this structure.
1693%
1694*/
1695MagickExport MagickBooleanType TransformImageColorspace(Image *image,
1696 const ColorspaceType colorspace,ExceptionInfo *exception)
1697{
1698 MagickBooleanType
1699 status;
1700
1701 assert(image != (Image *) NULL);
1702 assert(image->signature == MagickCoreSignature);
1703 if (IsEventLogging() != MagickFalse)
1704 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1705 if (image->colorspace == colorspace)
1706 return(SetImageColorspace(image,colorspace,exception));
1707 (void) DeleteImageProfile(image,"icc");
1708 (void) DeleteImageProfile(image,"icm");
1709 if (colorspace == UndefinedColorspace)
1710 return(SetImageColorspace(image,colorspace,exception));
1711 /*
1712 Convert the reference image from an alternate colorspace to sRGB.
1713 */
1714 if (IssRGBColorspace(colorspace) != MagickFalse)
1715 return(TransformsRGBImage(image,exception));
1716 status=MagickTrue;
1717 if (IssRGBColorspace(image->colorspace) == MagickFalse)
1718 status=TransformsRGBImage(image,exception);
1719 if (status == MagickFalse)
1720 return(status);
1721 /*
1722 Convert the reference image from sRGB to an alternate colorspace.
1723 */
1724 if (sRGBTransformImage(image,colorspace,exception) == MagickFalse)
1725 status=MagickFalse;
1726 return(status);
1727}
1728
1729/*
1730%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1731% %
1732% %
1733% %
1734+ T r a n s f o r m s R G B I m a g e %
1735% %
1736% %
1737% %
1738%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1739%
1740% TransformsRGBImage() converts the reference image from an alternate
1741% colorspace to sRGB. The transformation matrices are not the standard ones:
1742% the weights are rescaled to normalize the range of the transformed values
1743% to be [0..QuantumRange].
1744%
1745% The format of the TransformsRGBImage method is:
1746%
1747% MagickBooleanType TransformsRGBImage(Image *image,
1748% ExceptionInfo *exception)
1749%
1750% A description of each parameter follows:
1751%
1752% o image: the image.
1753%
1754% o exception: return any errors or warnings in this structure.
1755%
1756*/
1757
1758static inline void ConvertCMYToRGB(const double cyan,const double magenta,
1759 const double yellow,double *red,double *green,double *blue)
1760{
1761 *red=(double) QuantumRange*(1.0-cyan);
1762 *green=(double) QuantumRange*(1.0-magenta);
1763 *blue=(double) QuantumRange*(1.0-yellow);
1764}
1765
1766static inline void ConvertLMSToXYZ(const double L,const double M,const double S,
1767 double *X,double *Y,double *Z)
1768{
1769 *X=1.096123820835514*L-0.278869000218287*M+0.182745179382773*S;
1770 *Y=0.454369041975359*L+0.473533154307412*M+0.072097803717229*S;
1771 *Z=(-0.009627608738429)*L-0.005698031216113*M+1.015325639954543*S;
1772}
1773
1774static inline void ConvertLMSToRGB(const double L,const double M,
1775 const double S,double *red,double *green,double *blue)
1776{
1777 double
1778 X,
1779 Y,
1780 Z;
1781
1782 ConvertLMSToXYZ(L,M,S,&X,&Y,&Z);
1783 ConvertXYZToRGB(X,Y,Z,red,green,blue);
1784}
1785
1786static inline void ConvertLuvToRGB(const double L,const double u,
1787 const double v,const IlluminantType illuminant,double *red,double *green,
1788 double *blue)
1789{
1790 double
1791 X,
1792 Y,
1793 Z;
1794
1795 ConvertLuvToXYZ(100.0*L,354.0*u-134.0,262.0*v-140.0,illuminant,&X,&Y,&Z);
1796 ConvertXYZToRGB(X,Y,Z,red,green,blue);
1797}
1798
1799static inline ssize_t RoundToYCC(const double value)
1800{
1801 if (value <= 0.0)
1802 return(0);
1803 if (value >= 1388.0)
1804 return(1388);
1805 return((ssize_t) (value+0.5));
1806}
1807
1808static inline void ConvertLabToRGB(const double L,const double a,
1809 const double b,const IlluminantType illuminant,double *red,double *green,
1810 double *blue)
1811{
1812 double
1813 X,
1814 Y,
1815 Z;
1816
1817 ConvertLabToXYZ(100.0*L,255.0*(a-0.5),255.0*(b-0.5),illuminant,&X,&Y,&Z);
1818 ConvertXYZToRGB(X,Y,Z,red,green,blue);
1819}
1820
1821static inline void ConvertxyYToRGB(const double low_x,const double low_y,
1822 const double cap_Y,double *red,double *green,double *blue)
1823{
1824 double
1825 gamma,
1826 X,
1827 Y,
1828 Z;
1829
1830 gamma=PerceptibleReciprocal(low_y);
1831 X=gamma*cap_Y*low_x;
1832 Y=cap_Y;
1833 Z=gamma*cap_Y*(1.0-low_x-low_y);
1834 ConvertXYZToRGB(X,Y,Z,red,green,blue);
1835}
1836
1837static void ConvertYPbPrToRGB(const double Y,const double Pb,const double Pr,
1838 double *red,double *green,double *blue)
1839{
1840 *red=(double) QuantumRange*(0.99999999999914679361*Y-1.2188941887145875e-06*
1841 (Pb-0.5)+1.4019995886561440468*(Pr-0.5));
1842 *green=(double) QuantumRange*(0.99999975910502514331*Y-0.34413567816504303521*
1843 (Pb-0.5)-0.71413649331646789076*(Pr-0.5));
1844 *blue=(double) QuantumRange*(1.00000124040004623180*Y+1.77200006607230409200*
1845 (Pb-0.5)+2.1453384174593273e-06*(Pr-0.5));
1846}
1847
1848static void ConvertYCbCrToRGB(const double Y,const double Cb,
1849 const double Cr,double *red,double *green,double *blue)
1850{
1851 ConvertYPbPrToRGB(Y,Cb,Cr,red,green,blue);
1852}
1853
1854static void ConvertYIQToRGB(const double Y,const double I,const double Q,
1855 double *red,double *green,double *blue)
1856{
1857 *red=(double) QuantumRange*(Y+0.9562957197589482261*(I-0.5)+0.6210244164652610754*
1858 (Q-0.5));
1859 *green=(double) QuantumRange*(Y-0.2721220993185104464*(I-0.5)-0.6473805968256950427*
1860 (Q-0.5));
1861 *blue=(double) QuantumRange*(Y-1.1069890167364901945*(I-0.5)+1.7046149983646481374*
1862 (Q-0.5));
1863}
1864
1865static void ConvertYDbDrToRGB(const double Y,const double Db,const double Dr,
1866 double *red,double *green,double *blue)
1867{
1868 *red=(double) QuantumRange*(Y+9.2303716147657e-05*(Db-0.5)-
1869 0.52591263066186533*(Dr-0.5));
1870 *green=(double) QuantumRange*(Y-0.12913289889050927*(Db-0.5)+
1871 0.26789932820759876*(Dr-0.5));
1872 *blue=(double) QuantumRange*(Y+0.66467905997895482*(Db-0.5)-
1873 7.9202543533108e-05*(Dr-0.5));
1874}
1875
1876static void ConvertYUVToRGB(const double Y,const double U,const double V,
1877 double *red,double *green,double *blue)
1878{
1879 *red=(double) QuantumRange*(Y-3.945707070708279e-05*(U-0.5)+
1880 1.1398279671717170825*(V-0.5));
1881 *green=(double) QuantumRange*(Y-0.3946101641414141437*(U-0.5)-
1882 0.5805003156565656797*(V-0.5));
1883 *blue=(double) QuantumRange*(Y+2.0319996843434342537*(U-0.5)-
1884 4.813762626262513e-04*(V-0.5));
1885}
1886
1887static MagickBooleanType TransformsRGBImage(Image *image,
1888 ExceptionInfo *exception)
1889{
1890#define TransformsRGBImageTag "Transform/Image"
1891
1892 static const float
1893 YCCMap[1389] =
1894 {
1895 0.000000f, 0.000720f, 0.001441f, 0.002161f, 0.002882f, 0.003602f,
1896 0.004323f, 0.005043f, 0.005764f, 0.006484f, 0.007205f, 0.007925f,
1897 0.008646f, 0.009366f, 0.010086f, 0.010807f, 0.011527f, 0.012248f,
1898 0.012968f, 0.013689f, 0.014409f, 0.015130f, 0.015850f, 0.016571f,
1899 0.017291f, 0.018012f, 0.018732f, 0.019452f, 0.020173f, 0.020893f,
1900 0.021614f, 0.022334f, 0.023055f, 0.023775f, 0.024496f, 0.025216f,
1901 0.025937f, 0.026657f, 0.027378f, 0.028098f, 0.028818f, 0.029539f,
1902 0.030259f, 0.030980f, 0.031700f, 0.032421f, 0.033141f, 0.033862f,
1903 0.034582f, 0.035303f, 0.036023f, 0.036744f, 0.037464f, 0.038184f,
1904 0.038905f, 0.039625f, 0.040346f, 0.041066f, 0.041787f, 0.042507f,
1905 0.043228f, 0.043948f, 0.044669f, 0.045389f, 0.046110f, 0.046830f,
1906 0.047550f, 0.048271f, 0.048991f, 0.049712f, 0.050432f, 0.051153f,
1907 0.051873f, 0.052594f, 0.053314f, 0.054035f, 0.054755f, 0.055476f,
1908 0.056196f, 0.056916f, 0.057637f, 0.058357f, 0.059078f, 0.059798f,
1909 0.060519f, 0.061239f, 0.061960f, 0.062680f, 0.063401f, 0.064121f,
1910 0.064842f, 0.065562f, 0.066282f, 0.067003f, 0.067723f, 0.068444f,
1911 0.069164f, 0.069885f, 0.070605f, 0.071326f, 0.072046f, 0.072767f,
1912 0.073487f, 0.074207f, 0.074928f, 0.075648f, 0.076369f, 0.077089f,
1913 0.077810f, 0.078530f, 0.079251f, 0.079971f, 0.080692f, 0.081412f,
1914 0.082133f, 0.082853f, 0.083573f, 0.084294f, 0.085014f, 0.085735f,
1915 0.086455f, 0.087176f, 0.087896f, 0.088617f, 0.089337f, 0.090058f,
1916 0.090778f, 0.091499f, 0.092219f, 0.092939f, 0.093660f, 0.094380f,
1917 0.095101f, 0.095821f, 0.096542f, 0.097262f, 0.097983f, 0.098703f,
1918 0.099424f, 0.100144f, 0.100865f, 0.101585f, 0.102305f, 0.103026f,
1919 0.103746f, 0.104467f, 0.105187f, 0.105908f, 0.106628f, 0.107349f,
1920 0.108069f, 0.108790f, 0.109510f, 0.110231f, 0.110951f, 0.111671f,
1921 0.112392f, 0.113112f, 0.113833f, 0.114553f, 0.115274f, 0.115994f,
1922 0.116715f, 0.117435f, 0.118156f, 0.118876f, 0.119597f, 0.120317f,
1923 0.121037f, 0.121758f, 0.122478f, 0.123199f, 0.123919f, 0.124640f,
1924 0.125360f, 0.126081f, 0.126801f, 0.127522f, 0.128242f, 0.128963f,
1925 0.129683f, 0.130403f, 0.131124f, 0.131844f, 0.132565f, 0.133285f,
1926 0.134006f, 0.134726f, 0.135447f, 0.136167f, 0.136888f, 0.137608f,
1927 0.138329f, 0.139049f, 0.139769f, 0.140490f, 0.141210f, 0.141931f,
1928 0.142651f, 0.143372f, 0.144092f, 0.144813f, 0.145533f, 0.146254f,
1929 0.146974f, 0.147695f, 0.148415f, 0.149135f, 0.149856f, 0.150576f,
1930 0.151297f, 0.152017f, 0.152738f, 0.153458f, 0.154179f, 0.154899f,
1931 0.155620f, 0.156340f, 0.157061f, 0.157781f, 0.158501f, 0.159222f,
1932 0.159942f, 0.160663f, 0.161383f, 0.162104f, 0.162824f, 0.163545f,
1933 0.164265f, 0.164986f, 0.165706f, 0.166427f, 0.167147f, 0.167867f,
1934 0.168588f, 0.169308f, 0.170029f, 0.170749f, 0.171470f, 0.172190f,
1935 0.172911f, 0.173631f, 0.174352f, 0.175072f, 0.175793f, 0.176513f,
1936 0.177233f, 0.177954f, 0.178674f, 0.179395f, 0.180115f, 0.180836f,
1937 0.181556f, 0.182277f, 0.182997f, 0.183718f, 0.184438f, 0.185159f,
1938 0.185879f, 0.186599f, 0.187320f, 0.188040f, 0.188761f, 0.189481f,
1939 0.190202f, 0.190922f, 0.191643f, 0.192363f, 0.193084f, 0.193804f,
1940 0.194524f, 0.195245f, 0.195965f, 0.196686f, 0.197406f, 0.198127f,
1941 0.198847f, 0.199568f, 0.200288f, 0.201009f, 0.201729f, 0.202450f,
1942 0.203170f, 0.203890f, 0.204611f, 0.205331f, 0.206052f, 0.206772f,
1943 0.207493f, 0.208213f, 0.208934f, 0.209654f, 0.210375f, 0.211095f,
1944 0.211816f, 0.212536f, 0.213256f, 0.213977f, 0.214697f, 0.215418f,
1945 0.216138f, 0.216859f, 0.217579f, 0.218300f, 0.219020f, 0.219741f,
1946 0.220461f, 0.221182f, 0.221902f, 0.222622f, 0.223343f, 0.224063f,
1947 0.224784f, 0.225504f, 0.226225f, 0.226945f, 0.227666f, 0.228386f,
1948 0.229107f, 0.229827f, 0.230548f, 0.231268f, 0.231988f, 0.232709f,
1949 0.233429f, 0.234150f, 0.234870f, 0.235591f, 0.236311f, 0.237032f,
1950 0.237752f, 0.238473f, 0.239193f, 0.239914f, 0.240634f, 0.241354f,
1951 0.242075f, 0.242795f, 0.243516f, 0.244236f, 0.244957f, 0.245677f,
1952 0.246398f, 0.247118f, 0.247839f, 0.248559f, 0.249280f, 0.250000f,
1953 0.250720f, 0.251441f, 0.252161f, 0.252882f, 0.253602f, 0.254323f,
1954 0.255043f, 0.255764f, 0.256484f, 0.257205f, 0.257925f, 0.258646f,
1955 0.259366f, 0.260086f, 0.260807f, 0.261527f, 0.262248f, 0.262968f,
1956 0.263689f, 0.264409f, 0.265130f, 0.265850f, 0.266571f, 0.267291f,
1957 0.268012f, 0.268732f, 0.269452f, 0.270173f, 0.270893f, 0.271614f,
1958 0.272334f, 0.273055f, 0.273775f, 0.274496f, 0.275216f, 0.275937f,
1959 0.276657f, 0.277378f, 0.278098f, 0.278818f, 0.279539f, 0.280259f,
1960 0.280980f, 0.281700f, 0.282421f, 0.283141f, 0.283862f, 0.284582f,
1961 0.285303f, 0.286023f, 0.286744f, 0.287464f, 0.288184f, 0.288905f,
1962 0.289625f, 0.290346f, 0.291066f, 0.291787f, 0.292507f, 0.293228f,
1963 0.293948f, 0.294669f, 0.295389f, 0.296109f, 0.296830f, 0.297550f,
1964 0.298271f, 0.298991f, 0.299712f, 0.300432f, 0.301153f, 0.301873f,
1965 0.302594f, 0.303314f, 0.304035f, 0.304755f, 0.305476f, 0.306196f,
1966 0.306916f, 0.307637f, 0.308357f, 0.309078f, 0.309798f, 0.310519f,
1967 0.311239f, 0.311960f, 0.312680f, 0.313401f, 0.314121f, 0.314842f,
1968 0.315562f, 0.316282f, 0.317003f, 0.317723f, 0.318444f, 0.319164f,
1969 0.319885f, 0.320605f, 0.321326f, 0.322046f, 0.322767f, 0.323487f,
1970 0.324207f, 0.324928f, 0.325648f, 0.326369f, 0.327089f, 0.327810f,
1971 0.328530f, 0.329251f, 0.329971f, 0.330692f, 0.331412f, 0.332133f,
1972 0.332853f, 0.333573f, 0.334294f, 0.335014f, 0.335735f, 0.336455f,
1973 0.337176f, 0.337896f, 0.338617f, 0.339337f, 0.340058f, 0.340778f,
1974 0.341499f, 0.342219f, 0.342939f, 0.343660f, 0.344380f, 0.345101f,
1975 0.345821f, 0.346542f, 0.347262f, 0.347983f, 0.348703f, 0.349424f,
1976 0.350144f, 0.350865f, 0.351585f, 0.352305f, 0.353026f, 0.353746f,
1977 0.354467f, 0.355187f, 0.355908f, 0.356628f, 0.357349f, 0.358069f,
1978 0.358790f, 0.359510f, 0.360231f, 0.360951f, 0.361671f, 0.362392f,
1979 0.363112f, 0.363833f, 0.364553f, 0.365274f, 0.365994f, 0.366715f,
1980 0.367435f, 0.368156f, 0.368876f, 0.369597f, 0.370317f, 0.371037f,
1981 0.371758f, 0.372478f, 0.373199f, 0.373919f, 0.374640f, 0.375360f,
1982 0.376081f, 0.376801f, 0.377522f, 0.378242f, 0.378963f, 0.379683f,
1983 0.380403f, 0.381124f, 0.381844f, 0.382565f, 0.383285f, 0.384006f,
1984 0.384726f, 0.385447f, 0.386167f, 0.386888f, 0.387608f, 0.388329f,
1985 0.389049f, 0.389769f, 0.390490f, 0.391210f, 0.391931f, 0.392651f,
1986 0.393372f, 0.394092f, 0.394813f, 0.395533f, 0.396254f, 0.396974f,
1987 0.397695f, 0.398415f, 0.399135f, 0.399856f, 0.400576f, 0.401297f,
1988 0.402017f, 0.402738f, 0.403458f, 0.404179f, 0.404899f, 0.405620f,
1989 0.406340f, 0.407061f, 0.407781f, 0.408501f, 0.409222f, 0.409942f,
1990 0.410663f, 0.411383f, 0.412104f, 0.412824f, 0.413545f, 0.414265f,
1991 0.414986f, 0.415706f, 0.416427f, 0.417147f, 0.417867f, 0.418588f,
1992 0.419308f, 0.420029f, 0.420749f, 0.421470f, 0.422190f, 0.422911f,
1993 0.423631f, 0.424352f, 0.425072f, 0.425793f, 0.426513f, 0.427233f,
1994 0.427954f, 0.428674f, 0.429395f, 0.430115f, 0.430836f, 0.431556f,
1995 0.432277f, 0.432997f, 0.433718f, 0.434438f, 0.435158f, 0.435879f,
1996 0.436599f, 0.437320f, 0.438040f, 0.438761f, 0.439481f, 0.440202f,
1997 0.440922f, 0.441643f, 0.442363f, 0.443084f, 0.443804f, 0.444524f,
1998 0.445245f, 0.445965f, 0.446686f, 0.447406f, 0.448127f, 0.448847f,
1999 0.449568f, 0.450288f, 0.451009f, 0.451729f, 0.452450f, 0.453170f,
2000 0.453891f, 0.454611f, 0.455331f, 0.456052f, 0.456772f, 0.457493f,
2001 0.458213f, 0.458934f, 0.459654f, 0.460375f, 0.461095f, 0.461816f,
2002 0.462536f, 0.463256f, 0.463977f, 0.464697f, 0.465418f, 0.466138f,
2003 0.466859f, 0.467579f, 0.468300f, 0.469020f, 0.469741f, 0.470461f,
2004 0.471182f, 0.471902f, 0.472622f, 0.473343f, 0.474063f, 0.474784f,
2005 0.475504f, 0.476225f, 0.476945f, 0.477666f, 0.478386f, 0.479107f,
2006 0.479827f, 0.480548f, 0.481268f, 0.481988f, 0.482709f, 0.483429f,
2007 0.484150f, 0.484870f, 0.485591f, 0.486311f, 0.487032f, 0.487752f,
2008 0.488473f, 0.489193f, 0.489914f, 0.490634f, 0.491354f, 0.492075f,
2009 0.492795f, 0.493516f, 0.494236f, 0.494957f, 0.495677f, 0.496398f,
2010 0.497118f, 0.497839f, 0.498559f, 0.499280f, 0.500000f, 0.500720f,
2011 0.501441f, 0.502161f, 0.502882f, 0.503602f, 0.504323f, 0.505043f,
2012 0.505764f, 0.506484f, 0.507205f, 0.507925f, 0.508646f, 0.509366f,
2013 0.510086f, 0.510807f, 0.511527f, 0.512248f, 0.512968f, 0.513689f,
2014 0.514409f, 0.515130f, 0.515850f, 0.516571f, 0.517291f, 0.518012f,
2015 0.518732f, 0.519452f, 0.520173f, 0.520893f, 0.521614f, 0.522334f,
2016 0.523055f, 0.523775f, 0.524496f, 0.525216f, 0.525937f, 0.526657f,
2017 0.527378f, 0.528098f, 0.528818f, 0.529539f, 0.530259f, 0.530980f,
2018 0.531700f, 0.532421f, 0.533141f, 0.533862f, 0.534582f, 0.535303f,
2019 0.536023f, 0.536744f, 0.537464f, 0.538184f, 0.538905f, 0.539625f,
2020 0.540346f, 0.541066f, 0.541787f, 0.542507f, 0.543228f, 0.543948f,
2021 0.544669f, 0.545389f, 0.546109f, 0.546830f, 0.547550f, 0.548271f,
2022 0.548991f, 0.549712f, 0.550432f, 0.551153f, 0.551873f, 0.552594f,
2023 0.553314f, 0.554035f, 0.554755f, 0.555476f, 0.556196f, 0.556916f,
2024 0.557637f, 0.558357f, 0.559078f, 0.559798f, 0.560519f, 0.561239f,
2025 0.561960f, 0.562680f, 0.563401f, 0.564121f, 0.564842f, 0.565562f,
2026 0.566282f, 0.567003f, 0.567723f, 0.568444f, 0.569164f, 0.569885f,
2027 0.570605f, 0.571326f, 0.572046f, 0.572767f, 0.573487f, 0.574207f,
2028 0.574928f, 0.575648f, 0.576369f, 0.577089f, 0.577810f, 0.578530f,
2029 0.579251f, 0.579971f, 0.580692f, 0.581412f, 0.582133f, 0.582853f,
2030 0.583573f, 0.584294f, 0.585014f, 0.585735f, 0.586455f, 0.587176f,
2031 0.587896f, 0.588617f, 0.589337f, 0.590058f, 0.590778f, 0.591499f,
2032 0.592219f, 0.592939f, 0.593660f, 0.594380f, 0.595101f, 0.595821f,
2033 0.596542f, 0.597262f, 0.597983f, 0.598703f, 0.599424f, 0.600144f,
2034 0.600865f, 0.601585f, 0.602305f, 0.603026f, 0.603746f, 0.604467f,
2035 0.605187f, 0.605908f, 0.606628f, 0.607349f, 0.608069f, 0.608790f,
2036 0.609510f, 0.610231f, 0.610951f, 0.611671f, 0.612392f, 0.613112f,
2037 0.613833f, 0.614553f, 0.615274f, 0.615994f, 0.616715f, 0.617435f,
2038 0.618156f, 0.618876f, 0.619597f, 0.620317f, 0.621037f, 0.621758f,
2039 0.622478f, 0.623199f, 0.623919f, 0.624640f, 0.625360f, 0.626081f,
2040 0.626801f, 0.627522f, 0.628242f, 0.628963f, 0.629683f, 0.630403f,
2041 0.631124f, 0.631844f, 0.632565f, 0.633285f, 0.634006f, 0.634726f,
2042 0.635447f, 0.636167f, 0.636888f, 0.637608f, 0.638329f, 0.639049f,
2043 0.639769f, 0.640490f, 0.641210f, 0.641931f, 0.642651f, 0.643372f,
2044 0.644092f, 0.644813f, 0.645533f, 0.646254f, 0.646974f, 0.647695f,
2045 0.648415f, 0.649135f, 0.649856f, 0.650576f, 0.651297f, 0.652017f,
2046 0.652738f, 0.653458f, 0.654179f, 0.654899f, 0.655620f, 0.656340f,
2047 0.657061f, 0.657781f, 0.658501f, 0.659222f, 0.659942f, 0.660663f,
2048 0.661383f, 0.662104f, 0.662824f, 0.663545f, 0.664265f, 0.664986f,
2049 0.665706f, 0.666427f, 0.667147f, 0.667867f, 0.668588f, 0.669308f,
2050 0.670029f, 0.670749f, 0.671470f, 0.672190f, 0.672911f, 0.673631f,
2051 0.674352f, 0.675072f, 0.675793f, 0.676513f, 0.677233f, 0.677954f,
2052 0.678674f, 0.679395f, 0.680115f, 0.680836f, 0.681556f, 0.682277f,
2053 0.682997f, 0.683718f, 0.684438f, 0.685158f, 0.685879f, 0.686599f,
2054 0.687320f, 0.688040f, 0.688761f, 0.689481f, 0.690202f, 0.690922f,
2055 0.691643f, 0.692363f, 0.693084f, 0.693804f, 0.694524f, 0.695245f,
2056 0.695965f, 0.696686f, 0.697406f, 0.698127f, 0.698847f, 0.699568f,
2057 0.700288f, 0.701009f, 0.701729f, 0.702450f, 0.703170f, 0.703891f,
2058 0.704611f, 0.705331f, 0.706052f, 0.706772f, 0.707493f, 0.708213f,
2059 0.708934f, 0.709654f, 0.710375f, 0.711095f, 0.711816f, 0.712536f,
2060 0.713256f, 0.713977f, 0.714697f, 0.715418f, 0.716138f, 0.716859f,
2061 0.717579f, 0.718300f, 0.719020f, 0.719741f, 0.720461f, 0.721182f,
2062 0.721902f, 0.722622f, 0.723343f, 0.724063f, 0.724784f, 0.725504f,
2063 0.726225f, 0.726945f, 0.727666f, 0.728386f, 0.729107f, 0.729827f,
2064 0.730548f, 0.731268f, 0.731988f, 0.732709f, 0.733429f, 0.734150f,
2065 0.734870f, 0.735591f, 0.736311f, 0.737032f, 0.737752f, 0.738473f,
2066 0.739193f, 0.739914f, 0.740634f, 0.741354f, 0.742075f, 0.742795f,
2067 0.743516f, 0.744236f, 0.744957f, 0.745677f, 0.746398f, 0.747118f,
2068 0.747839f, 0.748559f, 0.749280f, 0.750000f, 0.750720f, 0.751441f,
2069 0.752161f, 0.752882f, 0.753602f, 0.754323f, 0.755043f, 0.755764f,
2070 0.756484f, 0.757205f, 0.757925f, 0.758646f, 0.759366f, 0.760086f,
2071 0.760807f, 0.761527f, 0.762248f, 0.762968f, 0.763689f, 0.764409f,
2072 0.765130f, 0.765850f, 0.766571f, 0.767291f, 0.768012f, 0.768732f,
2073 0.769452f, 0.770173f, 0.770893f, 0.771614f, 0.772334f, 0.773055f,
2074 0.773775f, 0.774496f, 0.775216f, 0.775937f, 0.776657f, 0.777378f,
2075 0.778098f, 0.778818f, 0.779539f, 0.780259f, 0.780980f, 0.781700f,
2076 0.782421f, 0.783141f, 0.783862f, 0.784582f, 0.785303f, 0.786023f,
2077 0.786744f, 0.787464f, 0.788184f, 0.788905f, 0.789625f, 0.790346f,
2078 0.791066f, 0.791787f, 0.792507f, 0.793228f, 0.793948f, 0.794669f,
2079 0.795389f, 0.796109f, 0.796830f, 0.797550f, 0.798271f, 0.798991f,
2080 0.799712f, 0.800432f, 0.801153f, 0.801873f, 0.802594f, 0.803314f,
2081 0.804035f, 0.804755f, 0.805476f, 0.806196f, 0.806916f, 0.807637f,
2082 0.808357f, 0.809078f, 0.809798f, 0.810519f, 0.811239f, 0.811960f,
2083 0.812680f, 0.813401f, 0.814121f, 0.814842f, 0.815562f, 0.816282f,
2084 0.817003f, 0.817723f, 0.818444f, 0.819164f, 0.819885f, 0.820605f,
2085 0.821326f, 0.822046f, 0.822767f, 0.823487f, 0.824207f, 0.824928f,
2086 0.825648f, 0.826369f, 0.827089f, 0.827810f, 0.828530f, 0.829251f,
2087 0.829971f, 0.830692f, 0.831412f, 0.832133f, 0.832853f, 0.833573f,
2088 0.834294f, 0.835014f, 0.835735f, 0.836455f, 0.837176f, 0.837896f,
2089 0.838617f, 0.839337f, 0.840058f, 0.840778f, 0.841499f, 0.842219f,
2090 0.842939f, 0.843660f, 0.844380f, 0.845101f, 0.845821f, 0.846542f,
2091 0.847262f, 0.847983f, 0.848703f, 0.849424f, 0.850144f, 0.850865f,
2092 0.851585f, 0.852305f, 0.853026f, 0.853746f, 0.854467f, 0.855187f,
2093 0.855908f, 0.856628f, 0.857349f, 0.858069f, 0.858790f, 0.859510f,
2094 0.860231f, 0.860951f, 0.861671f, 0.862392f, 0.863112f, 0.863833f,
2095 0.864553f, 0.865274f, 0.865994f, 0.866715f, 0.867435f, 0.868156f,
2096 0.868876f, 0.869597f, 0.870317f, 0.871037f, 0.871758f, 0.872478f,
2097 0.873199f, 0.873919f, 0.874640f, 0.875360f, 0.876081f, 0.876801f,
2098 0.877522f, 0.878242f, 0.878963f, 0.879683f, 0.880403f, 0.881124f,
2099 0.881844f, 0.882565f, 0.883285f, 0.884006f, 0.884726f, 0.885447f,
2100 0.886167f, 0.886888f, 0.887608f, 0.888329f, 0.889049f, 0.889769f,
2101 0.890490f, 0.891210f, 0.891931f, 0.892651f, 0.893372f, 0.894092f,
2102 0.894813f, 0.895533f, 0.896254f, 0.896974f, 0.897695f, 0.898415f,
2103 0.899135f, 0.899856f, 0.900576f, 0.901297f, 0.902017f, 0.902738f,
2104 0.903458f, 0.904179f, 0.904899f, 0.905620f, 0.906340f, 0.907061f,
2105 0.907781f, 0.908501f, 0.909222f, 0.909942f, 0.910663f, 0.911383f,
2106 0.912104f, 0.912824f, 0.913545f, 0.914265f, 0.914986f, 0.915706f,
2107 0.916427f, 0.917147f, 0.917867f, 0.918588f, 0.919308f, 0.920029f,
2108 0.920749f, 0.921470f, 0.922190f, 0.922911f, 0.923631f, 0.924352f,
2109 0.925072f, 0.925793f, 0.926513f, 0.927233f, 0.927954f, 0.928674f,
2110 0.929395f, 0.930115f, 0.930836f, 0.931556f, 0.932277f, 0.932997f,
2111 0.933718f, 0.934438f, 0.935158f, 0.935879f, 0.936599f, 0.937320f,
2112 0.938040f, 0.938761f, 0.939481f, 0.940202f, 0.940922f, 0.941643f,
2113 0.942363f, 0.943084f, 0.943804f, 0.944524f, 0.945245f, 0.945965f,
2114 0.946686f, 0.947406f, 0.948127f, 0.948847f, 0.949568f, 0.950288f,
2115 0.951009f, 0.951729f, 0.952450f, 0.953170f, 0.953891f, 0.954611f,
2116 0.955331f, 0.956052f, 0.956772f, 0.957493f, 0.958213f, 0.958934f,
2117 0.959654f, 0.960375f, 0.961095f, 0.961816f, 0.962536f, 0.963256f,
2118 0.963977f, 0.964697f, 0.965418f, 0.966138f, 0.966859f, 0.967579f,
2119 0.968300f, 0.969020f, 0.969741f, 0.970461f, 0.971182f, 0.971902f,
2120 0.972622f, 0.973343f, 0.974063f, 0.974784f, 0.975504f, 0.976225f,
2121 0.976945f, 0.977666f, 0.978386f, 0.979107f, 0.979827f, 0.980548f,
2122 0.981268f, 0.981988f, 0.982709f, 0.983429f, 0.984150f, 0.984870f,
2123 0.985591f, 0.986311f, 0.987032f, 0.987752f, 0.988473f, 0.989193f,
2124 0.989914f, 0.990634f, 0.991354f, 0.992075f, 0.992795f, 0.993516f,
2125 0.994236f, 0.994957f, 0.995677f, 0.996398f, 0.997118f, 0.997839f,
2126 0.998559f, 0.999280f, 1.000000f
2127 };
2128
2129 CacheView
2130 *image_view;
2131
2132 const char
2133 *artifact;
2134
2135 IlluminantType
2136 illuminant = D65Illuminant;
2137
2138 MagickBooleanType
2139 status;
2140
2141 MagickOffsetType
2142 progress;
2143
2144 ssize_t
2145 i,
2146 y;
2147
2149 *y_map,
2150 *x_map,
2151 *z_map;
2152
2153 assert(image != (Image *) NULL);
2154 assert(image->signature == MagickCoreSignature);
2155 if (IsEventLogging() != MagickFalse)
2156 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2157 artifact=GetImageArtifact(image,"color:illuminant");
2158 if (artifact != (const char *) NULL)
2159 {
2160 ssize_t
2161 illuminant_type;
2162
2163 illuminant_type=ParseCommandOption(MagickIlluminantOptions,MagickFalse,
2164 artifact);
2165 if (illuminant_type < 0)
2166 illuminant=UndefinedIlluminant;
2167 else
2168 illuminant=(IlluminantType) illuminant_type;
2169 }
2170 status=MagickTrue;
2171 progress=0;
2172 switch (image->colorspace)
2173 {
2174 case CMYKColorspace:
2175 {
2176 PixelInfo
2177 zero;
2178
2179 /*
2180 Transform image from CMYK to sRGB.
2181 */
2182 if (image->storage_class == PseudoClass)
2183 {
2184 if (SyncImage(image,exception) == MagickFalse)
2185 return(MagickFalse);
2186 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2187 return(MagickFalse);
2188 }
2189 GetPixelInfo(image,&zero);
2190 image_view=AcquireAuthenticCacheView(image,exception);
2191#if defined(MAGICKCORE_OPENMP_SUPPORT)
2192 #pragma omp parallel for schedule(static) shared(status) \
2193 magick_number_threads(image,image,image->rows,2)
2194#endif
2195 for (y=0; y < (ssize_t) image->rows; y++)
2196 {
2197 MagickBooleanType
2198 sync;
2199
2200 PixelInfo
2201 pixel;
2202
2203 ssize_t
2204 x;
2205
2206 Quantum
2207 *magick_restrict q;
2208
2209 if (status == MagickFalse)
2210 continue;
2211 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2212 exception);
2213 if (q == (Quantum *) NULL)
2214 {
2215 status=MagickFalse;
2216 continue;
2217 }
2218 pixel=zero;
2219 for (x=0; x < (ssize_t) image->columns; x++)
2220 {
2221 GetPixelInfoPixel(image,q,&pixel);
2222 ConvertCMYKToRGB(&pixel);
2223 SetPixelViaPixelInfo(image,&pixel,q);
2224 q+=GetPixelChannels(image);
2225 }
2226 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2227 if (sync == MagickFalse)
2228 status=MagickFalse;
2229 }
2230 image_view=DestroyCacheView(image_view);
2231 if (SetImageColorspace(image,sRGBColorspace,exception) == MagickFalse)
2232 return(MagickFalse);
2233 return(status);
2234 }
2235 case LinearGRAYColorspace:
2236 {
2237 /*
2238 Transform linear GRAY to sRGB colorspace.
2239 */
2240 if (image->storage_class == PseudoClass)
2241 {
2242 if (SyncImage(image,exception) == MagickFalse)
2243 return(MagickFalse);
2244 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2245 return(MagickFalse);
2246 }
2247 if (SetImageColorspace(image,sRGBColorspace,exception) == MagickFalse)
2248 return(MagickFalse);
2249 image_view=AcquireAuthenticCacheView(image,exception);
2250#if defined(MAGICKCORE_OPENMP_SUPPORT)
2251 #pragma omp parallel for schedule(static) shared(status) \
2252 magick_number_threads(image,image,image->rows,2)
2253#endif
2254 for (y=0; y < (ssize_t) image->rows; y++)
2255 {
2256 MagickBooleanType
2257 sync;
2258
2259 ssize_t
2260 x;
2261
2262 Quantum
2263 *magick_restrict q;
2264
2265 if (status == MagickFalse)
2266 continue;
2267 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2268 exception);
2269 if (q == (Quantum *) NULL)
2270 {
2271 status=MagickFalse;
2272 continue;
2273 }
2274 for (x=(ssize_t) image->columns; x != 0; x--)
2275 {
2276 MagickRealType
2277 gray;
2278
2279 gray=0.212656*EncodePixelGamma(GetPixelRed(image,q))+0.715158*
2280 EncodePixelGamma(GetPixelGreen(image,q))+0.072186*
2281 EncodePixelGamma(GetPixelBlue(image,q));
2282 SetPixelRed(image,ClampToQuantum(gray),q);
2283 SetPixelGreen(image,ClampToQuantum(gray),q);
2284 SetPixelBlue(image,ClampToQuantum(gray),q);
2285 q+=GetPixelChannels(image);
2286 }
2287 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2288 if (sync == MagickFalse)
2289 status=MagickFalse;
2290 }
2291 image_view=DestroyCacheView(image_view);
2292 if (SetImageColorspace(image,sRGBColorspace,exception) == MagickFalse)
2293 return(MagickFalse);
2294 return(status);
2295 }
2296 case GRAYColorspace:
2297 {
2298 /*
2299 Transform linear GRAY to sRGB colorspace.
2300 */
2301 if (image->storage_class == PseudoClass)
2302 {
2303 if (SyncImage(image,exception) == MagickFalse)
2304 return(MagickFalse);
2305 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2306 return(MagickFalse);
2307 }
2308 if (SetImageColorspace(image,sRGBColorspace,exception) == MagickFalse)
2309 return(MagickFalse);
2310 image_view=AcquireAuthenticCacheView(image,exception);
2311#if defined(MAGICKCORE_OPENMP_SUPPORT)
2312 #pragma omp parallel for schedule(static) shared(status) \
2313 magick_number_threads(image,image,image->rows,2)
2314#endif
2315 for (y=0; y < (ssize_t) image->rows; y++)
2316 {
2317 MagickBooleanType
2318 sync;
2319
2320 ssize_t
2321 x;
2322
2323 Quantum
2324 *magick_restrict q;
2325
2326 if (status == MagickFalse)
2327 continue;
2328 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2329 exception);
2330 if (q == (Quantum *) NULL)
2331 {
2332 status=MagickFalse;
2333 continue;
2334 }
2335 for (x=(ssize_t) image->columns; x != 0; x--)
2336 {
2337 MagickRealType
2338 gray;
2339
2340 gray=0.212656*(double) GetPixelRed(image,q)+0.715158*(double)
2341 GetPixelGreen(image,q)+0.072186*(double) GetPixelBlue(image,q);
2342 SetPixelRed(image,ClampToQuantum(gray),q);
2343 SetPixelGreen(image,ClampToQuantum(gray),q);
2344 SetPixelBlue(image,ClampToQuantum(gray),q);
2345 q+=GetPixelChannels(image);
2346 }
2347 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2348 if (sync == MagickFalse)
2349 status=MagickFalse;
2350 }
2351 image_view=DestroyCacheView(image_view);
2352 if (SetImageColorspace(image,sRGBColorspace,exception) == MagickFalse)
2353 return(MagickFalse);
2354 return(status);
2355 }
2356 case Adobe98Colorspace:
2357 case CMYColorspace:
2358 case DisplayP3Colorspace:
2359 case HCLColorspace:
2360 case HCLpColorspace:
2361 case HSBColorspace:
2362 case HSIColorspace:
2363 case HSLColorspace:
2364 case HSVColorspace:
2365 case HWBColorspace:
2366 case JzazbzColorspace:
2367 case LabColorspace:
2368 case LCHColorspace:
2369 case LCHabColorspace:
2370 case LCHuvColorspace:
2371 case LMSColorspace:
2372 case LuvColorspace:
2373 case OklabColorspace:
2374 case OklchColorspace:
2375 case ProPhotoColorspace:
2376 case xyYColorspace:
2377 case XYZColorspace:
2378 case YCbCrColorspace:
2379 case YDbDrColorspace:
2380 case YIQColorspace:
2381 case YPbPrColorspace:
2382 case YUVColorspace:
2383 {
2384 const char
2385 *value;
2386
2387 double
2388 white_luminance;
2389
2390 /*
2391 Transform image from source colorspace to sRGB.
2392 */
2393 white_luminance=10000.0;
2394 value=GetImageProperty(image,"white-luminance",exception);
2395 if (value != (const char *) NULL)
2396 white_luminance=StringToDouble(value,(char **) NULL);
2397 if (image->storage_class == PseudoClass)
2398 {
2399 if (SyncImage(image,exception) == MagickFalse)
2400 return(MagickFalse);
2401 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2402 return(MagickFalse);
2403 }
2404 image_view=AcquireAuthenticCacheView(image,exception);
2405#if defined(MAGICKCORE_OPENMP_SUPPORT)
2406 #pragma omp parallel for schedule(static) shared(status) \
2407 magick_number_threads(image,image,image->rows,2)
2408#endif
2409 for (y=0; y < (ssize_t) image->rows; y++)
2410 {
2411 MagickBooleanType
2412 sync;
2413
2414 ssize_t
2415 x;
2416
2417 Quantum
2418 *magick_restrict q;
2419
2420 if (status == MagickFalse)
2421 continue;
2422 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2423 exception);
2424 if (q == (Quantum *) NULL)
2425 {
2426 status=MagickFalse;
2427 continue;
2428 }
2429 for (x=0; x < (ssize_t) image->columns; x++)
2430 {
2431 double
2432 blue,
2433 green,
2434 red,
2435 X,
2436 Y,
2437 Z;
2438
2439 X=QuantumScale*(double) GetPixelRed(image,q);
2440 Y=QuantumScale*(double) GetPixelGreen(image,q);
2441 Z=QuantumScale*(double) GetPixelBlue(image,q);
2442 switch (image->colorspace)
2443 {
2444 case Adobe98Colorspace:
2445 {
2446 ConvertAdobe98ToRGB(X,Y,Z,&red,&green,&blue);
2447 break;
2448 }
2449 case CMYColorspace:
2450 {
2451 ConvertCMYToRGB(X,Y,Z,&red,&green,&blue);
2452 break;
2453 }
2454 case DisplayP3Colorspace:
2455 {
2456 ConvertDisplayP3ToRGB(X,Y,Z,&red,&green,&blue);
2457 break;
2458 }
2459 case HCLColorspace:
2460 {
2461 ConvertHCLToRGB(X,Y,Z,&red,&green,&blue);
2462 break;
2463 }
2464 case HCLpColorspace:
2465 {
2466 ConvertHCLpToRGB(X,Y,Z,&red,&green,&blue);
2467 break;
2468 }
2469 case HSBColorspace:
2470 {
2471 ConvertHSBToRGB(X,Y,Z,&red,&green,&blue);
2472 break;
2473 }
2474 case HSIColorspace:
2475 {
2476 ConvertHSIToRGB(X,Y,Z,&red,&green,&blue);
2477 break;
2478 }
2479 case HSLColorspace:
2480 {
2481 ConvertHSLToRGB(X,Y,Z,&red,&green,&blue);
2482 break;
2483 }
2484 case HSVColorspace:
2485 {
2486 ConvertHSVToRGB(X,Y,Z,&red,&green,&blue);
2487 break;
2488 }
2489 case HWBColorspace:
2490 {
2491 ConvertHWBToRGB(X,Y,Z,&red,&green,&blue);
2492 break;
2493 }
2494 case JzazbzColorspace:
2495 {
2496 ConvertJzazbzToRGB(X,Y,Z,white_luminance,&red,&green,&blue);
2497 break;
2498 }
2499 case LabColorspace:
2500 {
2501 ConvertLabToRGB(X,Y,Z,illuminant,&red,&green,&blue);
2502 break;
2503 }
2504 case LCHColorspace:
2505 case LCHabColorspace:
2506 {
2507 ConvertLCHabToRGB(X,Y,Z,illuminant,&red,&green,&blue);
2508 break;
2509 }
2510 case LCHuvColorspace:
2511 {
2512 ConvertLCHuvToRGB(X,Y,Z,illuminant,&red,&green,&blue);
2513 break;
2514 }
2515 case LMSColorspace:
2516 {
2517 ConvertLMSToRGB(X,Y,Z,&red,&green,&blue);
2518 break;
2519 }
2520 case LuvColorspace:
2521 {
2522 ConvertLuvToRGB(X,Y,Z,illuminant,&red,&green,&blue);
2523 break;
2524 }
2525 case OklabColorspace:
2526 {
2527 ConvertOklabToRGB(X,Y,Z,&red,&green,&blue);
2528 break;
2529 }
2530 case OklchColorspace:
2531 {
2532 ConvertOklchToRGB(X,Y,Z,&red,&green,&blue);
2533 break;
2534 }
2535 case ProPhotoColorspace:
2536 {
2537 ConvertProPhotoToRGB(X,Y,Z,&red,&green,&blue);
2538 break;
2539 }
2540 case xyYColorspace:
2541 {
2542 ConvertxyYToRGB(X,Y,Z,&red,&green,&blue);
2543 break;
2544 }
2545 case XYZColorspace:
2546 {
2547 ConvertXYZToRGB(X,Y,Z,&red,&green,&blue);
2548 break;
2549 }
2550 case YCbCrColorspace:
2551 {
2552 ConvertYCbCrToRGB(X,Y,Z,&red,&green,&blue);
2553 break;
2554 }
2555 case YDbDrColorspace:
2556 {
2557 ConvertYDbDrToRGB(X,Y,Z,&red,&green,&blue);
2558 break;
2559 }
2560 case YIQColorspace:
2561 {
2562 ConvertYIQToRGB(X,Y,Z,&red,&green,&blue);
2563 break;
2564 }
2565 case YPbPrColorspace:
2566 {
2567 ConvertYPbPrToRGB(X,Y,Z,&red,&green,&blue);
2568 break;
2569 }
2570 case YUVColorspace:
2571 {
2572 ConvertYUVToRGB(X,Y,Z,&red,&green,&blue);
2573 break;
2574 }
2575 default:
2576 {
2577 red=(double) QuantumRange*X;
2578 green=(double) QuantumRange*Y;
2579 blue=(double) QuantumRange*Z;
2580 break;
2581 }
2582 }
2583 SetPixelRed(image,ClampToQuantum(red),q);
2584 SetPixelGreen(image,ClampToQuantum(green),q);
2585 SetPixelBlue(image,ClampToQuantum(blue),q);
2586 q+=GetPixelChannels(image);
2587 }
2588 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2589 if (sync == MagickFalse)
2590 status=MagickFalse;
2591 }
2592 image_view=DestroyCacheView(image_view);
2593 if (SetImageColorspace(image,sRGBColorspace,exception) == MagickFalse)
2594 return(MagickFalse);
2595 return(status);
2596 }
2597 case LogColorspace:
2598 {
2599 const char
2600 *value;
2601
2602 double
2603 black,
2604 density,
2605 film_gamma,
2606 gamma,
2607 reference_black,
2608 reference_white;
2609
2610 Quantum
2611 *logmap;
2612
2613 /*
2614 Transform Log to sRGB colorspace.
2615 */
2616 density=DisplayGamma;
2617 gamma=DisplayGamma;
2618 value=GetImageProperty(image,"gamma",exception);
2619 if (value != (const char *) NULL)
2620 gamma=PerceptibleReciprocal(StringToDouble(value,(char **) NULL));
2621 film_gamma=FilmGamma;
2622 value=GetImageProperty(image,"film-gamma",exception);
2623 if (value != (const char *) NULL)
2624 film_gamma=StringToDouble(value,(char **) NULL);
2625 reference_black=ReferenceBlack;
2626 value=GetImageProperty(image,"reference-black",exception);
2627 if (value != (const char *) NULL)
2628 reference_black=StringToDouble(value,(char **) NULL);
2629 reference_white=ReferenceWhite;
2630 value=GetImageProperty(image,"reference-white",exception);
2631 if (value != (const char *) NULL)
2632 reference_white=StringToDouble(value,(char **) NULL);
2633 logmap=(Quantum *) AcquireQuantumMemory((size_t) MaxMap+1UL,
2634 sizeof(*logmap));
2635 if (logmap == (Quantum *) NULL)
2636 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2637 image->filename);
2638 black=pow(10.0,(reference_black-reference_white)*(gamma/density)*0.002*
2639 PerceptibleReciprocal(film_gamma));
2640 for (i=0; i <= (ssize_t) (reference_black*MaxMap/1024.0); i++)
2641 logmap[i]=(Quantum) 0;
2642 for ( ; i < (ssize_t) (reference_white*MaxMap/1024.0); i++)
2643 logmap[i]=ClampToQuantum((double) QuantumRange/(1.0-black)*
2644 (pow(10.0,(1024.0*i/MaxMap-reference_white)*(gamma/density)*0.002*
2645 PerceptibleReciprocal(film_gamma))-black));
2646 for ( ; i <= (ssize_t) MaxMap; i++)
2647 logmap[i]=(double) QuantumRange;
2648 if (image->storage_class == PseudoClass)
2649 {
2650 if (SyncImage(image,exception) == MagickFalse)
2651 return(MagickFalse);
2652 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2653 return(MagickFalse);
2654 }
2655 image_view=AcquireAuthenticCacheView(image,exception);
2656#if defined(MAGICKCORE_OPENMP_SUPPORT)
2657 #pragma omp parallel for schedule(static) shared(status) \
2658 magick_number_threads(image,image,image->rows,2)
2659#endif
2660 for (y=0; y < (ssize_t) image->rows; y++)
2661 {
2662 MagickBooleanType
2663 sync;
2664
2665 ssize_t
2666 x;
2667
2668 Quantum
2669 *magick_restrict q;
2670
2671 if (status == MagickFalse)
2672 continue;
2673 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2674 exception);
2675 if (q == (Quantum *) NULL)
2676 {
2677 status=MagickFalse;
2678 continue;
2679 }
2680 for (x=(ssize_t) image->columns; x != 0; x--)
2681 {
2682 double
2683 blue,
2684 green,
2685 red;
2686
2687 red=(double) logmap[ScaleQuantumToMap(GetPixelRed(image,q))];
2688 green=(double) logmap[ScaleQuantumToMap(GetPixelGreen(image,q))];
2689 blue=(double) logmap[ScaleQuantumToMap(GetPixelBlue(image,q))];
2690 SetPixelRed(image,ClampToQuantum(EncodePixelGamma((MagickRealType)
2691 red)),q);
2692 SetPixelGreen(image,ClampToQuantum(EncodePixelGamma((MagickRealType)
2693 green)),q);
2694 SetPixelBlue(image,ClampToQuantum(EncodePixelGamma((MagickRealType)
2695 blue)),q);
2696 q+=GetPixelChannels(image);
2697 }
2698 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2699 if (sync == MagickFalse)
2700 status=MagickFalse;
2701 }
2702 image_view=DestroyCacheView(image_view);
2703 logmap=(Quantum *) RelinquishMagickMemory(logmap);
2704 if (SetImageColorspace(image,sRGBColorspace,exception) == MagickFalse)
2705 return(MagickFalse);
2706 return(status);
2707 }
2708 case RGBColorspace:
2709 case scRGBColorspace:
2710 {
2711 /*
2712 Transform linear RGB to sRGB colorspace.
2713 */
2714 if (image->storage_class == PseudoClass)
2715 {
2716 if (SyncImage(image,exception) == MagickFalse)
2717 return(MagickFalse);
2718 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2719 return(MagickFalse);
2720 }
2721 image_view=AcquireAuthenticCacheView(image,exception);
2722#if defined(MAGICKCORE_OPENMP_SUPPORT)
2723 #pragma omp parallel for schedule(static) shared(status) \
2724 magick_number_threads(image,image,image->rows,2)
2725#endif
2726 for (y=0; y < (ssize_t) image->rows; y++)
2727 {
2728 MagickBooleanType
2729 sync;
2730
2731 ssize_t
2732 x;
2733
2734 Quantum
2735 *magick_restrict q;
2736
2737 if (status == MagickFalse)
2738 continue;
2739 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2740 exception);
2741 if (q == (Quantum *) NULL)
2742 {
2743 status=MagickFalse;
2744 continue;
2745 }
2746 for (x=(ssize_t) image->columns; x != 0; x--)
2747 {
2748 double
2749 blue,
2750 green,
2751 red;
2752
2753 red=EncodePixelGamma((MagickRealType) GetPixelRed(image,q));
2754 green=EncodePixelGamma((MagickRealType) GetPixelGreen(image,q));
2755 blue=EncodePixelGamma((MagickRealType) GetPixelBlue(image,q));
2756 SetPixelRed(image,ClampToQuantum(red),q);
2757 SetPixelGreen(image,ClampToQuantum(green),q);
2758 SetPixelBlue(image,ClampToQuantum(blue),q);
2759 q+=GetPixelChannels(image);
2760 }
2761 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2762 if (sync == MagickFalse)
2763 status=MagickFalse;
2764 }
2765 image_view=DestroyCacheView(image_view);
2766 if (SetImageColorspace(image,sRGBColorspace,exception) == MagickFalse)
2767 return(MagickFalse);
2768 return(status);
2769 }
2770 default:
2771 break;
2772 }
2773 /*
2774 Allocate the tables.
2775 */
2776 x_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
2777 sizeof(*x_map));
2778 y_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
2779 sizeof(*y_map));
2780 z_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
2781 sizeof(*z_map));
2782 if ((x_map == (TransformPacket *) NULL) ||
2783 (y_map == (TransformPacket *) NULL) ||
2784 (z_map == (TransformPacket *) NULL))
2785 {
2786 if (z_map != (TransformPacket *) NULL)
2787 z_map=(TransformPacket *) RelinquishMagickMemory(z_map);
2788 if (y_map != (TransformPacket *) NULL)
2789 y_map=(TransformPacket *) RelinquishMagickMemory(y_map);
2790 if (x_map != (TransformPacket *) NULL)
2791 x_map=(TransformPacket *) RelinquishMagickMemory(x_map);
2792 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2793 image->filename);
2794 }
2795 switch (image->colorspace)
2796 {
2797 case OHTAColorspace:
2798 {
2799 /*
2800 Initialize OHTA tables:
2801
2802 I1 = 0.33333*R+0.33334*G+0.33333*B
2803 I2 = 0.50000*R+0.00000*G-0.50000*B
2804 I3 =-0.25000*R+0.50000*G-0.25000*B
2805 R = I1+1.00000*I2-0.66668*I3
2806 G = I1+0.00000*I2+1.33333*I3
2807 B = I1-1.00000*I2-0.66668*I3
2808
2809 I and Q, normally -0.5 through 0.5, must be normalized to the range 0
2810 through QuantumRange.
2811 */
2812#if defined(MAGICKCORE_OPENMP_SUPPORT)
2813 #pragma omp parallel for schedule(static)
2814#endif
2815 for (i=0; i <= (ssize_t) MaxMap; i++)
2816 {
2817 x_map[i].x=(MagickRealType) (1.0*(double) i);
2818 y_map[i].x=(MagickRealType) (0.5*1.00000*(2.0*(double) i-MaxMap));
2819 z_map[i].x=(MagickRealType) (-0.5*0.66668*(2.0*(double) i-MaxMap));
2820 x_map[i].y=(MagickRealType) (1.0*(double) i);
2821 y_map[i].y=(MagickRealType) (0.5*0.00000*(2.0*(double) i-MaxMap));
2822 z_map[i].y=(MagickRealType) (0.5*1.33333*(2.0*(double) i-MaxMap));
2823 x_map[i].z=(MagickRealType) (1.0*(double) i);
2824 y_map[i].z=(MagickRealType) (-0.5*1.00000*(2.0*(double) i-MaxMap));
2825 z_map[i].z=(MagickRealType) (-0.5*0.66668*(2.0*(double) i-MaxMap));
2826 }
2827 break;
2828 }
2829 case Rec601YCbCrColorspace:
2830 {
2831 /*
2832 Initialize YCbCr tables:
2833
2834 R = Y +1.402000*Cr
2835 G = Y-0.344136*Cb-0.714136*Cr
2836 B = Y+1.772000*Cb
2837
2838 Cb and Cr, normally -0.5 through 0.5, must be normalized to the range 0
2839 through QuantumRange.
2840 */
2841#if defined(MAGICKCORE_OPENMP_SUPPORT)
2842 #pragma omp parallel for schedule(static)
2843#endif
2844 for (i=0; i <= (ssize_t) MaxMap; i++)
2845 {
2846 x_map[i].x=0.99999999999914679361*(double) i;
2847 y_map[i].x=0.5*(-1.2188941887145875e-06)*(2.00*(double) i-MaxMap);
2848 z_map[i].x=0.5*1.4019995886561440468*(2.00*(double) i-MaxMap);
2849 x_map[i].y=0.99999975910502514331*(double) i;
2850 y_map[i].y=0.5*(-0.34413567816504303521)*(2.00*(double) i-MaxMap);
2851 z_map[i].y=0.5*(-0.71413649331646789076)*(2.00*(double) i-MaxMap);
2852 x_map[i].z=1.00000124040004623180*(double) i;
2853 y_map[i].z=0.5*1.77200006607230409200*(2.00*(double) i-MaxMap);
2854 z_map[i].z=0.5*2.1453384174593273e-06*(2.00*(double) i-MaxMap);
2855 }
2856 break;
2857 }
2858 case Rec709YCbCrColorspace:
2859 {
2860 /*
2861 Initialize YCbCr tables:
2862
2863 R = Y +1.574800*Cr
2864 G = Y-0.187324*Cb-0.468124*Cr
2865 B = Y+1.855600*Cb
2866
2867 Cb and Cr, normally -0.5 through 0.5, must be normalized to the range 0
2868 through QuantumRange.
2869 */
2870#if defined(MAGICKCORE_OPENMP_SUPPORT)
2871 #pragma omp parallel for schedule(static)
2872#endif
2873 for (i=0; i <= (ssize_t) MaxMap; i++)
2874 {
2875 x_map[i].x=(MagickRealType) (1.0*i);
2876 y_map[i].x=(MagickRealType) (0.5*0.000000*(2.0*i-MaxMap));
2877 z_map[i].x=(MagickRealType) (0.5*1.574800*(2.0*i-MaxMap));
2878 x_map[i].y=(MagickRealType) (1.0*i);
2879 y_map[i].y=(MagickRealType) (0.5*(-0.187324)*(2.0*i-MaxMap));
2880 z_map[i].y=(MagickRealType) (0.5*(-0.468124)*(2.0*i-MaxMap));
2881 x_map[i].z=(MagickRealType) (1.0*i);
2882 y_map[i].z=(MagickRealType) (0.5*1.855600*(2.0*i-MaxMap));
2883 z_map[i].z=(MagickRealType) (0.5*0.000000*(2.0*i-MaxMap));
2884 }
2885 break;
2886 }
2887 case YCCColorspace:
2888 {
2889 /*
2890 Initialize YCC tables:
2891
2892 R = Y +1.340762*C2
2893 G = Y-0.317038*C1-0.682243*C2
2894 B = Y+1.632639*C1
2895
2896 YCC is scaled by 1.3584. C1 zero is 156 and C2 is at 137.
2897 */
2898#if defined(MAGICKCORE_OPENMP_SUPPORT)
2899 #pragma omp parallel for schedule(static)
2900#endif
2901 for (i=0; i <= (ssize_t) MaxMap; i++)
2902 {
2903 x_map[i].x=(MagickRealType) (1.3584000*(double) i);
2904 y_map[i].x=(MagickRealType) 0.0000000;
2905 z_map[i].x=(MagickRealType) (1.8215000*(1.0*(double) i-(double)
2906 ScaleQuantumToMap(ScaleCharToQuantum(137))));
2907 x_map[i].y=(MagickRealType) (1.3584000*(double) i);
2908 y_map[i].y=(MagickRealType) (-0.4302726*(1.0*(double) i-(double)
2909 ScaleQuantumToMap(ScaleCharToQuantum(156))));
2910 z_map[i].y=(MagickRealType) (-0.9271435*(1.0*(double) i-(double)
2911 ScaleQuantumToMap(ScaleCharToQuantum(137))));
2912 x_map[i].z=(MagickRealType) (1.3584000*(double) i);
2913 y_map[i].z=(MagickRealType) (2.2179000*(1.0*(double) i-(double)
2914 ScaleQuantumToMap(ScaleCharToQuantum(156))));
2915 z_map[i].z=(MagickRealType) 0.0000000;
2916 }
2917 break;
2918 }
2919 default:
2920 {
2921 /*
2922 Linear conversion tables.
2923 */
2924#if defined(MAGICKCORE_OPENMP_SUPPORT)
2925 #pragma omp parallel for schedule(static)
2926#endif
2927 for (i=0; i <= (ssize_t) MaxMap; i++)
2928 {
2929 x_map[i].x=(MagickRealType) (1.0*(double) i);
2930 y_map[i].x=(MagickRealType) 0.0;
2931 z_map[i].x=(MagickRealType) 0.0;
2932 x_map[i].y=(MagickRealType) 0.0;
2933 y_map[i].y=(MagickRealType) (1.0*(double) i);
2934 z_map[i].y=(MagickRealType) 0.0;
2935 x_map[i].z=(MagickRealType) 0.0;
2936 y_map[i].z=(MagickRealType) 0.0;
2937 z_map[i].z=(MagickRealType) (1.0*(double) i);
2938 }
2939 break;
2940 }
2941 }
2942 /*
2943 Convert to sRGB.
2944 */
2945 switch (image->storage_class)
2946 {
2947 case DirectClass:
2948 default:
2949 {
2950 /*
2951 Convert DirectClass image.
2952 */
2953 image_view=AcquireAuthenticCacheView(image,exception);
2954#if defined(MAGICKCORE_OPENMP_SUPPORT)
2955 #pragma omp parallel for schedule(static) shared(status) \
2956 magick_number_threads(image,image,image->rows,2)
2957#endif
2958 for (y=0; y < (ssize_t) image->rows; y++)
2959 {
2960 MagickBooleanType
2961 sync;
2962
2963 PixelInfo
2964 pixel;
2965
2966 ssize_t
2967 x;
2968
2969 Quantum
2970 *magick_restrict q;
2971
2972 if (status == MagickFalse)
2973 continue;
2974 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2975 exception);
2976 if (q == (Quantum *) NULL)
2977 {
2978 status=MagickFalse;
2979 continue;
2980 }
2981 for (x=0; x < (ssize_t) image->columns; x++)
2982 {
2983 size_t
2984 blue,
2985 green,
2986 red;
2987
2988 red=ScaleQuantumToMap(GetPixelRed(image,q));
2989 green=ScaleQuantumToMap(GetPixelGreen(image,q));
2990 blue=ScaleQuantumToMap(GetPixelBlue(image,q));
2991 pixel.red=x_map[red].x+y_map[green].x+z_map[blue].x;
2992 pixel.green=x_map[red].y+y_map[green].y+z_map[blue].y;
2993 pixel.blue=x_map[red].z+y_map[green].z+z_map[blue].z;
2994 if (image->colorspace == YCCColorspace)
2995 {
2996 pixel.red=(double) QuantumRange*(double)
2997 YCCMap[RoundToYCC(1024.0*pixel.red/(double) MaxMap)];
2998 pixel.green=(double) QuantumRange*(double)
2999 YCCMap[RoundToYCC(1024.0*pixel.green/(double) MaxMap)];
3000 pixel.blue=(double) QuantumRange*(double)
3001 YCCMap[RoundToYCC(1024.0*pixel.blue/(double) MaxMap)];
3002 }
3003 else
3004 {
3005 pixel.red=(MagickRealType) ScaleMapToQuantum(pixel.red);
3006 pixel.green=(MagickRealType) ScaleMapToQuantum(pixel.green);
3007 pixel.blue=(MagickRealType) ScaleMapToQuantum(pixel.blue);
3008 }
3009 SetPixelRed(image,ClampToQuantum(pixel.red),q);
3010 SetPixelGreen(image,ClampToQuantum(pixel.green),q);
3011 SetPixelBlue(image,ClampToQuantum(pixel.blue),q);
3012 q+=GetPixelChannels(image);
3013 }
3014 sync=SyncCacheViewAuthenticPixels(image_view,exception);
3015 if (sync == MagickFalse)
3016 status=MagickFalse;
3017 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3018 {
3019 MagickBooleanType
3020 proceed;
3021
3022#if defined(MAGICKCORE_OPENMP_SUPPORT)
3023 #pragma omp atomic
3024#endif
3025 progress++;
3026 proceed=SetImageProgress(image,TransformsRGBImageTag,progress,
3027 image->rows);
3028 if (proceed == MagickFalse)
3029 status=MagickFalse;
3030 }
3031 }
3032 image_view=DestroyCacheView(image_view);
3033 break;
3034 }
3035 case PseudoClass:
3036 {
3037 /*
3038 Convert PseudoClass image.
3039 */
3040#if defined(MAGICKCORE_OPENMP_SUPPORT)
3041 #pragma omp parallel for schedule(static) shared(status) \
3042 magick_number_threads(image,image,image->rows,1)
3043#endif
3044 for (i=0; i < (ssize_t) image->colors; i++)
3045 {
3046 PixelInfo
3047 pixel;
3048
3049 size_t
3050 blue,
3051 green,
3052 red;
3053
3054 red=ScaleQuantumToMap(ClampToQuantum(image->colormap[i].red));
3055 green=ScaleQuantumToMap(ClampToQuantum(image->colormap[i].green));
3056 blue=ScaleQuantumToMap(ClampToQuantum(image->colormap[i].blue));
3057 pixel.red=x_map[red].x+y_map[green].x+z_map[blue].x;
3058 pixel.green=x_map[red].y+y_map[green].y+z_map[blue].y;
3059 pixel.blue=x_map[red].z+y_map[green].z+z_map[blue].z;
3060 if (image->colorspace == YCCColorspace)
3061 {
3062 pixel.red=(double) QuantumRange*(double) YCCMap[RoundToYCC(1024.0*
3063 pixel.red/(double) MaxMap)];
3064 pixel.green=(double) QuantumRange*(double) YCCMap[RoundToYCC(1024.0*
3065 pixel.green/(double) MaxMap)];
3066 pixel.blue=(double) QuantumRange*(double) YCCMap[RoundToYCC(1024.0*
3067 pixel.blue/(double) MaxMap)];
3068 }
3069 else
3070 {
3071 pixel.red=(MagickRealType) ScaleMapToQuantum(pixel.red);
3072 pixel.green=(MagickRealType) ScaleMapToQuantum(pixel.green);
3073 pixel.blue=(MagickRealType) ScaleMapToQuantum(pixel.blue);
3074 }
3075 image->colormap[i].red=(double) ClampToQuantum(pixel.red);
3076 image->colormap[i].green=(double) ClampToQuantum(pixel.green);
3077 image->colormap[i].blue=(double) ClampToQuantum(pixel.blue);
3078 }
3079 (void) SyncImage(image,exception);
3080 break;
3081 }
3082 }
3083 /*
3084 Relinquish resources.
3085 */
3086 z_map=(TransformPacket *) RelinquishMagickMemory(z_map);
3087 y_map=(TransformPacket *) RelinquishMagickMemory(y_map);
3088 x_map=(TransformPacket *) RelinquishMagickMemory(x_map);
3089 if (SetImageColorspace(image,sRGBColorspace,exception) == MagickFalse)
3090 return(MagickFalse);
3091 return(MagickTrue);
3092}