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-2017 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 % https://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/image.h"
51 #include "MagickCore/linked-list.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 if (cms_exception == (CMSExceptionInfo *) NULL)
441 exception=cms_exception->exception;
442 if (exception == (ExceptionInfo *) NULL)
444 image=cms_exception->image;
445 if (image == (Image *) NULL)
447 (void) ThrowMagickException(exception,GetMagickModule(),ImageWarning,
448 "UnableToTransformColorspace","`%s'","unknown context");
451 if (image->debug != MagickFalse)
452 (void) LogMagickEvent(TransformEvent,GetMagickModule(),"lcms: #%u, %s",
453 severity,message != (char *) NULL ? message : "no message");
454 (void) ThrowMagickException(exception,GetMagickModule(),ImageWarning,
455 "UnableToTransformColorspace","`%s'",image->filename);
459 static MagickBooleanType SetsRGBImageProfile(Image *image,
460 ExceptionInfo *exception)
465 0x00, 0x00, 0x0c, 0x8c, 0x61, 0x72, 0x67, 0x6c, 0x02, 0x20, 0x00, 0x00,
466 0x6d, 0x6e, 0x74, 0x72, 0x52, 0x47, 0x42, 0x20, 0x58, 0x59, 0x5a, 0x20,
467 0x07, 0xde, 0x00, 0x01, 0x00, 0x06, 0x00, 0x16, 0x00, 0x0f, 0x00, 0x3a,
468 0x61, 0x63, 0x73, 0x70, 0x4d, 0x53, 0x46, 0x54, 0x00, 0x00, 0x00, 0x00,
469 0x49, 0x45, 0x43, 0x20, 0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00, 0x00,
470 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xd6,
471 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d, 0x61, 0x72, 0x67, 0x6c,
472 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
473 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
474 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
475 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
476 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x01, 0x50, 0x00, 0x00, 0x00, 0x99,
477 0x63, 0x70, 0x72, 0x74, 0x00, 0x00, 0x01, 0xec, 0x00, 0x00, 0x00, 0x67,
478 0x64, 0x6d, 0x6e, 0x64, 0x00, 0x00, 0x02, 0x54, 0x00, 0x00, 0x00, 0x70,
479 0x64, 0x6d, 0x64, 0x64, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x00, 0x88,
480 0x74, 0x65, 0x63, 0x68, 0x00, 0x00, 0x03, 0x4c, 0x00, 0x00, 0x00, 0x0c,
481 0x76, 0x75, 0x65, 0x64, 0x00, 0x00, 0x03, 0x58, 0x00, 0x00, 0x00, 0x67,
482 0x76, 0x69, 0x65, 0x77, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x24,
483 0x6c, 0x75, 0x6d, 0x69, 0x00, 0x00, 0x03, 0xe4, 0x00, 0x00, 0x00, 0x14,
484 0x6d, 0x65, 0x61, 0x73, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x24,
485 0x77, 0x74, 0x70, 0x74, 0x00, 0x00, 0x04, 0x1c, 0x00, 0x00, 0x00, 0x14,
486 0x62, 0x6b, 0x70, 0x74, 0x00, 0x00, 0x04, 0x30, 0x00, 0x00, 0x00, 0x14,
487 0x72, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x04, 0x44, 0x00, 0x00, 0x00, 0x14,
488 0x67, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x04, 0x58, 0x00, 0x00, 0x00, 0x14,
489 0x62, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x04, 0x6c, 0x00, 0x00, 0x00, 0x14,
490 0x72, 0x54, 0x52, 0x43, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x08, 0x0c,
491 0x67, 0x54, 0x52, 0x43, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x08, 0x0c,
492 0x62, 0x54, 0x52, 0x43, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x08, 0x0c,
493 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
494 0x73, 0x52, 0x47, 0x42, 0x20, 0x49, 0x45, 0x43, 0x36, 0x31, 0x39, 0x36,
495 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x20, 0x28, 0x45, 0x71, 0x75, 0x69, 0x76,
496 0x61, 0x6c, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x77, 0x77, 0x77,
497 0x2e, 0x73, 0x72, 0x67, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x31, 0x39,
498 0x39, 0x38, 0x20, 0x48, 0x50, 0x20, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c,
499 0x65, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
500 0x00, 0x3f, 0x73, 0x52, 0x47, 0x42, 0x20, 0x49, 0x45, 0x43, 0x36, 0x31,
501 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x20, 0x28, 0x45, 0x71, 0x75,
502 0x69, 0x76, 0x61, 0x6c, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x77,
503 0x77, 0x77, 0x2e, 0x73, 0x72, 0x67, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x20,
504 0x31, 0x39, 0x39, 0x38, 0x20, 0x48, 0x50, 0x20, 0x70, 0x72, 0x6f, 0x66,
505 0x69, 0x6c, 0x65, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
506 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x43, 0x72, 0x65, 0x61,
507 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x47, 0x72, 0x61, 0x65, 0x6d,
508 0x65, 0x20, 0x57, 0x2e, 0x20, 0x47, 0x69, 0x6c, 0x6c, 0x2e, 0x20, 0x52,
509 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x6f,
510 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20,
511 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x20, 0x4e, 0x6f, 0x20, 0x57,
512 0x61, 0x72, 0x72, 0x61, 0x6e, 0x74, 0x79, 0x2c, 0x20, 0x55, 0x73, 0x65,
513 0x20, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75, 0x72, 0x20, 0x6f, 0x77, 0x6e,
514 0x20, 0x72, 0x69, 0x73, 0x6b, 0x2e, 0x00, 0x00, 0x64, 0x65, 0x73, 0x63,
515 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x49, 0x45, 0x43, 0x20,
516 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69,
517 0x65, 0x63, 0x2e, 0x63, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
518 0x00, 0x00, 0x00, 0x00, 0x16, 0x49, 0x45, 0x43, 0x20, 0x68, 0x74, 0x74,
519 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x65, 0x63, 0x2e,
520 0x63, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
521 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
522 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
523 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
524 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e,
525 0x49, 0x45, 0x43, 0x20, 0x36, 0x31, 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e,
526 0x31, 0x20, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x52, 0x47,
527 0x42, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x75, 0x72, 0x20, 0x73, 0x70, 0x61,
528 0x63, 0x65, 0x20, 0x2d, 0x20, 0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00,
529 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x49, 0x45, 0x43,
530 0x20, 0x36, 0x31, 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x20, 0x44,
531 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x52, 0x47, 0x42, 0x20, 0x63,
532 0x6f, 0x6c, 0x6f, 0x75, 0x72, 0x20, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20,
533 0x2d, 0x20, 0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
534 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
535 0x00, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x20, 0x00, 0x00, 0x00, 0x00,
536 0x43, 0x52, 0x54, 0x20, 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00,
537 0x00, 0x00, 0x00, 0x0d, 0x49, 0x45, 0x43, 0x36, 0x31, 0x39, 0x36, 0x36,
538 0x2d, 0x32, 0x2e, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
539 0x00, 0x00, 0x00, 0x0d, 0x49, 0x45, 0x43, 0x36, 0x31, 0x39, 0x36, 0x36,
540 0x2d, 0x32, 0x2e, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
541 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
542 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
543 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
544 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
545 0x76, 0x69, 0x65, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xa4, 0x7c,
546 0x00, 0x14, 0x5f, 0x30, 0x00, 0x10, 0xce, 0x02, 0x00, 0x03, 0xed, 0xb2,
547 0x00, 0x04, 0x13, 0x0a, 0x00, 0x03, 0x5c, 0x67, 0x00, 0x00, 0x00, 0x01,
548 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x0a, 0x3d,
549 0x00, 0x50, 0x00, 0x00, 0x00, 0x57, 0x1e, 0xb8, 0x6d, 0x65, 0x61, 0x73,
550 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
551 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
552 0x00, 0x00, 0x02, 0x8f, 0x00, 0x00, 0x00, 0x02, 0x58, 0x59, 0x5a, 0x20,
553 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x51, 0x00, 0x01, 0x00, 0x00,
554 0x00, 0x01, 0x16, 0xcc, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00,
555 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
556 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xa0,
557 0x00, 0x00, 0x38, 0xf5, 0x00, 0x00, 0x03, 0x90, 0x58, 0x59, 0x5a, 0x20,
558 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x97, 0x00, 0x00, 0xb7, 0x87,
559 0x00, 0x00, 0x18, 0xd9, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00,
560 0x00, 0x00, 0x24, 0x9f, 0x00, 0x00, 0x0f, 0x84, 0x00, 0x00, 0xb6, 0xc4,
561 0x63, 0x75, 0x72, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
562 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x14, 0x00, 0x19,
563 0x00, 0x1e, 0x00, 0x23, 0x00, 0x28, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x37,
564 0x00, 0x3b, 0x00, 0x40, 0x00, 0x45, 0x00, 0x4a, 0x00, 0x4f, 0x00, 0x54,
565 0x00, 0x59, 0x00, 0x5e, 0x00, 0x63, 0x00, 0x68, 0x00, 0x6d, 0x00, 0x72,
566 0x00, 0x77, 0x00, 0x7c, 0x00, 0x81, 0x00, 0x86, 0x00, 0x8b, 0x00, 0x90,
567 0x00, 0x95, 0x00, 0x9a, 0x00, 0x9f, 0x00, 0xa4, 0x00, 0xa9, 0x00, 0xae,
568 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc1, 0x00, 0xc6, 0x00, 0xcb,
569 0x00, 0xd0, 0x00, 0xd5, 0x00, 0xdb, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0xeb,
570 0x00, 0xf0, 0x00, 0xf6, 0x00, 0xfb, 0x01, 0x01, 0x01, 0x07, 0x01, 0x0d,
571 0x01, 0x13, 0x01, 0x19, 0x01, 0x1f, 0x01, 0x25, 0x01, 0x2b, 0x01, 0x32,
572 0x01, 0x38, 0x01, 0x3e, 0x01, 0x45, 0x01, 0x4c, 0x01, 0x52, 0x01, 0x59,
573 0x01, 0x60, 0x01, 0x67, 0x01, 0x6e, 0x01, 0x75, 0x01, 0x7c, 0x01, 0x83,
574 0x01, 0x8b, 0x01, 0x92, 0x01, 0x9a, 0x01, 0xa1, 0x01, 0xa9, 0x01, 0xb1,
575 0x01, 0xb9, 0x01, 0xc1, 0x01, 0xc9, 0x01, 0xd1, 0x01, 0xd9, 0x01, 0xe1,
576 0x01, 0xe9, 0x01, 0xf2, 0x01, 0xfa, 0x02, 0x03, 0x02, 0x0c, 0x02, 0x14,
577 0x02, 0x1d, 0x02, 0x26, 0x02, 0x2f, 0x02, 0x38, 0x02, 0x41, 0x02, 0x4b,
578 0x02, 0x54, 0x02, 0x5d, 0x02, 0x67, 0x02, 0x71, 0x02, 0x7a, 0x02, 0x84,
579 0x02, 0x8e, 0x02, 0x98, 0x02, 0xa2, 0x02, 0xac, 0x02, 0xb6, 0x02, 0xc1,
580 0x02, 0xcb, 0x02, 0xd5, 0x02, 0xe0, 0x02, 0xeb, 0x02, 0xf5, 0x03, 0x00,
581 0x03, 0x0b, 0x03, 0x16, 0x03, 0x21, 0x03, 0x2d, 0x03, 0x38, 0x03, 0x43,
582 0x03, 0x4f, 0x03, 0x5a, 0x03, 0x66, 0x03, 0x72, 0x03, 0x7e, 0x03, 0x8a,
583 0x03, 0x96, 0x03, 0xa2, 0x03, 0xae, 0x03, 0xba, 0x03, 0xc7, 0x03, 0xd3,
584 0x03, 0xe0, 0x03, 0xec, 0x03, 0xf9, 0x04, 0x06, 0x04, 0x13, 0x04, 0x20,
585 0x04, 0x2d, 0x04, 0x3b, 0x04, 0x48, 0x04, 0x55, 0x04, 0x63, 0x04, 0x71,
586 0x04, 0x7e, 0x04, 0x8c, 0x04, 0x9a, 0x04, 0xa8, 0x04, 0xb6, 0x04, 0xc4,
587 0x04, 0xd3, 0x04, 0xe1, 0x04, 0xf0, 0x04, 0xfe, 0x05, 0x0d, 0x05, 0x1c,
588 0x05, 0x2b, 0x05, 0x3a, 0x05, 0x49, 0x05, 0x58, 0x05, 0x67, 0x05, 0x77,
589 0x05, 0x86, 0x05, 0x96, 0x05, 0xa6, 0x05, 0xb5, 0x05, 0xc5, 0x05, 0xd5,
590 0x05, 0xe5, 0x05, 0xf6, 0x06, 0x06, 0x06, 0x16, 0x06, 0x27, 0x06, 0x37,
591 0x06, 0x48, 0x06, 0x59, 0x06, 0x6a, 0x06, 0x7b, 0x06, 0x8c, 0x06, 0x9d,
592 0x06, 0xaf, 0x06, 0xc0, 0x06, 0xd1, 0x06, 0xe3, 0x06, 0xf5, 0x07, 0x07,
593 0x07, 0x19, 0x07, 0x2b, 0x07, 0x3d, 0x07, 0x4f, 0x07, 0x61, 0x07, 0x74,
594 0x07, 0x86, 0x07, 0x99, 0x07, 0xac, 0x07, 0xbf, 0x07, 0xd2, 0x07, 0xe5,
595 0x07, 0xf8, 0x08, 0x0b, 0x08, 0x1f, 0x08, 0x32, 0x08, 0x46, 0x08, 0x5a,
596 0x08, 0x6e, 0x08, 0x82, 0x08, 0x96, 0x08, 0xaa, 0x08, 0xbe, 0x08, 0xd2,
597 0x08, 0xe7, 0x08, 0xfb, 0x09, 0x10, 0x09, 0x25, 0x09, 0x3a, 0x09, 0x4f,
598 0x09, 0x64, 0x09, 0x79, 0x09, 0x8f, 0x09, 0xa4, 0x09, 0xba, 0x09, 0xcf,
599 0x09, 0xe5, 0x09, 0xfb, 0x0a, 0x11, 0x0a, 0x27, 0x0a, 0x3d, 0x0a, 0x54,
600 0x0a, 0x6a, 0x0a, 0x81, 0x0a, 0x98, 0x0a, 0xae, 0x0a, 0xc5, 0x0a, 0xdc,
601 0x0a, 0xf3, 0x0b, 0x0b, 0x0b, 0x22, 0x0b, 0x39, 0x0b, 0x51, 0x0b, 0x69,
602 0x0b, 0x80, 0x0b, 0x98, 0x0b, 0xb0, 0x0b, 0xc8, 0x0b, 0xe1, 0x0b, 0xf9,
603 0x0c, 0x12, 0x0c, 0x2a, 0x0c, 0x43, 0x0c, 0x5c, 0x0c, 0x75, 0x0c, 0x8e,
604 0x0c, 0xa7, 0x0c, 0xc0, 0x0c, 0xd9, 0x0c, 0xf3, 0x0d, 0x0d, 0x0d, 0x26,
605 0x0d, 0x40, 0x0d, 0x5a, 0x0d, 0x74, 0x0d, 0x8e, 0x0d, 0xa9, 0x0d, 0xc3,
606 0x0d, 0xde, 0x0d, 0xf8, 0x0e, 0x13, 0x0e, 0x2e, 0x0e, 0x49, 0x0e, 0x64,
607 0x0e, 0x7f, 0x0e, 0x9b, 0x0e, 0xb6, 0x0e, 0xd2, 0x0e, 0xee, 0x0f, 0x09,
608 0x0f, 0x25, 0x0f, 0x41, 0x0f, 0x5e, 0x0f, 0x7a, 0x0f, 0x96, 0x0f, 0xb3,
609 0x0f, 0xcf, 0x0f, 0xec, 0x10, 0x09, 0x10, 0x26, 0x10, 0x43, 0x10, 0x61,
610 0x10, 0x7e, 0x10, 0x9b, 0x10, 0xb9, 0x10, 0xd7, 0x10, 0xf5, 0x11, 0x13,
611 0x11, 0x31, 0x11, 0x4f, 0x11, 0x6d, 0x11, 0x8c, 0x11, 0xaa, 0x11, 0xc9,
612 0x11, 0xe8, 0x12, 0x07, 0x12, 0x26, 0x12, 0x45, 0x12, 0x64, 0x12, 0x84,
613 0x12, 0xa3, 0x12, 0xc3, 0x12, 0xe3, 0x13, 0x03, 0x13, 0x23, 0x13, 0x43,
614 0x13, 0x63, 0x13, 0x83, 0x13, 0xa4, 0x13, 0xc5, 0x13, 0xe5, 0x14, 0x06,
615 0x14, 0x27, 0x14, 0x49, 0x14, 0x6a, 0x14, 0x8b, 0x14, 0xad, 0x14, 0xce,
616 0x14, 0xf0, 0x15, 0x12, 0x15, 0x34, 0x15, 0x56, 0x15, 0x78, 0x15, 0x9b,
617 0x15, 0xbd, 0x15, 0xe0, 0x16, 0x03, 0x16, 0x26, 0x16, 0x49, 0x16, 0x6c,
618 0x16, 0x8f, 0x16, 0xb2, 0x16, 0xd6, 0x16, 0xfa, 0x17, 0x1d, 0x17, 0x41,
619 0x17, 0x65, 0x17, 0x89, 0x17, 0xae, 0x17, 0xd2, 0x17, 0xf7, 0x18, 0x1b,
620 0x18, 0x40, 0x18, 0x65, 0x18, 0x8a, 0x18, 0xaf, 0x18, 0xd5, 0x18, 0xfa,
621 0x19, 0x20, 0x19, 0x45, 0x19, 0x6b, 0x19, 0x91, 0x19, 0xb7, 0x19, 0xdd,
622 0x1a, 0x04, 0x1a, 0x2a, 0x1a, 0x51, 0x1a, 0x77, 0x1a, 0x9e, 0x1a, 0xc5,
623 0x1a, 0xec, 0x1b, 0x14, 0x1b, 0x3b, 0x1b, 0x63, 0x1b, 0x8a, 0x1b, 0xb2,
624 0x1b, 0xda, 0x1c, 0x02, 0x1c, 0x2a, 0x1c, 0x52, 0x1c, 0x7b, 0x1c, 0xa3,
625 0x1c, 0xcc, 0x1c, 0xf5, 0x1d, 0x1e, 0x1d, 0x47, 0x1d, 0x70, 0x1d, 0x99,
626 0x1d, 0xc3, 0x1d, 0xec, 0x1e, 0x16, 0x1e, 0x40, 0x1e, 0x6a, 0x1e, 0x94,
627 0x1e, 0xbe, 0x1e, 0xe9, 0x1f, 0x13, 0x1f, 0x3e, 0x1f, 0x69, 0x1f, 0x94,
628 0x1f, 0xbf, 0x1f, 0xea, 0x20, 0x15, 0x20, 0x41, 0x20, 0x6c, 0x20, 0x98,
629 0x20, 0xc4, 0x20, 0xf0, 0x21, 0x1c, 0x21, 0x48, 0x21, 0x75, 0x21, 0xa1,
630 0x21, 0xce, 0x21, 0xfb, 0x22, 0x27, 0x22, 0x55, 0x22, 0x82, 0x22, 0xaf,
631 0x22, 0xdd, 0x23, 0x0a, 0x23, 0x38, 0x23, 0x66, 0x23, 0x94, 0x23, 0xc2,
632 0x23, 0xf0, 0x24, 0x1f, 0x24, 0x4d, 0x24, 0x7c, 0x24, 0xab, 0x24, 0xda,
633 0x25, 0x09, 0x25, 0x38, 0x25, 0x68, 0x25, 0x97, 0x25, 0xc7, 0x25, 0xf7,
634 0x26, 0x27, 0x26, 0x57, 0x26, 0x87, 0x26, 0xb7, 0x26, 0xe8, 0x27, 0x18,
635 0x27, 0x49, 0x27, 0x7a, 0x27, 0xab, 0x27, 0xdc, 0x28, 0x0d, 0x28, 0x3f,
636 0x28, 0x71, 0x28, 0xa2, 0x28, 0xd4, 0x29, 0x06, 0x29, 0x38, 0x29, 0x6b,
637 0x29, 0x9d, 0x29, 0xd0, 0x2a, 0x02, 0x2a, 0x35, 0x2a, 0x68, 0x2a, 0x9b,
638 0x2a, 0xcf, 0x2b, 0x02, 0x2b, 0x36, 0x2b, 0x69, 0x2b, 0x9d, 0x2b, 0xd1,
639 0x2c, 0x05, 0x2c, 0x39, 0x2c, 0x6e, 0x2c, 0xa2, 0x2c, 0xd7, 0x2d, 0x0c,
640 0x2d, 0x41, 0x2d, 0x76, 0x2d, 0xab, 0x2d, 0xe1, 0x2e, 0x16, 0x2e, 0x4c,
641 0x2e, 0x82, 0x2e, 0xb7, 0x2e, 0xee, 0x2f, 0x24, 0x2f, 0x5a, 0x2f, 0x91,
642 0x2f, 0xc7, 0x2f, 0xfe, 0x30, 0x35, 0x30, 0x6c, 0x30, 0xa4, 0x30, 0xdb,
643 0x31, 0x12, 0x31, 0x4a, 0x31, 0x82, 0x31, 0xba, 0x31, 0xf2, 0x32, 0x2a,
644 0x32, 0x63, 0x32, 0x9b, 0x32, 0xd4, 0x33, 0x0d, 0x33, 0x46, 0x33, 0x7f,
645 0x33, 0xb8, 0x33, 0xf1, 0x34, 0x2b, 0x34, 0x65, 0x34, 0x9e, 0x34, 0xd8,
646 0x35, 0x13, 0x35, 0x4d, 0x35, 0x87, 0x35, 0xc2, 0x35, 0xfd, 0x36, 0x37,
647 0x36, 0x72, 0x36, 0xae, 0x36, 0xe9, 0x37, 0x24, 0x37, 0x60, 0x37, 0x9c,
648 0x37, 0xd7, 0x38, 0x14, 0x38, 0x50, 0x38, 0x8c, 0x38, 0xc8, 0x39, 0x05,
649 0x39, 0x42, 0x39, 0x7f, 0x39, 0xbc, 0x39, 0xf9, 0x3a, 0x36, 0x3a, 0x74,
650 0x3a, 0xb2, 0x3a, 0xef, 0x3b, 0x2d, 0x3b, 0x6b, 0x3b, 0xaa, 0x3b, 0xe8,
651 0x3c, 0x27, 0x3c, 0x65, 0x3c, 0xa4, 0x3c, 0xe3, 0x3d, 0x22, 0x3d, 0x61,
652 0x3d, 0xa1, 0x3d, 0xe0, 0x3e, 0x20, 0x3e, 0x60, 0x3e, 0xa0, 0x3e, 0xe0,
653 0x3f, 0x21, 0x3f, 0x61, 0x3f, 0xa2, 0x3f, 0xe2, 0x40, 0x23, 0x40, 0x64,
654 0x40, 0xa6, 0x40, 0xe7, 0x41, 0x29, 0x41, 0x6a, 0x41, 0xac, 0x41, 0xee,
655 0x42, 0x30, 0x42, 0x72, 0x42, 0xb5, 0x42, 0xf7, 0x43, 0x3a, 0x43, 0x7d,
656 0x43, 0xc0, 0x44, 0x03, 0x44, 0x47, 0x44, 0x8a, 0x44, 0xce, 0x45, 0x12,
657 0x45, 0x55, 0x45, 0x9a, 0x45, 0xde, 0x46, 0x22, 0x46, 0x67, 0x46, 0xab,
658 0x46, 0xf0, 0x47, 0x35, 0x47, 0x7b, 0x47, 0xc0, 0x48, 0x05, 0x48, 0x4b,
659 0x48, 0x91, 0x48, 0xd7, 0x49, 0x1d, 0x49, 0x63, 0x49, 0xa9, 0x49, 0xf0,
660 0x4a, 0x37, 0x4a, 0x7d, 0x4a, 0xc4, 0x4b, 0x0c, 0x4b, 0x53, 0x4b, 0x9a,
661 0x4b, 0xe2, 0x4c, 0x2a, 0x4c, 0x72, 0x4c, 0xba, 0x4d, 0x02, 0x4d, 0x4a,
662 0x4d, 0x93, 0x4d, 0xdc, 0x4e, 0x25, 0x4e, 0x6e, 0x4e, 0xb7, 0x4f, 0x00,
663 0x4f, 0x49, 0x4f, 0x93, 0x4f, 0xdd, 0x50, 0x27, 0x50, 0x71, 0x50, 0xbb,
664 0x51, 0x06, 0x51, 0x50, 0x51, 0x9b, 0x51, 0xe6, 0x52, 0x31, 0x52, 0x7c,
665 0x52, 0xc7, 0x53, 0x13, 0x53, 0x5f, 0x53, 0xaa, 0x53, 0xf6, 0x54, 0x42,
666 0x54, 0x8f, 0x54, 0xdb, 0x55, 0x28, 0x55, 0x75, 0x55, 0xc2, 0x56, 0x0f,
667 0x56, 0x5c, 0x56, 0xa9, 0x56, 0xf7, 0x57, 0x44, 0x57, 0x92, 0x57, 0xe0,
668 0x58, 0x2f, 0x58, 0x7d, 0x58, 0xcb, 0x59, 0x1a, 0x59, 0x69, 0x59, 0xb8,
669 0x5a, 0x07, 0x5a, 0x56, 0x5a, 0xa6, 0x5a, 0xf5, 0x5b, 0x45, 0x5b, 0x95,
670 0x5b, 0xe5, 0x5c, 0x35, 0x5c, 0x86, 0x5c, 0xd6, 0x5d, 0x27, 0x5d, 0x78,
671 0x5d, 0xc9, 0x5e, 0x1a, 0x5e, 0x6c, 0x5e, 0xbd, 0x5f, 0x0f, 0x5f, 0x61,
672 0x5f, 0xb3, 0x60, 0x05, 0x60, 0x57, 0x60, 0xaa, 0x60, 0xfc, 0x61, 0x4f,
673 0x61, 0xa2, 0x61, 0xf5, 0x62, 0x49, 0x62, 0x9c, 0x62, 0xf0, 0x63, 0x43,
674 0x63, 0x97, 0x63, 0xeb, 0x64, 0x40, 0x64, 0x94, 0x64, 0xe9, 0x65, 0x3d,
675 0x65, 0x92, 0x65, 0xe7, 0x66, 0x3d, 0x66, 0x92, 0x66, 0xe8, 0x67, 0x3d,
676 0x67, 0x93, 0x67, 0xe9, 0x68, 0x3f, 0x68, 0x96, 0x68, 0xec, 0x69, 0x43,
677 0x69, 0x9a, 0x69, 0xf1, 0x6a, 0x48, 0x6a, 0x9f, 0x6a, 0xf7, 0x6b, 0x4f,
678 0x6b, 0xa7, 0x6b, 0xff, 0x6c, 0x57, 0x6c, 0xaf, 0x6d, 0x08, 0x6d, 0x60,
679 0x6d, 0xb9, 0x6e, 0x12, 0x6e, 0x6b, 0x6e, 0xc4, 0x6f, 0x1e, 0x6f, 0x78,
680 0x6f, 0xd1, 0x70, 0x2b, 0x70, 0x86, 0x70, 0xe0, 0x71, 0x3a, 0x71, 0x95,
681 0x71, 0xf0, 0x72, 0x4b, 0x72, 0xa6, 0x73, 0x01, 0x73, 0x5d, 0x73, 0xb8,
682 0x74, 0x14, 0x74, 0x70, 0x74, 0xcc, 0x75, 0x28, 0x75, 0x85, 0x75, 0xe1,
683 0x76, 0x3e, 0x76, 0x9b, 0x76, 0xf8, 0x77, 0x56, 0x77, 0xb3, 0x78, 0x11,
684 0x78, 0x6e, 0x78, 0xcc, 0x79, 0x2a, 0x79, 0x89, 0x79, 0xe7, 0x7a, 0x46,
685 0x7a, 0xa5, 0x7b, 0x04, 0x7b, 0x63, 0x7b, 0xc2, 0x7c, 0x21, 0x7c, 0x81,
686 0x7c, 0xe1, 0x7d, 0x41, 0x7d, 0xa1, 0x7e, 0x01, 0x7e, 0x62, 0x7e, 0xc2,
687 0x7f, 0x23, 0x7f, 0x84, 0x7f, 0xe5, 0x80, 0x47, 0x80, 0xa8, 0x81, 0x0a,
688 0x81, 0x6b, 0x81, 0xcd, 0x82, 0x30, 0x82, 0x92, 0x82, 0xf4, 0x83, 0x57,
689 0x83, 0xba, 0x84, 0x1d, 0x84, 0x80, 0x84, 0xe3, 0x85, 0x47, 0x85, 0xab,
690 0x86, 0x0e, 0x86, 0x72, 0x86, 0xd7, 0x87, 0x3b, 0x87, 0x9f, 0x88, 0x04,
691 0x88, 0x69, 0x88, 0xce, 0x89, 0x33, 0x89, 0x99, 0x89, 0xfe, 0x8a, 0x64,
692 0x8a, 0xca, 0x8b, 0x30, 0x8b, 0x96, 0x8b, 0xfc, 0x8c, 0x63, 0x8c, 0xca,
693 0x8d, 0x31, 0x8d, 0x98, 0x8d, 0xff, 0x8e, 0x66, 0x8e, 0xce, 0x8f, 0x36,
694 0x8f, 0x9e, 0x90, 0x06, 0x90, 0x6e, 0x90, 0xd6, 0x91, 0x3f, 0x91, 0xa8,
695 0x92, 0x11, 0x92, 0x7a, 0x92, 0xe3, 0x93, 0x4d, 0x93, 0xb6, 0x94, 0x20,
696 0x94, 0x8a, 0x94, 0xf4, 0x95, 0x5f, 0x95, 0xc9, 0x96, 0x34, 0x96, 0x9f,
697 0x97, 0x0a, 0x97, 0x75, 0x97, 0xe0, 0x98, 0x4c, 0x98, 0xb8, 0x99, 0x24,
698 0x99, 0x90, 0x99, 0xfc, 0x9a, 0x68, 0x9a, 0xd5, 0x9b, 0x42, 0x9b, 0xaf,
699 0x9c, 0x1c, 0x9c, 0x89, 0x9c, 0xf7, 0x9d, 0x64, 0x9d, 0xd2, 0x9e, 0x40,
700 0x9e, 0xae, 0x9f, 0x1d, 0x9f, 0x8b, 0x9f, 0xfa, 0xa0, 0x69, 0xa0, 0xd8,
701 0xa1, 0x47, 0xa1, 0xb6, 0xa2, 0x26, 0xa2, 0x96, 0xa3, 0x06, 0xa3, 0x76,
702 0xa3, 0xe6, 0xa4, 0x56, 0xa4, 0xc7, 0xa5, 0x38, 0xa5, 0xa9, 0xa6, 0x1a,
703 0xa6, 0x8b, 0xa6, 0xfd, 0xa7, 0x6e, 0xa7, 0xe0, 0xa8, 0x52, 0xa8, 0xc4,
704 0xa9, 0x37, 0xa9, 0xa9, 0xaa, 0x1c, 0xaa, 0x8f, 0xab, 0x02, 0xab, 0x75,
705 0xab, 0xe9, 0xac, 0x5c, 0xac, 0xd0, 0xad, 0x44, 0xad, 0xb8, 0xae, 0x2d,
706 0xae, 0xa1, 0xaf, 0x16, 0xaf, 0x8b, 0xb0, 0x00, 0xb0, 0x75, 0xb0, 0xea,
707 0xb1, 0x60, 0xb1, 0xd6, 0xb2, 0x4b, 0xb2, 0xc2, 0xb3, 0x38, 0xb3, 0xae,
708 0xb4, 0x25, 0xb4, 0x9c, 0xb5, 0x13, 0xb5, 0x8a, 0xb6, 0x01, 0xb6, 0x79,
709 0xb6, 0xf0, 0xb7, 0x68, 0xb7, 0xe0, 0xb8, 0x59, 0xb8, 0xd1, 0xb9, 0x4a,
710 0xb9, 0xc2, 0xba, 0x3b, 0xba, 0xb5, 0xbb, 0x2e, 0xbb, 0xa7, 0xbc, 0x21,
711 0xbc, 0x9b, 0xbd, 0x15, 0xbd, 0x8f, 0xbe, 0x0a, 0xbe, 0x84, 0xbe, 0xff,
712 0xbf, 0x7a, 0xbf, 0xf5, 0xc0, 0x70, 0xc0, 0xec, 0xc1, 0x67, 0xc1, 0xe3,
713 0xc2, 0x5f, 0xc2, 0xdb, 0xc3, 0x58, 0xc3, 0xd4, 0xc4, 0x51, 0xc4, 0xce,
714 0xc5, 0x4b, 0xc5, 0xc8, 0xc6, 0x46, 0xc6, 0xc3, 0xc7, 0x41, 0xc7, 0xbf,
715 0xc8, 0x3d, 0xc8, 0xbc, 0xc9, 0x3a, 0xc9, 0xb9, 0xca, 0x38, 0xca, 0xb7,
716 0xcb, 0x36, 0xcb, 0xb6, 0xcc, 0x35, 0xcc, 0xb5, 0xcd, 0x35, 0xcd, 0xb5,
717 0xce, 0x36, 0xce, 0xb6, 0xcf, 0x37, 0xcf, 0xb8, 0xd0, 0x39, 0xd0, 0xba,
718 0xd1, 0x3c, 0xd1, 0xbe, 0xd2, 0x3f, 0xd2, 0xc1, 0xd3, 0x44, 0xd3, 0xc6,
719 0xd4, 0x49, 0xd4, 0xcb, 0xd5, 0x4e, 0xd5, 0xd1, 0xd6, 0x55, 0xd6, 0xd8,
720 0xd7, 0x5c, 0xd7, 0xe0, 0xd8, 0x64, 0xd8, 0xe8, 0xd9, 0x6c, 0xd9, 0xf1,
721 0xda, 0x76, 0xda, 0xfb, 0xdb, 0x80, 0xdc, 0x05, 0xdc, 0x8a, 0xdd, 0x10,
722 0xdd, 0x96, 0xde, 0x1c, 0xde, 0xa2, 0xdf, 0x29, 0xdf, 0xaf, 0xe0, 0x36,
723 0xe0, 0xbd, 0xe1, 0x44, 0xe1, 0xcc, 0xe2, 0x53, 0xe2, 0xdb, 0xe3, 0x63,
724 0xe3, 0xeb, 0xe4, 0x73, 0xe4, 0xfc, 0xe5, 0x84, 0xe6, 0x0d, 0xe6, 0x96,
725 0xe7, 0x1f, 0xe7, 0xa9, 0xe8, 0x32, 0xe8, 0xbc, 0xe9, 0x46, 0xe9, 0xd0,
726 0xea, 0x5b, 0xea, 0xe5, 0xeb, 0x70, 0xeb, 0xfb, 0xec, 0x86, 0xed, 0x11,
727 0xed, 0x9c, 0xee, 0x28, 0xee, 0xb4, 0xef, 0x40, 0xef, 0xcc, 0xf0, 0x58,
728 0xf0, 0xe5, 0xf1, 0x72, 0xf1, 0xff, 0xf2, 0x8c, 0xf3, 0x19, 0xf3, 0xa7,
729 0xf4, 0x34, 0xf4, 0xc2, 0xf5, 0x50, 0xf5, 0xde, 0xf6, 0x6d, 0xf6, 0xfb,
730 0xf7, 0x8a, 0xf8, 0x19, 0xf8, 0xa8, 0xf9, 0x38, 0xf9, 0xc7, 0xfa, 0x57,
731 0xfa, 0xe7, 0xfb, 0x77, 0xfc, 0x07, 0xfc, 0x98, 0xfd, 0x29, 0xfd, 0xba,
732 0xfe, 0x4b, 0xfe, 0xdc, 0xff, 0x6d, 0xff, 0xff
741 assert(image != (Image *) NULL);
742 assert(image->signature == MagickCoreSignature);
743 if (GetImageProfile(image,"icc") != (const StringInfo *) NULL)
745 profile=AcquireStringInfo(sizeof(sRGBProfile));
746 SetStringInfoDatum(profile,sRGBProfile);
747 status=SetImageProfile(image,"icc",profile,exception);
748 profile=DestroyStringInfo(profile);
752 MagickExport MagickBooleanType ProfileImage(Image *image,const char *name,
753 const void *datum,const size_t length,ExceptionInfo *exception)
755 #define ProfileImageTag "Profile/Image"
756 #define ThrowProfileException(severity,tag,context) \
758 if (source_profile != (cmsHPROFILE) NULL) \
759 (void) cmsCloseProfile(source_profile); \
760 if (target_profile != (cmsHPROFILE) NULL) \
761 (void) cmsCloseProfile(target_profile); \
762 ThrowBinaryException(severity,tag,context); \
771 assert(image != (Image *) NULL);
772 assert(image->signature == MagickCoreSignature);
773 if (image->debug != MagickFalse)
774 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
775 assert(name != (const char *) NULL);
776 if ((datum == (const void *) NULL) || (length == 0))
782 Delete image profile(s).
784 ResetImageProfileIterator(image);
785 for (next=GetNextImageProfile(image); next != (const char *) NULL; )
787 if (IsOptionMember(next,name) != MagickFalse)
789 (void) DeleteImageProfile(image,next);
790 ResetImageProfileIterator(image);
792 next=GetNextImageProfile(image);
797 Add a ICC, IPTC, or generic profile to the image.
800 profile=AcquireStringInfo((size_t) length);
801 SetStringInfoDatum(profile,(unsigned char *) datum);
802 if ((LocaleCompare(name,"icc") != 0) && (LocaleCompare(name,"icm") != 0))
803 status=SetImageProfile(image,name,profile,exception);
809 icc_profile=GetImageProfile(image,"icc");
810 if ((icc_profile != (const StringInfo *) NULL) &&
811 (CompareStringInfo(icc_profile,profile) == 0))
816 value=GetImageProperty(image,"exif:ColorSpace",exception);
818 if (LocaleCompare(value,"1") != 0)
819 (void) SetsRGBImageProfile(image,exception);
820 value=GetImageProperty(image,"exif:InteroperabilityIndex",exception);
821 if (LocaleCompare(value,"R98.") != 0)
822 (void) SetsRGBImageProfile(image,exception);
824 value=GetImageProperty(image,"exif:InteroperabilityIndex",exception);
825 if (LocaleCompare(value,"R03.") != 0)
826 (void) SetAdobeRGB1998ImageProfile(image,exception);
828 icc_profile=GetImageProfile(image,"icc");
830 if ((icc_profile != (const StringInfo *) NULL) &&
831 (CompareStringInfo(icc_profile,profile) == 0))
833 profile=DestroyStringInfo(profile);
836 #if !defined(MAGICKCORE_LCMS_DELEGATE)
837 (void) ThrowMagickException(exception,GetMagickModule(),
838 MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn",
839 "'%s' (LCMS)",image->filename);
849 Transform pixel colors as defined by the color profiles.
851 cmsSetLogErrorHandler(CMSExceptionHandler);
852 cms_exception.image=image;
853 cms_exception.exception=exception;
854 (void) cms_exception;
855 source_profile=cmsOpenProfileFromMemTHR((cmsContext) &cms_exception,
856 GetStringInfoDatum(profile),(cmsUInt32Number)
857 GetStringInfoLength(profile));
858 if (source_profile == (cmsHPROFILE) NULL)
859 ThrowBinaryException(ResourceLimitError,
860 "ColorspaceColorProfileMismatch",name);
861 if ((cmsGetDeviceClass(source_profile) != cmsSigLinkClass) &&
862 (icc_profile == (StringInfo *) NULL))
863 status=SetImageProfile(image,name,profile,exception);
873 cmsColorSpaceSignature
880 *magick_restrict transform;
901 **magick_restrict source_pixels,
902 **magick_restrict target_pixels;
904 target_profile=(cmsHPROFILE) NULL;
905 if (icc_profile != (StringInfo *) NULL)
907 target_profile=source_profile;
908 source_profile=cmsOpenProfileFromMemTHR((cmsContext)
909 &cms_exception,GetStringInfoDatum(icc_profile),
910 (cmsUInt32Number) GetStringInfoLength(icc_profile));
911 if (source_profile == (cmsHPROFILE) NULL)
912 ThrowProfileException(ResourceLimitError,
913 "ColorspaceColorProfileMismatch",name);
915 switch (cmsGetColorSpace(source_profile))
919 source_colorspace=CMYKColorspace;
920 source_type=(cmsUInt32Number) TYPE_CMYK_16;
926 source_colorspace=GRAYColorspace;
927 source_type=(cmsUInt32Number) TYPE_GRAY_16;
933 source_colorspace=LabColorspace;
934 source_type=(cmsUInt32Number) TYPE_Lab_16;
940 source_colorspace=YUVColorspace;
941 source_type=(cmsUInt32Number) TYPE_YUV_16;
947 source_colorspace=sRGBColorspace;
948 source_type=(cmsUInt32Number) TYPE_RGB_16;
954 source_colorspace=XYZColorspace;
955 source_type=(cmsUInt32Number) TYPE_XYZ_16;
959 case cmsSigYCbCrData:
961 source_colorspace=YCbCrColorspace;
962 source_type=(cmsUInt32Number) TYPE_YCbCr_16;
968 source_colorspace=UndefinedColorspace;
969 source_type=(cmsUInt32Number) TYPE_RGB_16;
974 signature=cmsGetPCS(source_profile);
975 if (target_profile != (cmsHPROFILE) NULL)
976 signature=cmsGetColorSpace(target_profile);
981 target_colorspace=CMYKColorspace;
982 target_type=(cmsUInt32Number) TYPE_CMYK_16;
988 target_colorspace=LabColorspace;
989 target_type=(cmsUInt32Number) TYPE_Lab_16;
995 target_colorspace=GRAYColorspace;
996 target_type=(cmsUInt32Number) TYPE_GRAY_16;
1002 target_colorspace=YUVColorspace;
1003 target_type=(cmsUInt32Number) TYPE_YUV_16;
1009 target_colorspace=sRGBColorspace;
1010 target_type=(cmsUInt32Number) TYPE_RGB_16;
1016 target_colorspace=XYZColorspace;
1017 target_type=(cmsUInt32Number) TYPE_XYZ_16;
1021 case cmsSigYCbCrData:
1023 target_colorspace=YCbCrColorspace;
1024 target_type=(cmsUInt32Number) TYPE_YCbCr_16;
1030 target_colorspace=UndefinedColorspace;
1031 target_type=(cmsUInt32Number) TYPE_RGB_16;
1036 if ((source_colorspace == UndefinedColorspace) ||
1037 (target_colorspace == UndefinedColorspace))
1038 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1040 if ((source_colorspace == GRAYColorspace) &&
1041 (SetImageGray(image,exception) == MagickFalse))
1042 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1044 if ((source_colorspace == CMYKColorspace) &&
1045 (image->colorspace != CMYKColorspace))
1046 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1048 if ((source_colorspace == XYZColorspace) &&
1049 (image->colorspace != XYZColorspace))
1050 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1052 if ((source_colorspace == YCbCrColorspace) &&
1053 (image->colorspace != YCbCrColorspace))
1054 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1056 if ((source_colorspace != CMYKColorspace) &&
1057 (source_colorspace != LabColorspace) &&
1058 (source_colorspace != XYZColorspace) &&
1059 (source_colorspace != YCbCrColorspace) &&
1060 (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse))
1061 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1063 switch (image->rendering_intent)
1065 case AbsoluteIntent: intent=INTENT_ABSOLUTE_COLORIMETRIC; break;
1066 case PerceptualIntent: intent=INTENT_PERCEPTUAL; break;
1067 case RelativeIntent: intent=INTENT_RELATIVE_COLORIMETRIC; break;
1068 case SaturationIntent: intent=INTENT_SATURATION; break;
1069 default: intent=INTENT_PERCEPTUAL; break;
1071 flags=cmsFLAGS_HIGHRESPRECALC;
1072 #if defined(cmsFLAGS_BLACKPOINTCOMPENSATION)
1073 if (image->black_point_compensation != MagickFalse)
1074 flags|=cmsFLAGS_BLACKPOINTCOMPENSATION;
1076 transform=AcquireTransformThreadSet(image,source_profile,
1077 source_type,target_profile,target_type,intent,flags);
1078 if (transform == (cmsHTRANSFORM *) NULL)
1079 ThrowProfileException(ImageError,"UnableToCreateColorTransform",
1082 Transform image as dictated by the source & target image profiles.
1084 source_pixels=AcquirePixelThreadSet(image->columns,source_channels);
1085 target_pixels=AcquirePixelThreadSet(image->columns,target_channels);
1086 if ((source_pixels == (unsigned short **) NULL) ||
1087 (target_pixels == (unsigned short **) NULL))
1089 transform=DestroyTransformThreadSet(transform);
1090 ThrowProfileException(ResourceLimitError,
1091 "MemoryAllocationFailed",image->filename);
1093 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1095 target_pixels=DestroyPixelThreadSet(target_pixels);
1096 source_pixels=DestroyPixelThreadSet(source_pixels);
1097 transform=DestroyTransformThreadSet(transform);
1098 if (source_profile != (cmsHPROFILE) NULL)
1099 (void) cmsCloseProfile(source_profile);
1100 if (target_profile != (cmsHPROFILE) NULL)
1101 (void) cmsCloseProfile(target_profile);
1102 return(MagickFalse);
1104 if (target_colorspace == CMYKColorspace)
1105 (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 ((status != MagickFalse) &&
1222 (cmsGetDeviceClass(source_profile) != cmsSigLinkClass))
1223 status=SetImageProfile(image,name,profile,exception);
1224 if (target_profile != (cmsHPROFILE) NULL)
1225 (void) cmsCloseProfile(target_profile);
1227 (void) cmsCloseProfile(source_profile);
1231 profile=DestroyStringInfo(profile);
1236 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1240 % R e m o v e I m a g e P r o f i l e %
1244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1246 % RemoveImageProfile() removes a named profile from the image and returns its
1249 % The format of the RemoveImageProfile method is:
1251 % void *RemoveImageProfile(Image *image,const char *name)
1253 % A description of each parameter follows:
1255 % o image: the image.
1257 % o name: the profile name.
1260 MagickExport StringInfo *RemoveImageProfile(Image *image,const char *name)
1265 assert(image != (Image *) NULL);
1266 assert(image->signature == MagickCoreSignature);
1267 if (image->debug != MagickFalse)
1268 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1269 if (image->profiles == (SplayTreeInfo *) NULL)
1270 return((StringInfo *) NULL);
1271 WriteTo8BimProfile(image,name,(StringInfo *) NULL);
1272 profile=(StringInfo *) RemoveNodeFromSplayTree((SplayTreeInfo *)
1273 image->profiles,name);
1278 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1282 % R e s e t P r o f i l e I t e r a t o r %
1286 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1288 % ResetImageProfileIterator() resets the image profile iterator. Use it in
1289 % conjunction with GetNextImageProfile() to iterate over all the profiles
1290 % associated with an image.
1292 % The format of the ResetImageProfileIterator method is:
1294 % ResetImageProfileIterator(Image *image)
1296 % A description of each parameter follows:
1298 % o image: the image.
1301 MagickExport void ResetImageProfileIterator(const Image *image)
1303 assert(image != (Image *) NULL);
1304 assert(image->signature == MagickCoreSignature);
1305 if (image->debug != MagickFalse)
1306 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1307 if (image->profiles == (SplayTreeInfo *) NULL)
1309 ResetSplayTreeIterator((SplayTreeInfo *) image->profiles);
1313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1317 % S e t I m a g e P r o f i l e %
1321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1323 % SetImageProfile() adds a named profile to the image. If a profile with the
1324 % same name already exists, it is replaced. This method differs from the
1325 % ProfileImage() method in that it does not apply CMS color profiles.
1327 % The format of the SetImageProfile method is:
1329 % MagickBooleanType SetImageProfile(Image *image,const char *name,
1330 % const StringInfo *profile)
1332 % A description of each parameter follows:
1334 % o image: the image.
1336 % o name: the profile name, for example icc, exif, and 8bim (8bim is the
1337 % Photoshop wrapper for iptc profiles).
1339 % o profile: A StringInfo structure that contains the named profile.
1343 static void *DestroyProfile(void *profile)
1345 return((void *) DestroyStringInfo((StringInfo *) profile));
1348 static inline const unsigned char *ReadResourceByte(const unsigned char *p,
1349 unsigned char *quantum)
1355 static inline const unsigned char *ReadResourceLong(const unsigned char *p,
1356 unsigned int *quantum)
1358 *quantum=(unsigned int) (*p++) << 24;
1359 *quantum|=(unsigned int) (*p++) << 16;
1360 *quantum|=(unsigned int) (*p++) << 8;
1361 *quantum|=(unsigned int) (*p++);
1365 static inline const unsigned char *ReadResourceShort(const unsigned char *p,
1366 unsigned short *quantum)
1368 *quantum=(unsigned short) (*p++) << 8;
1369 *quantum|=(unsigned short) (*p++);
1373 static inline void WriteResourceLong(unsigned char *p,
1374 const unsigned int quantum)
1379 buffer[0]=(unsigned char) (quantum >> 24);
1380 buffer[1]=(unsigned char) (quantum >> 16);
1381 buffer[2]=(unsigned char) (quantum >> 8);
1382 buffer[3]=(unsigned char) quantum;
1383 (void) CopyMagickMemory(p,buffer,4);
1386 static void WriteTo8BimProfile(Image *image,const char *name,
1387 const StringInfo *profile)
1393 register const unsigned char
1415 if (LocaleCompare(name,"icc") == 0)
1418 if (LocaleCompare(name,"iptc") == 0)
1421 if (LocaleCompare(name,"xmp") == 0)
1425 profile_8bim=(StringInfo *) GetValueFromSplayTree((SplayTreeInfo *)
1426 image->profiles,"8bim");
1427 if (profile_8bim == (StringInfo *) NULL)
1429 datum=GetStringInfoDatum(profile_8bim);
1430 length=GetStringInfoLength(profile_8bim);
1431 for (p=datum; p < (datum+length-16); )
1434 if (LocaleNCompare((char *) p,"8BIM",4) != 0)
1437 p=ReadResourceShort(p,&id);
1438 p=ReadResourceByte(p,&length_byte);
1440 if (((length_byte+1) & 0x01) != 0)
1442 if (p > (datum+length-4))
1444 p=ReadResourceLong(p,&value);
1445 count=(ssize_t) value;
1446 if ((count & 0x01) != 0)
1448 if ((count < 0) || (p > (datum+length-count)) ||
1449 (count > (ssize_t) length))
1451 if (id != profile_id)
1466 extent=(datum+length)-(p+count);
1467 if (profile == (StringInfo *) NULL)
1470 extract_profile=AcquireStringInfo(offset+extent);
1471 (void) CopyMagickMemory(extract_profile->datum,datum,offset);
1476 extract_extent=profile->length;
1477 if ((extract_extent & 0x01) != 0)
1479 extract_profile=AcquireStringInfo(offset+extract_extent+extent);
1480 (void) CopyMagickMemory(extract_profile->datum,datum,offset-4);
1481 WriteResourceLong(extract_profile->datum+offset-4,(unsigned int)
1483 (void) CopyMagickMemory(extract_profile->datum+offset,
1484 profile->datum,profile->length);
1486 (void) CopyMagickMemory(extract_profile->datum+offset+extract_extent,
1488 (void) AddValueToSplayTree((SplayTreeInfo *) image->profiles,
1489 ConstantString("8bim"),CloneStringInfo(extract_profile));
1490 extract_profile=DestroyStringInfo(extract_profile);
1496 static void GetProfilesFromResourceBlock(Image *image,
1497 const StringInfo *resource_block,ExceptionInfo *exception)
1502 register const unsigned char
1523 datum=GetStringInfoDatum(resource_block);
1524 length=GetStringInfoLength(resource_block);
1525 for (p=datum; p < (datum+length-16); )
1527 if (LocaleNCompare((char *) p,"8BIM",4) != 0)
1530 p=ReadResourceShort(p,&id);
1531 p=ReadResourceByte(p,&length_byte);
1533 if (((length_byte+1) & 0x01) != 0)
1535 if (p > (datum+length-4))
1537 p=ReadResourceLong(p,&value);
1538 count=(ssize_t) value;
1539 if ((p > (datum+length-count)) || (count > (ssize_t) length) ||
1555 p=ReadResourceLong(p,&resolution);
1556 image->resolution.x=((double) resolution)/65536.0;
1557 p=ReadResourceShort(p,&units)+2;
1558 p=ReadResourceLong(p,&resolution)+4;
1559 image->resolution.y=((double) resolution)/65536.0;
1561 Values are always stored as pixels per inch.
1563 if ((ResolutionType) units != PixelsPerCentimeterResolution)
1564 image->units=PixelsPerInchResolution;
1567 image->units=PixelsPerCentimeterResolution;
1568 image->resolution.x/=2.54;
1569 image->resolution.y/=2.54;
1578 profile=AcquireStringInfo(count);
1579 SetStringInfoDatum(profile,p);
1580 (void) SetImageProfileInternal(image,"iptc",profile,MagickTrue,
1582 profile=DestroyStringInfo(profile);
1599 profile=AcquireStringInfo(count);
1600 SetStringInfoDatum(profile,p);
1601 (void) SetImageProfileInternal(image,"icc",profile,MagickTrue,
1603 profile=DestroyStringInfo(profile);
1612 profile=AcquireStringInfo(count);
1613 SetStringInfoDatum(profile,p);
1614 (void) SetImageProfileInternal(image,"exif",profile,MagickTrue,
1616 profile=DestroyStringInfo(profile);
1625 profile=AcquireStringInfo(count);
1626 SetStringInfoDatum(profile,p);
1627 (void) SetImageProfileInternal(image,"xmp",profile,MagickTrue,
1629 profile=DestroyStringInfo(profile);
1639 if ((count & 0x01) != 0)
1644 static MagickBooleanType SetImageProfileInternal(Image *image,const char *name,
1645 const StringInfo *profile,const MagickBooleanType recursive,
1646 ExceptionInfo *exception)
1649 key[MagickPathExtent],
1650 property[MagickPathExtent];
1655 assert(image != (Image *) NULL);
1656 assert(image->signature == MagickCoreSignature);
1657 if (image->debug != MagickFalse)
1658 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1659 if (image->profiles == (SplayTreeInfo *) NULL)
1660 image->profiles=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
1662 (void) CopyMagickString(key,name,MagickPathExtent);
1664 status=AddValueToSplayTree((SplayTreeInfo *) image->profiles,
1665 ConstantString(key),CloneStringInfo(profile));
1666 if (status != MagickFalse)
1668 if (LocaleCompare(name,"8bim") == 0)
1669 GetProfilesFromResourceBlock(image,profile,exception);
1671 if (recursive == MagickFalse)
1672 WriteTo8BimProfile(image,name,profile);
1675 Inject profile into image properties.
1677 (void) FormatLocaleString(property,MagickPathExtent,"%s:*",name);
1678 (void) GetImageProperty(image,property,exception);
1682 MagickExport MagickBooleanType SetImageProfile(Image *image,const char *name,
1683 const StringInfo *profile,ExceptionInfo *exception)
1685 return(SetImageProfileInternal(image,name,profile,MagickFalse,exception));
1689 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1693 % S y n c I m a g e P r o f i l e s %
1697 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1699 % SyncImageProfiles() synchronizes image properties with the image profiles.
1700 % Currently we only support updating the EXIF resolution and orientation.
1702 % The format of the SyncImageProfiles method is:
1704 % MagickBooleanType SyncImageProfiles(Image *image)
1706 % A description of each parameter follows:
1708 % o image: the image.
1712 static inline int ReadProfileByte(unsigned char **p,size_t *length)
1724 static inline signed short ReadProfileShort(const EndianType endian,
1725 unsigned char *buffer)
1739 if (endian == LSBEndian)
1741 value=(unsigned short) buffer[1] << 8;
1742 value|=(unsigned short) buffer[0];
1743 quantum.unsigned_value=value & 0xffff;
1744 return(quantum.signed_value);
1746 value=(unsigned short) buffer[0] << 8;
1747 value|=(unsigned short) buffer[1];
1748 quantum.unsigned_value=value & 0xffff;
1749 return(quantum.signed_value);
1752 static inline signed int ReadProfileLong(const EndianType endian,
1753 unsigned char *buffer)
1767 if (endian == LSBEndian)
1769 value=(unsigned int) buffer[3] << 24;
1770 value|=(unsigned int) buffer[2] << 16;
1771 value|=(unsigned int) buffer[1] << 8;
1772 value|=(unsigned int) buffer[0];
1773 quantum.unsigned_value=value & 0xffffffff;
1774 return(quantum.signed_value);
1776 value=(unsigned int) buffer[0] << 24;
1777 value|=(unsigned int) buffer[1] << 16;
1778 value|=(unsigned int) buffer[2] << 8;
1779 value|=(unsigned int) buffer[3];
1780 quantum.unsigned_value=value & 0xffffffff;
1781 return(quantum.signed_value);
1784 static inline signed int ReadProfileMSBLong(unsigned char **p,size_t *length)
1791 value=ReadProfileLong(MSBEndian,*p);
1797 static inline signed short ReadProfileMSBShort(unsigned char **p,
1805 value=ReadProfileShort(MSBEndian,*p);
1811 static inline void WriteProfileLong(const EndianType endian,
1812 const size_t value,unsigned char *p)
1817 if (endian == LSBEndian)
1819 buffer[0]=(unsigned char) value;
1820 buffer[1]=(unsigned char) (value >> 8);
1821 buffer[2]=(unsigned char) (value >> 16);
1822 buffer[3]=(unsigned char) (value >> 24);
1823 (void) CopyMagickMemory(p,buffer,4);
1826 buffer[0]=(unsigned char) (value >> 24);
1827 buffer[1]=(unsigned char) (value >> 16);
1828 buffer[2]=(unsigned char) (value >> 8);
1829 buffer[3]=(unsigned char) value;
1830 (void) CopyMagickMemory(p,buffer,4);
1833 static void WriteProfileShort(const EndianType endian,
1834 const unsigned short value,unsigned char *p)
1839 if (endian == LSBEndian)
1841 buffer[0]=(unsigned char) value;
1842 buffer[1]=(unsigned char) (value >> 8);
1843 (void) CopyMagickMemory(p,buffer,2);
1846 buffer[0]=(unsigned char) (value >> 8);
1847 buffer[1]=(unsigned char) value;
1848 (void) CopyMagickMemory(p,buffer,2);
1851 static MagickBooleanType Sync8BimProfile(Image *image,StringInfo *profile)
1865 length=GetStringInfoLength(profile);
1866 p=GetStringInfoDatum(profile);
1869 if (ReadProfileByte(&p,&length) != 0x38)
1871 if (ReadProfileByte(&p,&length) != 0x42)
1873 if (ReadProfileByte(&p,&length) != 0x49)
1875 if (ReadProfileByte(&p,&length) != 0x4D)
1878 return(MagickFalse);
1879 id=ReadProfileMSBShort(&p,&length);
1880 count=(ssize_t) ReadProfileByte(&p,&length);
1881 if ((count > (ssize_t) length) || (count < 0))
1882 return(MagickFalse);
1884 if ((*p & 0x01) == 0)
1885 (void) ReadProfileByte(&p,&length);
1886 count=(ssize_t) ReadProfileMSBLong(&p,&length);
1887 if ((count > (ssize_t) length) || (count < 0))
1888 return(MagickFalse);
1889 if ((id == 0x3ED) && (count == 16))
1891 if (image->units == PixelsPerCentimeterResolution)
1892 WriteProfileLong(MSBEndian,(unsigned int) (image->resolution.x*2.54*
1895 WriteProfileLong(MSBEndian,(unsigned int) (image->resolution.x*
1897 WriteProfileShort(MSBEndian,(unsigned short) image->units,p+4);
1898 if (image->units == PixelsPerCentimeterResolution)
1899 WriteProfileLong(MSBEndian,(unsigned int) (image->resolution.y*2.54*
1902 WriteProfileLong(MSBEndian,(unsigned int) (image->resolution.y*
1904 WriteProfileShort(MSBEndian,(unsigned short) image->units,p+12);
1912 MagickBooleanType SyncExifProfile(Image *image,StringInfo *profile)
1914 #define MaxDirectoryStack 16
1915 #define EXIF_DELIMITER "\n"
1916 #define EXIF_NUM_FORMATS 12
1917 #define TAG_EXIF_OFFSET 0x8769
1918 #define TAG_INTEROP_OFFSET 0xa005
1920 typedef struct _DirectoryInfo
1930 directory_stack[MaxDirectoryStack];
1949 format_bytes[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
1956 Set EXIF resolution tag.
1958 length=GetStringInfoLength(profile);
1959 exif=GetStringInfoDatum(profile);
1961 return(MagickFalse);
1962 id=(ssize_t) ReadProfileShort(LSBEndian,exif);
1963 if ((id != 0x4949) && (id != 0x4D4D))
1967 if (ReadProfileByte(&exif,&length) != 0x45)
1969 if (ReadProfileByte(&exif,&length) != 0x78)
1971 if (ReadProfileByte(&exif,&length) != 0x69)
1973 if (ReadProfileByte(&exif,&length) != 0x66)
1975 if (ReadProfileByte(&exif,&length) != 0x00)
1977 if (ReadProfileByte(&exif,&length) != 0x00)
1982 return(MagickFalse);
1983 id=(ssize_t) ReadProfileShort(LSBEndian,exif);
1992 return(MagickFalse);
1993 if (ReadProfileShort(endian,exif+2) != 0x002a)
1994 return(MagickFalse);
1996 This the offset to the first IFD.
1998 offset=(ssize_t) ReadProfileLong(endian,exif+4);
1999 if ((offset < 0) || ((size_t) offset >= length))
2000 return(MagickFalse);
2001 directory=exif+offset;
2004 exif_resources=NewSplayTree((int (*)(const void *,const void *)) NULL,
2005 (void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
2011 directory=directory_stack[level].directory;
2012 entry=directory_stack[level].entry;
2014 if ((directory < exif) || (directory > (exif+length-2)))
2017 Determine how many entries there are in the current IFD.
2019 number_entries=ReadProfileShort(endian,directory);
2020 for ( ; entry < number_entries; entry++)
2025 register unsigned char
2036 q=(unsigned char *) (directory+2+(12*entry));
2037 if (q > (exif+length-12))
2038 break; /* corrupt EXIF */
2039 if (GetValueFromSplayTree(exif_resources,q) == q)
2041 (void) AddValueToSplayTree(exif_resources,q,q);
2042 tag_value=(ssize_t) ReadProfileShort(endian,q);
2043 format=(ssize_t) ReadProfileShort(endian,q+2);
2044 if ((format < 0) || ((format-1) >= EXIF_NUM_FORMATS))
2046 components=(int) ReadProfileLong(endian,q+4);
2048 break; /* corrupt EXIF */
2049 number_bytes=(size_t) components*format_bytes[format];
2050 if ((ssize_t) number_bytes < components)
2051 break; /* prevent overflow */
2052 if (number_bytes <= 4)
2057 The directory entry contains an offset.
2059 offset=(ssize_t) ReadProfileLong(endian,q+8);
2060 if ((offset < 0) || ((size_t) (offset+number_bytes) > length))
2062 if (~length < number_bytes)
2063 continue; /* prevent overflow */
2064 p=(unsigned char *) (exif+offset);
2070 (void) WriteProfileLong(endian,(size_t) (image->resolution.x+0.5),p);
2071 (void) WriteProfileLong(endian,1UL,p+4);
2076 (void) WriteProfileLong(endian,(size_t) (image->resolution.y+0.5),p);
2077 (void) WriteProfileLong(endian,1UL,p+4);
2082 if (number_bytes == 4)
2084 (void) WriteProfileLong(endian,(size_t) image->orientation,p);
2087 (void) WriteProfileShort(endian,(unsigned short) image->orientation,
2093 if (number_bytes == 4)
2095 (void) WriteProfileLong(endian,(size_t) (image->units+1),p);
2098 (void) WriteProfileShort(endian,(unsigned short) (image->units+1),p);
2104 if ((tag_value == TAG_EXIF_OFFSET) || (tag_value == TAG_INTEROP_OFFSET))
2106 offset=(ssize_t) ReadProfileLong(endian,p);
2107 if (((size_t) offset < length) && (level < (MaxDirectoryStack-2)))
2109 directory_stack[level].directory=directory;
2111 directory_stack[level].entry=entry;
2113 directory_stack[level].directory=exif+offset;
2114 directory_stack[level].entry=0;
2116 if ((directory+2+(12*number_entries)) > (exif+length))
2118 offset=(ssize_t) ReadProfileLong(endian,directory+2+(12*
2120 if ((offset != 0) && ((size_t) offset < length) &&
2121 (level < (MaxDirectoryStack-2)))
2123 directory_stack[level].directory=exif+offset;
2124 directory_stack[level].entry=0;
2131 } while (level > 0);
2132 exif_resources=DestroySplayTree(exif_resources);
2136 MagickPrivate MagickBooleanType SyncImageProfiles(Image *image)
2145 profile=(StringInfo *) GetImageProfile(image,"8BIM");
2146 if (profile != (StringInfo *) NULL)
2147 if (Sync8BimProfile(image,profile) == MagickFalse)
2149 profile=(StringInfo *) GetImageProfile(image,"EXIF");
2150 if (profile != (StringInfo *) NULL)
2151 if (SyncExifProfile(image,profile) == MagickFalse)