From 985c57d07564cb9c63f72624cba4df28d99b4ddb Mon Sep 17 00:00:00 2001 From: Marko Mattila Date: Mon, 18 Nov 2013 10:31:25 +0200 Subject: [PATCH] [transfer-engine] Rotate image to the right orientation after scaling. When scaling an image it actually destroys the metadata because Qt doesn't know anything about it. Before we have a proper metadata handling interface, let's just rotate image to the right orientation. TODO: Write exiv2 based metadata handling. --- lib/imageoperation.cpp | 90 +++++++++++++++++++++++++++++++++++------- lib/imageoperation.h | 1 + 2 files changed, 76 insertions(+), 15 deletions(-) diff --git a/lib/imageoperation.cpp b/lib/imageoperation.cpp index a6cf5b5..39771ea 100644 --- a/lib/imageoperation.cpp +++ b/lib/imageoperation.cpp @@ -29,9 +29,9 @@ #include #include -#include +#include #include -#include ) +#include /*! \class ImageOperation \brief The ImageOperation class is a helper class to manipulate images. @@ -71,7 +71,6 @@ QString ImageOperation::uniqueFilePath(const QString &sourceFilePath, const QStr QFileInfo fileInfo(sourceFilePath); - // Construct target temp file path first: QDir dir(path); QStringList prevFiles = dir.entryList(QStringList() << fileInfo.baseName() + QLatin1String("*"), QDir::Files); @@ -185,15 +184,32 @@ QString ImageOperation::scaleImage(const QString &sourceFile, qreal scaleFactor, // Using just basic QImage scale here. We can easily replace this implementation later, if we notice // performance bottlenecks here. - QImage tmpImg(sourceFile); - if (tmpImg.isNull()) { - qWarning() << Q_FUNC_INFO << "Null source image!"; + QImageReader ir(sourceFile); + if (!ir.canRead()) { + qWarning() << Q_FUNC_INFO << "Couldn't' source image!"; return QString(); } - QImage scaled = tmpImg.scaled(tmpImg.size() * scaleFactor, Qt::KeepAspectRatio, Qt::SmoothTransformation); + QSize imageSize(ir.size()); + imageSize = imageSize.scaled(imageSize * scaleFactor, Qt::KeepAspectRatio); + ir.setScaledSize(imageSize); + QImage image = ir.read(); + + int angle; + bool mirrored; + imageOrientation(sourceFile, angle, &mirrored); + + if (mirrored) { + image.mirrored(true, false); + } + + if (angle != 0) { + QTransform transform; + transform.rotate(angle); + image = image.transformed(transform); + } - if (!scaled.save(tmpFile)) { + if (!image.save(tmpFile)) { qWarning() << Q_FUNC_INFO << "Failed to save scaled image to temp file!"; return QString(); } @@ -234,9 +250,9 @@ QString ImageOperation::scaleImageToSize(const QString &sourceFile, quint64 targ tmpFile = uniqueFilePath(sourceFile); } - QImage tmpImage(sourceFile); - if (tmpImage.isNull()) { - qWarning() << Q_FUNC_INFO << "NULL original image!"; + QImageReader ir(sourceFile); + if (!ir.canRead()) { + qWarning() << Q_FUNC_INFO << "Can't read the original image!"; return QString(); } @@ -258,17 +274,61 @@ QString ImageOperation::scaleImageToSize(const QString &sourceFile, quint64 targ // w * w = (s' * r) / a => // w = sqrt( (s' * r) / a ) - qint32 w = tmpImage.width(); // Width - qint32 h = tmpImage.height(); // Height + qint32 w = ir.size().width(); // Width + qint32 h = ir.size().height(); // Height qreal r = w / (h * 1.0); // Aspect ratio qreal a = originalSize / (w * h * 1.0); // The magic number, which combines depth and compression qint32 newWidth = qSqrt((targetSize * r) / a); - QImage scaled = tmpImage.scaledToWidth(newWidth, Qt::SmoothTransformation); + qint32 newHeight = r / newWidth; + + QSize imageSize(ir.size()); + imageSize = imageSize.scaled(newWidth, newHeight, Qt::KeepAspectRatio); + ir.setScaledSize(imageSize); + QImage image = ir.read(); + + // Make sure orientation is right. + int angle; + bool mirrored; + imageOrientation(sourceFile, angle, &mirrored); + + if (mirrored) { + image.mirrored(true, false); + } - if (!scaled.save(tmpFile)) { + if (angle != 0) { + QTransform transform; + transform.rotate(angle); + image = image.transformed(transform); + } + + if (!image.save(tmpFile)) { qWarning() << Q_FUNC_INFO << "Failed to save scaled image to temp file!"; return QString(); } + return tmpFile; } + +void ImageOperation::imageOrientation(const QString &sourceFile, int &angle, bool *mirror) +{ + QuillMetadata md(sourceFile); + if (!md.isValid() || !md.hasExif()) { + angle = 0; + mirror = false; + return; + } + + int exifOrientation = md.entry(QuillMetadata::Tag_Orientation).toInt(); + switch (exifOrientation) { + case 1: angle = 0 ; *mirror = false; break; + case 2: angle = 0 ; *mirror = true ; break; + case 3: angle = 180; *mirror = false; break; + case 4: angle = 180; *mirror = true ; break; + case 5: angle = 90 ; *mirror = true ; break; + case 6: angle = 90 ; *mirror = false; break; + case 7: angle = 270; *mirror = true ; break; + case 8: angle = 270; *mirror = false; break; + default: break; + } +} diff --git a/lib/imageoperation.h b/lib/imageoperation.h index 5900643..c2f770b 100644 --- a/lib/imageoperation.h +++ b/lib/imageoperation.h @@ -37,6 +37,7 @@ class ImageOperation static QString removeImageMetadata(const QString &sourceFile); static QString scaleImage(const QString &sourceFile, qreal scaleFactor, const QString &targetFile=QString()); static QString scaleImageToSize(const QString &sourceFile, quint64 targetSize, const QString &targetFile=QString()); + static void imageOrientation(const QString &sourceFile, int &angle, bool *mirror); }; #endif // IMAGEOPERATION_H