diff options
-rw-r--r-- | src/plugins/imageformats/tiff/qtiffhandler.cpp | 177 | ||||
-rw-r--r-- | tests/auto/tiff/tst_qtiff.cpp | 36 |
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"); |