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