diff --git a/.gitignore b/.gitignore index 66f2fe25..d3090138 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ xcode_build* msvc_build* cygwin_build* mingw_build* +linux_build* po/POTFILES po/remove-potcdate.sed po/stamp-po diff --git a/.travis.yml b/.travis.yml index bf59f3f6..91cda2fc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ git: env: global: - - COMMON_CMAKE_OPTIONS="-DEXIV2_ENABLE_WEBREADY=ON -DEXIV2_ENABLE_CURL=ON -DEXIV2_BUILD_UNIT_TESTS=ON -DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON -DCMAKE_INSTALL_PREFIX=install" + - COMMON_CMAKE_OPTIONS="-DEXIV2_ENABLE_WEBREADY=ON -DEXIV2_ENABLE_CURL=ON -DEXIV2_BUILD_UNIT_TESTS=ON -DEXIV2_ENABLE_BMFF=ON -DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON -DCMAKE_INSTALL_PREFIX=install" matrix: include: diff --git a/CMakeLists.txt b/CMakeLists.txt index a8332d9f..8e267d49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ option( EXIV2_ENABLE_WIN_UNICODE "Use Unicode paths (wstring) on Windows" option( EXIV2_ENABLE_WEBREADY "Build webready support into library" OFF ) option( EXIV2_ENABLE_CURL "USE Libcurl for HttpIo (WEBREADY)" OFF ) option( EXIV2_ENABLE_SSH "USE Libssh for SshIo (WEBREADY)" OFF ) +option( EXIV2_ENABLE_BMFF "Build with BMFF support" OFF ) option( EXIV2_BUILD_SAMPLES "Build sample applications" ON ) option( EXIV2_BUILD_EXIV2_COMMAND "Build exiv2 command-line executable" ON ) diff --git a/README.md b/README.md index 9875d918..d444165b 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ The file ReadMe.txt in a build bundle describes how to install the library on th 16. [Cross Platform Build and Test on Linux for MinGW](#2-16) 17. [Building with C++11 and other compilers](#2-17) 18. [Static and Shared Libraries](#2-18) + 19. [Support for bmff files (CR3, HEIF and AVIF)](#2-19) 3. [License and Support](#3) 1. [License](#3-1) 2. [Support](#3-2) @@ -127,6 +128,7 @@ option( EXIV2_ENABLE_XMP "Build with XMP metadata support" ON option( EXIV2_ENABLE_EXTERNAL_XMP "Use external version of XMP" OFF ) option( EXIV2_ENABLE_PNG "Build with png support (requires libz)" ON ) ... +option( EXIV2_ENABLE_BMFF "Build with BMFF support" OFF ) 577 rmills@rmillsmm:~/gnu/github/exiv2/exiv2 $ ``` @@ -581,13 +583,18 @@ The level of thread safety within Exiv2 varies depending on the type of metadata Therefore, multi-threaded applications need to ensure that these two XMP functions are serialized, e.g., by calling them from an initialization section which is run before any threads are started. All exiv2 sample applications begin with: ```cpp +#include int main(int argc, const char* argv[]) { Exiv2::XmpParser::initialize(); ::atexit(Exiv2::XmpParser::terminate); +#if EXIV2_TEST_VERSION(0,27,4) + Exiv2::enableBMFF(true); +#endif ... } ``` +The use of the _**thread unsafe function**_ Exiv2::enableBMFF(true) is discussed in [2.19 Support for bmff files](#2-19) [TOC](#TOC) @@ -604,6 +611,7 @@ The exiv2 command-line program and sample applications call the following at the ```cpp Exiv2::XmpParser::initialize(); ::atexit(Exiv2::XmpParser::terminate); + Exiv2::enableBMFF(true); ``` [TOC](#TOC) @@ -773,6 +781,26 @@ This is discussed: [https://github.com/Exiv2/exiv2/issues/1230](https://github.c [TOC](#TOC) +
+ +2.19 Support for bmff files (CR3, HEIF and AVIF) + +**Attention is drawn to the possibility that bmff support may be the subject of patent rights. _Exiv2 shall not be held responsible for identifying any or all such patent rights. Exiv2 shall not be held responsible for the legal consequences of the use of this code_.** + +Access to the bmff code is guarded in two ways. Firstly, you have to build the library with the cmake option: `-DEXIV2_ENABLE_BMFF=On`. Secondly, the application must enable bmff support at run-time by calling the following function. + +```cpp +EXIV2API bool enableBMFF(bool enable); +``` + +The return value of `enableBMFF()` reports the build status of bmff support. A return value of true indicates that the library has been built with bmff support. + +Applications may wish the provide a preference setting to enable bmff support and thereby place the responsibility for the use of this code with the user of the application. + +It is recommended that you enclose the call to `enableBMFF()` with the compile time macro EXIV2\_TEST\_VERSION to ensure that your code builds cleanly on earlier versions of Exiv2. It is recommended that you call enableBMFF() at process start-up as it is not threadsafe. A code snippet is provided in [2.14 Thread Safety](#2-14). + +[TOC](#TOC) +
## 3 License and Support @@ -784,7 +812,7 @@ All project resources are accessible from the project website. ### 3.1 License -Copyright (C) 2004-2019 Exiv2 authors. +Copyright (C) 2004-2021 Exiv2 authors. You should have received a copy of the file [COPYING](COPYING) which details the GPLv2 license. Exiv2 is free software; you can redistribute it and/or modify @@ -1092,6 +1120,8 @@ Please note that the platform MinGW/msys2 32 is obsolete and superceded by MinGW #### MinGW/msys2 64 bit Install: [https://repo.msys2.org/distrib/x86\_64/msys2-x86\_64-20200903.exe](https://repo.msys2.org/distrib/x86_64/msys2-x86_64-20200903.exe) +The file `appveyor_mingw_cygwin.yml` has instructions to configure the AppVeyor CI to configures itself to build Exiv2 on MinGW/msys2 and Cygwin/64. + I use the following batch file to start the MinGW/msys2 64 bit bash shell from the Dos Command Prompt (cmd.exe) ```bat @@ -1154,7 +1184,9 @@ Please note that the platform Cygwin/32 is obsolete and superceded by Cygwin/64. Download: [https://cygwin.com/install.html](https://cygwin.com/install.html) and run setup-x86_64.exe. I install into c:\\cygwin64 You need: -make, cmake, curl, gcc, gettext-devel pkg-config, dos2unix, tar, zlib-devel, libexpat1-devel, git, python3-interpreter, libiconv, libxml2-utils, libncurses +make, cmake, curl, gcc, gettext-devel pkg-config, dos2unix, tar, zlib-devel, libexpat1-devel, git, libxml2-devel python3-interpreter, libiconv, libxml2-utils, libncurses, libxml2-devel libxslt-devel python38 python38-pip python38-libxml2 + +The file `appveyor_mingw_cygwin.yml` has instructions to configure the AppVeyor CI to configures itself to build Exiv2 on MinGW/msys2 and Cygwin/64. To build unit tests, you should install googletest-release-1.8.0 as discussed [4.3 Unit tests](#4-3) @@ -1304,5 +1336,5 @@ $ sudo pkg install developer/gcc-7 [TOC](#TOC) -Written by Robin Mills
robin@clanmills.com
Updated: 2020-11-20 +Written by Robin Mills
robin@clanmills.com
Updated: 2021-03-05 diff --git a/appveyor.yml b/appveyor.yml index 6ad59c87..29f4ce68 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -74,7 +74,7 @@ build_script: - cmd: conan --version - cmd: conan install .. -o webready=%WEBREADY% --build missing - cmd: echo %CMAKE_GENERATOR% - - cmd: cmake -G "%CMAKE_GENERATOR%" -DEXIV2_TEAM_WARNINGS_AS_ERRORS=%WARNINGS_AS_ERRORS% -DCMAKE_BUILD_TYPE=Release -DEXIV2_ENABLE_NLS=OFF -DEXIV2_ENABLE_PNG=ON -DEXIV2_ENABLE_WEBREADY=%WEBREADY% -DEXIV2_BUILD_UNIT_TESTS=%UNIT_TESTS% -DCMAKE_INSTALL_PREFIX=install .. + - cmd: cmake -G "%CMAKE_GENERATOR%" -DEXIV2_TEAM_WARNINGS_AS_ERRORS=%WARNINGS_AS_ERRORS% -DCMAKE_BUILD_TYPE=Release -DEXIV2_ENABLE_NLS=OFF -DEXIV2_ENABLE_PNG=ON -DEXIV2_ENABLE_BMFF=ON -DEXIV2_ENABLE_WEBREADY=%WEBREADY% -DEXIV2_BUILD_UNIT_TESTS=%UNIT_TESTS% -DCMAKE_INSTALL_PREFIX=install .. - cmd: cmake --build . --config Release - cmd: cmake --build . --config Release --target install - cmd: cd bin diff --git a/ci/install.sh b/ci/install.sh index 599dbce1..6d520d27 100755 --- a/ci/install.sh +++ b/ci/install.sh @@ -10,11 +10,12 @@ python3 --version if [[ "$(uname -s)" == 'Linux' ]]; then sudo apt-get update + sudo apt-get install cmake if [[ "$(lsb_release -cs)" == 'focal' ]]; then # In Ubuntu 20.04 python-pip does not exist. Furthermore we need to have the alias python for python3 - sudo apt-get install cmake zlib1g-dev libssh-dev python3-pip python-is-python3 libxml2-utils + sudo apt-get install zlib1g-dev libssh-dev python3-pip python-is-python3 libxml2-utils else - sudo apt-get install cmake zlib1g-dev libssh-dev python-pip libxml2-utils + sudo apt-get install zlib1g-dev libssh-dev python-pip libxml2-utils fi if [ -n "$WITH_VALGRIND" ]; then diff --git a/ci/test_build.py b/ci/test_build.py index 462409bd..9faaafc9 100644 --- a/ci/test_build.py +++ b/ci/test_build.py @@ -117,7 +117,7 @@ if __name__ == '__main__': type=str, nargs='?', default="-DEXIV2_TEAM_EXTRA_WARNINGS=ON -DEXIV2_ENABLE_VIDEO=ON " - "-DEXIV2_ENABLE_WEBREADY=ON -DEXIV2_BUILD_UNIT_TESTS=ON " + "-DEXIV2_ENABLE_WEBREADY=ON -DEXIV2_BUILD_UNIT_TESTS=ON -DEXIV2_ENABLE_BMFF=ON " "-DBUILD_WITH_CCACHE=ON -DEXIV2_ENABLE_CURL=ON" ) diff --git a/cmake/compilerFlagsExiv2.cmake b/cmake/compilerFlagsExiv2.cmake index 76f00fe6..d364b695 100644 --- a/cmake/compilerFlagsExiv2.cmake +++ b/cmake/compilerFlagsExiv2.cmake @@ -1,8 +1,14 @@ # These flags only applies to exiv2lib, and the applications, but not to the xmp code +include(CheckCXXCompilerFlag) + if (COMPILER_IS_GCC OR COMPILER_IS_CLANG) # MINGW, Linux, APPLE, CYGWIN if ( EXIV2_TEAM_WARNINGS_AS_ERRORS ) add_compile_options(-Werror -Wno-error=deprecated-declarations) + check_cxx_compiler_flag(-Wno-error=deprecated-copy DEPRECATED_COPY) + if ( DEPRECATED_COPY) + add_compile_options(-Wno-error=deprecated-copy) + endif () endif () if ( EXIV2_TEAM_EXTRA_WARNINGS ) diff --git a/cmake/config.h.cmake b/cmake/config.h.cmake index 4694d99e..b633d127 100644 --- a/cmake/config.h.cmake +++ b/cmake/config.h.cmake @@ -18,6 +18,9 @@ // Define if you want translation of program messages to the user's native language #cmakedefine EXV_ENABLE_NLS +// Define if you want BMFF support. +#cmakedefine EXV_ENABLE_BMFF + // Define if you want video support. #cmakedefine EXV_ENABLE_VIDEO diff --git a/cmake/generateConfigFile.cmake b/cmake/generateConfigFile.cmake index 58a632ca..fe1cabbd 100644 --- a/cmake/generateConfigFile.cmake +++ b/cmake/generateConfigFile.cmake @@ -7,6 +7,7 @@ if (${EXIV2_ENABLE_WEBREADY}) set(EXV_USE_SSH ${EXIV2_ENABLE_SSH}) set(EXV_USE_CURL ${EXIV2_ENABLE_CURL}) endif() +set(EXV_ENABLE_BMFF ${EXIV2_ENABLE_BMFF}) set(EXV_ENABLE_VIDEO ${EXIV2_ENABLE_VIDEO}) set(EXV_ENABLE_WEBREADY ${EXIV2_ENABLE_WEBREADY}) set(EXV_HAVE_LENSDATA ${EXIV2_ENABLE_LENSDATA}) diff --git a/cmake/printSummary.cmake b/cmake/printSummary.cmake index 8b9e1823..2f3e1fc4 100644 --- a/cmake/printSummary.cmake +++ b/cmake/printSummary.cmake @@ -50,6 +50,7 @@ if ( EXIV2_ENABLE_EXTERNAL_XMP ) else() OptionOutput( "XMP metadata support: " EXIV2_ENABLE_XMP ) endif() +OptionOutput( "Building BMFF support: " EXIV2_ENABLE_BMFF ) OptionOutput( "Native language support: " EXIV2_ENABLE_NLS ) OptionOutput( "Conversion of Windows XP tags: " EXIV2_ENABLE_PRINTUCS2 ) OptionOutput( "Nikon lens database: " EXIV2_ENABLE_LENSDATA ) diff --git a/include/exiv2/CMakeLists.txt b/include/exiv2/CMakeLists.txt index ccd9dfc6..c8900b56 100644 --- a/include/exiv2/CMakeLists.txt +++ b/include/exiv2/CMakeLists.txt @@ -1,6 +1,7 @@ install(FILES asfvideo.hpp basicio.hpp + bmffimage.hpp bmpimage.hpp config.h convert.hpp diff --git a/include/exiv2/bmffimage.hpp b/include/exiv2/bmffimage.hpp new file mode 100644 index 00000000..40128e44 --- /dev/null +++ b/include/exiv2/bmffimage.hpp @@ -0,0 +1,170 @@ +// ***************************************************************** -*- C++ -*- +/* + * Copyright (C) 2021 Exiv2 authors + * This program is part of the Exiv2 distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. + */ + +#pragma once + +// ***************************************************************************** +#include "exiv2lib_export.h" + +// included header files +#include "image.hpp" +#include "iostream" + +// ***************************************************************************** +// namespace extensions +namespace Exiv2 +{ + EXIV2API bool enableBMFF(bool enable = true); + + struct Iloc + { + Iloc(uint32_t ID = 0, uint32_t start = 0, uint32_t length = 0) : ID_(ID), start_(start), length_(length){}; + virtual ~Iloc(){}; + + uint32_t ID_; + uint32_t start_; + uint32_t length_; + + std::string toString() const; + }; // class Iloc + + // ***************************************************************************** + // class definitions + + // Add Base Media File Format to the supported image formats + namespace ImageType + { + const int bmff = 19; //!< BMFF (bmff) image type (see class BMFF) + } + + /*! + @brief Class to access BMFF images. + */ + class EXIV2API BmffImage : public Image + { + public: + //! @name Creators + //@{ + /*! + @brief Constructor to open a BMFF image. Since the + constructor can not return a result, callers should check the + good() method after object construction to determine success + or failure. + @param io An auto-pointer that owns a BasicIo instance used for + reading and writing image metadata. \b Important: The constructor + takes ownership of the passed in BasicIo instance through the + auto-pointer. Callers should not continue to use the BasicIo + instance after it is passed to this method. Use the Image::io() + method to get a temporary reference. + @param create Specifies if an existing image should be read (false) + or if a new file should be created (true). + */ + BmffImage(BasicIo::AutoPtr io, bool create); + //@} + + //@{ + /*! + @brief parse embedded tiff file (Exif metadata) + @param root_tag root of parse tree Tag::root, Tag::cmt2 etc. + @param length tiff block length + @param start offset in file (default, io_->tell()) + @ + */ + void parseTiff(uint32_t root_tag, uint32_t length); + void parseTiff(uint32_t root_tag, uint32_t length,uint32_t start); + //@} + + //@{ + /*! + @brief parse embedded xmp/xml + @param length xmp block length + @param start offset in file + @ + */ + void parseXmp(uint32_t length,uint32_t start); + //@} + + //! @name Manipulators + //@{ + void readMetadata() /* override */; + void writeMetadata() /* override */; + void setComment(const std::string& comment) /* override */; + void printStructure(std::ostream& out, Exiv2::PrintStructureOption option,int depth); + //@} + + //! @name Accessors + //@{ + std::string mimeType() const /* override */; + int pixelWidth() const; + int pixelHeight() const; + //@} + + Exiv2::ByteOrder endian_ ; + + private: + void openOrThrow(); + /*! + @brief recursiveBoxHandler + @throw Error if we visit a box more than once + @return address of next box + @warning This function should only be called by readMetadata() + */ + long boxHandler(std::ostream& out=std::cout, Exiv2::PrintStructureOption option=kpsNone,int depth = 0); + std::string indent(int i) + { + return std::string(2*i,' '); + } + + uint32_t fileType_; + std::set visits_; + uint64_t visits_max_; + uint16_t unknownID_; // 0xffff + uint16_t exifID_; + uint16_t xmpID_; + std::map ilocs_; + bool bReadMetadata_; + //@} + + /*! + @brief box utilities + */ + std::string toAscii(long n); + std::string boxName(uint32_t box); + bool superBox(uint32_t box); + bool fullBox(uint32_t box); + std::string uuidName(Exiv2::DataBuf& uuid); + + }; // class BmffImage + + // ***************************************************************************** + // template, inline and free functions + + // These could be static private functions on Image subclasses but then + // ImageFactory needs to be made a friend. + /*! + @brief Create a new BMFF instance and return an auto-pointer to it. + Caller owns the returned object and the auto-pointer ensures that + it will be deleted. + */ + EXIV2API Image::AutoPtr newBmffInstance(BasicIo::AutoPtr io, bool create); + + //! Check if the file iIo is a BMFF image. + EXIV2API bool isBmffType(BasicIo& iIo, bool advance); +} // namespace Exiv2 diff --git a/include/exiv2/exiv2.hpp b/include/exiv2/exiv2.hpp index e25733ca..5efd9d57 100644 --- a/include/exiv2/exiv2.hpp +++ b/include/exiv2/exiv2.hpp @@ -1,6 +1,6 @@ // ***************************************************************** -*- C++ -*- /* - * Copyright (C) 2004-2018 Exiv2 authors + * Copyright (C) 2004-2021 Exiv2 authors * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or @@ -17,13 +17,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ -/*! - @file exiv2.hpp - @brief Include all Exiv2 header files. - @author Andreas Huggel (ahu) - ahuggel@gmx.net - @date 21-Jun-10, ahu: created - */ #ifndef EXIV2_HPP_ #define EXIV2_HPP_ @@ -52,8 +45,11 @@ #include "exiv2/mrwimage.hpp" #include "exiv2/orfimage.hpp" #include "exiv2/pgfimage.hpp" +#ifdef EXV_ENABLE_BMFF +#include "bmffimage.hpp" +#endif -#ifdef EXV_HAVE_LIBZ +#ifdef EXV_HAVE_LIBZ #include "exiv2/pngimage.hpp" #endif @@ -76,4 +72,4 @@ #include "exiv2/xmp_exiv2.hpp" #include "exiv2/xmpsidecar.hpp" -#endif // #ifndef EXIV2_HPP_ +#endif//ifndef EXIV2_HPP_ diff --git a/man/man1/exiv2.1 b/man/man1/exiv2.1 index 448ab14e..c8b382de 100644 --- a/man/man1/exiv2.1 +++ b/man/man1/exiv2.1 @@ -2,7 +2,7 @@ .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) -.TH EXIV2 1 "Nov 6, 2020" +.TH EXIV2 1 "Mar 8, 2021" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: @@ -39,31 +39,34 @@ lB lB lB lB lB lB _ _ _ _ _ _ l l l l l l. Type Exif IPTC XMP Image Comments ICC Profile -JPEG Read/Write Read/Write Read/Write Read/Write Read/Write -EXV Read/Write Read/Write Read/Write Read/Write Read/Write +ARW Read Read Read - - +AVIF Read Read Read - - +BMP - - - - - CR2 Read/Write Read/Write Read/Write - Read/Write +CR3 Read Read Read - Read CRW Read/Write - - Read/Write - -MRW Read Read Read - - -TIFF Read/Write Read/Write Read/Write - Read/Write -WEBP Read/Write - Read/Write - Read/Write DNG Read/Write Read/Write Read/Write - Read/Write +EPS - - Read/Write - - +EXV Read/Write Read/Write Read/Write Read/Write Read/Write +GIF - - - - - +HEIF Read Read Read - - +JP2 Read/Write Read/Write Read/Write - Read/Write +JPEG Read/Write Read/Write Read/Write Read/Write Read/Write +MRW Read Read Read - - NEF Read/Write Read/Write Read/Write - Read/Write +ORF Read/Write Read/Write Read/Write - - PEF Read/Write Read/Write Read/Write - Read/Write -ARW Read Read Read - - +PGF Read/Write Read/Write Read/Write Read/Write Read/Write +PNG Read/Write Read/Write Read/Write Read/Write Read/Write +PSD Read/Write Read/Write Read/Write - - +RAF Read Read Read - - RW2 Read Read Read - - SR2 Read Read Read - - SRW Read/Write Read/Write Read/Write - - -ORF Read/Write Read/Write Read/Write - - -PNG Read/Write Read/Write Read/Write Read/Write Read/Write -PGF Read/Write Read/Write Read/Write Read/Write Read/Write -RAF Read Read Read - - -EPS - - Read/Write - - -XMP - - Read/Write - - -GIF - - - - - -PSD Read/Write Read/Write Read/Write - - TGA - - - - - -BMP - - - - - -JP2 Read/Write Read/Write Read/Write - Read/Write +TIFF Read/Write Read/Write Read/Write - Read/Write +WEBP Read/Write - Read/Write - Read/Write +XMP - - Read/Write - - .TE .IP \(bu 2 Support for GIF, TGA and BMP images is minimal: the image format is @@ -132,7 +135,7 @@ exiv2 [ opt [arg] ]+ [ act ] file ... .sp 1 option [arg] long option description -a tim --adjust Modify time stamps. [+|-]HH[:MM[:SS[.mmm]]] --b --binary This option is obsolete and does nothing. +-b --binary This option is obsolete and should not be used. Reserved for test suite (with option -pC) -c txt --comment JPEG comment string to set in the image ('modify' action). ... -d tgt --delete Delete target(s) for the 'delete' action. ... -D +-n --days Time adjustment by a positive or negative number of days ... diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 10235579..df355bc4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -118,6 +118,12 @@ if( EXIV2_ENABLE_VIDEO ) ) endif() +if( EXIV2_ENABLE_BMFF ) + target_sources(exiv2lib PRIVATE + bmffimage.cpp ../include/exiv2/bmffimage.hpp + ) +endif() + # Other library target properties # --------------------------------------------------------- diff --git a/src/actions.cpp b/src/actions.cpp index a6f885a1..c7ca7726 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -230,10 +230,34 @@ namespace Action { { } - int setModeAndPrintStructure(Exiv2::PrintStructureOption option, const std::string& path) - { - _setmode(_fileno(stdout),O_BINARY); - return printStructure(std::cout, option, path); + int setModeAndPrintStructure(Exiv2::PrintStructureOption option, const std::string& path,bool binary) + { + int result = 0 ; + if ( binary && option == Exiv2::kpsIccProfile ) { + std::stringstream output(std::stringstream::out|std::stringstream::binary); + result = printStructure(output, option, path); + if ( result == 0 ) { + size_t size = (long) output.str().size(); + Exiv2::DataBuf iccProfile((long)size); + Exiv2::DataBuf ascii((long)(size * 3 + 1)); + ascii.pData_[size * 3] = 0; + ::memcpy(iccProfile.pData_,output.str().c_str(),size); + if ( Exiv2::base64encode(iccProfile.pData_,size,(char*)ascii.pData_,size*3) ) { + long chunk = 60 ; + std::string code = std::string("data:") + std::string((char*)ascii.pData_); + long length = (long) code.size() ; + for ( long start = 0 ; start < length ; start += chunk ) { + long count = (start+chunk) < length ? chunk : length - start ; + std::cout << code.substr(start,count) << std::endl; + } + } + } + } else { + _setmode(_fileno(stdout),O_BINARY); + result = printStructure(std::cout, option, path); + } + + return result; } int Print::run(const std::string& path) @@ -252,12 +276,12 @@ namespace Action { case Params::pmXMP: if (option == Exiv2::kpsNone) option = Exiv2::kpsXMP; - rc = setModeAndPrintStructure(option, path_); + rc = setModeAndPrintStructure(option, path_,binary()); break; case Params::pmIccProfile: if (option == Exiv2::kpsNone) option = Exiv2::kpsIccProfile; - rc = setModeAndPrintStructure(option, path_); + rc = setModeAndPrintStructure(option, path_,binary()); break; } return rc; diff --git a/src/actions.hpp b/src/actions.hpp index e63613cd..68a96896 100644 --- a/src/actions.hpp +++ b/src/actions.hpp @@ -77,10 +77,22 @@ namespace Action { @return 0 if successful. */ virtual int run(const std::string& path) =0; + + /*! + @brief Application interface to perform a task. + + @param path Path of the file to process. + @return 0 if successful. + */ + bool setBinary(bool b) { bool bResult = binary_ ; binary_ = b ; return bResult ;} + bool binary() { return binary_ ; } private: //! Internal virtual copy constructor. virtual Task* clone_() const =0; + + //! copy binary_ from command-line params to task + bool binary_ ; }; // class Task diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp new file mode 100644 index 00000000..1ec511ae --- /dev/null +++ b/src/bmffimage.cpp @@ -0,0 +1,608 @@ +// ***************************************************************** -*- C++ -*- +/* + * Copyright (C) 2021 Exiv2 authors + * This program is part of the Exiv2 distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. + */ + +// ***************************************************************************** + +// #define EXIV2_DEBUG_MESSAGES + +// included header files +#include "bmffimage.hpp" + +#include "basicio.hpp" +#include "config.h" +#include "error.hpp" +#include "futils.hpp" +#include "image.hpp" +#include "image_int.hpp" +#include "safe_op.hpp" +#include "tiffimage.hpp" +#include "tiffimage_int.hpp" +#include "types.hpp" +#include "unused.h" + +// + standard includes +#include +#include +#include +#include +#include + +struct BmffBoxHeader +{ + uint32_t length; + uint32_t type; +}; + +#define TAG_ftyp 0x66747970 /**< "ftyp" File type box */ +#define TAG_avif 0x61766966 /**< "avif" AVIF */ +#define TAG_heic 0x68656963 /**< "heic" HEIC */ +#define TAG_heif 0x68656966 /**< "heif" HEIF */ +#define TAG_crx 0x63727820 /**< "crx " Canon CR3 */ +#define TAG_moov 0x6d6f6f76 /**< "moov" Movie */ +#define TAG_meta 0x6d657461 /**< "meta" Metadata */ +#define TAG_mdat 0x6d646174 /**< "mdat" Media data */ +#define TAG_uuid 0x75756964 /**< "uuid" UUID */ +#define TAG_dinf 0x64696e66 /**< "dinf" Data information */ +#define TAG_iprp 0x69707270 /**< "iprp" Item properties */ +#define TAG_ipco 0x6970636f /**< "ipco" Item property container */ +#define TAG_iinf 0x69696e66 /**< "iinf" Item info */ +#define TAG_iloc 0x696c6f63 /**< "iloc" Item location */ +#define TAG_ispe 0x69737065 /**< "ispe" Image spatial extents */ +#define TAG_infe 0x696e6665 /**< "infe" Item Info Extention */ +#define TAG_ipma 0x69706d61 /**< "ipma" Item Property Association */ +#define TAG_cmt1 0x434d5431 /**< "CMT1" ifd0Id */ +#define TAG_cmt2 0x434D5432 /**< "CMD2" exifID */ +#define TAG_cmt3 0x434D5433 /**< "CMT3" canonID */ +#define TAG_cmt4 0x434D5434 /**< "CMT4" gpsID */ +#define TAG_colr 0x636f6c72 /**< "colr" */ + +// ***************************************************************************** +// class member definitions +namespace Exiv2 +{ + static bool enabled = false; + + EXIV2API bool enableBMFF(bool enable) + { +#ifdef EXV_ENABLE_BMFF + enabled = enable; + return true; +#else + UNUSED(enable); + return false; +#endif // EXV_ENABLE_BMFF + } + + std::string Iloc::toString() const + { + return Internal::stringFormat("ID = %u from,length = %u,%u", ID_, start_, length_); + } + + BmffImage::BmffImage(BasicIo::AutoPtr io, bool /* create */) + : Image(ImageType::bmff, mdExif | mdIptc | mdXmp, io) + , endian_(Exiv2::bigEndian) + { + pixelWidth_ = 0; + pixelHeight_ = 0; + bReadMetadata_ = false; + } // BmffImage::BmffImage + + std::string BmffImage::toAscii(long n) + { + const char* p = (const char*)&n; + std::string result; + for (int i = 0; i < 4; i++) { + char c = p[isBigEndianPlatform() ? i : (3 - i)]; + result += (32<=c && c<127) ? c // only allow 7-bit printable ascii + : c==0 ? '_' // show 0 as _ + : '.' ; // others . + } + return result; + } + + bool BmffImage::superBox(uint32_t box) + { + return box == TAG_moov || box == TAG_dinf || box == TAG_iprp || box == TAG_ipco || box == TAG_meta || + box == TAG_iinf || box == TAG_iloc; + } + + bool BmffImage::fullBox(uint32_t box) + { + return box == TAG_meta || box == TAG_iinf || box == TAG_iloc; + } + + std::string BmffImage::mimeType() const + { + switch (fileType_) { + case TAG_avif: + return "image/avif"; + case TAG_heic: + case TAG_heif: + return "image/heif"; + case TAG_crx: + return "image/x-canon-cr3"; + default: + return "image/generic"; + } + } + + int BmffImage::pixelWidth() const + { + ExifData::const_iterator imageWidth = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelXDimension")); + if (imageWidth != exifData_.end() && imageWidth->count() > 0) { + return imageWidth->toLong(); + } + return 0; + } + + int BmffImage::pixelHeight() const + { + ExifData::const_iterator imageHeight = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelYDimension")); + if (imageHeight != exifData_.end() && imageHeight->count() > 0) { + return imageHeight->toLong(); + } + return 0; + } + + std::string BmffImage::uuidName(Exiv2::DataBuf& uuid) + { + const char* uuidCano = "\x85\xC0\xB6\x87\x82\xF\x11\xE0\x81\x11\xF4\xCE\x46\x2B\x6A\x48"; + const char* uuidXmp = "\xBE\x7A\xCF\xCB\x97\xA9\x42\xE8\x9C\x71\x99\x94\x91\xE3\xAF\xAC"; + const char* uuidCanp = "\xEA\xF4\x2B\x5E\x1C\x98\x4B\x88\xB9\xFB\xB7\xDC\x40\x6E\x4D\x16"; + const char* result = std::memcmp(uuid.pData_, uuidCano, 16) == 0 ? "cano" + : std::memcmp(uuid.pData_, uuidXmp, 16) == 0 ? "xmp" + : std::memcmp(uuid.pData_, uuidCanp, 16) == 0 ? "canp" + : ""; + return result; + } + + long BmffImage::boxHandler(std::ostream& out /* = std::cout*/ , Exiv2::PrintStructureOption option /* = kpsNone */,int depth /* =0 */) + { + long result = (long)io_->size(); + long address = (long)io_->tell(); + // never visit a box twice! + if ( depth == 0 ) visits_.clear(); + if (visits_.find(address) != visits_.end() || visits_.size() > visits_max_) { + throw Error(kerCorruptedMetadata); + } + visits_.insert(address); + + bool bTrace = option == kpsBasic || option == kpsRecursive ; +#ifdef EXIV2_DEBUG_MESSAGES + bTrace = true ; +#endif + + BmffBoxHeader box = {0, 0}; + if (io_->read((byte*)&box, sizeof(box)) != sizeof(box)) + return result; + + box.length = getLong((byte*)&box.length, endian_); + box.type = getLong((byte*)&box.type, endian_); + bool bLF = true; + + if ( bTrace ) { + bLF = true; + out << indent(depth) << "Exiv2::BmffImage::boxHandler: " << toAscii(box.type) + << Internal::stringFormat(" %8ld->%u ", address, box.length); + } + + if (box.length == 1) { + DataBuf data(8); + io_->read(data.pData_, data.size_); + result = (long) getULongLong(data.pData_, endian_); + // sanity check + if (result < 8 || result+address > (long)io_->size()) { + result = (long)io_->size(); + box.length = result; + } else { + box.length = (long) (io_->size() - address); + } + } + + // read data in box and restore file position + long restore = io_->tell(); + DataBuf data(box.length - 8); + io_->read(data.pData_, data.size_); + io_->seek(restore, BasicIo::beg); + + uint32_t skip = 0; // read position in data.pData_ + uint8_t version = 0; + uint32_t flags = 0; + + if (fullBox(box.type)) { + flags = getLong(data.pData_ + skip, endian_); // version/flags + version = (int8_t)flags >> 24; + version &= 0x00ffffff; + skip += 4; + } + + switch (box.type) { + case TAG_ftyp: { + fileType_ = getLong(data.pData_, endian_); + if ( bTrace ) { + out << "brand: " << toAscii(fileType_); + } + } break; + + // 8.11.6.1 + case TAG_iinf: { + if ( bTrace ) { + out << std::endl; + bLF = false; + } + + int n = getShort(data.pData_ + skip, endian_); + skip += 2; + + io_->seek(skip, BasicIo::cur); + while (n-- > 0) { + io_->seek(boxHandler(out,option,depth + 1), BasicIo::beg); + } + } break; + + // 8.11.6.2 + case TAG_infe: { // .__._.__hvc1_ 2 0 0 1 0 1 0 0 104 118 99 49 0 + /* getLong (data.pData_+skip,endian_) ; */ skip += 4; + uint16_t ID = getShort(data.pData_ + skip, endian_); + skip += 2; + /* getShort(data.pData_+skip,endian_) ; */ skip += 2; // protection + std::string id; + std::string name((const char*)data.pData_ + skip); + if ( !name.find("Exif") ) { // "Exif" or "ExifExif" + exifID_ = ID; + id=" *** Exif ***"; + } else if ( !name.find("mime\0xmp") || !name.find("mime\0application/rdf+xml") ) { + xmpID_ = ID; + id=" *** XMP ***"; + } + if ( bTrace ) { + out << Internal::stringFormat("ID = %3d ", ID) << name << " " << id; + } + } break; + + case TAG_moov: + case TAG_iprp: + case TAG_ipco: + case TAG_meta: { + if ( bTrace ) { + out << std::endl; + bLF = false; + } + io_->seek(skip, BasicIo::cur); + while ((long)io_->tell() < (long)(address + box.length)) { + io_->seek(boxHandler(out,option,depth + 1), BasicIo::beg); + } + // post-process meta box to recover Exif and XMP + if (box.type == TAG_meta) { + if ( ilocs_.find(exifID_) != ilocs_.end()) { + const Iloc& iloc = ilocs_.find(exifID_)->second; + if ( bTrace ) { + out << indent(depth) << "Exiv2::BMFF Exif: " << iloc.toString() << std::endl; + } + parseTiff(Internal::Tag::root,iloc.length_,iloc.start_); + } + if ( ilocs_.find(xmpID_) != ilocs_.end()) { + const Iloc& iloc = ilocs_.find(xmpID_)->second; + if ( bTrace ) { + out << indent(depth) << "Exiv2::BMFF XMP: " << iloc.toString() << std::endl; + } + parseXmp(iloc.length_,iloc.start_); + } + ilocs_.clear() ; + } + } break; + + // 8.11.3.1 + case TAG_iloc: { + uint8_t u = data.pData_[skip++]; + uint16_t offsetSize = u >> 4; + uint16_t lengthSize = u & 0xF; +#if 0 + uint16_t indexSize = 0 ; + u = data.pData_[skip++]; + if ( version == 1 || version == 2 ) { + indexSize = u & 0xF ; + } +#else + skip++; +#endif + uint32_t itemCount = version < 2 ? getShort(data.pData_ + skip, endian_) + : getLong(data.pData_ + skip, endian_); + skip += version < 2 ? 2 : 4; + if (itemCount && itemCount < box.length / 14 && offsetSize == 4 && lengthSize == 4 && + ((box.length - 16) % itemCount) == 0) { + if ( bTrace ) { + out << std::endl; + bLF = false; + } + uint32_t step = (box.length - 16) / itemCount; // length of data per item. + uint32_t base = skip; + for (uint32_t i = 0; i < itemCount; i++) { + skip = base + i * step; // move in 14, 16 or 18 byte steps + uint32_t ID = version > 2 ? getLong(data.pData_ + skip, endian_) + : getShort(data.pData_ + skip, endian_); + uint32_t offset = step==14 || step==16 ? getLong(data.pData_ + skip + step - 8, endian_) + : step== 18 ? getLong(data.pData_ + skip + 4, endian_) + : 0 ; + + uint32_t ldata = getLong(data.pData_ + skip + step - 4, endian_); + if ( bTrace ) { + out << indent(depth) + << Internal::stringFormat("%8ld | %8u | ID | %4u | %6u,%6u", address + skip, step, + ID, offset, ldata) + << std::endl; + } + // save data for post-processing in meta box + if ( offset && ldata && ID != unknownID_ ) { + ilocs_[ID] = Iloc(ID, offset, ldata); + } + } + } + } break; + + case TAG_ispe: { + skip += 4; + int width = (int)getLong(data.pData_ + skip, endian_); + skip += 4; + int height = (int)getLong(data.pData_ + skip, endian_); + skip += 4; + if ( bTrace ) { + out << "pixelWidth_, pixelHeight_ = " << Internal::stringFormat("%d, %d", width, height); + } + // HEIC files can have multiple ispe records + // Store largest width/height + if (width > pixelWidth_ && height > pixelHeight_) { + pixelWidth_ = width; + pixelHeight_ = height; + } + } break; + + // 12.1.5.2 + case TAG_colr: { + if ( data.size_ >= (long) (skip+4+sizeof(box)) ) { // .____.HLino..__mntrR 2 0 0 0 0 12 72 76 105 110 111 2 16 ... + // https://www.ics.uci.edu/~dan/class/267/papers/jpeg2000.pdf + uint8_t meth = data.pData_[skip+0]; + uint8_t prec = data.pData_[skip+1]; + uint8_t approx = data.pData_[skip+2]; + std::string colour_type = std::string((char*)data.pData_,4) ; + skip+=4; + if ( colour_type == "rICC" || colour_type == "prof" ) { + DataBuf profile(data.pData_+skip,data.size_-skip); + setIccProfile(profile); + } else if ( meth == 2 && prec == 0 && approx == 0 ) { + // JP2000 files have a 3 byte head // 2 0 0 icc...... + skip -= 1 ; + DataBuf profile(data.pData_+skip,data.size_-skip); + setIccProfile(profile); + } + } + } break; + + case TAG_uuid: { + DataBuf uuid(16); + io_->read(uuid.pData_, uuid.size_); + std::string name = uuidName(uuid); + if ( bTrace ) { + out << " uuidName " << name << std::endl; + bLF = false; + } + if (name == "cano") { + while ((long)io_->tell() < (long)(address + box.length)) { + io_->seek(boxHandler(out,option,depth + 1), BasicIo::beg); + } + } else if ( name == "xmp" ) { + parseXmp(box.length,io_->tell()); + } + } break; + + case TAG_cmt1: + parseTiff(Internal::Tag::root, box.length); + break; + case TAG_cmt2: + parseTiff(Internal::Tag::cmt2, box.length); + break; + case TAG_cmt3: + parseTiff(Internal::Tag::cmt3, box.length); + break; + case TAG_cmt4: + parseTiff(Internal::Tag::cmt4, box.length); + break; + + default: break ; /* do nothing */ + } + if ( bLF&& bTrace) out << std::endl; + + // return address of next box + result = static_cast(address + box.length); + + return result; + } + + void BmffImage::parseTiff(uint32_t root_tag, uint32_t length,uint32_t start) + { + // read and parse exif data + long restore = io_->tell(); + DataBuf exif(length); + io_->seek(start,BasicIo::beg); + if ( exif.size_ > 8 && io_->read(exif.pData_,exif.size_) == exif.size_ ) { + // hunt for "II" or "MM" + long eof = 0xffffffff; // impossible value for punt + long punt = eof; + for ( long i = 0 ; i < exif.size_ -8 && punt==eof ; i+=2) { + if ( exif.pData_[i] == exif.pData_[i+1] ) + if ( exif.pData_[i] == 'I' || exif.pData_[i] == 'M' ) + punt = i; + } + if ( punt != eof ) { + Internal::TiffParserWorker::decode(exifData(), iptcData(), xmpData(), + exif.pData_+punt, exif.size_-punt, root_tag, + Internal::TiffMapping::findDecoder); + } + } + io_->seek(restore,BasicIo::beg); + } + + void BmffImage::parseTiff(uint32_t root_tag, uint32_t length) + { + if (length > 8) { + DataBuf data(length - 8); + long bufRead = io_->read(data.pData_, data.size_); + + if (io_->error()) + throw Error(kerFailedToReadImageData); + if (bufRead != data.size_) + throw Error(kerInputDataReadFailed); + + Internal::TiffParserWorker::decode(exifData(), iptcData(), xmpData(), + data.pData_, data.size_, root_tag, + Internal::TiffMapping::findDecoder); + } + } + + void BmffImage::parseXmp(uint32_t length,uint32_t start) + { + if (length > 8) { + long restore = io_->tell() ; + io_->seek(start,BasicIo::beg); + + DataBuf xmp(length+1); + xmp.pData_[length]=0 ; // ensure xmp is null terminated! + if ( io_->read(xmp.pData_, length) != length ) + throw Error(kerInputDataReadFailed); + if ( io_->error() ) + throw Error(kerFailedToReadImageData); + try { + Exiv2::XmpParser::decode(xmpData(),std::string((char*)xmp.pData_)); + } catch (...) { + throw Error(kerFailedToReadImageData); + } + + io_->seek(restore,BasicIo::beg); + } + } + + void BmffImage::setComment(const std::string& /*comment*/) + { + // bmff files are read-only + throw(Error(kerInvalidSettingForImage, "Image comment", "BMFF")); + } // BmffImage::setComment + + void BmffImage::openOrThrow() + { + if (io_->open() != 0) { + throw Error(kerDataSourceOpenFailed, io_->path(), strError()); + } + // Ensure that this is the correct image type + if (!isBmffType(*io_, false)) { + if (io_->error() || io_->eof()) + throw Error(kerFailedToReadImageData); + throw Error(kerNotAnImage, "BMFF"); + } + } // Bmff::openOrThrow(); + + void BmffImage::readMetadata() + { + openOrThrow(); + IoCloser closer(*io_); + + clearMetadata(); + ilocs_.clear(); + visits_max_ = io_->size() / 16; + unknownID_ = 0xffff; + exifID_ = unknownID_; + + long address = 0; + while (address < (long)io_->size()) { + io_->seek(address, BasicIo::beg); + address = boxHandler(std::cout,kpsNone); + } + bReadMetadata_ = true; + } // BmffImage::readMetadata + + void BmffImage::printStructure(std::ostream& out, Exiv2::PrintStructureOption option,int depth) + { + if ( !bReadMetadata_ ) readMetadata(); + + switch (option) { + default: break; // do nothing + + case kpsIccProfile : { + out.write((const char*)iccProfile_.pData_,iccProfile_.size_); + } break; + +#ifdef EXV_HAVE_XMP_TOOLKIT + case kpsXMP : { + std::string xmp; + if ( Exiv2::XmpParser::encode(xmp, xmpData()) ) { + throw Exiv2::Error(Exiv2::kerErrorMessage, "Failed to serialize XMP data"); + } + out << xmp; + } break; +#endif + case kpsBasic : // drop + case kpsRecursive : { + openOrThrow(); + IoCloser closer(*io_); + + long address = 0; + while (address < (long)io_->size()) { + io_->seek(address, BasicIo::beg); + address = boxHandler(out,option,depth); + } + }; break; + } + } + + void BmffImage::writeMetadata() + { + // bmff files are read-only + throw(Error(kerInvalidSettingForImage, "Image comment", "BMFF")); + } // BmffImage::writeMetadata + + // ************************************************************************* + // free functions + Image::AutoPtr newBmffInstance(BasicIo::AutoPtr io, bool create) + { + Image::AutoPtr image(new BmffImage(io, create)); + if (!image->good()) { + image.reset(); + } + return image; + } + + bool isBmffType(BasicIo& iIo, bool advance) + { + if (!enabled) { + return false; + } + const int32_t len = 12; + byte buf[len]; + iIo.read(buf, len); + if (iIo.error() || iIo.eof()) { + return false; + } + + bool matched = buf[4] == 'f' && buf[5] == 't' && buf[6] == 'y' && buf[7] == 'p'; + if (!advance || !matched) { + iIo.seek(static_cast(0), BasicIo::beg); + } + return matched; + } +} // namespace Exiv2 diff --git a/src/exiv2.cpp b/src/exiv2.cpp index 0754cd78..7fc03a70 100644 --- a/src/exiv2.cpp +++ b/src/exiv2.cpp @@ -49,7 +49,6 @@ #include #endif - // ***************************************************************************** // local declarations namespace { @@ -137,6 +136,10 @@ int main(int argc, char* const argv[]) textdomain(EXV_PACKAGE_NAME); #endif +#ifdef EXV_ENABLE_BMFF + Exiv2::enableBMFF(); +#endif + // Handle command line arguments Params& params = Params::instance(); if (params.getopt(argc, argv)) { @@ -169,6 +172,7 @@ int main(int argc, char* const argv[]) std::cout << _("File") << " " << std::setw(w) << std::right << n++ << "/" << s << ": " << *i << std::endl; } + task->setBinary(params.binary_); int ret = task->run(*i); if (rc == 0) rc = ret; @@ -385,7 +389,7 @@ int Params::option(int opt, const std::string& optarg, int optopt) case 'q': Exiv2::LogMsg::setLevel(Exiv2::LogMsg::mute); break; case 'Q': rc = setLogLevel(optarg); break; case 'k': preserve_ = true; break; - case 'b': binary_ = false; break; + case 'b': binary_ = true; break; case 'u': unknown_ = false; break; case 'f': force_ = true; fileExistsPolicy_ = overwritePolicy; break; case 'F': force_ = true; fileExistsPolicy_ = renamePolicy; break; diff --git a/src/exiv2app.hpp b/src/exiv2app.hpp index b71fe9b5..dd3b8784 100644 --- a/src/exiv2app.hpp +++ b/src/exiv2app.hpp @@ -271,7 +271,7 @@ private: version_(false), verbose_(false), force_(false), - binary_(true), + binary_(false), unknown_(true), preserve_(false), timestamp_(false), diff --git a/src/futils.cpp b/src/futils.cpp index d55fcb6b..e0757e93 100644 --- a/src/futils.cpp +++ b/src/futils.cpp @@ -139,123 +139,83 @@ namespace Exiv2 { delete [] decodeStr; } + // https://stackoverflow.com/questions/342409/how-do-i-base64-encode-decode-in-c + static char base64_encode[]={'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/'}; + int base64encode(const void* data_buf, size_t dataLength, char* result, size_t resultSize) { - const char base64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - const uint8_t* data = (const uint8_t*)data_buf; - size_t resultIndex = 0; - size_t x; - uint32_t n = 0; - size_t padCount = dataLength % 3; - uint8_t n0, n1, n2, n3; - - /* increment over the length of the string, three characters at a time */ - for (x = 0; x < dataLength; x += 3) - { - /* these three 8-bit (ASCII) characters become one 24-bit number */ - n = data[x] << 16; - - if((x+1) < dataLength) - n += data[x+1] << 8; - - if((x+2) < dataLength) - n += data[x+2]; - - /* this 24-bit number gets separated into four 6-bit numbers */ - n0 = (uint8_t)(n >> 18) & 63; - n1 = (uint8_t)(n >> 12) & 63; - n2 = (uint8_t)(n >> 6) & 63; - n3 = (uint8_t)n & 63; - - /* - * if we have one byte available, then its encoding is spread - * out over two characters - */ - if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */ - result[resultIndex++] = base64chars[n0]; - if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */ - result[resultIndex++] = base64chars[n1]; - - /* - * if we have only two bytes available, then their encoding is - * spread out over three chars - */ - if((x+1) < dataLength) - { - if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */ - result[resultIndex++] = base64chars[n2]; - } + char* encoding_table = (char*)base64_encode; + size_t mod_table[] = {0, 2, 1}; - /* - * if we have all three bytes available, then their encoding is spread - * out over four characters - */ - if((x+2) < dataLength) - { - if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */ - result[resultIndex++] = base64chars[n3]; - } - } + size_t output_length = 4 * ((dataLength + 2) / 3); + int rc = result && data_buf && output_length < resultSize ? 1 : 0; + if ( rc ) { + const unsigned char* data = (const unsigned char*) data_buf ; + for (size_t i = 0, j = 0 ; i < dataLength;) { - /* - * create and add padding that is required if we did not have a multiple of 3 - * number of characters available - */ - if (padCount > 0) - { - for (; padCount < 3; padCount++) - { - if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */ - result[resultIndex++] = '='; + uint32_t octet_a = i < dataLength ? data[i++] : 0 ; + uint32_t octet_b = i < dataLength ? data[i++] : 0 ; + uint32_t octet_c = i < dataLength ? data[i++] : 0 ; + + uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; + + result[j++] = encoding_table[(triple >> 3 * 6) & 0x3F]; + result[j++] = encoding_table[(triple >> 2 * 6) & 0x3F]; + result[j++] = encoding_table[(triple >> 1 * 6) & 0x3F]; + result[j++] = encoding_table[(triple >> 0 * 6) & 0x3F]; } + + for (size_t i = 0; i < mod_table[dataLength % 3]; i++) + result[output_length - 1 - i] = '='; + result[output_length]=0; } - if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */ - result[resultIndex] = 0; - return 1; /* indicate success */ + return rc; } // base64encode - long base64decode(const char *in, char *out, size_t out_size) { - static const char decode[] = "|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW" - "$$$$$$XYZ[\\]^_`abcdefghijklmnopq"; - long len; - long i; - long done = 0; - unsigned char v; - unsigned char quad[4]; - - while (*in) { - len = 0; - for (i = 0; i < 4 && *in; i++) { - v = 0; - while (*in && !v) { - v = *in++; - v = (v < 43 || v > 122) ? 0 : decode[v - 43]; - if (v) - v = (v == '$') ? 0 : v - 61; - if (*in) { - len++; - if (v) - quad[i] = v - 1; - } else - quad[i] = 0; - } + long base64decode(const char* in,char* out,size_t out_size) { + long result = 0; + size_t input_length = in ? ::strlen(in) : 0; + if (!in || input_length % 4 != 0) return result; + + unsigned char* encoding_table = (unsigned char*)base64_encode; + unsigned char decoding_table[256]; + for (unsigned char i = 0; i < 64; i++) + decoding_table[encoding_table[i]] = i; + + size_t output_length = input_length / 4 * 3; + const unsigned char* buff = (const unsigned char*) in; + + if (buff[input_length - 1] == '=') (output_length)--; + if (buff[input_length - 2] == '=') (output_length)--; + + if ( output_length+1 < out_size ) { + for (size_t i = 0, j = 0; i < input_length;) { + + uint32_t sextet_a = buff[i] == '=' ? 0 & i++ : decoding_table[buff[i++]]; + uint32_t sextet_b = buff[i] == '=' ? 0 & i++ : decoding_table[buff[i++]]; + uint32_t sextet_c = buff[i] == '=' ? 0 & i++ : decoding_table[buff[i++]]; + uint32_t sextet_d = buff[i] == '=' ? 0 & i++ : decoding_table[buff[i++]]; + + uint32_t triple = (sextet_a << 3 * 6) + + (sextet_b << 2 * 6) + + (sextet_c << 1 * 6) + + (sextet_d << 0 * 6); + + if (j < output_length) out[j++] = (triple >> 2 * 8) & 0xFF; + if (j < output_length) out[j++] = (triple >> 1 * 8) & 0xFF; + if (j < output_length) out[j++] = (triple >> 0 * 8) & 0xFF; } - if (!len) - continue; - if (out_size < (size_t) (done + len - 1)) - /* out buffer is too small */ - return -1; - if (len >= 2) - *out++ = quad[0] << 2 | quad[1] >> 4; - if (len >= 3) - *out++ = quad[1] << 4 | quad[2] >> 2; - if (len >= 4) - *out++ = ((quad[2] << 6) & 0xc0) | quad[3]; - done += len - 1; + out[output_length]=0; + result = (long) output_length; } - if ((size_t)(done + 1) >= out_size) - return -1; - *out++ = '\0'; - return done; + + return result; } // base64decode Protocol fileProtocol(const std::string& path) { diff --git a/src/image.cpp b/src/image.cpp index c0d0633a..9267c8e4 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -31,14 +31,17 @@ #include "safe_op.hpp" #include "slice.hpp" +#ifdef EXV_ENABLE_BMFF +#include "bmffimage.hpp" +#endif// EXV_ENABLE_BMFF #include "cr2image.hpp" #include "crwimage.hpp" #include "epsimage.hpp" #include "jpgimage.hpp" #include "mrwimage.hpp" -#ifdef EXV_HAVE_LIBZ +#ifdef EXV_HAVE_LIBZ # include "pngimage.hpp" -#endif // EXV_HAVE_LIBZ +#endif// EXV_HAVE_LIBZ #include "rafimage.hpp" #include "tiffimage.hpp" #include "tiffimage_int.hpp" @@ -53,12 +56,12 @@ #include "jp2image.hpp" #include "nikonmn_int.hpp" -#ifdef EXV_ENABLE_VIDEO +#ifdef EXV_ENABLE_VIDEO #include "matroskavideo.hpp" #include "quicktimevideo.hpp" #include "riffvideo.hpp" #include "asfvideo.hpp" -#endif // EXV_ENABLE_VIDEO +#endif// EXV_ENABLE_VIDEO #include "rw2image.hpp" #include "pgfimage.hpp" #include "xmpsidecar.hpp" @@ -131,6 +134,9 @@ namespace { { ImageType::tga, newTgaInstance, isTgaType, amNone, amNone, amNone, amNone }, { ImageType::bmp, newBmpInstance, isBmpType, amNone, amNone, amNone, amNone }, { ImageType::jp2, newJp2Instance, isJp2Type, amReadWrite, amReadWrite, amReadWrite, amNone }, +#ifdef EXV_ENABLE_BMFF + { ImageType::bmff, newBmffInstance, isBmffType, amRead, amRead, amRead, amNone }, +#endif // EXV_ENABLE_BMFF #ifdef EXV_ENABLE_VIDEO { ImageType::qtime,newQTimeInstance,isQTimeType,amRead, amNone, amRead, amNone }, { ImageType::riff, newRiffInstance, isRiffType, amRead, amNone, amRead, amNone }, diff --git a/src/tiffcomposite_int.hpp b/src/tiffcomposite_int.hpp index 7153243b..f51bbbf3 100644 --- a/src/tiffcomposite_int.hpp +++ b/src/tiffcomposite_int.hpp @@ -76,12 +76,15 @@ namespace Exiv2 { Special TIFF tags for the use in TIFF structures only */ namespace Tag { - const uint32_t none = 0x10000; //!< Dummy tag - const uint32_t root = 0x20000; //!< Special tag: root IFD - const uint32_t next = 0x30000; //!< Special tag: next IFD - const uint32_t all = 0x40000; //!< Special tag: all tags in a group - const uint32_t pana = 0x80000; //!< Special tag: root IFD of Panasonic RAW images - const uint32_t fuji = 0x100000; //!< Special tag: root IFD of Fujifilm RAF images + const uint32_t none = 0x10000; //!< Dummy tag + const uint32_t root = 0x20000; //!< Special tag: root IFD + const uint32_t next = 0x30000; //!< Special tag: next IFD + const uint32_t all = 0x40000; //!< Special tag: all tags in a group + const uint32_t pana = 0x80000; //!< Special tag: root IFD of Panasonic RAW images + const uint32_t fuji = 0x100000; //!< Special tag: root IFD of Fujifilm RAF images + const uint32_t cmt2 = 0x110000; //!< Special tag: root IFD of CR3 images + const uint32_t cmt3 = 0x120000; //!< Special tag: root IFD of CR3 images + const uint32_t cmt4 = 0x130000; //!< Special tag: root IFD of CR3 images } /*! diff --git a/src/tiffimage_int.cpp b/src/tiffimage_int.cpp index 90e5d390..c18cc920 100644 --- a/src/tiffimage_int.cpp +++ b/src/tiffimage_int.cpp @@ -3,6 +3,7 @@ #include "error.hpp" #include "makernote_int.hpp" #include "sonymn_int.hpp" +#include "tags_int.hpp" #include "tiffvisitor_int.hpp" #include "i18n.h" // NLS support. @@ -1125,6 +1126,11 @@ namespace Exiv2 { { Tag::fuji, ifdIdNotSet, newTiffDirectory }, { 0xf000, fujiId, newTiffSubIfd }, + // CR3 images #1475 + { Tag::cmt2, ifdIdNotSet, newTiffDirectory }, + { Tag::cmt3, ifdIdNotSet, newTiffDirectory }, + { Tag::cmt4, ifdIdNotSet, newTiffDirectory }, + // IFD0 { 0x8769, ifd0Id, newTiffSubIfd }, { 0x8825, ifd0Id, newTiffSubIfd }, diff --git a/src/version.cpp b/src/version.cpp index ea8d504c..a3b53e08 100644 --- a/src/version.cpp +++ b/src/version.cpp @@ -345,6 +345,7 @@ void Exiv2::dumpLibraryInfo(std::ostream& os,const exv_grep_keys_t& keys) int have_unistd =0; int have_unicode_path=0; + int enable_bmff =0; int enable_video =0; int enable_webready =0; int enable_nls =0; @@ -461,6 +462,10 @@ void Exiv2::dumpLibraryInfo(std::ostream& os,const exv_grep_keys_t& keys) have_unicode_path=1; #endif +#ifdef EXV_ENABLE_BMFF + enable_bmff=1; +#endif + #ifdef EXV_ENABLE_VIDEO enable_video=1; #endif @@ -544,6 +549,7 @@ void Exiv2::dumpLibraryInfo(std::ostream& os,const exv_grep_keys_t& keys) output(os,keys,"have_sys_types" ,have_sys_types ); output(os,keys,"have_unistd" ,have_unistd ); output(os,keys,"have_unicode_path" ,have_unicode_path); + output(os,keys,"enable_bmff" ,enable_bmff ); output(os,keys,"enable_video" ,enable_video ); output(os,keys,"enable_webready" ,enable_webready ); output(os,keys,"enable_nls" ,enable_nls ); diff --git a/test/data/2021-02-13-1929.heic b/test/data/2021-02-13-1929.heic new file mode 100644 index 00000000..5c1934e9 Binary files /dev/null and b/test/data/2021-02-13-1929.heic differ diff --git a/test/data/Canon.HIF b/test/data/Canon.HIF new file mode 100644 index 00000000..5ea39731 Binary files /dev/null and b/test/data/Canon.HIF differ diff --git a/test/data/Canon_Sigma_18_35_F18_DC_HSM_firmware_1xx.exv b/test/data/Canon_Sigma_18_35_F18_DC_HSM_firmware_1xx.exv old mode 100755 new mode 100644 diff --git a/test/data/Canon_Sigma_18_35_F18_DC_HSM_firmware_2xx.exv b/test/data/Canon_Sigma_18_35_F18_DC_HSM_firmware_2xx.exv old mode 100755 new mode 100644 diff --git a/test/data/IMG_3578.heic b/test/data/IMG_3578.heic new file mode 100644 index 00000000..6a8515dd Binary files /dev/null and b/test/data/IMG_3578.heic differ diff --git a/test/data/Jp2Image_readMetadata_loop.poc b/test/data/Jp2Image_readMetadata_loop.poc old mode 100755 new mode 100644 diff --git a/test/data/Sony.HIF b/test/data/Sony.HIF new file mode 100644 index 00000000..85570575 Binary files /dev/null and b/test/data/Sony.HIF differ diff --git a/test/data/Stonehenge.heic b/test/data/Stonehenge.heic new file mode 100644 index 00000000..f6849afc Binary files /dev/null and b/test/data/Stonehenge.heic differ diff --git a/test/data/avif.avif b/test/data/avif.avif new file mode 100644 index 00000000..f8e029cf Binary files /dev/null and b/test/data/avif.avif differ diff --git a/test/data/avif_exif_xmp.avif b/test/data/avif_exif_xmp.avif new file mode 100644 index 00000000..60071690 Binary files /dev/null and b/test/data/avif_exif_xmp.avif differ diff --git a/test/data/avif_metadata2.avif b/test/data/avif_metadata2.avif new file mode 100644 index 00000000..56a69fd7 Binary files /dev/null and b/test/data/avif_metadata2.avif differ diff --git a/test/data/exiv2-bug922.jpg b/test/data/exiv2-bug922.jpg old mode 100755 new mode 100644 diff --git a/test/data/exiv2-bug922.tif b/test/data/exiv2-bug922.tif old mode 100755 new mode 100644 diff --git a/test/data/heic.heic b/test/data/heic.heic new file mode 100644 index 00000000..91d5dc14 Binary files /dev/null and b/test/data/heic.heic differ diff --git a/tests/bash_tests/utils.py b/tests/bash_tests/utils.py index c9fb6a81..9ab575b1 100644 --- a/tests/bash_tests/utils.py +++ b/tests/bash_tests/utils.py @@ -9,8 +9,10 @@ import shlex import shutil import subprocess import time -from http import server -from urllib import request +import sys +from http import server +from urllib import request +import system_tests """ @@ -685,3 +687,66 @@ def runTestCase(num, img): out += diff('iii', 'ttt') return str(out) +def runTest(cmd): + """ + Executes a command in the shell. + Add this function at PR . + """ + exiv2=system_tests.exiv2 + + if sys.platform == 'win32': + args = cmd + else: + args = shlex.split(cmd) + + # Updat PATH, LD_LIBRARY_PATH and DYLD_LIBRARY_PATH + key = "PATH" + bin_dir = os.path.dirname(exiv2) + if key in os.environ: + os.environ[key] = os.path.join(bin_dir, os.environ[key]) + else: + os.environ[key] = bin_dir + + for key in ["LD_LIBRARY_PATH", "DYLD_LIBRARY_PATH"]: + lib_dir = os.path.join(os.path.dirname(os.path.dirname(exiv2)), 'lib') + if key in os.environ: + os.environ[key] = os.path.join(lib_dir, os.environ[key]) + else: + os.environ[key] = lib_dir + + # Execute the command + try: + p = subprocess.Popen(args, stdout=subprocess.PIPE, shell=False) + stdout, stderr = p.communicate() + if p.returncode != 0: + print('{} returncode = {}'.format(cmd, p.returncode)) + # Split the output by newline + out = stdout.decode('utf-8').replace('\r', '').rstrip('\n').split('\n') + except: + print('** {} died **'.format(cmd)) + + return out + + +def verbose_version(verbose=False): + """ Get the key-value pairs of Exiv2 verbose version """ + vv = {} + exiv2=system_tests.exiv2 + lines = runTest(exiv2 + ' --verbose --version') + for line in lines: + kv = line.rstrip().split('=') + if len(kv) == 2: + key, val = kv + if not key in vv: + vv[key] = val + elif isinstance(vv[key], list): + vv[key].append(val) + else: + vv[key] = [vv[key]] + if verbose: + for key in vv: + val = vv[key] + if isinstance(val, list): + val = '[ {} +{} ]'.format(val[0], len(val) - 1) + print(key.ljust(20), val) + return vv diff --git a/tests/bugfixes/github/test_pr1475_AVIF.py b/tests/bugfixes/github/test_pr1475_AVIF.py new file mode 100644 index 00000000..fe1dbdab --- /dev/null +++ b/tests/bugfixes/github/test_pr1475_AVIF.py @@ -0,0 +1,423 @@ +# -*- coding: utf-8 -*- + +import system_tests + +# test needs system_tests.BT.vv.enable_bmff=1 +enable_bmff = 'enable_bmff' +vv=system_tests.BT.verbose_version() +bSkip = not (enable_bmff in vv and vv[enable_bmff] == '1') + +class pr_1475_avif_avif(metaclass=system_tests.CaseMeta): + url = "https://github.com/Exiv2/exiv2/pull/1475" + filename = "$data_path/avif.avif" + if bSkip: + commands=[] + retval=[] + stdin=[] + stderr=[] + stdout=[] + print("*** test skipped. requires enable_bmff=1***") + else: + commands = ["$exiv2 -pa $filename" + ,"$exiv2 -pS $filename" + ,"$exiv2 -pX $filename" + ,"$exiv2 -pC $filename" + ] + retval = [ 0 ] * len(commands) + stderr = [ "" ] * len(commands) + stdin = [ "" ] * len(commands) + stdout = ["""Exif.Image.ExifTag Long 1 26 +Exif.Photo.DateTimeOriginal Ascii 20 2018:08:15 11:37:35 +Exif.Photo.SubSecTimeOriginal Ascii 3 59 +""","""Exiv2::BmffImage::boxHandler: ftyp 0->32 brand: avif +Exiv2::BmffImage::boxHandler: meta 32->304 + Exiv2::BmffImage::boxHandler: hdlr 44->33 + Exiv2::BmffImage::boxHandler: pitm 77->14 + Exiv2::BmffImage::boxHandler: iinf 91->56 + Exiv2::BmffImage::boxHandler: infe 105->21 ID = 1 av01 + Exiv2::BmffImage::boxHandler: infe 126->21 ID = 2 Exif *** Exif *** + Exiv2::BmffImage::boxHandler: iloc 147->44 + 155 | 14 | ID | 1 | 408,218726 + 169 | 14 | ID | 2 | 219134, 82 + Exiv2::BmffImage::boxHandler: iprp 191->119 + Exiv2::BmffImage::boxHandler: ipco 199->88 + Exiv2::BmffImage::boxHandler: ispe 207->20 pixelWidth_, pixelHeight_ = 1920, 1080 + Exiv2::BmffImage::boxHandler: colr 227->19 + Exiv2::BmffImage::boxHandler: av1C 246->25 + Exiv2::BmffImage::boxHandler: pixi 271->16 + Exiv2::BmffImage::boxHandler: ipma 287->23 + Exiv2::BmffImage::boxHandler: iref 310->26 +Exiv2::BMFF Exif: ID = 2 from,length = 219134,82 +Exiv2::BmffImage::boxHandler: free 336->64 +Exiv2::BmffImage::boxHandler: mdat 400->218816 +""","",""] + +class pr_1475_exif_xmp_avif(metaclass=system_tests.CaseMeta): + url = "https://github.com/Exiv2/exiv2/pull/1475" + filename = "$data_path/avif_exif_xmp.avif" + if bSkip: + commands=[] + retval=[] + stdin=[] + stderr=[] + stdout=[] + print("*** test skipped. requires enable_bmff=1***") + else: + commands = ["$exiv2 -g Image.Make -g Date -g Xm -g Expo -g Flash $filename" + ,"$exiv2 -pS $filename" + ,"$exiv2 -pX $filename" + ,"$exiv2 -pC $filename" + ] + retval = [ 0 ] * len(commands) + stderr = [ "" ] * len(commands) + stdin = [ "" ] * len(commands) + stdout = ["""Exif.Image.DateTime Ascii 20 2021:02:13 21:19:50 +Xmp.iptcExt.DigitalSourceType XmpText 61 http://cv.iptc.org/newscodes/digitalsourcetype/digitalCapture +Xmp.iptcExt.LocationCreated XmpBag 0 +Xmp.iptcExt.LocationShown XmpBag 0 +Xmp.iptcExt.ArtworkOrObject XmpBag 0 +Xmp.iptcExt.RegistryId XmpBag 0 +Xmp.xmpMM.DocumentID XmpText 52 gimp:docid:gimp:8cf1b29a-9b12-4dec-9930-f2c608b298de +Xmp.xmpMM.InstanceID XmpText 44 xmp.iid:33e259b4-7237-4b2a-87bf-4609986012a8 +Xmp.xmpMM.OriginalDocumentID XmpText 44 xmp.did:02dfa8e8-ce11-4de7-971d-566a5bba5edb +Xmp.xmpMM.History XmpText 0 type="Seq" +Xmp.xmpMM.History[1] XmpText 0 type="Struct" +Xmp.xmpMM.History[1]/stEvt:action XmpText 5 saved +Xmp.xmpMM.History[1]/stEvt:changed XmpText 9 /metadata +Xmp.xmpMM.History[1]/stEvt:instanceID XmpText 44 xmp.iid:446f9de2-f964-4680-8461-ddf05bfcc53e +Xmp.xmpMM.History[1]/stEvt:softwareAgent XmpText 19 GIMP 2.99.5 (Linux) +Xmp.xmpMM.History[1]/stEvt:when XmpText 25 2021-02-13T21:19:04+01:00 +Xmp.xmpMM.History[2] XmpText 0 type="Struct" +Xmp.xmpMM.History[2]/stEvt:action XmpText 5 saved +Xmp.xmpMM.History[2]/stEvt:changed XmpText 1 / +Xmp.xmpMM.History[2]/stEvt:instanceID XmpText 44 xmp.iid:017dc808-2418-4f70-99f3-aa05905adb88 +Xmp.xmpMM.History[2]/stEvt:softwareAgent XmpText 19 GIMP 2.99.5 (Linux) +Xmp.xmpMM.History[2]/stEvt:when XmpText 25 2021-02-13T21:20:14+01:00 +Xmp.plus.ModelReleaseStatus XmpText 38 None +Xmp.plus.ImageSupplier XmpSeq 0 +Xmp.plus.ImageCreator XmpSeq 0 +Xmp.plus.CopyrightOwner XmpSeq 0 +Xmp.plus.Licensor XmpSeq 0 +Xmp.GIMP.API XmpText 3 3.0 +Xmp.GIMP.Platform XmpText 5 Linux +Xmp.GIMP.TimeStamp XmpText 16 1613247614397805 +Xmp.GIMP.Version XmpText 6 2.99.5 +Xmp.dc.Format XmpText 10 image/avif +Xmp.dc.creator XmpSeq 1 type="Seq" Developer +Xmp.dc.description LangAlt 1 lang="x-default" This is a testfile +Xmp.dc.rights LangAlt 1 lang="x-default" It is forbidden to use for evil purposes +Xmp.dc.title LangAlt 1 lang="x-default" Personal photo +Xmp.photoshop.AuthorsPosition XmpText 18 Computer Scientist +Xmp.xmp.CreatorTool XmpText 4 GIMP +Xmp.xmp.Rating XmpText 1 5 +Xmp.xmpRights.Marked XmpText 4 True +""","""Exiv2::BmffImage::boxHandler: ftyp 0->32 brand: avif +Exiv2::BmffImage::boxHandler: meta 32->379 + Exiv2::BmffImage::boxHandler: hdlr 44->40 + Exiv2::BmffImage::boxHandler: pitm 84->14 + Exiv2::BmffImage::boxHandler: iloc 98->58 + 106 | 14 | ID | 1 | 5418, 5445 + 120 | 14 | ID | 2 | 419, 316 + 134 | 14 | ID | 3 | 735, 4683 + Exiv2::BmffImage::boxHandler: iinf 156->109 + Exiv2::BmffImage::boxHandler: infe 170->26 ID = 1 av01Color + Exiv2::BmffImage::boxHandler: infe 196->25 ID = 2 ExifExif *** Exif *** + Exiv2::BmffImage::boxHandler: infe 221->44 ID = 3 mimeXMP *** XMP *** + Exiv2::BmffImage::boxHandler: iref 265->40 + Exiv2::BmffImage::boxHandler: iprp 305->106 + Exiv2::BmffImage::boxHandler: ipco 313->75 + Exiv2::BmffImage::boxHandler: ispe 321->20 pixelWidth_, pixelHeight_ = 120, 120 + Exiv2::BmffImage::boxHandler: pixi 341->16 + Exiv2::BmffImage::boxHandler: av1C 357->12 + Exiv2::BmffImage::boxHandler: colr 369->19 + Exiv2::BmffImage::boxHandler: ipma 388->23 +Exiv2::BMFF Exif: ID = 2 from,length = 419,316 +Exiv2::BMFF XMP: ID = 3 from,length = 735,4683 +Exiv2::BmffImage::boxHandler: mdat 411->10452 +""",""" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + type="Seq" Developer + + + + + This is a testfile + + + + + It is forbidden to use for evil purposes + + + + + Personal photo + + + + + + + + + + + + + + + + + + + + + + + + + + +""",""] + +class pr_1475_metadata2_avif(metaclass=system_tests.CaseMeta): + url = "https://github.com/Exiv2/exiv2/pull/1475" + filename = "$data_path/avif_metadata2.avif" + if bSkip: + commands=[] + retval=[] + stdin=[] + stderr=[] + stdout=[] + print("*** test skipped. requires enable_bmff=1***") + else: + commands = ["$exiv2 -g Image.Make -g Date -g Xm -g Expo -g Flash $filename" + ,"$exiv2 -pS $filename" + ,"$exiv2 -pX $filename" + ,"$exiv2 -pC $filename" + ] + retval = [ 0 ] * len(commands) + stderr = [ "" ] * len(commands) + stdin = [ "" ] * len(commands) + stdout = ["""Exif.Image.DateTime Ascii 20 2021:02:13 21:25:32 +Xmp.iptcExt.DigitalSourceType XmpText 61 http://cv.iptc.org/newscodes/digitalsourcetype/digitalCapture +Xmp.iptcExt.LocationCreated XmpBag 0 +Xmp.iptcExt.LocationShown XmpBag 0 +Xmp.iptcExt.ArtworkOrObject XmpBag 0 +Xmp.iptcExt.RegistryId XmpBag 0 +Xmp.xmpMM.DocumentID XmpText 52 gimp:docid:gimp:e38231ee-2d28-42e6-b17e-6fa80c9fd85b +Xmp.xmpMM.InstanceID XmpText 44 xmp.iid:34774f89-42e3-4411-a691-f8cdb5b11def +Xmp.xmpMM.OriginalDocumentID XmpText 44 xmp.did:e2129b55-045f-4085-bbd2-e11d11edfa0c +Xmp.xmpMM.History XmpText 0 type="Seq" +Xmp.xmpMM.History[1] XmpText 0 type="Struct" +Xmp.xmpMM.History[1]/stEvt:action XmpText 5 saved +Xmp.xmpMM.History[1]/stEvt:changed XmpText 9 /metadata +Xmp.xmpMM.History[1]/stEvt:instanceID XmpText 44 xmp.iid:928b36e2-0239-4616-847a-eff7a31816e3 +Xmp.xmpMM.History[1]/stEvt:softwareAgent XmpText 19 GIMP 2.99.5 (Linux) +Xmp.xmpMM.History[1]/stEvt:when XmpText 25 2021-02-13T21:24:26+01:00 +Xmp.xmpMM.History[2] XmpText 0 type="Struct" +Xmp.xmpMM.History[2]/stEvt:action XmpText 5 saved +Xmp.xmpMM.History[2]/stEvt:changed XmpText 1 / +Xmp.xmpMM.History[2]/stEvt:instanceID XmpText 44 xmp.iid:23f267c5-c40a-45c8-947d-11313b4881c1 +Xmp.xmpMM.History[2]/stEvt:softwareAgent XmpText 19 GIMP 2.99.5 (Linux) +Xmp.xmpMM.History[2]/stEvt:when XmpText 25 2021-02-13T21:25:41+01:00 +Xmp.plus.ModelReleaseStatus XmpText 38 None +Xmp.plus.ImageSupplier XmpSeq 0 +Xmp.plus.ImageCreator XmpSeq 0 +Xmp.plus.CopyrightOwner XmpSeq 0 +Xmp.plus.Licensor XmpSeq 0 +Xmp.GIMP.API XmpText 3 3.0 +Xmp.GIMP.Platform XmpText 5 Linux +Xmp.GIMP.TimeStamp XmpText 16 1613247941462908 +Xmp.GIMP.Version XmpText 6 2.99.5 +Xmp.dc.Format XmpText 10 image/avif +Xmp.dc.creator XmpSeq 1 type="Seq" me +Xmp.dc.description LangAlt 1 lang="x-default" bla bla bla +Xmp.xmp.CreatorTool XmpText 4 GIMP +""","""Exiv2::BmffImage::boxHandler: ftyp 0->24 brand: avif +Exiv2::BmffImage::boxHandler: meta 24->356 + Exiv2::BmffImage::boxHandler: hdlr 36->33 + Exiv2::BmffImage::boxHandler: pitm 69->14 + Exiv2::BmffImage::boxHandler: iloc 83->70 + 91 | 18 | ID | 1 | 388, 4730 + 109 | 18 | ID | 2 | 5118, 412 + 127 | 18 | ID | 3 | 5530, 4254 + Exiv2::BmffImage::boxHandler: iinf 153->98 + Exiv2::BmffImage::boxHandler: infe 167->21 ID = 1 av01 + Exiv2::BmffImage::boxHandler: infe 188->21 ID = 2 Exif *** Exif *** + Exiv2::BmffImage::boxHandler: infe 209->42 ID = 3 mime *** XMP *** + Exiv2::BmffImage::boxHandler: iprp 251->89 + Exiv2::BmffImage::boxHandler: ipco 259->59 + Exiv2::BmffImage::boxHandler: colr 267->19 + Exiv2::BmffImage::boxHandler: av1C 286->12 + Exiv2::BmffImage::boxHandler: ispe 298->20 pixelWidth_, pixelHeight_ = 120, 120 + Exiv2::BmffImage::boxHandler: ipma 318->22 + Exiv2::BmffImage::boxHandler: iref 340->40 +Exiv2::BMFF Exif: ID = 2 from,length = 5118,412 +Exiv2::BMFF XMP: ID = 3 from,length = 5530,4254 +Exiv2::BmffImage::boxHandler: mdat 380->9404 +""",""" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + type="Seq" me + + + + + bla bla bla + + + + + + + + + + + + + + + + + + + + + + + + + + +""",""] + diff --git a/tests/bugfixes/github/test_pr1475_HEIC.py b/tests/bugfixes/github/test_pr1475_HEIC.py new file mode 100644 index 00000000..6fc18345 --- /dev/null +++ b/tests/bugfixes/github/test_pr1475_HEIC.py @@ -0,0 +1,521 @@ +# -*- coding: utf-8 -*- + +import system_tests + +# test needs system_tests.BT.vv.enable_bmff=1 +vv=system_tests.BT.verbose_version() +enable_bmff = 'enable_bmff' +bSkip = not (enable_bmff in vv and vv[enable_bmff] == '1') + +class pr_1475_2021_heic(metaclass=system_tests.CaseMeta): + url = "https://github.com/Exiv2/exiv2/pull/1475" + filename = "$data_path/2021-02-13-1929.heic" + if bSkip: + commands=[] + retval=[] + stdin=[] + stderr=[] + stdout=[] + print("*** test skipped. requires enable_bmff=1***") + else: + commands = ["$exiv2 -g Image.Make -g Date -g Xm -g Expo -g Flash $filename" + ,"$exiv2 -pS $filename" + ,"$exiv2 -pX $filename" + ,"$exiv2 -pC --binary $filename" + ] + retval = [ 0 ] * len(commands) + stderr = [ "" ] * len(commands) + stdin = [ "" ] * len(commands) + stdout = ["""Exif.Image.Make Ascii 6 Apple +Exif.Image.DateTime Ascii 20 2021:02:13 11:03:31 +Exif.Photo.ExposureTime Rational 1 1/30 s +Exif.Photo.ExposureProgram Short 1 Auto +Exif.Photo.DateTimeOriginal Ascii 20 2021:02:13 11:03:31 +Exif.Photo.DateTimeDigitized Ascii 20 2021:02:13 11:03:31 +Exif.Photo.ExposureBiasValue SRational 1 0 EV +Exif.Photo.Flash Short 1 No, compulsory +Exif.Photo.FlashpixVersion Undefined 4 1.00 +Exif.Photo.ExposureMode Short 1 Auto +Exif.GPSInfo.GPSDateStamp Ascii 11 2021:02:13 +""","""Exiv2::BmffImage::boxHandler: ftyp 0->36 brand: heic +Exiv2::BmffImage::boxHandler: meta 36->3380 + Exiv2::BmffImage::boxHandler: hdlr 48->34 + Exiv2::BmffImage::boxHandler: dinf 82->36 + Exiv2::BmffImage::boxHandler: pitm 118->14 + Exiv2::BmffImage::boxHandler: iinf 132->1085 + Exiv2::BmffImage::boxHandler: infe 146->21 ID = 1 hvc1 + Exiv2::BmffImage::boxHandler: infe 167->21 ID = 2 hvc1 + Exiv2::BmffImage::boxHandler: infe 188->21 ID = 3 hvc1 + Exiv2::BmffImage::boxHandler: infe 209->21 ID = 4 hvc1 + Exiv2::BmffImage::boxHandler: infe 230->21 ID = 5 hvc1 + Exiv2::BmffImage::boxHandler: infe 251->21 ID = 6 hvc1 + Exiv2::BmffImage::boxHandler: infe 272->21 ID = 7 hvc1 + Exiv2::BmffImage::boxHandler: infe 293->21 ID = 8 hvc1 + Exiv2::BmffImage::boxHandler: infe 314->21 ID = 9 hvc1 + Exiv2::BmffImage::boxHandler: infe 335->21 ID = 10 hvc1 + Exiv2::BmffImage::boxHandler: infe 356->21 ID = 11 hvc1 + Exiv2::BmffImage::boxHandler: infe 377->21 ID = 12 hvc1 + Exiv2::BmffImage::boxHandler: infe 398->21 ID = 13 hvc1 + Exiv2::BmffImage::boxHandler: infe 419->21 ID = 14 hvc1 + Exiv2::BmffImage::boxHandler: infe 440->21 ID = 15 hvc1 + Exiv2::BmffImage::boxHandler: infe 461->21 ID = 16 hvc1 + Exiv2::BmffImage::boxHandler: infe 482->21 ID = 17 hvc1 + Exiv2::BmffImage::boxHandler: infe 503->21 ID = 18 hvc1 + Exiv2::BmffImage::boxHandler: infe 524->21 ID = 19 hvc1 + Exiv2::BmffImage::boxHandler: infe 545->21 ID = 20 hvc1 + Exiv2::BmffImage::boxHandler: infe 566->21 ID = 21 hvc1 + Exiv2::BmffImage::boxHandler: infe 587->21 ID = 22 hvc1 + Exiv2::BmffImage::boxHandler: infe 608->21 ID = 23 hvc1 + Exiv2::BmffImage::boxHandler: infe 629->21 ID = 24 hvc1 + Exiv2::BmffImage::boxHandler: infe 650->21 ID = 25 hvc1 + Exiv2::BmffImage::boxHandler: infe 671->21 ID = 26 hvc1 + Exiv2::BmffImage::boxHandler: infe 692->21 ID = 27 hvc1 + Exiv2::BmffImage::boxHandler: infe 713->21 ID = 28 hvc1 + Exiv2::BmffImage::boxHandler: infe 734->21 ID = 29 hvc1 + Exiv2::BmffImage::boxHandler: infe 755->21 ID = 30 hvc1 + Exiv2::BmffImage::boxHandler: infe 776->21 ID = 31 hvc1 + Exiv2::BmffImage::boxHandler: infe 797->21 ID = 32 hvc1 + Exiv2::BmffImage::boxHandler: infe 818->21 ID = 33 hvc1 + Exiv2::BmffImage::boxHandler: infe 839->21 ID = 34 hvc1 + Exiv2::BmffImage::boxHandler: infe 860->21 ID = 35 hvc1 + Exiv2::BmffImage::boxHandler: infe 881->21 ID = 36 hvc1 + Exiv2::BmffImage::boxHandler: infe 902->21 ID = 37 hvc1 + Exiv2::BmffImage::boxHandler: infe 923->21 ID = 38 hvc1 + Exiv2::BmffImage::boxHandler: infe 944->21 ID = 39 hvc1 + Exiv2::BmffImage::boxHandler: infe 965->21 ID = 40 hvc1 + Exiv2::BmffImage::boxHandler: infe 986->21 ID = 41 hvc1 + Exiv2::BmffImage::boxHandler: infe 1007->21 ID = 42 hvc1 + Exiv2::BmffImage::boxHandler: infe 1028->21 ID = 43 hvc1 + Exiv2::BmffImage::boxHandler: infe 1049->21 ID = 44 hvc1 + Exiv2::BmffImage::boxHandler: infe 1070->21 ID = 45 hvc1 + Exiv2::BmffImage::boxHandler: infe 1091->21 ID = 46 hvc1 + Exiv2::BmffImage::boxHandler: infe 1112->21 ID = 47 hvc1 + Exiv2::BmffImage::boxHandler: infe 1133->21 ID = 48 hvc1 + Exiv2::BmffImage::boxHandler: infe 1154->21 ID = 49 grid + Exiv2::BmffImage::boxHandler: infe 1175->21 ID = 50 hvc1 + Exiv2::BmffImage::boxHandler: infe 1196->21 ID = 51 Exif *** Exif *** + Exiv2::BmffImage::boxHandler: iref 1217->148 + Exiv2::BmffImage::boxHandler: iprp 1365->1203 + Exiv2::BmffImage::boxHandler: ipco 1373->876 + Exiv2::BmffImage::boxHandler: colr 1381->560 + Exiv2::BmffImage::boxHandler: hvcC 1941->112 + Exiv2::BmffImage::boxHandler: ispe 2053->20 pixelWidth_, pixelHeight_ = 512, 512 + Exiv2::BmffImage::boxHandler: ispe 2073->20 pixelWidth_, pixelHeight_ = 4032, 3024 + Exiv2::BmffImage::boxHandler: irot 2093->9 + Exiv2::BmffImage::boxHandler: pixi 2102->16 + Exiv2::BmffImage::boxHandler: hvcC 2118->111 + Exiv2::BmffImage::boxHandler: ispe 2229->20 pixelWidth_, pixelHeight_ = 320, 240 + Exiv2::BmffImage::boxHandler: ipma 2249->319 + Exiv2::BmffImage::boxHandler: idat 2568->16 + Exiv2::BmffImage::boxHandler: iloc 2584->832 + 2592 | 16 | ID | 1 | 23265, 15453 + 2608 | 16 | ID | 2 | 38718, 21882 + 2624 | 16 | ID | 3 | 60600, 20196 + 2640 | 16 | ID | 4 | 80796, 22234 + 2656 | 16 | ID | 5 | 103030, 41489 + 2672 | 16 | ID | 6 | 144519, 40845 + 2688 | 16 | ID | 7 | 185364, 34948 + 2704 | 16 | ID | 8 | 220312, 17650 + 2720 | 16 | ID | 9 | 237962, 15024 + 2736 | 16 | ID | 10 | 252986, 44647 + 2752 | 16 | ID | 11 | 297633, 38092 + 2768 | 16 | ID | 12 | 335725, 43666 + 2784 | 16 | ID | 13 | 379391, 48523 + 2800 | 16 | ID | 14 | 427914, 46992 + 2816 | 16 | ID | 15 | 474906, 36063 + 2832 | 16 | ID | 16 | 510969, 20737 + 2848 | 16 | ID | 17 | 531706, 25756 + 2864 | 16 | ID | 18 | 557462, 58455 + 2880 | 16 | ID | 19 | 615917, 44896 + 2896 | 16 | ID | 20 | 660813, 39730 + 2912 | 16 | ID | 21 | 700543, 38596 + 2928 | 16 | ID | 22 | 739139, 31795 + 2944 | 16 | ID | 23 | 770934, 33214 + 2960 | 16 | ID | 24 | 804148, 18858 + 2976 | 16 | ID | 25 | 823006, 35122 + 2992 | 16 | ID | 26 | 858128, 41015 + 3008 | 16 | ID | 27 | 899143, 40362 + 3024 | 16 | ID | 28 | 939505, 38288 + 3040 | 16 | ID | 29 | 977793, 34497 + 3056 | 16 | ID | 30 | 1012290, 31806 + 3072 | 16 | ID | 31 | 1044096, 25360 + 3088 | 16 | ID | 32 | 1069456, 19672 + 3104 | 16 | ID | 33 | 1089128, 25400 + 3120 | 16 | ID | 34 | 1114528, 34515 + 3136 | 16 | ID | 35 | 1149043, 20863 + 3152 | 16 | ID | 36 | 1169906, 25975 + 3168 | 16 | ID | 37 | 1195881, 33532 + 3184 | 16 | ID | 38 | 1229413, 31296 + 3200 | 16 | ID | 39 | 1260709, 29869 + 3216 | 16 | ID | 40 | 1290578, 16479 + 3232 | 16 | ID | 41 | 1307057, 17323 + 3248 | 16 | ID | 42 | 1324380, 17331 + 3264 | 16 | ID | 43 | 1341711, 13357 + 3280 | 16 | ID | 44 | 1355068, 22206 + 3296 | 16 | ID | 45 | 1377274, 31859 + 3312 | 16 | ID | 46 | 1409133, 26694 + 3328 | 16 | ID | 47 | 1435827, 23620 + 3344 | 16 | ID | 48 | 1459447, 15007 + 3360 | 16 | ID | 49 | 0, 8 + 3376 | 16 | ID | 50 | 3432, 17469 + 3392 | 16 | ID | 51 | 20901, 2364 +Exiv2::BMFF Exif: ID = 51 from,length = 20901,2364 +Exiv2::BmffImage::boxHandler: mdat 3416->1 +""","","""data:AAACJGFwcGwEAAAAbW50clJHQiBYWVogB+EABwAHAA0AFgAgYWNzcEF +QUEwAAAAAQVBQTAAAAAAAAAAAAAAAAAAAAAAAAPbWAAEAAAAA0y1hcHBsyhq +VgiV/EE04mRPV0eoVggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +KZGVzYwAAAPwAAABlY3BydAAAAWQAAAAjd3RwdAAAAYgAAAAUclhZWgAAAZw +AAAAUZ1hZWgAAAbAAAAAUYlhZWgAAAcQAAAAUclRSQwAAAdgAAAAgY2hhZAA +AAfgAAAAsYlRSQwAAAdgAAAAgZ1RSQwAAAdgAAAAgZGVzYwAAAAAAAAALRGl +zcGxheSBQMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB +0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSBJbmMuLCAyMDE3AABYWVogAAAAAAA +A81EAAQAAAAEWzFhZWiAAAAAAAACD3wAAPb////+7WFlaIAAAAAAAAEq/AAC +xNwAACrlYWVogAAAAAAAAKDgAABELAADIuXBhcmEAAAAAAAMAAAACZmYAAPK +nAAANWQAAE9AAAApbc2YzMgAAAAAAAQxCAAAF3v//8yYAAAeTAAD9kP//+6L +///2jAAAD3AAAwG4= +"""] + +class pr_1475_IMG_3578_heic(metaclass=system_tests.CaseMeta): + url = "https://github.com/Exiv2/exiv2/pull/1475" + filename = "$data_path/IMG_3578.heic" + if bSkip: + commands=[] + retval=[] + stdin=[] + stderr=[] + stdout=[] + print("*** test skipped. requires enable_bmff=1***") + else: + commands = ["$exiv2 -g Image.Make -g Date -g Xm -g Expo -g Flash $filename" + ,"$exiv2 -pS $filename" + ,"$exiv2 -pX $filename" + ,"$exiv2 -pC --binary $filename" + ] + retval = [ 0 ] * len(commands) + stderr = [ "" ] * len(commands) + stdin = [ "" ] * len(commands) + stdout = ["""Exif.Image.Make Ascii 6 Apple +Exif.Image.DateTime Ascii 20 2020:04:17 10:03:40 +Exif.Photo.ExposureTime Rational 1 1/60 s +Exif.Photo.ExposureProgram Short 1 Auto +Exif.Photo.DateTimeOriginal Ascii 20 2020:04:17 10:03:40 +Exif.Photo.DateTimeDigitized Ascii 20 2020:04:17 10:03:40 +Exif.Photo.ExposureBiasValue SRational 1 0 EV +Exif.Photo.Flash Short 1 No, compulsory +Exif.Photo.FlashpixVersion Undefined 4 1.00 +Exif.Photo.ExposureMode Short 1 Auto +""","""Exiv2::BmffImage::boxHandler: ftyp 0->32 brand: heic +Exiv2::BmffImage::boxHandler: meta 32->3380 + Exiv2::BmffImage::boxHandler: hdlr 44->34 + Exiv2::BmffImage::boxHandler: dinf 78->36 + Exiv2::BmffImage::boxHandler: pitm 114->14 + Exiv2::BmffImage::boxHandler: iinf 128->1085 + Exiv2::BmffImage::boxHandler: infe 142->21 ID = 1 hvc1 + Exiv2::BmffImage::boxHandler: infe 163->21 ID = 2 hvc1 + Exiv2::BmffImage::boxHandler: infe 184->21 ID = 3 hvc1 + Exiv2::BmffImage::boxHandler: infe 205->21 ID = 4 hvc1 + Exiv2::BmffImage::boxHandler: infe 226->21 ID = 5 hvc1 + Exiv2::BmffImage::boxHandler: infe 247->21 ID = 6 hvc1 + Exiv2::BmffImage::boxHandler: infe 268->21 ID = 7 hvc1 + Exiv2::BmffImage::boxHandler: infe 289->21 ID = 8 hvc1 + Exiv2::BmffImage::boxHandler: infe 310->21 ID = 9 hvc1 + Exiv2::BmffImage::boxHandler: infe 331->21 ID = 10 hvc1 + Exiv2::BmffImage::boxHandler: infe 352->21 ID = 11 hvc1 + Exiv2::BmffImage::boxHandler: infe 373->21 ID = 12 hvc1 + Exiv2::BmffImage::boxHandler: infe 394->21 ID = 13 hvc1 + Exiv2::BmffImage::boxHandler: infe 415->21 ID = 14 hvc1 + Exiv2::BmffImage::boxHandler: infe 436->21 ID = 15 hvc1 + Exiv2::BmffImage::boxHandler: infe 457->21 ID = 16 hvc1 + Exiv2::BmffImage::boxHandler: infe 478->21 ID = 17 hvc1 + Exiv2::BmffImage::boxHandler: infe 499->21 ID = 18 hvc1 + Exiv2::BmffImage::boxHandler: infe 520->21 ID = 19 hvc1 + Exiv2::BmffImage::boxHandler: infe 541->21 ID = 20 hvc1 + Exiv2::BmffImage::boxHandler: infe 562->21 ID = 21 hvc1 + Exiv2::BmffImage::boxHandler: infe 583->21 ID = 22 hvc1 + Exiv2::BmffImage::boxHandler: infe 604->21 ID = 23 hvc1 + Exiv2::BmffImage::boxHandler: infe 625->21 ID = 24 hvc1 + Exiv2::BmffImage::boxHandler: infe 646->21 ID = 25 hvc1 + Exiv2::BmffImage::boxHandler: infe 667->21 ID = 26 hvc1 + Exiv2::BmffImage::boxHandler: infe 688->21 ID = 27 hvc1 + Exiv2::BmffImage::boxHandler: infe 709->21 ID = 28 hvc1 + Exiv2::BmffImage::boxHandler: infe 730->21 ID = 29 hvc1 + Exiv2::BmffImage::boxHandler: infe 751->21 ID = 30 hvc1 + Exiv2::BmffImage::boxHandler: infe 772->21 ID = 31 hvc1 + Exiv2::BmffImage::boxHandler: infe 793->21 ID = 32 hvc1 + Exiv2::BmffImage::boxHandler: infe 814->21 ID = 33 hvc1 + Exiv2::BmffImage::boxHandler: infe 835->21 ID = 34 hvc1 + Exiv2::BmffImage::boxHandler: infe 856->21 ID = 35 hvc1 + Exiv2::BmffImage::boxHandler: infe 877->21 ID = 36 hvc1 + Exiv2::BmffImage::boxHandler: infe 898->21 ID = 37 hvc1 + Exiv2::BmffImage::boxHandler: infe 919->21 ID = 38 hvc1 + Exiv2::BmffImage::boxHandler: infe 940->21 ID = 39 hvc1 + Exiv2::BmffImage::boxHandler: infe 961->21 ID = 40 hvc1 + Exiv2::BmffImage::boxHandler: infe 982->21 ID = 41 hvc1 + Exiv2::BmffImage::boxHandler: infe 1003->21 ID = 42 hvc1 + Exiv2::BmffImage::boxHandler: infe 1024->21 ID = 43 hvc1 + Exiv2::BmffImage::boxHandler: infe 1045->21 ID = 44 hvc1 + Exiv2::BmffImage::boxHandler: infe 1066->21 ID = 45 hvc1 + Exiv2::BmffImage::boxHandler: infe 1087->21 ID = 46 hvc1 + Exiv2::BmffImage::boxHandler: infe 1108->21 ID = 47 hvc1 + Exiv2::BmffImage::boxHandler: infe 1129->21 ID = 48 hvc1 + Exiv2::BmffImage::boxHandler: infe 1150->21 ID = 49 grid + Exiv2::BmffImage::boxHandler: infe 1171->21 ID = 50 hvc1 + Exiv2::BmffImage::boxHandler: infe 1192->21 ID = 51 Exif *** Exif *** + Exiv2::BmffImage::boxHandler: iref 1213->148 + Exiv2::BmffImage::boxHandler: iprp 1361->1203 + Exiv2::BmffImage::boxHandler: ipco 1369->876 + Exiv2::BmffImage::boxHandler: colr 1377->560 + Exiv2::BmffImage::boxHandler: hvcC 1937->112 + Exiv2::BmffImage::boxHandler: ispe 2049->20 pixelWidth_, pixelHeight_ = 512, 512 + Exiv2::BmffImage::boxHandler: ispe 2069->20 pixelWidth_, pixelHeight_ = 4032, 3024 + Exiv2::BmffImage::boxHandler: irot 2089->9 + Exiv2::BmffImage::boxHandler: pixi 2098->16 + Exiv2::BmffImage::boxHandler: hvcC 2114->111 + Exiv2::BmffImage::boxHandler: ispe 2225->20 pixelWidth_, pixelHeight_ = 320, 240 + Exiv2::BmffImage::boxHandler: ipma 2245->319 + Exiv2::BmffImage::boxHandler: idat 2564->16 + Exiv2::BmffImage::boxHandler: iloc 2580->832 + 2588 | 16 | ID | 1 | 10931, 11943 + 2604 | 16 | ID | 2 | 22874, 24817 + 2620 | 16 | ID | 3 | 47691, 20110 + 2636 | 16 | ID | 4 | 67801, 19449 + 2652 | 16 | ID | 5 | 87250, 19714 + 2668 | 16 | ID | 6 | 106964, 20223 + 2684 | 16 | ID | 7 | 127187, 18124 + 2700 | 16 | ID | 8 | 145311, 8745 + 2716 | 16 | ID | 9 | 154056, 21761 + 2732 | 16 | ID | 10 | 175817, 25378 + 2748 | 16 | ID | 11 | 201195, 16664 + 2764 | 16 | ID | 12 | 217859, 18638 + 2780 | 16 | ID | 13 | 236497, 22750 + 2796 | 16 | ID | 14 | 259247, 15801 + 2812 | 16 | ID | 15 | 275048, 15063 + 2828 | 16 | ID | 16 | 290111, 15671 + 2844 | 16 | ID | 17 | 305782, 19360 + 2860 | 16 | ID | 18 | 325142, 19415 + 2876 | 16 | ID | 19 | 344557, 29895 + 2892 | 16 | ID | 20 | 374452, 21193 + 2908 | 16 | ID | 21 | 395645, 46228 + 2924 | 16 | ID | 22 | 441873, 9356 + 2940 | 16 | ID | 23 | 451229, 14175 + 2956 | 16 | ID | 24 | 465404, 16734 + 2972 | 16 | ID | 25 | 482138, 32304 + 2988 | 16 | ID | 26 | 514442, 44251 + 3004 | 16 | ID | 27 | 558693, 21635 + 3020 | 16 | ID | 28 | 580328, 27907 + 3036 | 16 | ID | 29 | 608235, 8462 + 3052 | 16 | ID | 30 | 616697, 17997 + 3068 | 16 | ID | 31 | 634694, 22077 + 3084 | 16 | ID | 32 | 656771, 17266 + 3100 | 16 | ID | 33 | 674037, 19623 + 3116 | 16 | ID | 34 | 693660, 22028 + 3132 | 16 | ID | 35 | 715688, 22078 + 3148 | 16 | ID | 36 | 737766, 21911 + 3164 | 16 | ID | 37 | 759677, 20937 + 3180 | 16 | ID | 38 | 780614, 35413 + 3196 | 16 | ID | 39 | 816027, 53869 + 3212 | 16 | ID | 40 | 869896, 33923 + 3228 | 16 | ID | 41 | 903819, 18130 + 3244 | 16 | ID | 42 | 921949, 16268 + 3260 | 16 | ID | 43 | 938217, 23620 + 3276 | 16 | ID | 44 | 961837, 31499 + 3292 | 16 | ID | 45 | 993336, 33513 + 3308 | 16 | ID | 46 | 1026849, 37642 + 3324 | 16 | ID | 47 | 1064491, 37734 + 3340 | 16 | ID | 48 | 1102225, 20085 + 3356 | 16 | ID | 49 | 0, 8 + 3372 | 16 | ID | 50 | 3428, 5479 + 3388 | 16 | ID | 51 | 8907, 2024 +Exiv2::BMFF Exif: ID = 51 from,length = 8907,2024 +Exiv2::BmffImage::boxHandler: mdat 3412->1 +""","","""data:AAACJGFwcGwEAAAAbW50clJHQiBYWVogB+EABwAHAA0AFgAgYWNzcEF +QUEwAAAAAQVBQTAAAAAAAAAAAAAAAAAAAAAAAAPbWAAEAAAAA0y1hcHBsyhq +VgiV/EE04mRPV0eoVggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +KZGVzYwAAAPwAAABlY3BydAAAAWQAAAAjd3RwdAAAAYgAAAAUclhZWgAAAZw +AAAAUZ1hZWgAAAbAAAAAUYlhZWgAAAcQAAAAUclRSQwAAAdgAAAAgY2hhZAA +AAfgAAAAsYlRSQwAAAdgAAAAgZ1RSQwAAAdgAAAAgZGVzYwAAAAAAAAALRGl +zcGxheSBQMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB +0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSBJbmMuLCAyMDE3AABYWVogAAAAAAA +A81EAAQAAAAEWzFhZWiAAAAAAAACD3wAAPb////+7WFlaIAAAAAAAAEq/AAC +xNwAACrlYWVogAAAAAAAAKDgAABELAADIuXBhcmEAAAAAAAMAAAACZmYAAPK +nAAANWQAAE9AAAApbc2YzMgAAAAAAAQxCAAAF3v//8yYAAAeTAAD9kP//+6L +///2jAAAD3AAAwG4= +"""] + +class pr_1475_Stonehenge_heic(metaclass=system_tests.CaseMeta): + url = "https://github.com/Exiv2/exiv2/pull/1475" + filename = "$data_path/Stonehenge.heic" + if bSkip: + commands=[] + retval=[] + stdin=[] + stderr=[] + stdout=[] + print("*** test skipped. requires enable_bmff=1***") + else: + commands = ["$exiv2 -g Image.Make -g Date -g Xm -g Expo -g Flash $filename" + ,"$exiv2 -pS $filename" + ,"$exiv2 -pX $filename" + ,"$exiv2 -pC --binary $filename" + ] + retval = [ 0 ] * len(commands) + stderr = [ "" ] * len(commands) + stdin = [ "" ] * len(commands) + stdout = ["""Exif.Image.Make Ascii 18 NIKON CORPORATION +Exif.Image.DateTime Ascii 20 2015:07:16 20:25:28 +Exif.Photo.ExposureTime Rational 1 1/400 s +Exif.Photo.ExposureProgram Short 1 Not defined +Exif.Photo.DateTimeOriginal Ascii 20 2015:07:16 15:38:54 +Exif.Photo.DateTimeDigitized Ascii 20 2015:07:16 15:38:54 +Exif.Photo.ExposureBiasValue SRational 1 0 EV +Exif.Photo.Flash Short 1 No, compulsory +Exif.Photo.FlashpixVersion Undefined 4 1.00 +Exif.Photo.ExposureMode Short 1 Auto +Xmp.aux.SerialNumber XmpText 7 2567806 +Xmp.aux.FlashCompensation XmpText 3 0/1 +Xmp.aux.LensInfo XmpText 20 18/1 250/1 7/2 63/10 +Xmp.aux.Lens XmpText 23 18.0-250.0 mm f/3.5-6.3 +Xmp.aux.ImageNumber XmpText 4 9608 +Xmp.aux.LensID XmpText 20 -7910804157571773682 +Xmp.xmp.Rating XmpText 1 0 +Xmp.xmp.CreatorTool XmpText 9 Ver.1.00 +Xmp.xmp.CreateDate XmpText 22 2015-07-16T15:38:54.00 +Xmp.xmp.ModifyDate XmpText 28 2015-07-16T20:25:28.00+01:00 +Xmp.cm2e.Father XmpText 11 Robin Mills +Xmp.cm2e.Family XmpBag 0 +Xmp.photoshop.DateCreated XmpText 22 2015-07-16T15:38:54.00 +Xmp.dc.description LangAlt 1 lang="x-default" Classic View +Xmp.dc.Family XmpBag 1 Robin +""","""Exiv2::BmffImage::boxHandler: ftyp 0->24 brand: heic +Exiv2::BmffImage::boxHandler: meta 24->508 + Exiv2::BmffImage::boxHandler: hdlr 36->34 + Exiv2::BmffImage::boxHandler: dinf 70->36 + Exiv2::BmffImage::boxHandler: pitm 106->14 + Exiv2::BmffImage::boxHandler: iinf 120->97 + Exiv2::BmffImage::boxHandler: infe 134->21 ID = 1 hvc1 + Exiv2::BmffImage::boxHandler: infe 155->21 ID = 2 Exif *** Exif *** + Exiv2::BmffImage::boxHandler: infe 176->41 ID = 3 mime *** XMP *** + Exiv2::BmffImage::boxHandler: iref 217->40 + Exiv2::BmffImage::boxHandler: iprp 257->217 + Exiv2::BmffImage::boxHandler: ipco 265->185 + Exiv2::BmffImage::boxHandler: colr 273->19 + Exiv2::BmffImage::boxHandler: hvcC 292->113 + Exiv2::BmffImage::boxHandler: ispe 405->20 pixelWidth_, pixelHeight_ = 300, 200 + Exiv2::BmffImage::boxHandler: irot 425->9 + Exiv2::BmffImage::boxHandler: pixi 434->16 + Exiv2::BmffImage::boxHandler: ipma 450->24 + Exiv2::BmffImage::boxHandler: iloc 474->58 + 482 | 14 | ID | 1 | 4780, 13461 + 496 | 14 | ID | 2 | 548, 1082 + 510 | 14 | ID | 3 | 1630, 3150 +Exiv2::BMFF Exif: ID = 2 from,length = 548,1082 +Exiv2::BMFF XMP: ID = 3 from,length = 1630,3150 +Exiv2::BmffImage::boxHandler: mdat 532->1 +""",""" + + + + + + + + + Classic View + + + + + Robin + + + + + + + + + + + + + + + + + + + + + + + + + + +""",""] + +class pr_1475_heic_heic(metaclass=system_tests.CaseMeta): + url = "https://github.com/Exiv2/exiv2/pull/1475" + filename = "$data_path/heic.heic" + if bSkip: + commands=[] + retval=[] + stdin=[] + stderr=[] + stdout=[] + print("*** test skipped. requires enable_bmff=1***") + else: + commands = ["$exiv2 -pa $filename" + ,"$exiv2 -pS $filename" + ,"$exiv2 -pX $filename" + ,"$exiv2 -pC --binary $filename" + ] + retval = [ 0 ] * len(commands) + stderr = [ "" ] * len(commands) + stdin = [ "" ] * len(commands) + stdout = ["","""Exiv2::BmffImage::boxHandler: ftyp 0->28 brand: mif1 +Exiv2::BmffImage::boxHandler: meta 28->921 + Exiv2::BmffImage::boxHandler: hdlr 40->33 + Exiv2::BmffImage::boxHandler: pitm 73->14 + Exiv2::BmffImage::boxHandler: iloc 87->88 + 95 | 18 | ID | 20004 | 957,333704 + 113 | 18 | ID | 20005 | 334669, 24523 + 131 | 18 | ID | 20006 | 359200,330132 + 149 | 18 | ID | 20007 | 689340, 28758 + Exiv2::BmffImage::boxHandler: iinf 175->140 + Exiv2::BmffImage::boxHandler: iref 315->40 + Exiv2::BmffImage::boxHandler: iprp 355->594 + Exiv2::BmffImage::boxHandler: ipco 363->550 + Exiv2::BmffImage::boxHandler: hvcC 371->126 + Exiv2::BmffImage::boxHandler: ispe 497->20 pixelWidth_, pixelHeight_ = 1280, 854 + Exiv2::BmffImage::boxHandler: hvcC 517->125 + Exiv2::BmffImage::boxHandler: ispe 642->20 pixelWidth_, pixelHeight_ = 320, 212 + Exiv2::BmffImage::boxHandler: hvcC 662->126 + Exiv2::BmffImage::boxHandler: hvcC 788->125 + Exiv2::BmffImage::boxHandler: ipma 913->36 +Exiv2::BmffImage::boxHandler: mdat 949->333712 +Exiv2::BmffImage::boxHandler: mdat 334661->24531 +Exiv2::BmffImage::boxHandler: mdat 359192->330140 +Exiv2::BmffImage::boxHandler: mdat 689332->28766 +Exiv2::BmffImage::boxHandler: mdat 718098->16 +""","",""] + diff --git a/tests/bugfixes/github/test_pr1475_HIF.py b/tests/bugfixes/github/test_pr1475_HIF.py new file mode 100644 index 00000000..de510d5c --- /dev/null +++ b/tests/bugfixes/github/test_pr1475_HIF.py @@ -0,0 +1,246 @@ +# -*- coding: utf-8 -*- + +import system_tests + +# test needs system_tests.BT.vv.enable_bmff=1 +vv=system_tests.BT.verbose_version() +enable_bmff = 'enable_bmff' +bSkip = not (enable_bmff in vv and vv[enable_bmff] == '1') + +class pr_1475_Sony_hif(metaclass=system_tests.CaseMeta): + url = "https://github.com/Exiv2/exiv2/pull/1475" + filename = "$data_path/Sony.HIF" + if bSkip: + commands=[] + retval=[] + stdin=[] + stderr=[] + stdout=[] + print("*** test skipped. requires enable_bmff=1***") + else: + commands = ["$exiv2 -g Image.Make -g Date -g Xm -g Expo -g Flash $filename" + ,"$exiv2 -pS $filename" + ,"$exiv2 -pX $filename" + ,"$exiv2 -pC $filename" + ] + retval = [ 0 ] * len(commands) + stderr = [ "" ] * len(commands) + stdin = [ "" ] * len(commands) + stdout = ["""Exif.Image.Make Ascii 5 SONY +Exif.Image.DateTime Ascii 20 2021:02:18 19:55:41 +Exif.Photo.ExposureTime Rational 1 1/1000 s +Exif.Photo.ExposureProgram Short 1 Manual +Exif.Photo.RecommendedExposureIndex Long 1 100 +Exif.Photo.DateTimeOriginal Ascii 20 2021:02:18 19:55:41 +Exif.Photo.DateTimeDigitized Ascii 20 2021:02:18 19:55:41 +Exif.Photo.ExposureBiasValue SRational 1 0 EV +Exif.Photo.Flash Short 1 No, compulsory +Exif.Sony1.FlashExposureComp SRational 1 0 EV +Exif.Sony1.ExposureMode Short 1 Manual +Exif.Sony1.FlashLevel SShort 1 Normal +Exif.Photo.FlashpixVersion Undefined 4 1.00 +Exif.Photo.ExposureMode Short 1 Manual +Xmp.xmp.Rating XmpText 1 0 +""","""Exiv2::BmffImage::boxHandler: ftyp 0->40 brand: heix +Exiv2::BmffImage::boxHandler: meta 40->2081 + Exiv2::BmffImage::boxHandler: hdlr 52->33 + Exiv2::BmffImage::boxHandler: pitm 85->14 + Exiv2::BmffImage::boxHandler: iinf 99->350 + Exiv2::BmffImage::boxHandler: infe 113->21 ID = 1 hvc1 + Exiv2::BmffImage::boxHandler: infe 134->21 ID = 2 hvc1 + Exiv2::BmffImage::boxHandler: infe 155->21 ID = 3 hvc1 + Exiv2::BmffImage::boxHandler: infe 176->21 ID = 4 hvc1 + Exiv2::BmffImage::boxHandler: infe 197->21 ID = 5 hvc1 + Exiv2::BmffImage::boxHandler: infe 218->21 ID = 6 hvc1 + Exiv2::BmffImage::boxHandler: infe 239->21 ID = 7 hvc1 + Exiv2::BmffImage::boxHandler: infe 260->21 ID = 8 hvc1 + Exiv2::BmffImage::boxHandler: infe 281->21 ID = 9 hvc1 + Exiv2::BmffImage::boxHandler: infe 302->21 ID = 10 grid + Exiv2::BmffImage::boxHandler: infe 323->21 ID = 11 hvc1 + Exiv2::BmffImage::boxHandler: infe 344->21 ID = 12 hvc1 + Exiv2::BmffImage::boxHandler: infe 365->21 ID = 13 jpeg + Exiv2::BmffImage::boxHandler: infe 386->21 ID = 14 Exif *** Exif *** + Exiv2::BmffImage::boxHandler: infe 407->42 ID = 15 mime *** XMP *** + Exiv2::BmffImage::boxHandler: iref 449->112 + Exiv2::BmffImage::boxHandler: iprp 561->1288 + Exiv2::BmffImage::boxHandler: ipco 569->1184 + Exiv2::BmffImage::boxHandler: irot 577->9 + Exiv2::BmffImage::boxHandler: colr 586->19 + Exiv2::BmffImage::boxHandler: pixi 605->16 + Exiv2::BmffImage::boxHandler: hvcC 621->345 + Exiv2::BmffImage::boxHandler: ispe 966->20 pixelWidth_, pixelHeight_ = 2880, 1920 + Exiv2::BmffImage::boxHandler: ispe 986->20 pixelWidth_, pixelHeight_ = 8640, 5760 + Exiv2::BmffImage::boxHandler: hvcC 1006->344 + Exiv2::BmffImage::boxHandler: ispe 1350->20 pixelWidth_, pixelHeight_ = 1616, 1080 + Exiv2::BmffImage::boxHandler: hvcC 1370->343 + Exiv2::BmffImage::boxHandler: ispe 1713->20 pixelWidth_, pixelHeight_ = 320, 212 + Exiv2::BmffImage::boxHandler: ispe 1733->20 pixelWidth_, pixelHeight_ = 160, 120 + Exiv2::BmffImage::boxHandler: ipma 1753->96 + Exiv2::BmffImage::boxHandler: idat 1849->16 + Exiv2::BmffImage::boxHandler: iloc 1865->256 + 1873 | 16 | ID | 15 | 4096, 57344 + 1889 | 16 | ID | 14 | 61440, 40960 + 1905 | 16 | ID | 13 | 102400, 4096 + 1921 | 16 | ID | 12 | 106496, 4096 + 1937 | 16 | ID | 1 | 110592, 4562 + 1953 | 16 | ID | 2 | 115154, 2802 + 1969 | 16 | ID | 3 | 117956, 4344 + 1985 | 16 | ID | 4 | 122300, 3772 + 2001 | 16 | ID | 5 | 126072, 2227 + 2017 | 16 | ID | 6 | 128299, 3668 + 2033 | 16 | ID | 7 | 131967, 4518 + 2049 | 16 | ID | 8 | 136485, 2840 + 2065 | 16 | ID | 9 | 139325, 8131 + 2081 | 16 | ID | 10 | 0, 8 + 2097 | 16 | ID | 11 | 147456, 4096 +Exiv2::BMFF Exif: ID = 14 from,length = 61440,40960 +Exiv2::BMFF XMP: ID = 15 from,length = 4096,57344 +Exiv2::BmffImage::boxHandler: free 2121->1967 +Exiv2::BmffImage::boxHandler: mdat 4088->147464 +""",""" + + + + + + + + + + + + + + + + + + + + + + + + + + +""",""] + +class pr_1475_Canon_hif(metaclass=system_tests.CaseMeta): + url = "https://github.com/Exiv2/exiv2/pull/1475" + filename = "$data_path/Canon.HIF" + + if bSkip: + commands=[] + retval=[] + stdin=[] + stderr=[] + stdin=[] + print("*** test skipped. requires enable_bmff=1***") + else: + commands = ["$exiv2 -g Image.Make -g Date -g Xm -g Expo -g Flash $filename" + ,"$exiv2 -pS $filename" + ,"$exiv2 -pX $filename" + ,"$exiv2 -pC $filename" + ] + retval = [ 0 ] * len(commands) + stderr = [ "" ] * len(commands) + stdin = [ "" ] * len(commands) + stdout = ["""Exif.Image.Make Ascii 6 Canon +Exif.Image.DateTime Ascii 20 2021:02:18 19:54:47 +Exif.Photo.ExposureTime Rational 1 1/1000 s +Exif.Photo.ExposureProgram Short 1 Manual +Exif.Photo.RecommendedExposureIndex Long 1 100 +Exif.Photo.DateTimeOriginal Ascii 20 2021:02:18 19:54:47 +Exif.Photo.DateTimeDigitized Ascii 20 2021:02:18 19:54:47 +Exif.Photo.ExposureBiasValue SRational 1 0 EV +Exif.Photo.Flash Short 1 No flash +Exif.CanonCs.FlashMode Short 1 Off +Exif.CanonCs.ExposureProgram Short 1 Manual (M) +Exif.CanonCs.FlashActivity Short 1 Did not fire +Exif.CanonCs.FlashDetails Short 1 E-TTL +Exif.CanonCs.ManualFlashOutput Short 1 n/a +Exif.CanonSi.FlashGuideNumber Short 1 0 +Exif.CanonSi.FlashBias Short 1 0 EV +Exif.CanonSi.AutoExposureBracketing Short 1 Off +Exif.CanonFi.FlashExposureLock SShort 1 Off +Exif.Photo.FlashpixVersion Undefined 4 1.00 +Exif.Photo.ExposureMode Short 1 Manual +Xmp.xmp.Rating XmpText 1 0 +""","""Exiv2::BmffImage::boxHandler: ftyp 0->32 brand: heix +Exiv2::BmffImage::boxHandler: meta 32->1163 + Exiv2::BmffImage::boxHandler: hdlr 44->33 + Exiv2::BmffImage::boxHandler: uuid 77->62 uuidName cano + Exiv2::BmffImage::boxHandler: CNCV 101->38 + Exiv2::BmffImage::boxHandler: dinf 139->36 + Exiv2::BmffImage::boxHandler: pitm 175->14 + Exiv2::BmffImage::boxHandler: iinf 189->203 + Exiv2::BmffImage::boxHandler: infe 203->21 ID = 1 grid + Exiv2::BmffImage::boxHandler: infe 224->21 ID = 256 hvc1 + Exiv2::BmffImage::boxHandler: infe 245->21 ID = 257 hvc1 + Exiv2::BmffImage::boxHandler: infe 266->21 ID = 258 hvc1 + Exiv2::BmffImage::boxHandler: infe 287->21 ID = 259 hvc1 + Exiv2::BmffImage::boxHandler: infe 308->21 ID = 512 hvc1 + Exiv2::BmffImage::boxHandler: infe 329->21 ID = 768 Exif *** Exif *** + Exiv2::BmffImage::boxHandler: infe 350->42 ID = 769 mime *** XMP *** + Exiv2::BmffImage::boxHandler: iref 392->74 + Exiv2::BmffImage::boxHandler: iprp 466->569 + Exiv2::BmffImage::boxHandler: ipco 474->507 + Exiv2::BmffImage::boxHandler: hvcC 482->176 + Exiv2::BmffImage::boxHandler: ispe 658->20 pixelWidth_, pixelHeight_ = 1216, 832 + Exiv2::BmffImage::boxHandler: colr 678->19 + Exiv2::BmffImage::boxHandler: pixi 697->16 + Exiv2::BmffImage::boxHandler: ispe 713->20 pixelWidth_, pixelHeight_ = 2400, 1600 + Exiv2::BmffImage::boxHandler: irot 733->9 + Exiv2::BmffImage::boxHandler: hvcC 742->175 + Exiv2::BmffImage::boxHandler: ispe 917->20 pixelWidth_, pixelHeight_ = 320, 214 + Exiv2::BmffImage::boxHandler: colr 937->19 + Exiv2::BmffImage::boxHandler: pixi 956->16 + Exiv2::BmffImage::boxHandler: irot 972->9 + Exiv2::BmffImage::boxHandler: ipma 981->54 + Exiv2::BmffImage::boxHandler: idat 1035->16 + Exiv2::BmffImage::boxHandler: iloc 1051->144 + 1059 | 16 | ID | 1 | 0, 8 + 1075 | 16 | ID | 256 | 46080,344284 + 1091 | 16 | ID | 257 | 390364,340989 + 1107 | 16 | ID | 258 | 731353,257177 + 1123 | 16 | ID | 259 | 988530,264862 + 1139 | 16 | ID | 512 | 32256, 10284 + 1155 | 16 | ID | 768 | 1536, 30463 + 1171 | 16 | ID | 769 | 43008, 3072 +Exiv2::BMFF Exif: ID = 768 from,length = 1536,30463 +Exiv2::BMFF XMP: ID = 769 from,length = 43008,3072 +Exiv2::BmffImage::boxHandler: mdat 1195->1252197 +""",""" + + + + + + + + + + + + + + + + + + + + + + + + + + +""",""] + diff --git a/unitTests/test_futils.cpp b/unitTests/test_futils.cpp index 25545fd1..46b21dd1 100644 --- a/unitTests/test_futils.cpp +++ b/unitTests/test_futils.cpp @@ -147,7 +147,7 @@ TEST(base64decode, decodesValidString) const std::string original ("VGhpcyBpcyBhIHVuaXQgdGVzdA=="); const std::string expected ("This is a unit test"); char * result = new char [original.size()]; - ASSERT_EQ(static_cast(expected.size()+1), + ASSERT_EQ(static_cast(expected.size()), base64decode(original.c_str(), result, original.size())); ASSERT_STREQ(expected.c_str(), result); delete [] result;