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