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