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