diff --git a/src/plugins/imageformats/tiff/qtiffhandler.cpp b/src/plugins/imageformats/tiff/qtiffhandler.cpp
index 84221d6f6f66220cec0ef059ab8e40f92b25b4e3..1232b506b052fc76f2202d24ca50b2544d6a5b75 100644
--- a/src/plugins/imageformats/tiff/qtiffhandler.cpp
+++ b/src/plugins/imageformats/tiff/qtiffhandler.cpp
@@ -46,6 +46,8 @@ extern "C" {
 #include "tiffio.h"
 }
 
+#include <memory>
+
 QT_BEGIN_NAMESPACE
 
 tsize_t qtiffReadProc(thandle_t fd, tdata_t buf, tsize_t size)
@@ -273,7 +275,10 @@ bool QTiffHandlerPrivate::readHeaders(QIODevice *device)
     else if ((grayscale || photometric == PHOTOMETRIC_PALETTE) && bitPerSample == 8 && samplesPerPixel == 1)
         format = QImage::Format_Indexed8;
     else if (samplesPerPixel < 4)
-        format = QImage::Format_RGB32;
+        if (bitPerSample > 8 && photometric == PHOTOMETRIC_RGB)
+            format = QImage::Format_RGBX64;
+        else
+            format = QImage::Format_RGB32;
     else {
         uint16 count;
         uint16 *extrasamples;
@@ -281,11 +286,25 @@ bool QTiffHandlerPrivate::readHeaders(QIODevice *device)
         // data to us. If there is none, libtiff will not touch it and  we assume it to be
         // non-premultiplied, matching behavior of tested image editors, and how older Qt
         // versions used to save it.
+        bool premultiplied = true;
         bool gotField = TIFFGetField(tiff, TIFFTAG_EXTRASAMPLES, &count, &extrasamples);
         if (!gotField || !count || extrasamples[0] == EXTRASAMPLE_UNSPECIFIED)
-            format = QImage::Format_ARGB32;
-        else
-            format = QImage::Format_ARGB32_Premultiplied;
+            premultiplied = false;
+
+        if (bitPerSample > 8 && photometric == PHOTOMETRIC_RGB) {
+            // We read 64-bit raw, so unassoc remains unpremultiplied.
+            if (gotField && count && extrasamples[0] == EXTRASAMPLE_UNASSALPHA)
+                premultiplied = false;
+            if (premultiplied)
+                format = QImage::Format_RGBA64_Premultiplied;
+            else
+                format = QImage::Format_RGBA64;
+        } else {
+            if (premultiplied)
+                format = QImage::Format_ARGB32_Premultiplied;
+            else
+                format = QImage::Format_ARGB32;
+        }
     }
 
     headersRead = true;
@@ -321,10 +340,9 @@ bool QTiffHandler::read(QImage *image)
         return false;
 
     QImage::Format format = d->format;
-    if (format == QImage::Format_RGB32 &&
-            (image->format() == QImage::Format_ARGB32 ||
-             image->format() == QImage::Format_ARGB32_Premultiplied))
-        format = image->format();
+
+    if (image->size() == d->size && image->format() != format)
+        image->reinterpretAsFormat(format);
 
     if (image->size() != d->size || image->format() != format)
         *image = QImage(d->size, format);
@@ -338,7 +356,8 @@ bool QTiffHandler::read(QImage *image)
     const quint32 width = d->size.width();
     const quint32 height = d->size.height();
 
