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