diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/3rdparty/libwebp.pri | 25 | ||||
-rw-r--r-- | src/imageformats/configure.json | 7 | ||||
-rw-r--r-- | src/plugins/imageformats/tiff/qtiffhandler.cpp | 19 | ||||
-rw-r--r-- | src/plugins/imageformats/webp/qwebphandler.cpp | 81 | ||||
-rw-r--r-- | src/plugins/imageformats/webp/qwebphandler_p.h | 3 |
5 files changed, 109 insertions, 26 deletions
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 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/tiff/qtiffhandler.cpp b/src/plugins/imageformats/tiff/qtiffhandler.cpp index 9f1c090..57def2c 100644 --- a/src/plugins/imageformats/tiff/qtiffhandler.cpp +++ b/src/plugins/imageformats/tiff/qtiffhandler.cpp @@ -39,6 +39,7 @@ #include "qtiffhandler_p.h" #include <qvariant.h> +#include <qcolorspace.h> #include <qdebug.h> #include <qimage.h> #include <qglobal.h> @@ -487,6 +488,15 @@ bool QTiffHandler::read(QImage *image) } } + uint32 count; + void *profile; + if (TIFFGetField(tiff, TIFFTAG_ICCPROFILE, &count, &profile)) { + QByteArray iccProfile(reinterpret_cast<const char *>(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<const void *>(iccProfile.constData()))) { + TIFFClose(tiff); + return false; + } + } // configure image depth const QImage::Format format = image.format(); if (format == QImage::Format_Mono || format == QImage::Format_MonoLSB) { diff --git a/src/plugins/imageformats/webp/qwebphandler.cpp b/src/plugins/imageformats/webp/qwebphandler.cpp index 4d6bcbe..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 <qcolor.h> #include <qimage.h> @@ -51,6 +52,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 +153,7 @@ bool QWebpHandler::ensureDemuxer() if (m_demuxer == NULL) return false; + m_formatFlags = WebPDemuxGetI(m_demuxer, WEBP_FF_FORMAT_FLAGS); return true; } @@ -160,6 +163,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<const char *>(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,23 +216,21 @@ bool QWebpHandler::read(QImage *image) *image = *m_composited; } + image->setColorSpace(m_colorSpace); 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; } + 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(); @@ -257,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; @@ -266,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<const uint8_t *>(iccProfile.constData()), + static_cast<size_t>(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<size_t>(device()->write(reinterpret_cast<const char *>(output_data.bytes), output_data.size))); + } + WebPDataClear(&output_data); + } + } + WebPMuxDelete(mux); + } + if (!res) { + res = (writer.size == + static_cast<size_t>(device()->write(reinterpret_cast<const char *>(writer.mem), writer.size))); + } WebPPictureFree(&picture); - return true; + return res; } QVariant QWebpHandler::option(ImageOption option) const 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 <QtGui/qcolor.h> +#include <QtGui/qcolorspace.h> #include <QtGui/qimage.h> #include <QtGui/qimageiohandler.h> #include <QtCore/qbytearray.h> @@ -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 }; |