diff options
author | Eirik Aavitsland <eirik.aavitsland@qt.io> | 2022-09-08 14:52:19 +0200 |
---|---|---|
committer | Eirik Aavitsland <eirik.aavitsland@qt.io> | 2022-09-13 07:25:47 +0200 |
commit | 369be99d82a7c1182e3693756ab545cea86bb90d (patch) | |
tree | c754df4db7f64cd272ad48fe6e7953528b7dbafb /src | |
parent | c5f837d59e1ebc628aa8393c49587795746dab7e (diff) | |
download | qtimageformats-369be99d82a7c1182e3693756ab545cea86bb90d.tar.gz |
webp: support sequential input device if full file is available
Since we do no random access during decoding, just a readAll() of the
whole image file. So if it is all available already, we can handle a
sequential device. That is useful for Quick AnimationImage, which will
pass a finished QNetworkReply as the input device.
This commit removes some seek() calls in the header checking, that
supposedly should reset the device position. These were in practice
either no-ops or bugs, since the device is only being peeked, so the
position never changes in the first place, and a QImageIOHandler is
supposed to read from the device at the position it is at when passed.
Fixes: QTBUG-70245
Change-Id: I5a4ff5fa4bbd19b0545ad41645969d714b4dc7d5
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/imageformats/webp/qwebphandler.cpp | 29 |
1 files changed, 14 insertions, 15 deletions
diff --git a/src/plugins/imageformats/webp/qwebphandler.cpp b/src/plugins/imageformats/webp/qwebphandler.cpp index 59513f6..922868c 100644 --- a/src/plugins/imageformats/webp/qwebphandler.cpp +++ b/src/plugins/imageformats/webp/qwebphandler.cpp @@ -9,6 +9,7 @@ #include <qdebug.h> #include <qpainter.h> #include <qvariant.h> +#include <QtEndian> static const int riffHeaderSize = 12; // RIFF_HEADER_SIZE from webp/format_constants.h @@ -66,21 +67,23 @@ bool QWebpHandler::ensureScanned() const m_scanState = ScanError; - if (device()->isSequential()) { - qWarning() << "Sequential devices are not supported"; + QWebpHandler *that = const_cast<QWebpHandler *>(this); + const int headerBytesNeeded = sizeof(WebPBitstreamFeatures); + QByteArray header = device()->peek(headerBytesNeeded); + if (header.size() < headerBytesNeeded) return false; - } - qint64 oldPos = device()->pos(); - device()->seek(0); - - QWebpHandler *that = const_cast<QWebpHandler *>(this); - QByteArray header = device()->peek(sizeof(WebPBitstreamFeatures)); + // We do no random access during decoding, just a readAll() of the whole image file. So if + // if it is all available already, we can accept a sequential device. The riff header contains + // the file size minus 8 bytes header + qint64 byteSize = qFromLittleEndian<quint32>(header.constData() + 4); + if (device()->isSequential() && device()->bytesAvailable() < byteSize + 8) { + qWarning() << "QWebpHandler: Insufficient data available in sequential device"; + return false; + } if (WebPGetFeatures((const uint8_t*)header.constData(), header.size(), &(that->m_features)) == VP8_STATUS_OK) { if (m_features.has_animation) { // For animation, we have to read and scan whole file to determine loop count and images count - device()->seek(oldPos); - if (that->ensureDemuxer()) { that->m_loop = WebPDemuxGetI(m_demuxer, WEBP_FF_LOOP_COUNT); that->m_frameCount = WebPDemuxGetI(m_demuxer, WEBP_FF_FRAME_COUNT); @@ -93,17 +96,13 @@ bool QWebpHandler::ensureScanned() const if (that->m_features.has_alpha) that->m_composited->fill(Qt::transparent); - // We do not reset device position since we have read in all data m_scanState = ScanSuccess; - return true; } } else { m_scanState = ScanSuccess; } } - device()->seek(oldPos); - return m_scanState == ScanSuccess; } @@ -126,7 +125,7 @@ bool QWebpHandler::ensureDemuxer() bool QWebpHandler::read(QImage *image) { - if (!ensureScanned() || device()->isSequential() || !ensureDemuxer()) + if (!ensureScanned() || !ensureDemuxer()) return false; QRect prevFrameRect; |