]> 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-2009 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         (void) ThrowMagickException(&image->exception,GetMagickModule(),
903           ImageWarning,"AssociateProfile","`%s'",name);
904       else
905         {
906           CacheView
907             *image_view;
908
909           ColorspaceType
910             source_colorspace,
911             target_colorspace;
912
913           cmsHPROFILE
914             source_profile,
915             target_profile;
916
917           cmsHTRANSFORM
918             *transform;
919
920           DWORD
921             flags,
922             source_type,
923             target_type;
924
925           ExceptionInfo
926             *exception;
927
928           int
929             intent;
930
931           long
932             progress,
933             y;
934
935           MagickBooleanType
936             status;
937
938           size_t
939             length,
940             source_channels,
941             target_channels;
942
943           unsigned short
944             **source_pixels,
945             **target_pixels;
946
947           /*
948             Transform pixel colors as defined by the color profiles.
949           */
950 #if defined(LCMS_VERSION) && (LCMS_VERSION > 1010)
951           cmsSetErrorHandler(LCMSErrorHandler);
952 #else
953           (void) cmsErrorAction(LCMS_ERROR_SHOW);
954 #endif
955           source_profile=cmsOpenProfileFromMem(GetStringInfoDatum(icc_profile),
956             (DWORD) GetStringInfoLength(icc_profile));
957           target_profile=cmsOpenProfileFromMem(GetStringInfoDatum(profile),
958             (DWORD) GetStringInfoLength(profile));
959           if ((source_profile == (cmsHPROFILE) NULL) ||
960               (target_profile == (cmsHPROFILE) NULL))
961             ThrowBinaryException(ResourceLimitError,
962               "ColorspaceColorProfileMismatch",name);
963           switch (cmsGetColorSpace(source_profile))
964           {
965             case icSigCmykData:
966             {
967               source_colorspace=CMYKColorspace;
968               source_type=(DWORD) TYPE_CMYK_16;
969               source_channels=4;
970               break;
971             }
972             case icSigGrayData:
973             {
974               source_colorspace=GRAYColorspace;
975               source_type=(DWORD) TYPE_GRAY_16;
976               source_channels=1;
977               break;
978             }
979             case icSigLabData:
980             {
981               source_colorspace=LabColorspace;
982               source_type=(DWORD) TYPE_Lab_16;
983               source_channels=3;
984               break;
985             }
986             case icSigLuvData:
987             {
988               source_colorspace=YUVColorspace;
989               source_type=(DWORD) TYPE_YUV_16;
990               source_channels=3;
991               break;
992             }
993             case icSigRgbData:
994             {
995               source_colorspace=RGBColorspace;
996               source_type=(DWORD) TYPE_RGB_16;
997               source_channels=3;
998               break;
999             }
1000             case icSigXYZData:
1001             {
1002               source_colorspace=XYZColorspace;
1003               source_type=(DWORD) TYPE_XYZ_16;
1004               source_channels=3;
1005               break;
1006             }
1007             case icSigYCbCrData:
1008             {
1009               source_colorspace=YCbCrColorspace;
1010               source_type=(DWORD) TYPE_YCbCr_16;
1011               source_channels=3;
1012               break;
1013             }
1014             default:
1015             {
1016               source_colorspace=UndefinedColorspace;
1017               source_type=(DWORD) TYPE_RGB_16;
1018               source_channels=3;
1019               break;
1020             }
1021           }
1022           switch (cmsGetColorSpace(target_profile))
1023           {
1024             case icSigCmykData:
1025             {
1026               target_colorspace=CMYKColorspace;
1027               target_type=(DWORD) TYPE_CMYK_16;
1028               target_channels=4;
1029               break;
1030             }
1031             case icSigLabData:
1032             {
1033               target_colorspace=LabColorspace;
1034               target_type=(DWORD) TYPE_Lab_16;
1035               target_channels=3;
1036               break;
1037             }
1038             case icSigGrayData:
1039             {
1040               target_colorspace=GRAYColorspace;
1041               target_type=(DWORD) TYPE_GRAY_16;
1042               target_channels=1;
1043               break;
1044             }
1045             case icSigLuvData:
1046             {
1047               target_colorspace=YUVColorspace;
1048               target_type=(DWORD) TYPE_YUV_16;
1049               target_channels=3;
1050               break;
1051             }
1052             case icSigRgbData:
1053             {
1054               target_colorspace=RGBColorspace;
1055               target_type=(DWORD) TYPE_RGB_16;
1056               target_channels=3;
1057               break;
1058             }
1059             case icSigXYZData:
1060             {
1061               target_colorspace=XYZColorspace;
1062               target_type=(DWORD) TYPE_XYZ_16;
1063               target_channels=3;
1064               break;
1065             }
1066             case icSigYCbCrData:
1067             {
1068               target_colorspace=YCbCrColorspace;
1069               target_type=(DWORD) TYPE_YCbCr_16;
1070               target_channels=3;
1071               break;
1072             }
1073             default:
1074             {
1075               target_colorspace=UndefinedColorspace;
1076               target_type=(DWORD) TYPE_RGB_16;
1077               target_channels=3;
1078               break;
1079             }
1080           }
1081           exception=(&image->exception);
1082           if ((source_colorspace == UndefinedColorspace) ||
1083               (target_colorspace == UndefinedColorspace))
1084             ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1085               name);
1086            if ((source_colorspace == GRAYColorspace) &&
1087                (IsGrayImage(image,exception) == MagickFalse))
1088             ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1089               name);
1090            if ((source_colorspace == CMYKColorspace) &&
1091                (image->colorspace != CMYKColorspace))
1092             ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1093               name);
1094            if ((source_colorspace == XYZColorspace) &&
1095                (image->colorspace != XYZColorspace))
1096             ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1097               name);
1098            if ((source_colorspace == YCbCrColorspace) &&
1099                (image->colorspace != YCbCrColorspace))
1100             ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1101               name);
1102            if ((source_colorspace != CMYKColorspace) &&
1103                (source_colorspace != GRAYColorspace) &&
1104                (source_colorspace != LabColorspace) &&
1105                (source_colorspace != XYZColorspace) &&
1106                (source_colorspace != YCbCrColorspace) &&
1107                (image->colorspace != RGBColorspace))
1108             ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
1109               name);
1110           switch (image->rendering_intent)
1111           {
1112             case AbsoluteIntent: intent=INTENT_ABSOLUTE_COLORIMETRIC; break;
1113             case PerceptualIntent: intent=INTENT_PERCEPTUAL; break;
1114             case RelativeIntent: intent=INTENT_RELATIVE_COLORIMETRIC; break;
1115             case SaturationIntent: intent=INTENT_SATURATION; break;
1116             default: intent=INTENT_PERCEPTUAL; break;
1117           }
1118           flags=cmsFLAGS_HIGHRESPRECALC;
1119 #if defined(cmsFLAGS_BLACKPOINTCOMPENSATION)
1120           if (image->black_point_compensation != MagickFalse)
1121             flags|=cmsFLAGS_BLACKPOINTCOMPENSATION;
1122 #endif
1123           transform=AcquireTransformThreadSet(source_profile,source_type,
1124             target_profile,target_type,intent,flags);
1125           (void) cmsCloseProfile(source_profile);
1126           if (transform == (cmsHTRANSFORM *) NULL)
1127             ThrowBinaryException(ImageError,"UnableToCreateColorTransform",
1128               name);
1129           /*
1130             Transform image as dictated by the source and target image profiles.
1131           */
1132           length=(size_t) image->columns;
1133           source_pixels=AcquirePixelThreadSet(image->columns,source_channels);
1134           target_pixels=AcquirePixelThreadSet(image->columns,target_channels);
1135           if ((source_pixels == (unsigned short **) NULL) ||
1136               (target_pixels == (unsigned short **) NULL))
1137             {
1138               transform=DestroyTransformThreadSet(transform);
1139               (void) cmsCloseProfile(target_profile);
1140               ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1141                 image->filename);
1142             }
1143           if (SetImageStorageClass(image,DirectClass) == MagickFalse)
1144             {
1145               target_pixels=DestroyPixelThreadSet(target_pixels);
1146               source_pixels=DestroyPixelThreadSet(source_pixels);
1147               transform=DestroyTransformThreadSet(transform);
1148               (void) cmsCloseProfile(target_profile);
1149               return(MagickFalse);
1150             }
1151           if (target_colorspace == CMYKColorspace)
1152             (void) SetImageColorspace(image,target_colorspace);
1153           status=MagickTrue;
1154           progress=0;
1155           image_view=AcquireCacheView(image);
1156 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1157           #pragma omp parallel for schedule(dynamic,4) shared(status)
1158 #endif
1159           for (y=0; y < (long) image->rows; y++)
1160           {
1161             MagickBooleanType
1162               sync;
1163
1164             register IndexPacket
1165               *__restrict indexes;
1166
1167             register long
1168               id,
1169               x;
1170
1171             register PixelPacket
1172               *__restrict q;
1173
1174             register unsigned short
1175               *p;
1176
1177             if (status == MagickFalse)
1178               continue;
1179             q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1180               exception);
1181             if (q == (PixelPacket *) NULL)
1182               {
1183                 status=MagickFalse;
1184                 continue;
1185               }
1186             indexes=GetCacheViewAuthenticIndexQueue(image_view);
1187             id=GetOpenMPThreadId();
1188             p=source_pixels[id];
1189             for (x=0; x < (long) image->columns; x++)
1190             {
1191               *p++=ScaleQuantumToShort(q->red);
1192               if (source_channels > 1)
1193                 {
1194                   *p++=ScaleQuantumToShort(q->green);
1195                   *p++=ScaleQuantumToShort(q->blue);
1196                 }
1197               if (source_channels > 3)
1198                 *p++=ScaleQuantumToShort(indexes[x]);
1199               q++;
1200             }
1201             cmsDoTransform(transform[id],source_pixels[id],target_pixels[id],
1202               (unsigned int) image->columns);
1203             p=target_pixels[id];
1204             q-=image->columns;
1205             for (x=0; x < (long) image->columns; x++)
1206             {
1207               q->red=ScaleShortToQuantum(*p);
1208               q->green=q->red;
1209               q->blue=q->red;
1210               p++;
1211               if (target_channels > 1)
1212                 {
1213                   q->green=ScaleShortToQuantum(*p);
1214                   p++;
1215                   q->blue=ScaleShortToQuantum(*p);
1216                   p++;
1217                 }
1218               if (target_channels > 3)
1219                 {
1220                   indexes[x]=ScaleShortToQuantum(*p);
1221                   p++;
1222                 }
1223               q++;
1224             }
1225             sync=SyncCacheViewAuthenticPixels(image_view,exception);
1226             if (sync == MagickFalse)
1227               status=MagickFalse;
1228             if (image->progress_monitor != (MagickProgressMonitor) NULL)
1229               {
1230                 MagickBooleanType
1231                   proceed;
1232
1233 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1234   #pragma omp critical (MagickCore_ProfileImage)
1235 #endif
1236                 proceed=SetImageProgress(image,ProfileImageTag,progress++,
1237                   image->rows);
1238                 if (proceed == MagickFalse)
1239                   status=MagickFalse;
1240               }
1241           }
1242           image_view=DestroyCacheView(image_view);
1243           (void) SetImageColorspace(image,target_colorspace);
1244           switch (cmsGetColorSpace(target_profile))
1245           {
1246             case icSigRgbData:
1247             {
1248               image->type=image->matte == MagickFalse ? TrueColorType :
1249                 TrueColorMatteType;
1250               break;
1251             }
1252             case icSigCmykData:
1253             {
1254               image->type=image->matte == MagickFalse ? ColorSeparationType :
1255                 ColorSeparationMatteType;
1256               break;
1257             }
1258             case icSigGrayData:
1259             {
1260               image->type=image->matte == MagickFalse ? GrayscaleType :
1261                 GrayscaleMatteType;
1262               break;
1263             }
1264             default:
1265               break;
1266           }
1267           target_pixels=DestroyPixelThreadSet(target_pixels);
1268           source_pixels=DestroyPixelThreadSet(source_pixels);
1269           transform=DestroyTransformThreadSet(transform);
1270           (void) cmsCloseProfile(target_profile);
1271         }
1272 #endif
1273     }
1274   status=SetImageProfile(image,name,profile);
1275   profile=DestroyStringInfo(profile);
1276   return(status);
1277 }
1278 \f
1279 /*
1280 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1281 %                                                                             %
1282 %                                                                             %
1283 %                                                                             %
1284 %   R e m o v e I m a g e P r o f i l e                                       %
1285 %                                                                             %
1286 %                                                                             %
1287 %                                                                             %
1288 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1289 %
1290 %  RemoveImageProfile() removes a named profile from the image and returns its
1291 %  value.
1292 %
1293 %  The format of the RemoveImageProfile method is:
1294 %
1295 %      void *RemoveImageProfile(Image *image,const char *name)
1296 %
1297 %  A description of each parameter follows:
1298 %
1299 %    o image: the image.
1300 %
1301 %    o name: the profile name.
1302 %
1303 */
1304 MagickExport StringInfo *RemoveImageProfile(Image *image,const char *name)
1305 {
1306   StringInfo
1307     *profile;
1308
1309   assert(image != (Image *) NULL);
1310   assert(image->signature == MagickSignature);
1311   if (image->debug != MagickFalse)
1312     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1313   if (image->profiles == (SplayTreeInfo *) NULL)
1314     return((StringInfo *) NULL);
1315   if (LocaleCompare(name,"icc") == 0)
1316     {
1317       /*
1318         Continue to support deprecated color profile for now.
1319       */
1320       image->color_profile.length=0;
1321       image->color_profile.info=(unsigned char *) NULL;
1322     }
1323   if (LocaleCompare(name,"iptc") == 0)
1324     {
1325       /*
1326         Continue to support deprecated IPTC profile for now.
1327       */
1328       image->iptc_profile.length=0;
1329       image->iptc_profile.info=(unsigned char *) NULL;
1330     }
1331   profile=(StringInfo *) RemoveNodeFromSplayTree((SplayTreeInfo *)
1332     image->profiles,name);
1333   return(profile);
1334 }
1335 \f
1336 /*
1337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1338 %                                                                             %
1339 %                                                                             %
1340 %                                                                             %
1341 %   R e s e t P r o f i l e I t e r a t o r                                   %
1342 %                                                                             %
1343 %                                                                             %
1344 %                                                                             %
1345 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1346 %
1347 %  ResetImageProfileIterator() resets the image profile iterator.  Use it in
1348 %  conjunction with GetNextImageProfile() to iterate over all the profiles
1349 %  associated with an image.
1350 %
1351 %  The format of the ResetImageProfileIterator method is:
1352 %
1353 %      ResetImageProfileIterator(Image *image)
1354 %
1355 %  A description of each parameter follows:
1356 %
1357 %    o image: the image.
1358 %
1359 */
1360 MagickExport void ResetImageProfileIterator(const Image *image)
1361 {
1362   assert(image != (Image *) NULL);
1363   assert(image->signature == MagickSignature);
1364   if (image->debug != MagickFalse)
1365     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1366   if (image->profiles == (SplayTreeInfo *) NULL)
1367     return;
1368   ResetSplayTreeIterator((SplayTreeInfo *) image->profiles);
1369 }
1370 \f
1371 /*
1372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1373 %                                                                             %
1374 %                                                                             %
1375 %                                                                             %
1376 %   S e t I m a g e P r o f i l e                                             %
1377 %                                                                             %
1378 %                                                                             %
1379 %                                                                             %
1380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1381 %
1382 %  SetImageProfile() adds a named profile to the image.  If a profile with the
1383 %  same name already exists, it is replaced.  This method differs from the
1384 %  ProfileImage() method in that it does not apply CMS color profiles.
1385 %
1386 %  The format of the SetImageProfile method is:
1387 %
1388 %      MagickBooleanType SetImageProfile(Image *image,const char *name,
1389 %        const StringInfo *profile)
1390 %
1391 %  A description of each parameter follows:
1392 %
1393 %    o image: the image.
1394 %
1395 %    o name: the profile name, for example icc, exif, and 8bim (8bim is the
1396 %      Photoshop wrapper for iptc profiles).
1397 %
1398 %    o profile: A StringInfo structure that contains the named profile.
1399 %
1400 */
1401
1402 static void *DestroyProfile(void *profile)
1403 {
1404   return((void *) DestroyStringInfo((StringInfo *) profile));
1405 }
1406
1407 static inline const unsigned char *ReadResourceByte(const unsigned char *p,
1408   unsigned char *quantum)
1409 {
1410   *quantum=(*p++);
1411   return(p);
1412 }
1413
1414 static inline const unsigned char *ReadResourceBytes(const unsigned char *p,
1415   const ssize_t count,unsigned char *quantum)
1416 {
1417   register ssize_t
1418     i;
1419
1420   for (i=0; i < count; i++)
1421     *quantum++=(*p++);
1422   return(p);
1423 }
1424
1425 static inline const unsigned char *ReadResourceLong(const unsigned char *p,
1426   unsigned long *quantum)
1427 {
1428   *quantum=(unsigned long) (*p++ << 24);
1429   *quantum|=(unsigned long) (*p++ << 16);
1430   *quantum|=(unsigned long) (*p++ << 8);
1431   *quantum|=(unsigned long) (*p++ << 0);
1432   return(p);
1433 }
1434
1435 static inline const unsigned char *ReadResourceShort(const unsigned char *p,
1436   unsigned short *quantum)
1437 {
1438   *quantum=(unsigned short) (*p++ << 8);
1439   *quantum|=(unsigned short) (*p++ << 0);
1440   return(p);
1441 }
1442
1443 static MagickBooleanType GetProfilesFromResourceBlock(Image *image,
1444   const StringInfo *resource_block)
1445 {
1446   const unsigned char
1447     *datum;
1448
1449   register const unsigned char
1450     *p;
1451
1452   size_t
1453     length;
1454
1455   StringInfo
1456     *profile;
1457
1458   unsigned char
1459     length_byte;
1460
1461   unsigned long
1462     count;
1463
1464   unsigned short
1465     id;
1466
1467   datum=GetStringInfoDatum(resource_block);
1468   length=GetStringInfoLength(resource_block);
1469   for (p=datum; p < (datum+length-16); )
1470   {
1471     if (LocaleNCompare((char *) p,"8BIM",4) != 0)
1472       break;
1473     p+=4;
1474     p=ReadResourceShort(p,&id);
1475     p=ReadResourceByte(p,&length_byte);
1476     p+=length_byte;
1477     if (((length_byte+1) & 0x01) != 0)
1478       p++;
1479     if (p > (datum+length-4))
1480       break;
1481     p=ReadResourceLong(p,&count);
1482     if ((p > (datum+length-count)) || (count > length))
1483       break;
1484     switch (id)
1485     {
1486       case 0x03ed:
1487       {
1488         unsigned short
1489           resolution;
1490
1491         /*
1492           Resolution.
1493         */
1494         p=ReadResourceShort(p,&resolution)+6;
1495         image->x_resolution=(double) resolution;
1496         p=ReadResourceShort(p,&resolution)+6;
1497         image->y_resolution=(double) resolution;
1498         break;
1499       }
1500       case 0x0404:
1501       {
1502         /*
1503           IPTC Profile
1504         */
1505         profile=AcquireStringInfo(count);
1506         SetStringInfoDatum(profile,p);
1507         (void) SetImageProfile(image,"iptc",profile);
1508         profile=DestroyStringInfo(profile);
1509         p+=count;
1510         break;
1511       }
1512       case 0x040c:
1513       {
1514         /*
1515           Thumbnail.
1516         */
1517         p+=count;
1518         break;
1519       }
1520       case 0x040f:
1521       {
1522         /*
1523           ICC Profile.
1524         */
1525         profile=AcquireStringInfo(count);
1526         SetStringInfoDatum(profile,p);
1527         (void) SetImageProfile(image,"icc",profile);
1528         profile=DestroyStringInfo(profile);
1529         p+=count;
1530         break;
1531       }
1532       case 0x0422:
1533       {
1534         /*
1535           EXIF Profile.
1536         */
1537         profile=AcquireStringInfo(count);
1538         SetStringInfoDatum(profile,p);
1539         (void) SetImageProfile(image,"exif",profile);
1540         profile=DestroyStringInfo(profile);
1541         p+=count;
1542         break;
1543       }
1544       case 0x0424:
1545       {
1546         /*
1547           XMP Profile.
1548         */
1549         profile=AcquireStringInfo(count);
1550         SetStringInfoDatum(profile,p);
1551         (void) SetImageProfile(image,"xmp",profile);
1552         profile=DestroyStringInfo(profile);
1553         p+=count;
1554         break;
1555       }
1556       default:
1557       {
1558         p+=count;
1559         break;
1560       }
1561     }
1562     if ((count & 0x01) != 0)
1563       p++;
1564   }
1565   return(MagickTrue);
1566 }
1567
1568 MagickExport MagickBooleanType SetImageProfile(Image *image,const char *name,
1569   const StringInfo *profile)
1570 {
1571   char
1572     key[MaxTextExtent],
1573     property[MaxTextExtent];
1574
1575   MagickBooleanType
1576     status;
1577
1578   assert(image != (Image *) NULL);
1579   assert(image->signature == MagickSignature);
1580   if (image->debug != MagickFalse)
1581     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1582   if (image->profiles == (SplayTreeInfo *) NULL)
1583     image->profiles=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
1584       DestroyProfile);
1585   (void) CopyMagickString(key,name,MaxTextExtent);
1586   status=AddValueToSplayTree((SplayTreeInfo *) image->profiles,
1587     ConstantString(key),CloneStringInfo(profile));
1588   if ((status != MagickFalse) &&
1589       ((LocaleCompare(name,"icc") == 0) || (LocaleCompare(name,"icm") == 0)))
1590     {
1591       const StringInfo
1592         *icc_profile;
1593
1594       /*
1595         Continue to support deprecated color profile member.
1596       */
1597       icc_profile=GetImageProfile(image,name);
1598       if (icc_profile != (const StringInfo *) NULL)
1599         {
1600           image->color_profile.length=GetStringInfoLength(icc_profile);
1601           image->color_profile.info=GetStringInfoDatum(icc_profile);
1602         }
1603     }
1604   if ((status != MagickFalse) &&
1605       ((LocaleCompare(name,"iptc") == 0) || (LocaleCompare(name,"8bim") == 0)))
1606     {
1607       const StringInfo
1608         *iptc_profile;
1609
1610       /*
1611         Continue to support deprecated IPTC profile member.
1612       */
1613       iptc_profile=GetImageProfile(image,name);
1614       if (iptc_profile != (const StringInfo *) NULL)
1615         {
1616           image->iptc_profile.length=GetStringInfoLength(iptc_profile);
1617           image->iptc_profile.info=GetStringInfoDatum(iptc_profile);
1618         }
1619       (void) GetProfilesFromResourceBlock(image,profile);
1620     }
1621   /*
1622     Inject profile into image properties.
1623   */
1624   (void) FormatMagickString(property,MaxTextExtent,"%s:sans",name);
1625   (void) GetImageProperty(image,property);
1626   return(status);
1627 }
1628 \f
1629 /*
1630 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1631 %                                                                             %
1632 %                                                                             %
1633 %                                                                             %
1634 %   S y n c I m a g e P r o f i l e s                                         %
1635 %                                                                             %
1636 %                                                                             %
1637 %                                                                             %
1638 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1639 %
1640 %  SyncImageProfiles() synchronizes image properties with the image profiles.
1641 %  Currently we only support updating the EXIF resolution and orientation.
1642 %
1643 %  The format of the SyncImageProfiles method is:
1644 %
1645 %      MagickBooleanType SyncImageProfiles(Image *image)
1646 %
1647 %  A description of each parameter follows:
1648 %
1649 %    o image: the image.
1650 %
1651 */
1652
1653 static inline int ReadProfileByte(unsigned char **p,size_t *length)
1654 {
1655   int
1656     c;
1657
1658   if (*length < 1)
1659     return(EOF);
1660   c=(int) (*(*p)++);
1661   (*length)--;
1662   return(c);
1663 }
1664
1665 static inline unsigned short ReadProfileShort(const EndianType endian,
1666   unsigned char *buffer)
1667 {
1668   unsigned short
1669     value;
1670
1671   if (endian == MSBEndian)
1672     {
1673       value=(unsigned short) ((((unsigned char *) buffer)[0] << 8) |
1674         ((unsigned char *) buffer)[1]);
1675       return((unsigned short) (value & 0xffff));
1676     }
1677   value=(unsigned short) ((buffer[1] << 8) | buffer[0]);
1678   return((unsigned short) (value & 0xffff));
1679 }
1680
1681 static inline unsigned long ReadProfileLong(const EndianType endian,
1682   unsigned char *buffer)
1683 {
1684   unsigned long
1685     value;
1686
1687   if (endian == MSBEndian)
1688     {
1689       value=(unsigned long) ((buffer[0] << 24) | (buffer[1] << 16) |
1690         (buffer[2] << 8) | buffer[3]);
1691       return((unsigned long) (value & 0xffffffff));
1692     }
1693   value=(unsigned long) ((buffer[3] << 24) | (buffer[2] << 16) |
1694     (buffer[1] << 8 ) | (buffer[0]));
1695   return((unsigned long) (value & 0xffffffff));
1696 }
1697
1698 static inline void WriteProfileLong(const EndianType endian,
1699   const unsigned long value,unsigned char *p)
1700 {
1701   unsigned char
1702     buffer[4];
1703
1704   if (endian == MSBEndian)
1705     {
1706       buffer[0]=(unsigned char) (value >> 24);
1707       buffer[1]=(unsigned char) (value >> 16);
1708       buffer[2]=(unsigned char) (value >> 8);
1709       buffer[3]=(unsigned char) value;
1710       (void) CopyMagickMemory(p,buffer,4);
1711       return;
1712     }
1713   buffer[0]=(unsigned char) value;
1714   buffer[1]=(unsigned char) (value >> 8);
1715   buffer[2]=(unsigned char) (value >> 16);
1716   buffer[3]=(unsigned char) (value >> 24);
1717   (void) CopyMagickMemory(p,buffer,4);
1718 }
1719
1720 static void WriteProfileShort(const EndianType endian,
1721   const unsigned short value,unsigned char *p)
1722 {
1723   unsigned char
1724     buffer[2];
1725
1726   if (endian == MSBEndian)
1727     {
1728       buffer[0]=(unsigned char) (value >> 8);
1729       buffer[1]=(unsigned char) value;
1730       (void) CopyMagickMemory(p,buffer,2);
1731       return;
1732     }
1733   buffer[0]=(unsigned char) value;
1734   buffer[1]=(unsigned char) (value >> 8);
1735   (void) CopyMagickMemory(p,buffer,2);
1736 }
1737
1738 MagickExport MagickBooleanType SyncImageProfiles(Image *image)
1739 {
1740 #define MaxDirectoryStack  16
1741 #define EXIF_DELIMITER  "\n"
1742 #define EXIF_NUM_FORMATS  12
1743 #define TAG_EXIF_OFFSET  0x8769
1744 #define TAG_INTEROP_OFFSET  0xa005
1745
1746   typedef struct _DirectoryInfo
1747   {
1748     unsigned char
1749       *directory;
1750
1751     unsigned long
1752       entry;
1753   } DirectoryInfo;
1754
1755   DirectoryInfo
1756     directory_stack[MaxDirectoryStack];
1757
1758   EndianType
1759     endian;
1760
1761   long
1762     id,
1763     level;
1764
1765   size_t
1766     length;
1767
1768   ssize_t
1769     offset;
1770
1771   static int
1772     format_bytes[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
1773
1774   StringInfo
1775     *profile;
1776
1777   unsigned char
1778     *directory,
1779     *exif;
1780
1781   unsigned long
1782     entry,
1783     number_entries;
1784
1785   /*
1786     Set EXIF resolution tag.
1787   */
1788   profile=(StringInfo *) GetImageProfile(image,"EXIF");
1789   if (profile == (StringInfo *) NULL)
1790     return(MagickTrue);
1791   length=GetStringInfoLength(profile);
1792   exif=GetStringInfoDatum(profile);
1793   while (length != 0)
1794   {
1795     if (ReadProfileByte(&exif,&length) != 0x45)
1796       continue;
1797     if (ReadProfileByte(&exif,&length) != 0x78)
1798       continue;
1799     if (ReadProfileByte(&exif,&length) != 0x69)
1800       continue;
1801     if (ReadProfileByte(&exif,&length) != 0x66)
1802       continue;
1803     if (ReadProfileByte(&exif,&length) != 0x00)
1804       continue;
1805     if (ReadProfileByte(&exif,&length) != 0x00)
1806       continue;
1807     break;
1808   }
1809   if (length < 16)
1810     return(MagickFalse);
1811   id=(int) ReadProfileShort(LSBEndian,exif);
1812   endian=LSBEndian;
1813   if (id == 0x4949)
1814     endian=LSBEndian;
1815   else
1816     if (id == 0x4D4D)
1817       endian=MSBEndian;
1818     else
1819       return(MagickFalse);
1820   if (ReadProfileShort(endian,exif+2) != 0x002a)
1821     return(MagickFalse);
1822   /*
1823     This the offset to the first IFD.
1824   */
1825   offset=(ssize_t) ReadProfileLong(endian,exif+4);
1826   if ((size_t) offset >= length)
1827     return(MagickFalse);
1828   directory=exif+offset;
1829   level=0;
1830   entry=0;
1831   do
1832   {
1833     if (level > 0)
1834       {
1835         level--;
1836         directory=directory_stack[level].directory;
1837         entry=directory_stack[level].entry;
1838       }
1839     /*
1840       Determine how many entries there are in the current IFD.
1841     */
1842     number_entries=ReadProfileShort(endian,directory);
1843     for ( ; entry < number_entries; entry++)
1844     {
1845       long
1846         components,
1847         format,
1848         tag_value;
1849
1850       register unsigned char
1851         *p,
1852         *q;
1853
1854       size_t
1855         number_bytes;
1856
1857       q=(unsigned char *) (directory+2+(12*entry));
1858       tag_value=(long) ReadProfileShort(endian,q);
1859       format=(long) ReadProfileShort(endian,q+2);
1860       if ((format-1) >= EXIF_NUM_FORMATS)
1861         break;
1862       components=(long) ReadProfileLong(endian,q+4);
1863       number_bytes=(size_t) components*format_bytes[format];
1864       if (number_bytes <= 4)
1865         p=q+8;
1866       else
1867         {
1868           ssize_t
1869             offset;
1870
1871           /*
1872             The directory entry contains an offset.
1873           */
1874           offset=(ssize_t) ReadProfileLong(endian,q+8);
1875           if ((size_t) (offset+number_bytes) > length)
1876             continue;
1877           p=(unsigned char *) (exif+offset);
1878         }
1879       switch (tag_value)
1880       {
1881         case 0x011a:
1882         {
1883           (void) WriteProfileLong(endian,(unsigned long)
1884             (image->x_resolution+0.5),p);
1885           (void) WriteProfileLong(endian,1UL,p+4);
1886           break;
1887         }
1888         case 0x011b:
1889         {
1890           (void) WriteProfileLong(endian,(unsigned long)
1891             (image->y_resolution+0.5),p);
1892           (void) WriteProfileLong(endian,1UL,p+4);
1893           break;
1894         }
1895         case 0x0112:
1896         {
1897           (void) WriteProfileShort(endian,(unsigned short)
1898             image->orientation,p);
1899           (void) WriteProfileLong(endian,1UL,p+4);
1900           break;
1901         }
1902         case 0x0128:
1903         {
1904           (void) WriteProfileShort(endian,(unsigned short)
1905             (image->units+1),p);
1906           break;
1907         }
1908         default:
1909           break;
1910       }
1911       if ((tag_value == TAG_EXIF_OFFSET) || (tag_value == TAG_INTEROP_OFFSET))
1912         {
1913           size_t
1914             offset;
1915
1916           offset=(size_t) ReadProfileLong(endian,p);
1917           if ((offset < length) && (level < (MaxDirectoryStack-2)))
1918             {
1919               directory_stack[level].directory=directory;
1920               entry++;
1921               directory_stack[level].entry=entry;
1922               level++;
1923               directory_stack[level].directory=exif+offset;
1924               directory_stack[level].entry=0;
1925               level++;
1926               if ((directory+2+(12*number_entries)) > (exif+length))
1927                 break;
1928               offset=(size_t) ReadProfileLong(endian,directory+2+(12*
1929                 number_entries));
1930               if ((offset != 0) && (offset < length) &&
1931                   (level < (MaxDirectoryStack-2)))
1932                 {
1933                   directory_stack[level].directory=exif+offset;
1934                   directory_stack[level].entry=0;
1935                   level++;
1936                 }
1937             }
1938           break;
1939         }
1940     }
1941   } while (level > 0);
1942   return(MagickTrue);
1943 }