MVE - Multi-View Environment mve-devel
Loading...
Searching...
No Matches
image_exif.cc
Go to the documentation of this file.
1/*
2 * This is a heavily rewritten version of the code found at:
3 * http://code.google.com/p/easyexif/
4 *
5 * EXIF specifications can be found here:
6 * http://www.cipa.jp/std/documents/e/DC-008-2012_E.pdf
7 *
8 * Modifications: Copyright (c) 2011 - 2014 Simon Fuhrmann
9 * Original code: Copyright (c) 2010 - 2013 Mayank Lahiri <mlahiri@gmail.com>
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are met:
13 *
14 * -- Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * -- Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS
21 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
23 * NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
27 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <iostream>
33#include <stdexcept>
34#include <cmath>
35#include <limits>
36
37#include "util/system.h"
38#include "util/strings.h"
39#include "mve/image_exif.h"
40
43
44namespace
45{
46 uint32_t
47 parse_u32 (unsigned char const* buf, bool intel)
48 {
49 uint32_t value;
50 std::copy(buf, buf + 4, reinterpret_cast<unsigned char*>(&value));
51 return intel ? util::system::letoh(value) : util::system::betoh(value);
52 }
53
54 int32_t
55 parse_s32 (unsigned char const* buf, bool intel)
56 {
57 int32_t value;
58 std::copy(buf, buf + 4, reinterpret_cast<unsigned char*>(&value));
59 return intel ? util::system::letoh(value) : util::system::betoh(value);
60 }
61
62 uint16_t
63 parse_u16 (unsigned char const* buf, bool intel)
64 {
65 uint16_t value;
66 std::copy(buf, buf + 2, reinterpret_cast<unsigned char*>(&value));
67 return intel ? util::system::letoh(value) : util::system::betoh(value);
68 }
69
70 float
71 parse_rational_u64 (unsigned char const* buf, bool intel)
72 {
73 uint32_t numerator = parse_u32(buf, intel);
74 uint32_t denominator = parse_u32(buf + 4, intel);
75 if (denominator == 0)
76 return std::numeric_limits<float>::infinity();
77 return static_cast<float>(numerator) / static_cast<float>(denominator);
78 }
79
80 float
81 parse_rational_s64 (unsigned char const* buf, bool intel)
82 {
83 int32_t numerator = parse_s32(buf, intel);
84 int32_t denominator = parse_s32(buf + 4, intel);
85 if (denominator == 0)
86 return std::numeric_limits<float>::infinity();
87 return static_cast<float>(numerator) / static_cast<float>(denominator);
88 }
89
90 void
91 copy_exif_string (unsigned char const* buf, unsigned int len,
92 std::string* dest)
93 {
94 dest->clear();
95 if (len == 0)
96 return;
97 dest->append(reinterpret_cast<char const*>(buf), len - 1);
98 }
99
100 /* EXIF type specifications. */
101 enum ExifType
102 {
103 EXIF_TYPE_BYTE = 1, // 8 bit
104 EXIF_TYPE_ASCII = 2, // 8 bit character
105 EXIF_TYPE_USHORT = 3, // 16 bit
106 EXIF_TYPE_ULONG = 4, // 32 bit
107 EXIF_TYPE_URATIONAL = 5, // 64 bit
108 EXIF_TYPE_SBYTE = 6, // 8 bit
109 EXIF_TYPE_UNDEF = 7, // 8 bit (field dependent value)
110 EXIF_TYPE_SSHORT = 8, // 16 bit
111 EXIF_TYPE_SLONG = 9, // 32 bit
112 EXIF_TYPE_SRATIONAL = 10, // 64 bit
113 EXIF_TYPE_FLOAT = 11, // 32 bit
114 EXIF_TYPE_DOUBLE = 12 // 64 bit
115 };
116
117 bool
118 ifd_is_offset (unsigned short type, unsigned int count)
119 {
120 return (type == EXIF_TYPE_BYTE && count > 4)
121 || (type == EXIF_TYPE_ASCII && count > 4)
122 || (type == EXIF_TYPE_USHORT && count > 2)
123 || (type == EXIF_TYPE_ULONG && count > 1)
124 || (type == EXIF_TYPE_URATIONAL && count > 0)
125 || (type == EXIF_TYPE_SBYTE && count > 4)
126 || (type == EXIF_TYPE_UNDEF && count > 4)
127 || (type == EXIF_TYPE_SSHORT && count > 2)
128 || (type == EXIF_TYPE_SLONG && count > 1)
129 || (type == EXIF_TYPE_SRATIONAL && count > 0)
130 || (type == EXIF_TYPE_FLOAT && count > 1)
131 || (type == EXIF_TYPE_DOUBLE && count > 0);
132 }
133
134 float
135 apex_time_to_exposure (float apex_time)
136 {
137 return 1.0f / std::pow(2.0f, apex_time);
138 }
139} /* namespace */
140
141/* ---------------------------------------------------------------- */
142
143ExifInfo
144exif_extract (char const* data, std::size_t len, bool is_jpeg)
145{
146 /* Data buffer. */
147 unsigned char const* buf = reinterpret_cast<unsigned char const*>(data);
148 /* Current offset into data buffer. */
149 std::size_t offs = 0;
150 /* Intel byte alignment. */
151 bool align_intel = true;
152
153 /* Prepare return structure. */
154 ExifInfo result;
155
156 /*
157 * Scan for EXIF header and do a sanity check.
158 * The full EXIF header with signature looks as follows:
159 *
160 * 2 bytes: EXIF header: 0xFFD8
161 * 2 bytes: Section size
162 * 6 bytes: "Exif\0\0" ASCII signature
163 * 2 bytes: TIFF header (either "II" or "MM" byte alignment)
164 * 2 bytes: TIFF magic: 0x2A00
165 * 4 bytes: Offset to first IFD
166 */
167 if (is_jpeg)
168 {
169 /*
170 * Make sanity check that this is really a JPEG file.
171 * Every JPEG file starts with 0xFFD8 (and ends with 0xFFD9).
172 */
173 if (buf[0] != 0xFF || buf[1] != 0xD8)
174 throw std::invalid_argument("Invalid JPEG signature.");
175
176 /* Scan forward and search for the EXIF header (0xFF 0xE1). */
177 for (offs = 0; offs < len - 1; offs++)
178 if (buf[offs] == 0xFF && buf[offs + 1] == 0xE1)
179 break;
180 if (offs == len - 1)
181 throw std::invalid_argument("Cannot find EXIF marker!");
182 offs += 4;
183 }
184
185 /* At least 14 more bytes required for a valid EXIF. */
186 if (offs + 14 > len)
187 throw std::invalid_argument("EXIF data corrupt (header)");
188
189 /* Check EXIF signature. */
190 if (!std::equal(buf + offs, buf + offs + 6, "Exif\0\0"))
191 throw std::invalid_argument("Cannot find EXIF signature");
192 offs += 6;
193
194 /* Get byte alignment (Intel "little endian" or Motorola "big endian"). */
195 std::size_t tiff_header_offset = offs;
196 if (std::equal(buf + offs, buf + offs + 2, "II"))
197 align_intel = true;
198 else if (std::equal(buf + offs, buf + offs + 2, "MM"))
199 align_intel = false;
200 else
201 throw std::invalid_argument("Cannot find EXIF byte alignment");
202 offs += 2;
203
204 /* Check TIFF magic number. */
205 uint16_t tiff_magic_number = parse_u16(buf + offs, align_intel);
206 if (tiff_magic_number != 0x2a)
207 throw std::invalid_argument("Cannot find TIFF magic bytes");
208 offs += 2;
209
210 /* Get offset and jump into first IFD (Image File Directory). */
211 std::size_t first_ifd_offset = parse_u32(buf + offs, align_intel);
212 offs += first_ifd_offset - 4; // Why subtract 4?
213
214 /*
215 * The first two bytes of the IFD section contain the number of directory
216 * entries in the section. Then the list of IFD entries follows. After all
217 * entries, the last 4 bytes contain an offset to the next IFD.
218 */
219 if (offs + 2 > len)
220 throw std::invalid_argument("EXIF data corrupt (IFD entries)");
221 int num_entries = parse_u16(buf + offs, align_intel);
222 offs += 2;
223 if (num_entries < 0 || num_entries > 10000)
224 throw std::invalid_argument("EXIF data corrupt (number of IFDs)");
225 if (offs + 4 + 12 * num_entries > len)
226 throw std::invalid_argument("EXIF data corrupt (IFD table)");
227
228 /*
229 * Each IFD entry consists of 12 bytes.
230 *
231 * 2 bytes: Identififes tag type (as in Tagged Image File Format)
232 * 2 bytes: Field data type (byte, ASCII, short int, long int, ...)
233 * 4 bytes: Number of values
234 * 4 bytes: Either the value itself or an offset to the values
235 *
236 * While parsing the IFD entries, try to find SubIFD and GPS offsets.
237 */
238 std::size_t exif_sub_ifd_offset = 0;
239 //unsigned int gps_sub_ifd_offset = 0;
240 for (int i = 0; i < num_entries; ++i)
241 {
242 unsigned short tag = parse_u16(buf + offs, align_intel);
243 unsigned short type = parse_u16(buf + offs + 2, align_intel);
244 unsigned int ncomp = parse_u32(buf + offs + 4, align_intel);
245 unsigned int coffs = parse_u32(buf + offs + 8, align_intel);
246
247 /*
248 * Compute offset to the entry value. Depending on 'type' and 'ncomp'
249 * the 'coffs' variable contains the value itself or an offset.
250 * In case of an offset, it is relative to the TIFF header.
251 */
252 std::size_t buf_off = offs + 8;
253 if (ifd_is_offset(type, ncomp))
254 buf_off = tiff_header_offset + coffs;
255 if (buf_off + ncomp > len)
256 throw std::invalid_argument("EXIF data corrupt (IFD entry)");
257
258 switch (tag)
259 {
260 case 0x8769: // EXIF subIFD offset.
261 exif_sub_ifd_offset = tiff_header_offset + coffs;
262 break;
263
264 //case 0x8825: // GPS IFS offset.
265 // gps_sub_ifd_offset = tiff_header_offset + coffs;
266 // break;
267
268 case 0x102: // Bits per color sample.
269 if (type == EXIF_TYPE_USHORT)
270 result.bits_per_sample = parse_u16(buf + buf_off, align_intel);
271 break;
272
273 case 0x112: // Image orientation.
274 if (type == EXIF_TYPE_USHORT)
275 result.orientation = parse_u16(buf + buf_off, align_intel);
276 break;
277
278 case 0x10F: // Digicam manufacturer.
279 if (type == EXIF_TYPE_ASCII)
280 copy_exif_string(buf + buf_off, ncomp, &result.camera_maker);
281 break;
282
283 case 0x110: // Digicam model.
284 if (type == EXIF_TYPE_ASCII)
285 copy_exif_string(buf + buf_off, ncomp, &result.camera_model);
286 break;
287
288 case 0x132: // EXIF/TIFF date/time of image.
289 if (type == EXIF_TYPE_ASCII)
290 copy_exif_string(buf + buf_off, ncomp, &result.date_modified);
291 break;
292
293 case 0x10E: // Image description.
294 if (type == EXIF_TYPE_ASCII)
295 copy_exif_string(buf + buf_off, ncomp, &result.description);
296 break;
297
298 case 0x131: // Software used to process the image.
299 if (type == EXIF_TYPE_ASCII)
300 copy_exif_string(buf + buf_off, ncomp, &result.software);
301 break;
302
303 case 0x8298: // Copyright information.
304 if (type == EXIF_TYPE_ASCII)
305 copy_exif_string(buf + buf_off, ncomp, &result.copyright);
306 break;
307
308 case 0x013b: // Artist information.
309 if (type == EXIF_TYPE_ASCII)
310 copy_exif_string(buf + buf_off, ncomp, &result.artist);
311 break;
312
313 default:
314 break;
315 }
316 offs += 12;
317 }
318
319 /* Check if a SubIFD section exists. */
320 if (exif_sub_ifd_offset == 0)
321 return result;
322
323 /* Parse SubIFD section. */
324 offs = exif_sub_ifd_offset;
325 if (offs + 2 > len)
326 throw std::invalid_argument("EXIF data corrupt (SubIFD entries)");
327 num_entries = parse_u16(buf + offs, align_intel);
328 offs += 2;
329 if (num_entries < 0 || num_entries > 10000)
330 throw std::invalid_argument("EXIF data corrupt (number of SubIFDs)");
331 if (offs + 4 + 12 * num_entries > len)
332 throw std::invalid_argument("EXIF data corrupt (SubIFD table)");
333
334 /* Like with IFD entries, each IFD entry consists of 12 bytes. */
335 for (int j = 0; j < num_entries; j++)
336 {
337 unsigned short tag = parse_u16(buf + offs, align_intel);
338 unsigned short type = parse_u16(buf + offs + 2, align_intel);
339 unsigned int ncomp = parse_u32(buf + offs + 4, align_intel);
340 unsigned int coffs = parse_u32(buf + offs + 8, align_intel);
341
342 std::size_t buf_off = offs + 8;
343 if (ifd_is_offset(type, ncomp))
344 buf_off = tiff_header_offset + coffs;
345 if (buf_off + ncomp > len)
346 throw std::invalid_argument("EXIF data corrupt (SubIFD entry)");
347
348 switch (tag)
349 {
350 case 0x9003: // Original image date/time string.
351 if (type == EXIF_TYPE_ASCII)
352 copy_exif_string(buf + buf_off, ncomp, &result.date_original);
353 break;
354
355 case 0x8827: // ISO speed ratings.
356 if (type == EXIF_TYPE_USHORT)
357 result.iso_speed = parse_u16(buf + buf_off, align_intel);
358 break;
359
360 case 0x920A: // Focal length in mm.
361 if (type == EXIF_TYPE_URATIONAL)
362 result.focal_length = parse_rational_u64(buf + buf_off, align_intel);
363 break;
364
365 case 0xA405: // Focal length (35 mm equivalent).
366 if (type == EXIF_TYPE_USHORT)
367 result.focal_length_35mm = (float)parse_u16(buf + buf_off, align_intel);
368 break;
369
370 case 0x829D: // F-stop number.
371 if (type == EXIF_TYPE_URATIONAL)
372 result.f_number = parse_rational_u64(buf + buf_off, align_intel);
373 break;
374
375 case 0x829A: // Exposure time.
376 if (type == EXIF_TYPE_URATIONAL)
377 result.exposure_time = parse_rational_u64(buf + buf_off, align_intel);
378 break;
379
380 case 0x9201: // Shutter speed (in APEX format).
381 if (type == EXIF_TYPE_SRATIONAL)
382 result.shutter_speed = apex_time_to_exposure(parse_rational_s64(buf + buf_off, align_intel));
383 break;
384
385 case 0x9204: // Exposure bias.
386 if (type == EXIF_TYPE_URATIONAL)
387 result.exposure_bias = parse_rational_u64(buf + buf_off, align_intel);
388 break;
389
390 case 0x9209: // Flash mode.
391 if (type == EXIF_TYPE_USHORT)
392 result.flash_mode = parse_u16(buf + buf_off, align_intel);
393 break;
394
395 case 0xA002: // Image width.
396 if (type == EXIF_TYPE_USHORT)
397 result.image_width = parse_u16(buf + buf_off, align_intel);
398 if (type == EXIF_TYPE_ULONG)
399 result.image_width = parse_u32(buf + buf_off, align_intel);
400 break;
401
402 case 0xA003: // Image height.
403 if (type == EXIF_TYPE_USHORT)
404 result.image_height = parse_u16(buf + buf_off, align_intel);
405 if (type == EXIF_TYPE_ULONG)
406 result.image_height = parse_u32(buf + buf_off, align_intel);
407 break;
408
409 default:
410 break;
411 }
412 offs += 12;
413 }
414
415 return result;
416}
417
418/* ---------------------------------------------------------------- */
419
420namespace
421{
422 template <typename T>
423 std::string
424 debug_print (T const& value, std::string extra = "")
425 {
426 if (value < T(0))
427 return "<not set>";
428 else
429 return util::string::get(value) + extra;
430 }
431
432 std::string
433 debug_print (std::string const& value)
434 {
435 if (value.empty())
436 return "<not set>";
437 else
438 return value;
439 }
440}
441
442void
443exif_debug_print (std::ostream& stream, ExifInfo const& exif, bool indent)
444{
445 int const width = indent ? 22 : 0;
446 stream
447 << std::setw(width) << std::left << "Camera manufacturer: "
448 << debug_print(exif.camera_maker) << std::endl
449 << std::setw(width) << std::left << "Camera model: "
450 << debug_print(exif.camera_model) << std::endl
451 << std::setw(width) << std::left << "Date (modified): "
452 << debug_print(exif.date_modified) << std::endl
453 << std::setw(width) << std::left << "Date (original): "
454 << debug_print(exif.date_original) << std::endl
455 << std::setw(width) << std::left << "Description: "
456 << debug_print(exif.description) << std::endl
457 << std::setw(width) << std::left << "Software: "
458 << debug_print(exif.software) << std::endl
459 << std::setw(width) << std::left << "Copyright info: "
460 << debug_print(exif.copyright) << std::endl
461 << std::setw(width) << std::left << "Artist info: "
462 << debug_print(exif.artist) << std::endl
463
464 << std::setw(width) << std::left << "ISO speed: "
465 << debug_print(exif.iso_speed) << std::endl
466 << std::setw(width) << std::left << "Bits per sample: "
467 << debug_print(exif.bits_per_sample) << std::endl
468 << std::setw(width) << std::left << "Image Orientation: "
469 << debug_print(exif.orientation) << std::endl
470 << std::setw(width) << std::left << "Focal length: "
471 << debug_print(exif.focal_length, " mm") << std::endl
472 << std::setw(width) << std::left << "Focal length (35mm): "
473 << debug_print(exif.focal_length_35mm, " mm") << std::endl
474 << std::setw(width) << std::left << "F-Number: "
475 << debug_print(exif.f_number) << std::endl
476 << std::setw(width) << std::left << "Exposure time: "
477 << debug_print(exif.exposure_time, " sec") << std::endl
478 << std::setw(width) << std::left << "Exposure bias: "
479 << debug_print(exif.exposure_bias) << std::endl
480 << std::setw(width) << std::left << "Shutter speed: "
481 << debug_print(exif.shutter_speed, " sec") << std::endl
482 << std::setw(width) << std::left << "Flash mode: "
483 << debug_print(exif.flash_mode) << std::endl
484 << std::setw(width) << std::left << "Image width: "
485 << debug_print(exif.image_width, " pixel") << std::endl
486 << std::setw(width) << std::left << "Image height: "
487 << debug_print(exif.image_height, " pixel") << std::endl;
488}
489
#define MVE_IMAGE_NAMESPACE_END
Definition defines.h:17
#define MVE_NAMESPACE_BEGIN
Definition defines.h:13
#define MVE_IMAGE_NAMESPACE_BEGIN
Definition defines.h:16
#define MVE_NAMESPACE_END
Definition defines.h:14
ExifInfo exif_extract(char const *data, std::size_t len, bool is_jpeg)
Function to extract a (selected) EXIF tags from binary data.
void exif_debug_print(std::ostream &stream, ExifInfo const &exif, bool indent)
Prints the EXIF information to stream.
std::string get(T const &value)
From arbitrary types to string conversion.
Definition strings.h:108
T betoh(T const &x)
Big endian to host order conversion.
T letoh(T const &x)
Little endian to host order conversion.
Parser, tokenizer, timer, smart pointer, threads, etc.
EXIF information.
Definition image_exif.h:32
std::string copyright
Copyright information.
Definition image_exif.h:48
std::string camera_maker
Camera manufacturer.
Definition image_exif.h:36
int iso_speed
Camera ISO speed rating for the image.
Definition image_exif.h:53
int image_width
EXIF image width.
Definition image_exif.h:85
int orientation
Orientation of the image:
Definition image_exif.h:69
float shutter_speed
Image shutter speed in seconds.
Definition image_exif.h:81
float focal_length_35mm
Focal length equivalent for 35mm film.
Definition image_exif.h:73
std::string camera_model
Camera model.
Definition image_exif.h:38
std::string artist
Artist information.
Definition image_exif.h:50
int flash_mode
Flash mode (see http://tinyurl.com/o7pawes).
Definition image_exif.h:83
float f_number
F-number in 1/f.
Definition image_exif.h:75
float focal_length
Focal length of the image in mm, relative to sensor size.
Definition image_exif.h:71
float exposure_time
Image exposure time in seconds.
Definition image_exif.h:77
std::string description
Description of the image.
Definition image_exif.h:44
int bits_per_sample
Bits per sample.
Definition image_exif.h:55
std::string date_original
Date/time string of original image.
Definition image_exif.h:42
std::string software
Software used to process the image.
Definition image_exif.h:46
std::string date_modified
Date/time string of last modification.
Definition image_exif.h:40
float exposure_bias
Image exposure bias in F-stops.
Definition image_exif.h:79
int image_height
EXIF image height.
Definition image_exif.h:87