-    if (format == QImage::Format_Mono || format == QImage::Format_Indexed8 || format == QImage::Format_Grayscale8) {
+    // Setup color tables
+    if (format == QImage::Format_Mono || format == QImage::Format_Indexed8) {
         if (format == QImage::Format_Mono) {
             QVector<QRgb> colortable(2);
             if (d->photometric == PHOTOMETRIC_MINISBLACK) {
@@ -381,7 +400,14 @@ bool QTiffHandler::read(QImage *image)
             image->setColorTable(qtColorTable);
             // free redTable, greenTable and greenTable done by libtiff
         }
+    }
+    bool format8bit = (format == QImage::Format_Mono || format == QImage::Format_Indexed8 || format == QImage::Format_Grayscale8);
+    bool format64bit = (format == QImage::Format_RGBX64 || format == QImage::Format_RGBA64 || format == QImage::Format_RGBA64_Premultiplied);
 
+    if (format8bit || format64bit) {
+        int bytesPerPixel = image->depth() / 8;
+        if (format == QImage::Format_RGBX64)
+            bytesPerPixel = 6;
         if (TIFFIsTiled(tiff)) {
             quint32 tileWidth, tileLength;
             TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tileWidth);
@@ -392,8 +418,8 @@ bool QTiffHandler::read(QImage *image)
                 d->close();
                 return false;
             }
-            quint32 byteWidth = (format == QImage::Format_Mono) ? (width + 7)/8 : width;
-            quint32 byteTileWidth = (format == QImage::Format_Mono) ? tileWidth/8 : tileWidth;
+            quint32 byteWidth = (format == QImage::Format_Mono) ? (width + 7)/8 : (width * bytesPerPixel);
+            quint32 byteTileWidth = (format == QImage::Format_Mono) ? tileWidth/8 : (tileWidth * bytesPerPixel);
             for (quint32 y = 0; y < height; y += tileLength) {
                 for (quint32 x = 0; x < width; x += tileWidth) {
                     if (TIFFReadTile(tiff, buf, x, y, 0, 0) < 0) {
@@ -402,7 +428,7 @@ bool QTiffHandler::read(QImage *image)
                         return false;
                     }
                     quint32 linesToCopy = qMin(tileLength, height - y);
-                    quint32 byteOffset = (format == QImage::Format_Mono) ? x/8 : x;
+                    quint32 byteOffset = (format == QImage::Format_Mono) ? x/8 : (x * bytesPerPixel);
                     quint32 widthToCopy = qMin(byteTileWidth, byteWidth - byteOffset);
                     for (quint32 i = 0; i < linesToCopy; i++) {
                         ::memcpy(image->scanLine(y + i) + byteOffset, buf + (i * byteTileWidth), widthToCopy);
@@ -418,6 +444,8 @@ bool QTiffHandler::read(QImage *image)
                 }
             }
         }
+        if (format == QImage::Format_RGBX64)
+            rgb48fixup(image);
     } else {
         const int stopOnError = 1;
         if (TIFFReadRGBAImageOriented(tiff, width, height, reinterpret_cast<uint32 *>(image->bits()), qt2Exif(d->transformation), stopOnError)) {
@@ -651,6 +679,50 @@ bool QTiffHandler::write(const QImage &image)
             }
         }
         TIFFClose(tiff);
+    } else if (format == QImage::Format_RGBX64) {
+        if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB)
+            || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_LZW)
+            || !TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, 3)
+            || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 16)
+            || !TIFFSetField(tiff, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tiff, 0))) {
+            TIFFClose(tiff);
+            return false;
+        }
+        std::unique_ptr<quint16[]> rgb48line(new quint16[width * 3]);
+        for (int y = 0; y < height; ++y) {
+            const quint16 *srcLine = reinterpret_cast<const quint16 *>(image.constScanLine(y));
+            for (int x = 0; x < width; ++x) {
+                rgb48line[x * 3 + 0] = srcLine[x * 4 + 0];
+                rgb48line[x * 3 + 1] = srcLine[x * 4 + 1];
+                rgb48line[x * 3 + 2] = srcLine[x * 4 + 2];
+            }
+
+            if (TIFFWriteScanline(tiff, (void*)rgb48line.get(), y) != 1) {
+                TIFFClose(tiff);
+                return false;
+            }
+        }
+        TIFFClose(tiff);
+    } else if (format == QImage::Format_RGBA64
+               || format == QImage::Format_RGBA64_Premultiplied) {
+        const bool premultiplied = image.format() != QImage::Format_RGBA64;
+        const uint16 extrasamples = premultiplied ? EXTRASAMPLE_ASSOCALPHA : EXTRASAMPLE_UNASSALPHA;
+        if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB)
+            || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_LZW)
+            || !TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, 4)
+            || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 16)
+            || !TIFFSetField(tiff, TIFFTAG_EXTRASAMPLES, 1, &extrasamples)
+            || !TIFFSetField(tiff, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tiff, 0))) {
+            TIFFClose(tiff);
+            return false;
+        }
+        for (int y = 0; y < height; ++y) {
+            if (TIFFWriteScanline(tiff, (void*)image.scanLine(y), y) != 1) {
+                TIFFClose(tiff);
+                return false;
+            }
+        }
+        TIFFClose(tiff);
     } else if (!image.hasAlphaChannel()) {
         if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB)
             || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_LZW)
@@ -812,6 +884,25 @@ void QTiffHandler::convert32BitOrder(void *buffer, int width)
     }
 }
 
+void QTiffHandler::rgb48fixup(QImage *image)
+{
+    Q_ASSERT(image->depth() == 64);
+    const int h = image->height();
+    const int w = image->width();
+    uchar *scanline = image->bits();
+    const qsizetype bpl = image->bytesPerLine();
+    for (int y = 0; y < h; ++y) {
+        quint16 *dst = reinterpret_cast<uint16 *>(scanline);
+        for (int x = w - 1; x >= 0; --x) {
+            dst[x * 4 + 3] = 0xffff;
+            dst[x * 4 + 2] = dst[x * 3 + 2];
+            dst[x * 4 + 1] = dst[x * 3 + 1];
+            dst[x * 4 + 0] = dst[x * 3 + 0];
+        }
+        scanline += bpl;
+    }
+}
+
 bool QTiffHandler::ensureHaveDirectoryCount() const
 {
     if (d->directoryCount > 0)
diff --git a/src/plugins/imageformats/tiff/qtiffhandler_p.h b/src/plugins/imageformats/tiff/qtiffhandler_p.h
index c7b074dbb5cdc7242b1690738a89b948ae67a9ca..2090e3891fe1552e07ff7a29f4199eb1fb50333c 100644
--- a/src/plugins/imageformats/tiff/qtiffhandler_p.h
+++ b/src/plugins/imageformats/tiff/qtiffhandler_p.h
@@ -74,6 +74,7 @@ public:
     };
 private:
     void convert32BitOrder(void *buffer, int width);
