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