3 Star 4 Fork 4

zhaowenwei / qt webp animation

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
qwebphandler.cpp 9.18 KB
一键复制 编辑 原始数据 按行查看 历史
zhaowenwei 提交于 2014-12-21 15:22 . 简单支持webp animation
/****************************************************************************
**
** Copyright (C) 2014 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:LGPL21$
** 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 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.
**
** 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.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qwebphandler_p.h"
#include "webp/encode.h"
#include "webp/mux.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),
m_demux(0),
m_webpItr(0)
{
}
QWebpHandler::~QWebpHandler()
{
safeDeleteDemux();
}
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;
if (m_scanState == ScanSuccess && that->m_features.has_animation)
{
device()->seek(0);
that->m_webpByteArray = device()->readAll();
WebPData webpData = {reinterpret_cast<const uint8_t*>(this->m_webpByteArray.constData()), this->m_webpByteArray.size()};
that->m_demux = WebPDemux(&webpData);
that->m_webpItr = new WebPIterator;
if (!WebPDemuxGetFrame(that->m_demux, 1, that->m_webpItr))
{
that->safeDeleteDemux();
that->m_webpByteArray = QByteArray();
}
}
device()->seek(oldPos);
return m_scanState == ScanSuccess;
}
void QWebpHandler::safeDeleteDemux()
{
if(m_webpItr)
{
WebPDemuxReleaseIterator(m_webpItr);
delete m_webpItr;
m_webpItr = 0;
}
if (m_demux)
{
WebPDemuxDelete(m_demux);
m_demux = 0;
}
}
bool QWebpHandler::read(QImage *image)
{
if (!ensureScanned() || device()->isSequential())
return false;
if (!m_features.has_animation) {
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;
}
else {
if (this->m_demux && this->m_webpItr)
{
QImage result(this->m_webpItr->width, this->m_webpItr->height, QImage::Format_ARGB32);
uint8_t *output = result.bits();
size_t output_size = result.byteCount();
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
if (!WebPDecodeBGRAInto(m_webpItr->fragment.bytes, m_webpItr->fragment.size, output, output_size, result.bytesPerLine()))
#else
if (!WebPDecodeARGBInto(m_webpItr->fragment.bytes, m_webpItr->fragment.size, output, output_size, result.bytesPerLine()))
#endif
return false;
*image = result;
jumpToNextImage();
}
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 Q_BYTE_ORDER == Q_LITTLE_ENDIAN
if (srcImage.format() != QImage::Format_ARGB32)
srcImage = srcImage.convertToFormat(QImage::Format_ARGB32);
#else /* Q_BIG_ENDIAN */
if (srcImage.format() != QImage::Format_RGBA8888)
srcImage = srcImage.convertToFormat(QImage::Format_RGBA8888);
#endif
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 Q_BYTE_ORDER == Q_LITTLE_ENDIAN
if (!WebPPictureImportBGRA(&picture, srcImage.bits(), srcImage.bytesPerLine())) {
#else /* Q_BIG_ENDIAN */
if (!WebPPictureImportRGBA(&picture, srcImage.bits(), srcImage.bytesPerLine())) {
#endif
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);
case Animation:
return m_features.has_animation;
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 || option == Animation;
}
bool QWebpHandler::jumpToNextImage()
{
if (this->m_demux && this->m_webpItr)
{
if (this->m_webpItr->frame_num+1 > this->imageCount())
{
return WebPDemuxGetFrame(this->m_demux, 1, this->m_webpItr) != 0;
}
return WebPDemuxNextFrame(this->m_webpItr) != 0;
}
return false;
}
bool QWebpHandler::jumpToImage(int imageNumber)
{
if (this->m_demux && this->m_webpItr)
{
return WebPDemuxGetFrame(this->m_demux, imageNumber, this->m_webpItr) != 0;
}
return false;
}
int QWebpHandler::loopCount() const
{
if (this->m_demux)
{
uint32_t loop = WebPDemuxGetI(this->m_demux, WEBP_FF_LOOP_COUNT);
return loop != 0 ? loop : -1;
}
return 0;
}
int QWebpHandler::imageCount() const
{
if (this->m_demux)
{
return WebPDemuxGetI(this->m_demux, WEBP_FF_FRAME_COUNT);
}
return 1;
}
int QWebpHandler::nextImageDelay() const
{
if (this->m_webpItr)
{
return this->m_webpItr->duration;
}
return 0;
}
int QWebpHandler::currentImageNumber() const
{
if (this->m_webpItr)
{
return this->m_webpItr->frame_num;
}
return -1;
}
QByteArray QWebpHandler::name() const
{
return QByteArrayLiteral("webp");
}
C++
1
https://gitee.com/noexcept1/qt-webp-animation.git
git@gitee.com:noexcept1/qt-webp-animation.git
noexcept1
qt-webp-animation
qt webp animation
master

搜索帮助