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 8da4803c71d9fba0fb5a70c8cc5feccbaf4fdac0 (commit) via d0497f46eebcf460bd1377686f1f6218804743b4 (commit) from 9dc7c882ccd99e87e0146b367037d89ceb98aef1 (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/8da4803c71d9fba0fb5a70c8cc5feccbaf4fd...
commit 8da4803c71d9fba0fb5a70c8cc5feccbaf4fdac0 Author: Cyril Hrubis metan@ucw.cz Date: Sat Jun 2 00:08:53 2012 +0200
loaders: Added Exif to MetaData parser.
diff --git a/demos/c_simple/meta_data.c b/demos/c_simple/meta_data.c index b5f2905..746f6b7 100644 --- a/demos/c_simple/meta_data.c +++ b/demos/c_simple/meta_data.c @@ -60,8 +60,8 @@ int main(void) * The last parameter says, if the string should be duplicated * in the metadata storage. */ - GP_MetaDataCreateString(data, "author", "Foo Bar foo@bar.net", 1); - GP_MetaDataCreateString(data, "comment", "Created in hurry.", 1); + GP_MetaDataCreateString(data, "author", "Foo Bar foo@bar.net", 0, 1); + GP_MetaDataCreateString(data, "comment", "Created in hurry.", 0, 1); GP_MetaDataCreateDouble(data, "pi", 3.141592);
const char *ret; diff --git a/include/loaders/GP_MetaData.h b/include/loaders/GP_MetaData.h index 4da30f1..2c529d2 100644 --- a/include/loaders/GP_MetaData.h +++ b/include/loaders/GP_MetaData.h @@ -23,18 +23,25 @@ #ifndef LOADERS_METADATA_H #define LOADERS_METADATA_H
-#define GP_META_RECORD_ID_MAX 16 +#define GP_META_RECORD_ID_MAX 32
enum GP_MetaType { GP_META_INT, GP_META_STRING, GP_META_DOUBLE, + GP_META_RATIONAL, +}; + +struct GP_MetaRational { + int num; + int den; };
union GP_MetaValue { int i; double d; const char *str; + struct GP_MetaRational r; };
typedef struct GP_MetaRecord { @@ -98,6 +105,9 @@ GP_MetaRecord *GP_MetaDataCreateRecord(GP_MetaData *self, const char *id); */ GP_MetaRecord *GP_MetaDataCreateInt(GP_MetaData *self, const char *id, int val);
+GP_MetaRecord *GP_MetaDataCreateRat(GP_MetaData *self, const char *id, + int num, int den); + /* * Creates an double record and returns pointer to it. */ @@ -107,10 +117,19 @@ GP_MetaRecord *GP_MetaDataCreateDouble(GP_MetaData *self, const char *id, /* * Creates an string record and returns pointer to it. * + * If len == 0, string is copied to the terminating '0', otherwise len + * characters is copied. This has no effect if dup == 0. + * * If dup is set to 1, the string is duplicated inside of the MetaData * structure, otherwise only the pointer is saved. */ GP_MetaRecord *GP_MetaDataCreateString(GP_MetaData *self, const char *id, - const char *str, int dup); + const char *str, int len, int dup); + +/* + * Parses Exif data from passed buffer. The start of the buffer must point to + * the ASCII 'Exif' string. + */ +int GP_MetaDataFromExif(GP_MetaData *self, void *buf, size_t buf_len);
#endif /* LOADERS_GP_METADATA_H */ diff --git a/libs/loaders/GP_JPG.c b/libs/loaders/GP_JPG.c index f600b57..72e4c86 100644 --- a/libs/loaders/GP_JPG.c +++ b/libs/loaders/GP_JPG.c @@ -214,24 +214,15 @@ static void read_jpg_metadata(struct jpeg_decompress_struct *cinfo,
for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) { switch (marker->marker) { - case JPEG_COM: { - char buf[JPEG_COM_MAX+1]; - - memcpy(buf, marker->data, marker->data_length); - buf[marker->data_length] = 0; - - /* Strip newline at the end of the commment */ - if (buf[marker->data_length-1] == 'n') - buf[marker->data_length-1] = 0; - - GP_MetaDataCreateString(data, "comment", buf, 1); - } + case JPEG_COM: + GP_MetaDataCreateString(data, "comment", (void*)marker->data, + marker->data_length, 1); break; case JPEG_APP0: GP_DEBUG(0, "TODO: JFIF"); break; case JPEG_APP0 + 1: - GP_DEBUG(0, "TODO: EXIF"); + GP_MetaDataFromExif(data, marker->data, marker->data_length); break; } } diff --git a/libs/loaders/GP_MetaData.c b/libs/loaders/GP_MetaData.c index e62af18..1403e01 100644 --- a/libs/loaders/GP_MetaData.c +++ b/libs/loaders/GP_MetaData.c @@ -29,6 +29,7 @@
struct GP_MetaData { struct GP_MetaRecord *root; + struct GP_MetaRecord *last; unsigned int rec_count; size_t size; size_t free; @@ -63,6 +64,7 @@ GP_MetaData *GP_MetaDataCreate(unsigned int expected_records) }
data->root = NULL; + data->last = NULL; data->rec_count = 0; data->size = size; data->free = size; @@ -76,6 +78,7 @@ void GP_MetaDataClear(GP_MetaData *self) self, self->rec_count); self->root = NULL; + self->last = NULL; self->rec_count = 0; self->free = self->size; } @@ -93,12 +96,15 @@ void GP_MetaDataPrint(GP_MetaData *self) printf("MetaData %u record(s)n", self->rec_count);
for (rec = self->root; rec != NULL; rec = rec->next) { - printf("%-16s: ", rec->id); + printf("%-32s: ", rec->id);
switch (rec->type) { case GP_META_INT: printf("%in", rec->val.i); break; + case GP_META_RATIONAL: + printf("%i/%in", rec->val.r.num, rec->val.r.den); + break; case GP_META_STRING: printf("'%s'n", rec->val.str); break; @@ -153,9 +159,16 @@ static GP_MetaRecord *record_create(GP_MetaData *self, const char *id,
strcpy(rec->id, id); rec->hash = hash; - rec->next = self->root; - self->root = rec; - + + if (self->root == NULL) { + self->root = rec; + self->last = rec; + } else { + self->last->next = rec; + self->last = rec; + rec->next = NULL; + } + self->rec_count++;
return rec; @@ -263,6 +276,30 @@ GP_MetaRecord *GP_MetaDataCreateInt(GP_MetaData *self, const char *id, int val) return rec; }
+GP_MetaRecord *GP_MetaDataCreateRat(GP_MetaData *self, const char *id, + int num, int den) +{ + GP_MetaRecord *rec; + + GP_DEBUG(2, "Creating GP_META_RATIONAL id '%s' = %i/%i", id, num, den); + + if (den == 0) { + GP_DEBUG(1, "Would not create '%s' with denominator == 0", id); + return NULL; + } + + rec = GP_MetaDataCreateRecord(self, id); + + if (rec == NULL) + return NULL; + + rec->type = GP_META_RATIONAL; + rec->val.r.num = num; + rec->val.r.den = den; + + return rec; +} + GP_MetaRecord *GP_MetaDataCreateDouble(GP_MetaData *self, const char *id, double val) { @@ -282,7 +319,7 @@ GP_MetaRecord *GP_MetaDataCreateDouble(GP_MetaData *self, const char *id, }
GP_MetaRecord *GP_MetaDataCreateString(GP_MetaData *self, const char *id, - const char *str, int dup) + const char *str, int len, int dup) { GP_MetaRecord *rec;
@@ -294,8 +331,13 @@ GP_MetaRecord *GP_MetaDataCreateString(GP_MetaData *self, const char *id, return NULL;
if (dup) { - size_t size = strlen(str) + 1; + size_t size; char *s; + + if (len == 0) + size = strlen(str) + 1; + else + size = len + 1;
/* Play safe with aligment */ if (size % 8) @@ -303,7 +345,8 @@ GP_MetaRecord *GP_MetaDataCreateString(GP_MetaData *self, const char *id,
//TODO: allocation error s = do_alloc(self, size); - strcpy(s, str); + strncpy(s, str, size - 1); + s[size - 1] = '0'; str = s; }
diff --git a/libs/loaders/GP_MetaExif.c b/libs/loaders/GP_MetaExif.c new file mode 100644 index 0000000..e6a89bc --- /dev/null +++ b/libs/loaders/GP_MetaExif.c @@ -0,0 +1,487 @@ +/***************************************************************************** + * 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-2012 Cyril Hrubis metan@ucw.cz * + * * + *****************************************************************************/ + +#include <stdlib.h> +#include <string.h> + +#include "core/GP_Debug.h" + +#include "GP_MetaData.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 description */ + IFD_IMAGE_DESCRIPTION = 0x010e, + /* camera manufacturer */ + IFD_MAKE = 0x010f, + /* camera model */ + IFD_MODEL = 0x0110, + /* 1 = upper left, 3 = lower right, 6 = upper right, * + * 8 = lower left, 9 = undefined */ + IFD_ORIENTATION = 0x0112, + /* x resolution */ + IFD_X_RESOLUTION = 0x011a, + /* y resolution */ + IFD_Y_RESOLUTION = 0x011b, + /* 1 = no unit, 2 = inch, 3 = centimeter */ + IFD_RESOLUTION_UNIT = 0x0128, + /* software */ + IFD_SOFTWARE = 0x0131, + /* date time */ + 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 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, +}; + +struct IFD_tag { + uint16_t tag; + const char *name; + uint16_t format; + /* 0 == not defined */ + uint32_t num_components; +}; + +/* These are sorted by tag */ +static const struct IFD_tag IFD_tags[] = { + /* TAGs from IFD0 */ + {IFD_IMAGE_DESCRIPTION, "Image Description", IFD_ASCII_STRING, 0}, + {IFD_MAKE, "Camera Manufacturer", IFD_ASCII_STRING, 0}, + {IFD_MODEL, "Camera 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_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, 2}, + {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}, +}; + +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 buf_char(void *buf, size_t pos, size_t buf_len) +{ + if (pos >= buf_len) { + GP_DEBUG(1, "Byte position %zu out of buffer len %zu", pos, buf_len); + return -1; + } + + return ((char*)buf)[pos]; +} + +#define GET_16(res, buf, pos, buf_len, swap) do { + if (pos + 1 >= buf_len) { + GP_DEBUG(1, "2-byte position %zu out of buffer len %zu", + (size_t)pos, buf_len); + return -1; + } + + if (swap) + res = ((uint8_t*)buf)[pos]<<8 | ((uint8_t*)buf)[pos+1]; + else + res = ((uint8_t*)buf)[pos] | ((uint8_t*)buf)[pos+1]<<8; +} while (0) + +#define GET_32(res, buf, pos, buf_len, swap) do { + if (pos + 3 >= buf_len) { + GP_DEBUG(1, "4-byte position %zu out of buffer len %zu", + (size_t)pos, buf_len); + return -1; + } + + if (swap) + res = (((uint8_t*)buf)[pos])<<24 | (((uint8_t*)buf)[pos+1])<<16 | + (((uint8_t*)buf)[pos+2])<<8 | ((uint8_t*)buf)[pos+3]; + else + res = ((uint8_t*)buf)[pos] | (((uint8_t*)buf)[pos+1])<<8 | + (((uint8_t*)buf)[pos+2])<<16 | (((uint8_t*)buf)[pos+3])<<24; +} while (0) + +#define GET_16_INC(res, buf, pos, buf_len, swap) do { + GET_16(res, buf, pos, buf_len, swap); + pos += 2; +} while (0) + +#define GET_32_INC(res, buf, pos, buf_len, swap) do { + GET_32(res, buf, pos, buf_len, swap); + pos += 4; +} while (0) + +static const char *get_string(void *buf, size_t buf_len, + uint32_t num_comp, uint32_t *val) +{ + if (num_comp <= 4) + return (const char*)val; + + if (*val + num_comp >= buf_len) { + GP_DEBUG(1, "String out of buffer offset 0x%08x length %u", + *val, num_comp); + return NULL; + } + + return ((const char*)buf) + *val; +} + +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 void load_tag(GP_MetaData *self, void *buf, size_t buf_len, int swap, + 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_DEBUG(1, "Skipping unknown IFD tag 0x%02x", tag); + return; + } + + if (res->format != format) { + GP_DEBUG(1, "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_DEBUG(1, "Unexpected tag '%s' num_components %u expected %u", + res->name, num_comp, res->num_components); + } + + switch (format) { + case IFD_ASCII_STRING: { + const char *addr = get_string(buf, buf_len, num_comp, &val); + + if (addr == NULL) + return; + + GP_MetaDataCreateString(self, res->name, addr, num_comp, 1); + } break; + case IFD_UNSIGNED_SHORT: + if (num_comp == 1) + GP_MetaDataCreateInt(self, res->name, val); + else + goto unused; + break; + case IFD_UNSIGNED_RATIONAL: + case IFD_SIGNED_RATIONAL: + if (num_comp == 1) + GP_MetaDataCreateRat(self, res->name, + rat_num(buf, val, buf_len, swap), + rat_den(buf, val, buf_len, swap)); + else + goto unused; + break; + unused: + default: + GP_DEBUG(1, "Unused record '%s' format '%s' (0x%02x)", res->name, + IFD_format_name(format), format); + } +} + +/* + * Loads IFD block. + */ +static int load_IFD(GP_MetaData *self, void *buf, size_t buf_len, + uint32_t IFD_offset, int swap) +{ + uint16_t IFD_entries_count; + + GET_16_INC(IFD_entries_count, buf, IFD_offset, buf_len, swap); + + GP_DEBUG(2, "-- IFD Offset 0x%08x Entries 0x%04x --", + IFD_offset, IFD_entries_count); + + int i; + + for (i = 0; i < IFD_entries_count; i++) { + uint16_t tag, format; + uint32_t num_components, val; + + GET_16_INC(tag, buf, IFD_offset, buf_len, swap); + GET_16_INC(format, buf, IFD_offset, buf_len, swap); + GET_32_INC(num_components, buf, IFD_offset, buf_len, swap); + GET_32_INC(val, buf, IFD_offset, buf_len, swap); + + GP_DEBUG(3, "IFD Entry tag 0x%04x format (0x%04x) components 0x%08x val 0x%08x", + tag, format, num_components, val); + + GP_DEBUG(3, "IFD Entry tag '%s' format '%s'", + IFD_tag_name(tag), IFD_format_name(format)); + + if (tag == IFD_EXIF_OFFSET) + load_IFD(self, buf, buf_len, val, swap); + else + load_tag(self, buf, buf_len, swap, tag, format, num_components, 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; +} + +/* Offset from the start of the Exit to TIFF header */ +#define TIFF_OFFSET 6 + +int GP_MetaDataFromExif(GP_MetaData *self, void *buf, size_t buf_len) +{ + static int swap = 0; + int c1, c2; + + if (buf_char(buf, 0, buf_len) != 'E' || + buf_char(buf, 1, buf_len) != 'x' || + buf_char(buf, 2, buf_len) != 'i' || + buf_char(buf, 3, buf_len) != 'f' || + buf_char(buf, 4, buf_len) != 0 || + buf_char(buf, 5, buf_len) != 0) { + GP_DEBUG(1, "Missing ASCII 'Exif + "the start of the buffer"); + return 1; + } + + if (((c1 = buf_char(buf, 6, buf_len)) != + (c2 = buf_char(buf, 7, buf_len))) + || (c1 != 'I' && c1 != 'M')) { + GP_DEBUG(1, "Expected II or MM got %x%x, corrupt header?", + c1, c2); + return 1; + } + + swap = (c1 == 'M'); + + GP_DEBUG(2, "TIFF aligment is '%c%c' swap = %i", c1, c1, swap); + + uint16_t tag; + + GET_16(tag, buf, 8, buf_len, swap); + + if (tag != 0x002a) { + GP_DEBUG(1, "Expected TIFF TAG '0x002a' got '0x%04x'", tag); + return 1; + } + + uint32_t IFD_offset; + + GET_32(IFD_offset, buf, 10, buf_len, swap); + + GP_DEBUG(2, "IFD offset is 0x%08x", IFD_offset); + + /* The offset starts from the II or MM */ + load_IFD(self, (char*)buf + TIFF_OFFSET, buf_len - TIFF_OFFSET, IFD_offset, swap); + + + return 0; +} diff --git a/libs/loaders/GP_PNG.c b/libs/loaders/GP_PNG.c index 5f324aa..2d099fd 100644 --- a/libs/loaders/GP_PNG.c +++ b/libs/loaders/GP_PNG.c @@ -267,7 +267,7 @@ static void load_meta_data(png_structp png, png_infop png_info, GP_MetaData *dat else unit_name = "unknown"; - GP_MetaDataCreateString(data, "res_unit", unit_name, 0); + GP_MetaDataCreateString(data, "res_unit", unit_name, 0, 0); }
png_timep mod_time; @@ -302,7 +302,7 @@ static void load_meta_data(png_structp png, png_infop png_info, GP_MetaData *dat char buf[GP_META_RECORD_ID_MAX]; snprintf(buf, GP_META_RECORD_ID_MAX, "text:%s", text_ptr[i].key); - GP_MetaDataCreateString(data, buf, text_ptr[i].text, 1); + GP_MetaDataCreateString(data, buf, text_ptr[i].text, 0, 1); } } }
http://repo.or.cz/w/gfxprim.git/commit/d0497f46eebcf460bd1377686f1f621880474...
commit d0497f46eebcf460bd1377686f1f6218804743b4 Author: Cyril Hrubis metan@ucw.cz Date: Fri Jun 1 16:58:34 2012 +0200
spiv: Rewrite the backend polling loop.
* Which is still hacky, but at least works now
diff --git a/demos/spiv/spiv.c b/demos/spiv/spiv.c index 9862049..6e03531 100644 --- a/demos/spiv/spiv.c +++ b/demos/spiv/spiv.c @@ -388,18 +388,88 @@ static void init_backend(const char *backend_opts) } }
+static int alarm_fired = 0; + +static void alarm_handler(int signo) +{ + alarm_fired = 1; +} + +static int wait_for_event(int sleep_msec) +{ + static int sleep_msec_count = 0; + static int alarm_set = 0; + + if (sleep_msec < 0) { + GP_BackendPoll(backend); + return 0; + } + + /* We can't sleep on backend fd, because the backend doesn't export it. */ + if (backend->fd < 0) { + GP_BackendPoll(backend); + usleep(10000); + + sleep_msec_count += 10; + + if (sleep_msec_count >= sleep_msec) { + sleep_msec_count = 0; + return 1; + } + + return 0; + } + + /* Initalize select */ + fd_set rfds; + FD_ZERO(&rfds); + + FD_SET(backend->fd, &rfds); + + if (!alarm_set) { + signal(SIGALRM, alarm_handler); + alarm(sleep_msec / 1000); + alarm_fired = 0; + alarm_set = 1; + } + + struct timeval tv = {.tv_sec = sleep_msec / 1000, + .tv_usec = (sleep_msec % 1000) * 1000}; + + int ret = select(backend->fd + 1, &rfds, NULL, NULL, &tv); + + switch (ret) { + case -1: + if (errno == EINTR) + return 1; + + GP_BackendExit(backend); + exit(1); + break; + case 0: + if (alarm_fired) { + alarm_set = 0; + return 1; + } + + return 0; + break; + default: + GP_BackendPoll(backend); + return 0; + } +} + int main(int argc, char *argv[]) { - GP_InputDriverLinux *drv = NULL; GP_Context *context = NULL; - const char *input_dev = NULL; const char *backend_opts = "X11"; int sleep_sec = -1; struct loader_params params = {NULL, 0, 0, 0, .img = NULL}; int opt, debug_level = 0; GP_PixelType emul_type = GP_PIXEL_UNKNOWN;
- while ((opt = getopt(argc, argv, "b:cd:e:fIi:Ps:r:")) != -1) { + while ((opt = getopt(argc, argv, "b:cd:e:fIPs:r:")) != -1) { switch (opt) { case 'I': params.show_info = 1; @@ -407,9 +477,6 @@ int main(int argc, char *argv[]) case 'P': params.show_progress = 1; break; - case 'i': - input_dev = optarg; - break; case 'f': dithering = 1; break; @@ -447,16 +514,6 @@ int main(int argc, char *argv[]) GP_SetDebugLevel(debug_level);
- if (input_dev != NULL) { - drv = GP_InputDriverLinuxOpen(input_dev); - - if (drv == NULL) { - fprintf(stderr, "Failed to initalize input device '%s'n", - input_dev); - return 1; - } - } - signal(SIGINT, sighandler); signal(SIGSEGV, sighandler); signal(SIGBUS, sighandler); @@ -482,56 +539,17 @@ int main(int argc, char *argv[])
params.show_progress_once = 1; show_image(¶ms, argv[argf]); - - for (;;) { - int ret; - - if (drv != NULL) { - /* Initalize select */ - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(drv->fd, &rfds); - struct timeval tv = {.tv_sec = sleep_sec, .tv_usec = 0}; - struct timeval *tvp = sleep_sec != -1 ? &tv : NULL; - - ret = select(drv->fd + 1, &rfds, NULL, NULL, tvp); - tv.tv_sec = sleep_sec; - - switch (ret) { - case -1: - GP_BackendExit(backend); - return 0; - break; - case 0: - argn++; - if (argn >= argc) - argn = argf; - - show_image(¶ms, argv[argn]); - break; - default: - while (GP_InputDriverLinuxRead(drv)); - } - - FD_SET(drv->fd, &rfds); - } else { - if (sleep_sec != -1) { - sleep(sleep_sec); - - argn++; - if (argn >= argc) - argn = argf; - - show_image(¶ms, argv[argn]); - } + for (;;) { + /* wait for event or a timeout */ + if (wait_for_event(sleep_sec * 1000)) { + argn++; + if (argn >= argc) + argn = argf; + + show_image(¶ms, argv[argn]); }
- if (backend->Poll) - GP_BackendPoll(backend); - - usleep(1000); - /* Read and parse events */ GP_Event ev;
-----------------------------------------------------------------------
Summary of changes: demos/c_simple/meta_data.c | 4 +- demos/spiv/spiv.c | 144 +++++++------ include/loaders/GP_MetaData.h | 23 ++- libs/loaders/GP_JPG.c | 17 +- libs/loaders/GP_MetaData.c | 57 +++++- libs/loaders/GP_MetaExif.c | 487 +++++++++++++++++++++++++++++++++++++++++ libs/loaders/GP_PNG.c | 4 +- 7 files changed, 647 insertions(+), 89 deletions(-) create mode 100644 libs/loaders/GP_MetaExif.c
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.