Home | History | Annotate | Download | only in MagickCore
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %               PPPP   RRRR    OOO   FFFFF  IIIII  L      EEEEE               %
      7 %               P   P  R   R  O   O  F        I    L      E                   %
      8 %               PPPP   RRRR   O   O  FFF      I    L      EEE                 %
      9 %               P      R R    O   O  F        I    L      E                   %
     10 %               P      R  R    OOO   F      IIIII  LLLLL  EEEEE               %
     11 %                                                                             %
     12 %                                                                             %
     13 %                       MagickCore Image Profile Methods                      %
     14 %                                                                             %
     15 %                              Software Design                                %
     16 %                                   Cristy                                    %
     17 %                                 July 1992                                   %
     18 %                                                                             %
     19 %                                                                             %
     20 %  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
     21 %  dedicated to making software imaging solutions freely available.           %
     22 %                                                                             %
     23 %  You may not use this file except in compliance with the License.  You may  %
     24 %  obtain a copy of the License at                                            %
     25 %                                                                             %
     26 %    http://www.imagemagick.org/script/license.php                            %
     27 %                                                                             %
     28 %  Unless required by applicable law or agreed to in writing, software        %
     29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
     30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
     31 %  See the License for the specific language governing permissions and        %
     32 %  limitations under the License.                                             %
     33 %                                                                             %
     34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     35 %
     36 %
     37 */
     38 
     39 /*
     41   Include declarations.
     42 */
     43 #include "MagickCore/studio.h"
     44 #include "MagickCore/attribute.h"
     45 #include "MagickCore/cache.h"
     46 #include "MagickCore/color.h"
     47 #include "MagickCore/colorspace-private.h"
     48 #include "MagickCore/configure.h"
     49 #include "MagickCore/exception.h"
     50 #include "MagickCore/exception-private.h"
     51 #include "MagickCore/image.h"
     52 #include "MagickCore/linked-list.h"
     53 #include "MagickCore/memory_.h"
     54 #include "MagickCore/monitor.h"
     55 #include "MagickCore/monitor-private.h"
     56 #include "MagickCore/option.h"
     57 #include "MagickCore/option-private.h"
     58 #include "MagickCore/pixel-accessor.h"
     59 #include "MagickCore/profile.h"
     60 #include "MagickCore/profile-private.h"
     61 #include "MagickCore/property.h"
     62 #include "MagickCore/quantum.h"
     63 #include "MagickCore/quantum-private.h"
     64 #include "MagickCore/resource_.h"
     65 #include "MagickCore/splay-tree.h"
     66 #include "MagickCore/string_.h"
     67 #include "MagickCore/thread-private.h"
     68 #include "MagickCore/token.h"
     69 #include "MagickCore/utility.h"
     70 #if defined(MAGICKCORE_LCMS_DELEGATE)
     71 #if defined(MAGICKCORE_HAVE_LCMS_LCMS2_H)
     72 #include <wchar.h>
     73 #include <lcms/lcms2.h>
     74 #else
     75 #include <wchar.h>
     76 #include "lcms2.h"
     77 #endif
     78 #endif
     79 
     80 /*
     82   Forward declarations
     83 */
     84 static MagickBooleanType
     85   SetImageProfileInternal(Image *,const char *,const StringInfo *,
     86     const MagickBooleanType,ExceptionInfo *);
     87 
     88 static void
     89   WriteTo8BimProfile(Image *,const char*,const StringInfo *);
     90 
     91 /*
     93   Typedef declarations
     94 */
     95 struct _ProfileInfo
     96 {
     97   char
     98     *name;
     99 
    100   size_t
    101     length;
    102 
    103   unsigned char
    104     *info;
    105 
    106   size_t
    107     signature;
    108 };
    109 
    110 typedef struct _CMSExceptionInfo
    111 {
    112   Image
    113     *image;
    114 
    115   ExceptionInfo
    116     *exception;
    117 } CMSExceptionInfo;
    118 
    119 /*
    121 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    122 %                                                                             %
    123 %                                                                             %
    124 %                                                                             %
    125 %   C l o n e I m a g e P r o f i l e s                                       %
    126 %                                                                             %
    127 %                                                                             %
    128 %                                                                             %
    129 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    130 %
    131 %  CloneImageProfiles() clones one or more image profiles.
    132 %
    133 %  The format of the CloneImageProfiles method is:
    134 %
    135 %      MagickBooleanType CloneImageProfiles(Image *image,
    136 %        const Image *clone_image)
    137 %
    138 %  A description of each parameter follows:
    139 %
    140 %    o image: the image.
    141 %
    142 %    o clone_image: the clone image.
    143 %
    144 */
    145 MagickExport MagickBooleanType CloneImageProfiles(Image *image,
    146   const Image *clone_image)
    147 {
    148   assert(image != (Image *) NULL);
    149   assert(image->signature == MagickCoreSignature);
    150   if (image->debug != MagickFalse)
    151     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    152   assert(clone_image != (const Image *) NULL);
    153   assert(clone_image->signature == MagickCoreSignature);
    154   if (clone_image->profiles != (void *) NULL)
    155     {
    156       if (image->profiles != (void *) NULL)
    157         DestroyImageProfiles(image);
    158       image->profiles=CloneSplayTree((SplayTreeInfo *) clone_image->profiles,
    159         (void *(*)(void *)) ConstantString,(void *(*)(void *)) CloneStringInfo);
    160     }
    161   return(MagickTrue);
    162 }
    163 
    164 /*
    166 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    167 %                                                                             %
    168 %                                                                             %
    169 %                                                                             %
    170 %   D e l e t e I m a g e P r o f i l e                                       %
    171 %                                                                             %
    172 %                                                                             %
    173 %                                                                             %
    174 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    175 %
    176 %  DeleteImageProfile() deletes a profile from the image by its name.
    177 %
    178 %  The format of the DeleteImageProfile method is:
    179 %
    180 %      MagickBooleanTyupe DeleteImageProfile(Image *image,const char *name)
    181 %
    182 %  A description of each parameter follows:
    183 %
    184 %    o image: the image.
    185 %
    186 %    o name: the profile name.
    187 %
    188 */
    189 MagickExport MagickBooleanType DeleteImageProfile(Image *image,const char *name)
    190 {
    191   assert(image != (Image *) NULL);
    192   assert(image->signature == MagickCoreSignature);
    193   if (image->debug != MagickFalse)
    194     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    195   if (image->profiles == (SplayTreeInfo *) NULL)
    196     return(MagickFalse);
    197   WriteTo8BimProfile(image,name,(StringInfo *) NULL);
    198   return(DeleteNodeFromSplayTree((SplayTreeInfo *) image->profiles,name));
    199 }
    200 
    201 /*
    203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    204 %                                                                             %
    205 %                                                                             %
    206 %                                                                             %
    207 %   D e s t r o y I m a g e P r o f i l e s                                   %
    208 %                                                                             %
    209 %                                                                             %
    210 %                                                                             %
    211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    212 %
    213 %  DestroyImageProfiles() releases memory associated with an image profile map.
    214 %
    215 %  The format of the DestroyProfiles method is:
    216 %
    217 %      void DestroyImageProfiles(Image *image)
    218 %
    219 %  A description of each parameter follows:
    220 %
    221 %    o image: the image.
    222 %
    223 */
    224 MagickExport void DestroyImageProfiles(Image *image)
    225 {
    226   if (image->profiles != (SplayTreeInfo *) NULL)
    227     image->profiles=DestroySplayTree((SplayTreeInfo *) image->profiles);
    228 }
    229 
    230 /*
    232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    233 %                                                                             %
    234 %                                                                             %
    235 %                                                                             %
    236 %   G e t I m a g e P r o f i l e                                             %
    237 %                                                                             %
    238 %                                                                             %
    239 %                                                                             %
    240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    241 %
    242 %  GetImageProfile() gets a profile associated with an image by name.
    243 %
    244 %  The format of the GetImageProfile method is:
    245 %
    246 %      const StringInfo *GetImageProfile(const Image *image,const char *name)
    247 %
    248 %  A description of each parameter follows:
    249 %
    250 %    o image: the image.
    251 %
    252 %    o name: the profile name.
    253 %
    254 */
    255 MagickExport const StringInfo *GetImageProfile(const Image *image,
    256   const char *name)
    257 {
    258   const StringInfo
    259     *profile;
    260 
    261   assert(image != (Image *) NULL);
    262   assert(image->signature == MagickCoreSignature);
    263   if (image->debug != MagickFalse)
    264     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    265   if (image->profiles == (SplayTreeInfo *) NULL)
    266     return((StringInfo *) NULL);
    267   profile=(const StringInfo *) GetValueFromSplayTree((SplayTreeInfo *)
    268     image->profiles,name);
    269   return(profile);
    270 }
    271 
    272 /*
    274 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    275 %                                                                             %
    276 %                                                                             %
    277 %                                                                             %
    278 %   G e t N e x t I m a g e P r o f i l e                                     %
    279 %                                                                             %
    280 %                                                                             %
    281 %                                                                             %
    282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    283 %
    284 %  GetNextImageProfile() gets the next profile name for an image.
    285 %
    286 %  The format of the GetNextImageProfile method is:
    287 %
    288 %      char *GetNextImageProfile(const Image *image)
    289 %
    290 %  A description of each parameter follows:
    291 %
    292 %    o hash_info: the hash info.
    293 %
    294 */
    295 MagickExport char *GetNextImageProfile(const Image *image)
    296 {
    297   assert(image != (Image *) NULL);
    298   assert(image->signature == MagickCoreSignature);
    299   if (image->debug != MagickFalse)
    300     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    301   if (image->profiles == (SplayTreeInfo *) NULL)
    302     return((char *) NULL);
    303   return((char *) GetNextKeyInSplayTree((SplayTreeInfo *) image->profiles));
    304 }
    305 
    306 /*
    308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    309 %                                                                             %
    310 %                                                                             %
    311 %                                                                             %
    312 %   P r o f i l e I m a g e                                                   %
    313 %                                                                             %
    314 %                                                                             %
    315 %                                                                             %
    316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    317 %
    318 %  ProfileImage() associates, applies, or removes an ICM, IPTC, or generic
    319 %  profile with / to / from an image.  If the profile is NULL, it is removed
    320 %  from the image otherwise added or applied.  Use a name of '*' and a profile
    321 %  of NULL to remove all profiles from the image.
    322 %
    323 %  ICC and ICM profiles are handled as follows: If the image does not have
    324 %  an associated color profile, the one you provide is associated with the
    325 %  image and the image pixels are not transformed.  Otherwise, the colorspace
    326 %  transform defined by the existing and new profile are applied to the image
    327 %  pixels and the new profile is associated with the image.
    328 %
    329 %  The format of the ProfileImage method is:
    330 %
    331 %      MagickBooleanType ProfileImage(Image *image,const char *name,
    332 %        const void *datum,const size_t length,const MagickBooleanType clone)
    333 %
    334 %  A description of each parameter follows:
    335 %
    336 %    o image: the image.
    337 %
    338 %    o name: Name of profile to add or remove: ICC, IPTC, or generic profile.
    339 %
    340 %    o datum: the profile data.
    341 %
    342 %    o length: the length of the profile.
    343 %
    344 %    o clone: should be MagickFalse.
    345 %
    346 */
    347 
    348 #if defined(MAGICKCORE_LCMS_DELEGATE)
    349 static unsigned short **DestroyPixelThreadSet(unsigned short **pixels)
    350 {
    351   register ssize_t
    352     i;
    353 
    354   assert(pixels != (unsigned short **) NULL);
    355   for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
    356     if (pixels[i] != (unsigned short *) NULL)
    357       pixels[i]=(unsigned short *) RelinquishMagickMemory(pixels[i]);
    358   pixels=(unsigned short **) RelinquishMagickMemory(pixels);
    359   return(pixels);
    360 }
    361 
    362 static unsigned short **AcquirePixelThreadSet(const size_t columns,
    363   const size_t channels)
    364 {
    365   register ssize_t
    366     i;
    367 
    368   unsigned short
    369     **pixels;
    370 
    371   size_t
    372     number_threads;
    373 
    374   number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
    375   pixels=(unsigned short **) AcquireQuantumMemory(number_threads,
    376     sizeof(*pixels));
    377   if (pixels == (unsigned short **) NULL)
    378     return((unsigned short **) NULL);
    379   (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
    380   for (i=0; i < (ssize_t) number_threads; i++)
    381   {
    382     pixels[i]=(unsigned short *) AcquireQuantumMemory(columns,channels*
    383       sizeof(**pixels));
    384     if (pixels[i] == (unsigned short *) NULL)
    385       return(DestroyPixelThreadSet(pixels));
    386   }
    387   return(pixels);
    388 }
    389 
    390 static cmsHTRANSFORM *DestroyTransformThreadSet(cmsHTRANSFORM *transform)
    391 {
    392   register ssize_t
    393     i;
    394 
    395   assert(transform != (cmsHTRANSFORM *) NULL);
    396   for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
    397     if (transform[i] != (cmsHTRANSFORM) NULL)
    398       cmsDeleteTransform(transform[i]);
    399   transform=(cmsHTRANSFORM *) RelinquishMagickMemory(transform);
    400   return(transform);
    401 }
    402 
    403 static cmsHTRANSFORM *AcquireTransformThreadSet(Image *image,
    404   const cmsHPROFILE source_profile,const cmsUInt32Number source_type,
    405   const cmsHPROFILE target_profile,const cmsUInt32Number target_type,
    406   const int intent,const cmsUInt32Number flags)
    407 {
    408   cmsHTRANSFORM
    409     *transform;
    410 
    411   register ssize_t
    412     i;
    413 
    414   size_t
    415     number_threads;
    416 
    417   number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
    418   transform=(cmsHTRANSFORM *) AcquireQuantumMemory(number_threads,
    419     sizeof(*transform));
    420   if (transform == (cmsHTRANSFORM *) NULL)
    421     return((cmsHTRANSFORM *) NULL);
    422   (void) ResetMagickMemory(transform,0,number_threads*sizeof(*transform));
    423   for (i=0; i < (ssize_t) number_threads; i++)
    424   {
    425     transform[i]=cmsCreateTransformTHR((cmsContext) image,source_profile,
    426       source_type,target_profile,target_type,intent,flags);
    427     if (transform[i] == (cmsHTRANSFORM) NULL)
    428       return(DestroyTransformThreadSet(transform));
    429   }
    430   return(transform);
    431 }
    432 #endif
    433 
    434 #if defined(MAGICKCORE_LCMS_DELEGATE)
    435 static void CMSExceptionHandler(cmsContext context,cmsUInt32Number severity,
    436   const char *message)
    437 {
    438   CMSExceptionInfo
    439     *cms_exception;
    440 
    441   ExceptionInfo
    442     *exception;
    443 
    444   Image
    445     *image;
    446 
    447   cms_exception=(CMSExceptionInfo *) context;
    448   if (cms_exception == (CMSExceptionInfo *) NULL)
    449     return;
    450   exception=cms_exception->exception;
    451   if (exception == (ExceptionInfo *) NULL)
    452     return;
    453   image=cms_exception->image;
    454   if (image == (Image *) NULL)
    455     {
    456       (void) ThrowMagickException(exception,GetMagickModule(),ImageWarning,
    457         "UnableToTransformColorspace","`%s'","unknown context");
    458       return;
    459     }
    460   if (image->debug != MagickFalse)
    461     (void) LogMagickEvent(TransformEvent,GetMagickModule(),"lcms: #%u, %s",
    462       severity,message != (char *) NULL ? message : "no message");
    463   (void) ThrowMagickException(exception,GetMagickModule(),ImageWarning,
    464     "UnableToTransformColorspace","`%s'",image->filename);
    465 }
    466 #endif
    467 
    468 static MagickBooleanType SetsRGBImageProfile(Image *image,
    469   ExceptionInfo *exception)
    470 {
    471   static unsigned char
    472     sRGBProfile[] =
    473     {
    474       0x00, 0x00, 0x0c, 0x8c, 0x61, 0x72, 0x67, 0x6c, 0x02, 0x20, 0x00, 0x00,
    475       0x6d, 0x6e, 0x74, 0x72, 0x52, 0x47, 0x42, 0x20, 0x58, 0x59, 0x5a, 0x20,
    476       0x07, 0xde, 0x00, 0x01, 0x00, 0x06, 0x00, 0x16, 0x00, 0x0f, 0x00, 0x3a,
    477       0x61, 0x63, 0x73, 0x70, 0x4d, 0x53, 0x46, 0x54, 0x00, 0x00, 0x00, 0x00,
    478       0x49, 0x45, 0x43, 0x20, 0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00, 0x00,
    479       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xd6,
    480       0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d, 0x61, 0x72, 0x67, 0x6c,
    481       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    482       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    483       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    484       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
    485       0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x01, 0x50, 0x00, 0x00, 0x00, 0x99,
    486       0x63, 0x70, 0x72, 0x74, 0x00, 0x00, 0x01, 0xec, 0x00, 0x00, 0x00, 0x67,
    487       0x64, 0x6d, 0x6e, 0x64, 0x00, 0x00, 0x02, 0x54, 0x00, 0x00, 0x00, 0x70,
    488       0x64, 0x6d, 0x64, 0x64, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x00, 0x88,
    489       0x74, 0x65, 0x63, 0x68, 0x00, 0x00, 0x03, 0x4c, 0x00, 0x00, 0x00, 0x0c,
    490       0x76, 0x75, 0x65, 0x64, 0x00, 0x00, 0x03, 0x58, 0x00, 0x00, 0x00, 0x67,
    491       0x76, 0x69, 0x65, 0x77, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x24,
    492       0x6c, 0x75, 0x6d, 0x69, 0x00, 0x00, 0x03, 0xe4, 0x00, 0x00, 0x00, 0x14,
    493       0x6d, 0x65, 0x61, 0x73, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x24,
    494       0x77, 0x74, 0x70, 0x74, 0x00, 0x00, 0x04, 0x1c, 0x00, 0x00, 0x00, 0x14,
    495       0x62, 0x6b, 0x70, 0x74, 0x00, 0x00, 0x04, 0x30, 0x00, 0x00, 0x00, 0x14,
    496       0x72, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x04, 0x44, 0x00, 0x00, 0x00, 0x14,
    497       0x67, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x04, 0x58, 0x00, 0x00, 0x00, 0x14,
    498       0x62, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x04, 0x6c, 0x00, 0x00, 0x00, 0x14,
    499       0x72, 0x54, 0x52, 0x43, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x08, 0x0c,
    500       0x67, 0x54, 0x52, 0x43, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x08, 0x0c,
    501       0x62, 0x54, 0x52, 0x43, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x08, 0x0c,
    502       0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
    503       0x73, 0x52, 0x47, 0x42, 0x20, 0x49, 0x45, 0x43, 0x36, 0x31, 0x39, 0x36,
    504       0x36, 0x2d, 0x32, 0x2e, 0x31, 0x20, 0x28, 0x45, 0x71, 0x75, 0x69, 0x76,
    505       0x61, 0x6c, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x77, 0x77, 0x77,
    506       0x2e, 0x73, 0x72, 0x67, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x31, 0x39,
    507       0x39, 0x38, 0x20, 0x48, 0x50, 0x20, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c,
    508       0x65, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    509       0x00, 0x3f, 0x73, 0x52, 0x47, 0x42, 0x20, 0x49, 0x45, 0x43, 0x36, 0x31,
    510       0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x20, 0x28, 0x45, 0x71, 0x75,
    511       0x69, 0x76, 0x61, 0x6c, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x77,
    512       0x77, 0x77, 0x2e, 0x73, 0x72, 0x67, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x20,
    513       0x31, 0x39, 0x39, 0x38, 0x20, 0x48, 0x50, 0x20, 0x70, 0x72, 0x6f, 0x66,
    514       0x69, 0x6c, 0x65, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    515       0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x43, 0x72, 0x65, 0x61,
    516       0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x47, 0x72, 0x61, 0x65, 0x6d,
    517       0x65, 0x20, 0x57, 0x2e, 0x20, 0x47, 0x69, 0x6c, 0x6c, 0x2e, 0x20, 0x52,
    518       0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x6f,
    519       0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20,
    520       0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x20, 0x4e, 0x6f, 0x20, 0x57,
    521       0x61, 0x72, 0x72, 0x61, 0x6e, 0x74, 0x79, 0x2c, 0x20, 0x55, 0x73, 0x65,
    522       0x20, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75, 0x72, 0x20, 0x6f, 0x77, 0x6e,
    523       0x20, 0x72, 0x69, 0x73, 0x6b, 0x2e, 0x00, 0x00, 0x64, 0x65, 0x73, 0x63,
    524       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x49, 0x45, 0x43, 0x20,
    525       0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69,
    526       0x65, 0x63, 0x2e, 0x63, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    527       0x00, 0x00, 0x00, 0x00, 0x16, 0x49, 0x45, 0x43, 0x20, 0x68, 0x74, 0x74,
    528       0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x65, 0x63, 0x2e,
    529       0x63, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    530       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    531       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    532       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    533       0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e,
    534       0x49, 0x45, 0x43, 0x20, 0x36, 0x31, 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e,
    535       0x31, 0x20, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x52, 0x47,
    536       0x42, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x75, 0x72, 0x20, 0x73, 0x70, 0x61,
    537       0x63, 0x65, 0x20, 0x2d, 0x20, 0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00,
    538       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x49, 0x45, 0x43,
    539       0x20, 0x36, 0x31, 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x20, 0x44,
    540       0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x52, 0x47, 0x42, 0x20, 0x63,
    541       0x6f, 0x6c, 0x6f, 0x75, 0x72, 0x20, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20,
    542       0x2d, 0x20, 0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    543       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    544       0x00, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x20, 0x00, 0x00, 0x00, 0x00,
    545       0x43, 0x52, 0x54, 0x20, 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00,
    546       0x00, 0x00, 0x00, 0x0d, 0x49, 0x45, 0x43, 0x36, 0x31, 0x39, 0x36, 0x36,
    547       0x2d, 0x32, 0x2e, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    548       0x00, 0x00, 0x00, 0x0d, 0x49, 0x45, 0x43, 0x36, 0x31, 0x39, 0x36, 0x36,
    549       0x2d, 0x32, 0x2e, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    550       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    551       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    552       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    553       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    554       0x76, 0x69, 0x65, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xa4, 0x7c,
    555       0x00, 0x14, 0x5f, 0x30, 0x00, 0x10, 0xce, 0x02, 0x00, 0x03, 0xed, 0xb2,
    556       0x00, 0x04, 0x13, 0x0a, 0x00, 0x03, 0x5c, 0x67, 0x00, 0x00, 0x00, 0x01,
    557       0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x0a, 0x3d,
    558       0x00, 0x50, 0x00, 0x00, 0x00, 0x57, 0x1e, 0xb8, 0x6d, 0x65, 0x61, 0x73,
    559       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
    560       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    561       0x00, 0x00, 0x02, 0x8f, 0x00, 0x00, 0x00, 0x02, 0x58, 0x59, 0x5a, 0x20,
    562       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x51, 0x00, 0x01, 0x00, 0x00,
    563       0x00, 0x01, 0x16, 0xcc, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00,
    564       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    565       0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xa0,
    566       0x00, 0x00, 0x38, 0xf5, 0x00, 0x00, 0x03, 0x90, 0x58, 0x59, 0x5a, 0x20,
    567       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x97, 0x00, 0x00, 0xb7, 0x87,
    568       0x00, 0x00, 0x18, 0xd9, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00,
    569       0x00, 0x00, 0x24, 0x9f, 0x00, 0x00, 0x0f, 0x84, 0x00, 0x00, 0xb6, 0xc4,
    570       0x63, 0x75, 0x72, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
    571       0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x14, 0x00, 0x19,
    572       0x00, 0x1e, 0x00, 0x23, 0x00, 0x28, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x37,
    573       0x00, 0x3b, 0x00, 0x40, 0x00, 0x45, 0x00, 0x4a, 0x00, 0x4f, 0x00, 0x54,
    574       0x00, 0x59, 0x00, 0x5e, 0x00, 0x63, 0x00, 0x68, 0x00, 0x6d, 0x00, 0x72,
    575       0x00, 0x77, 0x00, 0x7c, 0x00, 0x81, 0x00, 0x86, 0x00, 0x8b, 0x00, 0x90,
    576       0x00, 0x95, 0x00, 0x9a, 0x00, 0x9f, 0x00, 0xa4, 0x00, 0xa9, 0x00, 0xae,
    577       0x00, 0xb2, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc1, 0x00, 0xc6, 0x00, 0xcb,
    578       0x00, 0xd0, 0x00, 0xd5, 0x00, 0xdb, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0xeb,
    579       0x00, 0xf0, 0x00, 0xf6, 0x00, 0xfb, 0x01, 0x01, 0x01, 0x07, 0x01, 0x0d,
    580       0x01, 0x13, 0x01, 0x19, 0x01, 0x1f, 0x01, 0x25, 0x01, 0x2b, 0x01, 0x32,
    581       0x01, 0x38, 0x01, 0x3e, 0x01, 0x45, 0x01, 0x4c, 0x01, 0x52, 0x01, 0x59,
    582       0x01, 0x60, 0x01, 0x67, 0x01, 0x6e, 0x01, 0x75, 0x01, 0x7c, 0x01, 0x83,
    583       0x01, 0x8b, 0x01, 0x92, 0x01, 0x9a, 0x01, 0xa1, 0x01, 0xa9, 0x01, 0xb1,
    584       0x01, 0xb9, 0x01, 0xc1, 0x01, 0xc9, 0x01, 0xd1, 0x01, 0xd9, 0x01, 0xe1,
    585       0x01, 0xe9, 0x01, 0xf2, 0x01, 0xfa, 0x02, 0x03, 0x02, 0x0c, 0x02, 0x14,
    586       0x02, 0x1d, 0x02, 0x26, 0x02, 0x2f, 0x02, 0x38, 0x02, 0x41, 0x02, 0x4b,
    587       0x02, 0x54, 0x02, 0x5d, 0x02, 0x67, 0x02, 0x71, 0x02, 0x7a, 0x02, 0x84,
    588       0x02, 0x8e, 0x02, 0x98, 0x02, 0xa2, 0x02, 0xac, 0x02, 0xb6, 0x02, 0xc1,
    589       0x02, 0xcb, 0x02, 0xd5, 0x02, 0xe0, 0x02, 0xeb, 0x02, 0xf5, 0x03, 0x00,
    590       0x03, 0x0b, 0x03, 0x16, 0x03, 0x21, 0x03, 0x2d, 0x03, 0x38, 0x03, 0x43,
    591       0x03, 0x4f, 0x03, 0x5a, 0x03, 0x66, 0x03, 0x72, 0x03, 0x7e, 0x03, 0x8a,
    592       0x03, 0x96, 0x03, 0xa2, 0x03, 0xae, 0x03, 0xba, 0x03, 0xc7, 0x03, 0xd3,
    593       0x03, 0xe0, 0x03, 0xec, 0x03, 0xf9, 0x04, 0x06, 0x04, 0x13, 0x04, 0x20,
    594       0x04, 0x2d, 0x04, 0x3b, 0x04, 0x48, 0x04, 0x55, 0x04, 0x63, 0x04, 0x71,
    595       0x04, 0x7e, 0x04, 0x8c, 0x04, 0x9a, 0x04, 0xa8, 0x04, 0xb6, 0x04, 0xc4,
    596       0x04, 0xd3, 0x04, 0xe1, 0x04, 0xf0, 0x04, 0xfe, 0x05, 0x0d, 0x05, 0x1c,
    597       0x05, 0x2b, 0x05, 0x3a, 0x05, 0x49, 0x05, 0x58, 0x05, 0x67, 0x05, 0x77,
    598       0x05, 0x86, 0x05, 0x96, 0x05, 0xa6, 0x05, 0xb5, 0x05, 0xc5, 0x05, 0xd5,
    599       0x05, 0xe5, 0x05, 0xf6, 0x06, 0x06, 0x06, 0x16, 0x06, 0x27, 0x06, 0x37,
    600       0x06, 0x48, 0x06, 0x59, 0x06, 0x6a, 0x06, 0x7b, 0x06, 0x8c, 0x06, 0x9d,
    601       0x06, 0xaf, 0x06, 0xc0, 0x06, 0xd1, 0x06, 0xe3, 0x06, 0xf5, 0x07, 0x07,
    602       0x07, 0x19, 0x07, 0x2b, 0x07, 0x3d, 0x07, 0x4f, 0x07, 0x61, 0x07, 0x74,
    603       0x07, 0x86, 0x07, 0x99, 0x07, 0xac, 0x07, 0xbf, 0x07, 0xd2, 0x07, 0xe5,
    604       0x07, 0xf8, 0x08, 0x0b, 0x08, 0x1f, 0x08, 0x32, 0x08, 0x46, 0x08, 0x5a,
    605       0x08, 0x6e, 0x08, 0x82, 0x08, 0x96, 0x08, 0xaa, 0x08, 0xbe, 0x08, 0xd2,
    606       0x08, 0xe7, 0x08, 0xfb, 0x09, 0x10, 0x09, 0x25, 0x09, 0x3a, 0x09, 0x4f,
    607       0x09, 0x64, 0x09, 0x79, 0x09, 0x8f, 0x09, 0xa4, 0x09, 0xba, 0x09, 0xcf,
    608       0x09, 0xe5, 0x09, 0xfb, 0x0a, 0x11, 0x0a, 0x27, 0x0a, 0x3d, 0x0a, 0x54,
    609       0x0a, 0x6a, 0x0a, 0x81, 0x0a, 0x98, 0x0a, 0xae, 0x0a, 0xc5, 0x0a, 0xdc,
    610       0x0a, 0xf3, 0x0b, 0x0b, 0x0b, 0x22, 0x0b, 0x39, 0x0b, 0x51, 0x0b, 0x69,
    611       0x0b, 0x80, 0x0b, 0x98, 0x0b, 0xb0, 0x0b, 0xc8, 0x0b, 0xe1, 0x0b, 0xf9,
    612       0x0c, 0x12, 0x0c, 0x2a, 0x0c, 0x43, 0x0c, 0x5c, 0x0c, 0x75, 0x0c, 0x8e,
    613       0x0c, 0xa7, 0x0c, 0xc0, 0x0c, 0xd9, 0x0c, 0xf3, 0x0d, 0x0d, 0x0d, 0x26,
    614       0x0d, 0x40, 0x0d, 0x5a, 0x0d, 0x74, 0x0d, 0x8e, 0x0d, 0xa9, 0x0d, 0xc3,
    615       0x0d, 0xde, 0x0d, 0xf8, 0x0e, 0x13, 0x0e, 0x2e, 0x0e, 0x49, 0x0e, 0x64,
    616       0x0e, 0x7f, 0x0e, 0x9b, 0x0e, 0xb6, 0x0e, 0xd2, 0x0e, 0xee, 0x0f, 0x09,
    617       0x0f, 0x25, 0x0f, 0x41, 0x0f, 0x5e, 0x0f, 0x7a, 0x0f, 0x96, 0x0f, 0xb3,
    618       0x0f, 0xcf, 0x0f, 0xec, 0x10, 0x09, 0x10, 0x26, 0x10, 0x43, 0x10, 0x61,
    619       0x10, 0x7e, 0x10, 0x9b, 0x10, 0xb9, 0x10, 0xd7, 0x10, 0xf5, 0x11, 0x13,
    620       0x11, 0x31, 0x11, 0x4f, 0x11, 0x6d, 0x11, 0x8c, 0x11, 0xaa, 0x11, 0xc9,
    621       0x11, 0xe8, 0x12, 0x07, 0x12, 0x26, 0x12, 0x45, 0x12, 0x64, 0x12, 0x84,
    622       0x12, 0xa3, 0x12, 0xc3, 0x12, 0xe3, 0x13, 0x03, 0x13, 0x23, 0x13, 0x43,
    623       0x13, 0x63, 0x13, 0x83, 0x13, 0xa4, 0x13, 0xc5, 0x13, 0xe5, 0x14, 0x06,
    624       0x14, 0x27, 0x14, 0x49, 0x14, 0x6a, 0x14, 0x8b, 0x14, 0xad, 0x14, 0xce,
    625       0x14, 0xf0, 0x15, 0x12, 0x15, 0x34, 0x15, 0x56, 0x15, 0x78, 0x15, 0x9b,
    626       0x15, 0xbd, 0x15, 0xe0, 0x16, 0x03, 0x16, 0x26, 0x16, 0x49, 0x16, 0x6c,
    627       0x16, 0x8f, 0x16, 0xb2, 0x16, 0xd6, 0x16, 0xfa, 0x17, 0x1d, 0x17, 0x41,
    628       0x17, 0x65, 0x17, 0x89, 0x17, 0xae, 0x17, 0xd2, 0x17, 0xf7, 0x18, 0x1b,
    629       0x18, 0x40, 0x18, 0x65, 0x18, 0x8a, 0x18, 0xaf, 0x18, 0xd5, 0x18, 0xfa,
    630       0x19, 0x20, 0x19, 0x45, 0x19, 0x6b, 0x19, 0x91, 0x19, 0xb7, 0x19, 0xdd,
    631       0x1a, 0x04, 0x1a, 0x2a, 0x1a, 0x51, 0x1a, 0x77, 0x1a, 0x9e, 0x1a, 0xc5,
    632       0x1a, 0xec, 0x1b, 0x14, 0x1b, 0x3b, 0x1b, 0x63, 0x1b, 0x8a, 0x1b, 0xb2,
    633       0x1b, 0xda, 0x1c, 0x02, 0x1c, 0x2a, 0x1c, 0x52, 0x1c, 0x7b, 0x1c, 0xa3,
    634       0x1c, 0xcc, 0x1c, 0xf5, 0x1d, 0x1e, 0x1d, 0x47, 0x1d, 0x70, 0x1d, 0x99,
    635       0x1d, 0xc3, 0x1d, 0xec, 0x1e, 0x16, 0x1e, 0x40, 0x1e, 0x6a, 0x1e, 0x94,
    636       0x1e, 0xbe, 0x1e, 0xe9, 0x1f, 0x13, 0x1f, 0x3e, 0x1f, 0x69, 0x1f, 0x94,
    637       0x1f, 0xbf, 0x1f, 0xea, 0x20, 0x15, 0x20, 0x41, 0x20, 0x6c, 0x20, 0x98,
    638       0x20, 0xc4, 0x20, 0xf0, 0x21, 0x1c, 0x21, 0x48, 0x21, 0x75, 0x21, 0xa1,
    639       0x21, 0xce, 0x21, 0xfb, 0x22, 0x27, 0x22, 0x55, 0x22, 0x82, 0x22, 0xaf,
    640       0x22, 0xdd, 0x23, 0x0a, 0x23, 0x38, 0x23, 0x66, 0x23, 0x94, 0x23, 0xc2,
    641       0x23, 0xf0, 0x24, 0x1f, 0x24, 0x4d, 0x24, 0x7c, 0x24, 0xab, 0x24, 0xda,
    642       0x25, 0x09, 0x25, 0x38, 0x25, 0x68, 0x25, 0x97, 0x25, 0xc7, 0x25, 0xf7,
    643       0x26, 0x27, 0x26, 0x57, 0x26, 0x87, 0x26, 0xb7, 0x26, 0xe8, 0x27, 0x18,
    644       0x27, 0x49, 0x27, 0x7a, 0x27, 0xab, 0x27, 0xdc, 0x28, 0x0d, 0x28, 0x3f,
    645       0x28, 0x71, 0x28, 0xa2, 0x28, 0xd4, 0x29, 0x06, 0x29, 0x38, 0x29, 0x6b,
    646       0x29, 0x9d, 0x29, 0xd0, 0x2a, 0x02, 0x2a, 0x35, 0x2a, 0x68, 0x2a, 0x9b,
    647       0x2a, 0xcf, 0x2b, 0x02, 0x2b, 0x36, 0x2b, 0x69, 0x2b, 0x9d, 0x2b, 0xd1,
    648       0x2c, 0x05, 0x2c, 0x39, 0x2c, 0x6e, 0x2c, 0xa2, 0x2c, 0xd7, 0x2d, 0x0c,
    649       0x2d, 0x41, 0x2d, 0x76, 0x2d, 0xab, 0x2d, 0xe1, 0x2e, 0x16, 0x2e, 0x4c,
    650       0x2e, 0x82, 0x2e, 0xb7, 0x2e, 0xee, 0x2f, 0x24, 0x2f, 0x5a, 0x2f, 0x91,
    651       0x2f, 0xc7, 0x2f, 0xfe, 0x30, 0x35, 0x30, 0x6c, 0x30, 0xa4, 0x30, 0xdb,
    652       0x31, 0x12, 0x31, 0x4a, 0x31, 0x82, 0x31, 0xba, 0x31, 0xf2, 0x32, 0x2a,
    653       0x32, 0x63, 0x32, 0x9b, 0x32, 0xd4, 0x33, 0x0d, 0x33, 0x46, 0x33, 0x7f,
    654       0x33, 0xb8, 0x33, 0xf1, 0x34, 0x2b, 0x34, 0x65, 0x34, 0x9e, 0x34, 0xd8,
    655       0x35, 0x13, 0x35, 0x4d, 0x35, 0x87, 0x35, 0xc2, 0x35, 0xfd, 0x36, 0x37,
    656       0x36, 0x72, 0x36, 0xae, 0x36, 0xe9, 0x37, 0x24, 0x37, 0x60, 0x37, 0x9c,
    657       0x37, 0xd7, 0x38, 0x14, 0x38, 0x50, 0x38, 0x8c, 0x38, 0xc8, 0x39, 0x05,
    658       0x39, 0x42, 0x39, 0x7f, 0x39, 0xbc, 0x39, 0xf9, 0x3a, 0x36, 0x3a, 0x74,
    659       0x3a, 0xb2, 0x3a, 0xef, 0x3b, 0x2d, 0x3b, 0x6b, 0x3b, 0xaa, 0x3b, 0xe8,
    660       0x3c, 0x27, 0x3c, 0x65, 0x3c, 0xa4, 0x3c, 0xe3, 0x3d, 0x22, 0x3d, 0x61,
    661       0x3d, 0xa1, 0x3d, 0xe0, 0x3e, 0x20, 0x3e, 0x60, 0x3e, 0xa0, 0x3e, 0xe0,
    662       0x3f, 0x21, 0x3f, 0x61, 0x3f, 0xa2, 0x3f, 0xe2, 0x40, 0x23, 0x40, 0x64,
    663       0x40, 0xa6, 0x40, 0xe7, 0x41, 0x29, 0x41, 0x6a, 0x41, 0xac, 0x41, 0xee,
    664       0x42, 0x30, 0x42, 0x72, 0x42, 0xb5, 0x42, 0xf7, 0x43, 0x3a, 0x43, 0x7d,
    665       0x43, 0xc0, 0x44, 0x03, 0x44, 0x47, 0x44, 0x8a, 0x44, 0xce, 0x45, 0x12,
    666       0x45, 0x55, 0x45, 0x9a, 0x45, 0xde, 0x46, 0x22, 0x46, 0x67, 0x46, 0xab,
    667       0x46, 0xf0, 0x47, 0x35, 0x47, 0x7b, 0x47, 0xc0, 0x48, 0x05, 0x48, 0x4b,
    668       0x48, 0x91, 0x48, 0xd7, 0x49, 0x1d, 0x49, 0x63, 0x49, 0xa9, 0x49, 0xf0,
    669       0x4a, 0x37, 0x4a, 0x7d, 0x4a, 0xc4, 0x4b, 0x0c, 0x4b, 0x53, 0x4b, 0x9a,
    670       0x4b, 0xe2, 0x4c, 0x2a, 0x4c, 0x72, 0x4c, 0xba, 0x4d, 0x02, 0x4d, 0x4a,
    671       0x4d, 0x93, 0x4d, 0xdc, 0x4e, 0x25, 0x4e, 0x6e, 0x4e, 0xb7, 0x4f, 0x00,
    672       0x4f, 0x49, 0x4f, 0x93, 0x4f, 0xdd, 0x50, 0x27, 0x50, 0x71, 0x50, 0xbb,
    673       0x51, 0x06, 0x51, 0x50, 0x51, 0x9b, 0x51, 0xe6, 0x52, 0x31, 0x52, 0x7c,
    674       0x52, 0xc7, 0x53, 0x13, 0x53, 0x5f, 0x53, 0xaa, 0x53, 0xf6, 0x54, 0x42,
    675       0x54, 0x8f, 0x54, 0xdb, 0x55, 0x28, 0x55, 0x75, 0x55, 0xc2, 0x56, 0x0f,
    676       0x56, 0x5c, 0x56, 0xa9, 0x56, 0xf7, 0x57, 0x44, 0x57, 0x92, 0x57, 0xe0,
    677       0x58, 0x2f, 0x58, 0x7d, 0x58, 0xcb, 0x59, 0x1a, 0x59, 0x69, 0x59, 0xb8,
    678       0x5a, 0x07, 0x5a, 0x56, 0x5a, 0xa6, 0x5a, 0xf5, 0x5b, 0x45, 0x5b, 0x95,
    679       0x5b, 0xe5, 0x5c, 0x35, 0x5c, 0x86, 0x5c, 0xd6, 0x5d, 0x27, 0x5d, 0x78,
    680       0x5d, 0xc9, 0x5e, 0x1a, 0x5e, 0x6c, 0x5e, 0xbd, 0x5f, 0x0f, 0x5f, 0x61,
    681       0x5f, 0xb3, 0x60, 0x05, 0x60, 0x57, 0x60, 0xaa, 0x60, 0xfc, 0x61, 0x4f,
    682       0x61, 0xa2, 0x61, 0xf5, 0x62, 0x49, 0x62, 0x9c, 0x62, 0xf0, 0x63, 0x43,
    683       0x63, 0x97, 0x63, 0xeb, 0x64, 0x40, 0x64, 0x94, 0x64, 0xe9, 0x65, 0x3d,
    684       0x65, 0x92, 0x65, 0xe7, 0x66, 0x3d, 0x66, 0x92, 0x66, 0xe8, 0x67, 0x3d,
    685       0x67, 0x93, 0x67, 0xe9, 0x68, 0x3f, 0x68, 0x96, 0x68, 0xec, 0x69, 0x43,
    686       0x69, 0x9a, 0x69, 0xf1, 0x6a, 0x48, 0x6a, 0x9f, 0x6a, 0xf7, 0x6b, 0x4f,
    687       0x6b, 0xa7, 0x6b, 0xff, 0x6c, 0x57, 0x6c, 0xaf, 0x6d, 0x08, 0x6d, 0x60,
    688       0x6d, 0xb9, 0x6e, 0x12, 0x6e, 0x6b, 0x6e, 0xc4, 0x6f, 0x1e, 0x6f, 0x78,
    689       0x6f, 0xd1, 0x70, 0x2b, 0x70, 0x86, 0x70, 0xe0, 0x71, 0x3a, 0x71, 0x95,
    690       0x71, 0xf0, 0x72, 0x4b, 0x72, 0xa6, 0x73, 0x01, 0x73, 0x5d, 0x73, 0xb8,
    691       0x74, 0x14, 0x74, 0x70, 0x74, 0xcc, 0x75, 0x28, 0x75, 0x85, 0x75, 0xe1,
    692       0x76, 0x3e, 0x76, 0x9b, 0x76, 0xf8, 0x77, 0x56, 0x77, 0xb3, 0x78, 0x11,
    693       0x78, 0x6e, 0x78, 0xcc, 0x79, 0x2a, 0x79, 0x89, 0x79, 0xe7, 0x7a, 0x46,
    694       0x7a, 0xa5, 0x7b, 0x04, 0x7b, 0x63, 0x7b, 0xc2, 0x7c, 0x21, 0x7c, 0x81,
    695       0x7c, 0xe1, 0x7d, 0x41, 0x7d, 0xa1, 0x7e, 0x01, 0x7e, 0x62, 0x7e, 0xc2,
    696       0x7f, 0x23, 0x7f, 0x84, 0x7f, 0xe5, 0x80, 0x47, 0x80, 0xa8, 0x81, 0x0a,
    697       0x81, 0x6b, 0x81, 0xcd, 0x82, 0x30, 0x82, 0x92, 0x82, 0xf4, 0x83, 0x57,
    698       0x83, 0xba, 0x84, 0x1d, 0x84, 0x80, 0x84, 0xe3, 0x85, 0x47, 0x85, 0xab,
    699       0x86, 0x0e, 0x86, 0x72, 0x86, 0xd7, 0x87, 0x3b, 0x87, 0x9f, 0x88, 0x04,
    700       0x88, 0x69, 0x88, 0xce, 0x89, 0x33, 0x89, 0x99, 0x89, 0xfe, 0x8a, 0x64,
    701       0x8a, 0xca, 0x8b, 0x30, 0x8b, 0x96, 0x8b, 0xfc, 0x8c, 0x63, 0x8c, 0xca,
    702       0x8d, 0x31, 0x8d, 0x98, 0x8d, 0xff, 0x8e, 0x66, 0x8e, 0xce, 0x8f, 0x36,
    703       0x8f, 0x9e, 0x90, 0x06, 0x90, 0x6e, 0x90, 0xd6, 0x91, 0x3f, 0x91, 0xa8,
    704       0x92, 0x11, 0x92, 0x7a, 0x92, 0xe3, 0x93, 0x4d, 0x93, 0xb6, 0x94, 0x20,
    705       0x94, 0x8a, 0x94, 0xf4, 0x95, 0x5f, 0x95, 0xc9, 0x96, 0x34, 0x96, 0x9f,
    706       0x97, 0x0a, 0x97, 0x75, 0x97, 0xe0, 0x98, 0x4c, 0x98, 0xb8, 0x99, 0x24,
    707       0x99, 0x90, 0x99, 0xfc, 0x9a, 0x68, 0x9a, 0xd5, 0x9b, 0x42, 0x9b, 0xaf,
    708       0x9c, 0x1c, 0x9c, 0x89, 0x9c, 0xf7, 0x9d, 0x64, 0x9d, 0xd2, 0x9e, 0x40,
    709       0x9e, 0xae, 0x9f, 0x1d, 0x9f, 0x8b, 0x9f, 0xfa, 0xa0, 0x69, 0xa0, 0xd8,
    710       0xa1, 0x47, 0xa1, 0xb6, 0xa2, 0x26, 0xa2, 0x96, 0xa3, 0x06, 0xa3, 0x76,
    711       0xa3, 0xe6, 0xa4, 0x56, 0xa4, 0xc7, 0xa5, 0x38, 0xa5, 0xa9, 0xa6, 0x1a,
    712       0xa6, 0x8b, 0xa6, 0xfd, 0xa7, 0x6e, 0xa7, 0xe0, 0xa8, 0x52, 0xa8, 0xc4,
    713       0xa9, 0x37, 0xa9, 0xa9, 0xaa, 0x1c, 0xaa, 0x8f, 0xab, 0x02, 0xab, 0x75,
    714       0xab, 0xe9, 0xac, 0x5c, 0xac, 0xd0, 0xad, 0x44, 0xad, 0xb8, 0xae, 0x2d,
    715       0xae, 0xa1, 0xaf, 0x16, 0xaf, 0x8b, 0xb0, 0x00, 0xb0, 0x75, 0xb0, 0xea,
    716       0xb1, 0x60, 0xb1, 0xd6, 0xb2, 0x4b, 0xb2, 0xc2, 0xb3, 0x38, 0xb3, 0xae,
    717       0xb4, 0x25, 0xb4, 0x9c, 0xb5, 0x13, 0xb5, 0x8a, 0xb6, 0x01, 0xb6, 0x79,
    718       0xb6, 0xf0, 0xb7, 0x68, 0xb7, 0xe0, 0xb8, 0x59, 0xb8, 0xd1, 0xb9, 0x4a,
    719       0xb9, 0xc2, 0xba, 0x3b, 0xba, 0xb5, 0xbb, 0x2e, 0xbb, 0xa7, 0xbc, 0x21,
    720       0xbc, 0x9b, 0xbd, 0x15, 0xbd, 0x8f, 0xbe, 0x0a, 0xbe, 0x84, 0xbe, 0xff,
    721       0xbf, 0x7a, 0xbf, 0xf5, 0xc0, 0x70, 0xc0, 0xec, 0xc1, 0x67, 0xc1, 0xe3,
    722       0xc2, 0x5f, 0xc2, 0xdb, 0xc3, 0x58, 0xc3, 0xd4, 0xc4, 0x51, 0xc4, 0xce,
    723       0xc5, 0x4b, 0xc5, 0xc8, 0xc6, 0x46, 0xc6, 0xc3, 0xc7, 0x41, 0xc7, 0xbf,
    724       0xc8, 0x3d, 0xc8, 0xbc, 0xc9, 0x3a, 0xc9, 0xb9, 0xca, 0x38, 0xca, 0xb7,
    725       0xcb, 0x36, 0xcb, 0xb6, 0xcc, 0x35, 0xcc, 0xb5, 0xcd, 0x35, 0xcd, 0xb5,
    726       0xce, 0x36, 0xce, 0xb6, 0xcf, 0x37, 0xcf, 0xb8, 0xd0, 0x39, 0xd0, 0xba,
    727       0xd1, 0x3c, 0xd1, 0xbe, 0xd2, 0x3f, 0xd2, 0xc1, 0xd3, 0x44, 0xd3, 0xc6,
    728       0xd4, 0x49, 0xd4, 0xcb, 0xd5, 0x4e, 0xd5, 0xd1, 0xd6, 0x55, 0xd6, 0xd8,
    729       0xd7, 0x5c, 0xd7, 0xe0, 0xd8, 0x64, 0xd8, 0xe8, 0xd9, 0x6c, 0xd9, 0xf1,
    730       0xda, 0x76, 0xda, 0xfb, 0xdb, 0x80, 0xdc, 0x05, 0xdc, 0x8a, 0xdd, 0x10,
    731       0xdd, 0x96, 0xde, 0x1c, 0xde, 0xa2, 0xdf, 0x29, 0xdf, 0xaf, 0xe0, 0x36,
    732       0xe0, 0xbd, 0xe1, 0x44, 0xe1, 0xcc, 0xe2, 0x53, 0xe2, 0xdb, 0xe3, 0x63,
    733       0xe3, 0xeb, 0xe4, 0x73, 0xe4, 0xfc, 0xe5, 0x84, 0xe6, 0x0d, 0xe6, 0x96,
    734       0xe7, 0x1f, 0xe7, 0xa9, 0xe8, 0x32, 0xe8, 0xbc, 0xe9, 0x46, 0xe9, 0xd0,
    735       0xea, 0x5b, 0xea, 0xe5, 0xeb, 0x70, 0xeb, 0xfb, 0xec, 0x86, 0xed, 0x11,
    736       0xed, 0x9c, 0xee, 0x28, 0xee, 0xb4, 0xef, 0x40, 0xef, 0xcc, 0xf0, 0x58,
    737       0xf0, 0xe5, 0xf1, 0x72, 0xf1, 0xff, 0xf2, 0x8c, 0xf3, 0x19, 0xf3, 0xa7,
    738       0xf4, 0x34, 0xf4, 0xc2, 0xf5, 0x50, 0xf5, 0xde, 0xf6, 0x6d, 0xf6, 0xfb,
    739       0xf7, 0x8a, 0xf8, 0x19, 0xf8, 0xa8, 0xf9, 0x38, 0xf9, 0xc7, 0xfa, 0x57,
    740       0xfa, 0xe7, 0xfb, 0x77, 0xfc, 0x07, 0xfc, 0x98, 0xfd, 0x29, 0xfd, 0xba,
    741       0xfe, 0x4b, 0xfe, 0xdc, 0xff, 0x6d, 0xff, 0xff
    742     };
    743 
    744   StringInfo
    745     *profile;
    746 
    747   MagickBooleanType
    748     status;
    749 
    750   assert(image != (Image *) NULL);
    751   assert(image->signature == MagickCoreSignature);
    752   if (GetImageProfile(image,"icc") != (const StringInfo *) NULL)
    753     return(MagickFalse);
    754   profile=AcquireStringInfo(sizeof(sRGBProfile));
    755   SetStringInfoDatum(profile,sRGBProfile);
    756   status=SetImageProfile(image,"icc",profile,exception);
    757   profile=DestroyStringInfo(profile);
    758   return(status);
    759 }
    760 
    761 MagickExport MagickBooleanType ProfileImage(Image *image,const char *name,
    762   const void *datum,const size_t length,ExceptionInfo *exception)
    763 {
    764 #define ProfileImageTag  "Profile/Image"
    765 #define ThrowProfileException(severity,tag,context) \
    766 { \
    767   if (source_profile != (cmsHPROFILE) NULL) \
    768     (void) cmsCloseProfile(source_profile); \
    769   if (target_profile != (cmsHPROFILE) NULL) \
    770     (void) cmsCloseProfile(target_profile); \
    771   ThrowBinaryException(severity,tag,context); \
    772 }
    773 
    774   MagickBooleanType
    775     status;
    776 
    777   StringInfo
    778     *profile;
    779 
    780   assert(image != (Image *) NULL);
    781   assert(image->signature == MagickCoreSignature);
    782   if (image->debug != MagickFalse)
    783     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    784   assert(name != (const char *) NULL);
    785   if ((datum == (const void *) NULL) || (length == 0))
    786     {
    787       char
    788         *next;
    789 
    790       /*
    791         Delete image profile(s).
    792       */
    793       ResetImageProfileIterator(image);
    794       for (next=GetNextImageProfile(image); next != (const char *) NULL; )
    795       {
    796         if (IsOptionMember(next,name) != MagickFalse)
    797           {
    798             (void) DeleteImageProfile(image,next);
    799             ResetImageProfileIterator(image);
    800           }
    801         next=GetNextImageProfile(image);
    802       }
    803       return(MagickTrue);
    804     }
    805   /*
    806     Add a ICC, IPTC, or generic profile to the image.
    807   */
    808   status=MagickTrue;
    809   profile=AcquireStringInfo((size_t) length);
    810   SetStringInfoDatum(profile,(unsigned char *) datum);
    811   if ((LocaleCompare(name,"icc") != 0) && (LocaleCompare(name,"icm") != 0))
    812     status=SetImageProfile(image,name,profile,exception);
    813   else
    814     {
    815       const StringInfo
    816         *icc_profile;
    817 
    818       icc_profile=GetImageProfile(image,"icc");
    819       if ((icc_profile != (const StringInfo *) NULL) &&
    820           (CompareStringInfo(icc_profile,profile) == 0))
    821         {
    822           const char
    823             *value;
    824 
    825           value=GetImageProperty(image,"exif:ColorSpace",exception);
    826           (void) value;
    827           if (LocaleCompare(value,"1") != 0)
    828             (void) SetsRGBImageProfile(image,exception);
    829           value=GetImageProperty(image,"exif:InteroperabilityIndex",exception);
    830           if (LocaleCompare(value,"R98.") != 0)
    831             (void) SetsRGBImageProfile(image,exception);
    832           /* Future.
    833           value=GetImageProperty(image,"exif:InteroperabilityIndex",exception);
    834           if (LocaleCompare(value,"R03.") != 0)
    835             (void) SetAdobeRGB1998ImageProfile(image,exception);
    836           */
    837           icc_profile=GetImageProfile(image,"icc");
    838         }
    839       if ((icc_profile != (const StringInfo *) NULL) &&
    840           (CompareStringInfo(icc_profile,profile) == 0))
    841         {
    842           profile=DestroyStringInfo(profile);
    843           return(MagickTrue);
    844         }
    845 #if !defined(MAGICKCORE_LCMS_DELEGATE)
    846       (void) ThrowMagickException(exception,GetMagickModule(),
    847         MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn",
    848         "'%s' (LCMS)",image->filename);
    849 #else
    850       {
    851         cmsHPROFILE
    852           source_profile;
    853 
    854         CMSExceptionInfo
    855           cms_exception;
    856 
    857         /*
    858           Transform pixel colors as defined by the color profiles.
    859         */
    860         cmsSetLogErrorHandler(CMSExceptionHandler);
    861         cms_exception.image=image;
    862         cms_exception.exception=exception;
    863         (void) cms_exception;
    864         source_profile=cmsOpenProfileFromMemTHR((cmsContext) &cms_exception,
    865           GetStringInfoDatum(profile),(cmsUInt32Number)
    866           GetStringInfoLength(profile));
    867         if (source_profile == (cmsHPROFILE) NULL)
    868           ThrowBinaryException(ResourceLimitError,
    869             "ColorspaceColorProfileMismatch",name);
    870         if ((cmsGetDeviceClass(source_profile) != cmsSigLinkClass) &&
    871             (icc_profile == (StringInfo *) NULL))
    872           status=SetImageProfile(image,name,profile,exception);
    873         else
    874           {
    875             CacheView
    876               *image_view;
    877 
    878             ColorspaceType
    879               source_colorspace,
    880               target_colorspace;
    881 
    882             cmsColorSpaceSignature
    883               signature;
    884 
    885             cmsHPROFILE
    886               target_profile;
    887 
    888             cmsHTRANSFORM
    889               *magick_restrict transform;
    890 
    891             cmsUInt32Number
    892               flags,
    893               source_type,
    894               target_type;
    895 
    896             int
    897               intent;
    898 
    899             MagickOffsetType
    900               progress;
    901 
    902             size_t
    903               source_channels,
    904               target_channels;
    905 
    906             ssize_t
    907               y;
    908 
    909             unsigned short
    910               **magick_restrict source_pixels,
    911               **magick_restrict target_pixels;
    912 
    913             target_profile=(cmsHPROFILE) NULL;
    914             if (icc_profile != (StringInfo *) NULL)
    915               {
    916                 target_profile=source_profile;
    917                 source_profile=cmsOpenProfileFromMemTHR((cmsContext)
    918                   &cms_exception,GetStringInfoDatum(icc_profile),
    919                   (cmsUInt32Number) GetStringInfoLength(icc_profile));
    920                 if (source_profile == (cmsHPROFILE) NULL)
    921                   ThrowProfileException(ResourceLimitError,
    922                     "ColorspaceColorProfileMismatch",name);
    923               }
    924             switch (cmsGetColorSpace(source_profile))
    925             {
    926               case cmsSigCmykData:
    927               {
    928                 source_colorspace=CMYKColorspace;
    929                 source_type=(cmsUInt32Number) TYPE_CMYK_16;
    930                 source_channels=4;
    931                 break;
    932               }
    933               case cmsSigGrayData:
    934               {
    935                 source_colorspace=GRAYColorspace;
    936                 source_type=(cmsUInt32Number) TYPE_GRAY_16;
    937                 source_channels=1;
    938                 break;
    939               }
    940               case cmsSigLabData:
    941               {
    942                 source_colorspace=LabColorspace;
    943                 source_type=(cmsUInt32Number) TYPE_Lab_16;
    944                 source_channels=3;
    945                 break;
    946               }
    947               case cmsSigLuvData:
    948               {
    949                 source_colorspace=YUVColorspace;
    950                 source_type=(cmsUInt32Number) TYPE_YUV_16;
    951                 source_channels=3;
    952                 break;
    953               }
    954               case cmsSigRgbData:
    955               {
    956                 source_colorspace=sRGBColorspace;
    957                 source_type=(cmsUInt32Number) TYPE_RGB_16;
    958                 source_channels=3;
    959                 break;
    960               }
    961               case cmsSigXYZData:
    962               {
    963                 source_colorspace=XYZColorspace;
    964                 source_type=(cmsUInt32Number) TYPE_XYZ_16;
    965                 source_channels=3;
    966                 break;
    967               }
    968               case cmsSigYCbCrData:
    969               {
    970                 source_colorspace=YCbCrColorspace;
    971                 source_type=(cmsUInt32Number) TYPE_YCbCr_16;
    972                 source_channels=3;
    973                 break;
    974               }
    975               default:
    976               {
    977                 source_colorspace=UndefinedColorspace;
    978                 source_type=(cmsUInt32Number) TYPE_RGB_16;
    979                 source_channels=3;
    980                 break;
    981               }
    982             }
    983             signature=cmsGetPCS(source_profile);
    984             if (target_profile != (cmsHPROFILE) NULL)
    985               signature=cmsGetColorSpace(target_profile);
    986             switch (signature)
    987             {
    988               case cmsSigCmykData:
    989               {
    990                 target_colorspace=CMYKColorspace;
    991                 target_type=(cmsUInt32Number) TYPE_CMYK_16;
    992                 target_channels=4;
    993                 break;
    994               }
    995               case cmsSigLabData:
    996               {
    997                 target_colorspace=LabColorspace;
    998                 target_type=(cmsUInt32Number) TYPE_Lab_16;
    999                 target_channels=3;
   1000                 break;
   1001               }
   1002               case cmsSigGrayData:
   1003               {
   1004                 target_colorspace=GRAYColorspace;
   1005                 target_type=(cmsUInt32Number) TYPE_GRAY_16;
   1006                 target_channels=1;
   1007                 break;
   1008               }
   1009               case cmsSigLuvData:
   1010               {
   1011                 target_colorspace=YUVColorspace;
   1012                 target_type=(cmsUInt32Number) TYPE_YUV_16;
   1013                 target_channels=3;
   1014                 break;
   1015               }
   1016               case cmsSigRgbData:
   1017               {
   1018                 target_colorspace=sRGBColorspace;
   1019                 target_type=(cmsUInt32Number) TYPE_RGB_16;
   1020                 target_channels=3;
   1021                 break;
   1022               }
   1023               case cmsSigXYZData:
   1024               {
   1025                 target_colorspace=XYZColorspace;
   1026                 target_type=(cmsUInt32Number) TYPE_XYZ_16;
   1027                 target_channels=3;
   1028                 break;
   1029               }
   1030               case cmsSigYCbCrData:
   1031               {
   1032                 target_colorspace=YCbCrColorspace;
   1033                 target_type=(cmsUInt32Number) TYPE_YCbCr_16;
   1034                 target_channels=3;
   1035                 break;
   1036               }
   1037               default:
   1038               {
   1039                 target_colorspace=UndefinedColorspace;
   1040                 target_type=(cmsUInt32Number) TYPE_RGB_16;
   1041                 target_channels=3;
   1042                 break;
   1043               }
   1044             }
   1045             if ((source_colorspace == UndefinedColorspace) ||
   1046                 (target_colorspace == UndefinedColorspace))
   1047               ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
   1048                 name);
   1049              if ((source_colorspace == GRAYColorspace) &&
   1050                  (SetImageGray(image,exception) == MagickFalse))
   1051               ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
   1052                 name);
   1053              if ((source_colorspace == CMYKColorspace) &&
   1054                  (image->colorspace != CMYKColorspace))
   1055               ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
   1056                 name);
   1057              if ((source_colorspace == XYZColorspace) &&
   1058                  (image->colorspace != XYZColorspace))
   1059               ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
   1060                 name);
   1061              if ((source_colorspace == YCbCrColorspace) &&
   1062                  (image->colorspace != YCbCrColorspace))
   1063               ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
   1064                 name);
   1065              if ((source_colorspace != CMYKColorspace) &&
   1066                  (source_colorspace != LabColorspace) &&
   1067                  (source_colorspace != XYZColorspace) &&
   1068                  (source_colorspace != YCbCrColorspace) &&
   1069                  (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse))
   1070               ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
   1071                 name);
   1072             switch (image->rendering_intent)
   1073             {
   1074               case AbsoluteIntent: intent=INTENT_ABSOLUTE_COLORIMETRIC; break;
   1075               case PerceptualIntent: intent=INTENT_PERCEPTUAL; break;
   1076               case RelativeIntent: intent=INTENT_RELATIVE_COLORIMETRIC; break;
   1077               case SaturationIntent: intent=INTENT_SATURATION; break;
   1078               default: intent=INTENT_PERCEPTUAL; break;
   1079             }
   1080             flags=cmsFLAGS_HIGHRESPRECALC;
   1081 #if defined(cmsFLAGS_BLACKPOINTCOMPENSATION)
   1082             if (image->black_point_compensation != MagickFalse)
   1083               flags|=cmsFLAGS_BLACKPOINTCOMPENSATION;
   1084 #endif
   1085             transform=AcquireTransformThreadSet(image,source_profile,
   1086               source_type,target_profile,target_type,intent,flags);
   1087             if (transform == (cmsHTRANSFORM *) NULL)
   1088               ThrowProfileException(ImageError,"UnableToCreateColorTransform",
   1089                 name);
   1090             /*
   1091               Transform image as dictated by the source & target image profiles.
   1092             */
   1093             source_pixels=AcquirePixelThreadSet(image->columns,source_channels);
   1094             target_pixels=AcquirePixelThreadSet(image->columns,target_channels);
   1095             if ((source_pixels == (unsigned short **) NULL) ||
   1096                 (target_pixels == (unsigned short **) NULL))
   1097               {
   1098                 transform=DestroyTransformThreadSet(transform);
   1099                 ThrowProfileException(ResourceLimitError,
   1100                   "MemoryAllocationFailed",image->filename);
   1101               }
   1102             if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
   1103               {
   1104                 target_pixels=DestroyPixelThreadSet(target_pixels);
   1105                 source_pixels=DestroyPixelThreadSet(source_pixels);
   1106                 transform=DestroyTransformThreadSet(transform);
   1107                 if (source_profile != (cmsHPROFILE) NULL)
   1108                   (void) cmsCloseProfile(source_profile);
   1109                 if (target_profile != (cmsHPROFILE) NULL)
   1110                   (void) cmsCloseProfile(target_profile);
   1111                 return(MagickFalse);
   1112               }
   1113             if (target_colorspace == CMYKColorspace)
   1114               (void) SetImageColorspace(image,target_colorspace,exception);
   1115             progress=0;
   1116             image_view=AcquireAuthenticCacheView(image,exception);
   1117 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   1118             #pragma omp parallel for schedule(static,4) shared(status) \
   1119               magick_threads(image,image,image->rows,1)
   1120 #endif
   1121             for (y=0; y < (ssize_t) image->rows; y++)
   1122             {
   1123               const int
   1124                 id = GetOpenMPThreadId();
   1125 
   1126               MagickBooleanType
   1127                 sync;
   1128 
   1129               register ssize_t
   1130                 x;
   1131 
   1132               register Quantum
   1133                 *magick_restrict q;
   1134 
   1135               register unsigned short
   1136                 *p;
   1137 
   1138               if (status == MagickFalse)
   1139                 continue;
   1140               q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
   1141                 exception);
   1142               if (q == (Quantum *) NULL)
   1143                 {
   1144                   status=MagickFalse;
   1145                   continue;
   1146                 }
   1147               p=source_pixels[id];
   1148               for (x=0; x < (ssize_t) image->columns; x++)
   1149               {
   1150                 *p++=ScaleQuantumToShort(GetPixelRed(image,q));
   1151                 if (source_channels > 1)
   1152                   {
   1153                     *p++=ScaleQuantumToShort(GetPixelGreen(image,q));
   1154                     *p++=ScaleQuantumToShort(GetPixelBlue(image,q));
   1155                   }
   1156                 if (source_channels > 3)
   1157                   *p++=ScaleQuantumToShort(GetPixelBlack(image,q));
   1158                 q+=GetPixelChannels(image);
   1159               }
   1160               cmsDoTransform(transform[id],source_pixels[id],target_pixels[id],
   1161                 (unsigned int) image->columns);
   1162               p=target_pixels[id];
   1163               q-=GetPixelChannels(image)*image->columns;
   1164               for (x=0; x < (ssize_t) image->columns; x++)
   1165               {
   1166                 if (target_channels == 1)
   1167                   SetPixelGray(image,ScaleShortToQuantum(*p),q);
   1168                 else
   1169                   SetPixelRed(image,ScaleShortToQuantum(*p),q);
   1170                 p++;
   1171                 if (target_channels > 1)
   1172                   {
   1173                     SetPixelGreen(image,ScaleShortToQuantum(*p),q);
   1174                     p++;
   1175                     SetPixelBlue(image,ScaleShortToQuantum(*p),q);
   1176                     p++;
   1177                   }
   1178                 if (target_channels > 3)
   1179                   {
   1180                     SetPixelBlack(image,ScaleShortToQuantum(*p),q);
   1181                     p++;
   1182                   }
   1183                 q+=GetPixelChannels(image);
   1184               }
   1185               sync=SyncCacheViewAuthenticPixels(image_view,exception);
   1186               if (sync == MagickFalse)
   1187                 status=MagickFalse;
   1188               if (image->progress_monitor != (MagickProgressMonitor) NULL)
   1189                 {
   1190                   MagickBooleanType
   1191                     proceed;
   1192 
   1193 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   1194                   #pragma omp critical (MagickCore_ProfileImage)
   1195 #endif
   1196                   proceed=SetImageProgress(image,ProfileImageTag,progress++,
   1197                     image->rows);
   1198                   if (proceed == MagickFalse)
   1199                     status=MagickFalse;
   1200                 }
   1201             }
   1202             image_view=DestroyCacheView(image_view);
   1203             (void) SetImageColorspace(image,target_colorspace,exception);
   1204             switch (signature)
   1205             {
   1206               case cmsSigRgbData:
   1207               {
   1208                 image->type=image->alpha_trait == UndefinedPixelTrait ?
   1209                   TrueColorType : TrueColorAlphaType;
   1210                 break;
   1211               }
   1212               case cmsSigCmykData:
   1213               {
   1214                 image->type=image->alpha_trait == UndefinedPixelTrait ?
   1215                   ColorSeparationType : ColorSeparationAlphaType;
   1216                 break;
   1217               }
   1218               case cmsSigGrayData:
   1219               {
   1220                 image->type=image->alpha_trait == UndefinedPixelTrait ?
   1221                   GrayscaleType : GrayscaleAlphaType;
   1222                 break;
   1223               }
   1224               default:
   1225                 break;
   1226             }
   1227             target_pixels=DestroyPixelThreadSet(target_pixels);
   1228             source_pixels=DestroyPixelThreadSet(source_pixels);
   1229             transform=DestroyTransformThreadSet(transform);
   1230             if ((status != MagickFalse) &&
   1231                 (cmsGetDeviceClass(source_profile) != cmsSigLinkClass))
   1232               status=SetImageProfile(image,name,profile,exception);
   1233             if (target_profile != (cmsHPROFILE) NULL)
   1234               (void) cmsCloseProfile(target_profile);
   1235           }
   1236         (void) cmsCloseProfile(source_profile);
   1237       }
   1238 #endif
   1239     }
   1240   profile=DestroyStringInfo(profile);
   1241   return(status);
   1242 }
   1243 
   1244 /*
   1246 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1247 %                                                                             %
   1248 %                                                                             %
   1249 %                                                                             %
   1250 %   R e m o v e I m a g e P r o f i l e                                       %
   1251 %                                                                             %
   1252 %                                                                             %
   1253 %                                                                             %
   1254 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1255 %
   1256 %  RemoveImageProfile() removes a named profile from the image and returns its
   1257 %  value.
   1258 %
   1259 %  The format of the RemoveImageProfile method is:
   1260 %
   1261 %      void *RemoveImageProfile(Image *image,const char *name)
   1262 %
   1263 %  A description of each parameter follows:
   1264 %
   1265 %    o image: the image.
   1266 %
   1267 %    o name: the profile name.
   1268 %
   1269 */
   1270 MagickExport StringInfo *RemoveImageProfile(Image *image,const char *name)
   1271 {
   1272   StringInfo
   1273     *profile;
   1274 
   1275   assert(image != (Image *) NULL);
   1276   assert(image->signature == MagickCoreSignature);
   1277   if (image->debug != MagickFalse)
   1278     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   1279   if (image->profiles == (SplayTreeInfo *) NULL)
   1280     return((StringInfo *) NULL);
   1281   WriteTo8BimProfile(image,name,(StringInfo *) NULL);
   1282   profile=(StringInfo *) RemoveNodeFromSplayTree((SplayTreeInfo *)
   1283     image->profiles,name);
   1284   return(profile);
   1285 }
   1286 
   1287 /*
   1289 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1290 %                                                                             %
   1291 %                                                                             %
   1292 %                                                                             %
   1293 %   R e s e t P r o f i l e I t e r a t o r                                   %
   1294 %                                                                             %
   1295 %                                                                             %
   1296 %                                                                             %
   1297 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1298 %
   1299 %  ResetImageProfileIterator() resets the image profile iterator.  Use it in
   1300 %  conjunction with GetNextImageProfile() to iterate over all the profiles
   1301 %  associated with an image.
   1302 %
   1303 %  The format of the ResetImageProfileIterator method is:
   1304 %
   1305 %      ResetImageProfileIterator(Image *image)
   1306 %
   1307 %  A description of each parameter follows:
   1308 %
   1309 %    o image: the image.
   1310 %
   1311 */
   1312 MagickExport void ResetImageProfileIterator(const Image *image)
   1313 {
   1314   assert(image != (Image *) NULL);
   1315   assert(image->signature == MagickCoreSignature);
   1316   if (image->debug != MagickFalse)
   1317     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   1318   if (image->profiles == (SplayTreeInfo *) NULL)
   1319     return;
   1320   ResetSplayTreeIterator((SplayTreeInfo *) image->profiles);
   1321 }
   1322 
   1323 /*
   1325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1326 %                                                                             %
   1327 %                                                                             %
   1328 %                                                                             %
   1329 %   S e t I m a g e P r o f i l e                                             %
   1330 %                                                                             %
   1331 %                                                                             %
   1332 %                                                                             %
   1333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1334 %
   1335 %  SetImageProfile() adds a named profile to the image.  If a profile with the
   1336 %  same name already exists, it is replaced.  This method differs from the
   1337 %  ProfileImage() method in that it does not apply CMS color profiles.
   1338 %
   1339 %  The format of the SetImageProfile method is:
   1340 %
   1341 %      MagickBooleanType SetImageProfile(Image *image,const char *name,
   1342 %        const StringInfo *profile)
   1343 %
   1344 %  A description of each parameter follows:
   1345 %
   1346 %    o image: the image.
   1347 %
   1348 %    o name: the profile name, for example icc, exif, and 8bim (8bim is the
   1349 %      Photoshop wrapper for iptc profiles).
   1350 %
   1351 %    o profile: A StringInfo structure that contains the named profile.
   1352 %
   1353 */
   1354 
   1355 static void *DestroyProfile(void *profile)
   1356 {
   1357   return((void *) DestroyStringInfo((StringInfo *) profile));
   1358 }
   1359 
   1360 static inline const unsigned char *ReadResourceByte(const unsigned char *p,
   1361   unsigned char *quantum)
   1362 {
   1363   *quantum=(*p++);
   1364   return(p);
   1365 }
   1366 
   1367 static inline const unsigned char *ReadResourceLong(const unsigned char *p,
   1368   unsigned int *quantum)
   1369 {
   1370   *quantum=(unsigned int) (*p++) << 24;
   1371   *quantum|=(unsigned int) (*p++) << 16;
   1372   *quantum|=(unsigned int) (*p++) << 8;
   1373   *quantum|=(unsigned int) (*p++) << 0;
   1374   return(p);
   1375 }
   1376 
   1377 static inline const unsigned char *ReadResourceShort(const unsigned char *p,
   1378   unsigned short *quantum)
   1379 {
   1380   *quantum=(unsigned short) (*p++) << 8;
   1381   *quantum|=(unsigned short) (*p++);
   1382   return(p);
   1383 }
   1384 
   1385 static inline void WriteResourceLong(unsigned char *p,
   1386   const unsigned int quantum)
   1387 {
   1388   unsigned char
   1389     buffer[4];
   1390 
   1391   buffer[0]=(unsigned char) (quantum >> 24);
   1392   buffer[1]=(unsigned char) (quantum >> 16);
   1393   buffer[2]=(unsigned char) (quantum >> 8);
   1394   buffer[3]=(unsigned char) quantum;
   1395   (void) CopyMagickMemory(p,buffer,4);
   1396 }
   1397 
   1398 static void WriteTo8BimProfile(Image *image,const char *name,
   1399   const StringInfo *profile)
   1400 {
   1401   const unsigned char
   1402     *datum,
   1403     *q;
   1404 
   1405   register const unsigned char
   1406     *p;
   1407 
   1408   size_t
   1409     length;
   1410 
   1411   StringInfo
   1412     *profile_8bim;
   1413 
   1414   ssize_t
   1415     count;
   1416 
   1417   unsigned char
   1418     length_byte;
   1419 
   1420   unsigned int
   1421     value;
   1422 
   1423   unsigned short
   1424     id,
   1425     profile_id;
   1426 
   1427   if (LocaleCompare(name,"icc") == 0)
   1428     profile_id=0x040f;
   1429   else
   1430     if (LocaleCompare(name,"iptc") == 0)
   1431       profile_id=0x0404;
   1432     else
   1433       if (LocaleCompare(name,"xmp") == 0)
   1434         profile_id=0x0424;
   1435       else
   1436         return;
   1437   profile_8bim=(StringInfo *) GetValueFromSplayTree((SplayTreeInfo *)
   1438     image->profiles,"8bim");
   1439   if (profile_8bim == (StringInfo *) NULL)
   1440     return;
   1441   datum=GetStringInfoDatum(profile_8bim);
   1442   length=GetStringInfoLength(profile_8bim);
   1443   for (p=datum; p < (datum+length-16); )
   1444   {
   1445     q=p;
   1446     if (LocaleNCompare((char *) p,"8BIM",4) != 0)
   1447       break;
   1448     p+=4;
   1449     p=ReadResourceShort(p,&id);
   1450     p=ReadResourceByte(p,&length_byte);
   1451     p+=length_byte;
   1452     if (((length_byte+1) & 0x01) != 0)
   1453       p++;
   1454     if (p > (datum+length-4))
   1455       break;
   1456     p=ReadResourceLong(p,&value);
   1457     count=(ssize_t) value;
   1458     if ((count & 0x01) != 0)
   1459       count++;
   1460     if ((count < 0) || (p > (datum+length-count)) ||
   1461         (count > (ssize_t) length))
   1462       break;
   1463     if (id != profile_id)
   1464       p+=count;
   1465     else
   1466       {
   1467         size_t
   1468           extent,
   1469           offset;
   1470 
   1471         ssize_t
   1472           extract_count;
   1473 
   1474         StringInfo
   1475           *extract_profile;
   1476 
   1477         extract_count=0;
   1478         extent=(datum+length)-(p+count);
   1479         if (profile == (StringInfo *) NULL)
   1480           {
   1481             offset=(q-datum);
   1482             extract_profile=AcquireStringInfo(offset+extent);
   1483             (void) CopyMagickMemory(extract_profile->datum,datum,offset);
   1484           }
   1485         else
   1486           {
   1487             offset=(p-datum);
   1488             extract_count=profile->length;
   1489             if ((extract_count & 0x01) != 0)
   1490               extract_count++;
   1491             extract_profile=AcquireStringInfo(offset+extract_count+extent);
   1492             (void) CopyMagickMemory(extract_profile->datum,datum,offset-4);
   1493             WriteResourceLong(extract_profile->datum+offset-4,
   1494               (unsigned int)profile->length);
   1495             (void) CopyMagickMemory(extract_profile->datum+offset,
   1496               profile->datum,profile->length);
   1497           }
   1498         (void) CopyMagickMemory(extract_profile->datum+offset+extract_count,
   1499           p+count,extent);
   1500         (void) AddValueToSplayTree((SplayTreeInfo *) image->profiles,
   1501           ConstantString("8bim"),CloneStringInfo(extract_profile));
   1502         extract_profile=DestroyStringInfo(extract_profile);
   1503         break;
   1504       }
   1505   }
   1506 }
   1507 
   1508 static void GetProfilesFromResourceBlock(Image *image,
   1509   const StringInfo *resource_block,ExceptionInfo *exception)
   1510 {
   1511   const unsigned char
   1512     *datum;
   1513 
   1514   register const unsigned char
   1515     *p;
   1516 
   1517   size_t
   1518     length;
   1519 
   1520   ssize_t
   1521     count;
   1522 
   1523   StringInfo
   1524     *profile;
   1525 
   1526   unsigned char
   1527     length_byte;
   1528 
   1529    unsigned int
   1530      value;
   1531 
   1532   unsigned short
   1533     id;
   1534 
   1535   datum=GetStringInfoDatum(resource_block);
   1536   length=GetStringInfoLength(resource_block);
   1537   for (p=datum; p < (datum+length-16); )
   1538   {
   1539     if (LocaleNCompare((char *) p,"8BIM",4) != 0)
   1540       break;
   1541     p+=4;
   1542     p=ReadResourceShort(p,&id);
   1543     p=ReadResourceByte(p,&length_byte);
   1544     p+=length_byte;
   1545     if (((length_byte+1) & 0x01) != 0)
   1546       p++;
   1547     if (p > (datum+length-4))
   1548       break;
   1549     p=ReadResourceLong(p,&value);
   1550     count=(ssize_t) value;
   1551     if ((p > (datum+length-count)) || (count > (ssize_t) length) ||
   1552         (count < 0))
   1553       break;
   1554     switch (id)
   1555     {
   1556       case 0x03ed:
   1557       {
   1558         unsigned int
   1559           resolution;
   1560 
   1561         unsigned short
   1562           units;
   1563 
   1564         /*
   1565           Resolution.
   1566         */
   1567         p=ReadResourceLong(p,&resolution);
   1568         image->resolution.x=((double) resolution)/65536.0;
   1569         p=ReadResourceShort(p,&units)+2;
   1570         p=ReadResourceLong(p,&resolution)+4;
   1571         image->resolution.y=((double) resolution)/65536.0;
   1572         /*
   1573           Values are always stored as pixels per inch.
   1574         */
   1575         if ((ResolutionType) units != PixelsPerCentimeterResolution)
   1576           image->units=PixelsPerInchResolution;
   1577         else
   1578           {
   1579             image->units=PixelsPerCentimeterResolution;
   1580             image->resolution.x/=2.54;
   1581             image->resolution.y/=2.54;
   1582           }
   1583         break;
   1584       }
   1585       case 0x0404:
   1586       {
   1587         /*
   1588           IPTC Profile
   1589         */
   1590         profile=AcquireStringInfo(count);
   1591         SetStringInfoDatum(profile,p);
   1592         (void) SetImageProfileInternal(image,"iptc",profile,MagickTrue,
   1593           exception);
   1594         profile=DestroyStringInfo(profile);
   1595         p+=count;
   1596         break;
   1597       }
   1598       case 0x040c:
   1599       {
   1600         /*
   1601           Thumbnail.
   1602         */
   1603         p+=count;
   1604         break;
   1605       }
   1606       case 0x040f:
   1607       {
   1608         /*
   1609           ICC Profile.
   1610         */
   1611         profile=AcquireStringInfo(count);
   1612         SetStringInfoDatum(profile,p);
   1613         (void) SetImageProfileInternal(image,"icc",profile,MagickTrue,
   1614           exception);
   1615         profile=DestroyStringInfo(profile);
   1616         p+=count;
   1617         break;
   1618       }
   1619       case 0x0422:
   1620       {
   1621         /*
   1622           EXIF Profile.
   1623         */
   1624         profile=AcquireStringInfo(count);
   1625         SetStringInfoDatum(profile,p);
   1626         (void) SetImageProfileInternal(image,"exif",profile,MagickTrue,
   1627           exception);
   1628         profile=DestroyStringInfo(profile);
   1629         p+=count;
   1630         break;
   1631       }
   1632       case 0x0424:
   1633       {
   1634         /*
   1635           XMP Profile.
   1636         */
   1637         profile=AcquireStringInfo(count);
   1638         SetStringInfoDatum(profile,p);
   1639         (void) SetImageProfileInternal(image,"xmp",profile,MagickTrue,
   1640           exception);
   1641         profile=DestroyStringInfo(profile);
   1642         p+=count;
   1643         break;
   1644       }
   1645       default:
   1646       {
   1647         p+=count;
   1648         break;
   1649       }
   1650     }
   1651     if ((count & 0x01) != 0)
   1652       p++;
   1653   }
   1654 }
   1655 
   1656 static MagickBooleanType SetImageProfileInternal(Image *image,const char *name,
   1657   const StringInfo *profile,const MagickBooleanType recursive,
   1658   ExceptionInfo *exception)
   1659 {
   1660   char
   1661     key[MagickPathExtent],
   1662     property[MagickPathExtent];
   1663 
   1664   MagickBooleanType
   1665     status;
   1666 
   1667   assert(image != (Image *) NULL);
   1668   assert(image->signature == MagickCoreSignature);
   1669   if (image->debug != MagickFalse)
   1670     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   1671   if (image->profiles == (SplayTreeInfo *) NULL)
   1672     image->profiles=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
   1673       DestroyProfile);
   1674   (void) CopyMagickString(key,name,MagickPathExtent);
   1675   LocaleLower(key);
   1676   status=AddValueToSplayTree((SplayTreeInfo *) image->profiles,
   1677     ConstantString(key),CloneStringInfo(profile));
   1678   if (status != MagickFalse)
   1679     {
   1680       if (LocaleCompare(name,"8bim") == 0)
   1681         GetProfilesFromResourceBlock(image,profile,exception);
   1682       else if (recursive == MagickFalse)
   1683         WriteTo8BimProfile(image,name,profile);
   1684     }
   1685   /*
   1686     Inject profile into image properties.
   1687   */
   1688   (void) FormatLocaleString(property,MagickPathExtent,"%s:*",name);
   1689   (void) GetImageProperty(image,property,exception);
   1690   return(status);
   1691 }
   1692 
   1693 MagickExport MagickBooleanType SetImageProfile(Image *image,const char *name,
   1694   const StringInfo *profile,ExceptionInfo *exception)
   1695 {
   1696   return(SetImageProfileInternal(image,name,profile,MagickFalse,exception));
   1697 }
   1698 
   1699 /*
   1701 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1702 %                                                                             %
   1703 %                                                                             %
   1704 %                                                                             %
   1705 %   S y n c I m a g e P r o f i l e s                                         %
   1706 %                                                                             %
   1707 %                                                                             %
   1708 %                                                                             %
   1709 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1710 %
   1711 %  SyncImageProfiles() synchronizes image properties with the image profiles.
   1712 %  Currently we only support updating the EXIF resolution and orientation.
   1713 %
   1714 %  The format of the SyncImageProfiles method is:
   1715 %
   1716 %      MagickBooleanType SyncImageProfiles(Image *image)
   1717 %
   1718 %  A description of each parameter follows:
   1719 %
   1720 %    o image: the image.
   1721 %
   1722 */
   1723 
   1724 static inline int ReadProfileByte(unsigned char **p,size_t *length)
   1725 {
   1726   int
   1727     c;
   1728 
   1729   if (*length < 1)
   1730     return(EOF);
   1731   c=(int) (*(*p)++);
   1732   (*length)--;
   1733   return(c);
   1734 }
   1735 
   1736 static inline signed short ReadProfileShort(const EndianType endian,
   1737   unsigned char *buffer)
   1738 {
   1739   union
   1740   {
   1741     unsigned int
   1742       unsigned_value;
   1743 
   1744     signed int
   1745       signed_value;
   1746   } quantum;
   1747 
   1748   unsigned short
   1749     value;
   1750 
   1751   if (endian == LSBEndian)
   1752     {
   1753       value=(unsigned short) buffer[1] << 8;
   1754       value|=(unsigned short) buffer[0];
   1755       quantum.unsigned_value=value & 0xffff;
   1756       return(quantum.signed_value);
   1757     }
   1758   value=(unsigned short) buffer[0] << 8;
   1759   value|=(unsigned short) buffer[1];
   1760   quantum.unsigned_value=value & 0xffff;
   1761   return(quantum.signed_value);
   1762 }
   1763 
   1764 static inline signed int ReadProfileLong(const EndianType endian,
   1765   unsigned char *buffer)
   1766 {
   1767   union
   1768   {
   1769     unsigned int
   1770       unsigned_value;
   1771 
   1772     signed int
   1773       signed_value;
   1774   } quantum;
   1775 
   1776   unsigned int
   1777     value;
   1778 
   1779   if (endian == LSBEndian)
   1780     {
   1781       value=(unsigned int) buffer[3] << 24;
   1782       value|=(unsigned int) buffer[2] << 16;
   1783       value|=(unsigned int) buffer[1] << 8;
   1784       value|=(unsigned int) buffer[0];
   1785       quantum.unsigned_value=value & 0xffffffff;
   1786       return(quantum.signed_value);
   1787     }
   1788   value=(unsigned int) buffer[0] << 24;
   1789   value|=(unsigned int) buffer[1] << 16;
   1790   value|=(unsigned int) buffer[2] << 8;
   1791   value|=(unsigned int) buffer[3];
   1792   quantum.unsigned_value=value & 0xffffffff;
   1793   return(quantum.signed_value);
   1794 }
   1795 
   1796 static inline signed int ReadProfileMSBLong(unsigned char **p,size_t *length)
   1797 {
   1798   signed int
   1799     value;
   1800 
   1801   if (*length < 4)
   1802     return(0);
   1803   value=ReadProfileLong(MSBEndian,*p);
   1804   (*length)-=4;
   1805   *p+=4;
   1806   return(value);
   1807 }
   1808 
   1809 static inline signed short ReadProfileMSBShort(unsigned char **p,
   1810   size_t *length)
   1811 {
   1812   signed short
   1813     value;
   1814 
   1815   if (*length < 2)
   1816     return(0);
   1817   value=ReadProfileShort(MSBEndian,*p);
   1818   (*length)-=2;
   1819   *p+=2;
   1820   return(value);
   1821 }
   1822 
   1823 static inline void WriteProfileLong(const EndianType endian,
   1824   const size_t value,unsigned char *p)
   1825 {
   1826   unsigned char
   1827     buffer[4];
   1828 
   1829   if (endian == LSBEndian)
   1830     {
   1831       buffer[0]=(unsigned char) value;
   1832       buffer[1]=(unsigned char) (value >> 8);
   1833       buffer[2]=(unsigned char) (value >> 16);
   1834       buffer[3]=(unsigned char) (value >> 24);
   1835       (void) CopyMagickMemory(p,buffer,4);
   1836       return;
   1837     }
   1838   buffer[0]=(unsigned char) (value >> 24);
   1839   buffer[1]=(unsigned char) (value >> 16);
   1840   buffer[2]=(unsigned char) (value >> 8);
   1841   buffer[3]=(unsigned char) value;
   1842   (void) CopyMagickMemory(p,buffer,4);
   1843 }
   1844 
   1845 static void WriteProfileShort(const EndianType endian,
   1846   const unsigned short value,unsigned char *p)
   1847 {
   1848   unsigned char
   1849     buffer[2];
   1850 
   1851   if (endian == LSBEndian)
   1852     {
   1853       buffer[0]=(unsigned char) value;
   1854       buffer[1]=(unsigned char) (value >> 8);
   1855       (void) CopyMagickMemory(p,buffer,2);
   1856       return;
   1857     }
   1858   buffer[0]=(unsigned char) (value >> 8);
   1859   buffer[1]=(unsigned char) value;
   1860   (void) CopyMagickMemory(p,buffer,2);
   1861 }
   1862 
   1863 static MagickBooleanType Sync8BimProfile(Image *image,StringInfo *profile)
   1864 {
   1865   size_t
   1866     length;
   1867 
   1868   ssize_t
   1869     count;
   1870 
   1871   unsigned char
   1872     *p;
   1873 
   1874   unsigned short
   1875     id;
   1876 
   1877   length=GetStringInfoLength(profile);
   1878   p=GetStringInfoDatum(profile);
   1879   while (length != 0)
   1880   {
   1881     if (ReadProfileByte(&p,&length) != 0x38)
   1882       continue;
   1883     if (ReadProfileByte(&p,&length) != 0x42)
   1884       continue;
   1885     if (ReadProfileByte(&p,&length) != 0x49)
   1886       continue;
   1887     if (ReadProfileByte(&p,&length) != 0x4D)
   1888       continue;
   1889     if (length < 7)
   1890       return(MagickFalse);
   1891     id=ReadProfileMSBShort(&p,&length);
   1892     count=(ssize_t) ReadProfileByte(&p,&length);
   1893     if ((count > (ssize_t) length) || (count < 0))
   1894       return(MagickFalse);
   1895     p+=count;
   1896     if ((*p & 0x01) == 0)
   1897       (void) ReadProfileByte(&p,&length);
   1898     count=(ssize_t) ReadProfileMSBLong(&p,&length);
   1899     if ((count > (ssize_t) length) || (count < 0))
   1900       return(MagickFalse);
   1901     if ((id == 0x3ED) && (count == 16))
   1902       {
   1903         if (image->units == PixelsPerCentimeterResolution)
   1904           WriteProfileLong(MSBEndian, (unsigned int) (image->resolution.x*2.54*
   1905             65536.0),p);
   1906         else
   1907           WriteProfileLong(MSBEndian, (unsigned int) (image->resolution.x*
   1908             65536.0),p);
   1909         WriteProfileShort(MSBEndian,(unsigned short) image->units,p+4);
   1910         if (image->units == PixelsPerCentimeterResolution)
   1911           WriteProfileLong(MSBEndian, (unsigned int) (image->resolution.y*2.54*
   1912             65536.0),p+8);
   1913         else
   1914           WriteProfileLong(MSBEndian, (unsigned int) (image->resolution.y*
   1915             65536.0),p+8);
   1916         WriteProfileShort(MSBEndian,(unsigned short) image->units,p+12);
   1917       }
   1918     p+=count;
   1919     length-=count;
   1920   }
   1921   return(MagickTrue);
   1922 }
   1923 
   1924 MagickBooleanType SyncExifProfile(Image *image,StringInfo *profile)
   1925 {
   1926 #define MaxDirectoryStack  16
   1927 #define EXIF_DELIMITER  "\n"
   1928 #define EXIF_NUM_FORMATS  12
   1929 #define TAG_EXIF_OFFSET  0x8769
   1930 #define TAG_INTEROP_OFFSET  0xa005
   1931 
   1932   typedef struct _DirectoryInfo
   1933   {
   1934     unsigned char
   1935       *directory;
   1936 
   1937     size_t
   1938       entry;
   1939   } DirectoryInfo;
   1940 
   1941   DirectoryInfo
   1942     directory_stack[MaxDirectoryStack];
   1943 
   1944   EndianType
   1945     endian;
   1946 
   1947   size_t
   1948     entry,
   1949     length,
   1950     number_entries;
   1951 
   1952   ssize_t
   1953     id,
   1954     level,
   1955     offset;
   1956 
   1957   static int
   1958     format_bytes[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
   1959 
   1960   unsigned char
   1961     *directory,
   1962     *exif;
   1963 
   1964   /*
   1965     Set EXIF resolution tag.
   1966   */
   1967   length=GetStringInfoLength(profile);
   1968   exif=GetStringInfoDatum(profile);
   1969   if (length < 16)
   1970     return(MagickFalse);
   1971   id=(ssize_t) ReadProfileShort(LSBEndian,exif);
   1972   if ((id != 0x4949) && (id != 0x4D4D))
   1973     {
   1974       while (length != 0)
   1975       {
   1976         if (ReadProfileByte(&exif,&length) != 0x45)
   1977           continue;
   1978         if (ReadProfileByte(&exif,&length) != 0x78)
   1979           continue;
   1980         if (ReadProfileByte(&exif,&length) != 0x69)
   1981           continue;
   1982         if (ReadProfileByte(&exif,&length) != 0x66)
   1983           continue;
   1984         if (ReadProfileByte(&exif,&length) != 0x00)
   1985           continue;
   1986         if (ReadProfileByte(&exif,&length) != 0x00)
   1987           continue;
   1988         break;
   1989       }
   1990       if (length < 16)
   1991         return(MagickFalse);
   1992       id=(ssize_t) ReadProfileShort(LSBEndian,exif);
   1993     }
   1994   endian=LSBEndian;
   1995   if (id == 0x4949)
   1996     endian=LSBEndian;
   1997   else
   1998     if (id == 0x4D4D)
   1999       endian=MSBEndian;
   2000     else
   2001       return(MagickFalse);
   2002   if (ReadProfileShort(endian,exif+2) != 0x002a)
   2003     return(MagickFalse);
   2004   /*
   2005     This the offset to the first IFD.
   2006   */
   2007   offset=(ssize_t) ReadProfileLong(endian,exif+4);
   2008   if ((offset < 0) || (size_t) offset >= length)
   2009     return(MagickFalse);
   2010   directory=exif+offset;
   2011   level=0;
   2012   entry=0;
   2013   do
   2014   {
   2015     if (level > 0)
   2016       {
   2017         level--;
   2018         directory=directory_stack[level].directory;
   2019         entry=directory_stack[level].entry;
   2020       }
   2021     if ((directory < exif) || (directory > (exif+length-2)))
   2022       break;
   2023     /*
   2024       Determine how many entries there are in the current IFD.
   2025     */
   2026     number_entries=ReadProfileShort(endian,directory);
   2027     for ( ; entry < number_entries; entry++)
   2028     {
   2029       int
   2030         components;
   2031 
   2032       register unsigned char
   2033         *p,
   2034         *q;
   2035 
   2036       size_t
   2037         number_bytes;
   2038 
   2039       ssize_t
   2040         format,
   2041         tag_value;
   2042 
   2043       q=(unsigned char *) (directory+2+(12*entry));
   2044       if (q > (exif+length-12))
   2045         break;  /* corrupt EXIF */
   2046       tag_value=(ssize_t) ReadProfileShort(endian,q);
   2047       format=(ssize_t) ReadProfileShort(endian,q+2);
   2048       if ((format-1) >= EXIF_NUM_FORMATS)
   2049         break;
   2050       components=(ssize_t) ReadProfileLong(endian,q+4);
   2051       if (components < 0)
   2052         break;  /* corrupt EXIF */
   2053       number_bytes=(size_t) components*format_bytes[format];
   2054       if ((ssize_t) number_bytes < components)
   2055         break;  /* prevent overflow */
   2056       if (number_bytes <= 4)
   2057         p=q+8;
   2058       else
   2059         {
   2060           /*
   2061             The directory entry contains an offset.
   2062           */
   2063           offset=(ssize_t)  ReadProfileLong(endian,q+8);
   2064           if ((size_t) (offset+number_bytes) > length)
   2065             continue;
   2066           if (~length < number_bytes)
   2067             continue;  /* prevent overflow */
   2068           p=(unsigned char *) (exif+offset);
   2069         }
   2070       switch (tag_value)
   2071       {
   2072         case 0x011a:
   2073         {
   2074           (void) WriteProfileLong(endian,(size_t) (image->resolution.x+0.5),p);
   2075           (void) WriteProfileLong(endian,1UL,p+4);
   2076           break;
   2077         }
   2078         case 0x011b:
   2079         {
   2080           (void) WriteProfileLong(endian,(size_t) (image->resolution.y+0.5),p);
   2081           (void) WriteProfileLong(endian,1UL,p+4);
   2082           break;
   2083         }
   2084         case 0x0112:
   2085         {
   2086           if (number_bytes == 4)
   2087             {
   2088               (void) WriteProfileLong(endian,(size_t) image->orientation,p);
   2089               break;
   2090             }
   2091           (void) WriteProfileShort(endian,(unsigned short) image->orientation,
   2092             p);
   2093           break;
   2094         }
   2095         case 0x0128:
   2096         {
   2097           if (number_bytes == 4)
   2098             {
   2099               (void) WriteProfileLong(endian,(size_t) (image->units+1),p);
   2100               break;
   2101             }
   2102           (void) WriteProfileShort(endian,(unsigned short) (image->units+1),p);
   2103           break;
   2104         }
   2105         default:
   2106           break;
   2107       }
   2108       if ((tag_value == TAG_EXIF_OFFSET) || (tag_value == TAG_INTEROP_OFFSET))
   2109         {
   2110           offset=(ssize_t)  ReadProfileLong(endian,p);
   2111           if (((size_t) offset < length) && (level < (MaxDirectoryStack-2)))
   2112             {
   2113               directory_stack[level].directory=directory;
   2114               entry++;
   2115               directory_stack[level].entry=entry;
   2116               level++;
   2117               directory_stack[level].directory=exif+offset;
   2118               directory_stack[level].entry=0;
   2119               level++;
   2120               if ((directory+2+(12*number_entries)) > (exif+length))
   2121                 break;
   2122               offset=(ssize_t)  ReadProfileLong(endian,directory+2+(12*
   2123                 number_entries));
   2124               if ((offset != 0) && ((size_t) offset < length) &&
   2125                   (level < (MaxDirectoryStack-2)))
   2126                 {
   2127                   directory_stack[level].directory=exif+offset;
   2128                   directory_stack[level].entry=0;
   2129                   level++;
   2130                 }
   2131             }
   2132           break;
   2133         }
   2134     }
   2135   } while (level > 0);
   2136   return(MagickTrue);
   2137 }
   2138 
   2139 MagickPrivate MagickBooleanType SyncImageProfiles(Image *image)
   2140 {
   2141   MagickBooleanType
   2142     status;
   2143 
   2144   StringInfo
   2145     *profile;
   2146 
   2147   status=MagickTrue;
   2148   profile=(StringInfo *) GetImageProfile(image,"8BIM");
   2149   if (profile != (StringInfo *) NULL)
   2150     if (Sync8BimProfile(image,profile) == MagickFalse)
   2151       status=MagickFalse;
   2152   profile=(StringInfo *) GetImageProfile(image,"EXIF");
   2153   if (profile != (StringInfo *) NULL)
   2154     if (SyncExifProfile(image,profile) == MagickFalse)
   2155       status=MagickFalse;
   2156   return(status);
   2157 }
   2158