Skip to content

Commit

Permalink
Merge pull request #13 from zchydem/master
Browse files Browse the repository at this point in the history
[transfer-engine] Rotate image to the right orientation after scaling.
  • Loading branch information
Marko Mattila committed Nov 20, 2013
2 parents d5d5147 + c5cad52 commit 3009373
Show file tree
Hide file tree
Showing 14 changed files with 158 additions and 18 deletions.
110 changes: 93 additions & 17 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,16 +184,35 @@ 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 read 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 = image.mirrored(true, false);
}

if (angle != 0) {
QTransform transform;
transform.rotate(angle);
image = image.transformed(transform);
}

if (!scaled.save(tmpFile)) {
qWarning() << Q_FUNC_INFO << "Failed to save scaled image to temp file!";
if (!image.save(tmpFile)) {
qWarning() << Q_FUNC_INFO
<< "Failed to save scaled image to temp file!"
<< tmpFile;
return QString();
}

Expand Down Expand Up @@ -234,9 +252,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 +276,75 @@ 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 = newWidth / r;

if (!scaled.save(tmpFile)) {
qWarning() << Q_FUNC_INFO << "Failed to save scaled image to temp file!";
QSize imageSize(ir.size());
imageSize = imageSize.scaled(newWidth, newHeight, Qt::KeepAspectRatio);
ir.setScaledSize(imageSize);
QImage image = ir.read();

if (image.isNull()) {
qWarning() << Q_FUNC_INFO
<< "NULL image";
return QString();
}
// Make sure orientation is right.
int angle;
bool mirrored;
imageOrientation(sourceFile, &angle, &mirrored);

if (mirrored) {
image = image.mirrored(true, false);
}

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!"
<< tmpFile;
return QString();
}

return tmpFile;
}

void ImageOperation::imageOrientation(const QString &sourceFile, int *angle, bool *mirror)
{
if(!QuillMetadata::canRead(sourceFile)) {
qWarning() << Q_FUNC_INFO << "Can't read metadata";
*angle = 0;
*mirror = false;
return;
}
QuillMetadata md(sourceFile);
if (!md.hasExif()) {
qWarning() << "Metadata invalid";
*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
Binary file added tests/images/testimage-0-mirrored.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/images/testimage-0.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/images/testimage-180-mirrored.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/images/testimage-180.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/images/testimage-270-mirrored.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/images/testimage-270.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/images/testimage-90-mirrored.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/images/testimage-90.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/images/testimage-90.jpg.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion tests/tests.pro
Expand Up @@ -49,7 +49,7 @@ tests_install.path = $$PATH
tests_install.files = $$tests_xml.target
tests_install.CONFIG += no_check_exist

resources.files = images/testimage.jpg
resources.files = images/*.jpg
resources.path = $$PATH/images

target.path = $$PATH
Expand Down
62 changes: 62 additions & 0 deletions tests/ut_imageoperation.cpp
Expand Up @@ -114,17 +114,29 @@ void ut_imageoperation::testScale()
QString result = ImageOperation::scaleImage(filePath, 0.5, target);
QCOMPARE(result, target);

int angle;
bool mirror;
ImageOperation::imageOrientation(filePath, &angle, &mirror);
QCOMPARE(angle, 90);
QCOMPARE(mirror, false);

QImage resImage(result);
QTransform x;
x.rotate(angle);
resImage = resImage.transformed(x);

QCOMPARE(resImage.size(), img.size()*0.5);
QFile::remove(result);

result = ImageOperation::scaleImage(filePath, 0.1, target);
resImage.load(result);
resImage = resImage.transformed(x);
QCOMPARE(resImage.size(), img.size()*0.1);
QFile::remove(result);

result = ImageOperation::scaleImage(filePath, 0.9, target);
resImage.load(result);
resImage = resImage.transformed(x);
QVERIFY(qAbs(resImage.width() - img.width()*0.9) < 2);
QVERIFY(qAbs(resImage.height() - img.height()*0.9) < 2);
QFile::remove(result);
Expand All @@ -139,7 +151,20 @@ void ut_imageoperation::testScaleToSize()
QString filePath("images/testimage.jpg");

QString target = ImageOperation::uniqueFilePath(filePath);
QVERIFY(!target.isEmpty());

QFileInfo f("images/testimage.jpg");

int angle;
bool mirror;
ImageOperation::imageOrientation(filePath, &angle, &mirror);
QCOMPARE(angle, 90);
QCOMPARE(mirror, false);

QTransform x;
x.rotate(angle);
img = img.transformed(x);

int targetSize = f.size() * 0.5;

// Invalid sourceFile -> fail
Expand Down Expand Up @@ -216,6 +241,43 @@ void ut_imageoperation::testDropMetadata()
QFile::remove(path);
}

void ut_imageoperation::testOrientation()
{
int angle;
bool mirrored;
ImageOperation::imageOrientation("images/testimage-0.jpg", &angle, &mirrored);
QCOMPARE(angle, 0);
QCOMPARE(mirrored, false);

ImageOperation::imageOrientation("images/testimage-0-mirrored.jpg", &angle, &mirrored);
QCOMPARE(angle, 0);
QCOMPARE(mirrored, true);

ImageOperation::imageOrientation("images/testimage-90.jpg", &angle, &mirrored);
QCOMPARE(angle, 90);
QCOMPARE(mirrored, false);

ImageOperation::imageOrientation("images/testimage-90-mirrored.jpg", &angle, &mirrored);
QCOMPARE(angle, 90);
QCOMPARE(mirrored, true);

ImageOperation::imageOrientation("images/testimage-180.jpg", &angle, &mirrored);
QCOMPARE(angle, 180);
QCOMPARE(mirrored, false);

ImageOperation::imageOrientation("images/testimage-180-mirrored.jpg", &angle, &mirrored);
QCOMPARE(angle, 180);
QCOMPARE(mirrored, true);

ImageOperation::imageOrientation("images/testimage-270.jpg", &angle, &mirrored);
QCOMPARE(angle, 270);
QCOMPARE(mirrored, false);

ImageOperation::imageOrientation("images/testimage-270-mirrored.jpg", &angle, &mirrored);
QCOMPARE(angle, 270);
QCOMPARE(mirrored, true);
}

/*
QTEST_MAIN(ut_imageoperation)
Expand Down
1 change: 1 addition & 0 deletions tests/ut_imageoperation.h
Expand Up @@ -41,6 +41,7 @@ private slots:
void testScaleToSize();
void testDropMetadata();
void testUniqueFilePath();
void testOrientation();
};

#endif // UT_IMAGEOPERATION_H

0 comments on commit 3009373

Please sign in to comment.