source: ImageMagick/trunk/MagickCore/colorspace.c @ 7518

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