00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 #include "magick/studio.h"
00044 #include "magick/attribute.h"
00045 #include "magick/cache.h"
00046 #include "magick/color.h"
00047 #include "magick/compare.h"
00048 #include "magick/constitute.h"
00049 #include "magick/draw.h"
00050 #include "magick/effect.h"
00051 #include "magick/exception.h"
00052 #include "magick/exception-private.h"
00053 #include "magick/fx.h"
00054 #include "magick/fx-private.h"
00055 #include "magick/gem.h"
00056 #include "magick/geometry.h"
00057 #include "magick/histogram.h"
00058 #include "magick/image.h"
00059 #include "magick/image.h"
00060 #include "magick/layer.h"
00061 #include "magick/list.h"
00062 #include "magick/memory_.h"
00063 #include "magick/monitor.h"
00064 #include "magick/montage.h"
00065 #include "magick/option.h"
00066 #include "magick/profile.h"
00067 #include "magick/property.h"
00068 #include "magick/quantum.h"
00069 #include "magick/resource_.h"
00070 #include "magick/splay-tree.h"
00071 #include "magick/signature-private.h"
00072 #include "magick/statistic.h"
00073 #include "magick/string_.h"
00074 #include "magick/token.h"
00075 #include "magick/utility.h"
00076 #include "magick/xml-tree.h"
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 MagickExport MagickBooleanType CloneImageProperties(Image *image,
00104 const Image *clone_image)
00105 {
00106 assert(image != (Image *) NULL);
00107 assert(image->signature == MagickSignature);
00108 if (image->debug != MagickFalse)
00109 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00110 assert(clone_image != (const Image *) NULL);
00111 assert(clone_image->signature == MagickSignature);
00112 if (clone_image->debug != MagickFalse)
00113 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
00114 clone_image->filename);
00115 (void) CopyMagickString(image->filename,clone_image->filename,MaxTextExtent);
00116 (void) CopyMagickString(image->magick_filename,clone_image->magick_filename,
00117 MaxTextExtent);
00118 image->compression=clone_image->compression;
00119 image->quality=clone_image->quality;
00120 image->depth=clone_image->depth;
00121 image->background_color=clone_image->background_color;
00122 image->border_color=clone_image->border_color;
00123 image->matte_color=clone_image->matte_color;
00124 image->transparent_color=clone_image->transparent_color;
00125 image->gamma=clone_image->gamma;
00126 image->chromaticity=clone_image->chromaticity;
00127 image->rendering_intent=clone_image->rendering_intent;
00128 image->black_point_compensation=clone_image->black_point_compensation;
00129 image->units=clone_image->units;
00130 image->montage=(char *) NULL;
00131 image->directory=(char *) NULL;
00132 (void) CloneString(&image->geometry,clone_image->geometry);
00133 image->offset=clone_image->offset;
00134 image->x_resolution=clone_image->x_resolution;
00135 image->y_resolution=clone_image->y_resolution;
00136 image->page=clone_image->page;
00137 image->tile_offset=clone_image->tile_offset;
00138 image->extract_info=clone_image->extract_info;
00139 image->bias=clone_image->bias;
00140 image->filter=clone_image->filter;
00141 image->blur=clone_image->blur;
00142 image->fuzz=clone_image->fuzz;
00143 image->interlace=clone_image->interlace;
00144 image->interpolate=clone_image->interpolate;
00145 image->endian=clone_image->endian;
00146 image->gravity=clone_image->gravity;
00147 image->compose=clone_image->compose;
00148 image->scene=clone_image->scene;
00149 image->orientation=clone_image->orientation;
00150 image->dispose=clone_image->dispose;
00151 image->delay=clone_image->delay;
00152 image->ticks_per_second=clone_image->ticks_per_second;
00153 image->iterations=clone_image->iterations;
00154 image->total_colors=clone_image->total_colors;
00155 image->taint=clone_image->taint;
00156 image->progress_monitor=clone_image->progress_monitor;
00157 image->client_data=clone_image->client_data;
00158 image->start_loop=clone_image->start_loop;
00159 image->error=clone_image->error;
00160 image->signature=clone_image->signature;
00161 if (clone_image->properties != (void *) NULL)
00162 {
00163 if (image->properties != (void *) NULL)
00164 DestroyImageProperties(image);
00165 image->properties=CloneSplayTree((SplayTreeInfo *)
00166 clone_image->properties,(void *(*)(void *)) ConstantString,
00167 (void *(*)(void *)) ConstantString);
00168 }
00169 return(MagickTrue);
00170 }
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197 MagickExport MagickBooleanType DefineImageProperty(Image *image,
00198 const char *property)
00199 {
00200 char
00201 key[MaxTextExtent],
00202 value[MaxTextExtent];
00203
00204 register char
00205 *p;
00206
00207 assert(image != (Image *) NULL);
00208 assert(property != (const char *) NULL);
00209 (void) CopyMagickString(key,property,MaxTextExtent-1);
00210 for (p=key; *p != '\0'; p++)
00211 if (*p == '=')
00212 break;
00213 *value='\0';
00214 if (*p == '=')
00215 (void) CopyMagickString(value,p+1,MaxTextExtent);
00216 *p='\0';
00217 return(SetImageProperty(image,key,value));
00218 }
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244 MagickExport MagickBooleanType DeleteImageProperty(Image *image,
00245 const char *property)
00246 {
00247 assert(image != (Image *) NULL);
00248 assert(image->signature == MagickSignature);
00249 if (image->debug != MagickFalse)
00250 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
00251 image->filename);
00252 if (image->properties == (void *) NULL)
00253 return(MagickFalse);
00254 return(DeleteNodeFromSplayTree((SplayTreeInfo *) image->properties,property));
00255 }
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280 MagickExport void DestroyImageProperties(Image *image)
00281 {
00282 assert(image != (Image *) NULL);
00283 assert(image->signature == MagickSignature);
00284 if (image->debug != MagickFalse)
00285 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
00286 image->filename);
00287 if (image->properties != (void *) NULL)
00288 image->properties=(void *) DestroySplayTree((SplayTreeInfo *)
00289 image->properties);
00290 }
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322 MagickExport MagickBooleanType FormatImagePropertyList(Image *image,
00323 const char *property,const char *format,va_list operands)
00324 {
00325 char
00326 value[MaxTextExtent];
00327
00328 int
00329 n;
00330
00331 #if defined(MAGICKCORE_HAVE_VSNPRINTF)
00332 n=vsnprintf(value,MaxTextExtent,format,operands);
00333 #else
00334 n=vsprintf(value,format,operands);
00335 #endif
00336 if (n < 0)
00337 value[MaxTextExtent-1]='\0';
00338 return(SetImageProperty(image,property,value));
00339 }
00340
00341 MagickExport MagickBooleanType FormatImageProperty(Image *image,
00342 const char *property,const char *format,...)
00343 {
00344 MagickBooleanType
00345 status;
00346
00347 va_list
00348 operands;
00349
00350 va_start(operands,format);
00351 status=FormatImagePropertyList(image,property,format,operands);
00352 va_end(operands);
00353 return(status);
00354 }
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381 static char
00382 *TracePSClippath(const unsigned char *,size_t,const unsigned long,
00383 const unsigned long),
00384 *TraceSVGClippath(const unsigned char *,size_t,const unsigned long,
00385 const unsigned long);
00386
00387 static MagickBooleanType GetIPTCProperty(const Image *image,const char *key)
00388 {
00389 char
00390 *attribute,
00391 *message;
00392
00393 const StringInfo
00394 *profile;
00395
00396 long
00397 count,
00398 dataset,
00399 record;
00400
00401 register long
00402 i;
00403
00404 size_t
00405 length;
00406
00407 profile=GetImageProfile(image,"iptc");
00408 if (profile == (StringInfo *) NULL)
00409 profile=GetImageProfile(image,"8bim");
00410 if (profile == (StringInfo *) NULL)
00411 return(MagickFalse);
00412 count=sscanf(key,"IPTC:%ld:%ld",&dataset,&record);
00413 if (count != 2)
00414 return(MagickFalse);
00415 attribute=(char *) NULL;
00416 for (i=0; i < (long) GetStringInfoLength(profile); i+=(long) length)
00417 {
00418 length=1;
00419 if ((long) GetStringInfoDatum(profile)[i] != 0x1c)
00420 continue;
00421 length=(size_t) (GetStringInfoDatum(profile)[i+3] << 8);
00422 length|=GetStringInfoDatum(profile)[i+4];
00423 if (((long) GetStringInfoDatum(profile)[i+1] == dataset) &&
00424 ((long) GetStringInfoDatum(profile)[i+2] == record))
00425 {
00426 message=(char *) NULL;
00427 if (~length >= 1)
00428 message=(char *) AcquireQuantumMemory(length+1UL,sizeof(*message));
00429 if (message != (char *) NULL)
00430 {
00431 (void) CopyMagickString(message,(char *) GetStringInfoDatum(
00432 profile)+i+5,length+1);
00433 (void) ConcatenateString(&attribute,message);
00434 (void) ConcatenateString(&attribute,";");
00435 message=DestroyString(message);
00436 }
00437 }
00438 i+=5;
00439 }
00440 if ((attribute == (char *) NULL) || (*attribute == ';'))
00441 {
00442 if (attribute != (char *) NULL)
00443 attribute=DestroyString(attribute);
00444 return(MagickFalse);
00445 }
00446 attribute[strlen(attribute)-1]='\0';
00447 (void) SetImageProperty((Image *) image,key,(const char *) attribute);
00448 attribute=DestroyString(attribute);
00449 return(MagickTrue);
00450 }
00451
00452 static inline long MagickMax(const long x,const long y)
00453 {
00454 if (x > y)
00455 return(x);
00456 return(y);
00457 }
00458
00459 static inline int ReadPropertyByte(const unsigned char **p,size_t *length)
00460 {
00461 int
00462 c;
00463
00464 if (*length < 1)
00465 return(EOF);
00466 c=(int) (*(*p)++);
00467 (*length)--;
00468 return(c);
00469 }
00470
00471 static inline unsigned long ReadPropertyMSBLong(const unsigned char **p,
00472 size_t *length)
00473 {
00474 int
00475 c;
00476
00477 register long
00478 i;
00479
00480 unsigned char
00481 buffer[4];
00482
00483 unsigned long
00484 value;
00485
00486 if (*length < 4)
00487 return(~0UL);
00488 for (i=0; i < 4; i++)
00489 {
00490 c=(int) (*(*p)++);
00491 (*length)--;
00492 buffer[i]=(unsigned char) c;
00493 }
00494 value=(unsigned long) (buffer[0] << 24);
00495 value|=buffer[1] << 16;
00496 value|=buffer[2] << 8;
00497 value|=buffer[3];
00498 return(value & 0xffffffff);
00499 }
00500
00501 static inline unsigned short ReadPropertyMSBShort(const unsigned char **p,
00502 size_t *length)
00503 {
00504 int
00505 c;
00506
00507 register long
00508 i;
00509
00510 unsigned char
00511 buffer[2];
00512
00513 unsigned short
00514 value;
00515
00516 if (*length < 2)
00517 return((unsigned short) ~0U);
00518 for (i=0; i < 2; i++)
00519 {
00520 c=(int) (*(*p)++);
00521 (*length)--;
00522 buffer[i]=(unsigned char) c;
00523 }
00524 value=(unsigned short) (buffer[0] << 8);
00525 value|=buffer[1];
00526 return((unsigned short) (value & 0xffff));
00527 }
00528
00529 static MagickBooleanType Get8BIMProperty(const Image *image,const char *key)
00530 {
00531 char
00532 *attribute,
00533 format[MaxTextExtent],
00534 name[MaxTextExtent],
00535 *resource;
00536
00537 const StringInfo
00538 *profile;
00539
00540 const unsigned char
00541 *info;
00542
00543 long
00544 id,
00545 start,
00546 stop,
00547 sub_number;
00548
00549 MagickBooleanType
00550 status;
00551
00552 register long
00553 i;
00554
00555 ssize_t
00556 count;
00557
00558 size_t
00559 length;
00560
00561
00562
00563
00564 profile=GetImageProfile(image,"8bim");
00565 if (profile == (StringInfo *) NULL)
00566 return(MagickFalse);
00567 count=(ssize_t) sscanf(key,"8BIM:%ld,%ld:%[^\n]\n%[^\n]",&start,&stop,name,
00568 format);
00569 if ((count != 2) && (count != 3) && (count != 4))
00570 return(MagickFalse);
00571 if (count < 4)
00572 (void) CopyMagickString(format,"SVG",MaxTextExtent);
00573 if (count < 3)
00574 *name='\0';
00575 sub_number=1;
00576 if (*name == '#')
00577 sub_number=atol(&name[1]);
00578 sub_number=MagickMax(sub_number,1L);
00579 resource=(char *) NULL;
00580 status=MagickFalse;
00581 length=GetStringInfoLength(profile);
00582 info=GetStringInfoDatum(profile);
00583 while ((length > 0) && (status == MagickFalse))
00584 {
00585 if (ReadPropertyByte(&info,&length) != (unsigned char) '8')
00586 continue;
00587 if (ReadPropertyByte(&info,&length) != (unsigned char) 'B')
00588 continue;
00589 if (ReadPropertyByte(&info,&length) != (unsigned char) 'I')
00590 continue;
00591 if (ReadPropertyByte(&info,&length) != (unsigned char) 'M')
00592 continue;
00593 id=(long) ReadPropertyMSBShort(&info,&length);
00594 if (id < start)
00595 continue;
00596 if (id > stop)
00597 continue;
00598 if (resource != (char *) NULL)
00599 resource=DestroyString(resource);
00600 count=(ssize_t) ReadPropertyByte(&info,&length);
00601 if ((count != 0) && ((size_t) count <= length))
00602 {
00603 resource=(char *) NULL;
00604 if (~(1UL*count) >= MaxTextExtent)
00605 resource=(char *) AcquireQuantumMemory((size_t) count+MaxTextExtent,
00606 sizeof(*resource));
00607 if (resource != (char *) NULL)
00608 {
00609 for (i=0; i < (long) count; i++)
00610 resource[i]=(char) ReadPropertyByte(&info,&length);
00611 resource[count]='\0';
00612 }
00613 }
00614 if ((count & 0x01) == 0)
00615 (void) ReadPropertyByte(&info,&length);
00616 count=(ssize_t) ReadPropertyMSBLong(&info,&length);
00617 if ((*name != '\0') && (*name != '#'))
00618 if ((resource == (char *) NULL) || (LocaleCompare(name,resource) != 0))
00619 {
00620
00621
00622
00623 info+=count;
00624 length-=count;
00625 continue;
00626 }
00627 if ((*name == '#') && (sub_number != 1))
00628 {
00629
00630
00631
00632 sub_number--;
00633 info+=count;
00634 length-=count;
00635 continue;
00636 }
00637
00638
00639
00640 attribute=(char *) NULL;
00641 if (~(1UL*count) >= MaxTextExtent)
00642 attribute=(char *) AcquireQuantumMemory((size_t) count+MaxTextExtent,
00643 sizeof(*attribute));
00644 if (attribute != (char *) NULL)
00645 {
00646 (void) CopyMagickMemory(attribute,(char *) info,(size_t) count);
00647 attribute[count]='\0';
00648 info+=count;
00649 length-=count;
00650 if ((id <= 1999) || (id >= 2999))
00651 (void) SetImageProperty((Image *) image,key,(const char *)
00652 attribute);
00653 else
00654 {
00655 char
00656 *path;
00657
00658 if (LocaleCompare(format,"svg") == 0)
00659 path=TraceSVGClippath((unsigned char *) attribute,(size_t) count,
00660 image->columns,image->rows);
00661 else
00662 path=TracePSClippath((unsigned char *) attribute,(size_t) count,
00663 image->columns,image->rows);
00664 (void) SetImageProperty((Image *) image,key,(const char *) path);
00665 path=DestroyString(path);
00666 }
00667 attribute=DestroyString(attribute);
00668 status=MagickTrue;
00669 }
00670 }
00671 if (resource != (char *) NULL)
00672 resource=DestroyString(resource);
00673 return(status);
00674 }
00675
00676 static inline unsigned short ReadPropertyShort(const EndianType endian,
00677 const unsigned char *buffer)
00678 {
00679 unsigned short
00680 value;
00681
00682 if (endian == MSBEndian)
00683 {
00684 value=(unsigned short) ((((unsigned char *) buffer)[0] << 8) |
00685 ((unsigned char *) buffer)[1]);
00686 return((unsigned short) (value & 0xffff));
00687 }
00688 value=(unsigned short) ((buffer[1] << 8) | buffer[0]);
00689 return((unsigned short) (value & 0xffff));
00690 }
00691
00692 static inline unsigned long ReadPropertyLong(const EndianType endian,
00693 const unsigned char *buffer)
00694 {
00695 unsigned long
00696 value;
00697
00698 if (endian == MSBEndian)
00699 {
00700 value=(unsigned long) ((buffer[0] << 24) | (buffer[1] << 16) |
00701 (buffer[2] << 8) | buffer[3]);
00702 return((unsigned long) (value & 0xffffffff));
00703 }
00704 value=(unsigned long) ((buffer[3] << 24) | (buffer[2] << 16) |
00705 (buffer[1] << 8 ) | (buffer[0]));
00706 return((unsigned long) (value & 0xffffffff));
00707 }
00708
00709 static MagickBooleanType GetEXIFProperty(const Image *image,
00710 const char *property)
00711 {
00712 #define MaxDirectoryStack 16
00713 #define EXIF_DELIMITER "\n"
00714 #define EXIF_NUM_FORMATS 12
00715 #define EXIF_FMT_BYTE 1
00716 #define EXIF_FMT_STRING 2
00717 #define EXIF_FMT_USHORT 3
00718 #define EXIF_FMT_ULONG 4
00719 #define EXIF_FMT_URATIONAL 5
00720 #define EXIF_FMT_SBYTE 6
00721 #define EXIF_FMT_UNDEFINED 7
00722 #define EXIF_FMT_SSHORT 8
00723 #define EXIF_FMT_SLONG 9
00724 #define EXIF_FMT_SRATIONAL 10
00725 #define EXIF_FMT_SINGLE 11
00726 #define EXIF_FMT_DOUBLE 12
00727 #define TAG_EXIF_OFFSET 0x8769
00728 #define TAG_GPS_OFFSET 0x8825
00729 #define TAG_INTEROP_OFFSET 0xa005
00730
00731 #define EXIFMultipleValues(size, format, arg) \
00732 { \
00733 long \
00734 component; \
00735 \
00736 size_t \
00737 length; \
00738 \
00739 unsigned char \
00740 *p1; \
00741 \
00742 length=0; \
00743 p1=p; \
00744 for (component=0; component < components; component++) \
00745 { \
00746 length+=FormatMagickString(buffer+length,MaxTextExtent-length, \
00747 format", ",arg); \
00748 if (length >= MaxTextExtent - 1) \
00749 length=MaxTextExtent-1; \
00750 p1+=size; \
00751 } \
00752 if (length > 1) \
00753 buffer[length-2]='\0'; \
00754 value=AcquireString(buffer); \
00755 }
00756
00757 #define EXIFMultipleFractions(size, format, arg1, arg2) \
00758 { \
00759 long \
00760 component; \
00761 \
00762 size_t \
00763 length; \
00764 \
00765 unsigned char \
00766 *p1; \
00767 \
00768 length=0; \
00769 p1=p; \
00770 for (component=0; component < components; component++) \
00771 { \
00772 length+=FormatMagickString(buffer+length,MaxTextExtent-length, \
00773 format", ",arg1, arg2); \
00774 if (length >= MaxTextExtent - 1) \
00775 length=MaxTextExtent-1; \
00776 p1+=size; \
00777 } \
00778 if (length > 1) \
00779 buffer[length-2]='\0'; \
00780 value=AcquireString(buffer); \
00781 }
00782
00783 typedef struct _DirectoryInfo
00784 {
00785 const unsigned char
00786 *directory;
00787
00788 unsigned long
00789 entry,
00790 offset;
00791 } DirectoryInfo;
00792
00793 typedef struct _TagInfo
00794 {
00795 unsigned long
00796 tag;
00797
00798 const char
00799 *description;
00800 } TagInfo;
00801
00802 static TagInfo
00803 EXIFTag[] =
00804 {
00805 { 0x001, "exif:InteroperabilityIndex" },
00806 { 0x002, "exif:InteroperabilityVersion" },
00807 { 0x100, "exif:ImageWidth" },
00808 { 0x101, "exif:ImageLength" },
00809 { 0x102, "exif:BitsPerSample" },
00810 { 0x103, "exif:Compression" },
00811 { 0x106, "exif:PhotometricInterpretation" },
00812 { 0x10a, "exif:FillOrder" },
00813 { 0x10d, "exif:DocumentName" },
00814 { 0x10e, "exif:ImageDescription" },
00815 { 0x10f, "exif:Make" },
00816 { 0x110, "exif:Model" },
00817 { 0x111, "exif:StripOffsets" },
00818 { 0x112, "exif:Orientation" },
00819 { 0x115, "exif:SamplesPerPixel" },
00820 { 0x116, "exif:RowsPerStrip" },
00821 { 0x117, "exif:StripByteCounts" },
00822 { 0x11a, "exif:XResolution" },
00823 { 0x11b, "exif:YResolution" },
00824 { 0x11c, "exif:PlanarConfiguration" },
00825 { 0x11d, "exif:PageName" },
00826 { 0x11e, "exif:XPosition" },
00827 { 0x11f, "exif:YPosition" },
00828 { 0x118, "exif:MinSampleValue" },
00829 { 0x119, "exif:MaxSampleValue" },
00830 { 0x120, "exif:FreeOffsets" },
00831 { 0x121, "exif:FreeByteCounts" },
00832 { 0x122, "exif:GrayResponseUnit" },
00833 { 0x123, "exif:GrayResponseCurve" },
00834 { 0x124, "exif:T4Options" },
00835 { 0x125, "exif:T6Options" },
00836 { 0x128, "exif:ResolutionUnit" },
00837 { 0x12d, "exif:TransferFunction" },
00838 { 0x131, "exif:Software" },
00839 { 0x132, "exif:DateTime" },
00840 { 0x13b, "exif:Artist" },
00841 { 0x13e, "exif:WhitePoint" },
00842 { 0x13f, "exif:PrimaryChromaticities" },
00843 { 0x140, "exif:ColorMap" },
00844 { 0x141, "exif:HalfToneHints" },
00845 { 0x142, "exif:TileWidth" },
00846 { 0x143, "exif:TileLength" },
00847 { 0x144, "exif:TileOffsets" },
00848 { 0x145, "exif:TileByteCounts" },
00849 { 0x14a, "exif:SubIFD" },
00850 { 0x14c, "exif:InkSet" },
00851 { 0x14d, "exif:InkNames" },
00852 { 0x14e, "exif:NumberOfInks" },
00853 { 0x150, "exif:DotRange" },
00854 { 0x151, "exif:TargetPrinter" },
00855 { 0x152, "exif:ExtraSample" },
00856 { 0x153, "exif:SampleFormat" },
00857 { 0x154, "exif:SMinSampleValue" },
00858 { 0x155, "exif:SMaxSampleValue" },
00859 { 0x156, "exif:TransferRange" },
00860 { 0x157, "exif:ClipPath" },
00861 { 0x158, "exif:XClipPathUnits" },
00862 { 0x159, "exif:YClipPathUnits" },
00863 { 0x15a, "exif:Indexed" },
00864 { 0x15b, "exif:JPEGTables" },
00865 { 0x15f, "exif:OPIProxy" },
00866 { 0x200, "exif:JPEGProc" },
00867 { 0x201, "exif:JPEGInterchangeFormat" },
00868 { 0x202, "exif:JPEGInterchangeFormatLength" },
00869 { 0x203, "exif:JPEGRestartInterval" },
00870 { 0x205, "exif:JPEGLosslessPredictors" },
00871 { 0x206, "exif:JPEGPointTransforms" },
00872 { 0x207, "exif:JPEGQTables" },
00873 { 0x208, "exif:JPEGDCTables" },
00874 { 0x209, "exif:JPEGACTables" },
00875 { 0x211, "exif:YCbCrCoefficients" },
00876 { 0x212, "exif:YCbCrSubSampling" },
00877 { 0x213, "exif:YCbCrPositioning" },
00878 { 0x214, "exif:ReferenceBlackWhite" },
00879 { 0x2bc, "exif:ExtensibleMetadataPlatform" },
00880 { 0x301, "exif:Gamma" },
00881 { 0x302, "exif:ICCProfileDescriptor" },
00882 { 0x303, "exif:SRGBRenderingIntent" },
00883 { 0x320, "exif:ImageTitle" },
00884 { 0x5001, "exif:ResolutionXUnit" },
00885 { 0x5002, "exif:ResolutionYUnit" },
00886 { 0x5003, "exif:ResolutionXLengthUnit" },
00887 { 0x5004, "exif:ResolutionYLengthUnit" },
00888 { 0x5005, "exif:PrintFlags" },
00889 { 0x5006, "exif:PrintFlagsVersion" },
00890 { 0x5007, "exif:PrintFlagsCrop" },
00891 { 0x5008, "exif:PrintFlagsBleedWidth" },
00892 { 0x5009, "exif:PrintFlagsBleedWidthScale" },
00893 { 0x500A, "exif:HalftoneLPI" },
00894 { 0x500B, "exif:HalftoneLPIUnit" },
00895 { 0x500C, "exif:HalftoneDegree" },
00896 { 0x500D, "exif:HalftoneShape" },
00897 { 0x500E, "exif:HalftoneMisc" },
00898 { 0x500F, "exif:HalftoneScreen" },
00899 { 0x5010, "exif:JPEGQuality" },
00900 { 0x5011, "exif:GridSize" },
00901 { 0x5012, "exif:ThumbnailFormat" },
00902 { 0x5013, "exif:ThumbnailWidth" },
00903 { 0x5014, "exif:ThumbnailHeight" },
00904 { 0x5015, "exif:ThumbnailColorDepth" },
00905 { 0x5016, "exif:ThumbnailPlanes" },
00906 { 0x5017, "exif:ThumbnailRawBytes" },
00907 { 0x5018, "exif:ThumbnailSize" },
00908 { 0x5019, "exif:ThumbnailCompressedSize" },
00909 { 0x501a, "exif:ColorTransferFunction" },
00910 { 0x501b, "exif:ThumbnailData" },
00911 { 0x5020, "exif:ThumbnailImageWidth" },
00912 { 0x5021, "exif:ThumbnailImageHeight" },
00913 { 0x5022, "exif:ThumbnailBitsPerSample" },
00914 { 0x5023, "exif:ThumbnailCompression" },
00915 { 0x5024, "exif:ThumbnailPhotometricInterp" },
00916 { 0x5025, "exif:ThumbnailImageDescription" },
00917 { 0x5026, "exif:ThumbnailEquipMake" },
00918 { 0x5027, "exif:ThumbnailEquipModel" },
00919 { 0x5028, "exif:ThumbnailStripOffsets" },
00920 { 0x5029, "exif:ThumbnailOrientation" },
00921 { 0x502a, "exif:ThumbnailSamplesPerPixel" },
00922 { 0x502b, "exif:ThumbnailRowsPerStrip" },
00923 { 0x502c, "exif:ThumbnailStripBytesCount" },
00924 { 0x502d, "exif:ThumbnailResolutionX" },
00925 { 0x502e, "exif:ThumbnailResolutionY" },
00926 { 0x502f, "exif:ThumbnailPlanarConfig" },
00927 { 0x5030, "exif:ThumbnailResolutionUnit" },
00928 { 0x5031, "exif:ThumbnailTransferFunction" },
00929 { 0x5032, "exif:ThumbnailSoftwareUsed" },
00930 { 0x5033, "exif:ThumbnailDateTime" },
00931 { 0x5034, "exif:ThumbnailArtist" },
00932 { 0x5035, "exif:ThumbnailWhitePoint" },
00933 { 0x5036, "exif:ThumbnailPrimaryChromaticities" },
00934 { 0x5037, "exif:ThumbnailYCbCrCoefficients" },
00935 { 0x5038, "exif:ThumbnailYCbCrSubsampling" },
00936 { 0x5039, "exif:ThumbnailYCbCrPositioning" },
00937 { 0x503A, "exif:ThumbnailRefBlackWhite" },
00938 { 0x503B, "exif:ThumbnailCopyRight" },
00939 { 0x5090, "exif:LuminanceTable" },
00940 { 0x5091, "exif:ChrominanceTable" },
00941 { 0x5100, "exif:FrameDelay" },
00942 { 0x5101, "exif:LoopCount" },
00943 { 0x5110, "exif:PixelUnit" },
00944 { 0x5111, "exif:PixelPerUnitX" },
00945 { 0x5112, "exif:PixelPerUnitY" },
00946 { 0x5113, "exif:PaletteHistogram" },
00947 { 0x1000, "exif:RelatedImageFileFormat" },
00948 { 0x1001, "exif:RelatedImageLength" },
00949 { 0x1002, "exif:RelatedImageWidth" },
00950 { 0x800d, "exif:ImageID" },
00951 { 0x80e3, "exif:Matteing" },
00952 { 0x80e4, "exif:DataType" },
00953 { 0x80e5, "exif:ImageDepth" },
00954 { 0x80e6, "exif:TileDepth" },
00955 { 0x828d, "exif:CFARepeatPatternDim" },
00956 { 0x828e, "exif:CFAPattern2" },
00957 { 0x828f, "exif:BatteryLevel" },
00958 { 0x8298, "exif:Copyright" },
00959 { 0x829a, "exif:ExposureTime" },
00960 { 0x829d, "exif:FNumber" },
00961 { 0x83bb, "exif:IPTC/NAA" },
00962 { 0x84e3, "exif:IT8RasterPadding" },
00963 { 0x84e5, "exif:IT8ColorTable" },
00964 { 0x8649, "exif:ImageResourceInformation" },
00965 { 0x8769, "exif:ExifOffset" },
00966 { 0x8773, "exif:InterColorProfile" },
00967 { 0x8822, "exif:ExposureProgram" },
00968 { 0x8824, "exif:SpectralSensitivity" },
00969 { 0x8825, "exif:GPSInfo" },
00970 { 0x8827, "exif:ISOSpeedRatings" },
00971 { 0x8828, "exif:OECF" },
00972 { 0x8829, "exif:Interlace" },
00973 { 0x882a, "exif:TimeZoneOffset" },
00974 { 0x882b, "exif:SelfTimerMode" },
00975 { 0x9000, "exif:ExifVersion" },
00976 { 0x9003, "exif:DateTimeOriginal" },
00977 { 0x9004, "exif:DateTimeDigitized" },
00978 { 0x9101, "exif:ComponentsConfiguration" },
00979 { 0x9102, "exif:CompressedBitsPerPixel" },
00980 { 0x9201, "exif:ShutterSpeedValue" },
00981 { 0x9202, "exif:ApertureValue" },
00982 { 0x9203, "exif:BrightnessValue" },
00983 { 0x9204, "exif:ExposureBiasValue" },
00984 { 0x9205, "exif:MaxApertureValue" },
00985 { 0x9206, "exif:SubjectDistance" },
00986 { 0x9207, "exif:MeteringMode" },
00987 { 0x9208, "exif:LightSource" },
00988 { 0x9209, "exif:Flash" },
00989 { 0x920a, "exif:FocalLength" },
00990 { 0x920b, "exif:FlashEnergy" },
00991 { 0x920c, "exif:SpatialFrequencyResponse" },
00992 { 0x920d, "exif:Noise" },
00993 { 0x9211, "exif:ImageNumber" },
00994 { 0x9212, "exif:SecurityClassification" },
00995 { 0x9213, "exif:ImageHistory" },
00996 { 0x9214, "exif:SubjectArea" },
00997 { 0x9215, "exif:ExposureIndex" },
00998 { 0x9216, "exif:TIFF-EPStandardID" },
00999 { 0x927c, "exif:MakerNote" },
01000 { 0x9C9b, "exif:WinXP-Title" },
01001 { 0x9C9c, "exif:WinXP-Comments" },
01002 { 0x9C9d, "exif:WinXP-Author" },
01003 { 0x9C9e, "exif:WinXP-Keywords" },
01004 { 0x9C9f, "exif:WinXP-Subject" },
01005 { 0x9286, "exif:UserComment" },
01006 { 0x9290, "exif:SubSecTime" },
01007 { 0x9291, "exif:SubSecTimeOriginal" },
01008 { 0x9292, "exif:SubSecTimeDigitized" },
01009 { 0xa000, "exif:FlashPixVersion" },
01010 { 0xa001, "exif:ColorSpace" },
01011 { 0xa002, "exif:ExifImageWidth" },
01012 { 0xa003, "exif:ExifImageLength" },
01013 { 0xa004, "exif:RelatedSoundFile" },
01014 { 0xa005, "exif:InteroperabilityOffset" },
01015 { 0xa20b, "exif:FlashEnergy" },
01016 { 0xa20c, "exif:SpatialFrequencyResponse" },
01017 { 0xa20d, "exif:Noise" },
01018 { 0xa20e, "exif:FocalPlaneXResolution" },
01019 { 0xa20f, "exif:FocalPlaneYResolution" },
01020 { 0xa210, "exif:FocalPlaneResolutionUnit" },
01021 { 0xa214, "exif:SubjectLocation" },
01022 { 0xa215, "exif:ExposureIndex" },
01023 { 0xa216, "exif:TIFF/EPStandardID" },
01024 { 0xa217, "exif:SensingMethod" },
01025 { 0xa300, "exif:FileSource" },
01026 { 0xa301, "exif:SceneType" },
01027 { 0xa302, "exif:CFAPattern" },
01028 { 0xa401, "exif:CustomRendered" },
01029 { 0xa402, "exif:ExposureMode" },
01030 { 0xa403, "exif:WhiteBalance" },
01031 { 0xa404, "exif:DigitalZoomRatio" },
01032 { 0xa405, "exif:FocalLengthIn35mmFilm" },
01033 { 0xa406, "exif:SceneCaptureType" },
01034 { 0xa407, "exif:GainControl" },
01035 { 0xa408, "exif:Contrast" },
01036 { 0xa409, "exif:Saturation" },
01037 { 0xa40a, "exif:Sharpness" },
01038 { 0xa40b, "exif:DeviceSettingDescription" },
01039 { 0xa40c, "exif:SubjectDistanceRange" },
01040 { 0xa420, "exif:ImageUniqueID" },
01041 { 0xc4a5, "exif:PrintImageMatching" },
01042 { 0x10000, "exif:GPSVersionID" },
01043 { 0x10001, "exif:GPSLatitudeRef" },
01044 { 0x10002, "exif:GPSLatitude" },
01045 { 0x10003, "exif:GPSLongitudeRef" },
01046 { 0x10004, "exif:GPSLongitude" },
01047 { 0x10005, "exif:GPSAltitudeRef" },
01048 { 0x10006, "exif:GPSAltitude" },
01049 { 0x10007, "exif:GPSTimeStamp" },
01050 { 0x10008, "exif:GPSSatellites" },
01051 { 0x10009, "exif:GPSStatus" },
01052 { 0x1000a, "exif:GPSMeasureMode" },
01053 { 0x1000b, "exif:GPSDop" },
01054 { 0x1000c, "exif:GPSSpeedRef" },
01055 { 0x1000d, "exif:GPSSpeed" },
01056 { 0x1000e, "exif:GPSTrackRef" },
01057 { 0x1000f, "exif:GPSTrack" },
01058 { 0x10010, "exif:GPSImgDirectionRef" },
01059 { 0x10011, "exif:GPSImgDirection" },
01060 { 0x10012, "exif:GPSMapDatum" },
01061 { 0x10013, "exif:GPSDestLatitudeRef" },
01062 { 0x10014, "exif:GPSDestLatitude" },
01063 { 0x10015, "exif:GPSDestLongitudeRef" },
01064 { 0x10016, "exif:GPSDestLongitude" },
01065 { 0x10017, "exif:GPSDestBearingRef" },
01066 { 0x10018, "exif:GPSDestBearing" },
01067 { 0x10019, "exif:GPSDestDistanceRef" },
01068 { 0x1001a, "exif:GPSDestDistance" },
01069 { 0x1001b, "exif:GPSProcessingMethod" },
01070 { 0x1001c, "exif:GPSAreaInformation" },
01071 { 0x1001d, "exif:GPSDateStamp" },
01072 { 0x1001e, "exif:GPSDifferential" },
01073 { 0x0000, NULL}
01074 };
01075
01076 const StringInfo
01077 *profile;
01078
01079 const unsigned char
01080 *directory,
01081 *exif;
01082
01083 DirectoryInfo
01084 directory_stack[MaxDirectoryStack];
01085
01086 EndianType
01087 endian;
01088
01089 long
01090 all,
01091 id,
01092 level,
01093 tag_value;
01094
01095 register long
01096 i;
01097
01098 size_t
01099 length;
01100
01101 ssize_t
01102 offset;
01103
01104 static int
01105 tag_bytes[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
01106
01107 unsigned long
01108 entry,
01109 number_entries,
01110 tag_offset,
01111 tag;
01112
01113
01114
01115
01116 profile=GetImageProfile(image,"exif");
01117 if (profile == (StringInfo *) NULL)
01118 return(MagickFalse);
01119 if ((property == (const char *) NULL) || (*property == '\0'))
01120 return(MagickFalse);
01121 while (isspace((int) ((unsigned char) *property)) != 0)
01122 property++;
01123 all=0;
01124 tag=(~0UL);
01125 switch (*(property+5))
01126 {
01127 case '*':
01128 {
01129
01130
01131
01132 tag=0;
01133 all=1;
01134 break;
01135 }
01136 case '!':
01137 {
01138 tag=0;
01139 all=2;
01140 break;
01141 }
01142 case '#':
01143 case '@':
01144 {
01145 int
01146 c;
01147
01148 size_t
01149 n;
01150
01151
01152
01153
01154 tag=(*(property+5) == '@') ? 1UL : 0UL;
01155 property+=6;
01156 n=strlen(property);
01157 if (n != 4)
01158 return(MagickFalse);
01159
01160
01161
01162 n/=4;
01163 do
01164 {
01165 for (i=(long) n-1L; i >= 0; i--)
01166 {
01167 c=(*property++);
01168 tag<<=4;
01169 if ((c >= '0') && (c <= '9'))
01170 tag|=(c-'0');
01171 else
01172 if ((c >= 'A') && (c <= 'F'))
01173 tag|=(c-('A'-10));
01174 else
01175 if ((c >= 'a') && (c <= 'f'))
01176 tag|=(c-('a'-10));
01177 else
01178 return(MagickFalse);
01179 }
01180 } while (*property != '\0');
01181 break;
01182 }
01183 default:
01184 {
01185
01186
01187
01188 for (i=0; ; i++)
01189 {
01190 if (EXIFTag[i].tag == 0)
01191 break;
01192 if (LocaleCompare(EXIFTag[i].description,property) == 0)
01193 {
01194 tag=(unsigned long) EXIFTag[i].tag;
01195 break;
01196 }
01197 }
01198 break;
01199 }
01200 }
01201 if (tag == (~0UL))
01202 return(MagickFalse);
01203 length=GetStringInfoLength(profile);
01204 exif=GetStringInfoDatum(profile);
01205 while (length != 0)
01206 {
01207 if (ReadPropertyByte(&exif,&length) != 0x45)
01208 continue;
01209 if (ReadPropertyByte(&exif,&length) != 0x78)
01210 continue;
01211 if (ReadPropertyByte(&exif,&length) != 0x69)
01212 continue;
01213 if (ReadPropertyByte(&exif,&length) != 0x66)
01214 continue;
01215 if (ReadPropertyByte(&exif,&length) != 0x00)
01216 continue;
01217 if (ReadPropertyByte(&exif,&length) != 0x00)
01218 continue;
01219 break;
01220 }
01221 if (length < 16)
01222 return(MagickFalse);
01223 id=(long) ReadPropertyShort(LSBEndian,exif);
01224 endian=LSBEndian;
01225 if (id == 0x4949)
01226 endian=LSBEndian;
01227 else
01228 if (id == 0x4D4D)
01229 endian=MSBEndian;
01230 else
01231 return(MagickFalse);
01232 if (ReadPropertyShort(endian,exif+2) != 0x002a)
01233 return(MagickFalse);
01234
01235
01236
01237 offset=(ssize_t) ReadPropertyLong(endian,exif+4);
01238 if ((size_t) offset >= length)
01239 return(MagickFalse);
01240
01241
01242
01243 directory=exif+offset;
01244 level=0;
01245 entry=0;
01246 tag_offset=0;
01247 do
01248 {
01249
01250
01251
01252 if (level > 0)
01253 {
01254 level--;
01255 directory=directory_stack[level].directory;
01256 entry=directory_stack[level].entry;
01257 tag_offset=directory_stack[level].offset;
01258 }
01259
01260
01261
01262 number_entries=ReadPropertyShort(endian,directory);
01263 for ( ; entry < number_entries; entry++)
01264 {
01265 long
01266 components;
01267
01268 register unsigned char
01269 *p,
01270 *q;
01271
01272 size_t
01273 number_bytes;
01274
01275 unsigned long
01276 format;
01277
01278 q=(unsigned char *) (directory+2+(12*entry));
01279 tag_value=(long) ReadPropertyShort(endian,q)+tag_offset;
01280 format=(unsigned long) ReadPropertyShort(endian,q+2);
01281 if (format >= (sizeof(tag_bytes)/sizeof(*tag_bytes)))
01282 break;
01283 components=(long) ReadPropertyLong(endian,q+4);
01284 number_bytes=(size_t) components*tag_bytes[format];
01285 if (number_bytes <= 4)
01286 p=q+8;
01287 else
01288 {
01289 ssize_t
01290 offset;
01291
01292
01293
01294
01295 offset=(ssize_t) ReadPropertyLong(endian,q+8);
01296 if ((size_t) (offset+number_bytes) > length)
01297 continue;
01298 p=(unsigned char *) (exif+offset);
01299 }
01300 if ((all != 0) || (tag == (unsigned long) tag_value))
01301 {
01302 char
01303 buffer[MaxTextExtent],
01304 *value;
01305
01306 switch (format)
01307 {
01308 case EXIF_FMT_BYTE:
01309 case EXIF_FMT_UNDEFINED:
01310 {
01311 EXIFMultipleValues(1,"%lu",(unsigned long)
01312 (*(unsigned char *) p1));
01313 break;
01314 }
01315 case EXIF_FMT_SBYTE:
01316 {
01317 EXIFMultipleValues(1,"%ld",(long) (*(signed char *) p1));
01318 break;
01319 }
01320 case EXIF_FMT_SSHORT:
01321 {
01322 EXIFMultipleValues(2,"%hd",ReadPropertyShort(endian,p1));
01323 break;
01324 }
01325 case EXIF_FMT_USHORT:
01326 {
01327 EXIFMultipleValues(2,"%hu",ReadPropertyShort(endian,p1));
01328 break;
01329 }
01330 case EXIF_FMT_ULONG:
01331 {
01332 EXIFMultipleValues(4,"%lu",ReadPropertyLong(endian,p1));
01333 break;
01334 }
01335 case EXIF_FMT_SLONG:
01336 {
01337 EXIFMultipleValues(4,"%ld",ReadPropertyLong(endian,p1));
01338 break;
01339 }
01340 case EXIF_FMT_URATIONAL:
01341 {
01342 EXIFMultipleFractions(8,"%ld/%ld",ReadPropertyLong(endian,p1),
01343 ReadPropertyLong(endian,p1+4));
01344 break;
01345 }
01346 case EXIF_FMT_SRATIONAL:
01347 {
01348 EXIFMultipleFractions(8,"%ld/%ld",ReadPropertyLong(endian,p1),
01349 ReadPropertyLong(endian,p1+4));
01350 break;
01351 }
01352 case EXIF_FMT_SINGLE:
01353 {
01354 EXIFMultipleValues(4,"%f",(double) *(float *) p1);
01355 break;
01356 }
01357 case EXIF_FMT_DOUBLE:
01358 {
01359 EXIFMultipleValues(8,"%f",*(double *) p1);
01360 break;
01361 }
01362 default:
01363 case EXIF_FMT_STRING:
01364 {
01365 value=(char *) NULL;
01366 if (~(1UL*number_bytes) >= 1)
01367 value=(char *) AcquireQuantumMemory((size_t) number_bytes+1UL,
01368 sizeof(*value));
01369 if (value != (char *) NULL)
01370 {
01371 register long
01372 i;
01373
01374 for (i=0; i < (long) number_bytes; i++)
01375 {
01376 value[i]='.';
01377 if ((isprint((int) p[i]) != 0) || (p[i] == '\0'))
01378 value[i]=(char) p[i];
01379 }
01380 value[i]='\0';
01381 }
01382 break;
01383 }
01384 }
01385 if (value != (char *) NULL)
01386 {
01387 char
01388 key[MaxTextExtent];
01389
01390 register const char
01391 *p;
01392
01393 (void) CopyMagickString(key,property,MaxTextExtent);
01394 switch (all)
01395 {
01396 case 1:
01397 {
01398 const char
01399 *description;
01400
01401 register long
01402 i;
01403
01404 description="unknown";
01405 for (i=0; ; i++)
01406 {
01407 if (EXIFTag[i].tag == 0)
01408 break;
01409 if ((long) EXIFTag[i].tag == tag_value)
01410 {
01411 description=EXIFTag[i].description;
01412 break;
01413 }
01414 }
01415 (void) FormatMagickString(key,MaxTextExtent,"%s",
01416 description);
01417 break;
01418 }
01419 case 2:
01420 {
01421 if (tag_value < 0x10000)
01422 (void) FormatMagickString(key,MaxTextExtent,"#%04lx",
01423 tag_value);
01424 else
01425 if (tag_value < 0x20000)
01426 (void) FormatMagickString(key,MaxTextExtent,"@%04lx",
01427 tag_value & 0xffff);
01428 else
01429 (void) FormatMagickString(key,MaxTextExtent,"unknown");
01430 break;
01431 }
01432 }
01433 p=(const char *) NULL;
01434 if (image->properties != (void *) NULL)
01435 p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
01436 image->properties,key);
01437 if (p == (const char *) NULL)
01438 (void) SetImageProperty((Image *) image,key,value);
01439 value=DestroyString(value);
01440 }
01441 }
01442 if ((tag_value == TAG_EXIF_OFFSET) ||
01443 (tag_value == TAG_INTEROP_OFFSET) ||
01444 (tag_value == TAG_GPS_OFFSET))
01445 {
01446 size_t
01447 offset;
01448
01449 offset=(size_t) ReadPropertyLong(endian,p);
01450 if ((offset < length) && (level < (MaxDirectoryStack-2)))
01451 {
01452 unsigned long
01453 tag_offset1;
01454
01455 tag_offset1=(tag_value == TAG_GPS_OFFSET) ? 0x10000UL : 0UL;
01456 directory_stack[level].directory=directory;
01457 entry++;
01458 directory_stack[level].entry=entry;
01459 directory_stack[level].offset=tag_offset;
01460 level++;
01461 directory_stack[level].directory=exif+offset;
01462 directory_stack[level].offset=tag_offset1;
01463 directory_stack[level].entry=0;
01464 level++;
01465 if ((directory+2+(12*number_entries)) > (exif+length))
01466 break;
01467 offset=(size_t) ReadPropertyLong(endian,directory+2+(12*
01468 number_entries));
01469 if ((offset != 0) && (offset < length) &&
01470 (level < (MaxDirectoryStack-2)))
01471 {
01472 directory_stack[level].directory=exif+offset;
01473 directory_stack[level].entry=0;
01474 directory_stack[level].offset=tag_offset1;
01475 level++;
01476 }
01477 }
01478 break;
01479 }
01480 }
01481 } while (level > 0);
01482 return(MagickTrue);
01483 }
01484
01485 static MagickBooleanType GetXMPProperty(const Image *image,
01486 const char *property)
01487 {
01488 char
01489 *xmp_profile;
01490
01491 const StringInfo
01492 *profile;
01493
01494 ExceptionInfo
01495 *exception;
01496
01497 MagickBooleanType
01498 status;
01499
01500 register const char
01501 *p;
01502
01503 XMLTreeInfo
01504 *child,
01505 *description,
01506 *node,
01507 *rdf,
01508 *xmp;
01509
01510 profile=GetImageProfile(image,"xmp");
01511 if (profile == (StringInfo *) NULL)
01512 return(MagickFalse);
01513 if ((property == (const char *) NULL) || (*property == '\0'))
01514 return(MagickFalse);
01515 xmp_profile=StringInfoToString(profile);
01516 if (xmp_profile == (char *) NULL)
01517 return(MagickFalse);
01518 for (p=xmp_profile; *p != '\0'; p++)
01519 if ((*p == '<') && (*(p+1) == 'x'))
01520 break;
01521 exception=AcquireExceptionInfo();
01522 xmp=NewXMLTree((char *) p,exception);
01523 xmp_profile=DestroyString(xmp_profile);
01524 exception=DestroyExceptionInfo(exception);
01525 if (xmp == (XMLTreeInfo *) NULL)
01526 return(MagickFalse);
01527 status=MagickFalse;
01528 rdf=GetXMLTreeChild(xmp,"rdf:RDF");
01529 if (rdf != (XMLTreeInfo *) NULL)
01530 {
01531 if (image->properties == (void *) NULL)
01532 ((Image *) image)->properties=NewSplayTree(CompareSplayTreeString,
01533 RelinquishMagickMemory,RelinquishMagickMemory);
01534 description=GetXMLTreeChild(rdf,"rdf:Description");
01535 while (description != (XMLTreeInfo *) NULL)
01536 {
01537 node=GetXMLTreeChild(description,(const char *) NULL);
01538 while (node != (XMLTreeInfo *) NULL)
01539 {
01540 child=GetXMLTreeChild(node,(const char *) NULL);
01541 if (child == (XMLTreeInfo *) NULL)
01542 (void) AddValueToSplayTree((SplayTreeInfo *) image->properties,
01543 ConstantString(GetXMLTreeTag(node)),
01544 ConstantString(GetXMLTreeContent(node)));
01545 while (child != (XMLTreeInfo *) NULL)
01546 {
01547 if (LocaleCompare(GetXMLTreeTag(child),"rdf:Seq") != 0)
01548 (void) AddValueToSplayTree((SplayTreeInfo *) image->properties,
01549 ConstantString(GetXMLTreeTag(child)),
01550 ConstantString(GetXMLTreeContent(child)));
01551 child=GetXMLTreeSibling(child);
01552 }
01553 node=GetXMLTreeSibling(node);
01554 }
01555 description=GetNextXMLTreeTag(description);
01556 }
01557 }
01558 xmp=DestroyXMLTree(xmp);
01559 return(status);
01560 }
01561
01562 static char *TracePSClippath(const unsigned char *blob,size_t length,
01563 const unsigned long magick_unused(columns),
01564 const unsigned long magick_unused(rows))
01565 {
01566 char
01567 *path,
01568 *message;
01569
01570 long
01571 knot_count,
01572 selector,
01573 y;
01574
01575 MagickBooleanType
01576 in_subpath;
01577
01578 PointInfo
01579 first[3],
01580 last[3],
01581 point[3];
01582
01583 register long
01584 i,
01585 x;
01586
01587 path=AcquireString((char *) NULL);
01588 if (path == (char *) NULL)
01589 return((char *) NULL);
01590 message=AcquireString((char *) NULL);
01591 (void) FormatMagickString(message,MaxTextExtent,"/ClipImage\n");
01592 (void) ConcatenateString(&path,message);
01593 (void) FormatMagickString(message,MaxTextExtent,"{\n");
01594 (void) ConcatenateString(&path,message);
01595 (void) FormatMagickString(message,MaxTextExtent," /c {curveto} bind def\n");
01596 (void) ConcatenateString(&path,message);
01597 (void) FormatMagickString(message,MaxTextExtent," /l {lineto} bind def\n");
01598 (void) ConcatenateString(&path,message);
01599 (void) FormatMagickString(message,MaxTextExtent," /m {moveto} bind def\n");
01600 (void) ConcatenateString(&path,message);
01601 (void) FormatMagickString(message,MaxTextExtent,
01602 " /v {currentpoint 6 2 roll curveto} bind def\n");
01603 (void) ConcatenateString(&path,message);
01604 (void) FormatMagickString(message,MaxTextExtent,
01605 " /y {2 copy curveto} bind def\n");
01606 (void) ConcatenateString(&path,message);
01607 (void) FormatMagickString(message,MaxTextExtent,
01608 " /z {closepath} bind def\n");
01609 (void) ConcatenateString(&path,message);
01610 (void) FormatMagickString(message,MaxTextExtent," newpath\n");
01611 (void) ConcatenateString(&path,message);
01612
01613
01614
01615
01616 (void) ResetMagickMemory(point,0,sizeof(point));
01617 (void) ResetMagickMemory(first,0,sizeof(first));
01618 (void) ResetMagickMemory(last,0,sizeof(last));
01619 knot_count=0;
01620 in_subpath=MagickFalse;
01621 while (length > 0)
01622 {
01623 selector=(long) ReadPropertyMSBShort(&blob,&length);
01624 switch (selector)
01625 {
01626 case 0:
01627 case 3:
01628 {
01629 if (knot_count != 0)
01630 {
01631 blob+=24;
01632 length-=24;
01633 break;
01634 }
01635
01636
01637
01638 knot_count=(long) ReadPropertyMSBShort(&blob,&length);
01639 blob+=22;
01640 length-=22;
01641 break;
01642 }
01643 case 1:
01644 case 2:
01645 case 4:
01646 case 5:
01647 {
01648 if (knot_count == 0)
01649 {
01650
01651
01652
01653 blob+=24;
01654 length-=24;
01655 break;
01656 }
01657
01658
01659
01660 for (i=0; i < 3; i++)
01661 {
01662 unsigned long
01663 xx,
01664 yy;
01665
01666 yy=ReadPropertyMSBLong(&blob,&length);
01667 xx=ReadPropertyMSBLong(&blob,&length);
01668 x=(long) xx;
01669 if (xx > 2147483647)
01670 x=xx-4294967295-1;
01671 y=(long) yy;
01672 if (yy > 2147483647)
01673 y=yy-4294967295-1;
01674 point[i].x=(double) x/4096/4096;
01675 point[i].y=1.0-(double) y/4096/4096;
01676 }
01677 if (in_subpath == MagickFalse)
01678 {
01679 (void) FormatMagickString(message,MaxTextExtent," %g %g m\n",
01680 point[1].x,point[1].y);
01681 for (i=0; i < 3; i++)
01682 {
01683 first[i]=point[i];
01684 last[i]=point[i];
01685 }
01686 }
01687 else
01688 {
01689
01690
01691
01692
01693 if ((last[1].x == last[2].x) && (last[1].y == last[2].y) &&
01694 (point[0].x == point[1].x) && (point[0].y == point[1].y))
01695 (void) FormatMagickString(message,MaxTextExtent," %g %g l\n",
01696 point[1].x,point[1].y);
01697 else
01698 if ((last[1].x == last[2].x) && (last[1].y == last[2].y))
01699 (void) FormatMagickString(message,MaxTextExtent,
01700 " %g %g %g %g v\n",point[0].x,point[0].y,point[1].x,
01701 point[1].y);
01702 else
01703 if ((point[0].x == point[1].x) && (point[0].y == point[1].y))
01704 (void) FormatMagickString(message,MaxTextExtent,
01705 " %g %g %g %g y\n",last[2].x,last[2].y,point[1].x,
01706 point[1].y);
01707 else
01708 (void) FormatMagickString(message,MaxTextExtent,
01709 " %g %g %g %g %g %g c\n",last[2].x,last[2].y,point[0].x,
01710 point[0].y,point[1].x,point[1].y);
01711 for (i=0; i < 3; i++)
01712 last[i]=point[i];
01713 }
01714 (void) ConcatenateString(&path,message);
01715 in_subpath=MagickTrue;
01716 knot_count--;
01717
01718
01719
01720 if (knot_count == 0)
01721 {
01722
01723
01724
01725
01726 if ((last[1].x == last[2].x) && (last[1].y == last[2].y) &&
01727 (first[0].x == first[1].x) && (first[0].y == first[1].y))
01728 (void) FormatMagickString(message,MaxTextExtent," %g %g l z\n",
01729 first[1].x,first[1].y);
01730 else
01731 if ((last[1].x == last[2].x) && (last[1].y == last[2].y))
01732 (void) FormatMagickString(message,MaxTextExtent,
01733 " %g %g %g %g v z\n",first[0].x,first[0].y,first[1].x,
01734 first[1].y);
01735 else
01736 if ((first[0].x == first[1].x) && (first[0].y == first[1].y))
01737 (void) FormatMagickString(message,MaxTextExtent,
01738 " %g %g %g %g y z\n",last[2].x,last[2].y,first[1].x,
01739 first[1].y);
01740 else
01741 (void) FormatMagickString(message,MaxTextExtent,
01742 " %g %g %g %g %g %g c z\n",last[2].x,last[2].y,first[0].x,
01743 first[0].y,first[1].x,first[1].y);
01744 (void) ConcatenateString(&path,message);
01745 in_subpath=MagickFalse;
01746 }
01747 break;
01748 }
01749 case 6:
01750 case 7:
01751 case 8:
01752 default:
01753 {
01754 blob+=24;
01755 length-=24;
01756 break;
01757 }
01758 }
01759 }
01760
01761
01762
01763 (void) FormatMagickString(message,MaxTextExtent," eoclip\n");
01764 (void) ConcatenateString(&path,message);
01765 (void) FormatMagickString(message,MaxTextExtent,"} bind def");
01766 (void) ConcatenateString(&path,message);
01767 message=DestroyString(message);
01768 return(path);
01769 }
01770
01771 static char *TraceSVGClippath(const unsigned char *blob,size_t length,
01772 const unsigned long columns,const unsigned long rows)
01773 {
01774 char
01775 *path,
01776 *message;
01777
01778 long
01779 knot_count,
01780 selector,
01781 x,
01782 y;
01783
01784 MagickBooleanType
01785 in_subpath;
01786
01787 PointInfo
01788 first[3],
01789 last[3],
01790 point[3];
01791
01792 register long
01793 i;
01794
01795 path=AcquireString((char *) NULL);
01796 if (path == (char *) NULL)
01797 return((char *) NULL);
01798 message=AcquireString((char *) NULL);
01799 (void) FormatMagickString(message,MaxTextExtent,
01800 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n");
01801 (void) ConcatenateString(&path,message);
01802 (void) FormatMagickString(message,MaxTextExtent,
01803 "<svg width=\"%lu\" height=\"%lu\">\n",columns,rows);
01804 (void) ConcatenateString(&path,message);
01805 (void) FormatMagickString(message,MaxTextExtent,"<g>\n");
01806 (void) ConcatenateString(&path,message);
01807 (void) FormatMagickString(message,MaxTextExtent,
01808 "<path style=\"fill:#00000000;stroke:#00000000;");
01809 (void) ConcatenateString(&path,message);
01810 (void) FormatMagickString(message,MaxTextExtent,
01811 "stroke-width:0;stroke-antialiasing:false\" d=\"\n");
01812 (void) ConcatenateString(&path,message);
01813 (void) ResetMagickMemory(point,0,sizeof(point));
01814 (void) ResetMagickMemory(first,0,sizeof(first));
01815 (void) ResetMagickMemory(last,0,sizeof(last));
01816 knot_count=0;
01817 in_subpath=MagickFalse;
01818 while (length != 0)
01819 {
01820 selector=(long) ReadPropertyMSBShort(&blob,&length);
01821 switch (selector)
01822 {
01823 case 0:
01824 case 3:
01825 {
01826 if (knot_count != 0)
01827 {
01828 blob+=24;
01829 length-=24;
01830 break;
01831 }
01832
01833
01834
01835 knot_count=(long) ReadPropertyMSBShort(&blob,&length);
01836 blob+=22;
01837 length-=22;
01838 break;
01839 }
01840 case 1:
01841 case 2:
01842 case 4:
01843 case 5:
01844 {
01845 if (knot_count == 0)
01846 {
01847
01848
01849
01850 blob+=24;
01851 length-=24;
01852 break;
01853 }
01854
01855
01856
01857 for (i=0; i < 3; i++)
01858 {
01859 unsigned long
01860 xx,
01861 yy;
01862
01863 yy=ReadPropertyMSBLong(&blob,&length);
01864 xx=ReadPropertyMSBLong(&blob,&length);
01865 x=(long) xx;
01866 if (xx > 2147483647)
01867 x=xx-4294967295-1;
01868 y=(long) yy;
01869 if (yy > 2147483647)
01870 y=yy-4294967295-1;
01871 point[i].x=(double) x*columns/4096/4096;
01872 point[i].y=(double) y*rows/4096/4096;
01873 }
01874 if (in_subpath == MagickFalse)
01875 {
01876 (void) FormatMagickString(message,MaxTextExtent,"M %g,%g\n",
01877 point[1].x,point[1].y);
01878 for (i=0; i < 3; i++)
01879 {
01880 first[i]=point[i];
01881 last[i]=point[i];
01882 }
01883 }
01884 else
01885 {
01886 if ((last[1].x == last[2].x) && (last[1].y == last[2].y) &&
01887 (point[0].x == point[1].x) && (point[0].y == point[1].y))
01888 (void) FormatMagickString(message,MaxTextExtent,"L %g,%g\n",
01889 point[1].x,point[1].y);
01890 else
01891 (void) FormatMagickString(message,MaxTextExtent,
01892 "C %g,%g %g,%g %g,%g\n",last[2].x,last[2].y,
01893 point[0].x,point[0].y,point[1].x,point[1].y);
01894 for (i=0; i < 3; i++)
01895 last[i]=point[i];
01896 }
01897 (void) ConcatenateString(&path,message);
01898 in_subpath=MagickTrue;
01899 knot_count--;
01900
01901
01902
01903 if (knot_count == 0)
01904 {
01905 if ((last[1].x == last[2].x) && (last[1].y == last[2].y) &&
01906 (first[0].x == first[1].x) && (first[0].y == first[1].y))
01907 (void) FormatMagickString(message,MaxTextExtent,"L %g,%g Z\n",
01908 first[1].x,first[1].y);
01909 else
01910 {
01911 (void) FormatMagickString(message,MaxTextExtent,
01912 "C %g,%g %g,%g %g,%g Z\n",last[2].x,last[2].y,
01913 first[0].x,first[0].y,first[1].x,first[1].y);
01914 (void) ConcatenateString(&path,message);
01915 }
01916 in_subpath=MagickFalse;
01917 }
01918 break;
01919 }
01920 case 6:
01921 case 7:
01922 case 8:
01923 default:
01924 {
01925 blob+=24;
01926 length-=24;
01927 break;
01928 }
01929 }
01930 }
01931
01932
01933
01934 (void) FormatMagickString(message,MaxTextExtent,"\"/>\n");
01935 (void) ConcatenateString(&path,message);
01936 (void) FormatMagickString(message,MaxTextExtent,"</g>\n");
01937 (void) ConcatenateString(&path,message);
01938 (void) FormatMagickString(message,MaxTextExtent,"</svg>\n");
01939 (void) ConcatenateString(&path,message);
01940 message=DestroyString(message);
01941 return(path);
01942 }
01943
01944 MagickExport const char *GetImageProperty(const Image *image,
01945 const char *property)
01946 {
01947 ExceptionInfo
01948 *exception;
01949
01950 FxInfo
01951 *fx_info;
01952
01953 MagickRealType
01954 alpha;
01955
01956 MagickStatusType
01957 status;
01958
01959 register const char
01960 *p;
01961
01962 assert(image != (Image *) NULL);
01963 assert(image->signature == MagickSignature);
01964 if (image->debug != MagickFalse)
01965 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01966 p=(const char *) NULL;
01967 if (property == (const char *) NULL)
01968 {
01969 ResetSplayTreeIterator((SplayTreeInfo *) image->properties);
01970 p=(const char *) GetNextValueInSplayTree((SplayTreeInfo *)
01971 image->properties);
01972 return(p);
01973 }
01974 if ((image->properties != (void *) NULL) &&
01975 (LocaleNCompare("fx:",property,3) != 0))
01976 {
01977 p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
01978 image->properties,property);
01979 if (p != (const char *) NULL)
01980 return(p);
01981 }
01982 if (strchr(property,':') == (char *) NULL)
01983 return(p);
01984 exception=(&((Image *) image)->exception);
01985 switch (*property)
01986 {
01987 case '8':
01988 {
01989 if (LocaleNCompare("8bim:",property,5) == 0)
01990 {
01991 if (Get8BIMProperty(image,property) != MagickFalse)
01992 {
01993 p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
01994 image->properties,property);
01995 return(p);
01996 }
01997 }
01998 break;
01999 }
02000 case 'E':
02001 case 'e':
02002 {
02003 if (LocaleNCompare("exif:",property,5) == 0)
02004 {
02005 if (GetEXIFProperty(image,property) != MagickFalse)
02006 {
02007 p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
02008 image->properties,property);
02009 return(p);
02010 }
02011 }
02012 break;
02013 }
02014 case 'F':
02015 case 'f':
02016 {
02017 if (LocaleNCompare("fx:",property,3) == 0)
02018 {
02019 fx_info=AcquireFxInfo(image,property+3);
02020 status=FxEvaluateExpression(fx_info,&alpha,exception);
02021 fx_info=DestroyFxInfo(fx_info);
02022 if (status != MagickFalse)
02023 {
02024 char
02025 value[MaxTextExtent];
02026
02027 (void) FormatMagickString(value,MaxTextExtent,"%g",(double)
02028 alpha);
02029 (void) SetImageProperty((Image *) image,property,value);
02030 }
02031 p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
02032 image->properties,property);
02033 return(p);
02034 }
02035 break;
02036 }
02037 case 'I':
02038 case 'i':
02039 {
02040 if (LocaleNCompare("iptc:",property,5) == 0)
02041 {
02042 if (GetIPTCProperty(image,property) != MagickFalse)
02043 {
02044 p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
02045 image->properties,property);
02046 return(p);
02047 }
02048 }
02049 break;
02050 }
02051 case 'P':
02052 case 'p':
02053 {
02054 if (LocaleNCompare("pixel:",property,6) == 0)
02055 {
02056 MagickPixelPacket
02057 pixel;
02058
02059 GetMagickPixelPacket(image,&pixel);
02060 fx_info=AcquireFxInfo(image,property+6);
02061 status=FxEvaluateChannelExpression(fx_info,RedChannel,0,0,&alpha,
02062 exception);
02063 pixel.red=(MagickRealType) QuantumRange*alpha;
02064 status|=FxEvaluateChannelExpression(fx_info,GreenChannel,0,0,&alpha,
02065 exception);
02066 pixel.green=(MagickRealType) QuantumRange*alpha;
02067 status|=FxEvaluateChannelExpression(fx_info,BlueChannel,0,0,&alpha,
02068 exception);
02069 pixel.blue=(MagickRealType) QuantumRange*alpha;
02070 status|=FxEvaluateChannelExpression(fx_info,OpacityChannel,0,0,&alpha,
02071 exception);
02072 pixel.opacity=(MagickRealType) QuantumRange*(1.0-alpha);
02073 if (image->colorspace == CMYKColorspace)
02074 {
02075 status|=FxEvaluateChannelExpression(fx_info,BlackChannel,0,0,
02076 &alpha,exception);
02077 pixel.index=(MagickRealType) QuantumRange*alpha;
02078 }
02079 fx_info=DestroyFxInfo(fx_info);
02080 if (status != MagickFalse)
02081 {
02082 char
02083 name[MaxTextExtent];
02084
02085 (void) QueryMagickColorname(image,&pixel,SVGCompliance,name,
02086 exception);
02087 (void) SetImageProperty((Image *) image,property,name);
02088 return(GetImageProperty(image,property));
02089 }
02090 }
02091 break;
02092 }
02093 case 'X':
02094 case 'x':
02095 {
02096 if (LocaleNCompare("xmp:",property,4) == 0)
02097 {
02098 if (GetXMPProperty(image,property) != MagickFalse)
02099 {
02100 p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
02101 image->properties,property);
02102 return(p);
02103 }
02104 }
02105 break;
02106 }
02107 }
02108 return(p);
02109 }
02110
02111
02112
02113
02114
02115
02116
02117
02118
02119
02120
02121
02122
02123
02124
02125
02126
02127
02128
02129
02130
02131
02132
02133
02134
02135
02136
02137
02138 MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
02139 Image *image,const char *property)
02140 {
02141 char
02142 value[MaxTextExtent],
02143 filename[MaxTextExtent];
02144
02145 *value='\0';
02146 switch (*(property))
02147 {
02148 case 'b':
02149 {
02150 if (LocaleNCompare("base",property,4) == 0)
02151 {
02152 GetPathComponent(image->magick_filename,BasePath,filename);
02153 (void) CopyMagickString(value,filename,MaxTextExtent);
02154 break;
02155 }
02156 break;
02157 }
02158 case 'c':
02159 {
02160 if (LocaleNCompare("channels",property,8) == 0)
02161 {
02162
02163
02164
02165 (void) FormatMagickString(value,MaxTextExtent,"%s",
02166 MagickOptionToMnemonic(MagickColorspaceOptions,(long)
02167 image->colorspace));
02168 LocaleLower(value);
02169 if (image->matte != MagickFalse)
02170 (void) ConcatenateMagickString(value,"a",MaxTextExtent);
02171 break;
02172 }
02173 if (LocaleNCompare("colorspace",property,10) == 0)
02174 {
02175 ColorspaceType
02176 colorspace;
02177
02178
02179
02180
02181 colorspace=image->colorspace;
02182 if (IsGrayImage(image,&image->exception) != MagickFalse)
02183 colorspace=GRAYColorspace;
02184 (void) FormatMagickString(value,MaxTextExtent,"%s",
02185 MagickOptionToMnemonic(MagickColorspaceOptions,(long) colorspace));
02186 break;
02187 }
02188 break;
02189 }
02190 case 'd':
02191 {
02192 if (LocaleNCompare("depth",property,5) == 0)
02193 {
02194 (void) FormatMagickString(value,MaxTextExtent,"%lu",image->depth);
02195 break;
02196 }
02197 if (LocaleNCompare("directory",property,9) == 0)
02198 {
02199 GetPathComponent(image->magick_filename,HeadPath,filename);
02200 (void) CopyMagickString(value,filename,MaxTextExtent);
02201 break;
02202 }
02203 break;
02204 }
02205 case 'e':
02206 {
02207 if (LocaleNCompare("extension",property,9) == 0)
02208 {
02209 GetPathComponent(image->magick_filename,ExtensionPath,filename);
02210 (void) CopyMagickString(value,filename,MaxTextExtent);
02211 break;
02212 }
02213 break;
02214 }
02215 case 'g':
02216 {
02217 if (LocaleNCompare("group",property,5) == 0)
02218 {
02219 (void) FormatMagickString(value,MaxTextExtent,"0x%lx",
02220 image_info->group);
02221 break;
02222 }
02223 break;
02224 }
02225 case 'h':
02226 {
02227 if (LocaleNCompare("height",property,6) == 0)
02228 {
02229 (void) FormatMagickString(value,MaxTextExtent,"%lu",
02230 image->magick_rows != 0 ? image->magick_rows : 256UL);
02231 break;
02232 }
02233 break;
02234 }
02235 case 'i':
02236 {
02237 if (LocaleNCompare("input",property,5) == 0)
02238 {
02239 (void) CopyMagickString(value,image->filename,MaxTextExtent);
02240 break;
02241 }
02242 break;
02243 }
02244 case 'k':
02245 {
02246 if (LocaleNCompare("kurtosis",property,8) == 0)
02247 {
02248 double
02249 kurtosis,
02250 skewness;
02251
02252 (void) GetImageChannelKurtosis(image,image_info->channel,&kurtosis,
02253 &skewness,&image->exception);
02254 (void) FormatMagickString(value,MaxTextExtent,"%g",kurtosis);
02255 break;
02256 }
02257 break;
02258 }
02259 case 'm':
02260 {
02261 if (LocaleNCompare("magick",property,6) == 0)
02262 {
02263 (void) CopyMagickString(value,image->magick,MaxTextExtent);
02264 break;
02265 }
02266 if (LocaleNCompare("max",property,3) == 0)
02267 {
02268 double
02269 maximum,
02270 minimum;
02271
02272 (void) GetImageChannelRange(image,image_info->channel,&minimum,
02273 &maximum,&image->exception);
02274 (void) FormatMagickString(value,MaxTextExtent,"%g",maximum);
02275 break;
02276 }
02277 if (LocaleNCompare("mean",property,4) == 0)
02278 {
02279 double
02280 mean,
02281 standard_deviation;
02282
02283 (void) GetImageChannelMean(image,image_info->channel,&mean,
02284 &standard_deviation,&image->exception);
02285 (void) FormatMagickString(value,MaxTextExtent,"%g",mean);
02286 break;
02287 }
02288 if (LocaleNCompare("min",property,3) == 0)
02289 {
02290 double
02291 maximum,
02292 minimum;
02293
02294 (void) GetImageChannelRange(image,image_info->channel,&minimum,
02295 &maximum,&image->exception);
02296 (void) FormatMagickString(value,MaxTextExtent,"%g",minimum);
02297 break;
02298 }
02299 break;
02300 }
02301 case 'n':
02302 {
02303 if (LocaleNCompare("name",property,4) == 0)
02304 {
02305 (void) CopyMagickString(value,filename,MaxTextExtent);
02306 break;
02307 }
02308 break;
02309 }
02310 case 'o':
02311 {
02312 if (LocaleNCompare("output",property,6) == 0)
02313 {
02314 (void) CopyMagickString(value,image_info->filename,MaxTextExtent);
02315 break;
02316 }
02317 break;
02318 }
02319 case 'p':
02320 {
02321 if (LocaleNCompare("page",property,4) == 0)
02322 {
02323 register const Image
02324 *p;
02325
02326 unsigned long
02327 page;
02328
02329 p=image;
02330 for (page=1; GetPreviousImageInList(p) != (Image *) NULL; page++)
02331 p=GetPreviousImageInList(p);
02332 (void) FormatMagickString(value,MaxTextExtent,"%lu",page);
02333 break;
02334 }
02335 break;
02336 }
02337 case 's':
02338 {
02339 if (LocaleNCompare("size",property,4) == 0)
02340 {
02341 char
02342 format[MaxTextExtent];
02343
02344 (void) FormatMagickSize(GetBlobSize(image),format);
02345 (void) FormatMagickString(value,MaxTextExtent,"%s",format);
02346 break;
02347 }
02348 if (LocaleNCompare("scenes",property,6) == 0)
02349 {
02350 (void) FormatMagickString(value,MaxTextExtent,"%lu",
02351 (unsigned long) GetImageListLength(image));
02352 break;
02353 }
02354 if (LocaleNCompare("scene",property,5) == 0)
02355 {
02356 (void) FormatMagickString(value,MaxTextExtent,"%lu",image->scene);
02357 if (image_info->number_scenes != 0)
02358 (void) FormatMagickString(value,MaxTextExtent,"%lu",
02359 image_info->scene);
02360 break;
02361 }
02362 if (LocaleNCompare("skewness",property,8) == 0)
02363 {
02364 double
02365 kurtosis,
02366 skewness;
02367
02368 (void) GetImageChannelKurtosis(image,image_info->channel,&kurtosis,
02369 &skewness,&image->exception);
02370 (void) FormatMagickString(value,MaxTextExtent,"%g",skewness);
02371 break;
02372 }
02373 if ((LocaleNCompare("standard-deviation",property,18) == 0) ||
02374 (LocaleNCompare("standard_deviation",property,18) == 0))
02375 {
02376 double
02377 mean,
02378 standard_deviation;
02379
02380 (void) GetImageChannelMean(image,image_info->channel,&mean,
02381 &standard_deviation,&image->exception);
02382 (void) FormatMagickString(value,MaxTextExtent,"%g",
02383 standard_deviation);
02384 break;
02385 }
02386 break;
02387 }
02388 case 'u':
02389 {
02390 if (LocaleNCompare("unique",property,6) == 0)
02391 {
02392 (void) CopyMagickString(filename,image_info->unique,MaxTextExtent);
02393 (void) CopyMagickString(value,filename,MaxTextExtent);
02394 break;
02395 }
02396 break;
02397 }
02398 case 'w':
02399 {
02400 if (LocaleNCompare("width",property,5) == 0)
02401 {
02402 (void) FormatMagickString(value,MaxTextExtent,"%lu",
02403 image->magick_columns != 0 ? image->magick_columns : 256UL);
02404 break;
02405 }
02406 break;
02407 }
02408 case 'x':
02409 {
02410 if (LocaleNCompare("xresolution",property,11) == 0)
02411 {
02412 (void) FormatMagickString(value,MaxTextExtent,"%g",
02413 image->x_resolution);
02414 break;
02415 }
02416 break;
02417 }
02418 case 'y':
02419 {
02420 if (LocaleNCompare("yresolution",property,11) == 0)
02421 {
02422 (void) FormatMagickString(value,MaxTextExtent,"%g",
02423 image->y_resolution);
02424 break;
02425 }
02426 break;
02427 }
02428 case 'z':
02429 {
02430 if (LocaleNCompare("zero",property,4) == 0)
02431 {
02432 (void) CopyMagickString(filename,image_info->zero,MaxTextExtent);
02433 (void) CopyMagickString(value,filename,MaxTextExtent);
02434 break;
02435 }
02436 break;
02437 }
02438 }
02439 if (*value != '\0')
02440 {
02441 if (image->properties == (void *) NULL)
02442 image->properties=NewSplayTree(CompareSplayTreeString,
02443 RelinquishMagickMemory,RelinquishMagickMemory);
02444 (void) AddValueToSplayTree((SplayTreeInfo *) image->properties,
02445 ConstantString(property),ConstantString(value));
02446 }
02447 return(GetImageProperty(image,property));
02448 }
02449
02450
02451
02452
02453
02454
02455
02456
02457
02458
02459
02460
02461
02462
02463
02464
02465
02466
02467
02468
02469
02470
02471
02472 MagickExport char *GetNextImageProperty(const Image *image)
02473 {
02474 assert(image != (Image *) NULL);
02475 assert(image->signature == MagickSignature);
02476 if (image->debug != MagickFalse)
02477 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
02478 image->filename);
02479 if (image->properties == (void *) NULL)
02480 return((char *) NULL);
02481 return((char *) GetNextKeyInSplayTree((SplayTreeInfo *) image->properties));
02482 }
02483
02484
02485
02486
02487
02488
02489
02490
02491
02492
02493
02494
02495
02496
02497
02498
02499
02500
02501
02502
02503
02504
02505
02506
02507
02508
02509
02510
02511
02512
02513 MagickExport char *InterpretImageProperties(const ImageInfo *image_info,
02514 Image *image,const char *embed_text)
02515 {
02516 char
02517 filename[MaxTextExtent],
02518 *interpret_text,
02519 *text;
02520
02521 const char
02522 *value;
02523
02524 ImageInfo
02525 *text_info;
02526
02527 register char
02528 *q;
02529
02530 register const char
02531 *p;
02532
02533 register long
02534 i;
02535
02536 size_t
02537 extent,
02538 length;
02539
02540 assert(image != (Image *) NULL);
02541 assert(image->signature == MagickSignature);
02542 if (image->debug != MagickFalse)
02543 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
02544 if ((embed_text == (const char *) NULL) || (*embed_text == '\0'))
02545 return((char *) NULL);
02546 text=(char *) embed_text;
02547 if ((*text == '@') && ((*(text+1) == '-') ||
02548 (IsPathAccessible(text+1) != MagickFalse)))
02549 return(FileToString(embed_text+1,~0,&image->exception));
02550
02551
02552
02553 text_info=CloneImageInfo(image_info);
02554 interpret_text=AcquireString(text);
02555 extent=MaxTextExtent;
02556 p=text;
02557 for (q=interpret_text; *p != '\0'; p++)
02558 {
02559 *q='\0';
02560 if ((size_t) (q-interpret_text+MaxTextExtent) >= extent)
02561 {
02562 extent+=MaxTextExtent;
02563 interpret_text=(char *) ResizeQuantumMemory(interpret_text,extent+
02564 MaxTextExtent+1,sizeof(*interpret_text));
02565 if (interpret_text == (char *) NULL)
02566 break;
02567 q=interpret_text+strlen(interpret_text);
02568 }
02569
02570
02571
02572 if ((*p == '\\') && (*(p+1) == 'r'))
02573 {
02574 *q++='\r';
02575 p++;
02576 continue;
02577 }
02578 if ((*p == '\\') && (*(p+1) == 'n'))
02579 {
02580 *q++='\n';
02581 p++;
02582 continue;
02583 }
02584 if (*p == '\\')
02585 {
02586 p++;
02587 *q++=(*p);
02588 continue;
02589 }
02590 if (*p != '%')
02591 {
02592 *q++=(*p);
02593 continue;
02594 }
02595 p++;
02596 switch (*p)
02597 {
02598 case 'b':
02599 {
02600 char
02601 format[MaxTextExtent];
02602
02603 MagickSizeType
02604 length;
02605
02606
02607
02608
02609 length=GetBlobSize(image);
02610 (void) FormatMagickString(format,MaxTextExtent,"%lu",(unsigned long)
02611 length);
02612 if (length != (MagickSizeType) ((size_t) length))
02613 (void) FormatMagickSize(length,format);
02614 q+=ConcatenateMagickString(q,format,extent);
02615 break;
02616 }
02617 case 'c':
02618 {
02619
02620
02621
02622 value=GetImageProperty(image,"comment");
02623 if (value == (const char *) NULL)
02624 break;
02625 length=strlen(value);
02626 if ((size_t) (q-interpret_text+length+1) >= extent)
02627 {
02628 extent+=length;
02629 interpret_text=(char *) ResizeQuantumMemory(interpret_text,
02630 extent+MaxTextExtent,sizeof(*interpret_text));
02631 if (interpret_text == (char *) NULL)
02632 break;
02633 q=interpret_text+strlen(interpret_text);
02634 }
02635 (void) CopyMagickString(q,value,extent);
02636 q+=length;
02637 break;
02638 }
02639 case 'd':
02640 case 'e':
02641 case 'f':
02642 case 't':
02643 {
02644
02645
02646
02647 if (*image->magick_filename == '\0')
02648 break;
02649 switch (*p)
02650 {
02651 case 'd':
02652 {
02653
02654
02655
02656 GetPathComponent(image->magick_filename,HeadPath,filename);
02657 q+=CopyMagickString(q,filename,extent);
02658 break;
02659 }
02660 case 'e':
02661 {
02662
02663
02664
02665 GetPathComponent(image->magick_filename,ExtensionPath,filename);
02666 q+=CopyMagickString(q,filename,extent);
02667 break;
02668 }
02669 case 'f':
02670 {
02671
02672
02673
02674 GetPathComponent(image->magick_filename,TailPath,filename);
02675 q+=CopyMagickString(q,filename,extent);
02676 break;
02677 }
02678 case 't':
02679 {
02680
02681
02682
02683 GetPathComponent(image->magick_filename,BasePath,filename);
02684 q+=CopyMagickString(q,filename,extent);
02685 break;
02686 }
02687 }
02688 break;
02689 }
02690 case 'g':
02691 {
02692
02693
02694
02695 q+=FormatMagickString(q,extent,"%lux%lu%+ld%+ld",image->page.width,
02696 image->page.height,image->page.x,image->page.y);
02697 break;
02698 }
02699 case 'h':
02700 {
02701
02702
02703
02704 q+=FormatMagickString(q,extent,"%lu",image->rows != 0 ? image->rows :
02705 image->magick_rows);
02706 break;
02707 }
02708 case 'i':
02709 {
02710
02711
02712
02713 q+=CopyMagickString(q,image->filename,extent);
02714 break;
02715 }
02716 case 'k':
02717 {
02718
02719
02720
02721 q+=FormatMagickString(q,extent,"%lu",GetNumberColors(image,
02722 (FILE *) NULL,&image->exception));
02723 break;
02724 }
02725 case 'l':
02726 {
02727
02728
02729
02730 value=GetImageProperty(image,"label");
02731 if (value == (const char *) NULL)
02732 break;
02733 length=strlen(value);
02734 if ((size_t) (q-interpret_text+length+1) >= extent)
02735 {
02736 extent+=length;
02737 interpret_text=(char *) ResizeQuantumMemory(interpret_text,
02738 extent+MaxTextExtent,sizeof(*interpret_text));
02739 if (interpret_text == (char *) NULL)
02740 break;
02741 q=interpret_text+strlen(interpret_text);
02742 }
02743 q+=CopyMagickString(q,value,extent);
02744 break;
02745 }
02746 case 'm':
02747 {
02748
02749
02750
02751 q+=CopyMagickString(q,image->magick,extent);
02752 break;
02753 }
02754 case 'M':
02755 {
02756
02757
02758
02759 q+=CopyMagickString(q,image->magick_filename,extent);
02760 break;
02761 }
02762 case 'n':
02763 {
02764
02765
02766
02767 q+=FormatMagickString(q,extent,"%lu",(unsigned long)
02768 GetImageListLength(image));
02769 break;
02770 }
02771 case 'o':
02772 {
02773
02774
02775
02776 q+=CopyMagickString(q,text_info->filename,extent);
02777 break;
02778 }
02779 case 'p':
02780 {
02781 register const Image
02782 *p;
02783
02784 unsigned long
02785 page;
02786
02787
02788
02789
02790 p=image;
02791 for (page=1; GetPreviousImageInList(p) != (Image *) NULL; page++)
02792 p=GetPreviousImageInList(p);
02793 q+=FormatMagickString(q,extent,"%lu",page);
02794 break;
02795 }
02796 case 'q':
02797 {
02798
02799
02800
02801 q+=FormatMagickString(q,extent,"%lu",image->depth);
02802 break;
02803 }
02804 case 'r':
02805 {
02806 ColorspaceType
02807 colorspace;
02808
02809
02810
02811
02812 colorspace=image->colorspace;
02813 if (IsGrayImage(image,&image->exception) != MagickFalse)
02814 colorspace=GRAYColorspace;
02815 q+=FormatMagickString(q,extent,"%s%s%s",MagickOptionToMnemonic(
02816 MagickClassOptions,(long) image->storage_class),
02817 MagickOptionToMnemonic(MagickColorspaceOptions,(long) colorspace),
02818 image->matte != MagickFalse ? "Matte" : "");
02819 break;
02820 }
02821 case 's':
02822 {
02823
02824
02825
02826 if (text_info->number_scenes == 0)
02827 q+=FormatMagickString(q,extent,"%lu",image->scene);
02828 else
02829 q+=FormatMagickString(q,extent,"%lu",text_info->scene);
02830 break;
02831 }
02832 case 'u':
02833 {
02834
02835
02836
02837 (void) CopyMagickString(filename,text_info->unique,extent);
02838 q+=CopyMagickString(q,filename,extent);
02839 break;
02840 }
02841 case 'w':
02842 {
02843
02844
02845
02846 q+=FormatMagickString(q,extent,"%lu",image->columns != 0 ?
02847 image->columns : image->magick_columns);
02848 break;
02849 }
02850 case 'x':
02851 {
02852
02853
02854
02855 q+=FormatMagickString(q,extent,"%g %s",image->x_resolution,
02856 MagickOptionToMnemonic(MagickResolutionOptions,(long) image->units));
02857 break;
02858 }
02859 case 'y':
02860 {
02861
02862
02863
02864 q+=FormatMagickString(q,extent,"%g %s",image->y_resolution,
02865 MagickOptionToMnemonic(MagickResolutionOptions,(long) image->units));
02866 break;
02867 }
02868 case 'z':
02869 {
02870
02871
02872
02873 q+=FormatMagickString(q,extent,"%lu",image->depth);
02874 break;
02875 }
02876 case 'A':
02877 {
02878
02879
02880
02881 q+=FormatMagickString(q,extent,"%s",MagickOptionToMnemonic(
02882 MagickBooleanOptions,(long) image->matte));
02883 break;
02884 }
02885 case 'C':
02886 {
02887
02888
02889
02890 q+=FormatMagickString(q,extent,"%s",MagickOptionToMnemonic(
02891 MagickCompressOptions,(long) image->compression));
02892 break;
02893 }
02894 case 'D':
02895 {
02896
02897
02898
02899 q+=FormatMagickString(q,extent,"%s",MagickOptionToMnemonic(
02900 MagickDisposeOptions,(long) image->dispose));
02901 break;
02902 }
02903 case 'G':
02904 {
02905 q+=FormatMagickString(q,extent,"%lux%lu",image->magick_columns,
02906 image->magick_rows);
02907 break;
02908 }
02909 case 'H':
02910 {
02911 q+=FormatMagickString(q,extent,"%ld",image->page.height);
02912 break;
02913 }
02914 case 'O':
02915 {
02916 q+=FormatMagickString(q,extent,"%+ld%+ld",image->page.x,image->page.y);
02917 break;
02918 }
02919 case 'P':
02920 {
02921 q+=FormatMagickString(q,extent,"%lux%lu",image->page.width,
02922 image->page.height);
02923 break;
02924 }
02925 case 'Q':
02926 {
02927 q+=FormatMagickString(q,extent,"%lu",image->quality);
02928 break;
02929 }
02930 case 'S':
02931 {
02932
02933
02934
02935 if (text_info->number_scenes == 0)
02936 q+=CopyMagickString(q,"2147483647",extent);
02937 else
02938 q+=FormatMagickString(q,extent,"%lu",text_info->scene+
02939 text_info->number_scenes);
02940 break;
02941 }
02942 case 'T':
02943 {
02944 q+=FormatMagickString(q,extent,"%lu",image->delay);
02945 break;
02946 }
02947 case 'W':
02948 {
02949 q+=FormatMagickString(q,extent,"%ld",image->page.width);
02950 break;
02951 }
02952 case 'X':
02953 {
02954 q+=FormatMagickString(q,extent,"%+ld",image->page.x);
02955 break;
02956 }
02957 case 'Y':
02958 {
02959 q+=FormatMagickString(q,extent,"%+ld",image->page.y);
02960 break;
02961 }
02962 case 'Z':
02963 {
02964
02965
02966
02967 (void) CopyMagickString(filename,text_info->zero,extent);
02968 q+=CopyMagickString(q,filename,extent);
02969 break;
02970 }
02971 case '[':
02972 {
02973 char
02974 pattern[MaxTextExtent];
02975
02976 const char
02977 *key,
02978 *value;
02979
02980 long
02981 depth;
02982
02983
02984
02985
02986 if (strchr(p,']') == (char *) NULL)
02987 break;
02988 depth=1;
02989 p++;
02990 for (i=0; (i < (MaxTextExtent-1L)) && (*p != '\0'); i++)
02991 {
02992 if (*p == '[')
02993 depth++;
02994 if (*p == ']')
02995 depth--;
02996 if (depth <= 0)
02997 break;
02998 pattern[i]=(*p++);
02999 }
03000 pattern[i]='\0';
03001 value=GetImageProperty(image,pattern);
03002 if (value != (const char *) NULL)
03003 {
03004 length=strlen(value);
03005 if ((size_t) (q-interpret_text+length+1) >= extent)
03006 {
03007 extent+=length;
03008 interpret_text=(char *) ResizeQuantumMemory(interpret_text,
03009 extent+MaxTextExtent,sizeof(*interpret_text));
03010 if (interpret_text == (char *) NULL)
03011 break;
03012 q=interpret_text+strlen(interpret_text);
03013 }
03014 (void) CopyMagickString(q,value,extent);
03015 q+=length;
03016 break;
03017 }
03018 else
03019 if (IsGlob(pattern) != MagickFalse)
03020 {
03021
03022
03023
03024 ResetImagePropertyIterator(image);
03025 key=GetNextImageProperty(image);
03026 while (key != (const char *) NULL)
03027 {
03028 if (GlobExpression(key,pattern,MagickTrue) != MagickFalse)
03029 {
03030 value=GetImageProperty(image,key);
03031 if (value != (const char *) NULL)
03032 {
03033 length=strlen(key)+strlen(value)+2;
03034 if ((size_t) (q-interpret_text+length+1) >= extent)
03035 {
03036 extent+=length;
03037 interpret_text=(char *) ResizeQuantumMemory(
03038 interpret_text,extent+MaxTextExtent,
03039 sizeof(*interpret_text));
03040 if (interpret_text == (char *) NULL)
03041 break;
03042 q=interpret_text+strlen(interpret_text);
03043 }
03044 q+=FormatMagickString(q,extent,"%s=%s\n",key,value);
03045 }
03046 }
03047 key=GetNextImageProperty(image);
03048 }
03049 }
03050 value=GetMagickProperty(text_info,image,pattern);
03051 if (value != (const char *) NULL)
03052 {
03053 length=strlen(value);
03054 if ((size_t) (q-interpret_text+length+1) >= extent)
03055 {
03056 extent+=length;
03057 interpret_text=(char *) ResizeQuantumMemory(interpret_text,
03058 extent+MaxTextExtent,sizeof(*interpret_text));
03059 if (interpret_text == (char *) NULL)
03060 break;
03061 q=interpret_text+strlen(interpret_text);
03062 }
03063 (void) CopyMagickString(q,value,extent);
03064 q+=length;
03065 }
03066 if (image_info == (ImageInfo *) NULL)
03067 break;
03068 value=GetImageOption(image_info,pattern);
03069 if (value != (char *) NULL)
03070 {
03071 length=strlen(value);
03072 if ((size_t) (q-interpret_text+length+1) >= extent)
03073 {
03074 extent+=length;
03075 interpret_text=(char *) ResizeQuantumMemory(interpret_text,
03076 extent+MaxTextExtent,sizeof(*interpret_text));
03077 if (interpret_text == (char *) NULL)
03078 break;
03079 q=interpret_text+strlen(interpret_text);
03080 }
03081 (void) CopyMagickString(q,value,extent);
03082 q+=length;
03083 }
03084 break;
03085 }
03086 case '@':
03087 {
03088 RectangleInfo
03089 page;
03090
03091
03092
03093
03094 page=GetImageBoundingBox(image,&image->exception);
03095 q+=FormatMagickString(q,MaxTextExtent,"%lux%lu%+ld%+ld",page.width,
03096 page.height,page.x,page.y);
03097 break;
03098 }
03099 case '#':
03100 {
03101
03102
03103
03104 (void) SignatureImage(image);
03105 value=GetImageProperty(image,"signature");
03106 if (value == (const char *) NULL)
03107 break;
03108 q+=CopyMagickString(q,value,extent);
03109 break;
03110 }
03111 case '%':
03112 {
03113 *q++=(*p);
03114 break;
03115 }
03116 default:
03117 {
03118 *q++='%';
03119 *q++=(*p);
03120 break;
03121 }
03122 }
03123 }
03124 *q='\0';
03125 text_info=DestroyImageInfo(text_info);
03126 if (text != (const char *) embed_text)
03127 text=DestroyString(text);
03128 (void) SubstituteString(&interpret_text,"<","<");
03129 (void) SubstituteString(&interpret_text,">",">");
03130 return(interpret_text);
03131 }
03132
03133
03134
03135
03136
03137
03138
03139
03140
03141
03142
03143
03144
03145
03146
03147
03148
03149
03150
03151
03152
03153
03154
03155
03156
03157
03158 MagickExport char *RemoveImageProperty(Image *image,
03159 const char *property)
03160 {
03161 char
03162 *value;
03163
03164 assert(image != (Image *) NULL);
03165 assert(image->signature == MagickSignature);
03166 if (image->debug != MagickFalse)
03167 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
03168 image->filename);
03169 if (image->properties == (void *) NULL)
03170 return((char *) NULL);
03171 value=(char *) RemoveNodeFromSplayTree((SplayTreeInfo *) image->properties,
03172 property);
03173 return(value);
03174 }
03175
03176
03177
03178
03179
03180
03181
03182
03183
03184
03185
03186
03187
03188
03189
03190
03191
03192
03193
03194
03195
03196
03197
03198
03199
03200 MagickExport void ResetImagePropertyIterator(const Image *image)
03201 {
03202 assert(image != (Image *) NULL);
03203 assert(image->signature == MagickSignature);
03204 if (image->debug != MagickFalse)
03205 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
03206 image->filename);
03207 if (image->properties == (void *) NULL)
03208 return;
03209 ResetSplayTreeIterator((SplayTreeInfo *) image->properties);
03210 }
03211
03212
03213
03214
03215
03216
03217
03218
03219
03220
03221
03222
03223
03224
03225
03226
03227
03228
03229
03230
03231
03232
03233
03234
03235
03236
03237
03238
03239 MagickExport MagickBooleanType SetImageProperty(Image *image,
03240 const char *property,const char *value)
03241 {
03242 MagickBooleanType
03243 status;
03244
03245 MagickStatusType
03246 flags;
03247
03248 assert(image != (Image *) NULL);
03249 assert(image->signature == MagickSignature);
03250 if (image->debug != MagickFalse)
03251 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
03252 image->filename);
03253 if (image->properties == (void *) NULL)
03254 image->properties=NewSplayTree(CompareSplayTreeString,
03255 RelinquishMagickMemory,RelinquishMagickMemory);
03256 if ((value == (const char *) NULL) || (*value == '\0'))
03257 return(DeleteImageProperty(image,property));
03258 status=MagickTrue;
03259 switch (*property)
03260 {
03261 case 'B':
03262 case 'b':
03263 {
03264 if (LocaleCompare(property,"bias") == 0)
03265 {
03266 image->bias=StringToDouble(value,QuantumRange);
03267 break;
03268 }
03269 status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
03270 ConstantString(property),ConstantString(value));
03271 break;
03272 }
03273 case 'C':
03274 case 'c':
03275 {
03276 if (LocaleCompare(property,"colorspace") == 0)
03277 {
03278 long
03279 colorspace;
03280
03281 colorspace=ParseMagickOption(MagickColorspaceOptions,MagickFalse,
03282 value);
03283 if (colorspace < 0)
03284 break;
03285 (void) SetImageColorspace(image,(ColorspaceType) colorspace);
03286 break;
03287 }
03288 if (LocaleCompare(property,"compose") == 0)
03289 {
03290 long
03291 compose;
03292
03293 compose=ParseMagickOption(MagickComposeOptions,MagickFalse,value);
03294 if (compose < 0)
03295 break;
03296 image->compose=(CompositeOperator) compose;
03297 break;
03298 }
03299 if (LocaleCompare(property,"compress") == 0)
03300 {
03301 long
03302 compression;
03303
03304 compression=ParseMagickOption(MagickCompressOptions,MagickFalse,
03305 value);
03306 if (compression < 0)
03307 break;
03308 image->compression=(CompressionType) compression;
03309 break;
03310 }
03311 status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
03312 ConstantString(property),ConstantString(value));
03313 break;
03314 }
03315 case 'D':
03316 case 'd':
03317 {
03318 if (LocaleCompare(property,"delay") == 0)
03319 {
03320 GeometryInfo
03321 geometry_info;
03322
03323 flags=ParseGeometry(value,&geometry_info);
03324 if ((flags & GreaterValue) != 0)
03325 {
03326 if (image->delay > (unsigned long) (geometry_info.rho+0.5))
03327 image->delay=(unsigned long) (geometry_info.rho+0.5);
03328 }
03329 else
03330 if ((flags & LessValue) != 0)
03331 {
03332 if (image->delay < (unsigned long) (geometry_info.rho+0.5))
03333 image->ticks_per_second=(long) (geometry_info.sigma+0.5);
03334 }
03335 else
03336 image->delay=(unsigned long) (geometry_info.rho+0.5);
03337 if ((flags & SigmaValue) != 0)
03338 image->ticks_per_second=(long) (geometry_info.sigma+0.5);
03339 break;
03340 }
03341 if (LocaleCompare(property,"depth") == 0)
03342 {
03343 image->depth=(unsigned long) atol(value);
03344 break;
03345 }
03346 if (LocaleCompare(property,"dispose") == 0)
03347 {
03348 long
03349 dispose;
03350
03351 dispose=ParseMagickOption(MagickDisposeOptions,MagickFalse,value);
03352 if (dispose < 0)
03353 break;
03354 image->dispose=(DisposeType) dispose;
03355 break;
03356 }
03357 status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
03358 ConstantString(property),ConstantString(value));
03359 break;
03360 }
03361 case 'G':
03362 case 'g':
03363 {
03364 if (LocaleCompare(property,"gravity") == 0)
03365 {
03366 long
03367 gravity;
03368
03369 gravity=ParseMagickOption(MagickGravityOptions,MagickFalse,value);
03370 if (gravity < 0)
03371 break;
03372 image->gravity=(GravityType) gravity;
03373 break;
03374 }
03375 status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
03376 ConstantString(property),ConstantString(value));
03377 break;
03378 }
03379 case 'I':
03380 case 'i':
03381 {
03382 if (LocaleCompare(property,"intent") == 0)
03383 {
03384 long
03385 rendering_intent;
03386
03387 rendering_intent=ParseMagickOption(MagickIntentOptions,MagickFalse,
03388 value);
03389 if (rendering_intent < 0)
03390 break;
03391 image->rendering_intent=(RenderingIntent) rendering_intent;
03392 break;
03393 }
03394 if (LocaleCompare(property,"interpolate") == 0)
03395 {
03396 long
03397 interpolate;
03398
03399 interpolate=ParseMagickOption(MagickInterpolateOptions,MagickFalse,
03400 value);
03401 if (interpolate < 0)
03402 break;
03403 image->interpolate=(InterpolatePixelMethod) interpolate;
03404 break;
03405 }
03406 status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
03407 ConstantString(property),ConstantString(value));
03408 break;
03409 }
03410 case 'L':
03411 case 'l':
03412 {
03413 if (LocaleCompare(property,"loop") == 0)
03414 {
03415 image->iterations=(unsigned long) atol(value);
03416 break;
03417 }
03418 status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
03419 ConstantString(property),ConstantString(value));
03420 break;
03421 }
03422 case 'P':
03423 case 'p':
03424 {
03425 if (LocaleCompare(property,"page") == 0)
03426 {
03427 char
03428 *geometry;
03429
03430 geometry=GetPageGeometry(value);
03431 flags=ParseAbsoluteGeometry(geometry,&image->page);
03432 geometry=DestroyString(geometry);
03433 break;
03434 }
03435 status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
03436 ConstantString(property),ConstantString(value));
03437 break;
03438 }
03439 case 'R':
03440 case 'r':
03441 {
03442 if (LocaleCompare(property,"rendering-intent") == 0)
03443 {
03444 long
03445 rendering_intent;
03446
03447 rendering_intent=ParseMagickOption(MagickIntentOptions,MagickFalse,
03448 value);
03449 if (rendering_intent < 0)
03450 break;
03451 image->rendering_intent=(RenderingIntent) rendering_intent;
03452 break;
03453 }
03454 status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
03455 ConstantString(property),ConstantString(value));
03456 break;
03457 }
03458 case 'T':
03459 case 't':
03460 {
03461 if (LocaleCompare(property,"tile-offset") == 0)
03462 {
03463 char
03464 *geometry;
03465
03466 geometry=GetPageGeometry(value);
03467 flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
03468 geometry=DestroyString(geometry);
03469 break;
03470 }
03471 status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
03472 ConstantString(property),ConstantString(value));
03473 break;
03474 }
03475 default:
03476 {
03477 status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
03478 ConstantString(property),ConstantString(value));
03479 break;
03480 }
03481 }
03482 return(status);
03483 }