Skip to content

Commit

Permalink
Fix orientation handling -- the Exif is not trustworthy,have to use
Browse files Browse the repository at this point in the history
the rotations and mirrors in the properties to derive the orientation
ourselves.

Signed-off-by: Larry Gritz <[email protected]>
  • Loading branch information
lgritz committed Feb 7, 2024
1 parent a4e1e48 commit f2e59d3
Showing 1 changed file with 51 additions and 1 deletion.
52 changes: 51 additions & 1 deletion src/heif.imageio/heifinput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@

#include <libheif/heif_cxx.h>

#define MAKE_LIBHEIF_VERSION(a, b, c, d) \
(((a) << 24) | ((b) << 16) | ((c) << 8) | (d))

#if LIBHEIF_NUMERIC_VERSION >= MAKE_LIBHEIF_VERSION(1, 17, 0, 0)
# include <libheif/heif_properties.h>
#endif



// This plugin utilises libheif:
// https://github.com/strukturag/libheif
Expand Down Expand Up @@ -309,9 +317,51 @@ HeifInput::seek_subimage(int subimage, int miplevel)
}
}

// Try to discover the orientation. The Exif is unreliable. We have to go
// through the transformation properties ourselves. A tricky bit is that
// the C++ API doesn't give us a direct way to get the context ptr, we
// need to resort to some casting trickery, with knowledge that the C++
// heif::Context class consists solely of a std::shared_ptr to a
// heif_context.
// NO int orientation = m_spec.get_int_attribute("Orientation", 1);
int orientation = 1;
const heif_context* raw_ctx
= reinterpret_cast<std::shared_ptr<heif_context>*>(m_ctx.get())->get();
int xpcount = heif_item_get_transformation_properties(raw_ctx, id, nullptr,
100);
orientation = 1;
xpcount = std::min(xpcount, 100); // clamp to some reasonable limit
std::vector<heif_property_id> xprops(xpcount);
heif_item_get_transformation_properties(raw_ctx, id, xprops.data(),
xpcount);
for (int i = 0; i < xpcount; ++i) {
auto type = heif_item_get_property_type(raw_ctx, id, xprops[i]);
if (type == heif_item_property_type_transform_rotation) {
int rot = heif_item_get_property_transform_rotation_ccw(raw_ctx, id,
xprops[i]);
static const int cw[] = { 0, 6, 7, 8, 5, 2, 3, 4, 1 };
switch (rot) {
case 270: orientation = cw[orientation];
case 180: orientation = cw[orientation];
case 90: orientation = cw[orientation];
default: break;
}
} else if (type == heif_item_property_type_transform_mirror) {
int mirror = heif_item_get_property_transform_mirror(raw_ctx, id,
xprops[i]);
// 1 2 3 4 5 6 7 8
static const int mirrorh[] = { 0, 2, 1, 4, 3, 6, 5, 8, 7 };
static const int mirrorv[] = { 0, 4, 3, 2, 1, 8, 7, 6, 5 };
if (mirror == heif_transform_mirror_direction_vertical) {
orientation = mirrorv[orientation];
} else if (mirror == heif_transform_mirror_direction_horizontal) {
orientation = mirrorh[orientation];
}
}
}

// Erase the orientation metadata because libheif appears to be doing
// the rotation-to-canonical-direction for us.
int orientation = m_spec.get_int_attribute("Orientation", 1);
if (orientation != 1) {
if (m_reorient) {
// If libheif auto-reoriented, record the original orientation in
Expand Down

0 comments on commit f2e59d3

Please sign in to comment.