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
[email protected]
http://studio.imagemagick.org/mailman/listinfo/magick-developers