root / ImageMagick / branches / ImageMagick-6.3.5 / magick / colorspace.c

Revision 8037, 55.8 kB (checked in by cristy, 14 months ago)
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%                   ImageMagick Image Colorspace Methods                      %
14%                                                                             %
15%                              Software Design                                %
16%                                John Cristy                                  %
17%                                 July 1992                                   %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2007 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 "magick/studio.h"
43#include "magick/property.h"
44#include "magick/cache.h"
45#include "magick/color.h"
46#include "magick/color-private.h"
47#include "magick/colorspace.h"
48#include "magick/colorspace-private.h"
49#include "magick/exception.h"
50#include "magick/exception-private.h"
51#include "magick/image.h"
52#include "magick/image-private.h"
53#include "magick/gem.h"
54#include "magick/memory_.h"
55#include "magick/monitor.h"
56#include "magick/pixel-private.h"
57#include "magick/quantize.h"
58#include "magick/quantum.h"
59#include "magick/string_.h"
60#include "magick/utility.h"
61
62/*
63%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
64%                                                                             %
65%                                                                             %
66%                                                                             %
67+     R G B T r a n s f o r m I m a g e                                       %
68%                                                                             %
69%                                                                             %
70%                                                                             %
71%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72%
73%  RGBTransformImage() converts the reference image from RGB to an alternate
74%  colorspace.  The transformation matrices are not the standard ones: the
75%  weights are rescaled to normalized the range of the transformed values to
76%  be [0..QuantumRange].
77%
78%  The format of the RGBTransformImage method is:
79%
80%      MagickBooleanType RGBTransformImage(Image *image,
81%        const ColorspaceType colorspace)
82%
83%  A description of each parameter follows:
84%
85%    o image: The image.
86%
87%    o colorspace: the colorspace to transform the image to.
88%
89*/
90
91static inline void ConvertRGBToXYZ(const Quantum red,const Quantum green,
92  const Quantum blue,double *X,double *Y,double *Z)
93{
94  double
95    b,
96    g,
97    r;
98
99  assert(X != (double *) NULL);
100  assert(Y != (double *) NULL);
101  assert(Z != (double *) NULL);
102  r=QuantumScale*red;
103  g=QuantumScale*green;
104  b=QuantumScale*blue;
105  *X=0.4124240*r+0.3575790*g+0.1804640*b;
106  *Y=0.2126560*r+0.7151580*g+0.0721856*b;
107  *Z=0.0193324*r+0.1191930*g+0.9504440*b;
108}
109
110static inline void ConvertXYZToLab(const double X,const double Y,const double Z,
111  double *L,double *a,double *b)
112{
113  double
114    x,
115    y,
116    z;
117
118  assert(L != (double *) NULL);
119  assert(a != (double *) NULL);
120  assert(b != (double *) NULL);
121  x=X/0.9504559271;
122  if (x > (216/24389.0))
123    x=pow(x,1.0/3.0);
124  else 
125    x=(7.787*x)+(16.0/116.0);
126  y=Y/1.00000;
127  if (y > (216/24389.0))
128    y=pow(y,1.0/3.0);
129  else
130    y=(7.787*y)+(16.0/116.0);
131  z=Z/1.0890577508;
132  if (z > (216/24389.0))
133    z=pow(z,1.0/3.0);
134  else
135    z=(7.787*z)+(16.0/116.0);
136  *L=0.5*((1.160*y)-0.160+1.0);
137  *a=0.5*(5.000*(x-y)+1.0);
138  *b=0.5*(2.000*(y-z)+1.0);
139}
140
141MagickExport MagickBooleanType RGBTransformImage(Image *image,
142  const ColorspaceType colorspace)
143{
144#define RGBTransformImageTag  "RGBTransform/Image"
145
146  long
147    y;
148
149  IndexPacket
150    *indexes;
151
152  MagickBooleanType
153    status;
154
155  MagickPixelPacket
156    pixel;
157
158  PrimaryInfo
159    primary_info,
160    *x_map,
161    *y_map,
162    *z_map;
163
164  register long
165    i,
166    x;
167
168  register PixelPacket
169    *q;
170
171  assert(image != (Image *) NULL);
172  assert(image->signature == MagickSignature);
173  if (image->debug != MagickFalse)
174    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
175  assert(colorspace != RGBColorspace);
176  assert(colorspace != TransparentColorspace);
177  assert(colorspace != UndefinedColorspace);
178  switch (image->colorspace)
179  {
180    case GRAYColorspace:
181    case Rec601LumaColorspace:
182    case Rec709LumaColorspace:
183    case RGBColorspace:
184    case TransparentColorspace:
185      break;
186    default:
187    {
188      (void) SetImageColorspace(image,image->colorspace);
189      break;
190    }
191  }
192  image->colorspace=colorspace;
193  (void) SetImagePixels(image,0,0,image->columns,1);
194  switch (colorspace)
195  {
196    case CMYColorspace:
197    {
198      /*
199        Convert RGB to CMY colorspace.
200      */
201      if (image->storage_class == PseudoClass)
202        {
203          if (SyncImage(image) == MagickFalse)
204            return(MagickFalse);
205          if (SetImageStorageClass(image,DirectClass) == MagickFalse)
206            return(MagickFalse);
207        }
208      for (y=0; y < (long) image->rows; y++)
209      {
210        q=GetImagePixels(image,0,y,image->columns,1);
211        if (q == (PixelPacket *) NULL)
212          break;
213        indexes=GetIndexes(image);
214        for (x=0; x < (long) image->columns; x++)
215        {
216          q->red=RoundToQuantum((MagickRealType) QuantumRange-q->red);
217          q->green=RoundToQuantum((MagickRealType) QuantumRange-q->green);
218          q->blue=RoundToQuantum((MagickRealType) QuantumRange-q->blue);
219          q++;
220        }
221        if (SyncImagePixels(image) == MagickFalse)
222          break;
223      }
224      return(MagickTrue);
225    }
226    case CMYKColorspace:
227    {
228      MagickPixelPacket
229        pixel;
230
231      /*
232        Convert RGB to CMYK colorspace.
233      */
234      if (image->storage_class == PseudoClass)
235        {
236          if (SyncImage(image) == MagickFalse)
237            return(MagickFalse);
238          if (SetImageStorageClass(image,DirectClass) == MagickFalse)
239            return(MagickFalse);
240        }
241      GetMagickPixelPacket(image,&pixel);
242      for (y=0; y < (long) image->rows; y++)
243      {
244        q=GetImagePixels(image,0,y,image->columns,1);
245        if (q == (PixelPacket *) NULL)
246          break;
247        indexes=GetIndexes(image);
248        for (x=0; x < (long) image->columns; x++)
249        {
250          SetMagickPixelPacket(image,q,indexes+x,&pixel);
251          ConvertRGBToCMYK(&pixel);
252          SetPixelPacket(image,&pixel,q,indexes+x);
253          q++;
254        }
255        if (SyncImagePixels(image) == MagickFalse)
256          break;
257      }
258      return(MagickTrue);
259    }
260    case HSBColorspace:
261    {
262      double
263        brightness,
264        hue,
265        saturation;
266
267      /*
268        Transform image from RGB to HSB.
269      */
270      if (image->storage_class == PseudoClass)
271        {
272          if (SyncImage(image) == MagickFalse)
273            return(MagickFalse);
274          if (SetImageStorageClass(image,DirectClass) == MagickFalse)
275            return(MagickFalse);
276        }
277      hue=0.0;
278      saturation=0.0;
279      brightness=0.0;
280      for (y=0; y < (long) image->rows; y++)
281      {
282        q=GetImagePixels(image,0,y,image->columns,1);
283        if (q == (PixelPacket *) NULL)
284          break;
285        for (x=0; x < (long) image->columns; x++)
286        {
287          ConvertRGBToHSB(q->red,q->green,q->blue,&hue,&saturation,&brightness);
288          q->red=RoundToQuantum((MagickRealType) QuantumRange*hue);
289          q->green=RoundToQuantum((MagickRealType) QuantumRange*saturation);
290          q->blue=RoundToQuantum((MagickRealType) QuantumRange*brightness);
291          q++;
292        }
293        if (SyncImagePixels(image) == MagickFalse)
294          break;
295      }
296      return(MagickTrue);
297    }
298    case HSLColorspace:
299    {
300      double
301        hue,
302        luminosity,
303        saturation;
304
305      /*
306        Transform image from RGB to HSL.
307      */
308      if (image->storage_class == PseudoClass)
309        {
310          if (SyncImage(image) == MagickFalse)
311            return(MagickFalse);
312          if (SetImageStorageClass(image,DirectClass) == MagickFalse)
313            return(MagickFalse);
314        }
315      hue=0.0;
316      saturation=0.0;
317      luminosity=0.0;
318      for (y=0; y < (long) image->rows; y++)
319      {
320        q=GetImagePixels(image,0,y,image->columns,1);
321        if (q == (PixelPacket *) NULL)
322          break;
323        for (x=0; x < (long) image->columns; x++)
324        {
325          ConvertRGBToHSL(q->red,q->green,q->blue,&hue,&saturation,&luminosity);
326          q->red=RoundToQuantum((MagickRealType) QuantumRange*hue);
327          q->green=RoundToQuantum((MagickRealType) QuantumRange*saturation);
328          q->blue=RoundToQuantum((MagickRealType) QuantumRange*luminosity);
329          q++;
330        }
331        if (SyncImagePixels(image) == MagickFalse)
332          break;
333      }
334      return(MagickTrue);
335    }
336    case HWBColorspace:
337    {
338      double
339        blackness,
340        hue,
341        whiteness;
342
343      /*
344        Transform image from RGB to HWB.
345      */
346      if (image->storage_class == PseudoClass)
347        {
348          if (SyncImage(image) == MagickFalse)
349            return(MagickFalse);
350          if (SetImageStorageClass(image,DirectClass) == MagickFalse)
351            return(MagickFalse);
352        }
353      hue=0.0;
354      whiteness=0.0;
355      blackness=0.0;
356      for (y=0; y < (long) image->rows; y++)
357      {
358        q=GetImagePixels(image,0,y,image->columns,1);
359        if (q == (PixelPacket *) NULL)
360          break;
361        for (x=0; x < (long) image->columns; x++)
362        {
363          ConvertRGBToHWB(q->red,q->green,q->blue,&hue,&whiteness,&blackness);
364          q->red=RoundToQuantum((MagickRealType) QuantumRange*hue);
365          q->green=RoundToQuantum((MagickRealType) QuantumRange*whiteness);
366          q->blue=RoundToQuantum((MagickRealType) QuantumRange*blackness);
367          q++;
368        }
369        if (SyncImagePixels(image) == MagickFalse)
370          break;
371      }
372      return(MagickTrue);
373    }
374    case LabColorspace:
375    {
376      double
377        a,
378        b,
379        L,
380        X,
381        Y,
382        Z;
383
384      /*
385        Transform image from RGB to Lab.
386      */
387      if (image->storage_class == PseudoClass)
388        {
389          if (SyncImage(image) == MagickFalse)
390            return(MagickFalse);
391          if (SetImageStorageClass(image,DirectClass) == MagickFalse)
392            return(MagickFalse);
393        }
394      L=0.0;
395      a=0.0;
396      b=0.0;
397      X=0.0;
398      Y=0.0;
399      Z=0.0;
400      for (y=0; y < (long) image->rows; y++)
401      {
402        q=GetImagePixels(image,0,y,image->columns,1);
403        if (q == (PixelPacket *) NULL)
404          break;
405        for (x=0; x < (long) image->columns; x++)
406        {
407          ConvertRGBToXYZ(q->red,q->green,q->blue,&X,&Y,&Z);
408          ConvertXYZToLab(X,Y,Z,&L,&a,&b);
409          q->red=RoundToQuantum((MagickRealType) QuantumRange*L);
410          q->green=RoundToQuantum((MagickRealType) QuantumRange*a);
411          q->blue=RoundToQuantum((MagickRealType) QuantumRange*b);
412          q++;
413        }
414        if (SyncImagePixels(image) == MagickFalse)
415          break;
416      }
417      return(MagickTrue);
418    }
419    case LogColorspace:
420    {
421#define ReferenceBlack  95.0
422#define ReferenceWhite  685.0
423#define DisplayGamma  (1.0/1.7)
424
425      const char
426        *value;
427
428      double
429        black,
430        density,
431        gamma,
432        reference_black,
433        reference_white;
434
435      Quantum
436        *logmap;
437
438      /*
439        Transform RGB to Log colorspace.
440      */
441      density=2.03728;
442      gamma=DisplayGamma;
443      value=GetImageProperty(image,"Gamma");
444      if (value != (const char *) NULL)
445        gamma=1.0/atof(value) != 0.0 ? atof(value) : 1.0;
446      reference_black=ReferenceBlack;
447      value=GetImageProperty(image,"reference-black");
448      if (value != (const char *) NULL)
449        reference_black=atof(value);
450      reference_white=ReferenceWhite;
451      value=GetImageProperty(image,"reference-white");
452      if (value != (const char *) NULL)
453        reference_white=atof(value);
454      logmap=(Quantum *) AcquireQuantumMemory((size_t) MaxMap+1UL,
455        sizeof(*logmap));
456      if (logmap == (Quantum *) NULL)
457        ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
458          image->filename);
459      black=pow(10.0,(reference_black-reference_white)*(gamma/density)*
460        0.002/0.6);
461      for (i=0; i <= (long) MaxMap; i++)
462        logmap[i]=ScaleMapToQuantum((MagickRealType) (MaxMap*(reference_white+
463          log10(black+((double) i/MaxMap)*(1.0-black))/((gamma/density)*
464          0.002/0.6))/1024.0+0.5));
465      for (y=0; y < (long) image->rows; y++)
466      {
467        q=GetImagePixels(image,0,y,image->columns,1);
468        if (q == (PixelPacket *) NULL)
469          break;
470        for (x=(long) image->columns; x != 0; x--)
471        {
472          q->red=logmap[ScaleQuantumToMap(q->red)];
473          q->green=logmap[ScaleQuantumToMap(q->green)];
474          q->blue=logmap[ScaleQuantumToMap(q->blue)];
475          q++;
476        }
477        if (SyncImagePixels(image) == MagickFalse)
478          break;
479      }
480      logmap=(Quantum *) RelinquishMagickMemory(logmap);
481      return(y == (long) image->rows ? MagickTrue : MagickFalse);
482    }
483    default:
484      break;
485  }
486  /*
487    Allocate the tables.
488  */
489  x_map=(PrimaryInfo *) AcquireQuantumMemory((size_t) MaxMap+1UL,
490    sizeof(*x_map));
491  y_map=(PrimaryInfo *) AcquireQuantumMemory((size_t) MaxMap+1UL,
492    sizeof(*y_map));
493  z_map=(PrimaryInfo *) AcquireQuantumMemory((size_t) MaxMap+1UL,
494    sizeof(*z_map));
495  if ((x_map == (PrimaryInfo *) NULL) || (y_map == (PrimaryInfo *) NULL) ||
496      (z_map == (PrimaryInfo *) NULL))
497    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
498      image->filename);
499  (void) ResetMagickMemory(&primary_info,0,sizeof(primary_info));
500  switch (colorspace)
501  {
502    case OHTAColorspace:
503    {
504      /*
505        Initialize OHTA tables:
506
507          I1 = 0.33333*R+0.33334*G+0.33333*B
508          I2 = 0.50000*R+0.00000*G-0.50000*B
509          I3 =-0.25000*R+0.50000*G-0.25000*B
510
511        I and Q, normally -0.5 through 0.5, are normalized to the range 0
512        through QuantumRange.
513      */
514      primary_info.y=(double) (MaxMap+1.0)/2.0;
515      primary_info.z=(double) (MaxMap+1.0)/2.0;
516      for (i=0; i <= (long) MaxMap; i++)
517      {
518        x_map[i].x=0.33333*i;
519        y_map[i].x=0.33334*i;
520        z_map[i].x=0.33333*i;
521        x_map[i].y=0.50000*i;
522        y_map[i].y=0.00000*i;
523        z_map[i].y=(-0.50000)*i;
524        x_map[i].z=(-0.25000)*i;
525        y_map[i].z=0.50000*i;
526        z_map[i].z=(-0.25000)*i;
527      }
528      break;
529    }
530    case Rec601LumaColorspace:
531    case GRAYColorspace:
532    {
533      /*
534        Initialize Rec601 luma tables:
535
536          G = 0.29900*R+0.58700*G+0.11400*B
537      */
538      for (i=0; i <= (long) MaxMap; i++)
539      {
540        x_map[i].x=0.29900*i;
541        y_map[i].x=0.58700*i;
542        z_map[i].x=0.11400*i;
543        x_map[i].y=0.29900*i;
544        y_map[i].y=0.58700*i;
545        z_map[i].y=0.11400*i;
546        x_map[i].z=0.29900*i;
547        y_map[i].z=0.58700*i;
548        z_map[i].z=0.11400*i;
549      }
550      break;
551    }
552    case Rec601YCbCrColorspace:
553    case YCbCrColorspace:
554    {
555      /*
556        Initialize YCbCr tables (ITU-R BT.601):
557
558          Y =  0.299000*R+0.587000*G+0.114000*B
559          Cb= -0.168736*R-0.331264*G+0.500000*B
560          Cr=  0.500000*R-0.418688*G-0.081312*B
561
562        Cb and Cr, normally -0.5 through 0.5, are normalized to the range 0
563        through QuantumRange.
564      */
565      primary_info.y=(double) (MaxMap+1.0)/2.0;
566      primary_info.z=(double) (MaxMap+1.0)/2.0;
567      for (i=0; i <= (long) MaxMap; i++)
568      {
569        x_map[i].x=0.299000*i;
570        y_map[i].x=0.587000*i;
571        z_map[i].x=0.114000*i;
572        x_map[i].y=(-0.168730)*i;
573        y_map[i].y=(-0.331264)*i;
574        z_map[i].y=0.500000*i;
575        x_map[i].z=0.500000*i;
576        y_map[i].z=(-0.418688)*i;
577        z_map[i].z=(-0.081312)*i;
578      }
579      break;
580    }
581    case Rec709LumaColorspace:
582    {
583      /*
584        Initialize Rec709 luma tables:
585
586          G = 0.21260*R+0.71520*G+0.07220*B
587      */
588      for (i=0; i <= (long) MaxMap; i++)
589      {
590        x_map[i].x=0.21260*i;
591        y_map[i].x=0.71520*i;
592        z_map[i].x=0.07220*i;
593        x_map[i].y=0.21260*i;
594        y_map[i].y=0.71520*i;
595        z_map[i].y=0.07220*i;
596        x_map[i].z=0.21260*i;
597        y_map[i].z=0.71520*i;
598        z_map[i].z=0.07220*i;
599      }
600      break;
601    }
602    case Rec709YCbCrColorspace:
603    {
604      /*
605        Initialize YCbCr tables (ITU-R BT.709):
606
607          Y =  0.212600*R+0.715200*G+0.072200*B
608          Cb= -0.114572*R-0.385428*G+0.500000*B
609          Cr=  0.500000*R-0.454153*G-0.045847*B
610
611        Cb and Cr, normally -0.5 through 0.5, are normalized to the range 0
612        through QuantumRange.
613      */
614      primary_info.y=(double) (MaxMap+1.0)/2.0;
615      primary_info.z=(double) (MaxMap+1.0)/2.0;
616      for (i=0; i <= (long) MaxMap; i++)
617      {
618        x_map[i].x=0.212600*i;
619        y_map[i].x=0.715200*i;
620        z_map[i].x=0.072200*i;
621        x_map[i].y=(-0.114572)*i;
622        y_map[i].y=(-0.385428)*i;
623        z_map[i].y=0.500000*i;
624        x_map[i].z=0.500000*i;
625        y_map[i].z=(-0.454153)*i;
626        z_map[i].z=(-0.045847)*i;
627      }
628      break;
629    }
630    case sRGBColorspace:
631    {
632      double
633        v;
634
635      /*
636        Linear RGB to nonlinear sRGB (http://www.w3.org/Graphics/Color/sRGB):
637
638          R = 1.0*R+0.0*G+0.0*B
639          G = 0.0*R+0.1*G+0.0*B
640          B = 0.0*R+0.0*G+1.0*B
641      */
642      for (i=0; i <= (long) MaxMap; i++)
643      {
644        v=(double) i/MaxMap;
645        if (((double) i/MaxMap) <= 0.03928)
646          v/=12.92;
647        else
648          v=(double) MaxMap*pow((((double) i/MaxMap)+0.055)/1.055,2.4);
649        x_map[i].x=1.0*v;
650        y_map[i].x=0.0*v;
651        z_map[i].x=0.0*v;
652        x_map[i].y=0.0*v;
653        y_map[i].y=1.0*v;
654        z_map[i].y=0.0*v;
655        x_map[i].z=0.0*v;
656        y_map[i].z=0.0*v;
657        z_map[i].z=1.0*v;
658      }
659      break;
660    }
661    case XYZColorspace:
662    {
663      /*
664        Initialize CIE XYZ tables (ITU-R 709 RGB):
665
666          X = 0.4124240*R+0.3575790*G+0.1804640*B
667          Y = 0.2126560*R+0.7151580*G+0.0721856*B
668          Z = 0.0193324*R+0.1191930*G+0.9504440*B
669      */
670      for (i=0; i <= (long) MaxMap; i++)
671      {
672        x_map[i].x=0.4124240*i;
673        y_map[i].x=0.3575790*i;
674        z_map[i].x=0.1804640*i;
675        x_map[i].y=0.2126560*i;
676        y_map[i].y=0.7151580*i;
677        z_map[i].y=0.0721856*i;
678        x_map[i].z=0.0193324*i;
679        y_map[i].z=0.1191930*i;
680        z_map[i].z=0.9504440*i;
681      }
682      break;
683    }
684    case YCCColorspace:
685    {
686      /*
687        Initialize YCC tables:
688
689          Y =  0.29900*R+0.58700*G+0.11400*B
690          C1= -0.29900*R-0.58700*G+0.88600*B
691          C2=  0.70100*R-0.58700*G-0.11400*B
692
693        YCC is scaled by 1.3584.  C1 zero is 156 and C2 is at 137.
694      */
695      primary_info.y=(double) ScaleQuantumToMap(ScaleCharToQuantum(156));
696      primary_info.z=(double) ScaleQuantumToMap(ScaleCharToQuantum(137));
697      for (i=0; i <= (long) (0.018*MaxMap); i++)
698      {
699        x_map[i].x=0.003962014134275617*i;
700        y_map[i].x=0.007778268551236748*i;
701        z_map[i].x=0.001510600706713781*i;
702        x_map[i].y=(-0.002426619775463276)*i;
703        y_map[i].y=(-0.004763965913702149)*i;
704        z_map[i].y=0.007190585689165425*i;
705        x_map[i].z=0.006927257754597858*i;
706        y_map[i].z=(-0.005800713697502058)*i;
707        z_map[i].z=(-0.0011265440570958)*i;
708      }
709      for ( ; i <= (long) MaxMap; i++)
710      {
711        x_map[i].x=0.2201118963486454*(1.099*i-0.099);
712        y_map[i].x=0.4321260306242638*(1.099*i-0.099);
713        z_map[i].x=0.08392226148409894*(1.099*i-0.099);
714        x_map[i].y=(-0.1348122097479598)*(1.099*i-0.099);
715        y_map[i].y=(-0.2646647729834528)*(1.099*i-0.099);
716        z_map[i].y=0.3994769827314126*(1.099*i-0.099);
717        x_map[i].z=0.3848476530332144*(1.099*i-0.099);
718        y_map[i].z=(-0.3222618720834477)*(1.099*i-0.099);
719        z_map[i].z=(-0.06258578094976668)*(1.099*i-0.099);
720      }
721      break;
722    }
723    case YIQColorspace:
724    {
725      /*
726        Initialize YIQ tables:
727
728          Y = 0.29900*R+0.58700*G+0.11400*B
729          I = 0.59600*R-0.27400*G-0.32200*B
730          Q = 0.21100*R-0.52300*G+0.31200*B
731
732        I and Q, normally -0.5 through 0.5, are normalized to the range 0
733        through QuantumRange.
734      */
735      primary_info.y=(double) (MaxMap+1.0)/2.0;
736      primary_info.z=(double) (MaxMap+1.0)/2.0;
737      for (i=0; i <= (long) MaxMap; i++)
738      {
739        x_map[i].x=0.29900*i;
740        y_map[i].x=0.58700*i;
741        z_map[i].x=0.11400*i;
742        x_map[i].y=0.59600*i;
743        y_map[i].y=(-0.27400)*i;
744        z_map[i].y=(-0.32200)*i;
745        x_map[i].z=0.21100*i;
746        y_map[i].z=(-0.52300)*i;
747        z_map[i].z=0.31200*i;
748      }
749      break;
750    }
751    case YPbPrColorspace:
752    {
753      /*
754        Initialize YPbPr tables (ITU-R BT.601):
755
756          Y =  0.299000*R+0.587000*G+0.114000*B
757          Pb= -0.168736*R-0.331264*G+0.500000*B
758          Pr=  0.500000*R-0.418688*G-0.081312*B
759
760        Pb and Pr, normally -0.5 through 0.5, are normalized to the range 0
761        through QuantumRange.
762      */
763      primary_info.y=(double) (MaxMap+1.0)/2.0;
764      primary_info.z=(double) (MaxMap+1.0)/2.0;
765      for (i=0; i <= (long) MaxMap; i++)
766      {
767        x_map[i].x=0.299000*i;
768        y_map[i].x=0.587000*i;
769        z_map[i].x=0.114000*i;
770        y_map[i].y=(-0.331264)*i;
771        x_map[i].y=(-0.168736)*i;
772        z_map[i].y=0.500000*i;
773        x_map[i].z=0.500000*i;
774        y_map[i].z=(-0.418688)*i;
775        z_map[i].z=(-0.081312)*i;
776      }
777      break;
778    }
779    case YUVColorspace:
780    default:
781    {
782      /*
783        Initialize YUV tables:
784
785          Y =  0.29900*R+0.58700*G+0.11400*B
786          U = -0.14740*R-0.28950*G+0.43690*B
787          V =  0.61500*R-0.51500*G-0.10000*B
788
789        U and V, normally -0.5 through 0.5, are normalized to the range 0
790        through QuantumRange.  Note that U = 0.493*(B-Y), V = 0.877*(R-Y).
791      */
792      primary_info.y=(double) (MaxMap+1.0)/2.0;
793      primary_info.z=(double) (MaxMap+1.0)/2.0;
794      for (i=0; i <= (long) MaxMap; i++)
795      {
796        x_map[i].x=0.29900*i;
797        y_map[i].x=0.58700*i;
798        z_map[i].x=0.11400*i;
799        x_map[i].y=(-0.14740)*i;
800        y_map[i].y=(-0.28950)*i;
801        z_map[i].y=0.43690*i;
802        x_map[i].z=0.61500*i;
803        y_map[i].z=(-0.51500)*i;
804        z_map[i].z=(-0.10000)*i;
805      }
806      break;
807    }
808  }
809  /*
810    Convert from RGB.
811  */
812  switch (image->storage_class)
813  {
814    case DirectClass:
815    default:
816    {
817      ExceptionInfo
818        *exception;
819
820      /*
821        Convert DirectClass image.
822      */
823      exception=(&image->exception);
824      for (y=0; y < (long) image->rows; y++)
825      {
826        q=GetImagePixels(image,0,y,image->columns,1);
827        if (q == (PixelPacket *) NULL)
828          break;
829        for (x=0; x < (long) image->columns; x++)
830        {
831          pixel.red=x_map[ScaleQuantumToMap(q->red)].x+
832            y_map[ScaleQuantumToMap(q->green)].x+
833            z_map[ScaleQuantumToMap(q->blue)].x+primary_info.x;
834          pixel.green=x_map[ScaleQuantumToMap(q->red)].y+
835            y_map[ScaleQuantumToMap(q->green)].y+
836            z_map[ScaleQuantumToMap(q->blue)].y+primary_info.y;
837          pixel.blue=x_map[ScaleQuantumToMap(q->red)].z+
838            y_map[ScaleQuantumToMap(q->green)].z+
839            z_map[ScaleQuantumToMap(q->blue)].z+primary_info.z;
840          q->red=ScaleMapToQuantum(pixel.red);
841          q->green=ScaleMapToQuantum(pixel.green);
842          q->blue=ScaleMapToQuantum(pixel.blue);
843          q++;
844        }
845        if (SyncImagePixels(image) == MagickFalse)
846          break;
847        if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
848            (QuantumTick(y,image->rows) != MagickFalse))
849          {
850            status=image->progress_monitor(RGBTransformImageTag,y,image->rows,
851              image->client_data);
852            if (status == MagickFalse)
853              break;
854          }
855      }
856      break;
857    }
858    case PseudoClass:
859    {
860      /*
861        Convert PseudoClass image.
862      */
863      for (i=0; i < (long) image->colors; i++)
864      {
865        pixel.red=x_map[ScaleQuantumToMap(image->colormap[i].red)].x+
866          y_map[ScaleQuantumToMap(image->colormap[i].green)].x+
867          z_map[ScaleQuantumToMap(image->colormap[i].blue)].x+primary_info.x;
868        pixel.green=x_map[ScaleQuantumToMap(image->colormap[i].red)].y+
869          y_map[ScaleQuantumToMap(image->colormap[i].green)].y+
870          z_map[ScaleQuantumToMap(image->colormap[i].blue)].y+primary_info.y;
871        pixel.blue=x_map[ScaleQuantumToMap(image->colormap[i].red)].z+
872          y_map[ScaleQuantumToMap(image->colormap[i].green)].z+
873          z_map[ScaleQuantumToMap(image->colormap[i].blue)].z+primary_info.z;
874        image->colormap[i].red=ScaleMapToQuantum(pixel.red);
875        image->colormap[i].green=ScaleMapToQuantum(pixel.green);
876        image->colormap[i].blue=ScaleMapToQuantum(pixel.blue);
877      }
878      (void) SyncImage(image);
879      break;
880    }
881  }
882  /*
883    Free resources.
884  */
885  z_map=(PrimaryInfo *) RelinquishMagickMemory(z_map);
886  y_map=(PrimaryInfo *) RelinquishMagickMemory(y_map);
887  x_map=(PrimaryInfo *) RelinquishMagickMemory(x_map);
888  return(MagickTrue);
889}
890
891/*
892%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
893%                                                                             %
894%                                                                             %
895%                                                                             %
896%   S e t I m a g e C o l o r s p a c e                                       %
897%                                                                             %
898%                                                                             %
899%                                                                             %
900%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
901%
902%  SetImageColorspace() sets the colorspace member of the Image structure.
903%
904%  The format of the SetImageColorspace method is:
905%
906%      MagickBooleanType SetImageColorspace(Image *image,
907%        const ColorspaceType colorspace)
908%
909%  A description of each parameter follows:
910%
911%    o image: The image.
912%
913%    o colorspace: The colorspace.
914%
915*/
916MagickExport MagickBooleanType SetImageColorspace(Image *image,
917  const ColorspaceType colorspace)
918{
919  MagickBooleanType
920    status;
921
922  assert(image != (Image *) NULL);
923  assert(image->signature == MagickSignature);
924  if (image->debug != MagickFalse)
925    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
926  if (colorspace == UndefinedColorspace)
927    {
928      image->colorspace=UndefinedColorspace;
929      return(MagickTrue);
930    }
931  if (image->colorspace == colorspace)
932    return(MagickTrue);
933  if ((colorspace == RGBColorspace) || (colorspace == TransparentColorspace))
934    return(TransformRGBImage(image,image->colorspace));
935  status=MagickTrue;
936  if ((image->colorspace != RGBColorspace) &&
937      (image->colorspace != TransparentColorspace) &&
938      (image->colorspace != GRAYColorspace))
939    status=TransformRGBImage(image,image->colorspace);
940  if (RGBTransformImage(image,colorspace) == MagickFalse)
941    status=MagickFalse;
942  return(status);
943}
944
945/*
946%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
947%                                                                             %
948%                                                                             %
949%                                                                             %
950+     T r a n s f o r m R G B I m a g e                                       %
951%                                                                             %
952%                                                                             %
953%                                                                             %
954%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
955%
956%  TransformRGBImage() converts the reference image from an alternate
957%  colorspace to RGB.  The transformation matrices are not the standard ones:
958%  the weights are rescaled to normalize the range of the transformed values to
959%  be [0..QuantumRange].
960%
961%  The format of the TransformRGBImage method is:
962%
963%      MagickBooleanType TransformRGBImage(Image *image,
964%        const ColorspaceType colorspace)
965%
966%  A description of each parameter follows:
967%
968%    o image: The image.
969%
970%    o colorspace: the colorspace to transform the image to.
971%
972*/
973
974static inline void ConvertLabToXYZ(const double L,const double a,const double b,
975  double *X,double *Y,double *Z)
976{
977  double
978    x,
979    y,
980    z;
981
982  assert(X != (double *) NULL);
983  assert(Y != (double *) NULL);
984  assert(Z != (double *) NULL);
985  y=((2.0*L-1.0)+0.160)/1.160;
986  x=(2.0*a-1.0)/5.000+y;
987  z=y-(2.0*b-1.0)/2.000;
988  if ((x*x*x) > (216.0/24389.0))
989    x=x*x*x;
990  else
991    x=(x-16.0/116.0)/7.787;
992  if ((y*y*y) > (216.0/24389.0))
993    y=y*y*y;
994  else
995    y=(y-16.0/116.0)/7.787;
996  if ((z*z*z) > (216.0/24389.0))
997    z=z*z*z;
998  else
999    z=(z-16.0/116.0)/7.787;
1000  *X=0.9504559271*x;
1001  *Y=1.0000000000*y;
1002  *Z=1.0890577508*z;
1003}
1004
1005static inline unsigned short RoundToYCC(const MagickRealType value)
1006{
1007  if (value <= 0.0)
1008    return(0UL);
1009  if (value >= 351.0)
1010    return(351);
1011  return((unsigned short) (value+0.5));
1012}
1013
1014static inline void ConvertXYZToRGB(const double x,const double y,const double z,
1015  Quantum *red,Quantum *green,Quantum *blue)
1016{
1017  double
1018    b,
1019    g,
1020    r;
1021
1022  /*
1023    Convert XYZ to RGB colorspace.
1024  */
1025  assert(red != (Quantum *) NULL);
1026  assert(green != (Quantum *) NULL);
1027  assert(blue != (Quantum *) NULL);
1028  r=3.2407100*x-1.5372600*y-0.4985710*z;
1029  g=(-0.9692580*x+1.8759900*y+0.0415557*z);
1030  b=0.0556352*x-0.2039960*y+1.0570700*z;
1031  *red=RoundToQuantum((MagickRealType) QuantumRange*r);
1032  *green=RoundToQuantum((MagickRealType) QuantumRange*g);
1033  *blue=RoundToQuantum((MagickRealType) QuantumRange*b);
1034}
1035
1036static inline void ConvertCMYKToRGB(MagickPixelPacket *pixel)
1037{
1038  pixel->red=(MagickRealType) QuantumRange-(QuantumScale*pixel->red*
1039    (QuantumRange-pixel->index)+pixel->index);
1040  pixel->green=(MagickRealType) QuantumRange-(QuantumScale*pixel->green*
1041    (QuantumRange-pixel->index)+pixel->index);
1042Â