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