colorspace.c

Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %     CCCC   OOO   L       OOO   RRRR   SSSSS  PPPP    AAA    CCCC  EEEEE     %
00007 %    C      O   O  L      O   O  R   R  SS     P   P  A   A  C      E         %
00008 %    C      O   O  L      O   O  RRRR    SSS   PPPP   AAAAA  C      EEE       %
00009 %    C      O   O  L      O   O  R R       SS  P      A   A  C      E         %
00010 %     CCCC   OOO   LLLLL   OOO   R  R   SSSSS  P      A   A   CCCC  EEEEE     %
00011 %                                                                             %
00012 %                                                                             %
00013 %                     MagickCore Image Colorspace Methods                     %
00014 %                                                                             %
00015 %                              Software Design                                %
00016 %                                John Cristy                                  %
00017 %                                 July 1992                                   %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.imagemagick.org/script/license.php                            %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 %
00037 */
00038 
00039 /*
00040   Include declarations.
00041 */
00042 #include "magick/studio.h"
00043 #include "magick/property.h"
00044 #include "magick/cache.h"
00045 #include "magick/cache-private.h"
00046 #include "magick/cache-view.h"
00047 #include "magick/color.h"
00048 #include "magick/color-private.h"
00049 #include "magick/colorspace.h"
00050 #include "magick/colorspace-private.h"
00051 #include "magick/exception.h"
00052 #include "magick/exception-private.h"
00053 #include "magick/image.h"
00054 #include "magick/image-private.h"
00055 #include "magick/gem.h"
00056 #include "magick/memory_.h"
00057 #include "magick/monitor.h"
00058 #include "magick/monitor-private.h"
00059 #include "magick/pixel-private.h"
00060 #include "magick/quantize.h"
00061 #include "magick/quantum.h"
00062 #include "magick/string_.h"
00063 #include "magick/utility.h"
00064 
00065 /*
00066   Typedef declarations.
00067 */
00068 typedef struct _TransformPacket
00069 {
00070   MagickRealType
00071     x,
00072     y,
00073     z;
00074 } TransformPacket;
00075 
00076 /*
00077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00078 %                                                                             %
00079 %                                                                             %
00080 %                                                                             %
00081 +     R G B T r a n s f o r m I m a g e                                       %
00082 %                                                                             %
00083 %                                                                             %
00084 %                                                                             %
00085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00086 %
00087 %  RGBTransformImage() converts the reference image from RGB to an alternate
00088 %  colorspace.  The transformation matrices are not the standard ones: the
00089 %  weights are rescaled to normalized the range of the transformed values to
00090 %  be [0..QuantumRange].
00091 %
00092 %  The format of the RGBTransformImage method is:
00093 %
00094 %      MagickBooleanType RGBTransformImage(Image *image,
00095 %        const ColorspaceType colorspace)
00096 %
00097 %  A description of each parameter follows:
00098 %
00099 %    o image: the image.
00100 %
00101 %    o colorspace: the colorspace to transform the image to.
00102 %
00103 */
00104 
00105 static inline void ConvertRGBToXYZ(const Quantum red,const Quantum green,
00106   const Quantum blue,double *X,double *Y,double *Z)
00107 {
00108   double
00109     b,
00110     g,
00111     r;
00112 
00113   assert(X != (double *) NULL);
00114   assert(Y != (double *) NULL);
00115   assert(Z != (double *) NULL);
00116   r=QuantumScale*red;
00117   g=QuantumScale*green;
00118   b=QuantumScale*blue;
00119   *X=0.4124240*r+0.3575790*g+0.1804640*b;
00120   *Y=0.2126560*r+0.7151580*g+0.0721856*b;
00121   *Z=0.0193324*r+0.1191930*g+0.9504440*b;
00122 }
00123 
00124 static inline void ConvertXYZToLab(const double X,const double Y,const double Z,
00125   double *L,double *a,double *b)
00126 {
00127   double
00128     x,
00129     y,
00130     z;
00131 
00132   assert(L != (double *) NULL);
00133   assert(a != (double *) NULL);
00134   assert(b != (double *) NULL);
00135   x=X/0.9504559271;
00136   if (x > (216/24389.0))
00137     x=pow(x,1.0/3.0);
00138   else
00139     x=(7.787*x)+(16.0/116.0);
00140   y=Y/1.00000;
00141   if (y > (216/24389.0))
00142     y=pow(y,1.0/3.0);
00143   else
00144     y=(7.787*y)+(16.0/116.0);
00145   z=Z/1.0890577508;
00146   if (z > (216/24389.0))
00147     z=pow(z,1.0/3.0);
00148   else
00149     z=(7.787*z)+(16.0/116.0);
00150   *L=0.5*((1.160*y)-0.160+1.0);
00151   *a=0.5*(5.000*(x-y)+1.0);
00152   *b=0.5*(2.000*(y-z)+1.0);
00153 }
00154 
00155 MagickExport MagickBooleanType RGBTransformImage(Image *image,
00156   const ColorspaceType colorspace)
00157 {
00158 #define RGBTransformImageTag  "RGBTransform/Image"
00159 
00160   ExceptionInfo
00161     *exception;
00162 
00163   long
00164     progress,
00165     y;
00166 
00167   MagickBooleanType
00168     status,
00169     sync;
00170 
00171   PrimaryInfo
00172     primary_info;
00173 
00174   register long
00175     i;
00176 
00177   TransformPacket
00178     *x_map,
00179     *y_map,
00180     *z_map;
00181 
00182   CacheView
00183     *image_view;
00184 
00185   assert(image != (Image *) NULL);
00186   assert(image->signature == MagickSignature);
00187   if (image->debug != MagickFalse)
00188     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00189   assert(colorspace != RGBColorspace);
00190   assert(colorspace != TransparentColorspace);
00191   assert(colorspace != UndefinedColorspace);
00192   switch (image->colorspace)
00193   {
00194     case GRAYColorspace:
00195     case Rec601LumaColorspace:
00196     case Rec709LumaColorspace:
00197     case RGBColorspace:
00198     case TransparentColorspace:
00199       break;
00200     default:
00201     {
00202       (void) TransformImageColorspace(image,image->colorspace);
00203       break;
00204     }
00205   }
00206   if (SetImageColorspace(image,colorspace) == MagickFalse)
00207     return(MagickFalse);
00208   status=MagickTrue;
00209   progress=0;
00210   exception=(&image->exception);
00211   switch (colorspace)
00212   {
00213     case CMYColorspace:
00214     {
00215       /*
00216         Convert RGB to CMY colorspace.
00217       */
00218       if (image->storage_class == PseudoClass)
00219         {
00220           if (SyncImage(image) == MagickFalse)
00221             return(MagickFalse);
00222           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
00223             return(MagickFalse);
00224         }
00225       image_view=AcquireCacheView(image);
00226 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00227   #pragma omp parallel for schedule(dynamic,4) shared(status)
00228 #endif
00229       for (y=0; y < (long) image->rows; y++)
00230       {
00231         register long
00232           x;
00233 
00234         register PixelPacket
00235           *__restrict q;
00236 
00237         if (status == MagickFalse)
00238           continue;
00239         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
00240           exception);
00241         if (q == (PixelPacket *) NULL)
00242           {
00243             status=MagickFalse;
00244             continue;
00245           }
00246         for (x=0; x < (long) image->columns; x++)
00247         {
00248           q->red=RoundToQuantum((MagickRealType) (QuantumRange-q->red));
00249           q->green=RoundToQuantum((MagickRealType) (QuantumRange-q->green));
00250           q->blue=RoundToQuantum((MagickRealType) (QuantumRange-q->blue));
00251           q++;
00252         }
00253         sync=SyncCacheViewAuthenticPixels(image_view,exception);
00254         if (sync == MagickFalse)
00255           status=MagickFalse;
00256       }
00257       image_view=DestroyCacheView(image_view);
00258       image->type=image->matte == MagickFalse ? ColorSeparationType :
00259         ColorSeparationMatteType;
00260       return(status);
00261     }
00262     case CMYKColorspace:
00263     {
00264       MagickPixelPacket
00265         zero;
00266 
00267       /*
00268         Convert RGB to CMYK colorspace.
00269       */
00270       if (image->storage_class == PseudoClass)
00271         {
00272           if (SyncImage(image) == MagickFalse)
00273             return(MagickFalse);
00274           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
00275             return(MagickFalse);
00276         }
00277       GetMagickPixelPacket(image,&zero);
00278       image_view=AcquireCacheView(image);
00279 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00280   #pragma omp parallel for schedule(dynamic,4) shared(status)
00281 #endif
00282       for (y=0; y < (long) image->rows; y++)
00283       {
00284         MagickPixelPacket
00285           pixel;
00286 
00287         register IndexPacket
00288           *__restrict indexes;
00289 
00290         register long
00291           x;
00292 
00293         register PixelPacket
00294           *__restrict q;
00295 
00296         if (status == MagickFalse)
00297           continue;
00298         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
00299           exception);
00300         if (q == (PixelPacket *) NULL)
00301           {
00302             status=MagickFalse;
00303             continue;
00304           }
00305         indexes=GetCacheViewAuthenticIndexQueue(image_view);
00306         pixel=zero;
00307         for (x=0; x < (long) image->columns; x++)
00308         {
00309           SetMagickPixelPacket(image,q,indexes+x,&pixel);
00310           ConvertRGBToCMYK(&pixel);
00311           SetPixelPacket(image,&pixel,q,indexes+x);
00312           q++;
00313         }
00314         sync=SyncCacheViewAuthenticPixels(image_view,exception);
00315         if (sync == MagickFalse)
00316           status=MagickFalse;
00317       }
00318       image_view=DestroyCacheView(image_view);
00319       image->type=image->matte == MagickFalse ? ColorSeparationType :
00320         ColorSeparationMatteType;
00321       return(status);
00322     }
00323     case HSBColorspace:
00324     {
00325       /*
00326         Transform image from RGB to HSB.
00327       */
00328       if (image->storage_class == PseudoClass)
00329         {
00330           if (SyncImage(image) == MagickFalse)
00331             return(MagickFalse);
00332           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
00333             return(MagickFalse);
00334         }
00335       image_view=AcquireCacheView(image);
00336 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00337   #pragma omp parallel for schedule(dynamic,4) shared(status)
00338 #endif
00339       for (y=0; y < (long) image->rows; y++)
00340       {
00341         double
00342           brightness,
00343           hue,
00344           saturation;
00345 
00346         register long
00347           x;
00348 
00349         register PixelPacket
00350           *__restrict q;
00351 
00352         if (status == MagickFalse)
00353           continue;
00354         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
00355           exception);
00356         if (q == (PixelPacket *) NULL)
00357           {
00358             status=MagickFalse;
00359             continue;
00360           }
00361         hue=0.0;
00362         saturation=0.0;
00363         brightness=0.0;
00364         for (x=0; x < (long) image->columns; x++)
00365         {
00366           ConvertRGBToHSB(q->red,q->green,q->blue,&hue,&saturation,&brightness);
00367           q->red=RoundToQuantum((MagickRealType) QuantumRange*hue);
00368           q->green=RoundToQuantum((MagickRealType) QuantumRange*saturation);
00369           q->blue=RoundToQuantum((MagickRealType) QuantumRange*brightness);
00370           q++;
00371         }
00372         sync=SyncCacheViewAuthenticPixels(image_view,exception);
00373         if (sync == MagickFalse)
00374           status=MagickFalse;
00375       }
00376       image_view=DestroyCacheView(image_view);
00377       return(status);
00378     }
00379     case HSLColorspace:
00380     {
00381       /*
00382         Transform image from RGB to HSL.
00383       */
00384       if (image->storage_class == PseudoClass)
00385         {
00386           if (SyncImage(image) == MagickFalse)
00387             return(MagickFalse);
00388           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
00389             return(MagickFalse);
00390         }
00391       image_view=AcquireCacheView(image);
00392 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00393   #pragma omp parallel for schedule(dynamic,4) shared(status)
00394 #endif
00395       for (y=0; y < (long) image->rows; y++)
00396       {
00397         double
00398           hue,
00399           lightness,
00400           saturation;
00401 
00402         register long
00403           x;
00404 
00405         register PixelPacket
00406           *__restrict q;
00407 
00408         if (status == MagickFalse)
00409           continue;
00410         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
00411           exception);
00412         if (q == (PixelPacket *) NULL)
00413           {
00414             status=MagickFalse;
00415             continue;
00416           }
00417         hue=0.0;
00418         saturation=0.0;
00419         lightness=0.0;
00420         for (x=0; x < (long) image->columns; x++)
00421         {
00422           ConvertRGBToHSL(q->red,q->green,q->blue,&hue,&saturation,&lightness);
00423           q->red=RoundToQuantum((MagickRealType) QuantumRange*hue);
00424           q->green=RoundToQuantum((MagickRealType) QuantumRange*saturation);
00425           q->blue=RoundToQuantum((MagickRealType) QuantumRange*lightness);
00426           q++;
00427         }
00428         sync=SyncCacheViewAuthenticPixels(image_view,exception);
00429         if (sync == MagickFalse)
00430           status=MagickFalse;
00431       }
00432       image_view=DestroyCacheView(image_view);
00433       return(status);
00434     }
00435     case HWBColorspace:
00436     {
00437       /*
00438         Transform image from RGB to HWB.
00439       */
00440       if (image->storage_class == PseudoClass)
00441         {
00442           if (SyncImage(image) == MagickFalse)
00443             return(MagickFalse);
00444           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
00445             return(MagickFalse);
00446         }
00447       image_view=AcquireCacheView(image);
00448 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00449   #pragma omp parallel for schedule(dynamic,4) shared(status)
00450 #endif
00451       for (y=0; y < (long) image->rows; y++)
00452       {
00453         double
00454           blackness,
00455           hue,
00456           whiteness;
00457 
00458         register long
00459           x;
00460 
00461         register PixelPacket
00462           *__restrict q;
00463 
00464         if (status == MagickFalse)
00465           continue;
00466         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
00467           exception);
00468         if (q == (PixelPacket *) NULL)
00469           {
00470             status=MagickFalse;
00471             continue;
00472           }
00473         hue=0.0;
00474         whiteness=0.0;
00475         blackness=0.0;
00476         for (x=0; x < (long) image->columns; x++)
00477         {
00478           ConvertRGBToHWB(q->red,q->green,q->blue,&hue,&whiteness,&blackness);
00479           q->red=RoundToQuantum((MagickRealType) QuantumRange*hue);
00480           q->green=RoundToQuantum((MagickRealType) QuantumRange*whiteness);
00481           q->blue=RoundToQuantum((MagickRealType) QuantumRange*blackness);
00482           q++;
00483         }
00484         sync=SyncCacheViewAuthenticPixels(image_view,exception);
00485         if (sync == MagickFalse)
00486           status=MagickFalse;
00487       }
00488       image_view=DestroyCacheView(image_view);
00489       return(status);
00490     }
00491     case LabColorspace:
00492     {
00493       /*
00494         Transform image from RGB to Lab.
00495       */
00496       if (image->storage_class == PseudoClass)
00497         {
00498           if (SyncImage(image) == MagickFalse)
00499             return(MagickFalse);
00500           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
00501             return(MagickFalse);
00502         }
00503       image_view=AcquireCacheView(image);
00504 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00505   #pragma omp parallel for schedule(dynamic,4) shared(status)
00506 #endif
00507       for (y=0; y < (long) image->rows; y++)
00508       {
00509         double
00510           a,
00511           b,
00512           L,
00513           X,
00514           Y,
00515           Z;
00516 
00517         register long
00518           x;
00519 
00520         register PixelPacket
00521           *__restrict q;
00522 
00523         if (status == MagickFalse)
00524           continue;
00525         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
00526           exception);
00527         if (q == (PixelPacket *) NULL)
00528           {
00529             status=MagickFalse;
00530             continue;
00531           }
00532         L=0.0;
00533         a=0.0;
00534         b=0.0;
00535         X=0.0;
00536         Y=0.0;
00537         Z=0.0;
00538         for (x=0; x < (long) image->columns; x++)
00539         {
00540           ConvertRGBToXYZ(q->red,q->green,q->blue,&X,&Y,&Z);
00541           ConvertXYZToLab(X,Y,Z,&L,&a,&b);
00542           q->red=RoundToQuantum((MagickRealType) QuantumRange*L);
00543           q->green=RoundToQuantum((MagickRealType) QuantumRange*a);
00544           q->blue=RoundToQuantum((MagickRealType) QuantumRange*b);
00545           q++;
00546         }
00547         sync=SyncCacheViewAuthenticPixels(image_view,exception);
00548         if (sync == MagickFalse)
00549           status=MagickFalse;
00550       }
00551       image_view=DestroyCacheView(image_view);
00552       return(status);
00553     }
00554     case LogColorspace:
00555     {
00556 #define ReferenceBlack  95.0
00557 #define ReferenceWhite  685.0
00558 #define DisplayGamma  (1.0/1.7)
00559 
00560       const char
00561         *value;
00562 
00563       double
00564         black,
00565         density,
00566         gamma,
00567         reference_black,
00568         reference_white;
00569 
00570       Quantum
00571         *logmap;
00572 
00573       /*
00574         Transform RGB to Log colorspace.
00575       */
00576       density=2.03728;
00577       gamma=DisplayGamma;
00578       value=GetImageProperty(image,"gamma");
00579       if (value != (const char *) NULL)
00580         gamma=1.0/atof(value) != 0.0 ? atof(value) : 1.0;
00581       reference_black=ReferenceBlack;
00582       value=GetImageProperty(image,"reference-black");
00583       if (value != (const char *) NULL)
00584         reference_black=atof(value);
00585       reference_white=ReferenceWhite;
00586       value=GetImageProperty(image,"reference-white");
00587       if (value != (const char *) NULL)
00588         reference_white=atof(value);
00589       logmap=(Quantum *) AcquireQuantumMemory((size_t) MaxMap+1UL,
00590         sizeof(*logmap));
00591       if (logmap == (Quantum *) NULL)
00592         ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
00593           image->filename);
00594       black=pow(10.0,(reference_black-reference_white)*(gamma/density)*
00595         0.002/0.6);
00596 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00597   #pragma omp parallel for schedule(dynamic,4)
00598 #endif
00599       for (i=0; i <= (long) MaxMap; i++)
00600         logmap[i]=ScaleMapToQuantum((MagickRealType) (MaxMap*(reference_white+
00601           log10(black+((MagickRealType) i/MaxMap)*(1.0-black))/((gamma/density)*
00602           0.002/0.6))/1024.0+0.5));
00603       image_view=AcquireCacheView(image);
00604 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00605   #pragma omp parallel for schedule(dynamic,4) shared(status)
00606 #endif
00607       for (y=0; y < (long) image->rows; y++)
00608       {
00609         register long
00610           x;
00611 
00612         register PixelPacket
00613           *__restrict q;
00614 
00615         if (status == MagickFalse)
00616           continue;
00617         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
00618           exception);
00619         if (q == (PixelPacket *) NULL)
00620           {
00621             status=MagickFalse;
00622             continue;
00623           }
00624         for (x=(long) image->columns; x != 0; x--)
00625         {
00626           q->red=logmap[ScaleQuantumToMap(q->red)];
00627           q->green=logmap[ScaleQuantumToMap(q->green)];
00628           q->blue=logmap[ScaleQuantumToMap(q->blue)];
00629           q++;
00630         }
00631         sync=SyncCacheViewAuthenticPixels(image_view,exception);
00632         if (sync == MagickFalse)
00633           status=MagickFalse;
00634       }
00635       image_view=DestroyCacheView(image_view);
00636       logmap=(Quantum *) RelinquishMagickMemory(logmap);
00637       return(status);
00638     }
00639     default:
00640       break;
00641   }
00642   /*
00643     Allocate the tables.
00644   */
00645   x_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
00646     sizeof(*x_map));
00647   y_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
00648     sizeof(*y_map));
00649   z_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
00650     sizeof(*z_map));
00651   if ((x_map == (TransformPacket *) NULL) ||
00652       (y_map == (TransformPacket *) NULL) ||
00653       (z_map == (TransformPacket *) NULL))
00654     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
00655       image->filename);
00656   (void) ResetMagickMemory(&primary_info,0,sizeof(primary_info));
00657   switch (colorspace)
00658   {
00659     case OHTAColorspace:
00660     {
00661       /*
00662         Initialize OHTA tables:
00663 
00664           I1 = 0.33333*R+0.33334*G+0.33333*B
00665           I2 = 0.50000*R+0.00000*G-0.50000*B
00666           I3 =-0.25000*R+0.50000*G-0.25000*B
00667 
00668         I and Q, normally -0.5 through 0.5, are normalized to the range 0
00669         through QuantumRange.
00670       */
00671       primary_info.y=(double) (MaxMap+1.0)/2.0;
00672       primary_info.z=(double) (MaxMap+1.0)/2.0;
00673 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00674   #pragma omp parallel for schedule(dynamic,4)
00675 #endif
00676       for (i=0; i <= (long) MaxMap; i++)
00677       {
00678         x_map[i].x=0.33333f*(MagickRealType) i;
00679         y_map[i].x=0.33334f*(MagickRealType) i;
00680         z_map[i].x=0.33333f*(MagickRealType) i;
00681         x_map[i].y=0.50000f*(MagickRealType) i;
00682         y_map[i].y=0.00000f*(MagickRealType) i;
00683         z_map[i].y=(-0.50000f)*(MagickRealType) i;
00684         x_map[i].z=(-0.25000f)*(MagickRealType) i;
00685         y_map[i].z=0.50000f*(MagickRealType) i;
00686         z_map[i].z=(-0.25000f)*(MagickRealType) i;
00687       }
00688       break;
00689     }
00690     case Rec601LumaColorspace:
00691     case GRAYColorspace:
00692     {
00693       /*
00694         Initialize Rec601 luma tables:
00695 
00696           G = 0.29900*R+0.58700*G+0.11400*B
00697       */
00698 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00699   #pragma omp parallel for schedule(dynamic,4)
00700 #endif
00701       for (i=0; i <= (long) MaxMap; i++)
00702       {
00703         x_map[i].x=0.29900f*(MagickRealType) i;
00704         y_map[i].x=0.58700f*(MagickRealType) i;
00705         z_map[i].x=0.11400f*(MagickRealType) i;
00706         x_map[i].y=0.29900f*(MagickRealType) i;
00707         y_map[i].y=0.58700f*(MagickRealType) i;
00708         z_map[i].y=0.11400f*(MagickRealType) i;
00709         x_map[i].z=0.29900f*(MagickRealType) i;
00710         y_map[i].z=0.58700f*(MagickRealType) i;
00711         z_map[i].z=0.11400f*(MagickRealType) i;
00712       }
00713       image->type=GrayscaleType;
00714       break;
00715     }
00716     case Rec601YCbCrColorspace:
00717     case YCbCrColorspace:
00718     {
00719       /*
00720         Initialize YCbCr tables (ITU-R BT.601):
00721 
00722           Y =  0.299000*R+0.587000*G+0.114000*B
00723           Cb= -0.168736*R-0.331264*G+0.500000*B
00724           Cr=  0.500000*R-0.418688*G-0.081312*B
00725 
00726         Cb and Cr, normally -0.5 through 0.5, are normalized to the range 0
00727         through QuantumRange.
00728       */
00729       primary_info.y=(double) (MaxMap+1.0)/2.0;
00730       primary_info.z=(double) (MaxMap+1.0)/2.0;
00731 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00732   #pragma omp parallel for schedule(dynamic,4)
00733 #endif
00734       for (i=0; i <= (long) MaxMap; i++)
00735       {
00736         x_map[i].x=0.299000f*(MagickRealType) i;
00737         y_map[i].x=0.587000f*(MagickRealType) i;
00738         z_map[i].x=0.114000f*(MagickRealType) i;
00739         x_map[i].y=(-0.168730f)*(MagickRealType) i;
00740         y_map[i].y=(-0.331264f)*(MagickRealType) i;
00741         z_map[i].y=0.500000f*(MagickRealType) i;
00742         x_map[i].z=0.500000f*(MagickRealType) i;
00743         y_map[i].z=(-0.418688f)*(MagickRealType) i;
00744         z_map[i].z=(-0.081312f)*(MagickRealType) i;
00745       }
00746       break;
00747     }
00748     case Rec709LumaColorspace:
00749     {
00750       /*
00751         Initialize Rec709 luma tables:
00752 
00753           G = 0.21260*R+0.71520*G+0.07220*B
00754       */
00755 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00756   #pragma omp parallel for schedule(dynamic,4)
00757 #endif
00758       for (i=0; i <= (long) MaxMap; i++)
00759       {
00760         x_map[i].x=0.21260f*(MagickRealType) i;
00761         y_map[i].x=0.71520f*(MagickRealType) i;
00762         z_map[i].x=0.07220f*(MagickRealType) i;
00763         x_map[i].y=0.21260f*(MagickRealType) i;
00764         y_map[i].y=0.71520f*(MagickRealType) i;
00765         z_map[i].y=0.07220f*(MagickRealType) i;
00766         x_map[i].z=0.21260f*(MagickRealType) i;
00767         y_map[i].z=0.71520f*(MagickRealType) i;
00768         z_map[i].z=0.07220f*(MagickRealType) i;
00769       }
00770       break;
00771     }
00772     case Rec709YCbCrColorspace:
00773     {
00774       /*
00775         Initialize YCbCr tables (ITU-R BT.709):
00776 
00777           Y =  0.212600*R+0.715200*G+0.072200*B
00778           Cb= -0.114572*R-0.385428*G+0.500000*B
00779           Cr=  0.500000*R-0.454153*G-0.045847*B
00780 
00781         Cb and Cr, normally -0.5 through 0.5, are normalized to the range 0
00782         through QuantumRange.
00783       */
00784       primary_info.y=(double) (MaxMap+1.0)/2.0;
00785       primary_info.z=(double) (MaxMap+1.0)/2.0;
00786 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00787   #pragma omp parallel for schedule(dynamic,4)
00788 #endif
00789       for (i=0; i <= (long) MaxMap; i++)
00790       {
00791         x_map[i].x=0.212600f*(MagickRealType) i;
00792         y_map[i].x=0.715200f*(MagickRealType) i;
00793         z_map[i].x=0.072200f*(MagickRealType) i;
00794         x_map[i].y=(-0.114572f)*(MagickRealType) i;
00795         y_map[i].y=(-0.385428f)*(MagickRealType) i;
00796         z_map[i].y=0.500000f*(MagickRealType) i;
00797         x_map[i].z=0.500000f*(MagickRealType) i;
00798         y_map[i].z=(-0.454153f)*(MagickRealType) i;
00799         z_map[i].z=(-0.045847f)*(MagickRealType) i;
00800       }
00801       break;
00802     }
00803     case sRGBColorspace:
00804     {
00805       /*
00806         Linear RGB to nonlinear sRGB (http://www.w3.org/Graphics/Color/sRGB):
00807 
00808           R = 1.0*R+0.0*G+0.0*B
00809           G = 0.0*R+0.1*G+0.0*B
00810           B = 0.0*R+0.0*G+1.0*B
00811       */
00812 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00813   #pragma omp parallel for schedule(dynamic,4)
00814 #endif
00815       for (i=0; i <= (long) MaxMap; i++)
00816       {
00817         MagickRealType
00818           v;
00819 
00820         v=(MagickRealType) i/(MagickRealType) MaxMap;
00821         if (((MagickRealType) i/(MagickRealType) MaxMap) <= 0.03928f)
00822           v/=12.92f;
00823         else
00824           v=(MagickRealType) MaxMap*pow((((double) i/MaxMap)+0.055)/1.055,2.4);
00825         x_map[i].x=1.0f*v;
00826         y_map[i].x=0.0f*v;
00827         z_map[i].x=0.0f*v;
00828         x_map[i].y=0.0f*v;
00829         y_map[i].y=1.0f*v;
00830         z_map[i].y=0.0f*v;
00831         x_map[i].z=0.0f*v;
00832         y_map[i].z=0.0f*v;
00833         z_map[i].z=1.0f*v;
00834       }
00835       break;
00836     }
00837     case XYZColorspace:
00838     {
00839       /*
00840         Initialize CIE XYZ tables (ITU-R 709 RGB):
00841 
00842           X = 0.4124564*R+0.3575761*G+0.1804375*B
00843           Y = 0.2126729*R+0.7151522*G+0.0721750*B
00844           Z = 0.0193339*R+0.1191920*G+0.9503041*B
00845       */
00846 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00847   #pragma omp parallel for schedule(dynamic,4)
00848 #endif
00849       for (i=0; i <= (long) MaxMap; i++)
00850       {
00851         x_map[i].x=0.4124564f*(MagickRealType) i;
00852         y_map[i].x=0.3575761f*(MagickRealType) i;
00853         z_map[i].x=0.1804375f*(MagickRealType) i;
00854         x_map[i].y=0.2126729f*(MagickRealType) i;
00855         y_map[i].y=0.7151522f*(MagickRealType) i;
00856         z_map[i].y=0.0721750f*(MagickRealType) i;
00857         x_map[i].z=0.0193339f*(MagickRealType) i;
00858         y_map[i].z=0.1191920f*(MagickRealType) i;
00859         z_map[i].z=0.9503041f*(MagickRealType) i;
00860       }
00861       break;
00862     }
00863     case YCCColorspace:
00864     {
00865       /*
00866         Initialize YCC tables:
00867 
00868           Y =  0.29900*R+0.58700*G+0.11400*B
00869           C1= -0.29900*R-0.58700*G+0.88600*B
00870           C2=  0.70100*R-0.58700*G-0.11400*B
00871 
00872         YCC is scaled by 1.3584.  C1 zero is 156 and C2 is at 137.
00873       */
00874       primary_info.y=(double) ScaleQuantumToMap(ScaleCharToQuantum(156));
00875       primary_info.z=(double) ScaleQuantumToMap(ScaleCharToQuantum(137));
00876       for (i=0; i <= (long) (0.018*MaxMap); i++)
00877       {
00878         x_map[i].x=0.003962014134275617f*(MagickRealType) i;
00879         y_map[i].x=0.007778268551236748f*(MagickRealType) i;
00880         z_map[i].x=0.001510600706713781f*(MagickRealType) i;
00881         x_map[i].y=(-0.002426619775463276f)*(MagickRealType) i;
00882         y_map[i].y=(-0.004763965913702149f)*(MagickRealType) i;
00883         z_map[i].y=0.007190585689165425f*(MagickRealType) i;
00884         x_map[i].z=0.006927257754597858f*(MagickRealType) i;
00885         y_map[i].z=(-0.005800713697502058f)*(MagickRealType) i;
00886         z_map[i].z=(-0.0011265440570958f)*(MagickRealType) i;
00887       }
00888       for ( ; i <= (long) MaxMap; i++)
00889       {
00890         x_map[i].x=0.2201118963486454*(1.099f*(MagickRealType) i-0.099f);
00891         y_map[i].x=0.4321260306242638*(1.099f*(MagickRealType) i-0.099f);
00892         z_map[i].x=0.08392226148409894*(1.099f*(MagickRealType) i-0.099f);
00893         x_map[i].y=(-0.1348122097479598)*(1.099f*(MagickRealType) i-0.099f);
00894         y_map[i].y=(-0.2646647729834528)*(1.099f*(MagickRealType) i-0.099f);
00895         z_map[i].y=0.3994769827314126*(1.099f*(MagickRealType) i-0.099f);
00896         x_map[i].z=0.3848476530332144*(1.099f*(MagickRealType) i-0.099f);
00897         y_map[i].z=(-0.3222618720834477)*(1.099f*(MagickRealType) i-0.099f);
00898         z_map[i].z=(-0.06258578094976668)*(1.099f*(MagickRealType) i-0.099f);
00899       }
00900       break;
00901     }
00902     case YIQColorspace:
00903     {
00904       /*
00905         Initialize YIQ tables:
00906 
00907           Y = 0.29900*R+0.58700*G+0.11400*B
00908           I = 0.59600*R-0.27400*G-0.32200*B
00909           Q = 0.21100*R-0.52300*G+0.31200*B
00910 
00911         I and Q, normally -0.5 through 0.5, are normalized to the range 0
00912         through QuantumRange.
00913       */
00914       primary_info.y=(double) (MaxMap+1.0)/2.0;
00915       primary_info.z=(double) (MaxMap+1.0)/2.0;
00916 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00917   #pragma omp parallel for schedule(dynamic,4)
00918 #endif
00919       for (i=0; i <= (long) MaxMap; i++)
00920       {
00921         x_map[i].x=0.29900f*(MagickRealType) i;
00922         y_map[i].x=0.58700f*(MagickRealType) i;
00923         z_map[i].x=0.11400f*(MagickRealType) i;
00924         x_map[i].y=0.59600f*(MagickRealType) i;
00925         y_map[i].y=(-0.27400f)*(MagickRealType) i;
00926         z_map[i].y=(-0.32200f)*(MagickRealType) i;
00927         x_map[i].z=0.21100f*(MagickRealType) i;
00928         y_map[i].z=(-0.52300f)*(MagickRealType) i;
00929         z_map[i].z=0.31200f*(MagickRealType) i;
00930       }
00931       break;
00932     }
00933     case YPbPrColorspace:
00934     {
00935       /*
00936         Initialize YPbPr tables (ITU-R BT.601):
00937 
00938           Y =  0.299000*R+0.587000*G+0.114000*B
00939           Pb= -0.168736*R-0.331264*G+0.500000*B
00940           Pr=  0.500000*R-0.418688*G-0.081312*B
00941 
00942         Pb and Pr, normally -0.5 through 0.5, are normalized to the range 0
00943         through QuantumRange.
00944       */
00945       primary_info.y=(double) (MaxMap+1.0)/2.0;
00946       primary_info.z=(double) (MaxMap+1.0)/2.0;
00947 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00948   #pragma omp parallel for schedule(dynamic,4)
00949 #endif
00950       for (i=0; i <= (long) MaxMap; i++)
00951       {
00952         x_map[i].x=0.299000f*(MagickRealType) i;
00953         y_map[i].x=0.587000f*(MagickRealType) i;
00954         z_map[i].x=0.114000f*(MagickRealType) i;
00955         x_map[i].y=(-0.168736f)*(MagickRealType) i;
00956         y_map[i].y=(-0.331264f)*(MagickRealType) i;
00957         z_map[i].y=0.500000f*(MagickRealType) i;
00958         x_map[i].z=0.500000f*(MagickRealType) i;
00959         y_map[i].z=(-0.418688f)*(MagickRealType) i;
00960         z_map[i].z=(-0.081312f)*(MagickRealType) i;
00961       }
00962       break;
00963     }
00964     case YUVColorspace:
00965     default:
00966     {
00967       /*
00968         Initialize YUV tables:
00969 
00970           Y =  0.29900*R+0.58700*G+0.11400*B
00971           U = -0.14740*R-0.28950*G+0.43690*B
00972           V =  0.61500*R-0.51500*G-0.10000*B
00973 
00974         U and V, normally -0.5 through 0.5, are normalized to the range 0
00975         through QuantumRange.  Note that U = 0.493*(B-Y), V = 0.877*(R-Y).
00976       */
00977       primary_info.y=(double) (MaxMap+1.0)/2.0;
00978       primary_info.z=(double) (MaxMap+1.0)/2.0;
00979 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00980   #pragma omp parallel for schedule(dynamic,4)
00981 #endif
00982       for (i=0; i <= (long) MaxMap; i++)
00983       {
00984         x_map[i].x=0.29900f*(MagickRealType) i;
00985         y_map[i].x=0.58700f*(MagickRealType) i;
00986         z_map[i].x=0.11400f*(MagickRealType) i;
00987         x_map[i].y=(-0.14740f)*(MagickRealType) i;
00988         y_map[i].y=(-0.28950f)*(MagickRealType) i;
00989         z_map[i].y=0.43690f*(MagickRealType) i;
00990         x_map[i].z=0.61500f*(MagickRealType) i;
00991         y_map[i].z=(-0.51500f)*(MagickRealType) i;
00992         z_map[i].z=(-0.10000f)*(MagickRealType) i;
00993       }
00994       break;
00995     }
00996   }
00997   /*
00998     Convert from RGB.
00999   */
01000   switch (image->storage_class)
01001   {
01002     case DirectClass:
01003     default:
01004     {
01005       /*
01006         Convert DirectClass image.
01007       */
01008       image_view=AcquireCacheView(image);
01009 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01010   #pragma omp parallel for schedule(dynamic,4) shared(status)
01011 #endif
01012       for (y=0; y < (long) image->rows; y++)
01013       {
01014         MagickPixelPacket
01015           pixel;
01016 
01017         register long
01018           x;
01019 
01020         register PixelPacket
01021           *__restrict q;
01022 
01023         register unsigned long
01024           blue,
01025           green,
01026           red;
01027 
01028         if (status == MagickFalse)
01029           continue;
01030         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
01031           exception);
01032         if (q == (PixelPacket *) NULL)
01033           {
01034             status=MagickFalse;
01035             continue;
01036           }
01037         for (x=0; x < (long) image->columns; x++)
01038         {
01039           red=ScaleQuantumToMap(q->red);
01040           green=ScaleQuantumToMap(q->green);
01041           blue=ScaleQuantumToMap(q->blue);
01042           pixel.red=(x_map[red].x+y_map[green].x+z_map[blue].x)+
01043             (MagickRealType) primary_info.x;
01044           pixel.green=(x_map[red].y+y_map[green].y+z_map[blue].y)+
01045             (MagickRealType) primary_info.y;
01046           pixel.blue=(x_map[red].z+y_map[green].z+z_map[blue].z)+
01047             (MagickRealType) primary_info.z;
01048           q->red=ScaleMapToQuantum(pixel.red);
01049           q->green=ScaleMapToQuantum(pixel.green);
01050           q->blue=ScaleMapToQuantum(pixel.blue);
01051           q++;
01052         }
01053         sync=SyncCacheViewAuthenticPixels(image_view,exception);
01054         if (sync == MagickFalse)
01055           status=MagickFalse;
01056         if (image->progress_monitor != (MagickProgressMonitor) NULL)
01057           {
01058             MagickBooleanType
01059               proceed;
01060 
01061 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01062   #pragma omp critical (MagickCore_RGBTransformImage)
01063 #endif
01064             proceed=SetImageProgress(image,RGBTransformImageTag,progress++,
01065               image->rows);
01066             if (proceed == MagickFalse)
01067               status=MagickFalse;
01068           }
01069       }
01070       image_view=DestroyCacheView(image_view);
01071       break;
01072     }
01073     case PseudoClass:
01074     {
01075       register unsigned long
01076         blue,
01077         green,
01078         red;
01079 
01080       /*
01081         Convert PseudoClass image.
01082       */
01083       image_view=AcquireCacheView(image);
01084       for (i=0; i < (long) image->colors; i++)
01085       {
01086         MagickPixelPacket
01087           pixel;
01088 
01089         red=ScaleQuantumToMap(image->colormap[i].red);
01090         green=ScaleQuantumToMap(image->colormap[i].green);
01091         blue=ScaleQuantumToMap(image->colormap[i].blue);
01092         pixel.red=x_map[red].x+y_map[green].x+z_map[blue].x+primary_info.x;
01093         pixel.green=x_map[red].y+y_map[green].y+z_map[blue].y+primary_info.y;
01094         pixel.blue=x_map[red].z+y_map[green].z+z_map[blue].z+primary_info.z;
01095         image->colormap[i].red=ScaleMapToQuantum(pixel.red);
01096         image->colormap[i].green=ScaleMapToQuantum(pixel.green);
01097         image->colormap[i].blue=ScaleMapToQuantum(pixel.blue);
01098       }
01099       image_view=DestroyCacheView(image_view);
01100       (void) SyncImage(image);
01101       break;
01102     }
01103   }
01104   /*
01105     Relinquish resources.
01106   */
01107   z_map=(TransformPacket *) RelinquishMagickMemory(z_map);
01108   y_map=(TransformPacket *) RelinquishMagickMemory(y_map);
01109   x_map=(TransformPacket *) RelinquishMagickMemory(x_map);
01110   if (SetImageColorspace(image,colorspace) == MagickFalse)
01111     return(MagickFalse);
01112   return(status);
01113 }
01114 
01115 /*
01116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01117 %                                                                             %
01118 %                                                                             %
01119 %                                                                             %
01120 %   S e t I m a g e C o l o r s p a c e                                       %
01121 %                                                                             %
01122 %                                                                             %
01123 %                                                                             %
01124 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01125 %
01126 %  SetImageColorspace() sets the colorspace member of the Image structure.
01127 %
01128 %  The format of the SetImageColorspace method is:
01129 %
01130 %      MagickBooleanType SetImageColorspace(Image *image,
01131 %        const ColorspaceType colorspace)
01132 %
01133 %  A description of each parameter follows:
01134 %
01135 %    o image: the image.
01136 %
01137 %    o colorspace: the colorspace.
01138 %
01139 */
01140 MagickExport MagickBooleanType SetImageColorspace(Image *image,
01141   const ColorspaceType colorspace)
01142 {
01143   Cache
01144     cache;
01145 
01146   if (image->colorspace == colorspace)
01147     return(MagickTrue);
01148   image->colorspace=colorspace;
01149   cache=GetImagePixelCache(image,MagickTrue,&image->exception);
01150   image->colorspace=colorspace;  /* GRAY colorspace might get reset to RGB */
01151   return(cache == (Cache) NULL ? MagickFalse: MagickTrue);
01152 }
01153 
01154 /*
01155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01156 %                                                                             %
01157 %                                                                             %
01158 %                                                                             %
01159 %   T r a n s f o r m I m a g e C o l o r s p a c e                           %
01160 %                                                                             %
01161 %                                                                             %
01162 %                                                                             %
01163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01164 %
01165 %  TransformImageColorspace() transforms an image colorspace.
01166 %
01167 %  The format of the TransformImageColorspace method is:
01168 %
01169 %      MagickBooleanType TransformImageColorspace(Image *image,
01170 %        const ColorspaceType colorspace)
01171 %
01172 %  A description of each parameter follows:
01173 %
01174 %    o image: the image.
01175 %
01176 %    o colorspace: the colorspace.
01177 %
01178 */
01179 MagickExport MagickBooleanType TransformImageColorspace(Image *image,
01180   const ColorspaceType colorspace)
01181 {
01182   MagickBooleanType
01183     status;
01184 
01185   assert(image != (Image *) NULL);
01186   assert(image->signature == MagickSignature);
01187   if (image->debug != MagickFalse)
01188     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01189   if (colorspace == UndefinedColorspace)
01190     {
01191       if (SetImageColorspace(image,colorspace) == MagickFalse)
01192         return(MagickFalse);
01193       return(MagickTrue);
01194     }
01195   if (image->colorspace == colorspace)
01196     return(MagickTrue);
01197   if ((colorspace == RGBColorspace) || (colorspace == TransparentColorspace))
01198     return(TransformRGBImage(image,image->colorspace));
01199   status=MagickTrue;
01200   if ((image->colorspace != RGBColorspace) &&
01201       (image->colorspace != TransparentColorspace) &&
01202       (image->colorspace != GRAYColorspace))
01203     status=TransformRGBImage(image,image->colorspace);
01204   if (RGBTransformImage(image,colorspace) == MagickFalse)
01205     status=MagickFalse;
01206   return(status);
01207 }
01208 
01209 /*
01210 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01211 %                                                                             %
01212 %                                                                             %
01213 %                                                                             %
01214 +     T r a n s f o r m R G B I m a g e                                       %
01215 %                                                                             %
01216 %                                                                             %
01217 %                                                                             %
01218 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01219 %
01220 %  TransformRGBImage() converts the reference image from an alternate
01221 %  colorspace to RGB.  The transformation matrices are not the standard ones:
01222 %  the weights are rescaled to normalize the range of the transformed values to
01223 %  be [0..QuantumRange].
01224 %
01225 %  The format of the TransformRGBImage method is:
01226 %
01227 %      MagickBooleanType TransformRGBImage(Image *image,
01228 %        const ColorspaceType colorspace)
01229 %
01230 %  A description of each parameter follows:
01231 %
01232 %    o image: the image.
01233 %
01234 %    o colorspace: the colorspace to transform the image to.
01235 %
01236 */
01237 
01238 static inline void ConvertLabToXYZ(const double L,const double a,const double b,
01239   double *X,double *Y,double *Z)
01240 {
01241   double
01242     cube,
01243     x,
01244     y,
01245     z;
01246 
01247   assert(X != (double *) NULL);
01248   assert(Y != (double *) NULL);
01249   assert(Z != (double *) NULL);
01250   y=(100.0*L+16.0)/116.0;
01251   x=255.0*(a > 0.5 ? a-1.0 : a)/500.0+y;
01252   z=y-255.0*(b > 0.5 ? b-1.0 : b)/200.0;
01253   cube=y*y*y;
01254   if (cube > 0.008856)
01255     y=cube;
01256   else
01257     y=(y-16.0/116.0)/7.787;
01258   cube=x*x*x;
01259   if (cube > 0.008856)
01260     x=cube;
01261   else
01262     x=(x-16.0/116.0)/7.787;
01263   cube=z*z*z;
01264   if (cube > 0.008856)
01265     z=cube;
01266   else
01267     z=(z-16.0/116.0)/7.787;
01268   *X=0.9504559271*x;
01269   *Y=1.0000000000*y;
01270   *Z=1.0890577508*z;
01271 }
01272 
01273 static inline unsigned short RoundToYCC(const MagickRealType value)
01274 {
01275   if (value <= 0.0)
01276     return(0UL);
01277   if (value >= 350.0)
01278     return(350);
01279   return((unsigned short) (value+0.5));
01280 }
01281 
01282 static inline void ConvertXYZToRGB(const double x,const double y,const double z,
01283   Quantum *red,Quantum *green,Quantum *blue)
01284 {
01285   double
01286     b,
01287     g,
01288     r;
01289 
01290   /*
01291     Convert XYZ to RGB colorspace.
01292   */
01293   assert(red != (Quantum *) NULL);
01294   assert(green != (Quantum *) NULL);
01295   assert(blue != (Quantum *) NULL);
01296   r=3.2404542*x-1.5371385*y-0.4985314*z;
01297   g=(-0.9692660*x+1.8760108*y+0.0415560*z);
01298   b=0.0556434*x-0.2040259*y+1.0572252*z;
01299   if (r > 0.0031308)
01300     r=1.055*pow(r,1.0/2.4)-0.055;
01301   else
01302     r*=12.92;
01303   if (g > 0.0031308)
01304     g=1.055*pow(g,1.0/2.4)-0.055;
01305   else
01306     g*=12.92;
01307   if (b > 0.0031308)
01308     b=1.055*pow(b,1.0/2.4)-0.055;
01309   else
01310     b*=12.92;
01311   *red=RoundToQuantum((MagickRealType) QuantumRange*r);
01312   *green=RoundToQuantum((MagickRealType) QuantumRange*g);
01313   *blue=RoundToQuantum((MagickRealType) QuantumRange*b);
01314 }
01315 
01316 static inline void ConvertCMYKToRGB(MagickPixelPacket *pixel)
01317 {
01318   pixel->red=(MagickRealType) QuantumRange-(QuantumScale*pixel->red*
01319     (QuantumRange-pixel->index)+pixel->index);
01320   pixel->green=(MagickRealType) QuantumRange-(QuantumScale*pixel->green*
01321     (QuantumRange-pixel->index)+pixel->index);
01322   pixel->blue=(MagickRealType) QuantumRange-(QuantumScale*pixel->blue*
01323     (QuantumRange-pixel->index)+pixel->index);
01324 }
01325 
01326 MagickExport MagickBooleanType TransformRGBImage(Image *image,
01327   const ColorspaceType colorspace)
01328 {
01329 #define D50X  (0.9642)
01330 #define D50Y  (1.0)
01331 #define D50Z  (0.8249)
01332 #define TransformRGBImageTag  "Transform/Image"
01333 
01334 #if !defined(MAGICKCORE_HDRI_SUPPORT)
01335   static const unsigned char
01336     YCCMap[351] =  /* Photo CD information beyond 100% white, Gamma 2.2 */
01337     {
01338         0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,
01339        14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,
01340        28,  29,  30,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,
01341        43,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  56,  57,  58,
01342        59,  60,  61,  62,  63,  64,  66,  67,  68,  69,  70,  71,  72,  73,
01343        74,  76,  77,  78,  79,  80,  81,  82,  83,  84,  86,  87,  88,  89,
01344        90,  91,  92,  93,  94,  95,  97,  98,  99, 100, 101, 102, 103, 104,
01345       105, 106, 107, 108, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
01346       120, 121, 122, 123, 124, 125, 126, 127, 129, 130, 131, 132, 133, 134,
01347       135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148,
01348       149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162,
01349       163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176,
01350       176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189,
01351       190, 191, 192, 193, 193, 194, 195, 196, 197, 198, 199, 200, 201, 201,
01352       202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 211, 212, 213,
01353       214, 215, 215, 216, 217, 218, 218, 219, 220, 221, 221, 222, 223, 224,
01354       224, 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232, 233,
01355       234, 234, 235, 236, 236, 237, 237, 238, 238, 239, 240, 240, 241, 241,
01356       242, 242, 243, 243, 244, 244, 245, 245, 245, 246, 246, 247, 247, 247,
01357       248, 248, 248, 249, 249, 249, 249, 250, 250, 250, 250, 251, 251, 251,
01358       251, 251, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253,
01359       253, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254,
01360       254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255,
01361       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
01362       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
01363       255
01364     };
01365 #endif
01366 
01367   ExceptionInfo
01368     *exception;
01369 
01370   long
01371     progress,
01372     y;
01373 
01374   MagickBooleanType
01375     status;
01376 
01377   register long
01378     i;
01379 
01380   TransformPacket
01381     *y_map,
01382     *x_map,
01383     *z_map;
01384 
01385   CacheView
01386     *image_view;
01387 
01388   assert(image != (Image *) NULL);
01389   assert(image->signature == MagickSignature);
01390   if (image->debug != MagickFalse)
01391     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01392   switch (colorspace)
01393   {
01394     case GRAYColorspace:
01395     case Rec601LumaColorspace:
01396     case Rec709LumaColorspace:
01397     case RGBColorspace:
01398     case TransparentColorspace:
01399     case UndefinedColorspace:
01400       return(MagickTrue);
01401     default:
01402       break;
01403   }
01404   status=MagickTrue;
01405   progress=0;
01406   exception=(&image->exception);
01407   switch (colorspace)
01408   {
01409     case CMYColorspace:
01410     {
01411       /*
01412         Transform image from CMY to RGB.
01413       */
01414       if (image->storage_class == PseudoClass)
01415         {
01416           if (SyncImage(image) == MagickFalse)
01417             return(MagickFalse);
01418           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
01419             return(MagickFalse);
01420         }
01421       image_view=AcquireCacheView(image);
01422 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01423   #pragma omp parallel for schedule(dynamic,4) shared(status)
01424 #endif
01425       for (y=0; y < (long) image->rows; y++)
01426       {
01427         MagickBooleanType
01428           sync;
01429 
01430         register long
01431           x;
01432 
01433         register PixelPacket
01434           *__restrict q;
01435 
01436         if (status == MagickFalse)
01437           continue;
01438         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
01439           exception);
01440         if (q == (PixelPacket *) NULL)
01441           {
01442             status=MagickFalse;
01443             continue;
01444           }
01445         for (x=0; x < (long) image->columns; x++)
01446         {
01447           q->red=RoundToQuantum((MagickRealType) (QuantumRange-q->red));
01448           q->green=RoundToQuantum((MagickRealType) (QuantumRange-q->green));
01449           q->blue=RoundToQuantum((MagickRealType) (QuantumRange-q->blue));
01450           q++;
01451         }
01452         sync=SyncCacheViewAuthenticPixels(image_view,exception);
01453         if (sync == MagickFalse)
01454           status=MagickFalse;
01455       }
01456       image_view=DestroyCacheView(image_view);
01457       if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
01458         return(MagickFalse);
01459       return(status);
01460     }
01461     case CMYKColorspace:
01462     {
01463       MagickPixelPacket
01464         zero;
01465 
01466       /*
01467         Transform image from CMYK to RGB.
01468       */
01469       if (image->storage_class == PseudoClass)
01470         {
01471           if (SyncImage(image) == MagickFalse)
01472             return(MagickFalse);
01473           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
01474             return(MagickFalse);
01475         }
01476       GetMagickPixelPacket(image,&zero);
01477       image_view=AcquireCacheView(image);
01478 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01479   #pragma omp parallel for schedule(dynamic,4) shared(status)
01480 #endif
01481       for (y=0; y < (long) image->rows; y++)
01482       {
01483         MagickBooleanType
01484           sync;
01485 
01486         MagickPixelPacket
01487           pixel;
01488 
01489         register IndexPacket
01490           *__restrict indexes;
01491 
01492         register long
01493           x;
01494 
01495         register PixelPacket
01496           *__restrict q;
01497 
01498         if (status == MagickFalse)
01499           continue;
01500         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
01501           exception);
01502         if (q == (PixelPacket *) NULL)
01503           {
01504             status=MagickFalse;
01505             continue;
01506           }
01507         indexes=GetCacheViewAuthenticIndexQueue(image_view);
01508         pixel=zero;
01509         for (x=0; x < (long) image->columns; x++)
01510         {
01511           SetMagickPixelPacket(image,q,indexes+x,&pixel);
01512           ConvertCMYKToRGB(&pixel);
01513           SetPixelPacket(image,&pixel,q,indexes+x);
01514           q++;
01515         }
01516         sync=SyncCacheViewAuthenticPixels(image_view,exception);
01517         if (sync == MagickFalse)
01518           status=MagickFalse;
01519       }
01520       image_view=DestroyCacheView(image_view);
01521       if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
01522         return(MagickFalse);
01523       return(status);
01524     }
01525     case HSBColorspace:
01526     {
01527       /*
01528         Transform image from HSB to RGB.
01529       */
01530       if (image->storage_class == PseudoClass)
01531         {
01532           if (SyncImage(image) == MagickFalse)
01533             return(MagickFalse);
01534           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
01535             return(MagickFalse);
01536         }
01537       image_view=AcquireCacheView(image);
01538 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01539   #pragma omp parallel for schedule(dynamic,4) shared(status)
01540 #endif
01541       for (y=0; y < (long) image->rows; y++)
01542       {
01543         double
01544           brightness,
01545           hue,
01546           saturation;
01547 
01548         MagickBooleanType
01549           sync;
01550 
01551         register long
01552           x;
01553 
01554         register PixelPacket
01555           *__restrict q;
01556 
01557         if (status == MagickFalse)
01558           continue;
01559         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
01560           exception);
01561         if (q == (PixelPacket *) NULL)
01562           {
01563             status=MagickFalse;
01564             continue;
01565           }
01566         for (x=0; x < (long) image->columns; x++)
01567         {
01568           hue=(double) (QuantumScale*q->red);
01569           saturation=(double) (QuantumScale*q->green);
01570           brightness=(double) (QuantumScale*q->blue);
01571           ConvertHSBToRGB(hue,saturation,brightness,&q->red,&q->green,&q->blue);
01572           q++;
01573         }
01574         sync=SyncCacheViewAuthenticPixels(image_view,exception);
01575         if (sync == MagickFalse)
01576           status=MagickFalse;
01577       }
01578       image_view=DestroyCacheView(image_view);
01579       if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
01580         return(MagickFalse);
01581       return(status);
01582     }
01583     case HSLColorspace:
01584     {
01585       /*
01586         Transform image from HSL to RGB.
01587       */
01588       if (image->storage_class == PseudoClass)
01589         {
01590           if (SyncImage(image) == MagickFalse)
01591             return(MagickFalse);
01592           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
01593             return(MagickFalse);
01594         }
01595       image_view=AcquireCacheView(image);
01596 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01597   #pragma omp parallel for schedule(dynamic,4) shared(status)
01598 #endif
01599       for (y=0; y < (long) image->rows; y++)
01600       {
01601         double
01602           hue,
01603           lightness,
01604           saturation;
01605 
01606         MagickBooleanType
01607           sync;
01608 
01609         register long
01610           x;
01611 
01612         register PixelPacket
01613           *__restrict q;
01614 
01615         if (status == MagickFalse)
01616           continue;
01617         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
01618           exception);
01619         if (q == (PixelPacket *) NULL)
01620           {
01621             status=MagickFalse;
01622             continue;
01623           }
01624         for (x=0; x < (long) image->columns; x++)
01625         {
01626           hue=(double) (QuantumScale*q->red);
01627           saturation=(double) (QuantumScale*q->green);
01628           lightness=(double) (QuantumScale*q->blue);
01629           ConvertHSLToRGB(hue,saturation,lightness,&q->red,&q->green,&q->blue);
01630           q++;
01631         }
01632         sync=SyncCacheViewAuthenticPixels(image_view,exception);
01633         if (sync == MagickFalse)
01634           status=MagickFalse;
01635       }
01636       image_view=DestroyCacheView(image_view);
01637       if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
01638         return(MagickFalse);
01639       return(status);
01640     }
01641     case HWBColorspace:
01642     {
01643       /*
01644         Transform image from HWB to RGB.
01645       */
01646       if (image->storage_class == PseudoClass)
01647         {
01648           if (SyncImage(image) == MagickFalse)
01649             return(MagickFalse);
01650           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
01651             return(MagickFalse);
01652         }
01653       image_view=AcquireCacheView(image);
01654 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01655   #pragma omp parallel for schedule(dynamic,4) shared(status)
01656 #endif
01657       for (y=0; y < (long) image->rows; y++)
01658       {
01659         double
01660           blackness,
01661           hue,
01662           whiteness;
01663 
01664         MagickBooleanType
01665           sync;
01666 
01667         register long
01668           x;
01669 
01670         register PixelPacket
01671           *__restrict q;
01672 
01673         if (status == MagickFalse)
01674           continue;
01675         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
01676           exception);
01677         if (q == (PixelPacket *) NULL)
01678           {
01679             status=MagickFalse;
01680             continue;
01681           }
01682         for (x=0; x < (long) image->columns; x++)
01683         {
01684           hue=(double) (QuantumScale*q->red);
01685           whiteness=(double) (QuantumScale*q->green);
01686           blackness=(double) (QuantumScale*q->blue);
01687           ConvertHWBToRGB(hue,whiteness,blackness,&q->red,&q->green,&q->blue);
01688           q++;
01689         }
01690         sync=SyncCacheViewAuthenticPixels(image_view,exception);
01691         if (sync == MagickFalse)
01692           status=MagickFalse;
01693       }
01694       image_view=DestroyCacheView(image_view);
01695       if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
01696         return(MagickFalse);
01697       return(status);
01698     }
01699     case LabColorspace:
01700     {
01701       /*
01702         Transform image from Lab to RGB.
01703       */
01704       if (image->storage_class == PseudoClass)
01705         {
01706           if (SyncImage(image) == MagickFalse)
01707             return(MagickFalse);
01708           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
01709             return(MagickFalse);
01710         }
01711       image_view=AcquireCacheView(image);
01712 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01713   #pragma omp parallel for schedule(dynamic,4) shared(status)
01714 #endif
01715       for (y=0; y < (long) image->rows; y++)
01716       {
01717         double
01718           a,
01719           b,
01720           L,
01721           X,
01722           Y,
01723           Z;
01724 
01725         MagickBooleanType
01726           sync;
01727 
01728         register long
01729           x;
01730 
01731         register PixelPacket
01732           *__restrict q;
01733 
01734         if (status == MagickFalse)
01735           continue;
01736         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
01737           exception);
01738         if (q == (PixelPacket *) NULL)
01739           {
01740             status=MagickFalse;
01741             continue;
01742           }
01743         X=0.0;
01744         Y=0.0;
01745         Z=0.0;
01746         for (x=0; x < (long) image->columns; x++)
01747         {
01748           L=QuantumScale*q->red;
01749           a=QuantumScale*q->green;
01750           b=QuantumScale*q->blue;
01751           ConvertLabToXYZ(L,a,b,&X,&Y,&Z);
01752           ConvertXYZToRGB(X,Y,Z,&q->red,&q->green,&q->blue);
01753           q++;
01754         }
01755         sync=SyncCacheViewAuthenticPixels(image_view,exception);
01756         if (sync == MagickFalse)
01757           status=MagickFalse;
01758       }
01759       image_view=DestroyCacheView(image_view);
01760       if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
01761         return(MagickFalse);
01762       return(status);
01763     }
01764     case LogColorspace:
01765     {
01766       const char
01767         *value;
01768 
01769       double
01770         black,
01771         density,
01772         gamma,
01773         reference_black,
01774         reference_white;
01775 
01776       Quantum
01777         *logmap;
01778 
01779       /*
01780         Transform Log to RGB colorspace.
01781       */
01782       density=2.03728;
01783       gamma=DisplayGamma;
01784       value=GetImageProperty(image,"gamma");
01785       if (value != (const char *) NULL)
01786         gamma=1.0/atof(value) != 0.0 ? atof(value) : 1.0;
01787       reference_black=ReferenceBlack;
01788       value=GetImageProperty(image,"reference-black");
01789       if (value != (const char *) NULL)
01790         reference_black=atof(value);
01791       reference_white=ReferenceWhite;
01792       value=GetImageProperty(image,"reference-white");
01793       if (value != (const char *) NULL)
01794         reference_white=atof(value);
01795       logmap=(Quantum *) AcquireQuantumMemory((size_t) MaxMap+1UL,
01796         sizeof(*logmap));
01797       if (logmap == (Quantum *) NULL)
01798         ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
01799           image->filename);
01800       black=pow(10.0,(reference_black-reference_white)*(gamma/density)*
01801         0.002/0.6);
01802       for (i=0; i <= (long) (reference_black*MaxMap/1024.0); i++)
01803         logmap[i]=(Quantum) 0;
01804       for ( ; i < (long) (reference_white*MaxMap/1024.0); i++)
01805         logmap[i]=RoundToQuantum((MagickRealType) QuantumRange/(1.0-black)*
01806           (pow(10.0,(1024.0*i/MaxMap-reference_white)*
01807           (gamma/density)*0.002/0.6)-black));
01808       for ( ; i <= (long) MaxMap; i++)
01809         logmap[i]=(Quantum) QuantumRange;
01810       if (SetImageStorageClass(image,DirectClass) == MagickFalse)
01811         return(MagickFalse);
01812       image_view=AcquireCacheView(image);
01813 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01814   #pragma omp parallel for schedule(dynamic,4) shared(status)
01815 #endif
01816       for (y=0; y < (long) image->rows; y++)
01817       {
01818         MagickBooleanType
01819           sync;
01820 
01821         register long
01822           x;
01823 
01824         register PixelPacket
01825           *__restrict q;
01826 
01827         if (status == MagickFalse)
01828           continue;
01829         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
01830           exception);
01831         if (q == (PixelPacket *) NULL)
01832           {
01833             status=MagickFalse;
01834             continue;
01835           }
01836         for (x=(long) image->columns; x != 0; x--)
01837         {
01838           q->red=logmap[ScaleQuantumToMap(q->red)];
01839           q->green=logmap[ScaleQuantumToMap(q->green)];
01840           q->blue=logmap[ScaleQuantumToMap(q->blue)];
01841           q++;
01842         }
01843         sync=SyncCacheViewAuthenticPixels(image_view,exception);
01844         if (sync == MagickFalse)
01845           status=MagickFalse;
01846       }
01847       image_view=DestroyCacheView(image_view);
01848       logmap=(Quantum *) RelinquishMagickMemory(logmap);
01849       if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
01850         return(MagickFalse);
01851       return(status);
01852     }
01853     default:
01854       break;
01855   }
01856   /*
01857     Allocate the tables.
01858   */
01859   x_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
01860     sizeof(*x_map));
01861   y_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
01862     sizeof(*y_map));
01863   z_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
01864     sizeof(*z_map));
01865   if ((x_map == (TransformPacket *) NULL) ||
01866       (y_map == (TransformPacket *) NULL) ||
01867       (z_map == (TransformPacket *) NULL))
01868     {
01869       if (z_map != (TransformPacket *) NULL)
01870         z_map=(TransformPacket *) RelinquishMagickMemory(z_map);
01871       if (y_map != (TransformPacket *) NULL)
01872         y_map=(TransformPacket *) RelinquishMagickMemory(y_map);
01873       if (x_map != (TransformPacket *) NULL)
01874         x_map=(TransformPacket *) RelinquishMagickMemory(x_map);
01875       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
01876         image->filename);
01877     }
01878   switch (colorspace)
01879   {
01880     case OHTAColorspace:
01881     {
01882       /*
01883         Initialize OHTA tables:
01884 
01885           R = I1+1.00000*I2-0.66668*I3
01886           G = I1+0.00000*I2+1.33333*I3
01887           B = I1-1.00000*I2-0.66668*I3
01888 
01889         I and Q, normally -0.5 through 0.5, must be normalized to the range 0
01890         through QuantumRange.
01891       */
01892 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01893   #pragma omp parallel for schedule(dynamic,4)
01894 #endif
01895       for (i=0; i <= (long) MaxMap; i++)
01896       {
01897         x_map[i].x=(MagickRealType) i;
01898         y_map[i].x=0.500000f*(2.000000*(MagickRealType) i-(MagickRealType)
01899           MaxMap);
01900         z_map[i].x=(-0.333340f)*(2.000000f*(MagickRealType) i-(MagickRealType)
01901           MaxMap);
01902         x_map[i].y=(MagickRealType) i;
01903         y_map[i].y=0.000000f;
01904         z_map[i].y=0.666665f*(2.000000f*(MagickRealType) i-(MagickRealType)
01905           MaxMap);
01906         x_map[i].z=(MagickRealType) i;
01907         y_map[i].z=(-0.500000f)*(2.000000f*(MagickRealType) i-(MagickRealType)
01908           MaxMap);
01909         z_map[i].z=(-0.333340f)*(2.000000f*(MagickRealType) i-(MagickRealType)
01910           MaxMap);
01911       }
01912       break;
01913     }
01914     case Rec601YCbCrColorspace:
01915     case YCbCrColorspace:
01916     {
01917       /*
01918         Initialize YCbCr tables:
01919 
01920           R = Y            +1.402000*Cr
01921           G = Y-0.344136*Cb-0.714136*Cr
01922           B = Y+1.772000*Cb
01923 
01924         Cb and Cr, normally -0.5 through 0.5, must be normalized to the range 0
01925         through QuantumRange.
01926       */
01927 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01928   #pragma omp parallel for schedule(dynamic,4)
01929 #endif
01930       for (i=0; i <= (long) MaxMap; i++)
01931       {
01932         x_map[i].x=(MagickRealType) i;
01933         y_map[i].x=0.000000f;
01934         z_map[i].x=(1.402000f*0.500000f)*(2.000000f*(MagickRealType) i-
01935           (MagickRealType) MaxMap);
01936         x_map[i].y=(MagickRealType) i;
01937         y_map[i].y=(-0.344136f*0.500000f)*(2.000000f*(MagickRealType) i-
01938           (MagickRealType) MaxMap);
01939         z_map[i].y=(-0.714136f*0.500000f)*(2.000000f*(MagickRealType) i-
01940           (MagickRealType) MaxMap);
01941         x_map[i].z=(MagickRealType) i;
01942         y_map[i].z=(1.772000f*0.500000f)*(2.000000f*(MagickRealType) i-
01943           (MagickRealType) MaxMap);
01944         z_map[i].z=0.000000f;
01945       }
01946       break;
01947     }
01948     case Rec709YCbCrColorspace:
01949     {
01950       /*
01951         Initialize YCbCr tables:
01952 
01953           R = Y            +1.574800*Cr
01954           G = Y-0.187324*Cb-0.468124*Cr
01955           B = Y+1.855600*Cb
01956 
01957         Cb and Cr, normally -0.5 through 0.5, must be normalized to the range 0
01958         through QuantumRange.
01959       */
01960 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01961   #pragma omp parallel for schedule(dynamic,4)
01962 #endif
01963       for (i=0; i <= (long) MaxMap; i++)
01964       {
01965         x_map[i].x=(MagickRealType) i;
01966         y_map[i].x=0.000000f;
01967         z_map[i].x=(1.574800f*0.50000f)*(2.00000f*(MagickRealType) i-
01968           (MagickRealType) MaxMap);
01969         x_map[i].y=(MagickRealType) i;
01970         y_map[i].y=(-0.187324f*0.50000f)*(2.00000f*(MagickRealType) i-
01971           (MagickRealType) MaxMap);
01972         z_map[i].y=(-0.468124f*0.50000f)*(2.00000f*(MagickRealType) i-
01973           (MagickRealType) MaxMap);
01974         x_map[i].z=(MagickRealType) i;
01975         y_map[i].z=(1.855600f*0.50000f)*(2.00000f*(MagickRealType) i-
01976           (MagickRealType) MaxMap);
01977         z_map[i].z=0.00000f;
01978       }
01979       break;
01980     }
01981     case sRGBColorspace:
01982     {
01983       /*
01984         Nonlinear sRGB to linear RGB.
01985 
01986           R = 1.0*R+0.0*G+0.0*B
01987           G = 0.0*R+1.0*G+0.0*B
01988           B = 0.0*R+0.0*G+1.0*B
01989       */
01990 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01991   #pragma omp parallel for schedule(dynamic,4)
01992 #endif
01993       for (i=0; i <= (long) MaxMap; i++)
01994       {
01995         x_map[i].x=1.0f*(MagickRealType) i;
01996         y_map[i].x=0.0f*(MagickRealType) i;
01997         z_map[i].x=0.0f*(MagickRealType) i;
01998         x_map[i].y=0.0f*(MagickRealType) i;
01999         y_map[i].y=1.0f*(MagickRealType) i;
02000         z_map[i].y=0.0f*(MagickRealType) i;
02001         x_map[i].z=0.0f*(MagickRealType) i;
02002         y_map[i].z=0.0f*(MagickRealType) i;
02003         z_map[i].z=1.0f*(MagickRealType) i;
02004       }
02005       break;
02006     }
02007     case XYZColorspace:
02008     {
02009       /*
02010         Initialize CIE XYZ tables (ITU R-709 RGB):
02011 
02012           R =  3.2404542*X-1.5371385*Y-0.4985314*Z
02013           G = -0.9692660*X+1.8760108*Y+0.0415560*Z
02014           B =  0.0556434*X-0.2040259*Y+1.057225*Z
02015       */
02016 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02017   #pragma omp parallel for schedule(dynamic,4)
02018 #endif
02019       for (i=0; i <= (long) MaxMap; i++)
02020       {
02021         x_map[i].x=3.2404542f*(MagickRealType) i;
02022         x_map[i].y=(-0.9692660f)*(MagickRealType) i;
02023         x_map[i].z=0.0556434f*(MagickRealType) i;
02024         y_map[i].x=(-1.5371385f)*(MagickRealType) i;
02025         y_map[i].y=1.8760108f*(MagickRealType) i;
02026         y_map[i].z=(-0.2040259f)*(MagickRealType) i;
02027         z_map[i].x=(-0.4985314f)*(MagickRealType) i;
02028         z_map[i].y=0.0415560f*(MagickRealType) i;
02029         z_map[i].z=1.0572252f*(MagickRealType) i;
02030       }
02031       break;
02032     }
02033     case YCCColorspace:
02034     {
02035       /*
02036         Initialize YCC tables:
02037 
02038           R = Y            +1.340762*C2
02039           G = Y-0.317038*C1-0.682243*C2
02040           B = Y+1.632639*C1
02041 
02042         YCC is scaled by 1.3584.  C1 zero is 156 and C2 is at 137.
02043       */
02044 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02045   #pragma omp parallel for schedule(dynamic,4)
02046 #endif
02047       for (i=0; i <= (long) MaxMap; i++)
02048       {
02049         x_map[i].x=1.3584000f*(MagickRealType) i;
02050         y_map[i].x=0.0000000f;
02051         z_map[i].x=1.8215000f*((MagickRealType) i-(MagickRealType)
02052           ScaleQuantumToMap(ScaleCharToQuantum(137)));
02053         x_map[i].y=1.3584000f*(MagickRealType) i;
02054         y_map[i].y=(-0.4302726f)*((MagickRealType) i-(MagickRealType)
02055           ScaleQuantumToMap(ScaleCharToQuantum(156)));
02056         z_map[i].y=(-0.9271435f)*((MagickRealType) i-(MagickRealType)
02057           ScaleQuantumToMap(ScaleCharToQuantum(137)));
02058         x_map[i].z=1.3584000f*(MagickRealType) i;
02059         y_map[i].z=2.2179000f*((MagickRealType) i-(MagickRealType)
02060           ScaleQuantumToMap(ScaleCharToQuantum(156)));
02061         z_map[i].z=0.0000000f;
02062       }
02063       break;
02064     }
02065     case YIQColorspace:
02066     {
02067       /*
02068         Initialize YIQ tables:
02069 
02070           R = Y+0.95620*I+0.62140*Q
02071           G = Y-0.27270*I-0.64680*Q
02072           B = Y-1.10370*I+1.70060*Q
02073 
02074         I and Q, normally -0.5 through 0.5, must be normalized to the range 0
02075         through QuantumRange.
02076       */
02077 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02078   #pragma omp parallel for schedule(dynamic,4)
02079 #endif
02080       for (i=0; i <= (long) MaxMap; i++)
02081       {
02082         x_map[i].x=(MagickRealType) i;
02083         y_map[i].x=0.47810f*(2.00000f*(MagickRealType) i-(MagickRealType)
02084           MaxMap);
02085         z_map[i].x=0.31070f*(2.00000f*(MagickRealType) i-(MagickRealType)
02086           MaxMap);
02087         x_map[i].y=(MagickRealType) i;
02088         y_map[i].y=(-0.13635f)*(2.00000f*(MagickRealType) i-(MagickRealType)
02089           MaxMap);
02090         z_map[i].y=(-0.32340f)*(2.00000f*(MagickRealType) i-(MagickRealType)
02091           MaxMap);
02092         x_map[i].z=(MagickRealType) i;
02093         y_map[i].z=(-0.55185f)*(2.00000f*(MagickRealType) i-(MagickRealType)
02094           MaxMap);
02095         z_map[i].z=0.85030f*(2.00000f*(MagickRealType) i-(MagickRealType)
02096           MaxMap);
02097       }
02098       break;
02099     }
02100     case YPbPrColorspace:
02101     {
02102       /*
02103         Initialize YPbPr tables:
02104 
02105           R = Y            +1.402000*C2
02106           G = Y-0.344136*C1+0.714136*C2
02107           B = Y+1.772000*C1
02108 
02109         Pb and Pr, normally -0.5 through 0.5, must be normalized to the range 0
02110         through QuantumRange.
02111       */
02112 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02113   #pragma omp parallel for schedule(dynamic,4)
02114 #endif
02115       for (i=0; i <= (long) MaxMap; i++)
02116       {
02117         x_map[i].x=(MagickRealType) i;
02118         y_map[i].x=0.000000f;
02119         z_map[i].x=0.701000f*(2.00000f*(MagickRealType) i-(MagickRealType)
02120           MaxMap);
02121         x_map[i].y=(MagickRealType) i;
02122         y_map[i].y=(-0.172068f)*(2.00000f*(MagickRealType) i-(MagickRealType)
02123           MaxMap);
02124         z_map[i].y=0.357068f*(2.00000f*(MagickRealType) i-(MagickRealType)
02125           MaxMap);
02126         x_map[i].z=(MagickRealType) i;
02127         y_map[i].z=0.88600f*(2.00000f*(MagickRealType) i-(MagickRealType)
02128           MaxMap);
02129         z_map[i].z=0.00000f;
02130       }
02131       break;
02132     }
02133     case YUVColorspace:
02134     default:
02135     {
02136       /*
02137         Initialize YUV tables:
02138 
02139           R = Y          +1.13980*V
02140           G = Y-0.39380*U-0.58050*V
02141           B = Y+2.02790*U
02142 
02143         U and V, normally -0.5 through 0.5, must be normalized to the range 0
02144         through QuantumRange.
02145       */
02146 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02147   #pragma omp parallel for schedule(dynamic,4)
02148 #endif
02149       for (i=0; i <= (long) MaxMap; i++)
02150       {
02151         x_map[i].x=(MagickRealType) i;
02152         y_map[i].x=0.00000f;
02153         z_map[i].x=0.56990f*(2.0000f*(MagickRealType) i-(MagickRealType)
02154           MaxMap);
02155         x_map[i].y=(MagickRealType) i;
02156         y_map[i].y=(-0.19690f)*(2.00000f*(MagickRealType) i-(MagickRealType)
02157           MaxMap);
02158         z_map[i].y=(-0.29025f)*(2.00000f*(MagickRealType) i-(MagickRealType)
02159           MaxMap);
02160         x_map[i].z=(MagickRealType) i;
02161         y_map[i].z=1.01395f*(2.00000f*(MagickRealType) i-(MagickRealType)
02162           MaxMap);
02163         z_map[i].z=0.00000f;
02164       }
02165       break;
02166     }
02167   }
02168   /*
02169     Convert to RGB.
02170   */
02171   switch (image->storage_class)
02172   {
02173     case DirectClass:
02174     default:
02175     {
02176       /*
02177         Convert DirectClass image.
02178       */
02179       image_view=AcquireCacheView(image);
02180 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02181   #pragma omp parallel for schedule(dynamic,4) shared(status)
02182 #endif
02183       for (y=0; y < (long) image->rows; y++)
02184       {
02185         MagickBooleanType
02186           sync;
02187 
02188         MagickPixelPacket
02189           pixel;
02190 
02191         register long
02192           x;
02193 
02194         register PixelPacket
02195           *__restrict q;
02196 
02197         if (status == MagickFalse)
02198           continue;
02199         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
02200           exception);
02201         if (q == (PixelPacket *) NULL)
02202           {
02203             status=MagickFalse;
02204             continue;
02205           }
02206         for (x=0; x < (long) image->columns; x++)
02207         {
02208           register unsigned long
02209             blue,
02210             green,
02211             red;
02212 
02213           red=ScaleQuantumToMap(q->red);
02214           green=ScaleQuantumToMap(q->green);
02215           blue=ScaleQuantumToMap(q->blue);
02216           pixel.red=x_map[red].x+y_map[green].x+z_map[blue].x;
02217           pixel.green=x_map[red].y+y_map[green].y+z_map[blue].y;
02218           pixel.blue=x_map[red].z+y_map[green].z+z_map[blue].z;
02219           switch (colorspace)
02220           {
02221             case YCCColorspace:
02222             {
02223 #if !defined(MAGICKCORE_HDRI_SUPPORT)
02224               pixel.red=(MagickRealType) ScaleCharToQuantum(YCCMap[RoundToYCC(
02225                 255.0*QuantumScale*pixel.red)]);
02226               pixel.green=(MagickRealType) ScaleCharToQuantum(YCCMap[RoundToYCC(
02227                 255.0*QuantumScale*pixel.green)]);
02228               pixel.blue=(MagickRealType) ScaleCharToQuantum(YCCMap[RoundToYCC(
02229                 255.0*QuantumScale*pixel.blue)]);
02230 #endif
02231               break;
02232             }
02233             case sRGBColorspace:
02234             {
02235               if ((QuantumScale*pixel.red) <= 0.0031308)
02236                 pixel.red*=12.92f;
02237               else
02238                 pixel.red=(MagickRealType) QuantumRange*(1.055*
02239                   pow(QuantumScale*pixel.red,(1.0/2.4))-0.055);
02240               if ((QuantumScale*pixel.green) <= 0.0031308)
02241                 pixel.green*=12.92f;
02242               else
02243                 pixel.green=(MagickRealType) QuantumRange*(1.055*
02244                   pow(QuantumScale*pixel.green,(1.0/2.4))-0.055);
02245               if ((QuantumScale*pixel.blue) <= 0.0031308)
02246                 pixel.blue*=12.92f;
02247               else
02248                 pixel.blue=(MagickRealType) QuantumRange*(1.055*
02249                   pow(QuantumScale*pixel.blue,(1.0/2.4))-0.055);
02250               break;
02251             }
02252             default:
02253               break;
02254           }
02255           q->red=ScaleMapToQuantum((MagickRealType) MaxMap*QuantumScale*
02256             pixel.red);
02257           q->green=ScaleMapToQuantum((MagickRealType) MaxMap*QuantumScale*
02258             pixel.green);
02259           q->blue=ScaleMapToQuantum((MagickRealType) MaxMap*QuantumScale*
02260             pixel.blue);
02261           q++;
02262         }
02263         sync=SyncCacheViewAuthenticPixels(image_view,exception);
02264         if (sync == MagickFalse)
02265           status=MagickFalse;
02266         if (image->progress_monitor != (MagickProgressMonitor) NULL)
02267           {
02268             MagickBooleanType
02269               proceed;
02270 
02271 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02272   #pragma omp critical (MagickCore_TransformRGBImage)
02273 #endif
02274             proceed=SetImageProgress(image,TransformRGBImageTag,progress++,
02275               image->rows);
02276             if (proceed == MagickFalse)
02277               status=MagickFalse;
02278           }
02279       }
02280       image_view=DestroyCacheView(image_view);
02281       break;
02282     }
02283     case PseudoClass:
02284     {
02285       /*
02286         Convert PseudoClass image.
02287       */
02288       image_view=AcquireCacheView(image);
02289 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02290   #pragma omp parallel for schedule(dynamic,4) shared(status)
02291 #endif
02292       for (i=0; i < (long) image->colors; i++)
02293       {
02294         MagickPixelPacket
02295           pixel;
02296 
02297         register unsigned long
02298           blue,
02299           green,
02300           red;
02301 
02302         red=ScaleQuantumToMap(image->colormap[i].red);
02303         green=ScaleQuantumToMap(image->colormap[i].green);
02304         blue=ScaleQuantumToMap(image->colormap[i].blue);
02305         pixel.red=x_map[red].x+y_map[green].x+z_map[blue].x;
02306         pixel.green=x_map[red].y+y_map[green].y+z_map[blue].y;
02307         pixel.blue=x_map[red].z+y_map[green].z+z_map[blue].z;
02308         switch (colorspace)
02309         {
02310           case YCCColorspace:
02311           {
02312 #if !defined(MAGICKCORE_HDRI_SUPPORT)
02313             image->colormap[i].red=ScaleCharToQuantum(YCCMap[RoundToYCC(
02314               255.0*QuantumScale*pixel.red)]);
02315             image->colormap[i].green=ScaleCharToQuantum(YCCMap[RoundToYCC(
02316               255.0*QuantumScale*pixel.green)]);
02317             image->colormap[i].blue=ScaleCharToQuantum(YCCMap[RoundToYCC(
02318               255.0*QuantumScale*pixel.blue)]);
02319 #endif
02320             break;
02321           }
02322           case sRGBColorspace:
02323           {
02324             if ((QuantumScale*pixel.red) <= 0.0031308)
02325               pixel.red*=12.92f;
02326             else
02327               pixel.red=(MagickRealType) QuantumRange*(1.055*pow(QuantumScale*
02328                 pixel.red,(1.0/2.4))-0.055);
02329             if ((QuantumScale*pixel.green) <= 0.0031308)
02330               pixel.green*=12.92f;
02331             else
02332               pixel.green=(MagickRealType) QuantumRange*(1.055*pow(QuantumScale*
02333                 pixel.green,(1.0/2.4))-0.055);
02334             if ((QuantumScale*pixel.blue) <= 0.0031308)
02335               pixel.blue*=12.92f;
02336             else
02337               pixel.blue=(MagickRealType) QuantumRange*(1.055*pow(QuantumScale*
02338                 pixel.blue,(1.0/2.4))-0.055);
02339           }
02340           default:
02341           {
02342             image->colormap[i].red=ScaleMapToQuantum((MagickRealType) MaxMap*
02343               QuantumScale*pixel.red);
02344             image->colormap[i].green=ScaleMapToQuantum((MagickRealType) MaxMap*
02345               QuantumScale*pixel.green);
02346             image->colormap[i].blue=ScaleMapToQuantum((MagickRealType) MaxMap*
02347               QuantumScale*pixel.blue);
02348             break;
02349           }
02350         }
02351       }
02352       image_view=DestroyCacheView(image_view);
02353       (void) SyncImage(image);
02354       break;
02355     }
02356   }
02357   /*
02358     Relinquish resources.
02359   */
02360   z_map=(TransformPacket *) RelinquishMagickMemory(z_map);
02361   y_map=(TransformPacket *) RelinquishMagickMemory(y_map);
02362   x_map=(TransformPacket *) RelinquishMagickMemory(x_map);
02363   if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
02364     return(MagickFalse);
02365   return(MagickTrue);
02366 }

Generated on 19 Nov 2009 for MagickCore by  doxygen 1.6.1