/* 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, 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; } } /* * strip_thumbnail: strip thumbnail stored in EXIF table */ void strip_thumbnail (const char *filename) { try { Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(filename); g_assert (image.get() != 0); image->readMetadata(); Exiv2::ExifData &exifData = image->exifData(); if (! exifData.empty()) { exifData.eraseThumbnail(); image->writeMetadata(); } } catch (Exiv2::AnyError& e) { fprintf (stderr, "strip_thumbnail: Caught Exiv2 exception: '%s'\n", e.what()); } }