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