MagickCore  6.7.5
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-2012 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 "MagickCore/studio.h"
00043 #include "MagickCore/property.h"
00044 #include "MagickCore/cache.h"
00045 #include "MagickCore/cache-private.h"
00046 #include "MagickCore/cache-view.h"
00047 #include "MagickCore/color.h"
00048 #include "MagickCore/color-private.h"
00049 #include "MagickCore/colorspace.h"
00050 #include "MagickCore/colorspace-private.h"
00051 #include "MagickCore/exception.h"
00052 #include "MagickCore/exception-private.h"
00053 #include "MagickCore/image.h"
00054 #include "MagickCore/image-private.h"
00055 #include "MagickCore/gem.h"
00056 #include "MagickCore/gem-private.h"
00057 #include "MagickCore/memory_.h"
00058 #include "MagickCore/monitor.h"
00059 #include "MagickCore/monitor-private.h"
00060 #include "MagickCore/pixel-accessor.h"
00061 #include "MagickCore/quantize.h"
00062 #include "MagickCore/quantum.h"
00063 #include "MagickCore/quantum-private.h"
00064 #include "MagickCore/string_.h"
00065 #include "MagickCore/string-private.h"
00066 #include "MagickCore/utility.h"
00067 
00068 /*
00069   Typedef declarations.
00070 */
00071 typedef struct _TransformPacket
00072 {
00073   MagickRealType
00074     x,
00075     y,
00076     z;
00077 } TransformPacket;
00078 
00079 /*
00080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00081 %                                                                             %
00082 %                                                                             %
00083 %                                                                             %
00084 +     R G B T r a n s f o r m I m a g e                                       %
00085 %                                                                             %
00086 %                                                                             %
00087 %                                                                             %
00088 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00089 %
00090 %  RGBTransformImage() converts the reference image from RGB to an alternate
00091 %  colorspace.  The transformation matrices are not the standard ones: the
00092 %  weights are rescaled to normalized the range of the transformed values to
00093 %  be [0..QuantumRange].
00094 %
00095 %  The format of the RGBTransformImage method is:
00096 %
00097 %      MagickBooleanType RGBTransformImage(Image *image,
00098 %        const ColorspaceType colorspace,EsceptionInfo *exception)
00099 %
00100 %  A description of each parameter follows:
00101 %
00102 %    o image: the image.
00103 %
00104 %    o colorspace: the colorspace to transform the image to.
00105 %
00106 %   o exception: return any errors or warnings in this structure.
00107 %
00108 */
00109 
00110 static inline void ConvertRGBToXYZ(const Quantum red,const Quantum green,
00111   const Quantum blue,double *X,double *Y,double *Z)
00112 {
00113   double
00114     b,
00115     g,
00116     r;
00117 
00118   assert(X != (double *) NULL);
00119   assert(Y != (double *) NULL);
00120   assert(Z != (double *) NULL);
00121   r=QuantumScale*red;
00122   if (r > 0.04045)
00123     r=pow((r+0.055)/1.055,2.4);
00124   else
00125     r/=12.92;
00126   g=QuantumScale*green;
00127   if (g > 0.04045)
00128     g=pow((g+0.055)/1.055,2.4);
00129   else
00130     g/=12.92;
00131   b=QuantumScale*blue;
00132   if (b > 0.04045)
00133     b=pow((b+0.055)/1.055,2.4);
00134   else
00135     b/=12.92;
00136   *X=0.4124240*r+0.3575790*g+0.1804640*b;
00137   *Y=0.2126560*r+0.7151580*g+0.0721856*b;
00138   *Z=0.0193324*r+0.1191930*g+0.9504440*b;
00139 }
00140 
00141 static double LabF1(double alpha)
00142 {
00143 
00144   if (alpha <= ((24.0/116.0)*(24.0/116.0)*(24.0/116.0)))
00145     return((841.0/108.0)*alpha+(16.0/116.0));
00146   return(pow(alpha,1.0/3.0));
00147 }
00148 
00149 static inline void ConvertXYZToLab(const double X,const double Y,const double Z,
00150   double *L,double *a,double *b)
00151 {
00152 #define D50X  (0.9642)
00153 #define D50Y  (1.0)
00154 #define D50Z  (0.8249)
00155 
00156   double
00157     fx,
00158     fy,
00159     fz;
00160 
00161   assert(L != (double *) NULL);
00162   assert(a != (double *) NULL);
00163   assert(b != (double *) NULL);
00164   *L=0.0;
00165   *a=0.5;
00166   *b=0.5;
00167   if ((fabs(X) < MagickEpsilon) && (fabs(Y) < MagickEpsilon) &&
00168       (fabs(Z) < MagickEpsilon))
00169     return;
00170   fx=LabF1(X/D50X);
00171   fy=LabF1(Y/D50Y);
00172   fz=LabF1(Z/D50Z);
00173   *L=(116.0*fy-16.0)/100.0;
00174   *a=(500.0*(fx-fy))/255.0;
00175   if (*a < 0.0)
00176     *a+=1.0;
00177   *b=(200.0*(fy-fz))/255.0;
00178   if (*b < 0.0)
00179     *b+=1.0;
00180 }
00181 
00182 MagickExport MagickBooleanType RGBTransformImage(Image *image,
00183   const ColorspaceType colorspace,ExceptionInfo *exception)
00184 {
00185 #define RGBTransformImageTag  "RGBTransform/Image"
00186 
00187   CacheView
00188     *image_view;
00189 
00190   MagickBooleanType
00191     status;
00192 
00193   MagickOffsetType
00194     progress;
00195 
00196   PrimaryInfo
00197     primary_info;
00198 
00199   register ssize_t
00200     i;
00201 
00202   ssize_t
00203     y;
00204 
00205   TransformPacket
00206     *x_map,
00207     *y_map,
00208     *z_map;
00209 
00210   assert(image != (Image *) NULL);
00211   assert(image->signature == MagickSignature);
00212   if (image->debug != MagickFalse)
00213     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00214   assert(colorspace != RGBColorspace);
00215   assert(colorspace != TransparentColorspace);
00216   assert(colorspace != UndefinedColorspace);
00217   if (IsRGBColorspace(image->colorspace) == MagickFalse)
00218     (void) TransformRGBImage(image,image->colorspace,exception);
00219   if (SetImageColorspace(image,colorspace,exception) == MagickFalse)
00220     return(MagickFalse);
00221   status=MagickTrue;
00222   progress=0;
00223   switch (colorspace)
00224   {
00225     case CMYColorspace:
00226     {
00227       /*
00228         Convert RGB to CMY colorspace.
00229       */
00230       if (image->storage_class == PseudoClass)
00231         {
00232           if (SyncImage(image,exception) == MagickFalse)
00233             return(MagickFalse);
00234           if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
00235             return(MagickFalse);
00236         }
00237       image_view=AcquireCacheView(image);
00238 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00239       #pragma omp parallel for schedule(static,4) shared(status)
00240 #endif
00241       for (y=0; y < (ssize_t) image->rows; y++)
00242       {
00243         MagickBooleanType
00244           sync;
00245 
00246         register ssize_t
00247           x;
00248 
00249         register Quantum
00250           *restrict q;
00251 
00252         if (status == MagickFalse)
00253           continue;
00254         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
00255           exception);
00256         if (q == (Quantum *) NULL)
00257           {
00258             status=MagickFalse;
00259             continue;
00260           }
00261         for (x=0; x < (ssize_t) image->columns; x++)
00262         {
00263           SetPixelRed(image,ClampToQuantum((MagickRealType) (QuantumRange-
00264             GetPixelRed(image,q))),q);
00265           SetPixelGreen(image,ClampToQuantum((MagickRealType) (QuantumRange-
00266             GetPixelGreen(image,q))),q);
00267           SetPixelBlue(image,ClampToQuantum((MagickRealType) (QuantumRange-
00268             GetPixelBlue(image,q))),q);
00269           q+=GetPixelChannels(image);
00270         }
00271         sync=SyncCacheViewAuthenticPixels(image_view,exception);
00272         if (sync == MagickFalse)
00273           status=MagickFalse;
00274       }
00275       image_view=DestroyCacheView(image_view);
00276       image->type=image->matte == MagickFalse ? ColorSeparationType :
00277         ColorSeparationMatteType;
00278       return(status);
00279     }
00280     case CMYKColorspace:
00281     {
00282       PixelInfo
00283         zero;
00284 
00285       /*
00286         Convert RGB to CMYK colorspace.
00287       */
00288       if (image->storage_class == PseudoClass)
00289         {
00290           if (SyncImage(image,exception) == MagickFalse)
00291             return(MagickFalse);
00292           if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
00293             return(MagickFalse);
00294         }
00295       GetPixelInfo(image,&zero);
00296       image_view=AcquireCacheView(image);
00297 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00298       #pragma omp parallel for schedule(static,4) shared(status)
00299 #endif
00300       for (y=0; y < (ssize_t) image->rows; y++)
00301       {
00302         MagickBooleanType
00303           sync;
00304 
00305         PixelInfo
00306           pixel;
00307 
00308         register ssize_t
00309           x;
00310 
00311         register Quantum
00312           *restrict q;
00313 
00314         if (status == MagickFalse)
00315           continue;
00316         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
00317           exception);
00318         if (q == (Quantum *) NULL)
00319           {
00320             status=MagickFalse;
00321             continue;
00322           }
00323         pixel=zero;
00324         for (x=0; x < (ssize_t) image->columns; x++)
00325         {
00326           GetPixelInfoPixel(image,q,&pixel);
00327           ConvertRGBToCMYK(&pixel);
00328           SetPixelInfoPixel(image,&pixel,q);
00329           q+=GetPixelChannels(image);
00330         }
00331         sync=SyncCacheViewAuthenticPixels(image_view,exception);
00332         if (sync == MagickFalse)
00333           status=MagickFalse;
00334       }
00335       image_view=DestroyCacheView(image_view);
00336       image->type=image->matte == MagickFalse ? ColorSeparationType :
00337         ColorSeparationMatteType;
00338       return(status);
00339     }
00340     case HSBColorspace:
00341     {
00342       /*
00343         Transform image from RGB to HSB.
00344       */
00345       if (image->storage_class == PseudoClass)
00346         {
00347           if (SyncImage(image,exception) == MagickFalse)
00348             return(MagickFalse);
00349           if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
00350             return(MagickFalse);
00351         }
00352       image_view=AcquireCacheView(image);
00353 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00354       #pragma omp parallel for schedule(static,4) shared(status)
00355 #endif
00356       for (y=0; y < (ssize_t) image->rows; y++)
00357       {
00358         double
00359           brightness,
00360           hue,
00361           saturation;
00362 
00363         MagickBooleanType
00364           sync;
00365 
00366         register ssize_t
00367           x;
00368 
00369         register Quantum
00370           *restrict q;
00371 
00372         if (status == MagickFalse)
00373           continue;
00374         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
00375           exception);
00376         if (q == (Quantum *) NULL)
00377           {
00378             status=MagickFalse;
00379             continue;
00380           }
00381         hue=0.0;
00382         saturation=0.0;
00383         brightness=0.0;
00384         for (x=0; x < (ssize_t) image->columns; x++)
00385         {
00386           ConvertRGBToHSB((double) GetPixelRed(image,q),
00387             (double) GetPixelGreen(image,q),(double) GetPixelBlue(image,q),
00388             &hue,&saturation,&brightness);
00389           SetPixelRed(image,ClampToQuantum((MagickRealType) QuantumRange*
00390             hue),q);
00391           SetPixelGreen(image,ClampToQuantum((MagickRealType) QuantumRange*
00392             saturation),q);
00393           SetPixelBlue(image,ClampToQuantum((MagickRealType) QuantumRange*
00394             brightness),q);
00395           q+=GetPixelChannels(image);
00396         }
00397         sync=SyncCacheViewAuthenticPixels(image_view,exception);
00398         if (sync == MagickFalse)
00399           status=MagickFalse;
00400       }
00401       image_view=DestroyCacheView(image_view);
00402       return(status);
00403     }
00404     case HSLColorspace:
00405     {
00406       /*
00407         Transform image from RGB to HSL.
00408       */
00409       if (image->storage_class == PseudoClass)
00410         {
00411           if (SyncImage(image,exception) == MagickFalse)
00412             return(MagickFalse);
00413           if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
00414             return(MagickFalse);
00415         }
00416       image_view=AcquireCacheView(image);
00417 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00418       #pragma omp parallel for schedule(static,4) shared(status)
00419 #endif
00420       for (y=0; y < (ssize_t) image->rows; y++)
00421       {
00422         double
00423           hue,
00424           lightness,
00425           saturation;
00426 
00427         MagickBooleanType
00428           sync;
00429 
00430         register ssize_t
00431           x;
00432 
00433         register Quantum
00434           *restrict q;
00435 
00436         if (status == MagickFalse)
00437           continue;
00438         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
00439           exception);
00440         if (q == (Quantum *) NULL)
00441           {
00442             status=MagickFalse;
00443             continue;
00444           }
00445         hue=0.0;
00446         saturation=0.0;
00447         lightness=0.0;
00448         for (x=0; x < (ssize_t) image->columns; x++)
00449         {
00450           ConvertRGBToHSL((double) GetPixelRed(image,q),(double)
00451             GetPixelGreen(image,q),(double) GetPixelBlue(image,q),
00452             &hue,&saturation,&lightness);
00453           SetPixelRed(image,ClampToQuantum((MagickRealType) QuantumRange*
00454             hue),q);
00455           SetPixelGreen(image,ClampToQuantum((MagickRealType) QuantumRange*
00456             saturation),q);
00457           SetPixelBlue(image,ClampToQuantum((MagickRealType) QuantumRange*
00458             lightness),q);
00459           q+=GetPixelChannels(image);
00460         }
00461         sync=SyncCacheViewAuthenticPixels(image_view,exception);
00462         if (sync == MagickFalse)
00463           status=MagickFalse;
00464       }
00465       image_view=DestroyCacheView(image_view);
00466       return(status);
00467     }
00468     case HWBColorspace:
00469     {
00470       /*
00471         Transform image from RGB to HWB.
00472       */
00473       if (image->storage_class == PseudoClass)
00474         {
00475           if (SyncImage(image,exception) == MagickFalse)
00476             return(MagickFalse);
00477           if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
00478             return(MagickFalse);
00479         }
00480       image_view=AcquireCacheView(image);
00481 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00482       #pragma omp parallel for schedule(static,4) shared(status)
00483 #endif
00484       for (y=0; y < (ssize_t) image->rows; y++)
00485       {
00486         double
00487           blackness,
00488           hue,
00489           whiteness;
00490 
00491         MagickBooleanType
00492           sync;
00493 
00494         register ssize_t
00495           x;
00496 
00497         register Quantum
00498           *restrict q;
00499 
00500         if (status == MagickFalse)
00501           continue;
00502         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
00503           exception);
00504         if (q == (Quantum *) NULL)
00505           {
00506             status=MagickFalse;
00507             continue;
00508           }
00509         hue=0.0;
00510         whiteness=0.0;
00511         blackness=0.0;
00512         for (x=0; x < (ssize_t) image->columns; x++)
00513         {
00514           ConvertRGBToHWB((double) GetPixelRed(image,q),(double)
00515             GetPixelGreen(image,q),(double) GetPixelBlue(image,q),
00516             &hue,&whiteness,&blackness);
00517           SetPixelRed(image,ClampToQuantum((MagickRealType) QuantumRange*
00518             hue),q);
00519           SetPixelGreen(image,ClampToQuantum((MagickRealType) QuantumRange*
00520             whiteness),q);
00521           SetPixelBlue(image,ClampToQuantum((MagickRealType) QuantumRange*
00522             blackness),q);
00523           q+=GetPixelChannels(image);
00524         }
00525         sync=SyncCacheViewAuthenticPixels(image_view,exception);
00526         if (sync == MagickFalse)
00527           status=MagickFalse;
00528       }
00529       image_view=DestroyCacheView(image_view);
00530       return(status);
00531     }
00532     case LabColorspace:
00533     {
00534       /*
00535         Transform image from RGB to Lab.
00536       */
00537       if (image->storage_class == PseudoClass)
00538         {
00539           if (SyncImage(image,exception) == MagickFalse)
00540             return(MagickFalse);
00541           if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
00542             return(MagickFalse);
00543         }
00544       image_view=AcquireCacheView(image);
00545 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00546       #pragma omp parallel for schedule(static,4) shared(status)
00547 #endif
00548       for (y=0; y < (ssize_t) image->rows; y++)
00549       {
00550         double
00551           a,
00552           b,
00553           L,
00554           X,
00555           Y,
00556           Z;
00557 
00558         MagickBooleanType
00559           sync;
00560 
00561         register ssize_t
00562           x;
00563 
00564         register Quantum
00565           *restrict q;
00566 
00567         if (status == MagickFalse)
00568           continue;
00569         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
00570           exception);
00571         if (q == (Quantum *) NULL)
00572           {
00573             status=MagickFalse;
00574             continue;
00575           }
00576         L=0.0;
00577         a=0.0;
00578         b=0.0;
00579         X=0.0;
00580         Y=0.0;
00581         Z=0.0;
00582         for (x=0; x < (ssize_t) image->columns; x++)
00583         {
00584           ConvertRGBToXYZ(GetPixelRed(image,q),GetPixelGreen(image,q),
00585             GetPixelBlue(image,q),&X,&Y,&Z);
00586           ConvertXYZToLab(X,Y,Z,&L,&a,&b);
00587           SetPixelRed(image,ClampToQuantum((MagickRealType) QuantumRange*
00588             L),q);
00589           SetPixelGreen(image,ClampToQuantum((MagickRealType) QuantumRange*
00590             a),q);
00591           SetPixelBlue(image,ClampToQuantum((MagickRealType) QuantumRange*
00592             b),q);
00593           q+=GetPixelChannels(image);
00594         }
00595         sync=SyncCacheViewAuthenticPixels(image_view,exception);
00596         if (sync == MagickFalse)
00597           status=MagickFalse;
00598       }
00599       image_view=DestroyCacheView(image_view);
00600       return(status);
00601     }
00602     case LogColorspace:
00603     {
00604 #define DisplayGamma  (1.0/1.7)
00605 #define FilmGamma  0.6
00606 #define ReferenceBlack  95.0
00607 #define ReferenceWhite  685.0
00608 
00609       const char
00610         *value;
00611 
00612       double
00613         black,
00614         density,
00615         film_gamma,
00616         gamma,
00617         reference_black,
00618         reference_white;
00619 
00620       Quantum
00621         *logmap;
00622 
00623       /*
00624         Transform RGB to Log colorspace.
00625       */
00626       density=DisplayGamma;
00627       gamma=DisplayGamma;
00628       value=GetImageProperty(image,"gamma",exception);
00629       if (value != (const char *) NULL)
00630         gamma=1.0/fabs(StringToDouble(value,(char **) NULL)) >= MagickEpsilon ?
00631           StringToDouble(value,(char **) NULL) : 1.0;
00632       film_gamma=FilmGamma;
00633       value=GetImageProperty(image,"film-gamma",exception);
00634       if (value != (const char *) NULL)
00635         film_gamma=StringToDouble(value,(char **) NULL);
00636       reference_black=ReferenceBlack;
00637       value=GetImageProperty(image,"reference-black",exception);
00638       if (value != (const char *) NULL)
00639         reference_black=StringToDouble(value,(char **) NULL);
00640       reference_white=ReferenceWhite;
00641       value=GetImageProperty(image,"reference-white",exception);
00642       if (value != (const char *) NULL)
00643         reference_white=StringToDouble(value,(char **) NULL);
00644       logmap=(Quantum *) AcquireQuantumMemory((size_t) MaxMap+1UL,
00645         sizeof(*logmap));
00646       if (logmap == (Quantum *) NULL)
00647         ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
00648           image->filename);
00649       black=pow(10.0,(reference_black-reference_white)*(gamma/density)*
00650         0.002/film_gamma);
00651 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00652       #pragma omp parallel for schedule(static)
00653 #endif
00654       for (i=0; i <= (ssize_t) MaxMap; i++)
00655         logmap[i]=ScaleMapToQuantum((MagickRealType) (MaxMap*(reference_white+
00656           log10(black+((MagickRealType) i/MaxMap)*(1.0-black))/((gamma/density)*
00657           0.002/film_gamma))/1024.0));
00658       image_view=AcquireCacheView(image);
00659 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00660       #pragma omp parallel for schedule(static,4) shared(status)
00661 #endif
00662       for (y=0; y < (ssize_t) image->rows; y++)
00663       {
00664         MagickBooleanType
00665           sync;
00666 
00667         register ssize_t
00668           x;
00669 
00670         register Quantum
00671           *restrict q;
00672 
00673         if (status == MagickFalse)
00674           continue;
00675         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
00676           exception);
00677         if (q == (Quantum *) NULL)
00678           {
00679             status=MagickFalse;
00680             continue;
00681           }
00682         for (x=(ssize_t) image->columns; x != 0; x--)
00683         {
00684           SetPixelRed(image,logmap[ScaleQuantumToMap(
00685             GetPixelRed(image,q))],q);
00686           SetPixelGreen(image,logmap[ScaleQuantumToMap(
00687             GetPixelGreen(image,q))],q);
00688           SetPixelBlue(image,logmap[ScaleQuantumToMap(
00689             GetPixelBlue(image,q))],q);
00690           q+=GetPixelChannels(image);
00691         }
00692         sync=SyncCacheViewAuthenticPixels(image_view,exception);
00693         if (sync == MagickFalse)
00694           status=MagickFalse;
00695       }
00696       image_view=DestroyCacheView(image_view);
00697       logmap=(Quantum *) RelinquishMagickMemory(logmap);
00698       return(status);
00699     }
00700     default:
00701       break;
00702   }
00703   /*
00704     Allocate the tables.
00705   */
00706   x_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
00707     sizeof(*x_map));
00708   y_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
00709     sizeof(*y_map));
00710   z_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
00711     sizeof(*z_map));
00712   if ((x_map == (TransformPacket *) NULL) ||
00713       (y_map == (TransformPacket *) NULL) ||
00714       (z_map == (TransformPacket *) NULL))
00715     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
00716       image->filename);
00717   (void) ResetMagickMemory(&primary_info,0,sizeof(primary_info));
00718   switch (colorspace)
00719   {
00720     case OHTAColorspace:
00721     {
00722       /*
00723         Initialize OHTA tables:
00724 
00725           I1 = 0.33333*R+0.33334*G+0.33333*B
00726           I2 = 0.50000*R+0.00000*G-0.50000*B
00727           I3 =-0.25000*R+0.50000*G-0.25000*B
00728 
00729         I and Q, normally -0.5 through 0.5, are normalized to the range 0
00730         through QuantumRange.
00731       */
00732       primary_info.y=(double) (MaxMap+1.0)/2.0;
00733       primary_info.z=(double) (MaxMap+1.0)/2.0;
00734 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00735       #pragma omp parallel for schedule(static)
00736 #endif
00737       for (i=0; i <= (ssize_t) MaxMap; i++)
00738       {
00739         x_map[i].x=0.33333f*(MagickRealType) i;
00740         y_map[i].x=0.33334f*(MagickRealType) i;
00741         z_map[i].x=0.33333f*(MagickRealType) i;
00742         x_map[i].y=0.50000f*(MagickRealType) i;
00743         y_map[i].y=0.00000f*(MagickRealType) i;
00744         z_map[i].y=(-0.50000f)*(MagickRealType) i;
00745         x_map[i].z=(-0.25000f)*(MagickRealType) i;
00746         y_map[i].z=0.50000f*(MagickRealType) i;
00747         z_map[i].z=(-0.25000f)*(MagickRealType) i;
00748       }
00749       break;
00750     }
00751     case Rec601LumaColorspace:
00752     case GRAYColorspace:
00753     {
00754       /*
00755         Initialize Rec601 luma tables:
00756 
00757           G = 0.29900*R+0.58700*G+0.11400*B
00758       */
00759 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00760       #pragma omp parallel for schedule(static)
00761 #endif
00762       for (i=0; i <= (ssize_t) MaxMap; i++)
00763       {
00764         x_map[i].x=0.29900f*(MagickRealType) i;
00765         y_map[i].x=0.58700f*(MagickRealType) i;
00766         z_map[i].x=0.11400f*(MagickRealType) i;
00767         x_map[i].y=0.29900f*(MagickRealType) i;
00768         y_map[i].y=0.58700f*(MagickRealType) i;
00769         z_map[i].y=0.11400f*(MagickRealType) i;
00770         x_map[i].z=0.29900f*(MagickRealType) i;
00771         y_map[i].z=0.58700f*(MagickRealType) i;
00772         z_map[i].z=0.11400f*(MagickRealType) i;
00773       }
00774       image->type=GrayscaleType;
00775       break;
00776     }
00777     case Rec601YCbCrColorspace:
00778     case YCbCrColorspace:
00779     {
00780       /*
00781         Initialize YCbCr tables (ITU-R BT.601):
00782 
00783           Y =  0.299000*R+0.587000*G+0.114000*B
00784           Cb= -0.168736*R-0.331264*G+0.500000*B
00785           Cr=  0.500000*R-0.418688*G-0.081312*B
00786 
00787         Cb and Cr, normally -0.5 through 0.5, are normalized to the range 0
00788         through QuantumRange.
00789       */
00790       primary_info.y=(double) (MaxMap+1.0)/2.0;
00791       primary_info.z=(double) (MaxMap+1.0)/2.0;
00792 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00793       #pragma omp parallel for schedule(static)
00794 #endif
00795       for (i=0; i <= (ssize_t) MaxMap; i++)
00796       {
00797         x_map[i].x=0.299000f*(MagickRealType) i;
00798         y_map[i].x=0.587000f*(MagickRealType) i;
00799         z_map[i].x=0.114000f*(MagickRealType) i;
00800         x_map[i].y=(-0.168730f)*(MagickRealType) i;
00801         y_map[i].y=(-0.331264f)*(MagickRealType) i;
00802         z_map[i].y=0.500000f*(MagickRealType) i;
00803         x_map[i].z=0.500000f*(MagickRealType) i;
00804         y_map[i].z=(-0.418688f)*(MagickRealType) i;
00805         z_map[i].z=(-0.081312f)*(MagickRealType) i;
00806       }
00807       break;
00808     }
00809     case Rec709LumaColorspace:
00810     {
00811       /*
00812         Initialize Rec709 luma tables:
00813 
00814           G = 0.21260*R+0.71520*G+0.07220*B
00815       */
00816 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00817       #pragma omp parallel for schedule(static)
00818 #endif
00819       for (i=0; i <= (ssize_t) MaxMap; i++)
00820       {
00821         x_map[i].x=0.21260f*(MagickRealType) i;
00822         y_map[i].x=0.71520f*(MagickRealType) i;
00823         z_map[i].x=0.07220f*(MagickRealType) i;
00824         x_map[i].y=0.21260f*(MagickRealType) i;
00825         y_map[i].y=0.71520f*(MagickRealType) i;
00826         z_map[i].y=0.07220f*(MagickRealType) i;
00827         x_map[i].z=0.21260f*(MagickRealType) i;
00828         y_map[i].z=0.71520f*(MagickRealType) i;
00829         z_map[i].z=0.07220f*(MagickRealType) i;
00830       }
00831       break;
00832     }
00833     case Rec709YCbCrColorspace:
00834     {
00835       /*
00836         Initialize YCbCr tables (ITU-R BT.709):
00837 
00838           Y =  0.212600*R+0.715200*G+0.072200*B
00839           Cb= -0.114572*R-0.385428*G+0.500000*B
00840           Cr=  0.500000*R-0.454153*G-0.045847*B
00841 
00842         Cb and Cr, normally -0.5 through 0.5, are normalized to the range 0
00843         through QuantumRange.
00844       */
00845       primary_info.y=(double) (MaxMap+1.0)/2.0;
00846       primary_info.z=(double) (MaxMap+1.0)/2.0;
00847 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00848       #pragma omp parallel for schedule(static)
00849 #endif
00850       for (i=0; i <= (ssize_t) MaxMap; i++)
00851       {
00852         x_map[i].x=0.212600f*(MagickRealType) i;
00853         y_map[i].x=0.715200f*(MagickRealType) i;
00854         z_map[i].x=0.072200f*(MagickRealType) i;
00855         x_map[i].y=(-0.114572f)*(MagickRealType) i;
00856         y_map[i].y=(-0.385428f)*(MagickRealType) i;
00857         z_map[i].y=0.500000f*(MagickRealType) i;
00858         x_map[i].z=0.500000f*(MagickRealType) i;
00859         y_map[i].z=(-0.454153f)*(MagickRealType) i;
00860         z_map[i].z=(-0.045847f)*(MagickRealType) i;
00861       }
00862       break;
00863     }
00864     case sRGBColorspace:
00865     {
00866       /*
00867         Nonlinear sRGB to linear RGB (http://www.w3.org/Graphics/Color/sRGB):
00868 
00869           R = 1.0*R+0.0*G+0.0*B
00870           G = 0.0*R+1.0*G+0.0*B
00871           B = 0.0*R+0.0*G+1.0*B
00872       */
00873 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00874       #pragma omp parallel for schedule(static)
00875 #endif
00876       for (i=0; i <= (ssize_t) MaxMap; i++)
00877       {
00878         MagickRealType
00879           v;
00880 
00881         v=(MagickRealType) i/(MagickRealType) MaxMap;
00882         if (((MagickRealType) i/(MagickRealType) MaxMap) <= 0.0031308)
00883           v*=12.92f;
00884         else
00885           v=(MagickRealType) (1.055*pow((double) i/MaxMap,1.0/2.4)-0.055);
00886         x_map[i].x=1.0f*MaxMap*v;
00887         y_map[i].x=0.0f*MaxMap*v;
00888         z_map[i].x=0.0f*MaxMap*v;
00889         x_map[i].y=0.0f*MaxMap*v;
00890         y_map[i].y=1.0f*MaxMap*v;
00891         z_map[i].y=0.0f*MaxMap*v;
00892         x_map[i].z=0.0f*MaxMap*v;
00893         y_map[i].z=0.0f*MaxMap*v;
00894         z_map[i].z=1.0f*MaxMap*v;
00895       }
00896       break;
00897     }
00898     case XYZColorspace:
00899     {
00900       /*
00901         Initialize CIE XYZ tables (ITU-R 709 RGB):
00902 
00903           X = 0.4124564*R+0.3575761*G+0.1804375*B
00904           Y = 0.2126729*R+0.7151522*G+0.0721750*B
00905           Z = 0.0193339*R+0.1191920*G+0.9503041*B
00906       */
00907 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00908       #pragma omp parallel for schedule(static)
00909 #endif
00910       for (i=0; i <= (ssize_t) MaxMap; i++)
00911       {
00912         x_map[i].x=0.4124564f*(MagickRealType) i;
00913         y_map[i].x=0.3575761f*(MagickRealType) i;
00914         z_map[i].x=0.1804375f*(MagickRealType) i;
00915         x_map[i].y=0.2126729f*(MagickRealType) i;
00916         y_map[i].y=0.7151522f*(MagickRealType) i;
00917         z_map[i].y=0.0721750f*(MagickRealType) i;
00918         x_map[i].z=0.0193339f*(MagickRealType) i;
00919         y_map[i].z=0.1191920f*(MagickRealType) i;
00920         z_map[i].z=0.9503041f*(MagickRealType) i;
00921       }
00922       break;
00923     }
00924     case YCCColorspace:
00925     {
00926       /*
00927         Initialize YCC tables:
00928 
00929           Y =  0.29900*R+0.58700*G+0.11400*B
00930           C1= -0.29900*R-0.58700*G+0.88600*B
00931           C2=  0.70100*R-0.58700*G-0.11400*B
00932 
00933         YCC is scaled by 1.3584.  C1 zero is 156 and C2 is at 137.
00934       */
00935       primary_info.y=(double) ScaleQuantumToMap(ScaleCharToQuantum(156));
00936       primary_info.z=(double) ScaleQuantumToMap(ScaleCharToQuantum(137));
00937       for (i=0; i <= (ssize_t) (0.018*MaxMap); i++)
00938       {
00939         x_map[i].x=0.003962014134275617f*(MagickRealType) i;
00940         y_map[i].x=0.007778268551236748f*(MagickRealType) i;
00941         z_map[i].x=0.001510600706713781f*(MagickRealType) i;
00942         x_map[i].y=(-0.002426619775463276f)*(MagickRealType) i;
00943         y_map[i].y=(-0.004763965913702149f)*(MagickRealType) i;
00944         z_map[i].y=0.007190585689165425f*(MagickRealType) i;
00945         x_map[i].z=0.006927257754597858f*(MagickRealType) i;
00946         y_map[i].z=(-0.005800713697502058f)*(MagickRealType) i;
00947         z_map[i].z=(-0.0011265440570958f)*(MagickRealType) i;
00948       }
00949       for ( ; i <= (ssize_t) MaxMap; i++)
00950       {
00951         x_map[i].x=0.2201118963486454*(1.099f*(MagickRealType) i-0.099f);
00952         y_map[i].x=0.4321260306242638*(1.099f*(MagickRealType) i-0.099f);
00953         z_map[i].x=0.08392226148409894*(1.099f*(MagickRealType) i-0.099f);
00954         x_map[i].y=(-0.1348122097479598)*(1.099f*(MagickRealType) i-0.099f);
00955         y_map[i].y=(-0.2646647729834528)*(1.099f*(MagickRealType) i-0.099f);
00956         z_map[i].y=0.3994769827314126*(1.099f*(MagickRealType) i-0.099f);
00957         x_map[i].z=0.3848476530332144*(1.099f*(MagickRealType) i-0.099f);
00958         y_map[i].z=(-0.3222618720834477)*(1.099f*(MagickRealType) i-0.099f);
00959         z_map[i].z=(-0.06258578094976668)*(1.099f*(MagickRealType) i-0.099f);
00960       }
00961       break;
00962     }
00963     case YIQColorspace:
00964     {
00965       /*
00966         Initialize YIQ tables:
00967 
00968           Y = 0.29900*R+0.58700*G+0.11400*B
00969           I = 0.59600*R-0.27400*G-0.32200*B
00970           Q = 0.21100*R-0.52300*G+0.31200*B
00971 
00972         I and Q, normally -0.5 through 0.5, are normalized to the range 0
00973         through QuantumRange.
00974       */
00975       primary_info.y=(double) (MaxMap+1.0)/2.0;
00976       primary_info.z=(double) (MaxMap+1.0)/2.0;
00977 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00978       #pragma omp parallel for schedule(static)
00979 #endif
00980       for (i=0; i <= (ssize_t) MaxMap; i++)
00981       {
00982         x_map[i].x=0.29900f*(MagickRealType) i;
00983         y_map[i].x=0.58700f*(MagickRealType) i;
00984         z_map[i].x=0.11400f*(MagickRealType) i;
00985         x_map[i].y=0.59600f*(MagickRealType) i;
00986         y_map[i].y=(-0.27400f)*(MagickRealType) i;
00987         z_map[i].y=(-0.32200f)*(MagickRealType) i;
00988         x_map[i].z=0.21100f*(MagickRealType) i;
00989         y_map[i].z=(-0.52300f)*(MagickRealType) i;
00990         z_map[i].z=0.31200f*(MagickRealType) i;
00991       }
00992       break;
00993     }
00994     case YPbPrColorspace:
00995     {
00996       /*
00997         Initialize YPbPr tables (ITU-R BT.601):
00998 
00999           Y =  0.299000*R+0.587000*G+0.114000*B
01000           Pb= -0.168736*R-0.331264*G+0.500000*B
01001           Pr=  0.500000*R-0.418688*G-0.081312*B
01002 
01003         Pb and Pr, normally -0.5 through 0.5, are normalized to the range 0
01004         through QuantumRange.
01005       */
01006       primary_info.y=(double) (MaxMap+1.0)/2.0;
01007       primary_info.z=(double) (MaxMap+1.0)/2.0;
01008 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01009       #pragma omp parallel for schedule(static)
01010 #endif
01011       for (i=0; i <= (ssize_t) MaxMap; i++)
01012       {
01013         x_map[i].x=0.299000f*(MagickRealType) i;
01014         y_map[i].x=0.587000f*(MagickRealType) i;
01015         z_map[i].x=0.114000f*(MagickRealType) i;
01016         x_map[i].y=(-0.168736f)*(MagickRealType) i;
01017         y_map[i].y=(-0.331264f)*(MagickRealType) i;
01018         z_map[i].y=0.500000f*(MagickRealType) i;
01019         x_map[i].z=0.500000f*(MagickRealType) i;
01020         y_map[i].z=(-0.418688f)*(MagickRealType) i;
01021         z_map[i].z=(-0.081312f)*(MagickRealType) i;
01022       }
01023       break;
01024     }
01025     case YUVColorspace:
01026     default:
01027     {
01028       /*
01029         Initialize YUV tables:
01030 
01031           Y =  0.29900*R+0.58700*G+0.11400*B
01032           U = -0.14740*R-0.28950*G+0.43690*B
01033           V =  0.61500*R-0.51500*G-0.10000*B
01034 
01035         U and V, normally -0.5 through 0.5, are normalized to the range 0
01036         through QuantumRange.  Note that U = 0.493*(B-Y), V = 0.877*(R-Y).
01037       */
01038       primary_info.y=(double) (MaxMap+1.0)/2.0;
01039       primary_info.z=(double) (MaxMap+1.0)/2.0;
01040 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01041       #pragma omp parallel for schedule(static)
01042 #endif
01043       for (i=0; i <= (ssize_t) MaxMap; i++)
01044       {
01045         x_map[i].x=0.29900f*(MagickRealType) i;
01046         y_map[i].x=0.58700f*(MagickRealType) i;
01047         z_map[i].x=0.11400f*(MagickRealType) i;
01048         x_map[i].y=(-0.14740f)*(MagickRealType) i;
01049         y_map[i].y=(-0.28950f)*(MagickRealType) i;
01050         z_map[i].y=0.43690f*(MagickRealType) i;
01051         x_map[i].z=0.61500f*(MagickRealType) i;
01052         y_map[i].z=(-0.51500f)*(MagickRealType) i;
01053         z_map[i].z=(-0.10000f)*(MagickRealType) i;
01054       }
01055       break;
01056     }
01057   }
01058   /*
01059     Convert from RGB.
01060   */
01061   switch (image->storage_class)
01062   {
01063     case DirectClass:
01064     default:
01065     {
01066       /*
01067         Convert DirectClass image.
01068       */
01069       image_view=AcquireCacheView(image);
01070 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01071       #pragma omp parallel for schedule(static,4) shared(status)
01072 #endif
01073       for (y=0; y < (ssize_t) image->rows; y++)
01074       {
01075         MagickBooleanType
01076           sync;
01077 
01078         PixelInfo
01079           pixel;
01080 
01081         register Quantum
01082           *restrict q;
01083 
01084         register ssize_t
01085           x;
01086 
01087         register unsigned int
01088           blue,
01089           green,
01090           red;
01091 
01092         if (status == MagickFalse)
01093           continue;
01094         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
01095           exception);
01096         if (q == (Quantum *) NULL)
01097           {
01098             status=MagickFalse;
01099             continue;
01100           }
01101         for (x=0; x < (ssize_t) image->columns; x++)
01102         {
01103           red=ScaleQuantumToMap(GetPixelRed(image,q));
01104           green=ScaleQuantumToMap(GetPixelGreen(image,q));
01105           blue=ScaleQuantumToMap(GetPixelBlue(image,q));
01106           pixel.red=(x_map[red].x+y_map[green].x+z_map[blue].x)+
01107             (MagickRealType) primary_info.x;
01108           pixel.green=(x_map[red].y+y_map[green].y+z_map[blue].y)+
01109             (MagickRealType) primary_info.y;
01110           pixel.blue=(x_map[red].z+y_map[green].z+z_map[blue].z)+
01111             (MagickRealType) primary_info.z;
01112           SetPixelRed(image,ScaleMapToQuantum(pixel.red),q);
01113           SetPixelGreen(image,ScaleMapToQuantum(pixel.green),q);
01114           SetPixelBlue(image,ScaleMapToQuantum(pixel.blue),q);
01115           q+=GetPixelChannels(image);
01116         }
01117         sync=SyncCacheViewAuthenticPixels(image_view,exception);
01118         if (sync == MagickFalse)
01119           status=MagickFalse;
01120         if (image->progress_monitor != (MagickProgressMonitor) NULL)
01121           {
01122             MagickBooleanType
01123               proceed;
01124 
01125 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01126             #pragma omp critical (MagickCore_RGBTransformImage)
01127 #endif
01128             proceed=SetImageProgress(image,RGBTransformImageTag,progress++,
01129               image->rows);
01130             if (proceed == MagickFalse)
01131               status=MagickFalse;
01132           }
01133       }
01134       image_view=DestroyCacheView(image_view);
01135       break;
01136     }
01137     case PseudoClass:
01138     {
01139       register unsigned int
01140         blue,
01141         green,
01142         red;
01143 
01144       /*
01145         Convert PseudoClass image.
01146       */
01147       for (i=0; i < (ssize_t) image->colors; i++)
01148       {
01149         PixelInfo
01150           pixel;
01151 
01152         red=ScaleQuantumToMap(ClampToQuantum(image->colormap[i].red));
01153         green=ScaleQuantumToMap(ClampToQuantum(image->colormap[i].green));
01154         blue=ScaleQuantumToMap(ClampToQuantum(image->colormap[i].blue));
01155         pixel.red=x_map[red].x+y_map[green].x+z_map[blue].x+primary_info.x;
01156         pixel.green=x_map[red].y+y_map[green].y+z_map[blue].y+primary_info.y;
01157         pixel.blue=x_map[red].z+y_map[green].z+z_map[blue].z+primary_info.z;
01158         image->colormap[i].red=(double) ScaleMapToQuantum(pixel.red);
01159         image->colormap[i].green=(double) ScaleMapToQuantum(pixel.green);
01160         image->colormap[i].blue=(double) ScaleMapToQuantum(pixel.blue);
01161       }
01162       (void) SyncImage(image,exception);
01163       break;
01164     }
01165   }
01166   /*
01167     Relinquish resources.
01168   */
01169   z_map=(TransformPacket *) RelinquishMagickMemory(z_map);
01170   y_map=(TransformPacket *) RelinquishMagickMemory(y_map);
01171   x_map=(TransformPacket *) RelinquishMagickMemory(x_map);
01172   if (SetImageColorspace(image,colorspace,exception) == MagickFalse)
01173     return(MagickFalse);
01174   return(status);
01175 }
01176 
01177 /*
01178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01179 %                                                                             %
01180 %                                                                             %
01181 %                                                                             %
01182 %   S e t I m a g e C o l o r s p a c e                                       %
01183 %                                                                             %
01184 %                                                                             %
01185 %                                                                             %
01186 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01187 %
01188 %  SetImageColorspace() sets the colorspace member of the Image structure.
01189 %
01190 %  The format of the SetImageColorspace method is:
01191 %
01192 %      MagickBooleanType SetImageColorspace(Image *image,
01193 %        const ColorspaceType colorspace,ExceptiionInfo *exception)
01194 %
01195 %  A description of each parameter follows:
01196 %
01197 %    o image: the image.
01198 %
01199 %    o colorspace: the colorspace.
01200 %
01201 %   o exception: return any errors or warnings in this structure.
01202 %
01203 */
01204 MagickExport MagickBooleanType SetImageColorspace(Image *image,
01205   const ColorspaceType colorspace,ExceptionInfo *exception)
01206 {
01207   image->colorspace=colorspace;
01208   return(SyncImagePixelCache(image,exception));
01209 }
01210 
01211 /*
01212 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01213 %                                                                             %
01214 %                                                                             %
01215 %                                                                             %
01216 %   T r a n s f o r m I m a g e C o l o r s p a c e                           %
01217 %                                                                             %
01218 %                                                                             %
01219 %                                                                             %
01220 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01221 %
01222 %  TransformImageColorspace() transforms an image colorspace.
01223 %
01224 %  The format of the TransformImageColorspace method is:
01225 %
01226 %      MagickBooleanType TransformImageColorspace(Image *image,
01227 %        const ColorspaceType colorspace,ExceptionInfo *exception)
01228 %
01229 %  A description of each parameter follows:
01230 %
01231 %    o image: the image.
01232 %
01233 %    o colorspace: the colorspace.
01234 %
01235 %   o exception: return any errors or warnings in this structure.
01236 %
01237 */
01238 MagickExport MagickBooleanType TransformImageColorspace(Image *image,
01239   const ColorspaceType colorspace,ExceptionInfo *exception)
01240 {
01241   MagickBooleanType
01242     status;
01243 
01244   assert(image != (Image *) NULL);
01245   assert(image->signature == MagickSignature);
01246   if (image->debug != MagickFalse)
01247     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01248   if (colorspace == UndefinedColorspace)
01249     return(SetImageColorspace(image,colorspace,exception));
01250   if (image->colorspace == colorspace)
01251     return(MagickTrue);  /* same colorspace: no op */
01252   /*
01253     Convert the reference image from an alternate colorspace to RGB.
01254   */
01255   if ((colorspace == RGBColorspace) || (colorspace == TransparentColorspace))
01256     return(TransformRGBImage(image,colorspace,exception));
01257   status=MagickTrue;
01258   if (IsRGBColorspace(image->colorspace) == MagickFalse)
01259     status=TransformRGBImage(image,image->colorspace,exception);
01260   /*
01261     Convert the reference image from RGB to an alternate colorspace.
01262   */
01263   if (RGBTransformImage(image,colorspace,exception) == MagickFalse)
01264     status=MagickFalse;
01265   return(status);
01266 }
01267 
01268 /*
01269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01270 %                                                                             %
01271 %                                                                             %
01272 %                                                                             %
01273 +     T r a n s f o r m R G B I m a g e                                       %
01274 %                                                                             %
01275 %                                                                             %
01276 %                                                                             %
01277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01278 %
01279 %  TransformRGBImage() converts the reference image from an alternate
01280 %  colorspace to RGB.  The transformation matrices are not the standard ones:
01281 %  the weights are rescaled to normalize the range of the transformed values to
01282 %  be [0..QuantumRange].
01283 %
01284 %  The format of the TransformRGBImage method is:
01285 %
01286 %      MagickBooleanType TransformRGBImage(Image *image,
01287 %        const ColorspaceType colorspace,ExceptionInfo *exception)
01288 %
01289 %  A description of each parameter follows:
01290 %
01291 %    o image: the image.
01292 %
01293 %    o colorspace: the colorspace to transform the image to.
01294 %
01295 %   o exception: return any errors or warnings in this structure.
01296 %
01297 */
01298 
01299 static double LabF2(double alpha)
01300 {
01301   double
01302     beta;
01303 
01304   if (alpha > (24.0/116.0))
01305     return(alpha*alpha*alpha);
01306   beta=(108.0/841.0)*(alpha-(16.0/116.0));
01307   if (beta > 0.0)
01308     return(beta);
01309   return(0.0);
01310 }
01311 
01312 static inline void ConvertLabToXYZ(const double L,const double a,const double b,
01313   double *X,double *Y,double *Z)
01314 {
01315 
01316   double
01317     x,
01318     y,
01319     z;
01320 
01321   assert(X != (double *) NULL);
01322   assert(Y != (double *) NULL);
01323   assert(Z != (double *) NULL);
01324   *X=0.0;
01325   *Y=0.0;
01326   *Z=0.0;
01327   if (L <= 0.0)
01328     return;
01329   y=(100.0*L+16.0)/116.0;
01330   x=y+255.0*0.002*(a > 0.5 ? a-1.0 : a);
01331   z=y-255.0*0.005*(b > 0.5 ? b-1.0 : b);
01332   *X=D50X*LabF2(x);
01333   *Y=D50Y*LabF2(y);
01334   *Z=D50Z*LabF2(z);
01335 }
01336 
01337 static inline ssize_t RoundToYCC(const MagickRealType value)
01338 {
01339   if (value <= 0.0)
01340     return(0);
01341   if (value >= 1388.0)
01342     return(1388);
01343   return((ssize_t) (value+0.5));
01344 }
01345 
01346 static inline void ConvertXYZToRGB(const double x,const double y,const double z,
01347   Quantum *red,Quantum *green,Quantum *blue)
01348 {
01349   double
01350     b,
01351     g,
01352     r;
01353 
01354   /*
01355     Convert XYZ to RGB colorspace.
01356   */
01357   assert(red != (Quantum *) NULL);
01358   assert(green != (Quantum *) NULL);
01359   assert(blue != (Quantum *) NULL);
01360   r=3.2404542*x-1.5371385*y-0.4985314*z;
01361   g=(-0.9692660*x+1.8760108*y+0.0415560*z);
01362   b=0.0556434*x-0.2040259*y+1.0572252*z;
01363   if (r > 0.0031308)
01364     r=1.055*pow(r,1.0/2.4)-0.055;
01365   else
01366     r*=12.92;
01367   if (g > 0.0031308)
01368     g=1.055*pow(g,1.0/2.4)-0.055;
01369   else
01370     g*=12.92;
01371   if (b > 0.0031308)
01372     b=1.055*pow(b,1.0/2.4)-0.055;
01373   else
01374     b*=12.92;
01375   *red=RoundToQuantum((MagickRealType) QuantumRange*r);
01376   *green=RoundToQuantum((MagickRealType) QuantumRange*g);
01377   *blue=RoundToQuantum((MagickRealType) QuantumRange*b);
01378 }
01379 
01380 static inline void ConvertCMYKToRGB(PixelInfo *pixel)
01381 {
01382   pixel->red=(MagickRealType) QuantumRange-(QuantumScale*pixel->red*
01383     (QuantumRange-pixel->black)+pixel->black);
01384   pixel->green=(MagickRealType) QuantumRange-(QuantumScale*pixel->green*
01385     (QuantumRange-pixel->black)+pixel->black);
01386   pixel->blue=(MagickRealType) QuantumRange-(QuantumScale*pixel->blue*
01387     (QuantumRange-pixel->black)+pixel->black);
01388 }
01389 
01390 MagickExport MagickBooleanType TransformRGBImage(Image *image,
01391   const ColorspaceType colorspace,ExceptionInfo *exception)
01392 {
01393 #define D50X  (0.9642)
01394 #define D50Y  (1.0)
01395 #define D50Z  (0.8249)
01396 #define TransformRGBImageTag  "Transform/Image"
01397 
01398 #if !defined(MAGICKCORE_HDRI_SUPPORT)
01399   static const float
01400     YCCMap[1389] =
01401     {
01402       0.000000f, 0.000720f, 0.001441f, 0.002161f, 0.002882f, 0.003602f,
01403       0.004323f, 0.005043f, 0.005764f, 0.006484f, 0.007205f, 0.007925f,
01404       0.008646f, 0.009366f, 0.010086f, 0.010807f, 0.011527f, 0.012248f,
01405       0.012968f, 0.013689f, 0.014409f, 0.015130f, 0.015850f, 0.016571f,
01406       0.017291f, 0.018012f, 0.018732f, 0.019452f, 0.020173f, 0.020893f,
01407       0.021614f, 0.022334f, 0.023055f, 0.023775f, 0.024496f, 0.025216f,
01408       0.025937f, 0.026657f, 0.027378f, 0.028098f, 0.028818f, 0.029539f,
01409       0.030259f, 0.030980f, 0.031700f, 0.032421f, 0.033141f, 0.033862f,
01410       0.034582f, 0.035303f, 0.036023f, 0.036744f, 0.037464f, 0.038184f,
01411       0.038905f, 0.039625f, 0.040346f, 0.041066f, 0.041787f, 0.042507f,
01412       0.043228f, 0.043948f, 0.044669f, 0.045389f, 0.046110f, 0.046830f,
01413       0.047550f, 0.048271f, 0.048991f, 0.049712f, 0.050432f, 0.051153f,
01414       0.051873f, 0.052594f, 0.053314f, 0.054035f, 0.054755f, 0.055476f,
01415       0.056196f, 0.056916f, 0.057637f, 0.058357f, 0.059078f, 0.059798f,
01416       0.060519f, 0.061239f, 0.061960f, 0.062680f, 0.063401f, 0.064121f,
01417       0.064842f, 0.065562f, 0.066282f, 0.067003f, 0.067723f, 0.068444f,
01418       0.069164f, 0.069885f, 0.070605f, 0.071326f, 0.072046f, 0.072767f,
01419       0.073487f, 0.074207f, 0.074928f, 0.075648f, 0.076369f, 0.077089f,
01420       0.077810f, 0.078530f, 0.079251f, 0.079971f, 0.080692f, 0.081412f,
01421       0.082133f, 0.082853f, 0.083573f, 0.084294f, 0.085014f, 0.085735f,
01422       0.086455f, 0.087176f, 0.087896f, 0.088617f, 0.089337f, 0.090058f,
01423       0.090778f, 0.091499f, 0.092219f, 0.092939f, 0.093660f, 0.094380f,
01424       0.095101f, 0.095821f, 0.096542f, 0.097262f, 0.097983f, 0.098703f,
01425       0.099424f, 0.100144f, 0.100865f, 0.101585f, 0.102305f, 0.103026f,
01426       0.103746f, 0.104467f, 0.105187f, 0.105908f, 0.106628f, 0.107349f,
01427       0.108069f, 0.108790f, 0.109510f, 0.110231f, 0.110951f, 0.111671f,
01428       0.112392f, 0.113112f, 0.113833f, 0.114553f, 0.115274f, 0.115994f,
01429       0.116715f, 0.117435f, 0.118156f, 0.118876f, 0.119597f, 0.120317f,
01430       0.121037f, 0.121758f, 0.122478f, 0.123199f, 0.123919f, 0.124640f,
01431       0.125360f, 0.126081f, 0.126801f, 0.127522f, 0.128242f, 0.128963f,
01432       0.129683f, 0.130403f, 0.131124f, 0.131844f, 0.132565f, 0.133285f,
01433       0.134006f, 0.134726f, 0.135447f, 0.136167f, 0.136888f, 0.137608f,
01434       0.138329f, 0.139049f, 0.139769f, 0.140490f, 0.141210f, 0.141931f,
01435       0.142651f, 0.143372f, 0.144092f, 0.144813f, 0.145533f, 0.146254f,
01436       0.146974f, 0.147695f, 0.148415f, 0.149135f, 0.149856f, 0.150576f,
01437       0.151297f, 0.152017f, 0.152738f, 0.153458f, 0.154179f, 0.154899f,
01438       0.155620f, 0.156340f, 0.157061f, 0.157781f, 0.158501f, 0.159222f,
01439       0.159942f, 0.160663f, 0.161383f, 0.162104f, 0.162824f, 0.163545f,
01440       0.164265f, 0.164986f, 0.165706f, 0.166427f, 0.167147f, 0.167867f,
01441       0.168588f, 0.169308f, 0.170029f, 0.170749f, 0.171470f, 0.172190f,
01442       0.172911f, 0.173631f, 0.174352f, 0.175072f, 0.175793f, 0.176513f,
01443       0.177233f, 0.177954f, 0.178674f, 0.179395f, 0.180115f, 0.180836f,
01444       0.181556f, 0.182277f, 0.182997f, 0.183718f, 0.184438f, 0.185159f,
01445       0.185879f, 0.186599f, 0.187320f, 0.188040f, 0.188761f, 0.189481f,
01446       0.190202f, 0.190922f, 0.191643f, 0.192363f, 0.193084f, 0.193804f,
01447       0.194524f, 0.195245f, 0.195965f, 0.196686f, 0.197406f, 0.198127f,
01448       0.198847f, 0.199568f, 0.200288f, 0.201009f, 0.201729f, 0.202450f,
01449       0.203170f, 0.203890f, 0.204611f, 0.205331f, 0.206052f, 0.206772f,
01450       0.207493f, 0.208213f, 0.208934f, 0.209654f, 0.210375f, 0.211095f,
01451       0.211816f, 0.212536f, 0.213256f, 0.213977f, 0.214697f, 0.215418f,
01452       0.216138f, 0.216859f, 0.217579f, 0.218300f, 0.219020f, 0.219741f,
01453       0.220461f, 0.221182f, 0.221902f, 0.222622f, 0.223343f, 0.224063f,
01454       0.224784f, 0.225504f, 0.226225f, 0.226945f, 0.227666f, 0.228386f,
01455       0.229107f, 0.229827f, 0.230548f, 0.231268f, 0.231988f, 0.232709f,
01456       0.233429f, 0.234150f, 0.234870f, 0.235591f, 0.236311f, 0.237032f,
01457       0.237752f, 0.238473f, 0.239193f, 0.239914f, 0.240634f, 0.241354f,
01458       0.242075f, 0.242795f, 0.243516f, 0.244236f, 0.244957f, 0.245677f,
01459       0.246398f, 0.247118f, 0.247839f, 0.248559f, 0.249280f, 0.250000f,
01460       0.250720f, 0.251441f, 0.252161f, 0.252882f, 0.253602f, 0.254323f,
01461       0.255043f, 0.255764f, 0.256484f, 0.257205f, 0.257925f, 0.258646f,
01462       0.259366f, 0.260086f, 0.260807f, 0.261527f, 0.262248f, 0.262968f,
01463       0.263689f, 0.264409f, 0.265130f, 0.265850f, 0.266571f, 0.267291f,
01464       0.268012f, 0.268732f, 0.269452f, 0.270173f, 0.270893f, 0.271614f,
01465       0.272334f, 0.273055f, 0.273775f, 0.274496f, 0.275216f, 0.275937f,
01466       0.276657f, 0.277378f, 0.278098f, 0.278818f, 0.279539f, 0.280259f,
01467       0.280980f, 0.281700f, 0.282421f, 0.283141f, 0.283862f, 0.284582f,
01468       0.285303f, 0.286023f, 0.286744f, 0.287464f, 0.288184f, 0.288905f,
01469       0.289625f, 0.290346f, 0.291066f, 0.291787f, 0.292507f, 0.293228f,
01470       0.293948f, 0.294669f, 0.295389f, 0.296109f, 0.296830f, 0.297550f,
01471       0.298271f, 0.298991f, 0.299712f, 0.300432f, 0.301153f, 0.301873f,
01472       0.302594f, 0.303314f, 0.304035f, 0.304755f, 0.305476f, 0.306196f,
01473       0.306916f, 0.307637f, 0.308357f, 0.309078f, 0.309798f, 0.310519f,
01474       0.311239f, 0.311960f, 0.312680f, 0.313401f, 0.314121f, 0.314842f,
01475       0.315562f, 0.316282f, 0.317003f, 0.317723f, 0.318444f, 0.319164f,
01476       0.319885f, 0.320605f, 0.321326f, 0.322046f, 0.322767f, 0.323487f,
01477       0.324207f, 0.324928f, 0.325648f, 0.326369f, 0.327089f, 0.327810f,
01478       0.328530f, 0.329251f, 0.329971f, 0.330692f, 0.331412f, 0.332133f,
01479       0.332853f, 0.333573f, 0.334294f, 0.335014f, 0.335735f, 0.336455f,
01480       0.337176f, 0.337896f, 0.338617f, 0.339337f, 0.340058f, 0.340778f,
01481       0.341499f, 0.342219f, 0.342939f, 0.343660f, 0.344380f, 0.345101f,
01482       0.345821f, 0.346542f, 0.347262f, 0.347983f, 0.348703f, 0.349424f,
01483       0.350144f, 0.350865f, 0.351585f, 0.352305f, 0.353026f, 0.353746f,
01484       0.354467f, 0.355187f, 0.355908f, 0.356628f, 0.357349f, 0.358069f,
01485       0.358790f, 0.359510f, 0.360231f, 0.360951f, 0.361671f, 0.362392f,
01486       0.363112f, 0.363833f, 0.364553f, 0.365274f, 0.365994f, 0.366715f,
01487       0.367435f, 0.368156f, 0.368876f, 0.369597f, 0.370317f, 0.371037f,
01488       0.371758f, 0.372478f, 0.373199f, 0.373919f, 0.374640f, 0.375360f,
01489       0.376081f, 0.376801f, 0.377522f, 0.378242f, 0.378963f, 0.379683f,
01490       0.380403f, 0.381124f, 0.381844f, 0.382565f, 0.383285f, 0.384006f,
01491       0.384726f, 0.385447f, 0.386167f, 0.386888f, 0.387608f, 0.388329f,
01492       0.389049f, 0.389769f, 0.390490f, 0.391210f, 0.391931f, 0.392651f,
01493       0.393372f, 0.394092f, 0.394813f, 0.395533f, 0.396254f, 0.396974f,
01494       0.397695f, 0.398415f, 0.399135f, 0.399856f, 0.400576f, 0.401297f,
01495       0.402017f, 0.402738f, 0.403458f, 0.404179f, 0.404899f, 0.405620f,
01496       0.406340f, 0.407061f, 0.407781f, 0.408501f, 0.409222f, 0.409942f,
01497       0.410663f, 0.411383f, 0.412104f, 0.412824f, 0.413545f, 0.414265f,
01498       0.414986f, 0.415706f, 0.416427f, 0.417147f, 0.417867f, 0.418588f,
01499       0.419308f, 0.420029f, 0.420749f, 0.421470f, 0.422190f, 0.422911f,
01500       0.423631f, 0.424352f, 0.425072f, 0.425793f, 0.426513f, 0.427233f,
01501       0.427954f, 0.428674f, 0.429395f, 0.430115f, 0.430836f, 0.431556f,
01502       0.432277f, 0.432997f, 0.433718f, 0.434438f, 0.435158f, 0.435879f,
01503       0.436599f, 0.437320f, 0.438040f, 0.438761f, 0.439481f, 0.440202f,
01504       0.440922f, 0.441643f, 0.442363f, 0.443084f, 0.443804f, 0.444524f,
01505       0.445245f, 0.445965f, 0.446686f, 0.447406f, 0.448127f, 0.448847f,
01506       0.449568f, 0.450288f, 0.451009f, 0.451729f, 0.452450f, 0.453170f,
01507       0.453891f, 0.454611f, 0.455331f, 0.456052f, 0.456772f, 0.457493f,
01508       0.458213f, 0.458934f, 0.459654f, 0.460375f, 0.461095f, 0.461816f,
01509       0.462536f, 0.463256f, 0.463977f, 0.464697f, 0.465418f, 0.466138f,
01510       0.466859f, 0.467579f, 0.468300f, 0.469020f, 0.469741f, 0.470461f,
01511       0.471182f, 0.471902f, 0.472622f, 0.473343f, 0.474063f, 0.474784f,
01512       0.475504f, 0.476225f, 0.476945f, 0.477666f, 0.478386f, 0.479107f,
01513       0.479827f, 0.480548f, 0.481268f, 0.481988f, 0.482709f, 0.483429f,
01514       0.484150f, 0.484870f, 0.485591f, 0.486311f, 0.487032f, 0.487752f,
01515       0.488473f, 0.489193f, 0.489914f, 0.490634f, 0.491354f, 0.492075f,
01516       0.492795f, 0.493516f, 0.494236f, 0.494957f, 0.495677f, 0.496398f,
01517       0.497118f, 0.497839f, 0.498559f, 0.499280f, 0.500000f, 0.500720f,
01518       0.501441f, 0.502161f, 0.502882f, 0.503602f, 0.504323f, 0.505043f,
01519       0.505764f, 0.506484f, 0.507205f, 0.507925f, 0.508646f, 0.509366f,
01520       0.510086f, 0.510807f, 0.511527f, 0.512248f, 0.512968f, 0.513689f,
01521       0.514409f, 0.515130f, 0.515850f, 0.516571f, 0.517291f, 0.518012f,
01522       0.518732f, 0.519452f, 0.520173f, 0.520893f, 0.521614f, 0.522334f,
01523       0.523055f, 0.523775f, 0.524496f, 0.525216f, 0.525937f, 0.526657f,
01524       0.527378f, 0.528098f, 0.528818f, 0.529539f, 0.530259f, 0.530980f,
01525       0.531700f, 0.532421f, 0.533141f, 0.533862f, 0.534582f, 0.535303f,
01526       0.536023f, 0.536744f, 0.537464f, 0.538184f, 0.538905f, 0.539625f,
01527       0.540346f, 0.541066f, 0.541787f, 0.542507f, 0.543228f, 0.543948f,
01528       0.544669f, 0.545389f, 0.546109f, 0.546830f, 0.547550f, 0.548271f,
01529       0.548991f, 0.549712f, 0.550432f, 0.551153f, 0.551873f, 0.552594f,
01530       0.553314f, 0.554035f, 0.554755f, 0.555476f, 0.556196f, 0.556916f,
01531       0.557637f, 0.558357f, 0.559078f, 0.559798f, 0.560519f, 0.561239f,
01532       0.561960f, 0.562680f, 0.563401f, 0.564121f, 0.564842f, 0.565562f,
01533       0.566282f, 0.567003f, 0.567723f, 0.568444f, 0.569164f, 0.569885f,
01534       0.570605f, 0.571326f, 0.572046f, 0.572767f, 0.573487f, 0.574207f,
01535       0.574928f, 0.575648f, 0.576369f, 0.577089f, 0.577810f, 0.578530f,
01536       0.579251f, 0.579971f, 0.580692f, 0.581412f, 0.582133f, 0.582853f,
01537       0.583573f, 0.584294f, 0.585014f, 0.585735f, 0.586455f, 0.587176f,
01538       0.587896f, 0.588617f, 0.589337f, 0.590058f, 0.590778f, 0.591499f,
01539       0.592219f, 0.592939f, 0.593660f, 0.594380f, 0.595101f, 0.595821f,
01540       0.596542f, 0.597262f, 0.597983f, 0.598703f, 0.599424f, 0.600144f,
01541       0.600865f, 0.601585f, 0.602305f, 0.603026f, 0.603746f, 0.604467f,
01542       0.605187f, 0.605908f, 0.606628f, 0.607349f, 0.608069f, 0.608790f,
01543       0.609510f, 0.610231f, 0.610951f, 0.611671f, 0.612392f, 0.613112f,
01544       0.613833f, 0.614553f, 0.615274f, 0.615994f, 0.616715f, 0.617435f,
01545       0.618156f, 0.618876f, 0.619597f, 0.620317f, 0.621037f, 0.621758f,
01546       0.622478f, 0.623199f, 0.623919f, 0.624640f, 0.625360f, 0.626081f,
01547       0.626801f, 0.627522f, 0.628242f, 0.628963f, 0.629683f, 0.630403f,
01548       0.631124f, 0.631844f, 0.632565f, 0.633285f, 0.634006f, 0.634726f,
01549       0.635447f, 0.636167f, 0.636888f, 0.637608f, 0.638329f, 0.639049f,
01550       0.639769f, 0.640490f, 0.641210f, 0.641931f, 0.642651f, 0.643372f,
01551       0.644092f, 0.644813f, 0.645533f, 0.646254f, 0.646974f, 0.647695f,
01552       0.648415f, 0.649135f, 0.649856f, 0.650576f, 0.651297f, 0.652017f,
01553       0.652738f, 0.653458f, 0.654179f, 0.654899f, 0.655620f, 0.656340f,
01554       0.657061f, 0.657781f, 0.658501f, 0.659222f, 0.659942f, 0.660663f,
01555       0.661383f, 0.662104f, 0.662824f, 0.663545f, 0.664265f, 0.664986f,
01556       0.665706f, 0.666427f, 0.667147f, 0.667867f, 0.668588f, 0.669308f,
01557       0.670029f, 0.670749f, 0.671470f, 0.672190f, 0.672911f, 0.673631f,
01558       0.674352f, 0.675072f, 0.675793f, 0.676513f, 0.677233f, 0.677954f,
01559       0.678674f, 0.679395f, 0.680115f, 0.680836f, 0.681556f, 0.682277f,
01560       0.682997f, 0.683718f, 0.684438f, 0.685158f, 0.685879f, 0.686599f,
01561       0.687320f, 0.688040f, 0.688761f, 0.689481f, 0.690202f, 0.690922f,
01562       0.691643f, 0.692363f, 0.693084f, 0.693804f, 0.694524f, 0.695245f,
01563       0.695965f, 0.696686f, 0.697406f, 0.698127f, 0.698847f, 0.699568f,
01564       0.700288f, 0.701009f, 0.701729f, 0.702450f, 0.703170f, 0.703891f,
01565       0.704611f, 0.705331f, 0.706052f, 0.706772f, 0.707493f, 0.708213f,
01566       0.708934f, 0.709654f, 0.710375f, 0.711095f, 0.711816f, 0.712536f,
01567       0.713256f, 0.713977f, 0.714697f, 0.715418f, 0.716138f, 0.716859f,
01568       0.717579f, 0.718300f, 0.719020f, 0.719741f, 0.720461f, 0.721182f,
01569       0.721902f, 0.722622f, 0.723343f, 0.724063f, 0.724784f, 0.725504f,
01570       0.726225f, 0.726945f, 0.727666f, 0.728386f, 0.729107f, 0.729827f,
01571       0.730548f, 0.731268f, 0.731988f, 0.732709f, 0.733429f, 0.734150f,
01572       0.734870f, 0.735591f, 0.736311f, 0.737032f, 0.737752f, 0.738473f,
01573       0.739193f, 0.739914f, 0.740634f, 0.741354f, 0.742075f, 0.742795f,
01574       0.743516f, 0.744236f, 0.744957f, 0.745677f, 0.746398f, 0.747118f,
01575       0.747839f, 0.748559f, 0.749280f, 0.750000f, 0.750720f, 0.751441f,
01576       0.752161f, 0.752882f, 0.753602f, 0.754323f, 0.755043f, 0.755764f,
01577       0.756484f, 0.757205f, 0.757925f, 0.758646f, 0.759366f, 0.760086f,
01578       0.760807f, 0.761527f, 0.762248f, 0.762968f, 0.763689f, 0.764409f,
01579       0.765130f, 0.765850f, 0.766571f, 0.767291f, 0.768012f, 0.768732f,
01580       0.769452f, 0.770173f, 0.770893f, 0.771614f, 0.772334f, 0.773055f,
01581       0.773775f, 0.774496f, 0.775216f, 0.775937f, 0.776657f, 0.777378f,
01582       0.778098f, 0.778818f, 0.779539f, 0.780259f, 0.780980f, 0.781700f,
01583       0.782421f, 0.783141f, 0.783862f, 0.784582f, 0.785303f, 0.786023f,
01584       0.786744f, 0.787464f, 0.788184f, 0.788905f, 0.789625f, 0.790346f,
01585       0.791066f, 0.791787f, 0.792507f, 0.793228f, 0.793948f, 0.794669f,
01586       0.795389f, 0.796109f, 0.796830f, 0.797550f, 0.798271f, 0.798991f,
01587       0.799712f, 0.800432f, 0.801153f, 0.801873f, 0.802594f, 0.803314f,
01588       0.804035f, 0.804755f, 0.805476f, 0.806196f, 0.806916f, 0.807637f,
01589       0.808357f, 0.809078f, 0.809798f, 0.810519f, 0.811239f, 0.811960f,
01590       0.812680f, 0.813401f, 0.814121f, 0.814842f, 0.815562f, 0.816282f,
01591       0.817003f, 0.817723f, 0.818444f, 0.819164f, 0.819885f, 0.820605f,
01592       0.821326f, 0.822046f, 0.822767f, 0.823487f, 0.824207f, 0.824928f,
01593       0.825648f, 0.826369f, 0.827089f, 0.827810f, 0.828530f, 0.829251f,
01594       0.829971f, 0.830692f, 0.831412f, 0.832133f, 0.832853f, 0.833573f,
01595       0.834294f, 0.835014f, 0.835735f, 0.836455f, 0.837176f, 0.837896f,
01596       0.838617f, 0.839337f, 0.840058f, 0.840778f, 0.841499f, 0.842219f,
01597       0.842939f, 0.843660f, 0.844380f, 0.845101f, 0.845821f, 0.846542f,
01598       0.847262f, 0.847983f, 0.848703f, 0.849424f, 0.850144f, 0.850865f,
01599       0.851585f, 0.852305f, 0.853026f, 0.853746f, 0.854467f, 0.855187f,
01600       0.855908f, 0.856628f, 0.857349f, 0.858069f, 0.858790f, 0.859510f,
01601       0.860231f, 0.860951f, 0.861671f, 0.862392f, 0.863112f, 0.863833f,
01602       0.864553f, 0.865274f, 0.865994f, 0.866715f, 0.867435f, 0.868156f,
01603       0.868876f, 0.869597f, 0.870317f, 0.871037f, 0.871758f, 0.872478f,
01604       0.873199f, 0.873919f, 0.874640f, 0.875360f, 0.876081f, 0.876801f,
01605       0.877522f, 0.878242f, 0.878963f, 0.879683f, 0.880403f, 0.881124f,
01606       0.881844f, 0.882565f, 0.883285f, 0.884006f, 0.884726f, 0.885447f,
01607       0.886167f, 0.886888f, 0.887608f, 0.888329f, 0.889049f, 0.889769f,
01608       0.890490f, 0.891210f, 0.891931f, 0.892651f, 0.893372f, 0.894092f,
01609       0.894813f, 0.895533f, 0.896254f, 0.896974f, 0.897695f, 0.898415f,
01610       0.899135f, 0.899856f, 0.900576f, 0.901297f, 0.902017f, 0.902738f,
01611       0.903458f, 0.904179f, 0.904899f, 0.905620f, 0.906340f, 0.907061f,
01612       0.907781f, 0.908501f, 0.909222f, 0.909942f, 0.910663f, 0.911383f,
01613       0.912104f, 0.912824f, 0.913545f, 0.914265f, 0.914986f, 0.915706f,
01614       0.916427f, 0.917147f, 0.917867f, 0.918588f, 0.919308f, 0.920029f,
01615       0.920749f, 0.921470f, 0.922190f, 0.922911f, 0.923631f, 0.924352f,
01616       0.925072f, 0.925793f, 0.926513f, 0.927233f, 0.927954f, 0.928674f,
01617       0.929395f, 0.930115f, 0.930836f, 0.931556f, 0.932277f, 0.932997f,
01618       0.933718f, 0.934438f, 0.935158f, 0.935879f, 0.936599f, 0.937320f,
01619       0.938040f, 0.938761f, 0.939481f, 0.940202f, 0.940922f, 0.941643f,
01620       0.942363f, 0.943084f, 0.943804f, 0.944524f, 0.945245f, 0.945965f,
01621       0.946686f, 0.947406f, 0.948127f, 0.948847f, 0.949568f, 0.950288f,
01622       0.951009f, 0.951729f, 0.952450f, 0.953170f, 0.953891f, 0.954611f,
01623       0.955331f, 0.956052f, 0.956772f, 0.957493f, 0.958213f, 0.958934f,
01624       0.959654f, 0.960375f, 0.961095f, 0.961816f, 0.962536f, 0.963256f,
01625       0.963977f, 0.964697f, 0.965418f, 0.966138f, 0.966859f, 0.967579f,
01626       0.968300f, 0.969020f, 0.969741f, 0.970461f, 0.971182f, 0.971902f,
01627       0.972622f, 0.973343f, 0.974063f, 0.974784f, 0.975504f, 0.976225f,
01628       0.976945f, 0.977666f, 0.978386f, 0.979107f, 0.979827f, 0.980548f,
01629       0.981268f, 0.981988f, 0.982709f, 0.983429f, 0.984150f, 0.984870f,
01630       0.985591f, 0.986311f, 0.987032f, 0.987752f, 0.988473f, 0.989193f,
01631       0.989914f, 0.990634f, 0.991354f, 0.992075f, 0.992795f, 0.993516f,
01632       0.994236f, 0.994957f, 0.995677f, 0.996398f, 0.997118f, 0.997839f,
01633       0.998559f, 0.999280f, 1.000000f
01634     };
01635 #endif
01636 
01637   CacheView
01638     *image_view;
01639 
01640   MagickBooleanType
01641     status;
01642 
01643   MagickOffsetType
01644     progress;
01645 
01646   register ssize_t
01647     i;
01648 
01649   ssize_t
01650     y;
01651 
01652   TransformPacket
01653     *y_map,
01654     *x_map,
01655     *z_map;
01656 
01657   assert(image != (Image *) NULL);
01658   assert(image->signature == MagickSignature);
01659   if (image->debug != MagickFalse)
01660     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01661   if (IsRGBColorspace(image->colorspace) != MagickFalse)
01662     return(MagickTrue);
01663   status=MagickTrue;
01664   progress=0;
01665   switch (image->colorspace)
01666   {
01667     case CMYColorspace:
01668     {
01669       /*
01670         Transform image from CMY to RGB.
01671       */
01672       if (image->storage_class == PseudoClass)
01673         {
01674           if (SyncImage(image,exception) == MagickFalse)
01675             return(MagickFalse);
01676           if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
01677             return(MagickFalse);
01678         }
01679       image_view=AcquireCacheView(image);
01680 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01681       #pragma omp parallel for schedule(static,4) shared(status)
01682 #endif
01683       for (y=0; y < (ssize_t) image->rows; y++)
01684       {
01685         MagickBooleanType
01686           sync;
01687 
01688         register ssize_t
01689           x;
01690 
01691         register Quantum
01692           *restrict q;
01693 
01694         if (status == MagickFalse)
01695           continue;
01696         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
01697           exception);
01698         if (q == (Quantum *) NULL)
01699           {
01700             status=MagickFalse;
01701             continue;
01702           }
01703         for (x=0; x < (ssize_t) image->columns; x++)
01704         {
01705           SetPixelRed(image,ClampToQuantum((MagickRealType) (QuantumRange-
01706             GetPixelRed(image,q))),q);
01707           SetPixelGreen(image,ClampToQuantum((MagickRealType) (QuantumRange-
01708             GetPixelGreen(image,q))),q);
01709           SetPixelBlue(image,ClampToQuantum((MagickRealType) (QuantumRange-
01710             GetPixelBlue(image,q))),q);
01711           q+=GetPixelChannels(image);
01712         }
01713         sync=SyncCacheViewAuthenticPixels(image_view,exception);
01714         if (sync == MagickFalse)
01715           status=MagickFalse;
01716       }
01717       image_view=DestroyCacheView(image_view);
01718       if (SetImageColorspace(image,RGBColorspace,exception) == MagickFalse)
01719         return(MagickFalse);
01720       return(status);
01721     }
01722     case CMYKColorspace:
01723     {
01724       PixelInfo
01725         zero;
01726 
01727       /*
01728         Transform image from CMYK to RGB.
01729       */
01730       if (image->storage_class == PseudoClass)
01731         {
01732           if (SyncImage(image,exception) == MagickFalse)
01733             return(MagickFalse);
01734           if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
01735             return(MagickFalse);
01736         }
01737       GetPixelInfo(image,&zero);
01738       image_view=AcquireCacheView(image);
01739 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01740       #pragma omp parallel for schedule(static,4) shared(status)
01741 #endif
01742       for (y=0; y < (ssize_t) image->rows; y++)
01743       {
01744         MagickBooleanType
01745           sync;
01746 
01747         PixelInfo
01748           pixel;
01749 
01750         register ssize_t
01751           x;
01752 
01753         register Quantum
01754           *restrict q;
01755 
01756         if (status == MagickFalse)
01757           continue;
01758         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
01759           exception);
01760         if (q == (Quantum *) NULL)
01761           {
01762             status=MagickFalse;
01763             continue;
01764           }
01765         pixel=zero;
01766         for (x=0; x < (ssize_t) image->columns; x++)
01767         {
01768           GetPixelInfoPixel(image,q,&pixel);
01769           ConvertCMYKToRGB(&pixel);
01770           SetPixelInfoPixel(image,&pixel,q);
01771           q+=GetPixelChannels(image);
01772         }
01773         sync=SyncCacheViewAuthenticPixels(image_view,exception);
01774         if (sync == MagickFalse)
01775           status=MagickFalse;
01776       }
01777       image_view=DestroyCacheView(image_view);
01778       if (SetImageColorspace(image,RGBColorspace,exception) == MagickFalse)
01779         return(MagickFalse);
01780       return(status);
01781     }
01782     case HSBColorspace:
01783     {
01784       /*
01785         Transform image from HSB to RGB.
01786       */
01787       if (image->storage_class == PseudoClass)
01788         {
01789           if (SyncImage(image,exception) == MagickFalse)
01790             return(MagickFalse);
01791           if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
01792             return(MagickFalse);
01793         }
01794       image_view=AcquireCacheView(image);
01795 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01796       #pragma omp parallel for schedule(static,4) shared(status)
01797 #endif
01798       for (y=0; y < (ssize_t) image->rows; y++)
01799       {
01800         double
01801           brightness,
01802           hue,
01803           saturation;
01804 
01805         MagickBooleanType
01806           sync;
01807 
01808         register ssize_t
01809           x;
01810 
01811         register Quantum
01812           *restrict q;
01813 
01814         if (status == MagickFalse)
01815           continue;
01816         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
01817           exception);
01818         if (q == (Quantum *) NULL)
01819           {
01820             status=MagickFalse;
01821             continue;
01822           }
01823         for (x=0; x < (ssize_t) image->columns; x++)
01824         {
01825           double
01826             blue,
01827             green,
01828             red;
01829 
01830           hue=(double) (QuantumScale*GetPixelRed(image,q));
01831           saturation=(double) (QuantumScale*GetPixelGreen(image,q));
01832           brightness=(double) (QuantumScale*GetPixelBlue(image,q));
01833           ConvertHSBToRGB(hue,saturation,brightness,&red,&green,&blue);
01834           SetPixelRed(image,ClampToQuantum(red),q);
01835           SetPixelGreen(image,ClampToQuantum(green),q);
01836           SetPixelBlue(image,ClampToQuantum(blue),q);
01837           q+=GetPixelChannels(image);
01838         }
01839         sync=SyncCacheViewAuthenticPixels(image_view,exception);
01840         if (sync == MagickFalse)
01841           status=MagickFalse;
01842       }
01843       image_view=DestroyCacheView(image_view);
01844       if (SetImageColorspace(image,RGBColorspace,exception) == MagickFalse)
01845         return(MagickFalse);
01846       return(status);
01847     }
01848     case HSLColorspace:
01849     {
01850       /*
01851         Transform image from HSL to RGB.
01852       */
01853       if (image->storage_class == PseudoClass)
01854         {
01855           if (SyncImage(image,exception) == MagickFalse)
01856             return(MagickFalse);
01857           if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
01858             return(MagickFalse);
01859         }
01860       image_view=AcquireCacheView(image);
01861 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01862       #pragma omp parallel for schedule(static,4) shared(status)
01863 #endif
01864       for (y=0; y < (ssize_t) image->rows; y++)
01865       {
01866         double
01867           hue,
01868           lightness,
01869           saturation;
01870 
01871         MagickBooleanType
01872           sync;
01873 
01874         register ssize_t
01875           x;
01876 
01877         register Quantum
01878           *restrict q;
01879 
01880         if (status == MagickFalse)
01881           continue;
01882         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
01883           exception);
01884         if (q == (Quantum *) NULL)
01885           {
01886             status=MagickFalse;
01887             continue;
01888           }
01889         for (x=0; x < (ssize_t) image->columns; x++)
01890         {
01891           double
01892             blue,
01893             green,
01894             red;
01895 
01896           hue=(double) (QuantumScale*GetPixelRed(image,q));
01897           saturation=(double) (QuantumScale*GetPixelGreen(image,q));
01898           lightness=(double) (QuantumScale*GetPixelBlue(image,q));
01899           ConvertHSLToRGB(hue,saturation,lightness,&red,&green,&blue);
01900           SetPixelRed(image,ClampToQuantum(red),q);
01901           SetPixelGreen(image,ClampToQuantum(green),q);
01902           SetPixelBlue(image,ClampToQuantum(blue),q);
01903           q+=GetPixelChannels(image);
01904         }
01905         sync=SyncCacheViewAuthenticPixels(image_view,exception);
01906         if (sync == MagickFalse)
01907           status=MagickFalse;
01908       }
01909       image_view=DestroyCacheView(image_view);
01910       if (SetImageColorspace(image,RGBColorspace,exception) == MagickFalse)
01911         return(MagickFalse);
01912       return(status);
01913     }
01914     case HWBColorspace:
01915     {
01916       /*
01917         Transform image from HWB to RGB.
01918       */
01919       if (image->storage_class == PseudoClass)
01920         {
01921           if (SyncImage(image,exception) == MagickFalse)
01922             return(MagickFalse);
01923           if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
01924             return(MagickFalse);
01925         }
01926       image_view=AcquireCacheView(image);
01927 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01928       #pragma omp parallel for schedule(static,4) shared(status)
01929 #endif
01930       for (y=0; y < (ssize_t) image->rows; y++)
01931       {
01932         double
01933           blackness,
01934           hue,
01935           whiteness;
01936 
01937         MagickBooleanType
01938           sync;
01939 
01940         register ssize_t
01941           x;
01942 
01943         register Quantum
01944           *restrict q;
01945 
01946         if (status == MagickFalse)
01947           continue;
01948         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
01949           exception);
01950         if (q == (Quantum *) NULL)
01951           {
01952             status=MagickFalse;
01953             continue;
01954           }
01955         for (x=0; x < (ssize_t) image->columns; x++)
01956         {
01957           double
01958             blue,
01959             green,
01960             red;
01961 
01962           hue=(double) (QuantumScale*GetPixelRed(image,q));
01963           whiteness=(double) (QuantumScale*GetPixelGreen(image,q));
01964           blackness=(double) (QuantumScale*GetPixelBlue(image,q));
01965           ConvertHWBToRGB(hue,whiteness,blackness,&red,&green,&blue);
01966           SetPixelRed(image,ClampToQuantum(red),q);
01967           SetPixelGreen(image,ClampToQuantum(green),q);
01968           SetPixelBlue(image,ClampToQuantum(blue),q);
01969           q+=GetPixelChannels(image);
01970         }
01971         sync=SyncCacheViewAuthenticPixels(image_view,exception);
01972         if (sync == MagickFalse)
01973           status=MagickFalse;
01974       }
01975       image_view=DestroyCacheView(image_view);
01976       if (SetImageColorspace(image,RGBColorspace,exception) == MagickFalse)
01977         return(MagickFalse);
01978       return(status);
01979     }
01980     case LabColorspace:
01981     {
01982       /*
01983         Transform image from Lab to RGB.
01984       */
01985       if (image->storage_class == PseudoClass)
01986         {
01987           if (SyncImage(image,exception) == MagickFalse)
01988             return(MagickFalse);
01989           if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
01990             return(MagickFalse);
01991         }
01992       image_view=AcquireCacheView(image);
01993 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01994       #pragma omp parallel for schedule(static,4) shared(status)
01995 #endif
01996       for (y=0; y < (ssize_t) image->rows; y++)
01997       {
01998         double
01999           a,
02000           b,
02001           L,
02002           X,
02003           Y,
02004           Z;
02005 
02006         MagickBooleanType
02007           sync;
02008 
02009         register ssize_t
02010           x;
02011 
02012         register Quantum
02013           *restrict q;
02014 
02015         if (status == MagickFalse)
02016           continue;
02017         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
02018           exception);
02019         if (q == (Quantum *) NULL)
02020           {
02021             status=MagickFalse;
02022             continue;
02023           }
02024         X=0.0;
02025         Y=0.0;
02026         Z=0.0;
02027         for (x=0; x < (ssize_t) image->columns; x++)
02028         {
02029           Quantum
02030             blue,
02031             green,
02032             red;
02033 
02034           L=QuantumScale*GetPixelRed(image,q);
02035           a=QuantumScale*GetPixelGreen(image,q);
02036           b=QuantumScale*GetPixelBlue(image,q);
02037           ConvertLabToXYZ(L,a,b,&X,&Y,&Z);
02038           ConvertXYZToRGB(X,Y,Z,&red,&green,&blue);
02039           SetPixelRed(image,red,q);
02040           SetPixelGreen(image,green,q);
02041           SetPixelBlue(image,blue,q);
02042           q+=GetPixelChannels(image);
02043         }
02044         sync=SyncCacheViewAuthenticPixels(image_view,exception);
02045         if (sync == MagickFalse)
02046           status=MagickFalse;
02047       }
02048       image_view=DestroyCacheView(image_view);
02049       if (SetImageColorspace(image,RGBColorspace,exception) == MagickFalse)
02050         return(MagickFalse);
02051       return(status);
02052     }
02053     case LogColorspace:
02054     {
02055       const char
02056         *value;
02057 
02058       double
02059         black,
02060         density,
02061         film_gamma,
02062         gamma,
02063         reference_black,
02064         reference_white;
02065 
02066       Quantum
02067         *logmap;
02068 
02069       /*
02070         Transform Log to RGB colorspace.
02071       */
02072       density=DisplayGamma;
02073       gamma=DisplayGamma;
02074       value=GetImageProperty(image,"gamma",exception);
02075       if (value != (const char *) NULL)
02076         gamma=1.0/fabs(StringToDouble(value,(char **) NULL)) >=
02077           MagickEpsilon ? StringToDouble(value,(char **) NULL) : 1.0;
02078       film_gamma=FilmGamma;
02079       value=GetImageProperty(image,"film-gamma",exception);
02080       if (value != (const char *) NULL)
02081         film_gamma=StringToDouble(value,(char **) NULL);
02082       reference_black=ReferenceBlack;
02083       value=GetImageProperty(image,"reference-black",exception);
02084       if (value != (const char *) NULL)
02085         reference_black=StringToDouble(value,(char **) NULL);
02086       reference_white=ReferenceWhite;
02087       value=GetImageProperty(image,"reference-white",exception);
02088       if (value != (const char *) NULL)
02089         reference_white=StringToDouble(value,(char **) NULL);
02090       logmap=(Quantum *) AcquireQuantumMemory((size_t) MaxMap+1UL,
02091         sizeof(*logmap));
02092       if (logmap == (Quantum *) NULL)
02093         ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
02094           image->filename);
02095       black=pow(10.0,(reference_black-reference_white)*(gamma/density)*
02096         0.002/film_gamma);
02097       for (i=0; i <= (ssize_t) (reference_black*MaxMap/1024.0); i++)
02098         logmap[i]=(Quantum) 0;
02099       for ( ; i < (ssize_t) (reference_white*MaxMap/1024.0); i++)
02100         logmap[i]=ClampToQuantum((MagickRealType) QuantumRange/(1.0-black)*
02101           (pow(10.0,(1024.0*i/MaxMap-reference_white)*
02102           (gamma/density)*0.002/film_gamma)-black));
02103       for ( ; i <= (ssize_t) MaxMap; i++)
02104         logmap[i]=(Quantum) QuantumRange;
02105       if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
02106         return(MagickFalse);
02107       image_view=AcquireCacheView(image);
02108 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02109       #pragma omp parallel for schedule(static,4) shared(status)
02110 #endif
02111       for (y=0; y < (ssize_t) image->rows; y++)
02112       {
02113         MagickBooleanType
02114           sync;
02115 
02116         register ssize_t
02117           x;
02118 
02119         register Quantum
02120           *restrict q;
02121 
02122         if (status == MagickFalse)
02123           continue;
02124         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
02125           exception);
02126         if (q == (Quantum *) NULL)
02127           {
02128             status=MagickFalse;
02129             continue;
02130           }
02131         for (x=(ssize_t) image->columns; x != 0; x--)
02132         {
02133           SetPixelRed(image,logmap[ScaleQuantumToMap(
02134             GetPixelRed(image,q))],q);
02135           SetPixelGreen(image,logmap[ScaleQuantumToMap(
02136             GetPixelGreen(image,q))],q);
02137           SetPixelBlue(image,logmap[ScaleQuantumToMap(
02138             GetPixelBlue(image,q))],q);
02139           q+=GetPixelChannels(image);
02140         }
02141         sync=SyncCacheViewAuthenticPixels(image_view,exception);
02142         if (sync == MagickFalse)
02143           status=MagickFalse;
02144       }
02145       image_view=DestroyCacheView(image_view);
02146       logmap=(Quantum *) RelinquishMagickMemory(logmap);
02147       if (SetImageColorspace(image,RGBColorspace,exception) == MagickFalse)
02148         return(MagickFalse);
02149       return(status);
02150     }
02151     default:
02152       break;
02153   }
02154   /*
02155     Allocate the tables.
02156   */
02157   x_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
02158     sizeof(*x_map));
02159   y_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
02160     sizeof(*y_map));
02161   z_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
02162     sizeof(*z_map));
02163   if ((x_map == (TransformPacket *) NULL) ||
02164       (y_map == (TransformPacket *) NULL) ||
02165       (z_map == (TransformPacket *) NULL))
02166     {
02167       if (z_map != (TransformPacket *) NULL)
02168         z_map=(TransformPacket *) RelinquishMagickMemory(z_map);
02169       if (y_map != (TransformPacket *) NULL)
02170         y_map=(TransformPacket *) RelinquishMagickMemory(y_map);
02171       if (x_map != (TransformPacket *) NULL)
02172         x_map=(TransformPacket *) RelinquishMagickMemory(x_map);
02173       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
02174         image->filename);
02175     }
02176   switch (image->colorspace)
02177   {
02178     case OHTAColorspace:
02179     {
02180       /*
02181         Initialize OHTA tables:
02182 
02183           R = I1+1.00000*I2-0.66668*I3
02184           G = I1+0.00000*I2+1.33333*I3
02185           B = I1-1.00000*I2-0.66668*I3
02186 
02187         I and Q, normally -0.5 through 0.5, must be normalized to the range 0
02188         through QuantumRange.
02189       */
02190 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02191       #pragma omp parallel for schedule(static)
02192 #endif
02193       for (i=0; i <= (ssize_t) MaxMap; i++)
02194       {
02195         x_map[i].x=(MagickRealType) i;
02196         y_map[i].x=0.500000f*(2.000000*(MagickRealType) i-(MagickRealType)
02197           MaxMap);
02198         z_map[i].x=(-0.333340f)*(2.000000f*(MagickRealType) i-(MagickRealType)
02199           MaxMap);
02200         x_map[i].y=(MagickRealType) i;
02201         y_map[i].y=0.000000f;
02202         z_map[i].y=0.666665f*(2.000000f*(MagickRealType) i-(MagickRealType)
02203           MaxMap);
02204         x_map[i].z=(MagickRealType) i;
02205         y_map[i].z=(-0.500000f)*(2.000000f*(MagickRealType) i-(MagickRealType)
02206           MaxMap);
02207         z_map[i].z=(-0.333340f)*(2.000000f*(MagickRealType) i-(MagickRealType)
02208           MaxMap);
02209       }
02210       break;
02211     }
02212     case Rec601YCbCrColorspace:
02213     case YCbCrColorspace:
02214     {
02215       /*
02216         Initialize YCbCr tables:
02217 
02218           R = Y            +1.402000*Cr
02219           G = Y-0.344136*Cb-0.714136*Cr
02220           B = Y+1.772000*Cb
02221 
02222         Cb and Cr, normally -0.5 through 0.5, must be normalized to the range 0
02223         through QuantumRange.
02224       */
02225 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02226       #pragma omp parallel for schedule(static)
02227 #endif
02228       for (i=0; i <= (ssize_t) MaxMap; i++)
02229       {
02230         x_map[i].x=(MagickRealType) i;
02231         y_map[i].x=0.000000f;
02232         z_map[i].x=(1.402000f*0.500000f)*(2.000000f*(MagickRealType) i-
02233           (MagickRealType) MaxMap);
02234         x_map[i].y=(MagickRealType) i;
02235         y_map[i].y=(-0.344136f*0.500000f)*(2.000000f*(MagickRealType) i-
02236           (MagickRealType) MaxMap);
02237         z_map[i].y=(-0.714136f*0.500000f)*(2.000000f*(MagickRealType) i-
02238           (MagickRealType) MaxMap);
02239         x_map[i].z=(MagickRealType) i;
02240         y_map[i].z=(1.772000f*0.500000f)*(2.000000f*(MagickRealType) i-
02241           (MagickRealType) MaxMap);
02242         z_map[i].z=0.000000f;
02243       }
02244       break;
02245     }
02246     case Rec709YCbCrColorspace:
02247     {
02248       /*
02249         Initialize YCbCr tables:
02250 
02251           R = Y            +1.574800*Cr
02252           G = Y-0.187324*Cb-0.468124*Cr
02253           B = Y+1.855600*Cb
02254 
02255         Cb and Cr, normally -0.5 through 0.5, must be normalized to the range 0
02256         through QuantumRange.
02257       */
02258 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02259       #pragma omp parallel for schedule(static)
02260 #endif
02261       for (i=0; i <= (ssize_t) MaxMap; i++)
02262       {
02263         x_map[i].x=(MagickRealType) i;
02264         y_map[i].x=0.000000f;
02265         z_map[i].x=(1.574800f*0.50000f)*(2.00000f*(MagickRealType) i-
02266           (MagickRealType) MaxMap);
02267         x_map[i].y=(MagickRealType) i;
02268         y_map[i].y=(-0.187324f*0.50000f)*(2.00000f*(MagickRealType) i-
02269           (MagickRealType) MaxMap);
02270         z_map[i].y=(-0.468124f*0.50000f)*(2.00000f*(MagickRealType) i-
02271           (MagickRealType) MaxMap);
02272         x_map[i].z=(MagickRealType) i;
02273         y_map[i].z=(1.855600f*0.50000f)*(2.00000f*(MagickRealType) i-
02274           (MagickRealType) MaxMap);
02275         z_map[i].z=0.00000f;
02276       }
02277       break;
02278     }
02279     case sRGBColorspace:
02280     {
02281       /*
02282         Nonlinear sRGB to linear RGB.
02283 
02284           R = 1.0*R+0.0*G+0.0*B
02285           G = 0.0*R+1.0*G+0.0*B
02286           B = 0.0*R+0.0*G+1.0*B
02287       */
02288 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02289       #pragma omp parallel for schedule(static)
02290 #endif
02291       for (i=0; i <= (ssize_t) MaxMap; i++)
02292       {
02293         MagickRealType
02294           v;
02295 
02296         v=(MagickRealType) i/(MagickRealType) MaxMap;
02297         if (((MagickRealType) i/(MagickRealType) MaxMap) <= 0.04045f)
02298           v/=12.92f;
02299         else
02300           v=(MagickRealType) pow((((double) i/MaxMap)+0.055)/1.055,2.4);
02301         x_map[i].x=1.0f*MaxMap*v;
02302         y_map[i].x=0.0f*MaxMap*v;
02303         z_map[i].x=0.0f*MaxMap*v;
02304         x_map[i].y=0.0f*MaxMap*v;
02305         y_map[i].y=1.0f*MaxMap*v;
02306         z_map[i].y=0.0f*MaxMap*v;
02307         x_map[i].z=0.0f*MaxMap*v;
02308         y_map[i].z=0.0f*MaxMap*v;
02309         z_map[i].z=1.0f*MaxMap*v;
02310       }
02311       break;
02312     }
02313     case XYZColorspace:
02314     {
02315       /*
02316         Initialize CIE XYZ tables (ITU R-709 RGB):
02317 
02318           R =  3.2404542*X-1.5371385*Y-0.4985314*Z
02319           G = -0.9692660*X+1.8760108*Y+0.0415560*Z
02320           B =  0.0556434*X-0.2040259*Y+1.057225*Z
02321       */
02322 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02323       #pragma omp parallel for schedule(static)
02324 #endif
02325       for (i=0; i <= (ssize_t) MaxMap; i++)
02326       {
02327         x_map[i].x=3.2404542f*(MagickRealType) i;
02328         x_map[i].y=(-0.9692660f)*(MagickRealType) i;
02329         x_map[i].z=0.0556434f*(MagickRealType) i;
02330         y_map[i].x=(-1.5371385f)*(MagickRealType) i;
02331         y_map[i].y=1.8760108f*(MagickRealType) i;
02332         y_map[i].z=(-0.2040259f)*(MagickRealType) i;
02333         z_map[i].x=(-0.4985314f)*(MagickRealType) i;
02334         z_map[i].y=0.0415560f*(MagickRealType) i;
02335         z_map[i].z=1.0572252f*(MagickRealType) i;
02336       }
02337       break;
02338     }
02339     case YCCColorspace:
02340     {
02341       /*
02342         Initialize YCC tables:
02343 
02344           R = Y            +1.340762*C2
02345           G = Y-0.317038*C1-0.682243*C2
02346           B = Y+1.632639*C1
02347 
02348         YCC is scaled by 1.3584.  C1 zero is 156 and C2 is at 137.
02349       */
02350 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02351       #pragma omp parallel for schedule(static)
02352 #endif
02353       for (i=0; i <= (ssize_t) MaxMap; i++)
02354       {
02355         x_map[i].x=1.3584000f*(MagickRealType) i;
02356         y_map[i].x=0.0000000f;
02357         z_map[i].x=1.8215000f*((MagickRealType) i-(MagickRealType)
02358           ScaleQuantumToMap(ScaleCharToQuantum(137)));
02359         x_map[i].y=1.3584000f*(MagickRealType) i;
02360         y_map[i].y=(-0.4302726f)*((MagickRealType) i-(MagickRealType)
02361           ScaleQuantumToMap(ScaleCharToQuantum(156)));
02362         z_map[i].y=(-0.9271435f)*((MagickRealType) i-(MagickRealType)
02363           ScaleQuantumToMap(ScaleCharToQuantum(137)));
02364         x_map[i].z=1.3584000f*(MagickRealType) i;
02365         y_map[i].z=2.2179000f*((MagickRealType) i-(MagickRealType)
02366           ScaleQuantumToMap(ScaleCharToQuantum(156)));
02367         z_map[i].z=0.0000000f;
02368       }
02369       break;
02370     }
02371     case YIQColorspace:
02372     {
02373       /*
02374         Initialize YIQ tables:
02375 
02376           R = Y+0.95620*I+0.62140*Q
02377           G = Y-0.27270*I-0.64680*Q
02378           B = Y-1.10370*I+1.70060*Q
02379 
02380         I and Q, normally -0.5 through 0.5, must be normalized to the range 0
02381         through QuantumRange.
02382       */
02383 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02384       #pragma omp parallel for schedule(static)
02385 #endif
02386       for (i=0; i <= (ssize_t) MaxMap; i++)
02387       {
02388         x_map[i].x=(MagickRealType) i;
02389         y_map[i].x=0.47810f*(2.00000f*(MagickRealType) i-(MagickRealType)
02390           MaxMap);
02391         z_map[i].x=0.31070f*(2.00000f*(MagickRealType) i-(MagickRealType)
02392           MaxMap);
02393         x_map[i].y=(MagickRealType) i;
02394         y_map[i].y=(-0.13635f)*(2.00000f*(MagickRealType) i-(MagickRealType)
02395           MaxMap);
02396         z_map[i].y=(-0.32340f)*(2.00000f*(MagickRealType) i-(MagickRealType)
02397           MaxMap);
02398         x_map[i].z=(MagickRealType) i;
02399         y_map[i].z=(-0.55185f)*(2.00000f*(MagickRealType) i-(MagickRealType)
02400           MaxMap);
02401         z_map[i].z=0.85030f*(2.00000f*(MagickRealType) i-(MagickRealType)
02402           MaxMap);
02403       }
02404       break;
02405     }
02406     case YPbPrColorspace:
02407     {
02408       /*
02409         Initialize YPbPr tables:
02410 
02411           R = Y            +1.402000*C2
02412           G = Y-0.344136*C1+0.714136*C2
02413           B = Y+1.772000*C1
02414 
02415         Pb and Pr, normally -0.5 through 0.5, must be normalized to the range 0
02416         through QuantumRange.
02417       */
02418 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02419       #pragma omp parallel for schedule(static)
02420 #endif
02421       for (i=0; i <= (ssize_t) MaxMap; i++)
02422       {
02423         x_map[i].x=(MagickRealType) i;
02424         y_map[i].x=0.000000f;
02425         z_map[i].x=0.701000f*(2.00000f*(MagickRealType) i-(MagickRealType)
02426           MaxMap);
02427         x_map[i].y=(MagickRealType) i;
02428         y_map[i].y=(-0.172068f)*(2.00000f*(MagickRealType) i-(MagickRealType)
02429           MaxMap);
02430         z_map[i].y=0.357068f*(2.00000f*(MagickRealType) i-(MagickRealType)
02431           MaxMap);
02432         x_map[i].z=(MagickRealType) i;
02433         y_map[i].z=0.88600f*(2.00000f*(MagickRealType) i-(MagickRealType)
02434           MaxMap);
02435         z_map[i].z=0.00000f;
02436       }
02437       break;
02438     }
02439     case YUVColorspace:
02440     default:
02441     {
02442       /*
02443         Initialize YUV tables:
02444 
02445           R = Y          +1.13980*V
02446           G = Y-0.39380*U-0.58050*V
02447           B = Y+2.02790*U
02448 
02449         U and V, normally -0.5 through 0.5, must be normalized to the range 0
02450         through QuantumRange.
02451       */
02452 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02453       #pragma omp parallel for schedule(static)
02454 #endif
02455       for (i=0; i <= (ssize_t) MaxMap; i++)
02456       {
02457         x_map[i].x=(MagickRealType) i;
02458         y_map[i].x=0.00000f;
02459         z_map[i].x=0.56990f*(2.0000f*(MagickRealType) i-(MagickRealType)
02460           MaxMap);
02461         x_map[i].y=(MagickRealType) i;
02462         y_map[i].y=(-0.19690f)*(2.00000f*(MagickRealType) i-(MagickRealType)
02463           MaxMap);
02464         z_map[i].y=(-0.29025f)*(2.00000f*(MagickRealType) i-(MagickRealType)
02465           MaxMap);
02466         x_map[i].z=(MagickRealType) i;
02467         y_map[i].z=1.01395f*(2.00000f*(MagickRealType) i-(MagickRealType)
02468           MaxMap);
02469         z_map[i].z=0.00000f;
02470       }
02471       break;
02472     }
02473   }
02474   /*
02475     Convert to RGB.
02476   */
02477   switch (image->storage_class)
02478   {
02479     case DirectClass:
02480     default:
02481     {
02482       /*
02483         Convert DirectClass image.
02484       */
02485       image_view=AcquireCacheView(image);
02486 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02487       #pragma omp parallel for schedule(static,4) shared(status)
02488 #endif
02489       for (y=0; y < (ssize_t) image->rows; y++)
02490       {
02491         MagickBooleanType
02492           sync;
02493 
02494         PixelInfo
02495           pixel;
02496 
02497         register ssize_t
02498           x;
02499 
02500         register Quantum
02501           *restrict q;
02502 
02503         if (status == MagickFalse)
02504           continue;
02505         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
02506           exception);
02507         if (q == (Quantum *) NULL)
02508           {
02509             status=MagickFalse;
02510             continue;
02511           }
02512         for (x=0; x < (ssize_t) image->columns; x++)
02513         {
02514           register size_t
02515             blue,
02516             green,
02517             red;
02518 
02519           red=ScaleQuantumToMap(GetPixelRed(image,q));
02520           green=ScaleQuantumToMap(GetPixelGreen(image,q));
02521           blue=ScaleQuantumToMap(GetPixelBlue(image,q));
02522           pixel.red=x_map[red].x+y_map[green].x+z_map[blue].x;
02523           pixel.green=x_map[red].y+y_map[green].y+z_map[blue].y;
02524           pixel.blue=x_map[red].z+y_map[green].z+z_map[blue].z;
02525           switch (colorspace)
02526           {
02527             case YCCColorspace:
02528             {
02529 #if !defined(MAGICKCORE_HDRI_SUPPORT)
02530               pixel.red=QuantumRange*YCCMap[RoundToYCC(1024.0*QuantumScale*
02531                 pixel.red)];
02532               pixel.green=QuantumRange*YCCMap[RoundToYCC(1024.0*QuantumScale*
02533                 pixel.green)];
02534               pixel.blue=QuantumRange*YCCMap[RoundToYCC(1024.0*QuantumScale*
02535                 pixel.blue)];
02536 #endif
02537               break;
02538             }
02539             case sRGBColorspace:
02540             {
02541               if ((QuantumScale*pixel.red) <= 0.0031308)
02542                 pixel.red*=12.92f;
02543               else
02544                 pixel.red=(MagickRealType) QuantumRange*(1.055*
02545                   pow(QuantumScale*pixel.red,(1.0/2.4))-0.055);
02546               if ((QuantumScale*pixel.green) <= 0.0031308)
02547                 pixel.green*=12.92f;
02548               else
02549                 pixel.green=(MagickRealType) QuantumRange*(1.055*
02550                   pow(QuantumScale*pixel.green,(1.0/2.4))-0.055);
02551               if ((QuantumScale*pixel.blue) <= 0.0031308)
02552                 pixel.blue*=12.92f;
02553               else
02554                 pixel.blue=(MagickRealType) QuantumRange*(1.055*
02555                   pow(QuantumScale*pixel.blue,(1.0/2.4))-0.055);
02556               break;
02557             }
02558             default:
02559               break;
02560           }
02561           SetPixelRed(image,ScaleMapToQuantum((MagickRealType) MaxMap*
02562             QuantumScale*pixel.red),q);
02563           SetPixelGreen(image,ScaleMapToQuantum((MagickRealType) MaxMap*
02564             QuantumScale*pixel.green),q);
02565           SetPixelBlue(image,ScaleMapToQuantum((MagickRealType) MaxMap*
02566             QuantumScale*pixel.blue),q);
02567           q+=GetPixelChannels(image);
02568         }
02569         sync=SyncCacheViewAuthenticPixels(image_view,exception);
02570         if (sync == MagickFalse)
02571           status=MagickFalse;
02572         if (image->progress_monitor != (MagickProgressMonitor) NULL)
02573           {
02574             MagickBooleanType
02575               proceed;
02576 
02577 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02578             #pragma omp critical (MagickCore_TransformRGBImage)
02579 #endif
02580             proceed=SetImageProgress(image,TransformRGBImageTag,progress++,
02581               image->rows);
02582             if (proceed == MagickFalse)
02583               status=MagickFalse;
02584           }
02585       }
02586       image_view=DestroyCacheView(image_view);
02587       break;
02588     }
02589     case PseudoClass:
02590     {
02591       /*
02592         Convert PseudoClass image.
02593       */
02594       image_view=AcquireCacheView(image);
02595 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02596       #pragma omp parallel for schedule(static,4) shared(status)
02597 #endif
02598       for (i=0; i < (ssize_t) image->colors; i++)
02599       {
02600         PixelInfo
02601           pixel;
02602 
02603         register size_t
02604           blue,
02605           green,
02606           red;
02607 
02608         red=ScaleQuantumToMap(ClampToQuantum(image->colormap[i].red));
02609         green=ScaleQuantumToMap(ClampToQuantum(image->colormap[i].green));
02610         blue=ScaleQuantumToMap(ClampToQuantum(image->colormap[i].blue));
02611         pixel.red=x_map[red].x+y_map[green].x+z_map[blue].x;
02612         pixel.green=x_map[red].y+y_map[green].y+z_map[blue].y;
02613         pixel.blue=x_map[red].z+y_map[green].z+z_map[blue].z;
02614         switch (colorspace)
02615         {
02616           case YCCColorspace:
02617           {
02618 #if !defined(MAGICKCORE_HDRI_SUPPORT)
02619             image->colormap[i].red=(double) (QuantumRange*YCCMap[
02620               RoundToYCC(1024.0*QuantumScale*pixel.red)]);
02621             image->colormap[i].green=(double) (QuantumRange*YCCMap[
02622               RoundToYCC(1024.0*QuantumScale*pixel.green)]);
02623             image->colormap[i].blue=(double) (QuantumRange*YCCMap[
02624               RoundToYCC(1024.0*QuantumScale*pixel.blue)]);
02625 #endif
02626             break;
02627           }
02628           case sRGBColorspace:
02629           {
02630             if ((QuantumScale*pixel.red) <= 0.0031308)
02631               pixel.red*=12.92f;
02632             else
02633               pixel.red=(MagickRealType) QuantumRange*(1.055*pow(QuantumScale*
02634                 pixel.red,(1.0/2.4))-0.055);
02635             if ((QuantumScale*pixel.green) <= 0.0031308)
02636               pixel.green*=12.92f;
02637             else
02638               pixel.green=(MagickRealType) QuantumRange*(1.055*pow(QuantumScale*
02639                 pixel.green,(1.0/2.4))-0.055);
02640             if ((QuantumScale*pixel.blue) <= 0.0031308)
02641               pixel.blue*=12.92f;
02642             else
02643               pixel.blue=(MagickRealType) QuantumRange*(1.055*pow(QuantumScale*
02644                 pixel.blue,(1.0/2.4))-0.055);
02645           }
02646           default:
02647           {
02648             image->colormap[i].red=(double) ScaleMapToQuantum((MagickRealType)
02649               MaxMap*QuantumScale*pixel.red);
02650             image->colormap[i].green=(double) ScaleMapToQuantum((MagickRealType)
02651               MaxMap*QuantumScale*pixel.green);
02652             image->colormap[i].blue=(double) ScaleMapToQuantum((MagickRealType)
02653               MaxMap*QuantumScale*pixel.blue);
02654             break;
02655           }
02656         }
02657       }
02658       image_view=DestroyCacheView(image_view);
02659       (void) SyncImage(image,exception);
02660       break;
02661     }
02662   }
02663   /*
02664     Relinquish resources.
02665   */
02666   z_map=(TransformPacket *) RelinquishMagickMemory(z_map);
02667   y_map=(TransformPacket *) RelinquishMagickMemory(y_map);
02668   x_map=(TransformPacket *) RelinquishMagickMemory(x_map);
02669   if (SetImageColorspace(image,RGBColorspace,exception) == MagickFalse)
02670     return(MagickFalse);
02671   return(MagickTrue);
02672 }