summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2015-04-29 10:55:27 +0200
committerAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2015-05-19 08:32:10 +0000
commita1d412aec45e2232537795c5a1a8500daeb061d6 (patch)
tree7d6e1c4bf7fba37ff735e41ed343aecba0c248da
parent8363c855f5d31c3c7499b57621d79b10bc6ba088 (diff)
Optional application of orientation for TIFF
Make the image orientation only optionally applied for TIFF images to match the new image handler flags. The default however remains to apply transformation, as opposed to JPEGs. The patch also adds the capability to write metadata orientation. Change-Id: Ie24664516138641342ab6d7559d591f38b9f1e8a Reviewed-by: Gunnar Sletta <gunnar@sletta.org>
-rw-r--r--src/plugins/imageformats/tiff/qtiffhandler.cpp177
-rw-r--r--tests/auto/tiff/tst_qtiff.cpp36
2 files changed, 97 insertions, 116 deletions
diff --git a/src/plugins/imageformats/tiff/qtiffhandler.cpp b/src/plugins/imageformats/tiff/qtiffhandler.cpp
index 3fc1680..ceb6935 100644
--- a/src/plugins/imageformats/tiff/qtiffhandler.cpp
+++ b/src/plugins/imageformats/tiff/qtiffhandler.cpp
@@ -90,42 +90,6 @@ void qtiffUnmapProc(thandle_t /*fd*/, tdata_t /*base*/, toff_t /*size*/)
{
}
-// for 32 bits images
-inline void rotate_right_mirror_horizontal(QImage *const image)// rotate right->mirrored horizontal
-{
- const int height = image->height();
- const int width = image->width();
- QImage generated(/* width = */ height, /* height = */ width, image->format());
- const uint32 *originalPixel = reinterpret_cast<const uint32*>(image->bits());
- uint32 *const generatedPixels = reinterpret_cast<uint32*>(generated.bits());
- for (int row=0; row < height; ++row) {
- for (int col=0; col < width; ++col) {
- int idx = col * height + row;
- generatedPixels[idx] = *originalPixel;
- ++originalPixel;
- }
- }
- *image = generated;
-}
-
-inline void rotate_right_mirror_vertical(QImage *const image) // rotate right->mirrored vertical
-{
- const int height = image->height();
- const int width = image->width();
- QImage generated(/* width = */ height, /* height = */ width, image->format());
- const int lastCol = width - 1;
- const int lastRow = height - 1;
- const uint32 *pixel = reinterpret_cast<const uint32*>(image->bits());
- uint32 *const generatedBits = reinterpret_cast<uint32*>(generated.bits());
- for (int row=0; row < height; ++row) {
- for (int col=0; col < width; ++col) {
- int idx = (lastCol - col) * height + (lastRow - row);
- generatedBits[idx] = *pixel;
- ++pixel;
- }
- }
- *image = generated;
-}
class QTiffHandlerPrivate
{
@@ -140,6 +104,7 @@ public:
TIFF *tiff;
int compression;
+ QImageIOHandler::Transformations transformation;
QImage::Format format;
QSize size;
uint16 photometric;
@@ -147,9 +112,58 @@ public:
bool headersRead;
};
+static QImageIOHandler::Transformations exif2Qt(int exifOrientation)
+{
+ switch (exifOrientation) {
+ case 1: // normal
+ return QImageIOHandler::TransformationNone;
+ case 2: // mirror horizontal
+ return QImageIOHandler::TransformationMirror;
+ case 3: // rotate 180
+ return QImageIOHandler::TransformationRotate180;
+ case 4: // mirror vertical
+ return QImageIOHandler::TransformationFlip;
+ case 5: // mirror horizontal and rotate 270 CW
+ return QImageIOHandler::TransformationFlipAndRotate90;
+ case 6: // rotate 90 CW
+ return QImageIOHandler::TransformationRotate90;
+ case 7: // mirror horizontal and rotate 90 CW
+ return QImageIOHandler::TransformationMirrorAndRotate90;
+ case 8: // rotate 270 CW
+ return QImageIOHandler::TransformationRotate270;
+ }
+ qWarning("Invalid EXIF orientation");
+ return QImageIOHandler::TransformationNone;
+}
+
+static int qt2Exif(QImageIOHandler::Transformations transformation)
+{
+ switch (transformation) {
+ 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;
+ }
+ qWarning("Invalid Qt image transformation");
+ return 1;
+}
+
QTiffHandlerPrivate::QTiffHandlerPrivate()
: tiff(0)
, compression(QTiffHandler::NoCompression)
+ , transformation(QImageIOHandler::TransformationNone)
, format(QImage::Format_Invalid)
, photometric(false)
, grayscale(false)
@@ -215,6 +229,10 @@ bool QTiffHandlerPrivate::openForRead(QIODevice *device)
}
size = QSize(width, height);
+ uint16 orientationTag;
+ if (TIFFGetField(tiff, TIFFTAG_ORIENTATION, &orientationTag))
+ transformation = exif2Qt(orientationTag);
+
// BitsPerSample defaults to 1 according to the TIFF spec.
uint16 bitPerSample;
if (!TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitPerSample))
@@ -351,7 +369,7 @@ bool QTiffHandler::read(QImage *image)
} else {
if (!image->isNull()) {
const int stopOnError = 1;
- if (TIFFReadRGBAImageOriented(tiff, width, height, reinterpret_cast<uint32 *>(image->bits()), ORIENTATION_TOPLEFT, stopOnError)) {
+ if (TIFFReadRGBAImageOriented(tiff, width, height, reinterpret_cast<uint32 *>(image->bits()), qt2Exif(d->transformation), stopOnError)) {
for (uint32 y=0; y<height; ++y)
convert32BitOrder(image->scanLine(y), width);
} else {
@@ -392,72 +410,6 @@ bool QTiffHandler::read(QImage *image)
}
}
- // rotate the image if the orientation is defined in the file
- uint16 orientationTag;
- if (TIFFGetField(tiff, TIFFTAG_ORIENTATION, &orientationTag)) {
- if (image->format() == QImage::Format_ARGB32 || image->format() == QImage::Format_RGB32) {
- // TIFFReadRGBAImageOriented() flip the image but does not rotate them
- switch (orientationTag) {
- case 5:
- rotate_right_mirror_horizontal(image);
- break;
- case 6:
- rotate_right_mirror_vertical(image);
- break;
- case 7:
- rotate_right_mirror_horizontal(image);
- break;
- case 8:
- rotate_right_mirror_vertical(image);
- break;
- }
- } else {
- switch (orientationTag) {
- case 1: // default orientation
- break;
- case 2: // mirror horizontal
- *image = image->mirrored(true, false);
- break;
- case 3: // mirror both
- *image = image->mirrored(true, true);
- break;
- case 4: // mirror vertical
- *image = image->mirrored(false, true);
- break;
- case 5: // rotate right mirror horizontal
- {
- QMatrix transformation;
- transformation.rotate(90);
- *image = image->transformed(transformation);
- *image = image->mirrored(true, false);
- break;
- }
- case 6: // rotate right
- {
- QMatrix transformation;
- transformation.rotate(90);
- *image = image->transformed(transformation);
- break;
- }
- case 7: // rotate right, mirror vertical
- {
- QMatrix transformation;
- transformation.rotate(90);
- *image = image->transformed(transformation);
- *image = image->mirrored(false, true);
- break;
- }
- case 8: // rotate left
- {
- QMatrix transformation;
- transformation.rotate(270);
- *image = image->transformed(transformation);
- break;
- }
- }
- }
- }
-
d->close();
return true;
}
@@ -523,6 +475,13 @@ bool QTiffHandler::write(const QImage &image)
TIFFClose(tiff);
return false;
}
+ // set the orienataion
+ bool orientationSet = false;
+ orientationSet = TIFFSetField(tiff, TIFFTAG_ORIENTATION, qt2Exif(d->transformation));
+ if (!orientationSet) {
+ TIFFClose(tiff);
+ return false;
+ }
// configure image depth
const QImage::Format format = image.format();
@@ -701,6 +660,9 @@ QVariant QTiffHandler::option(ImageOption option) const
} else if (option == ImageFormat) {
if (d->readHeaders(device()))
return d->format;
+ } else if (option == ImageTransformation) {
+ if (d->readHeaders(device()))
+ return int(d->transformation);
}
return QVariant();
}
@@ -709,13 +671,20 @@ void QTiffHandler::setOption(ImageOption option, const QVariant &value)
{
if (option == CompressionRatio && value.type() == QVariant::Int)
d->compression = value.toInt();
+ if (option == ImageTransformation) {
+ int transformation = value.toInt();
+ if (transformation > 0 && transformation < 8)
+ d->transformation = QImageIOHandler::Transformations(transformation);
+ }
}
bool QTiffHandler::supportsOption(ImageOption option) const
{
return option == CompressionRatio
|| option == Size
- || option == ImageFormat;
+ || option == ImageFormat
+ || option == ImageTransformation
+ || option == TransformedByDefault;
}
void QTiffHandler::convert32BitOrder(void *buffer, int width)
diff --git a/tests/auto/tiff/tst_qtiff.cpp b/tests/auto/tiff/tst_qtiff.cpp
index 71c3b63..a073025 100644
--- a/tests/auto/tiff/tst_qtiff.cpp
+++ b/tests/auto/tiff/tst_qtiff.cpp
@@ -36,6 +36,7 @@
Q_DECLARE_METATYPE(QImage::Format)
Q_DECLARE_METATYPE(QImageWriter::ImageWriterError)
+Q_DECLARE_METATYPE(QImageIOHandler::Transformation)
typedef QList<int> QIntList;
Q_DECLARE_METATYPE(QIntList)
@@ -364,11 +365,12 @@ void tst_qtiff::readWriteNonDestructive_data()
QTest::addColumn<QImage::Format>("format");
QTest::addColumn<QImage::Format>("expectedFormat");
QTest::addColumn<bool>("grayscale");
- QTest::newRow("tiff mono") << QImage::Format_Mono << QImage::Format_Mono << false;
- QTest::newRow("tiff indexed") << QImage::Format_Indexed8 << QImage::Format_Indexed8 << false;
- QTest::newRow("tiff argb32pm") << QImage::Format_ARGB32_Premultiplied << QImage::Format_ARGB32_Premultiplied << false;
- QTest::newRow("tiff rgb32") << QImage::Format_RGB32 << QImage::Format_RGB32 << false;
- QTest::newRow("tiff grayscale") << QImage::Format_Indexed8 << QImage::Format_Indexed8 << true;
+ QTest::addColumn<QImageIOHandler::Transformation>("transformation");
+ QTest::newRow("tiff mono") << QImage::Format_Mono << QImage::Format_Mono << false << QImageIOHandler::TransformationNone;
+ QTest::newRow("tiff indexed") << QImage::Format_Indexed8 << QImage::Format_Indexed8 << false << QImageIOHandler::TransformationMirror;
+ QTest::newRow("tiff argb32pm") << QImage::Format_ARGB32_Premultiplied << QImage::Format_ARGB32_Premultiplied << false << QImageIOHandler::TransformationRotate90;
+ QTest::newRow("tiff rgb32") << QImage::Format_RGB32 << QImage::Format_RGB32 << false << QImageIOHandler::TransformationRotate270;
+ QTest::newRow("tiff grayscale") << QImage::Format_Indexed8 << QImage::Format_Indexed8 << true << QImageIOHandler::TransformationFlip;
}
void tst_qtiff::readWriteNonDestructive()
@@ -376,6 +378,7 @@ void tst_qtiff::readWriteNonDestructive()
QFETCH(QImage::Format, format);
QFETCH(QImage::Format, expectedFormat);
QFETCH(bool, grayscale);
+ QFETCH(QImageIOHandler::Transformation, transformation);
QImage image = QImage(prefix + "colorful.bmp").convertToFormat(format);
QVERIFY(!image.isNull());
@@ -389,19 +392,23 @@ void tst_qtiff::readWriteNonDestructive()
QByteArray output;
QBuffer buf(&output);
QVERIFY(buf.open(QIODevice::WriteOnly));
- QVERIFY(image.save(&buf, "tiff"));
+ QImageWriter writer(&buf, "tiff");
+ writer.setTransformation(transformation);
+ writer.write(image);
buf.close();
QVERIFY(buf.open(QIODevice::ReadOnly));
QImageReader reader(&buf);
QCOMPARE(reader.imageFormat(), expectedFormat);
QCOMPARE(reader.size(), image.size());
+ QCOMPARE(reader.autoTransform(), true);
+ reader.setAutoTransform(false);
+ QCOMPARE(reader.transformation(), transformation);
QImage image2 = reader.read();
QVERIFY2(!image.isNull(), qPrintable(reader.errorString()));
- QImage::Format readFormat = image2.format();
- QCOMPARE(readFormat, expectedFormat);
- QCOMPARE(image, image2);
+ QCOMPARE(image2.format(), expectedFormat);
+ QCOMPARE(image2, image);
}
void tst_qtiff::largeTiff()
@@ -441,8 +448,11 @@ void tst_qtiff::supportsOption_data()
{
QTest::addColumn<QIntList>("options");
- QTest::newRow("tiff") << (QIntList() << QImageIOHandler::Size
- << QImageIOHandler::CompressionRatio);
+ QTest::newRow("tiff") << (QIntList()
+ << QImageIOHandler::Size
+ << QImageIOHandler::CompressionRatio
+ << QImageIOHandler::ImageTransformation
+ << QImageIOHandler::TransformedByDefault);
}
void tst_qtiff::supportsOption()
@@ -463,7 +473,9 @@ void tst_qtiff::supportsOption()
<< QImageIOHandler::IncrementalReading
<< QImageIOHandler::Endianness
<< QImageIOHandler::Animation
- << QImageIOHandler::BackgroundColor;
+ << QImageIOHandler::BackgroundColor
+ << QImageIOHandler::ImageTransformation
+ << QImageIOHandler::TransformedByDefault;
QImageWriter writer;
writer.setFormat("tiff");