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