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