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