From f8b773d1d4b2f153eb97578ba5e49fd43564f7fb Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 29 Jul 2019 10:56:03 +0200 Subject: Do not try to write too large WebP images The WebP encoder doesn't check so we end up with undefined behavior. Change-Id: Id3a64b2be50684d07e799f97f64481ba57c02ffb Reviewed-by: Eirik Aavitsland --- src/plugins/imageformats/webp/qwebphandler.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/plugins/imageformats/webp/qwebphandler.cpp b/src/plugins/imageformats/webp/qwebphandler.cpp index 4d6bcbe..454d654 100644 --- a/src/plugins/imageformats/webp/qwebphandler.cpp +++ b/src/plugins/imageformats/webp/qwebphandler.cpp @@ -218,6 +218,10 @@ bool QWebpHandler::write(const QImage &image) qWarning() << "source image is null."; return false; } + if (std::max(image.width(), image.height()) > WEBP_MAX_DIMENSION) { + qWarning() << "QWebpHandler::write() source image too large for WebP: " << image.size(); + return false; + } QImage srcImage = image; bool alpha = srcImage.hasAlphaChannel(); -- cgit v1.2.1 From d63c1d05e455921b1ea4e351e770316c3494ee63 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 24 Jul 2019 18:27:46 +0200 Subject: Read/write ICC profile in TIFF plugin Adds reading and writing of embedded color spaces on the TIFF plugin. Change-Id: I53e8a16ff65f7986e9d51a5b543335e27b43e346 Reviewed-by: Eirik Aavitsland --- src/plugins/imageformats/tiff/qtiffhandler.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/plugins/imageformats/tiff/qtiffhandler.cpp b/src/plugins/imageformats/tiff/qtiffhandler.cpp index 3d404bd..0d0a133 100644 --- a/src/plugins/imageformats/tiff/qtiffhandler.cpp +++ b/src/plugins/imageformats/tiff/qtiffhandler.cpp @@ -39,6 +39,7 @@ #include "qtiffhandler_p.h" #include +#include #include #include #include @@ -487,6 +488,15 @@ bool QTiffHandler::read(QImage *image) } } + uint32 count; + void *profile; + if (TIFFGetField(tiff, TIFFTAG_ICCPROFILE, &count, &profile)) { + QByteArray iccProfile(reinterpret_cast(profile), count); + image->setColorSpace(QColorSpace::fromIccProfile(iccProfile)); + } + // We do not handle colorimetric metadat not on ICC profile form, it seems to be a lot + // less common, and would need additional API in QColorSpace. + return true; } @@ -591,7 +601,14 @@ bool QTiffHandler::write(const QImage &image) TIFFClose(tiff); return false; } - + // set color space + if (image.colorSpace().isValid()) { + QByteArray iccProfile = image.colorSpace().iccProfile(); + if (!TIFFSetField(tiff, TIFFTAG_ICCPROFILE, iccProfile.size(), reinterpret_cast(iccProfile.constData()))) { + TIFFClose(tiff); + return false; + } + } // configure image depth const QImage::Format format = image.format(); if (format == QImage::Format_Mono || format == QImage::Format_MonoLSB) { -- cgit v1.2.1 From 25e60237a576f975d72605d5459b2477ee1f555b Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 29 Jul 2019 13:32:17 +0200 Subject: Read color space from WebP Change-Id: If1b9645fe07fb2cf15dbf2421d6c66b20f02bdb6 Reviewed-by: Eirik Aavitsland --- src/plugins/imageformats/webp/qwebphandler.cpp | 15 +++++++++++++++ src/plugins/imageformats/webp/qwebphandler_p.h | 3 +++ 2 files changed, 18 insertions(+) (limited to 'src') diff --git a/src/plugins/imageformats/webp/qwebphandler.cpp b/src/plugins/imageformats/webp/qwebphandler.cpp index 454d654..d56d28c 100644 --- a/src/plugins/imageformats/webp/qwebphandler.cpp +++ b/src/plugins/imageformats/webp/qwebphandler.cpp @@ -51,6 +51,7 @@ QWebpHandler::QWebpHandler() : m_quality(75), m_scanState(ScanNotScanned), m_features(), + m_formatFlags(0), m_loop(0), m_frameCount(0), m_demuxer(NULL), @@ -151,6 +152,7 @@ bool QWebpHandler::ensureDemuxer() if (m_demuxer == NULL) return false; + m_formatFlags = WebPDemuxGetI(m_demuxer, WEBP_FF_FORMAT_FLAGS); return true; } @@ -160,6 +162,18 @@ bool QWebpHandler::read(QImage *image) return false; if (m_iter.frame_num == 0) { + // Read global meta-data chunks first + WebPChunkIterator metaDataIter; + if ((m_formatFlags & ICCP_FLAG) && WebPDemuxGetChunk(m_demuxer, "ICCP", 1, &metaDataIter)) { + const QByteArray iccProfile = QByteArray::fromRawData(reinterpret_cast(metaDataIter.chunk.bytes), + metaDataIter.chunk.size); + m_colorSpace = QColorSpace::fromIccProfile(iccProfile); + // ### consider parsing EXIF and/or XMP metadata too. + WebPDemuxReleaseChunkIterator(&metaDataIter); + } else { + m_colorSpace = QColorSpace::Undefined; + } + // Go to first frame if (!WebPDemuxGetFrame(m_demuxer, 1, &m_iter)) return false; @@ -201,6 +215,7 @@ bool QWebpHandler::read(QImage *image) *image = *m_composited; } + image->setColorSpace(m_colorSpace); return true; } diff --git a/src/plugins/imageformats/webp/qwebphandler_p.h b/src/plugins/imageformats/webp/qwebphandler_p.h index 31574b4..96a8811 100644 --- a/src/plugins/imageformats/webp/qwebphandler_p.h +++ b/src/plugins/imageformats/webp/qwebphandler_p.h @@ -41,6 +41,7 @@ #define QWEBPHANDLER_P_H #include +#include #include #include #include @@ -90,6 +91,7 @@ private: int m_quality; mutable ScanState m_scanState; WebPBitstreamFeatures m_features; + uint32_t m_formatFlags; int m_loop; int m_frameCount; QColor m_bgColor; @@ -97,6 +99,7 @@ private: WebPData m_webpData; WebPDemuxer *m_demuxer; WebPIterator m_iter; + QColorSpace m_colorSpace; QImage *m_composited; // For animation frames composition }; -- cgit v1.2.1 From 5214bcd3d868664bb057f2689c02ec263bbc980b Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 29 Jul 2019 13:33:47 +0200 Subject: Support writing WebP color space profiles Change-Id: I9d9473c2866d9792cd8752816a291be04e39ec19 Reviewed-by: Eirik Aavitsland --- src/imageformats/configure.json | 7 +-- src/plugins/imageformats/webp/qwebphandler.cpp | 62 +++++++++++++++++++++----- 2 files changed, 55 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/imageformats/configure.json b/src/imageformats/configure.json index 03d59d3..7c6eaef 100644 --- a/src/imageformats/configure.json +++ b/src/imageformats/configure.json @@ -117,10 +117,11 @@ "include": [ "webp/decode.h", "webp/encode.h", - "webp/demux.h" + "webp/demux.h", + "webp/mux.h" ], "qmake": [ - "LIBS += -lwebp -lwebpdemux" + "LIBS += -lwebp -lwebpdemux -lwebpmux" ], "main": [ "#if WEBP_ABI_IS_INCOMPATIBLE(WEBP_DECODER_ABI_VERSION, 0x0203) || WEBP_ABI_IS_INCOMPATIBLE(WEBP_ENCODER_ABI_VERSION, 0x0202)", @@ -144,7 +145,7 @@ } }, "sources": [ - "-lwebp -lwebpdemux" + "-lwebp -lwebpdemux -lwebpmux" ] } }, diff --git a/src/plugins/imageformats/webp/qwebphandler.cpp b/src/plugins/imageformats/webp/qwebphandler.cpp index d56d28c..3916996 100644 --- a/src/plugins/imageformats/webp/qwebphandler.cpp +++ b/src/plugins/imageformats/webp/qwebphandler.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the WebP plugins in the Qt ImageFormats module. @@ -38,6 +38,7 @@ ****************************************************************************/ #include "qwebphandler_p.h" +#include "webp/mux.h" #include "webp/encode.h" #include #include @@ -220,13 +221,6 @@ bool QWebpHandler::read(QImage *image) return true; } -static int pictureWriter(const quint8 *data, size_t data_size, const WebPPicture *const pic) -{ - QIODevice *io = reinterpret_cast(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()) { @@ -276,8 +270,10 @@ bool QWebpHandler::write(const QImage &image) config.quality = 70; // For lossless, specifies compression effort; 70 is libwebp default } config.alpha_quality = config.quality; - picture.writer = pictureWriter; - picture.custom_ptr = device(); + WebPMemoryWriter writer; + WebPMemoryWriterInit(&writer); + picture.writer = WebPMemoryWrite; + picture.custom_ptr = &writer; if (!WebPEncode(&config, &picture)) { qWarning() << "failed to encode webp picture, error code: " << picture.error_code; @@ -285,9 +281,53 @@ bool QWebpHandler::write(const QImage &image) return false; } + bool res = false; + if (image.colorSpace().isValid()) { + int copy_data = 0; + WebPMux *mux = WebPMuxNew(); + WebPData image_data = { writer.mem, writer.size }; + WebPMuxSetImage(mux, &image_data, copy_data); + uint8_t vp8xChunk[10]; + uint8_t flags = 0x20; // Has ICCP chunk, no XMP, EXIF or animation. + if (image.hasAlphaChannel()) + flags |= 0x10; + vp8xChunk[0] = flags; + vp8xChunk[1] = 0; + vp8xChunk[2] = 0; + vp8xChunk[3] = 0; + const unsigned width = image.width() - 1; + const unsigned height = image.height() - 1; + vp8xChunk[4] = width & 0xff; + vp8xChunk[5] = (width >> 8) & 0xff; + vp8xChunk[6] = (width >> 16) & 0xff; + vp8xChunk[7] = height & 0xff; + vp8xChunk[8] = (height >> 8) & 0xff; + vp8xChunk[9] = (height >> 16) & 0xff; + WebPData vp8x_data = { vp8xChunk, 10 }; + if (WebPMuxSetChunk(mux, "VP8X", &vp8x_data, copy_data) == WEBP_MUX_OK) { + QByteArray iccProfile = image.colorSpace().iccProfile(); + WebPData iccp_data = { + reinterpret_cast(iccProfile.constData()), + static_cast(iccProfile.size()) + }; + if (WebPMuxSetChunk(mux, "ICCP", &iccp_data, copy_data) == WEBP_MUX_OK) { + WebPData output_data; + if (WebPMuxAssemble(mux, &output_data) == WEBP_MUX_OK) { + res = (output_data.size == + static_cast(device()->write(reinterpret_cast(output_data.bytes), output_data.size))); + } + WebPDataClear(&output_data); + } + } + WebPMuxDelete(mux); + } + if (!res) { + res = (writer.size == + static_cast(device()->write(reinterpret_cast(writer.mem), writer.size))); + } WebPPictureFree(&picture); - return true; + return res; } QVariant QWebpHandler::option(ImageOption option) const -- cgit v1.2.1 From 17b503073d5aeb505c15ef94f5af10d76898b1cf Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Wed, 26 Jun 2019 08:46:37 +0300 Subject: Fix Android multi ABIs compilation Change-Id: I983e2559d27ab5778f0af16f659786c0d78f4338 Reviewed-by: BogDan Vatra --- src/3rdparty/libwebp.pri | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/3rdparty/libwebp.pri b/src/3rdparty/libwebp.pri index 3e839a2..6f49549 100644 --- a/src/3rdparty/libwebp.pri +++ b/src/3rdparty/libwebp.pri @@ -123,18 +123,21 @@ integrity { QMAKE_CFLAGS += -c99 } -equals(QT_ARCH, arm)|equals(QT_ARCH, arm64) { - SOURCES_FOR_NEON += \ - $$PWD/libwebp/src/dsp/alpha_processing_neon.c \ - $$PWD/libwebp/src/dsp/dec_neon.c \ - $$PWD/libwebp/src/dsp/enc_neon.c \ - $$PWD/libwebp/src/dsp/filters_neon.c \ - $$PWD/libwebp/src/dsp/lossless_enc_neon.c \ - $$PWD/libwebp/src/dsp/lossless_neon.c \ - $$PWD/libwebp/src/dsp/rescaler_neon.c \ - $$PWD/libwebp/src/dsp/upsampling_neon.c \ - $$PWD/libwebp/src/dsp/yuv_neon.c +SOURCES_FOR_NEON += \ + $$PWD/libwebp/src/dsp/alpha_processing_neon.c \ + $$PWD/libwebp/src/dsp/dec_neon.c \ + $$PWD/libwebp/src/dsp/enc_neon.c \ + $$PWD/libwebp/src/dsp/filters_neon.c \ + $$PWD/libwebp/src/dsp/lossless_enc_neon.c \ + $$PWD/libwebp/src/dsp/lossless_neon.c \ + $$PWD/libwebp/src/dsp/rescaler_neon.c \ + $$PWD/libwebp/src/dsp/upsampling_neon.c \ + $$PWD/libwebp/src/dsp/yuv_neon.c + +android { + arm64-v8a|equals(QT_ARCH, arm64): SOURCES += $$SOURCES_FOR_NEON +} else: equals(QT_ARCH, arm)|equals(QT_ARCH, arm64) { contains(QT_CPU_FEATURES.$$QT_ARCH, neon) { # Default compiler settings include this feature, so just add to SOURCES SOURCES += $$SOURCES_FOR_NEON -- cgit v1.2.1