This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project gfxprim.git.
The branch, master has been updated via 254ab1bb2cf59cfef000a55e64837a89e35e4008 (commit) via 76e4c74a3e527af4fe39c98123d4475a1ddc2a05 (commit) from 143e4e08779b9dcd3aeed69e2de28c64d9c3d4d0 (commit)
Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below.
- Log ----------------------------------------------------------------- http://repo.or.cz/w/gfxprim.git/commit/254ab1bb2cf59cfef000a55e64837a89e35e4...
commit 254ab1bb2cf59cfef000a55e64837a89e35e4008 Author: Cyril Hrubis metan@ucw.cz Date: Sun Feb 8 17:00:23 2015 +0100
loaders: DataStorage: Print strings enclosed in ''
Signed-off-by: Cyril Hrubis metan@ucw.cz
diff --git a/libs/loaders/GP_DataStorage.c b/libs/loaders/GP_DataStorage.c index cb02425..b453bea 100644 --- a/libs/loaders/GP_DataStorage.c +++ b/libs/loaders/GP_DataStorage.c @@ -411,7 +411,7 @@ static void data_print(const GP_DataNode *node, node->value.rat.num, node->value.rat.den); break; case GP_DATA_STRING: - padd_printf(padd, node->id, id_padd, " : %sn", node->value.str); + padd_printf(padd, node->id, id_padd, " : '%s'n", node->value.str); break; case GP_DATA_DICT: padd_printf(padd, node->id ? node->id : "Data Root", 0, " = {n");
http://repo.or.cz/w/gfxprim.git/commit/76e4c74a3e527af4fe39c98123d4475a1ddc2...
commit 76e4c74a3e527af4fe39c98123d4475a1ddc2a05 Author: Cyril Hrubis metan@ucw.cz Date: Sun Feb 8 15:49:27 2015 +0100
loaders: Exif: Fix subIFD handling, add subIFDs
* Add interoperability and GPS sub IFD handling
* Add a few more tags
Signed-off-by: Cyril Hrubis metan@ucw.cz
diff --git a/libs/loaders/GP_Exif.c b/libs/loaders/GP_Exif.c index 99f49f7..0cfd591 100644 --- a/libs/loaders/GP_Exif.c +++ b/libs/loaders/GP_Exif.c @@ -24,9 +24,9 @@ #include <string.h> #include <errno.h>
-#include "core/GP_Debug.h" - -#include "loaders/GP_Exif.h" +#include <core/GP_Common.h> +#include <core/GP_Debug.h> +#include <loaders/GP_Exif.h>
enum IFD_formats { /* 1 bytes/components */ @@ -71,133 +71,13 @@ static const char *IFD_format_names[] = { "Double Float", };
-enum IFD_tags { - /* Image width and height */ - IFD_IMAGE_WIDTH = 0x0100, - IFD_IMAGE_HEIGHT = 0x0101, - - IFD_BITS_PER_SAMPLE = 0x0102, - - /* TODO: enum of compressions */ - IFD_COMPRESSION = 0x0103, - /* TODO: enum of interpretations */ - IFD_PHOTOMETRIC_INTERPRETATION = 0x0106, - - /* ASCII text no multibyte encoding */ - IFD_IMAGE_DESCRIPTION = 0x010e, - /* Device (camer, scanner, ...) manufacturer */ - IFD_MAKE = 0x010f, - /* Device model */ - IFD_MODEL = 0x0110, - /* Image orientation * - * 1 upper left, 3 lower right, 6 upper right, * - * 8 lower left, other reserved */ - IFD_ORIENTATION = 0x0112, - /* X resolution 72 DPI is default */ - IFD_X_RESOLUTION = 0x011a, - /* Y resolution 72 DPI is default */ - IFD_Y_RESOLUTION = 0x011b, - /* 1 = Chunky, 2 = Planar */ - IFD_PLANAR_CONFIGURATION = 0x011c, - /* 1 = No unit, 2 = Inch (default), 3 = Centimeter */ - IFD_RESOLUTION_UNIT = 0x0128, - /* Software string. */ - IFD_SOFTWARE = 0x0131, - /* YYYY:MM:DD HH:MM:SS in 24 hours format */ - IFD_DATE_TIME = 0x0132, - /* White Point */ - IFD_WHITE_POINT = 0x013e, - /* Primary Chromaticies */ - IFD_PRIMARY_CHROMATICIES = 0x013f, - /* YCbCr Coefficients */ - IFD_Y_CB_CR_COEFFICIENTS = 0x0211, - /* YCbCr Positioning */ - IFD_Y_CB_CR_POSITIONING = 0x0213, - /* Reference Black White */ - IFD_REFERENCE_BLACK_WHITE = 0x0214, - /* Copyright */ - IFD_COPYRIGHT = 0x8298, - /* Exif SubIFD Offset */ - IFD_EXIF_OFFSET = 0x8769, - - /* TAGs from Exif SubIFD */ - IFD_EXPOSURE_TIME = 0x829a, - /* Actual F-Number of lens when image was taken */ - IFD_F_NUMBER = 0x829d, - /* 1 manual, 2 normal, 3 aperture priority, 4 shutter priority, * - * 5 creative (slow), 6 action (high-speed), 7 portrait mode, * - * 8 landscape mode */ - IFD_EXPOSURE_PROGRAM = 0x8822, - /* CCD sensitivity */ - IFD_ISO_SPEED_RATINGS = 0x8827, - /* ASCII 4 byte Exif version */ - IFD_EXIF_VERSION = 0x9000, - /* Original time should not be modified by user program */ - IFD_DATE_TIME_ORIGINAL = 0x9003, - IFD_DATE_TIME_DIGITIZED = 0x9004, - /* Undefined commonly 0x00, 0x01, 0x02, 0x03 */ - IFD_COMPONENT_CONFIGURATION = 0x9101, - /* Average compression ration */ - IFD_COMPRESSED_BITS_PER_PIXEL = 0x9102, - /* Shutter speed as 1 / (2 ^ val) */ - IFD_SHUTTER_SPEED_VALUE = 0x9201, - /* Aperture to convert to F-Number do 1.4142 ^ val */ - IFD_APERTURE_VALUE = 0x9202, - /* Brightness in EV */ - IFD_BRIGHTNESS_VALUE = 0x9203, - /* Exposure bias in EV */ - IFD_EXPOSURE_BIAS_VALUE = 0x9204, - /* Max Aperture in the same format as IFD_APERTURE_VALUE */ - IFD_MAX_APERTURE_VALUE = 0x9205, - /* Distance to focus point in meters */ - IFD_SUBJECT_DISTANCE = 0x9206, - /* Exposure metering method, 1 average, 2 center weighted average, * - * 3 spot, 4 multi-spot, 5 multi-segment */ - IFD_METERING_MODE = 0x9207, - /* White balance 0 auto, 1 daylight, 2 flourescent, 3 tungsten, 10 flash */ - IFD_LIGHT_SOURCE = 0x9208, - /* 0 off, 1 on */ - IFD_FLASH = 0x9209, - /* Focal length in milimeters */ - IFD_FOCAL_LENGTH = 0x920a, - /* Maker note, undefined may be IFD block */ - IFD_MAKER_NOTE = 0x927c, - /* Comment */ - IFD_USER_COMMENT = 0x9286, - - /* Stores FlashPix version, undefined, may be four ASCII numbers */ - IFD_FLASH_PIX_VERSION = 0xa000, - /* Unknown may be 1 */ - IFD_COLOR_SPACE = 0xa001, - /* Exif Image Width and Height */ - IFD_EXIF_IMAGE_WIDTH = 0xa002, - IFD_EXIF_IMAGE_HEIGHT = 0xa003, - /* May store related audio filename */ - IFD_RELATED_SOUND_FILE = 0xa004, - /* */ - IFD_FOCAL_PLANE_X_RESOLUTION = 0xa20e, - IFD_FOCAL_PLANE_Y_RESOLUTION = 0xa20f, - /* 1 = No unit, 2 = Inch (default), 3 = Centimeter */ - IFD_FOCAL_PLANE_RESOLUTION_UNIT = 0xa210, - /* TODO: enum of sensing methods */ - IFD_SENSING_METHOD = 0xa217, - IFD_FILE_SOURCE = 0xa300, - IFD_SCENE_TYPE = 0xa301, - /* 0 = Normal, 1 = Custom */ - IFD_CUSTOM_RENDERER = 0xa401, - /* 0 = Auto, 1 = Manual, 2 = Auto bracket */ - IFD_EXPOSURE_MODE = 0xa402, - /* 0 = Auto, 1 = Manual */ - IFD_WHITE_BALANCE = 0xa403, - /* 0 = Standard, 1 = Landscape, 2 = Portrait, 3 = Night Scene */ - IFD_SCENE_CAPTURE_TYPE = 0xa406, - /* 0 = Normal, 1 = Soft, 2 = Hard */ - IFD_CONTRAST = 0xa408, - /* 0 = Normal, 1 = Low Saturation, 2 = Hight Saturation */ - IFD_SATURATION = 0xa409, - /* 0 = Normal, 1 = Sort, 2 = Hard */ - IFD_SHARPNESS = 0xa40a, -}; +static const char *IFD_format_name(uint16_t format) +{ + if (format == 0 || format > IFD_FORMAT_LAST) + return "Unknown"; + + return IFD_format_names[format - 1]; +}
struct IFD_tag { uint16_t tag; @@ -207,120 +87,43 @@ struct IFD_tag { uint32_t num_components; };
-/* These are sorted by tag */ -static const struct IFD_tag IFD_tags[] = { - /* TAGs from IFD0 */ - /* TODO May be LONG */ - {IFD_IMAGE_WIDTH, "Image Width", IFD_UNSIGNED_SHORT, 1}, - {IFD_IMAGE_HEIGHT, "Image Height", IFD_UNSIGNED_SHORT, 1}, - - {IFD_BITS_PER_SAMPLE, "Bits Per Sample", IFD_UNSIGNED_SHORT, 3}, - {IFD_COMPRESSION, "Compression", IFD_UNSIGNED_SHORT, 1}, - {IFD_PHOTOMETRIC_INTERPRETATION, "Photometric Interpretation", IFD_UNSIGNED_SHORT, 1}, - - {IFD_IMAGE_DESCRIPTION, "Image Description", IFD_ASCII_STRING, 0}, - {IFD_MAKE, "Make", IFD_ASCII_STRING, 0}, - {IFD_MODEL, "Model", IFD_ASCII_STRING, 0}, - {IFD_ORIENTATION, "Orientation", IFD_UNSIGNED_SHORT, 1}, - {IFD_X_RESOLUTION, "X Resolution", IFD_UNSIGNED_RATIONAL, 1}, - {IFD_Y_RESOLUTION, "Y Resolution", IFD_UNSIGNED_RATIONAL, 1}, - {IFD_PLANAR_CONFIGURATION, "Planar Configuration", IFD_UNSIGNED_SHORT, 1}, - {IFD_RESOLUTION_UNIT, "Resolution Unit", IFD_UNSIGNED_SHORT, 1}, - {IFD_SOFTWARE, "Software", IFD_ASCII_STRING, 0}, - {IFD_DATE_TIME, "Date Time", IFD_ASCII_STRING, 20}, - {IFD_WHITE_POINT, "White Point", IFD_UNSIGNED_RATIONAL, 2}, - {IFD_PRIMARY_CHROMATICIES, "Primary Chromaticies", IFD_UNSIGNED_RATIONAL, 6}, - {IFD_Y_CB_CR_COEFFICIENTS, "YCbCr Conefficients", IFD_UNSIGNED_RATIONAL, 3}, - {IFD_Y_CB_CR_POSITIONING, "YCbCr Positioning", IFD_UNSIGNED_SHORT, 1}, - {IFD_REFERENCE_BLACK_WHITE, "Reference Black White", IFD_UNSIGNED_RATIONAL, 6}, - {IFD_COPYRIGHT, "Copyright", IFD_ASCII_STRING, 0}, - - /* TAGs from Exif SubIFD */ - {IFD_EXPOSURE_TIME, "Exposure Time", IFD_UNSIGNED_RATIONAL, 1}, - {IFD_F_NUMBER, "F-Number", IFD_UNSIGNED_RATIONAL, 1}, - - /* TAG from IFD0 */ - {IFD_EXIF_OFFSET, "Exif Offset", IFD_UNSIGNED_LONG, 1}, - - /* TAGs from Exif SubIFD */ - {IFD_EXPOSURE_PROGRAM, "Exposure Program", IFD_UNSIGNED_SHORT, 1}, - {IFD_ISO_SPEED_RATINGS, "ISO Speed Ratings", IFD_UNSIGNED_SHORT, 1}, - {IFD_EXIF_VERSION, "Exif Version", IFD_UNDEFINED, 4}, - {IFD_DATE_TIME_ORIGINAL, "Date Time Original", IFD_ASCII_STRING, 20}, - {IFD_DATE_TIME_DIGITIZED, "Date Time Digitized", IFD_ASCII_STRING, 20}, - {IFD_COMPONENT_CONFIGURATION, "Component Configuration", IFD_UNDEFINED, 0}, - {IFD_COMPRESSED_BITS_PER_PIXEL, "Compressed Bits Per Pixel", IFD_UNSIGNED_RATIONAL, 1}, - {IFD_SHUTTER_SPEED_VALUE, "Shutter Speed", IFD_SIGNED_RATIONAL, 1}, - {IFD_APERTURE_VALUE, "Aperture", IFD_UNSIGNED_RATIONAL, 1}, - {IFD_BRIGHTNESS_VALUE, "Brightness", IFD_SIGNED_RATIONAL, 1}, - {IFD_EXPOSURE_BIAS_VALUE, "Exposure Bias", IFD_SIGNED_RATIONAL, 1}, - {IFD_MAX_APERTURE_VALUE, "Max Aperture", IFD_UNSIGNED_RATIONAL, 1}, - {IFD_SUBJECT_DISTANCE, "Subject Distance", IFD_SIGNED_RATIONAL, 1}, - {IFD_METERING_MODE, "Metering Mode", IFD_UNSIGNED_SHORT, 1}, - {IFD_LIGHT_SOURCE, "Light Source", IFD_UNSIGNED_SHORT, 1}, - {IFD_FLASH, "Flash", IFD_UNSIGNED_SHORT, 1}, - {IFD_FOCAL_LENGTH, "Focal Length", IFD_UNSIGNED_RATIONAL, 1}, - {IFD_MAKER_NOTE, "Maker Note", IFD_UNDEFINED, 0}, - {IFD_USER_COMMENT, "User Comment", IFD_UNDEFINED, 0}, - {IFD_FLASH_PIX_VERSION, "Flash Pix Version", IFD_UNDEFINED, 4}, - {IFD_COLOR_SPACE, "Color Space", IFD_UNSIGNED_SHORT, 1}, - /* these two may be short in some cases */ - {IFD_EXIF_IMAGE_WIDTH, "Exif Image Width", IFD_UNSIGNED_LONG, 1}, - {IFD_EXIF_IMAGE_HEIGHT, "Exif Image Height", IFD_UNSIGNED_LONG, 1}, - {IFD_RELATED_SOUND_FILE, "Related Soundfile", IFD_ASCII_STRING, 0}, - {IFD_FOCAL_PLANE_X_RESOLUTION, "Focal Plane X Resolution", IFD_UNSIGNED_RATIONAL, 1}, - {IFD_FOCAL_PLANE_Y_RESOLUTION, "Focal Plane Y Resolution", IFD_UNSIGNED_RATIONAL, 1}, - {IFD_FOCAL_PLANE_RESOLUTION_UNIT, "Focal Plane Resolution Unit", IFD_UNSIGNED_SHORT, 1}, - {IFD_SENSING_METHOD, "Sensing Method", IFD_UNSIGNED_SHORT, 1}, - {IFD_FILE_SOURCE, "File Source", IFD_UNDEFINED, 1}, - {IFD_SCENE_TYPE, "Scene Type", IFD_UNDEFINED, 1}, - {IFD_CUSTOM_RENDERER, "Custom Renderer", IFD_UNSIGNED_SHORT, 1}, - {IFD_EXPOSURE_MODE, "Exposure Mode", IFD_UNSIGNED_SHORT, 1}, - {IFD_WHITE_BALANCE, "White Balance", IFD_UNSIGNED_SHORT, 1}, - {IFD_SCENE_CAPTURE_TYPE, "Scene Capture Type", IFD_UNSIGNED_SHORT, 1}, - {IFD_CONTRAST, "Contrast", IFD_UNSIGNED_SHORT, 1}, - {IFD_SATURATION, "Saturation", IFD_UNSIGNED_SHORT, 1}, - {IFD_SHARPNESS, "Sharpness", IFD_UNSIGNED_SHORT, 1}, +struct IFD_tags { + const struct IFD_tag *tags; + unsigned int tag_cnt; + const char *id; };
-static const char *IFD_format_name(uint16_t format) -{ - if (format == 0 || format > IFD_FORMAT_LAST) - return "Unknown"; - - return IFD_format_names[format - 1]; -} - -static const struct IFD_tag *IFD_tag_get(uint16_t tag) +static const struct IFD_tag *IFD_tag_get(const struct IFD_tags *tags, + uint16_t tag) { int left = 0; - int right = sizeof(IFD_tags)/sizeof(struct IFD_tag) - 1; + int right = tags->tag_cnt - 1;
while (right - left > 1) { int middle = (right + left)/2;
- if (IFD_tags[middle].tag == tag) - return &IFD_tags[middle]; + if (tags->tags[middle].tag == tag) + return &tags->tags[middle];
- if (IFD_tags[middle].tag > tag) + if (tags->tags[middle].tag > tag) right = middle; else left = middle; }
- if (IFD_tags[left].tag == tag) - return &IFD_tags[left]; + if (tags->tags[left].tag == tag) + return &tags->tags[left];
- if (IFD_tags[right].tag == tag) - return &IFD_tags[right]; + if (tags->tags[right].tag == tag) + return &tags->tags[right];
return NULL; }
-static const char *IFD_tag_name(uint16_t tag) +static const char *IFD_tag_name(const struct IFD_tags *taglist, uint16_t tag) { - const struct IFD_tag *res = IFD_tag_get(tag); + const struct IFD_tag *res = IFD_tag_get(taglist, tag);
if (res == NULL) return "Unknown"; @@ -328,6 +131,9 @@ static const char *IFD_tag_name(uint16_t tag) return res->name; }
+#include "GP_ExifGPS.h" +#include "GP_Exif.h" + static int get_buf(GP_IO *io, off_t offset, char *buf, size_t len) { off_t off; @@ -380,8 +186,7 @@ add: static int load_rat(GP_IO *io, GP_DataStorage *storage, GP_DataNode *node, const char *id, uint32_t num_comp, uint32_t val) { - uint32_t buf[2]; - + (void)io;(void)storage;(void)node;(void)id;(void)num_comp;(void)val; return GP_DataStorageAddRational(storage, node, id, 0, 0) != NULL; }
@@ -406,29 +211,29 @@ static int rat_den(void *buf, uint32_t offset, size_t buf_len, int swap) */
static int load_tag(GP_IO *io, GP_DataStorage *storage, - GP_DataNode* node, int endian, - uint16_t tag, uint16_t format, + GP_DataNode* node, const struct IFD_tags *taglist, + int endian, uint16_t tag, uint16_t format, uint32_t num_comp, uint32_t val) { - const struct IFD_tag *res = IFD_tag_get(tag); + const struct IFD_tag *res = IFD_tag_get(taglist, tag);
if (res == NULL) { - GP_TODO("Skipping unknown IFD tag 0x%02x format %s", - tag, IFD_format_name(format)); + GP_TODO("Skipping unknown IFD tag 0x%02x %s cnt %u in %s block", + tag, IFD_format_name(format), num_comp, taglist->id); return 0; }
if (res->format != format) { GP_WARN("Unexpected tag '%s' format '%s' (0x%02x) " - "expected '%s'", res->name, + "expected '%s' in %s block", res->name, IFD_format_name(format), format, - IFD_format_name(res->format)); + IFD_format_name(res->format), taglist->id); }
if ((res->num_components != 0) && (res->num_components != num_comp)) { - GP_WARN("Unexpected tag '%s' num_components %u expected %u", - res->name, num_comp, res->num_components); + GP_WARN("Unexpected '%s' num_components %u expected %u in %s block", + res->name, num_comp, res->num_components, taglist->id); }
switch (format) { @@ -436,7 +241,9 @@ static int load_tag(GP_IO *io, GP_DataStorage *storage, if (load_string(io, storage, node, res->name, num_comp, &val)) return 1; break; - //case IFD_UNSIGNED_LONG: + case IFD_SIGNED_LONG: + case IFD_UNSIGNED_LONG: + case IFD_SIGNED_SHORT: case IFD_UNSIGNED_SHORT: if (num_comp == 1) GP_DataStorageAddInt(storage, node, res->name, val); @@ -448,23 +255,13 @@ static int load_tag(GP_IO *io, GP_DataStorage *storage, case IFD_SIGNED_RATIONAL: if (load_rat(io, storage, node, res->name, num_comp, val)) return 1; - -/* if (num_comp == 1) { - rec.type = GP_DATA_RATIONAL; - rec.value.rat. - GP_MetaDataCreateRat(self, res->name, - rat_num(buf, val, buf_len, swap), - rat_den(buf, val, buf_len, swap)); - } else { - goto unused; - } -*/ break; case IFD_UNDEFINED: switch (res->tag) { case IFD_EXIF_VERSION: case IFD_FLASH_PIX_VERSION: case IFD_MAKER_NOTE: + case IFD_INTEROP_VERSION: if (load_string(io, storage, node, res->name, num_comp, &val)) return 1; break; @@ -482,11 +279,18 @@ static int load_tag(GP_IO *io, GP_DataStorage *storage, return 0; }
+struct IFD_subrecord { + uint16_t tag; + uint32_t offset; +}; + static int load_IFD(GP_IO *io, GP_DataStorage *storage, GP_DataNode *node, - uint32_t IFD_offset, int endian) + const struct IFD_tags *taglist, uint32_t IFD_offset, + int endian) { uint16_t IFD_entries_count; uint16_t i2 = endian == 'I' ? GP_IO_L2 : GP_IO_B2; + unsigned int i;
uint16_t IFD_header[] = { GP_IO_IGN | IFD_offset, @@ -494,14 +298,6 @@ static int load_IFD(GP_IO *io, GP_DataStorage *storage, GP_DataNode *node, GP_IO_END, };
- if (GP_IOReadF(io, IFD_header, &IFD_entries_count) != 2) { - GP_DEBUG(1, "Failed to read IFD entries count"); - return 1; - } - - GP_DEBUG(2, "-- IFD Offset 0x%08x Entries 0x%04x --", - IFD_offset, IFD_entries_count); - uint16_t IFD_record_LE[] = { GP_IO_L2, /* Tag */ GP_IO_L2, /* Format */ @@ -518,16 +314,24 @@ static int load_IFD(GP_IO *io, GP_DataStorage *storage, GP_DataNode *node, GP_IO_END, };
- uint16_t *IFD_record = endian == 'I' ? IFD_record_LE : IFD_record_BE; + uint16_t *IFD_rec_head = endian == 'I' ? IFD_record_LE : IFD_record_BE; + + if (GP_IOReadF(io, IFD_header, &IFD_entries_count) != 2) { + GP_DEBUG(1, "Failed to read IFD entries count"); + return 1; + } + + GP_DEBUG(2, "-- IFD Offset 0x%08x Entries %04u --", + IFD_offset, IFD_entries_count);
- int i; + struct IFD_subrecord subrecs[IFD_entries_count]; + unsigned int subrec_cnt = 0;
for (i = 0; i < IFD_entries_count; i++) { uint16_t tag, format; uint32_t num_comp, val; - off_t cur_off;
- if (GP_IOReadF(io, IFD_record, &tag, &format, &num_comp, &val) != 4) { + if (GP_IOReadF(io, IFD_rec_head, &tag, &format, &num_comp, &val) != 4) { GP_DEBUG(1, "Failed to read IFD record"); return 1; } @@ -536,28 +340,55 @@ static int load_IFD(GP_IO *io, GP_DataStorage *storage, GP_DataNode *node, tag, format, num_comp, val);
GP_DEBUG(3, "IFD Entry tag '%s' format '%s'", - IFD_tag_name(tag), IFD_format_name(format)); + IFD_tag_name(taglist, tag), IFD_format_name(format)); + + switch (tag) { + case IFD_EXIF_OFFSET: + case IFD_GPS_OFFSET: + case IFD_INTEROPERABILITY_OFFSET: + subrecs[subrec_cnt].tag = tag; + subrecs[subrec_cnt].offset = val; + subrec_cnt++; + break; + default: + load_tag(io, storage, node, taglist, endian, tag, format, num_comp, val); + break; + } + }
+ for (i = 0; i < subrec_cnt; i++) { + off_t cur_off = GP_IOTell(io); + const struct IFD_tags *tags; + GP_DataNode *new_node;
- if (tag == IFD_EXIF_OFFSET) { - cur_off = GP_IOTell(io); + GP_DEBUG(3, "-- Loading sub IFD %s --", + IFD_tag_name(taglist, subrecs[i].tag));
- /* Offset is counted from the II or MM in the Exif header */ - if (val + 6 < cur_off) - GP_DEBUG(1, "Negative offset!"); - else - load_IFD(io, storage, node, val + 6 - cur_off, endian); - } else { - load_tag(io, storage, node, endian, tag, format, num_comp, val); + switch (subrecs[i].tag) { + case IFD_EXIF_OFFSET: + tags = taglist; + new_node = node; + break; + case IFD_GPS_OFFSET: + tags = &IFD_GPS_tags; + new_node = GP_DataStorageAddDict(storage, node, "GPS"); + break; + case IFD_INTEROPERABILITY_OFFSET: + tags = taglist; + new_node = GP_DataStorageAddDict(storage, node, "Interoperability"); + break; + default: + GP_BUG("Invalid tag"); + return 1; } - }
-/* - GET_32(IFD_offset, buf, IFD_offset, buf_len, swap); + /* Offset is counted from the II or MM in the Exif header */ + if (subrecs[i].offset + 6 < cur_off) + GP_DEBUG(1, "Negative offset!"); + + load_IFD(io, storage, new_node, tags, subrecs[i].offset + 6 - cur_off, endian); + }
- if (IFD_offset != 0x00000000) - load_IFD(self, buf, buf_len, IFD_offset, swap); -*/ return 0; }
@@ -605,5 +436,5 @@ int GP_ReadExif(GP_IO *io, GP_DataStorage *storage) GP_DataNode *exif_root = GP_DataStorageAddDict(storage, NULL, "Exif");
/* The offset starts from the II or MM */ - return load_IFD(io, storage, exif_root, IFD_offset - 8, b1); + return load_IFD(io, storage, exif_root, &IFD_EXIF_tags, IFD_offset - 8, b1); } diff --git a/libs/loaders/GP_Exif.c b/libs/loaders/GP_Exif.h similarity index 53% copy from libs/loaders/GP_Exif.c copy to libs/loaders/GP_Exif.h index 99f49f7..2e09413 100644 --- a/libs/loaders/GP_Exif.c +++ b/libs/loaders/GP_Exif.h @@ -20,64 +20,15 @@ * * *****************************************************************************/
-#include <stdlib.h> -#include <string.h> -#include <errno.h> +enum IFD_EXIF_tags { + /* Stored in interop IFD */ + IFD_INTEROP_VERSION = 0x2,
-#include "core/GP_Debug.h" - -#include "loaders/GP_Exif.h" - -enum IFD_formats { - /* 1 bytes/components */ - IFD_UNSIGNED_BYTE = 0x01, - /* 1 bytes/components */ - IFD_ASCII_STRING = 0x02, - /* 2 bytes/components */ - IFD_UNSIGNED_SHORT = 0x03, - /* 4 bytes/components */ - IFD_UNSIGNED_LONG = 0x04, - /* 8 bytes/components */ - IFD_UNSIGNED_RATIONAL = 0x05, - /* 1 bytes/components */ - IFD_SIGNED_BYTE = 0x06, - /* 1 bytes/components */ - IFD_UNDEFINED = 0x07, - /* 2 bytes/components */ - IFD_SIGNED_SHORT = 0x08, - /* 4 bytes/components */ - IFD_SIGNED_LONG = 0x09, - /* 8 bytes/components */ - IFD_SIGNED_RATIONAL = 0x0a, - /* 4 bytes/components */ - IFD_SINGLE_FLOAT = 0x0b, - /* 8 bytes/components */ - IFD_SINGLE_DOUBLE = 0x0c, - IFD_FORMAT_LAST = IFD_SINGLE_DOUBLE, -}; - -static const char *IFD_format_names[] = { - "Unsigned Byte", - "ASCII String", - "Unsigned Short", - "Unsigned Long", - "Unsigned Rational", - "Signed Byte", - "Undefined", - "Signed Short", - "Signed Long", - "Signed Rational", - "Single Float", - "Double Float", -}; - -enum IFD_tags { /* Image width and height */ IFD_IMAGE_WIDTH = 0x0100, IFD_IMAGE_HEIGHT = 0x0101,
IFD_BITS_PER_SAMPLE = 0x0102, - /* TODO: enum of compressions */ IFD_COMPRESSION = 0x0103, /* TODO: enum of interpretations */ @@ -105,6 +56,8 @@ enum IFD_tags { IFD_SOFTWARE = 0x0131, /* YYYY:MM:DD HH:MM:SS in 24 hours format */ IFD_DATE_TIME = 0x0132, + /* Artist */ + IFD_ARTIST = 0x013b, /* White Point */ IFD_WHITE_POINT = 0x013e, /* Primary Chromaticies */ @@ -115,19 +68,22 @@ enum IFD_tags { IFD_Y_CB_CR_POSITIONING = 0x0213, /* Reference Black White */ IFD_REFERENCE_BLACK_WHITE = 0x0214, + /* Stored in interop IFD */ + IFD_RELATED_IMAGE_WIDTH = 0x1001, + IFD_RELATED_IMAGE_HEIGHT = 0x1002, /* Copyright */ IFD_COPYRIGHT = 0x8298, - /* Exif SubIFD Offset */ - IFD_EXIF_OFFSET = 0x8769, - - /* TAGs from Exif SubIFD */ IFD_EXPOSURE_TIME = 0x829a, /* Actual F-Number of lens when image was taken */ IFD_F_NUMBER = 0x829d, + /* Exif SubIFD Offset */ + IFD_EXIF_OFFSET = 0x8769, /* 1 manual, 2 normal, 3 aperture priority, 4 shutter priority, * * 5 creative (slow), 6 action (high-speed), 7 portrait mode, * * 8 landscape mode */ IFD_EXPOSURE_PROGRAM = 0x8822, + /* Offset to GPS data */ + IFD_GPS_OFFSET = 0x8825, /* CCD sensitivity */ IFD_ISO_SPEED_RATINGS = 0x8827, /* ASCII 4 byte Exif version */ @@ -165,6 +121,11 @@ enum IFD_tags { /* Comment */ IFD_USER_COMMENT = 0x9286,
+ /* Subsec time in addition to IFD_DATE_TIME* */ + IFD_SUBSEC_TIME = 0x9290, + IFD_SUBSEC_TIME_ORIGINAL = 0x9291, + IFD_SUBSEC_TIME_DIGITIZED = 0x9292, + /* Stores FlashPix version, undefined, may be four ASCII numbers */ IFD_FLASH_PIX_VERSION = 0xa000, /* Unknown may be 1 */ @@ -174,6 +135,8 @@ enum IFD_tags { IFD_EXIF_IMAGE_HEIGHT = 0xa003, /* May store related audio filename */ IFD_RELATED_SOUND_FILE = 0xa004, + /* Offset to Interoperability SubIFD */ + IFD_INTEROPERABILITY_OFFSET = 0xa005, /* */ IFD_FOCAL_PLANE_X_RESOLUTION = 0xa20e, IFD_FOCAL_PLANE_Y_RESOLUTION = 0xa20f, @@ -183,33 +146,47 @@ enum IFD_tags { IFD_SENSING_METHOD = 0xa217, IFD_FILE_SOURCE = 0xa300, IFD_SCENE_TYPE = 0xa301, + /* Color Filter Array pattern */ + IFD_CFA_PATTERN = 0xa302, /* 0 = Normal, 1 = Custom */ IFD_CUSTOM_RENDERER = 0xa401, /* 0 = Auto, 1 = Manual, 2 = Auto bracket */ IFD_EXPOSURE_MODE = 0xa402, /* 0 = Auto, 1 = Manual */ IFD_WHITE_BALANCE = 0xa403, + /* 0 == Not Used */ + IFD_DIGITAL_ZOOM_RATIO = 0xa404, + /* Equivalent lenght assuming 35mm camera */ + IFD_FOCAL_LENGTH_IN_35_MM_FILM = 0xa405, /* 0 = Standard, 1 = Landscape, 2 = Portrait, 3 = Night Scene */ IFD_SCENE_CAPTURE_TYPE = 0xa406, + /* 0 = None, 1 = Low Gain Up, 2 = High Gain Up, 3 = Low Gain Down, 4 = High Gain Down */ + IFD_GAIN_CONTROL = 0xa407, /* 0 = Normal, 1 = Soft, 2 = Hard */ IFD_CONTRAST = 0xa408, /* 0 = Normal, 1 = Low Saturation, 2 = Hight Saturation */ IFD_SATURATION = 0xa409, /* 0 = Normal, 1 = Sort, 2 = Hard */ IFD_SHARPNESS = 0xa40a, + /* 0 = Unknown, 1 = Macro, 2 = Close View, 3 = Distant View */ + IFD_SUBJECT_DISTANCE_RANGE = 0xa40c, + /* Unique in hex string */ + IFD_IMAGE_UNIQUE_ID = 0xa420, + + /* ??? */ + IFD_PRINT_IM = 0xc4a5, + + /* Padding */ + IFD_PADDING = 0xea1c, + /* Microsoft's ill-conceived maker note offset difference */ + IFD_OFFSET_SCHEMA = 0xea1d, };
-struct IFD_tag { - uint16_t tag; - const char *name; - uint16_t format; - /* 0 == not defined */ - uint32_t num_components; -}; +/* MUST SORTED BY TAG */ +static const struct IFD_tag IFD_EXIF_taglist[] = { + /* Stored in interop IFD */ + {IFD_INTEROP_VERSION, "Interop Version", IFD_UNDEFINED, 4},
-/* These are sorted by tag */ -static const struct IFD_tag IFD_tags[] = { - /* TAGs from IFD0 */ /* TODO May be LONG */ {IFD_IMAGE_WIDTH, "Image Width", IFD_UNSIGNED_SHORT, 1}, {IFD_IMAGE_HEIGHT, "Image Height", IFD_UNSIGNED_SHORT, 1}, @@ -228,22 +205,25 @@ static const struct IFD_tag IFD_tags[] = { {IFD_RESOLUTION_UNIT, "Resolution Unit", IFD_UNSIGNED_SHORT, 1}, {IFD_SOFTWARE, "Software", IFD_ASCII_STRING, 0}, {IFD_DATE_TIME, "Date Time", IFD_ASCII_STRING, 20}, + {IFD_ARTIST, "Artist", IFD_ASCII_STRING, 0}, {IFD_WHITE_POINT, "White Point", IFD_UNSIGNED_RATIONAL, 2}, {IFD_PRIMARY_CHROMATICIES, "Primary Chromaticies", IFD_UNSIGNED_RATIONAL, 6}, {IFD_Y_CB_CR_COEFFICIENTS, "YCbCr Conefficients", IFD_UNSIGNED_RATIONAL, 3}, {IFD_Y_CB_CR_POSITIONING, "YCbCr Positioning", IFD_UNSIGNED_SHORT, 1}, {IFD_REFERENCE_BLACK_WHITE, "Reference Black White", IFD_UNSIGNED_RATIONAL, 6}, + + /* Stored in interop IFD */ + {IFD_RELATED_IMAGE_WIDTH, "Related Image Width", IFD_UNSIGNED_LONG, 1}, + {IFD_RELATED_IMAGE_HEIGHT, "Related Image Height", IFD_UNSIGNED_LONG, 1}, + {IFD_COPYRIGHT, "Copyright", IFD_ASCII_STRING, 0},
/* TAGs from Exif SubIFD */ {IFD_EXPOSURE_TIME, "Exposure Time", IFD_UNSIGNED_RATIONAL, 1}, {IFD_F_NUMBER, "F-Number", IFD_UNSIGNED_RATIONAL, 1}, - - /* TAG from IFD0 */ {IFD_EXIF_OFFSET, "Exif Offset", IFD_UNSIGNED_LONG, 1}, - - /* TAGs from Exif SubIFD */ {IFD_EXPOSURE_PROGRAM, "Exposure Program", IFD_UNSIGNED_SHORT, 1}, + {IFD_GPS_OFFSET, "GPS Offset", IFD_UNSIGNED_LONG, 1}, {IFD_ISO_SPEED_RATINGS, "ISO Speed Ratings", IFD_UNSIGNED_SHORT, 1}, {IFD_EXIF_VERSION, "Exif Version", IFD_UNDEFINED, 4}, {IFD_DATE_TIME_ORIGINAL, "Date Time Original", IFD_ASCII_STRING, 20}, @@ -262,348 +242,42 @@ static const struct IFD_tag IFD_tags[] = { {IFD_FOCAL_LENGTH, "Focal Length", IFD_UNSIGNED_RATIONAL, 1}, {IFD_MAKER_NOTE, "Maker Note", IFD_UNDEFINED, 0}, {IFD_USER_COMMENT, "User Comment", IFD_UNDEFINED, 0}, + {IFD_SUBSEC_TIME, "Subsec Time", IFD_ASCII_STRING, 0}, + {IFD_SUBSEC_TIME_ORIGINAL, "Subsec Time Original", IFD_ASCII_STRING, 0}, + {IFD_SUBSEC_TIME_DIGITIZED, "Subsec Time Digitized", IFD_ASCII_STRING, 0}, {IFD_FLASH_PIX_VERSION, "Flash Pix Version", IFD_UNDEFINED, 4}, {IFD_COLOR_SPACE, "Color Space", IFD_UNSIGNED_SHORT, 1}, /* these two may be short in some cases */ {IFD_EXIF_IMAGE_WIDTH, "Exif Image Width", IFD_UNSIGNED_LONG, 1}, {IFD_EXIF_IMAGE_HEIGHT, "Exif Image Height", IFD_UNSIGNED_LONG, 1}, {IFD_RELATED_SOUND_FILE, "Related Soundfile", IFD_ASCII_STRING, 0}, + {IFD_INTEROPERABILITY_OFFSET, "Interoperability Offset", IFD_UNSIGNED_LONG, 1}, {IFD_FOCAL_PLANE_X_RESOLUTION, "Focal Plane X Resolution", IFD_UNSIGNED_RATIONAL, 1}, {IFD_FOCAL_PLANE_Y_RESOLUTION, "Focal Plane Y Resolution", IFD_UNSIGNED_RATIONAL, 1}, {IFD_FOCAL_PLANE_RESOLUTION_UNIT, "Focal Plane Resolution Unit", IFD_UNSIGNED_SHORT, 1}, {IFD_SENSING_METHOD, "Sensing Method", IFD_UNSIGNED_SHORT, 1}, {IFD_FILE_SOURCE, "File Source", IFD_UNDEFINED, 1}, {IFD_SCENE_TYPE, "Scene Type", IFD_UNDEFINED, 1}, + {IFD_CFA_PATTERN, "CFA Pattern", IFD_UNDEFINED, 0}, {IFD_CUSTOM_RENDERER, "Custom Renderer", IFD_UNSIGNED_SHORT, 1}, {IFD_EXPOSURE_MODE, "Exposure Mode", IFD_UNSIGNED_SHORT, 1}, {IFD_WHITE_BALANCE, "White Balance", IFD_UNSIGNED_SHORT, 1}, + {IFD_DIGITAL_ZOOM_RATIO, "Digital Zoom Ratio", IFD_UNSIGNED_RATIONAL, 1}, + {IFD_FOCAL_LENGTH_IN_35_MM_FILM, "Focal Lenght In 35mm Film", IFD_UNSIGNED_SHORT, 1}, {IFD_SCENE_CAPTURE_TYPE, "Scene Capture Type", IFD_UNSIGNED_SHORT, 1}, + {IFD_GAIN_CONTROL, "Gain Control", IFD_UNSIGNED_SHORT, 1}, {IFD_CONTRAST, "Contrast", IFD_UNSIGNED_SHORT, 1}, {IFD_SATURATION, "Saturation", IFD_UNSIGNED_SHORT, 1}, {IFD_SHARPNESS, "Sharpness", IFD_UNSIGNED_SHORT, 1}, + {IFD_SUBJECT_DISTANCE_RANGE, "Subject Distance Range", IFD_UNSIGNED_SHORT, 1}, + {IFD_IMAGE_UNIQUE_ID, "Image Unique ID", IFD_ASCII_STRING, 33}, + {IFD_PRINT_IM, "Print IM", IFD_UNDEFINED, 0}, + {IFD_PADDING, "Padding", IFD_UNDEFINED, 0}, + {IFD_OFFSET_SCHEMA, "Offset Schema", IFD_SIGNED_LONG, 1}, };
-static const char *IFD_format_name(uint16_t format) -{ - if (format == 0 || format > IFD_FORMAT_LAST) - return "Unknown"; - - return IFD_format_names[format - 1]; -} - -static const struct IFD_tag *IFD_tag_get(uint16_t tag) -{ - int left = 0; - int right = sizeof(IFD_tags)/sizeof(struct IFD_tag) - 1; - - while (right - left > 1) { - int middle = (right + left)/2; - - if (IFD_tags[middle].tag == tag) - return &IFD_tags[middle]; - - - if (IFD_tags[middle].tag > tag) - right = middle; - else - left = middle; - } - - if (IFD_tags[left].tag == tag) - return &IFD_tags[left]; - - if (IFD_tags[right].tag == tag) - return &IFD_tags[right]; - - return NULL; -} - -static const char *IFD_tag_name(uint16_t tag) -{ - const struct IFD_tag *res = IFD_tag_get(tag); - - if (res == NULL) - return "Unknown"; - else - return res->name; -} - -static int get_buf(GP_IO *io, off_t offset, char *buf, size_t len) -{ - off_t off; - - off = GP_IOTell(io); - - if (GP_IOSeek(io, offset, GP_IO_SEEK_SET) == -1) { - GP_WARN("Failed to seek to data"); - return 1; - } - - if (GP_IOFill(io, buf, len)) { - GP_WARN("Failed to read data"); - return 1; - } - - if (GP_IOSeek(io, off, GP_IO_SEEK_SET) == -1) { - GP_WARN("Failed to seek back"); - return 1; - } - - return 0; -} - -static int load_string(GP_IO *io, GP_DataStorage *storage, GP_DataNode *node, - const char *id, uint32_t num_comp, uint32_t *val) -{ - size_t max_len = GP_MIN(num_comp, 1024u); - char buf[max_len]; - - /* Short strings are stored in the value directly */ - if (num_comp <= 4) { - memcpy(buf, val, num_comp); - buf[num_comp > 0 ? num_comp - 1 : num_comp] = 0; - goto add; - } - - /* Longer are stored at offset starting from II or MM */ - if (get_buf(io, *val + 6, buf, max_len)) - return 1; - - buf[max_len - 1] = '0'; - -add: - GP_DEBUG(2, "ASCII String value = '%s'", buf); - - return GP_DataStorageAddString(storage, node, id, buf) != NULL; -} - -static int load_rat(GP_IO *io, GP_DataStorage *storage, GP_DataNode *node, - const char *id, uint32_t num_comp, uint32_t val) -{ - uint32_t buf[2]; - - return GP_DataStorageAddRational(storage, node, id, 0, 0) != NULL; -} - -/* -static int rat_num(void *buf, uint32_t offset, size_t buf_len, int swap) -{ - int ret; - - GET_32(ret, buf, offset, buf_len, swap); - - return ret; -} - -static int rat_den(void *buf, uint32_t offset, size_t buf_len, int swap) -{ - int ret; - - GET_32(ret, buf, offset + 4, buf_len, swap); - - return ret; -} -*/ - -static int load_tag(GP_IO *io, GP_DataStorage *storage, - GP_DataNode* node, int endian, - uint16_t tag, uint16_t format, - uint32_t num_comp, uint32_t val) -{ - const struct IFD_tag *res = IFD_tag_get(tag); - - if (res == NULL) { - GP_TODO("Skipping unknown IFD tag 0x%02x format %s", - tag, IFD_format_name(format)); - return 0; - } - - if (res->format != format) { - GP_WARN("Unexpected tag '%s' format '%s' (0x%02x) " - "expected '%s'", res->name, - IFD_format_name(format), format, - IFD_format_name(res->format)); - } - - if ((res->num_components != 0) && - (res->num_components != num_comp)) { - GP_WARN("Unexpected tag '%s' num_components %u expected %u", - res->name, num_comp, res->num_components); - } - - switch (format) { - case IFD_ASCII_STRING: - if (load_string(io, storage, node, res->name, num_comp, &val)) - return 1; - break; - //case IFD_UNSIGNED_LONG: - case IFD_UNSIGNED_SHORT: - if (num_comp == 1) - GP_DataStorageAddInt(storage, node, res->name, val); - else - goto unused; - break; - - case IFD_UNSIGNED_RATIONAL: - case IFD_SIGNED_RATIONAL: - if (load_rat(io, storage, node, res->name, num_comp, val)) - return 1; - -/* if (num_comp == 1) { - rec.type = GP_DATA_RATIONAL; - rec.value.rat. - GP_MetaDataCreateRat(self, res->name, - rat_num(buf, val, buf_len, swap), - rat_den(buf, val, buf_len, swap)); - } else { - goto unused; - } -*/ - break; - case IFD_UNDEFINED: - switch (res->tag) { - case IFD_EXIF_VERSION: - case IFD_FLASH_PIX_VERSION: - case IFD_MAKER_NOTE: - if (load_string(io, storage, node, res->name, num_comp, &val)) - return 1; - break; - default: - goto unused; - } - break; - - unused: - default: - GP_TODO("Unused record '%s' format '%s' (0x%02x)", res->name, - IFD_format_name(format), format); - } - - return 0; -} - -static int load_IFD(GP_IO *io, GP_DataStorage *storage, GP_DataNode *node, - uint32_t IFD_offset, int endian) -{ - uint16_t IFD_entries_count; - uint16_t i2 = endian == 'I' ? GP_IO_L2 : GP_IO_B2; - - uint16_t IFD_header[] = { - GP_IO_IGN | IFD_offset, - i2, - GP_IO_END, - }; - - if (GP_IOReadF(io, IFD_header, &IFD_entries_count) != 2) { - GP_DEBUG(1, "Failed to read IFD entries count"); - return 1; - } - - GP_DEBUG(2, "-- IFD Offset 0x%08x Entries 0x%04x --", - IFD_offset, IFD_entries_count); - - uint16_t IFD_record_LE[] = { - GP_IO_L2, /* Tag */ - GP_IO_L2, /* Format */ - GP_IO_L4, /* Number of components */ - GP_IO_L4, /* Value */ - GP_IO_END, - }; - - uint16_t IFD_record_BE[] = { - GP_IO_B2, /* Tag */ - GP_IO_B2, /* Format */ - GP_IO_B4, /* Number of components */ - GP_IO_B4, /* Value */ - GP_IO_END, - }; - - uint16_t *IFD_record = endian == 'I' ? IFD_record_LE : IFD_record_BE; - - int i; - - for (i = 0; i < IFD_entries_count; i++) { - uint16_t tag, format; - uint32_t num_comp, val; - off_t cur_off; - - if (GP_IOReadF(io, IFD_record, &tag, &format, &num_comp, &val) != 4) { - GP_DEBUG(1, "Failed to read IFD record"); - return 1; - } - - GP_DEBUG(3, "IFD Entry tag 0x%04x format (0x%04x) components 0x%08x val 0x%08x", - tag, format, num_comp, val); - - GP_DEBUG(3, "IFD Entry tag '%s' format '%s'", - IFD_tag_name(tag), IFD_format_name(format)); - - - if (tag == IFD_EXIF_OFFSET) { - cur_off = GP_IOTell(io); - - /* Offset is counted from the II or MM in the Exif header */ - if (val + 6 < cur_off) - GP_DEBUG(1, "Negative offset!"); - else - load_IFD(io, storage, node, val + 6 - cur_off, endian); - } else { - load_tag(io, storage, node, endian, tag, format, num_comp, val); - } - } - -/* - GET_32(IFD_offset, buf, IFD_offset, buf_len, swap); - - if (IFD_offset != 0x00000000) - load_IFD(self, buf, buf_len, IFD_offset, swap); -*/ - return 0; -} - -int GP_ReadExif(GP_IO *io, GP_DataStorage *storage) -{ - static int swap = 0; - char b1, b2; - uint32_t IFD_offset; - - uint16_t exif_header[] = { - 'E', 'x', 'i', 'f', 0, 0, /* EXIF signature */ - GP_IO_BYTE, GP_IO_BYTE, /* Endianity markers II or MM */ - 0x2a, 0x00, /* TIFF tag */ - GP_IO_L4, /* IFD offset */ - GP_IO_END, - }; - - if (GP_IOReadF(io, exif_header, &b1, &b2, &IFD_offset) != 11) { - GP_DEBUG(1, "Failed to read Exif header"); - return 1; - } - - if (b1 != b2 || (b1 != 'I' && b1 != 'M')) { - GP_WARN("Expected II or MM got %x%x, corrupt header?", b1, b2); - errno = EINVAL; - return 1; - } - - swap = (b1 == 'M'); - - GP_DEBUG(2, "TIFF aligment is '%c%c' swap = %i", b1, b1, swap); - - if (swap) { - //SWAP IFD_offset - } - - GP_DEBUG(2, "IFD offset is 0x%08x", IFD_offset); - - if (IFD_offset < 8) { - GP_WARN("Invalid (negative) IFD offset"); - errno = EINVAL; - return 1; - } - - GP_DataNode *exif_root = GP_DataStorageAddDict(storage, NULL, "Exif"); - - /* The offset starts from the II or MM */ - return load_IFD(io, storage, exif_root, IFD_offset - 8, b1); -} +static const struct IFD_tags IFD_EXIF_tags = { + .tags = IFD_EXIF_taglist, + .tag_cnt = GP_ARRAY_SIZE(IFD_EXIF_taglist), + .id = "Exif", +}; diff --git a/libs/loaders/GP_ExifGPS.h b/libs/loaders/GP_ExifGPS.h new file mode 100644 index 0000000..5e921f7 --- /dev/null +++ b/libs/loaders/GP_ExifGPS.h @@ -0,0 +1,62 @@ +/***************************************************************************** + * This file is part of gfxprim library. * + * * + * Gfxprim is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * Gfxprim is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with gfxprim; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, * + * Boston, MA 02110-1301 USA * + * * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * + * * + *****************************************************************************/ + +enum IFD_GPS_tags { + IFD_GPS_VERSION_ID = 0x0, + /* 'N' = North, 'S' = South */ + IFD_GPS_LATITUDE_REF = 0x1, + /* Degrees, Minutes, Seconds */ + IFD_GPS_LATITUDE = 0x2, + /* 'E' = East, 'W' = West */ + IFD_GPS_LONGITUDE_REF = 0x3, + /* Degrees, Minutes, Seconds */ + IFD_GPS_LONGITUDE = 0x4, + /* 0 = Sea level, 1 = Sea level reference (negative value) */ + IFD_GPS_ALTITUDE_REF = 0x5, + /* Altitude in meters */ + IFD_GPS_ALTITUDE = 0x6, + /* Hour, Minute, Second */ + IFD_GPS_TIMESTAMP = 0x7, + + /* 'TOKYO' or 'WGS-84' */ + IFD_GPS_MAP_DATUM = 0x12, +}; + +/* MUST SORTED BY TAG */ +static const struct IFD_tag IFD_GPS_taglist[] = { + {IFD_GPS_VERSION_ID, "Version Info", IFD_UNSIGNED_BYTE, 4}, + {IFD_GPS_LATITUDE_REF, "Latitude Ref", IFD_ASCII_STRING, 2}, + {IFD_GPS_LATITUDE, "Latitude", IFD_UNSIGNED_RATIONAL, 3}, + {IFD_GPS_LONGITUDE_REF, "Longitude Ref", IFD_ASCII_STRING, 2}, + {IFD_GPS_LONGITUDE, "Longitude", IFD_UNSIGNED_RATIONAL, 3}, + {IFD_GPS_ALTITUDE_REF, "Altitude Ref", IFD_UNSIGNED_BYTE, 1}, + {IFD_GPS_ALTITUDE, "Altitude", IFD_UNSIGNED_RATIONAL, 1}, + {IFD_GPS_TIMESTAMP, "Time Stamp", IFD_UNSIGNED_RATIONAL, 3}, + + {IFD_GPS_MAP_DATUM, "Map Datum", IFD_ASCII_STRING, 0}, +}; + +static const struct IFD_tags IFD_GPS_tags = { + .tags = IFD_GPS_taglist, + .tag_cnt = GP_ARRAY_SIZE(IFD_GPS_taglist), + .id = "GPS", +};
-----------------------------------------------------------------------
Summary of changes: libs/loaders/GP_DataStorage.c | 2 +- libs/loaders/GP_Exif.c | 383 +++++------------- libs/loaders/{GP_Exif.c => GP_Exif.h} | 462 ++++------------------ tests/loaders/PBM.h => libs/loaders/GP_ExifGPS.h | 67 ++-- 4 files changed, 209 insertions(+), 705 deletions(-) copy libs/loaders/{GP_Exif.c => GP_Exif.h} (53%) copy tests/loaders/PBM.h => libs/loaders/GP_ExifGPS.h (56%)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos@gmail.com if you want to unsubscribe, or site admin admin@repo.or.cz if you receive no reply.