summaryrefslogtreecommitdiff
path: root/src/jpeg-utils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/jpeg-utils.cpp')
-rw-r--r--src/jpeg-utils.cpp429
1 files changed, 429 insertions, 0 deletions
diff --git a/src/jpeg-utils.cpp b/src/jpeg-utils.cpp
new file mode 100644
index 0000000..501f7ea
--- /dev/null
+++ b/src/jpeg-utils.cpp
@@ -0,0 +1,429 @@
+/* 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 (...) { }
+ }
+
+ /* JPEG::Comment */
+ try {
+ data->jpeg_comment = strdup (image->comment().c_str());
+ } catch (...) { }
+ }
+ catch (Exiv2::AnyError& e)
+ {
+ fprintf (stderr, "get_exif: Caught Exiv2 exception: '%s'\n", e.what());
+ return -1;
+ }
+
+#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,
+ gboolean thumbnail)
+{
+ #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);
+ if (thumbnail)
+ MagickThumbnailImage (magick_wand, size_x, size_y);
+ else
+ 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 = (unsigned long) (max_width / real_ratio);
+ *width = max_width;
+ }
+ else
+ {
+ *width = (unsigned long) (max_height * real_ratio);
+ *height = max_height;
+ }
+}
+
+
+/*
+ * modify_exif: - strip thumbnail stored in EXIF table
+ * - add copyright to Exif::Image::Copyright and Iptc::Application2::Copyright
+ */
+void
+modify_exif (const char *filename, gboolean strip_thumbnail, const char *add_copyright)
+{
+ bool was_modified = false;
+
+ if ((! strip_thumbnail) && (add_copyright == NULL))
+ return;
+
+ try
+ {
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(filename);
+ g_assert (image.get() != 0);
+
+ image->readMetadata();
+ Exiv2::ExifData &exifData = image->exifData();
+ if (add_copyright) {
+ exifData["Exif.Image.Copyright"] = add_copyright;
+ image->iptcData()["Iptc.Application2.Copyright"] = add_copyright;
+ was_modified = true;
+ }
+
+ if (strip_thumbnail && (! exifData.empty())) {
+#ifdef HAVE_EXIFTHUMB
+ Exiv2::ExifThumb exifThumb(image->exifData());
+ std::string thumbExt = exifThumb.extension();
+#else
+ std::string thumbExt = exifData.thumbnailExtension();
+#endif
+
+ if (! thumbExt.empty()) {
+#ifdef HAVE_EXIFTHUMB
+ exifThumb.erase();
+#else
+ exifData.eraseThumbnail();
+#endif
+ was_modified = true;
+ }
+ }
+
+ if (was_modified)
+ image->writeMetadata();
+ }
+ catch (Exiv2::AnyError& e)
+ {
+ fprintf (stderr, "modify_exif: Caught Exiv2 exception: '%s'\n", e.what());
+ }
+}