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