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