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