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