source: ImageMagick/trunk/magick/profile.c @ 4289

Revision 4289, 77.6 KB checked in by cristy, 2 years ago (diff)
Line 
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%               PPPP   RRRR    OOO   FFFFF  IIIII  L      EEEEE               %
7%               P   P  R   R  O   O  F        I    L      E                   %
8%               PPPP   RRRR   O   O  FFF      I    L      EEE                 %
9%               P      R R    O   O  F        I    L      E                   %
10%               P      R  R    OOO   F      IIIII  LLLLL  EEEEE               %
11%                                                                             %
12%                                                                             %
13%                       MagickCore Image Profile Methods                      %
14%                                                                             %
15%                              Software Design                                %
16%                                John Cristy                                  %
17%                                 July 1992                                   %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
21%  dedicated to making software imaging solutions freely available.           %
22%                                                                             %
23%  You may not use this file except in compliance with the License.  You may  %
24%  obtain a copy of the License at                                            %
25%                                                                             %
26%    http://www.imagemagick.org/script/license.php                            %
27%                                                                             %
28%  Unless required by applicable law or agreed to in writing, software        %
29%  distributed under the License is distributed on an "AS IS" BASIS,          %
30%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31%  See the License for the specific language governing permissions and        %
32%  limitations under the License.                                             %
33%                                                                             %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37*/
38
39/*
40  Include declarations.
41*/
42#include "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)
64#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)
71#include <lcms/lcms.h>
72#else
73#include "lcms.h"
74#endif
75#endif
76
77/*
78  Define declarations.
79*/
80#if !defined(LCMS_VERSION) || (LCMS_VERSION < 2000)
81#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
88#define cmsSigLinkClass icSigLinkClass
89#define cmsColorSpaceSignature icColorSpaceSignature
90#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)
97#endif
98
99/*
100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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*/
167MagickExport MagickBooleanType DeleteImageProfile(Image *image,const char *name)
168{
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{
345  register ssize_t
346    i;
347
348  assert(pixels != (unsigned short **) NULL);
349  for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
350    if (pixels[i] != (unsigned short *) NULL)
351      pixels[i]=(unsigned short *) RelinquishMagickMemory(pixels[i]);
352  pixels=(unsigned short **) RelinquishMagickMemory(pixels);
353  return(pixels);
354}
355
356static unsigned short **AcquirePixelThreadSet(const size_t columns,
357  const size_t channels)
358{
359  register ssize_t
360    i;
361
362  unsigned short
363    **pixels;
364
365  size_t
366    number_threads;
367
368  number_threads=GetOpenMPMaximumThreads();
369  pixels=(unsigned short **) AcquireQuantumMemory(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));
374  for (i=0; i < (ssize_t) number_threads; i++)
375  {
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{
386  register ssize_t
387    i;
388
389  assert(transform != (cmsHTRANSFORM *) NULL);
390  for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
391    if (transform[i] != (cmsHTRANSFORM) NULL)
392      cmsDeleteTransform(transform[i]);
393  transform=(cmsHTRANSFORM *) RelinquishMagickMemory(transform);
394  return(transform);
395}
396
397static cmsHTRANSFORM *AcquireTransformThreadSet(Image *image,
398  const cmsHPROFILE source_profile,const cmsUInt32Number source_type,
399  const cmsHPROFILE target_profile,const cmsUInt32Number target_type,
400  const int intent,const cmsUInt32Number flags)
401{
402  cmsHTRANSFORM
403    *transform;
404
405  register ssize_t
406    i;
407
408  size_t
409    number_threads;
410
411  number_threads=GetOpenMPMaximumThreads();
412  transform=(cmsHTRANSFORM *) AcquireQuantumMemory(number_threads,
413    sizeof(*transform));
414  if (transform == (cmsHTRANSFORM *) NULL)
415    return((cmsHTRANSFORM *) NULL);
416  (void) ResetMagickMemory(transform,0,number_threads*sizeof(*transform));
417  for (i=0; i < (ssize_t) number_threads; i++)
418  {
419    transform[i]=cmsCreateTransformTHR(image,source_profile,source_type,
420      target_profile,target_type,intent,flags);
421    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)
813#if defined(LCMS_VERSION) && (LCMS_VERSION >= 2000)
814static void LCMSExceptionHandler(cmsContext context,cmsUInt32Number severity,
815  const char *message)
816{
817  Image
818    *image;
819
820  (void) LogMagickEvent(TransformEvent,GetMagickModule(),"lcms: #%u, %s",
821    severity,message != (char *) NULL ? message : "no message");
822  image=(Image *) context;
823  if (image != (Image *) NULL)
824    (void) ThrowMagickException(&image->exception,GetMagickModule(),
825      ImageWarning,"UnableToTransformColorspace","`%s'",image->filename);
826
827}
828#else
829static int LCMSExceptionHandler(int severity,const char *message)
830{
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{ \
845  if (source_profile != (cmsHPROFILE) NULL) \
846    (void) cmsCloseProfile(source_profile); \
847  if (target_profile != (cmsHPROFILE) NULL) \
848    (void) cmsCloseProfile(target_profile); \
849  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
872      register ssize_t
873        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      {
887        for (i=1; i < (ssize_t) number_arguments; i++)
888        {
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      }
901      for (i=0; i < (ssize_t) number_arguments; i++)
902        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  */
909  status=MagickTrue;
910  profile=AcquireStringInfo((size_t) length);
911  SetStringInfoDatum(profile,(unsigned char *) datum);
912  if ((LocaleCompare(name,"icc") != 0) && (LocaleCompare(name,"icm") != 0))
913    status=SetImageProfile(image,name,profile);
914  else
915    {
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
948      {
949        cmsHPROFILE
950          source_profile;
951
952        /*
953          Transform pixel colors as defined by the color profiles.
954        */
955        cmsSetLogErrorHandler(LCMSExceptionHandler);
956        source_profile=cmsOpenProfileFromMemTHR(image,
957          GetStringInfoDatum(profile),(cmsUInt32Number)
958          GetStringInfoLength(profile));
959        if (source_profile == (cmsHPROFILE) NULL)
960          ThrowBinaryException(ResourceLimitError,
961            "ColorspaceColorProfileMismatch",name);
962        if ((cmsGetDeviceClass(source_profile) != cmsSigLinkClass) &&
963            (icc_profile == (StringInfo *) NULL))
964          status=SetImageProfile(image,name,profile);
965        else
966          {
967            CacheView
968              *image_view;
969
970            ColorspaceType
971              source_colorspace,
972              target_colorspace;
973
974            cmsColorSpaceSignature
975              signature;
976
977            cmsHPROFILE
978              target_profile;
979
980            cmsHTRANSFORM
981              *restrict transform;
982
983            cmsUInt32Number
984              flags,
985              source_type,
986              target_type;
987
988            ExceptionInfo
989              *exception;
990
991            int
992              intent;
993
994            MagickBooleanType
995              status;
996
997            MagickOffsetType
998              progress;
999
1000            size_t
1001              source_channels,
1002              target_channels;
1003
1004            ssize_t
1005              y;
1006
1007            unsigned short
1008              **restrict source_pixels,
1009              **restrict target_pixels;
1010
1011            exception=(&image->exception);
1012            target_profile=(cmsHPROFILE) NULL;
1013            if (icc_profile != (StringInfo *) NULL)
1014              {
1015                target_profile=source_profile;
1016                source_profile=cmsOpenProfileFromMemTHR(image,
1017                  GetStringInfoDatum(icc_profile),(cmsUInt32Number)
1018                  GetStringInfoLength(icc_profile));
1019                if (source_profile == (cmsHPROFILE) NULL)
1020                  ThrowProfileException(ResourceLimitError,
1021                    "ColorspaceColorProfileMismatch",name);
1022              }
1023            switch (cmsGetColorSpace(source_profile))
1024            {
1025              case cmsSigCmykData:
1026              {
1027                source_colorspace=CMYKColorspace;
1028                source_type=(cmsUInt32Number) TYPE_CMYK_16;
1029                source_channels=4;
1030                break;
1031              }
1032              case cmsSigGrayData:
1033              {
1034                source_colorspace=GRAYColorspace;
1035                source_type=(cmsUInt32Number) TYPE_GRAY_16;
1036                source_channels=1;
1037                break;
1038              }
1039              case cmsSigLabData:
1040              {
1041                source_colorspace=LabColorspace;
1042                source_type=(cmsUInt32Number) TYPE_Lab_16;
1043                source_channels=3;
1044                break;
1045              }
1046              case cmsSigLuvData:
1047              {
1048                source_colorspace=YUVColorspace;
1049                source_type=(cmsUInt32Number) TYPE_YUV_16;
1050                source_channels=3;
1051                break;
1052              }
1053              case cmsSigRgbData:
1054              {
1055                source_colorspace=RGBColorspace;
1056                source_type=(cmsUInt32Number) TYPE_RGB_16;
1057                source_channels=3;
1058                break;
1059              }
1060              case cmsSigXYZData:
1061              {
1062                source_colorspace=XYZColorspace;
1063                source_type=(cmsUInt32Number) TYPE_XYZ_16;
1064                source_channels=3;
1065                break;
1066              }
1067              case cmsSigYCbCrData:
1068              {
1069                source_colorspace=YCbCrColorspace;
1070                source_type=(cmsUInt32Number) TYPE_YCbCr_16;
1071                source_channels=3;
1072                break;
1073              }
1074              default:
1075              {
1076                source_colorspace=UndefinedColorspace;
1077                source_type=(cmsUInt32Number) TYPE_RGB_16;
1078                source_channels=3;
1079                break;
1080              }
1081            }
1082            signature=cmsGetPCS(source_profile);
1083            if (target_profile != (cmsHPROFILE) NULL)
1084              signature=cmsGetColorSpace(target_profile);
1085            switch (signature)
1086            {
1087              case cmsSigCmykData:
1088              {
1089                target_colorspace=CMYKColorspace;
1090                target_type=(cmsUInt32Number) TYPE_CMYK_16;
1091                target_channels=4;
1092                break;
1093              }
1094              case cmsSigLabData:
1095              {
1096                target_colorspace=LabColorspace;
1097                target_type=(cmsUInt32Number) TYPE_Lab_16;
1098                target_channels=3;
1099                break;
1100              }
1101              case cmsSigGrayData:
1102              {
1103                target_colorspace=GRAYColorspace;
1104                target_type=(cmsUInt32Number) TYPE_GRAY_16;
1105                target_channels=1;
1106                break;
1107              }
1108              case cmsSigLuvData:
1109              {
1110                target_colorspace=YUVColorspace;
1111                target_type=(cmsUInt32Number) TYPE_YUV_16;
1112                target_channels=3;
1113                break;
1114              }
1115              case cmsSigRgbData:
1116              {
1117                target_colorspace=RGBColorspace;
1118                target_type=(cmsUInt32Number) TYPE_RGB_16;
1119                target_channels=3;
1120                break;
1121              }
1122              case cmsSigXYZData:
1123              {
1124                target_colorspace=XYZColorspace;
1125                target_type=(cmsUInt32Number) TYPE_XYZ_16;
1126                target_channels=3;
1127                break;
1128              }
1129              case cmsSigYCbCrData:
1130              {
1131                target_colorspace=YCbCrColorspace;
1132                target_type=(cmsUInt32Number) TYPE_YCbCr_16;
1133                target_channels=3;
1134                break;
1135              }
1136              default:
1137              {
1138                target_colorspace=UndefinedColorspace;
1139                target_type=(cmsUInt32Number) TYPE_RGB_16;
1140                target_channels=3;
1141                break;
1142              }
1143            }
1144            if ((source_colorspace == UndefinedColorspace) ||
1145                (target_colorspace == UndefinedColorspace))
1146              ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1147                name);
1148             if ((source_colorspace == GRAYColorspace) &&
1149                 (IsGrayImage(image,exception) == MagickFalse))
1150              ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1151                name);
1152             if ((source_colorspace == CMYKColorspace) &&
1153                 (image->colorspace != CMYKColorspace))
1154              ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1155                name);
1156             if ((source_colorspace == XYZColorspace) &&
1157                 (image->colorspace != XYZColorspace))
1158              ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1159                name);
1160             if ((source_colorspace == YCbCrColorspace) &&
1161                 (image->colorspace != YCbCrColorspace))
1162              ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1163                name);
1164             if ((source_colorspace != CMYKColorspace) &&
1165                 (source_colorspace != GRAYColorspace) &&
1166                 (source_colorspace != LabColorspace) &&
1167                 (source_colorspace != XYZColorspace) &&
1168                 (source_colorspace != YCbCrColorspace) &&
1169                 (image->colorspace != RGBColorspace))
1170              ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1171                name);
1172            switch (image->rendering_intent)
1173            {
1174              case AbsoluteIntent: intent=INTENT_ABSOLUTE_COLORIMETRIC; break;
1175              case PerceptualIntent: intent=INTENT_PERCEPTUAL; break;
1176              case RelativeIntent: intent=INTENT_RELATIVE_COLORIMETRIC; break;
1177              case SaturationIntent: intent=INTENT_SATURATION; break;
1178              default: intent=INTENT_PERCEPTUAL; break;
1179            }
1180            flags=cmsFLAGS_HIGHRESPRECALC;
1181#if defined(cmsFLAGS_BLACKPOINTCOMPENSATION)
1182            if (image->black_point_compensation != MagickFalse)
1183              flags|=cmsFLAGS_BLACKPOINTCOMPENSATION;
1184#endif
1185            transform=AcquireTransformThreadSet(image,source_profile,
1186              source_type,target_profile,target_type,intent,flags);
1187            if (transform == (cmsHTRANSFORM *) NULL)
1188              ThrowProfileException(ImageError,"UnableToCreateColorTransform",
1189                name);
1190            /*
1191              Transform image as dictated by the source & target image profiles.
1192            */
1193            source_pixels=AcquirePixelThreadSet(image->columns,source_channels);
1194            target_pixels=AcquirePixelThreadSet(image->columns,target_channels);
1195            if ((source_pixels == (unsigned short **) NULL) ||
1196                (target_pixels == (unsigned short **) NULL))
1197              {
1198                transform=DestroyTransformThreadSet(transform);
1199                ThrowProfileException(ResourceLimitError,
1200                  "MemoryAllocationFailed",image->filename);
1201              }
1202            if (SetImageStorageClass(image,DirectClass) == MagickFalse)
1203              {
1204                target_pixels=DestroyPixelThreadSet(target_pixels);
1205                source_pixels=DestroyPixelThreadSet(source_pixels);
1206                transform=DestroyTransformThreadSet(transform);
1207                if (source_profile != (cmsHPROFILE) NULL)
1208                  (void) cmsCloseProfile(source_profile);
1209                if (target_profile != (cmsHPROFILE) NULL)
1210                  (void) cmsCloseProfile(target_profile);
1211                return(MagickFalse);
1212              }
1213            if (target_colorspace == CMYKColorspace)
1214              (void) SetImageColorspace(image,target_colorspace);
1215            status=MagickTrue;
1216            progress=0;
1217            image_view=AcquireCacheView(image);
1218#if defined(MAGICKCORE_OPENMP_SUPPORT)
1219            #pragma omp parallel for schedule(dynamic,4) shared(status)
1220#endif
1221            for (y=0; y < (ssize_t) image->rows; y++)
1222            {
1223              const int
1224                id = GetOpenMPThreadId();
1225
1226              MagickBooleanType
1227                sync;
1228
1229              register IndexPacket
1230                *restrict indexes;
1231
1232              register ssize_t
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              p=source_pixels[id];
1252              for (x=0; x < (ssize_t) image->columns; x++)
1253              {
1254                *p++=ScaleQuantumToShort(q->red);
1255                if (source_channels > 1)
1256                  {
1257                    *p++=ScaleQuantumToShort(q->green);
1258                    *p++=ScaleQuantumToShort(q->blue);
1259                  }
1260                if (source_channels > 3)
1261                  *p++=ScaleQuantumToShort(indexes[x]);
1262                q++;
1263              }
1264              cmsDoTransform(transform[id],source_pixels[id],target_pixels[id],
1265                (unsigned int) image->columns);
1266              p=target_pixels[id];
1267              q-=image->columns;
1268              for (x=0; x < (ssize_t) image->columns; x++)
1269              {
1270                q->red=ScaleShortToQuantum(*p);
1271                SetGreenPixelComponent(q,GetRedPixelComponent(q));
1272                SetBluePixelComponent(q,GetRedPixelComponent(q));
1273                p++;
1274                if (target_channels > 1)
1275                  {
1276                    q->green=ScaleShortToQuantum(*p);
1277                    p++;
1278                    q->blue=ScaleShortToQuantum(*p);
1279                    p++;
1280                  }
1281                if (target_channels > 3)
1282                  {
1283                    indexes[x]=ScaleShortToQuantum(*p);
1284                    p++;
1285                  }
1286                q++;
1287              }
1288              sync=SyncCacheViewAuthenticPixels(image_view,exception);
1289              if (sync == MagickFalse)
1290                status=MagickFalse;
1291              if (image->progress_monitor != (MagickProgressMonitor) NULL)
1292                {
1293                  MagickBooleanType
1294                    proceed;
1295
1296#if defined(MAGICKCORE_OPENMP_SUPPORT)
1297#pragma omp critical (MagickCore_ProfileImage)
1298#endif
1299                  proceed=SetImageProgress(image,ProfileImageTag,progress++,
1300                    image->rows);
1301                  if (proceed == MagickFalse)
1302                    status=MagickFalse;
1303                }
1304            }
1305            image_view=DestroyCacheView(image_view);
1306            (void) SetImageColorspace(image,target_colorspace);
1307            switch (signature)
1308            {
1309              case cmsSigRgbData:
1310              {
1311                image->type=image->matte == MagickFalse ? TrueColorType :
1312                  TrueColorMatteType;
1313                break;
1314              }
1315              case cmsSigCmykData:
1316              {
1317                image->type=image->matte == MagickFalse ? ColorSeparationType :
1318                  ColorSeparationMatteType;
1319                break;
1320              }
1321              case cmsSigGrayData:
1322              {
1323                image->type=image->matte == MagickFalse ? GrayscaleType :
1324                  GrayscaleMatteType;
1325                break;
1326              }
1327              default:
1328                break;
1329            }
1330            target_pixels=DestroyPixelThreadSet(target_pixels);
1331            source_pixels=DestroyPixelThreadSet(source_pixels);
1332            transform=DestroyTransformThreadSet(transform);
1333            if (cmsGetDeviceClass(source_profile) != cmsSigLinkClass)
1334              status=SetImageProfile(image,name,profile);
1335            if (target_profile != (cmsHPROFILE) NULL)
1336              (void) cmsCloseProfile(target_profile);
1337          }
1338        (void) cmsCloseProfile(source_profile);
1339      }
1340#endif
1341    }
1342  profile=DestroyStringInfo(profile);
1343  return(status);
1344}
1345
1346/*
1347%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1348%                                                                             %
1349%                                                                             %
1350%                                                                             %
1351%   R e m o v e I m a g e P r o f i l e                                       %
1352%                                                                             %
1353%                                                                             %
1354%                                                                             %
1355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1356%
1357%  RemoveImageProfile() removes a named profile from the image and returns its
1358%  value.
1359%
1360%  The format of the RemoveImageProfile method is:
1361%
1362%      void *RemoveImageProfile(Image *image,const char *name)
1363%
1364%  A description of each parameter follows:
1365%
1366%    o image: the image.
1367%
1368%    o name: the profile name.
1369%
1370*/
1371MagickExport StringInfo *RemoveImageProfile(Image *image,const char *name)
1372{
1373  StringInfo
1374    *profile;
1375
1376  assert(image != (Image *) NULL);
1377  assert(image->signature == MagickSignature);
1378  if (image->debug != MagickFalse)
1379    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1380  if (image->profiles == (SplayTreeInfo *) NULL)
1381    return((StringInfo *) NULL);
1382  if (LocaleCompare(name,"icc") == 0)
1383    {
1384      /*
1385        Continue to support deprecated color profile for now.
1386      */
1387      image->color_profile.length=0;
1388      image->color_profile.info=(unsigned char *) NULL;
1389    }
1390  if (LocaleCompare(name,"iptc") == 0)
1391    {
1392      /*
1393        Continue to support deprecated IPTC profile for now.
1394      */
1395      image->iptc_profile.length=0;
1396      image->iptc_profile.info=(unsigned char *) NULL;
1397    }
1398  profile=(StringInfo *) RemoveNodeFromSplayTree((SplayTreeInfo *)
1399    image->profiles,name);
1400  return(profile);
1401}
1402
1403/*
1404%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1405%                                                                             %
1406%                                                                             %
1407%                                                                             %
1408%   R e s e t P r o f i l e I t e r a t o r                                   %
1409%                                                                             %
1410%                                                                             %
1411%                                                                             %
1412%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1413%
1414%  ResetImageProfileIterator() resets the image profile iterator.  Use it in
1415%  conjunction with GetNextImageProfile() to iterate over all the profiles
1416%  associated with an image.
1417%
1418%  The format of the ResetImageProfileIterator method is:
1419%
1420%      ResetImageProfileIterator(Image *image)
1421%
1422%  A description of each parameter follows:
1423%
1424%    o image: the image.
1425%
1426*/
1427MagickExport void ResetImageProfileIterator(const Image *image)
1428{
1429  assert(image != (Image *) NULL);
1430  assert(image->signature == MagickSignature);
1431  if (image->debug != MagickFalse)
1432    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1433  if (image->profiles == (SplayTreeInfo *) NULL)
1434    return;
1435  ResetSplayTreeIterator((SplayTreeInfo *) image->profiles);
1436}
1437
1438/*
1439%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1440%                                                                             %
1441%                                                                             %
1442%                                                                             %
1443%   S e t I m a g e P r o f i l e                                             %
1444%                                                                             %
1445%                                                                             %
1446%                                                                             %
1447%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1448%
1449%  SetImageProfile() adds a named profile to the image.  If a profile with the
1450%  same name already exists, it is replaced.  This method differs from the
1451%  ProfileImage() method in that it does not apply CMS color profiles.
1452%
1453%  The format of the SetImageProfile method is:
1454%
1455%      MagickBooleanType SetImageProfile(Image *image,const char *name,
1456%        const StringInfo *profile)
1457%
1458%  A description of each parameter follows:
1459%
1460%    o image: the image.
1461%
1462%    o name: the profile name, for example icc, exif, and 8bim (8bim is the
1463%      Photoshop wrapper for iptc profiles).
1464%
1465%    o profile: A StringInfo structure that contains the named profile.
1466%
1467*/
1468
1469static void *DestroyProfile(void *profile)
1470{
1471  return((void *) DestroyStringInfo((StringInfo *) profile));
1472}
1473
1474static inline const unsigned char *ReadResourceByte(const unsigned char *p,
1475  unsigned char *quantum)
1476{
1477  *quantum=(*p++);
1478  return(p);
1479}
1480
1481static inline const unsigned char *ReadResourceBytes(const unsigned char *p,
1482  const ssize_t count,unsigned char *quantum)
1483{
1484  register ssize_t
1485    i;
1486
1487  for (i=0; i < count; i++)
1488    *quantum++=(*p++);
1489  return(p);
1490}
1491
1492static inline const unsigned char *ReadResourceLong(const unsigned char *p,
1493  size_t *quantum)
1494{
1495  *quantum=(size_t) (*p++ << 24);
1496  *quantum|=(size_t) (*p++ << 16);
1497  *quantum|=(size_t) (*p++ << 8);
1498  *quantum|=(size_t) (*p++ << 0);
1499  return(p);
1500}
1501
1502static inline const unsigned char *ReadResourceShort(const unsigned char *p,
1503  unsigned short *quantum)
1504{
1505  *quantum=(unsigned short) (*p++ << 8);
1506  *quantum|=(unsigned short) (*p++ << 0);
1507  return(p);
1508}
1509
1510static MagickBooleanType GetProfilesFromResourceBlock(Image *image,
1511  const StringInfo *resource_block)
1512{
1513  const unsigned char
1514    *datum;
1515
1516  register const unsigned char
1517    *p;
1518
1519  size_t
1520    length;
1521
1522  StringInfo
1523    *profile;
1524
1525  unsigned char
1526    length_byte;
1527
1528  size_t
1529    count;
1530
1531  unsigned short
1532    id;
1533
1534  datum=GetStringInfoDatum(resource_block);
1535  length=GetStringInfoLength(resource_block);
1536  for (p=datum; p < (datum+length-16); )
1537  {
1538    if (LocaleNCompare((char *) p,"8BIM",4) != 0)
1539      break;
1540    p+=4;
1541    p=ReadResourceShort(p,&id);
1542    p=ReadResourceByte(p,&length_byte);
1543    p+=length_byte;
1544    if (((length_byte+1) & 0x01) != 0)
1545      p++;
1546    if (p > (datum+length-4))
1547      break;
1548    p=ReadResourceLong(p,&count);
1549    if ((p > (datum+length-count)) || (count > length))
1550      break;
1551    switch (id)
1552    {
1553      case 0x03ed:
1554      {
1555        unsigned short
1556          resolution;
1557
1558        /*
1559          Resolution.
1560        */
1561        p=ReadResourceShort(p,&resolution)+6;
1562        image->x_resolution=(double) resolution;
1563        p=ReadResourceShort(p,&resolution)+6;
1564        image->y_resolution=(double) resolution;
1565        break;
1566      }
1567      case 0x0404:
1568      {
1569        /*
1570          IPTC Profile
1571        */
1572        profile=AcquireStringInfo(count);
1573        SetStringInfoDatum(profile,p);
1574        (void) SetImageProfile(image,"iptc",profile);
1575        profile=DestroyStringInfo(profile);
1576        p+=count;
1577        break;
1578      }
1579      case 0x040c:
1580      {
1581        /*
1582          Thumbnail.
1583        */
1584        p+=count;
1585        break;
1586      }
1587      case 0x040f:
1588      {
1589        /*
1590          ICC Profile.
1591        */
1592        profile=AcquireStringInfo(count);
1593        SetStringInfoDatum(profile,p);
1594        (void) SetImageProfile(image,"icc",profile);
1595        profile=DestroyStringInfo(profile);
1596        p+=count;
1597        break;
1598      }
1599      case 0x0422:
1600      {
1601        /*
1602          EXIF Profile.
1603        */
1604        profile=AcquireStringInfo(count);
1605        SetStringInfoDatum(profile,p);
1606        (void) SetImageProfile(image,"exif",profile);
1607        profile=DestroyStringInfo(profile);
1608        p+=count;
1609        break;
1610      }
1611      case 0x0424:
1612      {
1613        /*
1614          XMP Profile.
1615        */
1616        profile=AcquireStringInfo(count);
1617        SetStringInfoDatum(profile,p);
1618        (void) SetImageProfile(image,"xmp",profile);
1619        profile=DestroyStringInfo(profile);
1620        p+=count;
1621        break;
1622      }
1623      default:
1624      {
1625        p+=count;
1626        break;
1627      }
1628    }
1629    if ((count & 0x01) != 0)
1630      p++;
1631  }
1632  return(MagickTrue);
1633}
1634
1635MagickExport MagickBooleanType SetImageProfile(Image *image,const char *name,
1636  const StringInfo *profile)
1637{
1638  char
1639    key[MaxTextExtent],
1640    property[MaxTextExtent];
1641
1642  MagickBooleanType
1643    status;
1644
1645  assert(image != (Image *) NULL);
1646  assert(image->signature == MagickSignature);
1647  if (image->debug != MagickFalse)
1648    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1649  if (image->profiles == (SplayTreeInfo *) NULL)
1650    image->profiles=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
1651      DestroyProfile);
1652  (void) CopyMagickString(key,name,MaxTextExtent);
1653  status=AddValueToSplayTree((SplayTreeInfo *) image->profiles,
1654    ConstantString(key),CloneStringInfo(profile));
1655  if ((status != MagickFalse) &&
1656      ((LocaleCompare(name,"icc") == 0) || (LocaleCompare(name,"icm") == 0)))
1657    {
1658      const StringInfo
1659        *icc_profile;
1660
1661      /*
1662        Continue to support deprecated color profile member.
1663      */
1664      icc_profile=GetImageProfile(image,name);
1665      if (icc_profile != (const StringInfo *) NULL)
1666        {
1667          image->color_profile.length=GetStringInfoLength(icc_profile);
1668          image->color_profile.info=GetStringInfoDatum(icc_profile);
1669        }
1670    }
1671  if ((status != MagickFalse) &&
1672      ((LocaleCompare(name,"iptc") == 0) || (LocaleCompare(name,"8bim") == 0)))
1673    {
1674      const StringInfo
1675        *iptc_profile;
1676
1677      /*
1678        Continue to support deprecated IPTC profile member.
1679      */
1680      iptc_profile=GetImageProfile(image,name);
1681      if (iptc_profile != (const StringInfo *) NULL)
1682        {
1683          image->iptc_profile.length=GetStringInfoLength(iptc_profile);
1684          image->iptc_profile.info=GetStringInfoDatum(iptc_profile);
1685        }
1686      (void) GetProfilesFromResourceBlock(image,profile);
1687    }
1688  /*
1689    Inject profile into image properties.
1690  */
1691  (void) FormatMagickString(property,MaxTextExtent,"%s:sans",name);
1692  (void) GetImageProperty(image,property);
1693  return(status);
1694}
1695
1696/*
1697%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1698%                                                                             %
1699%                                                                             %
1700%                                                                             %
1701%   S y n c I m a g e P r o f i l e s                                         %
1702%                                                                             %
1703%                                                                             %
1704%                                                                             %
1705%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1706%
1707%  SyncImageProfiles() synchronizes image properties with the image profiles.
1708%  Currently we only support updating the EXIF resolution and orientation.
1709%
1710%  The format of the SyncImageProfiles method is:
1711%
1712%      MagickBooleanType SyncImageProfiles(Image *image)
1713%
1714%  A description of each parameter follows:
1715%
1716%    o image: the image.
1717%
1718*/
1719
1720static inline int ReadProfileByte(unsigned char **p,size_t *length)
1721{
1722  int
1723    c;
1724
1725  if (*length < 1)
1726    return(EOF);
1727  c=(int) (*(*p)++);
1728  (*length)--;
1729  return(c);
1730}
1731
1732static inline unsigned short ReadProfileShort(const EndianType endian,
1733  unsigned char *buffer)
1734{
1735  unsigned short
1736    value;
1737
1738  if (endian == MSBEndian)
1739    {
1740      value=(unsigned short) ((((unsigned char *) buffer)[0] << 8) |
1741        ((unsigned char *) buffer)[1]);
1742      return((unsigned short) (value & 0xffff));
1743    }
1744  value=(unsigned short) ((buffer[1] << 8) | buffer[0]);
1745  return((unsigned short) (value & 0xffff));
1746}
1747
1748static inline size_t ReadProfileLong(const EndianType endian,
1749  unsigned char *buffer)
1750{
1751  size_t
1752    value;
1753
1754  if (endian == MSBEndian)
1755    {
1756      value=(size_t) ((buffer[0] << 24) | (buffer[1] << 16) |
1757        (buffer[2] << 8) | buffer[3]);
1758      return((size_t) (value & 0xffffffff));
1759    }
1760  value=(size_t) ((buffer[3] << 24) | (buffer[2] << 16) |
1761    (buffer[1] << 8 ) | (buffer[0]));
1762  return((size_t) (value & 0xffffffff));
1763}
1764
1765static inline void WriteProfileLong(const EndianType endian,
1766  const size_t value,unsigned char *p)
1767{
1768  unsigned char
1769    buffer[4];
1770
1771  if (endian == MSBEndian)
1772    {
1773      buffer[0]=(unsigned char) (value >> 24);
1774      buffer[1]=(unsigned char) (value >> 16);
1775      buffer[2]=(unsigned char) (value >> 8);
1776      buffer[3]=(unsigned char) value;
1777      (void) CopyMagickMemory(p,buffer,4);
1778      return;
1779    }
1780  buffer[0]=(unsigned char) value;
1781  buffer[1]=(unsigned char) (value >> 8);
1782  buffer[2]=(unsigned char) (value >> 16);
1783  buffer[3]=(unsigned char) (value >> 24);
1784  (void) CopyMagickMemory(p,buffer,4);
1785}
1786
1787static void WriteProfileShort(const EndianType endian,
1788  const unsigned short value,unsigned char *p)
1789{
1790  unsigned char
1791    buffer[2];
1792
1793  if (endian == MSBEndian)
1794    {
1795      buffer[0]=(unsigned char) (value >> 8);
1796      buffer[1]=(unsigned char) value;
1797      (void) CopyMagickMemory(p,buffer,2);
1798      return;
1799    }
1800  buffer[0]=(unsigned char) value;
1801  buffer[1]=(unsigned char) (value >> 8);
1802  (void) CopyMagickMemory(p,buffer,2);
1803}
1804
1805MagickExport MagickBooleanType SyncImageProfiles(Image *image)
1806{
1807#define MaxDirectoryStack  16
1808#define EXIF_DELIMITER  "\n"
1809#define EXIF_NUM_FORMATS  12
1810#define TAG_EXIF_OFFSET  0x8769
1811#define TAG_INTEROP_OFFSET  0xa005
1812
1813  typedef struct _DirectoryInfo
1814  {
1815    unsigned char
1816      *directory;
1817
1818    size_t
1819      entry;
1820  } DirectoryInfo;
1821
1822  DirectoryInfo
1823    directory_stack[MaxDirectoryStack];
1824
1825  EndianType
1826    endian;
1827
1828  int
1829    offset;
1830
1831  size_t
1832    entry,
1833    length,
1834    number_entries;
1835
1836  ssize_t
1837    id,
1838    level;
1839
1840  static int
1841    format_bytes[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
1842
1843  StringInfo
1844    *profile;
1845
1846  unsigned char
1847    *directory,
1848    *exif;
1849
1850  /*
1851    Set EXIF resolution tag.
1852  */
1853  profile=(StringInfo *) GetImageProfile(image,"EXIF");
1854  if (profile == (StringInfo *) NULL)
1855    return(MagickTrue);
1856  length=GetStringInfoLength(profile);
1857  exif=GetStringInfoDatum(profile);
1858  while (length != 0)
1859  {
1860    if (ReadProfileByte(&exif,&length) != 0x45)
1861      continue;
1862    if (ReadProfileByte(&exif,&length) != 0x78)
1863      continue;
1864    if (ReadProfileByte(&exif,&length) != 0x69)
1865      continue;
1866    if (ReadProfileByte(&exif,&length) != 0x66)
1867      continue;
1868    if (ReadProfileByte(&exif,&length) != 0x00)
1869      continue;
1870    if (ReadProfileByte(&exif,&length) != 0x00)
1871      continue;
1872    break;
1873  }
1874  if (length < 16)
1875    return(MagickFalse);
1876  id=(ssize_t) ReadProfileShort(LSBEndian,exif);
1877  endian=LSBEndian;
1878  if (id == 0x4949)
1879    endian=LSBEndian;
1880  else
1881    if (id == 0x4D4D)
1882      endian=MSBEndian;
1883    else
1884      return(MagickFalse);
1885  if (ReadProfileShort(endian,exif+2) != 0x002a)
1886    return(MagickFalse);
1887  /*
1888    This the offset to the first IFD.
1889  */
1890  offset=(int) ReadProfileLong(endian,exif+4);
1891  if ((size_t) offset >= length)
1892    return(MagickFalse);
1893  directory=exif+offset;
1894  level=0;
1895  entry=0;
1896  do
1897  {
1898    if (level > 0)
1899      {
1900        level--;
1901        directory=directory_stack[level].directory;
1902        entry=directory_stack[level].entry;
1903      }
1904    /*
1905      Determine how many entries there are in the current IFD.
1906    */
1907    number_entries=ReadProfileShort(endian,directory);
1908    for ( ; entry < number_entries; entry++)
1909    {
1910      int
1911        components;
1912
1913      register unsigned char
1914        *p,
1915        *q;
1916
1917      size_t
1918        number_bytes;
1919
1920      ssize_t
1921        format,
1922        tag_value;
1923
1924      q=(unsigned char *) (directory+2+(12*entry));
1925      tag_value=(ssize_t) ReadProfileShort(endian,q);
1926      format=(ssize_t) ReadProfileShort(endian,q+2);
1927      if ((format-1) >= EXIF_NUM_FORMATS)
1928        break;
1929      components=(int) ReadProfileLong(endian,q+4);
1930      number_bytes=(size_t) components*format_bytes[format];
1931      if (number_bytes <= 4)
1932        p=q+8;
1933      else
1934        {
1935          int
1936            offset;
1937
1938          /*
1939            The directory entry contains an offset.
1940          */
1941          offset=(int) ReadProfileLong(endian,q+8);
1942          if ((size_t) (offset+number_bytes) > length)
1943            continue;
1944          p=(unsigned char *) (exif+offset);
1945        }
1946      switch (tag_value)
1947      {
1948        case 0x011a:
1949        {
1950          (void) WriteProfileLong(endian,(size_t)
1951            (image->x_resolution+0.5),p);
1952          (void) WriteProfileLong(endian,1UL,p+4);
1953          break;
1954        }
1955        case 0x011b:
1956        {
1957          (void) WriteProfileLong(endian,(size_t)
1958            (image->y_resolution+0.5),p);
1959          (void) WriteProfileLong(endian,1UL,p+4);
1960          break;
1961        }
1962        case 0x0112:
1963        {
1964          (void) WriteProfileShort(endian,(unsigned short)
1965            image->orientation,p);
1966          break;
1967        }
1968        case 0x0128:
1969        {
1970          (void) WriteProfileShort(endian,(unsigned short)
1971            (image->units+1),p);
1972          break;
1973        }
1974        default:
1975          break;
1976      }
1977      if ((tag_value == TAG_EXIF_OFFSET) || (tag_value == TAG_INTEROP_OFFSET))
1978        {
1979          size_t
1980            offset;
1981
1982          offset=(size_t) ReadProfileLong(endian,p);
1983          if ((offset < length) && (level < (MaxDirectoryStack-2)))
1984            {
1985              directory_stack[level].directory=directory;
1986              entry++;
1987              directory_stack[level].entry=entry;
1988              level++;
1989              directory_stack[level].directory=exif+offset;
1990              directory_stack[level].entry=0;
1991              level++;
1992              if ((directory+2+(12*number_entries)) > (exif+length))
1993                break;
1994              offset=(size_t) ReadProfileLong(endian,directory+2+(12*
1995                number_entries));
1996              if ((offset != 0) && (offset < length) &&
1997                  (level < (MaxDirectoryStack-2)))
1998                {
1999                  directory_stack[level].directory=exif+offset;
2000                  directory_stack[level].entry=0;
2001                  level++;
2002                }
2003            }
2004          break;
2005        }
2006    }
2007  } while (level > 0);
2008  return(MagickTrue);
2009}
Note: See TracBrowser for help on using the repository browser.