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 double **DestroyPixelThreadSet(double **pixels)
345 assert(pixels != (double **) NULL);
346 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
347 if (pixels[i] != (double *) NULL)
348 pixels[i]=(double *) RelinquishMagickMemory(pixels[i]);
349 pixels=(double **) RelinquishMagickMemory(pixels);
353 static double **AcquirePixelThreadSet(const size_t columns,
354 const size_t channels)
365 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
366 pixels=(double **) AcquireQuantumMemory(number_threads,sizeof(*pixels));
367 if (pixels == (double **) NULL)
368 return((double **) NULL);
369 (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
370 for (i=0; i < (ssize_t) number_threads; i++)
372 pixels[i]=(double *) AcquireQuantumMemory(columns,channels*
374 if (pixels[i] == (double *) NULL)
375 return(DestroyPixelThreadSet(pixels));
380 static cmsHTRANSFORM *DestroyTransformThreadSet(cmsHTRANSFORM *transform)
385 assert(transform != (cmsHTRANSFORM *) NULL);
386 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
387 if (transform[i] != (cmsHTRANSFORM) NULL)
388 cmsDeleteTransform(transform[i]);
389 transform=(cmsHTRANSFORM *) RelinquishMagickMemory(transform);
393 static cmsHTRANSFORM *AcquireTransformThreadSet(Image *image,
394 const cmsHPROFILE source_profile,const cmsUInt32Number source_type,
395 const cmsHPROFILE target_profile,const cmsUInt32Number target_type,
396 const int intent,const cmsUInt32Number flags)
407 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
408 transform=(cmsHTRANSFORM *) AcquireQuantumMemory(number_threads,
410 if (transform == (cmsHTRANSFORM *) NULL)
411 return((cmsHTRANSFORM *) NULL);
412 (void) ResetMagickMemory(transform,0,number_threads*sizeof(*transform));
413 for (i=0; i < (ssize_t) number_threads; i++)
415 transform[i]=cmsCreateTransformTHR((cmsContext) image,source_profile,
416 source_type,target_profile,target_type,intent,flags);
417 if (transform[i] == (cmsHTRANSFORM) NULL)
418 return(DestroyTransformThreadSet(transform));
424 #if defined(MAGICKCORE_LCMS_DELEGATE)
425 static void CMSExceptionHandler(cmsContext context,cmsUInt32Number severity,
437 cms_exception=(CMSExceptionInfo *) context;
438 if (cms_exception == (CMSExceptionInfo *) NULL)
440 exception=cms_exception->exception;
441 if (exception == (ExceptionInfo *) NULL)
443 image=cms_exception->image;
444 if (image == (Image *) NULL)
446 (void) ThrowMagickException(exception,GetMagickModule(),ImageWarning,
447 "UnableToTransformColorspace","`%s'","unknown context");
450 if (image->debug != MagickFalse)
451 (void) LogMagickEvent(TransformEvent,GetMagickModule(),"lcms: #%u, %s",
452 severity,message != (char *) NULL ? message : "no message");
453 (void) ThrowMagickException(exception,GetMagickModule(),ImageWarning,
454 "UnableToTransformColorspace","`%s'",image->filename);
458 static MagickBooleanType SetsRGBImageProfile(Image *image,
459 ExceptionInfo *exception)
464 0x00, 0x00, 0x0c, 0x8c, 0x61, 0x72, 0x67, 0x6c, 0x02, 0x20, 0x00, 0x00,
465 0x6d, 0x6e, 0x74, 0x72, 0x52, 0x47, 0x42, 0x20, 0x58, 0x59, 0x5a, 0x20,
466 0x07, 0xde, 0x00, 0x01, 0x00, 0x06, 0x00, 0x16, 0x00, 0x0f, 0x00, 0x3a,
467 0x61, 0x63, 0x73, 0x70, 0x4d, 0x53, 0x46, 0x54, 0x00, 0x00, 0x00, 0x00,
468 0x49, 0x45, 0x43, 0x20, 0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00, 0x00,
469 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xd6,
470 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d, 0x61, 0x72, 0x67, 0x6c,
471 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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, 0x11,
475 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x01, 0x50, 0x00, 0x00, 0x00, 0x99,
476 0x63, 0x70, 0x72, 0x74, 0x00, 0x00, 0x01, 0xec, 0x00, 0x00, 0x00, 0x67,
477 0x64, 0x6d, 0x6e, 0x64, 0x00, 0x00, 0x02, 0x54, 0x00, 0x00, 0x00, 0x70,
478 0x64, 0x6d, 0x64, 0x64, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x00, 0x88,
479 0x74, 0x65, 0x63, 0x68, 0x00, 0x00, 0x03, 0x4c, 0x00, 0x00, 0x00, 0x0c,
480 0x76, 0x75, 0x65, 0x64, 0x00, 0x00, 0x03, 0x58, 0x00, 0x00, 0x00, 0x67,
481 0x76, 0x69, 0x65, 0x77, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x24,
482 0x6c, 0x75, 0x6d, 0x69, 0x00, 0x00, 0x03, 0xe4, 0x00, 0x00, 0x00, 0x14,
483 0x6d, 0x65, 0x61, 0x73, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x24,
484 0x77, 0x74, 0x70, 0x74, 0x00, 0x00, 0x04, 0x1c, 0x00, 0x00, 0x00, 0x14,
485 0x62, 0x6b, 0x70, 0x74, 0x00, 0x00, 0x04, 0x30, 0x00, 0x00, 0x00, 0x14,
486 0x72, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x04, 0x44, 0x00, 0x00, 0x00, 0x14,
487 0x67, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x04, 0x58, 0x00, 0x00, 0x00, 0x14,
488 0x62, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x04, 0x6c, 0x00, 0x00, 0x00, 0x14,
489 0x72, 0x54, 0x52, 0x43, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x08, 0x0c,
490 0x67, 0x54, 0x52, 0x43, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x08, 0x0c,
491 0x62, 0x54, 0x52, 0x43, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x08, 0x0c,
492 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
493 0x73, 0x52, 0x47, 0x42, 0x20, 0x49, 0x45, 0x43, 0x36, 0x31, 0x39, 0x36,
494 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x20, 0x28, 0x45, 0x71, 0x75, 0x69, 0x76,
495 0x61, 0x6c, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x77, 0x77, 0x77,
496 0x2e, 0x73, 0x72, 0x67, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x31, 0x39,
497 0x39, 0x38, 0x20, 0x48, 0x50, 0x20, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c,
498 0x65, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
499 0x00, 0x3f, 0x73, 0x52, 0x47, 0x42, 0x20, 0x49, 0x45, 0x43, 0x36, 0x31,
500 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x20, 0x28, 0x45, 0x71, 0x75,
501 0x69, 0x76, 0x61, 0x6c, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x77,
502 0x77, 0x77, 0x2e, 0x73, 0x72, 0x67, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x20,
503 0x31, 0x39, 0x39, 0x38, 0x20, 0x48, 0x50, 0x20, 0x70, 0x72, 0x6f, 0x66,
504 0x69, 0x6c, 0x65, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
505 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x43, 0x72, 0x65, 0x61,
506 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x47, 0x72, 0x61, 0x65, 0x6d,
507 0x65, 0x20, 0x57, 0x2e, 0x20, 0x47, 0x69, 0x6c, 0x6c, 0x2e, 0x20, 0x52,
508 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x6f,
509 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20,
510 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x20, 0x4e, 0x6f, 0x20, 0x57,
511 0x61, 0x72, 0x72, 0x61, 0x6e, 0x74, 0x79, 0x2c, 0x20, 0x55, 0x73, 0x65,
512 0x20, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75, 0x72, 0x20, 0x6f, 0x77, 0x6e,
513 0x20, 0x72, 0x69, 0x73, 0x6b, 0x2e, 0x00, 0x00, 0x64, 0x65, 0x73, 0x63,
514 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x49, 0x45, 0x43, 0x20,
515 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69,
516 0x65, 0x63, 0x2e, 0x63, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
517 0x00, 0x00, 0x00, 0x00, 0x16, 0x49, 0x45, 0x43, 0x20, 0x68, 0x74, 0x74,
518 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x65, 0x63, 0x2e,
519 0x63, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
520 0x00, 0x00, 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 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e,
524 0x49, 0x45, 0x43, 0x20, 0x36, 0x31, 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e,
525 0x31, 0x20, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x52, 0x47,
526 0x42, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x75, 0x72, 0x20, 0x73, 0x70, 0x61,
527 0x63, 0x65, 0x20, 0x2d, 0x20, 0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00,
528 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x49, 0x45, 0x43,
529 0x20, 0x36, 0x31, 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x20, 0x44,
530 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x52, 0x47, 0x42, 0x20, 0x63,
531 0x6f, 0x6c, 0x6f, 0x75, 0x72, 0x20, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20,
532 0x2d, 0x20, 0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
533 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
534 0x00, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x20, 0x00, 0x00, 0x00, 0x00,
535 0x43, 0x52, 0x54, 0x20, 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00,
536 0x00, 0x00, 0x00, 0x0d, 0x49, 0x45, 0x43, 0x36, 0x31, 0x39, 0x36, 0x36,
537 0x2d, 0x32, 0x2e, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
538 0x00, 0x00, 0x00, 0x0d, 0x49, 0x45, 0x43, 0x36, 0x31, 0x39, 0x36, 0x36,
539 0x2d, 0x32, 0x2e, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
540 0x00, 0x00, 0x00, 0x00, 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 0x76, 0x69, 0x65, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xa4, 0x7c,
545 0x00, 0x14, 0x5f, 0x30, 0x00, 0x10, 0xce, 0x02, 0x00, 0x03, 0xed, 0xb2,
546 0x00, 0x04, 0x13, 0x0a, 0x00, 0x03, 0x5c, 0x67, 0x00, 0x00, 0x00, 0x01,
547 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x0a, 0x3d,
548 0x00, 0x50, 0x00, 0x00, 0x00, 0x57, 0x1e, 0xb8, 0x6d, 0x65, 0x61, 0x73,
549 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
550 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
551 0x00, 0x00, 0x02, 0x8f, 0x00, 0x00, 0x00, 0x02, 0x58, 0x59, 0x5a, 0x20,
552 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x51, 0x00, 0x01, 0x00, 0x00,
553 0x00, 0x01, 0x16, 0xcc, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00,
554 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
555 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xa0,
556 0x00, 0x00, 0x38, 0xf5, 0x00, 0x00, 0x03, 0x90, 0x58, 0x59, 0x5a, 0x20,
557 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x97, 0x00, 0x00, 0xb7, 0x87,
558 0x00, 0x00, 0x18, 0xd9, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00,
559 0x00, 0x00, 0x24, 0x9f, 0x00, 0x00, 0x0f, 0x84, 0x00, 0x00, 0xb6, 0xc4,
560 0x63, 0x75, 0x72, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
561 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x14, 0x00, 0x19,
562 0x00, 0x1e, 0x00, 0x23, 0x00, 0x28, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x37,
563 0x00, 0x3b, 0x00, 0x40, 0x00, 0x45, 0x00, 0x4a, 0x00, 0x4f, 0x00, 0x54,
564 0x00, 0x59, 0x00, 0x5e, 0x00, 0x63, 0x00, 0x68, 0x00, 0x6d, 0x00, 0x72,
565 0x00, 0x77, 0x00, 0x7c, 0x00, 0x81, 0x00, 0x86, 0x00, 0x8b, 0x00, 0x90,
566 0x00, 0x95, 0x00, 0x9a, 0x00, 0x9f, 0x00, 0xa4, 0x00, 0xa9, 0x00, 0xae,
567 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc1, 0x00, 0xc6, 0x00, 0xcb,
568 0x00, 0xd0, 0x00, 0xd5, 0x00, 0xdb, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0xeb,
569 0x00, 0xf0, 0x00, 0xf6, 0x00, 0xfb, 0x01, 0x01, 0x01, 0x07, 0x01, 0x0d,
570 0x01, 0x13, 0x01, 0x19, 0x01, 0x1f, 0x01, 0x25, 0x01, 0x2b, 0x01, 0x32,
571 0x01, 0x38, 0x01, 0x3e, 0x01, 0x45, 0x01, 0x4c, 0x01, 0x52, 0x01, 0x59,
572 0x01, 0x60, 0x01, 0x67, 0x01, 0x6e, 0x01, 0x75, 0x01, 0x7c, 0x01, 0x83,
573 0x01, 0x8b, 0x01, 0x92, 0x01, 0x9a, 0x01, 0xa1, 0x01, 0xa9, 0x01, 0xb1,
574 0x01, 0xb9, 0x01, 0xc1, 0x01, 0xc9, 0x01, 0xd1, 0x01, 0xd9, 0x01, 0xe1,
575 0x01, 0xe9, 0x01, 0xf2, 0x01, 0xfa, 0x02, 0x03, 0x02, 0x0c, 0x02, 0x14,
576 0x02, 0x1d, 0x02, 0x26, 0x02, 0x2f, 0x02, 0x38, 0x02, 0x41, 0x02, 0x4b,
577 0x02, 0x54, 0x02, 0x5d, 0x02, 0x67, 0x02, 0x71, 0x02, 0x7a, 0x02, 0x84,
578 0x02, 0x8e, 0x02, 0x98, 0x02, 0xa2, 0x02, 0xac, 0x02, 0xb6, 0x02, 0xc1,
579 0x02, 0xcb, 0x02, 0xd5, 0x02, 0xe0, 0x02, 0xeb, 0x02, 0xf5, 0x03, 0x00,
580 0x03, 0x0b, 0x03, 0x16, 0x03, 0x21, 0x03, 0x2d, 0x03, 0x38, 0x03, 0x43,
581 0x03, 0x4f, 0x03, 0x5a, 0x03, 0x66, 0x03, 0x72, 0x03, 0x7e, 0x03, 0x8a,
582 0x03, 0x96, 0x03, 0xa2, 0x03, 0xae, 0x03, 0xba, 0x03, 0xc7, 0x03, 0xd3,
583 0x03, 0xe0, 0x03, 0xec, 0x03, 0xf9, 0x04, 0x06, 0x04, 0x13, 0x04, 0x20,
584 0x04, 0x2d, 0x04, 0x3b, 0x04, 0x48, 0x04, 0x55, 0x04, 0x63, 0x04, 0x71,
585 0x04, 0x7e, 0x04, 0x8c, 0x04, 0x9a, 0x04, 0xa8, 0x04, 0xb6, 0x04, 0xc4,
586 0x04, 0xd3, 0x04, 0xe1, 0x04, 0xf0, 0x04, 0xfe, 0x05, 0x0d, 0x05, 0x1c,
587 0x05, 0x2b, 0x05, 0x3a, 0x05, 0x49, 0x05, 0x58, 0x05, 0x67, 0x05, 0x77,
588 0x05, 0x86, 0x05, 0x96, 0x05, 0xa6, 0x05, 0xb5, 0x05, 0xc5, 0x05, 0xd5,
589 0x05, 0xe5, 0x05, 0xf6, 0x06, 0x06, 0x06, 0x16, 0x06, 0x27, 0x06, 0x37,
590 0x06, 0x48, 0x06, 0x59, 0x06, 0x6a, 0x06, 0x7b, 0x06, 0x8c, 0x06, 0x9d,
591 0x06, 0xaf, 0x06, 0xc0, 0x06, 0xd1, 0x06, 0xe3, 0x06, 0xf5, 0x07, 0x07,
592 0x07, 0x19, 0x07, 0x2b, 0x07, 0x3d, 0x07, 0x4f, 0x07, 0x61, 0x07, 0x74,
593 0x07, 0x86, 0x07, 0x99, 0x07, 0xac, 0x07, 0xbf, 0x07, 0xd2, 0x07, 0xe5,
594 0x07, 0xf8, 0x08, 0x0b, 0x08, 0x1f, 0x08, 0x32, 0x08, 0x46, 0x08, 0x5a,
595 0x08, 0x6e, 0x08, 0x82, 0x08, 0x96, 0x08, 0xaa, 0x08, 0xbe, 0x08, 0xd2,
596 0x08, 0xe7, 0x08, 0xfb, 0x09, 0x10, 0x09, 0x25, 0x09, 0x3a, 0x09, 0x4f,
597 0x09, 0x64, 0x09, 0x79, 0x09, 0x8f, 0x09, 0xa4, 0x09, 0xba, 0x09, 0xcf,
598 0x09, 0xe5, 0x09, 0xfb, 0x0a, 0x11, 0x0a, 0x27, 0x0a, 0x3d, 0x0a, 0x54,
599 0x0a, 0x6a, 0x0a, 0x81, 0x0a, 0x98, 0x0a, 0xae, 0x0a, 0xc5, 0x0a, 0xdc,
600 0x0a, 0xf3, 0x0b, 0x0b, 0x0b, 0x22, 0x0b, 0x39, 0x0b, 0x51, 0x0b, 0x69,
601 0x0b, 0x80, 0x0b, 0x98, 0x0b, 0xb0, 0x0b, 0xc8, 0x0b, 0xe1, 0x0b, 0xf9,
602 0x0c, 0x12, 0x0c, 0x2a, 0x0c, 0x43, 0x0c, 0x5c, 0x0c, 0x75, 0x0c, 0x8e,
603 0x0c, 0xa7, 0x0c, 0xc0, 0x0c, 0xd9, 0x0c, 0xf3, 0x0d, 0x0d, 0x0d, 0x26,
604 0x0d, 0x40, 0x0d, 0x5a, 0x0d, 0x74, 0x0d, 0x8e, 0x0d, 0xa9, 0x0d, 0xc3,
605 0x0d, 0xde, 0x0d, 0xf8, 0x0e, 0x13, 0x0e, 0x2e, 0x0e, 0x49, 0x0e, 0x64,
606 0x0e, 0x7f, 0x0e, 0x9b, 0x0e, 0xb6, 0x0e, 0xd2, 0x0e, 0xee, 0x0f, 0x09,
607 0x0f, 0x25, 0x0f, 0x41, 0x0f, 0x5e, 0x0f, 0x7a, 0x0f, 0x96, 0x0f, 0xb3,
608 0x0f, 0xcf, 0x0f, 0xec, 0x10, 0x09, 0x10, 0x26, 0x10, 0x43, 0x10, 0x61,
609 0x10, 0x7e, 0x10, 0x9b, 0x10, 0xb9, 0x10, 0xd7, 0x10, 0xf5, 0x11, 0x13,
610 0x11, 0x31, 0x11, 0x4f, 0x11, 0x6d, 0x11, 0x8c, 0x11, 0xaa, 0x11, 0xc9,
611 0x11, 0xe8, 0x12, 0x07, 0x12, 0x26, 0x12, 0x45, 0x12, 0x64, 0x12, 0x84,
612 0x12, 0xa3, 0x12, 0xc3, 0x12, 0xe3, 0x13, 0x03, 0x13, 0x23, 0x13, 0x43,
613 0x13, 0x63, 0x13, 0x83, 0x13, 0xa4, 0x13, 0xc5, 0x13, 0xe5, 0x14, 0x06,
614 0x14, 0x27, 0x14, 0x49, 0x14, 0x6a, 0x14, 0x8b, 0x14, 0xad, 0x14, 0xce,
615 0x14, 0xf0, 0x15, 0x12, 0x15, 0x34, 0x15, 0x56, 0x15, 0x78, 0x15, 0x9b,
616 0x15, 0xbd, 0x15, 0xe0, 0x16, 0x03, 0x16, 0x26, 0x16, 0x49, 0x16, 0x6c,
617 0x16, 0x8f, 0x16, 0xb2, 0x16, 0xd6, 0x16, 0xfa, 0x17, 0x1d, 0x17, 0x41,
618 0x17, 0x65, 0x17, 0x89, 0x17, 0xae, 0x17, 0xd2, 0x17, 0xf7, 0x18, 0x1b,
619 0x18, 0x40, 0x18, 0x65, 0x18, 0x8a, 0x18, 0xaf, 0x18, 0xd5, 0x18, 0xfa,
620 0x19, 0x20, 0x19, 0x45, 0x19, 0x6b, 0x19, 0x91, 0x19, 0xb7, 0x19, 0xdd,
621 0x1a, 0x04, 0x1a, 0x2a, 0x1a, 0x51, 0x1a, 0x77, 0x1a, 0x9e, 0x1a, 0xc5,
622 0x1a, 0xec, 0x1b, 0x14, 0x1b, 0x3b, 0x1b, 0x63, 0x1b, 0x8a, 0x1b, 0xb2,
623 0x1b, 0xda, 0x1c, 0x02, 0x1c, 0x2a, 0x1c, 0x52, 0x1c, 0x7b, 0x1c, 0xa3,
624 0x1c, 0xcc, 0x1c, 0xf5, 0x1d, 0x1e, 0x1d, 0x47, 0x1d, 0x70, 0x1d, 0x99,
625 0x1d, 0xc3, 0x1d, 0xec, 0x1e, 0x16, 0x1e, 0x40, 0x1e, 0x6a, 0x1e, 0x94,
626 0x1e, 0xbe, 0x1e, 0xe9, 0x1f, 0x13, 0x1f, 0x3e, 0x1f, 0x69, 0x1f, 0x94,
627 0x1f, 0xbf, 0x1f, 0xea, 0x20, 0x15, 0x20, 0x41, 0x20, 0x6c, 0x20, 0x98,
628 0x20, 0xc4, 0x20, 0xf0, 0x21, 0x1c, 0x21, 0x48, 0x21, 0x75, 0x21, 0xa1,
629 0x21, 0xce, 0x21, 0xfb, 0x22, 0x27, 0x22, 0x55, 0x22, 0x82, 0x22, 0xaf,
630 0x22, 0xdd, 0x23, 0x0a, 0x23, 0x38, 0x23, 0x66, 0x23, 0x94, 0x23, 0xc2,
631 0x23, 0xf0, 0x24, 0x1f, 0x24, 0x4d, 0x24, 0x7c, 0x24, 0xab, 0x24, 0xda,
632 0x25, 0x09, 0x25, 0x38, 0x25, 0x68, 0x25, 0x97, 0x25, 0xc7, 0x25, 0xf7,
633 0x26, 0x27, 0x26, 0x57, 0x26, 0x87, 0x26, 0xb7, 0x26, 0xe8, 0x27, 0x18,
634 0x27, 0x49, 0x27, 0x7a, 0x27, 0xab, 0x27, 0xdc, 0x28, 0x0d, 0x28, 0x3f,
635 0x28, 0x71, 0x28, 0xa2, 0x28, 0xd4, 0x29, 0x06, 0x29, 0x38, 0x29, 0x6b,
636 0x29, 0x9d, 0x29, 0xd0, 0x2a, 0x02, 0x2a, 0x35, 0x2a, 0x68, 0x2a, 0x9b,
637 0x2a, 0xcf, 0x2b, 0x02, 0x2b, 0x36, 0x2b, 0x69, 0x2b, 0x9d, 0x2b, 0xd1,
638 0x2c, 0x05, 0x2c, 0x39, 0x2c, 0x6e, 0x2c, 0xa2, 0x2c, 0xd7, 0x2d, 0x0c,
639 0x2d, 0x41, 0x2d, 0x76, 0x2d, 0xab, 0x2d, 0xe1, 0x2e, 0x16, 0x2e, 0x4c,
640 0x2e, 0x82, 0x2e, 0xb7, 0x2e, 0xee, 0x2f, 0x24, 0x2f, 0x5a, 0x2f, 0x91,
641 0x2f, 0xc7, 0x2f, 0xfe, 0x30, 0x35, 0x30, 0x6c, 0x30, 0xa4, 0x30, 0xdb,
642 0x31, 0x12, 0x31, 0x4a, 0x31, 0x82, 0x31, 0xba, 0x31, 0xf2, 0x32, 0x2a,
643 0x32, 0x63, 0x32, 0x9b, 0x32, 0xd4, 0x33, 0x0d, 0x33, 0x46, 0x33, 0x7f,
644 0x33, 0xb8, 0x33, 0xf1, 0x34, 0x2b, 0x34, 0x65, 0x34, 0x9e, 0x34, 0xd8,
645 0x35, 0x13, 0x35, 0x4d, 0x35, 0x87, 0x35, 0xc2, 0x35, 0xfd, 0x36, 0x37,
646 0x36, 0x72, 0x36, 0xae, 0x36, 0xe9, 0x37, 0x24, 0x37, 0x60, 0x37, 0x9c,
647 0x37, 0xd7, 0x38, 0x14, 0x38, 0x50, 0x38, 0x8c, 0x38, 0xc8, 0x39, 0x05,
648 0x39, 0x42, 0x39, 0x7f, 0x39, 0xbc, 0x39, 0xf9, 0x3a, 0x36, 0x3a, 0x74,
649 0x3a, 0xb2, 0x3a, 0xef, 0x3b, 0x2d, 0x3b, 0x6b, 0x3b, 0xaa, 0x3b, 0xe8,
650 0x3c, 0x27, 0x3c, 0x65, 0x3c, 0xa4, 0x3c, 0xe3, 0x3d, 0x22, 0x3d, 0x61,
651 0x3d, 0xa1, 0x3d, 0xe0, 0x3e, 0x20, 0x3e, 0x60, 0x3e, 0xa0, 0x3e, 0xe0,
652 0x3f, 0x21, 0x3f, 0x61, 0x3f, 0xa2, 0x3f, 0xe2, 0x40, 0x23, 0x40, 0x64,
653 0x40, 0xa6, 0x40, 0xe7, 0x41, 0x29, 0x41, 0x6a, 0x41, 0xac, 0x41, 0xee,
654 0x42, 0x30, 0x42, 0x72, 0x42, 0xb5, 0x42, 0xf7, 0x43, 0x3a, 0x43, 0x7d,
655 0x43, 0xc0, 0x44, 0x03, 0x44, 0x47, 0x44, 0x8a, 0x44, 0xce, 0x45, 0x12,
656 0x45, 0x55, 0x45, 0x9a, 0x45, 0xde, 0x46, 0x22, 0x46, 0x67, 0x46, 0xab,
657 0x46, 0xf0, 0x47, 0x35, 0x47, 0x7b, 0x47, 0xc0, 0x48, 0x05, 0x48, 0x4b,
658 0x48, 0x91, 0x48, 0xd7, 0x49, 0x1d, 0x49, 0x63, 0x49, 0xa9, 0x49, 0xf0,
659 0x4a, 0x37, 0x4a, 0x7d, 0x4a, 0xc4, 0x4b, 0x0c, 0x4b, 0x53, 0x4b, 0x9a,
660 0x4b, 0xe2, 0x4c, 0x2a, 0x4c, 0x72, 0x4c, 0xba, 0x4d, 0x02, 0x4d, 0x4a,
661 0x4d, 0x93, 0x4d, 0xdc, 0x4e, 0x25, 0x4e, 0x6e, 0x4e, 0xb7, 0x4f, 0x00,
662 0x4f, 0x49, 0x4f, 0x93, 0x4f, 0xdd, 0x50, 0x27, 0x50, 0x71, 0x50, 0xbb,
663 0x51, 0x06, 0x51, 0x50, 0x51, 0x9b, 0x51, 0xe6, 0x52, 0x31, 0x52, 0x7c,
664 0x52, 0xc7, 0x53, 0x13, 0x53, 0x5f, 0x53, 0xaa, 0x53, 0xf6, 0x54, 0x42,
665 0x54, 0x8f, 0x54, 0xdb, 0x55, 0x28, 0x55, 0x75, 0x55, 0xc2, 0x56, 0x0f,
666 0x56, 0x5c, 0x56, 0xa9, 0x56, 0xf7, 0x57, 0x44, 0x57, 0x92, 0x57, 0xe0,
667 0x58, 0x2f, 0x58, 0x7d, 0x58, 0xcb, 0x59, 0x1a, 0x59, 0x69, 0x59, 0xb8,
668 0x5a, 0x07, 0x5a, 0x56, 0x5a, 0xa6, 0x5a, 0xf5, 0x5b, 0x45, 0x5b, 0x95,
669 0x5b, 0xe5, 0x5c, 0x35, 0x5c, 0x86, 0x5c, 0xd6, 0x5d, 0x27, 0x5d, 0x78,
670 0x5d, 0xc9, 0x5e, 0x1a, 0x5e, 0x6c, 0x5e, 0xbd, 0x5f, 0x0f, 0x5f, 0x61,
671 0x5f, 0xb3, 0x60, 0x05, 0x60, 0x57, 0x60, 0xaa, 0x60, 0xfc, 0x61, 0x4f,
672 0x61, 0xa2, 0x61, 0xf5, 0x62, 0x49, 0x62, 0x9c, 0x62, 0xf0, 0x63, 0x43,
673 0x63, 0x97, 0x63, 0xeb, 0x64, 0x40, 0x64, 0x94, 0x64, 0xe9, 0x65, 0x3d,
674 0x65, 0x92, 0x65, 0xe7, 0x66, 0x3d, 0x66, 0x92, 0x66, 0xe8, 0x67, 0x3d,
675 0x67, 0x93, 0x67, 0xe9, 0x68, 0x3f, 0x68, 0x96, 0x68, 0xec, 0x69, 0x43,
676 0x69, 0x9a, 0x69, 0xf1, 0x6a, 0x48, 0x6a, 0x9f, 0x6a, 0xf7, 0x6b, 0x4f,
677 0x6b, 0xa7, 0x6b, 0xff, 0x6c, 0x57, 0x6c, 0xaf, 0x6d, 0x08, 0x6d, 0x60,
678 0x6d, 0xb9, 0x6e, 0x12, 0x6e, 0x6b, 0x6e, 0xc4, 0x6f, 0x1e, 0x6f, 0x78,
679 0x6f, 0xd1, 0x70, 0x2b, 0x70, 0x86, 0x70, 0xe0, 0x71, 0x3a, 0x71, 0x95,
680 0x71, 0xf0, 0x72, 0x4b, 0x72, 0xa6, 0x73, 0x01, 0x73, 0x5d, 0x73, 0xb8,
681 0x74, 0x14, 0x74, 0x70, 0x74, 0xcc, 0x75, 0x28, 0x75, 0x85, 0x75, 0xe1,
682 0x76, 0x3e, 0x76, 0x9b, 0x76, 0xf8, 0x77, 0x56, 0x77, 0xb3, 0x78, 0x11,
683 0x78, 0x6e, 0x78, 0xcc, 0x79, 0x2a, 0x79, 0x89, 0x79, 0xe7, 0x7a, 0x46,
684 0x7a, 0xa5, 0x7b, 0x04, 0x7b, 0x63, 0x7b, 0xc2, 0x7c, 0x21, 0x7c, 0x81,
685 0x7c, 0xe1, 0x7d, 0x41, 0x7d, 0xa1, 0x7e, 0x01, 0x7e, 0x62, 0x7e, 0xc2,
686 0x7f, 0x23, 0x7f, 0x84, 0x7f, 0xe5, 0x80, 0x47, 0x80, 0xa8, 0x81, 0x0a,
687 0x81, 0x6b, 0x81, 0xcd, 0x82, 0x30, 0x82, 0x92, 0x82, 0xf4, 0x83, 0x57,
688 0x83, 0xba, 0x84, 0x1d, 0x84, 0x80, 0x84, 0xe3, 0x85, 0x47, 0x85, 0xab,
689 0x86, 0x0e, 0x86, 0x72, 0x86, 0xd7, 0x87, 0x3b, 0x87, 0x9f, 0x88, 0x04,
690 0x88, 0x69, 0x88, 0xce, 0x89, 0x33, 0x89, 0x99, 0x89, 0xfe, 0x8a, 0x64,
691 0x8a, 0xca, 0x8b, 0x30, 0x8b, 0x96, 0x8b, 0xfc, 0x8c, 0x63, 0x8c, 0xca,
692 0x8d, 0x31, 0x8d, 0x98, 0x8d, 0xff, 0x8e, 0x66, 0x8e, 0xce, 0x8f, 0x36,
693 0x8f, 0x9e, 0x90, 0x06, 0x90, 0x6e, 0x90, 0xd6, 0x91, 0x3f, 0x91, 0xa8,
694 0x92, 0x11, 0x92, 0x7a, 0x92, 0xe3, 0x93, 0x4d, 0x93, 0xb6, 0x94, 0x20,
695 0x94, 0x8a, 0x94, 0xf4, 0x95, 0x5f, 0x95, 0xc9, 0x96, 0x34, 0x96, 0x9f,
696 0x97, 0x0a, 0x97, 0x75, 0x97, 0xe0, 0x98, 0x4c, 0x98, 0xb8, 0x99, 0x24,
697 0x99, 0x90, 0x99, 0xfc, 0x9a, 0x68, 0x9a, 0xd5, 0x9b, 0x42, 0x9b, 0xaf,
698 0x9c, 0x1c, 0x9c, 0x89, 0x9c, 0xf7, 0x9d, 0x64, 0x9d, 0xd2, 0x9e, 0x40,
699 0x9e, 0xae, 0x9f, 0x1d, 0x9f, 0x8b, 0x9f, 0xfa, 0xa0, 0x69, 0xa0, 0xd8,
700 0xa1, 0x47, 0xa1, 0xb6, 0xa2, 0x26, 0xa2, 0x96, 0xa3, 0x06, 0xa3, 0x76,
701 0xa3, 0xe6, 0xa4, 0x56, 0xa4, 0xc7, 0xa5, 0x38, 0xa5, 0xa9, 0xa6, 0x1a,
702 0xa6, 0x8b, 0xa6, 0xfd, 0xa7, 0x6e, 0xa7, 0xe0, 0xa8, 0x52, 0xa8, 0xc4,
703 0xa9, 0x37, 0xa9, 0xa9, 0xaa, 0x1c, 0xaa, 0x8f, 0xab, 0x02, 0xab, 0x75,
704 0xab, 0xe9, 0xac, 0x5c, 0xac, 0xd0, 0xad, 0x44, 0xad, 0xb8, 0xae, 0x2d,
705 0xae, 0xa1, 0xaf, 0x16, 0xaf, 0x8b, 0xb0, 0x00, 0xb0, 0x75, 0xb0, 0xea,
706 0xb1, 0x60, 0xb1, 0xd6, 0xb2, 0x4b, 0xb2, 0xc2, 0xb3, 0x38, 0xb3, 0xae,
707 0xb4, 0x25, 0xb4, 0x9c, 0xb5, 0x13, 0xb5, 0x8a, 0xb6, 0x01, 0xb6, 0x79,
708 0xb6, 0xf0, 0xb7, 0x68, 0xb7, 0xe0, 0xb8, 0x59, 0xb8, 0xd1, 0xb9, 0x4a,
709 0xb9, 0xc2, 0xba, 0x3b, 0xba, 0xb5, 0xbb, 0x2e, 0xbb, 0xa7, 0xbc, 0x21,
710 0xbc, 0x9b, 0xbd, 0x15, 0xbd, 0x8f, 0xbe, 0x0a, 0xbe, 0x84, 0xbe, 0xff,
711 0xbf, 0x7a, 0xbf, 0xf5, 0xc0, 0x70, 0xc0, 0xec, 0xc1, 0x67, 0xc1, 0xe3,
712 0xc2, 0x5f, 0xc2, 0xdb, 0xc3, 0x58, 0xc3, 0xd4, 0xc4, 0x51, 0xc4, 0xce,
713 0xc5, 0x4b, 0xc5, 0xc8, 0xc6, 0x46, 0xc6, 0xc3, 0xc7, 0x41, 0xc7, 0xbf,
714 0xc8, 0x3d, 0xc8, 0xbc, 0xc9, 0x3a, 0xc9, 0xb9, 0xca, 0x38, 0xca, 0xb7,
715 0xcb, 0x36, 0xcb, 0xb6, 0xcc, 0x35, 0xcc, 0xb5, 0xcd, 0x35, 0xcd, 0xb5,
716 0xce, 0x36, 0xce, 0xb6, 0xcf, 0x37, 0xcf, 0xb8, 0xd0, 0x39, 0xd0, 0xba,
717 0xd1, 0x3c, 0xd1, 0xbe, 0xd2, 0x3f, 0xd2, 0xc1, 0xd3, 0x44, 0xd3, 0xc6,
718 0xd4, 0x49, 0xd4, 0xcb, 0xd5, 0x4e, 0xd5, 0xd1, 0xd6, 0x55, 0xd6, 0xd8,
719 0xd7, 0x5c, 0xd7, 0xe0, 0xd8, 0x64, 0xd8, 0xe8, 0xd9, 0x6c, 0xd9, 0xf1,
720 0xda, 0x76, 0xda, 0xfb, 0xdb, 0x80, 0xdc, 0x05, 0xdc, 0x8a, 0xdd, 0x10,
721 0xdd, 0x96, 0xde, 0x1c, 0xde, 0xa2, 0xdf, 0x29, 0xdf, 0xaf, 0xe0, 0x36,
722 0xe0, 0xbd, 0xe1, 0x44, 0xe1, 0xcc, 0xe2, 0x53, 0xe2, 0xdb, 0xe3, 0x63,
723 0xe3, 0xeb, 0xe4, 0x73, 0xe4, 0xfc, 0xe5, 0x84, 0xe6, 0x0d, 0xe6, 0x96,
724 0xe7, 0x1f, 0xe7, 0xa9, 0xe8, 0x32, 0xe8, 0xbc, 0xe9, 0x46, 0xe9, 0xd0,
725 0xea, 0x5b, 0xea, 0xe5, 0xeb, 0x70, 0xeb, 0xfb, 0xec, 0x86, 0xed, 0x11,
726 0xed, 0x9c, 0xee, 0x28, 0xee, 0xb4, 0xef, 0x40, 0xef, 0xcc, 0xf0, 0x58,
727 0xf0, 0xe5, 0xf1, 0x72, 0xf1, 0xff, 0xf2, 0x8c, 0xf3, 0x19, 0xf3, 0xa7,
728 0xf4, 0x34, 0xf4, 0xc2, 0xf5, 0x50, 0xf5, 0xde, 0xf6, 0x6d, 0xf6, 0xfb,
729 0xf7, 0x8a, 0xf8, 0x19, 0xf8, 0xa8, 0xf9, 0x38, 0xf9, 0xc7, 0xfa, 0x57,
730 0xfa, 0xe7, 0xfb, 0x77, 0xfc, 0x07, 0xfc, 0x98, 0xfd, 0x29, 0xfd, 0xba,
731 0xfe, 0x4b, 0xfe, 0xdc, 0xff, 0x6d, 0xff, 0xff
740 assert(image != (Image *) NULL);
741 assert(image->signature == MagickCoreSignature);
742 if (GetImageProfile(image,"icc") != (const StringInfo *) NULL)
744 profile=AcquireStringInfo(sizeof(sRGBProfile));
745 SetStringInfoDatum(profile,sRGBProfile);
746 status=SetImageProfile(image,"icc",profile,exception);
747 profile=DestroyStringInfo(profile);
751 MagickExport MagickBooleanType ProfileImage(Image *image,const char *name,
752 const void *datum,const size_t length,ExceptionInfo *exception)
754 #define ProfileImageTag "Profile/Image"
755 #define ThrowProfileException(severity,tag,context) \
757 if (source_profile != (cmsHPROFILE) NULL) \
758 (void) cmsCloseProfile(source_profile); \
759 if (target_profile != (cmsHPROFILE) NULL) \
760 (void) cmsCloseProfile(target_profile); \
761 ThrowBinaryException(severity,tag,context); \
770 assert(image != (Image *) NULL);
771 assert(image->signature == MagickCoreSignature);
772 if (image->debug != MagickFalse)
773 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
774 assert(name != (const char *) NULL);
775 if ((datum == (const void *) NULL) || (length == 0))
781 Delete image profile(s).
783 ResetImageProfileIterator(image);
784 for (next=GetNextImageProfile(image); next != (const char *) NULL; )
786 if (IsOptionMember(next,name) != MagickFalse)
788 (void) DeleteImageProfile(image,next);
789 ResetImageProfileIterator(image);
791 next=GetNextImageProfile(image);
796 Add a ICC, IPTC, or generic profile to the image.
799 profile=AcquireStringInfo((size_t) length);
800 SetStringInfoDatum(profile,(unsigned char *) datum);
801 if ((LocaleCompare(name,"icc") != 0) && (LocaleCompare(name,"icm") != 0))
802 status=SetImageProfile(image,name,profile,exception);
808 icc_profile=GetImageProfile(image,"icc");
809 if ((icc_profile != (const StringInfo *) NULL) &&
810 (CompareStringInfo(icc_profile,profile) == 0))
815 value=GetImageProperty(image,"exif:ColorSpace",exception);
817 if (LocaleCompare(value,"1") != 0)
818 (void) SetsRGBImageProfile(image,exception);
819 value=GetImageProperty(image,"exif:InteroperabilityIndex",exception);
820 if (LocaleCompare(value,"R98.") != 0)
821 (void) SetsRGBImageProfile(image,exception);
823 value=GetImageProperty(image,"exif:InteroperabilityIndex",exception);
824 if (LocaleCompare(value,"R03.") != 0)
825 (void) SetAdobeRGB1998ImageProfile(image,exception);
827 icc_profile=GetImageProfile(image,"icc");
829 if ((icc_profile != (const StringInfo *) NULL) &&
830 (CompareStringInfo(icc_profile,profile) == 0))
832 profile=DestroyStringInfo(profile);
835 #if !defined(MAGICKCORE_LCMS_DELEGATE)
836 (void) ThrowMagickException(exception,GetMagickModule(),
837 MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn",
838 "'%s' (LCMS)",image->filename);
848 Transform pixel colors as defined by the color profiles.
850 cmsSetLogErrorHandler(CMSExceptionHandler);
851 cms_exception.image=image;
852 cms_exception.exception=exception;
853 (void) cms_exception;
854 source_profile=cmsOpenProfileFromMemTHR((cmsContext) &cms_exception,
855 GetStringInfoDatum(profile),(cmsUInt32Number)
856 GetStringInfoLength(profile));
857 if (source_profile == (cmsHPROFILE) NULL)
858 ThrowBinaryException(ResourceLimitError,
859 "ColorspaceColorProfileMismatch",name);
860 if ((cmsGetDeviceClass(source_profile) != cmsSigLinkClass) &&
861 (icc_profile == (StringInfo *) NULL))
862 status=SetImageProfile(image,name,profile,exception);
872 cmsColorSpaceSignature
879 *magick_restrict transform;
887 **magick_restrict source_pixels,
889 **magick_restrict target_pixels,
905 target_profile=(cmsHPROFILE) NULL;
906 if (icc_profile != (StringInfo *) NULL)
908 target_profile=source_profile;
909 source_profile=cmsOpenProfileFromMemTHR((cmsContext)
910 &cms_exception,GetStringInfoDatum(icc_profile),
911 (cmsUInt32Number) GetStringInfoLength(icc_profile));
912 if (source_profile == (cmsHPROFILE) NULL)
913 ThrowProfileException(ResourceLimitError,
914 "ColorspaceColorProfileMismatch",name);
918 switch (cmsGetColorSpace(source_profile))
922 source_colorspace=CMYKColorspace;
923 source_type=(cmsUInt32Number) TYPE_CMYK_DBL;
930 source_colorspace=GRAYColorspace;
931 source_type=(cmsUInt32Number) TYPE_GRAY_DBL;
937 source_colorspace=LabColorspace;
938 source_type=(cmsUInt32Number) TYPE_Lab_DBL;
945 source_colorspace=sRGBColorspace;
946 source_type=(cmsUInt32Number) TYPE_RGB_DBL;
951 source_colorspace=XYZColorspace;
952 source_type=(cmsUInt32Number) TYPE_XYZ_DBL;
957 source_colorspace=UndefinedColorspace;
958 source_type=(cmsUInt32Number) TYPE_RGB_DBL;
962 signature=cmsGetPCS(source_profile);
963 if (target_profile != (cmsHPROFILE) NULL)
964 signature=cmsGetColorSpace(target_profile);
971 target_colorspace=CMYKColorspace;
972 target_type=(cmsUInt32Number) TYPE_CMYK_DBL;
979 target_colorspace=LabColorspace;
980 target_type=(cmsUInt32Number) TYPE_Lab_DBL;
986 target_colorspace=GRAYColorspace;
987 target_type=(cmsUInt32Number) TYPE_GRAY_DBL;
993 target_colorspace=sRGBColorspace;
994 target_type=(cmsUInt32Number) TYPE_RGB_DBL;
999 target_colorspace=XYZColorspace;
1000 target_type=(cmsUInt32Number) TYPE_XYZ_DBL;
1005 target_colorspace=UndefinedColorspace;
1006 target_type=(cmsUInt32Number) TYPE_RGB_DBL;
1010 if ((source_colorspace == UndefinedColorspace) ||
1011 (target_colorspace == UndefinedColorspace))
1012 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1014 if ((source_colorspace == GRAYColorspace) &&
1015 (SetImageGray(image,exception) == MagickFalse))
1016 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1018 if ((source_colorspace == CMYKColorspace) &&
1019 (image->colorspace != CMYKColorspace))
1020 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1022 if ((source_colorspace == XYZColorspace) &&
1023 (image->colorspace != XYZColorspace))
1024 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1026 if ((source_colorspace == YCbCrColorspace) &&
1027 (image->colorspace != YCbCrColorspace))
1028 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1030 if ((source_colorspace != CMYKColorspace) &&
1031 (source_colorspace != LabColorspace) &&
1032 (source_colorspace != XYZColorspace) &&
1033 (source_colorspace != YCbCrColorspace) &&
1034 (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse))
1035 ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1037 switch (image->rendering_intent)
1039 case AbsoluteIntent: intent=INTENT_ABSOLUTE_COLORIMETRIC; break;
1040 case PerceptualIntent: intent=INTENT_PERCEPTUAL; break;
1041 case RelativeIntent: intent=INTENT_RELATIVE_COLORIMETRIC; break;
1042 case SaturationIntent: intent=INTENT_SATURATION; break;
1043 default: intent=INTENT_PERCEPTUAL; break;
1045 flags=cmsFLAGS_HIGHRESPRECALC;
1046 #if defined(cmsFLAGS_BLACKPOINTCOMPENSATION)
1047 if (image->black_point_compensation != MagickFalse)
1048 flags|=cmsFLAGS_BLACKPOINTCOMPENSATION;
1050 transform=AcquireTransformThreadSet(image,source_profile,
1051 source_type,target_profile,target_type,intent,flags);
1052 if (transform == (cmsHTRANSFORM *) NULL)
1053 ThrowProfileException(ImageError,"UnableToCreateColorTransform",
1056 Transform image as dictated by the source & target image profiles.
1058 source_pixels=AcquirePixelThreadSet(image->columns,source_channels);
1059 target_pixels=AcquirePixelThreadSet(image->columns,target_channels);
1060 if ((source_pixels == (double **) NULL) ||
1061 (target_pixels == (double **) NULL))
1063 transform=DestroyTransformThreadSet(transform);
1064 ThrowProfileException(ResourceLimitError,
1065 "MemoryAllocationFailed",image->filename);
1067 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1069 target_pixels=DestroyPixelThreadSet(target_pixels);
1070 source_pixels=DestroyPixelThreadSet(source_pixels);
1071 transform=DestroyTransformThreadSet(transform);
1072 if (source_profile != (cmsHPROFILE) NULL)
1073 (void) cmsCloseProfile(source_profile);
1074 if (target_profile != (cmsHPROFILE) NULL)
1075 (void) cmsCloseProfile(target_profile);
1076 return(MagickFalse);
1078 if (target_colorspace == CMYKColorspace)
1079 (void) SetImageColorspace(image,target_colorspace,exception);
1081 image_view=AcquireAuthenticCacheView(image,exception);
1082 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1083 #pragma omp parallel for schedule(static,4) shared(status) \
1084 magick_number_threads(image,image,image->rows,1)
1086 for (y=0; y < (ssize_t) image->rows; y++)
1089 id = GetOpenMPThreadId();
1103 if (status == MagickFalse)
1105 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1107 if (q == (Quantum *) NULL)
1112 p=source_pixels[id];
1113 for (x=0; x < (ssize_t) image->columns; x++)
1115 *p++=source_scale*QuantumScale*GetPixelRed(image,q);
1116 if (source_channels > 1)
1118 *p++=source_scale*QuantumScale*GetPixelGreen(image,q);
1119 *p++=source_scale*QuantumScale*GetPixelBlue(image,q);
1121 if (source_channels > 3)
1122 *p++=source_scale*QuantumScale*GetPixelBlack(image,q);
1123 q+=GetPixelChannels(image);
1125 cmsDoTransform(transform[id],source_pixels[id],target_pixels[id],
1126 (unsigned int) image->columns);
1127 p=target_pixels[id];
1128 q-=GetPixelChannels(image)*image->columns;
1129 for (x=0; x < (ssize_t) image->columns; x++)
1131 if (target_channels == 1)
1132 SetPixelGray(image,target_scale*QuantumRange*(*p),q);
1134 SetPixelRed(image,target_scale*QuantumRange*(*p),q);
1136 if (target_channels > 1)
1138 SetPixelGreen(image,target_scale*QuantumRange*(*p),q);
1140 SetPixelBlue(image,target_scale*QuantumRange*(*p),q);
1143 if (target_channels > 3)
1145 SetPixelBlack(image,target_scale*QuantumRange*(*p),q);
1148 q+=GetPixelChannels(image);
1150 sync=SyncCacheViewAuthenticPixels(image_view,exception);
1151 if (sync == MagickFalse)
1153 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1158 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1159 #pragma omp critical (MagickCore_ProfileImage)
1161 proceed=SetImageProgress(image,ProfileImageTag,progress++,
1163 if (proceed == MagickFalse)
1167 image_view=DestroyCacheView(image_view);
1168 (void) SetImageColorspace(image,target_colorspace,exception);
1173 image->type=image->alpha_trait == UndefinedPixelTrait ?
1174 TrueColorType : TrueColorAlphaType;
1177 case cmsSigCmykData:
1179 image->type=image->alpha_trait == UndefinedPixelTrait ?
1180 ColorSeparationType : ColorSeparationAlphaType;
1183 case cmsSigGrayData:
1185 image->type=image->alpha_trait == UndefinedPixelTrait ?
1186 GrayscaleType : GrayscaleAlphaType;
1192 target_pixels=DestroyPixelThreadSet(target_pixels);
1193 source_pixels=DestroyPixelThreadSet(source_pixels);
1194 transform=DestroyTransformThreadSet(transform);
1195 if ((status != MagickFalse) &&
1196 (cmsGetDeviceClass(source_profile) != cmsSigLinkClass))
1197 status=SetImageProfile(image,name,profile,exception);
1198 if (target_profile != (cmsHPROFILE) NULL)
1199 (void) cmsCloseProfile(target_profile);
1201 (void) cmsCloseProfile(source_profile);
1205 profile=DestroyStringInfo(profile);
1210 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1214 % R e m o v e I m a g e P r o f i l e %
1218 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1220 % RemoveImageProfile() removes a named profile from the image and returns its
1223 % The format of the RemoveImageProfile method is:
1225 % void *RemoveImageProfile(Image *image,const char *name)
1227 % A description of each parameter follows:
1229 % o image: the image.
1231 % o name: the profile name.
1234 MagickExport StringInfo *RemoveImageProfile(Image *image,const char *name)
1239 assert(image != (Image *) NULL);
1240 assert(image->signature == MagickCoreSignature);
1241 if (image->debug != MagickFalse)
1242 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1243 if (image->profiles == (SplayTreeInfo *) NULL)
1244 return((StringInfo *) NULL);
1245 WriteTo8BimProfile(image,name,(StringInfo *) NULL);
1246 profile=(StringInfo *) RemoveNodeFromSplayTree((SplayTreeInfo *)
1247 image->profiles,name);
1252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1256 % R e s e t P r o f i l e I t e r a t o r %
1260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1262 % ResetImageProfileIterator() resets the image profile iterator. Use it in
1263 % conjunction with GetNextImageProfile() to iterate over all the profiles
1264 % associated with an image.
1266 % The format of the ResetImageProfileIterator method is:
1268 % ResetImageProfileIterator(Image *image)
1270 % A description of each parameter follows:
1272 % o image: the image.
1275 MagickExport void ResetImageProfileIterator(const Image *image)
1277 assert(image != (Image *) NULL);
1278 assert(image->signature == MagickCoreSignature);
1279 if (image->debug != MagickFalse)
1280 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1281 if (image->profiles == (SplayTreeInfo *) NULL)
1283 ResetSplayTreeIterator((SplayTreeInfo *) image->profiles);
1287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1291 % S e t I m a g e P r o f i l e %
1295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1297 % SetImageProfile() adds a named profile to the image. If a profile with the
1298 % same name already exists, it is replaced. This method differs from the
1299 % ProfileImage() method in that it does not apply CMS color profiles.
1301 % The format of the SetImageProfile method is:
1303 % MagickBooleanType SetImageProfile(Image *image,const char *name,
1304 % const StringInfo *profile)
1306 % A description of each parameter follows:
1308 % o image: the image.
1310 % o name: the profile name, for example icc, exif, and 8bim (8bim is the
1311 % Photoshop wrapper for iptc profiles).
1313 % o profile: A StringInfo structure that contains the named profile.
1317 static void *DestroyProfile(void *profile)
1319 return((void *) DestroyStringInfo((StringInfo *) profile));
1322 static inline const unsigned char *ReadResourceByte(const unsigned char *p,
1323 unsigned char *quantum)
1329 static inline const unsigned char *ReadResourceLong(const unsigned char *p,
1330 unsigned int *quantum)
1332 *quantum=(unsigned int) (*p++) << 24;
1333 *quantum|=(unsigned int) (*p++) << 16;
1334 *quantum|=(unsigned int) (*p++) << 8;
1335 *quantum|=(unsigned int) (*p++);
1339 static inline const unsigned char *ReadResourceShort(const unsigned char *p,
1340 unsigned short *quantum)
1342 *quantum=(unsigned short) (*p++) << 8;
1343 *quantum|=(unsigned short) (*p++);
1347 static inline void WriteResourceLong(unsigned char *p,
1348 const unsigned int quantum)
1353 buffer[0]=(unsigned char) (quantum >> 24);
1354 buffer[1]=(unsigned char) (quantum >> 16);
1355 buffer[2]=(unsigned char) (quantum >> 8);
1356 buffer[3]=(unsigned char) quantum;
1357 (void) CopyMagickMemory(p,buffer,4);
1360 static void WriteTo8BimProfile(Image *image,const char *name,
1361 const StringInfo *profile)
1367 register const unsigned char
1389 if (LocaleCompare(name,"icc") == 0)
1392 if (LocaleCompare(name,"iptc") == 0)
1395 if (LocaleCompare(name,"xmp") == 0)
1399 profile_8bim=(StringInfo *) GetValueFromSplayTree((SplayTreeInfo *)
1400 image->profiles,"8bim");
1401 if (profile_8bim == (StringInfo *) NULL)
1403 datum=GetStringInfoDatum(profile_8bim);
1404 length=GetStringInfoLength(profile_8bim);
1405 for (p=datum; p < (datum+length-16); )
1408 if (LocaleNCompare((char *) p,"8BIM",4) != 0)
1411 p=ReadResourceShort(p,&id);
1412 p=ReadResourceByte(p,&length_byte);
1414 if (((length_byte+1) & 0x01) != 0)
1416 if (p > (datum+length-4))
1418 p=ReadResourceLong(p,&value);
1419 count=(ssize_t) value;
1420 if ((count & 0x01) != 0)
1422 if ((count < 0) || (p > (datum+length-count)) ||
1423 (count > (ssize_t) length))
1425 if (id != profile_id)
1440 extent=(datum+length)-(p+count);
1441 if (profile == (StringInfo *) NULL)
1444 extract_profile=AcquireStringInfo(offset+extent);
1445 (void) CopyMagickMemory(extract_profile->datum,datum,offset);
1450 extract_extent=profile->length;
1451 if ((extract_extent & 0x01) != 0)
1453 extract_profile=AcquireStringInfo(offset+extract_extent+extent);
1454 (void) CopyMagickMemory(extract_profile->datum,datum,offset-4);
1455 WriteResourceLong(extract_profile->datum+offset-4,(unsigned int)
1457 (void) CopyMagickMemory(extract_profile->datum+offset,
1458 profile->datum,profile->length);
1460 (void) CopyMagickMemory(extract_profile->datum+offset+extract_extent,
1462 (void) AddValueToSplayTree((SplayTreeInfo *) image->profiles,
1463 ConstantString("8bim"),CloneStringInfo(extract_profile));
1464 extract_profile=DestroyStringInfo(extract_profile);
1470 static void GetProfilesFromResourceBlock(Image *image,
1471 const StringInfo *resource_block,ExceptionInfo *exception)
1476 register const unsigned char
1497 datum=GetStringInfoDatum(resource_block);
1498 length=GetStringInfoLength(resource_block);
1499 for (p=datum; p < (datum+length-16); )
1501 if (LocaleNCompare((char *) p,"8BIM",4) != 0)
1504 p=ReadResourceShort(p,&id);
1505 p=ReadResourceByte(p,&length_byte);
1507 if (((length_byte+1) & 0x01) != 0)
1509 if (p > (datum+length-4))
1511 p=ReadResourceLong(p,&value);
1512 count=(ssize_t) value;
1513 if ((p > (datum+length-count)) || (count > (ssize_t) length) ||
1529 p=ReadResourceLong(p,&resolution);
1530 image->resolution.x=((double) resolution)/65536.0;
1531 p=ReadResourceShort(p,&units)+2;
1532 p=ReadResourceLong(p,&resolution)+4;
1533 image->resolution.y=((double) resolution)/65536.0;
1535 Values are always stored as pixels per inch.
1537 if ((ResolutionType) units != PixelsPerCentimeterResolution)
1538 image->units=PixelsPerInchResolution;
1541 image->units=PixelsPerCentimeterResolution;
1542 image->resolution.x/=2.54;
1543 image->resolution.y/=2.54;
1552 profile=AcquireStringInfo(count);
1553 SetStringInfoDatum(profile,p);
1554 (void) SetImageProfileInternal(image,"iptc",profile,MagickTrue,
1556 profile=DestroyStringInfo(profile);
1573 profile=AcquireStringInfo(count);
1574 SetStringInfoDatum(profile,p);
1575 (void) SetImageProfileInternal(image,"icc",profile,MagickTrue,
1577 profile=DestroyStringInfo(profile);
1586 profile=AcquireStringInfo(count);
1587 SetStringInfoDatum(profile,p);
1588 (void) SetImageProfileInternal(image,"exif",profile,MagickTrue,
1590 profile=DestroyStringInfo(profile);
1599 profile=AcquireStringInfo(count);
1600 SetStringInfoDatum(profile,p);
1601 (void) SetImageProfileInternal(image,"xmp",profile,MagickTrue,
1603 profile=DestroyStringInfo(profile);
1613 if ((count & 0x01) != 0)
1618 static MagickBooleanType SetImageProfileInternal(Image *image,const char *name,
1619 const StringInfo *profile,const MagickBooleanType recursive,
1620 ExceptionInfo *exception)
1623 key[MagickPathExtent],
1624 property[MagickPathExtent];
1629 assert(image != (Image *) NULL);
1630 assert(image->signature == MagickCoreSignature);
1631 if (image->debug != MagickFalse)
1632 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1633 if (image->profiles == (SplayTreeInfo *) NULL)
1634 image->profiles=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
1636 (void) CopyMagickString(key,name,MagickPathExtent);
1638 status=AddValueToSplayTree((SplayTreeInfo *) image->profiles,
1639 ConstantString(key),CloneStringInfo(profile));
1640 if (status != MagickFalse)
1642 if (LocaleCompare(name,"8bim") == 0)
1643 GetProfilesFromResourceBlock(image,profile,exception);
1645 if (recursive == MagickFalse)
1646 WriteTo8BimProfile(image,name,profile);
1649 Inject profile into image properties.
1651 (void) FormatLocaleString(property,MagickPathExtent,"%s:*",name);
1652 (void) GetImageProperty(image,property,exception);
1656 MagickExport MagickBooleanType SetImageProfile(Image *image,const char *name,
1657 const StringInfo *profile,ExceptionInfo *exception)
1659 return(SetImageProfileInternal(image,name,profile,MagickFalse,exception));
1663 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1667 % S y n c I m a g e P r o f i l e s %
1671 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1673 % SyncImageProfiles() synchronizes image properties with the image profiles.
1674 % Currently we only support updating the EXIF resolution and orientation.
1676 % The format of the SyncImageProfiles method is:
1678 % MagickBooleanType SyncImageProfiles(Image *image)
1680 % A description of each parameter follows:
1682 % o image: the image.
1686 static inline int ReadProfileByte(unsigned char **p,size_t *length)
1698 static inline signed short ReadProfileShort(const EndianType endian,
1699 unsigned char *buffer)
1713 if (endian == LSBEndian)
1715 value=(unsigned short) buffer[1] << 8;
1716 value|=(unsigned short) buffer[0];
1717 quantum.unsigned_value=value & 0xffff;
1718 return(quantum.signed_value);
1720 value=(unsigned short) buffer[0] << 8;
1721 value|=(unsigned short) buffer[1];
1722 quantum.unsigned_value=value & 0xffff;
1723 return(quantum.signed_value);
1726 static inline signed int ReadProfileLong(const EndianType endian,
1727 unsigned char *buffer)
1741 if (endian == LSBEndian)
1743 value=(unsigned int) buffer[3] << 24;
1744 value|=(unsigned int) buffer[2] << 16;
1745 value|=(unsigned int) buffer[1] << 8;
1746 value|=(unsigned int) buffer[0];
1747 quantum.unsigned_value=value & 0xffffffff;
1748 return(quantum.signed_value);
1750 value=(unsigned int) buffer[0] << 24;
1751 value|=(unsigned int) buffer[1] << 16;
1752 value|=(unsigned int) buffer[2] << 8;
1753 value|=(unsigned int) buffer[3];
1754 quantum.unsigned_value=value & 0xffffffff;
1755 return(quantum.signed_value);
1758 static inline signed int ReadProfileMSBLong(unsigned char **p,size_t *length)
1765 value=ReadProfileLong(MSBEndian,*p);
1771 static inline signed short ReadProfileMSBShort(unsigned char **p,
1779 value=ReadProfileShort(MSBEndian,*p);
1785 static inline void WriteProfileLong(const EndianType endian,
1786 const size_t value,unsigned char *p)
1791 if (endian == LSBEndian)
1793 buffer[0]=(unsigned char) value;
1794 buffer[1]=(unsigned char) (value >> 8);
1795 buffer[2]=(unsigned char) (value >> 16);
1796 buffer[3]=(unsigned char) (value >> 24);
1797 (void) CopyMagickMemory(p,buffer,4);
1800 buffer[0]=(unsigned char) (value >> 24);
1801 buffer[1]=(unsigned char) (value >> 16);
1802 buffer[2]=(unsigned char) (value >> 8);
1803 buffer[3]=(unsigned char) value;
1804 (void) CopyMagickMemory(p,buffer,4);
1807 static void WriteProfileShort(const EndianType endian,
1808 const unsigned short value,unsigned char *p)
1813 if (endian == LSBEndian)
1815 buffer[0]=(unsigned char) value;
1816 buffer[1]=(unsigned char) (value >> 8);
1817 (void) CopyMagickMemory(p,buffer,2);
1820 buffer[0]=(unsigned char) (value >> 8);
1821 buffer[1]=(unsigned char) value;
1822 (void) CopyMagickMemory(p,buffer,2);
1825 static MagickBooleanType Sync8BimProfile(Image *image,StringInfo *profile)
1839 length=GetStringInfoLength(profile);
1840 p=GetStringInfoDatum(profile);
1843 if (ReadProfileByte(&p,&length) != 0x38)
1845 if (ReadProfileByte(&p,&length) != 0x42)
1847 if (ReadProfileByte(&p,&length) != 0x49)
1849 if (ReadProfileByte(&p,&length) != 0x4D)
1852 return(MagickFalse);
1853 id=ReadProfileMSBShort(&p,&length);
1854 count=(ssize_t) ReadProfileByte(&p,&length);
1855 if ((count > (ssize_t) length) || (count < 0))
1856 return(MagickFalse);
1858 if ((*p & 0x01) == 0)
1859 (void) ReadProfileByte(&p,&length);
1860 count=(ssize_t) ReadProfileMSBLong(&p,&length);
1861 if ((count > (ssize_t) length) || (count < 0))
1862 return(MagickFalse);
1863 if ((id == 0x3ED) && (count == 16))
1865 if (image->units == PixelsPerCentimeterResolution)
1866 WriteProfileLong(MSBEndian,(unsigned int) (image->resolution.x*2.54*
1869 WriteProfileLong(MSBEndian,(unsigned int) (image->resolution.x*
1871 WriteProfileShort(MSBEndian,(unsigned short) image->units,p+4);
1872 if (image->units == PixelsPerCentimeterResolution)
1873 WriteProfileLong(MSBEndian,(unsigned int) (image->resolution.y*2.54*
1876 WriteProfileLong(MSBEndian,(unsigned int) (image->resolution.y*
1878 WriteProfileShort(MSBEndian,(unsigned short) image->units,p+12);
1886 MagickBooleanType SyncExifProfile(Image *image,StringInfo *profile)
1888 #define MaxDirectoryStack 16
1889 #define EXIF_DELIMITER "\n"
1890 #define EXIF_NUM_FORMATS 12
1891 #define TAG_EXIF_OFFSET 0x8769
1892 #define TAG_INTEROP_OFFSET 0xa005
1894 typedef struct _DirectoryInfo
1904 directory_stack[MaxDirectoryStack];
1923 format_bytes[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
1930 Set EXIF resolution tag.
1932 length=GetStringInfoLength(profile);
1933 exif=GetStringInfoDatum(profile);
1935 return(MagickFalse);
1936 id=(ssize_t) ReadProfileShort(LSBEndian,exif);
1937 if ((id != 0x4949) && (id != 0x4D4D))
1941 if (ReadProfileByte(&exif,&length) != 0x45)
1943 if (ReadProfileByte(&exif,&length) != 0x78)
1945 if (ReadProfileByte(&exif,&length) != 0x69)
1947 if (ReadProfileByte(&exif,&length) != 0x66)
1949 if (ReadProfileByte(&exif,&length) != 0x00)
1951 if (ReadProfileByte(&exif,&length) != 0x00)
1956 return(MagickFalse);
1957 id=(ssize_t) ReadProfileShort(LSBEndian,exif);
1966 return(MagickFalse);
1967 if (ReadProfileShort(endian,exif+2) != 0x002a)
1968 return(MagickFalse);
1970 This the offset to the first IFD.
1972 offset=(ssize_t) ReadProfileLong(endian,exif+4);
1973 if ((offset < 0) || ((size_t) offset >= length))
1974 return(MagickFalse);
1975 directory=exif+offset;
1978 exif_resources=NewSplayTree((int (*)(const void *,const void *)) NULL,
1979 (void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
1985 directory=directory_stack[level].directory;
1986 entry=directory_stack[level].entry;
1988 if ((directory < exif) || (directory > (exif+length-2)))
1991 Determine how many entries there are in the current IFD.
1993 number_entries=ReadProfileShort(endian,directory);
1994 for ( ; entry < number_entries; entry++)
1999 register unsigned char
2010 q=(unsigned char *) (directory+2+(12*entry));
2011 if (q > (exif+length-12))
2012 break; /* corrupt EXIF */
2013 if (GetValueFromSplayTree(exif_resources,q) == q)
2015 (void) AddValueToSplayTree(exif_resources,q,q);
2016 tag_value=(ssize_t) ReadProfileShort(endian,q);
2017 format=(ssize_t) ReadProfileShort(endian,q+2);
2018 if ((format < 0) || ((format-1) >= EXIF_NUM_FORMATS))
2020 components=(int) ReadProfileLong(endian,q+4);
2022 break; /* corrupt EXIF */
2023 number_bytes=(size_t) components*format_bytes[format];
2024 if ((ssize_t) number_bytes < components)
2025 break; /* prevent overflow */
2026 if (number_bytes <= 4)
2031 The directory entry contains an offset.
2033 offset=(ssize_t) ReadProfileLong(endian,q+8);
2034 if ((offset < 0) || ((size_t) (offset+number_bytes) > length))
2036 if (~length < number_bytes)
2037 continue; /* prevent overflow */
2038 p=(unsigned char *) (exif+offset);
2044 (void) WriteProfileLong(endian,(size_t) (image->resolution.x+0.5),p);
2045 (void) WriteProfileLong(endian,1UL,p+4);
2050 (void) WriteProfileLong(endian,(size_t) (image->resolution.y+0.5),p);
2051 (void) WriteProfileLong(endian,1UL,p+4);
2056 if (number_bytes == 4)
2058 (void) WriteProfileLong(endian,(size_t) image->orientation,p);
2061 (void) WriteProfileShort(endian,(unsigned short) image->orientation,
2067 if (number_bytes == 4)
2069 (void) WriteProfileLong(endian,(size_t) (image->units+1),p);
2072 (void) WriteProfileShort(endian,(unsigned short) (image->units+1),p);
2078 if ((tag_value == TAG_EXIF_OFFSET) || (tag_value == TAG_INTEROP_OFFSET))
2080 offset=(ssize_t) ReadProfileLong(endian,p);
2081 if (((size_t) offset < length) && (level < (MaxDirectoryStack-2)))
2083 directory_stack[level].directory=directory;
2085 directory_stack[level].entry=entry;
2087 directory_stack[level].directory=exif+offset;
2088 directory_stack[level].entry=0;
2090 if ((directory+2+(12*number_entries)) > (exif+length))
2092 offset=(ssize_t) ReadProfileLong(endian,directory+2+(12*
2094 if ((offset != 0) && ((size_t) offset < length) &&
2095 (level < (MaxDirectoryStack-2)))
2097 directory_stack[level].directory=exif+offset;
2098 directory_stack[level].entry=0;
2105 } while (level > 0);
2106 exif_resources=DestroySplayTree(exif_resources);
2110 MagickPrivate MagickBooleanType SyncImageProfiles(Image *image)
2119 profile=(StringInfo *) GetImageProfile(image,"8BIM");
2120 if (profile != (StringInfo *) NULL)
2121 if (Sync8BimProfile(image,profile) == MagickFalse)
2123 profile=(StringInfo *) GetImageProfile(image,"EXIF");
2124 if (profile != (StringInfo *) NULL)
2125 if (SyncExifProfile(image,profile) == MagickFalse)