HEIF: image transformation support
@@ -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")
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
BIN
autotests/read/heif/crop_orientation1.heif
Normal file
BIN
autotests/read/heif/crop_orientation1.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
autotests/read/heif/crop_orientation2.heif
Normal file
BIN
autotests/read/heif/crop_orientation2.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
autotests/read/heif/crop_orientation3.heif
Normal file
BIN
autotests/read/heif/crop_orientation3.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
autotests/read/heif/crop_orientation4.heif
Normal file
BIN
autotests/read/heif/crop_orientation4.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
autotests/read/heif/crop_orientation5.heif
Normal file
BIN
autotests/read/heif/crop_orientation5.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
autotests/read/heif/crop_orientation6.heif
Normal file
BIN
autotests/read/heif/crop_orientation6.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
autotests/read/heif/crop_orientation7.heif
Normal file
BIN
autotests/read/heif/crop_orientation7.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
autotests/read/heif/crop_orientation8.heif
Normal file
BIN
autotests/read/heif/crop_orientation8.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
autotests/read/heif/orientation1.heif
Normal file
17
autotests/read/heif/orientation1.heif.json
Normal file
@@ -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)"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
BIN
autotests/read/heif/orientation2.heif
Normal file
11
autotests/read/heif/orientation2.heif.json
Normal file
@@ -0,0 +1,11 @@
|
||||
[
|
||||
{
|
||||
"fileName" : "orientation_all.png",
|
||||
"metadata" : [
|
||||
{
|
||||
"key" : "Software" ,
|
||||
"value" : "LIFE Pro 2.20.35 (Linux)"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
BIN
autotests/read/heif/orientation3.heif
Normal file
11
autotests/read/heif/orientation3.heif.json
Normal file
@@ -0,0 +1,11 @@
|
||||
[
|
||||
{
|
||||
"fileName" : "orientation_all.png",
|
||||
"metadata" : [
|
||||
{
|
||||
"key" : "Software" ,
|
||||
"value" : "LIFE Pro 2.20.35 (Linux)"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
BIN
autotests/read/heif/orientation4.heif
Normal file
11
autotests/read/heif/orientation4.heif.json
Normal file
@@ -0,0 +1,11 @@
|
||||
[
|
||||
{
|
||||
"fileName" : "orientation_all.png",
|
||||
"metadata" : [
|
||||
{
|
||||
"key" : "Software" ,
|
||||
"value" : "LIFE Pro 2.20.35 (Linux)"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
BIN
autotests/read/heif/orientation5.heif
Normal file
11
autotests/read/heif/orientation5.heif.json
Normal file
@@ -0,0 +1,11 @@
|
||||
[
|
||||
{
|
||||
"fileName" : "orientation_all.png",
|
||||
"metadata" : [
|
||||
{
|
||||
"key" : "Software" ,
|
||||
"value" : "LIFE Pro 2.20.35 (Linux)"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
BIN
autotests/read/heif/orientation6.heif
Normal file
11
autotests/read/heif/orientation6.heif.json
Normal file
@@ -0,0 +1,11 @@
|
||||
[
|
||||
{
|
||||
"fileName" : "orientation_all.png",
|
||||
"metadata" : [
|
||||
{
|
||||
"key" : "Software" ,
|
||||
"value" : "LIFE Pro 2.20.35 (Linux)"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
BIN
autotests/read/heif/orientation7.heif
Normal file
11
autotests/read/heif/orientation7.heif.json
Normal file
@@ -0,0 +1,11 @@
|
||||
[
|
||||
{
|
||||
"fileName" : "orientation_all.png",
|
||||
"metadata" : [
|
||||
{
|
||||
"key" : "Software" ,
|
||||
"value" : "LIFE Pro 2.20.35 (Linux)"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
BIN
autotests/read/heif/orientation8.heif
Normal file
11
autotests/read/heif/orientation8.heif.json
Normal file
@@ -0,0 +1,11 @@
|
||||
[
|
||||
{
|
||||
"fileName" : "orientation_all.png",
|
||||
"metadata" : [
|
||||
{
|
||||
"key" : "Software" ,
|
||||
"value" : "LIFE Pro 2.20.35 (Linux)"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
BIN
autotests/read/heif/orientation_all.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
@@ -11,6 +11,7 @@
|
||||
#include "microexif_p.h"
|
||||
#include "util_p.h"
|
||||
#include <libheif/heif.h>
|
||||
#include <libheif/heif_properties.h>
|
||||
|
||||
#include <QColorSpace>
|
||||
#include <QLoggingCategory>
|
||||
@@ -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_image_handle *>(heif_handle);
|
||||
auto ctx = reinterpret_cast<const heif_context *>(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_image_handle *>(heif_handle);
|
||||
auto ctx = reinterpret_cast<const heif_context *>(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<HEIFHandler *>(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()
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||