• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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 
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 
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 
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 
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 */
CloneImageProfiles(Image * image,const Image * clone_image)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 
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 */
DeleteImageProfile(Image * image,const char * name)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 
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 */
DestroyImageProfiles(Image * image)254 MagickExport void DestroyImageProfiles(Image *image)
255 {
256   if (image->profiles != (SplayTreeInfo *) NULL)
257     image->profiles=DestroySplayTree((SplayTreeInfo *) image->profiles);
258 }
259 
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 */
GetImageProfile(const Image * image,const char * name)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 
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 */
GetNextImageProfile(const Image * image)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 
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)
DestroyPixelThreadSet(LCMSType ** pixels)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 
AcquirePixelThreadSet(const size_t columns,const size_t channels)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 
DestroyTransformThreadSet(cmsHTRANSFORM * transform)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 
AcquireTransformThreadSet(Image * image,const cmsHPROFILE source_profile,const cmsUInt32Number source_type,const cmsHPROFILE target_profile,const cmsUInt32Number target_type,const int intent,const cmsUInt32Number flags,CMSExceptionInfo * cms_exception)430 static cmsHTRANSFORM *AcquireTransformThreadSet(Image *image,
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)
CMSExceptionHandler(cmsContext context,cmsUInt32Number severity,const char * message)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 
SetsRGBImageProfile(Image * image,ExceptionInfo * exception)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 
ProfileImage(Image * image,const char * name,const void * datum,const size_t length,ExceptionInfo * exception)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(image,source_profile,
1137               source_type,target_profile,target_type,intent,flags,
1138 	      &cms_exception);
1139             if (transform == (cmsHTRANSFORM *) NULL)
1140               ThrowProfileException(ImageError,"UnableToCreateColorTransform",
1141                 name);
1142             /*
1143               Transform image as dictated by the source & target image profiles.
1144             */
1145             source_pixels=AcquirePixelThreadSet(image->columns,source_channels);
1146             target_pixels=AcquirePixelThreadSet(image->columns,target_channels);
1147             if ((source_pixels == (LCMSType **) NULL) ||
1148                 (target_pixels == (LCMSType **) NULL))
1149               {
1150                 target_pixels=DestroyPixelThreadSet(target_pixels);
1151                 source_pixels=DestroyPixelThreadSet(source_pixels);
1152                 transform=DestroyTransformThreadSet(transform);
1153                 ThrowProfileException(ResourceLimitError,
1154                   "MemoryAllocationFailed",image->filename);
1155               }
1156             if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1157               {
1158                 target_pixels=DestroyPixelThreadSet(target_pixels);
1159                 source_pixels=DestroyPixelThreadSet(source_pixels);
1160                 transform=DestroyTransformThreadSet(transform);
1161                 if (source_profile != (cmsHPROFILE) NULL)
1162                   (void) cmsCloseProfile(source_profile);
1163                 if (target_profile != (cmsHPROFILE) NULL)
1164                   (void) cmsCloseProfile(target_profile);
1165                 return(MagickFalse);
1166               }
1167             if (target_colorspace == CMYKColorspace)
1168               (void) SetImageColorspace(image,target_colorspace,exception);
1169             progress=0;
1170             image_view=AcquireAuthenticCacheView(image,exception);
1171 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1172             #pragma omp parallel for schedule(static) shared(status) \
1173               magick_number_threads(image,image,image->rows,1)
1174 #endif
1175             for (y=0; y < (ssize_t) image->rows; y++)
1176             {
1177               const int
1178                 id = GetOpenMPThreadId();
1179 
1180               MagickBooleanType
1181                 sync;
1182 
1183               register LCMSType
1184                 *p;
1185 
1186               register Quantum
1187                 *magick_restrict q;
1188 
1189               register ssize_t
1190                 x;
1191 
1192               if (status == MagickFalse)
1193                 continue;
1194               q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1195                 exception);
1196               if (q == (Quantum *) NULL)
1197                 {
1198                   status=MagickFalse;
1199                   continue;
1200                 }
1201               p=source_pixels[id];
1202               for (x=0; x < (ssize_t) image->columns; x++)
1203               {
1204                 *p++=LCMSScaleSource(GetPixelRed(image,q));
1205                 if (source_channels > 1)
1206                   {
1207                     *p++=LCMSScaleSource(GetPixelGreen(image,q));
1208                     *p++=LCMSScaleSource(GetPixelBlue(image,q));
1209                   }
1210                 if (source_channels > 3)
1211                   *p++=LCMSScaleSource(GetPixelBlack(image,q));
1212                 q+=GetPixelChannels(image);
1213               }
1214               cmsDoTransform(transform[id],source_pixels[id],target_pixels[id],
1215                 (unsigned int) image->columns);
1216               p=target_pixels[id];
1217               q-=GetPixelChannels(image)*image->columns;
1218               for (x=0; x < (ssize_t) image->columns; x++)
1219               {
1220                 if (target_channels == 1)
1221                   SetPixelGray(image,LCMSScaleTarget(*p),q);
1222                 else
1223                   SetPixelRed(image,LCMSScaleTarget(*p),q);
1224                 p++;
1225                 if (target_channels > 1)
1226                   {
1227                     SetPixelGreen(image,LCMSScaleTarget(*p),q);
1228                     p++;
1229                     SetPixelBlue(image,LCMSScaleTarget(*p),q);
1230                     p++;
1231                   }
1232                 if (target_channels > 3)
1233                   {
1234                     SetPixelBlack(image,LCMSScaleTarget(*p),q);
1235                     p++;
1236                   }
1237                 q+=GetPixelChannels(image);
1238               }
1239               sync=SyncCacheViewAuthenticPixels(image_view,exception);
1240               if (sync == MagickFalse)
1241                 status=MagickFalse;
1242               if (image->progress_monitor != (MagickProgressMonitor) NULL)
1243                 {
1244                   MagickBooleanType
1245                     proceed;
1246 
1247 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1248                   #pragma omp atomic
1249 #endif
1250                   progress++;
1251                   proceed=SetImageProgress(image,ProfileImageTag,progress,
1252                     image->rows);
1253                   if (proceed == MagickFalse)
1254                     status=MagickFalse;
1255                 }
1256             }
1257             image_view=DestroyCacheView(image_view);
1258             (void) SetImageColorspace(image,target_colorspace,exception);
1259             switch (signature)
1260             {
1261               case cmsSigRgbData:
1262               {
1263                 image->type=image->alpha_trait == UndefinedPixelTrait ?
1264                   TrueColorType : TrueColorAlphaType;
1265                 break;
1266               }
1267               case cmsSigCmykData:
1268               {
1269                 image->type=image->alpha_trait == UndefinedPixelTrait ?
1270                   ColorSeparationType : ColorSeparationAlphaType;
1271                 break;
1272               }
1273               case cmsSigGrayData:
1274               {
1275                 image->type=image->alpha_trait == UndefinedPixelTrait ?
1276                   GrayscaleType : GrayscaleAlphaType;
1277                 break;
1278               }
1279               default:
1280                 break;
1281             }
1282             target_pixels=DestroyPixelThreadSet(target_pixels);
1283             source_pixels=DestroyPixelThreadSet(source_pixels);
1284             transform=DestroyTransformThreadSet(transform);
1285             if ((status != MagickFalse) &&
1286                 (cmsGetDeviceClass(source_profile) != cmsSigLinkClass))
1287               status=SetImageProfile(image,name,profile,exception);
1288             if (target_profile != (cmsHPROFILE) NULL)
1289               (void) cmsCloseProfile(target_profile);
1290           }
1291         (void) cmsCloseProfile(source_profile);
1292       }
1293 #endif
1294     }
1295   profile=DestroyStringInfo(profile);
1296   return(status);
1297 }
1298 
1299 /*
1300 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1301 %                                                                             %
1302 %                                                                             %
1303 %                                                                             %
1304 %   R e m o v e I m a g e P r o f i l e                                       %
1305 %                                                                             %
1306 %                                                                             %
1307 %                                                                             %
1308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1309 %
1310 %  RemoveImageProfile() removes a named profile from the image and returns its
1311 %  value.
1312 %
1313 %  The format of the RemoveImageProfile method is:
1314 %
1315 %      void *RemoveImageProfile(Image *image,const char *name)
1316 %
1317 %  A description of each parameter follows:
1318 %
1319 %    o image: the image.
1320 %
1321 %    o name: the profile name.
1322 %
1323 */
RemoveImageProfile(Image * image,const char * name)1324 MagickExport StringInfo *RemoveImageProfile(Image *image,const char *name)
1325 {
1326   StringInfo
1327     *profile;
1328 
1329   assert(image != (Image *) NULL);
1330   assert(image->signature == MagickCoreSignature);
1331   if (image->debug != MagickFalse)
1332     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1333   if (image->profiles == (SplayTreeInfo *) NULL)
1334     return((StringInfo *) NULL);
1335   WriteTo8BimProfile(image,name,(StringInfo *) NULL);
1336   profile=(StringInfo *) RemoveNodeFromSplayTree((SplayTreeInfo *)
1337     image->profiles,name);
1338   return(profile);
1339 }
1340 
1341 /*
1342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1343 %                                                                             %
1344 %                                                                             %
1345 %                                                                             %
1346 %   R e s e t P r o f i l e I t e r a t o r                                   %
1347 %                                                                             %
1348 %                                                                             %
1349 %                                                                             %
1350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1351 %
1352 %  ResetImageProfileIterator() resets the image profile iterator.  Use it in
1353 %  conjunction with GetNextImageProfile() to iterate over all the profiles
1354 %  associated with an image.
1355 %
1356 %  The format of the ResetImageProfileIterator method is:
1357 %
1358 %      ResetImageProfileIterator(Image *image)
1359 %
1360 %  A description of each parameter follows:
1361 %
1362 %    o image: the image.
1363 %
1364 */
ResetImageProfileIterator(const Image * image)1365 MagickExport void ResetImageProfileIterator(const Image *image)
1366 {
1367   assert(image != (Image *) NULL);
1368   assert(image->signature == MagickCoreSignature);
1369   if (image->debug != MagickFalse)
1370     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1371   if (image->profiles == (SplayTreeInfo *) NULL)
1372     return;
1373   ResetSplayTreeIterator((SplayTreeInfo *) image->profiles);
1374 }
1375 
1376 /*
1377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1378 %                                                                             %
1379 %                                                                             %
1380 %                                                                             %
1381 %   S e t I m a g e P r o f i l e                                             %
1382 %                                                                             %
1383 %                                                                             %
1384 %                                                                             %
1385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1386 %
1387 %  SetImageProfile() adds a named profile to the image.  If a profile with the
1388 %  same name already exists, it is replaced.  This method differs from the
1389 %  ProfileImage() method in that it does not apply CMS color profiles.
1390 %
1391 %  The format of the SetImageProfile method is:
1392 %
1393 %      MagickBooleanType SetImageProfile(Image *image,const char *name,
1394 %        const StringInfo *profile)
1395 %
1396 %  A description of each parameter follows:
1397 %
1398 %    o image: the image.
1399 %
1400 %    o name: the profile name, for example icc, exif, and 8bim (8bim is the
1401 %      Photoshop wrapper for iptc profiles).
1402 %
1403 %    o profile: A StringInfo structure that contains the named profile.
1404 %
1405 */
1406 
DestroyProfile(void * profile)1407 static void *DestroyProfile(void *profile)
1408 {
1409   return((void *) DestroyStringInfo((StringInfo *) profile));
1410 }
1411 
ReadResourceByte(const unsigned char * p,unsigned char * quantum)1412 static inline const unsigned char *ReadResourceByte(const unsigned char *p,
1413   unsigned char *quantum)
1414 {
1415   *quantum=(*p++);
1416   return(p);
1417 }
1418 
ReadResourceLong(const unsigned char * p,unsigned int * quantum)1419 static inline const unsigned char *ReadResourceLong(const unsigned char *p,
1420   unsigned int *quantum)
1421 {
1422   *quantum=(unsigned int) (*p++) << 24;
1423   *quantum|=(unsigned int) (*p++) << 16;
1424   *quantum|=(unsigned int) (*p++) << 8;
1425   *quantum|=(unsigned int) (*p++);
1426   return(p);
1427 }
1428 
ReadResourceShort(const unsigned char * p,unsigned short * quantum)1429 static inline const unsigned char *ReadResourceShort(const unsigned char *p,
1430   unsigned short *quantum)
1431 {
1432   *quantum=(unsigned short) (*p++) << 8;
1433   *quantum|=(unsigned short) (*p++);
1434   return(p);
1435 }
1436 
WriteResourceLong(unsigned char * p,const unsigned int quantum)1437 static inline void WriteResourceLong(unsigned char *p,
1438   const unsigned int quantum)
1439 {
1440   unsigned char
1441     buffer[4];
1442 
1443   buffer[0]=(unsigned char) (quantum >> 24);
1444   buffer[1]=(unsigned char) (quantum >> 16);
1445   buffer[2]=(unsigned char) (quantum >> 8);
1446   buffer[3]=(unsigned char) quantum;
1447   (void) memcpy(p,buffer,4);
1448 }
1449 
WriteTo8BimProfile(Image * image,const char * name,const StringInfo * profile)1450 static void WriteTo8BimProfile(Image *image,const char *name,
1451   const StringInfo *profile)
1452 {
1453   const unsigned char
1454     *datum,
1455     *q;
1456 
1457   register const unsigned char
1458     *p;
1459 
1460   size_t
1461     length;
1462 
1463   StringInfo
1464     *profile_8bim;
1465 
1466   ssize_t
1467     count;
1468 
1469   unsigned char
1470     length_byte;
1471 
1472   unsigned int
1473     value;
1474 
1475   unsigned short
1476     id,
1477     profile_id;
1478 
1479   if (LocaleCompare(name,"icc") == 0)
1480     profile_id=0x040f;
1481   else
1482     if (LocaleCompare(name,"iptc") == 0)
1483       profile_id=0x0404;
1484     else
1485       if (LocaleCompare(name,"xmp") == 0)
1486         profile_id=0x0424;
1487       else
1488         return;
1489   profile_8bim=(StringInfo *) GetValueFromSplayTree((SplayTreeInfo *)
1490     image->profiles,"8bim");
1491   if (profile_8bim == (StringInfo *) NULL)
1492     return;
1493   datum=GetStringInfoDatum(profile_8bim);
1494   length=GetStringInfoLength(profile_8bim);
1495   for (p=datum; p < (datum+length-16); )
1496   {
1497     q=p;
1498     if (LocaleNCompare((char *) p,"8BIM",4) != 0)
1499       break;
1500     p+=4;
1501     p=ReadResourceShort(p,&id);
1502     p=ReadResourceByte(p,&length_byte);
1503     p+=length_byte;
1504     if (((length_byte+1) & 0x01) != 0)
1505       p++;
1506     if (p > (datum+length-4))
1507       break;
1508     p=ReadResourceLong(p,&value);
1509     count=(ssize_t) value;
1510     if ((count & 0x01) != 0)
1511       count++;
1512     if ((count < 0) || (p > (datum+length-count)) || (count > (ssize_t) length))
1513       break;
1514     if (id != profile_id)
1515       p+=count;
1516     else
1517       {
1518         size_t
1519           extent,
1520           offset;
1521 
1522         ssize_t
1523           extract_extent;
1524 
1525         StringInfo
1526           *extract_profile;
1527 
1528         extract_extent=0;
1529         extent=(datum+length)-(p+count);
1530         if (profile == (StringInfo *) NULL)
1531           {
1532             offset=(q-datum);
1533             extract_profile=AcquireStringInfo(offset+extent);
1534             (void) memcpy(extract_profile->datum,datum,offset);
1535           }
1536         else
1537           {
1538             offset=(p-datum);
1539             extract_extent=profile->length;
1540             if ((extract_extent & 0x01) != 0)
1541               extract_extent++;
1542             extract_profile=AcquireStringInfo(offset+extract_extent+extent);
1543             (void) memcpy(extract_profile->datum,datum,offset-4);
1544             WriteResourceLong(extract_profile->datum+offset-4,(unsigned int)
1545               profile->length);
1546             (void) memcpy(extract_profile->datum+offset,
1547               profile->datum,profile->length);
1548           }
1549         (void) memcpy(extract_profile->datum+offset+extract_extent,
1550           p+count,extent);
1551         (void) AddValueToSplayTree((SplayTreeInfo *) image->profiles,
1552           ConstantString("8bim"),CloneStringInfo(extract_profile));
1553         extract_profile=DestroyStringInfo(extract_profile);
1554         break;
1555       }
1556   }
1557 }
1558 
GetProfilesFromResourceBlock(Image * image,const StringInfo * resource_block,ExceptionInfo * exception)1559 static void GetProfilesFromResourceBlock(Image *image,
1560   const StringInfo *resource_block,ExceptionInfo *exception)
1561 {
1562   const unsigned char
1563     *datum;
1564 
1565   register const unsigned char
1566     *p;
1567 
1568   size_t
1569     length;
1570 
1571   ssize_t
1572     count;
1573 
1574   StringInfo
1575     *profile;
1576 
1577   unsigned char
1578     length_byte;
1579 
1580   unsigned int
1581     value;
1582 
1583   unsigned short
1584     id;
1585 
1586   datum=GetStringInfoDatum(resource_block);
1587   length=GetStringInfoLength(resource_block);
1588   for (p=datum; p < (datum+length-16); )
1589   {
1590     if (LocaleNCompare((char *) p,"8BIM",4) != 0)
1591       break;
1592     p+=4;
1593     p=ReadResourceShort(p,&id);
1594     p=ReadResourceByte(p,&length_byte);
1595     p+=length_byte;
1596     if (((length_byte+1) & 0x01) != 0)
1597       p++;
1598     if (p > (datum+length-4))
1599       break;
1600     p=ReadResourceLong(p,&value);
1601     count=(ssize_t) value;
1602     if ((p > (datum+length-count)) || (count > (ssize_t) length) || (count < 0))
1603       break;
1604     switch (id)
1605     {
1606       case 0x03ed:
1607       {
1608         unsigned int
1609           resolution;
1610 
1611         unsigned short
1612           units;
1613 
1614         /*
1615           Resolution.
1616         */
1617         if (count < 10)
1618           break;
1619         p=ReadResourceLong(p,&resolution);
1620         image->resolution.x=((double) resolution)/65536.0;
1621         p=ReadResourceShort(p,&units)+2;
1622         p=ReadResourceLong(p,&resolution)+4;
1623         image->resolution.y=((double) resolution)/65536.0;
1624         /*
1625           Values are always stored as pixels per inch.
1626         */
1627         if ((ResolutionType) units != PixelsPerCentimeterResolution)
1628           image->units=PixelsPerInchResolution;
1629         else
1630           {
1631             image->units=PixelsPerCentimeterResolution;
1632             image->resolution.x/=2.54;
1633             image->resolution.y/=2.54;
1634           }
1635         break;
1636       }
1637       case 0x0404:
1638       {
1639         /*
1640           IPTC Profile
1641         */
1642         profile=AcquireStringInfo(count);
1643         SetStringInfoDatum(profile,p);
1644         (void) SetImageProfileInternal(image,"iptc",profile,MagickTrue,
1645           exception);
1646         profile=DestroyStringInfo(profile);
1647         p+=count;
1648         break;
1649       }
1650       case 0x040c:
1651       {
1652         /*
1653           Thumbnail.
1654         */
1655         p+=count;
1656         break;
1657       }
1658       case 0x040f:
1659       {
1660         /*
1661           ICC Profile.
1662         */
1663         profile=AcquireStringInfo(count);
1664         SetStringInfoDatum(profile,p);
1665         (void) SetImageProfileInternal(image,"icc",profile,MagickTrue,
1666           exception);
1667         profile=DestroyStringInfo(profile);
1668         p+=count;
1669         break;
1670       }
1671       case 0x0422:
1672       {
1673         /*
1674           EXIF Profile.
1675         */
1676         profile=AcquireStringInfo(count);
1677         SetStringInfoDatum(profile,p);
1678         (void) SetImageProfileInternal(image,"exif",profile,MagickTrue,
1679           exception);
1680         profile=DestroyStringInfo(profile);
1681         p+=count;
1682         break;
1683       }
1684       case 0x0424:
1685       {
1686         /*
1687           XMP Profile.
1688         */
1689         profile=AcquireStringInfo(count);
1690         SetStringInfoDatum(profile,p);
1691         (void) SetImageProfileInternal(image,"xmp",profile,MagickTrue,
1692           exception);
1693         profile=DestroyStringInfo(profile);
1694         p+=count;
1695         break;
1696       }
1697       default:
1698       {
1699         p+=count;
1700         break;
1701       }
1702     }
1703     if ((count & 0x01) != 0)
1704       p++;
1705   }
1706 }
1707 
ValidateXMPProfile(const StringInfo * profile)1708 static MagickBooleanType ValidateXMPProfile(const StringInfo *profile)
1709 {
1710 #if defined(MAGICKCORE_XML_DELEGATE)
1711   {
1712     xmlDocPtr
1713       document;
1714 
1715     /*
1716       Parse XML profile.
1717     */
1718     document=xmlReadMemory((const char *) GetStringInfoDatum(profile),(int)
1719       GetStringInfoLength(profile),"xmp.xml",NULL,XML_PARSE_NOERROR |
1720       XML_PARSE_NOWARNING);
1721     if (document == (xmlDocPtr) NULL)
1722       return(MagickFalse);
1723     xmlFreeDoc(document);
1724     return(MagickTrue);
1725   }
1726 #else
1727   return(MagickTrue);
1728 #endif
1729 }
1730 
SetImageProfileInternal(Image * image,const char * name,const StringInfo * profile,const MagickBooleanType recursive,ExceptionInfo * exception)1731 static MagickBooleanType SetImageProfileInternal(Image *image,const char *name,
1732   const StringInfo *profile,const MagickBooleanType recursive,
1733   ExceptionInfo *exception)
1734 {
1735   char
1736     key[MagickPathExtent],
1737     property[MagickPathExtent];
1738 
1739   MagickBooleanType
1740     status;
1741 
1742   assert(image != (Image *) NULL);
1743   assert(image->signature == MagickCoreSignature);
1744   if (image->debug != MagickFalse)
1745     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1746   if ((LocaleCompare(name,"xmp") == 0) &&
1747       (ValidateXMPProfile(profile) == MagickFalse))
1748     {
1749       (void) ThrowMagickException(exception,GetMagickModule(),ImageWarning,
1750         "CorruptImageProfile","`%s'",name);
1751       return(MagickTrue);
1752     }
1753   if (image->profiles == (SplayTreeInfo *) NULL)
1754     image->profiles=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
1755       DestroyProfile);
1756   (void) CopyMagickString(key,name,MagickPathExtent);
1757   LocaleLower(key);
1758   status=AddValueToSplayTree((SplayTreeInfo *) image->profiles,
1759     ConstantString(key),CloneStringInfo(profile));
1760   if (status != MagickFalse)
1761     {
1762       if (LocaleCompare(name,"8bim") == 0)
1763         GetProfilesFromResourceBlock(image,profile,exception);
1764       else
1765         if (recursive == MagickFalse)
1766           WriteTo8BimProfile(image,name,profile);
1767     }
1768   /*
1769     Inject profile into image properties.
1770   */
1771   (void) FormatLocaleString(property,MagickPathExtent,"%s:*",name);
1772   (void) GetImageProperty(image,property,exception);
1773   return(status);
1774 }
1775 
SetImageProfile(Image * image,const char * name,const StringInfo * profile,ExceptionInfo * exception)1776 MagickExport MagickBooleanType SetImageProfile(Image *image,const char *name,
1777   const StringInfo *profile,ExceptionInfo *exception)
1778 {
1779   return(SetImageProfileInternal(image,name,profile,MagickFalse,exception));
1780 }
1781 
1782 /*
1783 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1784 %                                                                             %
1785 %                                                                             %
1786 %                                                                             %
1787 %   S y n c I m a g e P r o f i l e s                                         %
1788 %                                                                             %
1789 %                                                                             %
1790 %                                                                             %
1791 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1792 %
1793 %  SyncImageProfiles() synchronizes image properties with the image profiles.
1794 %  Currently we only support updating the EXIF resolution and orientation.
1795 %
1796 %  The format of the SyncImageProfiles method is:
1797 %
1798 %      MagickBooleanType SyncImageProfiles(Image *image)
1799 %
1800 %  A description of each parameter follows:
1801 %
1802 %    o image: the image.
1803 %
1804 */
1805 
ReadProfileByte(unsigned char ** p,size_t * length)1806 static inline int ReadProfileByte(unsigned char **p,size_t *length)
1807 {
1808   int
1809     c;
1810 
1811   if (*length < 1)
1812     return(EOF);
1813   c=(int) (*(*p)++);
1814   (*length)--;
1815   return(c);
1816 }
1817 
ReadProfileShort(const EndianType endian,unsigned char * buffer)1818 static inline signed short ReadProfileShort(const EndianType endian,
1819   unsigned char *buffer)
1820 {
1821   union
1822   {
1823     unsigned int
1824       unsigned_value;
1825 
1826     signed int
1827       signed_value;
1828   } quantum;
1829 
1830   unsigned short
1831     value;
1832 
1833   if (endian == LSBEndian)
1834     {
1835       value=(unsigned short) buffer[1] << 8;
1836       value|=(unsigned short) buffer[0];
1837       quantum.unsigned_value=value & 0xffff;
1838       return(quantum.signed_value);
1839     }
1840   value=(unsigned short) buffer[0] << 8;
1841   value|=(unsigned short) buffer[1];
1842   quantum.unsigned_value=value & 0xffff;
1843   return(quantum.signed_value);
1844 }
1845 
ReadProfileLong(const EndianType endian,unsigned char * buffer)1846 static inline signed int ReadProfileLong(const EndianType endian,
1847   unsigned char *buffer)
1848 {
1849   union
1850   {
1851     unsigned int
1852       unsigned_value;
1853 
1854     signed int
1855       signed_value;
1856   } quantum;
1857 
1858   unsigned int
1859     value;
1860 
1861   if (endian == LSBEndian)
1862     {
1863       value=(unsigned int) buffer[3] << 24;
1864       value|=(unsigned int) buffer[2] << 16;
1865       value|=(unsigned int) buffer[1] << 8;
1866       value|=(unsigned int) buffer[0];
1867       quantum.unsigned_value=value & 0xffffffff;
1868       return(quantum.signed_value);
1869     }
1870   value=(unsigned int) buffer[0] << 24;
1871   value|=(unsigned int) buffer[1] << 16;
1872   value|=(unsigned int) buffer[2] << 8;
1873   value|=(unsigned int) buffer[3];
1874   quantum.unsigned_value=value & 0xffffffff;
1875   return(quantum.signed_value);
1876 }
1877 
ReadProfileMSBLong(unsigned char ** p,size_t * length)1878 static inline signed int ReadProfileMSBLong(unsigned char **p,size_t *length)
1879 {
1880   signed int
1881     value;
1882 
1883   if (*length < 4)
1884     return(0);
1885   value=ReadProfileLong(MSBEndian,*p);
1886   (*length)-=4;
1887   *p+=4;
1888   return(value);
1889 }
1890 
ReadProfileMSBShort(unsigned char ** p,size_t * length)1891 static inline signed short ReadProfileMSBShort(unsigned char **p,
1892   size_t *length)
1893 {
1894   signed short
1895     value;
1896 
1897   if (*length < 2)
1898     return(0);
1899   value=ReadProfileShort(MSBEndian,*p);
1900   (*length)-=2;
1901   *p+=2;
1902   return(value);
1903 }
1904 
WriteProfileLong(const EndianType endian,const size_t value,unsigned char * p)1905 static inline void WriteProfileLong(const EndianType endian,
1906   const size_t value,unsigned char *p)
1907 {
1908   unsigned char
1909     buffer[4];
1910 
1911   if (endian == LSBEndian)
1912     {
1913       buffer[0]=(unsigned char) value;
1914       buffer[1]=(unsigned char) (value >> 8);
1915       buffer[2]=(unsigned char) (value >> 16);
1916       buffer[3]=(unsigned char) (value >> 24);
1917       (void) memcpy(p,buffer,4);
1918       return;
1919     }
1920   buffer[0]=(unsigned char) (value >> 24);
1921   buffer[1]=(unsigned char) (value >> 16);
1922   buffer[2]=(unsigned char) (value >> 8);
1923   buffer[3]=(unsigned char) value;
1924   (void) memcpy(p,buffer,4);
1925 }
1926 
WriteProfileShort(const EndianType endian,const unsigned short value,unsigned char * p)1927 static void WriteProfileShort(const EndianType endian,
1928   const unsigned short value,unsigned char *p)
1929 {
1930   unsigned char
1931     buffer[2];
1932 
1933   if (endian == LSBEndian)
1934     {
1935       buffer[0]=(unsigned char) value;
1936       buffer[1]=(unsigned char) (value >> 8);
1937       (void) memcpy(p,buffer,2);
1938       return;
1939     }
1940   buffer[0]=(unsigned char) (value >> 8);
1941   buffer[1]=(unsigned char) value;
1942   (void) memcpy(p,buffer,2);
1943 }
1944 
Sync8BimProfile(Image * image,StringInfo * profile)1945 static MagickBooleanType Sync8BimProfile(Image *image,StringInfo *profile)
1946 {
1947   size_t
1948     length;
1949 
1950   ssize_t
1951     count;
1952 
1953   unsigned char
1954     *p;
1955 
1956   unsigned short
1957     id;
1958 
1959   length=GetStringInfoLength(profile);
1960   p=GetStringInfoDatum(profile);
1961   while (length != 0)
1962   {
1963     if (ReadProfileByte(&p,&length) != 0x38)
1964       continue;
1965     if (ReadProfileByte(&p,&length) != 0x42)
1966       continue;
1967     if (ReadProfileByte(&p,&length) != 0x49)
1968       continue;
1969     if (ReadProfileByte(&p,&length) != 0x4D)
1970       continue;
1971     if (length < 7)
1972       return(MagickFalse);
1973     id=ReadProfileMSBShort(&p,&length);
1974     count=(ssize_t) ReadProfileByte(&p,&length);
1975     if ((count >= (ssize_t) length) || (count < 0))
1976       return(MagickFalse);
1977     p+=count;
1978     length-=count;
1979     if ((*p & 0x01) == 0)
1980       (void) ReadProfileByte(&p,&length);
1981     count=(ssize_t) ReadProfileMSBLong(&p,&length);
1982     if ((count > (ssize_t) length) || (count < 0))
1983       return(MagickFalse);
1984     if ((id == 0x3ED) && (count == 16))
1985       {
1986         if (image->units == PixelsPerCentimeterResolution)
1987           WriteProfileLong(MSBEndian,(unsigned int) (image->resolution.x*2.54*
1988             65536.0),p);
1989         else
1990           WriteProfileLong(MSBEndian,(unsigned int) (image->resolution.x*
1991             65536.0),p);
1992         WriteProfileShort(MSBEndian,(unsigned short) image->units,p+4);
1993         if (image->units == PixelsPerCentimeterResolution)
1994           WriteProfileLong(MSBEndian,(unsigned int) (image->resolution.y*2.54*
1995             65536.0),p+8);
1996         else
1997           WriteProfileLong(MSBEndian,(unsigned int) (image->resolution.y*
1998             65536.0),p+8);
1999         WriteProfileShort(MSBEndian,(unsigned short) image->units,p+12);
2000       }
2001     p+=count;
2002     length-=count;
2003   }
2004   return(MagickTrue);
2005 }
2006 
SyncExifProfile(Image * image,StringInfo * profile)2007 MagickBooleanType SyncExifProfile(Image *image,StringInfo *profile)
2008 {
2009 #define MaxDirectoryStack  16
2010 #define EXIF_DELIMITER  "\n"
2011 #define EXIF_NUM_FORMATS  12
2012 #define TAG_EXIF_OFFSET  0x8769
2013 #define TAG_INTEROP_OFFSET  0xa005
2014 
2015   typedef struct _DirectoryInfo
2016   {
2017     unsigned char
2018       *directory;
2019 
2020     size_t
2021       entry;
2022   } DirectoryInfo;
2023 
2024   DirectoryInfo
2025     directory_stack[MaxDirectoryStack];
2026 
2027   EndianType
2028     endian;
2029 
2030   size_t
2031     entry,
2032     length,
2033     number_entries;
2034 
2035   SplayTreeInfo
2036     *exif_resources;
2037 
2038   ssize_t
2039     id,
2040     level,
2041     offset;
2042 
2043   static int
2044     format_bytes[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
2045 
2046   unsigned char
2047     *directory,
2048     *exif;
2049 
2050   /*
2051     Set EXIF resolution tag.
2052   */
2053   length=GetStringInfoLength(profile);
2054   exif=GetStringInfoDatum(profile);
2055   if (length < 16)
2056     return(MagickFalse);
2057   id=(ssize_t) ReadProfileShort(LSBEndian,exif);
2058   if ((id != 0x4949) && (id != 0x4D4D))
2059     {
2060       while (length != 0)
2061       {
2062         if (ReadProfileByte(&exif,&length) != 0x45)
2063           continue;
2064         if (ReadProfileByte(&exif,&length) != 0x78)
2065           continue;
2066         if (ReadProfileByte(&exif,&length) != 0x69)
2067           continue;
2068         if (ReadProfileByte(&exif,&length) != 0x66)
2069           continue;
2070         if (ReadProfileByte(&exif,&length) != 0x00)
2071           continue;
2072         if (ReadProfileByte(&exif,&length) != 0x00)
2073           continue;
2074         break;
2075       }
2076       if (length < 16)
2077         return(MagickFalse);
2078       id=(ssize_t) ReadProfileShort(LSBEndian,exif);
2079     }
2080   endian=LSBEndian;
2081   if (id == 0x4949)
2082     endian=LSBEndian;
2083   else
2084     if (id == 0x4D4D)
2085       endian=MSBEndian;
2086     else
2087       return(MagickFalse);
2088   if (ReadProfileShort(endian,exif+2) != 0x002a)
2089     return(MagickFalse);
2090   /*
2091     This the offset to the first IFD.
2092   */
2093   offset=(ssize_t) ReadProfileLong(endian,exif+4);
2094   if ((offset < 0) || ((size_t) offset >= length))
2095     return(MagickFalse);
2096   directory=exif+offset;
2097   level=0;
2098   entry=0;
2099   exif_resources=NewSplayTree((int (*)(const void *,const void *)) NULL,
2100     (void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
2101   do
2102   {
2103     if (level > 0)
2104       {
2105         level--;
2106         directory=directory_stack[level].directory;
2107         entry=directory_stack[level].entry;
2108       }
2109     if ((directory < exif) || (directory > (exif+length-2)))
2110       break;
2111     /*
2112       Determine how many entries there are in the current IFD.
2113     */
2114     number_entries=ReadProfileShort(endian,directory);
2115     for ( ; entry < number_entries; entry++)
2116     {
2117       int
2118         components;
2119 
2120       register unsigned char
2121         *p,
2122         *q;
2123 
2124       size_t
2125         number_bytes;
2126 
2127       ssize_t
2128         format,
2129         tag_value;
2130 
2131       q=(unsigned char *) (directory+2+(12*entry));
2132       if (q > (exif+length-12))
2133         break;  /* corrupt EXIF */
2134       if (GetValueFromSplayTree(exif_resources,q) == q)
2135         break;
2136       (void) AddValueToSplayTree(exif_resources,q,q);
2137       tag_value=(ssize_t) ReadProfileShort(endian,q);
2138       format=(ssize_t) ReadProfileShort(endian,q+2);
2139       if ((format < 0) || ((format-1) >= EXIF_NUM_FORMATS))
2140         break;
2141       components=(int) ReadProfileLong(endian,q+4);
2142       if (components < 0)
2143         break;  /* corrupt EXIF */
2144       number_bytes=(size_t) components*format_bytes[format];
2145       if ((ssize_t) number_bytes < components)
2146         break;  /* prevent overflow */
2147       if (number_bytes <= 4)
2148         p=q+8;
2149       else
2150         {
2151           /*
2152             The directory entry contains an offset.
2153           */
2154           offset=(ssize_t) ReadProfileLong(endian,q+8);
2155           if ((offset < 0) || ((size_t) (offset+number_bytes) > length))
2156             continue;
2157           if (~length < number_bytes)
2158             continue;  /* prevent overflow */
2159           p=(unsigned char *) (exif+offset);
2160         }
2161       switch (tag_value)
2162       {
2163         case 0x011a:
2164         {
2165           (void) WriteProfileLong(endian,(size_t) (image->resolution.x+0.5),p);
2166           if (number_bytes == 8)
2167             (void) WriteProfileLong(endian,1UL,p+4);
2168           break;
2169         }
2170         case 0x011b:
2171         {
2172           (void) WriteProfileLong(endian,(size_t) (image->resolution.y+0.5),p);
2173           if (number_bytes == 8)
2174             (void) WriteProfileLong(endian,1UL,p+4);
2175           break;
2176         }
2177         case 0x0112:
2178         {
2179           if (number_bytes == 4)
2180             {
2181               (void) WriteProfileLong(endian,(size_t) image->orientation,p);
2182               break;
2183             }
2184           (void) WriteProfileShort(endian,(unsigned short) image->orientation,
2185             p);
2186           break;
2187         }
2188         case 0x0128:
2189         {
2190           if (number_bytes == 4)
2191             {
2192               (void) WriteProfileLong(endian,(size_t) (image->units+1),p);
2193               break;
2194             }
2195           (void) WriteProfileShort(endian,(unsigned short) (image->units+1),p);
2196           break;
2197         }
2198         default:
2199           break;
2200       }
2201       if ((tag_value == TAG_EXIF_OFFSET) || (tag_value == TAG_INTEROP_OFFSET))
2202         {
2203           offset=(ssize_t) ReadProfileLong(endian,p);
2204           if (((size_t) offset < length) && (level < (MaxDirectoryStack-2)))
2205             {
2206               directory_stack[level].directory=directory;
2207               entry++;
2208               directory_stack[level].entry=entry;
2209               level++;
2210               directory_stack[level].directory=exif+offset;
2211               directory_stack[level].entry=0;
2212               level++;
2213               if ((directory+2+(12*number_entries)) > (exif+length))
2214                 break;
2215               offset=(ssize_t) ReadProfileLong(endian,directory+2+(12*
2216                 number_entries));
2217               if ((offset != 0) && ((size_t) offset < length) &&
2218                   (level < (MaxDirectoryStack-2)))
2219                 {
2220                   directory_stack[level].directory=exif+offset;
2221                   directory_stack[level].entry=0;
2222                   level++;
2223                 }
2224             }
2225           break;
2226         }
2227     }
2228   } while (level > 0);
2229   exif_resources=DestroySplayTree(exif_resources);
2230   return(MagickTrue);
2231 }
2232 
SyncImageProfiles(Image * image)2233 MagickPrivate MagickBooleanType SyncImageProfiles(Image *image)
2234 {
2235   MagickBooleanType
2236     status;
2237 
2238   StringInfo
2239     *profile;
2240 
2241   status=MagickTrue;
2242   profile=(StringInfo *) GetImageProfile(image,"8BIM");
2243   if (profile != (StringInfo *) NULL)
2244     if (Sync8BimProfile(image,profile) == MagickFalse)
2245       status=MagickFalse;
2246   profile=(StringInfo *) GetImageProfile(image,"EXIF");
2247   if (profile != (StringInfo *) NULL)
2248     if (SyncExifProfile(image,profile) == MagickFalse)
2249       status=MagickFalse;
2250   return(status);
2251 }
2252