| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- #include "exif.h"
-
- #include <iostream>
- #include <fstream>
- #include <stdint.h>
- #include <math.h>
-
- using namespace std;
-
-
- urational_t::urational_t(): p(0), q(0)
- {}
-
- urational_t::urational_t(uint32_t p, uint32_t q): p(p), q(q)
- {}
-
- srational_t::srational_t(): p(0), q(0)
- {}
-
- srational_t::srational_t(int32_t p, int32_t q): p(p), q(q)
- {}
-
-
- ExifTags::ExifTags():
- ifd0_parsed_ok(false),
- exififd_parsed_ok(false),
- exififd_offset(0)
- {
- }
-
-
- static uint16_t read_be_uint16(istream &stream) {
- unsigned char buf[2];
- stream.read((char*)buf, 2);
- return ((uint16_t)buf[0]) * 256 + (uint16_t)buf[1];
- }
-
- static uint16_t read_le_uint16(istream &stream) {
- unsigned char buf[2];
- stream.read((char*)buf, 2);
- return (uint16_t)buf[0] + ((uint16_t)buf[1]) * 256;
- }
-
- static uint16_t read_uint16(istream &stream, bool is_little_endian) {
- if (is_little_endian) {
- return read_le_uint16(stream);
- } else {
- return read_be_uint16(stream);
- }
- }
-
- static uint32_t read_be_uint32(istream &stream) {
- unsigned char buf[4];
- stream.read((char*)buf, 4);
- return ((uint32_t)buf[0]) * 16777216 +
- ((uint32_t)buf[1]) * 65536 +
- ((uint32_t)buf[2]) * 256 +
- (uint32_t)buf[3];
- }
-
- static uint32_t read_le_uint32(istream &stream) {
- unsigned char buf[4];
- stream.read((char*)buf, 4);
- return ((uint32_t)buf[3]) * 16777216 +
- ((uint32_t)buf[2]) * 65536 +
- ((uint32_t)buf[1]) * 256 +
- (uint32_t)buf[0];
- }
-
- static uint32_t read_uint32(istream &stream, bool is_little_endian) {
- if (is_little_endian) {
- return read_le_uint32(stream);
- } else {
- return read_be_uint32(stream);
- }
- }
-
- static int32_t read_be_int32(istream &stream) {
- unsigned char buf[4];
- stream.read((char*)buf, 4);
- return (int32_t)(((uint32_t)buf[0]) * 16777216 +
- ((uint32_t)buf[1]) * 65536 +
- ((uint32_t)buf[2]) * 256 +
- (uint32_t)buf[3]);
- }
-
- static int32_t read_le_int32(istream &stream) {
- unsigned char buf[4];
- stream.read((char*)buf, 4);
- return (int32_t)(((uint32_t)buf[3]) * 16777216 +
- ((uint32_t)buf[2]) * 65536 +
- ((uint32_t)buf[1]) * 256 +
- (uint32_t)buf[0]);
- }
-
- /*
- static int32_t read_int32(istream &stream, bool is_little_endian) {
- if (is_little_endian) {
- return read_le_int32(stream);
- } else {
- return read_be_int32(stream);
- }
- }
- */
-
- static urational_t read_urational(istream &stream, bool is_little_endian) {
- if (is_little_endian) {
- uint32_t p = read_le_uint32(stream);
- uint32_t q = read_le_uint32(stream);
- return urational_t(p, q);
- } else {
- uint32_t p = read_be_uint32(stream);
- uint32_t q = read_be_uint32(stream);
- return urational_t(p, q);
- }
- }
-
- static srational_t read_srational(istream &stream, bool is_little_endian) {
- if (is_little_endian) {
- int32_t p = read_le_int32(stream);
- int32_t q = read_le_int32(stream);
- return srational_t(p, q);
- } else {
- int32_t p = read_be_int32(stream);
- int32_t q = read_be_int32(stream);
- return srational_t(p, q);
- }
- }
-
-
- static bool read_exif_tags(istream &stream,
- unsigned int num_entries,
- ExifTags &tags,
- uint64_t tiff_start_pos,
- bool is_little_endian)
- {
- for (unsigned int i = 0; i < num_entries; i++) {
- uint16_t tag_num = read_uint16(stream, is_little_endian);
- uint16_t data_format = read_uint16(stream, is_little_endian);
- uint32_t num_components = read_uint32(stream, is_little_endian);
- uint32_t tag_data = read_uint32(stream, is_little_endian);
-
- if (tag_num == 34665) {
- if (data_format == 4 && num_components == 1) {
- if (tag_data > 65535) {
- cerr << "Exif IFD offset too big (" << tag_data << ")." << endl;
- return false;
- }
- tags.exififd_offset = tag_data;
- } else {
- cerr << "Exif IFD offset has strange format." << endl;
- return false;
- }
-
- }
-
- if (tag_num == 0x829a) {
- uint64_t cur = stream.tellg();
- stream.seekg(tiff_start_pos + tag_data, std::ios_base::beg);
-
- tags.exposure_time = read_urational(stream, is_little_endian);
-
- stream.seekg(cur, std::ios_base::beg);
- }
-
- if (tag_num == 0x9201) {
- uint64_t cur = stream.tellg();
- stream.seekg(tiff_start_pos + tag_data, std::ios_base::beg);
-
- tags.shutter_speed_value = read_srational(stream, is_little_endian);
-
- stream.seekg(cur, std::ios_base::beg);
- }
- }
-
- return true;
- }
-
- static bool read_exif_ifd(istream &stream,
- uint64_t tiff_start_pos,
- uint16_t ifd_offset,
- ExifTags &tags,
- bool is_little_endian)
- {
- if (ifd_offset == 0) {
- return true;
- }
-
- {
- uint64_t cur = stream.tellg();
- if (cur < tiff_start_pos) {
- cerr << "Read backwards?" << endl;
- return false;
- }
-
- if (ifd_offset < (cur - tiff_start_pos)) {
- cerr << "IFD offset too small." << endl;
- return false;
- }
- }
-
- stream.seekg(tiff_start_pos + ifd_offset, std::ios_base::beg);
-
- uint16_t num_entries = read_le_uint16(stream);
-
- return read_exif_tags(stream, num_entries, tags, tiff_start_pos, is_little_endian);
- }
-
- static bool parse_exif(istream &stream, uint16_t length, ExifTags &output) {
- if (length < 8) {
- return false;
- }
-
- {
- char buf[6];
- const char *compare = "Exif\0\0";
- stream.read(buf, 6);
- for (unsigned int i = 0; i < 6; i++) {
- if (buf[i] != compare[i]) {
- return false;
- }
- }
- }
-
- uint64_t tiff_start_pos = stream.tellg();
-
- bool is_little_endian = false;
- {
-
- char buf[2];
- stream.read(buf, 2);
-
- if (buf[0] == 'I' && buf[1] == 'I') {
- is_little_endian = true;
- } else if (buf[0] == 'M' && buf[1] == 'M') {
- is_little_endian = false;
- } else {
- cerr << "Endian fail" << endl;
- return false;
- }
- }
-
- {
- uint16_t magic = read_uint16(stream, is_little_endian);
-
- if (magic != 0x002a) {
- cerr << "TIFF fail" << endl;
- return false;
- }
- }
-
- uint32_t ifd0_offset = read_uint32(stream, is_little_endian);
-
- // Read IFD0
- output.ifd0_parsed_ok = read_exif_ifd(stream, tiff_start_pos, ifd0_offset, output, is_little_endian);
-
- if (output.exififd_offset != 0) {
- // Read Exif IFD
- output.exififd_parsed_ok = read_exif_ifd(stream, tiff_start_pos, output.exififd_offset, output, is_little_endian);
- }
-
- if (stream.fail()) {
- cerr << "stream failed" << endl;
- return false;
- } else {
- return true;
- }
- }
-
- bool ExifTags::read_from_jpeg(istream &stream, ExifTags &output) {
- unsigned char buf[2];
- stream.read((char*)buf, 2);
- if (!(buf[0] == 0xff && buf[1] == 0xd8)) {
- return false;
- }
-
- while (stream.good()) {
- stream.read((char*)buf, 2);
- if (buf[0] != 0xff) {
- cerr << "not a tag" << endl;
- return false;
- }
- if (buf[1] == 0xff || buf[1] == 0x00) {
- cerr << "not a marker" << endl;
- return false;
- }
-
- if (buf[1] == 0xd9) {
- break;
- }
-
- if (buf[1] == 0xda || (buf[1] >= 0xd0 && buf[1] <= 0xd7)) {
- // SOS marker or segment without length
- unsigned char c = 0;
- while(stream.good()) {
- c = stream.get();
- if (c == 0xff) {
- c = stream.get();
- if (c != 0x00) {
- // end of section
- stream.seekg(-2, std::ios_base::cur);
- break;
- }
- }
- }
- } else {
- // read size, seek to next marker
-
- uint16_t s = read_be_uint16(stream);
-
- if (s < 2) {
- cerr << "invalid size" << endl;
- return false;
- }
-
- if (buf[1] == 0xe1) {
- return parse_exif(stream, s, output);
- }
-
- stream.seekg(s - 2, std::ios_base::cur);
- }
- }
-
- if (stream.fail()) {
- cerr << "stream failed" << endl;
- return false;
- } else {
- return true;
- }
- }
-
- bool ExifTags::get_exposure_time(double &output) {
- if (exposure_time.p != 0 or exposure_time.q != 0) {
- output = (double)exposure_time.p / (double)exposure_time.q;
- return true;
- } else if (shutter_speed_value.p != 0 or shutter_speed_value.q != 0) {
- output = 1.0 / pow(2.0, (double)shutter_speed_value.p / (double)shutter_speed_value.q);
- return true;
- } else {
- return false;
- }
- }
|