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