1 // This file is part of OpenMVG, an Open Multiple View Geometry C++ library.
2 
3 // Copyright (c) 2013-2015 Pierre MOULON.
4 
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9 #include "openMVG/exif/exif_IO_EasyExif.hpp"
10 
11 #include <fstream>
12 #include <limits>
13 #include <sstream>
14 #include <vector>
15 
16 #include "third_party/easyexif/exif.h"
17 
18 namespace openMVG
19 {
20 namespace exif
21 {
22 
23 /**
24 * Remove all leading and trailing spaces from the input. The result is a trimmed copy of the input
25 * @todo move this class elsewhere since it's not exif related
26 */
trim_copy(const std::string & s)27 inline std::string trim_copy( const std::string& s )
28 {
29   if (s.empty() )
30   {
31     return s;
32   }
33 
34   std::string res( s );
35   // remove leading and trailing spaces
36   res.erase( 0, res.find_first_not_of( ' ' ) );
37   res.erase( res.find_last_not_of( ' ' ) + 1 );
38   // handle multiple trailing end character
39   res = res.substr( 0, res.find( '\0' ) );
40   return res;
41 }
42 
43 class Exif_IO_EasyExif::EXIFInfoImpl {
44   easyexif::EXIFInfo exif_info;
45  public:
get()46   easyexif::EXIFInfo& get() {return exif_info;}
47 };
48 
Exif_IO_EasyExif()49 Exif_IO_EasyExif::Exif_IO_EasyExif():
50   bHaveExifInfo_( false ),
51   pimpl_(new Exif_IO_EasyExif::EXIFInfoImpl())
52 {
53 }
54 
Exif_IO_EasyExif(const std::string & sFileName)55 Exif_IO_EasyExif::Exif_IO_EasyExif( const std::string & sFileName ):
56   bHaveExifInfo_( false ),
57   pimpl_(new Exif_IO_EasyExif::EXIFInfoImpl())
58 {
59   open( sFileName );
60 }
61 
open(const std::string & sFileName)62 bool Exif_IO_EasyExif::open( const std::string & sFileName )
63 {
64   // Read the file into a buffer
65   FILE *fp = fopen( sFileName.c_str(), "rb" );
66   if ( !fp )
67   {
68     return false;
69   }
70   fseek( fp, 0, SEEK_END );
71   unsigned long fsize = ftell( fp );
72   rewind( fp );
73   std::vector<unsigned char> buf( fsize );
74   if ( fread( &buf[0], 1, fsize, fp ) != fsize )
75   {
76     fclose( fp );
77     return false;
78   }
79   fclose( fp );
80 
81   // Parse EXIF
82   bHaveExifInfo_ = ( (*pimpl_).get().parseFrom( &buf[0], fsize ) == PARSE_EXIF_SUCCESS );
83 
84   return bHaveExifInfo_;
85 }
86 
getWidth() const87 size_t Exif_IO_EasyExif::getWidth() const
88 {
89   return (*pimpl_).get().ImageWidth;
90 }
91 
getHeight() const92 size_t Exif_IO_EasyExif::getHeight() const
93 {
94   return (*pimpl_).get().ImageHeight;
95 }
96 
getFocal() const97 float Exif_IO_EasyExif::getFocal() const
98 {
99   return static_cast<float>( (*pimpl_).get().FocalLength );
100 }
101 
getFocalLengthIn35mm() const102 float Exif_IO_EasyExif::getFocalLengthIn35mm() const
103 {
104   return static_cast<float>( (*pimpl_).get().FocalLengthIn35mm );
105 }
106 
getFocalPlaneXResolution() const107 float Exif_IO_EasyExif::getFocalPlaneXResolution() const
108 {
109   return static_cast<float>( (*pimpl_).get().LensInfo.FocalPlaneXResolution );
110 }
111 
getFocalPlaneYResolution() const112 float Exif_IO_EasyExif::getFocalPlaneYResolution() const
113 {
114   return static_cast<float>( (*pimpl_).get().LensInfo.FocalPlaneYResolution );
115 }
116 
getFocalPlaneResolutionUnit() const117 int Exif_IO_EasyExif::getFocalPlaneResolutionUnit() const
118 {
119   return static_cast<int>( (*pimpl_).get().LensInfo.FocalPlaneResolutionUnit );
120 }
121 
getBrand() const122 std::string Exif_IO_EasyExif::getBrand() const
123 {
124   return trim_copy( (*pimpl_).get().Make );
125 }
126 
getModel() const127 std::string Exif_IO_EasyExif::getModel() const
128 {
129   return trim_copy( (*pimpl_).get().Model );
130 }
131 
getLensModel() const132 std::string Exif_IO_EasyExif::getLensModel() const
133 {
134   return trim_copy( (*pimpl_).get().LensInfo.Model );
135 }
136 
getImageUniqueID() const137 std::string Exif_IO_EasyExif::getImageUniqueID() const
138 {
139   return (*pimpl_).get().ImageUniqueID;
140 }
141 
doesHaveExifInfo() const142 bool Exif_IO_EasyExif::doesHaveExifInfo() const
143 {
144   return bHaveExifInfo_;
145 }
146 
allExifData() const147 std::string Exif_IO_EasyExif::allExifData() const
148 {
149   std::ostringstream os;
150   os
151       << "Camera make       : " << (*pimpl_).get().Make << "\n"
152       << "Camera model      : " << (*pimpl_).get().Model << "\n"
153       << "Software          : " << (*pimpl_).get().Software << "\n"
154       << "Bits per sample   : " << (*pimpl_).get().BitsPerSample << "\n"
155       << "Image width       : " << (*pimpl_).get().ImageWidth << "\n"
156       << "Image height      : " << (*pimpl_).get().ImageHeight << "\n"
157       << "Image description : " << (*pimpl_).get().ImageDescription << "\n"
158       << "Image orientation : " << (*pimpl_).get().Orientation << "\n"
159       << "Image copyright   : " << (*pimpl_).get().Copyright << "\n"
160       << "Image date/time   : " << (*pimpl_).get().DateTime << "\n"
161       << "Original date/time: " << (*pimpl_).get().DateTimeOriginal << "\n"
162       << "Digitize date/time: " << (*pimpl_).get().DateTimeDigitized << "\n"
163       << "Subsecond time    : " << (*pimpl_).get().SubSecTimeOriginal << "\n"
164       << "Exposure time     : 1/" << ( unsigned ) ( 1.0 / (*pimpl_).get().ExposureTime ) << "\n"
165       << "F-stop            : " << (*pimpl_).get().FNumber << "\n"
166       << "ISO speed         : " << (*pimpl_).get().ISOSpeedRatings << "\n"
167       << "Subject distance  : " << (*pimpl_).get().SubjectDistance << "\n"
168       << "Exposure bias     : EV" << (*pimpl_).get().ExposureBiasValue << "\n"
169       << "Flash used?       : " << (*pimpl_).get().Flash << "\n"
170       << "Metering mode     : " << (*pimpl_).get().MeteringMode << "\n"
171       << "Lens focal length : mm\n" << (*pimpl_).get().FocalLength << "\n"
172       << "35mm focal length : mm\n" << (*pimpl_).get().FocalLengthIn35mm << "\n"
173       << "GPS Latitude      : deg ( deg, min, sec )\n" << "("
174       <<  (*pimpl_).get().GeoLocation.Latitude << ", "
175       <<  (*pimpl_).get().GeoLocation.LatComponents.degrees << ", "
176       <<  (*pimpl_).get().GeoLocation.LatComponents.minutes << ", "
177       <<  (*pimpl_).get().GeoLocation.LatComponents.seconds << ", "
178       <<  (*pimpl_).get().GeoLocation.LatComponents.direction << ")" << "\n"
179       << "GPS Longitude      : deg ( deg, min, sec )\n" << "("
180       <<  (*pimpl_).get().GeoLocation.Longitude << ", "
181       <<  (*pimpl_).get().GeoLocation.LonComponents.degrees << ", "
182       <<  (*pimpl_).get().GeoLocation.LonComponents.minutes << ", "
183       <<  (*pimpl_).get().GeoLocation.LonComponents.seconds << ", "
184       <<  (*pimpl_).get().GeoLocation.LonComponents.direction << ")" << "\n"
185       << "GPS Altitude       : m" << (*pimpl_).get().GeoLocation.Altitude << "\n"
186       << "Lens stop (min, max) : " << "("
187       << (*pimpl_).get().LensInfo.FStopMin << ", "
188       << (*pimpl_).get().LensInfo.FStopMax << ")"
189       << "Lens focal (min, max) : " << "("
190       << (*pimpl_).get().LensInfo.FocalLengthMin << ", "
191       << (*pimpl_).get().LensInfo.FocalLengthMax << ")"
192       << "Lens make : " <<  (*pimpl_).get().LensInfo.Make << "\n"
193       << "Lens model : " << (*pimpl_).get().LensInfo.Model << "\n"
194       << "Image Unique ID    : " << (*pimpl_).get().ImageUniqueID << "\n";
195   return os.str();
196 }
197 
GPSLatitude(double * latitude) const198 bool Exif_IO_EasyExif::GPSLatitude(double * latitude) const
199 {
200   if ((*pimpl_).get().GeoLocation.Latitude != std::numeric_limits<double>::infinity())
201   {
202     (*latitude) = (*pimpl_).get().GeoLocation.Latitude;
203     return true;
204   }
205   return false;
206 }
207 
GPSLongitude(double * longitude) const208 bool Exif_IO_EasyExif::GPSLongitude(double * longitude) const
209 {
210   if ((*pimpl_).get().GeoLocation.Longitude != std::numeric_limits<double>::infinity())
211   {
212     (*longitude) = (*pimpl_).get().GeoLocation.Longitude;
213     return true;
214   }
215   return false;
216 }
217 
GPSAltitude(double * altitude) const218 bool Exif_IO_EasyExif::GPSAltitude(double * altitude) const
219 {
220   if ((*pimpl_).get().GeoLocation.Altitude != std::numeric_limits<double>::infinity())
221   {
222     (*altitude) = (*pimpl_).get().GeoLocation.Altitude;
223     return true;
224   }
225   return false;
226 }
227 
228 } // namespace exif
229 } // namespace openMVG
230