1
0
mirror of https://github.com/cdcseacave/TinyEXIF.git synced 2026-07-21 19:23:01 +04:00

7 Commits

Author SHA1 Message Date
cDc b6ea1b7bbe Fix possible integer overflow in parseString bounds check (#26)
* Fix integer overflow in parseString bounds check

Cast `base` to `uint64_t` in the parseString bounds check
`base+data+num_components <= len` to prevent unsigned integer overflow.

When `data` is attacker-controlled (e.g. 0xffffffff), the 32-bit
unsigned addition wraps around, causing the check to pass even though
the computed offset is far beyond the buffer. This leads to an
out-of-bounds heap read or segfault when dereferencing the resulting
pointer.

Fixes #16

* Fix type casting for base pointer comparison
2026-03-19 06:55:25 +02:00
cDc 841e292929 Fix potential heap buffer overflow in EntryParser::Fetch methods (#25)
* Fix heap buffer overflow in EntryParser::Fetch methods

Add buffer bounds validation to indexed Fetch methods that compute
offsets from attacker-controlled EXIF data via GetSubIFD().

Previously, Fetch(uint16_t, idx), Fetch(double), and Fetch(double, idx)
would read from buf at offsets derived from parsed EXIF fields without
checking against the actual buffer length. A crafted JPEG with a
malicious SubjectArea length (tag 0x9214) could trigger a heap buffer
overflow via parse16() reads past the end of the buffer.

Fixes #24

* Fix include directive and simplify Fetch method
2026-03-19 06:26:24 +02:00
cDc 39bba86ced Update version to 1.0.4 2025-11-17 19:12:20 +02:00
cDc 27a750ecf5 Robust parsing if missing offset 2025-11-17 18:47:27 +02:00
cDc 7a3167cc73 Add license 2025-11-17 18:04:59 +02:00
Azamat H. Hackimov 47dbeaca48 Update CMake project (#23) 2025-11-17 17:48:29 +02:00
Paul Gafton e5d0e39a9b Added support for DJI distortion (#21) 2025-10-09 12:45:16 +03:00
13 changed files with 271 additions and 242 deletions
+38
View File
@@ -0,0 +1,38 @@
name: build
on:
- push
- pull_request
jobs:
build:
env:
VCPKG_COMMIT: '74e6536215718009aae747d86d84b78376bf9e09'
name: "${{ matrix.os }} - BUILD_SHARED_LIBS=${{ matrix.shared_lib }}"
strategy:
fail-fast: false
matrix:
os:
- macos-latest
- ubuntu-latest
- windows-latest
shared_lib:
- ON
- OFF
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: lukka/get-cmake@v3.28.4
- uses: lukka/run-vcpkg@v11
with:
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT }}
- name: Build with -DBUILD_SHARED_LIBS=${{ matrix.shared_lib }}
uses: lukka/run-cmake@v10
with:
configurePreset: "vcpkg"
configurePresetAdditionalArgs: "[
'-DBUILD_SHARED_LIBS=${{ matrix.shared_lib }}',
'-DBUILD_DEMO=ON'
]"
buildPreset: "vcpkg"
buildPresetAdditionalArgs: "[ '--config Release' ]"
+1
View File
@@ -38,3 +38,4 @@ CMakeSettings.json
.vscode/
bin/
binaries/
make/
+54 -152
View File
@@ -1,187 +1,89 @@
cmake_minimum_required(VERSION 3.1)
project(TinyEXIF)
include(GNUInstallDirs)
find_package(tinyxml2 REQUIRED)
#CMAKE_BUILD_TOOL
cmake_minimum_required(VERSION 3.15)
################################
# set lib version here
set(GENERIC_LIB_VERSION "1.0.3")
project(TinyEXIF VERSION 1.0.4)
set(GENERIC_LIB_SOVERSION "1")
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
find_package(tinyxml2 CONFIG REQUIRED)
################################
# Add definitions
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
################################
# Add targets
# By Default shared libray is being built
# To build static libs also - Do cmake . -DBUILD_STATIC_LIBS:BOOL=ON
# User can choose not to build shared library by using cmake -DBUILD_SHARED_LIBS:BOOL=OFF
# To build only static libs use cmake . -DBUILD_SHARED_LIBS:BOOL=OFF -DBUILD_STATIC_LIBS:BOOL=ON
# User can choose to build static library by using cmake -DBUILD_SHARED_LIBS:BOOL=OFF
# To build the demo binary, use cmake . -DBUILD_DEMO:BOOL=ON
option(BUILD_SHARED_LIBS "build as shared library" ON)
option(BUILD_STATIC_LIBS "build as static library" OFF)
option(LINK_CRT_STATIC_LIBS "link CRT static library" OFF)
option(BUILD_DEMO "build demo binary" ON)
# set MSVC runtime linkage to static or dynamic
# as in: https://stackoverflow.com/questions/10113017/setting-the-msvc-runtime-in-cmake
macro(configure_runtime CRT_RUNTIME)
if(MSVC)
# Default to statically-linked runtime.
if("${CRT_RUNTIME}" STREQUAL "")
set(CRT_RUNTIME "static")
endif()
# Set compiler options.
set(variables
CMAKE_C_FLAGS_DEBUG
CMAKE_C_FLAGS_MINSIZEREL
CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_RELWITHDEBINFO
CMAKE_CXX_FLAGS_DEBUG
CMAKE_CXX_FLAGS_MINSIZEREL
CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_RELWITHDEBINFO
)
if(${CRT_RUNTIME} STREQUAL "static")
message(STATUS "MSVC -> forcing use of statically-linked runtime.")
foreach(variable ${variables})
if(${variable} MATCHES "/MD")
string(REGEX REPLACE "/MD" "/MT" ${variable} "${${variable}}")
endif()
endforeach()
else()
message(STATUS "MSVC -> forcing use of dynamically-linked runtime.")
foreach(variable ${variables})
if(${variable} MATCHES "/MT")
string(REGEX REPLACE "/MT" "/MD" ${variable} "${${variable}}")
endif()
endforeach()
endif()
endif()
endmacro()
if(LINK_CRT_STATIC_LIBS)
# set MSVC runtime linkage to static
configure_runtime("static")
endif()
# to distinguish between debug and release lib
set(CMAKE_DEBUG_POSTFIX "d")
if(BUILD_SHARED_LIBS)
add_library(TinyEXIF SHARED TinyEXIF.cpp TinyEXIF.h)
# Set MSVC runtime library globally so all targets use consistent /MT or /MD.
# This avoids LNK2038 mismatches between targets compiled with different CRT variants.
if(MSVC)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>$<$<NOT:$<BOOL:${LINK_CRT_STATIC_LIBS}>>:DLL>")
if(MSVC_VERSION GREATER 1300)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4251") # needs to have dll-interface
endif()
target_link_libraries(TinyEXIF tinyxml2::tinyxml2)
set_target_properties(TinyEXIF PROPERTIES
COMPILE_DEFINITIONS "TINYEXIF_EXPORT"
VERSION "${GENERIC_LIB_VERSION}"
SOVERSION "${GENERIC_LIB_SOVERSION}")
if(DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11")
target_include_directories(TinyEXIF PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>)
if(MSVC)
target_compile_definitions(TinyEXIF PUBLIC _CRT_SECURE_NO_WARNINGS)
endif()
else()
include_directories(${PROJECT_SOURCE_DIR})
if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
endif()
endif()
# export targets for find_package config mode
export(TARGETS TinyEXIF
FILE ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake)
install(TARGETS TinyEXIF
EXPORT ${CMAKE_PROJECT_NAME}Targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
if(BUILD_STATIC_LIBS)
add_library(TinyEXIFstatic STATIC TinyEXIF.cpp TinyEXIF.h)
target_link_libraries(TinyEXIFstatic tinyxml2::tinyxml2)
set_target_properties(TinyEXIFstatic PROPERTIES
OUTPUT_NAME TinyEXIF
VERSION "${GENERIC_LIB_VERSION}"
SOVERSION "${GENERIC_LIB_SOVERSION}")
add_library(TinyEXIF TinyEXIF.cpp TinyEXIF.h)
add_library(TinyEXIF::TinyEXIF ALIAS TinyEXIF)
if(DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11")
target_include_directories(TinyEXIFstatic PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>)
target_link_libraries(TinyEXIF tinyxml2::tinyxml2)
set_target_properties(TinyEXIF PROPERTIES
DEFINE_SYMBOL "TINYEXIF_EXPORT"
VERSION "${TinyEXIF_VERSION}"
SOVERSION "${GENERIC_LIB_SOVERSION}"
MSVC_RUNTIME_LIBRARY "${CMAKE_MSVC_RUNTIME_LIBRARY}"
)
if(MSVC)
target_compile_definitions(TinyEXIFstatic PUBLIC _CRT_SECURE_NO_WARNINGS)
endif()
else()
include_directories(${PROJECT_SOURCE_DIR})
target_include_directories(TinyEXIF PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
endif()
endif()
# export targets for find_package config mode
export(TARGETS TinyEXIFstatic
FILE ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake)
install(TARGETS TinyEXIFstatic
EXPORT ${CMAKE_PROJECT_NAME}Targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
target_compile_definitions(TinyEXIF
INTERFACE $<$<BOOL:${BUILD_SHARED_LIBS}>:TINYEXIF_IMPORT>
PRIVATE $<$<CXX_COMPILER_ID:MSVC>:_CRT_SECURE_NO_WARNINGS>
)
if(BUILD_DEMO)
add_executable(TinyEXIFdemo main.cpp)
if(BUILD_SHARED_LIBS)
add_dependencies(TinyEXIFdemo TinyEXIF)
target_link_libraries(TinyEXIFdemo TinyEXIF)
target_compile_definitions(TinyEXIFdemo PRIVATE TINYEXIF_IMPORT)
else(BUILD_STATIC_LIBS)
add_dependencies(TinyEXIFdemo TinyEXIFstatic)
target_link_libraries(TinyEXIFdemo TinyEXIFstatic tinyxml2::tinyxml2)
endif()
set_target_properties(TinyEXIFdemo PROPERTIES MSVC_RUNTIME_LIBRARY "${CMAKE_MSVC_RUNTIME_LIBRARY}")
target_link_libraries(TinyEXIFdemo TinyEXIF)
endif()
################################
# Install targets
install(TARGETS TinyEXIF
EXPORT TinyEXIFTargets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
install(FILES TinyEXIF.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
foreach(p LIB INCLUDE)
set(var CMAKE_INSTALL_${p}DIR)
if(NOT IS_ABSOLUTE "${${var}}")
set(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}")
endif()
endforeach()
install(EXPORT TinyEXIFTargets
FILE TinyEXIFTargets.cmake
NAMESPACE TinyEXIF::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/TinyEXIF
)
file(WRITE
${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake
"include(\${CMAKE_CURRENT_LIST_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake)\n")
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/TinyEXIFConfig.cmake"
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/TinyEXIF
)
install(FILES
${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake
DESTINATION lib/cmake/${CMAKE_PROJECT_NAME})
install(EXPORT ${CMAKE_PROJECT_NAME}Targets
DESTINATION lib/cmake/${CMAKE_PROJECT_NAME})
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/TinyEXIFConfig.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/TinyEXIF
)
+28
View File
@@ -0,0 +1,28 @@
{
"version": 6,
"cmakeMinimumRequired": {
"major": 3,
"minor": 15,
"patch": 0
},
"configurePresets": [
{
"name": "vcpkg",
"binaryDir": "${sourceDir}/builds/${presetName}",
"generator": "Ninja Multi-Config",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": {
"type": "FILEPATH",
"value": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
}
}
}
],
"buildPresets": [
{
"name": "vcpkg",
"configurePreset": "vcpkg"
}
]
}
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 cdcseacave
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+6 -18
View File
@@ -34,24 +34,12 @@ int main(int argc, const char** argv) {
```
See `main.cpp` for more details.
## Copyright
## License
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
MIT [License](https://github.com/cdcseacave/TinyEXIF/blob/master/LICENSE)
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
Copyright (c) 2025 cdcseacave
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
## Acknowledgments
Inspired by [easyexif](https://github.com/mayanklahiri/easyexif) library (2013 version) of Mayank Lahiri (mlahiri@gmail.com).
Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

+83 -44
View File
@@ -2,48 +2,24 @@
TinyEXIF.cpp -- A simple ISO C++ library to parse basic EXIF and XMP
information from a JPEG file.
Copyright (c) 2015-2017 Seacave
Copyright (c) 2015-2025 Seacave
cdc.seacave@gmail.com
All rights reserved.
Based on the easyexif library (2013 version)
https://github.com/mayanklahiri/easyexif
of Mayank Lahiri (mlahiri@gmail.com).
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
MIT License
*/
#include "TinyEXIF.h"
#ifndef TINYEXIF_NO_XMP_SUPPORT
#include <tinyxml2.h>
#endif // TINYEXIF_NO_XMP_SUPPORT
#include <cstdint>
#include <cstddef>
#include <cstdio>
#include <cmath>
#include <cfloat>
#include <vector>
#include <algorithm>
#include <iostream>
#include <sstream>
#ifndef TINYEXIF_NO_XMP_SUPPORT
#include <tinyxml2.h>
#endif // TINYEXIF_NO_XMP_SUPPORT
#ifdef _MSC_VER
namespace {
@@ -229,7 +205,10 @@ public:
bool Fetch(uint16_t& val, uint32_t idx) const {
if (!IsShort() || length <= idx)
return false;
val = parse16(buf + GetSubIFD() + idx*2, alignIntel);
const uint32_t offset = GetSubIFD() + idx*2;
if (offset + 2 > len)
return false;
val = parse16(buf + offset, alignIntel);
return true;
}
bool Fetch(uint32_t& val) const {
@@ -253,7 +232,10 @@ public:
bool Fetch(double& val, uint32_t idx) const {
if (!IsRational() || length <= idx)
return false;
val = parseRational(buf + GetSubIFD() + idx*8, alignIntel, IsSRational());
const uint32_t offset = GetSubIFD() + idx*8;
if (offset + 8 > len)
return false;
val = parseRational(buf + offset, alignIntel, IsSRational());
return true;
}
@@ -319,7 +301,7 @@ public:
if (value[num_components-1] == '\0')
value.resize(num_components-1);
} else
if (base+data+num_components <= len) {
if ((uint64_t)base+data+num_components <= (uint64_t)len) {
const char* const sz((const char*)buf+base+data);
unsigned num(0);
while (num < num_components && sz[num] != '\0')
@@ -969,15 +951,17 @@ int EXIFInfo::parseFromEXIFSegment(const uint8_t* buf, unsigned len) {
// entries in the section. The last 4 bytes of the IFD contain an offset
// to the next IFD, which means this IFD must contain exactly 6 + 12 * num
// bytes of data.
// Note that it's possible that the next IFD offset doesn't exist,
// so here the last 4 bytes are considered optional.
if (offs + 2 > len)
return PARSE_CORRUPT_DATA;
int num_entries = EntryParser::parse16(buf + offs, alignIntel);
if (offs + 6 + 12 * num_entries > len)
unsigned num_entries = EntryParser::parse16(buf + offs, alignIntel);
if (offs + 2 + 12 * num_entries > len)
return PARSE_CORRUPT_DATA;
unsigned exif_sub_ifd_offset = len;
unsigned gps_sub_ifd_offset = len;
parser.Init(offs+2);
while (--num_entries >= 0) {
while (num_entries-- > 0) {
parser.ParseTag();
parseIFDImage(parser, exif_sub_ifd_offset, gps_sub_ifd_offset);
}
@@ -989,10 +973,10 @@ int EXIFInfo::parseFromEXIFSegment(const uint8_t* buf, unsigned len) {
if (exif_sub_ifd_offset + 4 <= len) {
offs = exif_sub_ifd_offset;
num_entries = EntryParser::parse16(buf + offs, alignIntel);
if (offs + 6 + 12 * num_entries > len)
if (offs + 2 + 12 * num_entries > len)
return PARSE_CORRUPT_DATA;
parser.Init(offs+2);
while (--num_entries >= 0) {
while (num_entries-- > 0) {
parser.ParseTag();
parseIFDExif(parser);
}
@@ -1003,10 +987,10 @@ int EXIFInfo::parseFromEXIFSegment(const uint8_t* buf, unsigned len) {
if (gps_sub_ifd_offset + 4 <= len) {
offs = gps_sub_ifd_offset;
num_entries = EntryParser::parse16(buf + offs, alignIntel);
if (offs + 6 + 12 * num_entries > len)
if (offs + 2 + 12 * num_entries > len)
return PARSE_CORRUPT_DATA;
parser.Init(offs+2);
while (--num_entries >= 0) {
while (num_entries-- > 0) {
parser.ParseTag();
parseIFDGPS(parser);
}
@@ -1114,8 +1098,19 @@ int EXIFInfo::parseFromXMPSegmentXML(const char* szXML, unsigned len) {
if (element == NULL || (szAttribute = element->GetText()) == NULL)
return false;
}
value = strtoul(szAttribute, NULL, 0); return true;
return false;
value = strtoul(szAttribute, NULL, 0);
return true;
}
// same as previous function but with std::string
static bool Value(const tinyxml2::XMLElement* document, const char* name, std::string& value) {
const char* szAttribute = document->Attribute(name);
if (szAttribute == NULL) {
const tinyxml2::XMLElement* const element(document->FirstChildElement(name));
if (element == NULL || (szAttribute = element->GetText()) == NULL)
return false;
}
value = std::string(szAttribute);
return true;
}
};
const char* szAbout(document->Attribute("rdf:about"));
@@ -1128,6 +1123,28 @@ int EXIFInfo::parseFromXMPSegmentXML(const char* szXML, unsigned len) {
ParseXMP::Value(document, "drone-dji:CalibratedFocalLength", Calibration.FocalLength);
ParseXMP::Value(document, "drone-dji:CalibratedOpticalCenterX", Calibration.OpticalCenterX);
ParseXMP::Value(document, "drone-dji:CalibratedOpticalCenterY", Calibration.OpticalCenterY);
std::string dewarpData;
ParseXMP::Value(document, "drone-dji:DewarpFlag", Distortion.DewarpFlag);
ParseXMP::Value(document, "drone-dji:DewarpData", dewarpData);
std::vector<double> distortionParams;
size_t pos = dewarpData.find(';');
if (pos != std::string::npos) {
std::stringstream ss(dewarpData.substr(pos + 1));
std::string item;
while (std::getline(ss, item, ',')) {
distortionParams.push_back(std::stod(item));
}
}
// The DewarpData string has the following format:
// date;Fx,Fy,Cx,Cy,K1,K2,P1,P2,K3
// , where Fx, Fy are focal lengths in pixels, Cx, Cy are optical center offsets from the image center in pixels
if (distortionParams.size() == 9) {
Distortion.K1 = distortionParams[4];
Distortion.K2 = distortionParams[5];
Distortion.P1 = distortionParams[6];
Distortion.P2 = distortionParams[7];
Distortion.K3 = distortionParams[8];
}
} else
if (0 == strcasecmp(Make.c_str(), "senseFly") || 0 == strcasecmp(Make.c_str(), "Sentera")) {
ParseXMP::Value(document, "Camera:Roll", GeoLocation.RollDegree);
@@ -1165,6 +1182,17 @@ int EXIFInfo::parseFromXMPSegmentXML(const char* szXML, unsigned len) {
#endif // TINYEXIF_NO_XMP_SUPPORT
bool EXIFInfo::Calibration_t::hasCalibration() const {
return FocalLength > 0.0 && OpticalCenterX > 0.0 && OpticalCenterY > 0.0;
}
bool EXIFInfo::Distortion_t::hasDewarpFlag() const {
return DewarpFlag != UINT32_MAX;
}
bool EXIFInfo::Distortion_t::hasDistortion() const {
return K1 != 0.0 || K2 != 0.0 || P1 != 0.0 || P2 != 0.0 || K3 != 0.0;
}
void EXIFInfo::Geolocation_t::parseCoords() {
// Convert GPS latitude
if (LatComponents.degrees != DBL_MAX ||
@@ -1210,6 +1238,9 @@ bool EXIFInfo::Geolocation_t::hasOrientation() const {
bool EXIFInfo::Geolocation_t::hasSpeed() const {
return SpeedX != DBL_MAX && SpeedY != DBL_MAX && SpeedZ != DBL_MAX;
}
bool EXIFInfo::Geolocation_t::hasAccuracy() const {
return AccuracyXY != 0 && AccuracyZ != 0;
}
bool EXIFInfo::GPano_t::hasPosePitchDegrees() const {
return PosePitchDegrees != DBL_MAX;
@@ -1306,6 +1337,14 @@ void EXIFInfo::clear() {
GeoLocation.LonComponents.seconds = 0;
GeoLocation.LonComponents.direction = 0;
// Distortion
Distortion.DewarpFlag = UINT32_MAX;
Distortion.K1 = 0;
Distortion.K2 = 0;
Distortion.P1 = 0;
Distortion.P2 = 0;
Distortion.K3 = 0;
// GPano
GPano.PosePitchDegrees = DBL_MAX;
GPano.PoseRollDegrees = DBL_MAX;
+19 -28
View File
@@ -2,33 +2,9 @@
TinyEXIF.h -- A simple ISO C++ library to parse basic EXIF and XMP
information from a JPEG file.
Copyright (c) 2015-2017 Seacave
Copyright (c) 2015-2025 Seacave
cdc.seacave@gmail.com
All rights reserved.
Based on the easyexif library (2013 version)
https://github.com/mayanklahiri/easyexif
of Mayank Lahiri (mlahiri@gmail.com).
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
MIT License
*/
#ifndef __TINYEXIF_H__
@@ -251,7 +227,21 @@ public:
double FocalLength; // Focal length (pixels)
double OpticalCenterX; // Principal point X (pixels)
double OpticalCenterY; // Principal point Y (pixels)
bool hasCalibration() const; // Return true if FocalLength, OpticalCenterX, OpticalCenterY are available (nonzero)
} Calibration;
struct TINYEXIF_LIB Distortion_t { // Lens distortion information
uint32_t DewarpFlag; // Dewarp flag - indicates whether undistortion has been applied to the image
// UINT32_MAX: flag missing from EXIF data
// 0: no dewarp (raw image) - the image is distorted, should also have coefficients
// 1: dewarp applied (undistorted image)
double K1;
double K2;
double P1;
double P2;
double K3;
bool hasDewarpFlag() const; // Return true if DewarpFlag is available
bool hasDistortion() const; // Return true if any of K1, K2, P1, P2, K3 are available
} Distortion;
struct TINYEXIF_LIB LensInfo_t { // Lens information
double FStopMin; // Min aperture (f-stop)
double FStopMax; // Max aperture (f-stop)
@@ -302,14 +292,15 @@ public:
bool hasRelativeAltitude()const;// Return true if (rel_alt) is available
bool hasOrientation() const; // Return true if (roll,yaw,pitch) is available
bool hasSpeed() const; // Return true if (speedX,speedY,speedZ) is available
bool hasAccuracy() const; // Return true if (accuracyXY,accuracyZ) is available
} GeoLocation;
struct TINYEXIF_LIB GPano_t { // Spherical metadata. https://developers.google.com/streetview/spherical-metadata
struct TINYEXIF_LIB GPano_t { // Spherical metadata. https://developers.google.com/streetview/spherical-metadata
double PosePitchDegrees; // Pitch, measured in degrees above the horizon, for the center in the image. Value must be >= -90 and <= 90.
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.
bool hasPosePitchDegrees() const; // Return true if PosePitchDegrees is available
bool hasPoseRollDegrees() const; // Return true if PoseRollDegrees is available
} GPano;
struct TINYEXIF_LIB MicroVideo_t { // Google camera video file in metadata
struct TINYEXIF_LIB MicroVideo_t { // Google camera video file in metadata
uint32_t HasMicroVideo; // not zero if exists
uint32_t MicroVideoVersion; // just regularinfo
uint32_t MicroVideoOffset; // offset from end of file
+8
View File
@@ -0,0 +1,8 @@
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
find_dependency(tinyxml2)
include("${CMAKE_CURRENT_LIST_DIR}/TinyEXIFTargets.cmake")
check_required_components(TinyEXIF)
+6
View File
@@ -130,5 +130,11 @@ int main(int argc, const char** argv)
std::cout << "GPano.PosePitchDegrees " << imageEXIF.GPano.PosePitchDegrees << "\n";
if (imageEXIF.GPano.hasPoseRollDegrees())
std::cout << "GPano.PoseRollDegrees " << imageEXIF.GPano.PoseRollDegrees << "\n";
if (imageEXIF.Distortion.hasDewarpFlag())
std::cout << "Distortion.DewarpFlag " << imageEXIF.Distortion.DewarpFlag << "\n";
if (imageEXIF.Distortion.hasDistortion())
std::cout << "Distortion [K1 K2 P1 P2 K3] " << std::setprecision(6)
<< imageEXIF.Distortion.K1 << " " << imageEXIF.Distortion.K2 << " " << imageEXIF.Distortion.P1
<< " " << imageEXIF.Distortion.P2 << " " << imageEXIF.Distortion.K3 << "\n";
return EXIT_SUCCESS;
}
+7
View File
@@ -0,0 +1,7 @@
{
"name": "tinyexif",
"version-string": "1.0.4",
"dependencies": [
"tinyxml2"
]
}