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