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