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