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