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-2014 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>
73 #elif defined(MAGICKCORE_HAVE_LCMS2_H)
76 #elif defined(MAGICKCORE_HAVE_LCMS_LCMS_H)
77 #include <lcms/lcms.h>
86 #if !defined(LCMS_VERSION) || (LCMS_VERSION < 2000)
87 #define cmsSigCmykData icSigCmykData
88 #define cmsSigGrayData icSigGrayData
89 #define cmsSigLabData icSigLabData
90 #define cmsSigLuvData icSigLuvData
91 #define cmsSigRgbData icSigRgbData
92 #define cmsSigXYZData icSigXYZData
93 #define cmsSigYCbCrData icSigYCbCrData
94 #define cmsSigLinkClass icSigLinkClass
95 #define cmsColorSpaceSignature icColorSpaceSignature
96 #define cmsUInt32Number DWORD
97 #define cmsSetLogErrorHandler(handler) cmsSetErrorHandler(handler)
98 #define cmsCreateTransformTHR(context,source_profile,source_type, \
99 target_profile,target_type,intent,flags) cmsCreateTransform(source_profile, \
100 source_type,target_profile,target_type,intent,flags);
101 #define cmsOpenProfileFromMemTHR(context,profile,length) \
102 cmsOpenProfileFromMem(profile,length)
108 static MagickBooleanType
109 SetImageProfileInternal(Image *,const char *,const StringInfo *,
110 const MagickBooleanType,ExceptionInfo *);
113 WriteTo8BimProfile(Image *,const char*,const StringInfo *);
133 typedef struct _CMSExceptionInfo
143 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
147 % C l o n e I m a g e P r o f i l e s %
151 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
153 % CloneImageProfiles() clones one or more image profiles.
155 % The format of the CloneImageProfiles method is:
157 % MagickBooleanType CloneImageProfiles(Image *image,
158 % const Image *clone_image)
160 % A description of each parameter follows:
162 % o image: the image.
164 % o clone_image: the clone image.
167 MagickExport MagickBooleanType CloneImageProfiles(Image *image,
168 const Image *clone_image)
170 assert(image != (Image *) NULL);
171 assert(image->signature == MagickSignature);
172 if (image->debug != MagickFalse)
173 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
174 assert(clone_image != (const Image *) NULL);
175 assert(clone_image->signature == MagickSignature);
176 if (clone_image->profiles != (void *) NULL)
178 if (image->profiles != (void *) NULL)
179 DestroyImageProfiles(image);
180 image->profiles=CloneSplayTree((SplayTreeInfo *) clone_image->profiles,
181 (void *(*)(void *)) ConstantString,(void *(*)(void *)) CloneStringInfo);
187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
191 % D e l e t e I m a g e P r o f i l e %
195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
197 % DeleteImageProfile() deletes a profile from the image by its name.
199 % The format of the DeleteImageProfile method is:
201 % MagickBooleanTyupe DeleteImageProfile(Image *image,const char *name)
203 % A description of each parameter follows:
205 % o image: the image.
207 % o name: the profile name.
210 MagickExport MagickBooleanType DeleteImageProfile(Image *image,const char *name)
212 assert(image != (Image *) NULL);
213 assert(image->signature == MagickSignature);
214 if (image->debug != MagickFalse)
215 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
216 if (image->profiles == (SplayTreeInfo *) NULL)
218 WriteTo8BimProfile(image,name,(StringInfo *) NULL);
219 return(DeleteNodeFromSplayTree((SplayTreeInfo *) image->profiles,name));
223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
227 % D e s t r o y I m a g e P r o f i l e s %
231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
233 % DestroyImageProfiles() releases memory associated with an image profile map.
235 % The format of the DestroyProfiles method is:
237 % void DestroyImageProfiles(Image *image)
239 % A description of each parameter follows:
241 % o image: the image.
244 MagickExport void DestroyImageProfiles(Image *image)
246 if (image->profiles != (SplayTreeInfo *) NULL)
247 image->profiles=DestroySplayTree((SplayTreeInfo *) image->profiles);
251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
255 % G e t I m a g e P r o f i l e %
259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
261 % GetImageProfile() gets a profile associated with an image by name.
263 % The format of the GetImageProfile method is:
265 % const StringInfo *GetImageProfile(const Image *image,const char *name)
267 % A description of each parameter follows:
269 % o image: the image.
271 % o name: the profile name.
274 MagickExport const StringInfo *GetImageProfile(const Image *image,
283 assert(image != (Image *) NULL);
284 assert(image->signature == MagickSignature);
285 if (image->debug != MagickFalse)
286 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
287 if (image->profiles == (SplayTreeInfo *) NULL)
288 return((StringInfo *) NULL);
289 (void) CopyMagickString(key,name,MaxTextExtent);
290 profile=(const StringInfo *) GetValueFromSplayTree((SplayTreeInfo *)
291 image->profiles,key);
296 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
300 % G e t N e x t I m a g e P r o f i l e %
304 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
306 % GetNextImageProfile() gets the next profile name for an image.
308 % The format of the GetNextImageProfile method is:
310 % char *GetNextImageProfile(const Image *image)
312 % A description of each parameter follows:
314 % o hash_info: the hash info.
317 MagickExport char *GetNextImageProfile(const Image *image)
319 assert(image != (Image *) NULL);
320 assert(image->signature == MagickSignature);
321 if (image->debug != MagickFalse)
322 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
323 if (image->profiles == (SplayTreeInfo *) NULL)
324 return((char *) NULL);
325 return((char *) GetNextKeyInSplayTree((SplayTreeInfo *) image->profiles));
329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
333 % P r o f i l e I m a g e %
337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
339 % ProfileImage() associates, applies, or removes an ICM, IPTC, or generic
340 % profile with / to / from an image. If the profile is NULL, it is removed
341 % from the image otherwise added or applied. Use a name of '*' and a profile
342 % of NULL to remove all profiles from the image.
344 % ICC and ICM profiles are handled as follows: If the image does not have
345 % an associated color profile, the one you provide is associated with the
346 % image and the image pixels are not transformed. Otherwise, the colorspace
347 % transform defined by the existing and new profile are applied to the image
348 % pixels and the new profile is associated with the image.
350 % The format of the ProfileImage method is:
352 % MagickBooleanType ProfileImage(Image *image,const char *name,
353 % const void *datum,const size_t length,const MagickBooleanType clone)
355 % A description of each parameter follows:
357 % o image: the image.
359 % o name: Name of profile to add or remove: ICC, IPTC, or generic profile.
361 % o datum: the profile data.
363 % o length: the length of the profile.
365 % o clone: should be MagickFalse.
369 #if defined(MAGICKCORE_LCMS_DELEGATE)
371 static unsigned short **DestroyPixelThreadSet(unsigned short **pixels)
376 assert(pixels != (unsigned short **) NULL);
377 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
378 if (pixels[i] != (unsigned short *) NULL)
379 pixels[i]=(unsigned short *) RelinquishMagickMemory(pixels[i]);
380 pixels=(unsigned short **) RelinquishMagickMemory(pixels);
384 static unsigned short **AcquirePixelThreadSet(const size_t columns,
385 const size_t channels)
396 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
397 pixels=(unsigned short **) AcquireQuantumMemory(number_threads,
399 if (pixels == (unsigned short **) NULL)
400 return((unsigned short **) NULL);
401 (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
402 for (i=0; i < (ssize_t) number_threads; i++)
404 pixels[i]=(unsigned short *) AcquireQuantumMemory(columns,channels*
406 if (pixels[i] == (unsigned short *) NULL)
407 return(DestroyPixelThreadSet(pixels));
412 static cmsHTRANSFORM *DestroyTransformThreadSet(cmsHTRANSFORM *transform)
417 assert(transform != (cmsHTRANSFORM *) NULL);
418 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
419 if (transform[i] != (cmsHTRANSFORM) NULL)
420 cmsDeleteTransform(transform[i]);
421 transform=(cmsHTRANSFORM *) RelinquishMagickMemory(transform);
425 static cmsHTRANSFORM *AcquireTransformThreadSet(Image *image,
426 const cmsHPROFILE source_profile,const cmsUInt32Number source_type,
427 const cmsHPROFILE target_profile,const cmsUInt32Number target_type,
428 const int intent,const cmsUInt32Number flags)
439 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
440 transform=(cmsHTRANSFORM *) AcquireQuantumMemory(number_threads,
442 if (transform == (cmsHTRANSFORM *) NULL)
443 return((cmsHTRANSFORM *) NULL);
444 (void) ResetMagickMemory(transform,0,number_threads*sizeof(*transform));
445 for (i=0; i < (ssize_t) number_threads; i++)
447 transform[i]=cmsCreateTransformTHR((cmsContext) image,source_profile,
448 source_type,target_profile,target_type,intent,flags);
449 if (transform[i] == (cmsHTRANSFORM) NULL)
450 return(DestroyTransformThreadSet(transform));
456 #if defined(MAGICKCORE_LCMS_DELEGATE)
457 #if defined(LCMS_VERSION) && (LCMS_VERSION >= 2000)
458 static void CMSExceptionHandler(cmsContext context,cmsUInt32Number severity,
470 cms_exception=(CMSExceptionInfo *) context;
471 image=cms_exception->image;
472 exception=cms_exception->exception;
473 if (image == (Image *) NULL)
475 (void) ThrowMagickException(exception,GetMagickModule(),ImageWarning,
476 "UnableToTransformColorspace","`%s'","unknown context");
479 if (image->debug != MagickFalse)
480 (void) LogMagickEvent(TransformEvent,GetMagickModule(),"lcms: #%u, %s",
481 severity,message != (char *) NULL ? message : "no message");
482 (void) ThrowMagickException(exception,GetMagickModule(),ImageWarning,
483 "UnableToTransformColorspace","`%s'",image->filename);
486 static int CMSExceptionHandler(int severity,const char *message)
488 (void) LogMagickEvent(TransformEvent,GetMagickModule(),"lcms: #%d, %s",
489 severity,message != (char *) NULL ? message : "no message");
495 static MagickBooleanType SetsRGBImageProfile(Image *image,
496 ExceptionInfo *exception)
501 0x00, 0x00, 0x0c, 0x8c, 0x61, 0x72, 0x67, 0x6c, 0x02, 0x20, 0x00, 0x00,
502 0x6d, 0x6e, 0x74, 0x72, 0x52, 0x47, 0x42, 0x20, 0x58, 0x59, 0x5a, 0x20,
503 0x07, 0xde, 0x00, 0x01, 0x00, 0x06, 0x00, 0x16, 0x00, 0x0f, 0x00, 0x3a,
504 0x61, 0x63, 0x73, 0x70, 0x4d, 0x53, 0x46, 0x54, 0x00, 0x00, 0x00, 0x00,
505 0x49, 0x45, 0x43, 0x20, 0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00, 0x00,
506 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xd6,
507 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d, 0x61, 0x72, 0x67, 0x6c,
508 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
509 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
510 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
511 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
512 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x01, 0x50, 0x00, 0x00, 0x00, 0x99,
513 0x63, 0x70, 0x72, 0x74, 0x00, 0x00, 0x01, 0xec, 0x00, 0x00, 0x00, 0x67,
514 0x64, 0x6d, 0x6e, 0x64, 0x00, 0x00, 0x02, 0x54, 0x00, 0x00, 0x00, 0x70,
515 0x64, 0x6d, 0x64, 0x64, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x00, 0x88,
516 0x74, 0x65, 0x63, 0x68, 0x00, 0x00, 0x03, 0x4c, 0x00, 0x00, 0x00, 0x0c,
517 0x76, 0x75, 0x65, 0x64, 0x00, 0x00, 0x03, 0x58, 0x00, 0x00, 0x00, 0x67,
518 0x76, 0x69, 0x65, 0x77, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x24,
519 0x6c, 0x75, 0x6d, 0x69, 0x00, 0x00, 0x03, 0xe4, 0x00, 0x00, 0x00, 0x14,
520 0x6d, 0x65, 0x61, 0x73, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x24,
521 0x77, 0x74, 0x70, 0x74, 0x00, 0x00, 0x04, 0x1c, 0x00, 0x00, 0x00, 0x14,
522 0x62, 0x6b, 0x70, 0x74, 0x00, 0x00, 0x04, 0x30, 0x00, 0x00, 0x00, 0x14,
523 0x72, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x04, 0x44, 0x00, 0x00, 0x00, 0x14,
524 0x67, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x04, 0x58, 0x00, 0x00, 0x00, 0x14,
525 0x62, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x04, 0x6c, 0x00, 0x00, 0x00, 0x14,
526 0x72, 0x54, 0x52, 0x43, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x08, 0x0c,
527 0x67, 0x54, 0x52, 0x43, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x08, 0x0c,
528 0x62, 0x54, 0x52, 0x43, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x08, 0x0c,
529 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
530 0x73, 0x52, 0x47, 0x42, 0x20, 0x49, 0x45, 0x43, 0x36, 0x31, 0x39, 0x36,
531 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x20, 0x28, 0x45, 0x71, 0x75, 0x69, 0x76,
532 0x61, 0x6c, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x77, 0x77, 0x77,
533 0x2e, 0x73, 0x72, 0x67, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x31, 0x39,
534 0x39, 0x38, 0x20, 0x48, 0x50, 0x20, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c,
535 0x65, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
536 0x00, 0x3f, 0x73, 0x52, 0x47, 0x42, 0x20, 0x49, 0x45, 0x43, 0x36, 0x31,
537 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x20, 0x28, 0x45, 0x71, 0x75,
538 0x69, 0x76, 0x61, 0x6c, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x77,
539 0x77, 0x77, 0x2e, 0x73, 0x72, 0x67, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x20,
540 0x31, 0x39, 0x39, 0x38, 0x20, 0x48, 0x50, 0x20, 0x70, 0x72, 0x6f, 0x66,
541 0x69, 0x6c, 0x65, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
542 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x43, 0x72, 0x65, 0x61,
543 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x47, 0x72, 0x61, 0x65, 0x6d,
544 0x65, 0x20, 0x57, 0x2e, 0x20, 0x47, 0x69, 0x6c, 0x6c, 0x2e, 0x20, 0x52,
545 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x6f,
546 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20,
547 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x20, 0x4e, 0x6f, 0x20, 0x57,
548 0x61, 0x72, 0x72, 0x61, 0x6e, 0x74, 0x79, 0x2c, 0x20, 0x55, 0x73, 0x65,
549 0x20, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75, 0x72, 0x20, 0x6f, 0x77, 0x6e,
550 0x20, 0x72, 0x69, 0x73, 0x6b, 0x2e, 0x00, 0x00, 0x64, 0x65, 0x73, 0x63,
551 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x49, 0x45, 0x43, 0x20,
552 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69,
553 0x65, 0x63, 0x2e, 0x63, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
554 0x00, 0x00, 0x00, 0x00, 0x16, 0x49, 0x45, 0x43, 0x20, 0x68, 0x74, 0x74,
555 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x65, 0x63, 0x2e,
556 0x63, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
557 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
558 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
559 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
560 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e,
561 0x49, 0x45, 0x43, 0x20, 0x36, 0x31, 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e,
562 0x31, 0x20, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x52, 0x47,
563 0x42, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x75, 0x72, 0x20, 0x73, 0x70, 0x61,
564 0x63, 0x65, 0x20, 0x2d, 0x20, 0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00,
565 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x49, 0x45, 0x43,
566 0x20, 0x36, 0x31, 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x20, 0x44,
567 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x52, 0x47, 0x42, 0x20, 0x63,
568 0x6f, 0x6c, 0x6f, 0x75, 0x72, 0x20, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20,
569 0x2d, 0x20, 0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
570 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
571 0x00, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x20, 0x00, 0x00, 0x00, 0x00,
572 0x43, 0x52, 0x54, 0x20, 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00,
573 0x00, 0x00, 0x00, 0x0d, 0x49, 0x45, 0x43, 0x36, 0x31, 0x39, 0x36, 0x36,
574 0x2d, 0x32, 0x2e, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
575 0x00, 0x00, 0x00, 0x0d, 0x49, 0x45, 0x43, 0x36, 0x31, 0x39, 0x36, 0x36,
576 0x2d, 0x32, 0x2e, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
577 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
578 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
579 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
580 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
581 0x76, 0x69, 0x65, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xa4, 0x7c,
582 0x00, 0x14, 0x5f, 0x30, 0x00, 0x10, 0xce, 0x02, 0x00, 0x03, 0xed, 0xb2,
583 0x00, 0x04, 0x13, 0x0a, 0x00, 0x03, 0x5c, 0x67, 0x00, 0x00, 0x00, 0x01,
584 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x0a, 0x3d,
585 0x00, 0x50, 0x00, 0x00, 0x00, 0x57, 0x1e, 0xb8, 0x6d, 0x65, 0x61, 0x73,
586 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
587 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
588 0x00, 0x00, 0x02, 0x8f, 0x00, 0x00, 0x00, 0x02, 0x58, 0x59, 0x5a, 0x20,
589 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x51, 0x00, 0x01, 0x00, 0x00,
590 0x00, 0x01, 0x16, 0xcc, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00,
591 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
592 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xa0,
593 0x00, 0x00, 0x38, 0xf5, 0x00, 0x00, 0x03, 0x90, 0x58, 0x59, 0x5a, 0x20,
594 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x97, 0x00, 0x00, 0xb7, 0x87,
595 0x00, 0x00, 0x18, 0xd9, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00,
596 0x00, 0x00, 0x24, 0x9f, 0x00, 0x00, 0x0f, 0x84, 0x00, 0x00, 0xb6, 0xc4,
597 0x63, 0x75, 0x72, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
598 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x14, 0x00, 0x19,
599 0x00, 0x1e, 0x00, 0x23, 0x00, 0x28, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x37,
600 0x00, 0x3b, 0x00, 0x40, 0x00, 0x45, 0x00, 0x4a, 0x00, 0x4f, 0x00, 0x54,
601 0x00, 0x59, 0x00, 0x5e, 0x00, 0x63, 0x00, 0x68, 0x00, 0x6d, 0x00, 0x72,
602 0x00, 0x77, 0x00, 0x7c, 0x00, 0x81, 0x00, 0x86, 0x00, 0x8b, 0x00, 0x90,
603 0x00, 0x95, 0x00, 0x9a, 0x00, 0x9f, 0x00, 0xa4, 0x00, 0xa9, 0x00, 0xae,
604 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc1, 0x00, 0xc6, 0x00, 0xcb,
605 0x00, 0xd0, 0x00, 0xd5, 0x00, 0xdb, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0xeb,
606 0x00, 0xf0, 0x00, 0xf6, 0x00, 0xfb, 0x01, 0x01, 0x01, 0x07, 0x01, 0x0d,
607 0x01, 0x13, 0x01, 0x19, 0x01, 0x1f, 0x01, 0x25, 0x01, 0x2b, 0x01, 0x32,
608 0x01, 0x38, 0x01, 0x3e, 0x01, 0x45, 0x01, 0x4c, 0x01, 0x52, 0x01, 0x59,
609 0x01, 0x60, 0x01, 0x67, 0x01, 0x6e, 0x01, 0x75, 0x01, 0x7c, 0x01, 0x83,
610 0x01, 0x8b, 0x01, 0x92, 0x01, 0x9a, 0x01, 0xa1, 0x01, 0xa9, 0x01, 0xb1,
611 0x01, 0xb9, 0x01, 0xc1, 0x01, 0xc9, 0x01, 0xd1, 0x01, 0xd9, 0x01, 0xe1,
612 0x01, 0xe9, 0x01, 0xf2, 0x01, 0xfa, 0x02, 0x03, 0x02, 0x0c, 0x02, 0x14,
613 0x02, 0x1d, 0x02, 0x26, 0x02, 0x2f, 0x02, 0x38, 0x02, 0x41, 0x02, 0x4b,
614 0x02, 0x54, 0x02, 0x5d, 0x02, 0x67, 0x02, 0x71, 0x02, 0x7a, 0x02, 0x84,
615 0x02, 0x8e, 0x02, 0x98, 0x02, 0xa2, 0x02, 0xac, 0x02, 0xb6, 0x02, 0xc1,
616 0x02, 0xcb, 0x02, 0xd5, 0x02, 0xe0, 0x02, 0xeb, 0x02, 0xf5, 0x03, 0x00,
617 0x03, 0x0b, 0x03, 0x16, 0x03, 0x21, 0x03, 0x2d, 0x03, 0x38, 0x03, 0x43,
618 0x03, 0x4f, 0x03, 0x5a, 0x03, 0x66, 0x03, 0x72, 0x03, 0x7e, 0x03, 0x8a,
619 0x03, 0x96, 0x03, 0xa2, 0x03, 0xae, 0x03, 0xba, 0x03, 0xc7, 0x03, 0xd3,
620 0x03, 0xe0, 0x03, 0xec, 0x03, 0xf9, 0x04, 0x06, 0x04, 0x13, 0x04, 0x20,
621 0x04, 0x2d, 0x04, 0x3b, 0x04, 0x48, 0x04, 0x55, 0x04, 0x63, 0x04, 0x71,
622 0x04, 0x7e, 0x04, 0x8c, 0x04, 0x9a, 0x04, 0xa8, 0x04, 0xb6, 0x04, 0xc4,
623 0x04, 0xd3, 0x04, 0xe1, 0x04, 0xf0, 0x04, 0xfe, 0x05, 0x0d, 0x05, 0x1c,
624 0x05, 0x2b, 0x05, 0x3a, 0x05, 0x49, 0x05, 0x58, 0x05, 0x67, 0x05, 0x77,
625 0x05, 0x86, 0x05, 0x96, 0x05, 0xa6, 0x05, 0xb5, 0x05, 0xc5, 0x05, 0xd5,
626 0x05, 0xe5, 0x05, 0xf6, 0x06, 0x06, 0x06, 0x16, 0x06, 0x27, 0x06, 0x37,
627 0x06, 0x48, 0x06, 0x59, 0x06, 0x6a, 0x06, 0x7b, 0x06, 0x8c, 0x06, 0x9d,
628 0x06, 0xaf, 0x06, 0xc0, 0x06, 0xd1, 0x06, 0xe3, 0x06, 0xf5, 0x07, 0x07,
629 0x07, 0x19, 0x07, 0x2b, 0x07, 0x3d, 0x07, 0x4f, 0x07, 0x61, 0x07, 0x74,
630 0x07, 0x86, 0x07, 0x99, 0x07, 0xac, 0x07, 0xbf, 0x07, 0xd2, 0x07, 0xe5,
631 0x07, 0xf8, 0x08, 0x0b, 0x08, 0x1f, 0x08, 0x32, 0x08, 0x46, 0x08, 0x5a,
632 0x08, 0x6e, 0x08, 0x82, 0x08, 0x96, 0x08, 0xaa, 0x08, 0xbe, 0x08, 0xd2,
633 0x08, 0xe7, 0x08, 0xfb, 0x09, 0x10, 0x09, 0x25, 0x09, 0x3a, 0x09, 0x4f,
634 0x09, 0x64, 0x09, 0x79, 0x09, 0x8f, 0x09, 0xa4, 0x09, 0xba, 0x09, 0xcf,
635 0x09, 0xe5, 0x09, 0xfb, 0x0a, 0x11, 0x0a, 0x27, 0x0a, 0x3d, 0x0a, 0x54,
636 0x0a, 0x6a, 0x0a, 0x81, 0x0a, 0x98, 0x0a, 0xae, 0x0a, 0xc5, 0x0a, 0xdc,
637 0x0a, 0xf3, 0x0b, 0x0b, 0x0b, 0x22, 0x0b, 0x39, 0x0b, 0x51, 0x0b, 0x69,
638 0x0b, 0x80, 0x0b, 0x98, 0x0b, 0xb0, 0x0b, 0xc8, 0x0b, 0xe1, 0x0b, 0xf9,
639 0x0c, 0x12, 0x0c, 0x2a, 0x0c, 0x43, 0x0c, 0x5c, 0x0c, 0x75, 0x0c, 0x8e,
640 0x0c, 0xa7, 0x0c, 0xc0, 0x0c, 0xd9, 0x0c, 0xf3, 0x0d, 0x0d, 0x0d, 0x26,
641 0x0d, 0x40, 0x0d, 0x5a, 0x0d, 0x74, 0x0d, 0x8e, 0x0d, 0xa9, 0x0d, 0xc3,
642 0x0d, 0xde, 0x0d, 0xf8, 0x0e, 0x13, 0x0e, 0x2e, 0x0e, 0x49, 0x0e, 0x64,
643 0x0e, 0x7f, 0x0e, 0x9b, 0x0e, 0xb6, 0x0e, 0xd2, 0x0e, 0xee, 0x0f, 0x09,
644 0x0f, 0x25, 0x0f, 0x41, 0x0f, 0x5e, 0x0f, 0x7a, 0x0f, 0x96, 0x0f, 0xb3,
645 0x0f, 0xcf, 0x0f, 0xec, 0x10, 0x09, 0x10, 0x26, 0x10, 0x43, 0x10, 0x61,
646 0x10, 0x7e, 0x10, 0x9b, 0x10, 0xb9, 0x10, 0xd7, 0x10, 0xf5, 0x11, 0x13,
647 0x11, 0x31, 0x11, 0x4f, 0x11, 0x6d, 0x11, 0x8c, 0x11, 0xaa, 0x11, 0xc9,
648 0x11, 0xe8, 0x12, 0x07, 0x12, 0x26, 0x12, 0x45, 0x12, 0x64, 0x12, 0x84,
649 0x12, 0xa3, 0x12, 0xc3, 0x12, 0xe3, 0x13, 0x03, 0x13, 0x23, 0x13, 0x43,
650 0x13, 0x63, 0x13, 0x83, 0x13, 0xa4, 0x13, 0xc5, 0x13, 0xe5, 0x14, 0x06,
651 0x14, 0x27, 0x14, 0x49, 0x14, 0x6a, 0x14, 0x8b, 0x14, 0xad, 0x14, 0xce,
652 0x14, 0xf0, 0x15, 0x12, 0x15, 0x34, 0x15, 0x56, 0x15, 0x78, 0x15, 0x9b,
653 0x15, 0xbd, 0x15, 0xe0, 0x16, 0x03, 0x16, 0x26, 0x16, 0x49, 0x16, 0x6c,
654 0x16, 0x8f, 0x16, 0xb2, 0x16, 0xd6, 0x16, 0xfa, 0x17, 0x1d, 0x17, 0x41,
655 0x17, 0x65, 0x17, 0x89, 0x17, 0xae, 0x17, 0xd2, 0x17, 0xf7, 0x18, 0x1b,
656 0x18, 0x40, 0x18, 0x65, 0x18, 0x8a, 0x18, 0xaf, 0x18, 0xd5, 0x18, 0xfa,
657 0x19, 0x20, 0x19, 0x45, 0x19, 0x6b, 0x19, 0x91, 0x19, 0xb7, 0x19, 0xdd,
658 0x1a, 0x04, 0x1a, 0x2a, 0x1a, 0x51, 0x1a, 0x77, 0x1a, 0x9e, 0x1a, 0xc5,
659 0x1a, 0xec, 0x1b, 0x14, 0x1b, 0x3b, 0x1b, 0x63, 0x1b, 0x8a, 0x1b, 0xb2,
660 0x1b, 0xda, 0x1c, 0x02, 0x1c, 0x2a, 0x1c, 0x52, 0x1c, 0x7b, 0x1c, 0xa3,
661 0x1c, 0xcc, 0x1c, 0xf5, 0x1d, 0x1e, 0x1d, 0x47, 0x1d, 0x70, 0x1d, 0x99,
662 0x1d, 0xc3, 0x1d, 0xec, 0x1e, 0x16, 0x1e, 0x40, 0x1e, 0x6a, 0x1e, 0x94,
663 0x1e, 0xbe, 0x1e, 0xe9, 0x1f, 0x13, 0x1f, 0x3e, 0x1f, 0x69, 0x1f, 0x94,
664 0x1f, 0xbf, 0x1f, 0xea, 0x20, 0x15, 0x20, 0x41, 0x20, 0x6c, 0x20, 0x98,
665 0x20, 0xc4, 0x20, 0xf0, 0x21, 0x1c, 0x21, 0x48, 0x21, 0x75, 0x21, 0xa1,
666 0x21, 0xce, 0x21, 0xfb, 0x22, 0x27, 0x22, 0x55, 0x22, 0x82, 0x22, 0xaf,
667 0x22, 0xdd, 0x23, 0x0a, 0x23, 0x38, 0x23, 0x66, 0x23, 0x94, 0x23, 0xc2,
668 0x23, 0xf0, 0x24, 0x1f, 0x24, 0x4d, 0x24, 0x7c, 0x24, 0xab, 0x24, 0xda,
669 0x25, 0x09, 0x25, 0x38, 0x25, 0x68, 0x25, 0x97, 0x25, 0xc7, 0x25, 0xf7,
670 0x26, 0x27, 0x26, 0x57, 0x26, 0x87, 0x26, 0xb7, 0x26, 0xe8, 0x27, 0x18,
671 0x27, 0x49, 0x27, 0x7a, 0x27, 0xab, 0x27, 0xdc, 0x28, 0x0d, 0x28, 0x3f,
672 0x28, 0x71, 0x28, 0xa2, 0x28, 0xd4, 0x29, 0x06, 0x29, 0x38, 0x29, 0x6b,
673 0x29, 0x9d, 0x29, 0xd0, 0x2a, 0x02, 0x2a, 0x35, 0x2a, 0x68, 0x2a, 0x9b,
674 0x2a, 0xcf, 0x2b, 0x02, 0x2b, 0x36, 0x2b, 0x69, 0x2b, 0x9d, 0x2b, 0xd1,
675 0x2c, 0x05, 0x2c, 0x39, 0x2c, 0x6e, 0x2c, 0xa2, 0x2c, 0xd7, 0x2d, 0x0c,
676 0x2d, 0x41, 0x2d, 0x76, 0x2d, 0xab, 0x2d, 0xe1, 0x2e, 0x16, 0x2e, 0x4c,
677 0x2e, 0x82, 0x2e, 0xb7, 0x2e, 0xee, 0x2f, 0x24, 0x2f, 0x5a, 0x2f, 0x91,
678 0x2f, 0xc7, 0x2f, 0xfe, 0x30, 0x35, 0x30, 0x6c, 0x30, 0xa4, 0x30, 0xdb,
679 0x31, 0x12, 0x31, 0x4a, 0x31, 0x82, 0x31, 0xba, 0x31, 0xf2, 0x32, 0x2a,
680 0x32, 0x63, 0x32, 0x9b, 0x32, 0xd4, 0x33, 0x0d, 0x33, 0x46, 0x33, 0x7f,
681 0x33, 0xb8, 0x33, 0xf1, 0x34, 0x2b, 0x34, 0x65, 0x34, 0x9e, 0x34, 0xd8,
682 0x35, 0x13, 0x35, 0x4d, 0x35, 0x87, 0x35, 0xc2, 0x35, 0xfd, 0x36, 0x37,
683 0x36, 0x72, 0x36, 0xae, 0x36, 0xe9, 0x37, 0x24, 0x37, 0x60, 0x37, 0x9c,
684 0x37, 0xd7, 0x38, 0x14, 0x38, 0x50, 0x38, 0x8c, 0x38, 0xc8, 0x39, 0x05,
685 0x39, 0x42, 0x39, 0x7f, 0x39, 0xbc, 0x39, 0xf9, 0x3a, 0x36, 0x3a, 0x74,
686 0x3a, 0xb2, 0x3a, 0xef, 0x3b, 0x2d, 0x3b, 0x6b, 0x3b, 0xaa, 0x3b, 0xe8,
687 0x3c, 0x27, 0x3c, 0x65, 0x3c, 0xa4, 0x3c, 0xe3, 0x3d, 0x22, 0x3d, 0x61,
688 0x3d, 0xa1, 0x3d, 0xe0, 0x3e, 0x20, 0x3e, 0x60, 0x3e, 0xa0, 0x3e, 0xe0,
689 0x3f, 0x21, 0x3f, 0x61, 0x3f, 0xa2, 0x3f, 0xe2, 0x40, 0x23, 0x40, 0x64,
690 0x40, 0xa6, 0x40, 0xe7, 0x41, 0x29, 0x41, 0x6a, 0x41, 0xac, 0x41, 0xee,
691 0x42, 0x30, 0x42, 0x72, 0x42, 0xb5, 0x42, 0xf7, 0x43, 0x3a, 0x43, 0x7d,
692 0x43, 0xc0, 0x44, 0x03, 0x44, 0x47, 0x44, 0x8a, 0x44, 0xce, 0x45, 0x12,
693 0x45, 0x55, 0x45, 0x9a, 0x45, 0xde, 0x46, 0x22, 0x46, 0x67, 0x46, 0xab,
694 0x46, 0xf0, 0x47, 0x35, 0x47, 0x7b, 0x47, 0xc0, 0x48, 0x05, 0x48, 0x4b,
695 0x48, 0x91, 0x48, 0xd7, 0x49, 0x1d, 0x49, 0x63, 0x49, 0xa9, 0x49, 0xf0,
696 0x4a, 0x37, 0x4a, 0x7d, 0x4a, 0xc4, 0x4b, 0x0c, 0x4b, 0x53, 0x4b, 0x9a,
697 0x4b, 0xe2, 0x4c, 0x2a, 0x4c, 0x72, 0x4c, 0xba, 0x4d, 0x02, 0x4d, 0x4a,
698 0x4d, 0x93, 0x4d, 0xdc, 0x4e, 0x25, 0x4e, 0x6e, 0x4e, 0xb7, 0x4f, 0x00,
699 0x4f, 0x49, 0x4f, 0x93, 0x4f, 0xdd, 0x50, 0x27, 0x50, 0x71, 0x50, 0xbb,
700 0x51, 0x06, 0x51, 0x50, 0x51, 0x9b, 0x51, 0xe6, 0x52, 0x31, 0x52, 0x7c,
701 0x52, 0xc7, 0x53, 0x13, 0x53, 0x5f, 0x53, 0xaa, 0x53, 0xf6, 0x54, 0x42,
702 0x54, 0x8f, 0x54, 0xdb, 0x55, 0x28, 0x55, 0x75, 0x55, 0xc2, 0x56, 0x0f,
703 0x56, 0x5c, 0x56, 0xa9, 0x56, 0xf7, 0x57, 0x44, 0x57, 0x92, 0x57, 0xe0,
704 0x58, 0x2f, 0x58, 0x7d, 0x58, 0xcb, 0x59, 0x1a, 0x59, 0x69, 0x59, 0xb8,
705 0x5a, 0x07, 0x5a, 0x56, 0x5a, 0xa6, 0x5a, 0xf5, 0x5b, 0x45, 0x5b, 0x95,
706 0x5b, 0xe5, 0x5c, 0x35, 0x5c, 0x86, 0x5c, 0xd6, 0x5d, 0x27, 0x5d, 0x78,
707 0x5d, 0xc9, 0x5e, 0x1a, 0x5e, 0x6c, 0x5e, 0xbd, 0x5f, 0x0f, 0x5f, 0x61,
708 0x5f, 0xb3, 0x60, 0x05, 0x60, 0x57, 0x60, 0xaa, 0x60, 0xfc, 0x61, 0x4f,
709 0x61, 0xa2, 0x61, 0xf5, 0x62, 0x49, 0x62, 0x9c, 0x62, 0xf0, 0x63, 0x43,
710 0x63, 0x97, 0x63, 0xeb, 0x64, 0x40, 0x64, 0x94, 0x64, 0xe9, 0x65, 0x3d,
711 0x65, 0x92, 0x65, 0xe7, 0x66, 0x3d, 0x66, 0x92, 0x66, 0xe8, 0x67, 0x3d,
712 0x67, 0x93, 0x67, 0xe9, 0x68, 0x3f, 0x68, 0x96, 0x68, 0xec, 0x69, 0x43,
713 0x69, 0x9a, 0x69, 0xf1, 0x6a, 0x48, 0x6a, 0x9f, 0x6a, 0xf7, 0x6b, 0x4f,
714 0x6b, 0xa7, 0x6b, 0xff, 0x6c, 0x57, 0x6c, 0xaf, 0x6d, 0x08, 0x6d, 0x60,
715 0x6d, 0xb9, 0x6e, 0x12, 0x6e, 0x6b, 0x6e, 0xc4, 0x6f, 0x1e, 0x6f, 0x78,
716 0x6f, 0xd1, 0x70, 0x2b, 0x70, 0x86, 0x70, 0xe0, 0x71, 0x3a, 0x71, 0x95,
717 0x71, 0xf0, 0x72, 0x4b, 0x72, 0xa6, 0x73, 0x01, 0x73, 0x5d, 0x73, 0xb8,
718 0x74, 0x14, 0x74, 0x70, 0x74, 0xcc, 0x75, 0x28, 0x75, 0x85, 0x75, 0xe1,
719 0x76, 0x3e, 0x76, 0x9b, 0x76, 0xf8, 0x77, 0x56, 0x77, 0xb3, 0x78, 0x11,
720 0x78, 0x6e, 0x78, 0xcc, 0x79, 0x2a, 0x79, 0x89, 0x79, 0xe7, 0x7a, 0x46,
721 0x7a, 0xa5, 0x7b, 0x04, 0x7b, 0x63, 0x7b, 0xc2, 0x7c, 0x21, 0x7c, 0x81,
722 0x7c, 0xe1, 0x7d, 0x41, 0x7d, 0xa1, 0x7e, 0x01, 0x7e, 0x62, 0x7e, 0xc2,
723 0x7f, 0x23, 0x7f, 0x84, 0x7f, 0xe5, 0x80, 0x47, 0x80, 0xa8, 0x81, 0x0a,
724 0x81, 0x6b, 0x81, 0xcd, 0x82, 0x30, 0x82, 0x92, 0x82, 0xf4, 0x83, 0x57,
725 0x83, 0xba, 0x84, 0x1d, 0x84, 0x80, 0x84, 0xe3, 0x85, 0x47, 0x85, 0xab,
726 0x86, 0x0e, 0x86, 0x72, 0x86, 0xd7, 0x87, 0x3b, 0x87, 0x9f, 0x88, 0x04,
727 0x88, 0x69, 0x88, 0xce, 0x89, 0x33, 0x89, 0x99, 0x89, 0xfe, 0x8a, 0x64,
728 0x8a, 0xca, 0x8b, 0x30, 0x8b, 0x96, 0x8b, 0xfc, 0x8c, 0x63, 0x8c, 0xca,
729 0x8d, 0x31, 0x8d, 0x98, 0x8d, 0xff, 0x8e, 0x66, 0x8e, 0xce, 0x8f, 0x36,
730 0x8f, 0x9e, 0x90, 0x06, 0x90, 0x6e, 0x90, 0xd6, 0x91, 0x3f, 0x91, 0xa8,
731 0x92, 0x11, 0x92, 0x7a, 0x92, 0xe3, 0x93, 0x4d, 0x93, 0xb6, 0x94, 0x20,
732 0x94, 0x8a, 0x94, 0xf4, 0x95, 0x5f, 0x95, 0xc9, 0x96, 0x34, 0x96, 0x9f,
733 0x97, 0x0a, 0x97, 0x75, 0x97, 0xe0, 0x98, 0x4c, 0x98, 0xb8, 0x99, 0x24,
734 0x99, 0x90, 0x99, 0xfc, 0x9a, 0x68, 0x9a, 0xd5, 0x9b, 0x42, 0x9b, 0xaf,
735 0x9c, 0x1c, 0x9c, 0x89, 0x9c, 0xf7, 0x9d, 0x64, 0x9d, 0xd2, 0x9e, 0x40,
736 0x9e, 0xae, 0x9f, 0x1d, 0x9f, 0x8b, 0x9f, 0xfa, 0xa0, 0x69, 0xa0, 0xd8,
737 0xa1, 0x47, 0xa1, 0xb6, 0xa2, 0x26, 0xa2, 0x96, 0xa3, 0x06, 0xa3, 0x76,
738 0xa3, 0xe6, 0xa4, 0x56, 0xa4, 0xc7, 0xa5, 0x38, 0xa5, 0xa9, 0xa6, 0x1a,
739 0xa6, 0x8b, 0xa6, 0xfd, 0xa7, 0x6e, 0xa7, 0xe0, 0xa8, 0x52, 0xa8, 0xc4,
740 0xa9, 0x37, 0xa9, 0xa9, 0xaa, 0x1c, 0xaa, 0x8f, 0xab, 0x02, 0xab, 0x75,
741 0xab, 0xe9, 0xac, 0x5c, 0xac, 0xd0, 0xad, 0x44, 0xad, 0xb8, 0xae, 0x2d,
742 0xae, 0xa1, 0xaf, 0x16, 0xaf, 0x8b, 0xb0, 0x00, 0xb0, 0x75, 0xb0, 0xea,
743 0xb1, 0x60, 0xb1, 0xd6, 0xb2, 0x4b, 0xb2, 0xc2, 0xb3, 0x38, 0xb3, 0xae,
744 0xb4, 0x25, 0xb4, 0x9c, 0xb5, 0x13, 0xb5, 0x8a, 0xb6, 0x01, 0xb6, 0x79,
745 0xb6, 0xf0, 0xb7, 0x68, 0xb7, 0xe0, 0xb8, 0x59, 0xb8, 0xd1, 0xb9, 0x4a,
746 0xb9, 0xc2, 0xba, 0x3b, 0xba, 0xb5, 0xbb, 0x2e, 0xbb, 0xa7, 0xbc, 0x21,
747 0xbc, 0x9b, 0xbd, 0x15, 0xbd, 0x8f, 0xbe, 0x0a, 0xbe, 0x84, 0xbe, 0xff,
748 0xbf, 0x7a, 0xbf, 0xf5, 0xc0, 0x70, 0xc0, 0xec, 0xc1, 0x67, 0xc1, 0xe3,
749 0xc2, 0x5f, 0xc2, 0xdb, 0xc3, 0x58, 0xc3, 0xd4, 0xc4, 0x51, 0xc4, 0xce,
750 0xc5, 0x4b, 0xc5, 0xc8, 0xc6, 0x46, 0xc6, 0xc3, 0xc7, 0x41, 0xc7, 0xbf,
751 0xc8, 0x3d, 0xc8, 0xbc, 0xc9, 0x3a, 0xc9, 0xb9, 0xca, 0x38, 0xca, 0xb7,
752 0xcb, 0x36, 0xcb, 0xb6, 0xcc, 0x35, 0xcc, 0xb5, 0xcd, 0x35, 0xcd, 0xb5,
753 0xce, 0x36, 0xce, 0xb6, 0xcf, 0x37, 0xcf, 0xb8, 0xd0, 0x39, 0xd0, 0xba,
754 0xd1, 0x3c, 0xd1, 0xbe, 0xd2, 0x3f, 0xd2, 0xc1, 0xd3, 0x44, 0xd3, 0xc6,
755 0xd4, 0x49, 0xd4, 0xcb, 0xd5, 0x4e, 0xd5, 0xd1, 0xd6, 0x55, 0xd6, 0xd8,
756 0xd7, 0x5c, 0xd7, 0xe0, 0xd8, 0x64, 0xd8, 0xe8, 0xd9, 0x6c, 0xd9, 0xf1,
757 0xda, 0x76, 0xda, 0xfb, 0xdb, 0x80, 0xdc, 0x05, 0xdc, 0x8a, 0xdd, 0x10,
758 0xdd, 0x96, 0xde, 0x1c, 0xde, 0xa2, 0xdf, 0x29, 0xdf, 0xaf, 0xe0, 0x36,
759 0xe0, 0xbd, 0xe1, 0x44, 0xe1, 0xcc, 0xe2, 0x53, 0xe2, 0xdb, 0xe3, 0x63,
760 0xe3, 0xeb, 0xe4, 0x73, 0xe4, 0xfc, 0xe5, 0x84, 0xe6, 0x0d, 0xe6, 0x96,
761 0xe7, 0x1f, 0xe7, 0xa9, 0xe8, 0x32, 0xe8, 0xbc, 0xe9, 0x46, 0xe9, 0xd0,
762 0xea, 0x5b, 0xea, 0xe5, 0xeb, 0x70, 0xeb, 0xfb, 0xec, 0x86, 0xed, 0x11,
763 0xed, 0x9c, 0xee, 0x28, 0xee, 0xb4, 0xef, 0x40, 0xef, 0xcc, 0xf0, 0x58,
764 0xf0, 0xe5, 0xf1, 0x72, 0xf1, 0xff, 0xf2, 0x8c, 0xf3, 0x19, 0xf3, 0xa7,
765 0xf4, 0x34, 0xf4, 0xc2, 0xf5, 0x50, 0xf5, 0xde, 0xf6, 0x6d, 0xf6, 0xfb,
766 0xf7, 0x8a, 0xf8, 0x19, 0xf8, 0xa8, 0xf9, 0x38, 0xf9, 0xc7, 0xfa, 0x57,
767 0xfa, 0xe7, 0xfb, 0x77, 0xfc, 0x07, 0xfc, 0x98, 0xfd, 0x29, 0xfd, 0xba,
768 0xfe, 0x4b, 0xfe, 0xdc, 0xff, 0x6d, 0xff, 0xff
777 assert(image != (Image *) NULL);
778 assert(image->signature == MagickSignature);
779 if (GetImageProfile(image,"icm") != (const StringInfo *) NULL)
781 profile=AcquireStringInfo(sizeof(sRGBProfile));
782 SetStringInfoDatum(profile,sRGBProfile);
783 status=SetImageProfile(image,"icm",profile,exception);
784 profile=DestroyStringInfo(profile);
788 MagickExport MagickBooleanType ProfileImage(Image *image,const char *name,
789 const void *datum,const size_t length,ExceptionInfo *exception)
791 #define ProfileImageTag "Profile/Image"
792 #define ThrowProfileException(severity,tag,context) \
794 if (source_profile != (cmsHPROFILE) NULL) \
795 (void) cmsCloseProfile(source_profile); \
796 if (target_profile != (cmsHPROFILE) NULL) \
797 (void) cmsCloseProfile(target_profile); \
798 ThrowBinaryException(severity,tag,context); \
807 assert(image != (Image *) NULL);
808 assert(image->signature == MagickSignature);
809 if (image->debug != MagickFalse)
810 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
811 assert(name != (const char *) NULL);
812 if ((datum == (const void *) NULL) || (length == 0))
818 Delete image profile(s).
820 ResetImageProfileIterator(image);
821 for (next=GetNextImageProfile(image); next != (const char *) NULL; )
823 if (IsOptionMember(next,name) != MagickFalse)
825 (void) DeleteImageProfile(image,next);
826 ResetImageProfileIterator(image);
828 next=GetNextImageProfile(image);
833 Add a ICC, IPTC, or generic profile to the image.
836 profile=AcquireStringInfo((size_t) length);
837 SetStringInfoDatum(profile,(unsigned char *) datum);
838 if ((LocaleCompare(name,"icc") != 0) && (LocaleCompare(name,"icm") != 0))
839 status=SetImageProfile(image,name,profile,exception);
845 icc_profile=GetImageProfile(image,"icc");
846 if ((icc_profile != (const StringInfo *) NULL) &&
847 (CompareStringInfo(icc_profile,profile) == 0))
852 value=GetImageProperty(image,"exif:ColorSpace",exception);
854 if (LocaleCompare(value,"1") != 0)
855 (void) SetsRGBImageProfile(image,exception);
856 value=GetImageProperty(image,"exif:InteroperabilityIndex",exception);
857 if (LocaleCompare(value,"R98.") != 0)
858 (void) SetsRGBImageProfile(image,exception);
860 value=GetImageProperty(image,"exif:InteroperabilityIndex",exception);
861 if (LocaleCompare(value,"R03.") != 0)
862 (void) SetAdobeRGB1998ImageProfile(image,exception);
864 icc_profile=GetImageProfile(image,"icc");
866 if ((icc_profile != (const StringInfo *) NULL) &&
867 (CompareStringInfo(icc_profile,profile) == 0))
869 profile=DestroyStringInfo(profile);
872 #if !defined(MAGICKCORE_LCMS_DELEGATE)
873 (void) ThrowMagickException(exception,GetMagickModule(),
874 MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn",
875 "'%s' (LCMS)",image->filename);
885 Transform pixel colors as defined by the color profiles.
887 cmsSetLogErrorHandler(CMSExceptionHandler);
888 cms_exception.image=image;
889 cms_exception.exception=exception;
890 (void) cms_exception;
891 source_profile=cmsOpenProfileFromMemTHR((cmsContext) &cms_exception,
892 GetStringInfoDatum(profile),(cmsUInt32Number)
893 GetStringInfoLength(profile));
894 if (source_profile == (cmsHPROFILE) NULL)
895 ThrowBinaryException(ResourceLimitError,
896 "ColorspaceColorProfileMismatch",name);
897 if ((cmsGetDeviceClass(source_profile) != cmsSigLinkClass) &&
898 (icc_profile == (StringInfo *) NULL))
899 status=SetImageProfile(image,name,profile,exception);
909 cmsColorSpaceSignature
940 **restrict source_pixels,
941 **restrict target_pixels;
943 target_profile=(cmsHPROFILE) NULL;
944 if (icc_profile != (StringInfo *) NULL)
946 target_profile=source_profile;
947 source_profile=cmsOpenProfileFromMemTHR((cmsContext)
948 &cms_exception,GetStringInfoDatum(icc_profile),
949 (cmsUInt32Number) GetStringInfoLength(icc_profile));
950 if (source_profile == (cmsHPROFILE) NULL)
951 ThrowProfileException(ResourceLimitError,
952 "ColorspaceColorProfileMismatch",name);
954 switch (cmsGetColorSpace(source_profile))
958 source_colorspace=CMYKColorspace;
959 source_type=(cmsUInt32Number) TYPE_CMYK_16;
965 source_colorspace=GRAYColorspace;
966 source_type=(cmsUInt32Number) TYPE_GRAY_16;
972 source_colorspace=LabColorspace;
973 source_type=(cmsUInt32Number) TYPE_Lab_16;
979 source_colorspace=YUVColorspace;
980 source_type=(cmsUInt32Number) TYPE_YUV_16;
986 source_colorspace=sRGBColorspace;
987 source_type=(cmsUInt32Number) TYPE_RGB_16;
993 source_colorspace=XYZColorspace;
994 source_type=(cmsUInt32Number) TYPE_XYZ_16;
998 case cmsSigYCbCrData:
1000 source_colorspace=YCbCrColorspace;
1001 source_type=(cmsUInt32Number) TYPE_YCbCr_16;
1007 source_colorspace=UndefinedColorspace;
1008 source_type=(cmsUInt32Number) TYPE_RGB_16;
1013 signature=cmsGetPCS(source_profile);
1014 if (target_profile != (cmsHPROFILE) NULL)
1015 signature=cmsGetColorSpace(target_profile);
1018 case cmsSigCmykData:
1020 target_colorspace=CMYKColorspace;
1021 target_type=(cmsUInt32Number) TYPE_CMYK_16;
1027 target_colorspace=LabColorspace;
1028 target_type=(cmsUInt32Number) TYPE_Lab_16;
1032 case cmsSigGrayData:
1034 target_colorspace=GRAYColorspace;
1035 target_type=(cmsUInt32Number) TYPE_GRAY_16;
1041 target_colorspace=YUVColorspace;
1042 target_type=(cmsUInt32Number) TYPE_YUV_16;
1048 target_colorspace=sRGBColorspace;
1049 target_type=(cmsUInt32Number) TYPE_RGB_16;
1055 target_colorspace=XYZColorspace;
1056 target_type=(cmsUInt32Number) TYPE_XYZ_16;
1060 case cmsSigYCbCrData:
1062 target_colorspace=YCbCrColorspace;
1063 target_type=(cmsUInt32Number) TYPE_YCbCr_16;
1069 target_colorspace=UndefinedColorspace;
1070 target_type=(cmsUInt32Number) TYPE_RGB_16;
1075 if ((source_colorspace == UndefinedColorspace) ||
1076 (target_colorspace == UndefinedColorspace))
1077 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1079 if ((source_colorspace == GRAYColorspace) &&
1080 (IsImageGray(image,exception) == MagickFalse))
1081 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1083 if ((source_colorspace == CMYKColorspace) &&
1084 (image->colorspace != CMYKColorspace))
1085 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1087 if ((source_colorspace == XYZColorspace) &&
1088 (image->colorspace != XYZColorspace))
1089 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1091 if ((source_colorspace == YCbCrColorspace) &&
1092 (image->colorspace != YCbCrColorspace))
1093 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1095 if ((source_colorspace != CMYKColorspace) &&
1096 (source_colorspace != LabColorspace) &&
1097 (source_colorspace != XYZColorspace) &&
1098 (source_colorspace != YCbCrColorspace) &&
1099 (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse))
1100 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1102 switch (image->rendering_intent)
1104 case AbsoluteIntent: intent=INTENT_ABSOLUTE_COLORIMETRIC; break;
1105 case PerceptualIntent: intent=INTENT_PERCEPTUAL; break;
1106 case RelativeIntent: intent=INTENT_RELATIVE_COLORIMETRIC; break;
1107 case SaturationIntent: intent=INTENT_SATURATION; break;
1108 default: intent=INTENT_PERCEPTUAL; break;
1110 flags=cmsFLAGS_HIGHRESPRECALC;
1111 #if defined(cmsFLAGS_BLACKPOINTCOMPENSATION)
1112 if (image->black_point_compensation != MagickFalse)
1113 flags|=cmsFLAGS_BLACKPOINTCOMPENSATION;
1115 transform=AcquireTransformThreadSet(image,source_profile,
1116 source_type,target_profile,target_type,intent,flags);
1117 if (transform == (cmsHTRANSFORM *) NULL)
1118 ThrowProfileException(ImageError,"UnableToCreateColorTransform",
1121 Transform image as dictated by the source & target image profiles.
1123 source_pixels=AcquirePixelThreadSet(image->columns,source_channels);
1124 target_pixels=AcquirePixelThreadSet(image->columns,target_channels);
1125 if ((source_pixels == (unsigned short **) NULL) ||
1126 (target_pixels == (unsigned short **) NULL))
1128 transform=DestroyTransformThreadSet(transform);
1129 ThrowProfileException(ResourceLimitError,
1130 "MemoryAllocationFailed",image->filename);
1132 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1134 target_pixels=DestroyPixelThreadSet(target_pixels);
1135 source_pixels=DestroyPixelThreadSet(source_pixels);
1136 transform=DestroyTransformThreadSet(transform);
1137 if (source_profile != (cmsHPROFILE) NULL)
1138 (void) cmsCloseProfile(source_profile);
1139 if (target_profile != (cmsHPROFILE) NULL)
1140 (void) cmsCloseProfile(target_profile);
1141 return(MagickFalse);
1143 if (target_colorspace == CMYKColorspace)
1144 (void) SetImageColorspace(image,target_colorspace,exception);
1147 image_view=AcquireAuthenticCacheView(image,exception);
1148 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1149 #pragma omp parallel for schedule(static,4) shared(status) \
1150 magick_threads(image,image,image->rows,1)
1152 for (y=0; y < (ssize_t) image->rows; y++)
1155 id = GetOpenMPThreadId();
1166 register unsigned short
1169 if (status == MagickFalse)
1171 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1173 if (q == (Quantum *) NULL)
1178 p=source_pixels[id];
1179 for (x=0; x < (ssize_t) image->columns; x++)
1181 *p++=ScaleQuantumToShort(GetPixelRed(image,q));
1182 if (source_channels > 1)
1184 *p++=ScaleQuantumToShort(GetPixelGreen(image,q));
1185 *p++=ScaleQuantumToShort(GetPixelBlue(image,q));
1187 if (source_channels > 3)
1188 *p++=ScaleQuantumToShort(GetPixelBlack(image,q));
1189 q+=GetPixelChannels(image);
1191 cmsDoTransform(transform[id],source_pixels[id],target_pixels[id],
1192 (unsigned int) image->columns);
1193 p=target_pixels[id];
1194 q-=image->columns*GetPixelChannels(image);
1195 for (x=0; x < (ssize_t) image->columns; x++)
1197 if (target_channels == 1)
1198 SetPixelGray(image,ScaleShortToQuantum(*p),q);
1200 SetPixelRed(image,ScaleShortToQuantum(*p),q);
1202 if (target_channels > 1)
1204 SetPixelGreen(image,ScaleShortToQuantum(*p),q);
1206 SetPixelBlue(image,ScaleShortToQuantum(*p),q);
1209 if (target_channels > 3)
1211 SetPixelBlack(image,ScaleShortToQuantum(*p),q);
1214 q+=GetPixelChannels(image);
1216 sync=SyncCacheViewAuthenticPixels(image_view,exception);
1217 if (sync == MagickFalse)
1219 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1224 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1225 #pragma omp critical (MagickCore_ProfileImage)
1227 proceed=SetImageProgress(image,ProfileImageTag,progress++,
1229 if (proceed == MagickFalse)
1233 image_view=DestroyCacheView(image_view);
1234 (void) SetImageColorspace(image,target_colorspace,exception);
1239 image->type=image->alpha_trait != BlendPixelTrait ?
1240 TrueColorType : TrueColorMatteType;
1243 case cmsSigCmykData:
1245 image->type=image->alpha_trait != BlendPixelTrait ?
1246 ColorSeparationType : ColorSeparationMatteType;
1249 case cmsSigGrayData:
1251 image->type=image->alpha_trait != BlendPixelTrait ?
1252 GrayscaleType : GrayscaleMatteType;
1258 target_pixels=DestroyPixelThreadSet(target_pixels);
1259 source_pixels=DestroyPixelThreadSet(source_pixels);
1260 transform=DestroyTransformThreadSet(transform);
1261 if (cmsGetDeviceClass(source_profile) != cmsSigLinkClass)
1262 status=SetImageProfile(image,name,profile,exception);
1263 if (target_profile != (cmsHPROFILE) NULL)
1264 (void) cmsCloseProfile(target_profile);
1266 (void) cmsCloseProfile(source_profile);
1270 profile=DestroyStringInfo(profile);
1275 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1279 % R e m o v e I m a g e P r o f i l e %
1283 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1285 % RemoveImageProfile() removes a named profile from the image and returns its
1288 % The format of the RemoveImageProfile method is:
1290 % void *RemoveImageProfile(Image *image,const char *name)
1292 % A description of each parameter follows:
1294 % o image: the image.
1296 % o name: the profile name.
1299 MagickExport StringInfo *RemoveImageProfile(Image *image,const char *name)
1304 assert(image != (Image *) NULL);
1305 assert(image->signature == MagickSignature);
1306 if (image->debug != MagickFalse)
1307 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1308 if (image->profiles == (SplayTreeInfo *) NULL)
1309 return((StringInfo *) NULL);
1310 WriteTo8BimProfile(image,name,(StringInfo *) NULL);
1311 profile=(StringInfo *) RemoveNodeFromSplayTree((SplayTreeInfo *)
1312 image->profiles,name);
1317 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1321 % R e s e t P r o f i l e I t e r a t o r %
1325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1327 % ResetImageProfileIterator() resets the image profile iterator. Use it in
1328 % conjunction with GetNextImageProfile() to iterate over all the profiles
1329 % associated with an image.
1331 % The format of the ResetImageProfileIterator method is:
1333 % ResetImageProfileIterator(Image *image)
1335 % A description of each parameter follows:
1337 % o image: the image.
1340 MagickExport void ResetImageProfileIterator(const Image *image)
1342 assert(image != (Image *) NULL);
1343 assert(image->signature == MagickSignature);
1344 if (image->debug != MagickFalse)
1345 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1346 if (image->profiles == (SplayTreeInfo *) NULL)
1348 ResetSplayTreeIterator((SplayTreeInfo *) image->profiles);
1352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1356 % S e t I m a g e P r o f i l e %
1360 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1362 % SetImageProfile() adds a named profile to the image. If a profile with the
1363 % same name already exists, it is replaced. This method differs from the
1364 % ProfileImage() method in that it does not apply CMS color profiles.
1366 % The format of the SetImageProfile method is:
1368 % MagickBooleanType SetImageProfile(Image *image,const char *name,
1369 % const StringInfo *profile)
1371 % A description of each parameter follows:
1373 % o image: the image.
1375 % o name: the profile name, for example icc, exif, and 8bim (8bim is the
1376 % Photoshop wrapper for iptc profiles).
1378 % o profile: A StringInfo structure that contains the named profile.
1382 static void *DestroyProfile(void *profile)
1384 return((void *) DestroyStringInfo((StringInfo *) profile));
1387 static inline const unsigned char *ReadResourceByte(const unsigned char *p,
1388 unsigned char *quantum)
1394 static inline const unsigned char *ReadResourceLong(const unsigned char *p,
1395 unsigned int *quantum)
1397 *quantum=(size_t) (*p++ << 24);
1398 *quantum|=(size_t) (*p++ << 16);
1399 *quantum|=(size_t) (*p++ << 8);
1400 *quantum|=(size_t) (*p++ << 0);
1404 static inline const unsigned char *ReadResourceShort(const unsigned char *p,
1405 unsigned short *quantum)
1407 *quantum=(unsigned short) (*p++ << 8);
1408 *quantum|=(unsigned short) (*p++ << 0);
1410 }static inline void WriteResourceLong(unsigned char *p,
1411 const unsigned int quantum)
1416 buffer[0]=(unsigned char) (quantum >> 24);
1417 buffer[1]=(unsigned char) (quantum >> 16);
1418 buffer[2]=(unsigned char) (quantum >> 8);
1419 buffer[3]=(unsigned char) quantum;
1420 (void) CopyMagickMemory(p,buffer,4);
1423 static void WriteTo8BimProfile(Image *image,const char *name,
1424 const StringInfo *profile)
1430 register const unsigned char
1452 if (LocaleCompare(name,"icc") == 0)
1455 if (LocaleCompare(name,"iptc") == 0)
1458 if (LocaleCompare(name,"xmp") == 0)
1462 profile_8bim=(StringInfo *) GetValueFromSplayTree((SplayTreeInfo *)
1463 image->profiles,"8bim");
1464 if (profile_8bim == (StringInfo *) NULL)
1466 datum=GetStringInfoDatum(profile_8bim);
1467 length=GetStringInfoLength(profile_8bim);
1468 for (p=datum; p < (datum+length-16); )
1471 if (LocaleNCompare((char *) p,"8BIM",4) != 0)
1474 p=ReadResourceShort(p,&id);
1475 p=ReadResourceByte(p,&length_byte);
1477 if (((length_byte+1) & 0x01) != 0)
1479 if (p > (datum+length-4))
1481 p=ReadResourceLong(p,&value);
1482 count=(ssize_t) value;
1483 if ((count & 0x01) != 0)
1485 if ((p > (datum+length-count)) || (count > (ssize_t) length))
1487 if (id != profile_id)
1502 extent=(datum+length)-(p+count);
1503 if (profile == (StringInfo *) NULL)
1506 extract_profile=AcquireStringInfo(offset+extent);
1507 (void) CopyMagickMemory(extract_profile->datum,datum,offset);
1512 extract_count=profile->length;
1513 if ((extract_count & 0x01) != 0)
1515 extract_profile=AcquireStringInfo(offset+extract_count+extent);
1516 (void) CopyMagickMemory(extract_profile->datum,datum,offset-4);
1517 WriteResourceLong(extract_profile->datum+offset-4,profile->length);
1518 (void) CopyMagickMemory(extract_profile->datum+offset,
1519 profile->datum,profile->length);
1521 (void) CopyMagickMemory(extract_profile->datum+offset+extract_count,
1523 (void) AddValueToSplayTree((SplayTreeInfo *) image->profiles,
1524 ConstantString("8bim"),CloneStringInfo(extract_profile));
1525 extract_profile=DestroyStringInfo(extract_profile);
1531 static void GetProfilesFromResourceBlock(Image *image,
1532 const StringInfo *resource_block,ExceptionInfo *exception)
1537 register const unsigned char
1558 datum=GetStringInfoDatum(resource_block);
1559 length=GetStringInfoLength(resource_block);
1560 for (p=datum; p < (datum+length-16); )
1562 if (LocaleNCompare((char *) p,"8BIM",4) != 0)
1565 p=ReadResourceShort(p,&id);
1566 p=ReadResourceByte(p,&length_byte);
1568 if (((length_byte+1) & 0x01) != 0)
1570 if (p > (datum+length-4))
1572 p=ReadResourceLong(p,&value);
1573 count=(ssize_t) value;
1574 if ((p > (datum+length-count)) || (count > (ssize_t) length))
1589 p=ReadResourceLong(p,&resolution);
1590 image->resolution.x=((double) resolution)/65536.0;
1591 p=ReadResourceShort(p,&units)+2;
1592 p=ReadResourceLong(p,&resolution)+4;
1593 image->resolution.y=((double) resolution)/65536.0;
1595 Values are always stored as pixels per inch.
1597 if ((ResolutionType) units != PixelsPerCentimeterResolution)
1598 image->units=PixelsPerInchResolution;
1601 image->units=PixelsPerCentimeterResolution;
1602 image->resolution.x/=2.54;
1603 image->resolution.y/=2.54;
1612 profile=AcquireStringInfo(count);
1613 SetStringInfoDatum(profile,p);
1614 (void) SetImageProfileInternal(image,"iptc",profile,MagickTrue,
1616 profile=DestroyStringInfo(profile);
1633 profile=AcquireStringInfo(count);
1634 SetStringInfoDatum(profile,p);
1635 (void) SetImageProfileInternal(image,"icc",profile,MagickTrue,
1637 profile=DestroyStringInfo(profile);
1646 profile=AcquireStringInfo(count);
1647 SetStringInfoDatum(profile,p);
1648 (void) SetImageProfileInternal(image,"exif",profile,MagickTrue,
1650 profile=DestroyStringInfo(profile);
1659 profile=AcquireStringInfo(count);
1660 SetStringInfoDatum(profile,p);
1661 (void) SetImageProfileInternal(image,"xmp",profile,MagickTrue,
1663 profile=DestroyStringInfo(profile);
1673 if ((count & 0x01) != 0)
1678 static MagickBooleanType SetImageProfileInternal(Image *image,const char *name,
1679 const StringInfo *profile,const MagickBooleanType recursive,
1680 ExceptionInfo *exception)
1684 property[MaxTextExtent];
1689 assert(image != (Image *) NULL);
1690 assert(image->signature == MagickSignature);
1691 if (image->debug != MagickFalse)
1692 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1693 if (image->profiles == (SplayTreeInfo *) NULL)
1694 image->profiles=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
1696 (void) CopyMagickString(key,name,MaxTextExtent);
1698 status=AddValueToSplayTree((SplayTreeInfo *) image->profiles,
1699 ConstantString(key),CloneStringInfo(profile));
1700 if (status != MagickFalse)
1702 if (LocaleCompare(name,"8bim") == 0)
1703 GetProfilesFromResourceBlock(image,profile,exception);
1704 else if (recursive == MagickFalse)
1705 WriteTo8BimProfile(image,name,profile);
1708 Inject profile into image properties.
1710 (void) FormatLocaleString(property,MaxTextExtent,"%s:*",name);
1711 (void) GetImageProperty(image,property,exception);
1715 MagickExport MagickBooleanType SetImageProfile(Image *image,const char *name,
1716 const StringInfo *profile,ExceptionInfo *exception)
1718 return(SetImageProfileInternal(image,name,profile,MagickFalse,exception));
1722 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1726 % S y n c I m a g e P r o f i l e s %
1730 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1732 % SyncImageProfiles() synchronizes image properties with the image profiles.
1733 % Currently we only support updating the EXIF resolution and orientation.
1735 % The format of the SyncImageProfiles method is:
1737 % MagickBooleanType SyncImageProfiles(Image *image)
1739 % A description of each parameter follows:
1741 % o image: the image.
1745 static inline int ReadProfileByte(unsigned char **p,size_t *length)
1757 static inline unsigned short ReadProfileShort(const EndianType endian,
1758 unsigned char *buffer)
1763 if (endian == LSBEndian)
1765 value=(unsigned short) ((buffer[1] << 8) | buffer[0]);
1766 return((unsigned short) (value & 0xffff));
1768 value=(unsigned short) ((((unsigned char *) buffer)[0] << 8) |
1769 ((unsigned char *) buffer)[1]);
1770 return((unsigned short) (value & 0xffff));
1773 static inline size_t ReadProfileLong(const EndianType endian,
1774 unsigned char *buffer)
1779 if (endian == LSBEndian)
1781 value=(size_t) ((buffer[3] << 24) | (buffer[2] << 16) |
1782 (buffer[1] << 8 ) | (buffer[0]));
1783 return((size_t) (value & 0xffffffff));
1785 value=(size_t) ((buffer[0] << 24) | (buffer[1] << 16) |
1786 (buffer[2] << 8) | buffer[3]);
1787 return((size_t) (value & 0xffffffff));
1790 static inline size_t ReadProfileMSBLong(unsigned char **p,
1799 value=ReadProfileLong(MSBEndian,*p);
1805 static inline unsigned short ReadProfileMSBShort(unsigned char **p,
1814 value=ReadProfileShort(MSBEndian,*p);
1820 static inline void WriteProfileLong(const EndianType endian,
1821 const size_t value,unsigned char *p)
1826 if (endian == LSBEndian)
1828 buffer[0]=(unsigned char) value;
1829 buffer[1]=(unsigned char) (value >> 8);
1830 buffer[2]=(unsigned char) (value >> 16);
1831 buffer[3]=(unsigned char) (value >> 24);
1832 (void) CopyMagickMemory(p,buffer,4);
1835 buffer[0]=(unsigned char) (value >> 24);
1836 buffer[1]=(unsigned char) (value >> 16);
1837 buffer[2]=(unsigned char) (value >> 8);
1838 buffer[3]=(unsigned char) value;
1839 (void) CopyMagickMemory(p,buffer,4);
1842 static void WriteProfileShort(const EndianType endian,
1843 const unsigned short value,unsigned char *p)
1848 if (endian == LSBEndian)
1850 buffer[0]=(unsigned char) value;
1851 buffer[1]=(unsigned char) (value >> 8);
1852 (void) CopyMagickMemory(p,buffer,2);
1855 buffer[0]=(unsigned char) (value >> 8);
1856 buffer[1]=(unsigned char) value;
1857 (void) CopyMagickMemory(p,buffer,2);
1860 static MagickBooleanType Sync8BimProfile(Image *image,StringInfo *profile)
1872 length=GetStringInfoLength(profile);
1873 p=GetStringInfoDatum(profile);
1876 if (ReadProfileByte(&p,&length) != 0x38)
1878 if (ReadProfileByte(&p,&length) != 0x42)
1880 if (ReadProfileByte(&p,&length) != 0x49)
1882 if (ReadProfileByte(&p,&length) != 0x4D)
1885 return(MagickFalse);
1886 id=ReadProfileMSBShort(&p,&length);
1887 count=ReadProfileByte(&p,&length);
1889 return(MagickFalse);
1891 if ((*p & 0x01) == 0)
1893 count=ReadProfileMSBLong(&p,&length);
1895 return(MagickFalse);
1896 if (id == 0x3ED && count == 16)
1898 if (image->units == PixelsPerCentimeterResolution)
1899 WriteProfileLong(MSBEndian, (unsigned int) (image->resolution.x*2.54*
1902 WriteProfileLong(MSBEndian, (unsigned int) (image->resolution.x*
1904 WriteProfileShort(MSBEndian,(unsigned short) image->units,p+4);
1905 if (image->units == PixelsPerCentimeterResolution)
1906 WriteProfileLong(MSBEndian, (unsigned int) (image->resolution.y*2.54*
1909 WriteProfileLong(MSBEndian, (unsigned int) (image->resolution.y*
1911 WriteProfileShort(MSBEndian,(unsigned short) image->units,p+12);
1919 MagickBooleanType SyncExifProfile(Image *image,StringInfo *profile)
1921 #define MaxDirectoryStack 16
1922 #define EXIF_DELIMITER "\n"
1923 #define EXIF_NUM_FORMATS 12
1924 #define TAG_EXIF_OFFSET 0x8769
1925 #define TAG_INTEROP_OFFSET 0xa005
1927 typedef struct _DirectoryInfo
1937 directory_stack[MaxDirectoryStack];
1953 format_bytes[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
1960 Set EXIF resolution tag.
1962 length=GetStringInfoLength(profile);
1963 exif=GetStringInfoDatum(profile);
1965 return(MagickFalse);
1966 id=(ssize_t) ReadProfileShort(LSBEndian,exif);
1967 if ((id != 0x4949) && (id != 0x4D4D))
1971 if (ReadProfileByte(&exif,&length) != 0x45)
1973 if (ReadProfileByte(&exif,&length) != 0x78)
1975 if (ReadProfileByte(&exif,&length) != 0x69)
1977 if (ReadProfileByte(&exif,&length) != 0x66)
1979 if (ReadProfileByte(&exif,&length) != 0x00)
1981 if (ReadProfileByte(&exif,&length) != 0x00)
1986 return(MagickFalse);
1987 id=(ssize_t) ReadProfileShort(LSBEndian,exif);
1996 return(MagickFalse);
1997 if (ReadProfileShort(endian,exif+2) != 0x002a)
1998 return(MagickFalse);
2000 This the offset to the first IFD.
2002 offset=(ssize_t) ((int) ReadProfileLong(endian,exif+4));
2003 if ((offset < 0) || (size_t) offset >= length)
2004 return(MagickFalse);
2005 directory=exif+offset;
2013 directory=directory_stack[level].directory;
2014 entry=directory_stack[level].entry;
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 tag_value=(ssize_t) ReadProfileShort(endian,q);
2038 format=(ssize_t) ReadProfileShort(endian,q+2);
2039 if ((format-1) >= EXIF_NUM_FORMATS)
2041 components=(ssize_t) ((int) ReadProfileLong(endian,q+4));
2042 number_bytes=(size_t) components*format_bytes[format];
2043 if ((ssize_t) number_bytes < components)
2044 break; /* prevent overflow */
2045 if (number_bytes <= 4)
2053 The directory entry contains an offset.
2055 offset=(ssize_t) ((int) ReadProfileLong(endian,q+8));
2056 if ((size_t) (offset+number_bytes) > length)
2058 if (~length < number_bytes)
2059 continue; /* prevent overflow */
2060 p=(unsigned char *) (exif+offset);
2066 (void) WriteProfileLong(endian,(size_t) (image->resolution.x+0.5),p);
2067 (void) WriteProfileLong(endian,1UL,p+4);
2072 (void) WriteProfileLong(endian,(size_t) (image->resolution.y+0.5),p);
2073 (void) WriteProfileLong(endian,1UL,p+4);
2078 if (number_bytes == 4)
2080 (void) WriteProfileLong(endian,(size_t) image->orientation,p);
2083 (void) WriteProfileShort(endian,(unsigned short) image->orientation,
2089 if (number_bytes == 4)
2091 (void) WriteProfileLong(endian,(size_t) (image->units+1),p);
2094 (void) WriteProfileShort(endian,(unsigned short) (image->units+1),p);
2100 if ((tag_value == TAG_EXIF_OFFSET) || (tag_value == TAG_INTEROP_OFFSET))
2105 offset=(ssize_t) ((int) ReadProfileLong(endian,p));
2106 if (((size_t) offset < length) && (level < (MaxDirectoryStack-2)))
2108 directory_stack[level].directory=directory;
2110 directory_stack[level].entry=entry;
2112 directory_stack[level].directory=exif+offset;
2113 directory_stack[level].entry=0;
2115 if ((directory+2+(12*number_entries)) > (exif+length))
2117 offset=(ssize_t) ((int) ReadProfileLong(endian,directory+2+(12*
2119 if ((offset != 0) && ((size_t) offset < length) &&
2120 (level < (MaxDirectoryStack-2)))
2122 directory_stack[level].directory=exif+offset;
2123 directory_stack[level].entry=0;
2130 } while (level > 0);
2134 MagickPrivate MagickBooleanType SyncImageProfiles(Image *image)
2143 profile=(StringInfo *) GetImageProfile(image,"8BIM");
2144 if (profile != (StringInfo *) NULL)
2145 if (Sync8BimProfile(image,profile) == MagickFalse)
2147 profile=(StringInfo *) GetImageProfile(image,"EXIF");
2148 if (profile != (StringInfo *) NULL)
2149 if (SyncExifProfile(image,profile) == MagickFalse)