+    void rgb48fixup(QImage *image);
     const QScopedPointer<QTiffHandlerPrivate> d;
     bool ensureHaveDirectoryCount() const;
 };
diff --git a/tests/auto/tiff/tst_qtiff.cpp b/tests/auto/tiff/tst_qtiff.cpp
index 1a96ab381c04552aa03729784b809aa0d843033f..9c815d57813c20d34f5e6395d896226624a9f37c 100644
--- a/tests/auto/tiff/tst_qtiff.cpp
+++ b/tests/auto/tiff/tst_qtiff.cpp
@@ -84,6 +84,8 @@ private slots:
     void tiled_data();
     void tiled();
 
+    void readRgba64();
+
 private:
     QString prefix;
 };
@@ -165,6 +167,7 @@ void tst_qtiff::readImage_data()
     QTest::newRow("tiled_mono") << QString("tiled_mono.tiff") << QSize(64, 64);
     QTest::newRow("tiled_oddsize_grayscale") << QString("tiled_oddsize_grayscale.tiff") << QSize(59, 71);
     QTest::newRow("tiled_oddsize_mono") << QString("tiled_oddsize_mono.tiff") << QSize(59, 71);
+    QTest::newRow("16bpc") << QString("16bpc.tiff") << QSize(64, 46);
 }
 
 void tst_qtiff::readImage()
@@ -384,6 +387,9 @@ void tst_qtiff::readWriteNonDestructive_data()
     QTest::newRow("tiff argb32pm") << QImage::Format_ARGB32_Premultiplied << QImage::Format_ARGB32_Premultiplied << QImageIOHandler::TransformationRotate90;
     QTest::newRow("tiff rgb32") << QImage::Format_RGB32 << QImage::Format_RGB32 << QImageIOHandler::TransformationRotate270;
     QTest::newRow("tiff grayscale") << QImage::Format_Grayscale8 << QImage::Format_Grayscale8 << QImageIOHandler::TransformationFlip;
+    QTest::newRow("tiff rgb64") << QImage::Format_RGBX64 << QImage::Format_RGBX64 << QImageIOHandler::TransformationNone;
+    QTest::newRow("tiff rgba64") << QImage::Format_RGBA64 << QImage::Format_RGBA64 << QImageIOHandler::TransformationRotate90;
+    QTest::newRow("tiff rgba64pm") << QImage::Format_RGBA64_Premultiplied << QImage::Format_RGBA64_Premultiplied << QImageIOHandler::TransformationNone;
 }
 
 void tst_qtiff::readWriteNonDestructive()
@@ -592,5 +598,16 @@ void tst_qtiff::tiled()
     QCOMPARE(expectedImage, tiledImage);
 }
 
+void tst_qtiff::readRgba64()
+{
+    QString path = prefix + QString("16bpc.tiff");
+    QImageReader reader(path);
+    QVERIFY(reader.canRead());
+    QCOMPARE(reader.imageFormat(), QImage::Format_RGBX64);
+    QImage image = reader.read();
+    QVERIFY(!image.isNull());
+    QCOMPARE(image.format(), QImage::Format_RGBX64);
+}
+
 QTEST_MAIN(tst_qtiff)
 #include "tst_qtiff.moc"
diff --git a/tests/shared/images/tiff.qrc b/tests/shared/images/tiff.qrc
index 19675ba656e49951f3d8f2d42a6cc835a9212d24..91bbf93b112be867fcef9de00566541bce771879 100644
--- a/tests/shared/images/tiff.qrc
+++ b/tests/shared/images/tiff.qrc
@@ -1,5 +1,6 @@
 <RCC>
     <qresource prefix="/">
+        <file>tiff/16bpc.tiff</file>
         <file>tiff/corrupt-data.tif</file>
         <file>tiff/grayscale-ref.tif</file>
         <file>tiff/grayscale.tif</file>
diff --git a/tests/shared/images/tiff/16bpc.tiff b/tests/shared/images/tiff/16bpc.tiff
new file mode 100644
index 0000000000000000000000000000000000000000..b1ecf264b799818ea8af40d2ebe15cae6b83b2e6
Binary files /dev/null and b/tests/shared/images/tiff/16bpc.tiff differ