Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/imgcodecs/src/exif.cpp
16337 views
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(std::istream& stream) : m_stream(stream), m_format(NONE)
66
{
67
}
68
69
/**
70
* @brief ExifReader destructor
71
*/
72
ExifReader::~ExifReader()
73
{
74
}
75
76
/**
77
* @brief Parsing the file and prepare (internally) exif directory structure
78
* @return true if parsing was successful and exif information exists in JpegReader object
79
* false in case of unsuccessful parsing
80
*/
81
bool ExifReader::parse()
82
{
83
CV_TRY {
84
m_exif = getExif();
85
if( !m_exif.empty() )
86
{
87
return true;
88
}
89
return false;
90
} CV_CATCH (ExifParsingError, e) {
91
CV_UNUSED(e);
92
return false;
93
}
94
}
95
96
97
/**
98
* @brief Get tag value by tag number
99
*
100
* @param [in] tag The tag number
101
*
102
* @return ExifEntru_t structure. Caller has to know what tag it calls in order to extract proper field from the structure ExifEntry_t
103
*
104
*/
105
ExifEntry_t ExifReader::getTag(const ExifTagName tag)
106
{
107
ExifEntry_t entry;
108
std::map<int, ExifEntry_t>::iterator it = m_exif.find(tag);
109
110
if( it != m_exif.end() )
111
{
112
entry = it->second;
113
}
114
return entry;
115
}
116
117
118
/**
119
* @brief Get exif directory structure contained in file (if any)
120
* This is internal function and is not exposed to client
121
*
122
* @return Map where key is tag number and value is ExifEntry_t structure
123
*/
124
std::map<int, ExifEntry_t > ExifReader::getExif()
125
{
126
const std::streamsize markerSize = 2;
127
const std::streamsize offsetToTiffHeader = 6; //bytes from Exif size field to the first TIFF header
128
unsigned char appMarker[markerSize];
129
m_exif.erase( m_exif.begin(), m_exif.end() );
130
131
std::streamsize count;
132
133
bool exifFound = false, stopSearch = false;
134
while( ( !m_stream.eof() ) && !exifFound && !stopSearch )
135
{
136
m_stream.read( reinterpret_cast<char*>(appMarker), markerSize );
137
count = m_stream.gcount();
138
if( count < markerSize )
139
{
140
break;
141
}
142
unsigned char marker = appMarker[1];
143
size_t bytesToSkip;
144
size_t exifSize;
145
switch( marker )
146
{
147
//For all the markers just skip bytes in file pointed by followed two bytes (field size)
148
case SOF0: case SOF2: case DHT: case DQT: case DRI: case SOS:
149
case RST0: case RST1: case RST2: case RST3: case RST4: case RST5: case RST6: case RST7:
150
case APP0: case APP2: case APP3: case APP4: case APP5: case APP6: case APP7: case APP8:
151
case APP9: case APP10: case APP11: case APP12: case APP13: case APP14: case APP15:
152
case COM:
153
bytesToSkip = getFieldSize();
154
if (bytesToSkip < markerSize) {
155
CV_THROW (ExifParsingError());
156
}
157
m_stream.seekg( static_cast<long>( bytesToSkip - markerSize ), m_stream.cur );
158
if ( m_stream.fail() ) {
159
CV_THROW (ExifParsingError());
160
}
161
break;
162
163
//SOI and EOI don't have the size field after the marker
164
case SOI: case EOI:
165
break;
166
167
case APP1: //actual Exif Marker
168
exifSize = getFieldSize();
169
if (exifSize <= offsetToTiffHeader) {
170
CV_THROW (ExifParsingError());
171
}
172
m_data.resize( exifSize - offsetToTiffHeader );
173
m_stream.seekg( static_cast<long>( offsetToTiffHeader ), m_stream.cur );
174
if ( m_stream.fail() ) {
175
CV_THROW (ExifParsingError());
176
}
177
m_stream.read( reinterpret_cast<char*>(&m_data[0]), exifSize - offsetToTiffHeader );
178
exifFound = true;
179
break;
180
181
default: //No other markers are expected according to standard. May be a signal of error
182
stopSearch = true;
183
break;
184
}
185
}
186
187
if( !exifFound )
188
{
189
return m_exif;
190
}
191
192
parseExif();
193
194
return m_exif;
195
}
196
197
/**
198
* @brief Get the size of exif field (required to properly ready whole exif from the file)
199
* This is internal function and is not exposed to client
200
*
201
* @return size of exif field in the file
202
*/
203
size_t ExifReader::getFieldSize ()
204
{
205
unsigned char fieldSize[2];
206
m_stream.read( reinterpret_cast<char*>(fieldSize), 2 );
207
std::streamsize count = m_stream.gcount();
208
if (count < 2)
209
{
210
return 0;
211
}
212
return ( fieldSize[0] << 8 ) + fieldSize[1];
213
}
214
215
/**
216
* @brief Filling m_exif member with exif directory elements
217
* This is internal function and is not exposed to client
218
*
219
* @return The function doesn't return any value. In case of unsiccessful parsing
220
* the m_exif member is not filled up
221
*/
222
void ExifReader::parseExif()
223
{
224
m_format = getFormat();
225
226
if( !checkTagMark() )
227
{
228
return;
229
}
230
231
uint32_t offset = getStartOffset();
232
233
size_t numEntry = getNumDirEntry();
234
235
offset += 2; //go to start of tag fields
236
237
for( size_t entry = 0; entry < numEntry; entry++ )
238
{
239
ExifEntry_t exifEntry = parseExifEntry( offset );
240
m_exif.insert( std::make_pair( exifEntry.tag, exifEntry ) );
241
offset += tiffFieldSize;
242
}
243
}
244
245
/**
246
* @brief Get endianness of exif information
247
* This is internal function and is not exposed to client
248
*
249
* @return INTEL, MOTO or NONE
250
*/
251
Endianess_t ExifReader::getFormat() const
252
{
253
if (m_data.size() < 1)
254
return NONE;
255
256
if( m_data.size() > 1 && m_data[0] != m_data[1] )
257
{
258
return NONE;
259
}
260
261
if( m_data[0] == 'I' )
262
{
263
return INTEL;
264
}
265
266
if( m_data[0] == 'M' )
267
{
268
return MOTO;
269
}
270
271
return NONE;
272
}
273
274
/**
275
* @brief Checking whether Tag Mark (0x002A) correspond to one contained in the Jpeg file
276
* This is internal function and is not exposed to client
277
*
278
* @return true if tag mark equals 0x002A, false otherwise
279
*/
280
bool ExifReader::checkTagMark() const
281
{
282
uint16_t tagMark = getU16( 2 );
283
284
if( tagMark != tagMarkRequired )
285
{
286
return false;
287
}
288
return true;
289
}
290
291
/**
292
* @brief The utility function for extracting actual offset exif IFD0 info is started from
293
* This is internal function and is not exposed to client
294
*
295
* @return offset of IFD0 field
296
*/
297
uint32_t ExifReader::getStartOffset() const
298
{
299
return getU32( 4 );
300
}
301
302
/**
303
* @brief Get the number of Directory Entries in Jpeg file
304
*
305
* @return The number of directory entries
306
*/
307
size_t ExifReader::getNumDirEntry() const
308
{
309
return getU16( offsetNumDir );
310
}
311
312
/**
313
* @brief Parsing particular entry in exif directory
314
* This is internal function and is not exposed to client
315
*
316
* Entries are divided into 12-bytes blocks each
317
* Each block corresponds the following structure:
318
*
319
* +------+-------------+-------------------+------------------------+
320
* | Type | Data format | Num of components | Data or offset to data |
321
* +======+=============+===================+========================+
322
* | TTTT | ffff | NNNNNNNN | DDDDDDDD |
323
* +------+-------------+-------------------+------------------------+
324
*
325
* Details can be found here: http://www.media.mit.edu/pia/Research/deepview/exif.html
326
*
327
* @param [in] offset Offset to entry in bytes inside raw exif data
328
* @return ExifEntry_t structure which corresponds to particular entry
329
*
330
*/
331
ExifEntry_t ExifReader::parseExifEntry(const size_t offset)
332
{
333
ExifEntry_t entry;
334
uint16_t tagNum = getExifTag( offset );
335
entry.tag = tagNum;
336
337
switch( tagNum )
338
{
339
case IMAGE_DESCRIPTION:
340
entry.field_str = getString( offset );
341
break;
342
case MAKE:
343
entry.field_str = getString( offset );
344
break;
345
case MODEL:
346
entry.field_str = getString( offset );
347
break;
348
case ORIENTATION:
349
entry.field_u16 = getOrientation( offset );
350
break;
351
case XRESOLUTION:
352
entry.field_u_rational = getResolution( offset );
353
break;
354
case YRESOLUTION:
355
entry.field_u_rational = getResolution( offset );
356
break;
357
case RESOLUTION_UNIT:
358
entry.field_u16 = getResolutionUnit( offset );
359
break;
360
case SOFTWARE:
361
entry.field_str = getString( offset );
362
break;
363
case DATE_TIME:
364
entry.field_str = getString( offset );
365
break;
366
case WHITE_POINT:
367
entry.field_u_rational = getWhitePoint( offset );
368
break;
369
case PRIMARY_CHROMATICIES:
370
entry.field_u_rational = getPrimaryChromaticies( offset );
371
break;
372
case Y_CB_CR_COEFFICIENTS:
373
entry.field_u_rational = getYCbCrCoeffs( offset );
374
break;
375
case Y_CB_CR_POSITIONING:
376
entry.field_u16 = getYCbCrPos( offset );
377
break;
378
case REFERENCE_BLACK_WHITE:
379
entry.field_u_rational = getRefBW( offset );
380
break;
381
case COPYRIGHT:
382
entry.field_str = getString( offset );
383
break;
384
case EXIF_OFFSET:
385
break;
386
default:
387
entry.tag = INVALID_TAG;
388
break;
389
}
390
return entry;
391
}
392
393
/**
394
* @brief Get tag number from raw exif data
395
* This is internal function and is not exposed to client
396
* @param [in] offset Offset to entry in bytes inside raw exif data
397
* @return tag number
398
*/
399
uint16_t ExifReader::getExifTag(const size_t offset) const
400
{
401
return getU16( offset );
402
}
403
404
/**
405
* @brief Get string information from raw exif data
406
* This is internal function and is not exposed to client
407
* @param [in] offset Offset to entry in bytes inside raw exif data
408
* @return string value
409
*/
410
std::string ExifReader::getString(const size_t offset) const
411
{
412
size_t size = getU32( offset + 4 );
413
size_t dataOffset = 8; // position of data in the field
414
if( size > maxDataSize )
415
{
416
dataOffset = getU32( offset + 8 );
417
}
418
if (dataOffset > m_data.size() || dataOffset + size > m_data.size()) {
419
CV_THROW (ExifParsingError());
420
}
421
std::vector<uint8_t>::const_iterator it = m_data.begin() + dataOffset;
422
std::string result( it, it + size ); //copy vector content into result
423
424
return result;
425
}
426
427
/**
428
* @brief Get unsigned short data from raw exif data
429
* This is internal function and is not exposed to client
430
* @param [in] offset Offset to entry in bytes inside raw exif data
431
* @return Unsigned short data
432
*/
433
uint16_t ExifReader::getU16(const size_t offset) const
434
{
435
if (offset + 1 >= m_data.size())
436
CV_THROW (ExifParsingError());
437
438
if( m_format == INTEL )
439
{
440
return m_data[offset] + ( m_data[offset + 1] << 8 );
441
}
442
return ( m_data[offset] << 8 ) + m_data[offset + 1];
443
}
444
445
/**
446
* @brief Get unsigned 32-bit data from raw exif data
447
* This is internal function and is not exposed to client
448
* @param [in] offset Offset to entry in bytes inside raw exif data
449
* @return Unsigned 32-bit data
450
*/
451
uint32_t ExifReader::getU32(const size_t offset) const
452
{
453
if (offset + 3 >= m_data.size())
454
CV_THROW (ExifParsingError());
455
456
if( m_format == INTEL )
457
{
458
return m_data[offset] +
459
( m_data[offset + 1] << 8 ) +
460
( m_data[offset + 2] << 16 ) +
461
( m_data[offset + 3] << 24 );
462
}
463
464
return ( m_data[offset] << 24 ) +
465
( m_data[offset + 1] << 16 ) +
466
( m_data[offset + 2] << 8 ) +
467
m_data[offset + 3];
468
}
469
470
/**
471
* @brief Get unsigned rational data from raw exif data
472
* This is internal function and is not exposed to client
473
* @param [in] offset Offset to entry in bytes inside raw exif data
474
* @return Unsigned rational data
475
*
476
* "rational" means a fractional value, it contains 2 signed/unsigned long integer value,
477
* and the first represents the numerator, the second, the denominator.
478
*/
479
u_rational_t ExifReader::getURational(const size_t offset) const
480
{
481
uint32_t numerator = getU32( offset );
482
uint32_t denominator = getU32( offset + 4 );
483
484
return std::make_pair( numerator, denominator );
485
486
}
487
488
/**
489
* @brief Get orientation information from raw exif data
490
* This is internal function and is not exposed to client
491
* @param [in] offset Offset to entry in bytes inside raw exif data
492
* @return orientation number
493
*/
494
uint16_t ExifReader::getOrientation(const size_t offset) const
495
{
496
return getU16( offset + 8 );
497
}
498
499
/**
500
* @brief Get resolution 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 resolution value
504
*/
505
std::vector<u_rational_t> ExifReader::getResolution(const size_t offset) const
506
{
507
std::vector<u_rational_t> result;
508
uint32_t rationalOffset = getU32( offset + 8 );
509
result.push_back( getURational( rationalOffset ) );
510
511
return result;
512
}
513
514
/**
515
* @brief Get resolution unit from raw exif data
516
* This is internal function and is not exposed to client
517
* @param [in] offset Offset to entry in bytes inside raw exif data
518
* @return resolution unit value
519
*/
520
uint16_t ExifReader::getResolutionUnit(const size_t offset) const
521
{
522
return getU16( offset + 8 );
523
}
524
525
/**
526
* @brief Get White Point information from raw exif data
527
* This is internal function and is not exposed to client
528
* @param [in] offset Offset to entry in bytes inside raw exif data
529
* @return White Point value
530
*
531
* If the image uses CIE Standard Illumination D65(known as international
532
* standard of 'daylight'), the values are '3127/10000,3290/10000'.
533
*/
534
std::vector<u_rational_t> ExifReader::getWhitePoint(const size_t offset) const
535
{
536
std::vector<u_rational_t> result;
537
uint32_t rationalOffset = getU32( offset + 8 );
538
result.push_back( getURational( rationalOffset ) );
539
result.push_back( getURational( rationalOffset + 8 ) );
540
541
return result;
542
}
543
544
/**
545
* @brief Get Primary Chromaticies information from raw exif data
546
* This is internal function and is not exposed to client
547
* @param [in] offset Offset to entry in bytes inside raw exif data
548
* @return vector with primary chromaticies values
549
*
550
*/
551
std::vector<u_rational_t> ExifReader::getPrimaryChromaticies(const size_t offset) const
552
{
553
std::vector<u_rational_t> result;
554
uint32_t rationalOffset = getU32( offset + 8 );
555
for( size_t i = 0; i < primaryChromaticiesComponents; i++ )
556
{
557
result.push_back( getURational( rationalOffset ) );
558
rationalOffset += 8;
559
}
560
return result;
561
}
562
563
/**
564
* @brief Get YCbCr Coefficients information from raw exif data
565
* This is internal function and is not exposed to client
566
* @param [in] offset Offset to entry in bytes inside raw exif data
567
* @return vector with YCbCr coefficients values
568
*
569
*/
570
std::vector<u_rational_t> ExifReader::getYCbCrCoeffs(const size_t offset) const
571
{
572
std::vector<u_rational_t> result;
573
uint32_t rationalOffset = getU32( offset + 8 );
574
for( size_t i = 0; i < ycbcrCoeffs; i++ )
575
{
576
result.push_back( getURational( rationalOffset ) );
577
rationalOffset += 8;
578
}
579
return result;
580
}
581
582
/**
583
* @brief Get YCbCr Positioning information from raw exif data
584
* This is internal function and is not exposed to client
585
* @param [in] offset Offset to entry in bytes inside raw exif data
586
* @return vector with YCbCr positioning value
587
*
588
*/
589
uint16_t ExifReader::getYCbCrPos(const size_t offset) const
590
{
591
return getU16( offset + 8 );
592
}
593
594
/**
595
* @brief Get Reference Black&White point information from raw exif data
596
* This is internal function and is not exposed to client
597
* @param [in] offset Offset to entry in bytes inside raw exif data
598
* @return vector with reference BW points
599
*
600
* In case of YCbCr format, first 2 show black/white of Y, next 2 are Cb,
601
* last 2 are Cr. In case of RGB format, first 2 show black/white of R,
602
* next 2 are G, last 2 are B.
603
*
604
*/
605
std::vector<u_rational_t> ExifReader::getRefBW(const size_t offset) const
606
{
607
const size_t rationalFieldSize = 8;
608
std::vector<u_rational_t> result;
609
uint32_t rationalOffset = getU32( offset + rationalFieldSize );
610
for( size_t i = 0; i < refBWComponents; i++ )
611
{
612
result.push_back( getURational( rationalOffset ) );
613
rationalOffset += rationalFieldSize;
614
}
615
return result;
616
}
617
618
} //namespace cv
619
620