diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 8a0f570f47..cd0cbf7f49 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -5048,4 +5048,18 @@ QImage::Format QImage::toImageFormat(QPixelFormat format) Q_DECL_NOTHROW return Format_Invalid; } +Q_GUI_EXPORT void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient) +{ + if (orient == QImageIOHandler::TransformationNone) + return; + if (orient == QImageIOHandler::TransformationRotate270) { + src = rotated270(src); + } else { + src = qMove(src).mirrored(orient & QImageIOHandler::TransformationMirror, + orient & QImageIOHandler::TransformationFlip); + if (orient & QImageIOHandler::TransformationRotate90) + src = rotated90(src); + } +} + QT_END_NAMESPACE diff --git a/src/gui/image/qimageiohandler.cpp b/src/gui/image/qimageiohandler.cpp index cc9a6ae2a1..22b4bcf560 100644 --- a/src/gui/image/qimageiohandler.cpp +++ b/src/gui/image/qimageiohandler.cpp @@ -159,6 +159,43 @@ \value ProgressiveScanWrite. A handler which supports this option is expected to write the image as a progressive scan image. + + \value ImageTransformation. A handler which supports this option can read + the transformation metadata of an image. A handler that supports this option + should not apply the transformation itself. + + \value TransformedByDefault. A handler that reports support for this feature + will have image transformation metadata applied by default on read. +*/ + +/*! \enum QImageIOHandler::Transformation + \since 5.5 + + This enum describes the different transformations or orientations + supported by some image formats, usually through EXIF. + + \value TransformationNone No transformation should be applied. + + \value TransformationMirror Mirror the image horizontally. + + \value TransformationFlip Mirror the image vertically. + + \value TransformationRotate180 Rotate the image 180 degrees. + This is the same as mirroring it both horizontally and vertically. + + \value TransformationRotate90 Rotate the image 90 degrees. + + \value TransformationMirrorAndRotate90 Mirror the image horizontally + and then rotate it 90 degrees. + + \value TransformationFlipAndRotate90 Mirror the image vertically + and then rotate it 90 degrees. + + \value TransformationRotate270 Rotate the image 270 degrees. + This is the same as mirroring it both horizontally, vertically and + then rotating it 90 degrees. + + \sa QImageReader::transformation(), QImageReader::setAutoTransform(), QImageWriter::setTransformation() */ /*! diff --git a/src/gui/image/qimageiohandler.h b/src/gui/image/qimageiohandler.h index b48226f619..80cd87c4c3 100644 --- a/src/gui/image/qimageiohandler.h +++ b/src/gui/image/qimageiohandler.h @@ -86,8 +86,25 @@ public: ImageFormat, SupportedSubTypes, OptimizedWrite, - ProgressiveScanWrite + ProgressiveScanWrite, + ImageTransformation +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + , TransformedByDefault +#endif }; + + enum Transformation { + TransformationNone = 0, + TransformationMirror = 1, + TransformationFlip = 2, + TransformationRotate180 = TransformationMirror | TransformationFlip, + TransformationRotate90 = 4, + TransformationMirrorAndRotate90 = TransformationMirror | TransformationRotate90, + TransformationFlipAndRotate90 = TransformationFlip | TransformationRotate90, + TransformationRotate270 = TransformationRotate180 | TransformationRotate90 + }; + Q_DECLARE_FLAGS(Transformations, Transformation) + virtual QVariant option(ImageOption option) const; virtual void setOption(ImageOption option, const QVariant &value); virtual bool supportsOption(ImageOption option) const; diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp index c2795cc38d..ba79bf40e5 100644 --- a/src/gui/image/qimagereader.cpp +++ b/src/gui/image/qimagereader.cpp @@ -533,6 +533,11 @@ public: int quality; QMap text; void getText(); + enum { + UsePluginDefault, + ApplyTransform, + DoNotApplyTransform + } autoTransform; // error QImageReader::ImageReaderError imageReaderError; @@ -552,6 +557,7 @@ QImageReaderPrivate::QImageReaderPrivate(QImageReader *qq) handler = 0; quality = -1; imageReaderError = QImageReader::UnknownError; + autoTransform = UsePluginDefault; q = qq; } @@ -1143,6 +1149,59 @@ QList QImageReader::supportedSubTypes() const return QList(); } +/*! + \since 5.5 + + Returns the transformation metadata of the image, including image orientation. If the format + does not support transformation metadata \c QImageIOHandler::Transformation_None is returned. + + \sa setAutoTransform(), autoTransform() +*/ +QImageIOHandler::Transformations QImageReader::transformation() const +{ + int option = QImageIOHandler::TransformationNone; + if (d->initHandler() && d->handler->supportsOption(QImageIOHandler::ImageTransformation)) + option = d->handler->option(QImageIOHandler::ImageTransformation).toInt(); + return QImageIOHandler::Transformations(option); +} + +/*! + \since 5.5 + + Sets if images returned by read() should have transformation metadata automatically applied. + + \sa autoTransform(), transform(), read() +*/ +void QImageReader::setAutoTransform(bool enabled) +{ + d->autoTransform = enabled ? QImageReaderPrivate::ApplyTransform + : QImageReaderPrivate::DoNotApplyTransform; +} + +/*! + \since 5.5 + + Returns \c true if the image handler will apply transformation metadata on read(). + + \sa setAutoTransform(), transformation(), read() +*/ +bool QImageReader::autoTransform() const +{ + switch (d->autoTransform) { + case QImageReaderPrivate::ApplyTransform: + return true; + case QImageReaderPrivate::DoNotApplyTransform: + return false; + case QImageReaderPrivate::UsePluginDefault: + if (d->initHandler()) + return d->handler->supportsOption(QImageIOHandler::TransformedByDefault); + // no break + default: + break; + } + return false; +} + /*! Returns \c true if an image can be read for the device (i.e., the image format is supported, and the device seems to contain valid @@ -1185,6 +1244,8 @@ QImage QImageReader::read() return read(&image) ? image : QImage(); } +extern void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient); + /*! \overload @@ -1294,6 +1355,8 @@ bool QImageReader::read(QImage *image) if (!disable2xImageLoading && QFileInfo(fileName()).baseName().endsWith(QLatin1String("@2x"))) { image->setDevicePixelRatio(2.0); } + if (autoTransform()) + qt_imageTransform(*image, transformation()); return true; } diff --git a/src/gui/image/qimagereader.h b/src/gui/image/qimagereader.h index 34191ed657..27a29bed49 100644 --- a/src/gui/image/qimagereader.h +++ b/src/gui/image/qimagereader.h @@ -105,6 +105,11 @@ public: bool supportsAnimation() const; + QImageIOHandler::Transformations transformation() const; + + void setAutoTransform(bool enabled); + bool autoTransform() const; + QByteArray subType() const; QList supportedSubTypes() const; diff --git a/src/gui/image/qimagewriter.cpp b/src/gui/image/qimagewriter.cpp index b418101163..e9de1db4b2 100644 --- a/src/gui/image/qimagewriter.cpp +++ b/src/gui/image/qimagewriter.cpp @@ -91,6 +91,7 @@ #include #include #include +#include #include #include #include @@ -254,6 +255,7 @@ public: QByteArray subType; bool optimizedWrite; bool progressiveScanWrite; + QImageIOHandler::Transformations transformation; // error QImageWriter::ImageWriterError imageWriterError; @@ -277,6 +279,7 @@ QImageWriterPrivate::QImageWriterPrivate(QImageWriter *qq) progressiveScanWrite = false; imageWriterError = QImageWriter::UnknownError; errorString = QImageWriter::tr("Unknown error"); + transformation = QImageIOHandler::TransformationNone; q = qq; } @@ -615,6 +618,33 @@ bool QImageWriter::progressiveScanWrite() const return d->progressiveScanWrite; } +/*! + \since 5.5 + + Sets the image transformations metadata including orientation. + + If transformation metadata is not supported by the image format, + the transform is applied before writing. + + \sa transformation(), write() +*/ +void QImageWriter::setTransformation(QImageIOHandler::Transformations transform) +{ + d->transformation = transform; +} + +/*! + \since 5.5 + + Returns the transformation and orientation the image has been set to written with. + + \sa setTransformation() +*/ +QImageIOHandler::Transformations QImageWriter::transformation() const +{ + return d->transformation; +} + /*! \obsolete @@ -694,6 +724,8 @@ bool QImageWriter::canWrite() const return d->canWriteHelper(); } +extern void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient); + /*! Writes the image \a image to the assigned device or file name. Returns \c true on success; otherwise returns \c false. If the @@ -708,6 +740,7 @@ bool QImageWriter::write(const QImage &image) if (!canWrite()) return false; + QImage img = image; if (d->handler->supportsOption(QImageIOHandler::Quality)) d->handler->setOption(QImageIOHandler::Quality, d->quality); if (d->handler->supportsOption(QImageIOHandler::CompressionRatio)) @@ -722,8 +755,12 @@ bool QImageWriter::write(const QImage &image) d->handler->setOption(QImageIOHandler::OptimizedWrite, d->optimizedWrite); if (d->handler->supportsOption(QImageIOHandler::ProgressiveScanWrite)) d->handler->setOption(QImageIOHandler::ProgressiveScanWrite, d->progressiveScanWrite); + if (d->handler->supportsOption(QImageIOHandler::ImageTransformation)) + d->handler->setOption(QImageIOHandler::ImageTransformation, int(d->transformation)); + else + qt_imageTransform(img, d->transformation); - if (!d->handler->write(image)) + if (!d->handler->write(img)) return false; if (QFile *file = qobject_cast(d->device)) file->flush(); diff --git a/src/gui/image/qimagewriter.h b/src/gui/image/qimagewriter.h index 96d8f51b3a..7f92595c53 100644 --- a/src/gui/image/qimagewriter.h +++ b/src/gui/image/qimagewriter.h @@ -89,6 +89,9 @@ public: void setProgressiveScanWrite(bool progressive); bool progressiveScanWrite() const; + QImageIOHandler::Transformations transformation() const; + void setTransformation(QImageIOHandler::Transformations orientation); + // Obsolete as of 4.1 void setDescription(const QString &description); QString description() const; diff --git a/src/gui/image/qjpeghandler.cpp b/src/gui/image/qjpeghandler.cpp index 2014b7440c..4ff3917fe6 100644 --- a/src/gui/image/qjpeghandler.cpp +++ b/src/gui/image/qjpeghandler.cpp @@ -714,7 +714,7 @@ public: }; QJpegHandlerPrivate(QJpegHandler *qq) - : quality(75), iod_src(0), + : quality(75), transformation(QImageIOHandler::TransformationNone), iod_src(0), rgb888ToRgb32ConverterPtr(qt_convert_rgb888_to_rgb32), state(Ready), optimize(false), progressive(false), q(qq) {} @@ -732,6 +732,7 @@ public: bool read(QImage *image); int quality; + QImageIOHandler::Transformations transformation; QVariant size; QImage::Format format; QSize scaledSize; @@ -754,6 +755,122 @@ public: QJpegHandler *q; }; +static bool readExifHeader(QDataStream &stream) +{ + char prefix[6]; + if (stream.readRawData(prefix, sizeof(prefix)) != sizeof(prefix)) + return false; + static const char exifMagic[6] = {'E', 'x', 'i', 'f', 0, 0}; + return memcmp(prefix, exifMagic, 6) == 0; +} + +/* + * Returns -1 on error + * Returns 0 if no Exif orientation was found + * Returns 1 orientation is horizontal (normal) + * Returns 2 mirror horizontal + * Returns 3 rotate 180 + * Returns 4 mirror vertical + * Returns 5 mirror horizontal and rotate 270 CCW + * Returns 6 rotate 90 CW + * Returns 7 mirror horizontal and rotate 90 CW + * Returns 8 rotate 270 CW + */ +static int getExifOrientation(QByteArray &exifData) +{ + QDataStream stream(&exifData, QIODevice::ReadOnly); + + if (!readExifHeader(stream)) + return -1; + + quint16 val; + quint32 offset; + const qint64 headerStart = stream.device()->pos(); + + // read byte order marker + stream >> val; + if (val == 0x4949) // 'II' == Intel + stream.setByteOrder(QDataStream::LittleEndian); + else if (val == 0x4d4d) // 'MM' == Motorola + stream.setByteOrder(QDataStream::BigEndian); + else + return -1; // unknown byte order + + // read size + stream >> val; + if (val != 0x2a) + return -1; + + stream >> offset; + + // read IFD + while (!stream.atEnd()) { + quint16 numEntries; + + // skip offset bytes to get the next IFD + const qint64 bytesToSkip = offset - (stream.device()->pos() - headerStart); + + if (stream.skipRawData(bytesToSkip) != bytesToSkip) + return -1; + + stream >> numEntries; + + for (; numEntries > 0; --numEntries) { + quint16 tag; + quint16 type; + quint32 components; + quint16 value; + quint16 dummy; + + stream >> tag >> type >> components >> value >> dummy; + if (tag == 0x0112) { // Tag Exif.Image.Orientation + if (components != 1) + return -1; + if (type != 3) // we are expecting it to be an unsigned short + return -1; + if (value < 1 || value > 8) // check for valid range + return -1; + + // It is possible to include the orientation multiple times. + // Right now the first value is returned. + return value; + } + } + + // read offset to next IFD + stream >> offset; + if (offset == 0) // this is the last IFD + break; + } + + // No Exif orientation was found + return 0; +} + +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; +} + /*! \internal */ @@ -773,6 +890,7 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device) if (!setjmp(err.setjmp_buffer)) { jpeg_save_markers(&info, JPEG_COM, 0xFFFF); + jpeg_save_markers(&info, JPEG_APP0 + 1, 0xFFFF); // Exif uses APP1 marker (void) jpeg_read_header(&info, TRUE); @@ -784,6 +902,8 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device) format = QImage::Format_Invalid; read_jpeg_format(format, &info); + QByteArray exifData; + for (jpeg_saved_marker_ptr marker = info.marker_list; marker != NULL; marker = marker->next) { if (marker->marker == JPEG_COM) { QString key, value; @@ -801,9 +921,20 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device) description += key + QLatin1String(": ") + value.simplified(); readTexts.append(key); readTexts.append(value); + } else if (marker->marker == JPEG_APP0 + 1) { + exifData.append((const char*)marker->data, marker->data_length); } } + if (!exifData.isEmpty()) { + // Exif data present + int exifOrientation = getExifOrientation(exifData); + if (exifOrientation == -1) + return false; + if (exifOrientation > 0) + transformation = exif2Qt(exifOrientation); + } + state = ReadHeader; return true; } @@ -905,8 +1036,16 @@ bool QJpegHandler::read(QImage *image) return d->read(image); } +extern void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient); + bool QJpegHandler::write(const QImage &image) { + if (d->transformation != QImageIOHandler::TransformationNone) { + // We don't support writing EXIF headers so apply the transform to the data. + QImage img = image; + qt_imageTransform(img, d->transformation); + return write_jpeg_image(img, device(), d->quality, d->description, d->optimize, d->progressive); + } return write_jpeg_image(image, device(), d->quality, d->description, d->optimize, d->progressive); } @@ -920,7 +1059,8 @@ bool QJpegHandler::supportsOption(ImageOption option) const || option == Size || option == ImageFormat || option == OptimizedWrite - || option == ProgressiveScanWrite; + || option == ProgressiveScanWrite + || option == ImageTransformation; } QVariant QJpegHandler::option(ImageOption option) const @@ -947,6 +1087,9 @@ QVariant QJpegHandler::option(ImageOption option) const return d->optimize; case ProgressiveScanWrite: return d->progressive; + case ImageTransformation: + d->readJpegHeader(device()); + return int(d->transformation); default: break; } @@ -978,6 +1121,11 @@ void QJpegHandler::setOption(ImageOption option, const QVariant &value) case ProgressiveScanWrite: d->progressive = value.toBool(); break; + case ImageTransformation: { + int transformation = value.toInt(); + if (transformation > 0 && transformation < 8) + d->transformation = QImageIOHandler::Transformations(transformation); + } default: break; } diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_QTBUG-45865.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_QTBUG-45865.jpg new file mode 100644 index 0000000000..97deae3e25 Binary files /dev/null and b/tests/auto/gui/image/qimage/images/jpeg_exif_QTBUG-45865.jpg differ diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_1.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_1.jpg new file mode 100644 index 0000000000..aaa4ac4e10 Binary files /dev/null and b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_1.jpg differ diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_2.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_2.jpg new file mode 100644 index 0000000000..a61d2723d7 Binary files /dev/null and b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_2.jpg differ diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_3.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_3.jpg new file mode 100644 index 0000000000..43e56dcef7 Binary files /dev/null and b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_3.jpg differ diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_4.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_4.jpg new file mode 100644 index 0000000000..d5d06f7409 Binary files /dev/null and b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_4.jpg differ diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_5.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_5.jpg new file mode 100644 index 0000000000..1886f3775e Binary files /dev/null and b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_5.jpg differ diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_6.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_6.jpg new file mode 100644 index 0000000000..5cec757354 Binary files /dev/null and b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_6.jpg differ diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_6_motorola.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_6_motorola.jpg new file mode 100644 index 0000000000..0aa164b78b Binary files /dev/null and b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_6_motorola.jpg differ diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_7.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_7.jpg new file mode 100644 index 0000000000..b3dcc466a9 Binary files /dev/null and b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_7.jpg differ diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_8.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_8.jpg new file mode 100644 index 0000000000..8bc390e2b9 Binary files /dev/null and b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_8.jpg differ diff --git a/tests/auto/gui/image/qimage/tst_qimage.cpp b/tests/auto/gui/image/qimage/tst_qimage.cpp index 62a9f19f36..da29a57f98 100644 --- a/tests/auto/gui/image/qimage/tst_qimage.cpp +++ b/tests/auto/gui/image/qimage/tst_qimage.cpp @@ -181,6 +181,11 @@ private slots: void invertPixelsRGB_data(); void invertPixelsRGB(); + void exifOrientation_data(); + void exifOrientation(); + + void exif_QTBUG45865(); + void cleanupFunctions(); void devicePixelRatio(); @@ -2810,6 +2815,61 @@ void tst_QImage::invertPixelsRGB() QCOMPARE(qBlue(pixel) >> 4, (255 - 96) >> 4); } +void tst_QImage::exifOrientation_data() +{ + QTest::addColumn("fileName"); + QTest::addColumn("orientation"); + QTest::newRow("Orientation 1, Intel format") << m_prefix + "jpeg_exif_orientation_value_1.jpg" << (int)QImageIOHandler::TransformationNone; + QTest::newRow("Orientation 2, Intel format") << m_prefix + "jpeg_exif_orientation_value_2.jpg" << (int)QImageIOHandler::TransformationMirror; + QTest::newRow("Orientation 3, Intel format") << m_prefix + "jpeg_exif_orientation_value_3.jpg" << (int)QImageIOHandler::TransformationRotate180; + QTest::newRow("Orientation 4, Intel format") << m_prefix + "jpeg_exif_orientation_value_4.jpg" << (int)QImageIOHandler::TransformationFlip; + QTest::newRow("Orientation 5, Intel format") << m_prefix + "jpeg_exif_orientation_value_5.jpg" << (int)QImageIOHandler::TransformationFlipAndRotate90; + QTest::newRow("Orientation 6, Intel format") << m_prefix + "jpeg_exif_orientation_value_6.jpg" << (int)QImageIOHandler::TransformationRotate90; + QTest::newRow("Orientation 6, Motorola format") << m_prefix + "jpeg_exif_orientation_value_6_motorola.jpg" << (int)QImageIOHandler::TransformationRotate90; + QTest::newRow("Orientation 7, Intel format") << m_prefix + "jpeg_exif_orientation_value_7.jpg" << (int)QImageIOHandler::TransformationMirrorAndRotate90; + QTest::newRow("Orientation 8, Intel format") << m_prefix + "jpeg_exif_orientation_value_8.jpg" << (int)QImageIOHandler::TransformationRotate270; +} + +QT_BEGIN_NAMESPACE +extern void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient); +QT_END_NAMESPACE +QT_USE_NAMESPACE + +void tst_QImage::exifOrientation() +{ + QFETCH(QString, fileName); + QFETCH(int, orientation); + + QImageReader imageReader(fileName); + imageReader.setAutoTransform(true); + QCOMPARE(imageReader.transformation(), orientation); + QImage img = imageReader.read(); + QRgb px; + QVERIFY(!img.isNull()); + + px = img.pixel(0, 0); + QVERIFY(qRed(px) > 250 && qGreen(px) < 5 && qBlue(px) < 5); + + px = img.pixel(img.width() - 1, 0); + QVERIFY(qRed(px) < 5 && qGreen(px) < 5 && qBlue(px) > 250); + + QImageReader imageReader2(fileName); + QCOMPARE(imageReader2.autoTransform(), false); + QCOMPARE(imageReader2.transformation(), orientation); + QImage img2 = imageReader2.read(); + qt_imageTransform(img2, imageReader2.transformation()); + QCOMPARE(img, img2); +} + +void tst_QImage::exif_QTBUG45865() +{ + QFile file(m_prefix + "jpeg_exif_QTBUG-45865.jpg"); + QVERIFY(file.open(QIODevice::ReadOnly)); + QByteArray byteArray = file.readAll(); + QImage image = QImage::fromData(byteArray); + QCOMPARE(image.size(), QSize(5, 8)); +} + static void cleanupFunction(void* info) { bool *called = static_cast(info);