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