]> 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 ssize_t
342     i;
343
344   assert(pixels != (unsigned short **) NULL);
345   for (i=0; i < (ssize_t) 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 ssize_t
356     i;
357
358   unsigned short
359     **pixels;
360
361   size_t
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 < (ssize_t) 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 ssize_t
383     i;
384
385   assert(transform != (cmsHTRANSFORM *) NULL);
386   for (i=0; i < (ssize_t) 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 ssize_t
402     i;
403
404   size_t
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 < (ssize_t) 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   if (source_profile != (cmsHPROFILE) NULL) \
838     (void) cmsCloseProfile(source_profile); \
839   if (target_profile != (cmsHPROFILE) NULL) \
840     (void) cmsCloseProfile(target_profile); \
841   ThrowBinaryException(severity,tag,context); \
842 }
843
844   MagickBooleanType
845     status;
846
847   StringInfo
848     *profile;
849
850   assert(image != (Image *) NULL);
851   assert(image->signature == MagickSignature);
852   if (image->debug != MagickFalse)
853     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
854   assert(name != (const char *) NULL);
855   if ((datum == (const void *) NULL) || (length == 0))
856     {
857       char
858         **arguments,
859         *names;
860
861       int
862         number_arguments;
863
864       register ssize_t
865         i;
866
867       /*
868         Delete image profile(s).
869       */
870       names=ConstantString(name);
871       (void) SubstituteString(&names,","," ");
872       arguments=StringToArgv(names,&number_arguments);
873       names=DestroyString(names);
874       if (arguments == (char **) NULL)
875         return(MagickTrue);
876       ResetImageProfileIterator(image);
877       for (name=GetNextImageProfile(image); name != (const char *) NULL; )
878       {
879         for (i=1; i < number_arguments; i++)
880         {
881           if ((*arguments[i] == '!') &&
882               (LocaleCompare(name,arguments[i]+1) == 0))
883             break;
884           if (GlobExpression(name,arguments[i],MagickTrue) != MagickFalse)
885             {
886               (void) DeleteImageProfile(image,name);
887               ResetImageProfileIterator(image);
888               break;
889             }
890         }
891         name=GetNextImageProfile(image);
892       }
893       for (i=0; i < number_arguments; i++)
894         arguments[i]=DestroyString(arguments[i]);
895       arguments=(char **) RelinquishMagickMemory(arguments);
896       return(MagickTrue);
897     }
898   /*
899     Add a ICC, IPTC, or generic profile to the image.
900   */
901   status=MagickTrue;
902   profile=AcquireStringInfo((size_t) length);
903   SetStringInfoDatum(profile,(unsigned char *) datum);
904   if ((LocaleCompare(name,"icc") != 0) && (LocaleCompare(name,"icm") != 0))
905     status=SetImageProfile(image,name,profile);
906   else
907     {
908       const StringInfo
909         *icc_profile;
910
911       icc_profile=GetImageProfile(image,"icc");
912       if ((icc_profile != (const StringInfo *) NULL) &&
913           (CompareStringInfo(icc_profile,profile) == 0))
914         {
915           const char
916             *value;
917
918           value=GetImageProperty(image,"exif:ColorSpace");
919           if (LocaleCompare(value,"1") != 0)
920             (void) SetsRGBImageProfile(image);
921           value=GetImageProperty(image,"exif:InteroperabilityIndex");
922           if (LocaleCompare(value,"R98.") != 0)
923             (void) SetsRGBImageProfile(image);
924           value=GetImageProperty(image,"exif:InteroperabilityIndex");
925           if (LocaleCompare(value,"R03.") != 0)
926             (void) SetAdobeRGB1998ImageProfile(image);
927           icc_profile=GetImageProfile(image,"icc");
928         }
929       if ((icc_profile != (const StringInfo *) NULL) &&
930           (CompareStringInfo(icc_profile,profile) == 0))
931         {
932           profile=DestroyStringInfo(profile);
933           return(MagickTrue);
934         }
935 #if !defined(MAGICKCORE_LCMS_DELEGATE)
936       (void) ThrowMagickException(&image->exception,GetMagickModule(),
937         MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (LCMS)",
938         image->filename);
939 #else
940       {
941         cmsHPROFILE
942           source_profile;
943
944         /*
945           Transform pixel colors as defined by the color profiles.
946         */
947 #if defined(LCMS_VERSION) && (LCMS_VERSION >= 2000)
948         cmsSetLogErrorHandler(LCMSErrorHandler);
949 #endif
950 #if defined(LCMS_VERSION) && (LCMS_VERSION < 2000)
951 #if defined(LCMS_VERSION) && (LCMS_VERSION > 1010)
952         cmsSetErrorHandler(LCMSErrorHandler);
953 #else
954         (void) cmsErrorAction(LCMS_ERROR_SHOW);
955 #endif
956 #endif
957         source_profile=cmsOpenProfileFromMem(GetStringInfoDatum(profile),
958           (cmsUInt32Number) 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               length,
1002               source_channels,
1003               target_channels;
1004
1005             ssize_t
1006               y;
1007
1008             unsigned short
1009               **restrict source_pixels,
1010               **restrict target_pixels;
1011
1012             exception=(&image->exception);
1013             target_profile=(cmsHPROFILE) NULL;
1014             if (icc_profile != (StringInfo *) NULL)
1015               {
1016                 target_profile=source_profile;
1017                 source_profile=cmsOpenProfileFromMem(
1018                   GetStringInfoDatum(icc_profile),(cmsUInt32Number)
1019                   GetStringInfoLength(icc_profile));
1020                 if (source_profile == (cmsHPROFILE) NULL)
1021                   ThrowProfileException(ResourceLimitError,
1022                     "ColorspaceColorProfileMismatch",name);
1023               }
1024             switch (cmsGetColorSpace(source_profile))
1025             {
1026               case cmsSigCmykData:
1027               {
1028                 source_colorspace=CMYKColorspace;
1029                 source_type=(cmsUInt32Number) TYPE_CMYK_16;
1030                 source_channels=4;
1031                 break;
1032               }
1033               case cmsSigGrayData:
1034               {
1035                 source_colorspace=GRAYColorspace;
1036                 source_type=(cmsUInt32Number) TYPE_GRAY_16;
1037                 source_channels=1;
1038                 break;
1039               }
1040               case cmsSigLabData:
1041               {
1042                 source_colorspace=LabColorspace;
1043                 source_type=(cmsUInt32Number) TYPE_Lab_16;
1044                 source_channels=3;
1045                 break;
1046               }
1047               case cmsSigLuvData:
1048               {
1049                 source_colorspace=YUVColorspace;
1050                 source_type=(cmsUInt32Number) TYPE_YUV_16;
1051                 source_channels=3;
1052                 break;
1053               }
1054               case cmsSigRgbData:
1055               {
1056                 source_colorspace=RGBColorspace;
1057                 source_type=(cmsUInt32Number) TYPE_RGB_16;
1058                 source_channels=3;
1059                 break;
1060               }
1061               case cmsSigXYZData:
1062               {
1063                 source_colorspace=XYZColorspace;
1064                 source_type=(cmsUInt32Number) TYPE_XYZ_16;
1065                 source_channels=3;
1066                 break;
1067               }
1068               case cmsSigYCbCrData:
1069               {
1070                 source_colorspace=YCbCrColorspace;
1071                 source_type=(cmsUInt32Number) TYPE_YCbCr_16;
1072                 source_channels=3;
1073                 break;
1074               }
1075               default:
1076               {
1077                 source_colorspace=UndefinedColorspace;
1078                 source_type=(cmsUInt32Number) TYPE_RGB_16;
1079                 source_channels=3;
1080                 break;
1081               }
1082             }
1083             signature=cmsGetPCS(source_profile);
1084             if (target_profile != (cmsHPROFILE) NULL)
1085               signature=cmsGetColorSpace(target_profile);
1086             switch (signature)
1087             {
1088               case cmsSigCmykData:
1089               {
1090                 target_colorspace=CMYKColorspace;
1091                 target_type=(cmsUInt32Number) TYPE_CMYK_16;
1092                 target_channels=4;
1093                 break;
1094               }
1095               case cmsSigLabData:
1096               {
1097                 target_colorspace=LabColorspace;
1098                 target_type=(cmsUInt32Number) TYPE_Lab_16;
1099                 target_channels=3;
1100                 break;
1101               }
1102               case cmsSigGrayData:
1103               {
1104                 target_colorspace=GRAYColorspace;
1105                 target_type=(cmsUInt32Number) TYPE_GRAY_16;
1106                 target_channels=1;
1107                 break;
1108               }
1109               case cmsSigLuvData:
1110               {
1111                 target_colorspace=YUVColorspace;
1112                 target_type=(cmsUInt32Number) TYPE_YUV_16;
1113                 target_channels=3;
1114                 break;
1115               }
1116               case cmsSigRgbData:
1117               {
1118                 target_colorspace=RGBColorspace;
1119                 target_type=(cmsUInt32Number) TYPE_RGB_16;
1120                 target_channels=3;
1121                 break;
1122               }
1123               case cmsSigXYZData:
1124               {
1125                 target_colorspace=XYZColorspace;
1126                 target_type=(cmsUInt32Number) TYPE_XYZ_16;
1127                 target_channels=3;
1128                 break;
1129               }
1130               case cmsSigYCbCrData:
1131               {
1132                 target_colorspace=YCbCrColorspace;
1133                 target_type=(cmsUInt32Number) TYPE_YCbCr_16;
1134                 target_channels=3;
1135                 break;
1136               }
1137               default:
1138               {
1139                 target_colorspace=UndefinedColorspace;
1140                 target_type=(cmsUInt32Number) TYPE_RGB_16;
1141                 target_channels=3;
1142                 break;
1143               }
1144             }
1145             if ((source_colorspace == UndefinedColorspace) ||
1146                 (target_colorspace == UndefinedColorspace))
1147               ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1148                 name);
1149              if ((source_colorspace == GRAYColorspace) &&
1150                  (IsGrayImage(image,exception) == MagickFalse))
1151               ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1152                 name);
1153              if ((source_colorspace == CMYKColorspace) &&
1154                  (image->colorspace != CMYKColorspace))
1155               ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1156                 name);
1157              if ((source_colorspace == XYZColorspace) &&
1158                  (image->colorspace != XYZColorspace))
1159               ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1160                 name);
1161              if ((source_colorspace == YCbCrColorspace) &&
1162                  (image->colorspace != YCbCrColorspace))
1163               ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1164                 name);
1165              if ((source_colorspace != CMYKColorspace) &&
1166                  (source_colorspace != GRAYColorspace) &&
1167                  (source_colorspace != LabColorspace) &&
1168                  (source_colorspace != XYZColorspace) &&
1169                  (source_colorspace != YCbCrColorspace) &&
1170                  (image->colorspace != RGBColorspace))
1171               ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1172                 name);
1173             switch (image->rendering_intent)
1174             {
1175               case AbsoluteIntent: intent=INTENT_ABSOLUTE_COLORIMETRIC; break;
1176               case PerceptualIntent: intent=INTENT_PERCEPTUAL; break;
1177               case RelativeIntent: intent=INTENT_RELATIVE_COLORIMETRIC; break;
1178               case SaturationIntent: intent=INTENT_SATURATION; break;
1179               default: intent=INTENT_PERCEPTUAL; break;
1180             }
1181             flags=cmsFLAGS_HIGHRESPRECALC;
1182 #if defined(cmsFLAGS_BLACKPOINTCOMPENSATION)
1183             if (image->black_point_compensation != MagickFalse)
1184               flags|=cmsFLAGS_BLACKPOINTCOMPENSATION;
1185 #endif
1186             transform=AcquireTransformThreadSet(source_profile,source_type,
1187               target_profile,target_type,intent,flags);
1188             if (transform == (cmsHTRANSFORM *) NULL)
1189               ThrowProfileException(ImageError,"UnableToCreateColorTransform",
1190                 name);
1191             /*
1192               Transform image as dictated by the source & target image profiles.
1193             */
1194             length=(size_t) image->columns;
1195             source_pixels=AcquirePixelThreadSet(image->columns,source_channels);
1196             target_pixels=AcquirePixelThreadSet(image->columns,target_channels);
1197             if ((source_pixels == (unsigned short **) NULL) ||
1198                 (target_pixels == (unsigned short **) NULL))
1199               {
1200                 transform=DestroyTransformThreadSet(transform);
1201                 ThrowProfileException(ResourceLimitError,
1202                   "MemoryAllocationFailed",image->filename);
1203               }
1204             if (SetImageStorageClass(image,DirectClass) == MagickFalse)
1205               {
1206                 target_pixels=DestroyPixelThreadSet(target_pixels);
1207                 source_pixels=DestroyPixelThreadSet(source_pixels);
1208                 transform=DestroyTransformThreadSet(transform);
1209                 if (source_profile != (cmsHPROFILE) NULL)
1210                   (void) cmsCloseProfile(source_profile);
1211                 if (target_profile != (cmsHPROFILE) NULL)
1212                   (void) cmsCloseProfile(target_profile);
1213                 return(MagickFalse);
1214               }
1215             if (target_colorspace == CMYKColorspace)
1216               (void) SetImageColorspace(image,target_colorspace);
1217             status=MagickTrue;
1218             progress=0;
1219             image_view=AcquireCacheView(image);
1220 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1221             #pragma omp parallel for schedule(dynamic,4) shared(status)
1222 #endif
1223             for (y=0; y < (ssize_t) image->rows; y++)
1224             {
1225               MagickBooleanType
1226                 sync;
1227
1228               register IndexPacket
1229                 *restrict indexes;
1230
1231               register ssize_t
1232                 id,
1233                 x;
1234
1235               register PixelPacket
1236                 *restrict q;
1237
1238               register unsigned short
1239                 *p;
1240
1241               if (status == MagickFalse)
1242                 continue;
1243               q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1244                 exception);
1245               if (q == (PixelPacket *) NULL)
1246                 {
1247                   status=MagickFalse;
1248                   continue;
1249                 }
1250               indexes=GetCacheViewAuthenticIndexQueue(image_view);
1251               id=GetOpenMPThreadId();
1252               p=source_pixels[id];
1253               for (x=0; x < (ssize_t) image->columns; x++)
1254               {
1255                 *p++=ScaleQuantumToShort(q->red);
1256                 if (source_channels > 1)
1257                   {
1258                     *p++=ScaleQuantumToShort(q->green);
1259                     *p++=ScaleQuantumToShort(q->blue);
1260                   }
1261                 if (source_channels > 3)
1262                   *p++=ScaleQuantumToShort(indexes[x]);
1263                 q++;
1264               }
1265               cmsDoTransform(transform[id],source_pixels[id],target_pixels[id],
1266                 (unsigned int) image->columns);
1267               p=target_pixels[id];
1268               q-=image->columns;
1269               for (x=0; x < (ssize_t) image->columns; x++)
1270               {
1271                 q->red=ScaleShortToQuantum(*p);
1272                 q->green=q->red;
1273                 q->blue=q->red;
1274                 p++;
1275                 if (target_channels > 1)
1276                   {
1277                     q->green=ScaleShortToQuantum(*p);
1278                     p++;
1279                     q->blue=ScaleShortToQuantum(*p);
1280                     p++;
1281                   }
1282                 if (target_channels > 3)
1283                   {
1284                     indexes[x]=ScaleShortToQuantum(*p);
1285                     p++;
1286                   }
1287                 q++;
1288               }
1289               sync=SyncCacheViewAuthenticPixels(image_view,exception);
1290               if (sync == MagickFalse)
1291                 status=MagickFalse;
1292               if (image->progress_monitor != (MagickProgressMonitor) NULL)
1293                 {
1294                   MagickBooleanType
1295                     proceed;
1296
1297 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1298 #pragma omp critical (MagickCore_ProfileImage)
1299 #endif
1300                   proceed=SetImageProgress(image,ProfileImageTag,progress++,
1301                     image->rows);
1302                   if (proceed == MagickFalse)
1303                     status=MagickFalse;
1304                 }
1305             }
1306             image_view=DestroyCacheView(image_view);
1307             (void) SetImageColorspace(image,target_colorspace);
1308             switch (signature)
1309             {
1310               case cmsSigRgbData:
1311               {
1312                 image->type=image->matte == MagickFalse ? TrueColorType :
1313                   TrueColorMatteType;
1314                 break;
1315               }
1316               case cmsSigCmykData:
1317               {
1318                 image->type=image->matte == MagickFalse ? ColorSeparationType :
1319                   ColorSeparationMatteType;
1320                 break;
1321               }
1322               case cmsSigGrayData:
1323               {
1324                 image->type=image->matte == MagickFalse ? GrayscaleType :
1325                   GrayscaleMatteType;
1326                 break;
1327               }
1328               default:
1329                 break;
1330             }
1331             target_pixels=DestroyPixelThreadSet(target_pixels);
1332             source_pixels=DestroyPixelThreadSet(source_pixels);
1333             transform=DestroyTransformThreadSet(transform);
1334             if (cmsGetDeviceClass(source_profile) != cmsSigLinkClass)
1335               status=SetImageProfile(image,name,profile);
1336             if (target_profile != (cmsHPROFILE) NULL)
1337               (void) cmsCloseProfile(target_profile);
1338           }
1339         (void) cmsCloseProfile(source_profile);
1340       }
1341 #endif
1342     }
1343   profile=DestroyStringInfo(profile);
1344   return(status);
1345 }
1346 \f
1347 /*
1348 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1349 %                                                                             %
1350 %                                                                             %
1351 %                                                                             %
1352 %   R e m o v e I m a g e P r o f i l e                                       %
1353 %                                                                             %
1354 %                                                                             %
1355 %                                                                             %
1356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1357 %
1358 %  RemoveImageProfile() removes a named profile from the image and returns its
1359 %  value.
1360 %
1361 %  The format of the RemoveImageProfile method is:
1362 %
1363 %      void *RemoveImageProfile(Image *image,const char *name)
1364 %
1365 %  A description of each parameter follows:
1366 %
1367 %    o image: the image.
1368 %
1369 %    o name: the profile name.
1370 %
1371 */
1372 MagickExport StringInfo *RemoveImageProfile(Image *image,const char *name)
1373 {
1374   StringInfo
1375     *profile;
1376
1377   assert(image != (Image *) NULL);
1378   assert(image->signature == MagickSignature);
1379   if (image->debug != MagickFalse)
1380     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1381   if (image->profiles == (SplayTreeInfo *) NULL)
1382     return((StringInfo *) NULL);
1383   if (LocaleCompare(name,"icc") == 0)
1384     {
1385       /*
1386         Continue to support deprecated color profile for now.
1387       */
1388       image->color_profile.length=0;
1389       image->color_profile.info=(unsigned char *) NULL;
1390     }
1391   if (LocaleCompare(name,"iptc") == 0)
1392     {
1393       /*
1394         Continue to support deprecated IPTC profile for now.
1395       */
1396       image->iptc_profile.length=0;
1397       image->iptc_profile.info=(unsigned char *) NULL;
1398     }
1399   profile=(StringInfo *) RemoveNodeFromSplayTree((SplayTreeInfo *)
1400     image->profiles,name);
1401   return(profile);
1402 }
1403 \f
1404 /*
1405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1406 %                                                                             %
1407 %                                                                             %
1408 %                                                                             %
1409 %   R e s e t P r o f i l e I t e r a t o r                                   %
1410 %                                                                             %
1411 %                                                                             %
1412 %                                                                             %
1413 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1414 %
1415 %  ResetImageProfileIterator() resets the image profile iterator.  Use it in
1416 %  conjunction with GetNextImageProfile() to iterate over all the profiles
1417 %  associated with an image.
1418 %
1419 %  The format of the ResetImageProfileIterator method is:
1420 %
1421 %      ResetImageProfileIterator(Image *image)
1422 %
1423 %  A description of each parameter follows:
1424 %
1425 %    o image: the image.
1426 %
1427 */
1428 MagickExport void ResetImageProfileIterator(const Image *image)
1429 {
1430   assert(image != (Image *) NULL);
1431   assert(image->signature == MagickSignature);
1432   if (image->debug != MagickFalse)
1433     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1434   if (image->profiles == (SplayTreeInfo *) NULL)
1435     return;
1436   ResetSplayTreeIterator((SplayTreeInfo *) image->profiles);
1437 }
1438 \f
1439 /*
1440 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1441 %                                                                             %
1442 %                                                                             %
1443 %                                                                             %
1444 %   S e t I m a g e P r o f i l e                                             %
1445 %                                                                             %
1446 %                                                                             %
1447 %                                                                             %
1448 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1449 %
1450 %  SetImageProfile() adds a named profile to the image.  If a profile with the
1451 %  same name already exists, it is replaced.  This method differs from the
1452 %  ProfileImage() method in that it does not apply CMS color profiles.
1453 %
1454 %  The format of the SetImageProfile method is:
1455 %
1456 %      MagickBooleanType SetImageProfile(Image *image,const char *name,
1457 %        const StringInfo *profile)
1458 %
1459 %  A description of each parameter follows:
1460 %
1461 %    o image: the image.
1462 %
1463 %    o name: the profile name, for example icc, exif, and 8bim (8bim is the
1464 %      Photoshop wrapper for iptc profiles).
1465 %
1466 %    o profile: A StringInfo structure that contains the named profile.
1467 %
1468 */
1469
1470 static void *DestroyProfile(void *profile)
1471 {
1472   return((void *) DestroyStringInfo((StringInfo *) profile));
1473 }
1474
1475 static inline const unsigned char *ReadResourceByte(const unsigned char *p,
1476   unsigned char *quantum)
1477 {
1478   *quantum=(*p++);
1479   return(p);
1480 }
1481
1482 static inline const unsigned char *ReadResourceBytes(const unsigned char *p,
1483   const ssize_t count,unsigned char *quantum)
1484 {
1485   register ssize_t
1486     i;
1487
1488   for (i=0; i < count; i++)
1489     *quantum++=(*p++);
1490   return(p);
1491 }
1492
1493 static inline const unsigned char *ReadResourceLong(const unsigned char *p,
1494   size_t *quantum)
1495 {
1496   *quantum=(size_t) (*p++ << 24);
1497   *quantum|=(size_t) (*p++ << 16);
1498   *quantum|=(size_t) (*p++ << 8);
1499   *quantum|=(size_t) (*p++ << 0);
1500   return(p);
1501 }
1502
1503 static inline const unsigned char *ReadResourceShort(const unsigned char *p,
1504   unsigned short *quantum)
1505 {
1506   *quantum=(unsigned short) (*p++ << 8);
1507   *quantum|=(unsigned short) (*p++ << 0);
1508   return(p);
1509 }
1510
1511 static MagickBooleanType GetProfilesFromResourceBlock(Image *image,
1512   const StringInfo *resource_block)
1513 {
1514   const unsigned char
1515     *datum;
1516
1517   register const unsigned char
1518     *p;
1519
1520   size_t
1521     length;
1522
1523   StringInfo
1524     *profile;
1525
1526   unsigned char
1527     length_byte;
1528
1529   size_t
1530     count;
1531
1532   unsigned short
1533     id;
1534
1535   datum=GetStringInfoDatum(resource_block);
1536   length=GetStringInfoLength(resource_block);
1537   for (p=datum; p < (datum+length-16); )
1538   {
1539     if (LocaleNCompare((char *) p,"8BIM",4) != 0)
1540       break;
1541     p+=4;
1542     p=ReadResourceShort(p,&id);
1543     p=ReadResourceByte(p,&length_byte);
1544     p+=length_byte;
1545     if (((length_byte+1) & 0x01) != 0)
1546       p++;
1547     if (p > (datum+length-4))
1548       break;
1549     p=ReadResourceLong(p,&count);
1550     if ((p > (datum+length-count)) || (count > length))
1551       break;
1552     switch (id)
1553     {
1554       case 0x03ed:
1555       {
1556         unsigned short
1557           resolution;
1558
1559         /*
1560           Resolution.
1561         */
1562         p=ReadResourceShort(p,&resolution)+6;
1563         image->x_resolution=(double) resolution;
1564         p=ReadResourceShort(p,&resolution)+6;
1565         image->y_resolution=(double) resolution;
1566         break;
1567       }
1568       case 0x0404:
1569       {
1570         /*
1571           IPTC Profile
1572         */
1573         profile=AcquireStringInfo(count);
1574         SetStringInfoDatum(profile,p);
1575         (void) SetImageProfile(image,"iptc",profile);
1576         profile=DestroyStringInfo(profile);
1577         p+=count;
1578         break;
1579       }
1580       case 0x040c:
1581       {
1582         /*
1583           Thumbnail.
1584         */
1585         p+=count;
1586         break;
1587       }
1588       case 0x040f:
1589       {
1590         /*
1591           ICC Profile.
1592         */
1593         profile=AcquireStringInfo(count);
1594         SetStringInfoDatum(profile,p);
1595         (void) SetImageProfile(image,"icc",profile);
1596         profile=DestroyStringInfo(profile);
1597         p+=count;
1598         break;
1599       }
1600       case 0x0422:
1601       {
1602         /*
1603           EXIF Profile.
1604         */
1605         profile=AcquireStringInfo(count);
1606         SetStringInfoDatum(profile,p);
1607         (void) SetImageProfile(image,"exif",profile);
1608         profile=DestroyStringInfo(profile);
1609         p+=count;
1610         break;
1611       }
1612       case 0x0424:
1613       {
1614         /*
1615           XMP Profile.
1616         */
1617         profile=AcquireStringInfo(count);
1618         SetStringInfoDatum(profile,p);
1619         (void) SetImageProfile(image,"xmp",profile);
1620         profile=DestroyStringInfo(profile);
1621         p+=count;
1622         break;
1623       }
1624       default:
1625       {
1626         p+=count;
1627         break;
1628       }
1629     }
1630     if ((count & 0x01) != 0)
1631       p++;
1632   }
1633   return(MagickTrue);
1634 }
1635
1636 MagickExport MagickBooleanType SetImageProfile(Image *image,const char *name,
1637   const StringInfo *profile)
1638 {
1639   char
1640     key[MaxTextExtent],
1641     property[MaxTextExtent];
1642
1643   MagickBooleanType
1644     status;
1645
1646   assert(image != (Image *) NULL);
1647   assert(image->signature == MagickSignature);
1648   if (image->debug != MagickFalse)
1649     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1650   if (image->profiles == (SplayTreeInfo *) NULL)
1651     image->profiles=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
1652       DestroyProfile);
1653   (void) CopyMagickString(key,name,MaxTextExtent);
1654   status=AddValueToSplayTree((SplayTreeInfo *) image->profiles,
1655     ConstantString(key),CloneStringInfo(profile));
1656   if ((status != MagickFalse) &&
1657       ((LocaleCompare(name,"icc") == 0) || (LocaleCompare(name,"icm") == 0)))
1658     {
1659       const StringInfo
1660         *icc_profile;
1661
1662       /*
1663         Continue to support deprecated color profile member.
1664       */
1665       icc_profile=GetImageProfile(image,name);
1666       if (icc_profile != (const StringInfo *) NULL)
1667         {
1668           image->color_profile.length=GetStringInfoLength(icc_profile);
1669           image->color_profile.info=GetStringInfoDatum(icc_profile);
1670         }
1671     }
1672   if ((status != MagickFalse) &&
1673       ((LocaleCompare(name,"iptc") == 0) || (LocaleCompare(name,"8bim") == 0)))
1674     {
1675       const StringInfo
1676         *iptc_profile;
1677
1678       /*
1679         Continue to support deprecated IPTC profile member.
1680       */
1681       iptc_profile=GetImageProfile(image,name);
1682       if (iptc_profile != (const StringInfo *) NULL)
1683         {
1684           image->iptc_profile.length=GetStringInfoLength(iptc_profile);
1685           image->iptc_profile.info=GetStringInfoDatum(iptc_profile);
1686         }
1687       (void) GetProfilesFromResourceBlock(image,profile);
1688     }
1689   /*
1690     Inject profile into image properties.
1691   */
1692   (void) FormatMagickString(property,MaxTextExtent,"%s:sans",name);
1693   (void) GetImageProperty(image,property);
1694   return(status);
1695 }
1696 \f
1697 /*
1698 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1699 %                                                                             %
1700 %                                                                             %
1701 %                                                                             %
1702 %   S y n c I m a g e P r o f i l e s                                         %
1703 %                                                                             %
1704 %                                                                             %
1705 %                                                                             %
1706 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1707 %
1708 %  SyncImageProfiles() synchronizes image properties with the image profiles.
1709 %  Currently we only support updating the EXIF resolution and orientation.
1710 %
1711 %  The format of the SyncImageProfiles method is:
1712 %
1713 %      MagickBooleanType SyncImageProfiles(Image *image)
1714 %
1715 %  A description of each parameter follows:
1716 %
1717 %    o image: the image.
1718 %
1719 */
1720
1721 static inline int ReadProfileByte(unsigned char **p,size_t *length)
1722 {
1723   int
1724     c;
1725
1726   if (*length < 1)
1727     return(EOF);
1728   c=(int) (*(*p)++);
1729   (*length)--;
1730   return(c);
1731 }
1732
1733 static inline unsigned short ReadProfileShort(const EndianType endian,
1734   unsigned char *buffer)
1735 {
1736   unsigned short
1737     value;
1738
1739   if (endian == MSBEndian)
1740     {
1741       value=(unsigned short) ((((unsigned char *) buffer)[0] << 8) |
1742         ((unsigned char *) buffer)[1]);
1743       return((unsigned short) (value & 0xffff));
1744     }
1745   value=(unsigned short) ((buffer[1] << 8) | buffer[0]);
1746   return((unsigned short) (value & 0xffff));
1747 }
1748
1749 static inline size_t ReadProfileLong(const EndianType endian,
1750   unsigned char *buffer)
1751 {
1752   size_t
1753     value;
1754
1755   if (endian == MSBEndian)
1756     {
1757       value=(size_t) ((buffer[0] << 24) | (buffer[1] << 16) |
1758         (buffer[2] << 8) | buffer[3]);
1759       return((size_t) (value & 0xffffffff));
1760     }
1761   value=(size_t) ((buffer[3] << 24) | (buffer[2] << 16) |
1762     (buffer[1] << 8 ) | (buffer[0]));
1763   return((size_t) (value & 0xffffffff));
1764 }
1765
1766 static inline void WriteProfileLong(const EndianType endian,
1767   const size_t value,unsigned char *p)
1768 {
1769   unsigned char
1770     buffer[4];
1771
1772   if (endian == MSBEndian)
1773     {
1774       buffer[0]=(unsigned char) (value >> 24);
1775       buffer[1]=(unsigned char) (value >> 16);
1776       buffer[2]=(unsigned char) (value >> 8);
1777       buffer[3]=(unsigned char) value;
1778       (void) CopyMagickMemory(p,buffer,4);
1779       return;
1780     }
1781   buffer[0]=(unsigned char) value;
1782   buffer[1]=(unsigned char) (value >> 8);
1783   buffer[2]=(unsigned char) (value >> 16);
1784   buffer[3]=(unsigned char) (value >> 24);
1785   (void) CopyMagickMemory(p,buffer,4);
1786 }
1787
1788 static void WriteProfileShort(const EndianType endian,
1789   const unsigned short value,unsigned char *p)
1790 {
1791   unsigned char
1792     buffer[2];
1793
1794   if (endian == MSBEndian)
1795     {
1796       buffer[0]=(unsigned char) (value >> 8);
1797       buffer[1]=(unsigned char) value;
1798       (void) CopyMagickMemory(p,buffer,2);
1799       return;
1800     }
1801   buffer[0]=(unsigned char) value;
1802   buffer[1]=(unsigned char) (value >> 8);
1803   (void) CopyMagickMemory(p,buffer,2);
1804 }
1805
1806 MagickExport MagickBooleanType SyncImageProfiles(Image *image)
1807 {
1808 #define MaxDirectoryStack  16
1809 #define EXIF_DELIMITER  "\n"
1810 #define EXIF_NUM_FORMATS  12
1811 #define TAG_EXIF_OFFSET  0x8769
1812 #define TAG_INTEROP_OFFSET  0xa005
1813
1814   typedef struct _DirectoryInfo
1815   {
1816     unsigned char
1817       *directory;
1818
1819     size_t
1820       entry;
1821   } DirectoryInfo;
1822
1823   DirectoryInfo
1824     directory_stack[MaxDirectoryStack];
1825
1826   EndianType
1827     endian;
1828
1829   ssize_t
1830     id,
1831     level;
1832
1833   size_t
1834     length;
1835
1836   ssize_t
1837     offset;
1838
1839   static int
1840     format_bytes[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
1841
1842   StringInfo
1843     *profile;
1844
1845   unsigned char
1846     *directory,
1847     *exif;
1848
1849   size_t
1850     entry,
1851     number_entries;
1852
1853   /*
1854     Set EXIF resolution tag.
1855   */
1856   profile=(StringInfo *) GetImageProfile(image,"EXIF");
1857   if (profile == (StringInfo *) NULL)
1858     return(MagickTrue);
1859   length=GetStringInfoLength(profile);
1860   exif=GetStringInfoDatum(profile);
1861   while (length != 0)
1862   {
1863     if (ReadProfileByte(&exif,&length) != 0x45)
1864       continue;
1865     if (ReadProfileByte(&exif,&length) != 0x78)
1866       continue;
1867     if (ReadProfileByte(&exif,&length) != 0x69)
1868       continue;
1869     if (ReadProfileByte(&exif,&length) != 0x66)
1870       continue;
1871     if (ReadProfileByte(&exif,&length) != 0x00)
1872       continue;
1873     if (ReadProfileByte(&exif,&length) != 0x00)
1874       continue;
1875     break;
1876   }
1877   if (length < 16)
1878     return(MagickFalse);
1879   id=(int) ReadProfileShort(LSBEndian,exif);
1880   endian=LSBEndian;
1881   if (id == 0x4949)
1882     endian=LSBEndian;
1883   else
1884     if (id == 0x4D4D)
1885       endian=MSBEndian;
1886     else
1887       return(MagickFalse);
1888   if (ReadProfileShort(endian,exif+2) != 0x002a)
1889     return(MagickFalse);
1890   /*
1891     This the offset to the first IFD.
1892   */
1893   offset=(ssize_t) ReadProfileLong(endian,exif+4);
1894   if ((size_t) offset >= length)
1895     return(MagickFalse);
1896   directory=exif+offset;
1897   level=0;
1898   entry=0;
1899   do
1900   {
1901     if (level > 0)
1902       {
1903         level--;
1904         directory=directory_stack[level].directory;
1905         entry=directory_stack[level].entry;
1906       }
1907     /*
1908       Determine how many entries there are in the current IFD.
1909     */
1910     number_entries=ReadProfileShort(endian,directory);
1911     for ( ; entry < number_entries; entry++)
1912     {
1913       ssize_t
1914         components,
1915         format,
1916         tag_value;
1917
1918       register unsigned char
1919         *p,
1920         *q;
1921
1922       size_t
1923         number_bytes;
1924
1925       q=(unsigned char *) (directory+2+(12*entry));
1926       tag_value=(ssize_t) ReadProfileShort(endian,q);
1927       format=(ssize_t) ReadProfileShort(endian,q+2);
1928       if ((format-1) >= EXIF_NUM_FORMATS)
1929         break;
1930       components=(ssize_t) ReadProfileLong(endian,q+4);
1931       number_bytes=(size_t) components*format_bytes[format];
1932       if (number_bytes <= 4)
1933         p=q+8;
1934       else
1935         {
1936           ssize_t
1937             offset;
1938
1939           /*
1940             The directory entry contains an offset.
1941           */
1942           offset=(ssize_t) ReadProfileLong(endian,q+8);
1943           if ((size_t) (offset+number_bytes) > length)
1944             continue;
1945           p=(unsigned char *) (exif+offset);
1946         }
1947       switch (tag_value)
1948       {
1949         case 0x011a:
1950         {
1951           (void) WriteProfileLong(endian,(size_t)
1952             (image->x_resolution+0.5),p);
1953           (void) WriteProfileLong(endian,1UL,p+4);
1954           break;
1955         }
1956         case 0x011b:
1957         {
1958           (void) WriteProfileLong(endian,(size_t)
1959             (image->y_resolution+0.5),p);
1960           (void) WriteProfileLong(endian,1UL,p+4);
1961           break;
1962         }
1963         case 0x0112:
1964         {
1965           (void) WriteProfileShort(endian,(unsigned short)
1966             image->orientation,p);
1967           break;
1968         }
1969         case 0x0128:
1970         {
1971           (void) WriteProfileShort(endian,(unsigned short)
1972             (image->units+1),p);
1973           break;
1974         }
1975         default:
1976           break;
1977       }
1978       if ((tag_value == TAG_EXIF_OFFSET) || (tag_value == TAG_INTEROP_OFFSET))
1979         {
1980           size_t
1981             offset;
1982
1983           offset=(size_t) ReadProfileLong(endian,p);
1984           if ((offset < length) && (level < (MaxDirectoryStack-2)))
1985             {
1986               directory_stack[level].directory=directory;
1987               entry++;
1988               directory_stack[level].entry=entry;
1989               level++;
1990               directory_stack[level].directory=exif+offset;
1991               directory_stack[level].entry=0;
1992               level++;
1993               if ((directory+2+(12*number_entries)) > (exif+length))
1994                 break;
1995               offset=(size_t) ReadProfileLong(endian,directory+2+(12*
1996                 number_entries));
1997               if ((offset != 0) && (offset < length) &&
1998                   (level < (MaxDirectoryStack-2)))
1999                 {
2000                   directory_stack[level].directory=exif+offset;
2001                   directory_stack[level].entry=0;
2002                   level++;
2003                 }
2004             }
2005           break;
2006         }
2007     }
2008   } while (level > 0);
2009   return(MagickTrue);
2010 }