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