Exiv2 / exiv2

Image metadata library and tools
http://www.exiv2.org/
Other
920 stars 278 forks source link

Orientation: CLI tool and C++ API disagree #2958

Closed luspi closed 4 months ago

luspi commented 4 months ago

Describe the bug

I have a HEIF image that has an orientation value of 1 stored in it. With the exiv2 command line tool that value is correctly read as 1. However, when using the C++ API to read that value I get a value of 6 back. Converting that image to a JPEG makes the C++ API to also return the correct value of 1.

To Reproduce

Steps to reproduce the behavior:

  1. Take this test image: testimage.zip
  2. Run exiv2 -p a testimage.heif and obtain: Exif.Image.Orientation Short 1 right, top
  3. Compile and run the sample code below, ./exiv2test testimage.heif, and obtain: Exif.Image.Orientation = 6
  4. Run the same test with that file converted to JPEG (or use this one: testimage.jpg), run ./exiv2test testimage.jpg, and obtain: Exif.Image.Orientation = 1
  5. This is done with the latest released version, 0.28.2.

Expected behavior

The test code should return the correct value of 1 for both the HEIF and JPEG file.

Desktop (please complete the following information):

Additional context

The example test code consists of these two files:

CMakeLists.txt:

project(exiv2test LANGUAGES CXX)
find_package(exiv2 REQUIRED)
add_executable(exiv2test main.cpp)
include_directories(${EXIV2_INCLUDE_DIR})
target_link_libraries(exiv2test "exiv2")

main.cpp:

#include <exiv2/exiv2.hpp>

int main(int argc, char **argv) {
    if(argc == 1) {
        std::cout << "You need to add the filename as command line argument." << std::endl;
        return 0;
    }
    Exiv2::enableBMFF(true);
    Exiv2::Image::UniquePtr image = Exiv2::ImageFactory::open(argv[1]);
    image->readMetadata();
    std::cout << "Exif.Image.Orientation = " << Exiv2::orientation(image->exifData())->value().toInt64() << std::endl;
    return 0;
}
kmilos commented 4 months ago

There's no bug here: the "1" you see is the count of elements, the stored value is correct: "right, top" is 6. You can confirm this by exiv2 -Pkycvt (-pa is equivalent to -Pkyct).

Anyway, orientation w/ HEIFs is somewhat of a tricky beast - the HEIF irot/imir properties (see output of exiv2 -pS if those exist, although actual value is not parsed/printed by exiv2) take precedence over Exif tags, and they can be actually out of sync. In fact, HEIF readers are instructed to ignore the Exif orientation by the HEIF spec. When converting to JPEG and similar, some apps might actually do the orientation according to HEIF irot/imir, and then explicitly set Exif orientation to 1 (no further transformation, i.e. "top, left").

luspi commented 4 months ago

Ah, thanks, that makes sense :+1: