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