]> granicus.if.org Git - imagemagick/blob - magick/colorspace.c
(no commit message)
[imagemagick] / magick / colorspace.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %     CCCC   OOO   L       OOO   RRRR   SSSSS  PPPP    AAA    CCCC  EEEEE     %
7 %    C      O   O  L      O   O  R   R  SS     P   P  A   A  C      E         %
8 %    C      O   O  L      O   O  RRRR    SSS   PPPP   AAAAA  C      EEE       %
9 %    C      O   O  L      O   O  R R       SS  P      A   A  C      E         %
10 %     CCCC   OOO   LLLLL   OOO   R  R   SSSSS  P      A   A   CCCC  EEEEE     %
11 %                                                                             %
12 %                                                                             %
13 %                     MagickCore Image Colorspace Methods                     %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                John Cristy                                  %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2010 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 \f
39 /*
40   Include declarations.
41 */
42 #include "magick/studio.h"
43 #include "magick/property.h"
44 #include "magick/cache.h"
45 #include "magick/cache-private.h"
46 #include "magick/cache-view.h"
47 #include "magick/color.h"
48 #include "magick/color-private.h"
49 #include "magick/colorspace.h"
50 #include "magick/colorspace-private.h"
51 #include "magick/exception.h"
52 #include "magick/exception-private.h"
53 #include "magick/image.h"
54 #include "magick/image-private.h"
55 #include "magick/gem.h"
56 #include "magick/memory_.h"
57 #include "magick/monitor.h"
58 #include "magick/monitor-private.h"
59 #include "magick/pixel-private.h"
60 #include "magick/quantize.h"
61 #include "magick/quantum.h"
62 #include "magick/string_.h"
63 #include "magick/string-private.h"
64 #include "magick/utility.h"
65 \f
66 /*
67   Typedef declarations.
68 */
69 typedef struct _TransformPacket
70 {
71   MagickRealType
72     x,
73     y,
74     z;
75 } TransformPacket;
76 \f
77 /*
78 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79 %                                                                             %
80 %                                                                             %
81 %                                                                             %
82 +     R G B T r a n s f o r m I m a g e                                       %
83 %                                                                             %
84 %                                                                             %
85 %                                                                             %
86 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
87 %
88 %  RGBTransformImage() converts the reference image from RGB to an alternate
89 %  colorspace.  The transformation matrices are not the standard ones: the
90 %  weights are rescaled to normalized the range of the transformed values to
91 %  be [0..QuantumRange].
92 %
93 %  The format of the RGBTransformImage method is:
94 %
95 %      MagickBooleanType RGBTransformImage(Image *image,
96 %        const ColorspaceType colorspace)
97 %
98 %  A description of each parameter follows:
99 %
100 %    o image: the image.
101 %
102 %    o colorspace: the colorspace to transform the image to.
103 %
104 */
105
106 static inline void ConvertRGBToXYZ(const Quantum red,const Quantum green,
107   const Quantum blue,double *X,double *Y,double *Z)
108 {
109   double
110     b,
111     g,
112     r;
113
114   assert(X != (double *) NULL);
115   assert(Y != (double *) NULL);
116   assert(Z != (double *) NULL);
117   r=QuantumScale*red;
118   if (r > 0.04045)
119     r=pow((r+0.055)/1.055,2.4);
120   else
121     r/=12.92;
122   g=QuantumScale*green;
123   if (g > 0.04045)
124     g=pow((g+0.055)/1.055,2.4);
125   else
126     g/=12.92;
127   b=QuantumScale*blue;
128   if (b > 0.04045)
129     b=pow((b+0.055)/1.055,2.4);
130   else
131     b/=12.92;
132   *X=0.4124240*r+0.3575790*g+0.1804640*b;
133   *Y=0.2126560*r+0.7151580*g+0.0721856*b;
134   *Z=0.0193324*r+0.1191930*g+0.9504440*b;
135 }
136
137 static double LabF1(double alpha)
138 {
139
140   if (alpha <= ((24.0/116.0)*(24.0/116.0)*(24.0/116.0)))
141     return((841.0/108.0)*alpha+(16.0/116.0));
142   return(pow(alpha,1.0/3.0));
143 }
144
145 static inline void ConvertXYZToLab(const double X,const double Y,const double Z,
146   double *L,double *a,double *b)
147 {
148 #define D50X  (0.9642)
149 #define D50Y  (1.0)
150 #define D50Z  (0.8249)
151
152   double
153     fx,
154     fy,
155     fz;
156
157   assert(L != (double *) NULL);
158   assert(a != (double *) NULL);
159   assert(b != (double *) NULL);
160   *L=0.0;
161   *a=0.5;
162   *b=0.5;
163   if ((X == 0.0) && (Y == 0.0) && (Z == 0.0))
164     return;
165   fx=LabF1(X/D50X);
166   fy=LabF1(Y/D50Y);
167   fz=LabF1(Z/D50Z);
168   *L=(116.0*fy-16.0)/100.0;
169   *a=(500.0*(fx-fy))/255.0;
170   if (*a < 0.0)
171     *a+=1.0;
172   *b=(200.0*(fy-fz))/255.0;
173   if (*b < 0.0)
174     *b+=1.0;
175 }
176
177 MagickExport MagickBooleanType RGBTransformImage(Image *image,
178   const ColorspaceType colorspace)
179 {
180 #define RGBTransformImageTag  "RGBTransform/Image"
181
182   CacheView
183     *image_view;
184
185   ExceptionInfo
186     *exception;
187
188   MagickBooleanType
189     status,
190     sync;
191
192   MagickOffsetType
193     progress;
194
195   PrimaryInfo
196     primary_info;
197
198   register ssize_t
199     i;
200
201   ssize_t
202     y;
203
204   TransformPacket
205     *x_map,
206     *y_map,
207     *z_map;
208
209   assert(image != (Image *) NULL);
210   assert(image->signature == MagickSignature);
211   if (image->debug != MagickFalse)
212     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
213   assert(colorspace != RGBColorspace);
214   assert(colorspace != TransparentColorspace);
215   assert(colorspace != UndefinedColorspace);
216   switch (image->colorspace)
217   {
218     case GRAYColorspace:
219     case Rec601LumaColorspace:
220     case Rec709LumaColorspace:
221     case RGBColorspace:
222     case TransparentColorspace:
223       break;
224     default:
225     {
226       (void) TransformImageColorspace(image,image->colorspace);
227       break;
228     }
229   }
230   if (SetImageColorspace(image,colorspace) == MagickFalse)
231     return(MagickFalse);
232   status=MagickTrue;
233   progress=0;
234   exception=(&image->exception);
235   switch (colorspace)
236   {
237     case CMYColorspace:
238     {
239       /*
240         Convert RGB to CMY colorspace.
241       */
242       if (image->storage_class == PseudoClass)
243         {
244           if (SyncImage(image) == MagickFalse)
245             return(MagickFalse);
246           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
247             return(MagickFalse);
248         }
249       image_view=AcquireCacheView(image);
250 #if defined(MAGICKCORE_OPENMP_SUPPORT)
251   #pragma omp parallel for schedule(dynamic,4) shared(status)
252 #endif
253       for (y=0; y < (ssize_t) image->rows; y++)
254       {
255         register ssize_t
256           x;
257
258         register PixelPacket
259           *restrict q;
260
261         if (status == MagickFalse)
262           continue;
263         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
264           exception);
265         if (q == (PixelPacket *) NULL)
266           {
267             status=MagickFalse;
268             continue;
269           }
270         for (x=0; x < (ssize_t) image->columns; x++)
271         {
272           q->red=ClampToQuantum((MagickRealType) (QuantumRange-q->red));
273           q->green=ClampToQuantum((MagickRealType) (QuantumRange-q->green));
274           q->blue=ClampToQuantum((MagickRealType) (QuantumRange-q->blue));
275           q++;
276         }
277         sync=SyncCacheViewAuthenticPixels(image_view,exception);
278         if (sync == MagickFalse)
279           status=MagickFalse;
280       }
281       image_view=DestroyCacheView(image_view);
282       image->type=image->matte == MagickFalse ? ColorSeparationType :
283         ColorSeparationMatteType;
284       return(status);
285     }
286     case CMYKColorspace:
287     {
288       MagickPixelPacket
289         zero;
290
291       /*
292         Convert RGB to CMYK colorspace.
293       */
294       if (image->storage_class == PseudoClass)
295         {
296           if (SyncImage(image) == MagickFalse)
297             return(MagickFalse);
298           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
299             return(MagickFalse);
300         }
301       GetMagickPixelPacket(image,&zero);
302       image_view=AcquireCacheView(image);
303 #if defined(MAGICKCORE_OPENMP_SUPPORT)
304   #pragma omp parallel for schedule(dynamic,4) shared(status)
305 #endif
306       for (y=0; y < (ssize_t) image->rows; y++)
307       {
308         MagickPixelPacket
309           pixel;
310
311         register IndexPacket
312           *restrict indexes;
313
314         register ssize_t
315           x;
316
317         register PixelPacket
318           *restrict q;
319
320         if (status == MagickFalse)
321           continue;
322         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
323           exception);
324         if (q == (PixelPacket *) NULL)
325           {
326             status=MagickFalse;
327             continue;
328           }
329         indexes=GetCacheViewAuthenticIndexQueue(image_view);
330         pixel=zero;
331         for (x=0; x < (ssize_t) image->columns; x++)
332         {
333           SetMagickPixelPacket(image,q,indexes+x,&pixel);
334           ConvertRGBToCMYK(&pixel);
335           SetPixelPacket(image,&pixel,q,indexes+x);
336           q++;
337         }
338         sync=SyncCacheViewAuthenticPixels(image_view,exception);
339         if (sync == MagickFalse)
340           status=MagickFalse;
341       }
342       image_view=DestroyCacheView(image_view);
343       image->type=image->matte == MagickFalse ? ColorSeparationType :
344         ColorSeparationMatteType;
345       return(status);
346     }
347     case HSBColorspace:
348     {
349       /*
350         Transform image from RGB to HSB.
351       */
352       if (image->storage_class == PseudoClass)
353         {
354           if (SyncImage(image) == MagickFalse)
355             return(MagickFalse);
356           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
357             return(MagickFalse);
358         }
359       image_view=AcquireCacheView(image);
360 #if defined(MAGICKCORE_OPENMP_SUPPORT)
361   #pragma omp parallel for schedule(dynamic,4) shared(status)
362 #endif
363       for (y=0; y < (ssize_t) image->rows; y++)
364       {
365         double
366           brightness,
367           hue,
368           saturation;
369
370         register ssize_t
371           x;
372
373         register PixelPacket
374           *restrict q;
375
376         if (status == MagickFalse)
377           continue;
378         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
379           exception);
380         if (q == (PixelPacket *) NULL)
381           {
382             status=MagickFalse;
383             continue;
384           }
385         hue=0.0;
386         saturation=0.0;
387         brightness=0.0;
388         for (x=0; x < (ssize_t) image->columns; x++)
389         {
390           ConvertRGBToHSB(q->red,q->green,q->blue,&hue,&saturation,&brightness);
391           q->red=ClampToQuantum((MagickRealType) QuantumRange*hue);
392           q->green=ClampToQuantum((MagickRealType) QuantumRange*saturation);
393           q->blue=ClampToQuantum((MagickRealType) QuantumRange*brightness);
394           q++;
395         }
396         sync=SyncCacheViewAuthenticPixels(image_view,exception);
397         if (sync == MagickFalse)
398           status=MagickFalse;
399       }
400       image_view=DestroyCacheView(image_view);
401       return(status);
402     }
403     case HSLColorspace:
404     {
405       /*
406         Transform image from RGB to HSL.
407       */
408       if (image->storage_class == PseudoClass)
409         {
410           if (SyncImage(image) == MagickFalse)
411             return(MagickFalse);
412           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
413             return(MagickFalse);
414         }
415       image_view=AcquireCacheView(image);
416 #if defined(MAGICKCORE_OPENMP_SUPPORT)
417   #pragma omp parallel for schedule(dynamic,4) shared(status)
418 #endif
419       for (y=0; y < (ssize_t) image->rows; y++)
420       {
421         double
422           hue,
423           lightness,
424           saturation;
425
426         register ssize_t
427           x;
428
429         register PixelPacket
430           *restrict q;
431
432         if (status == MagickFalse)
433           continue;
434         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
435           exception);
436         if (q == (PixelPacket *) NULL)
437           {
438             status=MagickFalse;
439             continue;
440           }
441         hue=0.0;
442         saturation=0.0;
443         lightness=0.0;
444         for (x=0; x < (ssize_t) image->columns; x++)
445         {
446           ConvertRGBToHSL(q->red,q->green,q->blue,&hue,&saturation,&lightness);
447           q->red=ClampToQuantum((MagickRealType) QuantumRange*hue);
448           q->green=ClampToQuantum((MagickRealType) QuantumRange*saturation);
449           q->blue=ClampToQuantum((MagickRealType) QuantumRange*lightness);
450           q++;
451         }
452         sync=SyncCacheViewAuthenticPixels(image_view,exception);
453         if (sync == MagickFalse)
454           status=MagickFalse;
455       }
456       image_view=DestroyCacheView(image_view);
457       return(status);
458     }
459     case HWBColorspace:
460     {
461       /*
462         Transform image from RGB to HWB.
463       */
464       if (image->storage_class == PseudoClass)
465         {
466           if (SyncImage(image) == MagickFalse)
467             return(MagickFalse);
468           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
469             return(MagickFalse);
470         }
471       image_view=AcquireCacheView(image);
472 #if defined(MAGICKCORE_OPENMP_SUPPORT)
473   #pragma omp parallel for schedule(dynamic,4) shared(status)
474 #endif
475       for (y=0; y < (ssize_t) image->rows; y++)
476       {
477         double
478           blackness,
479           hue,
480           whiteness;
481
482         register ssize_t
483           x;
484
485         register PixelPacket
486           *restrict q;
487
488         if (status == MagickFalse)
489           continue;
490         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
491           exception);
492         if (q == (PixelPacket *) NULL)
493           {
494             status=MagickFalse;
495             continue;
496           }
497         hue=0.0;
498         whiteness=0.0;
499         blackness=0.0;
500         for (x=0; x < (ssize_t) image->columns; x++)
501         {
502           ConvertRGBToHWB(q->red,q->green,q->blue,&hue,&whiteness,&blackness);
503           q->red=ClampToQuantum((MagickRealType) QuantumRange*hue);
504           q->green=ClampToQuantum((MagickRealType) QuantumRange*whiteness);
505           q->blue=ClampToQuantum((MagickRealType) QuantumRange*blackness);
506           q++;
507         }
508         sync=SyncCacheViewAuthenticPixels(image_view,exception);
509         if (sync == MagickFalse)
510           status=MagickFalse;
511       }
512       image_view=DestroyCacheView(image_view);
513       return(status);
514     }
515     case LabColorspace:
516     {
517       /*
518         Transform image from RGB to Lab.
519       */
520       if (image->storage_class == PseudoClass)
521         {
522           if (SyncImage(image) == MagickFalse)
523             return(MagickFalse);
524           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
525             return(MagickFalse);
526         }
527       image_view=AcquireCacheView(image);
528 #if defined(MAGICKCORE_OPENMP_SUPPORT)
529   #pragma omp parallel for schedule(dynamic,4) shared(status)
530 #endif
531       for (y=0; y < (ssize_t) image->rows; y++)
532       {
533         double
534           a,
535           b,
536           L,
537           X,
538           Y,
539           Z;
540
541         register ssize_t
542           x;
543
544         register PixelPacket
545           *restrict q;
546
547         if (status == MagickFalse)
548           continue;
549         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
550           exception);
551         if (q == (PixelPacket *) NULL)
552           {
553             status=MagickFalse;
554             continue;
555           }
556         L=0.0;
557         a=0.0;
558         b=0.0;
559         X=0.0;
560         Y=0.0;
561         Z=0.0;
562         for (x=0; x < (ssize_t) image->columns; x++)
563         {
564           ConvertRGBToXYZ(q->red,q->green,q->blue,&X,&Y,&Z);
565           ConvertXYZToLab(X,Y,Z,&L,&a,&b);
566           q->red=ClampToQuantum((MagickRealType) QuantumRange*L);
567           q->green=ClampToQuantum((MagickRealType) QuantumRange*a);
568           q->blue=ClampToQuantum((MagickRealType) QuantumRange*b);
569           q++;
570         }
571         sync=SyncCacheViewAuthenticPixels(image_view,exception);
572         if (sync == MagickFalse)
573           status=MagickFalse;
574       }
575       image_view=DestroyCacheView(image_view);
576       return(status);
577     }
578     case LogColorspace:
579     {
580 #define DisplayGamma  (1.0/1.7)
581 #define FilmGamma  0.6
582 #define ReferenceBlack  95.0
583 #define ReferenceWhite  685.0
584
585       const char
586         *value;
587
588       double
589         black,
590         density,
591         film_gamma,
592         gamma,
593         reference_black,
594         reference_white;
595
596       Quantum
597         *logmap;
598
599       /*
600         Transform RGB to Log colorspace.
601       */
602       density=DisplayGamma;
603       gamma=DisplayGamma;
604       value=GetImageProperty(image,"gamma");
605       if (value != (const char *) NULL)
606         gamma=1.0/StringToDouble(value) != 0.0 ? StringToDouble(value) : 1.0;
607       film_gamma=FilmGamma;
608       value=GetImageProperty(image,"film-gamma");
609       if (value != (const char *) NULL)
610         film_gamma=StringToDouble(value);
611       reference_black=ReferenceBlack;
612       value=GetImageProperty(image,"reference-black");
613       if (value != (const char *) NULL)
614         reference_black=StringToDouble(value);
615       reference_white=ReferenceWhite;
616       value=GetImageProperty(image,"reference-white");
617       if (value != (const char *) NULL)
618         reference_white=StringToDouble(value);
619       logmap=(Quantum *) AcquireQuantumMemory((size_t) MaxMap+1UL,
620         sizeof(*logmap));
621       if (logmap == (Quantum *) NULL)
622         ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
623           image->filename);
624       black=pow(10.0,(reference_black-reference_white)*(gamma/density)*
625         0.002/film_gamma);
626 #if defined(MAGICKCORE_OPENMP_SUPPORT)
627   #pragma omp parallel for schedule(dynamic,4)
628 #endif
629       for (i=0; i <= (ssize_t) MaxMap; i++)
630         logmap[i]=ScaleMapToQuantum((MagickRealType) (MaxMap*(reference_white+
631           log10(black+((MagickRealType) i/MaxMap)*(1.0-black))/((gamma/density)*
632           0.002/film_gamma))/1024.0));
633       image_view=AcquireCacheView(image);
634 #if defined(MAGICKCORE_OPENMP_SUPPORT)
635   #pragma omp parallel for schedule(dynamic,4) shared(status)
636 #endif
637       for (y=0; y < (ssize_t) image->rows; y++)
638       {
639         register ssize_t
640           x;
641
642         register PixelPacket
643           *restrict q;
644
645         if (status == MagickFalse)
646           continue;
647         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
648           exception);
649         if (q == (PixelPacket *) NULL)
650           {
651             status=MagickFalse;
652             continue;
653           }
654         for (x=(ssize_t) image->columns; x != 0; x--)
655         {
656           q->red=logmap[ScaleQuantumToMap(q->red)];
657           q->green=logmap[ScaleQuantumToMap(q->green)];
658           q->blue=logmap[ScaleQuantumToMap(q->blue)];
659           q++;
660         }
661         sync=SyncCacheViewAuthenticPixels(image_view,exception);
662         if (sync == MagickFalse)
663           status=MagickFalse;
664       }
665       image_view=DestroyCacheView(image_view);
666       logmap=(Quantum *) RelinquishMagickMemory(logmap);
667       return(status);
668     }
669     default:
670       break;
671   }
672   /*
673     Allocate the tables.
674   */
675   x_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
676     sizeof(*x_map));
677   y_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
678     sizeof(*y_map));
679   z_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
680     sizeof(*z_map));
681   if ((x_map == (TransformPacket *) NULL) ||
682       (y_map == (TransformPacket *) NULL) ||
683       (z_map == (TransformPacket *) NULL))
684     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
685       image->filename);
686   (void) ResetMagickMemory(&primary_info,0,sizeof(primary_info));
687   switch (colorspace)
688   {
689     case OHTAColorspace:
690     {
691       /*
692         Initialize OHTA tables:
693
694           I1 = 0.33333*R+0.33334*G+0.33333*B
695           I2 = 0.50000*R+0.00000*G-0.50000*B
696           I3 =-0.25000*R+0.50000*G-0.25000*B
697
698         I and Q, normally -0.5 through 0.5, are normalized to the range 0
699         through QuantumRange.
700       */
701       primary_info.y=(double) (MaxMap+1.0)/2.0;
702       primary_info.z=(double) (MaxMap+1.0)/2.0;
703 #if defined(MAGICKCORE_OPENMP_SUPPORT)
704   #pragma omp parallel for schedule(dynamic,4)
705 #endif
706       for (i=0; i <= (ssize_t) MaxMap; i++)
707       {
708         x_map[i].x=0.33333f*(MagickRealType) i;
709         y_map[i].x=0.33334f*(MagickRealType) i;
710         z_map[i].x=0.33333f*(MagickRealType) i;
711         x_map[i].y=0.50000f*(MagickRealType) i;
712         y_map[i].y=0.00000f*(MagickRealType) i;
713         z_map[i].y=(-0.50000f)*(MagickRealType) i;
714         x_map[i].z=(-0.25000f)*(MagickRealType) i;
715         y_map[i].z=0.50000f*(MagickRealType) i;
716         z_map[i].z=(-0.25000f)*(MagickRealType) i;
717       }
718       break;
719     }
720     case Rec601LumaColorspace:
721     case GRAYColorspace:
722     {
723       /*
724         Initialize Rec601 luma tables:
725
726           G = 0.29900*R+0.58700*G+0.11400*B
727       */
728 #if defined(MAGICKCORE_OPENMP_SUPPORT)
729   #pragma omp parallel for schedule(dynamic,4)
730 #endif
731       for (i=0; i <= (ssize_t) MaxMap; i++)
732       {
733         x_map[i].x=0.29900f*(MagickRealType) i;
734         y_map[i].x=0.58700f*(MagickRealType) i;
735         z_map[i].x=0.11400f*(MagickRealType) i;
736         x_map[i].y=0.29900f*(MagickRealType) i;
737         y_map[i].y=0.58700f*(MagickRealType) i;
738         z_map[i].y=0.11400f*(MagickRealType) i;
739         x_map[i].z=0.29900f*(MagickRealType) i;
740         y_map[i].z=0.58700f*(MagickRealType) i;
741         z_map[i].z=0.11400f*(MagickRealType) i;
742       }
743       image->type=GrayscaleType;
744       break;
745     }
746     case Rec601YCbCrColorspace:
747     case YCbCrColorspace:
748     {
749       /*
750         Initialize YCbCr tables (ITU-R BT.601):
751
752           Y =  0.299000*R+0.587000*G+0.114000*B
753           Cb= -0.168736*R-0.331264*G+0.500000*B
754           Cr=  0.500000*R-0.418688*G-0.081312*B
755
756         Cb and Cr, normally -0.5 through 0.5, are normalized to the range 0
757         through QuantumRange.
758       */
759       primary_info.y=(double) (MaxMap+1.0)/2.0;
760       primary_info.z=(double) (MaxMap+1.0)/2.0;
761 #if defined(MAGICKCORE_OPENMP_SUPPORT)
762   #pragma omp parallel for schedule(dynamic,4)
763 #endif
764       for (i=0; i <= (ssize_t) MaxMap; i++)
765       {
766         x_map[i].x=0.299000f*(MagickRealType) i;
767         y_map[i].x=0.587000f*(MagickRealType) i;
768         z_map[i].x=0.114000f*(MagickRealType) i;
769         x_map[i].y=(-0.168730f)*(MagickRealType) i;
770         y_map[i].y=(-0.331264f)*(MagickRealType) i;
771         z_map[i].y=0.500000f*(MagickRealType) i;
772         x_map[i].z=0.500000f*(MagickRealType) i;
773         y_map[i].z=(-0.418688f)*(MagickRealType) i;
774         z_map[i].z=(-0.081312f)*(MagickRealType) i;
775       }
776       break;
777     }
778     case Rec709LumaColorspace:
779     {
780       /*
781         Initialize Rec709 luma tables:
782
783           G = 0.21260*R+0.71520*G+0.07220*B
784       */
785 #if defined(MAGICKCORE_OPENMP_SUPPORT)
786   #pragma omp parallel for schedule(dynamic,4)
787 #endif
788       for (i=0; i <= (ssize_t) MaxMap; i++)
789       {
790         x_map[i].x=0.21260f*(MagickRealType) i;
791         y_map[i].x=0.71520f*(MagickRealType) i;
792         z_map[i].x=0.07220f*(MagickRealType) i;
793         x_map[i].y=0.21260f*(MagickRealType) i;
794         y_map[i].y=0.71520f*(MagickRealType) i;
795         z_map[i].y=0.07220f*(MagickRealType) i;
796         x_map[i].z=0.21260f*(MagickRealType) i;
797         y_map[i].z=0.71520f*(MagickRealType) i;
798         z_map[i].z=0.07220f*(MagickRealType) i;
799       }
800       break;
801     }
802     case Rec709YCbCrColorspace:
803     {
804       /*
805         Initialize YCbCr tables (ITU-R BT.709):
806
807           Y =  0.212600*R+0.715200*G+0.072200*B
808           Cb= -0.114572*R-0.385428*G+0.500000*B
809           Cr=  0.500000*R-0.454153*G-0.045847*B
810
811         Cb and Cr, normally -0.5 through 0.5, are normalized to the range 0
812         through QuantumRange.
813       */
814       primary_info.y=(double) (MaxMap+1.0)/2.0;
815       primary_info.z=(double) (MaxMap+1.0)/2.0;
816 #if defined(MAGICKCORE_OPENMP_SUPPORT)
817   #pragma omp parallel for schedule(dynamic,4)
818 #endif
819       for (i=0; i <= (ssize_t) MaxMap; i++)
820       {
821         x_map[i].x=0.212600f*(MagickRealType) i;
822         y_map[i].x=0.715200f*(MagickRealType) i;
823         z_map[i].x=0.072200f*(MagickRealType) i;
824         x_map[i].y=(-0.114572f)*(MagickRealType) i;
825         y_map[i].y=(-0.385428f)*(MagickRealType) i;
826         z_map[i].y=0.500000f*(MagickRealType) i;
827         x_map[i].z=0.500000f*(MagickRealType) i;
828         y_map[i].z=(-0.454153f)*(MagickRealType) i;
829         z_map[i].z=(-0.045847f)*(MagickRealType) i;
830       }
831       break;
832     }
833     case sRGBColorspace:
834     {
835       /*
836         Linear sRGB to nonlinear RGB (http://www.w3.org/Graphics/Color/sRGB):
837
838           R = 1.0*R+0.0*G+0.0*B
839           G = 0.0*R+0.1*G+0.0*B
840           B = 0.0*R+0.0*G+1.0*B
841       */
842 #if defined(MAGICKCORE_OPENMP_SUPPORT)
843   #pragma omp parallel for schedule(dynamic,4)
844 #endif
845       for (i=0; i <= (ssize_t) MaxMap; i++)
846       {
847         MagickRealType
848           v;
849
850         v=(MagickRealType) i/(MagickRealType) MaxMap;
851         if (((MagickRealType) i/(MagickRealType) MaxMap) <= 0.04045f)
852           v/=12.92f;
853         else
854           v=(MagickRealType) pow((((double) i/MaxMap)+0.055)/1.055,2.4);
855         x_map[i].x=1.0f*MaxMap*v;
856         y_map[i].x=0.0f*MaxMap*v;
857         z_map[i].x=0.0f*MaxMap*v;
858         x_map[i].y=0.0f*MaxMap*v;
859         y_map[i].y=1.0f*MaxMap*v;
860         z_map[i].y=0.0f*MaxMap*v;
861         x_map[i].z=0.0f*MaxMap*v;
862         y_map[i].z=0.0f*MaxMap*v;
863         z_map[i].z=1.0f*MaxMap*v;
864       }
865       break;
866     }
867     case XYZColorspace:
868     {
869       /*
870         Initialize CIE XYZ tables (ITU-R 709 RGB):
871
872           X = 0.4124564*R+0.3575761*G+0.1804375*B
873           Y = 0.2126729*R+0.7151522*G+0.0721750*B
874           Z = 0.0193339*R+0.1191920*G+0.9503041*B
875       */
876 #if defined(MAGICKCORE_OPENMP_SUPPORT)
877   #pragma omp parallel for schedule(dynamic,4)
878 #endif
879       for (i=0; i <= (ssize_t) MaxMap; i++)
880       {
881         x_map[i].x=0.4124564f*(MagickRealType) i;
882         y_map[i].x=0.3575761f*(MagickRealType) i;
883         z_map[i].x=0.1804375f*(MagickRealType) i;
884         x_map[i].y=0.2126729f*(MagickRealType) i;
885         y_map[i].y=0.7151522f*(MagickRealType) i;
886         z_map[i].y=0.0721750f*(MagickRealType) i;
887         x_map[i].z=0.0193339f*(MagickRealType) i;
888         y_map[i].z=0.1191920f*(MagickRealType) i;
889         z_map[i].z=0.9503041f*(MagickRealType) i;
890       }
891       break;
892     }
893     case YCCColorspace:
894     {
895       /*
896         Initialize YCC tables:
897
898           Y =  0.29900*R+0.58700*G+0.11400*B
899           C1= -0.29900*R-0.58700*G+0.88600*B
900           C2=  0.70100*R-0.58700*G-0.11400*B
901
902         YCC is scaled by 1.3584.  C1 zero is 156 and C2 is at 137.
903       */
904       primary_info.y=(double) ScaleQuantumToMap(ScaleCharToQuantum(156));
905       primary_info.z=(double) ScaleQuantumToMap(ScaleCharToQuantum(137));
906       for (i=0; i <= (ssize_t) (0.018*MaxMap); i++)
907       {
908         x_map[i].x=0.003962014134275617f*(MagickRealType) i;
909         y_map[i].x=0.007778268551236748f*(MagickRealType) i;
910         z_map[i].x=0.001510600706713781f*(MagickRealType) i;
911         x_map[i].y=(-0.002426619775463276f)*(MagickRealType) i;
912         y_map[i].y=(-0.004763965913702149f)*(MagickRealType) i;
913         z_map[i].y=0.007190585689165425f*(MagickRealType) i;
914         x_map[i].z=0.006927257754597858f*(MagickRealType) i;
915         y_map[i].z=(-0.005800713697502058f)*(MagickRealType) i;
916         z_map[i].z=(-0.0011265440570958f)*(MagickRealType) i;
917       }
918       for ( ; i <= (ssize_t) MaxMap; i++)
919       {
920         x_map[i].x=0.2201118963486454*(1.099f*(MagickRealType) i-0.099f);
921         y_map[i].x=0.4321260306242638*(1.099f*(MagickRealType) i-0.099f);
922         z_map[i].x=0.08392226148409894*(1.099f*(MagickRealType) i-0.099f);
923         x_map[i].y=(-0.1348122097479598)*(1.099f*(MagickRealType) i-0.099f);
924         y_map[i].y=(-0.2646647729834528)*(1.099f*(MagickRealType) i-0.099f);
925         z_map[i].y=0.3994769827314126*(1.099f*(MagickRealType) i-0.099f);
926         x_map[i].z=0.3848476530332144*(1.099f*(MagickRealType) i-0.099f);
927         y_map[i].z=(-0.3222618720834477)*(1.099f*(MagickRealType) i-0.099f);
928         z_map[i].z=(-0.06258578094976668)*(1.099f*(MagickRealType) i-0.099f);
929       }
930       break;
931     }
932     case YIQColorspace:
933     {
934       /*
935         Initialize YIQ tables:
936
937           Y = 0.29900*R+0.58700*G+0.11400*B
938           I = 0.59600*R-0.27400*G-0.32200*B
939           Q = 0.21100*R-0.52300*G+0.31200*B
940
941         I and Q, normally -0.5 through 0.5, are normalized to the range 0
942         through QuantumRange.
943       */
944       primary_info.y=(double) (MaxMap+1.0)/2.0;
945       primary_info.z=(double) (MaxMap+1.0)/2.0;
946 #if defined(MAGICKCORE_OPENMP_SUPPORT)
947   #pragma omp parallel for schedule(dynamic,4)
948 #endif
949       for (i=0; i <= (ssize_t) MaxMap; i++)
950       {
951         x_map[i].x=0.29900f*(MagickRealType) i;
952         y_map[i].x=0.58700f*(MagickRealType) i;
953         z_map[i].x=0.11400f*(MagickRealType) i;
954         x_map[i].y=0.59600f*(MagickRealType) i;
955         y_map[i].y=(-0.27400f)*(MagickRealType) i;
956         z_map[i].y=(-0.32200f)*(MagickRealType) i;
957         x_map[i].z=0.21100f*(MagickRealType) i;
958         y_map[i].z=(-0.52300f)*(MagickRealType) i;
959         z_map[i].z=0.31200f*(MagickRealType) i;
960       }
961       break;
962     }
963     case YPbPrColorspace:
964     {
965       /*
966         Initialize YPbPr tables (ITU-R BT.601):
967
968           Y =  0.299000*R+0.587000*G+0.114000*B
969           Pb= -0.168736*R-0.331264*G+0.500000*B
970           Pr=  0.500000*R-0.418688*G-0.081312*B
971
972         Pb and Pr, normally -0.5 through 0.5, are normalized to the range 0
973         through QuantumRange.
974       */
975       primary_info.y=(double) (MaxMap+1.0)/2.0;
976       primary_info.z=(double) (MaxMap+1.0)/2.0;
977 #if defined(MAGICKCORE_OPENMP_SUPPORT)
978   #pragma omp parallel for schedule(dynamic,4)
979 #endif
980       for (i=0; i <= (ssize_t) MaxMap; i++)
981       {
982         x_map[i].x=0.299000f*(MagickRealType) i;
983         y_map[i].x=0.587000f*(MagickRealType) i;
984         z_map[i].x=0.114000f*(MagickRealType) i;
985         x_map[i].y=(-0.168736f)*(MagickRealType) i;
986         y_map[i].y=(-0.331264f)*(MagickRealType) i;
987         z_map[i].y=0.500000f*(MagickRealType) i;
988         x_map[i].z=0.500000f*(MagickRealType) i;
989         y_map[i].z=(-0.418688f)*(MagickRealType) i;
990         z_map[i].z=(-0.081312f)*(MagickRealType) i;
991       }
992       break;
993     }
994     case YUVColorspace:
995     default:
996     {
997       /*
998         Initialize YUV tables:
999
1000           Y =  0.29900*R+0.58700*G+0.11400*B
1001           U = -0.14740*R-0.28950*G+0.43690*B
1002           V =  0.61500*R-0.51500*G-0.10000*B
1003
1004         U and V, normally -0.5 through 0.5, are normalized to the range 0
1005         through QuantumRange.  Note that U = 0.493*(B-Y), V = 0.877*(R-Y).
1006       */
1007       primary_info.y=(double) (MaxMap+1.0)/2.0;
1008       primary_info.z=(double) (MaxMap+1.0)/2.0;
1009 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1010   #pragma omp parallel for schedule(dynamic,4)
1011 #endif
1012       for (i=0; i <= (ssize_t) MaxMap; i++)
1013       {
1014         x_map[i].x=0.29900f*(MagickRealType) i;
1015         y_map[i].x=0.58700f*(MagickRealType) i;
1016         z_map[i].x=0.11400f*(MagickRealType) i;
1017         x_map[i].y=(-0.14740f)*(MagickRealType) i;
1018         y_map[i].y=(-0.28950f)*(MagickRealType) i;
1019         z_map[i].y=0.43690f*(MagickRealType) i;
1020         x_map[i].z=0.61500f*(MagickRealType) i;
1021         y_map[i].z=(-0.51500f)*(MagickRealType) i;
1022         z_map[i].z=(-0.10000f)*(MagickRealType) i;
1023       }
1024       break;
1025     }
1026   }
1027   /*
1028     Convert from RGB.
1029   */
1030   switch (image->storage_class)
1031   {
1032     case DirectClass:
1033     default:
1034     {
1035       /*
1036         Convert DirectClass image.
1037       */
1038       image_view=AcquireCacheView(image);
1039 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1040   #pragma omp parallel for schedule(dynamic,4) shared(status)
1041 #endif
1042       for (y=0; y < (ssize_t) image->rows; y++)
1043       {
1044         MagickPixelPacket
1045           pixel;
1046
1047         register ssize_t
1048           x;
1049
1050         register PixelPacket
1051           *restrict q;
1052
1053         register size_t
1054           blue,
1055           green,
1056           red;
1057
1058         if (status == MagickFalse)
1059           continue;
1060         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1061           exception);
1062         if (q == (PixelPacket *) NULL)
1063           {
1064             status=MagickFalse;
1065             continue;
1066           }
1067         for (x=0; x < (ssize_t) image->columns; x++)
1068         {
1069           red=ScaleQuantumToMap(q->red);
1070           green=ScaleQuantumToMap(q->green);
1071           blue=ScaleQuantumToMap(q->blue);
1072           pixel.red=(x_map[red].x+y_map[green].x+z_map[blue].x)+
1073             (MagickRealType) primary_info.x;
1074           pixel.green=(x_map[red].y+y_map[green].y+z_map[blue].y)+
1075             (MagickRealType) primary_info.y;
1076           pixel.blue=(x_map[red].z+y_map[green].z+z_map[blue].z)+
1077             (MagickRealType) primary_info.z;
1078           q->red=ScaleMapToQuantum(pixel.red);
1079           q->green=ScaleMapToQuantum(pixel.green);
1080           q->blue=ScaleMapToQuantum(pixel.blue);
1081           q++;
1082         }
1083         sync=SyncCacheViewAuthenticPixels(image_view,exception);
1084         if (sync == MagickFalse)
1085           status=MagickFalse;
1086         if (image->progress_monitor != (MagickProgressMonitor) NULL)
1087           {
1088             MagickBooleanType
1089               proceed;
1090
1091 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1092   #pragma omp critical (MagickCore_RGBTransformImage)
1093 #endif
1094             proceed=SetImageProgress(image,RGBTransformImageTag,progress++,
1095               image->rows);
1096             if (proceed == MagickFalse)
1097               status=MagickFalse;
1098           }
1099       }
1100       image_view=DestroyCacheView(image_view);
1101       break;
1102     }
1103     case PseudoClass:
1104     {
1105       register size_t
1106         blue,
1107         green,
1108         red;
1109
1110       /*
1111         Convert PseudoClass image.
1112       */
1113       image_view=AcquireCacheView(image);
1114       for (i=0; i < (ssize_t) image->colors; i++)
1115       {
1116         MagickPixelPacket
1117           pixel;
1118
1119         red=ScaleQuantumToMap(image->colormap[i].red);
1120         green=ScaleQuantumToMap(image->colormap[i].green);
1121         blue=ScaleQuantumToMap(image->colormap[i].blue);
1122         pixel.red=x_map[red].x+y_map[green].x+z_map[blue].x+primary_info.x;
1123         pixel.green=x_map[red].y+y_map[green].y+z_map[blue].y+primary_info.y;
1124         pixel.blue=x_map[red].z+y_map[green].z+z_map[blue].z+primary_info.z;
1125         image->colormap[i].red=ScaleMapToQuantum(pixel.red);
1126         image->colormap[i].green=ScaleMapToQuantum(pixel.green);
1127         image->colormap[i].blue=ScaleMapToQuantum(pixel.blue);
1128       }
1129       image_view=DestroyCacheView(image_view);
1130       (void) SyncImage(image);
1131       break;
1132     }
1133   }
1134   /*
1135     Relinquish resources.
1136   */
1137   z_map=(TransformPacket *) RelinquishMagickMemory(z_map);
1138   y_map=(TransformPacket *) RelinquishMagickMemory(y_map);
1139   x_map=(TransformPacket *) RelinquishMagickMemory(x_map);
1140   if (SetImageColorspace(image,colorspace) == MagickFalse)
1141     return(MagickFalse);
1142   return(status);
1143 }
1144 \f
1145 /*
1146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1147 %                                                                             %
1148 %                                                                             %
1149 %                                                                             %
1150 %   S e t I m a g e C o l o r s p a c e                                       %
1151 %                                                                             %
1152 %                                                                             %
1153 %                                                                             %
1154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1155 %
1156 %  SetImageColorspace() sets the colorspace member of the Image structure.
1157 %
1158 %  The format of the SetImageColorspace method is:
1159 %
1160 %      MagickBooleanType SetImageColorspace(Image *image,
1161 %        const ColorspaceType colorspace)
1162 %
1163 %  A description of each parameter follows:
1164 %
1165 %    o image: the image.
1166 %
1167 %    o colorspace: the colorspace.
1168 %
1169 */
1170 MagickExport MagickBooleanType SetImageColorspace(Image *image,
1171   const ColorspaceType colorspace)
1172 {
1173   image->colorspace=colorspace;
1174   return(MagickTrue);
1175 }
1176 \f
1177 /*
1178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1179 %                                                                             %
1180 %                                                                             %
1181 %                                                                             %
1182 %   T r a n s f o r m I m a g e C o l o r s p a c e                           %
1183 %                                                                             %
1184 %                                                                             %
1185 %                                                                             %
1186 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1187 %
1188 %  TransformImageColorspace() transforms an image colorspace.
1189 %
1190 %  The format of the TransformImageColorspace method is:
1191 %
1192 %      MagickBooleanType TransformImageColorspace(Image *image,
1193 %        const ColorspaceType colorspace)
1194 %
1195 %  A description of each parameter follows:
1196 %
1197 %    o image: the image.
1198 %
1199 %    o colorspace: the colorspace.
1200 %
1201 */
1202 MagickExport MagickBooleanType TransformImageColorspace(Image *image,
1203   const ColorspaceType colorspace)
1204 {
1205   MagickBooleanType
1206     status;
1207
1208   assert(image != (Image *) NULL);
1209   assert(image->signature == MagickSignature);
1210   if (image->debug != MagickFalse)
1211     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1212   if (colorspace == UndefinedColorspace)
1213     {
1214       if (SetImageColorspace(image,colorspace) == MagickFalse)
1215         return(MagickFalse);
1216       return(MagickTrue);
1217     }
1218   if (image->colorspace == colorspace)
1219     return(MagickTrue);
1220   if ((colorspace == RGBColorspace) || (colorspace == TransparentColorspace))
1221     return(TransformRGBImage(image,image->colorspace));
1222   status=MagickTrue;
1223   if ((image->colorspace != RGBColorspace) &&
1224       (image->colorspace != TransparentColorspace) &&
1225       (image->colorspace != GRAYColorspace))
1226     status=TransformRGBImage(image,image->colorspace);
1227   if (RGBTransformImage(image,colorspace) == MagickFalse)
1228     status=MagickFalse;
1229   return(status);
1230 }
1231 \f
1232 /*
1233 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1234 %                                                                             %
1235 %                                                                             %
1236 %                                                                             %
1237 +     T r a n s f o r m R G B I m a g e                                       %
1238 %                                                                             %
1239 %                                                                             %
1240 %                                                                             %
1241 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1242 %
1243 %  TransformRGBImage() converts the reference image from an alternate
1244 %  colorspace to RGB.  The transformation matrices are not the standard ones:
1245 %  the weights are rescaled to normalize the range of the transformed values to
1246 %  be [0..QuantumRange].
1247 %
1248 %  The format of the TransformRGBImage method is:
1249 %
1250 %      MagickBooleanType TransformRGBImage(Image *image,
1251 %        const ColorspaceType colorspace)
1252 %
1253 %  A description of each parameter follows:
1254 %
1255 %    o image: the image.
1256 %
1257 %    o colorspace: the colorspace to transform the image to.
1258 %
1259 */
1260
1261 static double LabF2(double alpha)
1262 {
1263   double
1264     beta;
1265
1266   if (alpha > (24.0/116.0))
1267     return(alpha*alpha*alpha);
1268   beta=(108.0/841.0)*(alpha-(16.0/116.0));
1269   if (beta > 0.0)
1270     return(beta);
1271   return(0.0);
1272 }
1273
1274 static inline void ConvertLabToXYZ(const double L,const double a,const double b,
1275   double *X,double *Y,double *Z)
1276 {
1277
1278   double
1279     x,
1280     y,
1281     z;
1282
1283   assert(X != (double *) NULL);
1284   assert(Y != (double *) NULL);
1285   assert(Z != (double *) NULL);
1286   *X=0.0;
1287   *Y=0.0;
1288   *Z=0.0;
1289   if (L <= 0.0)
1290     return;
1291   y=(100.0*L+16.0)/116.0;
1292   x=y+255.0*0.002*(a > 0.5 ? a-1.0 : a);
1293   z=y-255.0*0.005*(b > 0.5 ? b-1.0 : b);
1294   *X=D50X*LabF2(x);
1295   *Y=D50Y*LabF2(y);
1296   *Z=D50Z*LabF2(z);
1297 }
1298
1299 static inline unsigned short RoundToYCC(const MagickRealType value)
1300 {
1301   if (value <= 0.0)
1302     return(0UL);
1303   if (value >= 350.0)
1304     return(350);
1305   return((unsigned short) (value+0.5));
1306 }
1307
1308 static inline void ConvertXYZToRGB(const double x,const double y,const double z,
1309   Quantum *red,Quantum *green,Quantum *blue)
1310 {
1311   double
1312     b,
1313     g,
1314     r;
1315
1316   /*
1317     Convert XYZ to RGB colorspace.
1318   */
1319   assert(red != (Quantum *) NULL);
1320   assert(green != (Quantum *) NULL);
1321   assert(blue != (Quantum *) NULL);
1322   r=3.2404542*x-1.5371385*y-0.4985314*z;
1323   g=(-0.9692660*x+1.8760108*y+0.0415560*z);
1324   b=0.0556434*x-0.2040259*y+1.0572252*z;
1325   if (r > 0.0031308)
1326     r=1.055*pow(r,1.0/2.4)-0.055;
1327   else
1328     r*=12.92;
1329   if (g > 0.0031308)
1330     g=1.055*pow(g,1.0/2.4)-0.055;
1331   else
1332     g*=12.92;
1333   if (b > 0.0031308)
1334     b=1.055*pow(b,1.0/2.4)-0.055;
1335   else
1336     b*=12.92;
1337   *red=RoundToQuantum((MagickRealType) QuantumRange*r);
1338   *green=RoundToQuantum((MagickRealType) QuantumRange*g);
1339   *blue=RoundToQuantum((MagickRealType) QuantumRange*b);
1340 }
1341
1342 static inline void ConvertCMYKToRGB(MagickPixelPacket *pixel)
1343 {
1344   pixel->red=(MagickRealType) QuantumRange-(QuantumScale*pixel->red*
1345     (QuantumRange-pixel->index)+pixel->index);
1346   pixel->green=(MagickRealType) QuantumRange-(QuantumScale*pixel->green*
1347     (QuantumRange-pixel->index)+pixel->index);
1348   pixel->blue=(MagickRealType) QuantumRange-(QuantumScale*pixel->blue*
1349     (QuantumRange-pixel->index)+pixel->index);
1350 }
1351
1352 MagickExport MagickBooleanType TransformRGBImage(Image *image,
1353   const ColorspaceType colorspace)
1354 {
1355 #define D50X  (0.9642)
1356 #define D50Y  (1.0)
1357 #define D50Z  (0.8249)
1358 #define TransformRGBImageTag  "Transform/Image"
1359
1360 #if !defined(MAGICKCORE_HDRI_SUPPORT)
1361   static const unsigned char
1362     YCCMap[351] =  /* Photo CD information beyond 100% white, Gamma 2.2 */
1363     {
1364         0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,
1365        14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,
1366        28,  29,  30,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,
1367        43,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  56,  57,  58,
1368        59,  60,  61,  62,  63,  64,  66,  67,  68,  69,  70,  71,  72,  73,
1369        74,  76,  77,  78,  79,  80,  81,  82,  83,  84,  86,  87,  88,  89,
1370        90,  91,  92,  93,  94,  95,  97,  98,  99, 100, 101, 102, 103, 104,
1371       105, 106, 107, 108, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
1372       120, 121, 122, 123, 124, 125, 126, 127, 129, 130, 131, 132, 133, 134,
1373       135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148,
1374       149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162,
1375       163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176,
1376       176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189,
1377       190, 191, 192, 193, 193, 194, 195, 196, 197, 198, 199, 200, 201, 201,
1378       202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 211, 212, 213,
1379       214, 215, 215, 216, 217, 218, 218, 219, 220, 221, 221, 222, 223, 224,
1380       224, 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232, 233,
1381       234, 234, 235, 236, 236, 237, 237, 238, 238, 239, 240, 240, 241, 241,
1382       242, 242, 243, 243, 244, 244, 245, 245, 245, 246, 246, 247, 247, 247,
1383       248, 248, 248, 249, 249, 249, 249, 250, 250, 250, 250, 251, 251, 251,
1384       251, 251, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253,
1385       253, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254,
1386       254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255,
1387       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1388       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1389       255
1390     };
1391 #endif
1392
1393   CacheView
1394     *image_view;
1395
1396   ExceptionInfo
1397     *exception;
1398
1399   MagickBooleanType
1400     status;
1401
1402   MagickOffsetType
1403     progress;
1404
1405   register ssize_t
1406     i;
1407
1408   ssize_t
1409     y;
1410
1411   TransformPacket
1412     *y_map,
1413     *x_map,
1414     *z_map;
1415
1416   assert(image != (Image *) NULL);
1417   assert(image->signature == MagickSignature);
1418   if (image->debug != MagickFalse)
1419     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1420   switch (colorspace)
1421   {
1422     case GRAYColorspace:
1423     case Rec601LumaColorspace:
1424     case Rec709LumaColorspace:
1425     case RGBColorspace:
1426     case TransparentColorspace:
1427     case UndefinedColorspace:
1428       return(MagickTrue);
1429     default:
1430       break;
1431   }
1432   status=MagickTrue;
1433   progress=0;
1434   exception=(&image->exception);
1435   switch (colorspace)
1436   {
1437     case CMYColorspace:
1438     {
1439       /*
1440         Transform image from CMY to RGB.
1441       */
1442       if (image->storage_class == PseudoClass)
1443         {
1444           if (SyncImage(image) == MagickFalse)
1445             return(MagickFalse);
1446           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
1447             return(MagickFalse);
1448         }
1449       image_view=AcquireCacheView(image);
1450 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1451   #pragma omp parallel for schedule(dynamic,4) shared(status)
1452 #endif
1453       for (y=0; y < (ssize_t) image->rows; y++)
1454       {
1455         MagickBooleanType
1456           sync;
1457
1458         register ssize_t
1459           x;
1460
1461         register PixelPacket
1462           *restrict q;
1463
1464         if (status == MagickFalse)
1465           continue;
1466         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1467           exception);
1468         if (q == (PixelPacket *) NULL)
1469           {
1470             status=MagickFalse;
1471             continue;
1472           }
1473         for (x=0; x < (ssize_t) image->columns; x++)
1474         {
1475           q->red=ClampToQuantum((MagickRealType) (QuantumRange-q->red));
1476           q->green=ClampToQuantum((MagickRealType) (QuantumRange-q->green));
1477           q->blue=ClampToQuantum((MagickRealType) (QuantumRange-q->blue));
1478           q++;
1479         }
1480         sync=SyncCacheViewAuthenticPixels(image_view,exception);
1481         if (sync == MagickFalse)
1482           status=MagickFalse;
1483       }
1484       image_view=DestroyCacheView(image_view);
1485       if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
1486         return(MagickFalse);
1487       return(status);
1488     }
1489     case CMYKColorspace:
1490     {
1491       MagickPixelPacket
1492         zero;
1493
1494       /*
1495         Transform image from CMYK to RGB.
1496       */
1497       if (image->storage_class == PseudoClass)
1498         {
1499           if (SyncImage(image) == MagickFalse)
1500             return(MagickFalse);
1501           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
1502             return(MagickFalse);
1503         }
1504       GetMagickPixelPacket(image,&zero);
1505       image_view=AcquireCacheView(image);
1506 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1507   #pragma omp parallel for schedule(dynamic,4) shared(status)
1508 #endif
1509       for (y=0; y < (ssize_t) image->rows; y++)
1510       {
1511         MagickBooleanType
1512           sync;
1513
1514         MagickPixelPacket
1515           pixel;
1516
1517         register IndexPacket
1518           *restrict indexes;
1519
1520         register ssize_t
1521           x;
1522
1523         register PixelPacket
1524           *restrict q;
1525
1526         if (status == MagickFalse)
1527           continue;
1528         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1529           exception);
1530         if (q == (PixelPacket *) NULL)
1531           {
1532             status=MagickFalse;
1533             continue;
1534           }
1535         indexes=GetCacheViewAuthenticIndexQueue(image_view);
1536         pixel=zero;
1537         for (x=0; x < (ssize_t) image->columns; x++)
1538         {
1539           SetMagickPixelPacket(image,q,indexes+x,&pixel);
1540           ConvertCMYKToRGB(&pixel);
1541           SetPixelPacket(image,&pixel,q,indexes+x);
1542           q++;
1543         }
1544         sync=SyncCacheViewAuthenticPixels(image_view,exception);
1545         if (sync == MagickFalse)
1546           status=MagickFalse;
1547       }
1548       image_view=DestroyCacheView(image_view);
1549       if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
1550         return(MagickFalse);
1551       return(status);
1552     }
1553     case HSBColorspace:
1554     {
1555       /*
1556         Transform image from HSB to RGB.
1557       */
1558       if (image->storage_class == PseudoClass)
1559         {
1560           if (SyncImage(image) == MagickFalse)
1561             return(MagickFalse);
1562           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
1563             return(MagickFalse);
1564         }
1565       image_view=AcquireCacheView(image);
1566 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1567   #pragma omp parallel for schedule(dynamic,4) shared(status)
1568 #endif
1569       for (y=0; y < (ssize_t) image->rows; y++)
1570       {
1571         double
1572           brightness,
1573           hue,
1574           saturation;
1575
1576         MagickBooleanType
1577           sync;
1578
1579         register ssize_t
1580           x;
1581
1582         register PixelPacket
1583           *restrict q;
1584
1585         if (status == MagickFalse)
1586           continue;
1587         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1588           exception);
1589         if (q == (PixelPacket *) NULL)
1590           {
1591             status=MagickFalse;
1592             continue;
1593           }
1594         for (x=0; x < (ssize_t) image->columns; x++)
1595         {
1596           hue=(double) (QuantumScale*q->red);
1597           saturation=(double) (QuantumScale*q->green);
1598           brightness=(double) (QuantumScale*q->blue);
1599           ConvertHSBToRGB(hue,saturation,brightness,&q->red,&q->green,&q->blue);
1600           q++;
1601         }
1602         sync=SyncCacheViewAuthenticPixels(image_view,exception);
1603         if (sync == MagickFalse)
1604           status=MagickFalse;
1605       }
1606       image_view=DestroyCacheView(image_view);
1607       if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
1608         return(MagickFalse);
1609       return(status);
1610     }
1611     case HSLColorspace:
1612     {
1613       /*
1614         Transform image from HSL to RGB.
1615       */
1616       if (image->storage_class == PseudoClass)
1617         {
1618           if (SyncImage(image) == MagickFalse)
1619             return(MagickFalse);
1620           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
1621             return(MagickFalse);
1622         }
1623       image_view=AcquireCacheView(image);
1624 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1625   #pragma omp parallel for schedule(dynamic,4) shared(status)
1626 #endif
1627       for (y=0; y < (ssize_t) image->rows; y++)
1628       {
1629         double
1630           hue,
1631           lightness,
1632           saturation;
1633
1634         MagickBooleanType
1635           sync;
1636
1637         register ssize_t
1638           x;
1639
1640         register PixelPacket
1641           *restrict q;
1642
1643         if (status == MagickFalse)
1644           continue;
1645         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1646           exception);
1647         if (q == (PixelPacket *) NULL)
1648           {
1649             status=MagickFalse;
1650             continue;
1651           }
1652         for (x=0; x < (ssize_t) image->columns; x++)
1653         {
1654           hue=(double) (QuantumScale*q->red);
1655           saturation=(double) (QuantumScale*q->green);
1656           lightness=(double) (QuantumScale*q->blue);
1657           ConvertHSLToRGB(hue,saturation,lightness,&q->red,&q->green,&q->blue);
1658           q++;
1659         }
1660         sync=SyncCacheViewAuthenticPixels(image_view,exception);
1661         if (sync == MagickFalse)
1662           status=MagickFalse;
1663       }
1664       image_view=DestroyCacheView(image_view);
1665       if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
1666         return(MagickFalse);
1667       return(status);
1668     }
1669     case HWBColorspace:
1670     {
1671       /*
1672         Transform image from HWB to RGB.
1673       */
1674       if (image->storage_class == PseudoClass)
1675         {
1676           if (SyncImage(image) == MagickFalse)
1677             return(MagickFalse);
1678           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
1679             return(MagickFalse);
1680         }
1681       image_view=AcquireCacheView(image);
1682 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1683   #pragma omp parallel for schedule(dynamic,4) shared(status)
1684 #endif
1685       for (y=0; y < (ssize_t) image->rows; y++)
1686       {
1687         double
1688           blackness,
1689           hue,
1690           whiteness;
1691
1692         MagickBooleanType
1693           sync;
1694
1695         register ssize_t
1696           x;
1697
1698         register PixelPacket
1699           *restrict q;
1700
1701         if (status == MagickFalse)
1702           continue;
1703         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1704           exception);
1705         if (q == (PixelPacket *) NULL)
1706           {
1707             status=MagickFalse;
1708             continue;
1709           }
1710         for (x=0; x < (ssize_t) image->columns; x++)
1711         {
1712           hue=(double) (QuantumScale*q->red);
1713           whiteness=(double) (QuantumScale*q->green);
1714           blackness=(double) (QuantumScale*q->blue);
1715           ConvertHWBToRGB(hue,whiteness,blackness,&q->red,&q->green,&q->blue);
1716           q++;
1717         }
1718         sync=SyncCacheViewAuthenticPixels(image_view,exception);
1719         if (sync == MagickFalse)
1720           status=MagickFalse;
1721       }
1722       image_view=DestroyCacheView(image_view);
1723       if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
1724         return(MagickFalse);
1725       return(status);
1726     }
1727     case LabColorspace:
1728     {
1729       /*
1730         Transform image from Lab to RGB.
1731       */
1732       if (image->storage_class == PseudoClass)
1733         {
1734           if (SyncImage(image) == MagickFalse)
1735             return(MagickFalse);
1736           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
1737             return(MagickFalse);
1738         }
1739       image_view=AcquireCacheView(image);
1740 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1741   #pragma omp parallel for schedule(dynamic,4) shared(status)
1742 #endif
1743       for (y=0; y < (ssize_t) image->rows; y++)
1744       {
1745         double
1746           a,
1747           b,
1748           L,
1749           X,
1750           Y,
1751           Z;
1752
1753         MagickBooleanType
1754           sync;
1755
1756         register ssize_t
1757           x;
1758
1759         register PixelPacket
1760           *restrict q;
1761
1762         if (status == MagickFalse)
1763           continue;
1764         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1765           exception);
1766         if (q == (PixelPacket *) NULL)
1767           {
1768             status=MagickFalse;
1769             continue;
1770           }
1771         X=0.0;
1772         Y=0.0;
1773         Z=0.0;
1774         for (x=0; x < (ssize_t) image->columns; x++)
1775         {
1776           L=QuantumScale*q->red;
1777           a=QuantumScale*q->green;
1778           b=QuantumScale*q->blue;
1779           ConvertLabToXYZ(L,a,b,&X,&Y,&Z);
1780           ConvertXYZToRGB(X,Y,Z,&q->red,&q->green,&q->blue);
1781           q++;
1782         }
1783         sync=SyncCacheViewAuthenticPixels(image_view,exception);
1784         if (sync == MagickFalse)
1785           status=MagickFalse;
1786       }
1787       image_view=DestroyCacheView(image_view);
1788       if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
1789         return(MagickFalse);
1790       return(status);
1791     }
1792     case LogColorspace:
1793     {
1794       const char
1795         *value;
1796
1797       double
1798         black,
1799         density,
1800         film_gamma,
1801         gamma,
1802         reference_black,
1803         reference_white;
1804
1805       Quantum
1806         *logmap;
1807
1808       /*
1809         Transform Log to RGB colorspace.
1810       */
1811       density=DisplayGamma;
1812       gamma=DisplayGamma;
1813       value=GetImageProperty(image,"gamma");
1814       if (value != (const char *) NULL)
1815         gamma=1.0/StringToDouble(value) != 0.0 ? StringToDouble(value) : 1.0;
1816       film_gamma=FilmGamma;
1817       value=GetImageProperty(image,"film-gamma");
1818       if (value != (const char *) NULL)
1819         film_gamma=StringToDouble(value);
1820       reference_black=ReferenceBlack;
1821       value=GetImageProperty(image,"reference-black");
1822       if (value != (const char *) NULL)
1823         reference_black=StringToDouble(value);
1824       reference_white=ReferenceWhite;
1825       value=GetImageProperty(image,"reference-white");
1826       if (value != (const char *) NULL)
1827         reference_white=StringToDouble(value);
1828       logmap=(Quantum *) AcquireQuantumMemory((size_t) MaxMap+1UL,
1829         sizeof(*logmap));
1830       if (logmap == (Quantum *) NULL)
1831         ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1832           image->filename);
1833       black=pow(10.0,(reference_black-reference_white)*(gamma/density)*
1834         0.002/film_gamma);
1835       for (i=0; i <= (ssize_t) (reference_black*MaxMap/1024.0); i++)
1836         logmap[i]=(Quantum) 0;
1837       for ( ; i < (ssize_t) (reference_white*MaxMap/1024.0); i++)
1838         logmap[i]=ClampToQuantum((MagickRealType) QuantumRange/(1.0-black)*
1839           (pow(10.0,(1024.0*i/MaxMap-reference_white)*
1840           (gamma/density)*0.002/film_gamma)-black));
1841       for ( ; i <= (ssize_t) MaxMap; i++)
1842         logmap[i]=(Quantum) QuantumRange;
1843       if (SetImageStorageClass(image,DirectClass) == MagickFalse)
1844         return(MagickFalse);
1845       image_view=AcquireCacheView(image);
1846 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1847   #pragma omp parallel for schedule(dynamic,4) shared(status)
1848 #endif
1849       for (y=0; y < (ssize_t) image->rows; y++)
1850       {
1851         MagickBooleanType
1852           sync;
1853
1854         register ssize_t
1855           x;
1856
1857         register PixelPacket
1858           *restrict q;
1859
1860         if (status == MagickFalse)
1861           continue;
1862         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1863           exception);
1864         if (q == (PixelPacket *) NULL)
1865           {
1866             status=MagickFalse;
1867             continue;
1868           }
1869         for (x=(ssize_t) image->columns; x != 0; x--)
1870         {
1871           q->red=logmap[ScaleQuantumToMap(q->red)];
1872           q->green=logmap[ScaleQuantumToMap(q->green)];
1873           q->blue=logmap[ScaleQuantumToMap(q->blue)];
1874           q++;
1875         }
1876         sync=SyncCacheViewAuthenticPixels(image_view,exception);
1877         if (sync == MagickFalse)
1878           status=MagickFalse;
1879       }
1880       image_view=DestroyCacheView(image_view);
1881       logmap=(Quantum *) RelinquishMagickMemory(logmap);
1882       if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
1883         return(MagickFalse);
1884       return(status);
1885     }
1886     default:
1887       break;
1888   }
1889   /*
1890     Allocate the tables.
1891   */
1892   x_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
1893     sizeof(*x_map));
1894   y_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
1895     sizeof(*y_map));
1896   z_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
1897     sizeof(*z_map));
1898   if ((x_map == (TransformPacket *) NULL) ||
1899       (y_map == (TransformPacket *) NULL) ||
1900       (z_map == (TransformPacket *) NULL))
1901     {
1902       if (z_map != (TransformPacket *) NULL)
1903         z_map=(TransformPacket *) RelinquishMagickMemory(z_map);
1904       if (y_map != (TransformPacket *) NULL)
1905         y_map=(TransformPacket *) RelinquishMagickMemory(y_map);
1906       if (x_map != (TransformPacket *) NULL)
1907         x_map=(TransformPacket *) RelinquishMagickMemory(x_map);
1908       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1909         image->filename);
1910     }
1911   switch (colorspace)
1912   {
1913     case OHTAColorspace:
1914     {
1915       /*
1916         Initialize OHTA tables:
1917
1918           R = I1+1.00000*I2-0.66668*I3
1919           G = I1+0.00000*I2+1.33333*I3
1920           B = I1-1.00000*I2-0.66668*I3
1921
1922         I and Q, normally -0.5 through 0.5, must be normalized to the range 0
1923         through QuantumRange.
1924       */
1925 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1926   #pragma omp parallel for schedule(dynamic,4)
1927 #endif
1928       for (i=0; i <= (ssize_t) MaxMap; i++)
1929       {
1930         x_map[i].x=(MagickRealType) i;
1931         y_map[i].x=0.500000f*(2.000000*(MagickRealType) i-(MagickRealType)
1932           MaxMap);
1933         z_map[i].x=(-0.333340f)*(2.000000f*(MagickRealType) i-(MagickRealType)
1934           MaxMap);
1935         x_map[i].y=(MagickRealType) i;
1936         y_map[i].y=0.000000f;
1937         z_map[i].y=0.666665f*(2.000000f*(MagickRealType) i-(MagickRealType)
1938           MaxMap);
1939         x_map[i].z=(MagickRealType) i;
1940         y_map[i].z=(-0.500000f)*(2.000000f*(MagickRealType) i-(MagickRealType)
1941           MaxMap);
1942         z_map[i].z=(-0.333340f)*(2.000000f*(MagickRealType) i-(MagickRealType)
1943           MaxMap);
1944       }
1945       break;
1946     }
1947     case Rec601YCbCrColorspace:
1948     case YCbCrColorspace:
1949     {
1950       /*
1951         Initialize YCbCr tables:
1952
1953           R = Y            +1.402000*Cr
1954           G = Y-0.344136*Cb-0.714136*Cr
1955           B = Y+1.772000*Cb
1956
1957         Cb and Cr, normally -0.5 through 0.5, must be normalized to the range 0
1958         through QuantumRange.
1959       */
1960 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1961   #pragma omp parallel for schedule(dynamic,4)
1962 #endif
1963       for (i=0; i <= (ssize_t) MaxMap; i++)
1964       {
1965         x_map[i].x=(MagickRealType) i;
1966         y_map[i].x=0.000000f;
1967         z_map[i].x=(1.402000f*0.500000f)*(2.000000f*(MagickRealType) i-
1968           (MagickRealType) MaxMap);
1969         x_map[i].y=(MagickRealType) i;
1970         y_map[i].y=(-0.344136f*0.500000f)*(2.000000f*(MagickRealType) i-
1971           (MagickRealType) MaxMap);
1972         z_map[i].y=(-0.714136f*0.500000f)*(2.000000f*(MagickRealType) i-
1973           (MagickRealType) MaxMap);
1974         x_map[i].z=(MagickRealType) i;
1975         y_map[i].z=(1.772000f*0.500000f)*(2.000000f*(MagickRealType) i-
1976           (MagickRealType) MaxMap);
1977         z_map[i].z=0.000000f;
1978       }
1979       break;
1980     }
1981     case Rec709YCbCrColorspace:
1982     {
1983       /*
1984         Initialize YCbCr tables:
1985
1986           R = Y            +1.574800*Cr
1987           G = Y-0.187324*Cb-0.468124*Cr
1988           B = Y+1.855600*Cb
1989
1990         Cb and Cr, normally -0.5 through 0.5, must be normalized to the range 0
1991         through QuantumRange.
1992       */
1993 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1994   #pragma omp parallel for schedule(dynamic,4)
1995 #endif
1996       for (i=0; i <= (ssize_t) MaxMap; i++)
1997       {
1998         x_map[i].x=(MagickRealType) i;
1999         y_map[i].x=0.000000f;
2000         z_map[i].x=(1.574800f*0.50000f)*(2.00000f*(MagickRealType) i-
2001           (MagickRealType) MaxMap);
2002         x_map[i].y=(MagickRealType) i;
2003         y_map[i].y=(-0.187324f*0.50000f)*(2.00000f*(MagickRealType) i-
2004           (MagickRealType) MaxMap);
2005         z_map[i].y=(-0.468124f*0.50000f)*(2.00000f*(MagickRealType) i-
2006           (MagickRealType) MaxMap);
2007         x_map[i].z=(MagickRealType) i;
2008         y_map[i].z=(1.855600f*0.50000f)*(2.00000f*(MagickRealType) i-
2009           (MagickRealType) MaxMap);
2010         z_map[i].z=0.00000f;
2011       }
2012       break;
2013     }
2014     case sRGBColorspace:
2015     {
2016       /*
2017         Nonlinear sRGB to linear RGB.
2018
2019           R = 1.0*R+0.0*G+0.0*B
2020           G = 0.0*R+1.0*G+0.0*B
2021           B = 0.0*R+0.0*G+1.0*B
2022       */
2023 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2024   #pragma omp parallel for schedule(dynamic,4)
2025 #endif
2026       for (i=0; i <= (ssize_t) MaxMap; i++)
2027       {
2028         x_map[i].x=1.0f*(MagickRealType) i;
2029         y_map[i].x=0.0f*(MagickRealType) i;
2030         z_map[i].x=0.0f*(MagickRealType) i;
2031         x_map[i].y=0.0f*(MagickRealType) i;
2032         y_map[i].y=1.0f*(MagickRealType) i;
2033         z_map[i].y=0.0f*(MagickRealType) i;
2034         x_map[i].z=0.0f*(MagickRealType) i;
2035         y_map[i].z=0.0f*(MagickRealType) i;
2036         z_map[i].z=1.0f*(MagickRealType) i;
2037       }
2038       break;
2039     }
2040     case XYZColorspace:
2041     {
2042       /*
2043         Initialize CIE XYZ tables (ITU R-709 RGB):
2044
2045           R =  3.2404542*X-1.5371385*Y-0.4985314*Z
2046           G = -0.9692660*X+1.8760108*Y+0.0415560*Z
2047           B =  0.0556434*X-0.2040259*Y+1.057225*Z
2048       */
2049 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2050   #pragma omp parallel for schedule(dynamic,4)
2051 #endif
2052       for (i=0; i <= (ssize_t) MaxMap; i++)
2053       {
2054         x_map[i].x=3.2404542f*(MagickRealType) i;
2055         x_map[i].y=(-0.9692660f)*(MagickRealType) i;
2056         x_map[i].z=0.0556434f*(MagickRealType) i;
2057         y_map[i].x=(-1.5371385f)*(MagickRealType) i;
2058         y_map[i].y=1.8760108f*(MagickRealType) i;
2059         y_map[i].z=(-0.2040259f)*(MagickRealType) i;
2060         z_map[i].x=(-0.4985314f)*(MagickRealType) i;
2061         z_map[i].y=0.0415560f*(MagickRealType) i;
2062         z_map[i].z=1.0572252f*(MagickRealType) i;
2063       }
2064       break;
2065     }
2066     case YCCColorspace:
2067     {
2068       /*
2069         Initialize YCC tables:
2070
2071           R = Y            +1.340762*C2
2072           G = Y-0.317038*C1-0.682243*C2
2073           B = Y+1.632639*C1
2074
2075         YCC is scaled by 1.3584.  C1 zero is 156 and C2 is at 137.
2076       */
2077 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2078   #pragma omp parallel for schedule(dynamic,4)
2079 #endif
2080       for (i=0; i <= (ssize_t) MaxMap; i++)
2081       {
2082         x_map[i].x=1.3584000f*(MagickRealType) i;
2083         y_map[i].x=0.0000000f;
2084         z_map[i].x=1.8215000f*((MagickRealType) i-(MagickRealType)
2085           ScaleQuantumToMap(ScaleCharToQuantum(137)));
2086         x_map[i].y=1.3584000f*(MagickRealType) i;
2087         y_map[i].y=(-0.4302726f)*((MagickRealType) i-(MagickRealType)
2088           ScaleQuantumToMap(ScaleCharToQuantum(156)));
2089         z_map[i].y=(-0.9271435f)*((MagickRealType) i-(MagickRealType)
2090           ScaleQuantumToMap(ScaleCharToQuantum(137)));
2091         x_map[i].z=1.3584000f*(MagickRealType) i;
2092         y_map[i].z=2.2179000f*((MagickRealType) i-(MagickRealType)
2093           ScaleQuantumToMap(ScaleCharToQuantum(156)));
2094         z_map[i].z=0.0000000f;
2095       }
2096       break;
2097     }
2098     case YIQColorspace:
2099     {
2100       /*
2101         Initialize YIQ tables:
2102
2103           R = Y+0.95620*I+0.62140*Q
2104           G = Y-0.27270*I-0.64680*Q
2105           B = Y-1.10370*I+1.70060*Q
2106
2107         I and Q, normally -0.5 through 0.5, must be normalized to the range 0
2108         through QuantumRange.
2109       */
2110 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2111   #pragma omp parallel for schedule(dynamic,4)
2112 #endif
2113       for (i=0; i <= (ssize_t) MaxMap; i++)
2114       {
2115         x_map[i].x=(MagickRealType) i;
2116         y_map[i].x=0.47810f*(2.00000f*(MagickRealType) i-(MagickRealType)
2117           MaxMap);
2118         z_map[i].x=0.31070f*(2.00000f*(MagickRealType) i-(MagickRealType)
2119           MaxMap);
2120         x_map[i].y=(MagickRealType) i;
2121         y_map[i].y=(-0.13635f)*(2.00000f*(MagickRealType) i-(MagickRealType)
2122           MaxMap);
2123         z_map[i].y=(-0.32340f)*(2.00000f*(MagickRealType) i-(MagickRealType)
2124           MaxMap);
2125         x_map[i].z=(MagickRealType) i;
2126         y_map[i].z=(-0.55185f)*(2.00000f*(MagickRealType) i-(MagickRealType)
2127           MaxMap);
2128         z_map[i].z=0.85030f*(2.00000f*(MagickRealType) i-(MagickRealType)
2129           MaxMap);
2130       }
2131       break;
2132     }
2133     case YPbPrColorspace:
2134     {
2135       /*
2136         Initialize YPbPr tables:
2137
2138           R = Y            +1.402000*C2
2139           G = Y-0.344136*C1+0.714136*C2
2140           B = Y+1.772000*C1
2141
2142         Pb and Pr, normally -0.5 through 0.5, must be normalized to the range 0
2143         through QuantumRange.
2144       */
2145 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2146   #pragma omp parallel for schedule(dynamic,4)
2147 #endif
2148       for (i=0; i <= (ssize_t) MaxMap; i++)
2149       {
2150         x_map[i].x=(MagickRealType) i;
2151         y_map[i].x=0.000000f;
2152         z_map[i].x=0.701000f*(2.00000f*(MagickRealType) i-(MagickRealType)
2153           MaxMap);
2154         x_map[i].y=(MagickRealType) i;
2155         y_map[i].y=(-0.172068f)*(2.00000f*(MagickRealType) i-(MagickRealType)
2156           MaxMap);
2157         z_map[i].y=0.357068f*(2.00000f*(MagickRealType) i-(MagickRealType)
2158           MaxMap);
2159         x_map[i].z=(MagickRealType) i;
2160         y_map[i].z=0.88600f*(2.00000f*(MagickRealType) i-(MagickRealType)
2161           MaxMap);
2162         z_map[i].z=0.00000f;
2163       }
2164       break;
2165     }
2166     case YUVColorspace:
2167     default:
2168     {
2169       /*
2170         Initialize YUV tables:
2171
2172           R = Y          +1.13980*V
2173           G = Y-0.39380*U-0.58050*V
2174           B = Y+2.02790*U
2175
2176         U and V, normally -0.5 through 0.5, must be normalized to the range 0
2177         through QuantumRange.
2178       */
2179 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2180   #pragma omp parallel for schedule(dynamic,4)
2181 #endif
2182       for (i=0; i <= (ssize_t) MaxMap; i++)
2183       {
2184         x_map[i].x=(MagickRealType) i;
2185         y_map[i].x=0.00000f;
2186         z_map[i].x=0.56990f*(2.0000f*(MagickRealType) i-(MagickRealType)
2187           MaxMap);
2188         x_map[i].y=(MagickRealType) i;
2189         y_map[i].y=(-0.19690f)*(2.00000f*(MagickRealType) i-(MagickRealType)
2190           MaxMap);
2191         z_map[i].y=(-0.29025f)*(2.00000f*(MagickRealType) i-(MagickRealType)
2192           MaxMap);
2193         x_map[i].z=(MagickRealType) i;
2194         y_map[i].z=1.01395f*(2.00000f*(MagickRealType) i-(MagickRealType)
2195           MaxMap);
2196         z_map[i].z=0.00000f;
2197       }
2198       break;
2199     }
2200   }
2201   /*
2202     Convert to RGB.
2203   */
2204   switch (image->storage_class)
2205   {
2206     case DirectClass:
2207     default:
2208     {
2209       /*
2210         Convert DirectClass image.
2211       */
2212       image_view=AcquireCacheView(image);
2213 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2214   #pragma omp parallel for schedule(dynamic,4) shared(status)
2215 #endif
2216       for (y=0; y < (ssize_t) image->rows; y++)
2217       {
2218         MagickBooleanType
2219           sync;
2220
2221         MagickPixelPacket
2222           pixel;
2223
2224         register ssize_t
2225           x;
2226
2227         register PixelPacket
2228           *restrict q;
2229
2230         if (status == MagickFalse)
2231           continue;
2232         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2233           exception);
2234         if (q == (PixelPacket *) NULL)
2235           {
2236             status=MagickFalse;
2237             continue;
2238           }
2239         for (x=0; x < (ssize_t) image->columns; x++)
2240         {
2241           register size_t
2242             blue,
2243             green,
2244             red;
2245
2246           red=ScaleQuantumToMap(q->red);
2247           green=ScaleQuantumToMap(q->green);
2248           blue=ScaleQuantumToMap(q->blue);
2249           pixel.red=x_map[red].x+y_map[green].x+z_map[blue].x;
2250           pixel.green=x_map[red].y+y_map[green].y+z_map[blue].y;
2251           pixel.blue=x_map[red].z+y_map[green].z+z_map[blue].z;
2252           switch (colorspace)
2253           {
2254             case YCCColorspace:
2255             {
2256 #if !defined(MAGICKCORE_HDRI_SUPPORT)
2257               pixel.red=(MagickRealType) ScaleCharToQuantum(YCCMap[RoundToYCC(
2258                 255.0*QuantumScale*pixel.red)]);
2259               pixel.green=(MagickRealType) ScaleCharToQuantum(YCCMap[RoundToYCC(
2260                 255.0*QuantumScale*pixel.green)]);
2261               pixel.blue=(MagickRealType) ScaleCharToQuantum(YCCMap[RoundToYCC(
2262                 255.0*QuantumScale*pixel.blue)]);
2263 #endif
2264               break;
2265             }
2266             case sRGBColorspace:
2267             {
2268               if ((QuantumScale*pixel.red) <= 0.0031308)
2269                 pixel.red*=12.92f;
2270               else
2271                 pixel.red=(MagickRealType) QuantumRange*(1.055*
2272                   pow(QuantumScale*pixel.red,(1.0/2.4))-0.055);
2273               if ((QuantumScale*pixel.green) <= 0.0031308)
2274                 pixel.green*=12.92f;
2275               else
2276                 pixel.green=(MagickRealType) QuantumRange*(1.055*
2277                   pow(QuantumScale*pixel.green,(1.0/2.4))-0.055);
2278               if ((QuantumScale*pixel.blue) <= 0.0031308)
2279                 pixel.blue*=12.92f;
2280               else
2281                 pixel.blue=(MagickRealType) QuantumRange*(1.055*
2282                   pow(QuantumScale*pixel.blue,(1.0/2.4))-0.055);
2283               break;
2284             }
2285             default:
2286               break;
2287           }
2288           q->red=ScaleMapToQuantum((MagickRealType) MaxMap*QuantumScale*
2289             pixel.red);
2290           q->green=ScaleMapToQuantum((MagickRealType) MaxMap*QuantumScale*
2291             pixel.green);
2292           q->blue=ScaleMapToQuantum((MagickRealType) MaxMap*QuantumScale*
2293             pixel.blue);
2294           q++;
2295         }
2296         sync=SyncCacheViewAuthenticPixels(image_view,exception);
2297         if (sync == MagickFalse)
2298           status=MagickFalse;
2299         if (image->progress_monitor != (MagickProgressMonitor) NULL)
2300           {
2301             MagickBooleanType
2302               proceed;
2303
2304 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2305   #pragma omp critical (MagickCore_TransformRGBImage)
2306 #endif
2307             proceed=SetImageProgress(image,TransformRGBImageTag,progress++,
2308               image->rows);
2309             if (proceed == MagickFalse)
2310               status=MagickFalse;
2311           }
2312       }
2313       image_view=DestroyCacheView(image_view);
2314       break;
2315     }
2316     case PseudoClass:
2317     {
2318       /*
2319         Convert PseudoClass image.
2320       */
2321       image_view=AcquireCacheView(image);
2322 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2323   #pragma omp parallel for schedule(dynamic,4) shared(status)
2324 #endif
2325       for (i=0; i < (ssize_t) image->colors; i++)
2326       {
2327         MagickPixelPacket
2328           pixel;
2329
2330         register size_t
2331           blue,
2332           green,
2333           red;
2334
2335         red=ScaleQuantumToMap(image->colormap[i].red);
2336         green=ScaleQuantumToMap(image->colormap[i].green);
2337         blue=ScaleQuantumToMap(image->colormap[i].blue);
2338         pixel.red=x_map[red].x+y_map[green].x+z_map[blue].x;
2339         pixel.green=x_map[red].y+y_map[green].y+z_map[blue].y;
2340         pixel.blue=x_map[red].z+y_map[green].z+z_map[blue].z;
2341         switch (colorspace)
2342         {
2343           case YCCColorspace:
2344           {
2345 #if !defined(MAGICKCORE_HDRI_SUPPORT)
2346             image->colormap[i].red=ScaleCharToQuantum(YCCMap[RoundToYCC(
2347               255.0*QuantumScale*pixel.red)]);
2348             image->colormap[i].green=ScaleCharToQuantum(YCCMap[RoundToYCC(
2349               255.0*QuantumScale*pixel.green)]);
2350             image->colormap[i].blue=ScaleCharToQuantum(YCCMap[RoundToYCC(
2351               255.0*QuantumScale*pixel.blue)]);
2352 #endif
2353             break;
2354           }
2355           case sRGBColorspace:
2356           {
2357             if ((QuantumScale*pixel.red) <= 0.0031308)
2358               pixel.red*=12.92f;
2359             else
2360               pixel.red=(MagickRealType) QuantumRange*(1.055*pow(QuantumScale*
2361                 pixel.red,(1.0/2.4))-0.055);
2362             if ((QuantumScale*pixel.green) <= 0.0031308)
2363               pixel.green*=12.92f;
2364             else
2365               pixel.green=(MagickRealType) QuantumRange*(1.055*pow(QuantumScale*
2366                 pixel.green,(1.0/2.4))-0.055);
2367             if ((QuantumScale*pixel.blue) <= 0.0031308)
2368               pixel.blue*=12.92f;
2369             else
2370               pixel.blue=(MagickRealType) QuantumRange*(1.055*pow(QuantumScale*
2371                 pixel.blue,(1.0/2.4))-0.055);
2372           }
2373           default:
2374           {
2375             image->colormap[i].red=ScaleMapToQuantum((MagickRealType) MaxMap*
2376               QuantumScale*pixel.red);
2377             image->colormap[i].green=ScaleMapToQuantum((MagickRealType) MaxMap*
2378               QuantumScale*pixel.green);
2379             image->colormap[i].blue=ScaleMapToQuantum((MagickRealType) MaxMap*
2380               QuantumScale*pixel.blue);
2381             break;
2382           }
2383         }
2384       }
2385       image_view=DestroyCacheView(image_view);
2386       (void) SyncImage(image);
2387       break;
2388     }
2389   }
2390   /*
2391     Relinquish resources.
2392   */
2393   z_map=(TransformPacket *) RelinquishMagickMemory(z_map);
2394   y_map=(TransformPacket *) RelinquishMagickMemory(y_map);
2395   x_map=(TransformPacket *) RelinquishMagickMemory(x_map);
2396   if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
2397     return(MagickFalse);
2398   return(MagickTrue);
2399 }