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