--- oiio-Release-2.0.13/src/libOpenImageIO/exif.cpp 2019-12-03 23:28:14.000000000 +0100 +++ oiio-Release-2.0.13/src/libOpenImageIO/exif.cpp 2021-02-02 02:54:55.000000000 +0100 @@ -554,40 +528,44 @@ +// libtiff > 4.1.0 defines these in tiff.h. For older libtiff, let's define +// them ourselves. +#ifndef GPSTAG_VERSIONID enum GPSTag { - GPSTAG_VERSIONID = 0, - GPSTAG_LATITUDEREF = 1, - GPSTAG_LATITUDE = 2, - GPSTAG_LONGITUDEREF = 3, - GPSTAG_LONGITUDE = 4, - GPSTAG_ALTITUDEREF = 5, - GPSTAG_ALTITUDE = 6, - GPSTAG_TIMESTAMP = 7, - GPSTAG_SATELLITES = 8, - GPSTAG_STATUS = 9, - GPSTAG_MEASUREMODE = 10, - GPSTAG_DOP = 11, - GPSTAG_SPEEDREF = 12, - GPSTAG_SPEED = 13, - GPSTAG_TRACKREF = 14, - GPSTAG_TRACK = 15, - GPSTAG_IMGDIRECTIONREF = 16, - GPSTAG_IMGDIRECTION = 17, - GPSTAG_MAPDATUM = 18, - GPSTAG_DESTLATITUDEREF = 19, - GPSTAG_DESTLATITUDE = 20, - GPSTAG_DESTLONGITUDEREF = 21, - GPSTAG_DESTLONGITUDE = 22, - GPSTAG_DESTBEARINGREF = 23, - GPSTAG_DESTBEARING = 24, - GPSTAG_DESTDISTANCEREF = 25, - GPSTAG_DESTDISTANCE = 26, - GPSTAG_PROCESSINGMETHOD = 27, - GPSTAG_AREAINFORMATION = 28, - GPSTAG_DATESTAMP = 29, - GPSTAG_DIFFERENTIAL = 30, - GPSTAG_HPOSITIONINGERROR = 31 + GPSTAG_VERSIONID = 0, + GPSTAG_LATITUDEREF = 1, + GPSTAG_LATITUDE = 2, + GPSTAG_LONGITUDEREF = 3, + GPSTAG_LONGITUDE = 4, + GPSTAG_ALTITUDEREF = 5, + GPSTAG_ALTITUDE = 6, + GPSTAG_TIMESTAMP = 7, + GPSTAG_SATELLITES = 8, + GPSTAG_STATUS = 9, + GPSTAG_MEASUREMODE = 10, + GPSTAG_DOP = 11, + GPSTAG_SPEEDREF = 12, + GPSTAG_SPEED = 13, + GPSTAG_TRACKREF = 14, + GPSTAG_TRACK = 15, + GPSTAG_IMGDIRECTIONREF = 16, + GPSTAG_IMGDIRECTION = 17, + GPSTAG_MAPDATUM = 18, + GPSTAG_DESTLATITUDEREF = 19, + GPSTAG_DESTLATITUDE = 20, + GPSTAG_DESTLONGITUDEREF = 21, + GPSTAG_DESTLONGITUDE = 22, + GPSTAG_DESTBEARINGREF = 23, + GPSTAG_DESTBEARING = 24, + GPSTAG_DESTDISTANCEREF = 25, + GPSTAG_DESTDISTANCE = 26, + GPSTAG_PROCESSINGMETHOD = 27, + GPSTAG_AREAINFORMATION = 28, + GPSTAG_DATESTAMP = 29, + GPSTAG_DIFFERENTIAL = 30, + GPSTAG_GPSHPOSITIONINGERROR = 31 }; +#endif static const TagInfo gps_tag_table[] = { // clang-format off @@ -622,7 +600,7 @@ { GPSTAG_AREAINFORMATION, "GPS:AreaInformation", TIFF_UNDEFINED, 1 }, { GPSTAG_DATESTAMP, "GPS:DateStamp", TIFF_ASCII, 0 }, { GPSTAG_DIFFERENTIAL, "GPS:Differential", TIFF_SHORT, 1 }, - { GPSTAG_HPOSITIONINGERROR, "GPS:HPositioningError",TIFF_RATIONAL, 1 } + { GPSTAG_GPSHPOSITIONINGERROR, "GPS:HPositioningError",TIFF_RATIONAL, 1 } // clang-format on }; @@ -685,7 +663,7 @@ } if (dirp->tdir_type == TIFF_RATIONAL) { int n = dirp->tdir_count; // How many - float* f = (float*)alloca(n * sizeof(float)); + float* f = OIIO_ALLOCA(float, n); for (int i = 0; i < n; ++i) { unsigned int num, den; num = ((const unsigned int*)dataptr)[2 * i + 0]; @@ -704,7 +682,7 @@ } if (dirp->tdir_type == TIFF_SRATIONAL) { int n = dirp->tdir_count; // How many - float* f = (float*)alloca(n * sizeof(float)); + float* f = OIIO_ALLOCA(float, n); for (int i = 0; i < n; ++i) { int num, den; num = ((const int*)dataptr)[2 * i + 0]; @@ -799,7 +777,7 @@ #if DEBUG_EXIF_READ std::cerr << "Read " << tagmap.mapname() << " "; - print_dir_entry(tagmap, dir, buf, offset_adjustment); + print_dir_entry(std::cerr, tagmap, dir, buf, offset_adjustment); #endif if (dir.tdir_tag == TIFFTAG_EXIFIFD || dir.tdir_tag == TIFFTAG_GPSIFD) { @@ -808,7 +786,7 @@ unsigned int offset = dirp->tdir_offset; // int stored in offset itself if (swab) swap_endian(&offset); - if (offset >= buf.size()) { + if (offset >= size_t(buf.size())) { #if DEBUG_EXIF_READ unsigned int off2 = offset; swap_endian(&off2); @@ -863,6 +841,16 @@ unsigned int offset = dirp->tdir_offset; // int stored in offset itself if (swab) swap_endian(&offset); + if (offset >= size_t(buf.size())) { +#if DEBUG_EXIF_READ + unsigned int off2 = offset; + swap_endian(&off2); + std::cerr << "Bad Exif block? ExifIFD has offset " << offset + << " inexplicably greater than exif buffer length " + << buf.size() << " (byte swapped = " << off2 << ")\n"; +#endif + return; + } // Don't recurse if we've already visited this IFD if (ifd_offsets_seen.find(offset) != ifd_offsets_seen.end()) return; @@ -964,49 +946,46 @@ const char* s = *(const char**)p.data(); int len = strlen(s) + 1; append_tiff_dir_entry(dirs, data, tag, type, len, s, - offset_correction); + offset_correction, 0, endianreq); return; } break; case TIFF_RATIONAL: if (element == TypeDesc::FLOAT) { - unsigned int* rat = (unsigned int*)alloca(2 * count - * sizeof(unsigned int)); + unsigned int* rat = OIIO_ALLOCA(unsigned int, 2 * count); const float* f = (const float*)p.data(); for (size_t i = 0; i < count; ++i) float_to_rational(f[i], rat[2 * i], rat[2 * i + 1]); append_tiff_dir_entry(dirs, data, tag, type, count, rat, - offset_correction); + offset_correction, 0, endianreq); return; } break; case TIFF_SRATIONAL: if (element == TypeDesc::FLOAT) { - int* rat = (int*)alloca(2 * count * sizeof(int)); + int* rat = OIIO_ALLOCA(int, 2 * count); const float* f = (const float*)p.data(); for (size_t i = 0; i < count; ++i) float_to_rational(f[i], rat[2 * i], rat[2 * i + 1]); append_tiff_dir_entry(dirs, data, tag, type, count, rat, - offset_correction); + offset_correction, 0, endianreq); return; } break; case TIFF_SHORT: - if (append_tiff_dir_entry_integer(p, dirs, data, tag, - type, - offset_correction)) + if (append_tiff_dir_entry_integer( + p, dirs, data, tag, type, offset_correction, endianreq)) return; break; case TIFF_LONG: if (append_tiff_dir_entry_integer(p, dirs, data, tag, - type, - offset_correction)) + type, offset_correction, + endianreq)) return; break; case TIFF_BYTE: - if (append_tiff_dir_entry_integer(p, dirs, data, tag, - type, - offset_correction)) + if (append_tiff_dir_entry_integer( + p, dirs, data, tag, type, offset_correction, endianreq)) return; break; default: break; @@ -1091,14 +1097,24 @@ bool decode_exif(cspan exif, ImageSpec& spec) { + // Sometimes an exif blob starts with "Exif". Skip it. + if (exif.size() >= 6 && exif[0] == 'E' && exif[1] == 'x' && exif[2] == 'i' + && exif[3] == 'f' && exif[4] == 0 && exif[5] == 0) { + exif = exif.subspan(6); + } + #if DEBUG_EXIF_READ std::cerr << "Exif dump:\n"; - for (size_t i = 0; i < exif.size(); ++i) { + for (size_t i = 0; i < std::min(200L, exif.size()); ++i) { + if ((i % 16) == 0) + std::cerr << "[" << i << "] "; if (exif[i] >= ' ') std::cerr << (char)exif[i] << ' '; std::cerr << "(" << (int)exif[i] << ") "; + if ((i % 16) == 15) + std::cerr << "\n"; } - std::cerr << "\n"; + std::cerr << std::endl; #endif // The first item should be a standard TIFF header. Note that HERE, @@ -1176,8 +1192,10 @@ template inline void -append(std::vector& blob, const T& v) +append(std::vector& blob, T v, endian endianreq = endian::native) { + if (endianreq != endian::native) + swap_endian(&v); blob.insert(blob.end(), (const char*)&v, (const char*)&v + sizeof(T)); } @@ -1191,10 +1209,20 @@ +// DEPRECATED(2.1) +void +encode_exif(const ImageSpec& spec, std::vector& blob) +{ + encode_exif(spec, blob, endian::native); +} + + + // Construct an Exif data block from the ImageSpec, appending the Exif // data as a big blob to the char vector. void -encode_exif(const ImageSpec& spec, std::vector& blob) +encode_exif(const ImageSpec& spec, std::vector& blob, + OIIO::endian endianreq) { const TagMap& exif_tagmap(exif_tagmap_ref()); const TagMap& gps_tagmap(gps_tagmap_ref()); @@ -1243,9 +1271,9 @@ // Put a TIFF header size_t tiffstart = blob.size(); // store initial size TIFFHeader head; - head.tiff_magic = littleendian() ? 0x4949 : 0x4d4d; + head.tiff_magic = (endianreq == endian::little) ? 0x4949 : 0x4d4d; head.tiff_version = 42; - // head.tiff_diroff -- fix below, once we know the sizes + // N.B. need to swap_endian head.tiff_diroff below, once we know the sizes append(blob, head); // Accumulate separate tag directories for TIFF, Exif, GPS, and Interop. @@ -1259,7 +1287,8 @@ if (Strutil::starts_with(p.name(), "GPS:")) { int tag = gps_tagmap.tag(p.name()); if (tag >= 0) - encode_exif_entry(p, tag, gpsdirs, blob, gps_tagmap, tiffstart); + encode_exif_entry(p, tag, gpsdirs, blob, gps_tagmap, tiffstart, + endianreq); } else { // Not GPS int tag = exif_tagmap.tag(p.name()); @@ -1267,10 +1296,10 @@ // This range of Exif tags go in the main TIFF directories, // not the Exif IFD. Whatever. encode_exif_entry(p, tag, tiffdirs, blob, exif_tagmap, - tiffstart); + tiffstart, endianreq); } else { encode_exif_entry(p, tag, exifdirs, blob, exif_tagmap, - tiffstart); + tiffstart, endianreq); } } } @@ -1293,12 +1322,14 @@ if (exifdirs.size() || makerdirs.size()) { // Add some required Exif tags that wouldn't be in the spec append_tiff_dir_entry(exifdirs, blob, EXIF_EXIFVERSION, TIFF_UNDEFINED, - 4, "0230", tiffstart); + 4, "0230", tiffstart, 0, endianreq); append_tiff_dir_entry(exifdirs, blob, EXIF_FLASHPIXVERSION, - TIFF_UNDEFINED, 4, "0100", tiffstart); + TIFF_UNDEFINED, 4, "0100", tiffstart, 0, + endianreq); static char componentsconfig[] = { 1, 2, 3, 0 }; append_tiff_dir_entry(exifdirs, blob, EXIF_COMPONENTSCONFIGURATION, - TIFF_UNDEFINED, 4, componentsconfig, tiffstart); + TIFF_UNDEFINED, 4, componentsconfig, tiffstart, 0, + endianreq); } // If any GPS info was found, add a version tag to the GPS fields. @@ -1306,7 +1337,7 @@ // Add some required Exif tags that wouldn't be in the spec static char ver[] = { 2, 2, 0, 0 }; append_tiff_dir_entry(gpsdirs, blob, GPSTAG_VERSIONID, TIFF_BYTE, 4, - &ver, tiffstart); + &ver, tiffstart, 0, endianreq); } // Compute offsets: