diff --git a/CMakeLists.txt b/CMakeLists.txt index 789ce68..359c250 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,7 +72,7 @@ set_property(CACHE KIMAGEFORMATS_HEJ2_TEST PROPERTY STRINGS "OFF" "READ_ONLY" "A set(KIMAGEFORMATS_AVCI_TEST "ALL" CACHE STRING "Enable AVCI tests: OFF, ALL") set_property(CACHE KIMAGEFORMATS_AVCI_TEST PROPERTY STRINGS "OFF" "ALL") if(KIMAGEFORMATS_HEIF) - pkg_check_modules(LibHeif IMPORTED_TARGET libheif>=1.10.0) + pkg_check_modules(LibHeif IMPORTED_TARGET libheif>=1.17.0) endif() add_feature_info(LibHeif LibHeif_FOUND "required for the QImage plugin for HEIF/HEIC images") diff --git a/README.md b/README.md index fa8fb66..a42a642 100644 --- a/README.md +++ b/README.md @@ -333,6 +333,15 @@ distributions. In particular, it is necessary that the HEIF library has support for HEVC codec. If HEVC codec is not available the plugin will compile but will fail the tests. +The following defines can be defined in cmake to modify the behavior of the +plugin: +- `HEIF_DISABLE_QT_TRANSFORMATION`: HEIF transformations, in addition to + rotations and reflections, also support image cropping. Consequently, the + Qt plugin, must also honor the crop. This define is useful in case + of problems: activating it disables Qt's support for transformations, + delegating them to the HEIF libraries (which will therefore always apply + them regardless of what is requested from Qt). + **If you are interested in compiling the plugin without running the tests, also use the following string options:** - `KIMAGEFORMATS_HEIF_TEST` to change the behaviour of HEIF tests. Set to diff --git a/autotests/read/heif/crop_orientation1.heif b/autotests/read/heif/crop_orientation1.heif new file mode 100644 index 0000000..6dddc8a Binary files /dev/null and b/autotests/read/heif/crop_orientation1.heif differ diff --git a/autotests/read/heif/crop_orientation1.png b/autotests/read/heif/crop_orientation1.png new file mode 100644 index 0000000..ae8a409 Binary files /dev/null and b/autotests/read/heif/crop_orientation1.png differ diff --git a/autotests/read/heif/crop_orientation2.heif b/autotests/read/heif/crop_orientation2.heif new file mode 100644 index 0000000..d99dc3f Binary files /dev/null and b/autotests/read/heif/crop_orientation2.heif differ diff --git a/autotests/read/heif/crop_orientation2.png b/autotests/read/heif/crop_orientation2.png new file mode 100644 index 0000000..8b34d7a Binary files /dev/null and b/autotests/read/heif/crop_orientation2.png differ diff --git a/autotests/read/heif/crop_orientation3.heif b/autotests/read/heif/crop_orientation3.heif new file mode 100644 index 0000000..7c2510c Binary files /dev/null and b/autotests/read/heif/crop_orientation3.heif differ diff --git a/autotests/read/heif/crop_orientation3.png b/autotests/read/heif/crop_orientation3.png new file mode 100644 index 0000000..5bba556 Binary files /dev/null and b/autotests/read/heif/crop_orientation3.png differ diff --git a/autotests/read/heif/crop_orientation4.heif b/autotests/read/heif/crop_orientation4.heif new file mode 100644 index 0000000..3e1cfaf Binary files /dev/null and b/autotests/read/heif/crop_orientation4.heif differ diff --git a/autotests/read/heif/crop_orientation4.png b/autotests/read/heif/crop_orientation4.png new file mode 100644 index 0000000..b0b6465 Binary files /dev/null and b/autotests/read/heif/crop_orientation4.png differ diff --git a/autotests/read/heif/crop_orientation5.heif b/autotests/read/heif/crop_orientation5.heif new file mode 100644 index 0000000..8f72a96 Binary files /dev/null and b/autotests/read/heif/crop_orientation5.heif differ diff --git a/autotests/read/heif/crop_orientation5.png b/autotests/read/heif/crop_orientation5.png new file mode 100644 index 0000000..4138e6e Binary files /dev/null and b/autotests/read/heif/crop_orientation5.png differ diff --git a/autotests/read/heif/crop_orientation6.heif b/autotests/read/heif/crop_orientation6.heif new file mode 100644 index 0000000..ad25afa Binary files /dev/null and b/autotests/read/heif/crop_orientation6.heif differ diff --git a/autotests/read/heif/crop_orientation6.png b/autotests/read/heif/crop_orientation6.png new file mode 100644 index 0000000..e4e89cc Binary files /dev/null and b/autotests/read/heif/crop_orientation6.png differ diff --git a/autotests/read/heif/crop_orientation7.heif b/autotests/read/heif/crop_orientation7.heif new file mode 100644 index 0000000..22e5d53 Binary files /dev/null and b/autotests/read/heif/crop_orientation7.heif differ diff --git a/autotests/read/heif/crop_orientation7.png b/autotests/read/heif/crop_orientation7.png new file mode 100644 index 0000000..f1effab Binary files /dev/null and b/autotests/read/heif/crop_orientation7.png differ diff --git a/autotests/read/heif/crop_orientation8.heif b/autotests/read/heif/crop_orientation8.heif new file mode 100644 index 0000000..65e272e Binary files /dev/null and b/autotests/read/heif/crop_orientation8.heif differ diff --git a/autotests/read/heif/crop_orientation8.png b/autotests/read/heif/crop_orientation8.png new file mode 100644 index 0000000..82e24ff Binary files /dev/null and b/autotests/read/heif/crop_orientation8.png differ diff --git a/autotests/read/heif/orientation1.heif b/autotests/read/heif/orientation1.heif new file mode 100644 index 0000000..3d5dea0 Binary files /dev/null and b/autotests/read/heif/orientation1.heif differ diff --git a/autotests/read/heif/orientation1.heif.json b/autotests/read/heif/orientation1.heif.json new file mode 100644 index 0000000..41d52f7 --- /dev/null +++ b/autotests/read/heif/orientation1.heif.json @@ -0,0 +1,17 @@ +[ + { + "fileName" : "orientation_all.png", + "colorSpace" : { + "description" : "GIMP built-in sRGB", + "primaries" : "SRgb", + "transferFunction" : "SRgb", + "gamma" : 0 + }, + "metadata" : [ + { + "key" : "Software" , + "value" : "LIFE Pro 2.20.35 (Linux)" + } + ] + } +] diff --git a/autotests/read/heif/orientation2.heif b/autotests/read/heif/orientation2.heif new file mode 100644 index 0000000..5900e51 Binary files /dev/null and b/autotests/read/heif/orientation2.heif differ diff --git a/autotests/read/heif/orientation2.heif.json b/autotests/read/heif/orientation2.heif.json new file mode 100644 index 0000000..5f917c3 --- /dev/null +++ b/autotests/read/heif/orientation2.heif.json @@ -0,0 +1,11 @@ +[ + { + "fileName" : "orientation_all.png", + "metadata" : [ + { + "key" : "Software" , + "value" : "LIFE Pro 2.20.35 (Linux)" + } + ] + } +] diff --git a/autotests/read/heif/orientation3.heif b/autotests/read/heif/orientation3.heif new file mode 100644 index 0000000..009e306 Binary files /dev/null and b/autotests/read/heif/orientation3.heif differ diff --git a/autotests/read/heif/orientation3.heif.json b/autotests/read/heif/orientation3.heif.json new file mode 100644 index 0000000..5f917c3 --- /dev/null +++ b/autotests/read/heif/orientation3.heif.json @@ -0,0 +1,11 @@ +[ + { + "fileName" : "orientation_all.png", + "metadata" : [ + { + "key" : "Software" , + "value" : "LIFE Pro 2.20.35 (Linux)" + } + ] + } +] diff --git a/autotests/read/heif/orientation4.heif b/autotests/read/heif/orientation4.heif new file mode 100644 index 0000000..b834ae0 Binary files /dev/null and b/autotests/read/heif/orientation4.heif differ diff --git a/autotests/read/heif/orientation4.heif.json b/autotests/read/heif/orientation4.heif.json new file mode 100644 index 0000000..5f917c3 --- /dev/null +++ b/autotests/read/heif/orientation4.heif.json @@ -0,0 +1,11 @@ +[ + { + "fileName" : "orientation_all.png", + "metadata" : [ + { + "key" : "Software" , + "value" : "LIFE Pro 2.20.35 (Linux)" + } + ] + } +] diff --git a/autotests/read/heif/orientation5.heif b/autotests/read/heif/orientation5.heif new file mode 100644 index 0000000..83f9b0c Binary files /dev/null and b/autotests/read/heif/orientation5.heif differ diff --git a/autotests/read/heif/orientation5.heif.json b/autotests/read/heif/orientation5.heif.json new file mode 100644 index 0000000..5f917c3 --- /dev/null +++ b/autotests/read/heif/orientation5.heif.json @@ -0,0 +1,11 @@ +[ + { + "fileName" : "orientation_all.png", + "metadata" : [ + { + "key" : "Software" , + "value" : "LIFE Pro 2.20.35 (Linux)" + } + ] + } +] diff --git a/autotests/read/heif/orientation6.heif b/autotests/read/heif/orientation6.heif new file mode 100644 index 0000000..7635754 Binary files /dev/null and b/autotests/read/heif/orientation6.heif differ diff --git a/autotests/read/heif/orientation6.heif.json b/autotests/read/heif/orientation6.heif.json new file mode 100644 index 0000000..5f917c3 --- /dev/null +++ b/autotests/read/heif/orientation6.heif.json @@ -0,0 +1,11 @@ +[ + { + "fileName" : "orientation_all.png", + "metadata" : [ + { + "key" : "Software" , + "value" : "LIFE Pro 2.20.35 (Linux)" + } + ] + } +] diff --git a/autotests/read/heif/orientation7.heif b/autotests/read/heif/orientation7.heif new file mode 100644 index 0000000..f98be75 Binary files /dev/null and b/autotests/read/heif/orientation7.heif differ diff --git a/autotests/read/heif/orientation7.heif.json b/autotests/read/heif/orientation7.heif.json new file mode 100644 index 0000000..5f917c3 --- /dev/null +++ b/autotests/read/heif/orientation7.heif.json @@ -0,0 +1,11 @@ +[ + { + "fileName" : "orientation_all.png", + "metadata" : [ + { + "key" : "Software" , + "value" : "LIFE Pro 2.20.35 (Linux)" + } + ] + } +] diff --git a/autotests/read/heif/orientation8.heif b/autotests/read/heif/orientation8.heif new file mode 100644 index 0000000..6ebcd1f Binary files /dev/null and b/autotests/read/heif/orientation8.heif differ diff --git a/autotests/read/heif/orientation8.heif.json b/autotests/read/heif/orientation8.heif.json new file mode 100644 index 0000000..5f917c3 --- /dev/null +++ b/autotests/read/heif/orientation8.heif.json @@ -0,0 +1,11 @@ +[ + { + "fileName" : "orientation_all.png", + "metadata" : [ + { + "key" : "Software" , + "value" : "LIFE Pro 2.20.35 (Linux)" + } + ] + } +] diff --git a/autotests/read/heif/orientation_all.png b/autotests/read/heif/orientation_all.png new file mode 100644 index 0000000..d8bec2d Binary files /dev/null and b/autotests/read/heif/orientation_all.png differ diff --git a/src/imageformats/heif.cpp b/src/imageformats/heif.cpp index 5005e67..922a644 100644 --- a/src/imageformats/heif.cpp +++ b/src/imageformats/heif.cpp @@ -11,6 +11,7 @@ #include "microexif_p.h" #include "util_p.h" #include +#include #include #include @@ -33,6 +34,18 @@ Q_LOGGING_CATEGORY(LOG_HEIFPLUGIN, "kf.imageformats.plugins.heif", QtWarningMsg) #define HEIF_MAX_METADATA_SIZE (4 * 1024 * 1024) #endif +#ifndef HEIF_DISABLE_QT_TRANSFORMATION +/*! + * HEIF transformations, in addition to rotations and reflections, + * also support image cropping. Consequently, the Qt plugin, must + * also honor the crop. This define is useful in case of problems: + * activating it disables Qt's support for transformations, + * delegating them to the HEIF libraries (which will therefore + * always apply them regardless of what is requested from Qt). + */ +// #define HEIF_DISABLE_QT_TRANSFORMATION +#endif + size_t HEIFHandler::m_initialized_count = 0; bool HEIFHandler::m_plugins_queried = false; bool HEIFHandler::m_heif_decoder_available = false; @@ -72,6 +85,7 @@ static struct heif_error heifhandler_write_callback(struct heif_context * /* ctx HEIFHandler::HEIFHandler() : m_parseState(ParseHeicNotParsed) , m_quality(100) + , m_orientation(0) { } @@ -123,15 +137,11 @@ bool HEIFHandler::write(const QImage &image) return false; } -#if LIBHEIF_HAVE_VERSION(1, 13, 0) startHeifLib(); -#endif bool success = write_helper(image); -#if LIBHEIF_HAVE_VERSION(1, 13, 0) finishHeifLib(); -#endif return success; } @@ -163,12 +173,10 @@ bool HEIFHandler::write_helper(const QImage &image) } heif_compression_format encoder_codec = heif_compression_HEVC; -#if LIBHEIF_HAVE_VERSION(1, 13, 0) if (format() == "hej2") { encoder_codec = heif_compression_JPEG2000; save_depth = 8; // for compatibility reasons } -#endif heif_chroma chroma; if (save_depth > 8) { @@ -325,12 +333,21 @@ bool HEIFHandler::write_helper(const QImage &image) } } + if (m_orientation >= 1 && m_orientation <= 8) { + // Function available from HEIF v1.14 + encoder_options->image_orientation = heif_orientation(m_orientation); + } + struct heif_image_handle *handle; err = heif_context_encode_image(context, h_image, encoder, encoder_options, &handle); // exif metadata if (err.code == heif_error_Ok) { auto exif = MicroExif::fromImage(tmpimage); + if (m_orientation >= 1 && m_orientation <= 8) { + // EXIF orientation must be coherent with HEIF orientation + exif.setOrientation(m_orientation); + } if (!exif.isEmpty()) { auto ba = exif.toByteArray(); err = heif_context_add_exif_metadata(context, handle, ba.constData(), ba.size()); @@ -376,6 +393,74 @@ bool HEIFHandler::write_helper(const QImage &image) return true; } +bool HEIFHandler::read_orientation_helper(void *heif_handle, const void *heif_ctx) +{ + if (heif_handle == nullptr || heif_ctx == nullptr) { + return false; + } + auto handle = reinterpret_cast(heif_handle); + auto ctx = reinterpret_cast(heif_ctx); + auto item_id = heif_image_handle_get_item_id(handle); + + // get the properties + heif_transform_mirror_direction mirror = heif_transform_mirror_direction::heif_transform_mirror_direction_invalid; + heif_property_id mir_id; + if (heif_item_get_properties_of_type(ctx, item_id, heif_item_property_type_transform_mirror, &mir_id, 1) > 0) { + mirror = heif_item_get_property_transform_mirror(ctx, item_id, mir_id); + if (mirror == heif_transform_mirror_direction::heif_transform_mirror_direction_invalid) + return false; + } + + int rotation_ccw = -1; + heif_property_id rot_id; + if (heif_item_get_properties_of_type(ctx, item_id, heif_item_property_type_transform_rotation, &rot_id, 1) > 0) { + rotation_ccw = heif_item_get_property_transform_rotation_ccw(ctx, item_id, rot_id); + if (rotation_ccw == -1) + return false; + } + + if (rotation_ccw == -1 && mirror == heif_transform_mirror_direction::heif_transform_mirror_direction_invalid) { + m_orientation = 0; + } else if (rotation_ccw == 0 && mirror == heif_transform_mirror_direction::heif_transform_mirror_direction_invalid) { + m_orientation = 1; + } else if (rotation_ccw <= 0 && mirror == heif_transform_mirror_direction::heif_transform_mirror_direction_horizontal) { + m_orientation = 2; + } else if (rotation_ccw == 180 && mirror == heif_transform_mirror_direction::heif_transform_mirror_direction_invalid) { + m_orientation = 3; + } else if (rotation_ccw <= 0 && mirror == heif_transform_mirror_direction::heif_transform_mirror_direction_vertical) { + m_orientation = 4; + } else if (rotation_ccw == 270 && mirror == heif_transform_mirror_direction::heif_transform_mirror_direction_horizontal) { + m_orientation = 5; + } else if (rotation_ccw == 270 && mirror == heif_transform_mirror_direction::heif_transform_mirror_direction_invalid) { + m_orientation = 6; + } else if (rotation_ccw == 270 && mirror == heif_transform_mirror_direction::heif_transform_mirror_direction_vertical) { + m_orientation = 7; + } else if (rotation_ccw == 90 && mirror == heif_transform_mirror_direction::heif_transform_mirror_direction_invalid) { + m_orientation = 8; + } + + return true; +} + +bool HEIFHandler::read_crop(void *heif_handle, const void *heif_ctx, const QSize &size, QRect &crop) +{ + if (heif_handle == nullptr || heif_ctx == nullptr) { + return false; + } + auto handle = reinterpret_cast(heif_handle); + auto ctx = reinterpret_cast(heif_ctx); + auto item_id = heif_image_handle_get_item_id(handle); + + heif_property_id crop_id; + if (heif_item_get_properties_of_type(ctx, item_id, heif_item_property_type_transform_crop, &crop_id, 1) > 0) { + int l = 0, t = 0, r = 0, b = 0; + heif_item_get_property_transform_crop_borders(ctx, item_id, crop_id, size.width(), size.height(), &l, &t, &r, &b); + crop = QRect(QPoint(t, l), size - QSize(b + t, r + l)); + } + + return crop.isValid(); +} + bool HEIFHandler::isSupportedBMFFType(const QByteArray &header) { if (header.size() < 28) { @@ -456,10 +541,10 @@ QVariant HEIFHandler::option(ImageOption option) const switch (option) { case Size: return m_current_image.size(); - break; + case ImageTransformation: + return int(MicroExif::orientationToTransformation(m_orientation)); default: return QVariant(); - break; } } @@ -474,6 +559,9 @@ void HEIFHandler::setOption(ImageOption option, const QVariant &value) m_quality = 100; } break; + case ImageTransformation: + m_orientation = MicroExif::transformationToOrientation(QImageIOHandler::Transformation(value.toUInt())); + break; default: QImageIOHandler::setOption(option, value); break; @@ -482,7 +570,11 @@ void HEIFHandler::setOption(ImageOption option, const QVariant &value) bool HEIFHandler::supportsOption(ImageOption option) const { - return option == Quality || option == Size; + auto ok = option == Quality || option == Size; +#ifndef HEIF_DISABLE_QT_TRANSFORMATION + ok = ok || option == ImageTransformation; +#endif + return ok; } bool HEIFHandler::ensureParsed() const @@ -496,15 +588,12 @@ bool HEIFHandler::ensureParsed() const HEIFHandler *that = const_cast(this); -#if LIBHEIF_HAVE_VERSION(1, 13, 0) startHeifLib(); -#endif bool success = that->ensureDecoder(); -#if LIBHEIF_HAVE_VERSION(1, 13, 0) finishHeifLib(); -#endif + return success; } @@ -589,16 +678,19 @@ bool HEIFHandler::ensureDecoder() return false; } + bool ignore_transformations = false; struct heif_decoding_options *decoder_option = heif_decoding_options_alloc(); -#if LIBHEIF_HAVE_VERSION(1, 13, 0) decoder_option->strict_decoding = 1; +#ifdef HEIF_DISABLE_QT_TRANSFORMATION + decoder_option->ignore_transformations = ignore_transformations; +#else + decoder_option->ignore_transformations = ignore_transformations = read_orientation_helper(handle, ctx); #endif struct heif_image *img = nullptr; err = heif_decode_image(handle, &img, heif_colorspace_RGB, chroma, decoder_option); -#if LIBHEIF_HAVE_VERSION(1, 13, 0) if (err.code == heif_error_Invalid_input && err.subcode == heif_suberror_Unknown_NCLX_matrix_coefficients && img == nullptr && buffer.contains("Xiaomi")) { qCWarning(LOG_HEIFPLUGIN) << "Non-standard HEIF image with invalid matrix_coefficients, probably made by a Xiaomi device!"; @@ -606,7 +698,6 @@ bool HEIFHandler::ensureDecoder() decoder_option->strict_decoding = 0; err = heif_decode_image(handle, &img, heif_colorspace_RGB, chroma, decoder_option); } -#endif if (decoder_option) { heif_decoding_options_free(decoder_option); @@ -852,6 +943,12 @@ bool HEIFHandler::ensureDecoder() break; } + if (ignore_transformations) { + QRect crop_rect; + if (read_crop(handle, ctx, m_current_image.size(), crop_rect)) + m_current_image = m_current_image.copy(crop_rect); + } + heif_color_profile_type profileType = heif_image_handle_get_color_profile_type(handle); if (profileType == heif_color_profile_type_prof || profileType == heif_color_profile_type_rICC) { size_t rawProfileSize = heif_image_handle_get_raw_color_profile_size(handle); @@ -1045,34 +1142,27 @@ void HEIFHandler::queryHeifLib() QMutexLocker locker(&getHEIFHandlerMutex()); if (!m_plugins_queried) { -#if LIBHEIF_HAVE_VERSION(1, 13, 0) if (m_initialized_count == 0) { heif_init(nullptr); } -#endif m_heif_encoder_available = heif_have_encoder_for_format(heif_compression_HEVC); m_heif_decoder_available = heif_have_decoder_for_format(heif_compression_HEVC); -#if LIBHEIF_HAVE_VERSION(1, 13, 0) m_hej2_decoder_available = heif_have_decoder_for_format(heif_compression_JPEG2000); m_hej2_encoder_available = heif_have_encoder_for_format(heif_compression_JPEG2000); -#endif #if LIBHEIF_HAVE_VERSION(1, 19, 6) m_avci_decoder_available = heif_have_decoder_for_format(heif_compression_AVC); #endif m_plugins_queried = true; -#if LIBHEIF_HAVE_VERSION(1, 13, 0) if (m_initialized_count == 0) { heif_deinit(); } -#endif } } void HEIFHandler::startHeifLib() { -#if LIBHEIF_HAVE_VERSION(1, 13, 0) QMutexLocker locker(&getHEIFHandlerMutex()); if (m_initialized_count == 0) { @@ -1080,12 +1170,10 @@ void HEIFHandler::startHeifLib() } m_initialized_count++; -#endif } void HEIFHandler::finishHeifLib() { -#if LIBHEIF_HAVE_VERSION(1, 13, 0) QMutexLocker locker(&getHEIFHandlerMutex()); if (m_initialized_count == 0) { @@ -1096,8 +1184,6 @@ void HEIFHandler::finishHeifLib() if (m_initialized_count == 0) { heif_deinit(); } - -#endif } QMutex &HEIFHandler::getHEIFHandlerMutex() diff --git a/src/imageformats/heif_p.h b/src/imageformats/heif_p.h index daf41e0..003ad87 100644 --- a/src/imageformats/heif_p.h +++ b/src/imageformats/heif_p.h @@ -51,9 +51,24 @@ private: ParseHeicState m_parseState; int m_quality; QImage m_current_image; + quint16 m_orientation; bool write_helper(const QImage &image); + /*! + * \brief heif_orientation_helper + * Read the transform_mirror and transform_rotation_ccw properties and set \a m_orientation + * \return True on success, otherwise false. + */ + bool read_orientation_helper(void *heif_handle, const void *heif_ctx); + + /*! + * \brief read_crop + * Read the crop information. + * \return True on success, otherwise false. + */ + bool read_crop(void *heif_handle, const void *heif_ctx, const QSize& size, QRect &crop); + static void startHeifLib(); static void finishHeifLib(); static void queryHeifLib(); diff --git a/src/imageformats/microexif.cpp b/src/imageformats/microexif.cpp index b723714..23dd3f4 100644 --- a/src/imageformats/microexif.cpp +++ b/src/imageformats/microexif.cpp @@ -744,7 +744,42 @@ void MicroExif::setOrientation(quint16 orient) QImageIOHandler::Transformation MicroExif::transformation() const { - switch (orientation()) { + return orientationToTransformation(orientation()); +} + +void MicroExif::setTransformation(const QImageIOHandler::Transformation &t) +{ + setOrientation(transformationToOrientation(t)); +} + +quint16 MicroExif::transformationToOrientation(const QImageIOHandler::Transformation &t) +{ + switch (t) { + case QImageIOHandler::TransformationNone: + return 1; + case QImageIOHandler::TransformationMirror: + return 2; + case QImageIOHandler::TransformationRotate180: + return 3; + case QImageIOHandler::TransformationFlip: + return 4; + case QImageIOHandler::TransformationFlipAndRotate90: + return 5; + case QImageIOHandler::TransformationRotate90: + return 6; + case QImageIOHandler::TransformationMirrorAndRotate90: + return 7; + case QImageIOHandler::TransformationRotate270: + return 8; + default: + break; + } + return 0; // no orientation set +} + +QImageIOHandler::Transformation MicroExif::orientationToTransformation(quint16 o) +{ + switch (o) { case 1: return QImageIOHandler::TransformationNone; case 2: @@ -767,39 +802,6 @@ QImageIOHandler::Transformation MicroExif::transformation() const return QImageIOHandler::TransformationNone; } -void MicroExif::setTransformation(const QImageIOHandler::Transformation &t) -{ - switch (t) { - case QImageIOHandler::TransformationNone: - setOrientation(1); - break; - case QImageIOHandler::TransformationMirror: - setOrientation(2); - break; - case QImageIOHandler::TransformationRotate180: - setOrientation(3); - break; - case QImageIOHandler::TransformationFlip: - setOrientation(4); - break; - case QImageIOHandler::TransformationFlipAndRotate90: - setOrientation(5); - break; - case QImageIOHandler::TransformationRotate90: - setOrientation(6); - break; - case QImageIOHandler::TransformationMirrorAndRotate90: - setOrientation(7); - break; - case QImageIOHandler::TransformationRotate270: - setOrientation(8); - break; - default: - break; - } - setOrientation(0); // no orientation set -} - QString MicroExif::software() const { return tiffString(TIFF_SOFTWARE); diff --git a/src/imageformats/microexif_p.h b/src/imageformats/microexif_p.h index 4994960..441d713 100644 --- a/src/imageformats/microexif_p.h +++ b/src/imageformats/microexif_p.h @@ -210,6 +210,19 @@ public: QImageIOHandler::Transformation transformation() const; void setTransformation(const QImageIOHandler::Transformation& t); + /*! + * \brief transformationToOrientation + * \param t The Qt transformation. + * \return The EXIF orientation value or 0 if none. + */ + static quint16 transformationToOrientation(const QImageIOHandler::Transformation& t); + /*! + * \brief orientationToTransformation + * \param o The EXIF orientation. + * \return The orientation converted in the equivalent Qt transformation. + */ + static QImageIOHandler::Transformation orientationToTransformation(quint16 o); + /*! * \brief software * \return Name and version number of the software package(s) used to create the image.