diff options
| -rw-r--r-- | Makefile | 8 | ||||
| -rw-r--r-- | README | 5 | ||||
| -rw-r--r-- | generators.c | 3 | ||||
| -rw-r--r-- | jpeg-utils.c | 280 | ||||
| -rw-r--r-- | jpeg-utils.cpp | 387 | ||||
| -rw-r--r-- | jpeg-utils.h | 28 |
6 files changed, 419 insertions, 292 deletions
@@ -13,15 +13,15 @@ OBJECTS=gallery-utils.o jpeg-utils.o xml-parser.o setup.o items.o generators.o c .SUFFIXES: .c .cpp .c.o: - $(CC) $(CFLAGS) `pkg-config libxml-2.0 glib-2.0 libexif --cflags` `Wand-config --cflags` -c $< + $(CC) $(CFLAGS) `pkg-config libxml-2.0 glib-2.0 --cflags` `Wand-config --cflags` -c $< .cpp.o: - $(CC) $(CFLAGS) `pkg-config libxml-2.0 glib-2.0 libexif --cflags` `Wand-config --cppflags` -c $< + $(CPP) $(CFLAGS) `pkg-config libxml-2.0 glib-2.0 exiv2 --cflags` `Wand-config --cppflags` -c $< all cgg: check $(OBJECTS) - $(CC) -o cgg $(OBJECTS) -lm $(CFLAGS) `pkg-config libxml-2.0 glib-2.0 libexif --libs` `Wand-config --ldflags --libs` + $(CC) -o cgg $(OBJECTS) -lm $(CFLAGS) `pkg-config libxml-2.0 glib-2.0 exiv2 --libs` `Wand-config --ldflags --libs` cgg.o: cgg.c -jpeg-utils.o: jpeg-utils.c jpeg-utils.h +jpeg-utils.o: jpeg-utils.cpp jpeg-utils.h gallery-utils.o: gallery-utils.c gallery-utils.h setup.o: setup.c setup.h xml-parser.o: xml-parser.c xml-parser.h @@ -18,14 +18,13 @@ Feature highlights: * fast, easy to cache/mirror * XML-based description files * modern design, valid XHTML 1.0 and CSS 2 - * EXIF support + * EXIF & IPTC support * console application, allowing easy scripting (e.g. auto-refresh after new images are uploaded via FTP) Planned features: * prefetch of next image (JavaScript) * strip unnecessary blocks from images - EXIF, thumbnails - * port to exiv2 library to get rid of that weird shutter times, IPTC support * support adding comments and copyright notes to images * switchable flat album view * groups in the album - e.g. separate years, decades... @@ -57,7 +56,7 @@ BUILDING First make sure you have meet the following requirements: libxml-2.0 (tested with 2.6.32) glib-2.0 (2.12.0 recommented, tested with 2.16.3) - libexif (tested with 0.6.16) + exiv2 (tested with 0.17) ImageMagick (tested with 6.4.2.0) To compile cgg, type 'make' diff --git a/generators.c b/generators.c index 3639309..a478389 100644 --- a/generators.c +++ b/generators.c @@ -486,8 +486,7 @@ write_html_image (TGallerySetup *setup, /* Get EXIF data from the original image */ - exif = malloc (sizeof (TExifData)); - if (get_exif (original_img, exif)) + if (get_exif (original_img, &exif)) fprintf (stderr, "write_html_image: error getting exif data from file \"%s\"\n", orig_dst); /* Retrieve image sizes of preview and original image */ diff --git a/jpeg-utils.c b/jpeg-utils.c deleted file mode 100644 index dc1c880..0000000 --- a/jpeg-utils.c +++ /dev/null @@ -1,280 +0,0 @@ -/* Cataract - Static web photo gallery generator - * Copyright (C) 2008 Tomas Bzatek <tbzatek@users.sourceforge.net> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> - -#include <libexif/exif-data.h> -#include <libexif/exif-content.h> -#include <libexif/exif-entry.h> - -#include <wand/magick-wand.h> - -#include "jpeg-utils.h" - - - - -/* - * get_exif: retrieve EXIF informations from a JPEG image - */ -int -get_exif (const char *filename, TExifData *data) -{ - ExifData *edata; - ExifEntry *entry; - ExifContent *content; - int i, j; - - if (data == NULL) - data = malloc (sizeof (TExifData)); - memset (data, 0, sizeof (TExifData)); - edata = exif_data_new_from_file (filename); - if (edata == NULL) - return -1; - - for (i = 0; i < EXIF_IFD_COUNT; i++) { - content = edata->ifd[i]; - if ((content == NULL) || (content->count == 0)) - continue; - - for (j = 0; j < content->count; j++) { - entry = content->entries[j]; - - if (! content->entries[j]) - continue; - - #define VALUE_LEN 1024 - char value[VALUE_LEN + 1]; - - switch (entry->tag) - { - case EXIF_TAG_DATE_TIME: - data->datetime = strdup (exif_entry_get_value (entry, value, VALUE_LEN)); - break; - - case EXIF_TAG_DATE_TIME_ORIGINAL: - case EXIF_TAG_DATE_TIME_DIGITIZED: - if (data->datetime == NULL) - data->datetime = strdup (exif_entry_get_value (entry, value, VALUE_LEN)); - break; - - case EXIF_TAG_MODEL: - if (data->camera_model == NULL) - data->camera_model = strdup (exif_entry_get_value (entry, value, VALUE_LEN)); - break; - - case EXIF_TAG_MAKE: - if (data->camera_model == NULL) - data->camera_model = strdup (exif_entry_get_value (entry, value, VALUE_LEN)); - break; - - case EXIF_TAG_ISO_SPEED_RATINGS: - data->iso = strdup (exif_entry_get_value (entry, value, VALUE_LEN)); - break; - - case EXIF_TAG_FOCAL_LENGTH: - data->focal_length = strdup (exif_entry_get_value (entry, value, VALUE_LEN)); - break; - - case EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM: - data->focal_length_35mm = strdup (exif_entry_get_value (entry, value, VALUE_LEN)); - break; - - case EXIF_TAG_FNUMBER: - data->aperture = strdup (exif_entry_get_value (entry, value, VALUE_LEN)); - break; - - case EXIF_TAG_APERTURE_VALUE: - if (data->aperture == NULL) - data->aperture = strdup (exif_entry_get_value (entry, value, VALUE_LEN)); - break; - - case EXIF_TAG_EXPOSURE_TIME: - data->exposure = strdup (exif_entry_get_value (entry, value, VALUE_LEN)); - break; - - case EXIF_TAG_FLASH: - data->flash = strdup (exif_entry_get_value (entry, value, VALUE_LEN)); - break; - - case EXIF_TAG_PIXEL_X_DIMENSION: - data->width = atol (exif_entry_get_value (entry, value, VALUE_LEN)); - break; - - case EXIF_TAG_PIXEL_Y_DIMENSION: - data->height = atol (exif_entry_get_value (entry, value, VALUE_LEN)); - break; - - default: - break; - } - } - } - exif_data_free (edata); - - #ifdef __DEBUG_ALL__ - printf("EXIF_TAG_DATE_TIME = %s\n", data->datetime); - printf("EXIF_TAG_MODEL = %s\n", data->camera_model); - printf("EXIF_TAG_ISO_SPEED_RATINGS = %s\n", data->iso); - printf("EXIF_TAG_FOCAL_LENGTH = %s\n", data->focal_length); - printf("EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM = %s\n", data->focal_length_35mm); - printf("EXIF_TAG_FNUMBER = %s\n", data->aperture); - printf("EXIF_TAG_EXPOSURE_TIME = %s\n", data->exposure); - printf("EXIF_TAG_FLASH = %s\n", data->flash); - printf("EXIF_TAG_PIXEL_X_DIMENSION = %lu\n", data->width); - printf("EXIF_TAG_PIXEL_Y_DIMENSION = %lu\n", data->height); - #endif - - return 0; -} - -/* - * free_exif_struct: free allocated structure - */ -void -free_exif_data (TExifData *data) -{ - if (data) { - if (data->aperture) - free (data->aperture); - if (data->camera_model) - free (data->camera_model); - if (data->datetime) - free (data->datetime); - if (data->exposure) - free (data->exposure); - if (data->flash) - free (data->flash); - if (data->focal_length) - free (data->focal_length); - if (data->focal_length_35mm) - free (data->focal_length_35mm); - if (data->iso) - free (data->iso); - free (data); - data = NULL; - } -} - - -/* - * resize_image: resize image pointed by src and save result to dst - */ -gboolean -resize_image (const char *src, const char *dst, - int size_x, int size_y, - int quality) -{ - #define ThrowWandException(wand) \ - { \ - char *description; \ - ExceptionType severity; \ - \ - description = MagickGetException (wand, &severity); \ - (void) fprintf (stderr, "Error converting image: %s %s %ld %s\n", GetMagickModule(), description); \ - description = (char*) MagickRelinquishMemory (description); \ - return FALSE; \ - } - - MagickBooleanType status; - MagickWand *magick_wand; - - /* Read an image. */ - MagickWandGenesis(); - magick_wand = NewMagickWand(); - status = MagickReadImage (magick_wand, src); - if (status == MagickFalse) - ThrowWandException (magick_wand); - MagickResizeImage (magick_wand, size_x, size_y, LanczosFilter, 1.0); - MagickSetImageCompressionQuality (magick_wand, quality); - - /* Write the image and destroy it. */ - status = MagickWriteImage (magick_wand, dst); - if (status == MagickFalse) - ThrowWandException (magick_wand); - magick_wand = DestroyMagickWand (magick_wand); - MagickWandTerminus(); - - return TRUE; -} - - -/* - * get_image_sizes: retrieve image dimensions - */ -void -get_image_sizes (const char *img, - unsigned long *width, unsigned long *height) -{ - #define xThrowWandException(wand) \ - { \ - char *description; \ - ExceptionType severity; \ - \ - description = MagickGetException (wand, &severity); \ - (void) fprintf (stderr, "Error reading image info: %s %s %ld %s\n", GetMagickModule(), description); \ - description = (char*) MagickRelinquishMemory(description); \ - return; \ - } - - MagickBooleanType status; - MagickWand *magick_wand; - - *width = -1; - *height = -1; - - /* Read an image. */ - MagickWandGenesis(); - magick_wand = NewMagickWand(); - status = MagickPingImage (magick_wand, img); - if (status == MagickFalse) - xThrowWandException (magick_wand); - *width = MagickGetImageWidth (magick_wand); - *height = MagickGetImageHeight (magick_wand); - - magick_wand = DestroyMagickWand (magick_wand); - MagickWandTerminus(); -} - - -/* - * calculate_sizes: calculate maximal image sizes within specified limits keeping aspect ratio - */ -void -calculate_sizes (const unsigned long max_width, const unsigned long max_height, - unsigned long *width, unsigned long *height) -{ - if ((max_width > *width) && (max_height > *height)) - return; - - double max_ratio = (double) max_width / (double) max_height; - double real_ratio = (double) *width / (double) *height; - - if ((*width > *height) && (max_ratio <= real_ratio)) - { - *height = max_width / real_ratio; - *width = max_width; - } - else - { - *width = max_height * real_ratio; - *height = max_height; - } -} - diff --git a/jpeg-utils.cpp b/jpeg-utils.cpp new file mode 100644 index 0000000..973b448 --- /dev/null +++ b/jpeg-utils.cpp @@ -0,0 +1,387 @@ +/* Cataract - Static web photo gallery generator + * Copyright (C) 2008 Tomas Bzatek <tbzatek@users.sourceforge.net> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <exiv2/image.hpp> +#include <exiv2/exif.hpp> + +#include <wand/magick-wand.h> + +#include "jpeg-utils.h" + + + +/* + * get_exif: retrieve EXIF informations from a JPEG image + */ +int +get_exif (const char *filename, TExifData **exif_data) +{ + TExifData *data; + + data = (TExifData*) malloc (sizeof (TExifData)); + memset (data, 0, sizeof (TExifData)); + *exif_data = data; + + try + { + Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(filename); + g_assert (image.get() != 0); + image->readMetadata(); + + Exiv2::ExifData &exifData = image->exifData(); + if (! exifData.empty()) { + /* EXIF::Aperture */ + try { + float val = exifData["Exif.Photo.FNumber"].toFloat(); + if (val >= 0) + data->aperture = g_strdup_printf ("f/%.1f", val); + } catch (...) { } + + /* EXIF::Camera model */ + try { + const char *val = exifData["Exif.Image.Model"].toString().c_str(); + if (val && strlen(val) > 0) + data->camera_model = strdup (val); + } catch (...) { } + + /* EXIF::DateTime */ + try { + const char *val = NULL; + try { + val = exifData["Exif.Photo.DateTimeOriginal"].toString().c_str(); + } catch (...) { } + if ((! val) || (strlen(val) == 0)) + try { + val = exifData["Exif.Image.DateTime"].toString().c_str(); + } catch (...) { } + + if (val && strlen(val) > 0) { + static struct tm tt; + static char conv[1024]; + + if (sscanf (val, "%d:%d:%d %d:%d:%d", &tt.tm_year, &tt.tm_mon, &tt.tm_mday, &tt.tm_hour, &tt.tm_min, &tt.tm_sec) == 6) + { + tt.tm_year -= 1900; + tt.tm_mon--; + if (strftime (&conv[0], sizeof(conv), "%c", &tt)) + data->datetime = strdup (&conv[0]); + } + } + } catch (...) { } + + /* EXIF::Shutter speed */ + try { + float val = exifData["Exif.Photo.ExposureTime"].toFloat(); + if (val > 0) { + if (val < 0.5) + data->exposure = g_strdup_printf ("1/%.0f s", 1/val); + else + data->exposure = g_strdup_printf ("%.1f s", val); + } + } catch (...) { } + + /* EXIF::Flash */ + try { + long int val = exifData["Exif.Photo.Flash"].toLong(); + if ((val > 0) && ((val & 1) == 1)) + data->flash = strdup ((char *) "Flash fired"); + else + data->flash = strdup ((char *) "--"); + } catch (...) { } + + /* EXIF::Focal length */ + try { + float val = exifData["Exif.Photo.FocalLength"].toFloat(); + if (val >= 0) + data->focal_length = g_strdup_printf ("%.0f mm", val); + } catch (...) { } + + /* EXIF::ISO */ + try { + long int val = exifData["Exif.Photo.ISOSpeedRatings"].toLong(); + if (val > 0) + data->iso = g_strdup_printf ("%ld", val); + } catch (...) { } + + /* EXIF::Software */ + try { + data->exif_software = strdup (exifData["Exif.Image.Software"].toString().c_str()); + } catch (...) { } + + /* EXIF::Image description */ + try { + data->exif_imgdesc = strdup (exifData["Exif.Image.ImageDescription"].toString().c_str()); + } catch (...) { } + + /* EXIF::Artist */ + try { + data->exif_artist = strdup (exifData["Exif.Image.Artist"].toString().c_str()); + } catch (...) { } + + /* EXIF::Copyright */ + try { + data->exif_copyright = strdup (exifData["Exif.Image.Copyright"].toString().c_str()); + } catch (...) { } + + /* EXIF::User comment */ + try { + data->exif_usercomment = strdup (exifData["Exif.Photo.UserComment"].toString().c_str()); + } catch (...) { } + } + + Exiv2::IptcData &iptcData = image->iptcData(); + if (! iptcData.empty()) { + /* IPTC::Object name */ + try { + data->iptc_objectname = strdup (iptcData["Iptc.Application2.ObjectName"].toString().c_str()); + } catch (...) { } + + /* IPTC::Copyright */ + try { + data->iptc_copyright = strdup (iptcData["Iptc.Application2.Copyright"].toString().c_str()); + } catch (...) { } + + /* IPTC::Credit */ + try { + data->iptc_credit = strdup (iptcData["Iptc.Application2.Credit"].toString().c_str()); + } catch (...) { } + + /* IPTC::Caption */ + try { + data->iptc_caption = strdup (iptcData["Iptc.Application2.Caption"].toString().c_str()); + } catch (...) { } + + /* IPTC::Author */ + try { + data->iptc_author = strdup (iptcData["Iptc.Application2.Byline"].toString().c_str()); + } catch (...) { } + } + + } + catch (Exiv2::AnyError& e) + { + fprintf (stderr, "get_exif: Caught Exiv2 exception: '%s'\n", e.what()); + return -1; + } + + /* Read the JPEG comment */ + MagickBooleanType status; + MagickWand *magick_wand; + char *comment; + + MagickWandGenesis(); + magick_wand = NewMagickWand(); + status = MagickPingImage (magick_wand, filename); + if (status == MagickTrue) { + comment = MagickGetImageProperty(magick_wand, "comment"); + if (comment) + data->jpeg_comment = strdup (comment); + MagickRelinquishMemory (comment); + } + magick_wand = DestroyMagickWand (magick_wand); + MagickWandTerminus(); + + +#ifdef __DEBUG_ALL__ + printf("EXIF_TAG_DATE_TIME = '%s'\n", data->datetime); + printf("EXIF_TAG_MODEL = '%s'\n", data->camera_model); + printf("EXIF_TAG_ISO_SPEED_RATINGS = '%s'\n", data->iso); + printf("EXIF_TAG_FOCAL_LENGTH = '%s'\n", data->focal_length); + printf("EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM = '%s'\n", data->focal_length_35mm); + printf("EXIF_TAG_FNUMBER = '%s'\n", data->aperture); + printf("EXIF_TAG_EXPOSURE_TIME = '%s'\n", data->exposure); + printf("EXIF_TAG_FLASH = '%s'\n", data->flash); + printf("Exif.Image.Software = '%s'\n", data->exif_software); + printf("Exif.Image.ImageDescription = '%s'\n", data->exif_imgdesc); + printf("Exif.Image.Artist = '%s'\n", data->exif_artist); + printf("Exif.Image.Copyright = '%s'\n", data->exif_copyright); + printf("Exif.Photo.UserComment = '%s'\n", data->exif_usercomment); + printf("Iptc.Application2.ObjectName = '%s'\n", data->iptc_objectname); + printf("Iptc.Application2.Copyright = '%s'\n", data->iptc_copyright); + printf("Iptc.Application2.Credit = '%s'\n", data->iptc_credit); + printf("Iptc.Application2.Caption = '%s'\n", data->iptc_caption); + printf("Iptc.Application2.Byline = '%s'\n", data->iptc_author); + printf("JPEG comment = '%s'\n", data->jpeg_comment); +#endif + + return 0; +} + +/* + * free_exif_struct: free allocated structure + */ +void +free_exif_data (TExifData *data) +{ + if (data) { + if (data->aperture) + free (data->aperture); + if (data->camera_model) + free (data->camera_model); + if (data->datetime) + free (data->datetime); + if (data->exposure) + free (data->exposure); + if (data->flash) + free (data->flash); + if (data->focal_length) + free (data->focal_length); + if (data->focal_length_35mm) + free (data->focal_length_35mm); + if (data->iso) + free (data->iso); + + if (data->exif_software) + free (data->exif_software); + if (data->exif_imgdesc) + free (data->exif_imgdesc); + if (data->exif_artist) + free (data->exif_artist); + if (data->exif_copyright) + free (data->exif_copyright); + if (data->exif_usercomment) + free (data->exif_usercomment); + + if (data->iptc_objectname) + free (data->iptc_objectname); + if (data->iptc_copyright) + free (data->iptc_copyright); + if (data->iptc_credit) + free (data->iptc_credit); + if (data->iptc_caption) + free (data->iptc_caption); + if (data->iptc_author) + free (data->iptc_author); + + if (data->jpeg_comment) + free (data->jpeg_comment); + + free (data); + data = NULL; + } +} + + +/* + * resize_image: resize image pointed by src and save result to dst + */ +gboolean +resize_image (const char *src, const char *dst, + int size_x, int size_y, + int quality) +{ + #define ThrowWandException(wand) \ + { \ + char *description; \ + ExceptionType severity; \ + \ + description = MagickGetException (wand, &severity); \ + (void) fprintf (stderr, "Error converting image: %s %s %ld %s\n", GetMagickModule(), description); \ + description = (char*) MagickRelinquishMemory (description); \ + return FALSE; \ + } + + MagickBooleanType status; + MagickWand *magick_wand; + + /* Read an image. */ + MagickWandGenesis(); + magick_wand = NewMagickWand(); + status = MagickReadImage (magick_wand, src); + if (status == MagickFalse) + ThrowWandException (magick_wand); + MagickResizeImage (magick_wand, size_x, size_y, LanczosFilter, 1.0); + MagickSetImageCompressionQuality (magick_wand, quality); + + /* Write the image and destroy it. */ + status = MagickWriteImage (magick_wand, dst); + if (status == MagickFalse) + ThrowWandException (magick_wand); + magick_wand = DestroyMagickWand (magick_wand); + MagickWandTerminus(); + + return TRUE; +} + + +/* + * get_image_sizes: retrieve image dimensions + */ +void +get_image_sizes (const char *img, + unsigned long *width, unsigned long *height) +{ + #define xThrowWandException(wand) \ + { \ + char *description; \ + ExceptionType severity; \ + \ + description = MagickGetException (wand, &severity); \ + (void) fprintf (stderr, "Error reading image info: %s %s %ld %s\n", GetMagickModule(), description); \ + description = (char*) MagickRelinquishMemory(description); \ + return; \ + } + + MagickBooleanType status; + MagickWand *magick_wand; + + *width = -1; + *height = -1; + + /* Read an image. */ + MagickWandGenesis(); + magick_wand = NewMagickWand(); + status = MagickPingImage (magick_wand, img); + if (status == MagickFalse) + xThrowWandException (magick_wand); + *width = MagickGetImageWidth (magick_wand); + *height = MagickGetImageHeight (magick_wand); + + magick_wand = DestroyMagickWand (magick_wand); + MagickWandTerminus(); +} + + +/* + * calculate_sizes: calculate maximal image sizes within specified limits keeping aspect ratio + */ +void +calculate_sizes (const unsigned long max_width, const unsigned long max_height, + unsigned long *width, unsigned long *height) +{ + if ((max_width > *width) && (max_height > *height)) + return; + + double max_ratio = (double) max_width / (double) max_height; + double real_ratio = (double) *width / (double) *height; + + if ((*width > *height) && (max_ratio <= real_ratio)) + { + *height = max_width / real_ratio; + *width = max_width; + } + else + { + *width = max_height * real_ratio; + *height = max_height; + } +} + diff --git a/jpeg-utils.h b/jpeg-utils.h index 56bb51d..4c47d3c 100644 --- a/jpeg-utils.h +++ b/jpeg-utils.h @@ -15,9 +15,15 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef __cplusplus + extern "C" { +#endif + #include <glib.h> +/* TODO: we want to have numerical values here at some point in the future */ typedef struct { char *datetime; char *camera_model; @@ -27,15 +33,27 @@ typedef struct { char *aperture; char *exposure; char *flash; - unsigned long width; - unsigned long height; + + char *exif_software; + char *exif_imgdesc; + char *exif_artist; + char *exif_copyright; + char *exif_usercomment; + + char *iptc_objectname; + char *iptc_copyright; + char *iptc_credit; + char *iptc_caption; + char *iptc_author; + + char *jpeg_comment; } TExifData; /* * get_exif: retrieve EXIF info from a JPEG image */ -int get_exif (const char *filename, TExifData *data); +int get_exif (const char *filename, TExifData **exif_data); /* * free_exif_struct: free allocated structure @@ -63,3 +81,7 @@ void get_image_sizes (const char *img, void calculate_sizes (const unsigned long max_width, const unsigned long max_height, unsigned long *width, unsigned long *height); + +#ifdef __cplusplus + } +#endif
\ No newline at end of file |
