MagickCore  6.9.12-97
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 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) (source_info.scale[index]* \
802  ((QuantumScale*(MagickRealType) (pixel))+source_info.translate[index]))
803 #define ProfileImageTag "Profile/Image"
804 #define SetLCMSPixel(target_info,pixel,index) ClampToQuantum( \
805  target_info.scale[index]*(((MagickRealType) QuantumRange*pixel)+ \
806  target_info.translate[index]))
807 #define ThrowProfileException(severity,tag,context) \
808 { \
809  if (profile != (StringInfo *) NULL) \
810  profile=DestroyStringInfo(profile); \
811  if (cms_context != (cmsContext) NULL) \
812  cmsDeleteContext(cms_context); \
813  if (source_info.profile != (cmsHPROFILE) NULL) \
814  (void) cmsCloseProfile(source_info.profile); \
815  if (target_info.profile != (cmsHPROFILE) NULL) \
816  (void) cmsCloseProfile(target_info.profile); \
817  ThrowBinaryException(severity,tag,context); \
818 }
819 
820  MagickBooleanType
821  status;
822 
823  StringInfo
824  *profile;
825 
826  magick_unreferenced(clone);
827 
828  assert(image != (Image *) NULL);
829  assert(image->signature == MagickCoreSignature);
830  assert(name != (const char *) NULL);
831  if (IsEventLogging() != MagickFalse)
832  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
833  if ((datum == (const void *) NULL) || (length == 0))
834  {
835  char
836  *next;
837 
838  /*
839  Delete image profile(s).
840  */
841  ResetImageProfileIterator(image);
842  for (next=GetNextImageProfile(image); next != (const char *) NULL; )
843  {
844  if (IsOptionMember(next,name) != MagickFalse)
845  {
846  (void) DeleteImageProfile(image,next);
847  ResetImageProfileIterator(image);
848  }
849  next=GetNextImageProfile(image);
850  }
851  return(MagickTrue);
852  }
853  /*
854  Add a ICC, IPTC, or generic profile to the image.
855  */
856  status=MagickTrue;
857  profile=AcquireStringInfo((size_t) length);
858  SetStringInfoDatum(profile,(unsigned char *) datum);
859  if ((LocaleCompare(name,"icc") != 0) && (LocaleCompare(name,"icm") != 0))
860  status=SetImageProfile(image,name,profile);
861  else
862  {
863  const StringInfo
864  *icc_profile;
865 
866  icc_profile=GetImageProfile(image,"icc");
867  if ((icc_profile != (const StringInfo *) NULL) &&
868  (CompareStringInfo(icc_profile,profile) == 0))
869  {
870  const char
871  *value;
872 
873  value=GetImageProperty(image,"exif:ColorSpace");
874  (void) value;
875  if (LocaleCompare(value,"1") != 0)
876  (void) SetsRGBImageProfile(image);
877  value=GetImageProperty(image,"exif:InteroperabilityIndex");
878  if (LocaleCompare(value,"R98.") != 0)
879  (void) SetsRGBImageProfile(image);
880  icc_profile=GetImageProfile(image,"icc");
881  }
882  if ((icc_profile != (const StringInfo *) NULL) &&
883  (CompareStringInfo(icc_profile,profile) == 0))
884  {
885  profile=DestroyStringInfo(profile);
886  return(MagickTrue);
887  }
888 #if !defined(MAGICKCORE_LCMS_DELEGATE)
889  (void) ThrowMagickException(&image->exception,GetMagickModule(),
890  MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (LCMS)",
891  image->filename);
892 #else
893  {
894  cmsContext
895  cms_context;
896 
897  LCMSInfo
898  source_info,
899  target_info;
900 
901  /*
902  Transform pixel colors as defined by the color profiles.
903  */
904  cms_context=cmsCreateContext(NULL,image);
905  if (cms_context == (cmsContext) NULL)
906  {
907  profile=DestroyStringInfo(profile);
908  ThrowBinaryImageException(ResourceLimitError,
909  "ColorspaceColorProfileMismatch",name);
910  }
911  cmsSetLogErrorHandlerTHR(cms_context,LCMSExceptionHandler);
912  source_info.profile=cmsOpenProfileFromMemTHR(cms_context,
913  GetStringInfoDatum(profile),(cmsUInt32Number)
914  GetStringInfoLength(profile));
915  if (source_info.profile == (cmsHPROFILE) NULL)
916  {
917  profile=DestroyStringInfo(profile);
918  cmsDeleteContext(cms_context);
919  ThrowBinaryImageException(ResourceLimitError,
920  "ColorspaceColorProfileMismatch",name);
921  }
922  if ((cmsGetDeviceClass(source_info.profile) != cmsSigLinkClass) &&
923  (icc_profile == (StringInfo *) NULL))
924  status=SetImageProfile(image,name,profile);
925  else
926  {
927  CacheView
928  *image_view;
929 
930  cmsColorSpaceSignature
931  signature;
932 
933  cmsHTRANSFORM
934  *magick_restrict transform;
935 
936  cmsUInt32Number
937  flags;
938 
940  *exception;
941 
942  MagickOffsetType
943  progress;
944 
945  ssize_t
946  y;
947 
948  exception=(&image->exception);
949  target_info.profile=(cmsHPROFILE) NULL;
950  if (icc_profile != (StringInfo *) NULL)
951  {
952  target_info.profile=source_info.profile;
953  source_info.profile=cmsOpenProfileFromMemTHR(cms_context,
954  GetStringInfoDatum(icc_profile),(cmsUInt32Number)
955  GetStringInfoLength(icc_profile));
956  if (source_info.profile == (cmsHPROFILE) NULL)
957  ThrowProfileException(ResourceLimitError,
958  "ColorspaceColorProfileMismatch",name);
959  }
960  SetLCMSInfoScale(&source_info,1.0);
961  SetLCMSInfoTranslate(&source_info,0.0);
962  source_info.colorspace=sRGBColorspace;
963  source_info.channels=3;
964  switch (cmsGetColorSpace(source_info.profile))
965  {
966  case cmsSigCmykData:
967  {
968  source_info.colorspace=CMYKColorspace;
969  source_info.channels=4;
970  source_info.type=(cmsUInt32Number) TYPE_CMYK_DBL;
971  SetLCMSInfoScale(&source_info,100.0);
972  break;
973  }
974  case cmsSigGrayData:
975  {
976  source_info.colorspace=GRAYColorspace;
977  source_info.channels=1;
978  source_info.type=(cmsUInt32Number) TYPE_GRAY_DBL;
979  break;
980  }
981  case cmsSigLabData:
982  {
983  source_info.colorspace=LabColorspace;
984  source_info.type=(cmsUInt32Number) TYPE_Lab_DBL;
985  source_info.scale[0]=100.0;
986  source_info.scale[1]=255.0;
987  source_info.scale[2]=255.0;
988  source_info.translate[1]=(-0.5);
989  source_info.translate[2]=(-0.5);
990  break;
991  }
992  case cmsSigRgbData:
993  {
994  source_info.colorspace=sRGBColorspace;
995  source_info.type=(cmsUInt32Number) TYPE_RGB_DBL;
996  break;
997  }
998  case cmsSigXYZData:
999  {
1000  source_info.colorspace=XYZColorspace;
1001  source_info.type=(cmsUInt32Number) TYPE_XYZ_DBL;
1002  break;
1003  }
1004  default:
1005  ThrowProfileException(ImageError,
1006  "ColorspaceColorProfileMismatch",name);
1007  }
1008  signature=cmsGetPCS(source_info.profile);
1009  if (target_info.profile != (cmsHPROFILE) NULL)
1010  signature=cmsGetColorSpace(target_info.profile);
1011  SetLCMSInfoScale(&target_info,1.0);
1012  SetLCMSInfoTranslate(&target_info,0.0);
1013  target_info.channels=3;
1014  switch (signature)
1015  {
1016  case cmsSigCmykData:
1017  {
1018  target_info.colorspace=CMYKColorspace;
1019  target_info.channels=4;
1020  target_info.type=(cmsUInt32Number) TYPE_CMYK_DBL;
1021  SetLCMSInfoScale(&target_info,0.01);
1022  break;
1023  }
1024  case cmsSigGrayData:
1025  {
1026  target_info.colorspace=GRAYColorspace;
1027  target_info.channels=1;
1028  target_info.type=(cmsUInt32Number) TYPE_GRAY_DBL;
1029  break;
1030  }
1031  case cmsSigLabData:
1032  {
1033  target_info.colorspace=LabColorspace;
1034  target_info.type=(cmsUInt32Number) TYPE_Lab_DBL;
1035  target_info.scale[0]=0.01;
1036  target_info.scale[1]=1/255.0;
1037  target_info.scale[2]=1/255.0;
1038  target_info.translate[1]=0.5;
1039  target_info.translate[2]=0.5;
1040  break;
1041  }
1042  case cmsSigRgbData:
1043  {
1044  target_info.colorspace=sRGBColorspace;
1045  target_info.type=(cmsUInt32Number) TYPE_RGB_DBL;
1046  break;
1047  }
1048  case cmsSigXYZData:
1049  {
1050  target_info.colorspace=XYZColorspace;
1051  target_info.type=(cmsUInt32Number) TYPE_XYZ_DBL;
1052  break;
1053  }
1054  default:
1055  ThrowProfileException(ImageError,
1056  "ColorspaceColorProfileMismatch",name);
1057  }
1058  switch (image->rendering_intent)
1059  {
1060  case AbsoluteIntent:
1061  {
1062  target_info.intent=INTENT_ABSOLUTE_COLORIMETRIC;
1063  break;
1064  }
1065  case PerceptualIntent:
1066  {
1067  target_info.intent=INTENT_PERCEPTUAL;
1068  break;
1069  }
1070  case RelativeIntent:
1071  {
1072  target_info.intent=INTENT_RELATIVE_COLORIMETRIC;
1073  break;
1074  }
1075  case SaturationIntent:
1076  {
1077  target_info.intent=INTENT_SATURATION;
1078  break;
1079  }
1080  default:
1081  {
1082  target_info.intent=INTENT_PERCEPTUAL;
1083  break;
1084  }
1085  }
1086  flags=cmsFLAGS_HIGHRESPRECALC;
1087 #if defined(cmsFLAGS_BLACKPOINTCOMPENSATION)
1088  if (image->black_point_compensation != MagickFalse)
1089  flags|=cmsFLAGS_BLACKPOINTCOMPENSATION;
1090 #endif
1091  transform=AcquireTransformTLS(&source_info,&target_info,
1092  flags,cms_context);
1093  if (transform == (cmsHTRANSFORM *) NULL)
1094  ThrowProfileException(ImageError,"UnableToCreateColorTransform",
1095  name);
1096  /*
1097  Transform image as dictated by the source & target image profiles.
1098  */
1099  source_info.pixels=AcquirePixelTLS(image->columns,
1100  source_info.channels);
1101  target_info.pixels=AcquirePixelTLS(image->columns,
1102  target_info.channels);
1103  if ((source_info.pixels == (double **) NULL) ||
1104  (target_info.pixels == (double **) NULL))
1105  {
1106  target_info.pixels=DestroyPixelTLS(target_info.pixels);
1107  source_info.pixels=DestroyPixelTLS(source_info.pixels);
1108  transform=DestroyTransformTLS(transform);
1109  ThrowProfileException(ResourceLimitError,
1110  "MemoryAllocationFailed",image->filename);
1111  }
1112  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
1113  {
1114  target_info.pixels=DestroyPixelTLS(target_info.pixels);
1115  source_info.pixels=DestroyPixelTLS(source_info.pixels);
1116  transform=DestroyTransformTLS(transform);
1117  profile=DestroyStringInfo(profile);
1118  if (source_info.profile != (cmsHPROFILE) NULL)
1119  (void) cmsCloseProfile(source_info.profile);
1120  if (target_info.profile != (cmsHPROFILE) NULL)
1121  (void) cmsCloseProfile(target_info.profile);
1122  return(MagickFalse);
1123  }
1124  if (target_info.colorspace == CMYKColorspace)
1125  (void) SetImageColorspace(image,target_info.colorspace);
1126  progress=0;
1127  image_view=AcquireAuthenticCacheView(image,exception);
1128 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1129  #pragma omp parallel for schedule(static) shared(status) \
1130  magick_number_threads(image,image,image->rows,1)
1131 #endif
1132  for (y=0; y < (ssize_t) image->rows; y++)
1133  {
1134  const int
1135  id = GetOpenMPThreadId();
1136 
1137  MagickBooleanType
1138  sync;
1139 
1140  IndexPacket
1141  *magick_restrict indexes;
1142 
1143  double
1144  *p;
1145 
1146  PixelPacket
1147  *magick_restrict q;
1148 
1149  ssize_t
1150  x;
1151 
1152  if (status == MagickFalse)
1153  continue;
1154  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1155  exception);
1156  if (q == (PixelPacket *) NULL)
1157  {
1158  status=MagickFalse;
1159  continue;
1160  }
1161  indexes=GetCacheViewAuthenticIndexQueue(image_view);
1162  p=source_info.pixels[id];
1163  for (x=0; x < (ssize_t) image->columns; x++)
1164  {
1165  *p++=GetLCMSPixel(source_info,GetPixelRed(q),0);
1166  if (source_info.channels > 1)
1167  {
1168  *p++=GetLCMSPixel(source_info,GetPixelGreen(q),1);
1169  *p++=GetLCMSPixel(source_info,GetPixelBlue(q),2);
1170  }
1171  if (source_info.channels > 3)
1172  {
1173  *p=GetLCMSPixel(source_info,0,3);
1174  if (indexes != (IndexPacket *) NULL)
1175  *p=GetLCMSPixel(source_info,GetPixelIndex(indexes+x),3);
1176  p++;
1177  }
1178  q++;
1179  }
1180  cmsDoTransform(transform[id],source_info.pixels[id],
1181  target_info.pixels[id],(unsigned int) image->columns);
1182  p=target_info.pixels[id];
1183  q-=image->columns;
1184  for (x=0; x < (ssize_t) image->columns; x++)
1185  {
1186  SetPixelRed(q,SetLCMSPixel(target_info,*p,0));
1187  SetPixelGreen(q,GetPixelRed(q));
1188  SetPixelBlue(q,GetPixelRed(q));
1189  p++;
1190  if (target_info.channels > 1)
1191  {
1192  SetPixelGreen(q,SetLCMSPixel(target_info,*p,1));
1193  p++;
1194  SetPixelBlue(q,SetLCMSPixel(target_info,*p,2));
1195  p++;
1196  }
1197  if (target_info.channels > 3)
1198  {
1199  if (indexes != (IndexPacket *) NULL)
1200  SetPixelIndex(indexes+x,SetLCMSPixel(target_info,*p,3));
1201  p++;
1202  }
1203  q++;
1204  }
1205  sync=SyncCacheViewAuthenticPixels(image_view,exception);
1206  if (sync == MagickFalse)
1207  status=MagickFalse;
1208  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1209  {
1210  MagickBooleanType
1211  proceed;
1212 
1213 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1214  #pragma omp atomic
1215 #endif
1216  progress++;
1217  proceed=SetImageProgress(image,ProfileImageTag,progress,
1218  image->rows);
1219  if (proceed == MagickFalse)
1220  status=MagickFalse;
1221  }
1222  }
1223  image_view=DestroyCacheView(image_view);
1224  (void) SetImageColorspace(image,target_info.colorspace);
1225  switch (signature)
1226  {
1227  case cmsSigRgbData:
1228  {
1229  image->type=image->matte == MagickFalse ? TrueColorType :
1230  TrueColorMatteType;
1231  break;
1232  }
1233  case cmsSigCmykData:
1234  {
1235  image->type=image->matte == MagickFalse ? ColorSeparationType :
1236  ColorSeparationMatteType;
1237  break;
1238  }
1239  case cmsSigGrayData:
1240  {
1241  image->type=image->matte == MagickFalse ? GrayscaleType :
1242  GrayscaleMatteType;
1243  break;
1244  }
1245  default:
1246  break;
1247  }
1248  target_info.pixels=DestroyPixelTLS(target_info.pixels);
1249  source_info.pixels=DestroyPixelTLS(source_info.pixels);
1250  transform=DestroyTransformTLS(transform);
1251  if ((status != MagickFalse) &&
1252  (cmsGetDeviceClass(source_info.profile) != cmsSigLinkClass))
1253  status=SetImageProfile(image,name,profile);
1254  if (target_info.profile != (cmsHPROFILE) NULL)
1255  (void) cmsCloseProfile(target_info.profile);
1256  }
1257  (void) cmsCloseProfile(source_info.profile);
1258  cmsDeleteContext(cms_context);
1259  }
1260 #endif
1261  }
1262  profile=DestroyStringInfo(profile);
1263  return(status);
1264 }
1265 
1266 /*
1267 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1268 % %
1269 % %
1270 % %
1271 % R e m o v e I m a g e P r o f i l e %
1272 % %
1273 % %
1274 % %
1275 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1276 %
1277 % RemoveImageProfile() removes a named profile from the image and returns its
1278 % value.
1279 %
1280 % The format of the RemoveImageProfile method is:
1281 %
1282 % void *RemoveImageProfile(Image *image,const char *name)
1283 %
1284 % A description of each parameter follows:
1285 %
1286 % o image: the image.
1287 %
1288 % o name: the profile name.
1289 %
1290 */
1291 MagickExport StringInfo *RemoveImageProfile(Image *image,const char *name)
1292 {
1293  StringInfo
1294  *profile;
1295 
1296  assert(image != (Image *) NULL);
1297  assert(image->signature == MagickCoreSignature);
1298  if (IsEventLogging() != MagickFalse)
1299  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1300  if (image->profiles == (SplayTreeInfo *) NULL)
1301  return((StringInfo *) NULL);
1302  if (LocaleCompare(name,"icc") == 0)
1303  {
1304  /*
1305  Continue to support deprecated color profile for now.
1306  */
1307  image->color_profile.length=0;
1308  image->color_profile.info=(unsigned char *) NULL;
1309  }
1310  if (LocaleCompare(name,"iptc") == 0)
1311  {
1312  /*
1313  Continue to support deprecated IPTC profile for now.
1314  */
1315  image->iptc_profile.length=0;
1316  image->iptc_profile.info=(unsigned char *) NULL;
1317  }
1318  WriteTo8BimProfile(image,name,(StringInfo *) NULL);
1319  profile=(StringInfo *) RemoveNodeFromSplayTree((SplayTreeInfo *)
1320  image->profiles,name);
1321  return(profile);
1322 }
1323 
1324 /*
1325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1326 % %
1327 % %
1328 % %
1329 % R e s e t P r o f i l e I t e r a t o r %
1330 % %
1331 % %
1332 % %
1333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1334 %
1335 % ResetImageProfileIterator() resets the image profile iterator. Use it in
1336 % conjunction with GetNextImageProfile() to iterate over all the profiles
1337 % associated with an image.
1338 %
1339 % The format of the ResetImageProfileIterator method is:
1340 %
1341 % ResetImageProfileIterator(Image *image)
1342 %
1343 % A description of each parameter follows:
1344 %
1345 % o image: the image.
1346 %
1347 */
1348 MagickExport void ResetImageProfileIterator(const Image *image)
1349 {
1350  assert(image != (Image *) NULL);
1351  assert(image->signature == MagickCoreSignature);
1352  if (IsEventLogging() != MagickFalse)
1353  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1354  if (image->profiles == (SplayTreeInfo *) NULL)
1355  return;
1356  ResetSplayTreeIterator((SplayTreeInfo *) image->profiles);
1357 }
1358 
1359 /*
1360 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1361 % %
1362 % %
1363 % %
1364 % S e t I m a g e P r o f i l e %
1365 % %
1366 % %
1367 % %
1368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1369 %
1370 % SetImageProfile() adds a named profile to the image. If a profile with the
1371 % same name already exists, it is replaced. This method differs from the
1372 % ProfileImage() method in that it does not apply CMS color profiles.
1373 %
1374 % The format of the SetImageProfile method is:
1375 %
1376 % MagickBooleanType SetImageProfile(Image *image,const char *name,
1377 % const StringInfo *profile)
1378 %
1379 % A description of each parameter follows:
1380 %
1381 % o image: the image.
1382 %
1383 % o name: the profile name, for example icc, exif, and 8bim (8bim is the
1384 % Photoshop wrapper for iptc profiles).
1385 %
1386 % o profile: A StringInfo structure that contains the named profile.
1387 %
1388 */
1389 
1390 static void *DestroyProfile(void *profile)
1391 {
1392  return((void *) DestroyStringInfo((StringInfo *) profile));
1393 }
1394 
1395 static inline const unsigned char *ReadResourceByte(const unsigned char *p,
1396  unsigned char *quantum)
1397 {
1398  *quantum=(*p++);
1399  return(p);
1400 }
1401 
1402 static inline const unsigned char *ReadResourceLong(const unsigned char *p,
1403  unsigned int *quantum)
1404 {
1405  *quantum=(unsigned int) (*p++) << 24;
1406  *quantum|=(unsigned int) (*p++) << 16;
1407  *quantum|=(unsigned int) (*p++) << 8;
1408  *quantum|=(unsigned int) (*p++);
1409  return(p);
1410 }
1411 
1412 static inline const unsigned char *ReadResourceShort(const unsigned char *p,
1413  unsigned short *quantum)
1414 {
1415  *quantum=(unsigned short) (*p++) << 8;
1416  *quantum|=(unsigned short) (*p++);
1417  return(p);
1418 }
1419 
1420 static inline void WriteResourceLong(unsigned char *p,
1421  const unsigned int quantum)
1422 {
1423  unsigned char
1424  buffer[4];
1425 
1426  buffer[0]=(unsigned char) (quantum >> 24);
1427  buffer[1]=(unsigned char) (quantum >> 16);
1428  buffer[2]=(unsigned char) (quantum >> 8);
1429  buffer[3]=(unsigned char) quantum;
1430  (void) memcpy(p,buffer,4);
1431 }
1432 
1433 static void WriteTo8BimProfile(Image *image,const char *name,
1434  const StringInfo *profile)
1435 {
1436 
1437  const unsigned char
1438  *datum,
1439  *q;
1440 
1441  const unsigned char
1442  *p;
1443 
1444  size_t
1445  length;
1446 
1447  StringInfo
1448  *profile_8bim;
1449 
1450  ssize_t
1451  count;
1452 
1453  unsigned char
1454  length_byte;
1455 
1456  unsigned int
1457  value;
1458 
1459  unsigned short
1460  id,
1461  profile_id;
1462 
1463  if (LocaleCompare(name,"icc") == 0)
1464  profile_id=0x040f;
1465  else
1466  if (LocaleCompare(name,"iptc") == 0)
1467  profile_id=0x0404;
1468  else
1469  if (LocaleCompare(name,"xmp") == 0)
1470  profile_id=0x0424;
1471  else
1472  return;
1473  profile_8bim=(StringInfo *) GetValueFromSplayTree((SplayTreeInfo *)
1474  image->profiles,"8bim");
1475  if (profile_8bim == (StringInfo *) NULL)
1476  return;
1477  datum=GetStringInfoDatum(profile_8bim);
1478  length=GetStringInfoLength(profile_8bim);
1479  for (p=datum; p < (datum+length-16); )
1480  {
1481  q=p;
1482  if (LocaleNCompare((char *) p,"8BIM",4) != 0)
1483  break;
1484  p+=4;
1485  p=ReadResourceShort(p,&id);
1486  p=ReadResourceByte(p,&length_byte);
1487  p+=length_byte;
1488  if (((length_byte+1) & 0x01) != 0)
1489  p++;
1490  if (p > (datum+length-4))
1491  break;
1492  p=ReadResourceLong(p,&value);
1493  count=(ssize_t) value;
1494  if ((count & 0x01) != 0)
1495  count++;
1496  if ((count < 0) || (p > (datum+length-count)) || (count > (ssize_t) length))
1497  break;
1498  if (id != profile_id)
1499  p+=count;
1500  else
1501  {
1502  size_t
1503  extent,
1504  offset;
1505 
1506  ssize_t
1507  extract_extent;
1508 
1509  StringInfo
1510  *extract_profile;
1511 
1512  extract_extent=0;
1513  extent=(datum+length)-(p+count);
1514  if (profile == (StringInfo *) NULL)
1515  {
1516  offset=(q-datum);
1517  extract_profile=AcquireStringInfo(offset+extent);
1518  (void) memcpy(extract_profile->datum,datum,offset);
1519  }
1520  else
1521  {
1522  offset=(p-datum);
1523  extract_extent=profile->length;
1524  if ((extract_extent & 0x01) != 0)
1525  extract_extent++;
1526  extract_profile=AcquireStringInfo(offset+extract_extent+extent);
1527  (void) memcpy(extract_profile->datum,datum,offset-4);
1528  WriteResourceLong(extract_profile->datum+offset-4,(unsigned int)
1529  profile->length);
1530  (void) memcpy(extract_profile->datum+offset,
1531  profile->datum,profile->length);
1532  }
1533  (void) memcpy(extract_profile->datum+offset+extract_extent,
1534  p+count,extent);
1535  (void) AddValueToSplayTree((SplayTreeInfo *) image->profiles,
1536  ConstantString("8bim"),CloneStringInfo(extract_profile));
1537  extract_profile=DestroyStringInfo(extract_profile);
1538  break;
1539  }
1540  }
1541 }
1542 
1543 static void GetProfilesFromResourceBlock(Image *image,
1544  const StringInfo *resource_block)
1545 {
1546  const unsigned char
1547  *datum;
1548 
1549  const unsigned char
1550  *p;
1551 
1552  size_t
1553  length;
1554 
1555  ssize_t
1556  count;
1557 
1558  StringInfo
1559  *profile;
1560 
1561  unsigned char
1562  length_byte;
1563 
1564  unsigned int
1565  value;
1566 
1567  unsigned short
1568  id;
1569 
1570  datum=GetStringInfoDatum(resource_block);
1571  length=GetStringInfoLength(resource_block);
1572  for (p=datum; p < (datum+length-16); )
1573  {
1574  if (LocaleNCompare((char *) p,"8BIM",4) != 0)
1575  break;
1576  p+=4;
1577  p=ReadResourceShort(p,&id);
1578  p=ReadResourceByte(p,&length_byte);
1579  p+=length_byte;
1580  if (((length_byte+1) & 0x01) != 0)
1581  p++;
1582  if (p > (datum+length-4))
1583  break;
1584  p=ReadResourceLong(p,&value);
1585  count=(ssize_t) value;
1586  if ((p > (datum+length-count)) || (count > (ssize_t) length) ||
1587  (count <= 0))
1588  break;
1589  switch (id)
1590  {
1591  case 0x03ed:
1592  {
1593  unsigned int
1594  resolution;
1595 
1596  unsigned short
1597  units;
1598 
1599  /*
1600  Resolution.
1601  */
1602  if (count < 10)
1603  break;
1604  p=ReadResourceLong(p,&resolution);
1605  image->x_resolution=((double) resolution)/65536.0;
1606  p=ReadResourceShort(p,&units)+2;
1607  p=ReadResourceLong(p,&resolution)+4;
1608  image->y_resolution=((double) resolution)/65536.0;
1609  /*
1610  Values are always stored as pixels per inch.
1611  */
1612  if ((ResolutionType) units != PixelsPerCentimeterResolution)
1613  image->units=PixelsPerInchResolution;
1614  else
1615  {
1616  image->units=PixelsPerCentimeterResolution;
1617  image->x_resolution/=2.54;
1618  image->y_resolution/=2.54;
1619  }
1620  break;
1621  }
1622  case 0x0404:
1623  {
1624  /*
1625  IPTC Profile
1626  */
1627  profile=AcquireStringInfo(count);
1628  SetStringInfoDatum(profile,p);
1629  (void) SetImageProfileInternal(image,"iptc",profile,MagickTrue);
1630  profile=DestroyStringInfo(profile);
1631  p+=count;
1632  break;
1633  }
1634  case 0x040c:
1635  {
1636  /*
1637  Thumbnail.
1638  */
1639  p+=count;
1640  break;
1641  }
1642  case 0x040f:
1643  {
1644  /*
1645  ICC profile.
1646  */
1647  profile=AcquireStringInfo(count);
1648  SetStringInfoDatum(profile,p);
1649  (void) SetImageProfileInternal(image,"icc",profile,MagickTrue);
1650  profile=DestroyStringInfo(profile);
1651  p+=count;
1652  break;
1653  }
1654  case 0x0422:
1655  {
1656  /*
1657  EXIF Profile.
1658  */
1659  profile=AcquireStringInfo(count);
1660  SetStringInfoDatum(profile,p);
1661  (void) SetImageProfileInternal(image,"exif",profile,MagickTrue);
1662  profile=DestroyStringInfo(profile);
1663  p+=count;
1664  break;
1665  }
1666  case 0x0424:
1667  {
1668  /*
1669  XMP Profile.
1670  */
1671  profile=AcquireStringInfo(count);
1672  SetStringInfoDatum(profile,p);
1673  (void) SetImageProfileInternal(image,"xmp",profile,MagickTrue);
1674  profile=DestroyStringInfo(profile);
1675  p+=count;
1676  break;
1677  }
1678  default:
1679  {
1680  p+=count;
1681  break;
1682  }
1683  }
1684  if ((count & 0x01) != 0)
1685  p++;
1686  }
1687 }
1688 
1689 #if defined(MAGICKCORE_XML_DELEGATE)
1690 static MagickBooleanType ValidateXMPProfile(Image *image,
1691  const StringInfo *profile)
1692 {
1693  xmlDocPtr
1694  document;
1695 
1696  /*
1697  Parse XML profile.
1698  */
1699  document=xmlReadMemory((const char *) GetStringInfoDatum(profile),(int)
1700  GetStringInfoLength(profile),"xmp.xml",NULL,XML_PARSE_NOERROR |
1701  XML_PARSE_NOWARNING);
1702  if (document == (xmlDocPtr) NULL)
1703  {
1704  (void) ThrowMagickException(&image->exception,GetMagickModule(),
1705  ImageWarning,"CorruptImageProfile","`%s' (XMP)",image->filename);
1706  return(MagickFalse);
1707  }
1708  xmlFreeDoc(document);
1709  return(MagickTrue);
1710 }
1711 #else
1712 static MagickBooleanType ValidateXMPProfile(Image *image,
1713  const StringInfo *profile)
1714 {
1715  (void) ThrowMagickException(&image->exception,GetMagickModule(),
1716  MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","'%s' (XML)",
1717  image->filename);
1718  return(MagickFalse);
1719 }
1720 #endif
1721 
1722 static MagickBooleanType SetImageProfileInternal(Image *image,const char *name,
1723  const StringInfo *profile,const MagickBooleanType recursive)
1724 {
1725  char
1726  key[MaxTextExtent];
1727 
1728  MagickBooleanType
1729  status;
1730 
1731  assert(image != (Image *) NULL);
1732  assert(image->signature == MagickCoreSignature);
1733  if (IsEventLogging() != MagickFalse)
1734  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1735  if ((LocaleCompare(name,"xmp") == 0) &&
1736  (ValidateXMPProfile(image,profile) == MagickFalse))
1737  return(MagickTrue);
1738  if (image->profiles == (SplayTreeInfo *) NULL)
1739  image->profiles=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
1740  DestroyProfile);
1741  (void) CopyMagickString(key,name,MaxTextExtent);
1742  LocaleLower(key);
1743  status=AddValueToSplayTree((SplayTreeInfo *) image->profiles,
1744  ConstantString(key),CloneStringInfo(profile));
1745  if ((status != MagickFalse) &&
1746  ((LocaleCompare(name,"icc") == 0) || (LocaleCompare(name,"icm") == 0)))
1747  {
1748  const StringInfo
1749  *icc_profile;
1750 
1751  /*
1752  Continue to support deprecated color profile member.
1753  */
1754  icc_profile=GetImageProfile(image,name);
1755  if (icc_profile != (const StringInfo *) NULL)
1756  {
1757  image->color_profile.length=GetStringInfoLength(icc_profile);
1758  image->color_profile.info=GetStringInfoDatum(icc_profile);
1759  }
1760  }
1761  if ((status != MagickFalse) &&
1762  ((LocaleCompare(name,"iptc") == 0) || (LocaleCompare(name,"8bim") == 0)))
1763  {
1764  const StringInfo
1765  *iptc_profile;
1766 
1767  /*
1768  Continue to support deprecated IPTC profile member.
1769  */
1770  iptc_profile=GetImageProfile(image,name);
1771  if (iptc_profile != (const StringInfo *) NULL)
1772  {
1773  image->iptc_profile.length=GetStringInfoLength(iptc_profile);
1774  image->iptc_profile.info=GetStringInfoDatum(iptc_profile);
1775  }
1776  }
1777  if (status != MagickFalse)
1778  {
1779  if (LocaleCompare(name,"8bim") == 0)
1780  GetProfilesFromResourceBlock(image,profile);
1781  else
1782  if (recursive == MagickFalse)
1783  WriteTo8BimProfile(image,name,profile);
1784  }
1785  return(status);
1786 }
1787 
1788 MagickExport MagickBooleanType SetImageProfile(Image *image,const char *name,
1789  const StringInfo *profile)
1790 {
1791  return(SetImageProfileInternal(image,name,profile,MagickFalse));
1792 }
1793 
1794 /*
1795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1796 % %
1797 % %
1798 % %
1799 % S y n c I m a g e P r o f i l e s %
1800 % %
1801 % %
1802 % %
1803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1804 %
1805 % SyncImageProfiles() synchronizes image properties with the image profiles.
1806 % Currently we only support updating the EXIF resolution and orientation.
1807 %
1808 % The format of the SyncImageProfiles method is:
1809 %
1810 % MagickBooleanType SyncImageProfiles(Image *image)
1811 %
1812 % A description of each parameter follows:
1813 %
1814 % o image: the image.
1815 %
1816 */
1817 
1818 static inline int ReadProfileByte(unsigned char **p,size_t *length)
1819 {
1820  int
1821  c;
1822 
1823  if (*length < 1)
1824  return(EOF);
1825  c=(int) (*(*p)++);
1826  (*length)--;
1827  return(c);
1828 }
1829 
1830 static inline signed short ReadProfileShort(const EndianType endian,
1831  unsigned char *buffer)
1832 {
1833  union
1834  {
1835  unsigned int
1836  unsigned_value;
1837 
1838  signed int
1839  signed_value;
1840  } quantum;
1841 
1842  unsigned short
1843  value;
1844 
1845  if (endian == LSBEndian)
1846  {
1847  value=(unsigned short) buffer[1] << 8;
1848  value|=(unsigned short) buffer[0];
1849  quantum.unsigned_value=value & 0xffff;
1850  return(quantum.signed_value);
1851  }
1852  value=(unsigned short) buffer[0] << 8;
1853  value|=(unsigned short) buffer[1];
1854  quantum.unsigned_value=value & 0xffff;
1855  return(quantum.signed_value);
1856 }
1857 
1858 static inline signed int ReadProfileLong(const EndianType endian,
1859  unsigned char *buffer)
1860 {
1861  union
1862  {
1863  unsigned int
1864  unsigned_value;
1865 
1866  signed int
1867  signed_value;
1868  } quantum;
1869 
1870  unsigned int
1871  value;
1872 
1873  if (endian == LSBEndian)
1874  {
1875  value=(unsigned int) buffer[3] << 24;
1876  value|=(unsigned int) buffer[2] << 16;
1877  value|=(unsigned int) buffer[1] << 8;
1878  value|=(unsigned int) buffer[0];
1879  quantum.unsigned_value=value & 0xffffffff;
1880  return(quantum.signed_value);
1881  }
1882  value=(unsigned int) buffer[0] << 24;
1883  value|=(unsigned int) buffer[1] << 16;
1884  value|=(unsigned int) buffer[2] << 8;
1885  value|=(unsigned int) buffer[3];
1886  quantum.unsigned_value=value & 0xffffffff;
1887  return(quantum.signed_value);
1888 }
1889 
1890 static inline signed int ReadProfileMSBLong(unsigned char **p,size_t *length)
1891 {
1892  signed int
1893  value;
1894 
1895  if (*length < 4)
1896  return(0);
1897  value=ReadProfileLong(MSBEndian,*p);
1898  (*length)-=4;
1899  *p+=4;
1900  return(value);
1901 }
1902 
1903 static inline signed short ReadProfileMSBShort(unsigned char **p,
1904  size_t *length)
1905 {
1906  signed short
1907  value;
1908 
1909  if (*length < 2)
1910  return(0);
1911  value=ReadProfileShort(MSBEndian,*p);
1912  (*length)-=2;
1913  *p+=2;
1914  return(value);
1915 }
1916 
1917 static inline void WriteProfileLong(const EndianType endian,
1918  const size_t value,unsigned char *p)
1919 {
1920  unsigned char
1921  buffer[4];
1922 
1923  if (endian == LSBEndian)
1924  {
1925  buffer[0]=(unsigned char) value;
1926  buffer[1]=(unsigned char) (value >> 8);
1927  buffer[2]=(unsigned char) (value >> 16);
1928  buffer[3]=(unsigned char) (value >> 24);
1929  (void) memcpy(p,buffer,4);
1930  return;
1931  }
1932  buffer[0]=(unsigned char) (value >> 24);
1933  buffer[1]=(unsigned char) (value >> 16);
1934  buffer[2]=(unsigned char) (value >> 8);
1935  buffer[3]=(unsigned char) value;
1936  (void) memcpy(p,buffer,4);
1937 }
1938 
1939 static void WriteProfileShort(const EndianType endian,
1940  const unsigned short value,unsigned char *p)
1941 {
1942  unsigned char
1943  buffer[2];
1944 
1945  if (endian == LSBEndian)
1946  {
1947  buffer[0]=(unsigned char) value;
1948  buffer[1]=(unsigned char) (value >> 8);
1949  (void) memcpy(p,buffer,2);
1950  return;
1951  }
1952  buffer[0]=(unsigned char) (value >> 8);
1953  buffer[1]=(unsigned char) value;
1954  (void) memcpy(p,buffer,2);
1955 }
1956 
1957 static MagickBooleanType SyncExifProfile(const Image *image,unsigned char *exif,
1958  size_t length)
1959 {
1960 #define MaxDirectoryStack 16
1961 #define EXIF_DELIMITER "\n"
1962 #define EXIF_NUM_FORMATS 12
1963 #define TAG_EXIF_OFFSET 0x8769
1964 #define TAG_INTEROP_OFFSET 0xa005
1965 
1966  typedef struct _DirectoryInfo
1967  {
1968  unsigned char
1969  *directory;
1970 
1971  size_t
1972  entry;
1973  } DirectoryInfo;
1974 
1975  DirectoryInfo
1976  directory_stack[MaxDirectoryStack] = { { 0, 0 } };
1977 
1978  EndianType
1979  endian;
1980 
1981  size_t
1982  entry,
1983  number_entries;
1984 
1986  *exif_resources;
1987 
1988  ssize_t
1989  id,
1990  level,
1991  offset;
1992 
1993  static int
1994  format_bytes[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
1995 
1996  unsigned char
1997  *directory;
1998 
1999  if (length < 16)
2000  return(MagickFalse);
2001  id=(ssize_t) ReadProfileShort(LSBEndian,exif);
2002  if ((id != 0x4949) && (id != 0x4D4D))
2003  {
2004  while (length != 0)
2005  {
2006  if (ReadProfileByte(&exif,&length) != 0x45)
2007  continue;
2008  if (ReadProfileByte(&exif,&length) != 0x78)
2009  continue;
2010  if (ReadProfileByte(&exif,&length) != 0x69)
2011  continue;
2012  if (ReadProfileByte(&exif,&length) != 0x66)
2013  continue;
2014  if (ReadProfileByte(&exif,&length) != 0x00)
2015  continue;
2016  if (ReadProfileByte(&exif,&length) != 0x00)
2017  continue;
2018  break;
2019  }
2020  if (length < 16)
2021  return(MagickFalse);
2022  id=(ssize_t) ReadProfileShort(LSBEndian,exif);
2023  }
2024  endian=LSBEndian;
2025  if (id == 0x4949)
2026  endian=LSBEndian;
2027  else
2028  if (id == 0x4D4D)
2029  endian=MSBEndian;
2030  else
2031  return(MagickFalse);
2032  if (ReadProfileShort(endian,exif+2) != 0x002a)
2033  return(MagickFalse);
2034  /*
2035  This the offset to the first IFD.
2036  */
2037  offset=(ssize_t) ReadProfileLong(endian,exif+4);
2038  if ((offset < 0) || ((size_t) offset >= length))
2039  return(MagickFalse);
2040  directory=exif+offset;
2041  level=0;
2042  entry=0;
2043  exif_resources=NewSplayTree((int (*)(const void *,const void *)) NULL,
2044  (void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
2045  do
2046  {
2047  if (level > 0)
2048  {
2049  level--;
2050  directory=directory_stack[level].directory;
2051  entry=directory_stack[level].entry;
2052  }
2053  if ((directory < exif) || (directory > (exif+length-2)))
2054  break;
2055  /*
2056  Determine how many entries there are in the current IFD.
2057  */
2058  number_entries=ReadProfileShort(endian,directory);
2059  for ( ; entry < number_entries; entry++)
2060  {
2061  int
2062  components;
2063 
2064  unsigned char
2065  *p,
2066  *q;
2067 
2068  size_t
2069  number_bytes;
2070 
2071  ssize_t
2072  format,
2073  tag_value;
2074 
2075  q=(unsigned char *) (directory+2+(12*entry));
2076  if (q > (exif+length-12))
2077  break; /* corrupt EXIF */
2078  if (GetValueFromSplayTree(exif_resources,q) == q)
2079  break;
2080  (void) AddValueToSplayTree(exif_resources,q,q);
2081  tag_value=(ssize_t) ReadProfileShort(endian,q);
2082  format=(ssize_t) ReadProfileShort(endian,q+2);
2083  if ((format < 0) || ((format-1) >= EXIF_NUM_FORMATS))
2084  break;
2085  components=(int) ReadProfileLong(endian,q+4);
2086  if (components < 0)
2087  break; /* corrupt EXIF */
2088  number_bytes=(size_t) components*format_bytes[format];
2089  if ((ssize_t) number_bytes < components)
2090  break; /* prevent overflow */
2091  if (number_bytes <= 4)
2092  p=q+8;
2093  else
2094  {
2095  /*
2096  The directory entry contains an offset.
2097  */
2098  offset=(ssize_t) ReadProfileLong(endian,q+8);
2099  if ((offset < 0) || ((size_t) (offset+number_bytes) > length))
2100  continue;
2101  if (~length < number_bytes)
2102  continue; /* prevent overflow */
2103  p=(unsigned char *) (exif+offset);
2104  }
2105  switch (tag_value)
2106  {
2107  case 0x011a:
2108  {
2109  (void) WriteProfileLong(endian,(size_t) (image->x_resolution+0.5),p);
2110  if (number_bytes == 8)
2111  (void) WriteProfileLong(endian,1UL,p+4);
2112  break;
2113  }
2114  case 0x011b:
2115  {
2116  (void) WriteProfileLong(endian,(size_t) (image->y_resolution+0.5),p);
2117  if (number_bytes == 8)
2118  (void) WriteProfileLong(endian,1UL,p+4);
2119  break;
2120  }
2121  case 0x0112:
2122  {
2123  if (number_bytes == 4)
2124  {
2125  (void) WriteProfileLong(endian,(size_t) image->orientation,p);
2126  break;
2127  }
2128  (void) WriteProfileShort(endian,(unsigned short) image->orientation,
2129  p);
2130  break;
2131  }
2132  case 0x0128:
2133  {
2134  if (number_bytes == 4)
2135  {
2136  (void) WriteProfileLong(endian,((size_t) image->units)+1,p);
2137  break;
2138  }
2139  (void) WriteProfileShort(endian,(unsigned short) (image->units+1),p);
2140  break;
2141  }
2142  default:
2143  break;
2144  }
2145  if ((tag_value == TAG_EXIF_OFFSET) || (tag_value == TAG_INTEROP_OFFSET))
2146  {
2147  offset=(ssize_t) ReadProfileLong(endian,p);
2148  if (((size_t) offset < length) && (level < (MaxDirectoryStack-2)))
2149  {
2150  directory_stack[level].directory=directory;
2151  entry++;
2152  directory_stack[level].entry=entry;
2153  level++;
2154  directory_stack[level].directory=exif+offset;
2155  directory_stack[level].entry=0;
2156  level++;
2157  if ((directory+2+(12*number_entries)) > (exif+length))
2158  break;
2159  offset=(ssize_t) ReadProfileLong(endian,directory+2+(12*
2160  number_entries));
2161  if ((offset != 0) && ((size_t) offset < length) &&
2162  (level < (MaxDirectoryStack-2)))
2163  {
2164  directory_stack[level].directory=exif+offset;
2165  directory_stack[level].entry=0;
2166  level++;
2167  }
2168  }
2169  break;
2170  }
2171  }
2172  } while (level > 0);
2173  exif_resources=DestroySplayTree(exif_resources);
2174  return(MagickTrue);
2175 }
2176 
2177 static MagickBooleanType Sync8BimProfile(const Image *image,
2178  const StringInfo *profile)
2179 {
2180  size_t
2181  length;
2182 
2183  ssize_t
2184  count;
2185 
2186  unsigned char
2187  *p;
2188 
2189  unsigned short
2190  id;
2191 
2192  length=GetStringInfoLength(profile);
2193  p=GetStringInfoDatum(profile);
2194  while (length != 0)
2195  {
2196  if (ReadProfileByte(&p,&length) != 0x38)
2197  continue;
2198  if (ReadProfileByte(&p,&length) != 0x42)
2199  continue;
2200  if (ReadProfileByte(&p,&length) != 0x49)
2201  continue;
2202  if (ReadProfileByte(&p,&length) != 0x4D)
2203  continue;
2204  if (length < 7)
2205  return(MagickFalse);
2206  id=ReadProfileMSBShort(&p,&length);
2207  count=(ssize_t) ReadProfileByte(&p,&length);
2208  if ((count >= (ssize_t) length) || (count < 0))
2209  return(MagickFalse);
2210  p+=count;
2211  length-=count;
2212  if ((*p & 0x01) == 0)
2213  (void) ReadProfileByte(&p,&length);
2214  count=(ssize_t) ReadProfileMSBLong(&p,&length);
2215  if ((count > (ssize_t) length) || (count < 0))
2216  return(MagickFalse);
2217  if ((id == 0x3ED) && (count == 16))
2218  {
2219  if (image->units == PixelsPerCentimeterResolution)
2220  WriteProfileLong(MSBEndian,(unsigned int) CastDoubleToLong(
2221  image->x_resolution*2.54*65536.0),p);
2222  else
2223  WriteProfileLong(MSBEndian,(unsigned int) CastDoubleToLong(
2224  image->x_resolution*65536.0),p);
2225  WriteProfileShort(MSBEndian,(unsigned short) image->units,p+4);
2226  if (image->units == PixelsPerCentimeterResolution)
2227  WriteProfileLong(MSBEndian,(unsigned int) CastDoubleToLong(
2228  image->y_resolution*2.54*65536.0),p+8);
2229  else
2230  WriteProfileLong(MSBEndian,(unsigned int) CastDoubleToLong(
2231  image->y_resolution*65536.0),p+8);
2232  WriteProfileShort(MSBEndian,(unsigned short) image->units,p+12);
2233  }
2234  if (id == 0x0422)
2235  (void) SyncExifProfile(image,p,count);
2236  p+=count;
2237  length-=count;
2238  }
2239  return(MagickTrue);
2240 }
2241 
2242 MagickExport MagickBooleanType SyncImageProfiles(Image *image)
2243 {
2244  MagickBooleanType
2245  status;
2246 
2247  StringInfo
2248  *profile;
2249 
2250  status=MagickTrue;
2251  profile=(StringInfo *) GetImageProfile(image,"8BIM");
2252  if (profile != (StringInfo *) NULL)
2253  if (Sync8BimProfile(image,profile) == MagickFalse)
2254  status=MagickFalse;
2255  profile=(StringInfo *) GetImageProfile(image,"EXIF");
2256  if (profile != (StringInfo *) NULL)
2257  if (SyncExifProfile(image,GetStringInfoDatum(profile),
2258  GetStringInfoLength(profile)) == MagickFalse)
2259  status=MagickFalse;
2260  return(status);
2261 }
Definition: image.h:152