webp handler: support alpha-less reading and writing

Webp files can be with or without alpha channel. The handler would
ignore this and read all as Format_ARGB32 images, and write all as
having alpha, in both cases losing that important bit of information.

As a driveby, simplify the endianness handling in write(). By always
converting the source image to an endianness-independent QImage
format, no special handling is required.

Task-number: QTBUG-48628
Change-Id: I624ed72b18a8b59a542979efcb4e8ff81214e0d7
Reviewed-by: Liang Qi <liang.qi@qt.io>
This commit is contained in:
Eirik Aavitsland 2018-05-25 16:15:14 +02:00
parent aa33202648
commit b9ba221756
4 changed files with 32 additions and 19 deletions

View File

@ -174,7 +174,8 @@ bool QWebpHandler::read(QImage *image)
if (status != VP8_STATUS_OK)
return false;
QImage frame(m_iter.width, m_iter.height, QImage::Format_ARGB32);
QImage::Format format = m_features.has_alpha ? QImage::Format_ARGB32 : QImage::Format_RGB32;
QImage frame(m_iter.width, m_iter.height, format);
uint8_t *output = frame.bits();
size_t output_size = frame.sizeInBytes();
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
@ -219,13 +220,10 @@ bool QWebpHandler::write(const QImage &image)
}
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
bool alpha = srcImage.hasAlphaChannel();
QImage::Format newFormat = alpha ? QImage::Format_RGBA8888 : QImage::Format_RGB888;
if (srcImage.format() != newFormat)
srcImage = srcImage.convertToFormat(newFormat);
WebPPicture picture;
WebPConfig config;
@ -238,13 +236,14 @@ bool QWebpHandler::write(const QImage &image)
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.";
bool failed = false;
if (alpha)
failed = !WebPPictureImportRGBA(&picture, srcImage.bits(), srcImage.bytesPerLine());
else
failed = !WebPPictureImportRGB(&picture, srcImage.bits(), srcImage.bytesPerLine());
if (failed) {
qWarning() << "failed to import image data to webp picture.";
WebPPictureFree(&picture);
return false;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -53,15 +53,18 @@ void tst_qwebp::readImage_data()
{
QTest::addColumn<QString>("fileName");
QTest::addColumn<QSize>("size");
QTest::addColumn<bool>("alpha");
QTest::newRow("kollada") << QString("kollada") << QSize(436, 160);
QTest::newRow("kollada_lossless") << QString("kollada_lossless") << QSize(436, 160);
QTest::newRow("kollada") << QString("kollada") << QSize(436, 160) << true;
QTest::newRow("kollada_lossless") << QString("kollada_lossless") << QSize(436, 160) << true;
QTest::newRow("kollada_noalpha") << QString("kollada_noalpha") << QSize(436, 160) << false;
}
void tst_qwebp::readImage()
{
QFETCH(QString, fileName);
QFETCH(QSize, size);
QFETCH(bool, alpha);
const QString path = QStringLiteral(":/images/") + fileName + QStringLiteral(".webp");
QImageReader reader(path);
@ -69,6 +72,7 @@ void tst_qwebp::readImage()
QImage image = reader.read();
QVERIFY2(!image.isNull(), qPrintable(reader.errorString()));
QCOMPARE(image.size(), size);
QCOMPARE(image.hasAlphaChannel(), alpha);
}
void tst_qwebp::readAnimation_data()
@ -136,10 +140,13 @@ void tst_qwebp::writeImage_data()
QTest::addColumn<QString>("postfix");
QTest::addColumn<int>("quality");
QTest::addColumn<QSize>("size");
QTest::addColumn<bool>("alpha");
QTest::addColumn<bool>("needcheck");
QTest::newRow("kollada-75") << QString("kollada") << QString(".png") << 75 << QSize(436, 160) << false;
QTest::newRow("kollada-100") << QString("kollada") << QString(".png") << 100 << QSize(436, 160) << true;
QTest::newRow("kollada-75") << QString("kollada") << QString(".png") << 75 << QSize(436, 160) << true << false;
QTest::newRow("kollada-100") << QString("kollada") << QString(".png") << 100 << QSize(436, 160) << true << true;
QTest::newRow("kollada_noalpha-75") << QString("kollada_noalpha") << QString(".webp") << 75 << QSize(436, 160) << false << false;
QTest::newRow("kollada_noalpha-100") << QString("kollada_noalpha") << QString(".webp") << 100 << QSize(436, 160) << false << true;
}
void tst_qwebp::writeImage()
@ -148,6 +155,7 @@ void tst_qwebp::writeImage()
QFETCH(QString, postfix);
QFETCH(int, quality);
QFETCH(QSize, size);
QFETCH(bool, alpha);
QFETCH(bool, needcheck);
const QString path = QString("%1-%2.webp").arg(fileName).arg(quality);
@ -162,8 +170,13 @@ void tst_qwebp::writeImage()
writer.setQuality(quality);
QVERIFY2(writer.write(image), qPrintable(writer.errorString()));
QImage reread(path);
QVERIFY(!reread.isNull());
QVERIFY(reread.size() == size);
QVERIFY(reread.hasAlphaChannel() == alpha);
if (needcheck)
QVERIFY(image == QImage(path));
QVERIFY(image == reread);
}
QTEST_MAIN(tst_qwebp)

View File

@ -4,5 +4,6 @@
<file>images/kollada.webp</file>
<file>images/kollada_lossless.webp</file>
<file>images/kollada_animation.webp</file>
<file>images/kollada_noalpha.webp</file>
</qresource>
</RCC>