From: Dan F. <dfa...@us...> - 2009-12-09 06:17:31
|
Update of /cvsroot/libexif/libexif/contrib/examples In directory sfp-cvsdas-2.v30.ch3.sourceforge.com:/tmp/cvs-serv27395/contrib/examples Modified Files: write-exif.c Log Message: Fixed some memory leaks in the write-exif.c example program and added some examples of allocating a new tag. Index: write-exif.c =================================================================== RCS file: /cvsroot/libexif/libexif/contrib/examples/write-exif.c,v retrieving revision 1.2 retrieving revision 1.3 diff -u -p -d -r1.2 -r1.3 --- write-exif.c 17 Jun 2009 19:07:45 -0000 1.2 +++ write-exif.c 9 Dec 2009 06:17:19 -0000 1.3 @@ -13,6 +13,8 @@ */ #include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <assert.h> #include <libexif/exif-data.h> @@ -114,21 +116,83 @@ static const unsigned char exif_header[] static const unsigned int exif_header_len = sizeof(exif_header); /* byte order to use in the EXIF block */ -#define BYTE_ORDER EXIF_BYTE_ORDER_INTEL +#define FILE_BYTE_ORDER EXIF_BYTE_ORDER_INTEL + +/* comment to write into the EXIF block */ +#define FILE_COMMENT "libexif demonstration image" + +/* special header required for EXIF_TAG_USER_COMMENT */ +#define ASCII_COMMENT "ASCII\0\0\0" + /* Get an existing tag, or create one if it doesn't exist */ static ExifEntry *init_tag(ExifData *exif, ExifIfd ifd, ExifTag tag) { ExifEntry *entry; + /* Return an existing tag if one exists */ if (!((entry = exif_content_get_entry (exif->ifd[ifd], tag)))) { + /* Allocate a new entry */ entry = exif_entry_new (); assert(entry != NULL); /* catch an out of memory condition */ + entry->tag = tag; /* tag must be set before calling + exif_content_add_entry */ + + /* Attach the ExifEntry to an IFD */ exif_content_add_entry (exif->ifd[ifd], entry); + + /* Allocate memory for the entry and fill with default data */ exif_entry_initialize (entry, tag); + + /* Ownership of the ExifEntry has now been passed to the IFD. + * One must be very careful in accessing a structure after + * unref'ing it; in this case, we know "entry" won't be freed + * because the reference count was bumped when it was added to + * the IFD. + */ + exif_entry_unref(entry); } return entry; } +/* Create a brand-new tag with a data field of the given length, in the + * given IFD. This is needed when exif_entry_initialize() isn't able to create + * this type of tag itself, or the default data length it creates isn't the + * correct length. + */ +static ExifEntry *create_tag(ExifData *exif, ExifIfd ifd, ExifTag tag, size_t len) +{ + void *buf; + ExifEntry *entry; + + /* Create a memory allocator to manage this ExifEntry */ + ExifMem *mem = exif_mem_new_default(); + assert(mem != NULL); /* catch an out of memory condition */ + + /* Create a new ExifEntry using our allocator */ + entry = exif_entry_new_mem (mem); + assert(entry != NULL); + + /* Allocate memory to use for holding the tag data */ + buf = exif_mem_alloc(mem, len); + assert(buf != NULL); + + /* Fill in the entry */ + entry->data = buf; + entry->size = len; + entry->tag = tag; + entry->components = len; + entry->format = EXIF_FORMAT_UNDEFINED; + + /* Attach the ExifEntry to an IFD */ + exif_content_add_entry (exif->ifd[ifd], entry); + + /* The ExifMem and ExifEntry are now owned elsewhere */ + exif_mem_unref(mem); + exif_entry_unref(entry); + + return entry; +} + int main(int argc, char **argv) { int rc = 1; @@ -145,7 +209,7 @@ int main(int argc, char **argv) /* Set the image options */ exif_data_set_option(exif, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION); exif_data_set_data_type(exif, EXIF_DATA_TYPE_COMPRESSED); - exif_data_set_byte_order(exif, BYTE_ORDER); + exif_data_set_byte_order(exif, FILE_BYTE_ORDER); /* Create the mandatory EXIF fields with default data */ exif_data_fix(exif); @@ -153,22 +217,41 @@ int main(int argc, char **argv) /* All these tags are created with default values by exif_data_fix() */ /* Change the data to the correct values for this image. */ entry = init_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_PIXEL_X_DIMENSION); - exif_set_long(entry->data, BYTE_ORDER, image_jpg_x); + exif_set_long(entry->data, FILE_BYTE_ORDER, image_jpg_x); entry = init_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_PIXEL_Y_DIMENSION); - exif_set_long(entry->data, BYTE_ORDER, image_jpg_y); + exif_set_long(entry->data, FILE_BYTE_ORDER, image_jpg_y); entry = init_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_COLOR_SPACE); - exif_set_short(entry->data, BYTE_ORDER, 1); + exif_set_short(entry->data, FILE_BYTE_ORDER, 1); - /* A good example to give here would be to add a new tag that isn't - * automatically created by exif_data_fix() (such as - * EXIF_TAG_USER_COMMENT) which requires allocating memory in - * entry->data. This isn't so easy to do, unfortunately. + /* Create a EXIF_TAG_USER_COMMENT tag. This one must be handled + * differently because that tag isn't automatically created and + * allocated by exif_data_fix(), nor can it be created using + * exif_entry_initialize() so it must be explicitly allocated here. */ + entry = create_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_USER_COMMENT, + sizeof(ASCII_COMMENT) + sizeof(FILE_COMMENT) - 2); + /* Write the special header needed for a comment tag */ + memcpy(entry->data, ASCII_COMMENT, sizeof(ASCII_COMMENT)-1); + /* Write the actual comment text, without the trailing NUL character */ + memcpy(entry->data+8, FILE_COMMENT, sizeof(FILE_COMMENT)-1); + /* create_tag() happens to set the format and components correctly for + * EXIF_TAG_USER_COMMENT, so there is nothing more to do. */ + + /* Create a EXIF_TAG_SUBJECT_AREA tag */ + entry = create_tag(exif, EXIF_IFD_EXIF, EXIF_TAG_SUBJECT_AREA, + 4 * exif_format_get_size(EXIF_FORMAT_SHORT)); + entry->format = EXIF_FORMAT_SHORT; + entry->components = 4; + exif_set_short(entry->data, FILE_BYTE_ORDER, image_jpg_x / 2); + exif_set_short(entry->data+2, FILE_BYTE_ORDER, image_jpg_y / 2); + exif_set_short(entry->data+4, FILE_BYTE_ORDER, image_jpg_x); + exif_set_short(entry->data+6, FILE_BYTE_ORDER, image_jpg_y); /* Get a pointer to the EXIF data block we just created */ exif_data_save_data(exif, &exif_data, &exif_data_len); + assert(exif_data != NULL); f = fopen(FILE_NAME, "wb"); if (!f) { @@ -181,7 +264,7 @@ int main(int argc, char **argv) fprintf(stderr, "Error writing to file %s\n", FILE_NAME); goto errout; } - /* Write EXIF block length */ + /* Write EXIF block length in big-endian order */ if (fputc((exif_data_len+2) >> 8, f) < 0) { fprintf(stderr, "Error writing to file %s\n", FILE_NAME); goto errout; @@ -195,7 +278,7 @@ int main(int argc, char **argv) fprintf(stderr, "Error writing to file %s\n", FILE_NAME); goto errout; } - /* Write JPEG image data */ + /* Write JPEG image data, skipping the non-EXIF header */ if (fwrite(image_jpg+image_data_offset, image_data_len, 1, f) != 1) { fprintf(stderr, "Error writing to file %s\n", FILE_NAME); goto errout; @@ -208,6 +291,10 @@ errout: fprintf(stderr, "Error writing to file %s\n", FILE_NAME); rc = 1; } + /* The allocator we're using for ExifData is the standard one, so use + * it directly to free this pointer. + */ + free(exif_data); exif_data_unref(exif); return rc; |