1 | /*M/////////////////////////////////////////////////////////////////////////////////////// |
2 | // |
3 | // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. |
4 | // |
5 | // By downloading, copying, installing or using the software you agree to this license. |
6 | // If you do not agree to this license, do not download, install, |
7 | // copy or use the software. |
8 | // |
9 | // |
10 | // License Agreement |
11 | // For Open Source Computer Vision Library |
12 | // |
13 | // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. |
14 | // Copyright (C) 2009, Willow Garage Inc., all rights reserved. |
15 | // Third party copyrights are property of their respective owners. |
16 | // |
17 | // Redistribution and use in source and binary forms, with or without modification, |
18 | // are permitted provided that the following conditions are met: |
19 | // |
20 | // * Redistribution's of source code must retain the above copyright notice, |
21 | // this list of conditions and the following disclaimer. |
22 | // |
23 | // * Redistribution's in binary form must reproduce the above copyright notice, |
24 | // this list of conditions and the following disclaimer in the documentation |
25 | // and/or other materials provided with the distribution. |
26 | // |
27 | // * The name of the copyright holders may not be used to endorse or promote products |
28 | // derived from this software without specific prior written permission. |
29 | // |
30 | // This software is provided by the copyright holders and contributors "as is" and |
31 | // any express or implied warranties, including, but not limited to, the implied |
32 | // warranties of merchantability and fitness for a particular purpose are disclaimed. |
33 | // In no event shall the Intel Corporation or contributors be liable for any direct, |
34 | // indirect, incidental, special, exemplary, or consequential damages |
35 | // (including, but not limited to, procurement of substitute goods or services; |
36 | // loss of use, data, or profits; or business interruption) however caused |
37 | // and on any theory of liability, whether in contract, strict liability, |
38 | // or tort (including negligence or otherwise) arising in any way out of |
39 | // the use of this software, even if advised of the possibility of such damage. |
40 | // |
41 | //M*/ |
42 | |
43 | #include "precomp.hpp" |
44 | #include "exif.hpp" |
45 | |
46 | namespace { |
47 | |
48 | class ExifParsingError { |
49 | }; |
50 | } |
51 | |
52 | |
53 | namespace cv |
54 | { |
55 | |
56 | ExifEntry_t::ExifEntry_t() : |
57 | field_float(0), field_double(0), field_u32(0), field_s32(0), |
58 | tag(INVALID_TAG), field_u16(0), field_s16(0), field_u8(0), field_s8(0) |
59 | { |
60 | } |
61 | |
62 | /** |
63 | * @brief ExifReader constructor |
64 | */ |
65 | ExifReader::ExifReader() : m_format(NONE) |
66 | { |
67 | } |
68 | |
69 | /** |
70 | * @brief ExifReader destructor |
71 | */ |
72 | ExifReader::~ExifReader() |
73 | { |
74 | } |
75 | |
76 | |
77 | /** |
78 | * @brief Get tag value by tag number |
79 | * |
80 | * @param [in] tag The tag number |
81 | * |
82 | * @return ExifEntru_t structure. Caller has to know what tag it calls in order to extract proper field from the structure ExifEntry_t |
83 | * |
84 | */ |
85 | ExifEntry_t ExifReader::getTag(const ExifTagName tag) const |
86 | { |
87 | ExifEntry_t entry; |
88 | std::map<int, ExifEntry_t>::const_iterator it = m_exif.find(x: tag); |
89 | |
90 | if( it != m_exif.end() ) |
91 | { |
92 | entry = it->second; |
93 | } |
94 | return entry; |
95 | } |
96 | |
97 | |
98 | /** |
99 | * @brief Parsing the exif data buffer and prepare (internal) exif directory |
100 | * |
101 | * @param [in] data The data buffer to read EXIF data starting with endianness |
102 | * @param [in] size The size of the data buffer |
103 | * |
104 | * @return true if parsing was successful |
105 | * false in case of unsuccessful parsing |
106 | */ |
107 | bool ExifReader::parseExif(unsigned char* data, const size_t size) |
108 | { |
109 | // Populate m_data, then call parseExif() (private) |
110 | if( data && size > 0 ) |
111 | { |
112 | m_data.assign(first: data, last: data + size); |
113 | } |
114 | else |
115 | { |
116 | return false; |
117 | } |
118 | |
119 | try { |
120 | parseExif(); |
121 | if( !m_exif.empty() ) |
122 | { |
123 | return true; |
124 | } |
125 | return false; |
126 | } |
127 | catch( ExifParsingError& ) { |
128 | return false; |
129 | } |
130 | } |
131 | |
132 | /** |
133 | * @brief Filling m_exif member with exif directory elements |
134 | * This is internal function and is not exposed to client |
135 | * |
136 | * The function doesn't return any value. In case of unsuccessful parsing |
137 | * the m_exif member is not filled up |
138 | */ |
139 | void ExifReader::parseExif() |
140 | { |
141 | m_format = getFormat(); |
142 | |
143 | if( !checkTagMark() ) |
144 | { |
145 | return; |
146 | } |
147 | |
148 | uint32_t offset = getStartOffset(); |
149 | |
150 | size_t numEntry = getNumDirEntry( offsetNumDir: offset ); |
151 | |
152 | offset += 2; //go to start of tag fields |
153 | |
154 | for( size_t entry = 0; entry < numEntry; entry++ ) |
155 | { |
156 | ExifEntry_t exifEntry = parseExifEntry( offset ); |
157 | m_exif.insert( x: std::make_pair( x&: exifEntry.tag, y&: exifEntry ) ); |
158 | offset += tiffFieldSize; |
159 | } |
160 | } |
161 | |
162 | /** |
163 | * @brief Get endianness of exif information |
164 | * This is internal function and is not exposed to client |
165 | * |
166 | * @return INTEL, MOTO or NONE |
167 | */ |
168 | Endianess_t ExifReader::getFormat() const |
169 | { |
170 | if (m_data.size() < 1) |
171 | return NONE; |
172 | |
173 | if( m_data.size() > 1 && m_data[0] != m_data[1] ) |
174 | { |
175 | return NONE; |
176 | } |
177 | |
178 | if( m_data[0] == 'I' ) |
179 | { |
180 | return INTEL; |
181 | } |
182 | |
183 | if( m_data[0] == 'M' ) |
184 | { |
185 | return MOTO; |
186 | } |
187 | |
188 | return NONE; |
189 | } |
190 | |
191 | /** |
192 | * @brief Checking whether Tag Mark (0x002A) correspond to one contained in the Jpeg file |
193 | * This is internal function and is not exposed to client |
194 | * |
195 | * @return true if tag mark equals 0x002A, false otherwise |
196 | */ |
197 | bool ExifReader::checkTagMark() const |
198 | { |
199 | uint16_t tagMark = getU16( offset: 2 ); |
200 | |
201 | if( tagMark != tagMarkRequired ) |
202 | { |
203 | return false; |
204 | } |
205 | return true; |
206 | } |
207 | |
208 | /** |
209 | * @brief The utility function for extracting actual offset exif IFD0 info is started from |
210 | * This is internal function and is not exposed to client |
211 | * |
212 | * @return offset of IFD0 field |
213 | */ |
214 | uint32_t ExifReader::getStartOffset() const |
215 | { |
216 | return getU32( offset: 4 ); |
217 | } |
218 | |
219 | /** |
220 | * @brief Get the number of Directory Entries in Jpeg file |
221 | * |
222 | * @return The number of directory entries |
223 | */ |
224 | size_t ExifReader::getNumDirEntry(const size_t offsetNumDir) const |
225 | { |
226 | return getU16( offset: offsetNumDir ); |
227 | } |
228 | |
229 | /** |
230 | * @brief Parsing particular entry in exif directory |
231 | * This is internal function and is not exposed to client |
232 | * |
233 | * Entries are divided into 12-bytes blocks each |
234 | * Each block corresponds the following structure: |
235 | * |
236 | * +------+-------------+-------------------+------------------------+ |
237 | * | Type | Data format | Num of components | Data or offset to data | |
238 | * +======+=============+===================+========================+ |
239 | * | TTTT | ffff | NNNNNNNN | DDDDDDDD | |
240 | * +------+-------------+-------------------+------------------------+ |
241 | * |
242 | * Details can be found here: http://www.media.mit.edu/pia/Research/deepview/exif.html |
243 | * |
244 | * @param [in] offset Offset to entry in bytes inside raw exif data |
245 | * @return ExifEntry_t structure which corresponds to particular entry |
246 | * |
247 | */ |
248 | ExifEntry_t ExifReader::parseExifEntry(const size_t offset) |
249 | { |
250 | ExifEntry_t entry; |
251 | uint16_t tagNum = getExifTag( offset ); |
252 | entry.tag = tagNum; |
253 | |
254 | switch( tagNum ) |
255 | { |
256 | case IMAGE_DESCRIPTION: |
257 | entry.field_str = getString( offset ); |
258 | break; |
259 | case MAKE: |
260 | entry.field_str = getString( offset ); |
261 | break; |
262 | case MODEL: |
263 | entry.field_str = getString( offset ); |
264 | break; |
265 | case ORIENTATION: |
266 | entry.field_u16 = getOrientation( offset ); |
267 | break; |
268 | case XRESOLUTION: |
269 | entry.field_u_rational = getResolution( offset ); |
270 | break; |
271 | case YRESOLUTION: |
272 | entry.field_u_rational = getResolution( offset ); |
273 | break; |
274 | case RESOLUTION_UNIT: |
275 | entry.field_u16 = getResolutionUnit( offset ); |
276 | break; |
277 | case SOFTWARE: |
278 | entry.field_str = getString( offset ); |
279 | break; |
280 | case DATE_TIME: |
281 | entry.field_str = getString( offset ); |
282 | break; |
283 | case WHITE_POINT: |
284 | entry.field_u_rational = getWhitePoint( offset ); |
285 | break; |
286 | case PRIMARY_CHROMATICIES: |
287 | entry.field_u_rational = getPrimaryChromaticies( offset ); |
288 | break; |
289 | case Y_CB_CR_COEFFICIENTS: |
290 | entry.field_u_rational = getYCbCrCoeffs( offset ); |
291 | break; |
292 | case Y_CB_CR_POSITIONING: |
293 | entry.field_u16 = getYCbCrPos( offset ); |
294 | break; |
295 | case REFERENCE_BLACK_WHITE: |
296 | entry.field_u_rational = getRefBW( offset ); |
297 | break; |
298 | case COPYRIGHT: |
299 | entry.field_str = getString( offset ); |
300 | break; |
301 | case EXIF_OFFSET: |
302 | break; |
303 | default: |
304 | entry.tag = INVALID_TAG; |
305 | break; |
306 | } |
307 | return entry; |
308 | } |
309 | |
310 | /** |
311 | * @brief Get tag number from raw exif data |
312 | * This is internal function and is not exposed to client |
313 | * @param [in] offset Offset to entry in bytes inside raw exif data |
314 | * @return tag number |
315 | */ |
316 | uint16_t ExifReader::getExifTag(const size_t offset) const |
317 | { |
318 | return getU16( offset ); |
319 | } |
320 | |
321 | /** |
322 | * @brief Get string information from raw exif data |
323 | * This is internal function and is not exposed to client |
324 | * @param [in] offset Offset to entry in bytes inside raw exif data |
325 | * @return string value |
326 | */ |
327 | std::string ExifReader::getString(const size_t offset) const |
328 | { |
329 | size_t size = getU32( offset: offset + 4 ); |
330 | size_t dataOffset = 8; // position of data in the field |
331 | if( size > maxDataSize ) |
332 | { |
333 | dataOffset = getU32( offset: offset + 8 ); |
334 | } |
335 | if (dataOffset > m_data.size() || dataOffset + size > m_data.size()) { |
336 | throw ExifParsingError(); |
337 | } |
338 | std::vector<uint8_t>::const_iterator it = m_data.begin() + dataOffset; |
339 | std::string result( it, it + size ); //copy vector content into result |
340 | |
341 | return result; |
342 | } |
343 | |
344 | /** |
345 | * @brief Get unsigned short data from raw exif data |
346 | * This is internal function and is not exposed to client |
347 | * @param [in] offset Offset to entry in bytes inside raw exif data |
348 | * @return Unsigned short data |
349 | */ |
350 | uint16_t ExifReader::getU16(const size_t offset) const |
351 | { |
352 | if (offset + 1 >= m_data.size()) |
353 | throw ExifParsingError(); |
354 | |
355 | if( m_format == INTEL ) |
356 | { |
357 | return m_data[offset] + ( m_data[offset + 1] << 8 ); |
358 | } |
359 | return ( m_data[offset] << 8 ) + m_data[offset + 1]; |
360 | } |
361 | |
362 | /** |
363 | * @brief Get unsigned 32-bit data from raw exif data |
364 | * This is internal function and is not exposed to client |
365 | * @param [in] offset Offset to entry in bytes inside raw exif data |
366 | * @return Unsigned 32-bit data |
367 | */ |
368 | uint32_t ExifReader::getU32(const size_t offset) const |
369 | { |
370 | if (offset + 3 >= m_data.size()) |
371 | throw ExifParsingError(); |
372 | |
373 | if( m_format == INTEL ) |
374 | { |
375 | return m_data[offset] + |
376 | ( m_data[offset + 1] << 8 ) + |
377 | ( m_data[offset + 2] << 16 ) + |
378 | ( m_data[offset + 3] << 24 ); |
379 | } |
380 | |
381 | return ( m_data[offset] << 24 ) + |
382 | ( m_data[offset + 1] << 16 ) + |
383 | ( m_data[offset + 2] << 8 ) + |
384 | m_data[offset + 3]; |
385 | } |
386 | |
387 | /** |
388 | * @brief Get unsigned rational data from raw exif data |
389 | * This is internal function and is not exposed to client |
390 | * @param [in] offset Offset to entry in bytes inside raw exif data |
391 | * @return Unsigned rational data |
392 | * |
393 | * "rational" means a fractional value, it contains 2 signed/unsigned long integer value, |
394 | * and the first represents the numerator, the second, the denominator. |
395 | */ |
396 | u_rational_t ExifReader::getURational(const size_t offset) const |
397 | { |
398 | uint32_t numerator = getU32( offset ); |
399 | uint32_t denominator = getU32( offset: offset + 4 ); |
400 | |
401 | return std::make_pair( x&: numerator, y&: denominator ); |
402 | |
403 | } |
404 | |
405 | /** |
406 | * @brief Get orientation information from raw exif data |
407 | * This is internal function and is not exposed to client |
408 | * @param [in] offset Offset to entry in bytes inside raw exif data |
409 | * @return orientation number |
410 | */ |
411 | uint16_t ExifReader::getOrientation(const size_t offset) const |
412 | { |
413 | return getU16( offset: offset + 8 ); |
414 | } |
415 | |
416 | /** |
417 | * @brief Get resolution information from raw exif data |
418 | * This is internal function and is not exposed to client |
419 | * @param [in] offset Offset to entry in bytes inside raw exif data |
420 | * @return resolution value |
421 | */ |
422 | std::vector<u_rational_t> ExifReader::getResolution(const size_t offset) const |
423 | { |
424 | std::vector<u_rational_t> result; |
425 | uint32_t rationalOffset = getU32( offset: offset + 8 ); |
426 | result.push_back( x: getURational( offset: rationalOffset ) ); |
427 | |
428 | return result; |
429 | } |
430 | |
431 | /** |
432 | * @brief Get resolution unit from raw exif data |
433 | * This is internal function and is not exposed to client |
434 | * @param [in] offset Offset to entry in bytes inside raw exif data |
435 | * @return resolution unit value |
436 | */ |
437 | uint16_t ExifReader::getResolutionUnit(const size_t offset) const |
438 | { |
439 | return getU16( offset: offset + 8 ); |
440 | } |
441 | |
442 | /** |
443 | * @brief Get White Point information from raw exif data |
444 | * This is internal function and is not exposed to client |
445 | * @param [in] offset Offset to entry in bytes inside raw exif data |
446 | * @return White Point value |
447 | * |
448 | * If the image uses CIE Standard Illumination D65(known as international |
449 | * standard of 'daylight'), the values are '3127/10000,3290/10000'. |
450 | */ |
451 | std::vector<u_rational_t> ExifReader::getWhitePoint(const size_t offset) const |
452 | { |
453 | std::vector<u_rational_t> result; |
454 | uint32_t rationalOffset = getU32( offset: offset + 8 ); |
455 | result.push_back( x: getURational( offset: rationalOffset ) ); |
456 | result.push_back( x: getURational( offset: rationalOffset + 8 ) ); |
457 | |
458 | return result; |
459 | } |
460 | |
461 | /** |
462 | * @brief Get Primary Chromaticies information from raw exif data |
463 | * This is internal function and is not exposed to client |
464 | * @param [in] offset Offset to entry in bytes inside raw exif data |
465 | * @return vector with primary chromaticies values |
466 | * |
467 | */ |
468 | std::vector<u_rational_t> ExifReader::getPrimaryChromaticies(const size_t offset) const |
469 | { |
470 | std::vector<u_rational_t> result; |
471 | uint32_t rationalOffset = getU32( offset: offset + 8 ); |
472 | for( size_t i = 0; i < primaryChromaticiesComponents; i++ ) |
473 | { |
474 | result.push_back( x: getURational( offset: rationalOffset ) ); |
475 | rationalOffset += 8; |
476 | } |
477 | return result; |
478 | } |
479 | |
480 | /** |
481 | * @brief Get YCbCr Coefficients information from raw exif data |
482 | * This is internal function and is not exposed to client |
483 | * @param [in] offset Offset to entry in bytes inside raw exif data |
484 | * @return vector with YCbCr coefficients values |
485 | * |
486 | */ |
487 | std::vector<u_rational_t> ExifReader::getYCbCrCoeffs(const size_t offset) const |
488 | { |
489 | std::vector<u_rational_t> result; |
490 | uint32_t rationalOffset = getU32( offset: offset + 8 ); |
491 | for( size_t i = 0; i < ycbcrCoeffs; i++ ) |
492 | { |
493 | result.push_back( x: getURational( offset: rationalOffset ) ); |
494 | rationalOffset += 8; |
495 | } |
496 | return result; |
497 | } |
498 | |
499 | /** |
500 | * @brief Get YCbCr Positioning information from raw exif data |
501 | * This is internal function and is not exposed to client |
502 | * @param [in] offset Offset to entry in bytes inside raw exif data |
503 | * @return vector with YCbCr positioning value |
504 | * |
505 | */ |
506 | uint16_t ExifReader::getYCbCrPos(const size_t offset) const |
507 | { |
508 | return getU16( offset: offset + 8 ); |
509 | } |
510 | |
511 | /** |
512 | * @brief Get Reference Black&White point information from raw exif data |
513 | * This is internal function and is not exposed to client |
514 | * @param [in] offset Offset to entry in bytes inside raw exif data |
515 | * @return vector with reference BW points |
516 | * |
517 | * In case of YCbCr format, first 2 show black/white of Y, next 2 are Cb, |
518 | * last 2 are Cr. In case of RGB format, first 2 show black/white of R, |
519 | * next 2 are G, last 2 are B. |
520 | * |
521 | */ |
522 | std::vector<u_rational_t> ExifReader::getRefBW(const size_t offset) const |
523 | { |
524 | const size_t rationalFieldSize = 8; |
525 | std::vector<u_rational_t> result; |
526 | uint32_t rationalOffset = getU32( offset: offset + rationalFieldSize ); |
527 | for( size_t i = 0; i < refBWComponents; i++ ) |
528 | { |
529 | result.push_back( x: getURational( offset: rationalOffset ) ); |
530 | rationalOffset += rationalFieldSize; |
531 | } |
532 | return result; |
533 | } |
534 | |
535 | } //namespace cv |
536 | |