summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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");