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