X-Git-Url: http://git.imager.perl.org/imager.git/blobdiff_plain/b8c2033e5aee9480ee5f2d219bde41ee1d365505..a34dc54c7c4b65e15d89a0e7934e728aa2eaea4f:/tags.c diff --git a/tags.c b/tags.c index dffe0eb6..1d759e7a 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 @@ -44,9 +48,11 @@ A tag is represented by an i_img_tag structure: =cut */ -#include "image.h" +#include "imager.h" #include #include +#include +#include /* useful for debugging */ void i_tags_print(i_img_tags *tags); @@ -54,9 +60,14 @@ void i_tags_print(i_img_tags *tags); /* =item i_tags_new(i_img_tags *tags) +=category Tags + Initialize a tags structure. Should not be used if the tags structure has been previously used. +This should be called tags member of an i_img object on creation (in +i_img_*_new() functions). + To destroy the contents use i_tags_destroy() =cut @@ -72,14 +83,14 @@ void i_tags_new(i_img_tags *tags) { Adds a tag that has an integer value. A simple wrapper around i_tags_add(). -Duplicate tags can be added. +Use i_tags_setn() instead, this function may be removed in the future. 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); } @@ -88,26 +99,28 @@ int i_tags_addn(i_img_tags *tags, char *name, int code, int idata) { Adds a tag to the tags list. -Duplicate tags can be added. +Use i_tags_set() instead, this function may be removed in the future. 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 = malloc(sizeof(i_img_tag) * alloc); + tags->tags = mymalloc(sizeof(i_img_tag) * alloc); if (!tags->tags) return 0; tags->alloc = alloc; } 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; } @@ -115,15 +128,17 @@ int i_tags_add(i_img_tags *tags, char *name, int code, char *data, int size, tags->alloc = newalloc; } if (name) { - work.name = malloc(strlen(name)+1); + work.name = mymalloc(strlen(name)+1); if (!work.name) return 0; strcpy(work.name, name); } if (data) { - work.data = malloc(size+1); + if (size == -1) + size = strlen(data); + work.data = mymalloc(size+1); if (!work.data) { - if (work.name) free(work.name); + if (work.name) myfree(work.name); return 0; } memcpy(work.data, data, size); @@ -134,23 +149,49 @@ 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; } +/* +=item i_tags_destroy(tags) + +=category Tags + +Destroys the given tags structure. Called by i_img_destroy(). + +=cut +*/ + void i_tags_destroy(i_img_tags *tags) { if (tags->tags) { int i; for (i = 0; i < tags->count; ++i) { if (tags->tags[i].name) - free(tags->tags[i].name); + myfree(tags->tags[i].name); if (tags->tags[i].data) - free(tags->tags[i].data); + myfree(tags->tags[i].data); } - free(tags->tags); + myfree(tags->tags); } } -int i_tags_find(i_img_tags *tags, char *name, int start, int *entry) { +/* +=item i_tags_find(tags, name, start, &entry) + +=category Tags + +Searches for a tag of the given I starting from index I. + +On success returns true and sets *I. + +On failure returns false. + +=cut +*/ + +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) { @@ -163,6 +204,20 @@ int i_tags_find(i_img_tags *tags, char *name, int start, int *entry) { return 0; } +/* +=item i_tags_findn(tags, code, start, &entry) + +=category Tags + +Searches for a tag of the given I starting from index I. + +On success returns true and sets *I. + +On failure returns false. + +=cut +*/ + int i_tags_findn(i_img_tags *tags, int code, int start, int *entry) { if (tags->tags) { while (start < tags->count) { @@ -176,24 +231,52 @@ int i_tags_findn(i_img_tags *tags, int code, int start, int *entry) { return 0; } +/* +=item i_tags_delete(tags, index) + +=category Tags + +Delete a tag by index. + +Returns true on success. + +=cut +*/ 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) - free(old.name); + myfree(old.name); if (old.data) - free(old.data); + myfree(old.data); --tags->count; + return 1; } return 0; } -int i_tags_delbyname(i_img_tags *tags, char *name) { +/* +=item i_tags_delbyname(tags, name) + +=category Tags + +Delete any tags with the given name. + +Returns the number of tags deleted. + +=cut +*/ + +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,9 +285,23 @@ int i_tags_delbyname(i_img_tags *tags, char *name) { } } } + /*i_tags_print(tags);*/ + return count; } +/* +=item i_tags_delbycode(tags, code) + +=category Tags + +Delete any tags with the given code. + +Returns the number of tags deleted. + +=cut +*/ + int i_tags_delbycode(i_img_tags *tags, int code) { int count = 0; int i; @@ -219,7 +316,25 @@ 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) { +/* +=item i_tags_get_float(tags, name, code, value) + +=category Tags + +Retrieves a tag as a floating point value. + +If the tag has a string value then that is parsed as a floating point +number, otherwise the integer value of the tag is used. + +On success sets *I and returns true. + +On failure returns false. + +=cut +*/ + +int i_tags_get_float(i_img_tags *tags, char const *name, int code, + double *value) { int index; i_img_tag *entry; @@ -240,10 +355,45 @@ 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) { +/* +=item i_tags_set_float(tags, name, code, value) + +=category Tags + +Equivalent to i_tags_set_float2(tags, name, code, value, 30). + +=cut +*/ + +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) + +=category Tags + +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 +402,21 @@ 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) { +/* +=item i_tags_get_int(tags, name, code, &value) + +=category Tags + +Retrieve a tag specified by name or code as an integer. + +On success sets the int *I to the integer and returns true. + +On failure returns false. + +=cut +*/ + +int i_tags_get_int(i_img_tags *tags, char const *name, int code, int *value) { int index; i_img_tag *entry; @@ -273,7 +437,155 @@ 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; +} + +/* +=item i_tags_get_color(tags, name, code, &value) + +=category Tags + +Retrieve a tag specified by name or code as color. + +On success sets the i_color *I to the color and returns true. + +On failure returns false. + +=cut +*/ + +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; +} + +/* +=item i_tags_set_color(tags, name, code, &value) + +=category Tags + +Stores the given color as a tag with the given name and code. + +=cut +*/ + +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); +} + +/* +=item i_tags_get_string(tags, name, code, value, value_size) + +=category Tags + +Retrieves a tag by name or code as a string. + +On success copies the string to value for a max of value_size and +returns true. + +On failure returns false. + +value_size must be at least large enough for a string representation +of an integer. + +The copied value is always C terminated. + +=cut +*/ + +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,12 +607,55 @@ 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; } +/* +=item i_tags_set(tags, name, data, size) +=synopsis i_tags_set(&img->tags, "i_comment", -1); +=category Tags + +Sets the given tag to the string I + +If size is -1 then the strlen(I) bytes are stored. + +Even on failure, if an existing tag I exists, it will be +removed. + +=cut +*/ + +int +i_tags_set(i_img_tags *tags, char const *name, char const *data, int size) { + i_tags_delbyname(tags, name); + + return i_tags_add(tags, name, 0, data, size, 0); +} + +/* +=item i_tags_setn(C, C, C) +=synopsis i_tags_setn(&img->tags, "i_xres", 204); +=synopsis i_tags_setn(&img->tags, "i_yres", 196); +=category Tags + +Sets the given tag to the integer C + +Even on failure, if an existing tag C exists, it will be +removed. + +=cut +*/ + +int +i_tags_setn(i_img_tags *tags, char const *name, int idata) { + i_tags_delbyname(tags, name); + + return i_tags_addn(tags, name, 0, idata); +} + void i_tags_print(i_img_tags *tags) { int i; printf("Alloc %d\n", tags->alloc); @@ -309,11 +664,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('\\');