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