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