diff options
Diffstat (limited to 'src/plugins/imageformats/webp/qwebphandler.cpp')
-rw-r--r-- | src/plugins/imageformats/webp/qwebphandler.cpp | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/src/plugins/imageformats/webp/qwebphandler.cpp b/src/plugins/imageformats/webp/qwebphandler.cpp new file mode 100644 index 0000000..8834820 --- /dev/null +++ b/src/plugins/imageformats/webp/qwebphandler.cpp @@ -0,0 +1,213 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the WebP plugins in the Qt ImageFormats module. +** +** $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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt 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 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwebphandler_p.h" +#include "webp/encode.h" +#include <qimage.h> +#include <qdebug.h> +#include <qvariant.h> + +static const int riffHeaderSize = 12; // RIFF_HEADER_SIZE from webp/format_constants.h + +QWebpHandler::QWebpHandler() : + m_lossless(false), + m_quality(75), + m_scanState(ScanNotScanned) +{ +} + +bool QWebpHandler::canRead() const +{ + if (m_scanState == ScanNotScanned && !canRead(device())) + return false; + + if (m_scanState != ScanError) { + setFormat(QByteArrayLiteral("webp")); + return true; + } + return false; +} + +bool QWebpHandler::canRead(QIODevice *device) +{ + if (!device) { + qWarning("QWebpHandler::canRead() called with no device"); + return false; + } + + QByteArray header = device->peek(riffHeaderSize); + return header.startsWith("RIFF") && header.endsWith("WEBP"); +} + +bool QWebpHandler::ensureScanned() const +{ + if (m_scanState != ScanNotScanned) + return m_scanState == ScanSuccess; + + m_scanState = ScanError; + + if (device()->isSequential()) { + qWarning() << "Sequential devices are not supported"; + return false; + } + + qint64 oldPos = device()->pos(); + device()->seek(0); + + 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; + + device()->seek(oldPos); + + return m_scanState == ScanSuccess; +} + +bool QWebpHandler::read(QImage *image) +{ + if (!ensureScanned() || device()->isSequential()) + 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(); +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + if (!WebPDecodeBGRAInto(reinterpret_cast<const uint8_t*>(data.constData()), data.size(), output, output_size, result.bytesPerLine())) +#else + if (!WebPDecodeARGBInto(reinterpret_cast<const uint8_t*>(data.constData()), data.size(), output, output_size, result.bytesPerLine())) +#endif + return false; + + *image = result; + return true; +} + +static int pictureWriter(const quint8 *data, size_t data_size, const WebPPicture *const pic) +{ + QIODevice *io = reinterpret_cast<QIODevice*>(pic->custom_ptr); + + return data_size ? ((quint64)(io->write((const char*)data, data_size)) == data_size) : 1; +} + +bool QWebpHandler::write(const QImage &image) +{ + if (image.isNull()) { + qWarning() << "source image is null."; + return false; + } + + QImage srcImage = image; + if (srcImage.format() != QImage::Format_ARGB32) + srcImage = srcImage.convertToFormat(QImage::Format_ARGB32); + + WebPPicture picture; + WebPConfig config; + + if (!WebPPictureInit(&picture) || !WebPConfigInit(&config)) { + qWarning() << "failed to init webp picture and config"; + return false; + } + + picture.width = srcImage.width(); + picture.height = srcImage.height(); + picture.use_argb = 1; + if (!WebPPictureImportBGRA(&picture, srcImage.bits(), srcImage.bytesPerLine())) { + qWarning() << "failed to import image data to webp picture."; + + WebPPictureFree(&picture); + return false; + } + + config.lossless = m_lossless; + config.quality = m_quality; + picture.writer = pictureWriter; + picture.custom_ptr = device(); + + if (!WebPEncode(&config, &picture)) { + qWarning() << "failed to encode webp picture, error code: " << picture.error_code; + WebPPictureFree(&picture); + return false; + } + + WebPPictureFree(&picture); + + return true; +} + +QVariant QWebpHandler::option(ImageOption option) const +{ + if (!supportsOption(option) || !ensureScanned()) + return QVariant(); + + switch (option) { + case Quality: + return m_quality; + case Size: + return QSize(m_features.width, m_features.height); + default: + return QVariant(); + } +} + +void QWebpHandler::setOption(ImageOption option, const QVariant &value) +{ + switch (option) { + case Quality: + m_quality = qBound(0, value.toInt(), 100); + m_lossless = (m_quality >= 100); + return; + default: + break; + } + return QImageIOHandler::setOption(option, value); +} + +bool QWebpHandler::supportsOption(ImageOption option) const +{ + return option == Quality || option == Size; +} + +QByteArray QWebpHandler::name() const +{ + return QByteArrayLiteral("webp"); +} |