profile.c

Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %               PPPP   RRRR    OOO   FFFFF  IIIII  L      EEEEE               %
00007 %               P   P  R   R  O   O  F        I    L      E                   %
00008 %               PPPP   RRRR   O   O  FFF      I    L      EEE                 %
00009 %               P      R R    O   O  F        I    L      E                   %
00010 %               P      R  R    OOO   F      IIIII  LLLLL  EEEEE               %
00011 %                                                                             %
00012 %                                                                             %
00013 %                       MagickCore Image Profile Methods                      %
00014 %                                                                             %
00015 %                              Software Design                                %
00016 %                                John Cristy                                  %
00017 %                                 July 1992                                   %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.imagemagick.org/script/license.php                            %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 %
00037 */
00038 
00039 /*
00040   Include declarations.
00041 */
00042 #include "magick/studio.h"
00043 #include "magick/cache.h"
00044 #include "magick/color.h"
00045 #include "magick/configure.h"
00046 #include "magick/exception.h"
00047 #include "magick/exception-private.h"
00048 #include "magick/hashmap.h"
00049 #include "magick/image.h"
00050 #include "magick/memory_.h"
00051 #include "magick/monitor.h"
00052 #include "magick/monitor-private.h"
00053 #include "magick/option.h"
00054 #include "magick/profile.h"
00055 #include "magick/property.h"
00056 #include "magick/quantum.h"
00057 #include "magick/quantum-private.h"
00058 #include "magick/splay-tree.h"
00059 #include "magick/string_.h"
00060 #include "magick/thread-private.h"
00061 #include "magick/token.h"
00062 #include "magick/utility.h"
00063 #if defined(MAGICKCORE_LCMS_DELEGATE)
00064 #if defined(MAGICKCORE_HAVE_LCMS_LCMS_H)
00065 #include <lcms/lcms.h>
00066 #else
00067 #include "lcms.h"
00068 #endif
00069 #endif
00070 
00071 /*
00072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00073 %                                                                             %
00074 %                                                                             %
00075 %                                                                             %
00076 %   C l o n e I m a g e P r o f i l e s                                       %
00077 %                                                                             %
00078 %                                                                             %
00079 %                                                                             %
00080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00081 %
00082 %  CloneImageProfiles() clones one or more image profiles.
00083 %
00084 %  The format of the CloneImageProfiles method is:
00085 %
00086 %      MagickBooleanType CloneImageProfiles(Image *image,
00087 %        const Image *clone_image)
00088 %
00089 %  A description of each parameter follows:
00090 %
00091 %    o image: the image.
00092 %
00093 %    o clone_image: the clone image.
00094 %
00095 */
00096 MagickExport MagickBooleanType CloneImageProfiles(Image *image,
00097   const Image *clone_image)
00098 {
00099   assert(image != (Image *) NULL);
00100   assert(image->signature == MagickSignature);
00101   if (image->debug != MagickFalse)
00102     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00103   assert(clone_image != (const Image *) NULL);
00104   assert(clone_image->signature == MagickSignature);
00105   image->color_profile.length=clone_image->color_profile.length;
00106   image->color_profile.info=clone_image->color_profile.info;
00107   image->iptc_profile.length=clone_image->iptc_profile.length;
00108   image->iptc_profile.info=clone_image->iptc_profile.info;
00109   if (clone_image->profiles != (void *) NULL)
00110     image->profiles=CloneSplayTree((SplayTreeInfo *) clone_image->profiles,
00111       (void *(*)(void *)) ConstantString,(void *(*)(void *)) CloneStringInfo);
00112   return(MagickTrue);
00113 }
00114 
00115 /*
00116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00117 %                                                                             %
00118 %                                                                             %
00119 %                                                                             %
00120 %   D e l e t e I m a g e P r o f i l e                                       %
00121 %                                                                             %
00122 %                                                                             %
00123 %                                                                             %
00124 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00125 %
00126 %  DeleteImageProfile() deletes a profile from the image by its name.
00127 %
00128 %  The format of the DeleteImageProfile method is:
00129 %
00130 %      MagickBooleanTyupe DeleteImageProfile(Image *image,const char *name)
00131 %
00132 %  A description of each parameter follows:
00133 %
00134 %    o image: the image.
00135 %
00136 %    o name: the profile name.
00137 %
00138 */
00139 MagickExport MagickBooleanType DeleteImageProfile(Image *image,
00140   const char *name)
00141 {
00142   assert(image != (Image *) NULL);
00143   assert(image->signature == MagickSignature);
00144   if (image->debug != MagickFalse)
00145     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00146   if (image->profiles == (SplayTreeInfo *) NULL)
00147     return(MagickFalse);
00148   if (LocaleCompare(name,"icc") == 0)
00149     {
00150       /*
00151         Continue to support deprecated color profile for now.
00152       */
00153       image->color_profile.length=0;
00154       image->color_profile.info=(unsigned char *) NULL;
00155     }
00156   if (LocaleCompare(name,"iptc") == 0)
00157     {
00158       /*
00159         Continue to support deprecated IPTC profile for now.
00160       */
00161       image->iptc_profile.length=0;
00162       image->iptc_profile.info=(unsigned char *) NULL;
00163     }
00164   return(DeleteNodeFromSplayTree((SplayTreeInfo *) image->profiles,name));
00165 }
00166 
00167 /*
00168 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00169 %                                                                             %
00170 %                                                                             %
00171 %                                                                             %
00172 %   D e s t r o y I m a g e P r o f i l e s                                   %
00173 %                                                                             %
00174 %                                                                             %
00175 %                                                                             %
00176 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00177 %
00178 %  DestroyImageProfiles() releases memory associated with an image profile map.
00179 %
00180 %  The format of the DestroyProfiles method is:
00181 %
00182 %      void DestroyImageProfiles(Image *image)
00183 %
00184 %  A description of each parameter follows:
00185 %
00186 %    o image: the image.
00187 %
00188 */
00189 MagickExport void DestroyImageProfiles(Image *image)
00190 {
00191   if (image->profiles != (SplayTreeInfo *) NULL)
00192     image->profiles=DestroySplayTree((SplayTreeInfo *) image->profiles);
00193 }
00194 
00195 /*
00196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00197 %                                                                             %
00198 %                                                                             %
00199 %                                                                             %
00200 %   G e t I m a g e P r o f i l e                                             %
00201 %                                                                             %
00202 %                                                                             %
00203 %                                                                             %
00204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00205 %
00206 %  GetImageProfile() gets a profile associated with an image by name.
00207 %
00208 %  The format of the GetImageProfile method is:
00209 %
00210 %      const StringInfo *GetImageProfile(const Image *image,const char *name)
00211 %
00212 %  A description of each parameter follows:
00213 %
00214 %    o image: the image.
00215 %
00216 %    o name: the profile name.
00217 %
00218 */
00219 MagickExport const StringInfo *GetImageProfile(const Image *image,
00220   const char *name)
00221 {
00222   char
00223     key[MaxTextExtent];
00224 
00225   const StringInfo
00226     *profile;
00227 
00228   assert(image != (Image *) NULL);
00229   assert(image->signature == MagickSignature);
00230   if (image->debug != MagickFalse)
00231     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00232   if (image->profiles == (SplayTreeInfo *) NULL)
00233     return((StringInfo *) NULL);
00234   (void) CopyMagickString(key,name,MaxTextExtent);
00235   profile=(const StringInfo *) GetValueFromSplayTree((SplayTreeInfo *)
00236     image->profiles,key);
00237   return(profile);
00238 }
00239 
00240 /*
00241 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00242 %                                                                             %
00243 %                                                                             %
00244 %                                                                             %
00245 %   G e t N e x t I m a g e P r o f i l e                                     %
00246 %                                                                             %
00247 %                                                                             %
00248 %                                                                             %
00249 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00250 %
00251 %  GetNextImageProfile() gets the next profile name for an image.
00252 %
00253 %  The format of the GetNextImageProfile method is:
00254 %
00255 %      char *GetNextImageProfile(const Image *image)
00256 %
00257 %  A description of each parameter follows:
00258 %
00259 %    o hash_info: the hash info.
00260 %
00261 */
00262 MagickExport char *GetNextImageProfile(const Image *image)
00263 {
00264   assert(image != (Image *) NULL);
00265   assert(image->signature == MagickSignature);
00266   if (image->debug != MagickFalse)
00267     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00268   if (image->profiles == (SplayTreeInfo *) NULL)
00269     return((char *) NULL);
00270   return((char *) GetNextKeyInSplayTree((SplayTreeInfo *) image->profiles));
00271 }
00272 
00273 /*
00274 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00275 %                                                                             %
00276 %                                                                             %
00277 %                                                                             %
00278 %   P r o f i l e I m a g e                                                   %
00279 %                                                                             %
00280 %                                                                             %
00281 %                                                                             %
00282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00283 %
00284 %  ProfileImage() associates, applies, or removes an ICM, IPTC, or generic
00285 %  profile with / to / from an image.  If the profile is NULL, it is removed
00286 %  from the image otherwise added or applied.  Use a name of '*' and a profile
00287 %  of NULL to remove all profiles from the image.
00288 %
00289 %  ICC and ICM profiles are handled as follows: If the image does not have
00290 %  an associated color profile, the one you provide is associated with the
00291 %  image and the image pixels are not transformed.  Otherwise, the colorspace
00292 %  transform defined by the existing and new profile are applied to the image
00293 %  pixels and the new profile is associated with the image.
00294 %
00295 %  The format of the ProfileImage method is:
00296 %
00297 %      MagickBooleanType ProfileImage(Image *image,const char *name,
00298 %        const void *datum,const size_t length,const MagickBooleanType clone)
00299 %
00300 %  A description of each parameter follows:
00301 %
00302 %    o image: the image.
00303 %
00304 %    o name: Name of profile to add or remove: ICC, IPTC, or generic profile.
00305 %
00306 %    o datum: the profile data.
00307 %
00308 %    o length: the length of the profile.
00309 %
00310 %    o clone: should be MagickFalse.
00311 %
00312 */
00313 
00314 #if defined(MAGICKCORE_LCMS_DELEGATE)
00315 
00316 static unsigned short **DestroyPixelThreadSet(unsigned short **pixels)
00317 {
00318   register long
00319     i;
00320 
00321   assert(pixels != (unsigned short **) NULL);
00322   for (i=0; i < (long) GetOpenMPMaximumThreads(); i++)
00323     if (pixels[i] != (unsigned short *) NULL)
00324       pixels[i]=(unsigned short *) RelinquishMagickMemory(pixels[i]);
00325   pixels=(unsigned short **) RelinquishAlignedMemory(pixels);
00326   return(pixels);
00327 }
00328 
00329 static unsigned short **AcquirePixelThreadSet(const size_t columns,
00330   const size_t channels)
00331 {
00332   register long
00333     i;
00334 
00335   unsigned short
00336     **pixels;
00337 
00338   unsigned long
00339     number_threads;
00340 
00341   number_threads=GetOpenMPMaximumThreads();
00342   pixels=(unsigned short **) AcquireAlignedMemory(number_threads,
00343     sizeof(*pixels));
00344   if (pixels == (unsigned short **) NULL)
00345     return((unsigned short **) NULL);
00346   (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
00347   for (i=0; i < (long) number_threads; i++)
00348   {
00349     pixels[i]=(unsigned short *) AcquireQuantumMemory(columns,channels*
00350       sizeof(**pixels));
00351     if (pixels[i] == (unsigned short *) NULL)
00352       return(DestroyPixelThreadSet(pixels));
00353   }
00354   return(pixels);
00355 }
00356 
00357 static cmsHTRANSFORM *DestroyTransformThreadSet(cmsHTRANSFORM *transform)
00358 {
00359   register long
00360     i;
00361 
00362   assert(transform != (cmsHTRANSFORM *) NULL);
00363   for (i=0; i < (long) GetOpenMPMaximumThreads(); i++)
00364     if (transform[i] != (cmsHTRANSFORM) NULL)
00365       cmsDeleteTransform(transform[i]);
00366   transform=(cmsHTRANSFORM *) RelinquishAlignedMemory(transform);
00367   return(transform);
00368 }
00369 
00370 static cmsHTRANSFORM *AcquireTransformThreadSet(
00371   const cmsHPROFILE source_profile,const DWORD source_type,
00372   const cmsHPROFILE target_profile,const DWORD target_type,const int intent,
00373   const DWORD flags)
00374 {
00375   cmsHTRANSFORM
00376     *transform;
00377 
00378   register long
00379     i;
00380 
00381   unsigned long
00382     number_threads;
00383 
00384   number_threads=GetOpenMPMaximumThreads();
00385   transform=(cmsHTRANSFORM *) AcquireAlignedMemory(number_threads,
00386     sizeof(*transform));
00387   if (transform == (cmsHTRANSFORM *) NULL)
00388     return((cmsHTRANSFORM *) NULL);
00389   (void) ResetMagickMemory(transform,0,number_threads*sizeof(*transform));
00390   for (i=0; i < (long) number_threads; i++)
00391   {
00392     transform[i]=cmsCreateTransform(source_profile,source_type,target_profile,
00393       target_type,intent,flags);
00394     if (transform[i] == (cmsHTRANSFORM) NULL)
00395       return(DestroyTransformThreadSet(transform));
00396   }
00397   return(transform);
00398 }
00399 #endif
00400 
00401 static MagickBooleanType SetAdobeRGB1998ImageProfile(Image *image)
00402 {
00403   static unsigned char
00404     AdobeRGB1998Profile[] =
00405     {
00406       0x00, 0x00, 0x02, 0x30, 0x41, 0x44, 0x42, 0x45, 0x02, 0x10, 0x00,
00407       0x00, 0x6d, 0x6e, 0x74, 0x72, 0x52, 0x47, 0x42, 0x20, 0x58, 0x59,
00408       0x5a, 0x20, 0x07, 0xd0, 0x00, 0x08, 0x00, 0x0b, 0x00, 0x13, 0x00,
00409       0x33, 0x00, 0x3b, 0x61, 0x63, 0x73, 0x70, 0x41, 0x50, 0x50, 0x4c,
00410       0x00, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x6e, 0x65, 0x00, 0x00, 0x00,
00411       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00412       0x00, 0x00, 0x00, 0x00, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00,
00413       0x00, 0xd3, 0x2d, 0x41, 0x44, 0x42, 0x45, 0x00, 0x00, 0x00, 0x00,
00414       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00415       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00416       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00417       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
00418       0x63, 0x70, 0x72, 0x74, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00,
00419       0x32, 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x01, 0x30, 0x00, 0x00,
00420       0x00, 0x6b, 0x77, 0x74, 0x70, 0x74, 0x00, 0x00, 0x01, 0x9c, 0x00,
00421       0x00, 0x00, 0x14, 0x62, 0x6b, 0x70, 0x74, 0x00, 0x00, 0x01, 0xb0,
00422       0x00, 0x00, 0x00, 0x14, 0x72, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01,
00423       0xc4, 0x00, 0x00, 0x00, 0x0e, 0x67, 0x54, 0x52, 0x43, 0x00, 0x00,
00424       0x01, 0xd4, 0x00, 0x00, 0x00, 0x0e, 0x62, 0x54, 0x52, 0x43, 0x00,
00425       0x00, 0x01, 0xe4, 0x00, 0x00, 0x00, 0x0e, 0x72, 0x58, 0x59, 0x5a,
00426       0x00, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x00, 0x14, 0x67, 0x58, 0x59,
00427       0x5a, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x14, 0x62, 0x58,
00428       0x59, 0x5a, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x14, 0x74,
00429       0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x70, 0x79,
00430       0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x32, 0x30, 0x30, 0x30, 0x20,
00431       0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65,
00432       0x6d, 0x73, 0x20, 0x49, 0x6e, 0x63, 0x6f, 0x72, 0x70, 0x6f, 0x72,
00433       0x61, 0x74, 0x65, 0x64, 0x00, 0x00, 0x00, 0x64, 0x65, 0x73, 0x63,
00434       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x41, 0x64, 0x6f,
00435       0x62, 0x65, 0x20, 0x52, 0x47, 0x42, 0x20, 0x28, 0x31, 0x39, 0x39,
00436       0x38, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00437       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00438       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00439       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00440       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00441       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00442       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00443       0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00,
00444       0x00, 0x00, 0x00, 0x00, 0xf3, 0x51, 0x00, 0x01, 0x00, 0x00, 0x00,
00445       0x01, 0x16, 0xcc, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00,
00446       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00447       0x00, 0x63, 0x75, 0x72, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00448       0x00, 0x01, 0x02, 0x33, 0x00, 0x00, 0x63, 0x75, 0x72, 0x76, 0x00,
00449       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x33, 0x00, 0x00,
00450       0x63, 0x75, 0x72, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00451       0x01, 0x02, 0x33, 0x00, 0x00, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00,
00452       0x00, 0x00, 0x00, 0x00, 0x9c, 0x18, 0x00, 0x00, 0x4f, 0xa5, 0x00,
00453       0x00, 0x04, 0xfc, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00,
00454       0x00, 0x00, 0x34, 0x8d, 0x00, 0x00, 0xa0, 0x2c, 0x00, 0x00, 0x0f,
00455       0x95, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00456       0x26, 0x31, 0x00, 0x00, 0x10, 0x2f, 0x00, 0x00, 0xbe, 0x9c
00457     };
00458 
00459   StringInfo
00460     *profile;
00461 
00462   MagickBooleanType
00463     status;
00464 
00465   assert(image != (Image *) NULL);
00466   assert(image->signature == MagickSignature);
00467   if (GetImageProfile(image,"icm") != (const StringInfo *) NULL)
00468     return(MagickFalse);
00469   profile=AcquireStringInfo(sizeof(AdobeRGB1998Profile));
00470   SetStringInfoDatum(profile,AdobeRGB1998Profile);
00471   status=SetImageProfile(image,"icm",profile);
00472   profile=DestroyStringInfo(profile);
00473   return(status);
00474 }
00475 
00476 static MagickBooleanType SetsRGBImageProfile(Image *image)
00477 {
00478   static unsigned char
00479     sRGBProfile[] =
00480     {
00481       0x00, 0x00, 0x0c, 0x48, 0x4c, 0x69, 0x6e, 0x6f, 0x02, 0x10, 0x00,
00482       0x00, 0x6d, 0x6e, 0x74, 0x72, 0x52, 0x47, 0x42, 0x20, 0x58, 0x59,
00483       0x5a, 0x20, 0x07, 0xce, 0x00, 0x02, 0x00, 0x09, 0x00, 0x06, 0x00,
00484       0x31, 0x00, 0x00, 0x61, 0x63, 0x73, 0x70, 0x4d, 0x53, 0x46, 0x54,
00485       0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x43, 0x20, 0x73, 0x52, 0x47,
00486       0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00487       0x00, 0x00, 0x00, 0x00, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00,
00488       0x00, 0xd3, 0x2d, 0x48, 0x50, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00,
00489       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00490       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00491       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00492       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
00493       0x63, 0x70, 0x72, 0x74, 0x00, 0x00, 0x01, 0x50, 0x00, 0x00, 0x00,
00494       0x33, 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x01, 0x84, 0x00, 0x00,
00495       0x00, 0x6c, 0x77, 0x74, 0x70, 0x74, 0x00, 0x00, 0x01, 0xf0, 0x00,
00496       0x00, 0x00, 0x14, 0x62, 0x6b, 0x70, 0x74, 0x00, 0x00, 0x02, 0x04,
00497       0x00, 0x00, 0x00, 0x14, 0x72, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x02,
00498       0x18, 0x00, 0x00, 0x00, 0x14, 0x67, 0x58, 0x59, 0x5a, 0x00, 0x00,
00499       0x02, 0x2c, 0x00, 0x00, 0x00, 0x14, 0x62, 0x58, 0x59, 0x5a, 0x00,
00500       0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x14, 0x64, 0x6d, 0x6e, 0x64,
00501       0x00, 0x00, 0x02, 0x54, 0x00, 0x00, 0x00, 0x70, 0x64, 0x6d, 0x64,
00502       0x64, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x00, 0x88, 0x76, 0x75,
00503       0x65, 0x64, 0x00, 0x00, 0x03, 0x4c, 0x00, 0x00, 0x00, 0x86, 0x76,
00504       0x69, 0x65, 0x77, 0x00, 0x00, 0x03, 0xd4, 0x00, 0x00, 0x00, 0x24,
00505       0x6c, 0x75, 0x6d, 0x69, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x00,
00506       0x14, 0x6d, 0x65, 0x61, 0x73, 0x00, 0x00, 0x04, 0x0c, 0x00, 0x00,
00507       0x00, 0x24, 0x74, 0x65, 0x63, 0x68, 0x00, 0x00, 0x04, 0x30, 0x00,
00508       0x00, 0x00, 0x0c, 0x72, 0x54, 0x52, 0x43, 0x00, 0x00, 0x04, 0x3c,
00509       0x00, 0x00, 0x08, 0x0c, 0x67, 0x54, 0x52, 0x43, 0x00, 0x00, 0x04,
00510       0x3c, 0x00, 0x00, 0x08, 0x0c, 0x62, 0x54, 0x52, 0x43, 0x00, 0x00,
00511       0x04, 0x3c, 0x00, 0x00, 0x08, 0x0c, 0x74, 0x65, 0x78, 0x74, 0x00,
00512       0x00, 0x00, 0x00, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68,
00513       0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x31, 0x39, 0x39, 0x38, 0x20,
00514       0x48, 0x65, 0x77, 0x6c, 0x65, 0x74, 0x74, 0x2d, 0x50, 0x61, 0x63,
00515       0x6b, 0x61, 0x72, 0x64, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e,
00516       0x79, 0x00, 0x00, 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00,
00517       0x00, 0x00, 0x00, 0x12, 0x73, 0x52, 0x47, 0x42, 0x20, 0x49, 0x45,
00518       0x43, 0x36, 0x31, 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x00,
00519       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12,
00520       0x73, 0x52, 0x47, 0x42, 0x20, 0x49, 0x45, 0x43, 0x36, 0x31, 0x39,
00521       0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00,
00522       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00523       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00524       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00525       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00526       0x00, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00527       0xf3, 0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x16, 0xcc, 0x58,
00528       0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00529       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x59, 0x5a,
00530       0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xa2, 0x00, 0x00,
00531       0x38, 0xf5, 0x00, 0x00, 0x03, 0x90, 0x58, 0x59, 0x5a, 0x20, 0x00,
00532       0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x99, 0x00, 0x00, 0xb7, 0x85,
00533       0x00, 0x00, 0x18, 0xda, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00,
00534       0x00, 0x00, 0x00, 0x24, 0xa0, 0x00, 0x00, 0x0f, 0x84, 0x00, 0x00,
00535       0xb6, 0xcf, 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00,
00536       0x00, 0x00, 0x16, 0x49, 0x45, 0x43, 0x20, 0x68, 0x74, 0x74, 0x70,
00537       0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x65, 0x63, 0x2e,
00538       0x63, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00539       0x00, 0x00, 0x16, 0x49, 0x45, 0x43, 0x20, 0x68, 0x74, 0x74, 0x70,
00540       0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x65, 0x63, 0x2e,
00541       0x63, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00542       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00543       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00544       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00545       0x00, 0x00, 0x00, 0x00, 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00,
00546       0x00, 0x00, 0x00, 0x00, 0x2e, 0x49, 0x45, 0x43, 0x20, 0x36, 0x31,
00547       0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x20, 0x44, 0x65, 0x66,
00548       0x61, 0x75, 0x6c, 0x74, 0x20, 0x52, 0x47, 0x42, 0x20, 0x63, 0x6f,
00549       0x6c, 0x6f, 0x75, 0x72, 0x20, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20,
00550       0x2d, 0x20, 0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00,
00551       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x49, 0x45, 0x43, 0x20,
00552       0x36, 0x31, 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x20, 0x44,
00553       0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x52, 0x47, 0x42, 0x20,
00554       0x63, 0x6f, 0x6c, 0x6f, 0x75, 0x72, 0x20, 0x73, 0x70, 0x61, 0x63,
00555       0x65, 0x20, 0x2d, 0x20, 0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00,
00556       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00557       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x65, 0x73,
00558       0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x52, 0x65,
00559       0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x56, 0x69, 0x65,
00560       0x77, 0x69, 0x6e, 0x67, 0x20, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74,
00561       0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x49, 0x45, 0x43, 0x36,
00562       0x31, 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x00, 0x00, 0x00,
00563       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x52, 0x65,
00564       0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x56, 0x69, 0x65,
00565       0x77, 0x69, 0x6e, 0x67, 0x20, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74,
00566       0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x49, 0x45, 0x43, 0x36,
00567       0x31, 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x00, 0x00, 0x00,
00568       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00569       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00570       0x00, 0x76, 0x69, 0x65, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13,
00571       0xa4, 0xfe, 0x00, 0x14, 0x5f, 0x2e, 0x00, 0x10, 0xcf, 0x14, 0x00,
00572       0x03, 0xed, 0xcc, 0x00, 0x04, 0x13, 0x0b, 0x00, 0x03, 0x5c, 0x9e,
00573       0x00, 0x00, 0x00, 0x01, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00,
00574       0x00, 0x00, 0x4c, 0x09, 0x56, 0x00, 0x50, 0x00, 0x00, 0x00, 0x57,
00575       0x1f, 0xe7, 0x6d, 0x65, 0x61, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00,
00576       0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00577       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
00578       0x8f, 0x00, 0x00, 0x00, 0x02, 0x73, 0x69, 0x67, 0x20, 0x00, 0x00,
00579       0x00, 0x00, 0x43, 0x52, 0x54, 0x20, 0x63, 0x75, 0x72, 0x76, 0x00,
00580       0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x05,
00581       0x00, 0x0a, 0x00, 0x0f, 0x00, 0x14, 0x00, 0x19, 0x00, 0x1e, 0x00,
00582       0x23, 0x00, 0x28, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x37, 0x00, 0x3b,
00583       0x00, 0x40, 0x00, 0x45, 0x00, 0x4a, 0x00, 0x4f, 0x00, 0x54, 0x00,
00584       0x59, 0x00, 0x5e, 0x00, 0x63, 0x00, 0x68, 0x00, 0x6d, 0x00, 0x72,
00585       0x00, 0x77, 0x00, 0x7c, 0x00, 0x81, 0x00, 0x86, 0x00, 0x8b, 0x00,
00586       0x90, 0x00, 0x95, 0x00, 0x9a, 0x00, 0x9f, 0x00, 0xa4, 0x00, 0xa9,
00587       0x00, 0xae, 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc1, 0x00,
00588       0xc6, 0x00, 0xcb, 0x00, 0xd0, 0x00, 0xd5, 0x00, 0xdb, 0x00, 0xe0,
00589       0x00, 0xe5, 0x00, 0xeb, 0x00, 0xf0, 0x00, 0xf6, 0x00, 0xfb, 0x01,
00590       0x01, 0x01, 0x07, 0x01, 0x0d, 0x01, 0x13, 0x01, 0x19, 0x01, 0x1f,
00591       0x01, 0x25, 0x01, 0x2b, 0x01, 0x32, 0x01, 0x38, 0x01, 0x3e, 0x01,
00592       0x45, 0x01, 0x4c, 0x01, 0x52, 0x01, 0x59, 0x01, 0x60, 0x01, 0x67,
00593       0x01, 0x6e, 0x01, 0x75, 0x01, 0x7c, 0x01, 0x83, 0x01, 0x8b, 0x01,
00594       0x92, 0x01, 0x9a, 0x01, 0xa1, 0x01, 0xa9, 0x01, 0xb1, 0x01, 0xb9,
00595       0x01, 0xc1, 0x01, 0xc9, 0x01, 0xd1, 0x01, 0xd9, 0x01, 0xe1, 0x01,
00596       0xe9, 0x01, 0xf2, 0x01, 0xfa, 0x02, 0x03, 0x02, 0x0c, 0x02, 0x14,
00597       0x02, 0x1d, 0x02, 0x26, 0x02, 0x2f, 0x02, 0x38, 0x02, 0x41, 0x02,
00598       0x4b, 0x02, 0x54, 0x02, 0x5d, 0x02, 0x67, 0x02, 0x71, 0x02, 0x7a,
00599       0x02, 0x84, 0x02, 0x8e, 0x02, 0x98, 0x02, 0xa2, 0x02, 0xac, 0x02,
00600       0xb6, 0x02, 0xc1, 0x02, 0xcb, 0x02, 0xd5, 0x02, 0xe0, 0x02, 0xeb,
00601       0x02, 0xf5, 0x03, 0x00, 0x03, 0x0b, 0x03, 0x16, 0x03, 0x21, 0x03,
00602       0x2d, 0x03, 0x38, 0x03, 0x43, 0x03, 0x4f, 0x03, 0x5a, 0x03, 0x66,
00603       0x03, 0x72, 0x03, 0x7e, 0x03, 0x8a, 0x03, 0x96, 0x03, 0xa2, 0x03,
00604       0xae, 0x03, 0xba, 0x03, 0xc7, 0x03, 0xd3, 0x03, 0xe0, 0x03, 0xec,
00605       0x03, 0xf9, 0x04, 0x06, 0x04, 0x13, 0x04, 0x20, 0x04, 0x2d, 0x04,
00606       0x3b, 0x04, 0x48, 0x04, 0x55, 0x04, 0x63, 0x04, 0x71, 0x04, 0x7e,
00607       0x04, 0x8c, 0x04, 0x9a, 0x04, 0xa8, 0x04, 0xb6, 0x04, 0xc4, 0x04,
00608       0xd3, 0x04, 0xe1, 0x04, 0xf0, 0x04, 0xfe, 0x05, 0x0d, 0x05, 0x1c,
00609       0x05, 0x2b, 0x05, 0x3a, 0x05, 0x49, 0x05, 0x58, 0x05, 0x67, 0x05,
00610       0x77, 0x05, 0x86, 0x05, 0x96, 0x05, 0xa6, 0x05, 0xb5, 0x05, 0xc5,
00611       0x05, 0xd5, 0x05, 0xe5, 0x05, 0xf6, 0x06, 0x06, 0x06, 0x16, 0x06,
00612       0x27, 0x06, 0x37, 0x06, 0x48, 0x06, 0x59, 0x06, 0x6a, 0x06, 0x7b,
00613       0x06, 0x8c, 0x06, 0x9d, 0x06, 0xaf, 0x06, 0xc0, 0x06, 0xd1, 0x06,
00614       0xe3, 0x06, 0xf5, 0x07, 0x07, 0x07, 0x19, 0x07, 0x2b, 0x07, 0x3d,
00615       0x07, 0x4f, 0x07, 0x61, 0x07, 0x74, 0x07, 0x86, 0x07, 0x99, 0x07,
00616       0xac, 0x07, 0xbf, 0x07, 0xd2, 0x07, 0xe5, 0x07, 0xf8, 0x08, 0x0b,
00617       0x08, 0x1f, 0x08, 0x32, 0x08, 0x46, 0x08, 0x5a, 0x08, 0x6e, 0x08,
00618       0x82, 0x08, 0x96, 0x08, 0xaa, 0x08, 0xbe, 0x08, 0xd2, 0x08, 0xe7,
00619       0x08, 0xfb, 0x09, 0x10, 0x09, 0x25, 0x09, 0x3a, 0x09, 0x4f, 0x09,
00620       0x64, 0x09, 0x79, 0x09, 0x8f, 0x09, 0xa4, 0x09, 0xba, 0x09, 0xcf,
00621       0x09, 0xe5, 0x09, 0xfb, 0x0a, 0x11, 0x0a, 0x27, 0x0a, 0x3d, 0x0a,
00622       0x54, 0x0a, 0x6a, 0x0a, 0x81, 0x0a, 0x98, 0x0a, 0xae, 0x0a, 0xc5,
00623       0x0a, 0xdc, 0x0a, 0xf3, 0x0b, 0x0b, 0x0b, 0x22, 0x0b, 0x39, 0x0b,
00624       0x51, 0x0b, 0x69, 0x0b, 0x80, 0x0b, 0x98, 0x0b, 0xb0, 0x0b, 0xc8,
00625       0x0b, 0xe1, 0x0b, 0xf9, 0x0c, 0x12, 0x0c, 0x2a, 0x0c, 0x43, 0x0c,
00626       0x5c, 0x0c, 0x75, 0x0c, 0x8e, 0x0c, 0xa7, 0x0c, 0xc0, 0x0c, 0xd9,
00627       0x0c, 0xf3, 0x0d, 0x0d, 0x0d, 0x26, 0x0d, 0x40, 0x0d, 0x5a, 0x0d,
00628       0x74, 0x0d, 0x8e, 0x0d, 0xa9, 0x0d, 0xc3, 0x0d, 0xde, 0x0d, 0xf8,
00629       0x0e, 0x13, 0x0e, 0x2e, 0x0e, 0x49, 0x0e, 0x64, 0x0e, 0x7f, 0x0e,
00630       0x9b, 0x0e, 0xb6, 0x0e, 0xd2, 0x0e, 0xee, 0x0f, 0x09, 0x0f, 0x25,
00631       0x0f, 0x41, 0x0f, 0x5e, 0x0f, 0x7a, 0x0f, 0x96, 0x0f, 0xb3, 0x0f,
00632       0xcf, 0x0f, 0xec, 0x10, 0x09, 0x10, 0x26, 0x10, 0x43, 0x10, 0x61,
00633       0x10, 0x7e, 0x10, 0x9b, 0x10, 0xb9, 0x10, 0xd7, 0x10, 0xf5, 0x11,
00634       0x13, 0x11, 0x31, 0x11, 0x4f, 0x11, 0x6d, 0x11, 0x8c, 0x11, 0xaa,
00635       0x11, 0xc9, 0x11, 0xe8, 0x12, 0x07, 0x12, 0x26, 0x12, 0x45, 0x12,
00636       0x64, 0x12, 0x84, 0x12, 0xa3, 0x12, 0xc3, 0x12, 0xe3, 0x13, 0x03,
00637       0x13, 0x23, 0x13, 0x43, 0x13, 0x63, 0x13, 0x83, 0x13, 0xa4, 0x13,
00638       0xc5, 0x13, 0xe5, 0x14, 0x06, 0x14, 0x27, 0x14, 0x49, 0x14, 0x6a,
00639       0x14, 0x8b, 0x14, 0xad, 0x14, 0xce, 0x14, 0xf0, 0x15, 0x12, 0x15,
00640       0x34, 0x15, 0x56, 0x15, 0x78, 0x15, 0x9b, 0x15, 0xbd, 0x15, 0xe0,
00641       0x16, 0x03, 0x16, 0x26, 0x16, 0x49, 0x16, 0x6c, 0x16, 0x8f, 0x16,
00642       0xb2, 0x16, 0xd6, 0x16, 0xfa, 0x17, 0x1d, 0x17, 0x41, 0x17, 0x65,
00643       0x17, 0x89, 0x17, 0xae, 0x17, 0xd2, 0x17, 0xf7, 0x18, 0x1b, 0x18,
00644       0x40, 0x18, 0x65, 0x18, 0x8a, 0x18, 0xaf, 0x18, 0xd5, 0x18, 0xfa,
00645       0x19, 0x20, 0x19, 0x45, 0x19, 0x6b, 0x19, 0x91, 0x19, 0xb7, 0x19,
00646       0xdd, 0x1a, 0x04, 0x1a, 0x2a, 0x1a, 0x51, 0x1a, 0x77, 0x1a, 0x9e,
00647       0x1a, 0xc5, 0x1a, 0xec, 0x1b, 0x14, 0x1b, 0x3b, 0x1b, 0x63, 0x1b,
00648       0x8a, 0x1b, 0xb2, 0x1b, 0xda, 0x1c, 0x02, 0x1c, 0x2a, 0x1c, 0x52,
00649       0x1c, 0x7b, 0x1c, 0xa3, 0x1c, 0xcc, 0x1c, 0xf5, 0x1d, 0x1e, 0x1d,
00650       0x47, 0x1d, 0x70, 0x1d, 0x99, 0x1d, 0xc3, 0x1d, 0xec, 0x1e, 0x16,
00651       0x1e, 0x40, 0x1e, 0x6a, 0x1e, 0x94, 0x1e, 0xbe, 0x1e, 0xe9, 0x1f,
00652       0x13, 0x1f, 0x3e, 0x1f, 0x69, 0x1f, 0x94, 0x1f, 0xbf, 0x1f, 0xea,
00653       0x20, 0x15, 0x20, 0x41, 0x20, 0x6c, 0x20, 0x98, 0x20, 0xc4, 0x20,
00654       0xf0, 0x21, 0x1c, 0x21, 0x48, 0x21, 0x75, 0x21, 0xa1, 0x21, 0xce,
00655       0x21, 0xfb, 0x22, 0x27, 0x22, 0x55, 0x22, 0x82, 0x22, 0xaf, 0x22,
00656       0xdd, 0x23, 0x0a, 0x23, 0x38, 0x23, 0x66, 0x23, 0x94, 0x23, 0xc2,
00657       0x23, 0xf0, 0x24, 0x1f, 0x24, 0x4d, 0x24, 0x7c, 0x24, 0xab, 0x24,
00658       0xda, 0x25, 0x09, 0x25, 0x38, 0x25, 0x68, 0x25, 0x97, 0x25, 0xc7,
00659       0x25, 0xf7, 0x26, 0x27, 0x26, 0x57, 0x26, 0x87, 0x26, 0xb7, 0x26,
00660       0xe8, 0x27, 0x18, 0x27, 0x49, 0x27, 0x7a, 0x27, 0xab, 0x27, 0xdc,
00661       0x28, 0x0d, 0x28, 0x3f, 0x28, 0x71, 0x28, 0xa2, 0x28, 0xd4, 0x29,
00662       0x06, 0x29, 0x38, 0x29, 0x6b, 0x29, 0x9d, 0x29, 0xd0, 0x2a, 0x02,
00663       0x2a, 0x35, 0x2a, 0x68, 0x2a, 0x9b, 0x2a, 0xcf, 0x2b, 0x02, 0x2b,
00664       0x36, 0x2b, 0x69, 0x2b, 0x9d, 0x2b, 0xd1, 0x2c, 0x05, 0x2c, 0x39,
00665       0x2c, 0x6e, 0x2c, 0xa2, 0x2c, 0xd7, 0x2d, 0x0c, 0x2d, 0x41, 0x2d,
00666       0x76, 0x2d, 0xab, 0x2d, 0xe1, 0x2e, 0x16, 0x2e, 0x4c, 0x2e, 0x82,
00667       0x2e, 0xb7, 0x2e, 0xee, 0x2f, 0x24, 0x2f, 0x5a, 0x2f, 0x91, 0x2f,
00668       0xc7, 0x2f, 0xfe, 0x30, 0x35, 0x30, 0x6c, 0x30, 0xa4, 0x30, 0xdb,
00669       0x31, 0x12, 0x31, 0x4a, 0x31, 0x82, 0x31, 0xba, 0x31, 0xf2, 0x32,
00670       0x2a, 0x32, 0x63, 0x32, 0x9b, 0x32, 0xd4, 0x33, 0x0d, 0x33, 0x46,
00671       0x33, 0x7f, 0x33, 0xb8, 0x33, 0xf1, 0x34, 0x2b, 0x34, 0x65, 0x34,
00672       0x9e, 0x34, 0xd8, 0x35, 0x13, 0x35, 0x4d, 0x35, 0x87, 0x35, 0xc2,
00673       0x35, 0xfd, 0x36, 0x37, 0x36, 0x72, 0x36, 0xae, 0x36, 0xe9, 0x37,
00674       0x24, 0x37, 0x60, 0x37, 0x9c, 0x37, 0xd7, 0x38, 0x14, 0x38, 0x50,
00675       0x38, 0x8c, 0x38, 0xc8, 0x39, 0x05, 0x39, 0x42, 0x39, 0x7f, 0x39,
00676       0xbc, 0x39, 0xf9, 0x3a, 0x36, 0x3a, 0x74, 0x3a, 0xb2, 0x3a, 0xef,
00677       0x3b, 0x2d, 0x3b, 0x6b, 0x3b, 0xaa, 0x3b, 0xe8, 0x3c, 0x27, 0x3c,
00678       0x65, 0x3c, 0xa4, 0x3c, 0xe3, 0x3d, 0x22, 0x3d, 0x61, 0x3d, 0xa1,
00679       0x3d, 0xe0, 0x3e, 0x20, 0x3e, 0x60, 0x3e, 0xa0, 0x3e, 0xe0, 0x3f,
00680       0x21, 0x3f, 0x61, 0x3f, 0xa2, 0x3f, 0xe2, 0x40, 0x23, 0x40, 0x64,
00681       0x40, 0xa6, 0x40, 0xe7, 0x41, 0x29, 0x41, 0x6a, 0x41, 0xac, 0x41,
00682       0xee, 0x42, 0x30, 0x42, 0x72, 0x42, 0xb5, 0x42, 0xf7, 0x43, 0x3a,
00683       0x43, 0x7d, 0x43, 0xc0, 0x44, 0x03, 0x44, 0x47, 0x44, 0x8a, 0x44,
00684       0xce, 0x45, 0x12, 0x45, 0x55, 0x45, 0x9a, 0x45, 0xde, 0x46, 0x22,
00685       0x46, 0x67, 0x46, 0xab, 0x46, 0xf0, 0x47, 0x35, 0x47, 0x7b, 0x47,
00686       0xc0, 0x48, 0x05, 0x48, 0x4b, 0x48, 0x91, 0x48, 0xd7, 0x49, 0x1d,
00687       0x49, 0x63, 0x49, 0xa9, 0x49, 0xf0, 0x4a, 0x37, 0x4a, 0x7d, 0x4a,
00688       0xc4, 0x4b, 0x0c, 0x4b, 0x53, 0x4b, 0x9a, 0x4b, 0xe2, 0x4c, 0x2a,
00689       0x4c, 0x72, 0x4c, 0xba, 0x4d, 0x02, 0x4d, 0x4a, 0x4d, 0x93, 0x4d,
00690       0xdc, 0x4e, 0x25, 0x4e, 0x6e, 0x4e, 0xb7, 0x4f, 0x00, 0x4f, 0x49,
00691       0x4f, 0x93, 0x4f, 0xdd, 0x50, 0x27, 0x50, 0x71, 0x50, 0xbb, 0x51,
00692       0x06, 0x51, 0x50, 0x51, 0x9b, 0x51, 0xe6, 0x52, 0x31, 0x52, 0x7c,
00693       0x52, 0xc7, 0x53, 0x13, 0x53, 0x5f, 0x53, 0xaa, 0x53, 0xf6, 0x54,
00694       0x42, 0x54, 0x8f, 0x54, 0xdb, 0x55, 0x28, 0x55, 0x75, 0x55, 0xc2,
00695       0x56, 0x0f, 0x56, 0x5c, 0x56, 0xa9, 0x56, 0xf7, 0x57, 0x44, 0x57,
00696       0x92, 0x57, 0xe0, 0x58, 0x2f, 0x58, 0x7d, 0x58, 0xcb, 0x59, 0x1a,
00697       0x59, 0x69, 0x59, 0xb8, 0x5a, 0x07, 0x5a, 0x56, 0x5a, 0xa6, 0x5a,
00698       0xf5, 0x5b, 0x45, 0x5b, 0x95, 0x5b, 0xe5, 0x5c, 0x35, 0x5c, 0x86,
00699       0x5c, 0xd6, 0x5d, 0x27, 0x5d, 0x78, 0x5d, 0xc9, 0x5e, 0x1a, 0x5e,
00700       0x6c, 0x5e, 0xbd, 0x5f, 0x0f, 0x5f, 0x61, 0x5f, 0xb3, 0x60, 0x05,
00701       0x60, 0x57, 0x60, 0xaa, 0x60, 0xfc, 0x61, 0x4f, 0x61, 0xa2, 0x61,
00702       0xf5, 0x62, 0x49, 0x62, 0x9c, 0x62, 0xf0, 0x63, 0x43, 0x63, 0x97,
00703       0x63, 0xeb, 0x64, 0x40, 0x64, 0x94, 0x64, 0xe9, 0x65, 0x3d, 0x65,
00704       0x92, 0x65, 0xe7, 0x66, 0x3d, 0x66, 0x92, 0x66, 0xe8, 0x67, 0x3d,
00705       0x67, 0x93, 0x67, 0xe9, 0x68, 0x3f, 0x68, 0x96, 0x68, 0xec, 0x69,
00706       0x43, 0x69, 0x9a, 0x69, 0xf1, 0x6a, 0x48, 0x6a, 0x9f, 0x6a, 0xf7,
00707       0x6b, 0x4f, 0x6b, 0xa7, 0x6b, 0xff, 0x6c, 0x57, 0x6c, 0xaf, 0x6d,
00708       0x08, 0x6d, 0x60, 0x6d, 0xb9, 0x6e, 0x12, 0x6e, 0x6b, 0x6e, 0xc4,
00709       0x6f, 0x1e, 0x6f, 0x78, 0x6f, 0xd1, 0x70, 0x2b, 0x70, 0x86, 0x70,
00710       0xe0, 0x71, 0x3a, 0x71, 0x95, 0x71, 0xf0, 0x72, 0x4b, 0x72, 0xa6,
00711       0x73, 0x01, 0x73, 0x5d, 0x73, 0xb8, 0x74, 0x14, 0x74, 0x70, 0x74,
00712       0xcc, 0x75, 0x28, 0x75, 0x85, 0x75, 0xe1, 0x76, 0x3e, 0x76, 0x9b,
00713       0x76, 0xf8, 0x77, 0x56, 0x77, 0xb3, 0x78, 0x11, 0x78, 0x6e, 0x78,
00714       0xcc, 0x79, 0x2a, 0x79, 0x89, 0x79, 0xe7, 0x7a, 0x46, 0x7a, 0xa5,
00715       0x7b, 0x04, 0x7b, 0x63, 0x7b, 0xc2, 0x7c, 0x21, 0x7c, 0x81, 0x7c,
00716       0xe1, 0x7d, 0x41, 0x7d, 0xa1, 0x7e, 0x01, 0x7e, 0x62, 0x7e, 0xc2,
00717       0x7f, 0x23, 0x7f, 0x84, 0x7f, 0xe5, 0x80, 0x47, 0x80, 0xa8, 0x81,
00718       0x0a, 0x81, 0x6b, 0x81, 0xcd, 0x82, 0x30, 0x82, 0x92, 0x82, 0xf4,
00719       0x83, 0x57, 0x83, 0xba, 0x84, 0x1d, 0x84, 0x80, 0x84, 0xe3, 0x85,
00720       0x47, 0x85, 0xab, 0x86, 0x0e, 0x86, 0x72, 0x86, 0xd7, 0x87, 0x3b,
00721       0x87, 0x9f, 0x88, 0x04, 0x88, 0x69, 0x88, 0xce, 0x89, 0x33, 0x89,
00722       0x99, 0x89, 0xfe, 0x8a, 0x64, 0x8a, 0xca, 0x8b, 0x30, 0x8b, 0x96,
00723       0x8b, 0xfc, 0x8c, 0x63, 0x8c, 0xca, 0x8d, 0x31, 0x8d, 0x98, 0x8d,
00724       0xff, 0x8e, 0x66, 0x8e, 0xce, 0x8f, 0x36, 0x8f, 0x9e, 0x90, 0x06,
00725       0x90, 0x6e, 0x90, 0xd6, 0x91, 0x3f, 0x91, 0xa8, 0x92, 0x11, 0x92,
00726       0x7a, 0x92, 0xe3, 0x93, 0x4d, 0x93, 0xb6, 0x94, 0x20, 0x94, 0x8a,
00727       0x94, 0xf4, 0x95, 0x5f, 0x95, 0xc9, 0x96, 0x34, 0x96, 0x9f, 0x97,
00728       0x0a, 0x97, 0x75, 0x97, 0xe0, 0x98, 0x4c, 0x98, 0xb8, 0x99, 0x24,
00729       0x99, 0x90, 0x99, 0xfc, 0x9a, 0x68, 0x9a, 0xd5, 0x9b, 0x42, 0x9b,
00730       0xaf, 0x9c, 0x1c, 0x9c, 0x89, 0x9c, 0xf7, 0x9d, 0x64, 0x9d, 0xd2,
00731       0x9e, 0x40, 0x9e, 0xae, 0x9f, 0x1d, 0x9f, 0x8b, 0x9f, 0xfa, 0xa0,
00732       0x69, 0xa0, 0xd8, 0xa1, 0x47, 0xa1, 0xb6, 0xa2, 0x26, 0xa2, 0x96,
00733       0xa3, 0x06, 0xa3, 0x76, 0xa3, 0xe6, 0xa4, 0x56, 0xa4, 0xc7, 0xa5,
00734       0x38, 0xa5, 0xa9, 0xa6, 0x1a, 0xa6, 0x8b, 0xa6, 0xfd, 0xa7, 0x6e,
00735       0xa7, 0xe0, 0xa8, 0x52, 0xa8, 0xc4, 0xa9, 0x37, 0xa9, 0xa9, 0xaa,
00736       0x1c, 0xaa, 0x8f, 0xab, 0x02, 0xab, 0x75, 0xab, 0xe9, 0xac, 0x5c,
00737       0xac, 0xd0, 0xad, 0x44, 0xad, 0xb8, 0xae, 0x2d, 0xae, 0xa1, 0xaf,
00738       0x16, 0xaf, 0x8b, 0xb0, 0x00, 0xb0, 0x75, 0xb0, 0xea, 0xb1, 0x60,
00739       0xb1, 0xd6, 0xb2, 0x4b, 0xb2, 0xc2, 0xb3, 0x38, 0xb3, 0xae, 0xb4,
00740       0x25, 0xb4, 0x9c, 0xb5, 0x13, 0xb5, 0x8a, 0xb6, 0x01, 0xb6, 0x79,
00741       0xb6, 0xf0, 0xb7, 0x68, 0xb7, 0xe0, 0xb8, 0x59, 0xb8, 0xd1, 0xb9,
00742       0x4a, 0xb9, 0xc2, 0xba, 0x3b, 0xba, 0xb5, 0xbb, 0x2e, 0xbb, 0xa7,
00743       0xbc, 0x21, 0xbc, 0x9b, 0xbd, 0x15, 0xbd, 0x8f, 0xbe, 0x0a, 0xbe,
00744       0x84, 0xbe, 0xff, 0xbf, 0x7a, 0xbf, 0xf5, 0xc0, 0x70, 0xc0, 0xec,
00745       0xc1, 0x67, 0xc1, 0xe3, 0xc2, 0x5f, 0xc2, 0xdb, 0xc3, 0x58, 0xc3,
00746       0xd4, 0xc4, 0x51, 0xc4, 0xce, 0xc5, 0x4b, 0xc5, 0xc8, 0xc6, 0x46,
00747       0xc6, 0xc3, 0xc7, 0x41, 0xc7, 0xbf, 0xc8, 0x3d, 0xc8, 0xbc, 0xc9,
00748       0x3a, 0xc9, 0xb9, 0xca, 0x38, 0xca, 0xb7, 0xcb, 0x36, 0xcb, 0xb6,
00749       0xcc, 0x35, 0xcc, 0xb5, 0xcd, 0x35, 0xcd, 0xb5, 0xce, 0x36, 0xce,
00750       0xb6, 0xcf, 0x37, 0xcf, 0xb8, 0xd0, 0x39, 0xd0, 0xba, 0xd1, 0x3c,
00751       0xd1, 0xbe, 0xd2, 0x3f, 0xd2, 0xc1, 0xd3, 0x44, 0xd3, 0xc6, 0xd4,
00752       0x49, 0xd4, 0xcb, 0xd5, 0x4e, 0xd5, 0xd1, 0xd6, 0x55, 0xd6, 0xd8,
00753       0xd7, 0x5c, 0xd7, 0xe0, 0xd8, 0x64, 0xd8, 0xe8, 0xd9, 0x6c, 0xd9,
00754       0xf1, 0xda, 0x76, 0xda, 0xfb, 0xdb, 0x80, 0xdc, 0x05, 0xdc, 0x8a,
00755       0xdd, 0x10, 0xdd, 0x96, 0xde, 0x1c, 0xde, 0xa2, 0xdf, 0x29, 0xdf,
00756       0xaf, 0xe0, 0x36, 0xe0, 0xbd, 0xe1, 0x44, 0xe1, 0xcc, 0xe2, 0x53,
00757       0xe2, 0xdb, 0xe3, 0x63, 0xe3, 0xeb, 0xe4, 0x73, 0xe4, 0xfc, 0xe5,
00758       0x84, 0xe6, 0x0d, 0xe6, 0x96, 0xe7, 0x1f, 0xe7, 0xa9, 0xe8, 0x32,
00759       0xe8, 0xbc, 0xe9, 0x46, 0xe9, 0xd0, 0xea, 0x5b, 0xea, 0xe5, 0xeb,
00760       0x70, 0xeb, 0xfb, 0xec, 0x86, 0xed, 0x11, 0xed, 0x9c, 0xee, 0x28,
00761       0xee, 0xb4, 0xef, 0x40, 0xef, 0xcc, 0xf0, 0x58, 0xf0, 0xe5, 0xf1,
00762       0x72, 0xf1, 0xff, 0xf2, 0x8c, 0xf3, 0x19, 0xf3, 0xa7, 0xf4, 0x34,
00763       0xf4, 0xc2, 0xf5, 0x50, 0xf5, 0xde, 0xf6, 0x6d, 0xf6, 0xfb, 0xf7,
00764       0x8a, 0xf8, 0x19, 0xf8, 0xa8, 0xf9, 0x38, 0xf9, 0xc7, 0xfa, 0x57,
00765       0xfa, 0xe7, 0xfb, 0x77, 0xfc, 0x07, 0xfc, 0x98, 0xfd, 0x29, 0xfd,
00766       0xba, 0xfe, 0x4b, 0xfe, 0xdc, 0xff, 0x6d, 0xff, 0xff
00767     };
00768 
00769   StringInfo
00770     *profile;
00771 
00772   MagickBooleanType
00773     status;
00774 
00775   assert(image != (Image *) NULL);
00776   assert(image->signature == MagickSignature);
00777   if (GetImageProfile(image,"icm") != (const StringInfo *) NULL)
00778     return(MagickFalse);
00779   profile=AcquireStringInfo(sizeof(sRGBProfile));
00780   SetStringInfoDatum(profile,sRGBProfile);
00781   status=SetImageProfile(image,"icm",profile);
00782   profile=DestroyStringInfo(profile);
00783   return(status);
00784 }
00785 #if defined(MAGICKCORE_LCMS_DELEGATE)
00786 #if defined(LCMS_VERSION) && (LCMS_VERSION > 1010)
00787 static int LCMSErrorHandler(int severity,const char *message)
00788 {
00789   (void) LogMagickEvent(TransformEvent,GetMagickModule(),"lcms: #%d, %s",
00790     severity,message != (char *) NULL ? message : "no message");
00791   return(1);
00792 }
00793 #endif
00794 #endif
00795 
00796 MagickExport MagickBooleanType ProfileImage(Image *image,const char *name,
00797   const void *datum,const size_t length,
00798   const MagickBooleanType magick_unused(clone))
00799 {
00800 #define ProfileImageTag  "Profile/Image"
00801 #define ThrowProfileException(severity,tag,context) \
00802 { \
00803   (void) cmsCloseProfile(source_profile); \
00804   (void) cmsCloseProfile(target_profile); \
00805   ThrowBinaryException(severity,tag,context); \
00806 }
00807 
00808   MagickBooleanType
00809     status;
00810 
00811   StringInfo
00812     *profile;
00813 
00814   assert(image != (Image *) NULL);
00815   assert(image->signature == MagickSignature);
00816   if (image->debug != MagickFalse)
00817     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00818   assert(name != (const char *) NULL);
00819   if ((datum == (const void *) NULL) || (length == 0))
00820     {
00821       char
00822         **arguments,
00823         *names;
00824 
00825       int
00826         number_arguments;
00827 
00828       register long
00829         i;
00830 
00831       /*
00832         Delete image profile(s).
00833       */
00834       names=ConstantString(name);
00835       (void) SubstituteString(&names,","," ");
00836       arguments=StringToArgv(names,&number_arguments);
00837       names=DestroyString(names);
00838       if (arguments == (char **) NULL)
00839         return(MagickTrue);
00840       ResetImageProfileIterator(image);
00841       for (name=GetNextImageProfile(image); name != (const char *) NULL; )
00842       {
00843         for (i=1; i < number_arguments; i++)
00844         {
00845           if ((*arguments[i] == '!') &&
00846               (LocaleCompare(name,arguments[i]+1) == 0))
00847             break;
00848           if (GlobExpression(name,arguments[i],MagickTrue) != MagickFalse)
00849             {
00850               (void) DeleteImageProfile(image,name);
00851               ResetImageProfileIterator(image);
00852               break;
00853             }
00854         }
00855         name=GetNextImageProfile(image);
00856       }
00857       for (i=0; i < number_arguments; i++)
00858         arguments[i]=DestroyString(arguments[i]);
00859       arguments=(char **) RelinquishMagickMemory(arguments);
00860       return(MagickTrue);
00861     }
00862   /*
00863     Add a ICC, IPTC, or generic profile to the image.
00864   */
00865   profile=AcquireStringInfo((size_t) length);
00866   SetStringInfoDatum(profile,(unsigned char *) datum);
00867   if ((LocaleCompare(name,"icc") == 0) || (LocaleCompare(name,"icm") == 0))
00868     {
00869       const StringInfo
00870         *icc_profile;
00871 
00872       icc_profile=GetImageProfile(image,"icc");
00873       if ((icc_profile != (const StringInfo *) NULL) &&
00874           (CompareStringInfo(icc_profile,profile) == 0))
00875         {
00876           const char
00877             *value;
00878 
00879           value=GetImageProperty(image,"exif:ColorSpace");
00880           if (LocaleCompare(value,"1") != 0)
00881             (void) SetsRGBImageProfile(image);
00882           value=GetImageProperty(image,"exif:InteroperabilityIndex");
00883           if (LocaleCompare(value,"R98.") != 0)
00884             (void) SetsRGBImageProfile(image);
00885           value=GetImageProperty(image,"exif:InteroperabilityIndex");
00886           if (LocaleCompare(value,"R03.") != 0)
00887             (void) SetAdobeRGB1998ImageProfile(image);
00888           icc_profile=GetImageProfile(image,"icc");
00889         }
00890       if ((icc_profile != (const StringInfo *) NULL) &&
00891           (CompareStringInfo(icc_profile,profile) == 0))
00892         {
00893           profile=DestroyStringInfo(profile);
00894           return(MagickTrue);
00895         }
00896 #if !defined(MAGICKCORE_LCMS_DELEGATE)
00897       (void) ThrowMagickException(&image->exception,GetMagickModule(),
00898         MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (LCMS)",
00899         image->filename);
00900 #else
00901       if (icc_profile != (StringInfo *) NULL)
00902         {
00903           CacheView
00904             *image_view;
00905 
00906           ColorspaceType
00907             source_colorspace,
00908             target_colorspace;
00909 
00910           cmsHPROFILE
00911             source_profile,
00912             target_profile;
00913 
00914           cmsHTRANSFORM
00915             *transform;
00916 
00917           DWORD
00918             flags,
00919             source_type,
00920             target_type;
00921 
00922           ExceptionInfo
00923             *exception;
00924 
00925           int
00926             intent;
00927 
00928           long
00929             progress,
00930             y;
00931 
00932           MagickBooleanType
00933             status;
00934 
00935           size_t
00936             length,
00937             source_channels,
00938             target_channels;
00939 
00940           unsigned short
00941             **source_pixels,
00942             **target_pixels;
00943 
00944           /*
00945             Transform pixel colors as defined by the color profiles.
00946           */
00947 #if defined(LCMS_VERSION) && (LCMS_VERSION > 1010)
00948           cmsSetErrorHandler(LCMSErrorHandler);
00949 #else
00950           (void) cmsErrorAction(LCMS_ERROR_SHOW);
00951 #endif
00952           source_profile=cmsOpenProfileFromMem(GetStringInfoDatum(icc_profile),
00953             (DWORD) GetStringInfoLength(icc_profile));
00954           target_profile=cmsOpenProfileFromMem(GetStringInfoDatum(profile),
00955             (DWORD) GetStringInfoLength(profile));
00956           if ((source_profile == (cmsHPROFILE) NULL) ||
00957               (target_profile == (cmsHPROFILE) NULL))
00958             ThrowBinaryException(ResourceLimitError,
00959               "ColorspaceColorProfileMismatch",name);
00960           switch (cmsGetColorSpace(source_profile))
00961           {
00962             case icSigCmykData:
00963             {
00964               source_colorspace=CMYKColorspace;
00965               source_type=(DWORD) TYPE_CMYK_16;
00966               source_channels=4;
00967               break;
00968             }
00969             case icSigGrayData:
00970             {
00971               source_colorspace=GRAYColorspace;
00972               source_type=(DWORD) TYPE_GRAY_16;
00973               source_channels=1;
00974               break;
00975             }
00976             case icSigLabData:
00977             {
00978               source_colorspace=LabColorspace;
00979               source_type=(DWORD) TYPE_Lab_16;
00980               source_channels=3;
00981               break;
00982             }
00983             case icSigLuvData:
00984             {
00985               source_colorspace=YUVColorspace;
00986               source_type=(DWORD) TYPE_YUV_16;
00987               source_channels=3;
00988               break;
00989             }
00990             case icSigRgbData:
00991             {
00992               source_colorspace=RGBColorspace;
00993               source_type=(DWORD) TYPE_RGB_16;
00994               source_channels=3;
00995               break;
00996             }
00997             case icSigXYZData:
00998             {
00999               source_colorspace=XYZColorspace;
01000               source_type=(DWORD) TYPE_XYZ_16;
01001               source_channels=3;
01002               break;
01003             }
01004             case icSigYCbCrData:
01005             {
01006               source_colorspace=YCbCrColorspace;
01007               source_type=(DWORD) TYPE_YCbCr_16;
01008               source_channels=3;
01009               break;
01010             }
01011             default:
01012             {
01013               source_colorspace=UndefinedColorspace;
01014               source_type=(DWORD) TYPE_RGB_16;
01015               source_channels=3;
01016               break;
01017             }
01018           }
01019           switch (cmsGetColorSpace(target_profile))
01020           {
01021             case icSigCmykData:
01022             {
01023               target_colorspace=CMYKColorspace;
01024               target_type=(DWORD) TYPE_CMYK_16;
01025               target_channels=4;
01026               break;
01027             }
01028             case icSigLabData:
01029             {
01030               target_colorspace=LabColorspace;
01031               target_type=(DWORD) TYPE_Lab_16;
01032               target_channels=3;
01033               break;
01034             }
01035             case icSigGrayData:
01036             {
01037               target_colorspace=GRAYColorspace;
01038               target_type=(DWORD) TYPE_GRAY_16;
01039               target_channels=1;
01040               break;
01041             }
01042             case icSigLuvData:
01043             {
01044               target_colorspace=YUVColorspace;
01045               target_type=(DWORD) TYPE_YUV_16;
01046               target_channels=3;
01047               break;
01048             }
01049             case icSigRgbData:
01050             {
01051               target_colorspace=RGBColorspace;
01052               target_type=(DWORD) TYPE_RGB_16;
01053               target_channels=3;
01054               break;
01055             }
01056             case icSigXYZData:
01057             {
01058               target_colorspace=XYZColorspace;
01059               target_type=(DWORD) TYPE_XYZ_16;
01060               target_channels=3;
01061               break;
01062             }
01063             case icSigYCbCrData:
01064             {
01065               target_colorspace=YCbCrColorspace;
01066               target_type=(DWORD) TYPE_YCbCr_16;
01067               target_channels=3;
01068               break;
01069             }
01070             default:
01071             {
01072               target_colorspace=UndefinedColorspace;
01073               target_type=(DWORD) TYPE_RGB_16;
01074               target_channels=3;
01075               break;
01076             }
01077           }
01078           exception=(&image->exception);
01079           if ((source_colorspace == UndefinedColorspace) ||
01080               (target_colorspace == UndefinedColorspace))
01081             ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
01082               name);
01083            if ((source_colorspace == GRAYColorspace) &&
01084                (IsGrayImage(image,exception) == MagickFalse))
01085             ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
01086               name);
01087            if ((source_colorspace == CMYKColorspace) &&
01088                (image->colorspace != CMYKColorspace))
01089             ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
01090               name);
01091            if ((source_colorspace == XYZColorspace) &&
01092                (image->colorspace != XYZColorspace))
01093             ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
01094               name);
01095            if ((source_colorspace == YCbCrColorspace) &&
01096                (image->colorspace != YCbCrColorspace))
01097             ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
01098               name);
01099            if ((source_colorspace != CMYKColorspace) &&
01100                (source_colorspace != GRAYColorspace) &&
01101                (source_colorspace != LabColorspace) &&
01102                (source_colorspace != XYZColorspace) &&
01103                (source_colorspace != YCbCrColorspace) &&
01104                (image->colorspace != RGBColorspace))
01105             ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
01106               name);
01107           switch (image->rendering_intent)
01108           {
01109             case AbsoluteIntent: intent=INTENT_ABSOLUTE_COLORIMETRIC; break;
01110             case PerceptualIntent: intent=INTENT_PERCEPTUAL; break;
01111             case RelativeIntent: intent=INTENT_RELATIVE_COLORIMETRIC; break;
01112             case SaturationIntent: intent=INTENT_SATURATION; break;
01113             default: intent=INTENT_PERCEPTUAL; break;
01114           }
01115           flags=cmsFLAGS_HIGHRESPRECALC;
01116 #if defined(cmsFLAGS_BLACKPOINTCOMPENSATION)
01117           if (image->black_point_compensation != MagickFalse)
01118             flags|=cmsFLAGS_BLACKPOINTCOMPENSATION;
01119 #endif
01120           transform=AcquireTransformThreadSet(source_profile,source_type,
01121             target_profile,target_type,intent,flags);
01122           (void) cmsCloseProfile(source_profile);
01123           if (transform == (cmsHTRANSFORM *) NULL)
01124             ThrowBinaryException(ImageError,"UnableToCreateColorTransform",
01125               name);
01126           /*
01127             Transform image as dictated by the source and target image profiles.
01128           */
01129           length=(size_t) image->columns;
01130           source_pixels=AcquirePixelThreadSet(image->columns,source_channels);
01131           target_pixels=AcquirePixelThreadSet(image->columns,target_channels);
01132           if ((source_pixels == (unsigned short **) NULL) ||
01133               (target_pixels == (unsigned short **) NULL))
01134             {
01135               transform=DestroyTransformThreadSet(transform);
01136               (void) cmsCloseProfile(target_profile);
01137               ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
01138                 image->filename);
01139             }
01140           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
01141             {
01142               target_pixels=DestroyPixelThreadSet(target_pixels);
01143               source_pixels=DestroyPixelThreadSet(source_pixels);
01144               transform=DestroyTransformThreadSet(transform);
01145               (void) cmsCloseProfile(target_profile);
01146               return(MagickFalse);
01147             }
01148           if (target_colorspace == CMYKColorspace)
01149             (void) SetImageColorspace(image,target_colorspace);
01150           status=MagickTrue;
01151           progress=0;
01152           image_view=AcquireCacheView(image);
01153 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01154           #pragma omp parallel for schedule(dynamic,4) shared(status)
01155 #endif
01156           for (y=0; y < (long) image->rows; y++)
01157           {
01158             MagickBooleanType
01159               sync;
01160 
01161             register IndexPacket
01162               *__restrict indexes;
01163 
01164             register long
01165               id,
01166               x;
01167 
01168             register PixelPacket
01169               *__restrict q;
01170 
01171             register unsigned short
01172               *p;
01173 
01174             if (status == MagickFalse)
01175               continue;
01176             q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
01177               exception);
01178             if (q == (PixelPacket *) NULL)
01179               {
01180                 status=MagickFalse;
01181                 continue;
01182               }
01183             indexes=GetCacheViewAuthenticIndexQueue(image_view);
01184             id=GetOpenMPThreadId();
01185             p=source_pixels[id];
01186             for (x=0; x < (long) image->columns; x++)
01187             {
01188               *p++=ScaleQuantumToShort(q->red);
01189               if (source_channels > 1)
01190                 {
01191                   *p++=ScaleQuantumToShort(q->green);
01192                   *p++=ScaleQuantumToShort(q->blue);
01193                 }
01194               if (source_channels > 3)
01195                 *p++=ScaleQuantumToShort(indexes[x]);
01196               q++;
01197             }
01198             cmsDoTransform(transform[id],source_pixels[id],target_pixels[id],
01199               (unsigned int) image->columns);
01200             p=target_pixels[id];
01201             q-=image->columns;
01202             for (x=0; x < (long) image->columns; x++)
01203             {
01204               q->red=ScaleShortToQuantum(*p);
01205               q->green=q->red;
01206               q->blue=q->red;
01207               p++;
01208               if (target_channels > 1)
01209                 {
01210                   q->green=ScaleShortToQuantum(*p);
01211                   p++;
01212                   q->blue=ScaleShortToQuantum(*p);
01213                   p++;
01214                 }
01215               if (target_channels > 3)
01216                 {
01217                   indexes[x]=ScaleShortToQuantum(*p);
01218                   p++;
01219                 }
01220               q++;
01221             }
01222             sync=SyncCacheViewAuthenticPixels(image_view,exception);
01223             if (sync == MagickFalse)
01224               status=MagickFalse;
01225             if (image->progress_monitor != (MagickProgressMonitor) NULL)
01226               {
01227                 MagickBooleanType
01228                   proceed;
01229 
01230 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01231   #pragma omp critical (MagickCore_ProfileImage)
01232 #endif
01233                 proceed=SetImageProgress(image,ProfileImageTag,progress++,
01234                   image->rows);
01235                 if (proceed == MagickFalse)
01236                   status=MagickFalse;
01237               }
01238           }
01239           image_view=DestroyCacheView(image_view);
01240           (void) SetImageColorspace(image,target_colorspace);
01241           switch (cmsGetColorSpace(target_profile))
01242           {
01243             case icSigRgbData:
01244             {
01245               image->type=image->matte == MagickFalse ? TrueColorType :
01246                 TrueColorMatteType;
01247               break;
01248             }
01249             case icSigCmykData:
01250             {
01251               image->type=image->matte == MagickFalse ? ColorSeparationType :
01252                 ColorSeparationMatteType;
01253               break;
01254             }
01255             case icSigGrayData:
01256             {
01257               image->type=image->matte == MagickFalse ? GrayscaleType :
01258                 GrayscaleMatteType;
01259               break;
01260             }
01261             default:
01262               break;
01263           }
01264           target_pixels=DestroyPixelThreadSet(target_pixels);
01265           source_pixels=DestroyPixelThreadSet(source_pixels);
01266           transform=DestroyTransformThreadSet(transform);
01267           (void) cmsCloseProfile(target_profile);
01268         }
01269 #endif
01270     }
01271   status=SetImageProfile(image,name,profile);
01272   profile=DestroyStringInfo(profile);
01273   return(status);
01274 }
01275 
01276 /*
01277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01278 %                                                                             %
01279 %                                                                             %
01280 %                                                                             %
01281 %   R e m o v e I m a g e P r o f i l e                                       %
01282 %                                                                             %
01283 %                                                                             %
01284 %                                                                             %
01285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01286 %
01287 %  RemoveImageProfile() removes a named profile from the image and returns its
01288 %  value.
01289 %
01290 %  The format of the RemoveImageProfile method is:
01291 %
01292 %      void *RemoveImageProfile(Image *image,const char *name)
01293 %
01294 %  A description of each parameter follows:
01295 %
01296 %    o image: the image.
01297 %
01298 %    o name: the profile name.
01299 %
01300 */
01301 MagickExport StringInfo *RemoveImageProfile(Image *image,const char *name)
01302 {
01303   StringInfo
01304     *profile;
01305 
01306   assert(image != (Image *) NULL);
01307   assert(image->signature == MagickSignature);
01308   if (image->debug != MagickFalse)
01309     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01310   if (image->profiles == (SplayTreeInfo *) NULL)
01311     return((StringInfo *) NULL);
01312   if (LocaleCompare(name,"icc") == 0)
01313     {
01314       /*
01315         Continue to support deprecated color profile for now.
01316       */
01317       image->color_profile.length=0;
01318       image->color_profile.info=(unsigned char *) NULL;
01319     }
01320   if (LocaleCompare(name,"iptc") == 0)
01321     {
01322       /*
01323         Continue to support deprecated IPTC profile for now.
01324       */
01325       image->iptc_profile.length=0;
01326       image->iptc_profile.info=(unsigned char *) NULL;
01327     }
01328   profile=(StringInfo *) RemoveNodeFromSplayTree((SplayTreeInfo *)
01329     image->profiles,name);
01330   return(profile);
01331 }
01332 
01333 /*
01334 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01335 %                                                                             %
01336 %                                                                             %
01337 %                                                                             %
01338 %   R e s e t P r o f i l e I t e r a t o r                                   %
01339 %                                                                             %
01340 %                                                                             %
01341 %                                                                             %
01342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01343 %
01344 %  ResetImageProfileIterator() resets the image profile iterator.  Use it in
01345 %  conjunction with GetNextImageProfile() to iterate over all the profiles
01346 %  associated with an image.
01347 %
01348 %  The format of the ResetImageProfileIterator method is:
01349 %
01350 %      ResetImageProfileIterator(Image *image)
01351 %
01352 %  A description of each parameter follows:
01353 %
01354 %    o image: the image.
01355 %
01356 */
01357 MagickExport void ResetImageProfileIterator(const Image *image)
01358 {
01359   assert(image != (Image *) NULL);
01360   assert(image->signature == MagickSignature);
01361   if (image->debug != MagickFalse)
01362     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01363   if (image->profiles == (SplayTreeInfo *) NULL)
01364     return;
01365   ResetSplayTreeIterator((SplayTreeInfo *) image->profiles);
01366 }
01367 
01368 /*
01369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01370 %                                                                             %
01371 %                                                                             %
01372 %                                                                             %
01373 %   S e t I m a g e P r o f i l e                                             %
01374 %                                                                             %
01375 %                                                                             %
01376 %                                                                             %
01377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01378 %
01379 %  SetImageProfile() adds a named profile to the image.  If a profile with the
01380 %  same name already exists, it is replaced.  This method differs from the
01381 %  ProfileImage() method in that it does not apply CMS color profiles.
01382 %
01383 %  The format of the SetImageProfile method is:
01384 %
01385 %      MagickBooleanType SetImageProfile(Image *image,const char *name,
01386 %        const StringInfo *profile)
01387 %
01388 %  A description of each parameter follows:
01389 %
01390 %    o image: the image.
01391 %
01392 %    o name: the profile name, for example icc, exif, and 8bim (8bim is the
01393 %      Photoshop wrapper for iptc profiles).
01394 %
01395 %    o profile: A StringInfo structure that contains the named profile.
01396 %
01397 */
01398 
01399 static void *DestroyProfile(void *profile)
01400 {
01401   return((void *) DestroyStringInfo((StringInfo *) profile));
01402 }
01403 
01404 static inline const unsigned char *ReadResourceByte(const unsigned char *p,
01405   unsigned char *quantum)
01406 {
01407   *quantum=(*p++);
01408   return(p);
01409 }
01410 
01411 static inline const unsigned char *ReadResourceBytes(const unsigned char *p,
01412   const ssize_t count,unsigned char *quantum)
01413 {
01414   register ssize_t
01415     i;
01416 
01417   for (i=0; i < count; i++)
01418     *quantum++=(*p++);
01419   return(p);
01420 }
01421 
01422 static inline const unsigned char *ReadResourceLong(const unsigned char *p,
01423   unsigned long *quantum)
01424 {
01425   *quantum=(unsigned long) (*p++ << 24);
01426   *quantum|=(unsigned long) (*p++ << 16);
01427   *quantum|=(unsigned long) (*p++ << 8);
01428   *quantum|=(unsigned long) (*p++ << 0);
01429   return(p);
01430 }
01431 
01432 static inline const unsigned char *ReadResourceShort(const unsigned char *p,
01433   unsigned short *quantum)
01434 {
01435   *quantum=(unsigned short) (*p++ << 8);
01436   *quantum|=(unsigned short) (*p++ << 0);
01437   return(p);
01438 }
01439 
01440 static MagickBooleanType GetProfilesFromResourceBlock(Image *image,
01441   const StringInfo *resource_block)
01442 {
01443   const unsigned char
01444     *datum;
01445 
01446   register const unsigned char
01447     *p;
01448 
01449   size_t
01450     length;
01451 
01452   StringInfo
01453     *profile;
01454 
01455   unsigned char
01456     length_byte;
01457 
01458   unsigned long
01459     count;
01460 
01461   unsigned short
01462     id;
01463 
01464   datum=GetStringInfoDatum(resource_block);
01465   length=GetStringInfoLength(resource_block);
01466   for (p=datum; p < (datum+length-16); )
01467   {
01468     if (LocaleNCompare((char *) p,"8BIM",4) != 0)
01469       break;
01470     p+=4;
01471     p=ReadResourceShort(p,&id);
01472     p=ReadResourceByte(p,&length_byte);
01473     p+=length_byte;
01474     if (((length_byte+1) & 0x01) != 0)
01475       p++;
01476     if (p > (datum+length-4))
01477       break;
01478     p=ReadResourceLong(p,&count);
01479     if ((p > (datum+length-count)) || (count > length))
01480       break;
01481     switch (id)
01482     {
01483       case 0x03ed:
01484       {
01485         unsigned short
01486           resolution;
01487 
01488         /*
01489           Resolution.
01490         */
01491         p=ReadResourceShort(p,&resolution)+6;
01492         image->x_resolution=(double) resolution;
01493         p=ReadResourceShort(p,&resolution)+6;
01494         image->y_resolution=(double) resolution;
01495         break;
01496       }
01497       case 0x0404:
01498       {
01499         /*
01500           IPTC Profile
01501         */
01502         profile=AcquireStringInfo(count);
01503         SetStringInfoDatum(profile,p);
01504         (void) SetImageProfile(image,"iptc",profile);
01505         profile=DestroyStringInfo(profile);
01506         p+=count;
01507         break;
01508       }
01509       case 0x040c:
01510       {
01511         /*
01512           Thumbnail.
01513         */
01514         p+=count;
01515         break;
01516       }
01517       case 0x040f:
01518       {
01519         /*
01520           ICC Profile.
01521         */
01522         profile=AcquireStringInfo(count);
01523         SetStringInfoDatum(profile,p);
01524         (void) SetImageProfile(image,"icc",profile);
01525         profile=DestroyStringInfo(profile);
01526         p+=count;
01527         break;
01528       }
01529       case 0x0422:
01530       {
01531         /*
01532           EXIF Profile.
01533         */
01534         profile=AcquireStringInfo(count);
01535         SetStringInfoDatum(profile,p);
01536         (void) SetImageProfile(image,"exif",profile);
01537         profile=DestroyStringInfo(profile);
01538         p+=count;
01539         break;
01540       }
01541       case 0x0424:
01542       {
01543         /*
01544           XMP Profile.
01545         */
01546         profile=AcquireStringInfo(count);
01547         SetStringInfoDatum(profile,p);
01548         (void) SetImageProfile(image,"xmp",profile);
01549         profile=DestroyStringInfo(profile);
01550         p+=count;
01551         break;
01552       }
01553       default:
01554       {
01555         p+=count;
01556         break;
01557       }
01558     }
01559     if ((count & 0x01) != 0)
01560       p++;
01561   }
01562   return(MagickTrue);
01563 }
01564 
01565 MagickExport MagickBooleanType SetImageProfile(Image *image,const char *name,
01566   const StringInfo *profile)
01567 {
01568   char
01569     key[MaxTextExtent],
01570     property[MaxTextExtent];
01571 
01572   MagickBooleanType
01573     status;
01574 
01575   assert(image != (Image *) NULL);
01576   assert(image->signature == MagickSignature);
01577   if (image->debug != MagickFalse)
01578     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01579   if (image->profiles == (SplayTreeInfo *) NULL)
01580     image->profiles=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
01581       DestroyProfile);
01582   (void) CopyMagickString(key,name,MaxTextExtent);
01583   status=AddValueToSplayTree((SplayTreeInfo *) image->profiles,
01584     ConstantString(key),CloneStringInfo(profile));
01585   if ((status != MagickFalse) &&
01586       ((LocaleCompare(name,"icc") == 0) || (LocaleCompare(name,"icm") == 0)))
01587     {
01588       const StringInfo
01589         *icc_profile;
01590 
01591       /*
01592         Continue to support deprecated color profile member.
01593       */
01594       icc_profile=GetImageProfile(image,name);
01595       if (icc_profile != (const StringInfo *) NULL)
01596         {
01597           image->color_profile.length=GetStringInfoLength(icc_profile);
01598           image->color_profile.info=GetStringInfoDatum(icc_profile);
01599         }
01600     }
01601   if ((status != MagickFalse) &&
01602       ((LocaleCompare(name,"iptc") == 0) || (LocaleCompare(name,"8bim") == 0)))
01603     {
01604       const StringInfo
01605         *iptc_profile;
01606 
01607       /*
01608         Continue to support deprecated IPTC profile member.
01609       */
01610       iptc_profile=GetImageProfile(image,name);
01611       if (iptc_profile != (const StringInfo *) NULL)
01612         {
01613           image->iptc_profile.length=GetStringInfoLength(iptc_profile);
01614           image->iptc_profile.info=GetStringInfoDatum(iptc_profile);
01615         }
01616       (void) GetProfilesFromResourceBlock(image,profile);
01617     }
01618   /*
01619     Inject profile into image properties.
01620   */
01621   (void) FormatMagickString(property,MaxTextExtent,"%s:sans",name);
01622   (void) GetImageProperty(image,property);
01623   return(status);
01624 }
01625 
01626 /*
01627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01628 %                                                                             %
01629 %                                                                             %
01630 %                                                                             %
01631 %   S y n c I m a g e P r o f i l e s                                         %
01632 %                                                                             %
01633 %                                                                             %
01634 %                                                                             %
01635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01636 %
01637 %  SyncImageProfiles() synchronizes image properties with the image profiles.
01638 %  Currently we only support updating the EXIF resolution and orientation.
01639 %
01640 %  The format of the SyncImageProfiles method is:
01641 %
01642 %      MagickBooleanType SyncImageProfiles(Image *image)
01643 %
01644 %  A description of each parameter follows:
01645 %
01646 %    o image: the image.
01647 %
01648 */
01649 
01650 static inline int ReadProfileByte(unsigned char **p,size_t *length)
01651 {
01652   int
01653     c;
01654 
01655   if (*length < 1)
01656     return(EOF);
01657   c=(int) (*(*p)++);
01658   (*length)--;
01659   return(c);
01660 }
01661 
01662 static inline unsigned short ReadProfileShort(const EndianType endian,
01663   unsigned char *buffer)
01664 {
01665   unsigned short
01666     value;
01667 
01668   if (endian == MSBEndian)
01669     {
01670       value=(unsigned short) ((((unsigned char *) buffer)[0] << 8) |
01671         ((unsigned char *) buffer)[1]);
01672       return((unsigned short) (value & 0xffff));
01673     }
01674   value=(unsigned short) ((buffer[1] << 8) | buffer[0]);
01675   return((unsigned short) (value & 0xffff));
01676 }
01677 
01678 static inline unsigned long ReadProfileLong(const EndianType endian,
01679   unsigned char *buffer)
01680 {
01681   unsigned long
01682     value;
01683 
01684   if (endian == MSBEndian)
01685     {
01686       value=(unsigned long) ((buffer[0] << 24) | (buffer[1] << 16) |
01687         (buffer[2] << 8) | buffer[3]);
01688       return((unsigned long) (value & 0xffffffff));
01689     }
01690   value=(unsigned long) ((buffer[3] << 24) | (buffer[2] << 16) |
01691     (buffer[1] << 8 ) | (buffer[0]));
01692   return((unsigned long) (value & 0xffffffff));
01693 }
01694 
01695 static inline void WriteProfileLong(const EndianType endian,
01696   const unsigned long value,unsigned char *p)
01697 {
01698   unsigned char
01699     buffer[4];
01700 
01701   if (endian == MSBEndian)
01702     {
01703       buffer[0]=(unsigned char) (value >> 24);
01704       buffer[1]=(unsigned char) (value >> 16);
01705       buffer[2]=(unsigned char) (value >> 8);
01706       buffer[3]=(unsigned char) value;
01707       (void) CopyMagickMemory(p,buffer,4);
01708       return;
01709     }
01710   buffer[0]=(unsigned char) value;
01711   buffer[1]=(unsigned char) (value >> 8);
01712   buffer[2]=(unsigned char) (value >> 16);
01713   buffer[3]=(unsigned char) (value >> 24);
01714   (void) CopyMagickMemory(p,buffer,4);
01715 }
01716 
01717 static void WriteProfileShort(const EndianType endian,
01718   const unsigned short value,unsigned char *p)
01719 {
01720   unsigned char
01721     buffer[2];
01722 
01723   if (endian == MSBEndian)
01724     {
01725       buffer[0]=(unsigned char) (value >> 8);
01726       buffer[1]=(unsigned char) value;
01727       (void) CopyMagickMemory(p,buffer,2);
01728       return;
01729     }
01730   buffer[0]=(unsigned char) value;
01731   buffer[1]=(unsigned char) (value >> 8);
01732   (void) CopyMagickMemory(p,buffer,2);
01733 }
01734 
01735 MagickExport MagickBooleanType SyncImageProfiles(Image *image)
01736 {
01737 #define MaxDirectoryStack  16
01738 #define EXIF_DELIMITER  "\n"
01739 #define EXIF_NUM_FORMATS  12
01740 #define TAG_EXIF_OFFSET  0x8769
01741 #define TAG_INTEROP_OFFSET  0xa005
01742 
01743   typedef struct _DirectoryInfo
01744   {
01745     unsigned char
01746       *directory;
01747 
01748     unsigned long
01749       entry;
01750   } DirectoryInfo;
01751 
01752   DirectoryInfo
01753     directory_stack[MaxDirectoryStack];
01754 
01755   EndianType
01756     endian;
01757 
01758   long
01759     id,
01760     level;
01761 
01762   size_t
01763     length;
01764 
01765   ssize_t
01766     offset;
01767 
01768   static int
01769     format_bytes[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
01770 
01771   StringInfo
01772     *profile;
01773 
01774   unsigned char
01775     *directory,
01776     *exif;
01777 
01778   unsigned long
01779     entry,
01780     number_entries;
01781 
01782   /*
01783     Set EXIF resolution tag.
01784   */
01785   profile=(StringInfo *) GetImageProfile(image,"EXIF");
01786   if (profile == (StringInfo *) NULL)
01787     return(MagickTrue);
01788   length=GetStringInfoLength(profile);
01789   exif=GetStringInfoDatum(profile);
01790   while (length != 0)
01791   {
01792     if (ReadProfileByte(&exif,&length) != 0x45)
01793       continue;
01794     if (ReadProfileByte(&exif,&length) != 0x78)
01795       continue;
01796     if (ReadProfileByte(&exif,&length) != 0x69)
01797       continue;
01798     if (ReadProfileByte(&exif,&length) != 0x66)
01799       continue;
01800     if (ReadProfileByte(&exif,&length) != 0x00)
01801       continue;
01802     if (ReadProfileByte(&exif,&length) != 0x00)
01803       continue;
01804     break;
01805   }
01806   if (length < 16)
01807     return(MagickFalse);
01808   id=(int) ReadProfileShort(LSBEndian,exif);
01809   endian=LSBEndian;
01810   if (id == 0x4949)
01811     endian=LSBEndian;
01812   else
01813     if (id == 0x4D4D)
01814       endian=MSBEndian;
01815     else
01816       return(MagickFalse);
01817   if (ReadProfileShort(endian,exif+2) != 0x002a)
01818     return(MagickFalse);
01819   /*
01820     This the offset to the first IFD.
01821   */
01822   offset=(ssize_t) ReadProfileLong(endian,exif+4);
01823   if ((size_t) offset >= length)
01824     return(MagickFalse);
01825   directory=exif+offset;
01826   level=0;
01827   entry=0;
01828   do
01829   {
01830     if (level > 0)
01831       {
01832         level--;
01833         directory=directory_stack[level].directory;
01834         entry=directory_stack[level].entry;
01835       }
01836     /*
01837       Determine how many entries there are in the current IFD.
01838     */
01839     number_entries=ReadProfileShort(endian,directory);
01840     for ( ; entry < number_entries; entry++)
01841     {
01842       long
01843         components,
01844         format,
01845         tag_value;
01846 
01847       register unsigned char
01848         *p,
01849         *q;
01850 
01851       size_t
01852         number_bytes;
01853 
01854       q=(unsigned char *) (directory+2+(12*entry));
01855       tag_value=(long) ReadProfileShort(endian,q);
01856       format=(long) ReadProfileShort(endian,q+2);
01857       if ((format-1) >= EXIF_NUM_FORMATS)
01858         break;
01859       components=(long) ReadProfileLong(endian,q+4);
01860       number_bytes=(size_t) components*format_bytes[format];
01861       if (number_bytes <= 4)
01862         p=q+8;
01863       else
01864         {
01865           ssize_t
01866             offset;
01867 
01868           /*
01869             The directory entry contains an offset.
01870           */
01871           offset=(ssize_t) ReadProfileLong(endian,q+8);
01872           if ((size_t) (offset+number_bytes) > length)
01873             continue;
01874           p=(unsigned char *) (exif+offset);
01875         }
01876       switch (tag_value)
01877       {
01878         case 0x011a:
01879         {
01880           (void) WriteProfileLong(endian,(unsigned long)
01881             (image->x_resolution+0.5),p);
01882           (void) WriteProfileLong(endian,1UL,p+4);
01883           break;
01884         }
01885         case 0x011b:
01886         {
01887           (void) WriteProfileLong(endian,(unsigned long)
01888             (image->y_resolution+0.5),p);
01889           (void) WriteProfileLong(endian,1UL,p+4);
01890           break;
01891         }
01892         case 0x0112:
01893         {
01894           (void) WriteProfileShort(endian,(unsigned short)
01895             image->orientation,p);
01896           break;
01897         }
01898         case 0x0128:
01899         {
01900           (void) WriteProfileShort(endian,(unsigned short)
01901             (image->units+1),p);
01902           break;
01903         }
01904         default:
01905           break;
01906       }
01907       if ((tag_value == TAG_EXIF_OFFSET) || (tag_value == TAG_INTEROP_OFFSET))
01908         {
01909           size_t
01910             offset;
01911 
01912           offset=(size_t) ReadProfileLong(endian,p);
01913           if ((offset < length) && (level < (MaxDirectoryStack-2)))
01914             {
01915               directory_stack[level].directory=directory;
01916               entry++;
01917               directory_stack[level].entry=entry;
01918               level++;
01919               directory_stack[level].directory=exif+offset;
01920               directory_stack[level].entry=0;
01921               level++;
01922               if ((directory+2+(12*number_entries)) > (exif+length))
01923                 break;
01924               offset=(size_t) ReadProfileLong(endian,directory+2+(12*
01925                 number_entries));
01926               if ((offset != 0) && (offset < length) &&
01927                   (level < (MaxDirectoryStack-2)))
01928                 {
01929                   directory_stack[level].directory=exif+offset;
01930                   directory_stack[level].entry=0;
01931                   level++;
01932                 }
01933             }
01934           break;
01935         }
01936     }
01937   } while (level > 0);
01938   return(MagickTrue);
01939 }

Generated on 19 Nov 2009 for MagickCore by  doxygen 1.6.1