diff options
Diffstat (limited to 'src/gui/image')
-rw-r--r-- | src/gui/image/qimage.cpp | 4 | ||||
-rw-r--r-- | src/gui/image/qimagereader.cpp | 29 | ||||
-rw-r--r-- | src/gui/image/qmovie.cpp | 13 | ||||
-rw-r--r-- | src/gui/image/qpixmapcache.cpp | 33 | ||||
-rw-r--r-- | src/gui/image/qpnghandler.cpp | 56 |
5 files changed, 111 insertions, 24 deletions
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 61d32b0dec..cd2fe5bc10 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -5067,12 +5067,12 @@ void QImage::applyColorTransform(const QColorTransform &transform) if (depth() > 32) { for (int i = 0; i < height(); ++i) { QRgba64 *scanline = reinterpret_cast<QRgba64 *>(scanLine(i)); - transform.d_func()->apply(scanline, scanline, width(), flags); + transform.d->apply(scanline, scanline, width(), flags); } } else { for (int i = 0; i < height(); ++i) { QRgb *scanline = reinterpret_cast<QRgb *>(scanLine(i)); - transform.d_func()->apply(scanline, scanline, width(), flags); + transform.d->apply(scanline, scanline, width(), flags); } } diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp index 2762b702b2..6a0763e696 100644 --- a/src/gui/image/qimagereader.cpp +++ b/src/gui/image/qimagereader.cpp @@ -197,7 +197,7 @@ static QImageIOHandler *createReadHandlerHelper(QIODevice *device, #ifdef QIMAGEREADER_DEBUG qDebug() << "QImageReader::createReadHandler( device =" << (void *)device << ", format =" << format << ")," - << keyMap.size() << "plugins available: " << keyMap.values(); + << keyMap.uniqueKeys().size() << "plugins available: " << keyMap; #endif int suffixPluginIndex = -1; @@ -325,6 +325,29 @@ static QImageIOHandler *createReadHandlerHelper(QIODevice *device, #endif } + if (handler && device && !suffix.isEmpty()) { + Q_ASSERT(qobject_cast<QFile *>(device)); + // We have a file claiming to be of a recognized format. Now confirm that + // the handler also recognizes the file contents. + const qint64 pos = device->pos(); + handler->setDevice(device); + if (!form.isEmpty()) + handler->setFormat(form); + bool canRead = handler->canRead(); + device->seek(pos); + if (canRead) { + // ok, we're done. + return handler; + } +#ifdef QIMAGEREADER_DEBUG + qDebug() << "QImageReader::createReadHandler: the" << suffix << "handler can not read this file"; +#endif + // File may still be valid, just with wrong suffix, so fall back to + // finding a handler based on contents, below. + delete handler; + handler = nullptr; + } + #ifndef QT_NO_IMAGEFORMATPLUGIN if (!handler && (autoDetectImageFormat || ignoresFormatAndExtension)) { // check if any of our plugins recognize the file from its contents. @@ -336,7 +359,7 @@ static QImageIOHandler *createReadHandlerHelper(QIODevice *device, if (plugin && plugin->capabilities(device, QByteArray()) & QImageIOPlugin::CanRead) { handler = plugin->create(device, testFormat); #ifdef QIMAGEREADER_DEBUG - qDebug() << "QImageReader::createReadHandler: the" << keyMap.keys().at(i) << "plugin can read this data"; + qDebug() << "QImageReader::createReadHandler: the" << keyMap.value(i) << "plugin can read this data"; #endif break; } @@ -1074,7 +1097,7 @@ QList<QByteArray> QImageReader::supportedSubTypes() const \since 5.5 Returns the transformation metadata of the image, including image orientation. If the format - does not support transformation metadata \c QImageIOHandler::Transformation_None is returned. + does not support transformation metadata, QImageIOHandler::TransformationNone is returned. \sa setAutoTransform(), autoTransform() */ diff --git a/src/gui/image/qmovie.cpp b/src/gui/image/qmovie.cpp index 4b588527ae..3e975115ab 100644 --- a/src/gui/image/qmovie.cpp +++ b/src/gui/image/qmovie.cpp @@ -207,8 +207,8 @@ public: : pixmap(QPixmap()), delay(QMOVIE_INVALID_DELAY), endMark(false) { } - inline QFrameInfo(const QPixmap &pixmap, int delay) - : pixmap(pixmap), delay(delay), endMark(false) + inline QFrameInfo(QPixmap &&pixmap, int delay) + : pixmap(std::move(pixmap)), delay(delay), endMark(false) { } inline bool isValid() @@ -222,6 +222,7 @@ public: static inline QFrameInfo endMarker() { return QFrameInfo(true); } }; +Q_DECLARE_TYPEINFO(QFrameInfo, Q_MOVABLE_TYPE); class QMoviePrivate : public QObjectPrivate { @@ -380,9 +381,7 @@ QFrameInfo QMoviePrivate::infoForFrame(int frameNumber) } if (frameNumber > greatestFrameNumber) greatestFrameNumber = frameNumber; - QPixmap aPixmap = QPixmap::fromImage(std::move(anImage)); - int aDelay = reader->nextImageDelay(); - return QFrameInfo(aPixmap, aDelay); + return QFrameInfo(QPixmap::fromImage(std::move(anImage)), reader->nextImageDelay()); } else if (frameNumber != 0) { // We've read all frames now. Return an end marker haveReadAll = true; @@ -406,9 +405,7 @@ QFrameInfo QMoviePrivate::infoForFrame(int frameNumber) return QFrameInfo(); // Invalid } greatestFrameNumber = i; - QPixmap aPixmap = QPixmap::fromImage(std::move(anImage)); - int aDelay = reader->nextImageDelay(); - QFrameInfo info(aPixmap, aDelay); + QFrameInfo info(QPixmap::fromImage(std::move(anImage)), reader->nextImageDelay()); // Cache it! frameMap.insert(i, info); if (i == frameNumber) { diff --git a/src/gui/image/qpixmapcache.cpp b/src/gui/image/qpixmapcache.cpp index a41ec8f35c..483d6d79a2 100644 --- a/src/gui/image/qpixmapcache.cpp +++ b/src/gui/image/qpixmapcache.cpp @@ -42,6 +42,8 @@ #include "qobject.h" #include "qdebug.h" #include "qpixmapcache_p.h" +#include "qthread.h" +#include "qcoreapplication.h" QT_BEGIN_NAMESPACE @@ -83,6 +85,9 @@ QT_BEGIN_NAMESPACE with QPixmapCache} explains how to use QPixmapCache to speed up applications by caching the results of painting. + \note QPixmapCache is only usable from the application's main thread. + Access from other threads will be ignored and return failure. + \sa QCache, QPixmap */ @@ -98,6 +103,14 @@ static inline int cost(const QPixmap &pixmap) return static_cast<int>(qBound(1LL, costKb, costMax)); } +static inline bool qt_pixmapcache_thread_test() +{ + if (Q_LIKELY(QCoreApplication::instance() && QThread::currentThread() == QCoreApplication::instance()->thread())) + return true; + + return false; +} + /*! \class QPixmapCache::Key \brief The QPixmapCache::Key class can be used for efficient access @@ -490,6 +503,8 @@ QPixmapCacheEntry::~QPixmapCacheEntry() QPixmap *QPixmapCache::find(const QString &key) { + if (!qt_pixmapcache_thread_test()) + return nullptr; return pm_cache()->object(key); } @@ -519,6 +534,8 @@ bool QPixmapCache::find(const QString &key, QPixmap &pixmap) bool QPixmapCache::find(const QString &key, QPixmap *pixmap) { + if (!qt_pixmapcache_thread_test()) + return false; QPixmap *ptr = pm_cache()->object(key); if (ptr && pixmap) *pixmap = *ptr; @@ -536,6 +553,8 @@ bool QPixmapCache::find(const QString &key, QPixmap *pixmap) */ bool QPixmapCache::find(const Key &key, QPixmap *pixmap) { + if (!qt_pixmapcache_thread_test()) + return false; //The key is not valid anymore, a flush happened before probably if (!key.d || !key.d->isValid) return false; @@ -567,6 +586,8 @@ bool QPixmapCache::find(const Key &key, QPixmap *pixmap) bool QPixmapCache::insert(const QString &key, const QPixmap &pixmap) { + if (!qt_pixmapcache_thread_test()) + return false; return pm_cache()->insert(key, pixmap, cost(pixmap)); } @@ -587,6 +608,8 @@ bool QPixmapCache::insert(const QString &key, const QPixmap &pixmap) */ QPixmapCache::Key QPixmapCache::insert(const QPixmap &pixmap) { + if (!qt_pixmapcache_thread_test()) + return QPixmapCache::Key(); return pm_cache()->insert(pixmap, cost(pixmap)); } @@ -601,6 +624,8 @@ QPixmapCache::Key QPixmapCache::insert(const QPixmap &pixmap) */ bool QPixmapCache::replace(const Key &key, const QPixmap &pixmap) { + if (!qt_pixmapcache_thread_test()) + return false; //The key is not valid anymore, a flush happened before probably if (!key.d || !key.d->isValid) return false; @@ -630,6 +655,8 @@ int QPixmapCache::cacheLimit() void QPixmapCache::setCacheLimit(int n) { + if (!qt_pixmapcache_thread_test()) + return; pm_cache()->setMaxCost(n); } @@ -638,6 +665,8 @@ void QPixmapCache::setCacheLimit(int n) */ void QPixmapCache::remove(const QString &key) { + if (!qt_pixmapcache_thread_test()) + return; pm_cache()->remove(key); } @@ -649,6 +678,8 @@ void QPixmapCache::remove(const QString &key) */ void QPixmapCache::remove(const Key &key) { + if (!qt_pixmapcache_thread_test()) + return; //The key is not valid anymore, a flush happened before probably if (!key.d || !key.d->isValid) return; @@ -661,6 +692,8 @@ void QPixmapCache::remove(const Key &key) void QPixmapCache::clear() { + if (!QCoreApplication::closingDown() && !qt_pixmapcache_thread_test()) + return; QT_TRY { if (pm_cache.exists()) pm_cache->clear(); diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp index 864a944fcb..16d6c25b8b 100644 --- a/src/gui/image/qpnghandler.cpp +++ b/src/gui/image/qpnghandler.cpp @@ -53,7 +53,6 @@ #include <qcolorspace.h> #include <private/qcolorspace_p.h> -#include <private/qicc_p.h> #include <png.h> #include <pngconf.h> @@ -607,9 +606,13 @@ bool QPngHandlerPrivate::readPngHeader() #endif png_uint_32 profLen; png_get_iCCP(png_ptr, info_ptr, &name, &compressionType, &profileData, &profLen); - if (!QIcc::fromIccProfile(QByteArray::fromRawData((const char *)profileData, profLen), &colorSpace)) { + colorSpace = QColorSpace::fromIccProfile(QByteArray::fromRawData((const char *)profileData, profLen)); + if (!colorSpace.isValid()) { qWarning() << "QPngHandler: Failed to parse ICC profile"; } else { + QColorSpacePrivate *csD = QColorSpacePrivate::getWritable(colorSpace); + if (csD->description.isEmpty()) + csD->description = QString::fromLatin1((const char *)name); colorSpaceState = Icc; } } @@ -628,11 +631,25 @@ bool QPngHandlerPrivate::readPngHeader() png_get_gAMA(png_ptr, info_ptr, &file_gamma); fileGamma = file_gamma; if (fileGamma > 0.0f && colorSpaceState <= GammaChrm) { - QColorSpacePrivate *csPrivate = colorSpace.d_func(); - csPrivate->gamut = QColorSpace::Gamut::SRgb; - csPrivate->transferFunction = QColorSpace::TransferFunction::Gamma; - csPrivate->gamma = fileGamma; - csPrivate->initialize(); + QColorSpacePrimaries primaries; + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_cHRM)) { + double white_x, white_y, red_x, red_y; + double green_x, green_y, blue_x, blue_y; + png_get_cHRM(png_ptr, info_ptr, + &white_x, &white_y, &red_x, &red_y, + &green_x, &green_y, &blue_x, &blue_y); + primaries.whitePoint = QPointF(white_x, white_y); + primaries.redPoint = QPointF(red_x, red_y); + primaries.greenPoint = QPointF(green_x, green_y); + primaries.bluePoint = QPointF(blue_x, blue_y); + } + if (primaries.areValid()) { + colorSpace = QColorSpace(primaries.whitePoint, primaries.redPoint, primaries.greenPoint, primaries.bluePoint, + QColorSpace::TransferFunction::Gamma, fileGamma); + } else { + colorSpace = QColorSpace(QColorSpace::Primaries::SRgb, + QColorSpace::TransferFunction::Gamma, fileGamma); + } colorSpaceState = GammaChrm; } } @@ -663,10 +680,7 @@ bool QPngHandlerPrivate::readPngImage(QImage *outImage) // This configuration forces gamma correction and // thus changes the output colorspace png_set_gamma(png_ptr, 1.0f / gamma, fileGamma); - QColorSpacePrivate *csPrivate = colorSpace.d_func(); - csPrivate->transferFunction = QColorSpace::TransferFunction::Gamma; - csPrivate->gamma = gamma; - csPrivate->initialize(); + colorSpace = colorSpace.withTransferFunction(QColorSpace::TransferFunction::Gamma, 1.0f / gamma); colorSpaceState = GammaChrm; } @@ -962,6 +976,26 @@ bool QPNGImageWriter::writeImage(const QImage& image, volatile int compression_i bpc, // per channel color_type, 0, 0, 0); // sets #channels +#ifdef PNG_iCCP_SUPPORTED + if (image.colorSpace().isValid()) { + QColorSpace cs = image.colorSpace(); + // Support the old gamma making it override transferfunction. + if (gamma != 0.0 && !qFuzzyCompare(cs.gamma(), 1.0f / gamma)) + cs = cs.withTransferFunction(QColorSpace::TransferFunction::Gamma, 1.0f / gamma); + QByteArray iccProfileName = QColorSpacePrivate::get(cs)->description.toLatin1(); + if (iccProfileName.isEmpty()) + iccProfileName = QByteArrayLiteral("Custom"); + QByteArray iccProfile = cs.iccProfile(); + png_set_iCCP(png_ptr, info_ptr, + #if PNG_LIBPNG_VER < 10500 + iccProfileName.data(), PNG_COMPRESSION_TYPE_BASE, iccProfile.data(), + #else + iccProfileName.constData(), PNG_COMPRESSION_TYPE_BASE, + (png_const_bytep)iccProfile.constData(), + #endif + iccProfile.length()); + } else +#endif if (gamma != 0.0) { png_set_gAMA(png_ptr, info_ptr, 1.0/gamma); } |