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) if (status != VP8_STATUS_OK)
return false; 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(); uint8_t *output = frame.bits();
size_t output_size = frame.sizeInBytes(); size_t output_size = frame.sizeInBytes();
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
@ -219,13 +220,10 @@ bool QWebpHandler::write(const QImage &image)
} }
QImage srcImage = image; QImage srcImage = image;
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN bool alpha = srcImage.hasAlphaChannel();
if (srcImage.format() != QImage::Format_ARGB32) QImage::Format newFormat = alpha ? QImage::Format_RGBA8888 : QImage::Format_RGB888;
srcImage = srcImage.convertToFormat(QImage::Format_ARGB32); if (srcImage.format() != newFormat)
#else /* Q_BIG_ENDIAN */ srcImage = srcImage.convertToFormat(newFormat);
if (srcImage.format() != QImage::Format_RGBA8888)
srcImage = srcImage.convertToFormat(QImage::Format_RGBA8888);
#endif
WebPPicture picture; WebPPicture picture;
WebPConfig config; WebPConfig config;
@ -238,13 +236,14 @@ bool QWebpHandler::write(const QImage &image)
picture.width = srcImage.width(); picture.width = srcImage.width();
picture.height = srcImage.height(); picture.height = srcImage.height();
picture.use_argb = 1; picture.use_argb = 1;
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN bool failed = false;
if (!WebPPictureImportBGRA(&picture, srcImage.bits(), srcImage.bytesPerLine())) { if (alpha)
#else /* Q_BIG_ENDIAN */ failed = !WebPPictureImportRGBA(&picture, srcImage.bits(), srcImage.bytesPerLine());
if (!WebPPictureImportRGBA(&picture, srcImage.bits(), srcImage.bytesPerLine())) { else
#endif failed = !WebPPictureImportRGB(&picture, srcImage.bits(), srcImage.bytesPerLine());
qWarning() << "failed to import image data to webp picture.";
if (failed) {
qWarning() << "failed to import image data to webp picture.";
WebPPictureFree(&picture); WebPPictureFree(&picture);
return false; 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<QString>("fileName");
QTest::addColumn<QSize>("size"); QTest::addColumn<QSize>("size");
QTest::addColumn<bool>("alpha");
QTest::newRow("kollada") << QString("kollada") << QSize(436, 160); QTest::newRow("kollada") << QString("kollada") << QSize(436, 160) << true;
QTest::newRow("kollada_lossless") << QString("kollada_lossless") << QSize(436, 160); 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() void tst_qwebp::readImage()
{ {
QFETCH(QString, fileName); QFETCH(QString, fileName);
QFETCH(QSize, size); QFETCH(QSize, size);
QFETCH(bool, alpha);
const QString path = QStringLiteral(":/images/") + fileName + QStringLiteral(".webp"); const QString path = QStringLiteral(":/images/") + fileName + QStringLiteral(".webp");
QImageReader reader(path); QImageReader reader(path);
@ -69,6 +72,7 @@ void tst_qwebp::readImage()
QImage image = reader.read(); QImage image = reader.read();
QVERIFY2(!image.isNull(), qPrintable(reader.errorString())); QVERIFY2(!image.isNull(), qPrintable(reader.errorString()));
QCOMPARE(image.size(), size); QCOMPARE(image.size(), size);
QCOMPARE(image.hasAlphaChannel(), alpha);
} }
void tst_qwebp::readAnimation_data() void tst_qwebp::readAnimation_data()
@ -136,10 +140,13 @@ void tst_qwebp::writeImage_data()
QTest::addColumn<QString>("postfix"); QTest::addColumn<QString>("postfix");
QTest::addColumn<int>("quality"); QTest::addColumn<int>("quality");
QTest::addColumn<QSize>("size"); QTest::addColumn<QSize>("size");
QTest::addColumn<bool>("alpha");
QTest::addColumn<bool>("needcheck"); QTest::addColumn<bool>("needcheck");
QTest::newRow("kollada-75") << QString("kollada") << QString(".png") << 75 << QSize(436, 160) << false; 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; 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() void tst_qwebp::writeImage()
@ -148,6 +155,7 @@ void tst_qwebp::writeImage()
QFETCH(QString, postfix); QFETCH(QString, postfix);
QFETCH(int, quality); QFETCH(int, quality);
QFETCH(QSize, size); QFETCH(QSize, size);
QFETCH(bool, alpha);
QFETCH(bool, needcheck); QFETCH(bool, needcheck);
const QString path = QString("%1-%2.webp").arg(fileName).arg(quality); const QString path = QString("%1-%2.webp").arg(fileName).arg(quality);
@ -162,8 +170,13 @@ void tst_qwebp::writeImage()
writer.setQuality(quality); writer.setQuality(quality);
QVERIFY2(writer.write(image), qPrintable(writer.errorString())); QVERIFY2(writer.write(image), qPrintable(writer.errorString()));
QImage reread(path);
QVERIFY(!reread.isNull());
QVERIFY(reread.size() == size);
QVERIFY(reread.hasAlphaChannel() == alpha);
if (needcheck) if (needcheck)
QVERIFY(image == QImage(path)); QVERIFY(image == reread);
} }
QTEST_MAIN(tst_qwebp) QTEST_MAIN(tst_qwebp)

View File

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