diff options
Diffstat (limited to 'src/plugins/imageformats/webp/qwebphandler.cpp')
-rw-r--r-- | src/plugins/imageformats/webp/qwebphandler.cpp | 186 |
1 files changed, 160 insertions, 26 deletions
diff --git a/src/plugins/imageformats/webp/qwebphandler.cpp b/src/plugins/imageformats/webp/qwebphandler.cpp index 41a568d..a59e6bd 100644 --- a/src/plugins/imageformats/webp/qwebphandler.cpp +++ b/src/plugins/imageformats/webp/qwebphandler.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the WebP plugins in the Qt ImageFormats module. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -33,8 +39,10 @@ #include "qwebphandler_p.h" #include "webp/encode.h" +#include <qcolor.h> #include <qimage.h> #include <qdebug.h> +#include <qpainter.h> #include <qvariant.h> static const int riffHeaderSize = 12; // RIFF_HEADER_SIZE from webp/format_constants.h @@ -42,8 +50,20 @@ static const int riffHeaderSize = 12; // RIFF_HEADER_SIZE from webp/format_const QWebpHandler::QWebpHandler() : m_lossless(false), m_quality(75), - m_scanState(ScanNotScanned) + m_scanState(ScanNotScanned), + m_loop(0), + m_frameCount(0), + m_demuxer(NULL), + m_composited(NULL) { + memset(&m_iter, 0, sizeof(m_iter)); +} + +QWebpHandler::~QWebpHandler() +{ + WebPDemuxReleaseIterator(&m_iter); + WebPDemuxDelete(m_demuxer); + delete m_composited; } bool QWebpHandler::canRead() const @@ -86,31 +106,93 @@ bool QWebpHandler::ensureScanned() const QWebpHandler *that = const_cast<QWebpHandler *>(this); QByteArray header = device()->peek(sizeof(WebPBitstreamFeatures)); - if (WebPGetFeatures((const uint8_t*)header.constData(), header.size(), &(that->m_features)) == VP8_STATUS_OK) - m_scanState = ScanSuccess; + 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); + that->m_bgColor = QColor::fromRgba(QRgb(WebPDemuxGetI(m_demuxer, WEBP_FF_BACKGROUND_COLOR))); + + that->m_composited = new QImage(that->m_features.width, that->m_features.height, QImage::Format_ARGB32); + + // 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; } +bool QWebpHandler::ensureDemuxer() +{ + if (m_demuxer) + return true; + + m_rawData = device()->readAll(); + m_webpData.bytes = reinterpret_cast<const uint8_t *>(m_rawData.constData()); + m_webpData.size = m_rawData.size(); + + m_demuxer = WebPDemux(&m_webpData); + if (m_demuxer == NULL) + return false; + + return true; +} + bool QWebpHandler::read(QImage *image) { - if (!ensureScanned() || device()->isSequential()) + if (!ensureScanned() || device()->isSequential() || !ensureDemuxer()) + return false; + + if (m_iter.frame_num == 0) { + // Go to first frame + if (!WebPDemuxGetFrame(m_demuxer, 1, &m_iter)) + return false; + } else { + // Go to next frame + if (!WebPDemuxNextFrame(&m_iter)) + return false; + } + + WebPBitstreamFeatures features; + VP8StatusCode status = WebPGetFeatures(m_iter.fragment.bytes, m_iter.fragment.size, &features); + if (status != VP8_STATUS_OK) return false; - QByteArray data = device()->readAll(); - QImage result(m_features.width, m_features.height, QImage::Format_ARGB32); - uint8_t *output = result.bits(); - size_t output_size = result.byteCount(); + QImage frame(m_iter.width, m_iter.height, QImage::Format_ARGB32); + uint8_t *output = frame.bits(); + size_t output_size = frame.byteCount(); #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - if (!WebPDecodeBGRAInto(reinterpret_cast<const uint8_t*>(data.constData()), data.size(), output, output_size, result.bytesPerLine())) + if (!WebPDecodeBGRAInto( + reinterpret_cast<const uint8_t*>(m_iter.fragment.bytes), m_iter.fragment.size, + output, output_size, frame.bytesPerLine())) #else - if (!WebPDecodeARGBInto(reinterpret_cast<const uint8_t*>(data.constData()), data.size(), output, output_size, result.bytesPerLine())) + if (!WebPDecodeARGBInto( + reinterpret_cast<const uint8_t*>(m_iter.fragment.bytes), m_iter.fragment.size, + output, output_size, frame.bytesPerLine())) #endif return false; - *image = result; + if (!m_features.has_animation) { + // Single image + *image = frame; + } else { + // Animation + QPainter painter(m_composited); + painter.drawImage(currentImageRect(), frame); + + *image = *m_composited; + } + return true; } @@ -185,6 +267,10 @@ QVariant QWebpHandler::option(ImageOption option) const return m_quality; case Size: return QSize(m_features.width, m_features.height); + case Animation: + return m_features.has_animation; + case BackgroundColor: + return m_bgColor; default: return QVariant(); } @@ -205,10 +291,58 @@ void QWebpHandler::setOption(ImageOption option, const QVariant &value) bool QWebpHandler::supportsOption(ImageOption option) const { - return option == Quality || option == Size; + return option == Quality + || option == Size + || option == Animation + || option == BackgroundColor; } QByteArray QWebpHandler::name() const { return QByteArrayLiteral("webp"); } + +int QWebpHandler::imageCount() const +{ + if (!ensureScanned()) + return 0; + + if (!m_features.has_animation) + return 1; + + return m_frameCount; +} + +int QWebpHandler::currentImageNumber() const +{ + if (!ensureScanned() || !m_features.has_animation) + return 0; + + // Frame number in WebP starts from 1 + return m_iter.frame_num - 1; +} + +QRect QWebpHandler::currentImageRect() const +{ + if (!ensureScanned()) + return QRect(); + + return QRect(m_iter.x_offset, m_iter.y_offset, m_iter.width, m_iter.height); +} + +int QWebpHandler::loopCount() const +{ + if (!ensureScanned() || !m_features.has_animation) + return 0; + + // Loop count in WebP starts from 0 + return m_loop - 1; +} + +int QWebpHandler::nextImageDelay() const +{ + if (!ensureScanned() || !m_features.has_animation) + return 0; + + return m_iter.duration; +} |