MagickCore  6.9.12-67
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 % MagickBooleanTyupe 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) || (count < 0))
1586  break;
1587  switch (id)
1588  {
1589  case 0x03ed:
1590  {
1591  unsigned int
1592  resolution;
1593 
1594  unsigned short
1595  units;
1596 
1597  /*
1598  Resolution.
1599  */
1600  if (count < 10)
1601  break;
1602  p=ReadResourceLong(p,&resolution);
1603  image->x_resolution=((double) resolution)/65536.0;
1604  p=ReadResourceShort(p,&units)+2;
1605  p=ReadResourceLong(p,&resolution)+4;
1606  image->y_resolution=((double) resolution)/65536.0;
1607  /*
1608  Values are always stored as pixels per inch.
1609  */
1610  if ((ResolutionType) units != PixelsPerCentimeterResolution)
1611  image->units=PixelsPerInchResolution;
1612  else
1613  {
1614  image->units=PixelsPerCentimeterResolution;
1615  image->x_resolution/=2.54;
1616  image->y_resolution/=2.54;
1617  }
1618  break;
1619  }
1620  case 0x0404:
1621  {
1622  /*
1623  IPTC Profile
1624  */
1625  profile=AcquireStringInfo(count);
1626  SetStringInfoDatum(profile,p);
1627  (void) SetImageProfileInternal(image,"iptc",profile,MagickTrue);
1628  profile=DestroyStringInfo(profile);
1629  p+=count;
1630  break;
1631  }
1632  case 0x040c:
1633  {
1634  /*
1635  Thumbnail.
1636  */
1637  p+=count;
1638  break;
1639  }
1640  case 0x040f:
1641  {
1642  /*
1643  ICC Profile.
1644  */
1645  profile=AcquireStringInfo(count);
1646  SetStringInfoDatum(profile,p);
1647  (void) SetImageProfileInternal(image,"icc",profile,MagickTrue);
1648  profile=DestroyStringInfo(profile);
1649  p+=count;
1650  break;
1651  }
1652  case 0x0422:
1653  {
1654  /*
1655  EXIF Profile.
1656  */
1657  profile=AcquireStringInfo(count);
1658  SetStringInfoDatum(profile,p);
1659  (void) SetImageProfileInternal(image,"exif",profile,MagickTrue);
1660  profile=DestroyStringInfo(profile);
1661  p+=count;
1662  break;
1663  }
1664  case 0x0424:
1665  {
1666  /*
1667  XMP Profile.
1668  */
1669  profile=AcquireStringInfo(count);
1670  SetStringInfoDatum(profile,p);
1671  (void) SetImageProfileInternal(image,"xmp",profile,MagickTrue);
1672  profile=DestroyStringInfo(profile);
1673  p+=count;
1674  break;
1675  }
1676  default:
1677  {
1678  p+=count;
1679  break;
1680  }
1681  }
1682  if ((count & 0x01) != 0)
1683  p++;
1684  }
1685 }
1686 
1687 #if defined(MAGICKCORE_XML_DELEGATE)
1688 static MagickBooleanType ValidateXMPProfile(Image *image,
1689  const StringInfo *profile)
1690 {
1691  xmlDocPtr
1692  document;
1693 
1694  /*
1695  Parse XML profile.
1696  */
1697  document=xmlReadMemory((const char *) GetStringInfoDatum(profile),(int)
1698  GetStringInfoLength(profile),"xmp.xml",NULL,XML_PARSE_NOERROR |
1699  XML_PARSE_NOWARNING);
1700  if (document == (xmlDocPtr) NULL)
1701  {
1702  (void) ThrowMagickException(&image->exception,GetMagickModule(),
1703  ImageWarning,"CorruptImageProfile","`%s' (XMP)",image->filename);
1704  return(MagickFalse);
1705  }
1706  xmlFreeDoc(document);
1707  return(MagickTrue);
1708 }
1709 #else
1710 static MagickBooleanType ValidateXMPProfile(Image *image,
1711  const StringInfo *profile)
1712 {
1713  (void) ThrowMagickException(&image->exception,GetMagickModule(),
1714  MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","'%s' (XML)",
1715  image->filename);
1716  return(MagickFalse);
1717 }
1718 #endif
1719 
1720 static MagickBooleanType SetImageProfileInternal(Image *image,const char *name,
1721  const StringInfo *profile,const MagickBooleanType recursive)
1722 {
1723  char
1724  key[MaxTextExtent];
1725 
1726  MagickBooleanType
1727  status;
1728 
1729  assert(image != (Image *) NULL);
1730  assert(image->signature == MagickCoreSignature);
1731  if (IsEventLogging() != MagickFalse)
1732  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1733  if ((LocaleCompare(name,"xmp") == 0) &&
1734  (ValidateXMPProfile(image,profile) == MagickFalse))
1735  return(MagickTrue);
1736  if (image->profiles == (SplayTreeInfo *) NULL)
1737  image->profiles=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
1738  DestroyProfile);
1739  (void) CopyMagickString(key,name,MaxTextExtent);
1740  LocaleLower(key);
1741  status=AddValueToSplayTree((SplayTreeInfo *) image->profiles,
1742  ConstantString(key),CloneStringInfo(profile));
1743  if ((status != MagickFalse) &&
1744  ((LocaleCompare(name,"icc") == 0) || (LocaleCompare(name,"icm") == 0)))
1745  {
1746  const StringInfo
1747  *icc_profile;
1748 
1749  /*
1750  Continue to support deprecated color profile member.
1751  */
1752  icc_profile=GetImageProfile(image,name);
1753  if (icc_profile != (const StringInfo *) NULL)
1754  {
1755  image->color_profile.length=GetStringInfoLength(icc_profile);
1756  image->color_profile.info=GetStringInfoDatum(icc_profile);
1757  }
1758  }
1759  if ((status != MagickFalse) &&
1760  ((LocaleCompare(name,"iptc") == 0) || (LocaleCompare(name,"8bim") == 0)))
1761  {
1762  const StringInfo
1763  *iptc_profile;
1764 
1765  /*
1766  Continue to support deprecated IPTC profile member.
1767  */
1768  iptc_profile=GetImageProfile(image,name);
1769  if (iptc_profile != (const StringInfo *) NULL)
1770  {
1771  image->iptc_profile.length=GetStringInfoLength(iptc_profile);
1772  image->iptc_profile.info=GetStringInfoDatum(iptc_profile);
1773  }
1774  }
1775  if (status != MagickFalse)
1776  {
1777  if (LocaleCompare(name,"8bim") == 0)
1778  GetProfilesFromResourceBlock(image,profile);
1779  else
1780  if (recursive == MagickFalse)
1781  WriteTo8BimProfile(image,name,profile);
1782  }
1783  return(status);
1784 }
1785 
1786 MagickExport MagickBooleanType SetImageProfile(Image *image,const char *name,
1787  const StringInfo *profile)
1788 {
1789  return(SetImageProfileInternal(image,name,profile,MagickFalse));
1790 }
1791 
1792 /*
1793 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1794 % %
1795 % %
1796 % %
1797 % S y n c I m a g e P r o f i l e s %
1798 % %
1799 % %
1800 % %
1801 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1802 %
1803 % SyncImageProfiles() synchronizes image properties with the image profiles.
1804 % Currently we only support updating the EXIF resolution and orientation.
1805 %
1806 % The format of the SyncImageProfiles method is:
1807 %
1808 % MagickBooleanType SyncImageProfiles(Image *image)
1809 %
1810 % A description of each parameter follows:
1811 %
1812 % o image: the image.
1813 %
1814 */
1815 
1816 static inline int ReadProfileByte(unsigned char **p,size_t *length)
1817 {
1818  int
1819  c;
1820 
1821  if (*length < 1)
1822  return(EOF);
1823  c=(int) (*(*p)++);
1824  (*length)--;
1825  return(c);
1826 }
1827 
1828 static inline signed short ReadProfileShort(const EndianType endian,
1829  unsigned char *buffer)
1830 {
1831  union
1832  {
1833  unsigned int
1834  unsigned_value;
1835 
1836  signed int
1837  signed_value;
1838  } quantum;
1839 
1840  unsigned short
1841  value;
1842 
1843  if (endian == LSBEndian)
1844  {
1845  value=(unsigned short) buffer[1] << 8;
1846  value|=(unsigned short) buffer[0];
1847  quantum.unsigned_value=value & 0xffff;
1848  return(quantum.signed_value);
1849  }
1850  value=(unsigned short) buffer[0] << 8;
1851  value|=(unsigned short) buffer[1];
1852  quantum.unsigned_value=value & 0xffff;
1853  return(quantum.signed_value);
1854 }
1855 
1856 static inline signed int ReadProfileLong(const EndianType endian,
1857  unsigned char *buffer)
1858 {
1859  union
1860  {
1861  unsigned int
1862  unsigned_value;
1863 
1864  signed int
1865  signed_value;
1866  } quantum;
1867 
1868  unsigned int
1869  value;
1870 
1871  if (endian == LSBEndian)
1872  {
1873  value=(unsigned int) buffer[3] << 24;
1874  value|=(unsigned int) buffer[2] << 16;
1875  value|=(unsigned int) buffer[1] << 8;
1876  value|=(unsigned int) buffer[0];
1877  quantum.unsigned_value=value & 0xffffffff;
1878  return(quantum.signed_value);
1879  }
1880  value=(unsigned int) buffer[0] << 24;
1881  value|=(unsigned int) buffer[1] << 16;
1882  value|=(unsigned int) buffer[2] << 8;
1883  value|=(unsigned int) buffer[3];
1884  quantum.unsigned_value=value & 0xffffffff;
1885  return(quantum.signed_value);
1886 }
1887 
1888 static inline signed int ReadProfileMSBLong(unsigned char **p,size_t *length)
1889 {
1890  signed int
1891  value;
1892 
1893  if (*length < 4)
1894  return(0);
1895  value=ReadProfileLong(MSBEndian,*p);
1896  (*length)-=4;
1897  *p+=4;
1898  return(value);
1899 }
1900 
1901 static inline signed short ReadProfileMSBShort(unsigned char **p,
1902  size_t *length)
1903 {
1904  signed short
1905  value;
1906 
1907  if (*length < 2)
1908  return(0);
1909  value=ReadProfileShort(MSBEndian,*p);
1910  (*length)-=2;
1911  *p+=2;
1912  return(value);
1913 }
1914 
1915 static inline void WriteProfileLong(const EndianType endian,
1916  const size_t value,unsigned char *p)
1917 {
1918  unsigned char
1919  buffer[4];
1920 
1921  if (endian == LSBEndian)
1922  {
1923  buffer[0]=(unsigned char) value;
1924  buffer[1]=(unsigned char) (value >> 8);
1925  buffer[2]=(unsigned char) (value >> 16);
1926  buffer[3]=(unsigned char) (value >> 24);
1927  (void) memcpy(p,buffer,4);
1928  return;
1929  }
1930  buffer[0]=(unsigned char) (value >> 24);
1931  buffer[1]=(unsigned char) (value >> 16);
1932  buffer[2]=(unsigned char) (value >> 8);
1933  buffer[3]=(unsigned char) value;
1934  (void) memcpy(p,buffer,4);
1935 }
1936 
1937 static void WriteProfileShort(const EndianType endian,
1938  const unsigned short value,unsigned char *p)
1939 {
1940  unsigned char
1941  buffer[2];
1942 
1943  if (endian == LSBEndian)
1944  {
1945  buffer[0]=(unsigned char) value;
1946  buffer[1]=(unsigned char) (value >> 8);
1947  (void) memcpy(p,buffer,2);
1948  return;
1949  }
1950  buffer[0]=(unsigned char) (value >> 8);
1951  buffer[1]=(unsigned char) value;
1952  (void) memcpy(p,buffer,2);
1953 }
1954 
1955 static MagickBooleanType SyncExifProfile(const Image *image,unsigned char *exif,
1956  size_t length)
1957 {
1958 #define MaxDirectoryStack 16
1959 #define EXIF_DELIMITER "\n"
1960 #define EXIF_NUM_FORMATS 12
1961 #define TAG_EXIF_OFFSET 0x8769
1962 #define TAG_INTEROP_OFFSET 0xa005
1963 
1964  typedef struct _DirectoryInfo
1965  {
1966  unsigned char
1967  *directory;
1968 
1969  size_t
1970  entry;
1971  } DirectoryInfo;
1972 
1973  DirectoryInfo
1974  directory_stack[MaxDirectoryStack] = {{ 0 }};
1975 
1976  EndianType
1977  endian;
1978 
1979  size_t
1980  entry,
1981  number_entries;
1982 
1984  *exif_resources;
1985 
1986  ssize_t
1987  id,
1988  level,
1989  offset;
1990 
1991  static int
1992  format_bytes[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
1993 
1994  unsigned char
1995  *directory;
1996 
1997  if (length < 16)
1998  return(MagickFalse);
1999  id=(ssize_t) ReadProfileShort(LSBEndian,exif);
2000  if ((id != 0x4949) && (id != 0x4D4D))
2001  {
2002  while (length != 0)
2003  {
2004  if (ReadProfileByte(&exif,&length) != 0x45)
2005  continue;
2006  if (ReadProfileByte(&exif,&length) != 0x78)
2007  continue;
2008  if (ReadProfileByte(&exif,&length) != 0x69)
2009  continue;
2010  if (ReadProfileByte(&exif,&length) != 0x66)
2011  continue;
2012  if (ReadProfileByte(&exif,&length) != 0x00)
2013  continue;
2014  if (ReadProfileByte(&exif,&length) != 0x00)
2015  continue;
2016  break;
2017  }
2018  if (length < 16)
2019  return(MagickFalse);
2020  id=(ssize_t) ReadProfileShort(LSBEndian,exif);
2021  }
2022  endian=LSBEndian;
2023  if (id == 0x4949)
2024  endian=LSBEndian;
2025  else
2026  if (id == 0x4D4D)
2027  endian=MSBEndian;
2028  else
2029  return(MagickFalse);
2030  if (ReadProfileShort(endian,exif+2) != 0x002a)
2031  return(MagickFalse);
2032  /*
2033  This the offset to the first IFD.
2034  */
2035  offset=(ssize_t) ReadProfileLong(endian,exif+4);
2036  if ((offset < 0) || ((size_t) offset >= length))
2037  return(MagickFalse);
2038  directory=exif+offset;
2039  level=0;
2040  entry=0;
2041  exif_resources=NewSplayTree((int (*)(const void *,const void *)) NULL,
2042  (void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
2043  do
2044  {
2045  if (level > 0)
2046  {
2047  level--;
2048  directory=directory_stack[level].directory;
2049  entry=directory_stack[level].entry;
2050  }
2051  if ((directory < exif) || (directory > (exif+length-2)))
2052  break;
2053  /*
2054  Determine how many entries there are in the current IFD.
2055  */
2056  number_entries=ReadProfileShort(endian,directory);
2057  for ( ; entry < number_entries; entry++)
2058  {
2059  int
2060  components;
2061 
2062  unsigned char
2063  *p,
2064  *q;
2065 
2066  size_t
2067  number_bytes;
2068 
2069  ssize_t
2070  format,
2071  tag_value;
2072 
2073  q=(unsigned char *) (directory+2+(12*entry));
2074  if (q > (exif+length-12))
2075  break; /* corrupt EXIF */
2076  if (GetValueFromSplayTree(exif_resources,q) == q)
2077  break;
2078  (void) AddValueToSplayTree(exif_resources,q,q);
2079  tag_value=(ssize_t) ReadProfileShort(endian,q);
2080  format=(ssize_t) ReadProfileShort(endian,q+2);
2081  if ((format < 0) || ((format-1) >= EXIF_NUM_FORMATS))
2082  break;
2083  components=(int) ReadProfileLong(endian,q+4);
2084  if (components < 0)
2085  break; /* corrupt EXIF */
2086  number_bytes=(size_t) components*format_bytes[format];
2087  if ((ssize_t) number_bytes < components)
2088  break; /* prevent overflow */
2089  if (number_bytes <= 4)
2090  p=q+8;
2091  else
2092  {
2093  /*
2094  The directory entry contains an offset.
2095  */
2096  offset=(ssize_t) ReadProfileLong(endian,q+8);
2097  if ((offset < 0) || ((size_t) (offset+number_bytes) > length))
2098  continue;
2099  if (~length < number_bytes)
2100  continue; /* prevent overflow */
2101  p=(unsigned char *) (exif+offset);
2102  }
2103  switch (tag_value)
2104  {
2105  case 0x011a:
2106  {
2107  (void) WriteProfileLong(endian,(size_t) (image->x_resolution+0.5),p);
2108  if (number_bytes == 8)
2109  (void) WriteProfileLong(endian,1UL,p+4);
2110  break;
2111  }
2112  case 0x011b:
2113  {
2114  (void) WriteProfileLong(endian,(size_t) (image->y_resolution+0.5),p);
2115  if (number_bytes == 8)
2116  (void) WriteProfileLong(endian,1UL,p+4);
2117  break;
2118  }
2119  case 0x0112:
2120  {
2121  if (number_bytes == 4)
2122  {
2123  (void) WriteProfileLong(endian,(size_t) image->orientation,p);
2124  break;
2125  }
2126  (void) WriteProfileShort(endian,(unsigned short) image->orientation,
2127  p);
2128  break;
2129  }
2130  case 0x0128:
2131  {
2132  if (number_bytes == 4)
2133  {
2134  (void) WriteProfileLong(endian,((size_t) image->units)+1,p);
2135  break;
2136  }
2137  (void) WriteProfileShort(endian,(unsigned short) (image->units+1),p);
2138  break;
2139  }
2140  default:
2141  break;
2142  }
2143  if ((tag_value == TAG_EXIF_OFFSET) || (tag_value == TAG_INTEROP_OFFSET))
2144  {
2145  offset=(ssize_t) ReadProfileLong(endian,p);
2146  if (((size_t) offset < length) && (level < (MaxDirectoryStack-2)))
2147  {
2148  directory_stack[level].directory=directory;
2149  entry++;
2150  directory_stack[level].entry=entry;
2151  level++;
2152  directory_stack[level].directory=exif+offset;
2153  directory_stack[level].entry=0;
2154  level++;
2155  if ((directory+2+(12*number_entries)) > (exif+length))
2156  break;
2157  offset=(ssize_t) ReadProfileLong(endian,directory+2+(12*
2158  number_entries));
2159  if ((offset != 0) && ((size_t) offset < length) &&
2160  (level < (MaxDirectoryStack-2)))
2161  {
2162  directory_stack[level].directory=exif+offset;
2163  directory_stack[level].entry=0;
2164  level++;
2165  }
2166  }
2167  break;
2168  }
2169  }
2170  } while (level > 0);
2171  exif_resources=DestroySplayTree(exif_resources);
2172  return(MagickTrue);
2173 }
2174 
2175 static MagickBooleanType Sync8BimProfile(const Image *image,
2176  const StringInfo *profile)
2177 {
2178  size_t
2179  length;
2180 
2181  ssize_t
2182  count;
2183 
2184  unsigned char
2185  *p;
2186 
2187  unsigned short
2188  id;
2189 
2190  length=GetStringInfoLength(profile);
2191  p=GetStringInfoDatum(profile);
2192  while (length != 0)
2193  {
2194  if (ReadProfileByte(&p,&length) != 0x38)
2195  continue;
2196  if (ReadProfileByte(&p,&length) != 0x42)
2197  continue;
2198  if (ReadProfileByte(&p,&length) != 0x49)
2199  continue;
2200  if (ReadProfileByte(&p,&length) != 0x4D)
2201  continue;
2202  if (length < 7)
2203  return(MagickFalse);
2204  id=ReadProfileMSBShort(&p,&length);
2205  count=(ssize_t) ReadProfileByte(&p,&length);
2206  if ((count >= (ssize_t) length) || (count < 0))
2207  return(MagickFalse);
2208  p+=count;
2209  length-=count;
2210  if ((*p & 0x01) == 0)
2211  (void) ReadProfileByte(&p,&length);
2212  count=(ssize_t) ReadProfileMSBLong(&p,&length);
2213  if ((count > (ssize_t) length) || (count < 0))
2214  return(MagickFalse);
2215  if ((id == 0x3ED) && (count == 16))
2216  {
2217  if (image->units == PixelsPerCentimeterResolution)
2218  WriteProfileLong(MSBEndian,(unsigned int) CastDoubleToLong(
2219  image->x_resolution*2.54*65536.0),p);
2220  else
2221  WriteProfileLong(MSBEndian,(unsigned int) CastDoubleToLong(
2222  image->x_resolution*65536.0),p);
2223  WriteProfileShort(MSBEndian,(unsigned short) image->units,p+4);
2224  if (image->units == PixelsPerCentimeterResolution)
2225  WriteProfileLong(MSBEndian,(unsigned int) CastDoubleToLong(
2226  image->y_resolution*2.54*65536.0),p+8);
2227  else
2228  WriteProfileLong(MSBEndian,(unsigned int) CastDoubleToLong(
2229  image->y_resolution*65536.0),p+8);
2230  WriteProfileShort(MSBEndian,(unsigned short) image->units,p+12);
2231  }
2232  if (id == 0x0422)
2233  (void) SyncExifProfile(image,p,count);
2234  p+=count;
2235  length-=count;
2236  }
2237  return(MagickTrue);
2238 }
2239 
2240 MagickExport MagickBooleanType SyncImageProfiles(Image *image)
2241 {
2242  MagickBooleanType
2243  status;
2244 
2245  StringInfo
2246  *profile;
2247 
2248  status=MagickTrue;
2249  profile=(StringInfo *) GetImageProfile(image,"8BIM");
2250  if (profile != (StringInfo *) NULL)
2251  if (Sync8BimProfile(image,profile) == MagickFalse)
2252  status=MagickFalse;
2253  profile=(StringInfo *) GetImageProfile(image,"EXIF");
2254  if (profile != (StringInfo *) NULL)
2255  if (SyncExifProfile(image,GetStringInfoDatum(profile),
2256  GetStringInfoLength(profile)) == MagickFalse)
2257  status=MagickFalse;
2258  return(status);
2259 }
Definition: image.h:152