]> 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-2015 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,
1518               (unsigned int)profile->length);
1519             (void) CopyMagickMemory(extract_profile->datum+offset,
1520               profile->datum,profile->length);
1521           }
1522         (void) CopyMagickMemory(extract_profile->datum+offset+extract_count,
1523           p+count,extent);
1524         (void) AddValueToSplayTree((SplayTreeInfo *) image->profiles,
1525           ConstantString("8bim"),CloneStringInfo(extract_profile));
1526         extract_profile=DestroyStringInfo(extract_profile);
1527         break;
1528       }
1529   }
1530 }
1531
1532 static void GetProfilesFromResourceBlock(Image *image,
1533   const StringInfo *resource_block,ExceptionInfo *exception)
1534 {
1535   const unsigned char
1536     *datum;
1537
1538   register const unsigned char
1539     *p;
1540
1541   size_t
1542     length;
1543
1544   ssize_t
1545     count;
1546
1547   StringInfo
1548     *profile;
1549
1550   unsigned char
1551     length_byte;
1552
1553    unsigned int
1554      value;
1555
1556   unsigned short
1557     id;
1558
1559   datum=GetStringInfoDatum(resource_block);
1560   length=GetStringInfoLength(resource_block);
1561   for (p=datum; p < (datum+length-16); )
1562   {
1563     if (LocaleNCompare((char *) p,"8BIM",4) != 0)
1564       break;
1565     p+=4;
1566     p=ReadResourceShort(p,&id);
1567     p=ReadResourceByte(p,&length_byte);
1568     p+=length_byte;
1569     if (((length_byte+1) & 0x01) != 0)
1570       p++;
1571     if (p > (datum+length-4))
1572       break;
1573     p=ReadResourceLong(p,&value);
1574     count=(ssize_t) value;
1575     if ((p > (datum+length-count)) || (count > (ssize_t) length))
1576       break;
1577     switch (id)
1578     {
1579       case 0x03ed:
1580       {
1581         unsigned int
1582           resolution;
1583
1584         unsigned short
1585           units;
1586
1587         /*
1588           Resolution.
1589         */
1590         p=ReadResourceLong(p,&resolution);
1591         image->resolution.x=((double) resolution)/65536.0;
1592         p=ReadResourceShort(p,&units)+2;
1593         p=ReadResourceLong(p,&resolution)+4;
1594         image->resolution.y=((double) resolution)/65536.0;
1595         /*
1596           Values are always stored as pixels per inch.
1597         */
1598         if ((ResolutionType) units != PixelsPerCentimeterResolution)
1599           image->units=PixelsPerInchResolution;
1600         else
1601           {
1602             image->units=PixelsPerCentimeterResolution;
1603             image->resolution.x/=2.54;
1604             image->resolution.y/=2.54;
1605           }
1606         break;
1607       }
1608       case 0x0404:
1609       {
1610         /*
1611           IPTC Profile
1612         */
1613         profile=AcquireStringInfo(count);
1614         SetStringInfoDatum(profile,p);
1615         (void) SetImageProfileInternal(image,"iptc",profile,MagickTrue,
1616           exception);
1617         profile=DestroyStringInfo(profile);
1618         p+=count;
1619         break;
1620       }
1621       case 0x040c:
1622       {
1623         /*
1624           Thumbnail.
1625         */
1626         p+=count;
1627         break;
1628       }
1629       case 0x040f:
1630       {
1631         /*
1632           ICC Profile.
1633         */
1634         profile=AcquireStringInfo(count);
1635         SetStringInfoDatum(profile,p);
1636         (void) SetImageProfileInternal(image,"icc",profile,MagickTrue,
1637           exception);
1638         profile=DestroyStringInfo(profile);
1639         p+=count;
1640         break;
1641       }
1642       case 0x0422:
1643       {
1644         /*
1645           EXIF Profile.
1646         */
1647         profile=AcquireStringInfo(count);
1648         SetStringInfoDatum(profile,p);
1649         (void) SetImageProfileInternal(image,"exif",profile,MagickTrue,
1650           exception);
1651         profile=DestroyStringInfo(profile);
1652         p+=count;
1653         break;
1654       }
1655       case 0x0424:
1656       {
1657         /*
1658           XMP Profile.
1659         */
1660         profile=AcquireStringInfo(count);
1661         SetStringInfoDatum(profile,p);
1662         (void) SetImageProfileInternal(image,"xmp",profile,MagickTrue,
1663           exception);
1664         profile=DestroyStringInfo(profile);
1665         p+=count;
1666         break;
1667       }
1668       default:
1669       {
1670         p+=count;
1671         break;
1672       }
1673     }
1674     if ((count & 0x01) != 0)
1675       p++;
1676   }
1677 }
1678
1679 static MagickBooleanType SetImageProfileInternal(Image *image,const char *name,
1680   const StringInfo *profile,const MagickBooleanType recursive,
1681   ExceptionInfo *exception)
1682 {
1683   char
1684     key[MaxTextExtent],
1685     property[MaxTextExtent];
1686
1687   MagickBooleanType
1688     status;
1689
1690   assert(image != (Image *) NULL);
1691   assert(image->signature == MagickSignature);
1692   if (image->debug != MagickFalse)
1693     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1694   if (image->profiles == (SplayTreeInfo *) NULL)
1695     image->profiles=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
1696       DestroyProfile);
1697   (void) CopyMagickString(key,name,MaxTextExtent);
1698   LocaleLower(key);
1699   status=AddValueToSplayTree((SplayTreeInfo *) image->profiles,
1700     ConstantString(key),CloneStringInfo(profile));
1701   if (status != MagickFalse)
1702     {
1703       if (LocaleCompare(name,"8bim") == 0)
1704         GetProfilesFromResourceBlock(image,profile,exception);
1705       else if (recursive == MagickFalse)
1706         WriteTo8BimProfile(image,name,profile);
1707     }
1708   /*
1709     Inject profile into image properties.
1710   */
1711   (void) FormatLocaleString(property,MaxTextExtent,"%s:*",name);
1712   (void) GetImageProperty(image,property,exception);
1713   return(status);
1714 }
1715
1716 MagickExport MagickBooleanType SetImageProfile(Image *image,const char *name,
1717   const StringInfo *profile,ExceptionInfo *exception)
1718 {
1719   return(SetImageProfileInternal(image,name,profile,MagickFalse,exception));
1720 }
1721 \f
1722 /*
1723 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1724 %                                                                             %
1725 %                                                                             %
1726 %                                                                             %
1727 %   S y n c I m a g e P r o f i l e s                                         %
1728 %                                                                             %
1729 %                                                                             %
1730 %                                                                             %
1731 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1732 %
1733 %  SyncImageProfiles() synchronizes image properties with the image profiles.
1734 %  Currently we only support updating the EXIF resolution and orientation.
1735 %
1736 %  The format of the SyncImageProfiles method is:
1737 %
1738 %      MagickBooleanType SyncImageProfiles(Image *image)
1739 %
1740 %  A description of each parameter follows:
1741 %
1742 %    o image: the image.
1743 %
1744 */
1745
1746 static inline int ReadProfileByte(unsigned char **p,size_t *length)
1747 {
1748   int
1749     c;
1750
1751   if (*length < 1)
1752     return(EOF);
1753   c=(int) (*(*p)++);
1754   (*length)--;
1755   return(c);
1756 }
1757
1758 static inline unsigned short ReadProfileShort(const EndianType endian,
1759   unsigned char *buffer)
1760 {
1761   unsigned short
1762     value;
1763
1764   if (endian == LSBEndian)
1765     {
1766       value=(unsigned short) ((buffer[1] << 8) | buffer[0]);
1767       return((unsigned short) (value & 0xffff));
1768     }
1769   value=(unsigned short) ((((unsigned char *) buffer)[0] << 8) |
1770     ((unsigned char *) buffer)[1]);
1771   return((unsigned short) (value & 0xffff));
1772 }
1773
1774 static inline unsigned int ReadProfileLong(const EndianType endian,
1775   unsigned char *buffer)
1776 {
1777   unsigned int
1778     value;
1779
1780   if (endian == LSBEndian)
1781     {
1782       value=(unsigned int) ((buffer[3] << 24) | (buffer[2] << 16) |
1783         (buffer[1] << 8 ) | (buffer[0]));
1784       return((unsigned int) (value & 0xffffffff));
1785     }
1786   value=(unsigned int) ((buffer[0] << 24) | (buffer[1] << 16) |
1787     (buffer[2] << 8) | buffer[3]);
1788   return((unsigned int) (value & 0xffffffff));
1789 }
1790
1791 static inline unsigned int ReadProfileMSBLong(unsigned char **p,size_t *length)
1792 {
1793   unsigned int
1794     value;
1795
1796   if (*length < 4)
1797     return(0);
1798   value=ReadProfileLong(MSBEndian,*p);
1799   (*length)-=4;
1800   *p+=4;
1801   return(value);
1802 }
1803
1804 static inline unsigned short ReadProfileMSBShort(unsigned char **p,
1805   size_t *length)
1806 {
1807   unsigned short
1808     value;
1809
1810   if (*length < 2)
1811     return(0);
1812   value=ReadProfileShort(MSBEndian,*p);
1813   (*length)-=2;
1814   *p+=2;
1815   return(value);
1816 }
1817
1818 static inline void WriteProfileLong(const EndianType endian,
1819   const size_t value,unsigned char *p)
1820 {
1821   unsigned char
1822     buffer[4];
1823
1824   if (endian == LSBEndian)
1825     {
1826       buffer[0]=(unsigned char) value;
1827       buffer[1]=(unsigned char) (value >> 8);
1828       buffer[2]=(unsigned char) (value >> 16);
1829       buffer[3]=(unsigned char) (value >> 24);
1830       (void) CopyMagickMemory(p,buffer,4);
1831       return;
1832     }
1833   buffer[0]=(unsigned char) (value >> 24);
1834   buffer[1]=(unsigned char) (value >> 16);
1835   buffer[2]=(unsigned char) (value >> 8);
1836   buffer[3]=(unsigned char) value;
1837   (void) CopyMagickMemory(p,buffer,4);
1838 }
1839
1840 static void WriteProfileShort(const EndianType endian,
1841   const unsigned short value,unsigned char *p)
1842 {
1843   unsigned char
1844     buffer[2];
1845
1846   if (endian == LSBEndian)
1847     {
1848       buffer[0]=(unsigned char) value;
1849       buffer[1]=(unsigned char) (value >> 8);
1850       (void) CopyMagickMemory(p,buffer,2);
1851       return;
1852     }
1853   buffer[0]=(unsigned char) (value >> 8);
1854   buffer[1]=(unsigned char) value;
1855   (void) CopyMagickMemory(p,buffer,2);
1856 }
1857
1858 static MagickBooleanType Sync8BimProfile(Image *image,StringInfo *profile)
1859 {
1860   size_t
1861     length;
1862
1863   ssize_t
1864     count;
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=(ssize_t) ReadProfileByte(&p,&length);
1888     if (count > (ssize_t) length)
1889       return(MagickFalse);
1890     p+=count;
1891     if ((*p & 0x01) == 0)
1892       (void) ReadProfileByte(&p,&length);
1893     count=(ssize_t) ReadProfileMSBLong(&p,&length);
1894     if (count > (ssize_t) 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 }