1 /*
2 * UFRaw - Unidentified Flying Raw converter for digital camera images
3 *
4 * ufraw_exiv2.cc - read the EXIF data from the RAW file using exiv2.
5 * Copyright 2004-2016 by Udi Fuchs
6 *
7 * Based on a sample program from exiv2 and neftags2jpg.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 */
14
15 #include "ufraw.h"
16
17 #ifdef HAVE_EXIV2
18 #include <exiv2/exiv2.hpp>
19 #include <sstream>
20 #include <cassert>
21 #include <iostream>
22
23 /*
24 * Helper function to copy a string to a buffer, converting it from
25 * current locale (in which exiv2 often returns strings) to UTF-8.
26 */
uf_strlcpy_to_utf8(char * dest,size_t dest_max,Exiv2::ExifData::const_iterator pos,Exiv2::ExifData & exifData)27 static void uf_strlcpy_to_utf8(char *dest, size_t dest_max,
28 Exiv2::ExifData::const_iterator pos, Exiv2::ExifData& exifData)
29 {
30 std::string str = pos->print(&exifData);
31
32 char *s = g_locale_to_utf8(str.c_str(), str.length(),
33 NULL, NULL, NULL);
34 if (s != NULL) {
35 g_strlcpy(dest, s, dest_max);
36 g_free(s);
37 } else {
38 g_strlcpy(dest, str.c_str(), dest_max);
39 }
40 }
41
ufraw_exif_read_input(ufraw_data * uf)42 extern "C" int ufraw_exif_read_input(ufraw_data *uf)
43 {
44 /* Redirect exiv2 errors to a string buffer */
45 std::ostringstream stderror;
46 std::streambuf *savecerr = std::cerr.rdbuf();
47 std::cerr.rdbuf(stderror.rdbuf());
48
49 try {
50 uf->inputExifBuf = NULL;
51 uf->inputExifBufLen = 0;
52
53 Exiv2::Image::AutoPtr image;
54 if (uf->unzippedBuf != NULL) {
55 image = Exiv2::ImageFactory::open(
56 (const Exiv2::byte*)uf->unzippedBuf, uf->unzippedBufLen);
57 } else {
58 char *filename = uf_win32_locale_filename_from_utf8(uf->filename);
59 image = Exiv2::ImageFactory::open(filename);
60 uf_win32_locale_filename_free(filename);
61 }
62 assert(image.get() != 0);
63 image->readMetadata();
64
65 Exiv2::ExifData &exifData = image->exifData();
66 if (exifData.empty()) {
67 std::string error(uf->filename);
68 error += ": No Exif data found in the file";
69 #if EXIV2_TEST_VERSION(0,27,0)
70 throw Exiv2::Error(Exiv2::kerErrorMessage, error);
71 #else
72 throw Exiv2::Error(1, error);
73 #endif
74 }
75
76 /* List of tag names taken from exiv2's printSummary() in actions.cpp */
77 Exiv2::ExifData::const_iterator pos;
78 /* Read shutter time */
79 if ((pos = Exiv2::exposureTime(exifData)) != exifData.end()) {
80 uf_strlcpy_to_utf8(uf->conf->shutterText, max_name, pos, exifData);
81 uf->conf->shutter = pos->toFloat();
82 }
83 /* Read aperture */
84 if ((pos = Exiv2::fNumber(exifData)) != exifData.end()) {
85 uf_strlcpy_to_utf8(uf->conf->apertureText, max_name, pos, exifData);
86 uf->conf->aperture = pos->toFloat();
87 }
88 /* Read ISO speed */
89 if ((pos = Exiv2::isoSpeed(exifData)) != exifData.end()) {
90 uf_strlcpy_to_utf8(uf->conf->isoText, max_name, pos, exifData);
91 }
92 /* Read focal length */
93 if ((pos = Exiv2::focalLength(exifData)) != exifData.end()) {
94 uf_strlcpy_to_utf8(uf->conf->focalLenText, max_name, pos, exifData);
95 uf->conf->focal_len = pos->toFloat();
96 }
97 /* Read focal length in 35mm equivalent */
98 if ((pos = exifData.findKey(Exiv2::ExifKey(
99 "Exif.Photo.FocalLengthIn35mmFilm")))
100 != exifData.end()) {
101 uf_strlcpy_to_utf8(uf->conf->focalLen35Text, max_name, pos, exifData);
102 }
103 /* Read full lens name */
104 if ((pos = Exiv2::lensName(exifData)) != exifData.end()) {
105 uf_strlcpy_to_utf8(uf->conf->lensText, max_name, pos, exifData);
106 }
107 /* Read flash mode */
108 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Photo.Flash")))
109 != exifData.end()) {
110 uf_strlcpy_to_utf8(uf->conf->flashText, max_name, pos, exifData);
111 }
112 /* Read White Balance Setting */
113 if ((pos = Exiv2::whiteBalance(exifData)) != exifData.end()) {
114 uf_strlcpy_to_utf8(uf->conf->whiteBalanceText, max_name, pos, exifData);
115 }
116
117 if ((pos = Exiv2::make(exifData)) != exifData.end()) {
118 uf_strlcpy_to_utf8(uf->conf->real_make, max_name, pos, exifData);
119 }
120 if ((pos = Exiv2::model(exifData)) != exifData.end()) {
121 uf_strlcpy_to_utf8(uf->conf->real_model, max_name, pos, exifData);
122 }
123
124 /* Store all EXIF data read in. */
125 Exiv2::Blob blob;
126 Exiv2::ExifParser::encode(blob, Exiv2::bigEndian, exifData);
127 uf->inputExifBufLen = blob.size();
128 uf->inputExifBuf = g_new(unsigned char, uf->inputExifBufLen);
129 memcpy(uf->inputExifBuf, &blob[0], blob.size());
130 ufraw_message(UFRAW_SET_LOG, "EXIF data read using exiv2, buflen %d\n",
131 uf->inputExifBufLen);
132 g_strlcpy(uf->conf->exifSource, EXV_PACKAGE_STRING, max_name);
133
134 std::cerr.rdbuf(savecerr);
135 ufraw_message(UFRAW_SET_LOG, "%s\n", stderror.str().c_str());
136
137 return UFRAW_SUCCESS;
138 } catch (Exiv2::AnyError& e) {
139 std::cerr.rdbuf(savecerr);
140 std::string s(e.what());
141 ufraw_message(UFRAW_SET_WARNING, "%s\n", s.c_str());
142 return UFRAW_ERROR;
143 }
144
145 }
146
ufraw_prepare_exifdata(ufraw_data * uf)147 static Exiv2::ExifData ufraw_prepare_exifdata(ufraw_data *uf)
148 {
149 Exiv2::ExifData exifData = Exiv2::ExifData();
150
151 /* Start from the input EXIF data */
152 Exiv2::ExifParser::decode(exifData, uf->inputExifBuf, uf->inputExifBufLen);
153 Exiv2::ExifData::iterator pos;
154 if (uf->conf->rotate) {
155 /* Reset orientation tag since UFRaw already rotates the image */
156 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.Orientation")))
157 != exifData.end()) {
158 ufraw_message(UFRAW_SET_LOG, "Resetting %s from '%d' to '1'\n",
159 pos->key().c_str(), pos->value().toLong());
160 pos->setValue("1"); /* 1 = Normal orientation */
161 }
162 }
163
164 /* Delete original TIFF data, which is irrelevant*/
165 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.ImageWidth")))
166 != exifData.end())
167 exifData.erase(pos);
168 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.ImageLength")))
169 != exifData.end())
170 exifData.erase(pos);
171 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.BitsPerSample")))
172 != exifData.end())
173 exifData.erase(pos);
174 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.Compression")))
175 != exifData.end())
176 exifData.erase(pos);
177 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.PhotometricInterpretation")))
178 != exifData.end())
179 exifData.erase(pos);
180 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.FillOrder")))
181 != exifData.end())
182 exifData.erase(pos);
183 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.SamplesPerPixel")))
184 != exifData.end())
185 exifData.erase(pos);
186 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.StripOffsets")))
187 != exifData.end())
188 exifData.erase(pos);
189 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.RowsPerStrip")))
190 != exifData.end())
191 exifData.erase(pos);
192 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.StripByteCounts")))
193 != exifData.end())
194 exifData.erase(pos);
195 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.XResolution")))
196 != exifData.end())
197 exifData.erase(pos);
198 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.YResolution")))
199 != exifData.end())
200 exifData.erase(pos);
201 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.PlanarConfiguration")))
202 != exifData.end())
203 exifData.erase(pos);
204 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.ResolutionUnit")))
205 != exifData.end())
206 exifData.erase(pos);
207
208 /* Delete various MakerNote fields only applicable to the raw file */
209
210 // Nikon thumbnail data
211 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Nikon3.Preview")))
212 != exifData.end())
213 exifData.erase(pos);
214 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.NikonPreview.JPEGInterchangeFormat")))
215 != exifData.end())
216 exifData.erase(pos);
217
218 // DCRaw handles TIFF files as raw if DNGVersion is found.
219 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.DNGVersion")))
220 != exifData.end())
221 exifData.erase(pos);
222
223 // DNG private data
224 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.DNGPrivateData")))
225 != exifData.end())
226 exifData.erase(pos);
227
228 // Pentax thumbnail data
229 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Pentax.PreviewResolution")))
230 != exifData.end())
231 exifData.erase(pos);
232 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Pentax.PreviewLength")))
233 != exifData.end())
234 exifData.erase(pos);
235 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Pentax.PreviewOffset")))
236 != exifData.end())
237 exifData.erase(pos);
238
239 // Minolta thumbnail data
240 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Minolta.Thumbnail")))
241 != exifData.end())
242 exifData.erase(pos);
243 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Minolta.ThumbnailOffset")))
244 != exifData.end())
245 exifData.erase(pos);
246 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Minolta.ThumbnailLength")))
247 != exifData.end())
248 exifData.erase(pos);
249
250 // Olympus thumbnail data
251 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Olympus.Thumbnail")))
252 != exifData.end())
253 exifData.erase(pos);
254 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Olympus.ThumbnailOffset")))
255 != exifData.end())
256 exifData.erase(pos);
257 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Olympus.ThumbnailLength")))
258 != exifData.end())
259 exifData.erase(pos);
260
261 /* Write appropriate color space tag if using sRGB output */
262 if (!strcmp(uf->developer->profileFile[out_profile], ""))
263 exifData["Exif.Photo.ColorSpace"] = uint16_t(1); /* sRGB */
264
265 /* Add "UFRaw" and version used to output file as processing software. */
266 exifData["Exif.Image.ProcessingSoftware"] = "UFRaw " VERSION;
267
268 return exifData;
269 }
270
ufraw_exif_prepare_output(ufraw_data * uf)271 extern "C" int ufraw_exif_prepare_output(ufraw_data *uf)
272 {
273 /* Redirect exiv2 errors to a string buffer */
274 std::ostringstream stderror;
275 std::streambuf *savecerr = std::cerr.rdbuf();
276 std::cerr.rdbuf(stderror.rdbuf());
277 try {
278 uf->outputExifBuf = NULL;
279 uf->outputExifBufLen = 0;
280
281 Exiv2::ExifData exifData = ufraw_prepare_exifdata(uf);
282
283 int size;
284 Exiv2::Blob blob;
285 Exiv2::ExifParser::encode(blob, Exiv2::bigEndian, exifData);
286 size = blob.size();
287 const unsigned char ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00};
288 /* If buffer too big for JPEG, try deleting some stuff. */
289 if (size + sizeof(ExifHeader) > 65533) {
290 Exiv2::ExifData::iterator pos;
291 if ((pos = exifData.findKey(Exiv2::ExifKey("Exif.Photo.MakerNote")))
292 != exifData.end()) {
293 exifData.erase(pos);
294 ufraw_message(UFRAW_SET_LOG,
295 "buflen %d too big, erasing Exif.Photo.MakerNote "
296 "and related decoded metadata\n",
297 size + sizeof(ExifHeader));
298 /* Delete decoded metadata associated with
299 * Exif.Photo.MakerNote, otherwise erasing it isn't
300 * effective. */
301 for (pos = exifData.begin(); pos != exifData.end();) {
302 if (!strcmp(pos->ifdName(), "Makernote"))
303 pos = exifData.erase(pos);
304 else
305 pos++;
306 }
307 blob.clear();
308 Exiv2::ExifParser::encode(blob, Exiv2::bigEndian, exifData);
309 size = blob.size();
310 }
311 }
312 if (size + sizeof(ExifHeader) > 65533) {
313 Exiv2::ExifThumb thumb(exifData);
314 thumb.erase();
315 ufraw_message(UFRAW_SET_LOG,
316 "buflen %d too big, erasing Thumbnail\n",
317 size + sizeof(ExifHeader));
318 blob.clear();
319 Exiv2::ExifParser::encode(blob, Exiv2::bigEndian, exifData);
320 size = blob.size();
321 }
322 uf->outputExifBufLen = size + sizeof(ExifHeader);
323 uf->outputExifBuf = g_new(unsigned char, uf->outputExifBufLen);
324 memcpy(uf->outputExifBuf, ExifHeader, sizeof(ExifHeader));
325 memcpy(uf->outputExifBuf + sizeof(ExifHeader), &blob[0], blob.size());
326 std::cerr.rdbuf(savecerr);
327 ufraw_message(UFRAW_SET_LOG, "%s\n", stderror.str().c_str());
328
329 return UFRAW_SUCCESS;
330 } catch (Exiv2::AnyError& e) {
331 std::cerr.rdbuf(savecerr);
332 std::string s(e.what());
333 ufraw_message(UFRAW_SET_WARNING, "%s\n", s.c_str());
334 return UFRAW_ERROR;
335 }
336
337 }
338
ufraw_exif_write(ufraw_data * uf)339 extern "C" int ufraw_exif_write(ufraw_data *uf)
340 {
341 /* Redirect exiv2 errors to a string buffer */
342 std::ostringstream stderror;
343 std::streambuf *savecerr = std::cerr.rdbuf();
344 std::cerr.rdbuf(stderror.rdbuf());
345 try {
346 Exiv2::ExifData rawExifData = ufraw_prepare_exifdata(uf);
347
348 char *filename =
349 uf_win32_locale_filename_from_utf8(uf->conf->outputFilename);
350 Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(filename);
351 uf_win32_locale_filename_free(filename);
352 assert(image.get() != 0);
353
354 image->readMetadata();
355 Exiv2::ExifData &outExifData = image->exifData();
356
357 Exiv2::ExifData::iterator pos = rawExifData.begin();
358 while (!rawExifData.empty()) {
359 outExifData.add(*pos);
360 pos = rawExifData.erase(pos);
361 }
362 outExifData.sortByTag();
363 image->setExifData(outExifData);
364 image->writeMetadata();
365
366 std::cerr.rdbuf(savecerr);
367 ufraw_message(UFRAW_SET_LOG, "%s\n", stderror.str().c_str());
368
369 return UFRAW_SUCCESS;
370 } catch (Exiv2::AnyError& e) {
371 std::cerr.rdbuf(savecerr);
372 std::string s(e.what());
373 ufraw_message(UFRAW_SET_WARNING, "%s\n", s.c_str());
374 return UFRAW_ERROR;
375 }
376 }
377
378 #else
ufraw_exif_read_input(ufraw_data * uf)379 extern "C" int ufraw_exif_read_input(ufraw_data *uf)
380 {
381 (void)uf;
382 ufraw_message(UFRAW_SET_LOG, "ufraw built without EXIF support\n");
383 return UFRAW_ERROR;
384 }
385
ufraw_exif_prepare_output(ufraw_data * uf)386 extern "C" int ufraw_exif_prepare_output(ufraw_data *uf)
387 {
388 (void)uf;
389 return UFRAW_ERROR;
390 }
391
ufraw_exif_write(ufraw_data * uf)392 extern "C" int ufraw_exif_write(ufraw_data *uf)
393 {
394 (void)uf;
395 return UFRAW_ERROR;
396 }
397 #endif /* HAVE_EXIV2 */
398