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