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