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