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