/*M///////////////////////////////////////////////////////////////////////////////////////1//2// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.3//4// By downloading, copying, installing or using the software you agree to this license.5// If you do not agree to this license, do not download, install,6// copy or use the software.7//8//9// License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.13// Copyright (C) 2009, Willow Garage Inc., all rights reserved.14// Third party copyrights are property of their respective owners.15//16// Redistribution and use in source and binary forms, with or without modification,17// are permitted provided that the following conditions are met:18//19// * Redistribution's of source code must retain the above copyright notice,20// this list of conditions and the following disclaimer.21//22// * Redistribution's in binary form must reproduce the above copyright notice,23// this list of conditions and the following disclaimer in the documentation24// and/or other materials provided with the distribution.25//26// * The name of the copyright holders may not be used to endorse or promote products27// derived from this software without specific prior written permission.28//29// This software is provided by the copyright holders and contributors "as is" and30// any express or implied warranties, including, but not limited to, the implied31// warranties of merchantability and fitness for a particular purpose are disclaimed.32// In no event shall the Intel Corporation or contributors be liable for any direct,33// indirect, incidental, special, exemplary, or consequential damages34// (including, but not limited to, procurement of substitute goods or services;35// loss of use, data, or profits; or business interruption) however caused36// and on any theory of liability, whether in contract, strict liability,37// or tort (including negligence or otherwise) arising in any way out of38// the use of this software, even if advised of the possibility of such damage.39//40//M*/4142#include "precomp.hpp"43#include "exif.hpp"4445namespace {4647class ExifParsingError {48};49}505152namespace cv53{5455ExifEntry_t::ExifEntry_t() :56field_float(0), field_double(0), field_u32(0), field_s32(0),57tag(INVALID_TAG), field_u16(0), field_s16(0), field_u8(0), field_s8(0)58{59}6061/**62* @brief ExifReader constructor63*/64ExifReader::ExifReader(std::istream& stream) : m_stream(stream), m_format(NONE)65{66}6768/**69* @brief ExifReader destructor70*/71ExifReader::~ExifReader()72{73}7475/**76* @brief Parsing the file and prepare (internally) exif directory structure77* @return true if parsing was successful and exif information exists in JpegReader object78* false in case of unsuccessful parsing79*/80bool ExifReader::parse()81{82CV_TRY {83m_exif = getExif();84if( !m_exif.empty() )85{86return true;87}88return false;89} CV_CATCH (ExifParsingError, e) {90CV_UNUSED(e);91return false;92}93}949596/**97* @brief Get tag value by tag number98*99* @param [in] tag The tag number100*101* @return ExifEntru_t structure. Caller has to know what tag it calls in order to extract proper field from the structure ExifEntry_t102*103*/104ExifEntry_t ExifReader::getTag(const ExifTagName tag)105{106ExifEntry_t entry;107std::map<int, ExifEntry_t>::iterator it = m_exif.find(tag);108109if( it != m_exif.end() )110{111entry = it->second;112}113return entry;114}115116117/**118* @brief Get exif directory structure contained in file (if any)119* This is internal function and is not exposed to client120*121* @return Map where key is tag number and value is ExifEntry_t structure122*/123std::map<int, ExifEntry_t > ExifReader::getExif()124{125const std::streamsize markerSize = 2;126const std::streamsize offsetToTiffHeader = 6; //bytes from Exif size field to the first TIFF header127unsigned char appMarker[markerSize];128m_exif.erase( m_exif.begin(), m_exif.end() );129130std::streamsize count;131132bool exifFound = false, stopSearch = false;133while( ( !m_stream.eof() ) && !exifFound && !stopSearch )134{135m_stream.read( reinterpret_cast<char*>(appMarker), markerSize );136count = m_stream.gcount();137if( count < markerSize )138{139break;140}141unsigned char marker = appMarker[1];142size_t bytesToSkip;143size_t exifSize;144switch( marker )145{146//For all the markers just skip bytes in file pointed by followed two bytes (field size)147case SOF0: case SOF2: case DHT: case DQT: case DRI: case SOS:148case RST0: case RST1: case RST2: case RST3: case RST4: case RST5: case RST6: case RST7:149case APP0: case APP2: case APP3: case APP4: case APP5: case APP6: case APP7: case APP8:150case APP9: case APP10: case APP11: case APP12: case APP13: case APP14: case APP15:151case COM:152bytesToSkip = getFieldSize();153if (bytesToSkip < markerSize) {154CV_THROW (ExifParsingError());155}156m_stream.seekg( static_cast<long>( bytesToSkip - markerSize ), m_stream.cur );157if ( m_stream.fail() ) {158CV_THROW (ExifParsingError());159}160break;161162//SOI and EOI don't have the size field after the marker163case SOI: case EOI:164break;165166case APP1: //actual Exif Marker167exifSize = getFieldSize();168if (exifSize <= offsetToTiffHeader) {169CV_THROW (ExifParsingError());170}171m_data.resize( exifSize - offsetToTiffHeader );172m_stream.seekg( static_cast<long>( offsetToTiffHeader ), m_stream.cur );173if ( m_stream.fail() ) {174CV_THROW (ExifParsingError());175}176m_stream.read( reinterpret_cast<char*>(&m_data[0]), exifSize - offsetToTiffHeader );177exifFound = true;178break;179180default: //No other markers are expected according to standard. May be a signal of error181stopSearch = true;182break;183}184}185186if( !exifFound )187{188return m_exif;189}190191parseExif();192193return m_exif;194}195196/**197* @brief Get the size of exif field (required to properly ready whole exif from the file)198* This is internal function and is not exposed to client199*200* @return size of exif field in the file201*/202size_t ExifReader::getFieldSize ()203{204unsigned char fieldSize[2];205m_stream.read( reinterpret_cast<char*>(fieldSize), 2 );206std::streamsize count = m_stream.gcount();207if (count < 2)208{209return 0;210}211return ( fieldSize[0] << 8 ) + fieldSize[1];212}213214/**215* @brief Filling m_exif member with exif directory elements216* This is internal function and is not exposed to client217*218* @return The function doesn't return any value. In case of unsiccessful parsing219* the m_exif member is not filled up220*/221void ExifReader::parseExif()222{223m_format = getFormat();224225if( !checkTagMark() )226{227return;228}229230uint32_t offset = getStartOffset();231232size_t numEntry = getNumDirEntry();233234offset += 2; //go to start of tag fields235236for( size_t entry = 0; entry < numEntry; entry++ )237{238ExifEntry_t exifEntry = parseExifEntry( offset );239m_exif.insert( std::make_pair( exifEntry.tag, exifEntry ) );240offset += tiffFieldSize;241}242}243244/**245* @brief Get endianness of exif information246* This is internal function and is not exposed to client247*248* @return INTEL, MOTO or NONE249*/250Endianess_t ExifReader::getFormat() const251{252if (m_data.size() < 1)253return NONE;254255if( m_data.size() > 1 && m_data[0] != m_data[1] )256{257return NONE;258}259260if( m_data[0] == 'I' )261{262return INTEL;263}264265if( m_data[0] == 'M' )266{267return MOTO;268}269270return NONE;271}272273/**274* @brief Checking whether Tag Mark (0x002A) correspond to one contained in the Jpeg file275* This is internal function and is not exposed to client276*277* @return true if tag mark equals 0x002A, false otherwise278*/279bool ExifReader::checkTagMark() const280{281uint16_t tagMark = getU16( 2 );282283if( tagMark != tagMarkRequired )284{285return false;286}287return true;288}289290/**291* @brief The utility function for extracting actual offset exif IFD0 info is started from292* This is internal function and is not exposed to client293*294* @return offset of IFD0 field295*/296uint32_t ExifReader::getStartOffset() const297{298return getU32( 4 );299}300301/**302* @brief Get the number of Directory Entries in Jpeg file303*304* @return The number of directory entries305*/306size_t ExifReader::getNumDirEntry() const307{308return getU16( offsetNumDir );309}310311/**312* @brief Parsing particular entry in exif directory313* This is internal function and is not exposed to client314*315* Entries are divided into 12-bytes blocks each316* Each block corresponds the following structure:317*318* +------+-------------+-------------------+------------------------+319* | Type | Data format | Num of components | Data or offset to data |320* +======+=============+===================+========================+321* | TTTT | ffff | NNNNNNNN | DDDDDDDD |322* +------+-------------+-------------------+------------------------+323*324* Details can be found here: http://www.media.mit.edu/pia/Research/deepview/exif.html325*326* @param [in] offset Offset to entry in bytes inside raw exif data327* @return ExifEntry_t structure which corresponds to particular entry328*329*/330ExifEntry_t ExifReader::parseExifEntry(const size_t offset)331{332ExifEntry_t entry;333uint16_t tagNum = getExifTag( offset );334entry.tag = tagNum;335336switch( tagNum )337{338case IMAGE_DESCRIPTION:339entry.field_str = getString( offset );340break;341case MAKE:342entry.field_str = getString( offset );343break;344case MODEL:345entry.field_str = getString( offset );346break;347case ORIENTATION:348entry.field_u16 = getOrientation( offset );349break;350case XRESOLUTION:351entry.field_u_rational = getResolution( offset );352break;353case YRESOLUTION:354entry.field_u_rational = getResolution( offset );355break;356case RESOLUTION_UNIT:357entry.field_u16 = getResolutionUnit( offset );358break;359case SOFTWARE:360entry.field_str = getString( offset );361break;362case DATE_TIME:363entry.field_str = getString( offset );364break;365case WHITE_POINT:366entry.field_u_rational = getWhitePoint( offset );367break;368case PRIMARY_CHROMATICIES:369entry.field_u_rational = getPrimaryChromaticies( offset );370break;371case Y_CB_CR_COEFFICIENTS:372entry.field_u_rational = getYCbCrCoeffs( offset );373break;374case Y_CB_CR_POSITIONING:375entry.field_u16 = getYCbCrPos( offset );376break;377case REFERENCE_BLACK_WHITE:378entry.field_u_rational = getRefBW( offset );379break;380case COPYRIGHT:381entry.field_str = getString( offset );382break;383case EXIF_OFFSET:384break;385default:386entry.tag = INVALID_TAG;387break;388}389return entry;390}391392/**393* @brief Get tag number from raw exif data394* This is internal function and is not exposed to client395* @param [in] offset Offset to entry in bytes inside raw exif data396* @return tag number397*/398uint16_t ExifReader::getExifTag(const size_t offset) const399{400return getU16( offset );401}402403/**404* @brief Get string information from raw exif data405* This is internal function and is not exposed to client406* @param [in] offset Offset to entry in bytes inside raw exif data407* @return string value408*/409std::string ExifReader::getString(const size_t offset) const410{411size_t size = getU32( offset + 4 );412size_t dataOffset = 8; // position of data in the field413if( size > maxDataSize )414{415dataOffset = getU32( offset + 8 );416}417if (dataOffset > m_data.size() || dataOffset + size > m_data.size()) {418CV_THROW (ExifParsingError());419}420std::vector<uint8_t>::const_iterator it = m_data.begin() + dataOffset;421std::string result( it, it + size ); //copy vector content into result422423return result;424}425426/**427* @brief Get unsigned short data from raw exif data428* This is internal function and is not exposed to client429* @param [in] offset Offset to entry in bytes inside raw exif data430* @return Unsigned short data431*/432uint16_t ExifReader::getU16(const size_t offset) const433{434if (offset + 1 >= m_data.size())435CV_THROW (ExifParsingError());436437if( m_format == INTEL )438{439return m_data[offset] + ( m_data[offset + 1] << 8 );440}441return ( m_data[offset] << 8 ) + m_data[offset + 1];442}443444/**445* @brief Get unsigned 32-bit data from raw exif data446* This is internal function and is not exposed to client447* @param [in] offset Offset to entry in bytes inside raw exif data448* @return Unsigned 32-bit data449*/450uint32_t ExifReader::getU32(const size_t offset) const451{452if (offset + 3 >= m_data.size())453CV_THROW (ExifParsingError());454455if( m_format == INTEL )456{457return m_data[offset] +458( m_data[offset + 1] << 8 ) +459( m_data[offset + 2] << 16 ) +460( m_data[offset + 3] << 24 );461}462463return ( m_data[offset] << 24 ) +464( m_data[offset + 1] << 16 ) +465( m_data[offset + 2] << 8 ) +466m_data[offset + 3];467}468469/**470* @brief Get unsigned rational data from raw exif data471* This is internal function and is not exposed to client472* @param [in] offset Offset to entry in bytes inside raw exif data473* @return Unsigned rational data474*475* "rational" means a fractional value, it contains 2 signed/unsigned long integer value,476* and the first represents the numerator, the second, the denominator.477*/478u_rational_t ExifReader::getURational(const size_t offset) const479{480uint32_t numerator = getU32( offset );481uint32_t denominator = getU32( offset + 4 );482483return std::make_pair( numerator, denominator );484485}486487/**488* @brief Get orientation information from raw exif data489* This is internal function and is not exposed to client490* @param [in] offset Offset to entry in bytes inside raw exif data491* @return orientation number492*/493uint16_t ExifReader::getOrientation(const size_t offset) const494{495return getU16( offset + 8 );496}497498/**499* @brief Get resolution information from raw exif data500* This is internal function and is not exposed to client501* @param [in] offset Offset to entry in bytes inside raw exif data502* @return resolution value503*/504std::vector<u_rational_t> ExifReader::getResolution(const size_t offset) const505{506std::vector<u_rational_t> result;507uint32_t rationalOffset = getU32( offset + 8 );508result.push_back( getURational( rationalOffset ) );509510return result;511}512513/**514* @brief Get resolution unit from raw exif data515* This is internal function and is not exposed to client516* @param [in] offset Offset to entry in bytes inside raw exif data517* @return resolution unit value518*/519uint16_t ExifReader::getResolutionUnit(const size_t offset) const520{521return getU16( offset + 8 );522}523524/**525* @brief Get White Point information from raw exif data526* This is internal function and is not exposed to client527* @param [in] offset Offset to entry in bytes inside raw exif data528* @return White Point value529*530* If the image uses CIE Standard Illumination D65(known as international531* standard of 'daylight'), the values are '3127/10000,3290/10000'.532*/533std::vector<u_rational_t> ExifReader::getWhitePoint(const size_t offset) const534{535std::vector<u_rational_t> result;536uint32_t rationalOffset = getU32( offset + 8 );537result.push_back( getURational( rationalOffset ) );538result.push_back( getURational( rationalOffset + 8 ) );539540return result;541}542543/**544* @brief Get Primary Chromaticies information from raw exif data545* This is internal function and is not exposed to client546* @param [in] offset Offset to entry in bytes inside raw exif data547* @return vector with primary chromaticies values548*549*/550std::vector<u_rational_t> ExifReader::getPrimaryChromaticies(const size_t offset) const551{552std::vector<u_rational_t> result;553uint32_t rationalOffset = getU32( offset + 8 );554for( size_t i = 0; i < primaryChromaticiesComponents; i++ )555{556result.push_back( getURational( rationalOffset ) );557rationalOffset += 8;558}559return result;560}561562/**563* @brief Get YCbCr Coefficients information from raw exif data564* This is internal function and is not exposed to client565* @param [in] offset Offset to entry in bytes inside raw exif data566* @return vector with YCbCr coefficients values567*568*/569std::vector<u_rational_t> ExifReader::getYCbCrCoeffs(const size_t offset) const570{571std::vector<u_rational_t> result;572uint32_t rationalOffset = getU32( offset + 8 );573for( size_t i = 0; i < ycbcrCoeffs; i++ )574{575result.push_back( getURational( rationalOffset ) );576rationalOffset += 8;577}578return result;579}580581/**582* @brief Get YCbCr Positioning information from raw exif data583* This is internal function and is not exposed to client584* @param [in] offset Offset to entry in bytes inside raw exif data585* @return vector with YCbCr positioning value586*587*/588uint16_t ExifReader::getYCbCrPos(const size_t offset) const589{590return getU16( offset + 8 );591}592593/**594* @brief Get Reference Black&White point information from raw exif data595* This is internal function and is not exposed to client596* @param [in] offset Offset to entry in bytes inside raw exif data597* @return vector with reference BW points598*599* In case of YCbCr format, first 2 show black/white of Y, next 2 are Cb,600* last 2 are Cr. In case of RGB format, first 2 show black/white of R,601* next 2 are G, last 2 are B.602*603*/604std::vector<u_rational_t> ExifReader::getRefBW(const size_t offset) const605{606const size_t rationalFieldSize = 8;607std::vector<u_rational_t> result;608uint32_t rationalOffset = getU32( offset + rationalFieldSize );609for( size_t i = 0; i < refBWComponents; i++ )610{611result.push_back( getURational( rationalOffset ) );612rationalOffset += rationalFieldSize;613}614return result;615}616617} //namespace cv618619620