summaryrefslogtreecommitdiff
path: root/jpeg-utils.cpp
diff options
context:
space:
mode:
authorTomas Bzatek <tbzatek@users.sourceforge.net>2008-08-02 13:50:16 +0200
committerTomas Bzatek <tbzatek@users.sourceforge.net>2008-08-02 13:50:16 +0200
commit1e355114311d7bf44b96b11b745857a2b68e8a06 (patch)
treee9e63419c60b1668a22bceda4447794469db21ba /jpeg-utils.cpp
parent64c8713ab4a64eaf53a764530837bd3ae47a89d2 (diff)
downloadcataract-1e355114311d7bf44b96b11b745857a2b68e8a06.tar.xz
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.
Diffstat (limited to 'jpeg-utils.cpp')
-rw-r--r--jpeg-utils.cpp387
1 files changed, 387 insertions, 0 deletions
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;
+ }
+}
+