Commit 30093739 authored by Marko Mattila's avatar Marko Mattila

Merge pull request #13 from zchydem/master

[transfer-engine] Rotate image to the right orientation after scaling.
parents d5d51474 c5cad52b
......@@ -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.
......@@ -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,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();
}
......@@ -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();
}
......@@ -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;
}
}
......@@ -37,6 +37,7 @@ public:
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
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -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
......
......@@ -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);
......@@ -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
......@@ -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)
......
......@@ -41,6 +41,7 @@ private slots:
void testScaleToSize();
void testDropMetadata();
void testUniqueFilePath();
void testOrientation();
};
#endif // UT_IMAGEOPERATION_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment