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