From 1e355114311d7bf44b96b11b745857a2b68e8a06 Mon Sep 17 00:00:00 2001 From: Tomas Bzatek Date: Sat, 2 Aug 2008 13:50:16 +0200 Subject: Port to exiv2 library Now we are able to read EXIF, IPTC and JPEG metadata such as caption, copyright, author etc. though we don't display them anywhere yet. Fixes weird shutter times. --- jpeg-utils.cpp | 387 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 387 insertions(+) create mode 100644 jpeg-utils.cpp (limited to 'jpeg-utils.cpp') 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 + * + * 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 +#include +#include + +#include +#include + +#include + +#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; + } +} + -- cgit v1.2.3