Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[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.
  • Loading branch information
Marko Mattila committed Nov 19, 2013
1 parent 3d04699 commit 985c57d
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 15 deletions.
90 changes: 75 additions & 15 deletions lib/imageoperation.cpp
Expand Up @@ -29,9 +29,9 @@

#include <QFileInfo>
#include <QtDebug>
#include <QImage>
#include <QImageReader>
#include <QSize>
#include <QtCore/qmath.h>)
#include <QtCore/qmath.h>
/*!
\class ImageOperation
\brief The ImageOperation class is a helper class to manipulate images.
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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();
}

Expand All @@ -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;
}
}
1 change: 1 addition & 0 deletions lib/imageoperation.h
Expand Up @@ -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

0 comments on commit 985c57d

Please sign in to comment.