MagickCore  7.0.8
Convert, Edit, Or Compose Bitmap Images
property.c
Go to the documentation of this file.
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % PPPP RRRR OOO PPPP EEEEE RRRR TTTTT Y Y %
7 % P P R R O O P P E R R T Y Y %
8 % PPPP RRRR O O PPPP EEE RRRR T Y %
9 % P R R O O P E R R T Y %
10 % P R R OOO P EEEEE R R T Y %
11 % %
12 % %
13 % MagickCore Property Methods %
14 % %
15 % Software Design %
16 % Cristy %
17 % March 2000 %
18 % %
19 % %
20 % Copyright 1999-2018 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://www.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 /*
41  Include declarations.
42 */
43 #include "MagickCore/studio.h"
44 #include "MagickCore/artifact.h"
45 #include "MagickCore/attribute.h"
46 #include "MagickCore/cache.h"
48 #include "MagickCore/color.h"
51 #include "MagickCore/compare.h"
52 #include "MagickCore/constitute.h"
53 #include "MagickCore/draw.h"
54 #include "MagickCore/effect.h"
55 #include "MagickCore/exception.h"
57 #include "MagickCore/fx.h"
58 #include "MagickCore/fx-private.h"
59 #include "MagickCore/gem.h"
60 #include "MagickCore/geometry.h"
61 #include "MagickCore/histogram.h"
62 #include "MagickCore/image.h"
63 #include "MagickCore/layer.h"
65 #include "MagickCore/list.h"
66 #include "MagickCore/magick.h"
67 #include "MagickCore/memory_.h"
68 #include "MagickCore/monitor.h"
69 #include "MagickCore/montage.h"
70 #include "MagickCore/option.h"
71 #include "MagickCore/policy.h"
72 #include "MagickCore/profile.h"
73 #include "MagickCore/property.h"
74 #include "MagickCore/quantum.h"
75 #include "MagickCore/resource_.h"
76 #include "MagickCore/splay-tree.h"
77 #include "MagickCore/signature.h"
78 #include "MagickCore/statistic.h"
79 #include "MagickCore/string_.h"
81 #include "MagickCore/token.h"
83 #include "MagickCore/utility.h"
85 #include "MagickCore/version.h"
86 #include "MagickCore/xml-tree.h"
88 #if defined(MAGICKCORE_LCMS_DELEGATE)
89 #if defined(MAGICKCORE_HAVE_LCMS2_LCMS2_H)
90 #include <lcms2/lcms2.h>
91 #elif defined(MAGICKCORE_HAVE_LCMS2_H)
92 #include "lcms2.h"
93 #elif defined(MAGICKCORE_HAVE_LCMS_LCMS_H)
94 #include <lcms/lcms.h>
95 #else
96 #include "lcms.h"
97 #endif
98 #endif
99 #if defined(MAGICKCORE_XML_DELEGATE)
100 # if defined(MAGICKCORE_WINDOWS_SUPPORT)
101 # if !defined(__MINGW32__)
102 # include <win32config.h>
103 # endif
104 # endif
105 # include <libxml/parser.h>
106 # include <libxml/tree.h>
107 #endif
108 
109 /*
110  Define declarations.
111 */
112 #if defined(MAGICKCORE_LCMS_DELEGATE)
113 #if defined(LCMS_VERSION) && (LCMS_VERSION < 2000)
114 #define cmsUInt32Number DWORD
115 #endif
116 #endif
117 
118 /*
119 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
120 % %
121 % %
122 % %
123 % C l o n e I m a g e P r o p e r t i e s %
124 % %
125 % %
126 % %
127 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
128 %
129 % CloneImageProperties() clones all the image properties to another image.
130 %
131 % The format of the CloneImageProperties method is:
132 %
133 % MagickBooleanType CloneImageProperties(Image *image,
134 % const Image *clone_image)
135 %
136 % A description of each parameter follows:
137 %
138 % o image: the image.
139 %
140 % o clone_image: the clone image.
141 %
142 */
144  const Image *clone_image)
145 {
146  assert(image != (Image *) NULL);
147  assert(image->signature == MagickCoreSignature);
148  if (image->debug != MagickFalse)
149  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
150  assert(clone_image != (const Image *) NULL);
151  assert(clone_image->signature == MagickCoreSignature);
152  if (clone_image->debug != MagickFalse)
154  clone_image->filename);
155  (void) CopyMagickString(image->filename,clone_image->filename,
157  (void) CopyMagickString(image->magick_filename,clone_image->magick_filename,
159  image->compression=clone_image->compression;
160  image->quality=clone_image->quality;
161  image->depth=clone_image->depth;
162  image->matte_color=clone_image->matte_color;
163  image->background_color=clone_image->background_color;
164  image->border_color=clone_image->border_color;
165  image->transparent_color=clone_image->transparent_color;
166  image->gamma=clone_image->gamma;
167  image->chromaticity=clone_image->chromaticity;
168  image->rendering_intent=clone_image->rendering_intent;
170  image->units=clone_image->units;
171  image->montage=(char *) NULL;
172  image->directory=(char *) NULL;
173  (void) CloneString(&image->geometry,clone_image->geometry);
174  image->offset=clone_image->offset;
175  image->resolution.x=clone_image->resolution.x;
176  image->resolution.y=clone_image->resolution.y;
177  image->page=clone_image->page;
178  image->tile_offset=clone_image->tile_offset;
179  image->extract_info=clone_image->extract_info;
180  image->filter=clone_image->filter;
181  image->fuzz=clone_image->fuzz;
182  image->intensity=clone_image->intensity;
183  image->interlace=clone_image->interlace;
184  image->interpolate=clone_image->interpolate;
185  image->endian=clone_image->endian;
186  image->gravity=clone_image->gravity;
187  image->compose=clone_image->compose;
188  image->orientation=clone_image->orientation;
189  image->scene=clone_image->scene;
190  image->dispose=clone_image->dispose;
191  image->delay=clone_image->delay;
192  image->ticks_per_second=clone_image->ticks_per_second;
193  image->iterations=clone_image->iterations;
194  image->total_colors=clone_image->total_colors;
195  image->taint=clone_image->taint;
196  image->progress_monitor=clone_image->progress_monitor;
197  image->client_data=clone_image->client_data;
198  image->start_loop=clone_image->start_loop;
199  image->error=clone_image->error;
200  image->signature=clone_image->signature;
201  if (clone_image->properties != (void *) NULL)
202  {
203  if (image->properties != (void *) NULL)
204  DestroyImageProperties(image);
206  clone_image->properties,(void *(*)(void *)) ConstantString,
207  (void *(*)(void *)) ConstantString);
208  }
209  return(MagickTrue);
210 }
211 
212 /*
213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
214 % %
215 % %
216 % %
217 % D e f i n e I m a g e P r o p e r t y %
218 % %
219 % %
220 % %
221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
222 %
223 % DefineImageProperty() associates an assignment string of the form
224 % "key=value" with an artifact or options. It is equivelent to
225 % SetImageProperty().
226 %
227 % The format of the DefineImageProperty method is:
228 %
229 % MagickBooleanType DefineImageProperty(Image *image,const char *property,
230 % ExceptionInfo *exception)
231 %
232 % A description of each parameter follows:
233 %
234 % o image: the image.
235 %
236 % o property: the image property.
237 %
238 % o exception: return any errors or warnings in this structure.
239 %
240 */
242  const char *property,ExceptionInfo *exception)
243 {
244  char
245  key[MagickPathExtent],
246  value[MagickPathExtent];
247 
248  register char
249  *p;
250 
251  assert(image != (Image *) NULL);
252  assert(property != (const char *) NULL);
253  (void) CopyMagickString(key,property,MagickPathExtent-1);
254  for (p=key; *p != '\0'; p++)
255  if (*p == '=')
256  break;
257  *value='\0';
258  if (*p == '=')
259  (void) CopyMagickString(value,p+1,MagickPathExtent);
260  *p='\0';
261  return(SetImageProperty(image,key,value,exception));
262 }
263 
264 /*
265 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
266 % %
267 % %
268 % %
269 % D e l e t e I m a g e P r o p e r t y %
270 % %
271 % %
272 % %
273 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274 %
275 % DeleteImageProperty() deletes an image property.
276 %
277 % The format of the DeleteImageProperty method is:
278 %
279 % MagickBooleanType DeleteImageProperty(Image *image,const char *property)
280 %
281 % A description of each parameter follows:
282 %
283 % o image: the image.
284 %
285 % o property: the image property.
286 %
287 */
289  const char *property)
290 {
291  assert(image != (Image *) NULL);
292  assert(image->signature == MagickCoreSignature);
293  if (image->debug != MagickFalse)
294  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
295  if (image->properties == (void *) NULL)
296  return(MagickFalse);
297  return(DeleteNodeFromSplayTree((SplayTreeInfo *) image->properties,property));
298 }
299 
300 /*
301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
302 % %
303 % %
304 % %
305 % D e s t r o y I m a g e P r o p e r t i e s %
306 % %
307 % %
308 % %
309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
310 %
311 % DestroyImageProperties() destroys all properties and associated memory
312 % attached to the given image.
313 %
314 % The format of the DestroyDefines method is:
315 %
316 % void DestroyImageProperties(Image *image)
317 %
318 % A description of each parameter follows:
319 %
320 % o image: the image.
321 %
322 */
324 {
325  assert(image != (Image *) NULL);
326  assert(image->signature == MagickCoreSignature);
327  if (image->debug != MagickFalse)
328  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
329  if (image->properties != (void *) NULL)
330  image->properties=(void *) DestroySplayTree((SplayTreeInfo *)
331  image->properties);
332 }
333 
334 /*
335 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
336 % %
337 % %
338 % %
339 % F o r m a t I m a g e P r o p e r t y %
340 % %
341 % %
342 % %
343 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
344 %
345 % FormatImageProperty() permits formatted property/value pairs to be saved as
346 % an image property.
347 %
348 % The format of the FormatImageProperty method is:
349 %
350 % MagickBooleanType FormatImageProperty(Image *image,const char *property,
351 % const char *format,...)
352 %
353 % A description of each parameter follows.
354 %
355 % o image: The image.
356 %
357 % o property: The attribute property.
358 %
359 % o format: A string describing the format to use to write the remaining
360 % arguments.
361 %
362 */
364  const char *property,const char *format,...)
365 {
366  char
367  value[MagickPathExtent];
368 
370  *exception;
371 
373  status;
374 
375  ssize_t
376  n;
377 
378  va_list
379  operands;
380 
381  va_start(operands,format);
382  n=FormatLocaleStringList(value,MagickPathExtent,format,operands);
383  (void) n;
384  va_end(operands);
385  exception=AcquireExceptionInfo();
386  status=SetImageProperty(image,property,value,exception);
387  exception=DestroyExceptionInfo(exception);
388  return(status);
389 }
390 
391 /*
392 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
393 % %
394 % %
395 % %
396 % G e t I m a g e P r o p e r t y %
397 % %
398 % %
399 % %
400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
401 %
402 % GetImageProperty() gets a value associated with an image property.
403 %
404 % This includes, profile prefixes, such as "exif:", "iptc:" and "8bim:"
405 % It does not handle non-prifile prefixes, such as "fx:", "option:", or
406 % "artifact:".
407 %
408 % The returned string is stored as a properity of the same name for faster
409 % lookup later. It should NOT be freed by the caller.
410 %
411 % The format of the GetImageProperty method is:
412 %
413 % const char *GetImageProperty(const Image *image,const char *key,
414 % ExceptionInfo *exception)
415 %
416 % A description of each parameter follows:
417 %
418 % o image: the image.
419 %
420 % o key: the key.
421 %
422 % o exception: return any errors or warnings in this structure.
423 %
424 */
425 
426 static char
427  *TracePSClippath(const unsigned char *,size_t),
428  *TraceSVGClippath(const unsigned char *,size_t,const size_t,
429  const size_t);
430 
431 static MagickBooleanType GetIPTCProperty(const Image *image,const char *key,
432  ExceptionInfo *exception)
433 {
434  char
435  *attribute,
436  *message;
437 
438  const StringInfo
439  *profile;
440 
441  long
442  count,
443  dataset,
444  record;
445 
446  register ssize_t
447  i;
448 
449  size_t
450  length;
451 
452  profile=GetImageProfile(image,"iptc");
453  if (profile == (StringInfo *) NULL)
454  profile=GetImageProfile(image,"8bim");
455  if (profile == (StringInfo *) NULL)
456  return(MagickFalse);
457  count=sscanf(key,"IPTC:%ld:%ld",&dataset,&record);
458  if (count != 2)
459  return(MagickFalse);
460  attribute=(char *) NULL;
461  for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=(ssize_t) length)
462  {
463  length=1;
464  if ((ssize_t) GetStringInfoDatum(profile)[i] != 0x1c)
465  continue;
466  length=(size_t) (GetStringInfoDatum(profile)[i+3] << 8);
467  length|=GetStringInfoDatum(profile)[i+4];
468  if (((long) GetStringInfoDatum(profile)[i+1] == dataset) &&
469  ((long) GetStringInfoDatum(profile)[i+2] == record))
470  {
471  message=(char *) NULL;
472  if (~length >= 1)
473  message=(char *) AcquireQuantumMemory(length+1UL,sizeof(*message));
474  if (message != (char *) NULL)
475  {
476  (void) CopyMagickString(message,(char *) GetStringInfoDatum(
477  profile)+i+5,length+1);
478  (void) ConcatenateString(&attribute,message);
479  (void) ConcatenateString(&attribute,";");
480  message=DestroyString(message);
481  }
482  }
483  i+=5;
484  }
485  if ((attribute == (char *) NULL) || (*attribute == ';'))
486  {
487  if (attribute != (char *) NULL)
488  attribute=DestroyString(attribute);
489  return(MagickFalse);
490  }
491  attribute[strlen(attribute)-1]='\0';
492  (void) SetImageProperty((Image *) image,key,(const char *) attribute,
493  exception);
494  attribute=DestroyString(attribute);
495  return(MagickTrue);
496 }
497 
498 static inline int ReadPropertyByte(const unsigned char **p,size_t *length)
499 {
500  int
501  c;
502 
503  if (*length < 1)
504  return(EOF);
505  c=(int) (*(*p)++);
506  (*length)--;
507  return(c);
508 }
509 
510 static inline signed int ReadPropertyMSBLong(const unsigned char **p,
511  size_t *length)
512 {
513  union
514  {
515  unsigned int
516  unsigned_value;
517 
518  signed int
519  signed_value;
520  } quantum;
521 
522  int
523  c;
524 
525  register ssize_t
526  i;
527 
528  unsigned char
529  buffer[4];
530 
531  unsigned int
532  value;
533 
534  if (*length < 4)
535  return(-1);
536  for (i=0; i < 4; i++)
537  {
538  c=(int) (*(*p)++);
539  (*length)--;
540  buffer[i]=(unsigned char) c;
541  }
542  value=(unsigned int) buffer[0] << 24;
543  value|=(unsigned int) buffer[1] << 16;
544  value|=(unsigned int) buffer[2] << 8;
545  value|=(unsigned int) buffer[3];
546  quantum.unsigned_value=value & 0xffffffff;
547  return(quantum.signed_value);
548 }
549 
550 static inline signed short ReadPropertyMSBShort(const unsigned char **p,
551  size_t *length)
552 {
553  union
554  {
555  unsigned short
556  unsigned_value;
557 
558  signed short
559  signed_value;
560  } quantum;
561 
562  int
563  c;
564 
565  register ssize_t
566  i;
567 
568  unsigned char
569  buffer[2];
570 
571  unsigned short
572  value;
573 
574  if (*length < 2)
575  return((unsigned short) ~0);
576  for (i=0; i < 2; i++)
577  {
578  c=(int) (*(*p)++);
579  (*length)--;
580  buffer[i]=(unsigned char) c;
581  }
582  value=(unsigned short) buffer[0] << 8;
583  value|=(unsigned short) buffer[1];
584  quantum.unsigned_value=value & 0xffff;
585  return(quantum.signed_value);
586 }
587 
588 static MagickBooleanType Get8BIMProperty(const Image *image,const char *key,
589  ExceptionInfo *exception)
590 {
591  char
592  *attribute,
593  format[MagickPathExtent],
595  *resource;
596 
597  const StringInfo
598  *profile;
599 
600  const unsigned char
601  *info;
602 
603  long
604  start,
605  stop;
606 
608  status;
609 
610  register ssize_t
611  i;
612 
613  size_t
614  length;
615 
616  ssize_t
617  count,
618  id,
619  sub_number;
620 
621  /*
622  There are no newlines in path names, so it's safe as terminator.
623  */
624  profile=GetImageProfile(image,"8bim");
625  if (profile == (StringInfo *) NULL)
626  return(MagickFalse);
627  count=(ssize_t) sscanf(key,"8BIM:%ld,%ld:%1024[^\n]\n%1024[^\n]",&start,&stop,
628  name,format);
629  if ((count != 2) && (count != 3) && (count != 4))
630  return(MagickFalse);
631  if (count < 4)
632  (void) CopyMagickString(format,"SVG",MagickPathExtent);
633  if (count < 3)
634  *name='\0';
635  sub_number=1;
636  if (*name == '#')
637  sub_number=(ssize_t) StringToLong(&name[1]);
638  sub_number=MagickMax(sub_number,1L);
639  resource=(char *) NULL;
640  status=MagickFalse;
641  length=GetStringInfoLength(profile);
642  info=GetStringInfoDatum(profile);
643  while ((length > 0) && (status == MagickFalse))
644  {
645  if (ReadPropertyByte(&info,&length) != (unsigned char) '8')
646  continue;
647  if (ReadPropertyByte(&info,&length) != (unsigned char) 'B')
648  continue;
649  if (ReadPropertyByte(&info,&length) != (unsigned char) 'I')
650  continue;
651  if (ReadPropertyByte(&info,&length) != (unsigned char) 'M')
652  continue;
653  id=(ssize_t) ReadPropertyMSBShort(&info,&length);
654  if (id < (ssize_t) start)
655  continue;
656  if (id > (ssize_t) stop)
657  continue;
658  if (resource != (char *) NULL)
659  resource=DestroyString(resource);
660  count=(ssize_t) ReadPropertyByte(&info,&length);
661  if ((count != 0) && ((size_t) count <= length))
662  {
663  resource=(char *) NULL;
664  if (~((size_t) count) >= (MagickPathExtent-1))
665  resource=(char *) AcquireQuantumMemory((size_t) count+
666  MagickPathExtent,sizeof(*resource));
667  if (resource != (char *) NULL)
668  {
669  for (i=0; i < (ssize_t) count; i++)
670  resource[i]=(char) ReadPropertyByte(&info,&length);
671  resource[count]='\0';
672  }
673  }
674  if ((count & 0x01) == 0)
675  (void) ReadPropertyByte(&info,&length);
676  count=(ssize_t) ReadPropertyMSBLong(&info,&length);
677  if ((count < 0) || ((size_t) count > length))
678  {
679  length=0;
680  continue;
681  }
682  if ((*name != '\0') && (*name != '#'))
683  if ((resource == (char *) NULL) || (LocaleCompare(name,resource) != 0))
684  {
685  /*
686  No name match, scroll forward and try next.
687  */
688  info+=count;
689  length-=MagickMin(count,(ssize_t) length);
690  continue;
691  }
692  if ((*name == '#') && (sub_number != 1))
693  {
694  /*
695  No numbered match, scroll forward and try next.
696  */
697  sub_number--;
698  info+=count;
699  length-=MagickMin(count,(ssize_t) length);
700  continue;
701  }
702  /*
703  We have the resource of interest.
704  */
705  attribute=(char *) NULL;
706  if (~((size_t) count) >= (MagickPathExtent-1))
707  attribute=(char *) AcquireQuantumMemory((size_t) count+MagickPathExtent,
708  sizeof(*attribute));
709  if (attribute != (char *) NULL)
710  {
711  (void) memcpy(attribute,(char *) info,(size_t) count);
712  attribute[count]='\0';
713  info+=count;
714  length-=MagickMin(count,(ssize_t) length);
715  if ((id <= 1999) || (id >= 2999))
716  (void) SetImageProperty((Image *) image,key,(const char *) attribute,
717  exception);
718  else
719  {
720  char
721  *path;
722 
723  if (LocaleCompare(format,"svg") == 0)
724  path=TraceSVGClippath((unsigned char *) attribute,(size_t) count,
725  image->columns,image->rows);
726  else
727  path=TracePSClippath((unsigned char *) attribute,(size_t) count);
728  (void) SetImageProperty((Image *) image,key,(const char *) path,
729  exception);
730  path=DestroyString(path);
731  }
732  attribute=DestroyString(attribute);
733  status=MagickTrue;
734  }
735  }
736  if (resource != (char *) NULL)
737  resource=DestroyString(resource);
738  return(status);
739 }
740 
741 static inline signed int ReadPropertySignedLong(const EndianType endian,
742  const unsigned char *buffer)
743 {
744  union
745  {
746  unsigned int
747  unsigned_value;
748 
749  signed int
750  signed_value;
751  } quantum;
752 
753  unsigned int
754  value;
755 
756  if (endian == LSBEndian)
757  {
758  value=(unsigned int) buffer[3] << 24;
759  value|=(unsigned int) buffer[2] << 16;
760  value|=(unsigned int) buffer[1] << 8;
761  value|=(unsigned int) buffer[0];
762  quantum.unsigned_value=value & 0xffffffff;
763  return(quantum.signed_value);
764  }
765  value=(unsigned int) buffer[0] << 24;
766  value|=(unsigned int) buffer[1] << 16;
767  value|=(unsigned int) buffer[2] << 8;
768  value|=(unsigned int) buffer[3];
769  quantum.unsigned_value=value & 0xffffffff;
770  return(quantum.signed_value);
771 }
772 
773 static inline unsigned int ReadPropertyUnsignedLong(const EndianType endian,
774  const unsigned char *buffer)
775 {
776  unsigned int
777  value;
778 
779  if (endian == LSBEndian)
780  {
781  value=(unsigned int) buffer[3] << 24;
782  value|=(unsigned int) buffer[2] << 16;
783  value|=(unsigned int) buffer[1] << 8;
784  value|=(unsigned int) buffer[0];
785  return(value & 0xffffffff);
786  }
787  value=(unsigned int) buffer[0] << 24;
788  value|=(unsigned int) buffer[1] << 16;
789  value|=(unsigned int) buffer[2] << 8;
790  value|=(unsigned int) buffer[3];
791  return(value & 0xffffffff);
792 }
793 
794 static inline signed short ReadPropertySignedShort(const EndianType endian,
795  const unsigned char *buffer)
796 {
797  union
798  {
799  unsigned short
800  unsigned_value;
801 
802  signed short
803  signed_value;
804  } quantum;
805 
806  unsigned short
807  value;
808 
809  if (endian == LSBEndian)
810  {
811  value=(unsigned short) buffer[1] << 8;
812  value|=(unsigned short) buffer[0];
813  quantum.unsigned_value=value & 0xffff;
814  return(quantum.signed_value);
815  }
816  value=(unsigned short) buffer[0] << 8;
817  value|=(unsigned short) buffer[1];
818  quantum.unsigned_value=value & 0xffff;
819  return(quantum.signed_value);
820 }
821 
822 static inline unsigned short ReadPropertyUnsignedShort(const EndianType endian,
823  const unsigned char *buffer)
824 {
825  unsigned short
826  value;
827 
828  if (endian == LSBEndian)
829  {
830  value=(unsigned short) buffer[1] << 8;
831  value|=(unsigned short) buffer[0];
832  return(value & 0xffff);
833  }
834  value=(unsigned short) buffer[0] << 8;
835  value|=(unsigned short) buffer[1];
836  return(value & 0xffff);
837 }
838 
840  const char *property,ExceptionInfo *exception)
841 {
842 #define MaxDirectoryStack 16
843 #define EXIF_DELIMITER "\n"
844 #define EXIF_NUM_FORMATS 12
845 #define EXIF_FMT_BYTE 1
846 #define EXIF_FMT_STRING 2
847 #define EXIF_FMT_USHORT 3
848 #define EXIF_FMT_ULONG 4
849 #define EXIF_FMT_URATIONAL 5
850 #define EXIF_FMT_SBYTE 6
851 #define EXIF_FMT_UNDEFINED 7
852 #define EXIF_FMT_SSHORT 8
853 #define EXIF_FMT_SLONG 9
854 #define EXIF_FMT_SRATIONAL 10
855 #define EXIF_FMT_SINGLE 11
856 #define EXIF_FMT_DOUBLE 12
857 #define TAG_EXIF_OFFSET 0x8769
858 #define TAG_GPS_OFFSET 0x8825
859 #define TAG_INTEROP_OFFSET 0xa005
860 
861 #define EXIFMultipleValues(size,format,arg) \
862 { \
863  ssize_t \
864  component; \
865  \
866  size_t \
867  len; \
868  \
869  unsigned char \
870  *p1; \
871  \
872  len=0; \
873  p1=p; \
874  for (component=0; component < components; component++) \
875  { \
876  len+=FormatLocaleString(buffer+len,MagickPathExtent-len,format", ",arg); \
877  if (len >= (MagickPathExtent-1)) \
878  len=MagickPathExtent-1; \
879  p1+=size; \
880  } \
881  if (len > 1) \
882  buffer[len-2]='\0'; \
883  value=AcquireString(buffer); \
884 }
885 
886 #define EXIFMultipleFractions(size,format,arg1,arg2) \
887 { \
888  ssize_t \
889  component; \
890  \
891  size_t \
892  len; \
893  \
894  unsigned char \
895  *p1; \
896  \
897  len=0; \
898  p1=p; \
899  for (component=0; component < components; component++) \
900  { \
901  len+=FormatLocaleString(buffer+len,MagickPathExtent-len,format", ", \
902  (arg1),(arg2)); \
903  if (len >= (MagickPathExtent-1)) \
904  len=MagickPathExtent-1; \
905  p1+=size; \
906  } \
907  if (len > 1) \
908  buffer[len-2]='\0'; \
909  value=AcquireString(buffer); \
910 }
911 
912  typedef struct _DirectoryInfo
913  {
914  const unsigned char
915  *directory;
916 
917  size_t
918  entry;
919 
920  ssize_t
921  offset;
922  } DirectoryInfo;
923 
924  typedef struct _TagInfo
925  {
926  size_t
927  tag;
928 
929  const char
930  *description;
931  } TagInfo;
932 
933  static TagInfo
934  EXIFTag[] =
935  {
936  { 0x001, "exif:InteroperabilityIndex" },
937  { 0x002, "exif:InteroperabilityVersion" },
938  { 0x100, "exif:ImageWidth" },
939  { 0x101, "exif:ImageLength" },
940  { 0x102, "exif:BitsPerSample" },
941  { 0x103, "exif:Compression" },
942  { 0x106, "exif:PhotometricInterpretation" },
943  { 0x10a, "exif:FillOrder" },
944  { 0x10d, "exif:DocumentName" },
945  { 0x10e, "exif:ImageDescription" },
946  { 0x10f, "exif:Make" },
947  { 0x110, "exif:Model" },
948  { 0x111, "exif:StripOffsets" },
949  { 0x112, "exif:Orientation" },
950  { 0x115, "exif:SamplesPerPixel" },
951  { 0x116, "exif:RowsPerStrip" },
952  { 0x117, "exif:StripByteCounts" },
953  { 0x11a, "exif:XResolution" },
954  { 0x11b, "exif:YResolution" },
955  { 0x11c, "exif:PlanarConfiguration" },
956  { 0x11d, "exif:PageName" },
957  { 0x11e, "exif:XPosition" },
958  { 0x11f, "exif:YPosition" },
959  { 0x118, "exif:MinSampleValue" },
960  { 0x119, "exif:MaxSampleValue" },
961  { 0x120, "exif:FreeOffsets" },
962  { 0x121, "exif:FreeByteCounts" },
963  { 0x122, "exif:GrayResponseUnit" },
964  { 0x123, "exif:GrayResponseCurve" },
965  { 0x124, "exif:T4Options" },
966  { 0x125, "exif:T6Options" },
967  { 0x128, "exif:ResolutionUnit" },
968  { 0x12d, "exif:TransferFunction" },
969  { 0x131, "exif:Software" },
970  { 0x132, "exif:DateTime" },
971  { 0x13b, "exif:Artist" },
972  { 0x13e, "exif:WhitePoint" },
973  { 0x13f, "exif:PrimaryChromaticities" },
974  { 0x140, "exif:ColorMap" },
975  { 0x141, "exif:HalfToneHints" },
976  { 0x142, "exif:TileWidth" },
977  { 0x143, "exif:TileLength" },
978  { 0x144, "exif:TileOffsets" },
979  { 0x145, "exif:TileByteCounts" },
980  { 0x14a, "exif:SubIFD" },
981  { 0x14c, "exif:InkSet" },
982  { 0x14d, "exif:InkNames" },
983  { 0x14e, "exif:NumberOfInks" },
984  { 0x150, "exif:DotRange" },
985  { 0x151, "exif:TargetPrinter" },
986  { 0x152, "exif:ExtraSample" },
987  { 0x153, "exif:SampleFormat" },
988  { 0x154, "exif:SMinSampleValue" },
989  { 0x155, "exif:SMaxSampleValue" },
990  { 0x156, "exif:TransferRange" },
991  { 0x157, "exif:ClipPath" },
992  { 0x158, "exif:XClipPathUnits" },
993  { 0x159, "exif:YClipPathUnits" },
994  { 0x15a, "exif:Indexed" },
995  { 0x15b, "exif:JPEGTables" },
996  { 0x15f, "exif:OPIProxy" },
997  { 0x200, "exif:JPEGProc" },
998  { 0x201, "exif:JPEGInterchangeFormat" },
999  { 0x202, "exif:JPEGInterchangeFormatLength" },
1000  { 0x203, "exif:JPEGRestartInterval" },
1001  { 0x205, "exif:JPEGLosslessPredictors" },
1002  { 0x206, "exif:JPEGPointTransforms" },
1003  { 0x207, "exif:JPEGQTables" },
1004  { 0x208, "exif:JPEGDCTables" },
1005  { 0x209, "exif:JPEGACTables" },
1006  { 0x211, "exif:YCbCrCoefficients" },
1007  { 0x212, "exif:YCbCrSubSampling" },
1008  { 0x213, "exif:YCbCrPositioning" },
1009  { 0x214, "exif:ReferenceBlackWhite" },
1010  { 0x2bc, "exif:ExtensibleMetadataPlatform" },
1011  { 0x301, "exif:Gamma" },
1012  { 0x302, "exif:ICCProfileDescriptor" },
1013  { 0x303, "exif:SRGBRenderingIntent" },
1014  { 0x320, "exif:ImageTitle" },
1015  { 0x5001, "exif:ResolutionXUnit" },
1016  { 0x5002, "exif:ResolutionYUnit" },
1017  { 0x5003, "exif:ResolutionXLengthUnit" },
1018  { 0x5004, "exif:ResolutionYLengthUnit" },
1019  { 0x5005, "exif:PrintFlags" },
1020  { 0x5006, "exif:PrintFlagsVersion" },
1021  { 0x5007, "exif:PrintFlagsCrop" },
1022  { 0x5008, "exif:PrintFlagsBleedWidth" },
1023  { 0x5009, "exif:PrintFlagsBleedWidthScale" },
1024  { 0x500A, "exif:HalftoneLPI" },
1025  { 0x500B, "exif:HalftoneLPIUnit" },
1026  { 0x500C, "exif:HalftoneDegree" },
1027  { 0x500D, "exif:HalftoneShape" },
1028  { 0x500E, "exif:HalftoneMisc" },
1029  { 0x500F, "exif:HalftoneScreen" },
1030  { 0x5010, "exif:JPEGQuality" },
1031  { 0x5011, "exif:GridSize" },
1032  { 0x5012, "exif:ThumbnailFormat" },
1033  { 0x5013, "exif:ThumbnailWidth" },
1034  { 0x5014, "exif:ThumbnailHeight" },
1035  { 0x5015, "exif:ThumbnailColorDepth" },
1036  { 0x5016, "exif:ThumbnailPlanes" },
1037  { 0x5017, "exif:ThumbnailRawBytes" },
1038  { 0x5018, "exif:ThumbnailSize" },
1039  { 0x5019, "exif:ThumbnailCompressedSize" },
1040  { 0x501a, "exif:ColorTransferFunction" },
1041  { 0x501b, "exif:ThumbnailData" },
1042  { 0x5020, "exif:ThumbnailImageWidth" },
1043  { 0x5021, "exif:ThumbnailImageHeight" },
1044  { 0x5022, "exif:ThumbnailBitsPerSample" },
1045  { 0x5023, "exif:ThumbnailCompression" },
1046  { 0x5024, "exif:ThumbnailPhotometricInterp" },
1047  { 0x5025, "exif:ThumbnailImageDescription" },
1048  { 0x5026, "exif:ThumbnailEquipMake" },
1049  { 0x5027, "exif:ThumbnailEquipModel" },
1050  { 0x5028, "exif:ThumbnailStripOffsets" },
1051  { 0x5029, "exif:ThumbnailOrientation" },
1052  { 0x502a, "exif:ThumbnailSamplesPerPixel" },
1053  { 0x502b, "exif:ThumbnailRowsPerStrip" },
1054  { 0x502c, "exif:ThumbnailStripBytesCount" },
1055  { 0x502d, "exif:ThumbnailResolutionX" },
1056  { 0x502e, "exif:ThumbnailResolutionY" },
1057  { 0x502f, "exif:ThumbnailPlanarConfig" },
1058  { 0x5030, "exif:ThumbnailResolutionUnit" },
1059  { 0x5031, "exif:ThumbnailTransferFunction" },
1060  { 0x5032, "exif:ThumbnailSoftwareUsed" },
1061  { 0x5033, "exif:ThumbnailDateTime" },
1062  { 0x5034, "exif:ThumbnailArtist" },
1063  { 0x5035, "exif:ThumbnailWhitePoint" },
1064  { 0x5036, "exif:ThumbnailPrimaryChromaticities" },
1065  { 0x5037, "exif:ThumbnailYCbCrCoefficients" },
1066  { 0x5038, "exif:ThumbnailYCbCrSubsampling" },
1067  { 0x5039, "exif:ThumbnailYCbCrPositioning" },
1068  { 0x503A, "exif:ThumbnailRefBlackWhite" },
1069  { 0x503B, "exif:ThumbnailCopyRight" },
1070  { 0x5090, "exif:LuminanceTable" },
1071  { 0x5091, "exif:ChrominanceTable" },
1072  { 0x5100, "exif:FrameDelay" },
1073  { 0x5101, "exif:LoopCount" },
1074  { 0x5110, "exif:PixelUnit" },
1075  { 0x5111, "exif:PixelPerUnitX" },
1076  { 0x5112, "exif:PixelPerUnitY" },
1077  { 0x5113, "exif:PaletteHistogram" },
1078  { 0x1000, "exif:RelatedImageFileFormat" },
1079  { 0x1001, "exif:RelatedImageLength" },
1080  { 0x1002, "exif:RelatedImageWidth" },
1081  { 0x800d, "exif:ImageID" },
1082  { 0x80e3, "exif:Matteing" },
1083  { 0x80e4, "exif:DataType" },
1084  { 0x80e5, "exif:ImageDepth" },
1085  { 0x80e6, "exif:TileDepth" },
1086  { 0x828d, "exif:CFARepeatPatternDim" },
1087  { 0x828e, "exif:CFAPattern2" },
1088  { 0x828f, "exif:BatteryLevel" },
1089  { 0x8298, "exif:Copyright" },
1090  { 0x829a, "exif:ExposureTime" },
1091  { 0x829d, "exif:FNumber" },
1092  { 0x83bb, "exif:IPTC/NAA" },
1093  { 0x84e3, "exif:IT8RasterPadding" },
1094  { 0x84e5, "exif:IT8ColorTable" },
1095  { 0x8649, "exif:ImageResourceInformation" },
1096  { 0x8769, "exif:ExifOffset" },
1097  { 0x8773, "exif:InterColorProfile" },
1098  { 0x8822, "exif:ExposureProgram" },
1099  { 0x8824, "exif:SpectralSensitivity" },
1100  { 0x8825, "exif:GPSInfo" },
1101  { 0x8827, "exif:ISOSpeedRatings" },
1102  { 0x8828, "exif:OECF" },
1103  { 0x8829, "exif:Interlace" },
1104  { 0x882a, "exif:TimeZoneOffset" },
1105  { 0x882b, "exif:SelfTimerMode" },
1106  { 0x9000, "exif:ExifVersion" },
1107  { 0x9003, "exif:DateTimeOriginal" },
1108  { 0x9004, "exif:DateTimeDigitized" },
1109  { 0x9101, "exif:ComponentsConfiguration" },
1110  { 0x9102, "exif:CompressedBitsPerPixel" },
1111  { 0x9201, "exif:ShutterSpeedValue" },
1112  { 0x9202, "exif:ApertureValue" },
1113  { 0x9203, "exif:BrightnessValue" },
1114  { 0x9204, "exif:ExposureBiasValue" },
1115  { 0x9205, "exif:MaxApertureValue" },
1116  { 0x9206, "exif:SubjectDistance" },
1117  { 0x9207, "exif:MeteringMode" },
1118  { 0x9208, "exif:LightSource" },
1119  { 0x9209, "exif:Flash" },
1120  { 0x920a, "exif:FocalLength" },
1121  { 0x920b, "exif:FlashEnergy" },
1122  { 0x920c, "exif:SpatialFrequencyResponse" },
1123  { 0x920d, "exif:Noise" },
1124  { 0x9211, "exif:ImageNumber" },
1125  { 0x9212, "exif:SecurityClassification" },
1126  { 0x9213, "exif:ImageHistory" },
1127  { 0x9214, "exif:SubjectArea" },
1128  { 0x9215, "exif:ExposureIndex" },
1129  { 0x9216, "exif:TIFF-EPStandardID" },
1130  { 0x927c, "exif:MakerNote" },
1131  { 0x9C9b, "exif:WinXP-Title" },
1132  { 0x9C9c, "exif:WinXP-Comments" },
1133  { 0x9C9d, "exif:WinXP-Author" },
1134  { 0x9C9e, "exif:WinXP-Keywords" },
1135  { 0x9C9f, "exif:WinXP-Subject" },
1136  { 0x9286, "exif:UserComment" },
1137  { 0x9290, "exif:SubSecTime" },
1138  { 0x9291, "exif:SubSecTimeOriginal" },
1139  { 0x9292, "exif:SubSecTimeDigitized" },
1140  { 0xa000, "exif:FlashPixVersion" },
1141  { 0xa001, "exif:ColorSpace" },
1142  { 0xa002, "exif:ExifImageWidth" },
1143  { 0xa003, "exif:ExifImageLength" },
1144  { 0xa004, "exif:RelatedSoundFile" },
1145  { 0xa005, "exif:InteroperabilityOffset" },
1146  { 0xa20b, "exif:FlashEnergy" },
1147  { 0xa20c, "exif:SpatialFrequencyResponse" },
1148  { 0xa20d, "exif:Noise" },
1149  { 0xa20e, "exif:FocalPlaneXResolution" },
1150  { 0xa20f, "exif:FocalPlaneYResolution" },
1151  { 0xa210, "exif:FocalPlaneResolutionUnit" },
1152  { 0xa214, "exif:SubjectLocation" },
1153  { 0xa215, "exif:ExposureIndex" },
1154  { 0xa216, "exif:TIFF/EPStandardID" },
1155  { 0xa217, "exif:SensingMethod" },
1156  { 0xa300, "exif:FileSource" },
1157  { 0xa301, "exif:SceneType" },
1158  { 0xa302, "exif:CFAPattern" },
1159  { 0xa401, "exif:CustomRendered" },
1160  { 0xa402, "exif:ExposureMode" },
1161  { 0xa403, "exif:WhiteBalance" },
1162  { 0xa404, "exif:DigitalZoomRatio" },
1163  { 0xa405, "exif:FocalLengthIn35mmFilm" },
1164  { 0xa406, "exif:SceneCaptureType" },
1165  { 0xa407, "exif:GainControl" },
1166  { 0xa408, "exif:Contrast" },
1167  { 0xa409, "exif:Saturation" },
1168  { 0xa40a, "exif:Sharpness" },
1169  { 0xa40b, "exif:DeviceSettingDescription" },
1170  { 0xa40c, "exif:SubjectDistanceRange" },
1171  { 0xa420, "exif:ImageUniqueID" },
1172  { 0xc4a5, "exif:PrintImageMatching" },
1173  { 0xa500, "exif:Gamma" },
1174  { 0xc640, "exif:CR2Slice" },
1175  { 0x10000, "exif:GPSVersionID" },
1176  { 0x10001, "exif:GPSLatitudeRef" },
1177  { 0x10002, "exif:GPSLatitude" },
1178  { 0x10003, "exif:GPSLongitudeRef" },
1179  { 0x10004, "exif:GPSLongitude" },
1180  { 0x10005, "exif:GPSAltitudeRef" },
1181  { 0x10006, "exif:GPSAltitude" },
1182  { 0x10007, "exif:GPSTimeStamp" },
1183  { 0x10008, "exif:GPSSatellites" },
1184  { 0x10009, "exif:GPSStatus" },
1185  { 0x1000a, "exif:GPSMeasureMode" },
1186  { 0x1000b, "exif:GPSDop" },
1187  { 0x1000c, "exif:GPSSpeedRef" },
1188  { 0x1000d, "exif:GPSSpeed" },
1189  { 0x1000e, "exif:GPSTrackRef" },
1190  { 0x1000f, "exif:GPSTrack" },
1191  { 0x10010, "exif:GPSImgDirectionRef" },
1192  { 0x10011, "exif:GPSImgDirection" },
1193  { 0x10012, "exif:GPSMapDatum" },
1194  { 0x10013, "exif:GPSDestLatitudeRef" },
1195  { 0x10014, "exif:GPSDestLatitude" },
1196  { 0x10015, "exif:GPSDestLongitudeRef" },
1197  { 0x10016, "exif:GPSDestLongitude" },
1198  { 0x10017, "exif:GPSDestBearingRef" },
1199  { 0x10018, "exif:GPSDestBearing" },
1200  { 0x10019, "exif:GPSDestDistanceRef" },
1201  { 0x1001a, "exif:GPSDestDistance" },
1202  { 0x1001b, "exif:GPSProcessingMethod" },
1203  { 0x1001c, "exif:GPSAreaInformation" },
1204  { 0x1001d, "exif:GPSDateStamp" },
1205  { 0x1001e, "exif:GPSDifferential" },
1206  { 0x00000, (const char *) NULL }
1207  };
1208 
1209  const StringInfo
1210  *profile;
1211 
1212  const unsigned char
1213  *directory,
1214  *exif;
1215 
1216  DirectoryInfo
1217  directory_stack[MaxDirectoryStack];
1218 
1219  EndianType
1220  endian;
1221 
1223  status;
1224 
1225  register ssize_t
1226  i;
1227 
1228  size_t
1229  entry,
1230  length,
1231  number_entries,
1232  tag,
1233  tag_value;
1234 
1236  *exif_resources;
1237 
1238  ssize_t
1239  all,
1240  id,
1241  level,
1242  offset,
1243  tag_offset;
1244 
1245  static int
1246  tag_bytes[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
1247 
1248  /*
1249  If EXIF data exists, then try to parse the request for a tag.
1250  */
1251  profile=GetImageProfile(image,"exif");
1252  if (profile == (const StringInfo *) NULL)
1253  return(MagickFalse);
1254  if ((property == (const char *) NULL) || (*property == '\0'))
1255  return(MagickFalse);
1256  while (isspace((int) ((unsigned char) *property)) != 0)
1257  property++;
1258  if (strlen(property) <= 5)
1259  return(MagickFalse);
1260  all=0;
1261  tag=(~0UL);
1262  switch (*(property+5))
1263  {
1264  case '*':
1265  {
1266  /*
1267  Caller has asked for all the tags in the EXIF data.
1268  */
1269  tag=0;
1270  all=1; /* return the data in description=value format */
1271  break;
1272  }
1273  case '!':
1274  {
1275  tag=0;
1276  all=2; /* return the data in tagid=value format */
1277  break;
1278  }
1279  case '#':
1280  case '@':
1281  {
1282  int
1283  c;
1284 
1285  size_t
1286  n;
1287 
1288  /*
1289  Check for a hex based tag specification first.
1290  */
1291  tag=(*(property+5) == '@') ? 1UL : 0UL;
1292  property+=6;
1293  n=strlen(property);
1294  if (n != 4)
1295  return(MagickFalse);
1296  /*
1297  Parse tag specification as a hex number.
1298  */
1299  n/=4;
1300  do
1301  {
1302  for (i=(ssize_t) n-1L; i >= 0; i--)
1303  {
1304  c=(*property++);
1305  tag<<=4;
1306  if ((c >= '0') && (c <= '9'))
1307  tag|=(c-'0');
1308  else
1309  if ((c >= 'A') && (c <= 'F'))
1310  tag|=(c-('A'-10));
1311  else
1312  if ((c >= 'a') && (c <= 'f'))
1313  tag|=(c-('a'-10));
1314  else
1315  return(MagickFalse);
1316  }
1317  } while (*property != '\0');
1318  break;
1319  }
1320  default:
1321  {
1322  /*
1323  Try to match the text with a tag name instead.
1324  */
1325  for (i=0; ; i++)
1326  {
1327  if (EXIFTag[i].tag == 0)
1328  break;
1329  if (LocaleCompare(EXIFTag[i].description,property) == 0)
1330  {
1331  tag=(size_t) EXIFTag[i].tag;
1332  break;
1333  }
1334  }
1335  break;
1336  }
1337  }
1338  if (tag == (~0UL))
1339  return(MagickFalse);
1340  length=GetStringInfoLength(profile);
1341  if (length < 6)
1342  return(MagickFalse);
1343  exif=GetStringInfoDatum(profile);
1344  while (length != 0)
1345  {
1346  if (ReadPropertyByte(&exif,&length) != 0x45)
1347  continue;
1348  if (ReadPropertyByte(&exif,&length) != 0x78)
1349  continue;
1350  if (ReadPropertyByte(&exif,&length) != 0x69)
1351  continue;
1352  if (ReadPropertyByte(&exif,&length) != 0x66)
1353  continue;
1354  if (ReadPropertyByte(&exif,&length) != 0x00)
1355  continue;
1356  if (ReadPropertyByte(&exif,&length) != 0x00)
1357  continue;
1358  break;
1359  }
1360  if (length < 16)
1361  return(MagickFalse);
1362  id=(ssize_t) ReadPropertySignedShort(LSBEndian,exif);
1363  endian=LSBEndian;
1364  if (id == 0x4949)
1365  endian=LSBEndian;
1366  else
1367  if (id == 0x4D4D)
1368  endian=MSBEndian;
1369  else
1370  return(MagickFalse);
1371  if (ReadPropertyUnsignedShort(endian,exif+2) != 0x002a)
1372  return(MagickFalse);
1373  /*
1374  This the offset to the first IFD.
1375  */
1376  offset=(ssize_t) ReadPropertySignedLong(endian,exif+4);
1377  if ((offset < 0) || (size_t) offset >= length)
1378  return(MagickFalse);
1379  /*
1380  Set the pointer to the first IFD and follow it were it leads.
1381  */
1382  status=MagickFalse;
1383  directory=exif+offset;
1384  level=0;
1385  entry=0;
1386  tag_offset=0;
1387  exif_resources=NewSplayTree((int (*)(const void *,const void *)) NULL,
1388  (void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
1389  do
1390  {
1391  /*
1392  If there is anything on the stack then pop it off.
1393  */
1394  if (level > 0)
1395  {
1396  level--;
1397  directory=directory_stack[level].directory;
1398  entry=directory_stack[level].entry;
1399  tag_offset=directory_stack[level].offset;
1400  }
1401  if ((directory < exif) || (directory > (exif+length-2)))
1402  break;
1403  /*
1404  Determine how many entries there are in the current IFD.
1405  */
1406  number_entries=(size_t) ReadPropertyUnsignedShort(endian,directory);
1407  for ( ; entry < number_entries; entry++)
1408  {
1409  register unsigned char
1410  *p,
1411  *q;
1412 
1413  size_t
1414  format;
1415 
1416  ssize_t
1417  number_bytes,
1418  components;
1419 
1420  q=(unsigned char *) (directory+(12*entry)+2);
1421  if (q > (exif+length-12))
1422  break; /* corrupt EXIF */
1423  if (GetValueFromSplayTree(exif_resources,q) == q)
1424  break;
1425  (void) AddValueToSplayTree(exif_resources,q,q);
1426  tag_value=(size_t) ReadPropertyUnsignedShort(endian,q)+tag_offset;
1427  format=(size_t) ReadPropertyUnsignedShort(endian,q+2);
1428  if (format >= (sizeof(tag_bytes)/sizeof(*tag_bytes)))
1429  break;
1430  components=(ssize_t) ReadPropertySignedLong(endian,q+4);
1431  if (components < 0)
1432  break; /* corrupt EXIF */
1433  number_bytes=(size_t) components*tag_bytes[format];
1434  if (number_bytes < components)
1435  break; /* prevent overflow */
1436  if (number_bytes <= 4)
1437  p=q+8;
1438  else
1439  {
1440  ssize_t
1441  dir_offset;
1442 
1443  /*
1444  The directory entry contains an offset.
1445  */
1446  dir_offset=(ssize_t) ReadPropertySignedLong(endian,q+8);
1447  if ((dir_offset < 0) || (size_t) dir_offset >= length)
1448  continue;
1449  if ((ssize_t) (dir_offset+number_bytes) < dir_offset)
1450  continue; /* prevent overflow */
1451  if ((size_t) (dir_offset+number_bytes) > length)
1452  continue;
1453  p=(unsigned char *) (exif+dir_offset);
1454  }
1455  if ((all != 0) || (tag == (size_t) tag_value))
1456  {
1457  char
1458  buffer[MagickPathExtent],
1459  *value;
1460 
1461  value=(char *) NULL;
1462  *buffer='\0';
1463  switch (format)
1464  {
1465  case EXIF_FMT_BYTE:
1466  case EXIF_FMT_UNDEFINED:
1467  {
1468  EXIFMultipleValues(1,"%.20g",(double) (*(unsigned char *) p1));
1469  break;
1470  }
1471  case EXIF_FMT_SBYTE:
1472  {
1473  EXIFMultipleValues(1,"%.20g",(double) (*(signed char *) p1));
1474  break;
1475  }
1476  case EXIF_FMT_SSHORT:
1477  {
1478  EXIFMultipleValues(2,"%hd",ReadPropertySignedShort(endian,p1));
1479  break;
1480  }
1481  case EXIF_FMT_USHORT:
1482  {
1483  EXIFMultipleValues(2,"%hu",ReadPropertyUnsignedShort(endian,p1));
1484  break;
1485  }
1486  case EXIF_FMT_ULONG:
1487  {
1488  EXIFMultipleValues(4,"%.20g",(double)
1489  ReadPropertyUnsignedLong(endian,p1));
1490  break;
1491  }
1492  case EXIF_FMT_SLONG:
1493  {
1494  EXIFMultipleValues(4,"%.20g",(double)
1495  ReadPropertySignedLong(endian,p1));
1496  break;
1497  }
1498  case EXIF_FMT_URATIONAL:
1499  {
1500  EXIFMultipleFractions(8,"%.20g/%.20g",(double)
1501  ReadPropertyUnsignedLong(endian,p1),(double)
1502  ReadPropertyUnsignedLong(endian,p1+4));
1503  break;
1504  }
1505  case EXIF_FMT_SRATIONAL:
1506  {
1507  EXIFMultipleFractions(8,"%.20g/%.20g",(double)
1508  ReadPropertySignedLong(endian,p1),(double)
1509  ReadPropertySignedLong(endian,p1+4));
1510  break;
1511  }
1512  case EXIF_FMT_SINGLE:
1513  {
1514  EXIFMultipleValues(4,"%f",(double) *(float *) p1);
1515  break;
1516  }
1517  case EXIF_FMT_DOUBLE:
1518  {
1519  EXIFMultipleValues(8,"%f",*(double *) p1);
1520  break;
1521  }
1522  default:
1523  case EXIF_FMT_STRING:
1524  {
1525  value=(char *) NULL;
1526  if (~((size_t) number_bytes) >= 1)
1527  value=(char *) AcquireQuantumMemory((size_t) number_bytes+1UL,
1528  sizeof(*value));
1529  if (value != (char *) NULL)
1530  {
1531  for (i=0; i < (ssize_t) number_bytes; i++)
1532  {
1533  value[i]='.';
1534  if ((isprint((int) p[i]) != 0) || (p[i] == '\0'))
1535  value[i]=(char) p[i];
1536  }
1537  value[i]='\0';
1538  }
1539  break;
1540  }
1541  }
1542  if (value != (char *) NULL)
1543  {
1544  char
1545  *key;
1546 
1547  key=AcquireString(property);
1548  switch (all)
1549  {
1550  case 1:
1551  {
1552  const char
1553  *description;
1554 
1555  description="unknown";
1556  for (i=0; ; i++)
1557  {
1558  if (EXIFTag[i].tag == 0)
1559  break;
1560  if (EXIFTag[i].tag == tag_value)
1561  {
1562  description=EXIFTag[i].description;
1563  break;
1564  }
1565  }
1566  (void) FormatLocaleString(key,MagickPathExtent,"%s",
1567  description);
1568  if (level == 2)
1569  (void) SubstituteString(&key,"exif:","exif:thumbnail:");
1570  break;
1571  }
1572  case 2:
1573  {
1574  if (tag_value < 0x10000)
1575  (void) FormatLocaleString(key,MagickPathExtent,"#%04lx",
1576  (unsigned long) tag_value);
1577  else
1578  if (tag_value < 0x20000)
1579  (void) FormatLocaleString(key,MagickPathExtent,"@%04lx",
1580  (unsigned long) (tag_value & 0xffff));
1581  else
1582  (void) FormatLocaleString(key,MagickPathExtent,"unknown");
1583  break;
1584  }
1585  default:
1586  {
1587  if (level == 2)
1588  (void) SubstituteString(&key,"exif:","exif:thumbnail:");
1589  }
1590  }
1591  if ((image->properties == (void *) NULL) ||
1593  key) == (const void *) NULL))
1594  (void) SetImageProperty((Image *) image,key,value,exception);
1595  value=DestroyString(value);
1596  key=DestroyString(key);
1597  status=MagickTrue;
1598  }
1599  }
1600  if ((tag_value == TAG_EXIF_OFFSET) ||
1601  (tag_value == TAG_INTEROP_OFFSET) || (tag_value == TAG_GPS_OFFSET))
1602  {
1603  ssize_t
1604  tag_offset1;
1605 
1606  tag_offset1=(ssize_t) ReadPropertySignedLong(endian,p);
1607  if (((size_t) tag_offset1 < length) &&
1608  (level < (MaxDirectoryStack-2)))
1609  {
1610  ssize_t
1611  tag_offset2;
1612 
1613  tag_offset2=(ssize_t) ((tag_value == TAG_GPS_OFFSET) ? 0x10000 :
1614  0);
1615  directory_stack[level].directory=directory;
1616  entry++;
1617  directory_stack[level].entry=entry;
1618  directory_stack[level].offset=tag_offset;
1619  level++;
1620  directory_stack[level].directory=exif+tag_offset1;
1621  directory_stack[level].offset=tag_offset2;
1622  directory_stack[level].entry=0;
1623  level++;
1624  if ((directory+2+(12*number_entries)) > (exif+length))
1625  break;
1626  tag_offset1=(ssize_t) ReadPropertySignedLong(endian,directory+
1627  2+(12*number_entries));
1628  if ((tag_offset1 != 0) && ((size_t) tag_offset1 < length) &&
1629  (level < (MaxDirectoryStack-2)))
1630  {
1631  directory_stack[level].directory=exif+tag_offset1;
1632  directory_stack[level].entry=0;
1633  directory_stack[level].offset=tag_offset2;
1634  level++;
1635  }
1636  }
1637  break;
1638  }
1639  }
1640  } while (level > 0);
1641  exif_resources=DestroySplayTree(exif_resources);
1642  return(status);
1643 }
1644 
1645 static MagickBooleanType GetICCProperty(const Image *image,const char *property,
1646  ExceptionInfo *exception)
1647 {
1648  const StringInfo
1649  *profile;
1650 
1651  magick_unreferenced(property);
1652 
1653  profile=GetImageProfile(image,"icc");
1654  if (profile == (StringInfo *) NULL)
1655  profile=GetImageProfile(image,"icm");
1656  if (profile == (StringInfo *) NULL)
1657  return(MagickFalse);
1658  if (GetStringInfoLength(profile) < 128)
1659  return(MagickFalse); /* minimum ICC profile length */
1660 #if defined(MAGICKCORE_LCMS_DELEGATE)
1661  {
1662  cmsHPROFILE
1663  icc_profile;
1664 
1665  icc_profile=cmsOpenProfileFromMem(GetStringInfoDatum(profile),
1666  (cmsUInt32Number) GetStringInfoLength(profile));
1667  if (icc_profile != (cmsHPROFILE *) NULL)
1668  {
1669 #if defined(LCMS_VERSION) && (LCMS_VERSION < 2000)
1670  const char
1671  *name;
1672 
1673  name=cmsTakeProductName(icc_profile);
1674  if (name != (const char *) NULL)
1675  (void) SetImageProperty((Image *) image,"icc:name",name,exception);
1676 #else
1677  char
1678  info[MagickPathExtent];
1679 
1680  unsigned int
1681  extent;
1682 
1683  (void) memset(info,0,sizeof(info));
1684  extent=cmsGetProfileInfoASCII(icc_profile,cmsInfoDescription,"en","US",
1685  NULL,0);
1686  if (extent != 0)
1687  {
1688  extent=cmsGetProfileInfoASCII(icc_profile,cmsInfoDescription,"en",
1689  "US",info,MagickMin(MagickPathExtent-1,extent));
1690  (void) SetImageProperty((Image *) image,"icc:description",info,
1691  exception);
1692  }
1693  extent=cmsGetProfileInfoASCII(icc_profile,cmsInfoManufacturer,"en","US",
1694  NULL,0);
1695  if (extent != 0)
1696  {
1697  extent=cmsGetProfileInfoASCII(icc_profile,cmsInfoManufacturer,"en",
1698  "US",info,MagickMin(MagickPathExtent-1,extent));
1699  (void) SetImageProperty((Image *) image,"icc:manufacturer",info,
1700  exception);
1701  }
1702  extent=cmsGetProfileInfoASCII(icc_profile,cmsInfoModel,"en","US",
1703  NULL,0);
1704  if (extent != 0)
1705  {
1706  extent=cmsGetProfileInfoASCII(icc_profile,cmsInfoModel,"en","US",
1707  info,MagickMin(MagickPathExtent-1,extent));
1708  (void) SetImageProperty((Image *) image,"icc:model",info,exception);
1709  }
1710  extent=cmsGetProfileInfoASCII(icc_profile,cmsInfoCopyright,"en","US",
1711  NULL,0);
1712  if (extent != 0)
1713  {
1714  extent=cmsGetProfileInfoASCII(icc_profile,cmsInfoCopyright,"en",
1715  "US",info,MagickMin(MagickPathExtent-1,extent));
1716  (void) SetImageProperty((Image *) image,"icc:copyright",info,
1717  exception);
1718  }
1719 #endif
1720  (void) cmsCloseProfile(icc_profile);
1721  }
1722  }
1723 #endif
1724  return(MagickTrue);
1725 }
1726 
1727 static MagickBooleanType SkipXMPValue(const char *value)
1728 {
1729  if (value == (const char*) NULL)
1730  return(MagickTrue);
1731  while (*value != '\0')
1732  {
1733  if (isspace((int) ((unsigned char) *value)) == 0)
1734  return(MagickFalse);
1735  value++;
1736  }
1737  return(MagickTrue);
1738 }
1739 
1740 static MagickBooleanType ValidateXMPProfile(const char *profile,
1741  const size_t length)
1742 {
1743 #if defined(MAGICKCORE_XML_DELEGATE)
1744  {
1745  xmlDocPtr
1746  document;
1747 
1748  /*
1749  Parse XML profile.
1750  */
1751  document=xmlReadMemory(profile,(int) length,"xmp.xml",NULL,
1752  XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
1753  if (document == (xmlDocPtr) NULL)
1754  return(MagickFalse);
1755  xmlFreeDoc(document);
1756  return(MagickTrue);
1757  }
1758 #else
1759  return(MagickFalse);
1760 #endif
1761 }
1762 
1763 static MagickBooleanType GetXMPProperty(const Image *image,const char *property)
1764 {
1765  char
1766  *xmp_profile;
1767 
1768  const char
1769  *content;
1770 
1771  const StringInfo
1772  *profile;
1773 
1775  *exception;
1776 
1778  status;
1779 
1780  register const char
1781  *p;
1782 
1783  XMLTreeInfo
1784  *child,
1785  *description,
1786  *node,
1787  *rdf,
1788  *xmp;
1789 
1790  profile=GetImageProfile(image,"xmp");
1791  if (profile == (StringInfo *) NULL)
1792  return(MagickFalse);
1793  if (GetStringInfoLength(profile) < 17)
1794  return(MagickFalse);
1795  if ((property == (const char *) NULL) || (*property == '\0'))
1796  return(MagickFalse);
1797  xmp_profile=StringInfoToString(profile);
1798  if (xmp_profile == (char *) NULL)
1799  return(MagickFalse);
1800  if (ValidateXMPProfile(xmp_profile,GetStringInfoLength(profile)) == MagickFalse)
1801  {
1802  xmp_profile=DestroyString(xmp_profile);
1803  return(MagickFalse);
1804  }
1805  for (p=xmp_profile; *p != '\0'; p++)
1806  if ((*p == '<') && (*(p+1) == 'x'))
1807  break;
1808  exception=AcquireExceptionInfo();
1809  xmp=NewXMLTree((char *) p,exception);
1810  xmp_profile=DestroyString(xmp_profile);
1811  exception=DestroyExceptionInfo(exception);
1812  if (xmp == (XMLTreeInfo *) NULL)
1813  return(MagickFalse);
1814  status=MagickFalse;
1815  rdf=GetXMLTreeChild(xmp,"rdf:RDF");
1816  if (rdf != (XMLTreeInfo *) NULL)
1817  {
1818  if (image->properties == (void *) NULL)
1819  ((Image *) image)->properties=NewSplayTree(CompareSplayTreeString,
1821  description=GetXMLTreeChild(rdf,"rdf:Description");
1822  while (description != (XMLTreeInfo *) NULL)
1823  {
1824  char
1825  *xmp_namespace;
1826 
1827  node=GetXMLTreeChild(description,(const char *) NULL);
1828  while (node != (XMLTreeInfo *) NULL)
1829  {
1830  child=GetXMLTreeChild(node,(const char *) NULL);
1831  content=GetXMLTreeContent(node);
1832  if ((child == (XMLTreeInfo *) NULL) &&
1833  (SkipXMPValue(content) == MagickFalse))
1834  {
1835  xmp_namespace=ConstantString(GetXMLTreeTag(node));
1836  (void) SubstituteString(&xmp_namespace,"exif:","xmp:");
1837  (void) AddValueToSplayTree((SplayTreeInfo *) image->properties,
1838  xmp_namespace,ConstantString(content));
1839  }
1840  while (child != (XMLTreeInfo *) NULL)
1841  {
1842  content=GetXMLTreeContent(child);
1843  if (SkipXMPValue(content) == MagickFalse)
1844  {
1845  xmp_namespace=ConstantString(GetXMLTreeTag(node));
1846  (void) SubstituteString(&xmp_namespace,"exif:","xmp:");
1847  (void) AddValueToSplayTree((SplayTreeInfo *) image->properties,
1848  xmp_namespace,ConstantString(content));
1849  }
1850  child=GetXMLTreeSibling(child);
1851  }
1852  node=GetXMLTreeSibling(node);
1853  }
1854  description=GetNextXMLTreeTag(description);
1855  }
1856  }
1857  xmp=DestroyXMLTree(xmp);
1858  return(status);
1859 }
1860 
1861 static char *TracePSClippath(const unsigned char *blob,size_t length)
1862 {
1863  char
1864  *path,
1865  *message;
1866 
1868  in_subpath;
1869 
1870  PointInfo
1871  first[3],
1872  last[3],
1873  point[3];
1874 
1875  register ssize_t
1876  i,
1877  x;
1878 
1879  ssize_t
1880  knot_count,
1881  selector,
1882  y;
1883 
1884  path=AcquireString((char *) NULL);
1885  if (path == (char *) NULL)
1886  return((char *) NULL);
1887  message=AcquireString((char *) NULL);
1888  (void) FormatLocaleString(message,MagickPathExtent,"/ClipImage\n");
1889  (void) ConcatenateString(&path,message);
1890  (void) FormatLocaleString(message,MagickPathExtent,"{\n");
1891  (void) ConcatenateString(&path,message);
1892  (void) FormatLocaleString(message,MagickPathExtent,
1893  " /c {curveto} bind def\n");
1894  (void) ConcatenateString(&path,message);
1895  (void) FormatLocaleString(message,MagickPathExtent,
1896  " /l {lineto} bind def\n");
1897  (void) ConcatenateString(&path,message);
1898  (void) FormatLocaleString(message,MagickPathExtent,
1899  " /m {moveto} bind def\n");
1900  (void) ConcatenateString(&path,message);
1901  (void) FormatLocaleString(message,MagickPathExtent,
1902  " /v {currentpoint 6 2 roll curveto} bind def\n");
1903  (void) ConcatenateString(&path,message);
1904  (void) FormatLocaleString(message,MagickPathExtent,
1905  " /y {2 copy curveto} bind def\n");
1906  (void) ConcatenateString(&path,message);
1907  (void) FormatLocaleString(message,MagickPathExtent,
1908  " /z {closepath} bind def\n");
1909  (void) ConcatenateString(&path,message);
1910  (void) FormatLocaleString(message,MagickPathExtent," newpath\n");
1911  (void) ConcatenateString(&path,message);
1912  /*
1913  The clipping path format is defined in "Adobe Photoshop File Formats
1914  Specification" version 6.0 downloadable from adobe.com.
1915  */
1916  (void) memset(point,0,sizeof(point));
1917  (void) memset(first,0,sizeof(first));
1918  (void) memset(last,0,sizeof(last));
1919  knot_count=0;
1920  in_subpath=MagickFalse;
1921  while (length > 0)
1922  {
1923  selector=(ssize_t) ReadPropertyMSBShort(&blob,&length);
1924  switch (selector)
1925  {
1926  case 0:
1927  case 3:
1928  {
1929  if (knot_count != 0)
1930  {
1931  blob+=24;
1932  length-=MagickMin(24,(ssize_t) length);
1933  break;
1934  }
1935  /*
1936  Expected subpath length record.
1937  */
1938  knot_count=(ssize_t) ReadPropertyMSBShort(&blob,&length);
1939  blob+=22;
1940  length-=MagickMin(22,(ssize_t) length);
1941  break;
1942  }
1943  case 1:
1944  case 2:
1945  case 4:
1946  case 5:
1947  {
1948  if (knot_count == 0)
1949  {
1950  /*
1951  Unexpected subpath knot
1952  */
1953  blob+=24;
1954  length-=MagickMin(24,(ssize_t) length);
1955  break;
1956  }
1957  /*
1958  Add sub-path knot
1959  */
1960  for (i=0; i < 3; i++)
1961  {
1962  size_t
1963  xx,
1964  yy;
1965 
1966  yy=(size_t) ReadPropertyMSBLong(&blob,&length);
1967  xx=(size_t) ReadPropertyMSBLong(&blob,&length);
1968  x=(ssize_t) xx;
1969  if (xx > 2147483647)
1970  x=(ssize_t) xx-4294967295U-1;
1971  y=(ssize_t) yy;
1972  if (yy > 2147483647)
1973  y=(ssize_t) yy-4294967295U-1;
1974  point[i].x=(double) x/4096/4096;
1975  point[i].y=1.0-(double) y/4096/4096;
1976  }
1977  if (in_subpath == MagickFalse)
1978  {
1979  (void) FormatLocaleString(message,MagickPathExtent," %g %g m\n",
1980  point[1].x,point[1].y);
1981  for (i=0; i < 3; i++)
1982  {
1983  first[i]=point[i];
1984  last[i]=point[i];
1985  }
1986  }
1987  else
1988  {
1989  /*
1990  Handle special cases when Bezier curves are used to describe
1991  corners and straight lines.
1992  */
1993  if ((last[1].x == last[2].x) && (last[1].y == last[2].y) &&
1994  (point[0].x == point[1].x) && (point[0].y == point[1].y))
1995  (void) FormatLocaleString(message,MagickPathExtent,
1996  " %g %g l\n",point[1].x,point[1].y);
1997  else
1998  if ((last[1].x == last[2].x) && (last[1].y == last[2].y))
1999  (void) FormatLocaleString(message,MagickPathExtent,
2000  " %g %g %g %g v\n",point[0].x,point[0].y,
2001  point[1].x,point[1].y);
2002  else
2003  if ((point[0].x == point[1].x) && (point[0].y == point[1].y))
2004  (void) FormatLocaleString(message,MagickPathExtent,
2005  " %g %g %g %g y\n",last[2].x,last[2].y,
2006  point[1].x,point[1].y);
2007  else
2008  (void) FormatLocaleString(message,MagickPathExtent,
2009  " %g %g %g %g %g %g c\n",last[2].x,
2010  last[2].y,point[0].x,point[0].y,point[1].x,point[1].y);
2011  for (i=0; i < 3; i++)
2012  last[i]=point[i];
2013  }
2014  (void) ConcatenateString(&path,message);
2015  in_subpath=MagickTrue;
2016  knot_count--;
2017  /*
2018  Close the subpath if there are no more knots.
2019  */
2020  if (knot_count == 0)
2021  {
2022  /*
2023  Same special handling as above except we compare to the
2024  first point in the path and close the path.
2025  */
2026  if ((last[1].x == last[2].x) && (last[1].y == last[2].y) &&
2027  (first[0].x == first[1].x) && (first[0].y == first[1].y))
2028  (void) FormatLocaleString(message,MagickPathExtent,
2029  " %g %g l z\n",first[1].x,first[1].y);
2030  else
2031  if ((last[1].x == last[2].x) && (last[1].y == last[2].y))
2032  (void) FormatLocaleString(message,MagickPathExtent,
2033  " %g %g %g %g v z\n",first[0].x,first[0].y,
2034  first[1].x,first[1].y);
2035  else
2036  if ((first[0].x == first[1].x) && (first[0].y == first[1].y))
2037  (void) FormatLocaleString(message,MagickPathExtent,
2038  " %g %g %g %g y z\n",last[2].x,last[2].y,
2039  first[1].x,first[1].y);
2040  else
2041  (void) FormatLocaleString(message,MagickPathExtent,
2042  " %g %g %g %g %g %g c z\n",last[2].x,
2043  last[2].y,first[0].x,first[0].y,first[1].x,first[1].y);
2044  (void) ConcatenateString(&path,message);
2045  in_subpath=MagickFalse;
2046  }
2047  break;
2048  }
2049  case 6:
2050  case 7:
2051  case 8:
2052  default:
2053  {
2054  blob+=24;
2055  length-=MagickMin(24,(ssize_t) length);
2056  break;
2057  }
2058  }
2059  }
2060  /*
2061  Returns an empty PS path if the path has no knots.
2062  */
2063  (void) FormatLocaleString(message,MagickPathExtent," eoclip\n");
2064  (void) ConcatenateString(&path,message);
2065  (void) FormatLocaleString(message,MagickPathExtent,"} bind def");
2066  (void) ConcatenateString(&path,message);
2067  message=DestroyString(message);
2068  return(path);
2069 }
2070 
2071 static char *TraceSVGClippath(const unsigned char *blob,size_t length,
2072  const size_t columns,const size_t rows)
2073 {
2074  char
2075  *path,
2076  *message;
2077 
2079  in_subpath;
2080 
2081  PointInfo
2082  first[3],
2083  last[3],
2084  point[3];
2085 
2086  register ssize_t
2087  i;
2088 
2089  ssize_t
2090  knot_count,
2091  selector,
2092  x,
2093  y;
2094 
2095  path=AcquireString((char *) NULL);
2096  if (path == (char *) NULL)
2097  return((char *) NULL);
2098  message=AcquireString((char *) NULL);
2099  (void) FormatLocaleString(message,MagickPathExtent,(
2100  "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
2101  "<svg xmlns=\"http://www.w3.org/2000/svg\""
2102  " width=\"%.20g\" height=\"%.20g\">\n"
2103  "<g>\n"
2104  "<path fill-rule=\"evenodd\" style=\"fill:#000000;stroke:#000000;"
2105  "stroke-width:0;stroke-antialiasing:false\" d=\"\n"),(double) columns,
2106  (double) rows);
2107  (void) ConcatenateString(&path,message);
2108  (void) memset(point,0,sizeof(point));
2109  (void) memset(first,0,sizeof(first));
2110  (void) memset(last,0,sizeof(last));
2111  knot_count=0;
2112  in_subpath=MagickFalse;
2113  while (length != 0)
2114  {
2115  selector=(ssize_t) ReadPropertyMSBShort(&blob,&length);
2116  switch (selector)
2117  {
2118  case 0:
2119  case 3:
2120  {
2121  if (knot_count != 0)
2122  {
2123  blob+=24;
2124  length-=MagickMin(24,(ssize_t) length);
2125  break;
2126  }
2127  /*
2128  Expected subpath length record.
2129  */
2130  knot_count=(ssize_t) ReadPropertyMSBShort(&blob,&length);
2131  blob+=22;
2132  length-=MagickMin(22,(ssize_t) length);
2133  break;
2134  }
2135  case 1:
2136  case 2:
2137  case 4:
2138  case 5:
2139  {
2140  if (knot_count == 0)
2141  {
2142  /*
2143  Unexpected subpath knot.
2144  */
2145  blob+=24;
2146  length-=MagickMin(24,(ssize_t) length);
2147  break;
2148  }
2149  /*
2150  Add sub-path knot
2151  */
2152  for (i=0; i < 3; i++)
2153  {
2154  unsigned int
2155  xx,
2156  yy;
2157 
2158  yy=(unsigned int) ReadPropertyMSBLong(&blob,&length);
2159  xx=(unsigned int) ReadPropertyMSBLong(&blob,&length);
2160  x=(ssize_t) xx;
2161  if (xx > 2147483647)
2162  x=(ssize_t) xx-4294967295U-1;
2163  y=(ssize_t) yy;
2164  if (yy > 2147483647)
2165  y=(ssize_t) yy-4294967295U-1;
2166  point[i].x=(double) x*columns/4096/4096;
2167  point[i].y=(double) y*rows/4096/4096;
2168  }
2169  if (in_subpath == MagickFalse)
2170  {
2171  (void) FormatLocaleString(message,MagickPathExtent,"M %g %g\n",
2172  point[1].x,point[1].y);
2173  for (i=0; i < 3; i++)
2174  {
2175  first[i]=point[i];
2176  last[i]=point[i];
2177  }
2178  }
2179  else
2180  {
2181  /*
2182  Handle special cases when Bezier curves are used to describe
2183  corners and straight lines.
2184  */
2185  if (((last[1].x == last[2].x) || (last[1].y == last[2].y)) &&
2186  (point[0].x == point[1].x) && (point[0].y == point[1].y))
2187  (void) FormatLocaleString(message,MagickPathExtent,
2188  "L %g %g\n",point[1].x,point[1].y);
2189  else
2190  (void) FormatLocaleString(message,MagickPathExtent,
2191  "C %g %g %g %g %g %g\n",last[2].x,last[2].y,point[0].x,
2192  point[0].y,point[1].x,point[1].y);
2193  for (i=0; i < 3; i++)
2194  last[i]=point[i];
2195  }
2196  (void) ConcatenateString(&path,message);
2197  in_subpath=MagickTrue;
2198  knot_count--;
2199  /*
2200  Close the subpath if there are no more knots.
2201  */
2202  if (knot_count == 0)
2203  {
2204  /*
2205  Same special handling as above except we compare to the
2206  first point in the path and close the path.
2207  */
2208  if (((last[1].x == last[2].x) || (last[1].y == last[2].y)) &&
2209  (first[0].x == first[1].x) && (first[0].y == first[1].y))
2210  (void) FormatLocaleString(message,MagickPathExtent,
2211  "L %g %g Z\n",first[1].x,first[1].y);
2212  else
2213  (void) FormatLocaleString(message,MagickPathExtent,
2214  "C %g %g %g %g %g %g Z\n",last[2].x,last[2].y,first[0].x,
2215  first[0].y,first[1].x,first[1].y);
2216  (void) ConcatenateString(&path,message);
2217  in_subpath=MagickFalse;
2218  }
2219  break;
2220  }
2221  case 6:
2222  case 7:
2223  case 8:
2224  default:
2225  {
2226  blob+=24;
2227  length-=MagickMin(24,(ssize_t) length);
2228  break;
2229  }
2230  }
2231  }
2232  /*
2233  Return an empty SVG image if the path does not have knots.
2234  */
2235  (void) ConcatenateString(&path,"\"/>\n</g>\n</svg>\n");
2236  message=DestroyString(message);
2237  return(path);
2238 }
2239 
2240 MagickExport const char *GetImageProperty(const Image *image,
2241  const char *property,ExceptionInfo *exception)
2242 {
2243  register const char
2244  *p;
2245 
2246  assert(image != (Image *) NULL);
2247  assert(image->signature == MagickCoreSignature);
2248  if (image->debug != MagickFalse)
2249  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2250  p=(const char *) NULL;
2251  if (image->properties != (void *) NULL)
2252  {
2253  if (property == (const char *) NULL)
2254  return((const char *) GetRootValueFromSplayTree((SplayTreeInfo *)
2255  image->properties));
2256  p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
2257  image->properties,property);
2258  if (p != (const char *) NULL)
2259  return(p);
2260  }
2261  if ((property == (const char *) NULL) ||
2262  (strchr(property,':') == (char *) NULL))
2263  return(p);
2264  switch (*property)
2265  {
2266  case '8':
2267  {
2268  if (LocaleNCompare("8bim:",property,5) == 0)
2269  {
2270  (void) Get8BIMProperty(image,property,exception);
2271  break;
2272  }
2273  break;
2274  }
2275  case 'E':
2276  case 'e':
2277  {
2278  if (LocaleNCompare("exif:",property,5) == 0)
2279  {
2280  (void) GetEXIFProperty(image,property,exception);
2281  break;
2282  }
2283  break;
2284  }
2285  case 'I':
2286  case 'i':
2287  {
2288  if ((LocaleNCompare("icc:",property,4) == 0) ||
2289  (LocaleNCompare("icm:",property,4) == 0))
2290  {
2291  (void) GetICCProperty(image,property,exception);
2292  break;
2293  }
2294  if (LocaleNCompare("iptc:",property,5) == 0)
2295  {
2296  (void) GetIPTCProperty(image,property,exception);
2297  break;
2298  }
2299  break;
2300  }
2301  case 'X':
2302  case 'x':
2303  {
2304  if (LocaleNCompare("xmp:",property,4) == 0)
2305  {
2306  (void) GetXMPProperty(image,property);
2307  break;
2308  }
2309  break;
2310  }
2311  default:
2312  break;
2313  }
2314  if (image->properties != (void *) NULL)
2315  {
2316  p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
2317  image->properties,property);
2318  return(p);
2319  }
2320  return((const char *) NULL);
2321 }
2322 
2323 /*
2324 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2325 % %
2326 % %
2327 % %
2328 + G e t M a g i c k P r o p e r t y %
2329 % %
2330 % %
2331 % %
2332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2333 %
2334 % GetMagickProperty() gets attributes or calculated values that is associated
2335 % with a fixed known property name, or single letter property. It may be
2336 % called if no image is defined (IMv7), in which case only global image_info
2337 % values are available:
2338 %
2339 % \n newline
2340 % \r carriage return
2341 % < less-than character.
2342 % > greater-than character.
2343 % & ampersand character.
2344 % %% a percent sign
2345 % %b file size of image read in
2346 % %c comment meta-data property
2347 % %d directory component of path
2348 % %e filename extension or suffix
2349 % %f filename (including suffix)
2350 % %g layer canvas page geometry (equivalent to "%Wx%H%X%Y")
2351 % %h current image height in pixels
2352 % %i image filename (note: becomes output filename for "info:")
2353 % %k CALCULATED: number of unique colors
2354 % %l label meta-data property
2355 % %m image file format (file magic)
2356 % %n number of images in current image sequence
2357 % %o output filename (used for delegates)
2358 % %p index of image in current image list
2359 % %q quantum depth (compile-time constant)
2360 % %r image class and colorspace
2361 % %s scene number (from input unless re-assigned)
2362 % %t filename without directory or extension (suffix)
2363 % %u unique temporary filename (used for delegates)
2364 % %w current width in pixels
2365 % %x x resolution (density)
2366 % %y y resolution (density)
2367 % %z image depth (as read in unless modified, image save depth)
2368 % %A image transparency channel enabled (true/false)
2369 % %B file size of image in bytes
2370 % %C image compression type
2371 % %D image GIF dispose method
2372 % %G original image size (%wx%h; before any resizes)
2373 % %H page (canvas) height
2374 % %M Magick filename (original file exactly as given, including read mods)
2375 % %O page (canvas) offset ( = %X%Y )
2376 % %P page (canvas) size ( = %Wx%H )
2377 % %Q image compression quality ( 0 = default )
2378 % %S ?? scenes ??
2379 % %T image time delay (in centi-seconds)
2380 % %U image resolution units
2381 % %W page (canvas) width
2382 % %X page (canvas) x offset (including sign)
2383 % %Y page (canvas) y offset (including sign)
2384 % %Z unique filename (used for delegates)
2385 % %@ CALCULATED: trim bounding box (without actually trimming)
2386 % %# CALCULATED: 'signature' hash of image values
2387 %
2388 % This routine only handles specifically known properties. It does not
2389 % handle special prefixed properties, profiles, or expressions. Nor does
2390 % it return any free-form property strings.
2391 %
2392 % The returned string is stored in a structure somewhere, and should not be
2393 % directly freed. If the string was generated (common) the string will be
2394 % stored as as either as artifact or option 'get-property'. These may be
2395 % deleted (cleaned up) when no longer required, but neither artifact or
2396 % option is guranteed to exist.
2397 %
2398 % The format of the GetMagickProperty method is:
2399 %
2400 % const char *GetMagickProperty(ImageInfo *image_info,Image *image,
2401 % const char *property,ExceptionInfo *exception)
2402 %
2403 % A description of each parameter follows:
2404 %
2405 % o image_info: the image info (optional)
2406 %
2407 % o image: the image (optional)
2408 %
2409 % o key: the key.
2410 %
2411 % o exception: return any errors or warnings in this structure.
2412 %
2413 */
2414 static const char *GetMagickPropertyLetter(ImageInfo *image_info,
2415  Image *image,const char letter,ExceptionInfo *exception)
2416 {
2417 #define WarnNoImageReturn(format,arg) \
2418  if (image == (Image *) NULL ) { \
2419  (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, \
2420  "NoImageForProperty",format,arg); \
2421  return((const char *) NULL); \
2422  }
2423 #define WarnNoImageInfoReturn(format,arg) \
2424  if (image_info == (ImageInfo *) NULL ) { \
2425  (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, \
2426  "NoImageInfoForProperty",format,arg); \
2427  return((const char *) NULL); \
2428  }
2429 
2430  char
2431  value[MagickPathExtent]; /* formatted string to store as an artifact */
2432 
2433  const char
2434  *string; /* return a string already stored somewher */
2435 
2436  if ((image != (Image *) NULL) && (image->debug != MagickFalse))
2437  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2438  else
2439  if ((image_info != (ImageInfo *) NULL) &&
2440  (image_info->debug != MagickFalse))
2441  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s","no-images");
2442  *value='\0'; /* formatted string */
2443  string=(char *) NULL; /* constant string reference */
2444  /*
2445  Get properities that are directly defined by images.
2446  */
2447  switch (letter)
2448  {
2449  case 'b': /* image size read in - in bytes */
2450  {
2451  WarnNoImageReturn("\"%%%c\"",letter);
2453  value);
2454  if (image->extent == 0)
2455  (void) FormatMagickSize(GetBlobSize(image),MagickFalse,"B",
2456  MagickPathExtent,value);
2457  break;
2458  }
2459  case 'c': /* image comment property - empty string by default */
2460  {
2461  WarnNoImageReturn("\"%%%c\"",letter);
2462  string=GetImageProperty(image,"comment",exception);
2463  if ( string == (const char *) NULL )
2464  string="";
2465  break;
2466  }
2467  case 'd': /* Directory component of filename */
2468  {
2469  WarnNoImageReturn("\"%%%c\"",letter);
2471  if (*value == '\0')
2472  string="";
2473  break;
2474  }
2475  case 'e': /* Filename extension (suffix) of image file */
2476  {
2477  WarnNoImageReturn("\"%%%c\"",letter);
2479  if (*value == '\0')
2480  string="";
2481  break;
2482  }
2483  case 'f': /* Filename without directory component */
2484  {
2485  WarnNoImageReturn("\"%%%c\"",letter);
2487  if (*value == '\0')
2488  string="";
2489  break;
2490  }
2491  case 'g': /* Image geometry, canvas and offset %Wx%H+%X+%Y */
2492  {
2493  WarnNoImageReturn("\"%%%c\"",letter);
2494  (void) FormatLocaleString(value,MagickPathExtent,
2495  "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
2496  image->page.height,(double) image->page.x,(double) image->page.y);
2497  break;
2498  }
2499  case 'h': /* Image height (current) */
2500  {
2501  WarnNoImageReturn("\"%%%c\"",letter);
2502  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
2503  (image->rows != 0 ? image->rows : image->magick_rows));
2504  break;
2505  }
2506  case 'i': /* Filename last used for an image (read or write) */
2507  {
2508  WarnNoImageReturn("\"%%%c\"",letter);
2509  string=image->filename;
2510  break;
2511  }
2512  case 'k': /* Number of unique colors */
2513  {
2514  /*
2515  FUTURE: ensure this does not generate the formatted comment!
2516  */
2517  WarnNoImageReturn("\"%%%c\"",letter);
2518  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
2519  GetNumberColors(image,(FILE *) NULL,exception));
2520  break;
2521  }
2522  case 'l': /* Image label property - empty string by default */
2523  {
2524  WarnNoImageReturn("\"%%%c\"",letter);
2525  string=GetImageProperty(image,"label",exception);
2526  if (string == (const char *) NULL)
2527  string="";
2528  break;
2529  }
2530  case 'm': /* Image format (file magick) */
2531  {
2532  WarnNoImageReturn("\"%%%c\"",letter);
2533  string=image->magick;
2534  break;
2535  }
2536  case 'n': /* Number of images in the list. */
2537  {
2538  if ( image != (Image *) NULL )
2539  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
2540  GetImageListLength(image));
2541  else
2542  string="0"; /* no images or scenes */
2543  break;
2544  }
2545  case 'o': /* Output Filename - for delegate use only */
2546  WarnNoImageInfoReturn("\"%%%c\"",letter);
2547  string=image_info->filename;
2548  break;
2549  case 'p': /* Image index in current image list */
2550  {
2551  WarnNoImageReturn("\"%%%c\"",letter);
2552  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
2553  GetImageIndexInList(image));
2554  break;
2555  }
2556  case 'q': /* Quantum depth of image in memory */
2557  {
2558  WarnNoImageReturn("\"%%%c\"",letter);
2559  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
2561  break;
2562  }
2563  case 'r': /* Image storage class, colorspace, and alpha enabled. */
2564  {
2566  colorspace;
2567 
2568  WarnNoImageReturn("\"%%%c\"",letter);
2569  colorspace=image->colorspace;
2570  if ((image->columns != 0) && (image->rows != 0) &&
2571  (SetImageGray(image,exception) != MagickFalse))
2572  colorspace=GRAYColorspace; /* FUTURE: this is IMv6 not IMv7 */
2573  (void) FormatLocaleString(value,MagickPathExtent,"%s %s %s",
2576  (ssize_t) colorspace),image->alpha_trait != UndefinedPixelTrait ?
2577  "Alpha" : "");
2578  break;
2579  }
2580  case 's': /* Image scene number */
2581  {
2582 #if 0 /* this seems non-sensical -- simplifing */
2583  if (image_info->number_scenes != 0)
2584  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
2585  image_info->scene);
2586  else if (image != (Image *) NULL)
2587  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
2588  image->scene);
2589  else
2590  string="0";
2591 #else
2592  WarnNoImageReturn("\"%%%c\"",letter);
2593  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
2594  image->scene);
2595 #endif
2596  break;
2597  }
2598  case 't': /* Base filename without directory or extention */
2599  {
2600  WarnNoImageReturn("\"%%%c\"",letter);
2602  if (*value == '\0')
2603  string="";
2604  break;
2605  }
2606  case 'u': /* Unique filename */
2607  {
2608  WarnNoImageInfoReturn("\"%%%c\"",letter);
2609  string=image_info->unique;
2610  break;
2611  }
2612  case 'w': /* Image width (current) */
2613  {
2614  WarnNoImageReturn("\"%%%c\"",letter);
2615  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
2616  (image->columns != 0 ? image->columns : image->magick_columns));
2617  break;
2618  }
2619  case 'x': /* Image horizontal resolution (with units) */
2620  {
2621  WarnNoImageReturn("\"%%%c\"",letter);
2622  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",
2623  fabs(image->resolution.x) > MagickEpsilon ? image->resolution.x : 72.0);
2624  break;
2625  }
2626  case 'y': /* Image vertical resolution (with units) */
2627  {
2628  WarnNoImageReturn("\"%%%c\"",letter);
2629  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",
2630  fabs(image->resolution.y) > MagickEpsilon ? image->resolution.y : 72.0);
2631  break;
2632  }
2633  case 'z': /* Image depth as read in */
2634  {
2635  WarnNoImageReturn("\"%%%c\"",letter);
2636  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
2637  image->depth);
2638  break;
2639  }
2640  case 'A': /* Image alpha channel */
2641  {
2642  WarnNoImageReturn("\"%%%c\"",letter);
2644  image->alpha_trait);
2645  break;
2646  }
2647  case 'B': /* image size read in - in bytes */
2648  {
2649  WarnNoImageReturn("\"%%%c\"",letter);
2650  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
2651  image->extent);
2652  if (image->extent == 0)
2653  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
2654  GetBlobSize(image));
2655  break;
2656  }
2657  case 'C': /* Image compression method. */
2658  {
2659  WarnNoImageReturn("\"%%%c\"",letter);
2661  image->compression);
2662  break;
2663  }
2664  case 'D': /* Image dispose method. */
2665  {
2666  WarnNoImageReturn("\"%%%c\"",letter);
2668  image->dispose);
2669  break;
2670  }
2671  case 'G': /* Image size as geometry = "%wx%h" */
2672  {
2673  WarnNoImageReturn("\"%%%c\"",letter);
2674  (void) FormatLocaleString(value,MagickPathExtent,"%.20gx%.20g",(double)
2675  image->magick_columns,(double) image->magick_rows);
2676  break;
2677  }
2678  case 'H': /* layer canvas height */
2679  {
2680  WarnNoImageReturn("\"%%%c\"",letter);
2681  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
2682  image->page.height);
2683  break;
2684  }
2685  case 'M': /* Magick filename - filename given incl. coder & read mods */
2686  {
2687  WarnNoImageReturn("\"%%%c\"",letter);
2688  string=image->magick_filename;
2689  break;
2690  }
2691  case 'O': /* layer canvas offset with sign = "+%X+%Y" */
2692  {
2693  WarnNoImageReturn("\"%%%c\"",letter);
2694  (void) FormatLocaleString(value,MagickPathExtent,"%+ld%+ld",(long)
2695  image->page.x,(long) image->page.y);
2696  break;
2697  }
2698  case 'P': /* layer canvas page size = "%Wx%H" */
2699  {
2700  WarnNoImageReturn("\"%%%c\"",letter);
2701  (void) FormatLocaleString(value,MagickPathExtent,"%.20gx%.20g",(double)
2702  image->page.width,(double) image->page.height);
2703  break;
2704  }
2705  case 'Q': /* image compression quality */
2706  {
2707  WarnNoImageReturn("\"%%%c\"",letter);
2708  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
2709  (image->quality == 0 ? 92 : image->quality));
2710  break;
2711  }
2712  case 'S': /* Number of scenes in image list. */
2713  {
2714  WarnNoImageInfoReturn("\"%%%c\"",letter);
2715 #if 0 /* What is this number? -- it makes no sense - simplifing */
2716  if (image_info->number_scenes == 0)
2717  string="2147483647";
2718  else if ( image != (Image *) NULL )
2719  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
2720  image_info->scene+image_info->number_scenes);
2721  else
2722  string="0";
2723 #else
2724  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
2725  (image_info->number_scenes == 0 ? 2147483647 :
2726  image_info->number_scenes));
2727 #endif
2728  break;
2729  }
2730  case 'T': /* image time delay for animations */
2731  {
2732  WarnNoImageReturn("\"%%%c\"",letter);
2733  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
2734  image->delay);
2735  break;
2736  }
2737  case 'U': /* Image resolution units. */
2738  {
2739  WarnNoImageReturn("\"%%%c\"",letter);
2741  image->units);
2742  break;
2743  }
2744  case 'W': /* layer canvas width */
2745  {
2746  WarnNoImageReturn("\"%%%c\"",letter);
2747  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
2748  image->page.width);
2749  break;
2750  }
2751  case 'X': /* layer canvas X offset */
2752  {
2753  WarnNoImageReturn("\"%%%c\"",letter);
2754  (void) FormatLocaleString(value,MagickPathExtent,"%+.20g",(double)
2755  image->page.x);
2756  break;
2757  }
2758  case 'Y': /* layer canvas Y offset */
2759  {
2760  WarnNoImageReturn("\"%%%c\"",letter);
2761  (void) FormatLocaleString(value,MagickPathExtent,"%+.20g",(double)
2762  image->page.y);
2763  break;
2764  }
2765  case '%': /* percent escaped */
2766  {
2767  string="%";
2768  break;
2769  }
2770  case '@': /* Trim bounding box, without actually Trimming! */
2771  {
2773  page;
2774 
2775  WarnNoImageReturn("\"%%%c\"",letter);
2776  page=GetImageBoundingBox(image,exception);
2777  (void) FormatLocaleString(value,MagickPathExtent,
2778  "%.20gx%.20g%+.20g%+.20g",(double) page.width,(double) page.height,
2779  (double) page.x,(double)page.y);
2780  break;
2781  }
2782  case '#':
2783  {
2784  /*
2785  Image signature.
2786  */
2787  WarnNoImageReturn("\"%%%c\"",letter);
2788  if ((image->columns != 0) && (image->rows != 0))
2789  (void) SignatureImage(image,exception);
2790  string=GetImageProperty(image,"signature",exception);
2791  break;
2792  }
2793  }
2794  if (string != (char *) NULL)
2795  return(string);
2796  if (*value != '\0')
2797  {
2798  /*
2799  Create a cloned copy of result.
2800  */
2801  if (image != (Image *) NULL)
2802  {
2803  (void) SetImageArtifact(image,"get-property",value);
2804  return(GetImageArtifact(image,"get-property"));
2805  }
2806  else
2807  {
2808  (void) SetImageOption(image_info,"get-property",value);
2809  return(GetImageOption(image_info,"get-property"));
2810  }
2811  }
2812  return((char *) NULL);
2813 }
2814 
2815 MagickExport const char *GetMagickProperty(ImageInfo *image_info,
2816  Image *image,const char *property,ExceptionInfo *exception)
2817 {
2818  char
2819  value[MagickPathExtent];
2820 
2821  const char
2822  *string;
2823 
2824  assert(property[0] != '\0');
2825  assert(image != (Image *) NULL || image_info != (ImageInfo *) NULL );
2826  if (property[1] == '\0') /* single letter property request */
2827  return(GetMagickPropertyLetter(image_info,image,*property,exception));
2828  if ((image != (Image *) NULL) && (image->debug != MagickFalse))
2829  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2830  else
2831  if ((image_info != (ImageInfo *) NULL) &&
2832  (image_info->debug != MagickFalse))
2833  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s","no-images");
2834  *value='\0'; /* formated string */
2835  string=(char *) NULL; /* constant string reference */
2836  switch (*property)
2837  {
2838  case 'b':
2839  {
2840  if (LocaleCompare("basename",property) == 0)
2841  {
2842  WarnNoImageReturn("\"%%[%s]\"",property);
2844  if (*value == '\0')
2845  string="";
2846  break;
2847  }
2848  if (LocaleCompare("bit-depth",property) == 0)
2849  {
2850  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
2851  GetImageDepth(image,exception));
2852  break;
2853  }
2854  break;
2855  }
2856  case 'c':
2857  {
2858  if (LocaleCompare("channels",property) == 0)
2859  {
2860  WarnNoImageReturn("\"%%[%s]\"",property);
2861  /* FUTURE: return actual image channels */
2862  (void) FormatLocaleString(value,MagickPathExtent,"%s",
2864  image->colorspace));
2865  LocaleLower(value);
2866  if( image->alpha_trait != UndefinedPixelTrait )
2867  (void) ConcatenateMagickString(value,"a",MagickPathExtent);
2868  break;
2869  }
2870  if (LocaleCompare("colorspace",property) == 0)
2871  {
2872  WarnNoImageReturn("\"%%[%s]\"",property);
2874  image->colorspace);
2875  break;
2876  }
2877  if (LocaleCompare("compose",property) == 0)
2878  {
2879  WarnNoImageReturn("\"%%[%s]\"",property);
2881  image->compose);
2882  break;
2883  }
2884  if (LocaleCompare("compression",property) == 0)
2885  {
2886  WarnNoImageReturn("\"%%[%s]\"",property);
2888  image->compression);
2889  break;
2890  }
2891  if (LocaleCompare("copyright",property) == 0)
2892  {
2894  break;
2895  }
2896  break;
2897  }
2898  case 'd':
2899  {
2900  if (LocaleCompare("depth",property) == 0)
2901  {
2902  WarnNoImageReturn("\"%%[%s]\"",property);
2903  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
2904  image->depth);
2905  break;
2906  }
2907  if (LocaleCompare("directory",property) == 0)
2908  {
2909  WarnNoImageReturn("\"%%[%s]\"",property);
2911  if (*value == '\0')
2912  string="";
2913  break;
2914  }
2915  break;
2916  }
2917  case 'e':
2918  {
2919  if (LocaleCompare("entropy",property) == 0)
2920  {
2921  double
2922  entropy;
2923 
2924  WarnNoImageReturn("\"%%[%s]\"",property);
2925  (void) GetImageEntropy(image,&entropy,exception);
2926  (void) FormatLocaleString(value,MagickPathExtent,"%.*g",
2927  GetMagickPrecision(),entropy);
2928  break;
2929  }
2930  if (LocaleCompare("extension",property) == 0)
2931  {
2932  WarnNoImageReturn("\"%%[%s]\"",property);
2934  if (*value == '\0')
2935  string="";
2936  break;
2937  }
2938  break;
2939  }
2940  case 'g':
2941  {
2942  if (LocaleCompare("gamma",property) == 0)
2943  {
2944  WarnNoImageReturn("\"%%[%s]\"",property);
2945  (void) FormatLocaleString(value,MagickPathExtent,"%.*g",
2946  GetMagickPrecision(),image->gamma);
2947  break;
2948  }
2949  break;
2950  }
2951  case 'h':
2952  {
2953  if (LocaleCompare("height",property) == 0)
2954  {
2955  WarnNoImageReturn("\"%%[%s]\"",property);
2956  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",
2957  image->magick_rows != 0 ? (double) image->magick_rows : 256.0);
2958  break;
2959  }
2960  break;
2961  }
2962  case 'i':
2963  {
2964  if (LocaleCompare("input",property) == 0)
2965  {
2966  WarnNoImageReturn("\"%%[%s]\"",property);
2967  string=image->filename;
2968  break;
2969  }
2970  if (LocaleCompare("interlace",property) == 0)
2971  {
2973  image->interlace);
2974  break;
2975  }
2976  break;
2977  }
2978  case 'k':
2979  {
2980  if (LocaleCompare("kurtosis",property) == 0)
2981  {
2982  double
2983  kurtosis,
2984  skewness;
2985 
2986  WarnNoImageReturn("\"%%[%s]\"",property);
2987  (void) GetImageKurtosis(image,&kurtosis,&skewness,exception);
2988  (void) FormatLocaleString(value,MagickPathExtent,"%.*g",
2989  GetMagickPrecision(),kurtosis);
2990  break;
2991  }
2992  break;
2993  }
2994  case 'm':
2995  {
2996  if (LocaleCompare("magick",property) == 0)
2997  {
2998  WarnNoImageReturn("\"%%[%s]\"",property);
2999  string=image->magick;
3000  break;
3001  }
3002  if ((LocaleCompare("maxima",property) == 0) ||
3003  (LocaleCompare("max",property) == 0))
3004  {
3005  double
3006  maximum,
3007  minimum;
3008 
3009  WarnNoImageReturn("\"%%[%s]\"",property);
3010  (void) GetImageRange(image,&minimum,&maximum,exception);
3011  (void) FormatLocaleString(value,MagickPathExtent,"%.*g",
3012  GetMagickPrecision(),maximum);
3013  break;
3014  }
3015  if (LocaleCompare("mean",property) == 0)
3016  {
3017  double
3018  mean,
3019  standard_deviation;
3020 
3021  WarnNoImageReturn("\"%%[%s]\"",property);
3022  (void) GetImageMean(image,&mean,&standard_deviation,exception);
3023  (void) FormatLocaleString(value,MagickPathExtent,"%.*g",
3024  GetMagickPrecision(),mean);
3025  break;
3026  }
3027  if ((LocaleCompare("minima",property) == 0) ||
3028  (LocaleCompare("min",property) == 0))
3029  {
3030  double
3031  maximum,
3032  minimum;
3033 
3034  WarnNoImageReturn("\"%%[%s]\"",property);
3035  (void) GetImageRange(image,&minimum,&maximum,exception);
3036  (void) FormatLocaleString(value,MagickPathExtent,"%.*g",
3037  GetMagickPrecision(),minimum);
3038  break;
3039  }
3040  break;
3041  }
3042  case 'o':
3043  {
3044  if (LocaleCompare("opaque",property) == 0)
3045  {
3046  WarnNoImageReturn("\"%%[%s]\"",property);
3048  IsImageOpaque(image,exception));
3049  break;
3050  }
3051  if (LocaleCompare("orientation",property) == 0)
3052  {
3053  WarnNoImageReturn("\"%%[%s]\"",property);
3055  image->orientation);
3056  break;
3057  }
3058  if (LocaleCompare("output",property) == 0)
3059  {
3060  WarnNoImageInfoReturn("\"%%[%s]\"",property);
3061  (void) CopyMagickString(value,image_info->filename,MagickPathExtent);
3062  break;
3063  }
3064  break;
3065  }
3066  case 'p':
3067  {
3068  if (LocaleCompare("page",property) == 0)
3069  {
3070  WarnNoImageReturn("\"%%[%s]\"",property);
3071  (void) FormatLocaleString(value,MagickPathExtent,"%.20gx%.20g",
3072  (double) image->page.width,(double) image->page.height);
3073  break;
3074  }
3075 #if defined(MAGICKCORE_LCMS_DELEGATE)
3076  if (LocaleCompare("profile:icc",property) == 0 ||
3077  LocaleCompare("profile:icm",property) == 0)
3078  {
3079 #if !defined(LCMS_VERSION) || (LCMS_VERSION < 2000)
3080 #define cmsUInt32Number DWORD
3081 #endif
3082 
3083  const StringInfo
3084  *profile;
3085 
3086  cmsHPROFILE
3087  icc_profile;
3088 
3089  profile=GetImageProfile(image,property+8);
3090  if (profile == (StringInfo *) NULL)
3091  break;
3092  icc_profile=cmsOpenProfileFromMem(GetStringInfoDatum(profile),
3093  (cmsUInt32Number) GetStringInfoLength(profile));
3094  if (icc_profile != (cmsHPROFILE *) NULL)
3095  {
3096 #if defined(LCMS_VERSION) && (LCMS_VERSION < 2000)
3097  string=cmsTakeProductName(icc_profile);
3098 #else
3099  (void) cmsGetProfileInfoASCII(icc_profile,cmsInfoDescription,
3100  "en","US",value,MagickPathExtent);
3101 #endif
3102  (void) cmsCloseProfile(icc_profile);
3103  }
3104  }
3105 #endif
3106  if (LocaleCompare("profiles",property) == 0)
3107  {
3108  const char
3109  *name;
3110 
3112  name=GetNextImageProfile(image);
3113  if (name != (char *) NULL)
3114  {
3115  (void) CopyMagickString(value,name,MagickPathExtent);
3116  name=GetNextImageProfile(image);
3117  while (name != (char *) NULL)
3118  {
3121  name=GetNextImageProfile(image);
3122  }
3123  }
3124  break;
3125  }
3126  break;
3127  }
3128  case 'q':
3129  {
3130  if (LocaleCompare("quality",property) == 0)
3131  {
3132  WarnNoImageReturn("\"%%[%s]\"",property);
3133  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
3134  image->quality);
3135  break;
3136  }
3137  break;
3138  }
3139  case 'r':
3140  {
3141  if (LocaleCompare("resolution.x",property) == 0)
3142  {
3143  WarnNoImageReturn("\"%%[%s]\"",property);
3144  (void) FormatLocaleString(value,MagickPathExtent,"%g",
3145  image->resolution.x);
3146  break;
3147  }
3148  if (LocaleCompare("resolution.y",property) == 0)
3149  {
3150  WarnNoImageReturn("\"%%[%s]\"",property);
3151  (void) FormatLocaleString(value,MagickPathExtent,"%g",
3152  image->resolution.y);
3153  break;
3154  }
3155  break;
3156  }
3157  case 's':
3158  {
3159  if (LocaleCompare("scene",property) == 0)
3160  {
3161  WarnNoImageInfoReturn("\"%%[%s]\"",property);
3162  if (image_info->number_scenes != 0)
3163  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
3164  image_info->scene);
3165  else {
3166  WarnNoImageReturn("\"%%[%s]\"",property);
3167  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
3168  image->scene);
3169  }
3170  break;
3171  }
3172  if (LocaleCompare("scenes",property) == 0)
3173  {
3174  /* FUTURE: equivelent to %n? */
3175  WarnNoImageReturn("\"%%[%s]\"",property);
3176  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
3177  GetImageListLength(image));
3178  break;
3179  }
3180  if (LocaleCompare("size",property) == 0)
3181  {
3182  WarnNoImageReturn("\"%%[%s]\"",property);
3183  (void) FormatMagickSize(GetBlobSize(image),MagickFalse,"B",
3184  MagickPathExtent,value);
3185  break;
3186  }
3187  if (LocaleCompare("skewness",property) == 0)
3188  {
3189  double
3190  kurtosis,
3191  skewness;
3192 
3193  WarnNoImageReturn("\"%%[%s]\"",property);
3194  (void) GetImageKurtosis(image,&kurtosis,&skewness,exception);
3195  (void) FormatLocaleString(value,MagickPathExtent,"%.*g",
3196  GetMagickPrecision(),skewness);
3197  break;
3198  }
3199  if (LocaleCompare("standard-deviation",property) == 0)
3200  {
3201  double
3202  mean,
3203  standard_deviation;
3204 
3205  WarnNoImageReturn("\"%%[%s]\"",property);
3206  (void) GetImageMean(image,&mean,&standard_deviation,exception);
3207  (void) FormatLocaleString(value,MagickPathExtent,"%.*g",
3208  GetMagickPrecision(),standard_deviation);
3209  break;
3210  }
3211  break;
3212  }
3213  case 't':
3214  {
3215  if (LocaleCompare("type",property) == 0)
3216  {
3217  WarnNoImageReturn("\"%%[%s]\"",property);
3219  IdentifyImageType(image,exception));
3220  break;
3221  }
3222  break;
3223  }
3224  case 'u':
3225  {
3226  if (LocaleCompare("unique",property) == 0)
3227  {
3228  WarnNoImageInfoReturn("\"%%[%s]\"",property);
3229  string=image_info->unique;
3230  break;
3231  }
3232  if (LocaleCompare("units",property) == 0)
3233  {
3234  WarnNoImageReturn("\"%%[%s]\"",property);
3236  image->units);
3237  break;
3238  }
3239  break;
3240  }
3241  case 'v':
3242  {
3243  if (LocaleCompare("version",property) == 0)
3244  {
3245  string=GetMagickVersion((size_t *) NULL);
3246  break;
3247  }
3248  break;
3249  }
3250  case 'w':
3251  {
3252  if (LocaleCompare("width",property) == 0)
3253  {
3254  WarnNoImageReturn("\"%%[%s]\"",property);
3255  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
3256  (image->magick_columns != 0 ? image->magick_columns : 256));
3257  break;
3258  }
3259  break;
3260  }
3261  }
3262  if (string != (char *) NULL)
3263  return(string);
3264  if (*value != '\0')
3265  {
3266  /*
3267  Create a cloned copy of result, that will get cleaned up, eventually.
3268  */
3269  if (image != (Image *) NULL)
3270  {
3271  (void) SetImageArtifact(image,"get-property",value);
3272  return(GetImageArtifact(image,"get-property"));
3273  }
3274  else
3275  {
3276  (void) SetImageOption(image_info,"get-property",value);
3277  return(GetImageOption(image_info,"get-property"));
3278  }
3279  }
3280  return((char *) NULL);
3281 }
3282 #undef WarnNoImageReturn
3283 
3284 /*
3285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3286 % %
3287 % %
3288 % %
3289 % G e t N e x t I m a g e P r o p e r t y %
3290 % %
3291 % %
3292 % %
3293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3294 %
3295 % GetNextImageProperty() gets the next free-form string property name.
3296 %
3297 % The format of the GetNextImageProperty method is:
3298 %
3299 % char *GetNextImageProperty(const Image *image)
3300 %
3301 % A description of each parameter follows:
3302 %
3303 % o image: the image.
3304 %
3305 */
3306 MagickExport const char *GetNextImageProperty(const Image *image)
3307 {
3308  assert(image != (Image *) NULL);
3309  assert(image->signature == MagickCoreSignature);
3310  if (image->debug != MagickFalse)
3312  image->filename);
3313  if (image->properties == (void *) NULL)
3314  return((const char *) NULL);
3315  return((const char *) GetNextKeyInSplayTree((SplayTreeInfo *) image->properties));
3316 }
3317 
3318 /*
3319 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3320 % %
3321 % %
3322 % %
3323 % I n t e r p r e t I m a g e P r o p e r t i e s %
3324 % %
3325 % %
3326 % %
3327 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3328 %
3329 % InterpretImageProperties() replaces any embedded formatting characters with
3330 % the appropriate image property and returns the interpreted text.
3331 %
3332 % This searches for and replaces
3333 % \n \r \% replaced by newline, return, and percent resp.
3334 % &lt; &gt; &amp; replaced by '<', '>', '&' resp.
3335 % %% replaced by percent
3336 %
3337 % %x %[x] where 'x' is a single letter properity, case sensitive).
3338 % %[type:name] where 'type' a is special and known prefix.
3339 % %[name] where 'name' is a specifically known attribute, calculated
3340 % value, or a per-image property string name, or a per-image
3341 % 'artifact' (as generated from a global option).
3342 % It may contain ':' as long as the prefix is not special.
3343 %
3344 % Single letter % substitutions will only happen if the character before the
3345 % percent is NOT a number. But braced substitutions will always be performed.
3346 % This prevents the typical usage of percent in a interpreted geometry
3347 % argument from being substituted when the percent is a geometry flag.
3348 %
3349 % If 'glob-expresions' ('*' or '?' characters) is used for 'name' it may be
3350 % used as a search pattern to print multiple lines of "name=value\n" pairs of
3351 % the associacted set of properties.
3352 %
3353 % The returned string must be freed using DestoryString() by the caller.
3354 %
3355 % The format of the InterpretImageProperties method is:
3356 %
3357 % char *InterpretImageProperties(ImageInfo *image_info,
3358 % Image *image,const char *embed_text,ExceptionInfo *exception)
3359 %
3360 % A description of each parameter follows:
3361 %
3362 % o image_info: the image info. (required)
3363 %
3364 % o image: the image. (optional)
3365 %
3366 % o embed_text: the address of a character string containing the embedded
3367 % formatting characters.
3368 %
3369 % o exception: return any errors or warnings in this structure.
3370 %
3371 */
3373  const char *embed_text,ExceptionInfo *exception)
3374 {
3375 #define ExtendInterpretText(string_length) \
3376 DisableMSCWarning(4127) \
3377 { \
3378  size_t length=(string_length); \
3379  if ((size_t) (q-interpret_text+length+1) >= extent) \
3380  { \
3381  extent+=length; \
3382  interpret_text=(char *) ResizeQuantumMemory(interpret_text,extent+ \
3383  MaxTextExtent,sizeof(*interpret_text)); \
3384  if (interpret_text == (char *) NULL) \
3385  { \
3386  if (property_image != image) \
3387  property_image=DestroyImage(property_image); \
3388  if (property_info != image_info) \
3389  property_info=DestroyImageInfo(property_info); \
3390  return((char *) NULL); \
3391  } \
3392  q=interpret_text+strlen(interpret_text); \
3393  } \
3394 } \
3395 RestoreMSCWarning
3396 
3397 #define AppendKeyValue2Text(key,value)\
3398 DisableMSCWarning(4127) \
3399 { \
3400  size_t length=strlen(key)+strlen(value)+2; \
3401  if ((size_t) (q-interpret_text+length+1) >= extent) \
3402  { \
3403  extent+=length; \
3404  interpret_text=(char *) ResizeQuantumMemory(interpret_text,extent+ \
3405  MaxTextExtent,sizeof(*interpret_text)); \
3406  if (interpret_text == (char *) NULL) \
3407  { \
3408  if (property_image != image) \
3409  property_image=DestroyImage(property_image); \
3410  if (property_info != image_info) \
3411  property_info=DestroyImageInfo(property_info); \
3412  return((char *) NULL); \
3413  } \
3414  q=interpret_text+strlen(interpret_text); \
3415  } \
3416  q+=FormatLocaleString(q,extent,"%s=%s\n",(key),(value)); \
3417 } \
3418 RestoreMSCWarning
3419 
3420 #define AppendString2Text(string) \
3421 DisableMSCWarning(4127) \
3422 { \
3423  size_t length=strlen((string)); \
3424  if ((size_t) (q-interpret_text+length+1) >= extent) \
3425  { \
3426  extent+=length; \
3427  interpret_text=(char *) ResizeQuantumMemory(interpret_text,extent+ \
3428  MaxTextExtent,sizeof(*interpret_text)); \
3429  if (interpret_text == (char *) NULL) \
3430  { \
3431  if (property_image != image) \
3432  property_image=DestroyImage(property_image); \
3433  if (property_info != image_info) \
3434  property_info=DestroyImageInfo(property_info); \
3435  return((char *) NULL); \
3436  } \
3437  q=interpret_text+strlen(interpret_text); \
3438  } \
3439  (void) CopyMagickString(q,(string),extent); \
3440  q+=length; \
3441 } \
3442 RestoreMSCWarning
3443 
3444  char
3445  *interpret_text;
3446 
3447  Image
3448  *property_image;
3449 
3450  ImageInfo
3451  *property_info;
3452 
3454  number;
3455 
3456  register char
3457  *q; /* current position in interpret_text */
3458 
3459  register const char
3460  *p; /* position in embed_text string being expanded */
3461 
3462  size_t
3463  extent; /* allocated length of interpret_text */
3464 
3465  if ((image != (Image *) NULL) && (image->debug != MagickFalse))
3466  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3467  else
3468  if ((image_info != (ImageInfo *) NULL) && (image_info->debug != MagickFalse))
3470  image_info->filename);
3471  else
3472  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s","no image");
3473  if (embed_text == (const char *) NULL)
3474  return(ConstantString(""));
3475  p=embed_text;
3476  while ((isspace((int) ((unsigned char) *p)) != 0) && (*p != '\0'))
3477  p++;
3478  if (*p == '\0')
3479  return(ConstantString(""));
3480  if ((*p == '@') && (IsPathAccessible(p+1) != MagickFalse))
3481  {
3482  /*
3483  Handle a '@' replace string from file.
3484  */
3486  {
3487  errno=EPERM;
3489  "NotAuthorized","`%s'",p);
3490  return(ConstantString(""));
3491  }
3492  interpret_text=FileToString(p+1,~0UL,exception);
3493  if (interpret_text != (char *) NULL)
3494  return(interpret_text);
3495  }
3496  /*
3497  Translate any embedded format characters.
3498  */
3499  if (image_info != (ImageInfo *) NULL)
3500  property_info=image_info;
3501  else
3502  property_info=CloneImageInfo(image_info);
3503  if ((image != (Image *) NULL) && (image->columns != 0) && (image->rows != 0))
3504  property_image=image;
3505  else
3506  {
3507  property_image=AcquireImage(image_info,exception);
3508  (void) SetImageExtent(property_image,1,1,exception);
3509  (void) SetImageBackgroundColor(property_image,exception);
3510  }
3511  interpret_text=AcquireString(embed_text); /* new string with extra space */
3512  extent=MagickPathExtent; /* allocated space in string */
3513  number=MagickFalse; /* is last char a number? */
3514  for (q=interpret_text; *p!='\0'; number=isdigit((int) ((unsigned char) *p)) ? MagickTrue : MagickFalse,p++)
3515  {
3516  /*
3517  Look for the various escapes, (and handle other specials)
3518  */
3519  *q='\0';
3521  switch (*p)
3522  {
3523  case '\\':
3524  {
3525  switch (*(p+1))
3526  {
3527  case '\0':
3528  continue;
3529  case 'r': /* convert to RETURN */
3530  {
3531  *q++='\r';
3532  p++;
3533  continue;
3534  }
3535  case 'n': /* convert to NEWLINE */
3536  {
3537  *q++='\n';
3538  p++;
3539  continue;
3540  }
3541  case '\n': /* EOL removal UNIX,MacOSX */
3542  {
3543  p++;
3544  continue;
3545  }
3546  case '\r': /* EOL removal DOS,Windows */
3547  {
3548  p++;
3549  if (*p == '\n') /* return-newline EOL */
3550  p++;
3551  continue;
3552  }
3553  default:
3554  {
3555  p++;
3556  *q++=(*p);
3557  }
3558  }
3559  continue;
3560  }
3561  case '&':
3562  {
3563  if (LocaleNCompare("&lt;",p,4) == 0)
3564  {
3565  *q++='<';
3566  p+=3;
3567  }
3568  else
3569  if (LocaleNCompare("&gt;",p,4) == 0)
3570  {
3571  *q++='>';
3572  p+=3;
3573  }
3574  else
3575  if (LocaleNCompare("&amp;",p,5) == 0)
3576  {
3577  *q++='&';
3578  p+=4;
3579  }
3580  else
3581  *q++=(*p);
3582  continue;
3583  }
3584  case '%':
3585  break; /* continue to next set of handlers */
3586  default:
3587  {
3588  *q++=(*p); /* any thing else is 'as normal' */
3589  continue;
3590  }
3591  }
3592  p++; /* advance beyond the percent */
3593  /*
3594  Doubled Percent - or percent at end of string.
3595  */
3596  if ((*p == '\0') || (*p == '\'') || (*p == '"'))
3597  p--;
3598  if (*p == '%')
3599  {
3600  *q++='%';
3601  continue;
3602  }
3603  /*
3604  Single letter escapes %c.
3605  */
3606  if (*p != '[')
3607  {
3608  const char
3609  *string;
3610 
3611  if (number != MagickFalse)
3612  {
3613  /*
3614  But only if not preceeded by a number!
3615  */
3616  *q++='%'; /* do NOT substitute the percent */
3617  p--; /* back up one */
3618  continue;
3619  }
3620  string=GetMagickPropertyLetter(property_info,property_image,*p,
3621  exception);
3622  if (string != (char *) NULL)
3623  {
3624  AppendString2Text(string);
3625  (void) DeleteImageArtifact(property_image,"get-property");
3626  (void) DeleteImageOption(property_info,"get-property");
3627  continue;
3628  }
3630  "UnknownImageProperty","\"%%%c\"",*p);
3631  continue;
3632  }
3633  {
3634  char
3635  pattern[2*MagickPathExtent];
3636 
3637  const char
3638  *key,
3639  *string;
3640 
3641  register ssize_t
3642  len;
3643 
3644  ssize_t
3645  depth;
3646 
3647  /*
3648  Braced Percent Escape %[...].
3649  */
3650  p++; /* advance p to just inside the opening brace */
3651  depth=1;
3652  if (*p == ']')
3653  {
3655  "UnknownImageProperty","\"%%[]\"");
3656  break;
3657  }
3658  for (len=0; len < (MagickPathExtent-1L) && (*p != '\0'); )
3659  {
3660  if ((*p == '\\') && (*(p+1) != '\0'))
3661  {
3662  /*
3663  Skip escaped braces within braced pattern.
3664  */
3665  pattern[len++]=(*p++);
3666  pattern[len++]=(*p++);
3667  continue;
3668  }
3669  if (*p == '[')
3670  depth++;
3671  if (*p == ']')
3672  depth--;
3673  if (depth <= 0)
3674  break;
3675  pattern[len++]=(*p++);
3676  }
3677  pattern[len]='\0';
3678  if (depth != 0)
3679  {
3680  /*
3681  Check for unmatched final ']' for "%[...]".
3682  */
3683  if (len >= 64)
3684  {
3685  pattern[61] = '.'; /* truncate string for error message */
3686  pattern[62] = '.';
3687  pattern[63] = '.';
3688  pattern[64] = '\0';
3689  }
3691  "UnbalancedBraces","\"%%[%s\"",pattern);
3692  interpret_text=DestroyString(interpret_text);
3693  if (property_image != image)
3694  property_image=DestroyImage(property_image);
3695  if (property_info != image_info)
3696  property_info=DestroyImageInfo(property_info);
3697  return((char *) NULL);
3698  }
3699  /*
3700  Special Lookup Prefixes %[prefix:...].
3701  */
3702  if (LocaleNCompare("fx:",pattern,3) == 0)
3703  {
3704  double
3705  value;
3706 
3707  FxInfo
3708  *fx_info;
3709 
3711  status;
3712 
3713  /*
3714  FX - value calculator.
3715  */
3716  fx_info=AcquireFxInfo(property_image,pattern+3,exception);
3718  &value,exception);
3719  fx_info=DestroyFxInfo(fx_info);
3720  if (status != MagickFalse)
3721  {
3722  char
3723  result[MagickPathExtent];
3724 
3725  (void) FormatLocaleString(result,MagickPathExtent,"%.*g",
3726  GetMagickPrecision(),(double) value);
3727  AppendString2Text(result);
3728  }
3729  continue;
3730  }
3731  if (LocaleNCompare("hex:",pattern,4) == 0)
3732  {
3733  double
3734  value;
3735 
3736  FxInfo
3737  *fx_info;
3738 
3740  status;
3741 
3742  PixelInfo
3743  pixel;
3744 
3745  /*
3746  Pixel - color value calculator.
3747  */
3748  GetPixelInfo(property_image,&pixel);
3749  fx_info=AcquireFxInfo(property_image,pattern+4,exception);
3750  status=FxEvaluateChannelExpression(fx_info,RedPixelChannel,0,0,
3751  &value,exception);
3752  pixel.red=(double) QuantumRange*value;
3753  status&=FxEvaluateChannelExpression(fx_info,GreenPixelChannel,0,0,
3754  &value,exception);
3755  pixel.green=(double) QuantumRange*value;
3756  status&=FxEvaluateChannelExpression(fx_info,BluePixelChannel,0,0,
3757  &value,exception);
3758  pixel.blue=(double) QuantumRange*value;
3759  if (property_image->colorspace == CMYKColorspace)
3760  {
3761  status&=FxEvaluateChannelExpression(fx_info,BlackPixelChannel,0,0,
3762  &value,exception);
3763  pixel.black=(double) QuantumRange*value;
3764  }
3765  status&=FxEvaluateChannelExpression(fx_info,AlphaPixelChannel,0,0,
3766  &value,exception);
3767  pixel.alpha=(double) QuantumRange*value;
3768  fx_info=DestroyFxInfo(fx_info);
3769  if (status != MagickFalse)
3770  {
3771  char
3772  hex[MagickPathExtent],
3773  name[MagickPathExtent];
3774 
3775  (void) QueryColorname(property_image,&pixel,SVGCompliance,name,
3776  exception);
3777  GetColorTuple(&pixel,MagickTrue,hex);
3778  AppendString2Text(hex+1);
3779  }
3780  continue;
3781  }
3782  if (LocaleNCompare("pixel:",pattern,6) == 0)
3783  {
3784  double
3785  value;
3786 
3787  FxInfo
3788  *fx_info;
3789 
3791  status;
3792 
3793  PixelInfo
3794  pixel;
3795 
3796  /*
3797  Pixel - color value calculator.
3798  */
3799  GetPixelInfo(property_image,&pixel);
3800  fx_info=AcquireFxInfo(property_image,pattern+6,exception);
3801  status=FxEvaluateChannelExpression(fx_info,RedPixelChannel,0,0,
3802  &value,exception);
3803  pixel.red=(double) QuantumRange*value;
3804  status&=FxEvaluateChannelExpression(fx_info,GreenPixelChannel,0,0,
3805  &value,exception);
3806  pixel.green=(double) QuantumRange*value;
3807  status&=FxEvaluateChannelExpression(fx_info,BluePixelChannel,0,0,
3808  &value,exception);
3809  pixel.blue=(double) QuantumRange*value;
3810  if (property_image->colorspace == CMYKColorspace)
3811  {
3812  status&=FxEvaluateChannelExpression(fx_info,BlackPixelChannel,0,0,
3813  &value,exception);
3814  pixel.black=(double) QuantumRange*value;
3815  }
3816  status&=FxEvaluateChannelExpression(fx_info,AlphaPixelChannel,0,0,
3817  &value,exception);
3818  pixel.alpha=(double) QuantumRange*value;
3819  fx_info=DestroyFxInfo(fx_info);
3820  if (status != MagickFalse)
3821  {
3822  char
3823  name[MagickPathExtent];
3824 
3825  (void) QueryColorname(property_image,&pixel,SVGCompliance,name,
3826  exception);
3827  AppendString2Text(name);
3828  }
3829  continue;
3830  }
3831  if (LocaleNCompare("option:",pattern,7) == 0)
3832  {
3833  /*
3834  Option - direct global option lookup (with globbing).
3835  */
3836  if (IsGlob(pattern+7) != MagickFalse)
3837  {
3838  ResetImageOptionIterator(property_info);
3839  while ((key=GetNextImageOption(property_info)) != (const char *) NULL)
3840  if (GlobExpression(key,pattern+7,MagickTrue) != MagickFalse)
3841  {
3842  string=GetImageOption(property_info,key);
3843  if (string != (const char *) NULL)
3844  AppendKeyValue2Text(key,string);
3845  /* else - assertion failure? key found but no string value! */
3846  }
3847  continue;
3848  }
3849  string=GetImageOption(property_info,pattern+7);
3850  if (string == (char *) NULL)
3851  goto PropertyLookupFailure; /* no artifact of this specifc name */
3852  AppendString2Text(string);
3853  continue;
3854  }
3855  if (LocaleNCompare("artifact:",pattern,9) == 0)
3856  {
3857  /*
3858  Artifact - direct image artifact lookup (with glob).
3859  */
3860  if (IsGlob(pattern+9) != MagickFalse)
3861  {
3862  ResetImageArtifactIterator(property_image);
3863  while ((key=GetNextImageArtifact(property_image)) != (const char *) NULL)
3864  if (GlobExpression(key,pattern+9,MagickTrue) != MagickFalse)
3865  {
3866  string=GetImageArtifact(property_image,key);
3867  if (string != (const char *) NULL)
3868  AppendKeyValue2Text(key,string);
3869  /* else - assertion failure? key found but no string value! */
3870  }
3871  continue;
3872  }
3873  string=GetImageArtifact(property_image,pattern+9);
3874  if (string == (char *) NULL)
3875  goto PropertyLookupFailure; /* no artifact of this specifc name */
3876  AppendString2Text(string);
3877  continue;
3878  }
3879  if (LocaleNCompare("property:",pattern,9) == 0)
3880  {
3881  /*
3882  Property - direct image property lookup (with glob).
3883  */
3884  if (IsGlob(pattern+9) != MagickFalse)
3885  {
3886  ResetImagePropertyIterator(property_image);
3887  while ((key=GetNextImageProperty(property_image)) != (const char *) NULL)
3888  if (GlobExpression(key,pattern,MagickTrue) != MagickFalse)
3889  {
3890  string=GetImageProperty(property_image,key,exception);
3891  if (string != (const char *) NULL)
3892  AppendKeyValue2Text(key,string);
3893  /* else - assertion failure? */
3894  }
3895  continue;
3896  }
3897  string=GetImageProperty(property_image,pattern+9,exception);
3898  if (string == (char *) NULL)
3899  goto PropertyLookupFailure; /* no artifact of this specifc name */
3900  AppendString2Text(string);
3901  continue;
3902  }
3903  /*
3904  Properties without special prefix. This handles attributes,
3905  properties, and profiles such as %[exif:...]. Note the profile
3906  properties may also include a glob expansion pattern.
3907  */
3908  string=GetImageProperty(property_image,pattern,exception);
3909  if (string != (const char *) NULL)
3910  {
3911  AppendString2Text(string);
3912  (void)DeleteImageArtifact(property_image,"get-property");
3913  (void)DeleteImageOption(property_info,"get-property");
3914  continue;
3915  }
3916  if (IsGlob(pattern) != MagickFalse)
3917  {
3918  /*
3919  Handle property 'glob' patterns such as:
3920  %[*] %[user:array_??] %[filename:e*]>
3921  */
3922  ResetImagePropertyIterator(property_image);
3923  while ((key=GetNextImageProperty(property_image)) != (const char *) NULL)
3924  if (GlobExpression(key,pattern,MagickTrue) != MagickFalse)
3925  {
3926  string=GetImageProperty(property_image,key,exception);
3927  if (string != (const char *) NULL)
3928  AppendKeyValue2Text(key,string);
3929  /* else - assertion failure? */
3930  }
3931  continue;
3932  }
3933  /*
3934  Look for a known property or image attribute such as
3935  %[basename] %[denisty] %[delay]. Also handles a braced single
3936  letter: %[b] %[G] %[g].
3937  */
3938  string=GetMagickProperty(property_info,property_image,pattern,exception);
3939  if (string != (const char *) NULL)
3940  {
3941  AppendString2Text(string);
3942  continue;
3943  }
3944  /*
3945  Look for a per-image artifact. This includes option lookup
3946  (FUTURE: interpreted according to image).
3947  */
3948  string=GetImageArtifact(property_image,pattern);
3949  if (string != (char *) NULL)
3950  {
3951  AppendString2Text(string);
3952  continue;
3953  }
3954  /*
3955  No image, so direct 'option' lookup (no delayed percent escapes).
3956  */
3957  string=GetImageOption(property_info,pattern);
3958  if (string != (char *) NULL)
3959  {
3960  AppendString2Text(string);
3961  continue;
3962  }
3963 PropertyLookupFailure:
3964  /*
3965  Failed to find any match anywhere!
3966  */
3967  if (len >= 64)
3968  {
3969  pattern[61] = '.'; /* truncate string for error message */
3970  pattern[62] = '.';
3971  pattern[63] = '.';
3972  pattern[64] = '\0';
3973  }
3975  "UnknownImageProperty","\"%%[%s]\"",pattern);
3976  }
3977  }
3978  *q='\0';
3979  if (property_image != image)
3980  property_image=DestroyImage(property_image);
3981  if (property_info != image_info)
3982  property_info=DestroyImageInfo(property_info);
3983  return(interpret_text);
3984 }
3985 
3986 /*
3987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3988 % %
3989 % %
3990 % %
3991 % R e m o v e I m a g e P r o p e r t y %
3992 % %
3993 % %
3994 % %
3995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3996 %
3997 % RemoveImageProperty() removes a property from the image and returns its
3998 % value.
3999 %
4000 % In this case the ConstantString() value returned should be freed by the
4001 % caller when finished.
4002 %
4003 % The format of the RemoveImageProperty method is:
4004 %
4005 % char *RemoveImageProperty(Image *image,const char *property)
4006 %
4007 % A description of each parameter follows:
4008 %
4009 % o image: the image.
4010 %
4011 % o property: the image property.
4012 %
4013 */
4014 MagickExport char *RemoveImageProperty(Image *image,const char *property)
4015 {
4016  char
4017  *value;
4018 
4019  assert(image != (Image *) NULL);
4020  assert(image->signature == MagickCoreSignature);
4021  if (image->debug != MagickFalse)
4022  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4023  if (image->properties == (void *) NULL)
4024  return((char *) NULL);
4025  value=(char *) RemoveNodeFromSplayTree((SplayTreeInfo *) image->properties,
4026  property);
4027  return(value);
4028 }
4029 
4030 /*
4031 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4032 % %
4033 % %
4034 % %
4035 % R e s e t I m a g e P r o p e r t y I t e r a t o r %
4036 % %
4037 % %
4038 % %
4039 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4040 %
4041 % ResetImagePropertyIterator() resets the image properties iterator. Use it
4042 % in conjunction with GetNextImageProperty() to iterate over all the values
4043 % associated with an image property.
4044 %
4045 % The format of the ResetImagePropertyIterator method is:
4046 %
4047 % ResetImagePropertyIterator(Image *image)
4048 %
4049 % A description of each parameter follows:
4050 %
4051 % o image: the image.
4052 %
4053 */
4055 {
4056  assert(image != (Image *) NULL);
4057  assert(image->signature == MagickCoreSignature);
4058  if (image->debug != MagickFalse)
4059  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4060  if (image->properties == (void *) NULL)
4061  return;
4063 }
4064 
4065 /*
4066 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4067 % %
4068 % %
4069 % %
4070 % S e t I m a g e P r o p e r t y %
4071 % %
4072 % %
4073 % %
4074 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4075 %
4076 % SetImageProperty() saves the given string value either to specific known
4077 % attribute or to a freeform property string.
4078 %
4079 % Attempting to set a property that is normally calculated will produce
4080 % an exception.
4081 %
4082 % The format of the SetImageProperty method is:
4083 %
4084 % MagickBooleanType SetImageProperty(Image *image,const char *property,
4085 % const char *value,ExceptionInfo *exception)
4086 %
4087 % A description of each parameter follows:
4088 %
4089 % o image: the image.
4090 %
4091 % o property: the image property.
4092 %
4093 % o values: the image property values.
4094 %
4095 % o exception: return any errors or warnings in this structure.
4096 %
4097 */
4099  const char *property,const char *value,ExceptionInfo *exception)
4100 {
4102  status;
4103 
4105  flags;
4106 
4107  assert(image != (Image *) NULL);
4108  assert(image->signature == MagickCoreSignature);
4109  if (image->debug != MagickFalse)
4110  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4111  if (image->properties == (void *) NULL)
4113  RelinquishMagickMemory,RelinquishMagickMemory); /* create splay-tree */
4114  if (value == (const char *) NULL)
4115  return(DeleteImageProperty(image,property)); /* delete if NULL */
4116  status=MagickTrue;
4117  if (strlen(property) <= 1)
4118  {
4119  /*
4120  Do not 'set' single letter properties - read only shorthand.
4121  */
4123  "SetReadOnlyProperty","`%s'",property);
4124  return(MagickFalse);
4125  }
4126 
4127  /* FUTURE: binary chars or quotes in key should produce a error */
4128  /* Set attributes with known names or special prefixes
4129  return result is found, or break to set a free form properity
4130  */
4131  switch (*property)
4132  {
4133 #if 0 /* Percent escape's sets values with this prefix: for later use
4134  Throwing an exception causes this setting to fail */
4135  case '8':
4136  {
4137  if (LocaleNCompare("8bim:",property,5) == 0)
4138  {
4140  "SetReadOnlyProperty","`%s'",property);
4141  return(MagickFalse);
4142  }
4143  break;
4144  }
4145 #endif
4146  case 'B':
4147  case 'b':
4148  {
4149  if (LocaleCompare("background",property) == 0)
4150  {
4151  (void) QueryColorCompliance(value,AllCompliance,
4152  &image->background_color,exception);
4153  /* check for FUTURE: value exception?? */
4154  /* also add user input to splay tree */
4155  }
4156  break; /* not an attribute, add as a property */
4157  }
4158  case 'C':
4159  case 'c':
4160  {
4161  if (LocaleCompare("channels",property) == 0)
4162  {
4164  "SetReadOnlyProperty","`%s'",property);
4165  return(MagickFalse);
4166  }
4167  if (LocaleCompare("colorspace",property) == 0)
4168  {
4169  ssize_t
4170  colorspace;
4171 
4173  value);
4174  if (colorspace < 0)
4175  return(MagickFalse); /* FUTURE: value exception?? */
4176  return(SetImageColorspace(image,(ColorspaceType) colorspace,exception));
4177  }
4178  if (LocaleCompare("compose",property) == 0)
4179  {
4180  ssize_t
4181  compose;
4182 
4184  if (compose < 0)
4185  return(MagickFalse); /* FUTURE: value exception?? */
4186  image->compose=(CompositeOperator) compose;
4187  return(MagickTrue);
4188  }
4189  if (LocaleCompare("compress",property) == 0)
4190  {
4191  ssize_t
4192  compression;
4193 
4195  value);
4196  if (compression < 0)
4197  return(MagickFalse); /* FUTURE: value exception?? */
4198  image->compression=(CompressionType) compression;
4199  return(MagickTrue);
4200  }
4201  break; /* not an attribute, add as a property */
4202  }
4203  case 'D':
4204  case 'd':
4205  {
4206  if (LocaleCompare("delay",property) == 0)
4207  {
4208  GeometryInfo
4209  geometry_info;
4210 
4211  flags=ParseGeometry(value,&geometry_info);
4212  if ((flags & GreaterValue) != 0)
4213  {
4214  if (image->delay > (size_t) floor(geometry_info.rho+0.5))
4215  image->delay=(size_t) floor(geometry_info.rho+0.5);
4216  }
4217  else
4218  if ((flags & LessValue) != 0)
4219  {
4220  if (image->delay < (size_t) floor(geometry_info.rho+0.5))
4221  image->delay=(ssize_t)
4222  floor(geometry_info.sigma+0.5);
4223  }
4224  else
4225  image->delay=(size_t) floor(geometry_info.rho+0.5);
4226  if ((flags & SigmaValue) != 0)
4227  image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
4228  return(MagickTrue);
4229  }
4230  if (LocaleCompare("delay_units",property) == 0)
4231  {
4233  "SetReadOnlyProperty","`%s'",property);
4234  return(MagickFalse);
4235  }
4236  if (LocaleCompare("density",property) == 0)
4237  {
4238  GeometryInfo
4239  geometry_info;
4240 
4241  flags=ParseGeometry(value,&geometry_info);
4242  if ((flags & RhoValue) != 0)
4243  image->resolution.x=geometry_info.rho;
4244  image->resolution.y=image->resolution.x;
4245  if ((flags & SigmaValue) != 0)
4246  image->resolution.y=geometry_info.sigma;
4247  return(MagickTrue);
4248  }
4249  if (LocaleCompare("depth",property) == 0)
4250  {
4251  image->depth=StringToUnsignedLong(value);
4252  return(MagickTrue);
4253  }
4254  if (LocaleCompare("dispose",property) == 0)
4255  {
4256  ssize_t
4257  dispose;
4258 
4260  if (dispose < 0)
4261  return(MagickFalse); /* FUTURE: value exception?? */
4262  image->dispose=(DisposeType) dispose;
4263  return(MagickTrue);
4264  }
4265  break; /* not an attribute, add as a property */
4266  }
4267 #if 0 /* Percent escape's sets values with this prefix: for later use
4268  Throwing an exception causes this setting to fail */
4269  case 'E':
4270  case 'e':
4271  {
4272  if (LocaleNCompare("exif:",property,5) == 0)
4273  {
4275  "SetReadOnlyProperty","`%s'",property);
4276  return(MagickFalse);
4277  }
4278  break; /* not an attribute, add as a property */
4279  }
4280  case 'F':
4281  case 'f':
4282  {
4283  if (LocaleNCompare("fx:",property,3) == 0)
4284  {
4286  "SetReadOnlyProperty","`%s'",property);
4287  return(MagickFalse);
4288  }
4289  break; /* not an attribute, add as a property */
4290  }
4291 #endif
4292  case 'G':
4293  case 'g':
4294  {
4295  if (LocaleCompare("gamma",property) == 0)
4296  {
4297  image->gamma=StringToDouble(value,(char **) NULL);
4298  return(MagickTrue);
4299  }
4300  if (LocaleCompare("gravity",property) == 0)
4301  {
4302  ssize_t
4303  gravity;
4304 
4306  if (gravity < 0)
4307  return(MagickFalse); /* FUTURE: value exception?? */
4308  image->gravity=(GravityType) gravity;
4309  return(MagickTrue);
4310  }
4311  break; /* not an attribute, add as a property */
4312  }
4313  case 'H':
4314  case 'h':
4315  {
4316  if (LocaleCompare("height",property) == 0)
4317  {
4319  "SetReadOnlyProperty","`%s'",property);
4320  return(MagickFalse);
4321  }
4322  break; /* not an attribute, add as a property */
4323  }
4324  case 'I':
4325  case 'i':
4326  {
4327  if (LocaleCompare("intensity",property) == 0)
4328  {
4329  ssize_t
4330  intensity;
4331 
4333  if (intensity < 0)
4334  return(MagickFalse);
4335  image->intensity=(PixelIntensityMethod) intensity;
4336  return(MagickTrue);
4337  }
4338  if (LocaleCompare("intent",property) == 0)
4339  {
4340  ssize_t
4341  rendering_intent;
4342 
4344  value);
4345  if (rendering_intent < 0)
4346  return(MagickFalse); /* FUTURE: value exception?? */
4347  image->rendering_intent=(RenderingIntent) rendering_intent;
4348  return(MagickTrue);
4349  }
4350  if (LocaleCompare("interpolate",property) == 0)
4351  {
4352  ssize_t
4353  interpolate;
4354 
4356  value);
4357  if (interpolate < 0)
4358  return(MagickFalse); /* FUTURE: value exception?? */
4359  image->interpolate=(PixelInterpolateMethod) interpolate;
4360  return(MagickTrue);
4361  }
4362 #if 0 /* Percent escape's sets values with this prefix: for later use
4363  Throwing an exception causes this setting to fail */
4364  if (LocaleNCompare("iptc:",property,5) == 0)
4365  {
4367  "SetReadOnlyProperty","`%s'",property);
4368  return(MagickFalse);
4369  }
4370 #endif
4371  break; /* not an attribute, add as a property */
4372  }
4373  case 'K':
4374  case 'k':
4375  if (LocaleCompare("kurtosis",property) == 0)
4376  {
4378  "SetReadOnlyProperty","`%s'",property);
4379  return(MagickFalse);
4380  }
4381  break; /* not an attribute, add as a property */
4382  case 'L':
4383  case 'l':
4384  {
4385  if (LocaleCompare("loop",property) == 0)
4386  {
4387  image->iterations=StringToUnsignedLong(value);
4388  return(MagickTrue);
4389  }
4390  break; /* not an attribute, add as a property */
4391  }
4392  case 'M':
4393  case 'm':
4394  if ((LocaleCompare("magick",property) == 0) ||
4395  (LocaleCompare("max",property) == 0) ||
4396  (LocaleCompare("mean",property) == 0) ||
4397  (LocaleCompare("min",property) == 0) ||
4398  (LocaleCompare("min",property) == 0))
4399  {
4401  "SetReadOnlyProperty","`%s'",property);
4402  return(MagickFalse);
4403  }
4404  break; /* not an attribute, add as a property */
4405  case 'O':
4406  case 'o':
4407  if (LocaleCompare("opaque",property) == 0)
4408  {
4410  "SetReadOnlyProperty","`%s'",property);
4411  return(MagickFalse);
4412  }
4413  break; /* not an attribute, add as a property */
4414  case 'P':
4415  case 'p':
4416  {
4417  if (LocaleCompare("page",property) == 0)
4418  {
4419  char
4420  *geometry;
4421 
4422  geometry=GetPageGeometry(value);
4423  flags=ParseAbsoluteGeometry(geometry,&image->page);
4424  geometry=DestroyString(geometry);
4425  return(MagickTrue);
4426  }
4427 #if 0 /* Percent escape's sets values with this prefix: for later use
4428  Throwing an exception causes this setting to fail */
4429  if (LocaleNCompare("pixel:",property,6) == 0)
4430  {
4432  "SetReadOnlyProperty","`%s'",property);
4433  return(MagickFalse);
4434  }
4435 #endif
4436  if (LocaleCompare("profile",property) == 0)
4437  {
4438  ImageInfo
4439  *image_info;
4440 
4441  StringInfo
4442  *profile;
4443 
4444  image_info=AcquireImageInfo();
4445  (void) CopyMagickString(image_info->filename,value,MagickPathExtent);
4446  (void) SetImageInfo(image_info,1,exception);
4447  profile=FileToStringInfo(image_info->filename,~0UL,exception);
4448  if (profile != (StringInfo *) NULL)
4449  status=SetImageProfile(image,image_info->magick,profile,exception);
4450  image_info=DestroyImageInfo(image_info);
4451  return(MagickTrue);
4452  }
4453  break; /* not an attribute, add as a property */
4454  }
4455  case 'R':
4456  case 'r':
4457  {
4458  if (LocaleCompare("rendering-intent",property) == 0)
4459  {
4460  ssize_t
4461  rendering_intent;
4462 
4464  value);
4465  if (rendering_intent < 0)
4466  return(MagickFalse); /* FUTURE: value exception?? */
4467  image->rendering_intent=(RenderingIntent) rendering_intent;
4468  return(MagickTrue);
4469  }
4470  break; /* not an attribute, add as a property */
4471  }
4472  case 'S':
4473  case 's':
4474  if ((LocaleCompare("size",property) == 0) ||
4475  (LocaleCompare("skewness",property) == 0) ||
4476  (LocaleCompare("scenes",property) == 0) ||
4477  (LocaleCompare("standard-deviation",property) == 0))
4478  {
4480  "SetReadOnlyProperty","`%s'",property);
4481  return(MagickFalse);
4482  }
4483  break; /* not an attribute, add as a property */
4484  case 'T':
4485  case 't':
4486  {
4487  if (LocaleCompare("tile-offset",property) == 0)
4488  {
4489  char
4490  *geometry;
4491 
4492  geometry=GetPageGeometry(value);
4493  flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
4494  geometry=DestroyString(geometry);
4495  return(MagickTrue);
4496  }
4497  break; /* not an attribute, add as a property */
4498  }
4499  case 'U':
4500  case 'u':
4501  {
4502  if (LocaleCompare("units",property) == 0)
4503  {
4504  ssize_t
4505  units;
4506 
4508  if (units < 0)
4509  return(MagickFalse); /* FUTURE: value exception?? */
4510  image->units=(ResolutionType) units;
4511  return(MagickTrue);
4512  }
4513  break; /* not an attribute, add as a property */
4514  }
4515  case 'V':
4516  case 'v':
4517  {
4518  if (LocaleCompare("version",property) == 0)
4519  {
4521  "SetReadOnlyProperty","`%s'",property);
4522  return(MagickFalse);
4523  }
4524  break; /* not an attribute, add as a property */
4525  }
4526  case 'W':
4527  case 'w':
4528  {
4529  if (LocaleCompare("width",property) == 0)
4530  {
4532  "SetReadOnlyProperty","`%s'",property);
4533  return(MagickFalse);
4534  }
4535  break; /* not an attribute, add as a property */
4536  }
4537 #if 0 /* Percent escape's sets values with this prefix: for later use
4538  Throwing an exception causes this setting to fail */
4539  case 'X':
4540  case 'x':
4541  {
4542  if (LocaleNCompare("xmp:",property,4) == 0)
4543  {
4545  "SetReadOnlyProperty","`%s'",property);
4546  return(MagickFalse);
4547  }
4548  break; /* not an attribute, add as a property */
4549  }
4550 #endif
4551  }
4552  /* Default: not an attribute, add as a property */
4553  status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
4554  ConstantString(property),ConstantString(value));
4555  /* FUTURE: error if status is bad? */
4556  return(status);
4557 }
size_t rows
Definition: image.h:172
PixelInfo matte_color
Definition: image.h:357
#define AppendString2Text(string)
PixelIntensityMethod intensity
Definition: image.h:222
MagickExport ssize_t FormatMagickSize(const MagickSizeType size, const MagickBooleanType bi, const char *suffix, const size_t length, char *format)
Definition: string.c:1093
#define EXIF_FMT_SINGLE
MagickExport MagickBooleanType QueryColorname(const Image *magick_unused(image), const PixelInfo *color, const ComplianceType compliance, char *name, ExceptionInfo *exception)
Definition: color.c:2591
MagickExport ImageInfo * AcquireImageInfo(void)
Definition: image.c:343
InterlaceType interlace
Definition: image.h:225
static const char * GetMagickPropertyLetter(ImageInfo *image_info, Image *image, const char letter, ExceptionInfo *exception)
Definition: property.c:2414
MagickExport XMLTreeInfo * DestroyXMLTree(XMLTreeInfo *xml_info)
Definition: xml-tree.c:558
DisposeType dispose
Definition: image.h:237
MagickExport MagickBooleanType AddValueToSplayTree(SplayTreeInfo *splay_tree, const void *key, const void *value)
Definition: splay-tree.c:154
char magick[MagickPathExtent]
Definition: image.h:480
MagickProgressMonitor progress_monitor
Definition: image.h:303
MagickExport char * RemoveImageProperty(Image *image, const char *property)
Definition: property.c:4014
MagickExport MagickBooleanType IsRightsAuthorized(const PolicyDomain domain, const PolicyRights rights, const char *pattern)
Definition: policy.c:594
size_t iterations
Definition: image.h:248
ssize_t ticks_per_second
Definition: image.h:245
static unsigned short ReadPropertyUnsignedShort(const EndianType endian, const unsigned char *buffer)
Definition: property.c:822
FilterType filter
Definition: image.h:219
static unsigned int ReadPropertyUnsignedLong(const EndianType endian, const unsigned char *buffer)
Definition: property.c:773
MagickExport MagickBooleanType DeleteImageOption(ImageInfo *image_info, const char *option)
Definition: option.c:2219
MagickExport void ResetImagePropertyIterator(const Image *image)
Definition: property.c:4054
static unsigned long StringToUnsignedLong(const char *magick_restrict value)
#define EXIF_FMT_SLONG
MagickExport ssize_t ParseCommandOption(const CommandOption option, const MagickBooleanType list, const char *options)
Definition: option.c:2957
#define EXIF_FMT_SSHORT
PixelInfo border_color
Definition: image.h:179
PixelInterpolateMethod
Definition: pixel.h:110
PixelInterpolateMethod interpolate
Definition: image.h:255
MagickPrivate ssize_t FormatLocaleStringList(char *magick_restrict, const size_t, const char *magick_restrict, va_list) magick_attribute((__format__(__printf__
MagickExport XMLTreeInfo * GetNextXMLTreeTag(XMLTreeInfo *xml_info)
Definition: xml-tree.c:744
size_t number_scenes
Definition: image.h:396
double rho
Definition: geometry.h:106
MagickExport MagickStatusType ParseAbsoluteGeometry(const char *geometry, RectangleInfo *region_info)
Definition: geometry.c:702
EndianType endian
Definition: image.h:228
MagickExport MagickBooleanType DeleteImageArtifact(Image *image, const char *artifact)
Definition: artifact.c:198
MagickBooleanType taint
Definition: image.h:169
MagickExport size_t ConcatenateMagickString(char *destination, const char *source, const size_t length)
Definition: string.c:426
static signed int ReadPropertyMSBLong(const unsigned char **p, size_t *length)
Definition: property.c:510
PixelIntensityMethod
Definition: pixel.h:96
MagickBooleanType debug
Definition: image.h:485
static MagickBooleanType SkipXMPValue(const char *value)
Definition: property.c:1727
#define ExtendInterpretText(string_length)
MagickExport MagickBooleanType SetImageArtifact(Image *image, const char *artifact, const char *value)
Definition: artifact.c:445
MagickExport const char * GetImageArtifact(const Image *image, const char *artifact)
Definition: artifact.c:273
MagickRealType red
Definition: pixel.h:191
static MagickBooleanType GetEXIFProperty(const Image *image, const char *property, ExceptionInfo *exception)
Definition: property.c:839
static double StringToDouble(const char *magick_restrict string, char **magick_restrict sentinal)
MagickExport ExceptionInfo * AcquireExceptionInfo(void)
Definition: exception.c:108
MagickExport ssize_t FormatLocaleString(char *magick_restrict string, const size_t length, const char *magick_restrict format,...)
Definition: locale.c:504
ResolutionType units
Definition: image.h:198
static MagickBooleanType GetICCProperty(const Image *image, const char *property, ExceptionInfo *exception)
Definition: property.c:1645
MagickExport MagickBooleanType SignatureImage(Image *image, ExceptionInfo *exception)
Definition: signature.c:466
size_t delay
Definition: image.h:240
char magick[MagickPathExtent]
Definition: image.h:319
#define MAGICKCORE_QUANTUM_DEPTH
Definition: magick-type.h:28
size_t magick_rows
Definition: image.h:324
MagickExport void ResetImageArtifactIterator(const Image *image)
Definition: artifact.c:406
static long StringToLong(const char *magick_restrict value)
MagickRealType alpha
Definition: pixel.h:191
unsigned char * info
Definition: profile.c:128
static char * TraceSVGClippath(const unsigned char *, size_t, const size_t, const size_t)
Definition: property.c:2071
MagickExport const char * GetImageOption(const ImageInfo *image_info, const char *option)
Definition: option.c:2294
MagickExport char * GetPageGeometry(const char *page_geometry)
Definition: geometry.c:361
char * montage
Definition: image.h:201
#define MagickEpsilon
Definition: magick-type.h:110
CompressionType compression
Definition: image.h:160
MagickExport XMLTreeInfo * GetXMLTreeChild(XMLTreeInfo *xml_info, const char *tag)
Definition: xml-tree.c:896
double sigma
Definition: geometry.h:106
ClassType storage_class
Definition: image.h:154
size_t width
Definition: geometry.h:130
static signed int ReadPropertySignedLong(const EndianType endian, const unsigned char *buffer)
Definition: property.c:741
RectangleInfo tile_offset
Definition: image.h:261
MagickExport MagickBooleanType GetImageEntropy(const Image *image, double *entropy, ExceptionInfo *exception)
Definition: statistic.c:1124
#define EXIF_FMT_BYTE
Definition: log.h:52
MagickExport char * FileToString(const char *filename, const size_t extent, ExceptionInfo *exception)
Definition: string.c:1000
#define EXIF_FMT_URATIONAL
MagickExport void GetPixelInfo(const Image *image, PixelInfo *pixel)
Definition: pixel.c:2170
MagickExport const char * GetXMLTreeTag(XMLTreeInfo *xml_info)
Definition: xml-tree.c:1159
EndianType
Definition: quantum.h:28
MagickExport MagickBooleanType SetImageOption(ImageInfo *image_info, const char *option, const char *value)
Definition: option.c:3227
Definition: image.h:151
static signed short ReadPropertySignedShort(const EndianType endian, const unsigned char *buffer)
Definition: property.c:794
static int ReadPropertyByte(const unsigned char **p, size_t *length)
Definition: property.c:498
static char * TracePSClippath(const unsigned char *, size_t)
Definition: property.c:1861
MagickExport MagickBooleanType SetImageGray(Image *image, ExceptionInfo *exception)
Definition: colorspace.c:1214
#define EXIF_FMT_USHORT
double x
Definition: geometry.h:123
#define TAG_GPS_OFFSET
#define MagickCoreSignature
MagickExport unsigned char * GetStringInfoDatum(const StringInfo *string_info)
Definition: string.c:1295
MagickExport MagickBooleanType CloneImageProperties(Image *image, const Image *clone_image)
Definition: property.c:143
#define TAG_INTEROP_OFFSET
MagickExport void GetPathComponent(const char *path, PathType type, char *component)
Definition: utility.c:1213
MagickBooleanType
Definition: magick-type.h:156
size_t scene
Definition: image.h:240
unsigned int MagickStatusType
Definition: magick-type.h:119
MagickExport char * AcquireString(const char *source)
Definition: string.c:129
MagickExport void LocaleLower(char *string)
Definition: locale.c:1493
MagickBooleanType black_point_compensation
Definition: image.h:258
MagickPrivate FxInfo * DestroyFxInfo(FxInfo *)
Definition: fx.c:1048
MagickExport const char * CommandOptionToMnemonic(const CommandOption option, const ssize_t type)
Definition: option.c:2670
MagickExport StringInfo * FileToStringInfo(const char *filename, const size_t extent, ExceptionInfo *exception)
Definition: string.c:1039
static MagickBooleanType GetIPTCProperty(const Image *image, const char *key, ExceptionInfo *exception)
Definition: property.c:431
MagickExport void * AcquireQuantumMemory(const size_t count, const size_t quantum)
Definition: memory.c:533
char filename[MagickPathExtent]
Definition: image.h:480
MagickExport void GetColorTuple(const PixelInfo *pixel, const MagickBooleanType hex, char *tuple)
Definition: color.c:1556
MagickExport int LocaleNCompare(const char *p, const char *q, const size_t length)
Definition: locale.c:1540
double y
Definition: geometry.h:123
MagickPrivate MagickBooleanType FxEvaluateChannelExpression(FxInfo *, const PixelChannel, const ssize_t, const ssize_t, double *, ExceptionInfo *)
Definition: fx.c:3002
GravityType gravity
Definition: image.h:231
MagickExport MagickBooleanType SetImageProperty(Image *image, const char *property, const char *value, ExceptionInfo *exception)
Definition: property.c:4098
MagickExport MagickBooleanType ConcatenateString(char **destination, const char *source)
Definition: string.c:492
MagickExport const StringInfo * GetImageProfile(const Image *image, const char *name)
Definition: profile.c:275
size_t scene
Definition: image.h:396
RectangleInfo page
Definition: image.h:212
MagickExport const char * GetXMLTreeContent(XMLTreeInfo *xml_info)
Definition: xml-tree.c:936
MagickExport void DestroyImageProperties(Image *image)
Definition: property.c:323
size_t magick_columns
Definition: image.h:324
MagickExport SplayTreeInfo * DestroySplayTree(SplayTreeInfo *splay_tree)
Definition: splay-tree.c:682
MagickExport MagickBooleanType GlobExpression(const char *expression, const char *pattern, const MagickBooleanType case_insensitive)
Definition: token.c:352
#define MagickPathExtent
PixelTrait alpha_trait
Definition: image.h:280
MagickExport int GetMagickPrecision(void)
Definition: magick.c:877
MagickRealType blue
Definition: pixel.h:191
MagickExport SplayTreeInfo * NewSplayTree(int(*compare)(const void *, const void *), void *(*relinquish_key)(void *), void *(*relinquish_value)(void *))
Definition: splay-tree.c:1141
#define EXIF_FMT_DOUBLE
MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info, const unsigned int frames, ExceptionInfo *exception)
Definition: image.c:2701
GravityType
Definition: geometry.h:77
char magick_filename[MagickPathExtent]
Definition: image.h:319
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:1064
MagickExport MagickBooleanType LogMagickEvent(const LogEventType type, const char *module, const char *function, const size_t line, const char *format,...)
Definition: log.c:1397
Definition: fx.c:111
MagickExport MagickBooleanType IsPathAccessible(const char *path)
Definition: utility.c:1468
MagickExport const char * GetMagickVersion(size_t *version)
Definition: version.c:567
MagickExport MagickBooleanType SetImageBackgroundColor(Image *image, ExceptionInfo *exception)
Definition: image.c:2413
size_t signature
Definition: image.h:354
size_t columns
Definition: image.h:172
MagickExport const char * GetNextImageProperty(const Image *image)
Definition: property.c:3306
MagickPrivate MagickBooleanType IsGlob(const char *)
Definition: token.c:623
static signed short ReadPropertyMSBShort(const unsigned char **p, size_t *length)
Definition: property.c:550
MagickExport Image * AcquireImage(const ImageInfo *image_info, ExceptionInfo *exception)
Definition: image.c:155
MagickExport MagickBooleanType SubstituteString(char **string, const char *search, const char *replace)
Definition: string.c:2649
#define EXIFMultipleValues(size, format, arg)
ssize_t x
Definition: geometry.h:134
#define WarnNoImageInfoReturn(format, arg)
MagickExport void ResetImageOptionIterator(const ImageInfo *image_info)
Definition: option.c:3188
MagickExport const char * GetMagickCopyright(void)
Definition: version.c:75
size_t height
Definition: geometry.h:130
MagickExport ImageType IdentifyImageType(const Image *image, ExceptionInfo *exception)
Definition: attribute.c:791
MagickExport MagickBooleanType GetImageRange(const Image *image, double *minima, double *maxima, ExceptionInfo *exception)
Definition: statistic.c:1779
MagickExport MagickBooleanType QueryColorCompliance(const char *name, const ComplianceType compliance, PixelInfo *color, ExceptionInfo *exception)
Definition: color.c:2216
MagickExport MagickBooleanType GetImageKurtosis(const Image *image, double *kurtosis, double *skewness, ExceptionInfo *exception)
Definition: statistic.c:1222
MagickExport size_t CopyMagickString(char *destination, const char *source, const size_t length)
Definition: string.c:755
ssize_t offset
Definition: image.h:206
RectangleInfo extract_info
Definition: image.h:212
MagickExport const void * GetValueFromSplayTree(SplayTreeInfo *splay_tree, const void *key)
Definition: splay-tree.c:921
MagickExport MagickBooleanType GetImageMean(const Image *image, double *mean, double *standard_deviation, ExceptionInfo *exception)
Definition: statistic.c:1272
#define EXIF_FMT_STRING
MagickExport MagickBooleanType SetImageExtent(Image *image, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: image.c:2655
MagickExport char * GetNextImageProfile(const Image *image)
Definition: profile.c:314
RenderingIntent
Definition: profile.h:30
#define MagickMax(x, y)
Definition: image-private.h:26
MagickExport MagickBooleanType SetImageProfile(Image *image, const char *name, const StringInfo *profile, ExceptionInfo *exception)
Definition: profile.c:1733
#define EXIF_FMT_SRATIONAL
size_t quality
Definition: image.h:163
#define AppendKeyValue2Text(key, value)
#define MaxDirectoryStack
MagickExport int LocaleCompare(const char *p, const char *q)
Definition: locale.c:1440
DisposeType
Definition: layer.h:27
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
MagickExport size_t GetNumberColors(const Image *image, FILE *file, ExceptionInfo *exception)
Definition: histogram.c:1002
MagickExport char * InterpretImageProperties(ImageInfo *image_info, Image *image, const char *embed_text, ExceptionInfo *exception)
Definition: property.c:3372
MagickExport MagickSizeType GetBlobSize(const Image *image)
Definition: blob.c:1782
char unique[MagickPathExtent]
Definition: image.h:480
MagickExport XMLTreeInfo * GetXMLTreeSibling(XMLTreeInfo *xml_info)
Definition: xml-tree.c:1127
MagickExport ImageInfo * DestroyImageInfo(ImageInfo *image_info)
Definition: image.c:1248
CompressionType
Definition: compress.h:25
ssize_t start_loop
Definition: image.h:252
RenderingIntent rendering_intent
Definition: image.h:192
ErrorInfo error
Definition: image.h:297
MagickExport const void * GetNextKeyInSplayTree(SplayTreeInfo *splay_tree)
Definition: splay-tree.c:769
MagickExport size_t GetImageDepth(const Image *image, ExceptionInfo *exception)
Definition: attribute.c:274
#define EXIFMultipleFractions(size, format, arg1, arg2)
static MagickBooleanType GetXMPProperty(const Image *image, const char *property)
Definition: property.c:1763
MagickExport RectangleInfo GetImageBoundingBox(const Image *image, ExceptionInfo *exception)
Definition: attribute.c:125
MagickExport MagickBooleanType SetImageColorspace(Image *image, const ColorspaceType colorspace, ExceptionInfo *exception)
Definition: colorspace.c:1134
MagickExport ssize_t GetImageIndexInList(const Image *images)
Definition: list.c:641
MagickRealType black
Definition: pixel.h:191
MagickExport char * DestroyString(char *string)
Definition: string.c:823
char * geometry
Definition: image.h:201
MagickExport MagickBooleanType DeleteImageProperty(Image *image, const char *property)
Definition: property.c:288
MagickExport const char * GetImageProperty(const Image *image, const char *property, ExceptionInfo *exception)
Definition: property.c:2240
#define EXIF_FMT_UNDEFINED
MagickExport ImageInfo * CloneImageInfo(const ImageInfo *image_info)
Definition: image.c:937
MagickExport const void * GetRootValueFromSplayTree(SplayTreeInfo *splay_tree)
Definition: splay-tree.c:877
MagickExport MagickStatusType ParseGeometry(const char *geometry, GeometryInfo *geometry_info)
Definition: geometry.c:852
char * directory
Definition: image.h:201
ChromaticityInfo chromaticity
Definition: image.h:189
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
size_t length
Definition: profile.c:125
static MagickBooleanType Get8BIMProperty(const Image *image, const char *key, ExceptionInfo *exception)
Definition: property.c:588
#define MagickMin(x, y)
Definition: image-private.h:27
MagickExport const char * GetNextImageArtifact(const Image *image)
Definition: artifact.c:323
ColorspaceType
Definition: colorspace.h:25
#define EXIF_FMT_SBYTE
MagickExport void ResetSplayTreeIterator(SplayTreeInfo *splay_tree)
Definition: splay-tree.c:1472
MagickExport void * RelinquishMagickMemory(void *memory)
Definition: memory.c:1053
size_t total_colors
Definition: image.h:248
PointInfo resolution
Definition: image.h:209
#define magick_unreferenced(x)
void * properties
Definition: image.h:315
MagickExport MagickBooleanType DefineImageProperty(Image *image, const char *property, ExceptionInfo *exception)
Definition: property.c:241
MagickRealType green
Definition: pixel.h:191
MagickExport char * CloneString(char **destination, const char *source)
Definition: string.c:286
MagickExport const char * GetMagickProperty(ImageInfo *image_info, Image *image, const char *property, ExceptionInfo *exception)
Definition: property.c:2815
CompositeOperator compose
Definition: image.h:234
char * name
Definition: profile.c:122
CompositeOperator
Definition: composite.h:25
ResolutionType
Definition: image.h:89
MagickExport void ResetImageProfileIterator(const Image *image)
Definition: profile.c:1352
#define MagickExport
MagickSizeType extent
Definition: image.h:270
OrientationType orientation
Definition: image.h:166
#define EXIF_FMT_ULONG
double fuzz
Definition: image.h:216
ssize_t y
Definition: geometry.h:134
MagickExport MagickBooleanType FormatImageProperty(Image *image, const char *property, const char *format,...)
Definition: property.c:363
MagickExport char * StringInfoToString(const StringInfo *string_info)
Definition: string.c:1971
PixelInfo transparent_color
Definition: image.h:179
#define WarnNoImageReturn(format, arg)
MagickExport size_t GetStringInfoLength(const StringInfo *string_info)
Definition: string.c:1324
PixelInfo background_color
Definition: image.h:179
MagickExport size_t GetImageListLength(const Image *images)
Definition: list.c:680
MagickExport char * GetNextImageOption(const ImageInfo *image_info)
Definition: option.c:2596
void * client_data
Definition: image.h:306
MagickExport Image * DestroyImage(Image *image)
Definition: image.c:1177
MagickExport char * ConstantString(const char *source)
Definition: string.c:700
static MagickBooleanType ValidateXMPProfile(const char *profile, const size_t length)
Definition: property.c:1740
double gamma
Definition: image.h:186
ColorspaceType colorspace
Definition: image.h:157
MagickExport MagickBooleanType IsImageOpaque(const Image *image, ExceptionInfo *exception)
Definition: attribute.c:915
MagickExport XMLTreeInfo * NewXMLTree(const char *xml, ExceptionInfo *exception)
Definition: xml-tree.c:1952
#define TAG_EXIF_OFFSET
#define QuantumRange
Definition: magick-type.h:83
MagickPrivate FxInfo * AcquireFxInfo(const Image *, const char *, ExceptionInfo *)
MagickBooleanType debug
Definition: image.h:334
MagickExport ExceptionInfo * DestroyExceptionInfo(ExceptionInfo *exception)
Definition: exception.c:411
size_t depth
Definition: image.h:172