| 1 | /*  |
| 2 | TinyEXIF.h -- A simple ISO C++ library to parse basic EXIF and XMP  |
| 3 | information from a JPEG file.  |
| 4 |   |
| 5 | Copyright (c) 2015-2017 Seacave  |
| 6 | cdc.seacave@gmail.com  |
| 7 | All rights reserved.  |
| 8 |   |
| 9 | Based on the easyexif library (2013 version)  |
| 10 | https://github.com/mayanklahiri/easyexif  |
| 11 | of Mayank Lahiri (mlahiri@gmail.com).  |
| 12 |   |
| 13 | Redistribution and use in source and binary forms, with or without   |
| 14 | modification, are permitted provided that the following conditions are met:  |
| 15 |   |
| 16 | - Redistributions of source code must retain the above copyright notice,   |
| 17 | this list of conditions and the following disclaimer.  |
| 18 | - Redistributions in binary form must reproduce the above copyright notice,   |
| 19 | this list of conditions and the following disclaimer in the documentation   |
| 20 | and/or other materials provided with the distribution.  |
| 21 |   |
| 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS   |
| 23 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES   |
| 24 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN   |
| 25 | NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,   |
| 26 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,   |
| 27 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,   |
| 28 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY   |
| 29 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING   |
| 30 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,   |
| 31 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  |
| 32 | */  |
| 33 |   |
| 34 | #ifndef __TINYEXIF_H__  |
| 35 | #define __TINYEXIF_H__  |
| 36 |   |
| 37 | #include <cstdint>  |
| 38 | #include <string>  |
| 39 | #include <vector>  |
| 40 |   |
| 41 | #define TINYEXIF_MAJOR_VERSION 1  |
| 42 | #define TINYEXIF_MINOR_VERSION 0  |
| 43 | #define TINYEXIF_PATCH_VERSION 1  |
| 44 |   |
| 45 | #ifdef _MSC_VER  |
| 46 | # ifdef TINYEXIF_EXPORT  |
| 47 | # define TINYEXIF_LIB __declspec(dllexport)  |
| 48 | # elif defined(TINYEXIF_IMPORT)  |
| 49 | # define TINYEXIF_LIB __declspec(dllimport)  |
| 50 | # else  |
| 51 | # define TINYEXIF_LIB  |
| 52 | # endif  |
| 53 | #elif __GNUC__ >= 4  |
| 54 | # define TINYEXIF_LIB __attribute__((visibility("default")))  |
| 55 | #else  |
| 56 | # define TINYEXIF_LIB  |
| 57 | #endif  |
| 58 |   |
| 59 | namespace TinyEXIF {  |
| 60 |   |
| 61 | enum ErrorCode {  |
| 62 | PARSE_SUCCESS = 0, // Parse EXIF and/or XMP was successful  |
| 63 | PARSE_INVALID_JPEG = 1, // No JPEG markers found in buffer, possibly invalid JPEG file  |
| 64 | PARSE_UNKNOWN_BYTEALIGN = 2, // Byte alignment specified in EXIF file was unknown (neither Motorola nor Intel)  |
| 65 | PARSE_ABSENT_DATA = 3, // No EXIF and/or XMP data found in JPEG file  |
| 66 | PARSE_CORRUPT_DATA = 4, // EXIF and/or XMP header was found, but data was corrupted  |
| 67 | };  |
| 68 |   |
| 69 | enum FieldCode {  |
| 70 | FIELD_NA = 0, // No EXIF or XMP data  |
| 71 | FIELD_EXIF = (1 << 0), // EXIF data available  |
| 72 | FIELD_XMP = (1 << 1), // XMP data available  |
| 73 | FIELD_ALL = FIELD_EXIF|FIELD_XMP  |
| 74 | };  |
| 75 |   |
| 76 | class EntryParser;  |
| 77 |   |
| 78 | //  |
| 79 | // Interface class responsible for fetching stream data to be parsed  |
| 80 | //  |
| 81 | class TINYEXIF_LIB EXIFStream {  |
| 82 | public:  |
| 83 | virtual ~EXIFStream() {}  |
| 84 |   |
| 85 | // Check the state of the stream.  |
| 86 | virtual bool IsValid() const = 0;  |
| 87 |   |
| 88 | // Return the pointer to the beginning of the desired size buffer  |
| 89 | // following current buffer position.  |
| 90 | virtual const uint8_t* GetBuffer(unsigned desiredLength) = 0;  |
| 91 |   |
| 92 | // Advance current buffer position with the desired size;  |
| 93 | // return false if stream ends in less than the desired size.  |
| 94 | virtual bool SkipBuffer(unsigned desiredLength) = 0;  |
| 95 | };  |
| 96 |   |
| 97 | //  |
| 98 | // Class responsible for storing and parsing EXIF & XMP metadata from a JPEG stream  |
| 99 | //  |
| 100 | class TINYEXIF_LIB EXIFInfo {  |
| 101 | public:  |
| 102 | EXIFInfo();  |
| 103 | EXIFInfo(EXIFStream& stream);  |
| 104 | EXIFInfo(std::istream& stream); // NB: the stream must have been opened in binary mode  |
| 105 | EXIFInfo(const uint8_t* data, unsigned length);  |
| 106 |   |
| 107 | // Parsing function for an entire JPEG image stream.  |
| 108 | //  |
| 109 | // PARAM 'stream': Interface to fetch JPEG image stream.  |
| 110 | // PARAM 'data': A pointer to a JPEG image.  |
| 111 | // PARAM 'length': The length of the JPEG image.  |
| 112 | // RETURN: PARSE_SUCCESS (0) on success with 'result' filled out  |
| 113 | // error code otherwise, as defined by the PARSE_* macros  |
| 114 | int parseFrom(EXIFStream& stream);  |
| 115 | int parseFrom(std::istream& stream); // NB: the stream must have been opened in binary mode  |
| 116 | int parseFrom(const uint8_t* data, unsigned length);  |
| 117 |   |
| 118 | // Parsing function for an EXIF segment. This is used internally by parseFrom()  |
| 119 | // but can be called for special cases where only the EXIF section is   |
| 120 | // available (i.e., a blob starting with the bytes "Exif\0\0").  |
| 121 | int parseFromEXIFSegment(const uint8_t* buf, unsigned len);  |
| 122 |   |
| 123 | #ifndef TINYEXIF_NO_XMP_SUPPORT  |
| 124 | // Parsing function for an XMP segment. This is used internally by parseFrom()  |
| 125 | // but can be called for special cases where only the XMP section is   |
| 126 | // available (i.e., a blob starting with the bytes "http://ns.adobe.com/xap/1.0/\0").  |
| 127 | int parseFromXMPSegment(const uint8_t* buf, unsigned len);  |
| 128 | int parseFromXMPSegmentXML(const char* szXML, unsigned len);  |
| 129 | #endif // TINYEXIF_NO_XMP_SUPPORT  |
| 130 |   |
| 131 | // Set all data members to default values.  |
| 132 | // Should be called before parsing a new stream.  |
| 133 | void clear();  |
| 134 |   |
| 135 | private:  |
| 136 | // Parse tag as Image IFD.  |
| 137 | void parseIFDImage(EntryParser&, unsigned&, unsigned&);  |
| 138 | // Parse tag as Exif IFD.  |
| 139 | void parseIFDExif(EntryParser&);  |
| 140 | // Parse tag as GPS IFD.  |
| 141 | void parseIFDGPS(EntryParser&);  |
| 142 | // Parse tag as MakerNote IFD.  |
| 143 | void parseIFDMakerNote(EntryParser&);  |
| 144 |   |
| 145 | public:  |
| 146 | // Data fields  |
| 147 | uint32_t Fields; // Store if EXIF and/or XMP data fields are available  |
| 148 | uint32_t ImageWidth; // Image width reported in EXIF data  |
| 149 | uint32_t ImageHeight; // Image height reported in EXIF data  |
| 150 | uint32_t RelatedImageWidth; // Original image width reported in EXIF data  |
| 151 | uint32_t RelatedImageHeight; // Original image height reported in EXIF data  |
| 152 | std::string ImageDescription; // Image description  |
| 153 | std::string Make; // Camera manufacturer's name  |
| 154 | std::string Model; // Camera model  |
| 155 | std::string SerialNumber; // Serial number of the body of the camera  |
| 156 | uint16_t Orientation; // Image orientation, start of data corresponds to  |
| 157 | // 0: unspecified in EXIF data  |
| 158 | // 1: upper left of image  |
| 159 | // 3: lower right of image  |
| 160 | // 6: upper right of image  |
| 161 | // 8: lower left of image  |
| 162 | // 9: undefined  |
| 163 | double XResolution; // Number of pixels per ResolutionUnit in the ImageWidth direction  |
| 164 | double YResolution; // Number of pixels per ResolutionUnit in the ImageLength direction  |
| 165 | uint16_t ResolutionUnit; // Unit of measurement for XResolution and YResolution  |
| 166 | // 1: no absolute unit of measurement. Used for images that may have a non-square aspect ratio, but no meaningful absolute dimensions  |
| 167 | // 2: inch  |
| 168 | // 3: centimeter  |
| 169 | uint16_t BitsPerSample; // Number of bits per component  |
| 170 | std::string Software; // Software used  |
| 171 | std::string DateTime; // File change date and time  |
| 172 | std::string DateTimeOriginal; // Original file date and time (may not exist)  |
| 173 | std::string DateTimeDigitized; // Digitization date and time (may not exist)  |
| 174 | std::string SubSecTimeOriginal; // Sub-second time that original picture was taken  |
| 175 | std::string Copyright; // File copyright information  |
| 176 | double ExposureTime; // Exposure time in seconds  |
| 177 | double FNumber; // F/stop  |
| 178 | uint16_t ExposureProgram; // Exposure program  |
| 179 | // 0: not defined  |
| 180 | // 1: manual  |
| 181 | // 2: normal program  |
| 182 | // 3: aperture priority  |
| 183 | // 4: shutter priority  |
| 184 | // 5: creative program  |
| 185 | // 6: action program  |
| 186 | // 7: portrait mode  |
| 187 | // 8: landscape mode  |
| 188 | uint16_t ISOSpeedRatings; // ISO speed  |
| 189 | double ShutterSpeedValue; // Shutter speed (reciprocal of exposure time)  |
| 190 | double ApertureValue; // The lens aperture  |
| 191 | double BrightnessValue; // The value of brightness  |
| 192 | double ExposureBiasValue; // Exposure bias value in EV  |
| 193 | double SubjectDistance; // Distance to focus point in meters  |
| 194 | double FocalLength; // Focal length of lens in millimeters  |
| 195 | uint16_t Flash; // Flash info  |
| 196 | // Flash used (Flash&1)  |
| 197 | // 0: no flash, >0: flash used  |
| 198 | // Flash returned light status ((Flash & 6) >> 1)  |
| 199 | // 0: no strobe return detection function  |
| 200 | // 1: reserved  |
| 201 | // 2: strobe return light not detected  |
| 202 | // 3: strobe return light detected  |
| 203 | // Flash mode ((Flash & 24) >> 3)  |
| 204 | // 0: unknown  |
| 205 | // 1: compulsory flash firing  |
| 206 | // 2: compulsory flash suppression  |
| 207 | // 3: auto mode  |
| 208 | // Flash function ((Flash & 32) >> 5)  |
| 209 | // 0: flash function present, >0: no flash function  |
| 210 | // Flash red-eye ((Flash & 64) >> 6)  |
| 211 | // 0: no red-eye reduction mode or unknown, >0: red-eye reduction supported  |
| 212 | uint16_t MeteringMode; // Metering mode  |
| 213 | // 0: unknown  |
| 214 | // 1: average  |
| 215 | // 2: center weighted average  |
| 216 | // 3: spot  |
| 217 | // 4: multi-spot  |
| 218 | // 5: pattern  |
| 219 | // 6: partial  |
| 220 | uint16_t LightSource; // Kind of light source  |
| 221 | // 0: unknown  |
| 222 | // 1: daylight  |
| 223 | // 2: fluorescent  |
| 224 | // 3: tungsten (incandescent light)  |
| 225 | // 4: flash  |
| 226 | // 9: fine weather  |
| 227 | // 10: cloudy weather  |
| 228 | // 11: shade  |
| 229 | // 12: daylight fluorescent (D 5700 - 7100K)  |
| 230 | // 13: day white fluorescent (N 4600 - 5400K)  |
| 231 | // 14: cool white fluorescent (W 3900 - 4500K)  |
| 232 | // 15: white fluorescent (WW 3200 - 3700K)  |
| 233 | // 17: standard light A  |
| 234 | // 18: standard light B  |
| 235 | // 19: standard light C  |
| 236 | // 20: D55  |
| 237 | // 21: D65  |
| 238 | // 22: D75  |
| 239 | // 23: D50  |
| 240 | // 24: ISO studio tungsten  |
| 241 | uint16_t ProjectionType; // Projection type  |
| 242 | // 0: unknown projection  |
| 243 | // 1: perspective projection  |
| 244 | // 2: equirectangular/spherical projection  |
| 245 | std::vector<uint16_t> SubjectArea; // Location and area of the main subject in the overall scene expressed in relation to the upper left as origin, prior to rotation  |
| 246 | // 0: unknown  |
| 247 | // 2: location of the main subject as coordinates (first value is the X coordinate and second is the Y coordinate)  |
| 248 | // 3: area of the main subject as a circle (first value is the center X coordinate, second is the center Y coordinate, and third is the diameter)  |
| 249 | // 4: area of the main subject as a rectangle (first value is the center X coordinate, second is the center Y coordinate, third is the width of the area, and fourth is the height of the area)  |
| 250 | struct TINYEXIF_LIB Calibration_t { // Camera calibration information  |
| 251 | double FocalLength; // Focal length (pixels)  |
| 252 | double OpticalCenterX; // Principal point X (pixels)  |
| 253 | double OpticalCenterY; // Principal point Y (pixels)  |
| 254 | } Calibration;  |
| 255 | struct TINYEXIF_LIB LensInfo_t { // Lens information  |
| 256 | double FStopMin; // Min aperture (f-stop)  |
| 257 | double FStopMax; // Max aperture (f-stop)  |
| 258 | double FocalLengthMin; // Min focal length (mm)  |
| 259 | double FocalLengthMax; // Max focal length (mm)  |
| 260 | double DigitalZoomRatio; // Digital zoom ratio when the image was shot  |
| 261 | double FocalLengthIn35mm; // Focal length in 35mm film  |
| 262 | double FocalPlaneXResolution; // Number of pixels in the image width (X) direction per FocalPlaneResolutionUnit on the camera focal plane (may not exist)  |
| 263 | double FocalPlaneYResolution; // Number of pixels in the image width (Y) direction per FocalPlaneResolutionUnit on the camera focal plane (may not exist)  |
| 264 | uint16_t FocalPlaneResolutionUnit;// Unit for measuring FocalPlaneXResolution and FocalPlaneYResolution (may not exist)  |
| 265 | // 0: unspecified in EXIF data  |
| 266 | // 1: no absolute unit of measurement  |
| 267 | // 2: inch  |
| 268 | // 3: centimeter  |
| 269 | std::string Make; // Lens manufacturer  |
| 270 | std::string Model; // Lens model  |
| 271 | } LensInfo;  |
| 272 | struct TINYEXIF_LIB Geolocation_t { // GPS information embedded in file  |
| 273 | double Latitude; // Image latitude expressed as decimal  |
| 274 | double Longitude; // Image longitude expressed as decimal  |
| 275 | double Altitude; // Altitude in meters, relative to sea level  |
| 276 | int8_t AltitudeRef; // 0: above sea level, -1: below sea level  |
| 277 | double RelativeAltitude; // Relative altitude in meters  |
| 278 | double RollDegree; // Flight roll in degrees  |
| 279 | double PitchDegree; // Flight pitch in degrees  |
| 280 | double YawDegree; // Flight yaw in degrees  |
| 281 | double SpeedX; // Flight speed on X in meters/second  |
| 282 | double SpeedY; // Flight speed on Y in meters/second  |
| 283 | double SpeedZ; // Flight speed on Z in meters/second  |
| 284 | double AccuracyXY; // GPS accuracy on XY in meters  |
| 285 | double AccuracyZ; // GPS accuracy on Z in meters  |
| 286 | double GPSDOP; // GPS DOP (data degree of precision)  |
| 287 | uint16_t GPSDifferential; // Differential correction applied to the GPS receiver (may not exist)  |
| 288 | // 0: measurement without differential correction  |
| 289 | // 1: differential correction applied   |
| 290 | std::string GPSMapDatum; // Geodetic survey data (may not exist)  |
| 291 | std::string GPSTimeStamp; // Time as UTC (Coordinated Universal Time) (may not exist)  |
| 292 | std::string GPSDateStamp; // A character string recording date and time information relative to UTC (Coordinated Universal Time) YYYY:MM:DD (may not exist)  |
| 293 | struct Coord_t {  |
| 294 | double degrees;  |
| 295 | double minutes;  |
| 296 | double seconds;  |
| 297 | uint8_t direction;  |
| 298 | } LatComponents, LonComponents; // Latitude/Longitude expressed in deg/min/sec  |
| 299 | void parseCoords(); // Convert Latitude/Longitude from deg/min/sec to decimal  |
| 300 | bool hasLatLon() const; // Return true if (lat,lon) is available  |
| 301 | bool hasAltitude() const; // Return true if (alt) is available  |
| 302 | bool hasRelativeAltitude()const;// Return true if (rel_alt) is available  |
| 303 | bool hasOrientation() const; // Return true if (roll,yaw,pitch) is available  |
| 304 | bool hasSpeed() const; // Return true if (speedX,speedY,speedZ) is available  |
| 305 | } GeoLocation;  |
| 306 | struct TINYEXIF_LIB GPano_t { // Spherical metadata. https://developers.google.com/streetview/spherical-metadata  |
| 307 | double PosePitchDegrees; // Pitch, measured in degrees above the horizon, for the center in the image. Value must be >= -90 and <= 90.  |
| 308 | double PoseRollDegrees; // Roll, measured in degrees, of the image where level with the horizon is 0. As roll increases, the horizon rotates counterclockwise in the image. Value must be > -180 and <= 180.  |
| 309 | bool hasPosePitchDegrees() const; // Return true if PosePitchDegrees is available  |
| 310 | bool hasPoseRollDegrees() const; // Return true if PoseRollDegrees is available  |
| 311 | } GPano;  |
| 312 | struct TINYEXIF_LIB MicroVideo_t { // Google camera video file in metadata  |
| 313 | uint32_t HasMicroVideo; // not zero if exists  |
| 314 | uint32_t MicroVideoVersion; // just regularinfo  |
| 315 | uint32_t MicroVideoOffset; // offset from end of file  |
| 316 | } MicroVideo;  |
| 317 | };  |
| 318 |   |
| 319 | } // namespace TinyEXIF  |
| 320 |   |
| 321 | #endif // __TINYEXIF_H__  |
| 322 | |