2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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 %
10 % P R R OOO F IIIII LLLLL EEEEE %
13 % MagickCore Image Profile Methods %
20 % Copyright 1999-2015 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
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. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42 #include "MagickCore/studio.h"
43 #include "MagickCore/attribute.h"
44 #include "MagickCore/cache.h"
45 #include "MagickCore/color.h"
46 #include "MagickCore/colorspace-private.h"
47 #include "MagickCore/configure.h"
48 #include "MagickCore/exception.h"
49 #include "MagickCore/exception-private.h"
50 #include "MagickCore/hashmap.h"
51 #include "MagickCore/image.h"
52 #include "MagickCore/memory_.h"
53 #include "MagickCore/monitor.h"
54 #include "MagickCore/monitor-private.h"
55 #include "MagickCore/option.h"
56 #include "MagickCore/option-private.h"
57 #include "MagickCore/pixel-accessor.h"
58 #include "MagickCore/profile.h"
59 #include "MagickCore/profile-private.h"
60 #include "MagickCore/property.h"
61 #include "MagickCore/quantum.h"
62 #include "MagickCore/quantum-private.h"
63 #include "MagickCore/resource_.h"
64 #include "MagickCore/splay-tree.h"
65 #include "MagickCore/string_.h"
66 #include "MagickCore/thread-private.h"
67 #include "MagickCore/token.h"
68 #include "MagickCore/utility.h"
69 #if defined(MAGICKCORE_LCMS_DELEGATE)
70 #if defined(MAGICKCORE_HAVE_LCMS_LCMS2_H)
72 #include <lcms/lcms2.h>
82 static MagickBooleanType
83 SetImageProfileInternal(Image *,const char *,const StringInfo *,
84 const MagickBooleanType,ExceptionInfo *);
87 WriteTo8BimProfile(Image *,const char*,const StringInfo *);
107 typedef struct _CMSExceptionInfo
117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
121 % C l o n e I m a g e P r o f i l e s %
125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
127 % CloneImageProfiles() clones one or more image profiles.
129 % The format of the CloneImageProfiles method is:
131 % MagickBooleanType CloneImageProfiles(Image *image,
132 % const Image *clone_image)
134 % A description of each parameter follows:
136 % o image: the image.
138 % o clone_image: the clone image.
141 MagickExport MagickBooleanType CloneImageProfiles(Image *image,
142 const Image *clone_image)
144 assert(image != (Image *) NULL);
145 assert(image->signature == MagickCoreSignature);
146 if (image->debug != MagickFalse)
147 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
148 assert(clone_image != (const Image *) NULL);
149 assert(clone_image->signature == MagickCoreSignature);
150 if (clone_image->profiles != (void *) NULL)
152 if (image->profiles != (void *) NULL)
153 DestroyImageProfiles(image);
154 image->profiles=CloneSplayTree((SplayTreeInfo *) clone_image->profiles,
155 (void *(*)(void *)) ConstantString,(void *(*)(void *)) CloneStringInfo);
161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
165 % D e l e t e I m a g e P r o f i l e %
169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171 % DeleteImageProfile() deletes a profile from the image by its name.
173 % The format of the DeleteImageProfile method is:
175 % MagickBooleanTyupe DeleteImageProfile(Image *image,const char *name)
177 % A description of each parameter follows:
179 % o image: the image.
181 % o name: the profile name.
184 MagickExport MagickBooleanType DeleteImageProfile(Image *image,const char *name)
186 assert(image != (Image *) NULL);
187 assert(image->signature == MagickCoreSignature);
188 if (image->debug != MagickFalse)
189 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
190 if (image->profiles == (SplayTreeInfo *) NULL)
192 WriteTo8BimProfile(image,name,(StringInfo *) NULL);
193 return(DeleteNodeFromSplayTree((SplayTreeInfo *) image->profiles,name));
197 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
201 % D e s t r o y I m a g e P r o f i l e s %
205 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
207 % DestroyImageProfiles() releases memory associated with an image profile map.
209 % The format of the DestroyProfiles method is:
211 % void DestroyImageProfiles(Image *image)
213 % A description of each parameter follows:
215 % o image: the image.
218 MagickExport void DestroyImageProfiles(Image *image)
220 if (image->profiles != (SplayTreeInfo *) NULL)
221 image->profiles=DestroySplayTree((SplayTreeInfo *) image->profiles);
225 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
229 % G e t I m a g e P r o f i l e %
233 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
235 % GetImageProfile() gets a profile associated with an image by name.
237 % The format of the GetImageProfile method is:
239 % const StringInfo *GetImageProfile(const Image *image,const char *name)
241 % A description of each parameter follows:
243 % o image: the image.
245 % o name: the profile name.
248 MagickExport const StringInfo *GetImageProfile(const Image *image,
254 assert(image != (Image *) NULL);
255 assert(image->signature == MagickCoreSignature);
256 if (image->debug != MagickFalse)
257 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
258 if (image->profiles == (SplayTreeInfo *) NULL)
259 return((StringInfo *) NULL);
260 profile=(const StringInfo *) GetValueFromSplayTree((SplayTreeInfo *)
261 image->profiles,name);
266 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
270 % G e t N e x t I m a g e P r o f i l e %
274 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
276 % GetNextImageProfile() gets the next profile name for an image.
278 % The format of the GetNextImageProfile method is:
280 % char *GetNextImageProfile(const Image *image)
282 % A description of each parameter follows:
284 % o hash_info: the hash info.
287 MagickExport char *GetNextImageProfile(const Image *image)
289 assert(image != (Image *) NULL);
290 assert(image->signature == MagickCoreSignature);
291 if (image->debug != MagickFalse)
292 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
293 if (image->profiles == (SplayTreeInfo *) NULL)
294 return((char *) NULL);
295 return((char *) GetNextKeyInSplayTree((SplayTreeInfo *) image->profiles));
299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
303 % P r o f i l e I m a g e %
307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
309 % ProfileImage() associates, applies, or removes an ICM, IPTC, or generic
310 % profile with / to / from an image. If the profile is NULL, it is removed
311 % from the image otherwise added or applied. Use a name of '*' and a profile
312 % of NULL to remove all profiles from the image.
314 % ICC and ICM profiles are handled as follows: If the image does not have
315 % an associated color profile, the one you provide is associated with the
316 % image and the image pixels are not transformed. Otherwise, the colorspace
317 % transform defined by the existing and new profile are applied to the image
318 % pixels and the new profile is associated with the image.
320 % The format of the ProfileImage method is:
322 % MagickBooleanType ProfileImage(Image *image,const char *name,
323 % const void *datum,const size_t length,const MagickBooleanType clone)
325 % A description of each parameter follows:
327 % o image: the image.
329 % o name: Name of profile to add or remove: ICC, IPTC, or generic profile.
331 % o datum: the profile data.
333 % o length: the length of the profile.
335 % o clone: should be MagickFalse.
339 #if defined(MAGICKCORE_LCMS_DELEGATE)
340 static unsigned short **DestroyPixelThreadSet(unsigned short **pixels)
345 assert(pixels != (unsigned short **) NULL);
346 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
347 if (pixels[i] != (unsigned short *) NULL)
348 pixels[i]=(unsigned short *) RelinquishMagickMemory(pixels[i]);
349 pixels=(unsigned short **) RelinquishMagickMemory(pixels);
353 static unsigned short **AcquirePixelThreadSet(const size_t columns,
354 const size_t channels)
365 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
366 pixels=(unsigned short **) AcquireQuantumMemory(number_threads,
368 if (pixels == (unsigned short **) NULL)
369 return((unsigned short **) NULL);
370 (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
371 for (i=0; i < (ssize_t) number_threads; i++)
373 pixels[i]=(unsigned short *) AcquireQuantumMemory(columns,channels*
375 if (pixels[i] == (unsigned short *) NULL)
376 return(DestroyPixelThreadSet(pixels));
381 static cmsHTRANSFORM *DestroyTransformThreadSet(cmsHTRANSFORM *transform)
386 assert(transform != (cmsHTRANSFORM *) NULL);
387 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
388 if (transform[i] != (cmsHTRANSFORM) NULL)
389 cmsDeleteTransform(transform[i]);
390 transform=(cmsHTRANSFORM *) RelinquishMagickMemory(transform);
394 static cmsHTRANSFORM *AcquireTransformThreadSet(Image *image,
395 const cmsHPROFILE source_profile,const cmsUInt32Number source_type,
396 const cmsHPROFILE target_profile,const cmsUInt32Number target_type,
397 const int intent,const cmsUInt32Number flags)
408 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
409 transform=(cmsHTRANSFORM *) AcquireQuantumMemory(number_threads,
411 if (transform == (cmsHTRANSFORM *) NULL)
412 return((cmsHTRANSFORM *) NULL);
413 (void) ResetMagickMemory(transform,0,number_threads*sizeof(*transform));
414 for (i=0; i < (ssize_t) number_threads; i++)
416 transform[i]=cmsCreateTransformTHR((cmsContext) image,source_profile,
417 source_type,target_profile,target_type,intent,flags);
418 if (transform[i] == (cmsHTRANSFORM) NULL)
419 return(DestroyTransformThreadSet(transform));
425 #if defined(MAGICKCORE_LCMS_DELEGATE)
426 static void CMSExceptionHandler(cmsContext context,cmsUInt32Number severity,
438 cms_exception=(CMSExceptionInfo *) context;
439 image=cms_exception->image;
440 exception=cms_exception->exception;
441 if (image == (Image *) NULL)
443 (void) ThrowMagickException(exception,GetMagickModule(),ImageWarning,
444 "UnableToTransformColorspace","`%s'","unknown context");
447 if (image->debug != MagickFalse)
448 (void) LogMagickEvent(TransformEvent,GetMagickModule(),"lcms: #%u, %s",
449 severity,message != (char *) NULL ? message : "no message");
450 (void) ThrowMagickException(exception,GetMagickModule(),ImageWarning,
451 "UnableToTransformColorspace","`%s'",image->filename);
455 static MagickBooleanType SetsRGBImageProfile(Image *image,
456 ExceptionInfo *exception)
461 0x00, 0x00, 0x0c, 0x8c, 0x61, 0x72, 0x67, 0x6c, 0x02, 0x20, 0x00, 0x00,
462 0x6d, 0x6e, 0x74, 0x72, 0x52, 0x47, 0x42, 0x20, 0x58, 0x59, 0x5a, 0x20,
463 0x07, 0xde, 0x00, 0x01, 0x00, 0x06, 0x00, 0x16, 0x00, 0x0f, 0x00, 0x3a,
464 0x61, 0x63, 0x73, 0x70, 0x4d, 0x53, 0x46, 0x54, 0x00, 0x00, 0x00, 0x00,
465 0x49, 0x45, 0x43, 0x20, 0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00, 0x00,
466 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xd6,
467 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d, 0x61, 0x72, 0x67, 0x6c,
468 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
469 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
470 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
471 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
472 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x01, 0x50, 0x00, 0x00, 0x00, 0x99,
473 0x63, 0x70, 0x72, 0x74, 0x00, 0x00, 0x01, 0xec, 0x00, 0x00, 0x00, 0x67,
474 0x64, 0x6d, 0x6e, 0x64, 0x00, 0x00, 0x02, 0x54, 0x00, 0x00, 0x00, 0x70,
475 0x64, 0x6d, 0x64, 0x64, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x00, 0x88,
476 0x74, 0x65, 0x63, 0x68, 0x00, 0x00, 0x03, 0x4c, 0x00, 0x00, 0x00, 0x0c,
477 0x76, 0x75, 0x65, 0x64, 0x00, 0x00, 0x03, 0x58, 0x00, 0x00, 0x00, 0x67,
478 0x76, 0x69, 0x65, 0x77, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x24,
479 0x6c, 0x75, 0x6d, 0x69, 0x00, 0x00, 0x03, 0xe4, 0x00, 0x00, 0x00, 0x14,
480 0x6d, 0x65, 0x61, 0x73, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x24,
481 0x77, 0x74, 0x70, 0x74, 0x00, 0x00, 0x04, 0x1c, 0x00, 0x00, 0x00, 0x14,
482 0x62, 0x6b, 0x70, 0x74, 0x00, 0x00, 0x04, 0x30, 0x00, 0x00, 0x00, 0x14,
483 0x72, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x04, 0x44, 0x00, 0x00, 0x00, 0x14,
484 0x67, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x04, 0x58, 0x00, 0x00, 0x00, 0x14,
485 0x62, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x04, 0x6c, 0x00, 0x00, 0x00, 0x14,
486 0x72, 0x54, 0x52, 0x43, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x08, 0x0c,
487 0x67, 0x54, 0x52, 0x43, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x08, 0x0c,
488 0x62, 0x54, 0x52, 0x43, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x08, 0x0c,
489 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
490 0x73, 0x52, 0x47, 0x42, 0x20, 0x49, 0x45, 0x43, 0x36, 0x31, 0x39, 0x36,
491 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x20, 0x28, 0x45, 0x71, 0x75, 0x69, 0x76,
492 0x61, 0x6c, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x77, 0x77, 0x77,
493 0x2e, 0x73, 0x72, 0x67, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x31, 0x39,
494 0x39, 0x38, 0x20, 0x48, 0x50, 0x20, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c,
495 0x65, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
496 0x00, 0x3f, 0x73, 0x52, 0x47, 0x42, 0x20, 0x49, 0x45, 0x43, 0x36, 0x31,
497 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x20, 0x28, 0x45, 0x71, 0x75,
498 0x69, 0x76, 0x61, 0x6c, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x77,
499 0x77, 0x77, 0x2e, 0x73, 0x72, 0x67, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x20,
500 0x31, 0x39, 0x39, 0x38, 0x20, 0x48, 0x50, 0x20, 0x70, 0x72, 0x6f, 0x66,
501 0x69, 0x6c, 0x65, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
502 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x43, 0x72, 0x65, 0x61,
503 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x47, 0x72, 0x61, 0x65, 0x6d,
504 0x65, 0x20, 0x57, 0x2e, 0x20, 0x47, 0x69, 0x6c, 0x6c, 0x2e, 0x20, 0x52,
505 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x6f,
506 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20,
507 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x20, 0x4e, 0x6f, 0x20, 0x57,
508 0x61, 0x72, 0x72, 0x61, 0x6e, 0x74, 0x79, 0x2c, 0x20, 0x55, 0x73, 0x65,
509 0x20, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75, 0x72, 0x20, 0x6f, 0x77, 0x6e,
510 0x20, 0x72, 0x69, 0x73, 0x6b, 0x2e, 0x00, 0x00, 0x64, 0x65, 0x73, 0x63,
511 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x49, 0x45, 0x43, 0x20,
512 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69,
513 0x65, 0x63, 0x2e, 0x63, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
514 0x00, 0x00, 0x00, 0x00, 0x16, 0x49, 0x45, 0x43, 0x20, 0x68, 0x74, 0x74,
515 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x65, 0x63, 0x2e,
516 0x63, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
517 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
518 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
519 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
520 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e,
521 0x49, 0x45, 0x43, 0x20, 0x36, 0x31, 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e,
522 0x31, 0x20, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x52, 0x47,
523 0x42, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x75, 0x72, 0x20, 0x73, 0x70, 0x61,
524 0x63, 0x65, 0x20, 0x2d, 0x20, 0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00,
525 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x49, 0x45, 0x43,
526 0x20, 0x36, 0x31, 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x20, 0x44,
527 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x52, 0x47, 0x42, 0x20, 0x63,
528 0x6f, 0x6c, 0x6f, 0x75, 0x72, 0x20, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20,
529 0x2d, 0x20, 0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
530 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
531 0x00, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x20, 0x00, 0x00, 0x00, 0x00,
532 0x43, 0x52, 0x54, 0x20, 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00,
533 0x00, 0x00, 0x00, 0x0d, 0x49, 0x45, 0x43, 0x36, 0x31, 0x39, 0x36, 0x36,
534 0x2d, 0x32, 0x2e, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
535 0x00, 0x00, 0x00, 0x0d, 0x49, 0x45, 0x43, 0x36, 0x31, 0x39, 0x36, 0x36,
536 0x2d, 0x32, 0x2e, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
537 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
538 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
539 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
540 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
541 0x76, 0x69, 0x65, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xa4, 0x7c,
542 0x00, 0x14, 0x5f, 0x30, 0x00, 0x10, 0xce, 0x02, 0x00, 0x03, 0xed, 0xb2,
543 0x00, 0x04, 0x13, 0x0a, 0x00, 0x03, 0x5c, 0x67, 0x00, 0x00, 0x00, 0x01,
544 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x0a, 0x3d,
545 0x00, 0x50, 0x00, 0x00, 0x00, 0x57, 0x1e, 0xb8, 0x6d, 0x65, 0x61, 0x73,
546 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
547 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
548 0x00, 0x00, 0x02, 0x8f, 0x00, 0x00, 0x00, 0x02, 0x58, 0x59, 0x5a, 0x20,
549 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x51, 0x00, 0x01, 0x00, 0x00,
550 0x00, 0x01, 0x16, 0xcc, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00,
551 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
552 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xa0,
553 0x00, 0x00, 0x38, 0xf5, 0x00, 0x00, 0x03, 0x90, 0x58, 0x59, 0x5a, 0x20,
554 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x97, 0x00, 0x00, 0xb7, 0x87,
555 0x00, 0x00, 0x18, 0xd9, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00,
556 0x00, 0x00, 0x24, 0x9f, 0x00, 0x00, 0x0f, 0x84, 0x00, 0x00, 0xb6, 0xc4,
557 0x63, 0x75, 0x72, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
558 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x14, 0x00, 0x19,
559 0x00, 0x1e, 0x00, 0x23, 0x00, 0x28, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x37,
560 0x00, 0x3b, 0x00, 0x40, 0x00, 0x45, 0x00, 0x4a, 0x00, 0x4f, 0x00, 0x54,
561 0x00, 0x59, 0x00, 0x5e, 0x00, 0x63, 0x00, 0x68, 0x00, 0x6d, 0x00, 0x72,
562 0x00, 0x77, 0x00, 0x7c, 0x00, 0x81, 0x00, 0x86, 0x00, 0x8b, 0x00, 0x90,
563 0x00, 0x95, 0x00, 0x9a, 0x00, 0x9f, 0x00, 0xa4, 0x00, 0xa9, 0x00, 0xae,
564 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc1, 0x00, 0xc6, 0x00, 0xcb,
565 0x00, 0xd0, 0x00, 0xd5, 0x00, 0xdb, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0xeb,
566 0x00, 0xf0, 0x00, 0xf6, 0x00, 0xfb, 0x01, 0x01, 0x01, 0x07, 0x01, 0x0d,
567 0x01, 0x13, 0x01, 0x19, 0x01, 0x1f, 0x01, 0x25, 0x01, 0x2b, 0x01, 0x32,
568 0x01, 0x38, 0x01, 0x3e, 0x01, 0x45, 0x01, 0x4c, 0x01, 0x52, 0x01, 0x59,
569 0x01, 0x60, 0x01, 0x67, 0x01, 0x6e, 0x01, 0x75, 0x01, 0x7c, 0x01, 0x83,
570 0x01, 0x8b, 0x01, 0x92, 0x01, 0x9a, 0x01, 0xa1, 0x01, 0xa9, 0x01, 0xb1,
571 0x01, 0xb9, 0x01, 0xc1, 0x01, 0xc9, 0x01, 0xd1, 0x01, 0xd9, 0x01, 0xe1,
572 0x01, 0xe9, 0x01, 0xf2, 0x01, 0xfa, 0x02, 0x03, 0x02, 0x0c, 0x02, 0x14,
573 0x02, 0x1d, 0x02, 0x26, 0x02, 0x2f, 0x02, 0x38, 0x02, 0x41, 0x02, 0x4b,
574 0x02, 0x54, 0x02, 0x5d, 0x02, 0x67, 0x02, 0x71, 0x02, 0x7a, 0x02, 0x84,
575 0x02, 0x8e, 0x02, 0x98, 0x02, 0xa2, 0x02, 0xac, 0x02, 0xb6, 0x02, 0xc1,
576 0x02, 0xcb, 0x02, 0xd5, 0x02, 0xe0, 0x02, 0xeb, 0x02, 0xf5, 0x03, 0x00,
577 0x03, 0x0b, 0x03, 0x16, 0x03, 0x21, 0x03, 0x2d, 0x03, 0x38, 0x03, 0x43,
578 0x03, 0x4f, 0x03, 0x5a, 0x03, 0x66, 0x03, 0x72, 0x03, 0x7e, 0x03, 0x8a,
579 0x03, 0x96, 0x03, 0xa2, 0x03, 0xae, 0x03, 0xba, 0x03, 0xc7, 0x03, 0xd3,
580 0x03, 0xe0, 0x03, 0xec, 0x03, 0xf9, 0x04, 0x06, 0x04, 0x13, 0x04, 0x20,
581 0x04, 0x2d, 0x04, 0x3b, 0x04, 0x48, 0x04, 0x55, 0x04, 0x63, 0x04, 0x71,
582 0x04, 0x7e, 0x04, 0x8c, 0x04, 0x9a, 0x04, 0xa8, 0x04, 0xb6, 0x04, 0xc4,
583 0x04, 0xd3, 0x04, 0xe1, 0x04, 0xf0, 0x04, 0xfe, 0x05, 0x0d, 0x05, 0x1c,
584 0x05, 0x2b, 0x05, 0x3a, 0x05, 0x49, 0x05, 0x58, 0x05, 0x67, 0x05, 0x77,
585 0x05, 0x86, 0x05, 0x96, 0x05, 0xa6, 0x05, 0xb5, 0x05, 0xc5, 0x05, 0xd5,
586 0x05, 0xe5, 0x05, 0xf6, 0x06, 0x06, 0x06, 0x16, 0x06, 0x27, 0x06, 0x37,
587 0x06, 0x48, 0x06, 0x59, 0x06, 0x6a, 0x06, 0x7b, 0x06, 0x8c, 0x06, 0x9d,
588 0x06, 0xaf, 0x06, 0xc0, 0x06, 0xd1, 0x06, 0xe3, 0x06, 0xf5, 0x07, 0x07,
589 0x07, 0x19, 0x07, 0x2b, 0x07, 0x3d, 0x07, 0x4f, 0x07, 0x61, 0x07, 0x74,
590 0x07, 0x86, 0x07, 0x99, 0x07, 0xac, 0x07, 0xbf, 0x07, 0xd2, 0x07, 0xe5,
591 0x07, 0xf8, 0x08, 0x0b, 0x08, 0x1f, 0x08, 0x32, 0x08, 0x46, 0x08, 0x5a,
592 0x08, 0x6e, 0x08, 0x82, 0x08, 0x96, 0x08, 0xaa, 0x08, 0xbe, 0x08, 0xd2,
593 0x08, 0xe7, 0x08, 0xfb, 0x09, 0x10, 0x09, 0x25, 0x09, 0x3a, 0x09, 0x4f,
594 0x09, 0x64, 0x09, 0x79, 0x09, 0x8f, 0x09, 0xa4, 0x09, 0xba, 0x09, 0xcf,
595 0x09, 0xe5, 0x09, 0xfb, 0x0a, 0x11, 0x0a, 0x27, 0x0a, 0x3d, 0x0a, 0x54,
596 0x0a, 0x6a, 0x0a, 0x81, 0x0a, 0x98, 0x0a, 0xae, 0x0a, 0xc5, 0x0a, 0xdc,
597 0x0a, 0xf3, 0x0b, 0x0b, 0x0b, 0x22, 0x0b, 0x39, 0x0b, 0x51, 0x0b, 0x69,
598 0x0b, 0x80, 0x0b, 0x98, 0x0b, 0xb0, 0x0b, 0xc8, 0x0b, 0xe1, 0x0b, 0xf9,
599 0x0c, 0x12, 0x0c, 0x2a, 0x0c, 0x43, 0x0c, 0x5c, 0x0c, 0x75, 0x0c, 0x8e,
600 0x0c, 0xa7, 0x0c, 0xc0, 0x0c, 0xd9, 0x0c, 0xf3, 0x0d, 0x0d, 0x0d, 0x26,
601 0x0d, 0x40, 0x0d, 0x5a, 0x0d, 0x74, 0x0d, 0x8e, 0x0d, 0xa9, 0x0d, 0xc3,
602 0x0d, 0xde, 0x0d, 0xf8, 0x0e, 0x13, 0x0e, 0x2e, 0x0e, 0x49, 0x0e, 0x64,
603 0x0e, 0x7f, 0x0e, 0x9b, 0x0e, 0xb6, 0x0e, 0xd2, 0x0e, 0xee, 0x0f, 0x09,
604 0x0f, 0x25, 0x0f, 0x41, 0x0f, 0x5e, 0x0f, 0x7a, 0x0f, 0x96, 0x0f, 0xb3,
605 0x0f, 0xcf, 0x0f, 0xec, 0x10, 0x09, 0x10, 0x26, 0x10, 0x43, 0x10, 0x61,
606 0x10, 0x7e, 0x10, 0x9b, 0x10, 0xb9, 0x10, 0xd7, 0x10, 0xf5, 0x11, 0x13,
607 0x11, 0x31, 0x11, 0x4f, 0x11, 0x6d, 0x11, 0x8c, 0x11, 0xaa, 0x11, 0xc9,
608 0x11, 0xe8, 0x12, 0x07, 0x12, 0x26, 0x12, 0x45, 0x12, 0x64, 0x12, 0x84,
609 0x12, 0xa3, 0x12, 0xc3, 0x12, 0xe3, 0x13, 0x03, 0x13, 0x23, 0x13, 0x43,
610 0x13, 0x63, 0x13, 0x83, 0x13, 0xa4, 0x13, 0xc5, 0x13, 0xe5, 0x14, 0x06,
611 0x14, 0x27, 0x14, 0x49, 0x14, 0x6a, 0x14, 0x8b, 0x14, 0xad, 0x14, 0xce,
612 0x14, 0xf0, 0x15, 0x12, 0x15, 0x34, 0x15, 0x56, 0x15, 0x78, 0x15, 0x9b,
613 0x15, 0xbd, 0x15, 0xe0, 0x16, 0x03, 0x16, 0x26, 0x16, 0x49, 0x16, 0x6c,
614 0x16, 0x8f, 0x16, 0xb2, 0x16, 0xd6, 0x16, 0xfa, 0x17, 0x1d, 0x17, 0x41,
615 0x17, 0x65, 0x17, 0x89, 0x17, 0xae, 0x17, 0xd2, 0x17, 0xf7, 0x18, 0x1b,
616 0x18, 0x40, 0x18, 0x65, 0x18, 0x8a, 0x18, 0xaf, 0x18, 0xd5, 0x18, 0xfa,
617 0x19, 0x20, 0x19, 0x45, 0x19, 0x6b, 0x19, 0x91, 0x19, 0xb7, 0x19, 0xdd,
618 0x1a, 0x04, 0x1a, 0x2a, 0x1a, 0x51, 0x1a, 0x77, 0x1a, 0x9e, 0x1a, 0xc5,
619 0x1a, 0xec, 0x1b, 0x14, 0x1b, 0x3b, 0x1b, 0x63, 0x1b, 0x8a, 0x1b, 0xb2,
620 0x1b, 0xda, 0x1c, 0x02, 0x1c, 0x2a, 0x1c, 0x52, 0x1c, 0x7b, 0x1c, 0xa3,
621 0x1c, 0xcc, 0x1c, 0xf5, 0x1d, 0x1e, 0x1d, 0x47, 0x1d, 0x70, 0x1d, 0x99,
622 0x1d, 0xc3, 0x1d, 0xec, 0x1e, 0x16, 0x1e, 0x40, 0x1e, 0x6a, 0x1e, 0x94,
623 0x1e, 0xbe, 0x1e, 0xe9, 0x1f, 0x13, 0x1f, 0x3e, 0x1f, 0x69, 0x1f, 0x94,
624 0x1f, 0xbf, 0x1f, 0xea, 0x20, 0x15, 0x20, 0x41, 0x20, 0x6c, 0x20, 0x98,
625 0x20, 0xc4, 0x20, 0xf0, 0x21, 0x1c, 0x21, 0x48, 0x21, 0x75, 0x21, 0xa1,
626 0x21, 0xce, 0x21, 0xfb, 0x22, 0x27, 0x22, 0x55, 0x22, 0x82, 0x22, 0xaf,
627 0x22, 0xdd, 0x23, 0x0a, 0x23, 0x38, 0x23, 0x66, 0x23, 0x94, 0x23, 0xc2,
628 0x23, 0xf0, 0x24, 0x1f, 0x24, 0x4d, 0x24, 0x7c, 0x24, 0xab, 0x24, 0xda,
629 0x25, 0x09, 0x25, 0x38, 0x25, 0x68, 0x25, 0x97, 0x25, 0xc7, 0x25, 0xf7,
630 0x26, 0x27, 0x26, 0x57, 0x26, 0x87, 0x26, 0xb7, 0x26, 0xe8, 0x27, 0x18,
631 0x27, 0x49, 0x27, 0x7a, 0x27, 0xab, 0x27, 0xdc, 0x28, 0x0d, 0x28, 0x3f,
632 0x28, 0x71, 0x28, 0xa2, 0x28, 0xd4, 0x29, 0x06, 0x29, 0x38, 0x29, 0x6b,
633 0x29, 0x9d, 0x29, 0xd0, 0x2a, 0x02, 0x2a, 0x35, 0x2a, 0x68, 0x2a, 0x9b,
634 0x2a, 0xcf, 0x2b, 0x02, 0x2b, 0x36, 0x2b, 0x69, 0x2b, 0x9d, 0x2b, 0xd1,
635 0x2c, 0x05, 0x2c, 0x39, 0x2c, 0x6e, 0x2c, 0xa2, 0x2c, 0xd7, 0x2d, 0x0c,
636 0x2d, 0x41, 0x2d, 0x76, 0x2d, 0xab, 0x2d, 0xe1, 0x2e, 0x16, 0x2e, 0x4c,
637 0x2e, 0x82, 0x2e, 0xb7, 0x2e, 0xee, 0x2f, 0x24, 0x2f, 0x5a, 0x2f, 0x91,
638 0x2f, 0xc7, 0x2f, 0xfe, 0x30, 0x35, 0x30, 0x6c, 0x30, 0xa4, 0x30, 0xdb,
639 0x31, 0x12, 0x31, 0x4a, 0x31, 0x82, 0x31, 0xba, 0x31, 0xf2, 0x32, 0x2a,
640 0x32, 0x63, 0x32, 0x9b, 0x32, 0xd4, 0x33, 0x0d, 0x33, 0x46, 0x33, 0x7f,
641 0x33, 0xb8, 0x33, 0xf1, 0x34, 0x2b, 0x34, 0x65, 0x34, 0x9e, 0x34, 0xd8,
642 0x35, 0x13, 0x35, 0x4d, 0x35, 0x87, 0x35, 0xc2, 0x35, 0xfd, 0x36, 0x37,
643 0x36, 0x72, 0x36, 0xae, 0x36, 0xe9, 0x37, 0x24, 0x37, 0x60, 0x37, 0x9c,
644 0x37, 0xd7, 0x38, 0x14, 0x38, 0x50, 0x38, 0x8c, 0x38, 0xc8, 0x39, 0x05,
645 0x39, 0x42, 0x39, 0x7f, 0x39, 0xbc, 0x39, 0xf9, 0x3a, 0x36, 0x3a, 0x74,
646 0x3a, 0xb2, 0x3a, 0xef, 0x3b, 0x2d, 0x3b, 0x6b, 0x3b, 0xaa, 0x3b, 0xe8,
647 0x3c, 0x27, 0x3c, 0x65, 0x3c, 0xa4, 0x3c, 0xe3, 0x3d, 0x22, 0x3d, 0x61,
648 0x3d, 0xa1, 0x3d, 0xe0, 0x3e, 0x20, 0x3e, 0x60, 0x3e, 0xa0, 0x3e, 0xe0,
649 0x3f, 0x21, 0x3f, 0x61, 0x3f, 0xa2, 0x3f, 0xe2, 0x40, 0x23, 0x40, 0x64,
650 0x40, 0xa6, 0x40, 0xe7, 0x41, 0x29, 0x41, 0x6a, 0x41, 0xac, 0x41, 0xee,
651 0x42, 0x30, 0x42, 0x72, 0x42, 0xb5, 0x42, 0xf7, 0x43, 0x3a, 0x43, 0x7d,
652 0x43, 0xc0, 0x44, 0x03, 0x44, 0x47, 0x44, 0x8a, 0x44, 0xce, 0x45, 0x12,
653 0x45, 0x55, 0x45, 0x9a, 0x45, 0xde, 0x46, 0x22, 0x46, 0x67, 0x46, 0xab,
654 0x46, 0xf0, 0x47, 0x35, 0x47, 0x7b, 0x47, 0xc0, 0x48, 0x05, 0x48, 0x4b,
655 0x48, 0x91, 0x48, 0xd7, 0x49, 0x1d, 0x49, 0x63, 0x49, 0xa9, 0x49, 0xf0,
656 0x4a, 0x37, 0x4a, 0x7d, 0x4a, 0xc4, 0x4b, 0x0c, 0x4b, 0x53, 0x4b, 0x9a,
657 0x4b, 0xe2, 0x4c, 0x2a, 0x4c, 0x72, 0x4c, 0xba, 0x4d, 0x02, 0x4d, 0x4a,
658 0x4d, 0x93, 0x4d, 0xdc, 0x4e, 0x25, 0x4e, 0x6e, 0x4e, 0xb7, 0x4f, 0x00,
659 0x4f, 0x49, 0x4f, 0x93, 0x4f, 0xdd, 0x50, 0x27, 0x50, 0x71, 0x50, 0xbb,
660 0x51, 0x06, 0x51, 0x50, 0x51, 0x9b, 0x51, 0xe6, 0x52, 0x31, 0x52, 0x7c,
661 0x52, 0xc7, 0x53, 0x13, 0x53, 0x5f, 0x53, 0xaa, 0x53, 0xf6, 0x54, 0x42,
662 0x54, 0x8f, 0x54, 0xdb, 0x55, 0x28, 0x55, 0x75, 0x55, 0xc2, 0x56, 0x0f,
663 0x56, 0x5c, 0x56, 0xa9, 0x56, 0xf7, 0x57, 0x44, 0x57, 0x92, 0x57, 0xe0,
664 0x58, 0x2f, 0x58, 0x7d, 0x58, 0xcb, 0x59, 0x1a, 0x59, 0x69, 0x59, 0xb8,
665 0x5a, 0x07, 0x5a, 0x56, 0x5a, 0xa6, 0x5a, 0xf5, 0x5b, 0x45, 0x5b, 0x95,
666 0x5b, 0xe5, 0x5c, 0x35, 0x5c, 0x86, 0x5c, 0xd6, 0x5d, 0x27, 0x5d, 0x78,
667 0x5d, 0xc9, 0x5e, 0x1a, 0x5e, 0x6c, 0x5e, 0xbd, 0x5f, 0x0f, 0x5f, 0x61,
668 0x5f, 0xb3, 0x60, 0x05, 0x60, 0x57, 0x60, 0xaa, 0x60, 0xfc, 0x61, 0x4f,
669 0x61, 0xa2, 0x61, 0xf5, 0x62, 0x49, 0x62, 0x9c, 0x62, 0xf0, 0x63, 0x43,
670 0x63, 0x97, 0x63, 0xeb, 0x64, 0x40, 0x64, 0x94, 0x64, 0xe9, 0x65, 0x3d,
671 0x65, 0x92, 0x65, 0xe7, 0x66, 0x3d, 0x66, 0x92, 0x66, 0xe8, 0x67, 0x3d,
672 0x67, 0x93, 0x67, 0xe9, 0x68, 0x3f, 0x68, 0x96, 0x68, 0xec, 0x69, 0x43,
673 0x69, 0x9a, 0x69, 0xf1, 0x6a, 0x48, 0x6a, 0x9f, 0x6a, 0xf7, 0x6b, 0x4f,
674 0x6b, 0xa7, 0x6b, 0xff, 0x6c, 0x57, 0x6c, 0xaf, 0x6d, 0x08, 0x6d, 0x60,
675 0x6d, 0xb9, 0x6e, 0x12, 0x6e, 0x6b, 0x6e, 0xc4, 0x6f, 0x1e, 0x6f, 0x78,
676 0x6f, 0xd1, 0x70, 0x2b, 0x70, 0x86, 0x70, 0xe0, 0x71, 0x3a, 0x71, 0x95,
677 0x71, 0xf0, 0x72, 0x4b, 0x72, 0xa6, 0x73, 0x01, 0x73, 0x5d, 0x73, 0xb8,
678 0x74, 0x14, 0x74, 0x70, 0x74, 0xcc, 0x75, 0x28, 0x75, 0x85, 0x75, 0xe1,
679 0x76, 0x3e, 0x76, 0x9b, 0x76, 0xf8, 0x77, 0x56, 0x77, 0xb3, 0x78, 0x11,
680 0x78, 0x6e, 0x78, 0xcc, 0x79, 0x2a, 0x79, 0x89, 0x79, 0xe7, 0x7a, 0x46,
681 0x7a, 0xa5, 0x7b, 0x04, 0x7b, 0x63, 0x7b, 0xc2, 0x7c, 0x21, 0x7c, 0x81,
682 0x7c, 0xe1, 0x7d, 0x41, 0x7d, 0xa1, 0x7e, 0x01, 0x7e, 0x62, 0x7e, 0xc2,
683 0x7f, 0x23, 0x7f, 0x84, 0x7f, 0xe5, 0x80, 0x47, 0x80, 0xa8, 0x81, 0x0a,
684 0x81, 0x6b, 0x81, 0xcd, 0x82, 0x30, 0x82, 0x92, 0x82, 0xf4, 0x83, 0x57,
685 0x83, 0xba, 0x84, 0x1d, 0x84, 0x80, 0x84, 0xe3, 0x85, 0x47, 0x85, 0xab,
686 0x86, 0x0e, 0x86, 0x72, 0x86, 0xd7, 0x87, 0x3b, 0x87, 0x9f, 0x88, 0x04,
687 0x88, 0x69, 0x88, 0xce, 0x89, 0x33, 0x89, 0x99, 0x89, 0xfe, 0x8a, 0x64,
688 0x8a, 0xca, 0x8b, 0x30, 0x8b, 0x96, 0x8b, 0xfc, 0x8c, 0x63, 0x8c, 0xca,
689 0x8d, 0x31, 0x8d, 0x98, 0x8d, 0xff, 0x8e, 0x66, 0x8e, 0xce, 0x8f, 0x36,
690 0x8f, 0x9e, 0x90, 0x06, 0x90, 0x6e, 0x90, 0xd6, 0x91, 0x3f, 0x91, 0xa8,
691 0x92, 0x11, 0x92, 0x7a, 0x92, 0xe3, 0x93, 0x4d, 0x93, 0xb6, 0x94, 0x20,
692 0x94, 0x8a, 0x94, 0xf4, 0x95, 0x5f, 0x95, 0xc9, 0x96, 0x34, 0x96, 0x9f,
693 0x97, 0x0a, 0x97, 0x75, 0x97, 0xe0, 0x98, 0x4c, 0x98, 0xb8, 0x99, 0x24,
694 0x99, 0x90, 0x99, 0xfc, 0x9a, 0x68, 0x9a, 0xd5, 0x9b, 0x42, 0x9b, 0xaf,
695 0x9c, 0x1c, 0x9c, 0x89, 0x9c, 0xf7, 0x9d, 0x64, 0x9d, 0xd2, 0x9e, 0x40,
696 0x9e, 0xae, 0x9f, 0x1d, 0x9f, 0x8b, 0x9f, 0xfa, 0xa0, 0x69, 0xa0, 0xd8,
697 0xa1, 0x47, 0xa1, 0xb6, 0xa2, 0x26, 0xa2, 0x96, 0xa3, 0x06, 0xa3, 0x76,
698 0xa3, 0xe6, 0xa4, 0x56, 0xa4, 0xc7, 0xa5, 0x38, 0xa5, 0xa9, 0xa6, 0x1a,
699 0xa6, 0x8b, 0xa6, 0xfd, 0xa7, 0x6e, 0xa7, 0xe0, 0xa8, 0x52, 0xa8, 0xc4,
700 0xa9, 0x37, 0xa9, 0xa9, 0xaa, 0x1c, 0xaa, 0x8f, 0xab, 0x02, 0xab, 0x75,
701 0xab, 0xe9, 0xac, 0x5c, 0xac, 0xd0, 0xad, 0x44, 0xad, 0xb8, 0xae, 0x2d,
702 0xae, 0xa1, 0xaf, 0x16, 0xaf, 0x8b, 0xb0, 0x00, 0xb0, 0x75, 0xb0, 0xea,
703 0xb1, 0x60, 0xb1, 0xd6, 0xb2, 0x4b, 0xb2, 0xc2, 0xb3, 0x38, 0xb3, 0xae,
704 0xb4, 0x25, 0xb4, 0x9c, 0xb5, 0x13, 0xb5, 0x8a, 0xb6, 0x01, 0xb6, 0x79,
705 0xb6, 0xf0, 0xb7, 0x68, 0xb7, 0xe0, 0xb8, 0x59, 0xb8, 0xd1, 0xb9, 0x4a,
706 0xb9, 0xc2, 0xba, 0x3b, 0xba, 0xb5, 0xbb, 0x2e, 0xbb, 0xa7, 0xbc, 0x21,
707 0xbc, 0x9b, 0xbd, 0x15, 0xbd, 0x8f, 0xbe, 0x0a, 0xbe, 0x84, 0xbe, 0xff,
708 0xbf, 0x7a, 0xbf, 0xf5, 0xc0, 0x70, 0xc0, 0xec, 0xc1, 0x67, 0xc1, 0xe3,
709 0xc2, 0x5f, 0xc2, 0xdb, 0xc3, 0x58, 0xc3, 0xd4, 0xc4, 0x51, 0xc4, 0xce,
710 0xc5, 0x4b, 0xc5, 0xc8, 0xc6, 0x46, 0xc6, 0xc3, 0xc7, 0x41, 0xc7, 0xbf,
711 0xc8, 0x3d, 0xc8, 0xbc, 0xc9, 0x3a, 0xc9, 0xb9, 0xca, 0x38, 0xca, 0xb7,
712 0xcb, 0x36, 0xcb, 0xb6, 0xcc, 0x35, 0xcc, 0xb5, 0xcd, 0x35, 0xcd, 0xb5,
713 0xce, 0x36, 0xce, 0xb6, 0xcf, 0x37, 0xcf, 0xb8, 0xd0, 0x39, 0xd0, 0xba,
714 0xd1, 0x3c, 0xd1, 0xbe, 0xd2, 0x3f, 0xd2, 0xc1, 0xd3, 0x44, 0xd3, 0xc6,
715 0xd4, 0x49, 0xd4, 0xcb, 0xd5, 0x4e, 0xd5, 0xd1, 0xd6, 0x55, 0xd6, 0xd8,
716 0xd7, 0x5c, 0xd7, 0xe0, 0xd8, 0x64, 0xd8, 0xe8, 0xd9, 0x6c, 0xd9, 0xf1,
717 0xda, 0x76, 0xda, 0xfb, 0xdb, 0x80, 0xdc, 0x05, 0xdc, 0x8a, 0xdd, 0x10,
718 0xdd, 0x96, 0xde, 0x1c, 0xde, 0xa2, 0xdf, 0x29, 0xdf, 0xaf, 0xe0, 0x36,
719 0xe0, 0xbd, 0xe1, 0x44, 0xe1, 0xcc, 0xe2, 0x53, 0xe2, 0xdb, 0xe3, 0x63,
720 0xe3, 0xeb, 0xe4, 0x73, 0xe4, 0xfc, 0xe5, 0x84, 0xe6, 0x0d, 0xe6, 0x96,
721 0xe7, 0x1f, 0xe7, 0xa9, 0xe8, 0x32, 0xe8, 0xbc, 0xe9, 0x46, 0xe9, 0xd0,
722 0xea, 0x5b, 0xea, 0xe5, 0xeb, 0x70, 0xeb, 0xfb, 0xec, 0x86, 0xed, 0x11,
723 0xed, 0x9c, 0xee, 0x28, 0xee, 0xb4, 0xef, 0x40, 0xef, 0xcc, 0xf0, 0x58,
724 0xf0, 0xe5, 0xf1, 0x72, 0xf1, 0xff, 0xf2, 0x8c, 0xf3, 0x19, 0xf3, 0xa7,
725 0xf4, 0x34, 0xf4, 0xc2, 0xf5, 0x50, 0xf5, 0xde, 0xf6, 0x6d, 0xf6, 0xfb,
726 0xf7, 0x8a, 0xf8, 0x19, 0xf8, 0xa8, 0xf9, 0x38, 0xf9, 0xc7, 0xfa, 0x57,
727 0xfa, 0xe7, 0xfb, 0x77, 0xfc, 0x07, 0xfc, 0x98, 0xfd, 0x29, 0xfd, 0xba,
728 0xfe, 0x4b, 0xfe, 0xdc, 0xff, 0x6d, 0xff, 0xff
737 assert(image != (Image *) NULL);
738 assert(image->signature == MagickCoreSignature);
739 if (GetImageProfile(image,"icc") != (const StringInfo *) NULL)
741 profile=AcquireStringInfo(sizeof(sRGBProfile));
742 SetStringInfoDatum(profile,sRGBProfile);
743 status=SetImageProfile(image,"icc",profile,exception);
744 profile=DestroyStringInfo(profile);
748 MagickExport MagickBooleanType ProfileImage(Image *image,const char *name,
749 const void *datum,const size_t length,ExceptionInfo *exception)
751 #define ProfileImageTag "Profile/Image"
752 #define ThrowProfileException(severity,tag,context) \
754 if (source_profile != (cmsHPROFILE) NULL) \
755 (void) cmsCloseProfile(source_profile); \
756 if (target_profile != (cmsHPROFILE) NULL) \
757 (void) cmsCloseProfile(target_profile); \
758 ThrowBinaryException(severity,tag,context); \
767 assert(image != (Image *) NULL);
768 assert(image->signature == MagickCoreSignature);
769 if (image->debug != MagickFalse)
770 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
771 assert(name != (const char *) NULL);
772 if ((datum == (const void *) NULL) || (length == 0))
778 Delete image profile(s).
780 ResetImageProfileIterator(image);
781 for (next=GetNextImageProfile(image); next != (const char *) NULL; )
783 if (IsOptionMember(next,name) != MagickFalse)
785 (void) DeleteImageProfile(image,next);
786 ResetImageProfileIterator(image);
788 next=GetNextImageProfile(image);
793 Add a ICC, IPTC, or generic profile to the image.
796 profile=AcquireStringInfo((size_t) length);
797 SetStringInfoDatum(profile,(unsigned char *) datum);
798 if ((LocaleCompare(name,"icc") != 0) && (LocaleCompare(name,"icm") != 0))
799 status=SetImageProfile(image,name,profile,exception);
805 icc_profile=GetImageProfile(image,"icc");
806 if ((icc_profile != (const StringInfo *) NULL) &&
807 (CompareStringInfo(icc_profile,profile) == 0))
812 value=GetImageProperty(image,"exif:ColorSpace",exception);
814 if (LocaleCompare(value,"1") != 0)
815 (void) SetsRGBImageProfile(image,exception);
816 value=GetImageProperty(image,"exif:InteroperabilityIndex",exception);
817 if (LocaleCompare(value,"R98.") != 0)
818 (void) SetsRGBImageProfile(image,exception);
820 value=GetImageProperty(image,"exif:InteroperabilityIndex",exception);
821 if (LocaleCompare(value,"R03.") != 0)
822 (void) SetAdobeRGB1998ImageProfile(image,exception);
824 icc_profile=GetImageProfile(image,"icc");
826 if ((icc_profile != (const StringInfo *) NULL) &&
827 (CompareStringInfo(icc_profile,profile) == 0))
829 profile=DestroyStringInfo(profile);
832 #if !defined(MAGICKCORE_LCMS_DELEGATE)
833 (void) ThrowMagickException(exception,GetMagickModule(),
834 MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn",
835 "'%s' (LCMS)",image->filename);
845 Transform pixel colors as defined by the color profiles.
847 cmsSetLogErrorHandler(CMSExceptionHandler);
848 cms_exception.image=image;
849 cms_exception.exception=exception;
850 (void) cms_exception;
851 source_profile=cmsOpenProfileFromMemTHR((cmsContext) &cms_exception,
852 GetStringInfoDatum(profile),(cmsUInt32Number)
853 GetStringInfoLength(profile));
854 if (source_profile == (cmsHPROFILE) NULL)
855 ThrowBinaryException(ResourceLimitError,
856 "ColorspaceColorProfileMismatch",name);
857 if ((cmsGetDeviceClass(source_profile) != cmsSigLinkClass) &&
858 (icc_profile == (StringInfo *) NULL))
859 status=SetImageProfile(image,name,profile,exception);
869 cmsColorSpaceSignature
900 **restrict source_pixels,
901 **restrict target_pixels;
903 target_profile=(cmsHPROFILE) NULL;
904 if (icc_profile != (StringInfo *) NULL)
906 target_profile=source_profile;
907 source_profile=cmsOpenProfileFromMemTHR((cmsContext)
908 &cms_exception,GetStringInfoDatum(icc_profile),
909 (cmsUInt32Number) GetStringInfoLength(icc_profile));
910 if (source_profile == (cmsHPROFILE) NULL)
911 ThrowProfileException(ResourceLimitError,
912 "ColorspaceColorProfileMismatch",name);
914 switch (cmsGetColorSpace(source_profile))
918 source_colorspace=CMYKColorspace;
919 source_type=(cmsUInt32Number) TYPE_CMYK_16;
925 source_colorspace=GRAYColorspace;
926 source_type=(cmsUInt32Number) TYPE_GRAY_16;
932 source_colorspace=LabColorspace;
933 source_type=(cmsUInt32Number) TYPE_Lab_16;
939 source_colorspace=YUVColorspace;
940 source_type=(cmsUInt32Number) TYPE_YUV_16;
946 source_colorspace=sRGBColorspace;
947 source_type=(cmsUInt32Number) TYPE_RGB_16;
953 source_colorspace=XYZColorspace;
954 source_type=(cmsUInt32Number) TYPE_XYZ_16;
958 case cmsSigYCbCrData:
960 source_colorspace=YCbCrColorspace;
961 source_type=(cmsUInt32Number) TYPE_YCbCr_16;
967 source_colorspace=UndefinedColorspace;
968 source_type=(cmsUInt32Number) TYPE_RGB_16;
973 signature=cmsGetPCS(source_profile);
974 if (target_profile != (cmsHPROFILE) NULL)
975 signature=cmsGetColorSpace(target_profile);
980 target_colorspace=CMYKColorspace;
981 target_type=(cmsUInt32Number) TYPE_CMYK_16;
987 target_colorspace=LabColorspace;
988 target_type=(cmsUInt32Number) TYPE_Lab_16;
994 target_colorspace=GRAYColorspace;
995 target_type=(cmsUInt32Number) TYPE_GRAY_16;
1001 target_colorspace=YUVColorspace;
1002 target_type=(cmsUInt32Number) TYPE_YUV_16;
1008 target_colorspace=sRGBColorspace;
1009 target_type=(cmsUInt32Number) TYPE_RGB_16;
1015 target_colorspace=XYZColorspace;
1016 target_type=(cmsUInt32Number) TYPE_XYZ_16;
1020 case cmsSigYCbCrData:
1022 target_colorspace=YCbCrColorspace;
1023 target_type=(cmsUInt32Number) TYPE_YCbCr_16;
1029 target_colorspace=UndefinedColorspace;
1030 target_type=(cmsUInt32Number) TYPE_RGB_16;
1035 if ((source_colorspace == UndefinedColorspace) ||
1036 (target_colorspace == UndefinedColorspace))
1037 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1039 if ((source_colorspace == GRAYColorspace) &&
1040 (SetImageGray(image,exception) == MagickFalse))
1041 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1043 if ((source_colorspace == CMYKColorspace) &&
1044 (image->colorspace != CMYKColorspace))
1045 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1047 if ((source_colorspace == XYZColorspace) &&
1048 (image->colorspace != XYZColorspace))
1049 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1051 if ((source_colorspace == YCbCrColorspace) &&
1052 (image->colorspace != YCbCrColorspace))
1053 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1055 if ((source_colorspace != CMYKColorspace) &&
1056 (source_colorspace != LabColorspace) &&
1057 (source_colorspace != XYZColorspace) &&
1058 (source_colorspace != YCbCrColorspace) &&
1059 (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse))
1060 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1062 switch (image->rendering_intent)
1064 case AbsoluteIntent: intent=INTENT_ABSOLUTE_COLORIMETRIC; break;
1065 case PerceptualIntent: intent=INTENT_PERCEPTUAL; break;
1066 case RelativeIntent: intent=INTENT_RELATIVE_COLORIMETRIC; break;
1067 case SaturationIntent: intent=INTENT_SATURATION; break;
1068 default: intent=INTENT_PERCEPTUAL; break;
1070 flags=cmsFLAGS_HIGHRESPRECALC;
1071 #if defined(cmsFLAGS_BLACKPOINTCOMPENSATION)
1072 if (image->black_point_compensation != MagickFalse)
1073 flags|=cmsFLAGS_BLACKPOINTCOMPENSATION;
1075 transform=AcquireTransformThreadSet(image,source_profile,
1076 source_type,target_profile,target_type,intent,flags);
1077 if (transform == (cmsHTRANSFORM *) NULL)
1078 ThrowProfileException(ImageError,"UnableToCreateColorTransform",
1081 Transform image as dictated by the source & target image profiles.
1083 source_pixels=AcquirePixelThreadSet(image->columns,source_channels);
1084 target_pixels=AcquirePixelThreadSet(image->columns,target_channels);
1085 if ((source_pixels == (unsigned short **) NULL) ||
1086 (target_pixels == (unsigned short **) NULL))
1088 transform=DestroyTransformThreadSet(transform);
1089 ThrowProfileException(ResourceLimitError,
1090 "MemoryAllocationFailed",image->filename);
1092 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1094 target_pixels=DestroyPixelThreadSet(target_pixels);
1095 source_pixels=DestroyPixelThreadSet(source_pixels);
1096 transform=DestroyTransformThreadSet(transform);
1097 if (source_profile != (cmsHPROFILE) NULL)
1098 (void) cmsCloseProfile(source_profile);
1099 if (target_profile != (cmsHPROFILE) NULL)
1100 (void) cmsCloseProfile(target_profile);
1101 return(MagickFalse);
1103 if (target_colorspace == CMYKColorspace)
1104 (void) SetImageColorspace(image,target_colorspace,exception);
1107 image_view=AcquireAuthenticCacheView(image,exception);
1108 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1109 #pragma omp parallel for schedule(static,4) shared(status) \
1110 magick_threads(image,image,image->rows,1)
1112 for (y=0; y < (ssize_t) image->rows; y++)
1115 id = GetOpenMPThreadId();
1126 register unsigned short
1129 if (status == MagickFalse)
1131 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1133 if (q == (Quantum *) NULL)
1138 p=source_pixels[id];
1139 for (x=0; x < (ssize_t) image->columns; x++)
1141 *p++=ScaleQuantumToShort(GetPixelRed(image,q));
1142 if (source_channels > 1)
1144 *p++=ScaleQuantumToShort(GetPixelGreen(image,q));
1145 *p++=ScaleQuantumToShort(GetPixelBlue(image,q));
1147 if (source_channels > 3)
1148 *p++=ScaleQuantumToShort(GetPixelBlack(image,q));
1149 q+=GetPixelChannels(image);
1151 cmsDoTransform(transform[id],source_pixels[id],target_pixels[id],
1152 (unsigned int) image->columns);
1153 p=target_pixels[id];
1154 q-=GetPixelChannels(image)*image->columns;
1155 for (x=0; x < (ssize_t) image->columns; x++)
1157 if (target_channels == 1)
1158 SetPixelGray(image,ScaleShortToQuantum(*p),q);
1160 SetPixelRed(image,ScaleShortToQuantum(*p),q);
1162 if (target_channels > 1)
1164 SetPixelGreen(image,ScaleShortToQuantum(*p),q);
1166 SetPixelBlue(image,ScaleShortToQuantum(*p),q);
1169 if (target_channels > 3)
1171 SetPixelBlack(image,ScaleShortToQuantum(*p),q);
1174 q+=GetPixelChannels(image);
1176 sync=SyncCacheViewAuthenticPixels(image_view,exception);
1177 if (sync == MagickFalse)
1179 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1184 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1185 #pragma omp critical (MagickCore_ProfileImage)
1187 proceed=SetImageProgress(image,ProfileImageTag,progress++,
1189 if (proceed == MagickFalse)
1193 image_view=DestroyCacheView(image_view);
1194 (void) SetImageColorspace(image,target_colorspace,exception);
1199 image->type=image->alpha_trait == UndefinedPixelTrait ?
1200 TrueColorType : TrueColorAlphaType;
1203 case cmsSigCmykData:
1205 image->type=image->alpha_trait == UndefinedPixelTrait ?
1206 ColorSeparationType : ColorSeparationAlphaType;
1209 case cmsSigGrayData:
1211 image->type=image->alpha_trait == UndefinedPixelTrait ?
1212 GrayscaleType : GrayscaleAlphaType;
1218 target_pixels=DestroyPixelThreadSet(target_pixels);
1219 source_pixels=DestroyPixelThreadSet(source_pixels);
1220 transform=DestroyTransformThreadSet(transform);
1221 if (cmsGetDeviceClass(source_profile) != cmsSigLinkClass)
1222 status=SetImageProfile(image,name,profile,exception);
1223 if (target_profile != (cmsHPROFILE) NULL)
1224 (void) cmsCloseProfile(target_profile);
1226 (void) cmsCloseProfile(source_profile);
1230 profile=DestroyStringInfo(profile);
1235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1239 % R e m o v e I m a g e P r o f i l e %
1243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1245 % RemoveImageProfile() removes a named profile from the image and returns its
1248 % The format of the RemoveImageProfile method is:
1250 % void *RemoveImageProfile(Image *image,const char *name)
1252 % A description of each parameter follows:
1254 % o image: the image.
1256 % o name: the profile name.
1259 MagickExport StringInfo *RemoveImageProfile(Image *image,const char *name)
1264 assert(image != (Image *) NULL);
1265 assert(image->signature == MagickCoreSignature);
1266 if (image->debug != MagickFalse)
1267 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1268 if (image->profiles == (SplayTreeInfo *) NULL)
1269 return((StringInfo *) NULL);
1270 WriteTo8BimProfile(image,name,(StringInfo *) NULL);
1271 profile=(StringInfo *) RemoveNodeFromSplayTree((SplayTreeInfo *)
1272 image->profiles,name);
1277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1281 % R e s e t P r o f i l e I t e r a t o r %
1285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1287 % ResetImageProfileIterator() resets the image profile iterator. Use it in
1288 % conjunction with GetNextImageProfile() to iterate over all the profiles
1289 % associated with an image.
1291 % The format of the ResetImageProfileIterator method is:
1293 % ResetImageProfileIterator(Image *image)
1295 % A description of each parameter follows:
1297 % o image: the image.
1300 MagickExport void ResetImageProfileIterator(const Image *image)
1302 assert(image != (Image *) NULL);
1303 assert(image->signature == MagickCoreSignature);
1304 if (image->debug != MagickFalse)
1305 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1306 if (image->profiles == (SplayTreeInfo *) NULL)
1308 ResetSplayTreeIterator((SplayTreeInfo *) image->profiles);
1312 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1316 % S e t I m a g e P r o f i l e %
1320 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1322 % SetImageProfile() adds a named profile to the image. If a profile with the
1323 % same name already exists, it is replaced. This method differs from the
1324 % ProfileImage() method in that it does not apply CMS color profiles.
1326 % The format of the SetImageProfile method is:
1328 % MagickBooleanType SetImageProfile(Image *image,const char *name,
1329 % const StringInfo *profile)
1331 % A description of each parameter follows:
1333 % o image: the image.
1335 % o name: the profile name, for example icc, exif, and 8bim (8bim is the
1336 % Photoshop wrapper for iptc profiles).
1338 % o profile: A StringInfo structure that contains the named profile.
1342 static void *DestroyProfile(void *profile)
1344 return((void *) DestroyStringInfo((StringInfo *) profile));
1347 static inline const unsigned char *ReadResourceByte(const unsigned char *p,
1348 unsigned char *quantum)
1354 static inline const unsigned char *ReadResourceLong(const unsigned char *p,
1355 unsigned int *quantum)
1357 *quantum=(size_t) (*p++ << 24);
1358 *quantum|=(size_t) (*p++ << 16);
1359 *quantum|=(size_t) (*p++ << 8);
1360 *quantum|=(size_t) (*p++ << 0);
1364 static inline const unsigned char *ReadResourceShort(const unsigned char *p,
1365 unsigned short *quantum)
1367 *quantum=(unsigned short) (*p++ << 8);
1368 *quantum|=(unsigned short) (*p++ << 0);
1370 }static inline void WriteResourceLong(unsigned char *p,
1371 const unsigned int quantum)
1376 buffer[0]=(unsigned char) (quantum >> 24);
1377 buffer[1]=(unsigned char) (quantum >> 16);
1378 buffer[2]=(unsigned char) (quantum >> 8);
1379 buffer[3]=(unsigned char) quantum;
1380 (void) CopyMagickMemory(p,buffer,4);
1383 static void WriteTo8BimProfile(Image *image,const char *name,
1384 const StringInfo *profile)
1390 register const unsigned char
1412 if (LocaleCompare(name,"icc") == 0)
1415 if (LocaleCompare(name,"iptc") == 0)
1418 if (LocaleCompare(name,"xmp") == 0)
1422 profile_8bim=(StringInfo *) GetValueFromSplayTree((SplayTreeInfo *)
1423 image->profiles,"8bim");
1424 if (profile_8bim == (StringInfo *) NULL)
1426 datum=GetStringInfoDatum(profile_8bim);
1427 length=GetStringInfoLength(profile_8bim);
1428 for (p=datum; p < (datum+length-16); )
1431 if (LocaleNCompare((char *) p,"8BIM",4) != 0)
1434 p=ReadResourceShort(p,&id);
1435 p=ReadResourceByte(p,&length_byte);
1437 if (((length_byte+1) & 0x01) != 0)
1439 if (p > (datum+length-4))
1441 p=ReadResourceLong(p,&value);
1442 count=(ssize_t) value;
1443 if ((count & 0x01) != 0)
1445 if ((p > (datum+length-count)) || (count > (ssize_t) length))
1447 if (id != profile_id)
1462 extent=(datum+length)-(p+count);
1463 if (profile == (StringInfo *) NULL)
1466 extract_profile=AcquireStringInfo(offset+extent);
1467 (void) CopyMagickMemory(extract_profile->datum,datum,offset);
1472 extract_count=profile->length;
1473 if ((extract_count & 0x01) != 0)
1475 extract_profile=AcquireStringInfo(offset+extract_count+extent);
1476 (void) CopyMagickMemory(extract_profile->datum,datum,offset-4);
1477 WriteResourceLong(extract_profile->datum+offset-4,
1478 (unsigned int)profile->length);
1479 (void) CopyMagickMemory(extract_profile->datum+offset,
1480 profile->datum,profile->length);
1482 (void) CopyMagickMemory(extract_profile->datum+offset+extract_count,
1484 (void) AddValueToSplayTree((SplayTreeInfo *) image->profiles,
1485 ConstantString("8bim"),CloneStringInfo(extract_profile));
1486 extract_profile=DestroyStringInfo(extract_profile);
1492 static void GetProfilesFromResourceBlock(Image *image,
1493 const StringInfo *resource_block,ExceptionInfo *exception)
1498 register const unsigned char
1519 datum=GetStringInfoDatum(resource_block);
1520 length=GetStringInfoLength(resource_block);
1521 for (p=datum; p < (datum+length-16); )
1523 if (LocaleNCompare((char *) p,"8BIM",4) != 0)
1526 p=ReadResourceShort(p,&id);
1527 p=ReadResourceByte(p,&length_byte);
1529 if (((length_byte+1) & 0x01) != 0)
1531 if (p > (datum+length-4))
1533 p=ReadResourceLong(p,&value);
1534 count=(ssize_t) value;
1535 if ((p > (datum+length-count)) || (count > (ssize_t) length))
1550 p=ReadResourceLong(p,&resolution);
1551 image->resolution.x=((double) resolution)/65536.0;
1552 p=ReadResourceShort(p,&units)+2;
1553 p=ReadResourceLong(p,&resolution)+4;
1554 image->resolution.y=((double) resolution)/65536.0;
1556 Values are always stored as pixels per inch.
1558 if ((ResolutionType) units != PixelsPerCentimeterResolution)
1559 image->units=PixelsPerInchResolution;
1562 image->units=PixelsPerCentimeterResolution;
1563 image->resolution.x/=2.54;
1564 image->resolution.y/=2.54;
1573 profile=AcquireStringInfo(count);
1574 SetStringInfoDatum(profile,p);
1575 (void) SetImageProfileInternal(image,"iptc",profile,MagickTrue,
1577 profile=DestroyStringInfo(profile);
1594 profile=AcquireStringInfo(count);
1595 SetStringInfoDatum(profile,p);
1596 (void) SetImageProfileInternal(image,"icc",profile,MagickTrue,
1598 profile=DestroyStringInfo(profile);
1607 profile=AcquireStringInfo(count);
1608 SetStringInfoDatum(profile,p);
1609 (void) SetImageProfileInternal(image,"exif",profile,MagickTrue,
1611 profile=DestroyStringInfo(profile);
1620 profile=AcquireStringInfo(count);
1621 SetStringInfoDatum(profile,p);
1622 (void) SetImageProfileInternal(image,"xmp",profile,MagickTrue,
1624 profile=DestroyStringInfo(profile);
1634 if ((count & 0x01) != 0)
1639 static MagickBooleanType SetImageProfileInternal(Image *image,const char *name,
1640 const StringInfo *profile,const MagickBooleanType recursive,
1641 ExceptionInfo *exception)
1644 key[MagickPathExtent],
1645 property[MagickPathExtent];
1650 assert(image != (Image *) NULL);
1651 assert(image->signature == MagickCoreSignature);
1652 if (image->debug != MagickFalse)
1653 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1654 if (image->profiles == (SplayTreeInfo *) NULL)
1655 image->profiles=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
1657 (void) CopyMagickString(key,name,MagickPathExtent);
1659 status=AddValueToSplayTree((SplayTreeInfo *) image->profiles,
1660 ConstantString(key),CloneStringInfo(profile));
1661 if (status != MagickFalse)
1663 if (LocaleCompare(name,"8bim") == 0)
1664 GetProfilesFromResourceBlock(image,profile,exception);
1665 else if (recursive == MagickFalse)
1666 WriteTo8BimProfile(image,name,profile);
1669 Inject profile into image properties.
1671 (void) FormatLocaleString(property,MagickPathExtent,"%s:*",name);
1672 (void) GetImageProperty(image,property,exception);
1676 MagickExport MagickBooleanType SetImageProfile(Image *image,const char *name,
1677 const StringInfo *profile,ExceptionInfo *exception)
1679 return(SetImageProfileInternal(image,name,profile,MagickFalse,exception));
1683 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1687 % S y n c I m a g e P r o f i l e s %
1691 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1693 % SyncImageProfiles() synchronizes image properties with the image profiles.
1694 % Currently we only support updating the EXIF resolution and orientation.
1696 % The format of the SyncImageProfiles method is:
1698 % MagickBooleanType SyncImageProfiles(Image *image)
1700 % A description of each parameter follows:
1702 % o image: the image.
1706 static inline int ReadProfileByte(unsigned char **p,size_t *length)
1718 static inline unsigned short ReadProfileShort(const EndianType endian,
1719 unsigned char *buffer)
1724 if (endian == LSBEndian)
1726 value=(unsigned short) ((buffer[1] << 8) | buffer[0]);
1727 return((unsigned short) (value & 0xffff));
1729 value=(unsigned short) ((((unsigned char *) buffer)[0] << 8) |
1730 ((unsigned char *) buffer)[1]);
1731 return((unsigned short) (value & 0xffff));
1734 static inline unsigned int ReadProfileLong(const EndianType endian,
1735 unsigned char *buffer)
1740 if (endian == LSBEndian)
1742 value=(unsigned int) ((buffer[3] << 24) | (buffer[2] << 16) |
1743 (buffer[1] << 8 ) | (buffer[0]));
1744 return((unsigned int) (value & 0xffffffff));
1746 value=(unsigned int) ((buffer[0] << 24) | (buffer[1] << 16) |
1747 (buffer[2] << 8) | buffer[3]);
1748 return((unsigned int) (value & 0xffffffff));
1751 static inline unsigned int ReadProfileMSBLong(unsigned char **p,size_t *length)
1758 value=ReadProfileLong(MSBEndian,*p);
1764 static inline unsigned short ReadProfileMSBShort(unsigned char **p,
1772 value=ReadProfileShort(MSBEndian,*p);
1778 static inline void WriteProfileLong(const EndianType endian,
1779 const size_t value,unsigned char *p)
1784 if (endian == LSBEndian)
1786 buffer[0]=(unsigned char) value;
1787 buffer[1]=(unsigned char) (value >> 8);
1788 buffer[2]=(unsigned char) (value >> 16);
1789 buffer[3]=(unsigned char) (value >> 24);
1790 (void) CopyMagickMemory(p,buffer,4);
1793 buffer[0]=(unsigned char) (value >> 24);
1794 buffer[1]=(unsigned char) (value >> 16);
1795 buffer[2]=(unsigned char) (value >> 8);
1796 buffer[3]=(unsigned char) value;
1797 (void) CopyMagickMemory(p,buffer,4);
1800 static void WriteProfileShort(const EndianType endian,
1801 const unsigned short value,unsigned char *p)
1806 if (endian == LSBEndian)
1808 buffer[0]=(unsigned char) value;
1809 buffer[1]=(unsigned char) (value >> 8);
1810 (void) CopyMagickMemory(p,buffer,2);
1813 buffer[0]=(unsigned char) (value >> 8);
1814 buffer[1]=(unsigned char) value;
1815 (void) CopyMagickMemory(p,buffer,2);
1818 static MagickBooleanType Sync8BimProfile(Image *image,StringInfo *profile)
1832 length=GetStringInfoLength(profile);
1833 p=GetStringInfoDatum(profile);
1836 if (ReadProfileByte(&p,&length) != 0x38)
1838 if (ReadProfileByte(&p,&length) != 0x42)
1840 if (ReadProfileByte(&p,&length) != 0x49)
1842 if (ReadProfileByte(&p,&length) != 0x4D)
1845 return(MagickFalse);
1846 id=ReadProfileMSBShort(&p,&length);
1847 count=(ssize_t) ReadProfileByte(&p,&length);
1848 if (count > (ssize_t) length)
1849 return(MagickFalse);
1851 if ((*p & 0x01) == 0)
1852 (void) ReadProfileByte(&p,&length);
1853 count=(ssize_t) ReadProfileMSBLong(&p,&length);
1854 if (count > (ssize_t) length)
1855 return(MagickFalse);
1856 if ((id == 0x3ED) && (count == 16))
1858 if (image->units == PixelsPerCentimeterResolution)
1859 WriteProfileLong(MSBEndian, (unsigned int) (image->resolution.x*2.54*
1862 WriteProfileLong(MSBEndian, (unsigned int) (image->resolution.x*
1864 WriteProfileShort(MSBEndian,(unsigned short) image->units,p+4);
1865 if (image->units == PixelsPerCentimeterResolution)
1866 WriteProfileLong(MSBEndian, (unsigned int) (image->resolution.y*2.54*
1869 WriteProfileLong(MSBEndian, (unsigned int) (image->resolution.y*
1871 WriteProfileShort(MSBEndian,(unsigned short) image->units,p+12);
1879 MagickBooleanType SyncExifProfile(Image *image,StringInfo *profile)
1881 #define MaxDirectoryStack 16
1882 #define EXIF_DELIMITER "\n"
1883 #define EXIF_NUM_FORMATS 12
1884 #define TAG_EXIF_OFFSET 0x8769
1885 #define TAG_INTEROP_OFFSET 0xa005
1887 typedef struct _DirectoryInfo
1897 directory_stack[MaxDirectoryStack];
1913 format_bytes[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
1920 Set EXIF resolution tag.
1922 length=GetStringInfoLength(profile);
1923 exif=GetStringInfoDatum(profile);
1925 return(MagickFalse);
1926 id=(ssize_t) ReadProfileShort(LSBEndian,exif);
1927 if ((id != 0x4949) && (id != 0x4D4D))
1931 if (ReadProfileByte(&exif,&length) != 0x45)
1933 if (ReadProfileByte(&exif,&length) != 0x78)
1935 if (ReadProfileByte(&exif,&length) != 0x69)
1937 if (ReadProfileByte(&exif,&length) != 0x66)
1939 if (ReadProfileByte(&exif,&length) != 0x00)
1941 if (ReadProfileByte(&exif,&length) != 0x00)
1946 return(MagickFalse);
1947 id=(ssize_t) ReadProfileShort(LSBEndian,exif);
1956 return(MagickFalse);
1957 if (ReadProfileShort(endian,exif+2) != 0x002a)
1958 return(MagickFalse);
1960 This the offset to the first IFD.
1962 offset=(ssize_t) ((int) ReadProfileLong(endian,exif+4));
1963 if ((offset < 0) || (size_t) offset >= length)
1964 return(MagickFalse);
1965 directory=exif+offset;
1973 directory=directory_stack[level].directory;
1974 entry=directory_stack[level].entry;
1976 if ((directory < exif) || (directory > (exif+length-2)))
1979 Determine how many entries there are in the current IFD.
1981 number_entries=ReadProfileShort(endian,directory);
1982 for ( ; entry < number_entries; entry++)
1987 register unsigned char
1998 q=(unsigned char *) (directory+2+(12*entry));
1999 tag_value=(ssize_t) ReadProfileShort(endian,q);
2000 format=(ssize_t) ReadProfileShort(endian,q+2);
2001 if ((format-1) >= EXIF_NUM_FORMATS)
2003 components=(ssize_t) ((int) ReadProfileLong(endian,q+4));
2004 number_bytes=(size_t) components*format_bytes[format];
2005 if ((ssize_t) number_bytes < components)
2006 break; /* prevent overflow */
2007 if (number_bytes <= 4)
2015 The directory entry contains an offset.
2017 offset=(ssize_t) ((int) ReadProfileLong(endian,q+8));
2018 if ((size_t) (offset+number_bytes) > length)
2020 if (~length < number_bytes)
2021 continue; /* prevent overflow */
2022 p=(unsigned char *) (exif+offset);
2028 (void) WriteProfileLong(endian,(size_t) (image->resolution.x+0.5),p);
2029 (void) WriteProfileLong(endian,1UL,p+4);
2034 (void) WriteProfileLong(endian,(size_t) (image->resolution.y+0.5),p);
2035 (void) WriteProfileLong(endian,1UL,p+4);
2040 if (number_bytes == 4)
2042 (void) WriteProfileLong(endian,(size_t) image->orientation,p);
2045 (void) WriteProfileShort(endian,(unsigned short) image->orientation,
2051 if (number_bytes == 4)
2053 (void) WriteProfileLong(endian,(size_t) (image->units+1),p);
2056 (void) WriteProfileShort(endian,(unsigned short) (image->units+1),p);
2062 if ((tag_value == TAG_EXIF_OFFSET) || (tag_value == TAG_INTEROP_OFFSET))
2067 offset=(ssize_t) ((int) ReadProfileLong(endian,p));
2068 if (((size_t) offset < length) && (level < (MaxDirectoryStack-2)))
2070 directory_stack[level].directory=directory;
2072 directory_stack[level].entry=entry;
2074 directory_stack[level].directory=exif+offset;
2075 directory_stack[level].entry=0;
2077 if ((directory+2+(12*number_entries)) > (exif+length))
2079 offset=(ssize_t) ((int) ReadProfileLong(endian,directory+2+(12*
2081 if ((offset != 0) && ((size_t) offset < length) &&
2082 (level < (MaxDirectoryStack-2)))
2084 directory_stack[level].directory=exif+offset;
2085 directory_stack[level].entry=0;
2092 } while (level > 0);
2096 MagickPrivate MagickBooleanType SyncImageProfiles(Image *image)
2105 profile=(StringInfo *) GetImageProfile(image,"8BIM");
2106 if (profile != (StringInfo *) NULL)
2107 if (Sync8BimProfile(image,profile) == MagickFalse)
2109 profile=(StringInfo *) GetImageProfile(image,"EXIF");
2110 if (profile != (StringInfo *) NULL)
2111 if (SyncExifProfile(image,profile) == MagickFalse)