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/cache.h"
00045 #include "magick/color.h"
00046 #include "magick/compare.h"
00047 #include "magick/constitute.h"
00048 #include "magick/draw.h"
00049 #include "magick/effect.h"
00050 #include "magick/exception.h"
00051 #include "magick/exception-private.h"
00052 #include "magick/fx.h"
00053 #include "magick/fx-private.h"
00054 #include "magick/gem.h"
00055 #include "magick/geometry.h"
00056 #include "magick/image.h"
00057 #include "magick/layer.h"
00058 #include "magick/list.h"
00059 #include "magick/memory_.h"
00060 #include "magick/monitor.h"
00061 #include "magick/montage.h"
00062 #include "magick/option.h"
00063 #include "magick/profile.h"
00064 #include "magick/property.h"
00065 #include "magick/quantum.h"
00066 #include "magick/resource_.h"
00067 #include "magick/splay-tree.h"
00068 #include "magick/signature-private.h"
00069 #include "magick/statistic.h"
00070 #include "magick/string_.h"
00071 #include "magick/token.h"
00072 #include "magick/utility.h"
00073 #include "magick/xml-tree.h"
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100 MagickExport MagickBooleanType CloneImageProperties(Image *image,
00101 const Image *clone_image)
00102 {
00103 assert(image != (Image *) NULL);
00104 assert(image->signature == MagickSignature);
00105 if (image->debug != MagickFalse)
00106 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00107 assert(clone_image != (const Image *) NULL);
00108 assert(clone_image->signature == MagickSignature);
00109 if (clone_image->debug != MagickFalse)
00110 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
00111 clone_image->filename);
00112 (void) CopyMagickString(image->filename,clone_image->filename,MaxTextExtent);
00113 (void) CopyMagickString(image->magick_filename,clone_image->magick_filename,
00114 MaxTextExtent);
00115 image->compression=clone_image->compression;
00116 image->quality=clone_image->quality;
00117 image->depth=clone_image->depth;
00118 image->background_color=clone_image->background_color;
00119 image->border_color=clone_image->border_color;
00120 image->matte_color=clone_image->matte_color;
00121 image->transparent_color=clone_image->transparent_color;
00122 image->gamma=clone_image->gamma;
00123 image->chromaticity=clone_image->chromaticity;
00124 image->rendering_intent=clone_image->rendering_intent;
00125 image->black_point_compensation=clone_image->black_point_compensation;
00126 image->units=clone_image->units;
00127 image->montage=(char *) NULL;
00128 image->directory=(char *) NULL;
00129 (void) CloneString(&image->geometry,clone_image->geometry);
00130 image->offset=clone_image->offset;
00131 image->x_resolution=clone_image->x_resolution;
00132 image->y_resolution=clone_image->y_resolution;
00133 image->page=clone_image->page;
00134 image->tile_offset=clone_image->tile_offset;
00135 image->extract_info=clone_image->extract_info;
00136 image->bias=clone_image->bias;
00137 image->filter=clone_image->filter;
00138 image->blur=clone_image->blur;
00139 image->fuzz=clone_image->fuzz;
00140 image->interlace=clone_image->interlace;
00141 image->interpolate=clone_image->interpolate;
00142 image->endian=clone_image->endian;
00143 image->gravity=clone_image->gravity;
00144 image->compose=clone_image->compose;
00145 image->scene=clone_image->scene;
00146 image->orientation=clone_image->orientation;
00147 image->dispose=clone_image->dispose;
00148 image->delay=clone_image->delay;
00149 image->ticks_per_second=clone_image->ticks_per_second;
00150 image->iterations=clone_image->iterations;
00151 image->total_colors=clone_image->total_colors;
00152 image->taint=clone_image->taint;
00153 image->progress_monitor=clone_image->progress_monitor;
00154 image->client_data=clone_image->client_data;
00155 image->start_loop=clone_image->start_loop;
00156 image->error=clone_image->error;
00157 image->signature=clone_image->signature;
00158 if (clone_image->properties != (void *) NULL)
00159 {
00160 if (image->properties != (void *) NULL)
00161 DestroyImageProperties(image);
00162 image->properties=CloneSplayTree((SplayTreeInfo *)
00163 clone_image->properties,(void *(*)(void *)) ConstantString,
00164 (void *(*)(void *)) ConstantString);
00165 }
00166 return(MagickTrue);
00167 }
00168
00169
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 MagickExport MagickBooleanType DefineImageProperty(Image *image,
00195 const char *property)
00196 {
00197 char
00198 key[MaxTextExtent],
00199 value[MaxTextExtent];
00200
00201 register char
00202 *p;
00203
00204 assert(image != (Image *) NULL);
00205 assert(property != (const char *) NULL);
00206 (void) CopyMagickString(key,property,MaxTextExtent-1);
00207 for (p=key; *p != '\0'; p++)
00208 if (*p == '=')
00209 break;
00210 *value='\0';
00211 if (*p == '=')
00212 (void) CopyMagickString(value,p+1,MaxTextExtent);
00213 *p='\0';
00214 return(SetImageProperty(image,key,value));
00215 }
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241 MagickExport MagickBooleanType DeleteImageProperty(Image *image,
00242 const char *property)
00243 {
00244 assert(image != (Image *) NULL);
00245 assert(image->signature == MagickSignature);
00246 if (image->debug != MagickFalse)
00247 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
00248 image->filename);
00249 if (image->properties == (void *) NULL)
00250 return(MagickFalse);
00251 return(DeleteNodeFromSplayTree((SplayTreeInfo *) image->properties,property));
00252 }
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277 MagickExport void DestroyImageProperties(Image *image)
00278 {
00279 assert(image != (Image *) NULL);
00280 assert(image->signature == MagickSignature);
00281 if (image->debug != MagickFalse)
00282 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
00283 image->filename);
00284 if (image->properties != (void *) NULL)
00285 image->properties=(void *) DestroySplayTree((SplayTreeInfo *)
00286 image->properties);
00287 }
00288
00289
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 MagickExport MagickBooleanType FormatImagePropertyList(Image *image,
00320 const char *property,const char *format,va_list operands)
00321 {
00322 char
00323 value[MaxTextExtent];
00324
00325 int
00326 n;
00327
00328 #if defined(MAGICKCORE_HAVE_VSNPRINTF)
00329 n=vsnprintf(value,MaxTextExtent,format,operands);
00330 #else
00331 n=vsprintf(value,format,operands);
00332 #endif
00333 if (n < 0)
00334 value[MaxTextExtent-1]='\0';
00335 return(SetImageProperty(image,property,value));
00336 }
00337
00338 MagickExport MagickBooleanType FormatImageProperty(Image *image,
00339 const char *property,const char *format,...)
00340 {
00341 MagickBooleanType
00342 status;
00343
00344 va_list
00345 operands;
00346
00347 va_start(operands,format);
00348 status=FormatImagePropertyList(image,property,format,operands);
00349 va_end(operands);
00350 return(status);
00351 }
00352
00353
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 static char
00379 *TracePSClippath(const unsigned char *,size_t,const unsigned long,
00380 const unsigned long),
00381 *TraceSVGClippath(const unsigned char *,size_t,const unsigned long,
00382 const unsigned long);
00383
00384 static MagickBooleanType GetIPTCProperty(const Image *image,const char *key)
00385 {
00386 char
00387 *attribute,
00388 *message;
00389
00390 const StringInfo
00391 *profile;
00392
00393 long
00394 count,
00395 dataset,
00396 record;
00397
00398 register long
00399 i;
00400
00401 size_t
00402 length;
00403
00404 profile=GetImageProfile(image,"iptc");
00405 if (profile == (StringInfo *) NULL)
00406 profile=GetImageProfile(image,"8bim");
00407 if (profile == (StringInfo *) NULL)
00408 return(MagickFalse);
00409 count=sscanf(key,"IPTC:%ld:%ld",&dataset,&record);
00410 if (count != 2)
00411 return(MagickFalse);
00412 attribute=(char *) NULL;
00413 for (i=0; i < (long) GetStringInfoLength(profile); i+=(long) length)
00414 {
00415 length=1;
00416 if ((long) GetStringInfoDatum(profile)[i] != 0x1c)
00417 continue;
00418 length=(size_t) (GetStringInfoDatum(profile)[i+3] << 8);
00419 length|=GetStringInfoDatum(profile)[i+4];
00420 if (((long) GetStringInfoDatum(profile)[i+1] == dataset) &&
00421 ((long) GetStringInfoDatum(profile)[i+2] == record))
00422 {
00423 message=(char *) NULL;
00424 if (~length >= 1)
00425 message=(char *) AcquireQuantumMemory(length+1UL,sizeof(*message));
00426 if (message != (char *) NULL)
00427 {
00428 (void) CopyMagickString(message,(char *) GetStringInfoDatum(
00429 profile)+i+5,length+1);
00430 (void) ConcatenateString(&attribute,message);
00431 (void) ConcatenateString(&attribute,";");
00432 message=DestroyString(message);
00433 }
00434 }
00435 i+=5;
00436 }
00437 if ((attribute == (char *) NULL) || (*attribute == ';'))
00438 {
00439 if (attribute != (char *) NULL)
00440 attribute=DestroyString(attribute);
00441 return(MagickFalse);
00442 }
00443 attribute[strlen(attribute)-1]='\0';
00444 (void) SetImageProperty((Image *) image,key,(const char *) attribute);
00445 attribute=DestroyString(attribute);
00446 return(MagickTrue);
00447 }
00448
00449 static inline long MagickMax(const long x,const long y)
00450 {
00451 if (x > y)
00452 return(x);
00453 return(y);
00454 }
00455
00456 static inline int ReadPropertyByte(const unsigned char **p,size_t *length)
00457 {
00458 int
00459 c;
00460
00461 if (*length < 1)
00462 return(EOF);
00463 c=(int) (*(*p)++);
00464 (*length)--;
00465 return(c);
00466 }
00467
00468 static inline unsigned long ReadPropertyMSBLong(const unsigned char **p,
00469 size_t *length)
00470 {
00471 int
00472 c;
00473
00474 register long
00475 i;
00476
00477 unsigned char
00478 buffer[4];
00479
00480 unsigned long
00481 value;
00482
00483 if (*length < 4)
00484 return(~0UL);
00485 for (i=0; i < 4; i++)
00486 {
00487 c=(int) (*(*p)++);
00488 (*length)--;
00489 buffer[i]=(unsigned char) c;
00490 }
00491 value=(unsigned long) (buffer[0] << 24);
00492 value|=buffer[1] << 16;
00493 value|=buffer[2] << 8;
00494 value|=buffer[3];
00495 return(value & 0xffffffff);
00496 }
00497
00498 static inline unsigned short ReadPropertyMSBShort(const unsigned char **p,
00499 size_t *length)
00500 {
00501 int
00502 c;
00503
00504 register long
00505 i;
00506
00507 unsigned char
00508 buffer[2];
00509
00510 unsigned short
00511 value;
00512
00513 if (*length < 2)
00514 return((unsigned short) ~0U);
00515 for (i=0; i < 2; i++)
00516 {
00517 c=(int) (*(*p)++);
00518 (*length)--;
00519 buffer[i]=(unsigned char) c;
00520 }
00521 value=(unsigned short) (buffer[0] << 8);
00522 value|=buffer[1];
00523 return((unsigned short) (value & 0xffff));
00524 }
00525
00526 static MagickBooleanType Get8BIMProperty(const Image *image,const char *key)
00527 {
00528 char
00529 *attribute,
00530 format[MaxTextExtent],
00531 name[MaxTextExtent],
00532 *resource;
00533
00534 const StringInfo
00535 *profile;
00536
00537 const unsigned char
00538 *info;
00539
00540 long
00541 id,
00542 start,
00543 stop,
00544 sub_number;
00545
00546 MagickBooleanType
00547 status;
00548
00549 register long
00550 i;
00551
00552 ssize_t
00553 count;
00554
00555 size_t
00556 length;
00557
00558
00559
00560
00561 profile=GetImageProfile(image,"8bim");
00562 if (profile == (StringInfo *) NULL)
00563 return(MagickFalse);
00564 count=(ssize_t) sscanf(key,"8BIM:%ld,%ld:%[^\n]\n%[^\n]",&start,&stop,name,
00565 format);
00566 if ((count != 2) && (count != 3) && (count != 4))
00567 return(MagickFalse);
00568 if (count < 4)
00569 (void) CopyMagickString(format,"SVG",MaxTextExtent);
00570 if (count < 3)
00571 *name='\0';
00572 sub_number=1;
00573 if (*name == '#')
00574 sub_number=atol(&name[1]);
00575 sub_number=MagickMax(sub_number,1L);
00576 resource=(char *) NULL;
00577 status=MagickFalse;
00578 length=GetStringInfoLength(profile);
00579 info=GetStringInfoDatum(profile);
00580 while ((length > 0) && (status == MagickFalse))
00581 {
00582 if (ReadPropertyByte(&info,&length) != (unsigned char) '8')
00583 continue;
00584 if (ReadPropertyByte(&info,&length) != (unsigned char) 'B')
00585 continue;
00586 if (ReadPropertyByte(&info,&length) != (unsigned char) 'I')
00587 continue;
00588 if (ReadPropertyByte(&info,&length) != (unsigned char) 'M')
00589 continue;
00590 id=(long) ReadPropertyMSBShort(&info,&length);
00591 if (id < start)
00592 continue;
00593 if (id > stop)
00594 continue;
00595 if (resource != (char *) NULL)
00596 resource=DestroyString(resource);
00597 count=(ssize_t) ReadPropertyByte(&info,&length);
00598 if ((count != 0) && ((size_t) count <= length))
00599 {
00600 resource=(char *) NULL;
00601 if (~(1UL*count) >= MaxTextExtent)
00602 resource=(char *) AcquireQuantumMemory((size_t) count+MaxTextExtent,
00603 sizeof(*resource));
00604 if (resource != (char *) NULL)
00605 {
00606 for (i=0; i < (long) count; i++)
00607 resource[i]=(char) ReadPropertyByte(&info,&length);
00608 resource[count]='\0';
00609 }
00610 }
00611 if ((count & 0x01) == 0)
00612 (void) ReadPropertyByte(&info,&length);
00613 count=(ssize_t) ReadPropertyMSBLong(&info,&length);
00614 if ((*name != '\0') && (*name != '#'))
00615 if ((resource == (char *) NULL) || (LocaleCompare(name,resource) != 0))
00616 {
00617
00618
00619
00620 info+=count;
00621 length-=count;
00622 continue;
00623 }
00624 if ((*name == '#') && (sub_number != 1))
00625 {
00626
00627
00628
00629 sub_number--;
00630 info+=count;
00631 length-=count;
00632 continue;
00633 }
00634
00635
00636
00637 attribute=(char *) NULL;
00638 if (~(1UL*count) >= MaxTextExtent)
00639 attribute=(char *) AcquireQuantumMemory((size_t) count+MaxTextExtent,
00640 sizeof(*attribute));
00641 if (attribute != (char *) NULL)
00642 {
00643 (void) CopyMagickMemory(attribute,(char *) info,(size_t) count);
00644 attribute[count]='\0';
00645 info+=count;
00646 length-=count;
00647 if ((id <= 1999) || (id >= 2999))
00648 (void) SetImageProperty((Image *) image,key,(const char *)
00649 attribute);
00650 else
00651 {
00652 char
00653 *path;
00654
00655 if (LocaleCompare(format,"svg") == 0)
00656 path=TraceSVGClippath((unsigned char *) attribute,(size_t) count,
00657 image->columns,image->rows);
00658 else
00659 path=TracePSClippath((unsigned char *) attribute,(size_t) count,
00660 image->columns,image->rows);
00661 (void) SetImageProperty((Image *) image,key,(const char *) path);
00662 path=DestroyString(path);
00663 }
00664 attribute=DestroyString(attribute);
00665 status=MagickTrue;
00666 }
00667 }
00668 if (resource != (char *) NULL)
00669 resource=DestroyString(resource);
00670 return(status);
00671 }
00672
00673 static inline unsigned short ReadPropertyShort(const EndianType endian,
00674 const unsigned char *buffer)
00675 {
00676 unsigned short
00677 value;
00678
00679 if (endian == MSBEndian)
00680 {
00681 value=(unsigned short) ((((unsigned char *) buffer)[0] << 8) |
00682 ((unsigned char *) buffer)[1]);
00683 return((unsigned short) (value & 0xffff));
00684 }
00685 value=(unsigned short) ((buffer[1] << 8) | buffer[0]);
00686 return((unsigned short) (value & 0xffff));
00687 }
00688
00689 static inline unsigned long ReadPropertyLong(const EndianType endian,
00690 const unsigned char *buffer)
00691 {
00692 unsigned long
00693 value;
00694
00695 if (endian == MSBEndian)
00696 {
00697 value=(unsigned long) ((buffer[0] << 24) | (buffer[1] << 16) |
00698 (buffer[2] << 8) | buffer[3]);
00699 return((unsigned long) (value & 0xffffffff));
00700 }
00701 value=(unsigned long) ((buffer[3] << 24) | (buffer[2] << 16) |
00702 (buffer[1] << 8 ) | (buffer[0]));
00703 return((unsigned long) (value & 0xffffffff));
00704 }
00705
00706 static MagickBooleanType GetEXIFProperty(const Image *image,
00707 const char *property)
00708 {
00709 #define MaxDirectoryStack 16
00710 #define EXIF_DELIMITER "\n"
00711 #define EXIF_NUM_FORMATS 12
00712 #define EXIF_FMT_BYTE 1
00713 #define EXIF_FMT_STRING 2
00714 #define EXIF_FMT_USHORT 3
00715 #define EXIF_FMT_ULONG 4
00716 #define EXIF_FMT_URATIONAL 5
00717 #define EXIF_FMT_SBYTE 6
00718 #define EXIF_FMT_UNDEFINED 7
00719 #define EXIF_FMT_SSHORT 8
00720 #define EXIF_FMT_SLONG 9
00721 #define EXIF_FMT_SRATIONAL 10
00722 #define EXIF_FMT_SINGLE 11
00723 #define EXIF_FMT_DOUBLE 12
00724 #define TAG_EXIF_OFFSET 0x8769
00725 #define TAG_GPS_OFFSET 0x8825
00726 #define TAG_INTEROP_OFFSET 0xa005
00727
00728 #define EXIFMultipleValues(size, format, arg) \
00729 { \
00730 long component; \
00731 size_t used_space; \
00732 unsigned char *p1; \
00733 used_space=0; \
00734 p1=p; \
00735 for (component = 0; component < components; component++) \
00736 { \
00737 used_space+=FormatMagickString(buffer+used_space, \
00738 MaxTextExtent-used_space,format", ",arg); \
00739 if (used_space >= MaxTextExtent - 1) \
00740 used_space=MaxTextExtent-1; \
00741 p1+=size; \
00742 } \
00743 buffer[used_space-2]='\0'; \
00744 value=AcquireString(buffer); \
00745 }
00746
00747 #define EXIFMultipleFractions(size, format, arg1, arg2) \
00748 { \
00749 long component; \
00750 size_t used_space; \
00751 unsigned char *p1; \
00752 used_space=0; \
00753 p1=p; \
00754 for (component = 0; component < components; component++) \
00755 { \
00756 used_space+=FormatMagickString(buffer+used_space, \
00757 MaxTextExtent-used_space,format", ",arg1, arg2); \
00758 if (used_space >= MaxTextExtent - 1) \
00759 used_space=MaxTextExtent-1; \
00760 p1+=size; \
00761 } \
00762 buffer[used_space-2]='\0'; \
00763 value=AcquireString(buffer); \
00764 }
00765
00766 typedef struct _DirectoryInfo
00767 {
00768 const unsigned char
00769 *directory;
00770
00771 unsigned long
00772 entry,
00773 offset;
00774 } DirectoryInfo;
00775
00776 typedef struct _TagInfo
00777 {
00778 unsigned long
00779 tag;
00780
00781 const char
00782 *description;
00783 } TagInfo;
00784
00785 static TagInfo
00786 EXIFTag[] =
00787 {
00788 { 0x001, "exif:InteroperabilityIndex" },
00789 { 0x002, "exif:InteroperabilityVersion" },
00790 { 0x100, "exif:ImageWidth" },
00791 { 0x101, "exif:ImageLength" },
00792 { 0x102, "exif:BitsPerSample" },
00793 { 0x103, "exif:Compression" },
00794 { 0x106, "exif:PhotometricInterpretation" },
00795 { 0x10a, "exif:FillOrder" },
00796 { 0x10d, "exif:DocumentName" },
00797 { 0x10e, "exif:ImageDescription" },
00798 { 0x10f, "exif:Make" },
00799 { 0x110, "exif:Model" },
00800 { 0x111, "exif:StripOffsets" },
00801 { 0x112, "exif:Orientation" },
00802 { 0x115, "exif:SamplesPerPixel" },
00803 { 0x116, "exif:RowsPerStrip" },
00804 { 0x117, "exif:StripByteCounts" },
00805 { 0x11a, "exif:XResolution" },
00806 { 0x11b, "exif:YResolution" },
00807 { 0x11c, "exif:PlanarConfiguration" },
00808 { 0x11d, "exif:PageName" },
00809 { 0x11e, "exif:XPosition" },
00810 { 0x11f, "exif:YPosition" },
00811 { 0x118, "exif:MinSampleValue" },
00812 { 0x119, "exif:MaxSampleValue" },
00813 { 0x120, "exif:FreeOffsets" },
00814 { 0x121, "exif:FreeByteCounts" },
00815 { 0x122, "exif:GrayResponseUnit" },
00816 { 0x123, "exif:GrayResponseCurve" },
00817 { 0x124, "exif:T4Options" },
00818 { 0x125, "exif:T6Options" },
00819 { 0x128, "exif:ResolutionUnit" },
00820 { 0x12d, "exif:TransferFunction" },
00821 { 0x131, "exif:Software" },
00822 { 0x132, "exif:DateTime" },
00823 { 0x13b, "exif:Artist" },
00824 { 0x13e, "exif:WhitePoint" },
00825 { 0x13f, "exif:PrimaryChromaticities" },
00826 { 0x140, "exif:ColorMap" },
00827 { 0x141, "exif:HalfToneHints" },
00828 { 0x142, "exif:TileWidth" },
00829 { 0x143, "exif:TileLength" },
00830 { 0x144, "exif:TileOffsets" },
00831 { 0x145, "exif:TileByteCounts" },
00832 { 0x14a, "exif:SubIFD" },
00833 { 0x14c, "exif:InkSet" },
00834 { 0x14d, "exif:InkNames" },
00835 { 0x14e, "exif:NumberOfInks" },
00836 { 0x150, "exif:DotRange" },
00837 { 0x151, "exif:TargetPrinter" },
00838 { 0x152, "exif:ExtraSample" },
00839 { 0x153, "exif:SampleFormat" },
00840 { 0x154, "exif:SMinSampleValue" },
00841 { 0x155, "exif:SMaxSampleValue" },
00842 { 0x156, "exif:TransferRange" },
00843 { 0x157, "exif:ClipPath" },
00844 { 0x158, "exif:XClipPathUnits" },
00845 { 0x159, "exif:YClipPathUnits" },
00846 { 0x15a, "exif:Indexed" },
00847 { 0x15b, "exif:JPEGTables" },
00848 { 0x15f, "exif:OPIProxy" },
00849 { 0x200, "exif:JPEGProc" },
00850 { 0x201, "exif:JPEGInterchangeFormat" },
00851 { 0x202, "exif:JPEGInterchangeFormatLength" },
00852 { 0x203, "exif:JPEGRestartInterval" },
00853 { 0x205, "exif:JPEGLosslessPredictors" },
00854 { 0x206, "exif:JPEGPointTransforms" },
00855 { 0x207, "exif:JPEGQTables" },
00856 { 0x208, "exif:JPEGDCTables" },
00857 { 0x209, "exif:JPEGACTables" },
00858 { 0x211, "exif:YCbCrCoefficients" },
00859 { 0x212, "exif:YCbCrSubSampling" },
00860 { 0x213, "exif:YCbCrPositioning" },
00861 { 0x214, "exif:ReferenceBlackWhite" },
00862 { 0x2bc, "exif:ExtensibleMetadataPlatform" },
00863 { 0x301, "exif:Gamma" },
00864 { 0x302, "exif:ICCProfileDescriptor" },
00865 { 0x303, "exif:SRGBRenderingIntent" },
00866 { 0x320, "exif:ImageTitle" },
00867 { 0x5001, "exif:ResolutionXUnit" },
00868 { 0x5002, "exif:ResolutionYUnit" },
00869 { 0x5003, "exif:ResolutionXLengthUnit" },
00870 { 0x5004, "exif:ResolutionYLengthUnit" },
00871 { 0x5005, "exif:PrintFlags" },
00872 { 0x5006, "exif:PrintFlagsVersion" },
00873 { 0x5007, "exif:PrintFlagsCrop" },
00874 { 0x5008, "exif:PrintFlagsBleedWidth" },
00875 { 0x5009, "exif:PrintFlagsBleedWidthScale" },
00876 { 0x500A, "exif:HalftoneLPI" },
00877 { 0x500B, "exif:HalftoneLPIUnit" },
00878 { 0x500C, "exif:HalftoneDegree" },
00879 { 0x500D, "exif:HalftoneShape" },
00880 { 0x500E, "exif:HalftoneMisc" },
00881 { 0x500F, "exif:HalftoneScreen" },
00882 { 0x5010, "exif:JPEGQuality" },
00883 { 0x5011, "exif:GridSize" },
00884 { 0x5012, "exif:ThumbnailFormat" },
00885 { 0x5013, "exif:ThumbnailWidth" },
00886 { 0x5014, "exif:ThumbnailHeight" },
00887 { 0x5015, "exif:ThumbnailColorDepth" },
00888 { 0x5016, "exif:ThumbnailPlanes" },
00889 { 0x5017, "exif:ThumbnailRawBytes" },
00890 { 0x5018, "exif:ThumbnailSize" },
00891 { 0x5019, "exif:ThumbnailCompressedSize" },
00892 { 0x501a, "exif:ColorTransferFunction" },
00893 { 0x501b, "exif:ThumbnailData" },
00894 { 0x5020, "exif:ThumbnailImageWidth" },
00895 { 0x5021, "exif:ThumbnailImageHeight" },
00896 { 0x5022, "exif:ThumbnailBitsPerSample" },
00897 { 0x5023, "exif:ThumbnailCompression" },
00898 { 0x5024, "exif:ThumbnailPhotometricInterp" },
00899 { 0x5025, "exif:ThumbnailImageDescription" },
00900 { 0x5026, "exif:ThumbnailEquipMake" },
00901 { 0x5027, "exif:ThumbnailEquipModel" },
00902 { 0x5028, "exif:ThumbnailStripOffsets" },
00903 { 0x5029, "exif:ThumbnailOrientation" },
00904 { 0x502a, "exif:ThumbnailSamplesPerPixel" },
00905 { 0x502b, "exif:ThumbnailRowsPerStrip" },
00906 { 0x502c, "exif:ThumbnailStripBytesCount" },
00907 { 0x502d, "exif:ThumbnailResolutionX" },
00908 { 0x502e, "exif:ThumbnailResolutionY" },
00909 { 0x502f, "exif:ThumbnailPlanarConfig" },
00910 { 0x5030, "exif:ThumbnailResolutionUnit" },
00911 { 0x5031, "exif:ThumbnailTransferFunction" },
00912 { 0x5032, "exif:ThumbnailSoftwareUsed" },
00913 { 0x5033, "exif:ThumbnailDateTime" },
00914 { 0x5034, "exif:ThumbnailArtist" },
00915 { 0x5035, "exif:ThumbnailWhitePoint" },
00916 { 0x5036, "exif:ThumbnailPrimaryChromaticities" },
00917 { 0x5037, "exif:ThumbnailYCbCrCoefficients" },
00918 { 0x5038, "exif:ThumbnailYCbCrSubsampling" },
00919 { 0x5039, "exif:ThumbnailYCbCrPositioning" },
00920 { 0x503A, "exif:ThumbnailRefBlackWhite" },
00921 { 0x503B, "exif:ThumbnailCopyRight" },
00922 { 0x5090, "exif:LuminanceTable" },
00923 { 0x5091, "exif:ChrominanceTable" },
00924 { 0x5100, "exif:FrameDelay" },
00925 { 0x5101, "exif:LoopCount" },
00926 { 0x5110, "exif:PixelUnit" },
00927 { 0x5111, "exif:PixelPerUnitX" },
00928 { 0x5112, "exif:PixelPerUnitY" },
00929 { 0x5113, "exif:PaletteHistogram" },
00930 { 0x1000, "exif:RelatedImageFileFormat" },
00931 { 0x1001, "exif:RelatedImageLength" },
00932 { 0x1002, "exif:RelatedImageWidth" },
00933 { 0x800d, "exif:ImageID" },
00934 { 0x80e3, "exif:Matteing" },
00935 { 0x80e4, "exif:DataType" },
00936 { 0x80e5, "exif:ImageDepth" },
00937 { 0x80e6, "exif:TileDepth" },
00938 { 0x828d, "exif:CFARepeatPatternDim" },
00939 { 0x828e, "exif:CFAPattern2" },
00940 { 0x828f, "exif:BatteryLevel" },
00941 { 0x8298, "exif:Copyright" },
00942 { 0x829a, "exif:ExposureTime" },
00943 { 0x829d, "exif:FNumber" },
00944 { 0x83bb, "exif:IPTC/NAA" },
00945 { 0x84e3, "exif:IT8RasterPadding" },
00946 { 0x84e5, "exif:IT8ColorTable" },
00947 { 0x8649, "exif:ImageResourceInformation" },
00948 { 0x8769, "exif:ExifOffset" },
00949 { 0x8773, "exif:InterColorProfile" },
00950 { 0x8822, "exif:ExposureProgram" },
00951 { 0x8824, "exif:SpectralSensitivity" },
00952 { 0x8825, "exif:GPSInfo" },
00953 { 0x8827, "exif:ISOSpeedRatings" },
00954 { 0x8828, "exif:OECF" },
00955 { 0x8829, "exif:Interlace" },
00956 { 0x882a, "exif:TimeZoneOffset" },
00957 { 0x882b, "exif:SelfTimerMode" },
00958 { 0x9000, "exif:ExifVersion" },
00959 { 0x9003, "exif:DateTimeOriginal" },
00960 { 0x9004, "exif:DateTimeDigitized" },
00961 { 0x9101, "exif:ComponentsConfiguration" },
00962 { 0x9102, "exif:CompressedBitsPerPixel" },
00963 { 0x9201, "exif:ShutterSpeedValue" },
00964 { 0x9202, "exif:ApertureValue" },
00965 { 0x9203, "exif:BrightnessValue" },
00966 { 0x9204, "exif:ExposureBiasValue" },
00967 { 0x9205, "exif:MaxApertureValue" },
00968 { 0x9206, "exif:SubjectDistance" },
00969 { 0x9207, "exif:MeteringMode" },
00970 { 0x9208, "exif:LightSource" },
00971 { 0x9209, "exif:Flash" },
00972 { 0x920a, "exif:FocalLength" },
00973 { 0x920b, "exif:FlashEnergy" },
00974 { 0x920c, "exif:SpatialFrequencyResponse" },
00975 { 0x920d, "exif:Noise" },
00976 { 0x9211, "exif:ImageNumber" },
00977 { 0x9212, "exif:SecurityClassification" },
00978 { 0x9213, "exif:ImageHistory" },
00979 { 0x9214, "exif:SubjectArea" },
00980 { 0x9215, "exif:ExposureIndex" },
00981 { 0x9216, "exif:TIFF-EPStandardID" },
00982 { 0x927c, "exif:MakerNote" },
00983 { 0x9C9b, "exif:WinXP-Title" },
00984 { 0x9C9c, "exif:WinXP-Comments" },
00985 { 0x9C9d, "exif:WinXP-Author" },
00986 { 0x9C9e, "exif:WinXP-Keywords" },
00987 { 0x9C9f, "exif:WinXP-Subject" },
00988 { 0x9286, "exif:UserComment" },
00989 { 0x9290, "exif:SubSecTime" },
00990 { 0x9291, "exif:SubSecTimeOriginal" },
00991 { 0x9292, "exif:SubSecTimeDigitized" },
00992 { 0xa000, "exif:FlashPixVersion" },
00993 { 0xa001, "exif:ColorSpace" },
00994 { 0xa002, "exif:ExifImageWidth" },
00995 { 0xa003, "exif:ExifImageLength" },
00996 { 0xa004, "exif:RelatedSoundFile" },
00997 { 0xa005, "exif:InteroperabilityOffset" },
00998 { 0xa20b, "exif:FlashEnergy" },
00999 { 0xa20c, "exif:SpatialFrequencyResponse" },
01000 { 0xa20d, "exif:Noise" },
01001 { 0xa20e, "exif:FocalPlaneXResolution" },
01002 { 0xa20f, "exif:FocalPlaneYResolution" },
01003 { 0xa210, "exif:FocalPlaneResolutionUnit" },
01004 { 0xa214, "exif:SubjectLocation" },
01005 { 0xa215, "exif:ExposureIndex" },
01006 { 0xa216, "exif:TIFF/EPStandardID" },
01007 { 0xa217, "exif:SensingMethod" },
01008 { 0xa300, "exif:FileSource" },
01009 { 0xa301, "exif:SceneType" },
01010 { 0xa302, "exif:CFAPattern" },
01011 { 0xa401, "exif:CustomRendered" },
01012 { 0xa402, "exif:ExposureMode" },
01013 { 0xa403, "exif:WhiteBalance" },
01014 { 0xa404, "exif:DigitalZoomRatio" },
01015 { 0xa405, "exif:FocalLengthIn35mmFilm" },
01016 { 0xa406, "exif:SceneCaptureType" },
01017 { 0xa407, "exif:GainControl" },
01018 { 0xa408, "exif:Contrast" },
01019 { 0xa409, "exif:Saturation" },
01020 { 0xa40a, "exif:Sharpness" },
01021 { 0xa40b, "exif:DeviceSettingDescription" },
01022 { 0xa40c, "exif:SubjectDistanceRange" },
01023 { 0xa420, "exif:ImageUniqueID" },
01024 { 0xc4a5, "exif:PrintImageMatching" },
01025 { 0x10000, "exif:GPSVersionID" },
01026 { 0x10001, "exif:GPSLatitudeRef" },
01027 { 0x10002, "exif:GPSLatitude" },
01028 { 0x10003, "exif:GPSLongitudeRef" },
01029 { 0x10004, "exif:GPSLongitude" },
01030 { 0x10005, "exif:GPSAltitudeRef" },
01031 { 0x10006, "exif:GPSAltitude" },
01032 { 0x10007, "exif:GPSTimeStamp" },
01033 { 0x10008, "exif:GPSSatellites" },
01034 { 0x10009, "exif:GPSStatus" },
01035 { 0x1000a, "exif:GPSMeasureMode" },
01036 { 0x1000b, "exif:GPSDop" },
01037 { 0x1000c, "exif:GPSSpeedRef" },
01038 { 0x1000d, "exif:GPSSpeed" },
01039 { 0x1000e, "exif:GPSTrackRef" },
01040 { 0x1000f, "exif:GPSTrack" },
01041 { 0x10010, "exif:GPSImgDirectionRef" },
01042 { 0x10011, "exif:GPSImgDirection" },
01043 { 0x10012, "exif:GPSMapDatum" },
01044 { 0x10013, "exif:GPSDestLatitudeRef" },
01045 { 0x10014, "exif:GPSDestLatitude" },
01046 { 0x10015, "exif:GPSDestLongitudeRef" },
01047 { 0x10016, "exif:GPSDestLongitude" },
01048 { 0x10017, "exif:GPSDestBearingRef" },
01049 { 0x10018, "exif:GPSDestBearing" },
01050 { 0x10019, "exif:GPSDestDistanceRef" },
01051 { 0x1001a, "exif:GPSDestDistance" },
01052 { 0x1001b, "exif:GPSProcessingMethod" },
01053 { 0x1001c, "exif:GPSAreaInformation" },
01054 { 0x1001d, "exif:GPSDateStamp" },
01055 { 0x1001e, "exif:GPSDifferential" },
01056 { 0x0000, NULL}
01057 };
01058
01059 const StringInfo
01060 *profile;
01061
01062 const unsigned char
01063 *directory,
01064 *exif;
01065
01066 DirectoryInfo
01067 directory_stack[MaxDirectoryStack];
01068
01069 EndianType
01070 endian;
01071
01072 long
01073 all,
01074 id,
01075 level,
01076 tag_value;
01077
01078 register long
01079 i;
01080
01081 size_t
01082 length;
01083
01084 ssize_t
01085 offset;
01086
01087 static int
01088 tag_bytes[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
01089
01090 unsigned long
01091 entry,
01092 number_entries,
01093 tag_offset,
01094 tag;
01095
01096
01097
01098
01099 profile=GetImageProfile(image,"exif");
01100 if (profile == (StringInfo *) NULL)
01101 return(MagickFalse);
01102 if ((property == (const char *) NULL) || (*property == '\0'))
01103 return(MagickFalse);
01104 while (isspace((int) ((unsigned char) *property)) != 0)
01105 property++;
01106 all=0;
01107 tag=(~0UL);
01108 switch (*(property+5))
01109 {
01110 case '*':
01111 {
01112
01113
01114
01115 tag=0;
01116 all=1;
01117 break;
01118 }
01119 case '!':
01120 {
01121 tag=0;
01122 all=2;
01123 break;
01124 }
01125 case '#':
01126 case '@':
01127 {
01128 int
01129 c;
01130
01131 size_t
01132 n;
01133
01134
01135
01136
01137 tag=(*(property+5) == '@') ? 1 : 0;
01138 property+=6;
01139 n=strlen(property);
01140 if (n != 4)
01141 return(MagickFalse);
01142
01143
01144
01145 n/=4;
01146 do
01147 {
01148 for (i=(long) n-1L; i >= 0; i--)
01149 {
01150 c=(*property++);
01151 tag<<=4;
01152 if ((c >= '0') && (c <= '9'))
01153 tag|=(c-'0');
01154 else
01155 if ((c >= 'A') && (c <= 'F'))
01156 tag|=(c-('A'-10));
01157 else
01158 if ((c >= 'a') && (c <= 'f'))
01159 tag|=(c-('a'-10));
01160 else
01161 return(MagickFalse);
01162 }
01163 } while (*property != '\0');
01164 break;
01165 }
01166 default:
01167 {
01168
01169
01170
01171 for (i=0; ; i++)
01172 {
01173 <