I wrote: > Hi, > > the attached patch adds the functionality to extract GPS information > from images.
Oops, GMANE ate it. Here it is again, inline. --- ImageMagick-6.4.4.orig/magick/property.c 2008-10-10 07:26:57.000000000 +0600 +++ ImageMagick-6.4.4/magick/property.c 2008-11-15 15:43:53.000000000 +0500 @@ -722,6 +722,7 @@ #define EXIF_FMT_SINGLE 11 #define EXIF_FMT_DOUBLE 12 #define TAG_EXIF_OFFSET 0x8769 +#define TAG_GPS_OFFSET 0x8825 #define TAG_INTEROP_OFFSET 0xa005 typedef struct _DirectoryInfo @@ -731,11 +732,14 @@ unsigned long entry; + + unsigned long + tag_offset; } DirectoryInfo; typedef struct _TagInfo { - unsigned short + unsigned long tag; const char @@ -982,6 +986,37 @@ { 0xa40c, "exif:SubjectDistanceRange" }, { 0xa420, "exif:ImageUniqueID" }, { 0xc4a5, "exif:PrintImageMatching" }, + { 0x10000, "exif:GPSVersionID" }, + { 0x10001, "exif:GPSLatitudeRef" }, + { 0x10002, "exif:GPSLatitude" }, + { 0x10003, "exif:GPSLongitudeRef" }, + { 0x10004, "exif:GPSLongitude" }, + { 0x10005, "exif:GPSAltitudeRef" }, + { 0x10006, "exif:GPSAltitude" }, + { 0x10007, "exif:GPSTimeStamp" }, + { 0x10008, "exif:GPSSatellites" }, + { 0x10009, "exif:GPSStatus" }, + { 0x1000a, "exif:GPSMeasureMode" }, + { 0x1000b, "exif:GPSDop" }, + { 0x1000c, "exif:GPSSpeedRef" }, + { 0x1000d, "exif:GPSSpeed" }, + { 0x1000e, "exif:GPSTrackRef" }, + { 0x1000f, "exif:GPSTrack" }, + { 0x10010, "exif:GPSImgDirectionRef" }, + { 0x10011, "exif:GPSImgDirection" }, + { 0x10012, "exif:GPSMapDatum" }, + { 0x10013, "exif:GPSDestLatitudeRef" }, + { 0x10014, "exif:GPSDestLatitude" }, + { 0x10015, "exif:GPSDestLongitudeRef" }, + { 0x10016, "exif:GPSDestLongitude" }, + { 0x10017, "exif:GPSDestBearingRef" }, + { 0x10018, "exif:GPSDestBearing" }, + { 0x10019, "exif:GPSDestDistanceRef" }, + { 0x1001a, "exif:GPSDestDistance" }, + { 0x1001b, "exif:GPSProcessingMethod" }, + { 0x1001c, "exif:GPSAreaInformation" }, + { 0x1001d, "exif:GPSDateStamp" }, + { 0x1001e, "exif:GPSDifferential" }, { 0x0000, NULL} }; @@ -1019,6 +1054,7 @@ unsigned long entry, number_entries, + tag_offset, tag; /* @@ -1051,6 +1087,7 @@ break; } case '#': + case '@': { int c; @@ -1061,7 +1098,7 @@ /* Check for a hex based tag specification first. */ - tag=0; + tag=(*(property+5) == '@') ? 1 : 0; property+=6; n=strlen(property); if (n != 4) @@ -1153,6 +1190,7 @@ directory=exif+offset; level=0; entry=0; + tag_offset=0; do { /* @@ -1163,6 +1201,7 @@ level--; directory=directory_stack[level].directory; entry=directory_stack[level].entry; + tag_offset=directory_stack[level].tag_offset; } /* Determine how many entries there are in the current IFD. @@ -1184,7 +1223,7 @@ format; q=(unsigned char *) (directory+2+(12*entry)); - tag_value=(long) ReadPropertyShort(endian,q); + tag_value=(long) ReadPropertyShort(endian,q) + tag_offset; format=(unsigned long) ReadPropertyShort(endian,q+2); if (format >= (sizeof(tag_bytes)/sizeof(*tag_bytes))) break; @@ -1211,74 +1250,99 @@ buffer[MaxTextExtent], *value; +#define FORMAT_MULTIPLE_VALUES(size, format, arg) \ + long component; \ + size_t used_space; \ + unsigned char *p1; \ + used_space=0; \ + p1=p; \ + for (component = 0; component < components; component++) \ + { \ + used_space+=FormatMagickString(buffer+used_space, \ + MaxTextExtent-used_space,format", ",arg); \ + if (used_space >= MaxTextExtent - 1) \ + used_space=MaxTextExtent-1; \ + p1+=size; \ + } \ + buffer[used_space-2]='\0'; \ + value=AcquireString(buffer); + +#define FORMAT_MULTIPLE_FRACTIONS(size, format, arg1, arg2) \ + long component; \ + size_t used_space; \ + unsigned char *p1; \ + used_space=0; \ + p1=p; \ + for (component = 0; component < components; component++) \ + { \ + used_space+=FormatMagickString(buffer+used_space, \ + MaxTextExtent-used_space,format", ",arg1, arg2); \ + if (used_space >= MaxTextExtent - 1) \ + used_space=MaxTextExtent-1; \ + p1+=size; \ + } \ + buffer[used_space-2]='\0'; \ + value=AcquireString(buffer); + switch (format) { + case EXIF_FMT_BYTE: + case EXIF_FMT_UNDEFINED: + { + FORMAT_MULTIPLE_VALUES(1, "%lu", + (unsigned long) (*(unsigned char *) p1)); + break; + } case EXIF_FMT_SBYTE: { - (void) FormatMagickString(buffer,MaxTextExtent,"%ld", - (long) (*(char *) p)); - value=AcquireString(buffer); + FORMAT_MULTIPLE_VALUES(1, "%ld", (long) (*(signed char *) p1)); break; } case EXIF_FMT_SSHORT: { - (void) FormatMagickString(buffer,MaxTextExtent,"%hd", - ReadPropertyShort(endian,p)); - value=AcquireString(buffer); + FORMAT_MULTIPLE_VALUES(2, "%hd", ReadPropertyShort(endian,p1)); break; } case EXIF_FMT_USHORT: { - (void) FormatMagickString(buffer,MaxTextExtent,"%hu", - ReadPropertyShort(endian,p)); - value=AcquireString(buffer); + FORMAT_MULTIPLE_VALUES(2, "%hu", ReadPropertyShort(endian,p1)); break; } case EXIF_FMT_ULONG: { - (void) FormatMagickString(buffer,MaxTextExtent,"%lu", - ReadPropertyLong(endian,p)); - value=AcquireString(buffer); + FORMAT_MULTIPLE_VALUES(4, "%lu", ReadPropertyLong(endian,p1)); break; } case EXIF_FMT_SLONG: { - (void) FormatMagickString(buffer,MaxTextExtent,"%ld", - ReadPropertyLong(endian,p)); - value=AcquireString(buffer); + FORMAT_MULTIPLE_VALUES(4, "%ld", ReadPropertyLong(endian,p1)); break; } case EXIF_FMT_URATIONAL: { - (void) FormatMagickString(buffer,MaxTextExtent,"%ld/%ld", - ReadPropertyLong(endian,p),ReadPropertyLong(endian,p+4)); - value=AcquireString(buffer); + FORMAT_MULTIPLE_FRACTIONS(8, "%ld/%ld", + ReadPropertyLong(endian,p1),ReadPropertyLong(endian,p1+4)); break; } case EXIF_FMT_SRATIONAL: { - (void) FormatMagickString(buffer,MaxTextExtent,"%ld/%ld", - ReadPropertyLong(endian,p),ReadPropertyLong(endian,p+4)); - value=AcquireString(buffer); + FORMAT_MULTIPLE_FRACTIONS(8, "%ld/%ld", + ReadPropertyLong(endian,p1),ReadPropertyLong(endian,p1+4)); break; } case EXIF_FMT_SINGLE: { - (void) FormatMagickString(buffer,MaxTextExtent,"%f", - (double) *(float *) p); - value=AcquireString(buffer); + FORMAT_MULTIPLE_VALUES(4, "%f", (double) *(float *) p1); break; } case EXIF_FMT_DOUBLE: { - (void) FormatMagickString(buffer,MaxTextExtent,"%f", - *(double *) p); - value=AcquireString(buffer); + FORMAT_MULTIPLE_VALUES(8, "%f", *(double *) p1); break; } +#undef FORMAT_MULTIPLE_VALUES +#undef FORMAT_MULTIPLE_FRACTIONS default: - case EXIF_FMT_UNDEFINED: - case EXIF_FMT_BYTE: case EXIF_FMT_STRING: { value=(char *) NULL; @@ -1337,8 +1401,14 @@ } case 2: { - (void) FormatMagickString(key,MaxTextExtent,"#%04lx", - tag_value); + if (tag_value < 0x10000) + (void) FormatMagickString(key,MaxTextExtent,"#%04lx", + tag_value); + else if (tag_value < 0x20000) + (void) FormatMagickString(key,MaxTextExtent,"@%04lx", + tag_value & 0xffff); + else + (void) FormatMagickString(key,MaxTextExtent,"bug"); break; } } @@ -1349,7 +1419,9 @@ value=DestroyString(value); } } - if ((tag_value == TAG_EXIF_OFFSET) || (tag_value == TAG_INTEROP_OFFSET)) + if ((tag_value == TAG_EXIF_OFFSET) + || (tag_value == TAG_INTEROP_OFFSET) + || (tag_value == TAG_GPS_OFFSET)) { size_t offset; @@ -1357,11 +1429,16 @@ offset=(size_t) ReadPropertyLong(endian,p); if ((offset < length) && (level < (MaxDirectoryStack-2))) { + unsigned long tag_offset1=(tag_value == TAG_GPS_OFFSET) ? + 0x10000 : 0; + directory_stack[level].directory=directory; entry++; directory_stack[level].entry=entry; + directory_stack[level].tag_offset=tag_offset; level++; directory_stack[level].directory=exif+offset; + directory_stack[level].tag_offset=tag_offset1; directory_stack[level].entry=0; level++; if ((directory+2+(12*number_entries)) > (exif+length)) @@ -1373,6 +1450,7 @@ { directory_stack[level].directory=exif+offset; directory_stack[level].entry=0; + directory_stack[level].tag_offset=tag_offset1; level++; } } _______________________________________________ Magick-developers mailing list Magick-developers@imagemagick.org http://studio.imagemagick.org/mailman/listinfo/magick-developers