X-Git-Url: http://git.imager.perl.org/imager.git/blobdiff_plain/4dfa55222d1fe433a6f5e0e8c67b1168a9cb1ee3..454ad005690f1fdfe644ffb186cb2d30e3c40cab:/tags.c diff --git a/tags.c b/tags.c index b6f39602..bf8d3a5b 100644 --- a/tags.c +++ b/tags.c @@ -15,6 +15,10 @@ tags.c - functions for manipulating an images tags list i_tags_delete(&tags, index); count = i_tags_delbyname(tags, name); count = i_tags_delbycode(tags, code); + if (i_tags_get_float(&tags, name, code, &float_value)) { found } + i_tags_set_float(&tags, name, code, value); + i_tags_set_float2(&tags, name, code, value, sig_digits); + i_tags_get_int(&tags, name, code, &int_value); =head1 DESCRIPTION @@ -47,6 +51,8 @@ A tag is represented by an i_img_tag structure: #include "image.h" #include #include +#include +#include /* useful for debugging */ void i_tags_print(i_img_tags *tags); @@ -79,7 +85,7 @@ Returns non-zero on success. =cut */ -int i_tags_addn(i_img_tags *tags, char *name, int code, int idata) { +int i_tags_addn(i_img_tags *tags, char const *name, int code, int idata) { return i_tags_add(tags, name, code, NULL, 0, idata); } @@ -95,9 +101,11 @@ Returns non-zero on success. =cut */ -int i_tags_add(i_img_tags *tags, char *name, int code, char *data, int size, - int idata) { +int i_tags_add(i_img_tags *tags, char const *name, int code, char const *data, + int size, int idata) { i_img_tag work = {0}; + /*printf("i_tags_add(tags %p [count %d], name %s, code %d, data %p, size %d, idata %d)\n", + tags, tags->count, name, code, data, size, idata);*/ if (tags->tags == NULL) { int alloc = 10; tags->tags = mymalloc(sizeof(i_img_tag) * alloc); @@ -107,7 +115,7 @@ int i_tags_add(i_img_tags *tags, char *name, int code, char *data, int size, } else if (tags->count == tags->alloc) { int newalloc = tags->alloc + 10; - void *newtags = realloc(tags->tags, sizeof(i_img_tag) * newalloc); + void *newtags = myrealloc(tags->tags, sizeof(i_img_tag) * newalloc); if (!newtags) { return 0; } @@ -121,6 +129,8 @@ int i_tags_add(i_img_tags *tags, char *name, int code, char *data, int size, strcpy(work.name, name); } if (data) { + if (size == -1) + size = strlen(data); work.data = mymalloc(size+1); if (!work.data) { if (work.name) myfree(work.name); @@ -134,6 +144,8 @@ int i_tags_add(i_img_tags *tags, char *name, int code, char *data, int size, work.idata = idata; tags->tags[tags->count++] = work; + /*i_tags_print(tags);*/ + return 1; } @@ -150,7 +162,7 @@ void i_tags_destroy(i_img_tags *tags) { } } -int i_tags_find(i_img_tags *tags, char *name, int start, int *entry) { +int i_tags_find(i_img_tags *tags, char const *name, int start, int *entry) { if (tags->tags) { while (start < tags->count) { if (tags->tags[start].name && strcmp(name, tags->tags[start].name) == 0) { @@ -177,23 +189,28 @@ int i_tags_findn(i_img_tags *tags, int code, int start, int *entry) { } int i_tags_delete(i_img_tags *tags, int entry) { + /*printf("i_tags_delete(tags %p [count %d], entry %d)\n", + tags, tags->count, entry);*/ if (tags->tags && entry >= 0 && entry < tags->count) { i_img_tag old = tags->tags[entry]; memmove(tags->tags+entry, tags->tags+entry+1, - tags->count-entry-1); + (tags->count-entry-1) * sizeof(i_img_tag)); if (old.name) myfree(old.name); if (old.data) myfree(old.data); --tags->count; + return 1; } return 0; } -int i_tags_delbyname(i_img_tags *tags, char *name) { +int i_tags_delbyname(i_img_tags *tags, char const *name) { int count = 0; int i; + /*printf("i_tags_delbyname(tags %p [count %d], name %s)\n", + tags, tags->count, name);*/ if (tags->tags) { for (i = tags->count-1; i >= 0; --i) { if (tags->tags[i].name && strcmp(name, tags->tags[i].name) == 0) { @@ -202,6 +219,8 @@ int i_tags_delbyname(i_img_tags *tags, char *name) { } } } + /*i_tags_print(tags);*/ + return count; } @@ -219,7 +238,8 @@ int i_tags_delbycode(i_img_tags *tags, int code) { return count; } -int i_tags_get_float(i_img_tags *tags, char *name, int code, double *value) { +int i_tags_get_float(i_img_tags *tags, char const *name, int code, + double *value) { int index; i_img_tag *entry; @@ -240,10 +260,33 @@ int i_tags_get_float(i_img_tags *tags, char *name, int code, double *value) { return 1; } -int i_tags_set_float(i_img_tags *tags, char *name, int code, double value) { +int i_tags_set_float(i_img_tags *tags, char const *name, int code, + double value) { + return i_tags_set_float2(tags, name, code, value, 30); +} + +/* +=item i_tags_set_float2(tags, name, code, value, places) + +Sets the tag with the given name and code to the given floating point +value. + +Since tags are strings or ints, we convert the value to a string before +storage at the precision specified by C. + +=cut +*/ + +int i_tags_set_float2(i_img_tags *tags, char const *name, int code, + double value, int places) { char temp[40]; - sprintf(temp, "%.30g", value); + if (places < 0) + places = 30; + else if (places > 30) + places = 30; + + sprintf(temp, "%.*g", places, value); if (name) i_tags_delbyname(tags, name); else @@ -252,7 +295,7 @@ int i_tags_set_float(i_img_tags *tags, char *name, int code, double value) { return i_tags_add(tags, name, code, temp, strlen(temp), 0); } -int i_tags_get_int(i_img_tags *tags, char *name, int code, int *value) { +int i_tags_get_int(i_img_tags *tags, char const *name, int code, int *value) { int index; i_img_tag *entry; @@ -273,7 +316,111 @@ int i_tags_get_int(i_img_tags *tags, char *name, int code, int *value) { return 1; } -int i_tags_get_string(i_img_tags *tags, char *name, int code, +static int parse_long(char *data, char **end, long *out) { + long result; + int savederr = errno; + char *myend; + + errno = 0; + result = strtol(data, &myend, 10); + if ((result == LONG_MIN || result == LONG_MAX) && errno == ERANGE + || myend == data) { + errno = savederr; + return 0; + } + + errno = savederr; + *out = result; + *end = myend; + + return 1; +} + +/* parse a comma-separated list of integers + returns when it has maxcount numbers, finds a non-comma after a number + or can't parse a number + if it can't parse a number after a comma, that's considered an error +*/ +static int parse_long_list(char *data, char **end, int maxcount, long *out) { + int i; + + i = 0; + while (i < maxcount-1) { + if (!parse_long(data, &data, out)) + return 0; + out++; + i++; + if (*data != ',') + return i; + ++data; + } + if (!parse_long(data, &data, out)) + return 0; + ++i; + *end = data; + return i; +} + +/* parse "color(red,green,blue,alpha)" */ +static int parse_color(char *data, char **end, i_color *value) { + long n[4]; + int count, i; + + if (memcmp(data, "color(", 6)) + return 0; /* not a color */ + data += 6; + count = parse_long_list(data, &data, 4, n); + if (count < 3) + return 0; + for (i = 0; i < count; ++i) + value->channel[i] = n[i]; + if (count < 4) + value->channel[3] = 255; + + return 1; +} + +int i_tags_get_color(i_img_tags *tags, char const *name, int code, + i_color *value) { + int index; + i_img_tag *entry; + char *end; + + if (name) { + if (!i_tags_find(tags, name, 0, &index)) + return 0; + } + else { + if (!i_tags_findn(tags, code, 0, &index)) + return 0; + } + entry = tags->tags+index; + if (!entry->data) + return 0; + + if (!parse_color(entry->data, &end, value)) + return 0; + + /* for now we're sloppy about the end */ + + return 1; +} + +int i_tags_set_color(i_img_tags *tags, char const *name, int code, + i_color const *value) { + char temp[80]; + + sprintf(temp, "color(%d,%d,%d,%d)", value->channel[0], value->channel[1], + value->channel[2], value->channel[3]); + if (name) + i_tags_delbyname(tags, name); + else + i_tags_delbycode(tags, code); + + return i_tags_add(tags, name, code, temp, strlen(temp), 0); +} + +int i_tags_get_string(i_img_tags *tags, char const *name, int code, char *value, size_t value_size) { int index; i_img_tag *entry; @@ -295,7 +442,7 @@ int i_tags_get_string(i_img_tags *tags, char *name, int code, value[cpsize] = '\0'; } else { - sprintf(value, "%d", entry->data); + sprintf(value, "%d", entry->idata); } return 1; @@ -309,11 +456,11 @@ void i_tags_print(i_img_tags *tags) { i_img_tag *tag = tags->tags + i; printf("Tag %d\n", i); if (tag->name) - printf(" Name : %s\n", tag->name); + printf(" Name : %s (%p)\n", tag->name, tag->name); printf(" Code : %d\n", tag->code); if (tag->data) { int pos; - printf(" Data : %d => '", tag->size); + printf(" Data : %d (%p) => '", tag->size, tag->data); for (pos = 0; pos < tag->size; ++pos) { if (tag->data[pos] == '\\' || tag->data[pos] == '\'') { putchar('\\');