comparison src/exiv2.cc @ 1069:aeae25d5d50d

infrastructure for preprocessing of metadata
author nadvornik
date Sat, 18 Oct 2008 18:22:57 +0000
parents 90dcc0060e22
children abf48b53216b
comparison
equal deleted inserted replaced
1068:e67636316f4c 1069:aeae25d5d50d
59 #include "ui_fileops.h" 59 #include "ui_fileops.h"
60 } 60 }
61 61
62 struct _ExifData 62 struct _ExifData
63 { 63 {
64 Exiv2::Image::AutoPtr image;
65 Exiv2::Image::AutoPtr sidecar;
66 Exiv2::ExifData::const_iterator exifIter; /* for exif_get_next_item */ 64 Exiv2::ExifData::const_iterator exifIter; /* for exif_get_next_item */
67 Exiv2::IptcData::const_iterator iptcIter; /* for exif_get_next_item */ 65 Exiv2::IptcData::const_iterator iptcIter; /* for exif_get_next_item */
68 #if EXIV2_TEST_VERSION(0,16,0) 66 #if EXIV2_TEST_VERSION(0,16,0)
69 Exiv2::XmpData::const_iterator xmpIter; /* for exif_get_next_item */ 67 Exiv2::XmpData::const_iterator xmpIter; /* for exif_get_next_item */
70 #endif 68 #endif
71 bool have_sidecar; 69
70 virtual ~_ExifData()
71 {
72 }
73
74 virtual void writeMetadata()
75 {
76 g_critical("Unsupported method of writing metadata");
77 }
78
79 virtual ExifData *original()
80 {
81 return NULL;
82 }
83
84 virtual Exiv2::Image *image() = 0;
85
86 virtual Exiv2::ExifData &exifData() = 0;
87
88 virtual Exiv2::IptcData &iptcData() = 0;
89
90 #if EXIV2_TEST_VERSION(0,16,0)
91 virtual Exiv2::XmpData &xmpData() = 0;
92 #endif
93
94 virtual void add_jpeg_color_profile(unsigned char *cp_data, guint cp_length) = 0;
95
96 virtual guchar *get_jpeg_color_profile(guint *data_len) = 0;
97 };
98
99 // This allows read-only access to the original metadata
100 struct _ExifDataOriginal : public _ExifData
101 {
102 protected:
103 Exiv2::Image::AutoPtr image_;
72 104
73 /* the icc profile in jpeg is not technically exif - store it here */ 105 /* the icc profile in jpeg is not technically exif - store it here */
74 unsigned char *cp_data; 106 unsigned char *cp_data_;
75 guint cp_length; 107 guint cp_length_;
76 108
77 _ExifData(gchar *path, gchar *sidecar_path) 109 public:
78 { 110
79 have_sidecar = false; 111 _ExifDataOriginal(gchar *path)
80 cp_data = NULL; 112 {
81 cp_length = 0; 113 cp_data_ = NULL;
114 cp_length_ = 0;
82 gchar *pathl = path_from_utf8(path); 115 gchar *pathl = path_from_utf8(path);
83 image = Exiv2::ImageFactory::open(pathl); 116 image_ = Exiv2::ImageFactory::open(pathl);
84 g_free(pathl); 117 g_free(pathl);
85 // g_assert (image.get() != 0); 118 // g_assert (image.get() != 0);
86 image->readMetadata(); 119 image_->readMetadata();
87 120
88 #if EXIV2_TEST_VERSION(0,16,0) 121 #if EXIV2_TEST_VERSION(0,16,0)
89 DEBUG_2("xmp count %li", image->xmpData().count()); 122 if (image_->mimeType() == "application/rdf+xml")
90 if (sidecar_path && image->xmpData().empty()) 123 {
91 { 124 //Exiv2 sidecar converts xmp to exif and iptc, we don't want it.
92 gchar *sidecar_pathl = path_from_utf8(sidecar_path); 125 image_->clearExifData();
93 sidecar = Exiv2::ImageFactory::open(sidecar_pathl); 126 image_->clearIptcData();
94 g_free(sidecar_pathl); 127 }
95 sidecar->readMetadata(); 128 #endif
96 have_sidecar = sidecar->good(); 129
97 DEBUG_2("sidecar xmp count %li", sidecar->xmpData().count());
98 }
99
100 #endif
101 #if EXIV2_TEST_VERSION(0,14,0) 130 #if EXIV2_TEST_VERSION(0,14,0)
102 if (image->mimeType() == std::string("image/jpeg")) 131 if (image_->mimeType() == "image/jpeg")
103 { 132 {
104 /* try to get jpeg color profile */ 133 /* try to get jpeg color profile */
105 Exiv2::BasicIo &io = image->io(); 134 Exiv2::BasicIo &io = image_->io();
106 gint open = io.isopen(); 135 gint open = io.isopen();
107 if (!open) io.open(); 136 if (!open) io.open();
108 unsigned char *mapped = (unsigned char*)io.mmap(); 137 unsigned char *mapped = (unsigned char*)io.mmap();
109 if (mapped) exif_jpeg_parse_color(this, mapped, io.size()); 138 if (mapped) exif_jpeg_parse_color(this, mapped, io.size());
110 io.munmap(); 139 io.munmap();
111 if (!open) io.close(); 140 if (!open) io.close();
112 } 141 }
113 #endif 142 #endif
114 } 143 }
115 144
116 ~_ExifData() 145 virtual ~_ExifDataOriginal()
117 { 146 {
118 if (cp_data) g_free(cp_data); 147 if (cp_data_) g_free(cp_data_);
119 } 148 }
120 149
121 void writeMetadata() 150 virtual Exiv2::Image *image()
122 { 151 {
123 if (have_sidecar) sidecar->writeMetadata(); 152 return image_.get();
124 image->writeMetadata(); 153 }
125 } 154
126 155 virtual Exiv2::ExifData &exifData ()
127 Exiv2::ExifData &exifData () 156 {
128 { 157 return image_->exifData();
129 return image->exifData(); 158 }
130 } 159
131 160 virtual Exiv2::IptcData &iptcData ()
132 Exiv2::IptcData &iptcData () 161 {
133 { 162 return image_->iptcData();
134 return image->iptcData(); 163 }
135 } 164
136 165 #if EXIV2_TEST_VERSION(0,16,0)
137 #if EXIV2_TEST_VERSION(0,16,0) 166 virtual Exiv2::XmpData &xmpData ()
138 Exiv2::XmpData &xmpData () 167 {
139 { 168 return image_->xmpData();
140 return have_sidecar ? sidecar->xmpData() : image->xmpData(); 169 }
141 } 170 #endif
142 #endif 171
143 172 virtual void add_jpeg_color_profile(unsigned char *cp_data, guint cp_length)
173 {
174 if (cp_data_) g_free(cp_data_);
175 cp_data_ = cp_data;
176 cp_length_ = cp_length;
177 }
178
179 virtual guchar *get_jpeg_color_profile(guint *data_len)
180 {
181 if (cp_data_)
182 {
183 if (data_len) *data_len = cp_length_;
184 return (unsigned char *) g_memdup(cp_data_, cp_length_);
185 }
186 return NULL;
187 }
144 }; 188 };
145 189
190 // This allows read-write access to the metadata
191 struct _ExifDataProcessed : public _ExifData
192 {
193 protected:
194 _ExifDataOriginal *imageData_;
195 _ExifDataOriginal *sidecarData_;
196
197 Exiv2::ExifData exifData_;
198 Exiv2::IptcData iptcData_;
199 #if EXIV2_TEST_VERSION(0,16,0)
200 Exiv2::XmpData xmpData_;
201 #endif
202
203 public:
204 _ExifDataProcessed(gchar *path, gchar *sidecar_path)
205 {
206 imageData_ = new _ExifDataOriginal(path);
207 sidecarData_ = NULL;
208 #if EXIV2_TEST_VERSION(0,16,0)
209 xmpData_ = imageData_->xmpData();
210 DEBUG_2("xmp count %li", xmpData_.count());
211 if (sidecar_path && xmpData_.empty())
212 {
213 sidecarData_ = new _ExifDataOriginal(sidecar_path);
214 xmpData_ = sidecarData_->xmpData();
215 }
216 #endif
217 exifData_ = imageData_->exifData();
218 iptcData_ = imageData_->iptcData();
219 }
220
221 virtual ~_ExifDataProcessed()
222 {
223 if (imageData_) delete imageData_;
224 if (sidecarData_) delete sidecarData_;
225 }
226
227 virtual ExifData *original()
228 {
229 return imageData_;
230 }
231
232 virtual void writeMetadata()
233 {
234
235 if (sidecarData_)
236 {
237 sidecarData_->image()->setXmpData(xmpData_);
238 //Exiv2 sidecar converts xmp to exif and iptc, we don't want it.
239 sidecarData_->image()->clearExifData();
240 sidecarData_->image()->clearIptcData();
241 sidecarData_->image()->writeMetadata();
242 }
243 else
244 {
245 imageData_->image()->setExifData(exifData_);
246 imageData_->image()->setIptcData(iptcData_);
247 imageData_->image()->setXmpData(xmpData_);
248 imageData_->image()->writeMetadata();
249 }
250 }
251
252 virtual Exiv2::Image *image()
253 {
254 return imageData_->image();
255 }
256
257 virtual Exiv2::ExifData &exifData ()
258 {
259 return exifData_;
260 }
261
262 virtual Exiv2::IptcData &iptcData ()
263 {
264 return iptcData_;
265 }
266
267 #if EXIV2_TEST_VERSION(0,16,0)
268 virtual Exiv2::XmpData &xmpData ()
269 {
270 return xmpData_;
271 }
272 #endif
273
274 virtual void add_jpeg_color_profile(unsigned char *cp_data, guint cp_length)
275 {
276 imageData_->add_jpeg_color_profile(cp_data, cp_length);
277 }
278
279 virtual guchar *get_jpeg_color_profile(guint *data_len)
280 {
281 return imageData_->get_jpeg_color_profile(data_len);
282 }
283 };
284
285
286
287
146 extern "C" { 288 extern "C" {
147 289
148 ExifData *exif_read(gchar *path, gchar *sidecar_path) 290 ExifData *exif_read(gchar *path, gchar *sidecar_path)
149 { 291 {
150 DEBUG_1("exif read %s, sidecar: %s", path, sidecar_path ? sidecar_path : "-"); 292 DEBUG_1("exif read %s, sidecar: %s", path, sidecar_path ? sidecar_path : "-");
151 try { 293 try {
152 return new ExifData(path, sidecar_path); 294 return new _ExifDataProcessed(path, sidecar_path);
153 } 295 }
154 catch (Exiv2::AnyError& e) { 296 catch (Exiv2::AnyError& e) {
155 std::cout << "Caught Exiv2 exception '" << e << "'\n"; 297 std::cout << "Caught Exiv2 exception '" << e << "'\n";
156 return NULL; 298 return NULL;
157 } 299 }
172 } 314 }
173 315
174 316
175 void exif_free(ExifData *exif) 317 void exif_free(ExifData *exif)
176 { 318 {
177 319 g_assert(dynamic_cast<_ExifDataProcessed *>(exif)); // this should not be called on ExifDataOriginal
178 delete exif; 320 delete exif;
179 } 321 }
322
323 ExifData *exif_get_original(ExifData *exif)
324 {
325 return exif->original();
326 }
327
180 328
181 ExifItem *exif_get_item(ExifData *exif, const gchar *key) 329 ExifItem *exif_get_item(ExifData *exif, const gchar *key)
182 { 330 {
183 try { 331 try {
184 Exiv2::Metadatum *item = NULL; 332 Exiv2::Metadatum *item = NULL;
586 } 734 }
587 } 735 }
588 736
589 void exif_add_jpeg_color_profile(ExifData *exif, unsigned char *cp_data, guint cp_length) 737 void exif_add_jpeg_color_profile(ExifData *exif, unsigned char *cp_data, guint cp_length)
590 { 738 {
591 if (exif->cp_data) g_free(exif->cp_data); 739 exif->add_jpeg_color_profile(cp_data, cp_length);
592 exif->cp_data = cp_data;
593 exif->cp_length =cp_length;
594 } 740 }
595 741
596 guchar *exif_get_color_profile(ExifData *exif, guint *data_len) 742 guchar *exif_get_color_profile(ExifData *exif, guint *data_len)
597 { 743 {
598 if (exif->cp_data) 744 guchar *ret = exif->get_jpeg_color_profile(data_len);
599 { 745 if (ret) return ret;
600 if (data_len) *data_len = exif->cp_length; 746
601 return (unsigned char *) g_memdup(exif->cp_data, exif->cp_length);
602 }
603 ExifItem *prof_item = exif_get_item(exif, "Exif.Image.InterColorProfile"); 747 ExifItem *prof_item = exif_get_item(exif, "Exif.Image.InterColorProfile");
604 if (prof_item && exif_item_get_format_id(prof_item) == EXIF_FORMAT_UNDEFINED) 748 if (prof_item && exif_item_get_format_id(prof_item) == EXIF_FORMAT_UNDEFINED)
605 return (unsigned char *) exif_item_get_data(prof_item, data_len); 749 ret = (guchar *)exif_item_get_data(prof_item, data_len);
606 return NULL; 750 return ret;
607 } 751 }
608 752
609 #if EXIV2_TEST_VERSION(0,17,90) 753 #if EXIV2_TEST_VERSION(0,17,90)
610 754
611 guchar *exif_get_preview(ExifData *exif, guint *data_len, gint requested_width, gint requested_height) 755 guchar *exif_get_preview(ExifData *exif, guint *data_len, gint requested_width, gint requested_height)
612 { 756 {
613 if (!exif) return NULL; 757 if (!exif) return NULL;
614 758
615 const char* path = exif->image->io().path().c_str(); 759 const char* path = exif->image()->io().path().c_str();
616 /* given image pathname, first do simple (and fast) file extension test */ 760 /* given image pathname, first do simple (and fast) file extension test */
617 gboolean is_raw = filter_file_class(path, FORMAT_CLASS_RAWIMAGE); 761 gboolean is_raw = filter_file_class(path, FORMAT_CLASS_RAWIMAGE);
618 762
619 if (!is_raw && requested_width == 0) return NULL; 763 if (!is_raw && requested_width == 0) return NULL;
620 764
621 try { 765 try {
622 766
623 Exiv2::PreviewManager pm(*exif->image); 767 Exiv2::PreviewManager pm(*exif->image());
624 768
625 Exiv2::PreviewPropertiesList list = pm.getPreviewProperties(); 769 Exiv2::PreviewPropertiesList list = pm.getPreviewProperties();
626 770
627 if (!list.empty()) 771 if (!list.empty())
628 { 772 {
710 extern "C" guchar *exif_get_preview(ExifData *exif, guint *data_len, gint requested_width, gint requested_height) 854 extern "C" guchar *exif_get_preview(ExifData *exif, guint *data_len, gint requested_width, gint requested_height)
711 { 855 {
712 unsigned long offset; 856 unsigned long offset;
713 857
714 if (!exif) return NULL; 858 if (!exif) return NULL;
715 const char* path = exif->image->io().path().c_str(); 859 const char* path = exif->image()->io().path().c_str();
716 860
717 /* given image pathname, first do simple (and fast) file extension test */ 861 /* given image pathname, first do simple (and fast) file extension test */
718 if (!filter_file_class(path, FORMAT_CLASS_RAWIMAGE)) return NULL; 862 if (!filter_file_class(path, FORMAT_CLASS_RAWIMAGE)) return NULL;
719 863
720 try { 864 try {
722 guchar *map_data; 866 guchar *map_data;
723 size_t map_len; 867 size_t map_len;
724 UnmapData *ud; 868 UnmapData *ud;
725 int fd; 869 int fd;
726 870
727 RawFile rf(exif->image->io()); 871 RawFile rf(exif->image()->io());
728 offset = rf.preview_offset(); 872 offset = rf.preview_offset();
729 DEBUG_1("%s: offset %lu", path, offset); 873 DEBUG_1("%s: offset %lu", path, offset);
730 874
731 fd = open(path, O_RDONLY); 875 fd = open(path, O_RDONLY);
732 if (fd == -1) 876 if (fd == -1)