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