# HG changeset patch # User nadvornik # Date 1224354177 0 # Node ID aeae25d5d50d4dcdb01a701fa3260218951cbede # Parent e67636316f4ccb802ae45bbb87e281e01fc24636 infrastructure for preprocessing of metadata diff -r e67636316f4c -r aeae25d5d50d src/bar_exif.c --- a/src/bar_exif.c Sat Oct 18 09:07:52 2008 +0000 +++ b/src/bar_exif.c Sat Oct 18 18:22:57 2008 +0000 @@ -180,16 +180,27 @@ static void bar_exif_update(ExifBar *eb) { + ExifData *exif_processed; ExifData *exif; gint i; - exif = exif_read_fd(eb->fd); + exif_processed = exif_read_fd(eb->fd); - if (!exif) + if (!exif_processed) { bar_exif_sensitive(eb, FALSE); return; } + + if (eb->advanced_scrolled) + { + /* show the original values from the file */ + exif = exif_get_original(exif_processed); + } + else + { + exif = exif_processed; + } bar_exif_sensitive(eb, TRUE); @@ -334,7 +345,7 @@ } } - exif_free_fd(eb->fd, exif); + exif_free_fd(eb->fd, exif_processed); } static void bar_exif_clear(ExifBar *eb) diff -r e67636316f4c -r aeae25d5d50d src/exif.c --- a/src/exif.c Sat Oct 18 09:07:52 2008 +0000 +++ b/src/exif.c Sat Oct 18 18:22:57 2008 +0000 @@ -1185,6 +1185,11 @@ return 0; } +ExifData *exif_get_original(ExifData *processed) +{ + return processed; +} + void exif_free(ExifData *exif) { GList *work; diff -r e67636316f4c -r aeae25d5d50d src/exif.h --- a/src/exif.h Sat Oct 18 09:07:52 2008 +0000 +++ b/src/exif.h Sat Oct 18 18:22:57 2008 +0000 @@ -110,6 +110,10 @@ ExifData *exif_read_fd(FileData *fd); void exif_free_fd(FileData *fd, ExifData *exif); +/* exif_read returns processed data (merged from image and sidecar, etc.) + this function gives access to the original data from the image. + original data are part of the processed data and should not be freed separately */ +ExifData *exif_get_original(ExifData *processed); gint exif_write(ExifData *exif); void exif_free(ExifData *exif); diff -r e67636316f4c -r aeae25d5d50d src/exiv2.cc --- a/src/exiv2.cc Sat Oct 18 09:07:52 2008 +0000 +++ b/src/exiv2.cc Sat Oct 18 18:22:57 2008 +0000 @@ -61,48 +61,77 @@ struct _ExifData { - Exiv2::Image::AutoPtr image; - Exiv2::Image::AutoPtr sidecar; Exiv2::ExifData::const_iterator exifIter; /* for exif_get_next_item */ Exiv2::IptcData::const_iterator iptcIter; /* for exif_get_next_item */ #if EXIV2_TEST_VERSION(0,16,0) Exiv2::XmpData::const_iterator xmpIter; /* for exif_get_next_item */ #endif - bool have_sidecar; - /* the icc profile in jpeg is not technically exif - store it here */ - unsigned char *cp_data; - guint cp_length; - - _ExifData(gchar *path, gchar *sidecar_path) + virtual ~_ExifData() + { + } + + virtual void writeMetadata() { - have_sidecar = false; - cp_data = NULL; - cp_length = 0; - gchar *pathl = path_from_utf8(path); - image = Exiv2::ImageFactory::open(pathl); - g_free(pathl); -// g_assert (image.get() != 0); - image->readMetadata(); + g_critical("Unsupported method of writing metadata"); + } + + virtual ExifData *original() + { + return NULL; + } + + virtual Exiv2::Image *image() = 0; + + virtual Exiv2::ExifData &exifData() = 0; + + virtual Exiv2::IptcData &iptcData() = 0; #if EXIV2_TEST_VERSION(0,16,0) - DEBUG_2("xmp count %li", image->xmpData().count()); - if (sidecar_path && image->xmpData().empty()) + virtual Exiv2::XmpData &xmpData() = 0; +#endif + + virtual void add_jpeg_color_profile(unsigned char *cp_data, guint cp_length) = 0; + + virtual guchar *get_jpeg_color_profile(guint *data_len) = 0; +}; + +// This allows read-only access to the original metadata +struct _ExifDataOriginal : public _ExifData +{ +protected: + Exiv2::Image::AutoPtr image_; + + /* the icc profile in jpeg is not technically exif - store it here */ + unsigned char *cp_data_; + guint cp_length_; + +public: + + _ExifDataOriginal(gchar *path) + { + cp_data_ = NULL; + cp_length_ = 0; + gchar *pathl = path_from_utf8(path); + image_ = Exiv2::ImageFactory::open(pathl); + g_free(pathl); +// g_assert (image.get() != 0); + image_->readMetadata(); + +#if EXIV2_TEST_VERSION(0,16,0) + if (image_->mimeType() == "application/rdf+xml") { - gchar *sidecar_pathl = path_from_utf8(sidecar_path); - sidecar = Exiv2::ImageFactory::open(sidecar_pathl); - g_free(sidecar_pathl); - sidecar->readMetadata(); - have_sidecar = sidecar->good(); - DEBUG_2("sidecar xmp count %li", sidecar->xmpData().count()); + //Exiv2 sidecar converts xmp to exif and iptc, we don't want it. + image_->clearExifData(); + image_->clearIptcData(); } +#endif -#endif #if EXIV2_TEST_VERSION(0,14,0) - if (image->mimeType() == std::string("image/jpeg")) + if (image_->mimeType() == "image/jpeg") { /* try to get jpeg color profile */ - Exiv2::BasicIo &io = image->io(); + Exiv2::BasicIo &io = image_->io(); gint open = io.isopen(); if (!open) io.open(); unsigned char *mapped = (unsigned char*)io.mmap(); @@ -113,43 +142,156 @@ #endif } - ~_ExifData() + virtual ~_ExifDataOriginal() { - if (cp_data) g_free(cp_data); + if (cp_data_) g_free(cp_data_); } - void writeMetadata() + virtual Exiv2::Image *image() { - if (have_sidecar) sidecar->writeMetadata(); - image->writeMetadata(); + return image_.get(); } - Exiv2::ExifData &exifData () + virtual Exiv2::ExifData &exifData () { - return image->exifData(); + return image_->exifData(); } - Exiv2::IptcData &iptcData () + virtual Exiv2::IptcData &iptcData () { - return image->iptcData(); + return image_->iptcData(); } #if EXIV2_TEST_VERSION(0,16,0) - Exiv2::XmpData &xmpData () + virtual Exiv2::XmpData &xmpData () { - return have_sidecar ? sidecar->xmpData() : image->xmpData(); + return image_->xmpData(); } #endif + virtual void add_jpeg_color_profile(unsigned char *cp_data, guint cp_length) + { + if (cp_data_) g_free(cp_data_); + cp_data_ = cp_data; + cp_length_ = cp_length; + } + + virtual guchar *get_jpeg_color_profile(guint *data_len) + { + if (cp_data_) + { + if (data_len) *data_len = cp_length_; + return (unsigned char *) g_memdup(cp_data_, cp_length_); + } + return NULL; + } }; +// This allows read-write access to the metadata +struct _ExifDataProcessed : public _ExifData +{ +protected: + _ExifDataOriginal *imageData_; + _ExifDataOriginal *sidecarData_; + + Exiv2::ExifData exifData_; + Exiv2::IptcData iptcData_; +#if EXIV2_TEST_VERSION(0,16,0) + Exiv2::XmpData xmpData_; +#endif + +public: + _ExifDataProcessed(gchar *path, gchar *sidecar_path) + { + imageData_ = new _ExifDataOriginal(path); + sidecarData_ = NULL; +#if EXIV2_TEST_VERSION(0,16,0) + xmpData_ = imageData_->xmpData(); + DEBUG_2("xmp count %li", xmpData_.count()); + if (sidecar_path && xmpData_.empty()) + { + sidecarData_ = new _ExifDataOriginal(sidecar_path); + xmpData_ = sidecarData_->xmpData(); + } +#endif + exifData_ = imageData_->exifData(); + iptcData_ = imageData_->iptcData(); + } + + virtual ~_ExifDataProcessed() + { + if (imageData_) delete imageData_; + if (sidecarData_) delete sidecarData_; + } + + virtual ExifData *original() + { + return imageData_; + } + + virtual void writeMetadata() + { + + if (sidecarData_) + { + sidecarData_->image()->setXmpData(xmpData_); + //Exiv2 sidecar converts xmp to exif and iptc, we don't want it. + sidecarData_->image()->clearExifData(); + sidecarData_->image()->clearIptcData(); + sidecarData_->image()->writeMetadata(); + } + else + { + imageData_->image()->setExifData(exifData_); + imageData_->image()->setIptcData(iptcData_); + imageData_->image()->setXmpData(xmpData_); + imageData_->image()->writeMetadata(); + } + } + + virtual Exiv2::Image *image() + { + return imageData_->image(); + } + + virtual Exiv2::ExifData &exifData () + { + return exifData_; + } + + virtual Exiv2::IptcData &iptcData () + { + return iptcData_; + } + +#if EXIV2_TEST_VERSION(0,16,0) + virtual Exiv2::XmpData &xmpData () + { + return xmpData_; + } +#endif + + virtual void add_jpeg_color_profile(unsigned char *cp_data, guint cp_length) + { + imageData_->add_jpeg_color_profile(cp_data, cp_length); + } + + virtual guchar *get_jpeg_color_profile(guint *data_len) + { + return imageData_->get_jpeg_color_profile(data_len); + } +}; + + + + extern "C" { ExifData *exif_read(gchar *path, gchar *sidecar_path) { DEBUG_1("exif read %s, sidecar: %s", path, sidecar_path ? sidecar_path : "-"); try { - return new ExifData(path, sidecar_path); + return new _ExifDataProcessed(path, sidecar_path); } catch (Exiv2::AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; @@ -174,10 +316,16 @@ void exif_free(ExifData *exif) { - + g_assert(dynamic_cast<_ExifDataProcessed *>(exif)); // this should not be called on ExifDataOriginal delete exif; } +ExifData *exif_get_original(ExifData *exif) +{ + return exif->original(); +} + + ExifItem *exif_get_item(ExifData *exif, const gchar *key) { try { @@ -588,22 +736,18 @@ void exif_add_jpeg_color_profile(ExifData *exif, unsigned char *cp_data, guint cp_length) { - if (exif->cp_data) g_free(exif->cp_data); - exif->cp_data = cp_data; - exif->cp_length =cp_length; + exif->add_jpeg_color_profile(cp_data, cp_length); } guchar *exif_get_color_profile(ExifData *exif, guint *data_len) { - if (exif->cp_data) - { - if (data_len) *data_len = exif->cp_length; - return (unsigned char *) g_memdup(exif->cp_data, exif->cp_length); - } + guchar *ret = exif->get_jpeg_color_profile(data_len); + if (ret) return ret; + ExifItem *prof_item = exif_get_item(exif, "Exif.Image.InterColorProfile"); if (prof_item && exif_item_get_format_id(prof_item) == EXIF_FORMAT_UNDEFINED) - return (unsigned char *) exif_item_get_data(prof_item, data_len); - return NULL; + ret = (guchar *)exif_item_get_data(prof_item, data_len); + return ret; } #if EXIV2_TEST_VERSION(0,17,90) @@ -612,7 +756,7 @@ { if (!exif) return NULL; - const char* path = exif->image->io().path().c_str(); + const char* path = exif->image()->io().path().c_str(); /* given image pathname, first do simple (and fast) file extension test */ gboolean is_raw = filter_file_class(path, FORMAT_CLASS_RAWIMAGE); @@ -620,7 +764,7 @@ try { - Exiv2::PreviewManager pm(*exif->image); + Exiv2::PreviewManager pm(*exif->image()); Exiv2::PreviewPropertiesList list = pm.getPreviewProperties(); @@ -712,7 +856,7 @@ unsigned long offset; if (!exif) return NULL; - const char* path = exif->image->io().path().c_str(); + const char* path = exif->image()->io().path().c_str(); /* given image pathname, first do simple (and fast) file extension test */ if (!filter_file_class(path, FORMAT_CLASS_RAWIMAGE)) return NULL; @@ -724,7 +868,7 @@ UnmapData *ud; int fd; - RawFile rf(exif->image->io()); + RawFile rf(exif->image()->io()); offset = rf.preview_offset(); DEBUG_1("%s: offset %lu", path, offset);