diff options
Diffstat (limited to 'src/gui/image')
28 files changed, 792 insertions, 332 deletions
diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp index 21c1a2f813..bf3563932d 100644 --- a/src/gui/image/qbmphandler.cpp +++ b/src/gui/image/qbmphandler.cpp @@ -791,6 +791,10 @@ bool QBmpHandler::write(const QImage &img) case QImage::Format_ARGB32: image = img; break; + case QImage::Format_Alpha8: + case QImage::Format_Grayscale8: + image = img.convertToFormat(QImage::Format_Indexed8); + break; default: if (img.hasAlphaChannel()) image = img.convertToFormat(QImage::Format_ARGB32); diff --git a/src/gui/image/qgifhandler_p.h b/src/gui/image/qgifhandler_p.h index 40bff19e7a..08910bf111 100644 --- a/src/gui/image/qgifhandler_p.h +++ b/src/gui/image/qgifhandler_p.h @@ -63,22 +63,22 @@ public: QGifHandler(); ~QGifHandler(); - bool canRead() const; - bool read(QImage *image); - bool write(const QImage &image); + bool canRead() const Q_DECL_OVERRIDE; + bool read(QImage *image) Q_DECL_OVERRIDE; + bool write(const QImage &image) Q_DECL_OVERRIDE; - QByteArray name() const; + QByteArray name() const Q_DECL_OVERRIDE; static bool canRead(QIODevice *device); - QVariant option(ImageOption option) const; - void setOption(ImageOption option, const QVariant &value); - bool supportsOption(ImageOption option) const; + QVariant option(ImageOption option) const Q_DECL_OVERRIDE; + void setOption(ImageOption option, const QVariant &value) Q_DECL_OVERRIDE; + bool supportsOption(ImageOption option) const Q_DECL_OVERRIDE; - int imageCount() const; - int loopCount() const; - int nextImageDelay() const; - int currentImageNumber() const; + int imageCount() const Q_DECL_OVERRIDE; + int loopCount() const Q_DECL_OVERRIDE; + int nextImageDelay() const Q_DECL_OVERRIDE; + int currentImageNumber() const Q_DECL_OVERRIDE; private: bool imageIsComing() const; diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp index 86d9c02c6e..3e27ba3efa 100644 --- a/src/gui/image/qicon.cpp +++ b/src/gui/image/qicon.cpp @@ -46,7 +46,7 @@ #include "qdebug.h" #include "qpalette.h" -#ifdef Q_WS_MAC +#ifdef Q_DEAD_CODE_FROM_QT4_MAC #include <private/qt_mac_p.h> #include <private/qt_cocoa_helpers_mac_p.h> #endif @@ -1024,7 +1024,7 @@ void QIcon::addFile(const QString &fileName, const QSize &size, Mode mode, State d->engine->addFile(fileName, size, mode, state); // Check if a "@2x" file exists and add it. - static bool disable2xImageLoading = !qgetenv("QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING").isEmpty(); + static bool disable2xImageLoading = !qEnvironmentVariableIsEmpty("QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING"); if (!disable2xImageLoading && qApp->devicePixelRatio() > 1.0) { QString at2xfileName = fileName; int dotIndex = fileName.lastIndexOf(QLatin1Char('.')); @@ -1197,7 +1197,7 @@ bool QIcon::hasThemeIcon(const QString &name) { QIcon icon = fromTheme(name); - return !icon.isNull(); + return icon.name() == name; } diff --git a/src/gui/image/qicon_p.h b/src/gui/image/qicon_p.h index 4896aa89c0..e5ae8ec431 100644 --- a/src/gui/image/qicon_p.h +++ b/src/gui/image/qicon_p.h @@ -104,18 +104,18 @@ public: QPixmapIconEngine(); QPixmapIconEngine(const QPixmapIconEngine &); ~QPixmapIconEngine(); - void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state); - QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state); + void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE; + QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE; QPixmapIconEngineEntry *bestMatch(const QSize &size, QIcon::Mode mode, QIcon::State state, bool sizeOnly); - QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state); - void addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state); - void addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state); - - QString key() const; - QIconEngine *clone() const; - bool read(QDataStream &in); - bool write(QDataStream &out) const; - void virtual_hook(int id, void *data); + QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE; + void addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE; + void addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE; + + QString key() const Q_DECL_OVERRIDE; + QIconEngine *clone() const Q_DECL_OVERRIDE; + bool read(QDataStream &in) Q_DECL_OVERRIDE; + bool write(QDataStream &out) const Q_DECL_OVERRIDE; + void virtual_hook(int id, void *data) Q_DECL_OVERRIDE; private: QPixmapIconEngineEntry *tryMatch(const QSize &size, QIcon::Mode mode, QIcon::State state); diff --git a/src/gui/image/qiconloader.cpp b/src/gui/image/qiconloader.cpp index 06491f1155..c7a08a7938 100644 --- a/src/gui/image/qiconloader.cpp +++ b/src/gui/image/qiconloader.cpp @@ -47,7 +47,7 @@ #include <QtCore/QSettings> #include <QtGui/QPainter> -#ifdef Q_WS_MAC +#ifdef Q_DEAD_CODE_FROM_QT4_MAC #include <private/qt_cocoa_helpers_mac_p.h> #endif @@ -172,11 +172,15 @@ QIconTheme::QIconTheme(const QString &themeName) for ( int i = 0 ; i < iconDirs.size() ; ++i) { QDir iconDir(iconDirs[i]); QString themeDir = iconDir.path() + QLatin1Char('/') + themeName; - themeIndex.setFileName(themeDir + QLatin1String("/index.theme")); - if (themeIndex.exists()) { - m_contentDir = themeDir; - m_valid = true; - break; + QFileInfo themeDirInfo(themeDir); + + if (themeDirInfo.isDir()) + m_contentDirs << themeDir; + + if (!m_valid) { + themeIndex.setFileName(themeDir + QLatin1String("/index.theme")); + if (themeIndex.exists()) + m_valid = true; } } #ifndef QT_NO_SETTINGS @@ -239,11 +243,11 @@ QIconTheme::QIconTheme(const QString &themeName) #endif //QT_NO_SETTINGS } -QThemeIconEntries QIconLoader::findIconHelper(const QString &themeName, - const QString &iconName, - QStringList &visited) const +QThemeIconInfo QIconLoader::findIconHelper(const QString &themeName, + const QString &iconName, + QStringList &visited) const { - QThemeIconEntries entries; + QThemeIconInfo info; Q_ASSERT(!themeName.isEmpty()); QPixmap pixmap; @@ -260,34 +264,54 @@ QThemeIconEntries QIconLoader::findIconHelper(const QString &themeName, themeList.insert(themeName, theme); } - QString contentDir = theme.contentDir() + QLatin1Char('/'); + const QStringList contentDirs = theme.contentDirs(); const QVector<QIconDirInfo> subDirs = theme.keyList(); - const QString svgext(QLatin1String(".svg")); - const QString pngext(QLatin1String(".png")); - - // Add all relevant files - for (int i = 0; i < subDirs.size() ; ++i) { - const QIconDirInfo &dirInfo = subDirs.at(i); - QString subdir = dirInfo.path; - QDir currentDir(contentDir + subdir); - if (currentDir.exists(iconName + pngext)) { - PixmapEntry *iconEntry = new PixmapEntry; - iconEntry->dir = dirInfo; - iconEntry->filename = currentDir.filePath(iconName + pngext); - // Notice we ensure that pixmap entries always come before - // scalable to preserve search order afterwards - entries.prepend(iconEntry); - } else if (m_supportsSvg && - currentDir.exists(iconName + svgext)) { - ScalableEntry *iconEntry = new ScalableEntry; - iconEntry->dir = dirInfo; - iconEntry->filename = currentDir.filePath(iconName + svgext); - entries.append(iconEntry); + QString iconNameFallback = iconName; + + // Iterate through all icon's fallbacks in current theme + while (info.entries.isEmpty()) { + const QString svgIconName = iconNameFallback + QLatin1String(".svg"); + const QString pngIconName = iconNameFallback + QLatin1String(".png"); + + // Add all relevant files + for (int i = 0; i < contentDirs.size(); ++i) { + QString contentDir = contentDirs.at(i) + QLatin1Char('/'); + for (int j = 0; j < subDirs.size() ; ++j) { + const QIconDirInfo &dirInfo = subDirs.at(j); + QString subdir = dirInfo.path; + QDir currentDir(contentDir + subdir); + if (currentDir.exists(pngIconName)) { + PixmapEntry *iconEntry = new PixmapEntry; + iconEntry->dir = dirInfo; + iconEntry->filename = currentDir.filePath(pngIconName); + // Notice we ensure that pixmap entries always come before + // scalable to preserve search order afterwards + info.entries.prepend(iconEntry); + } else if (m_supportsSvg && + currentDir.exists(svgIconName)) { + ScalableEntry *iconEntry = new ScalableEntry; + iconEntry->dir = dirInfo; + iconEntry->filename = currentDir.filePath(svgIconName); + info.entries.append(iconEntry); + } + } + } + + if (!info.entries.isEmpty()) { + info.iconName = iconNameFallback; + break; } + + // If it's possible - find next fallback for the icon + const int indexOfDash = iconNameFallback.lastIndexOf(QLatin1Char('-')); + if (indexOfDash == -1) + break; + + iconNameFallback.truncate(indexOfDash); } - if (entries.isEmpty()) { + if (info.entries.isEmpty()) { const QStringList parents = theme.parents(); // Search recursively through inherited themes for (int i = 0 ; i < parents.size() ; ++i) { @@ -295,23 +319,23 @@ QThemeIconEntries QIconLoader::findIconHelper(const QString &themeName, const QString parentTheme = parents.at(i).trimmed(); if (!visited.contains(parentTheme)) // guard against recursion - entries = findIconHelper(parentTheme, iconName, visited); + info = findIconHelper(parentTheme, iconName, visited); - if (!entries.isEmpty()) // success + if (!info.entries.isEmpty()) // success break; } } - return entries; + return info; } -QThemeIconEntries QIconLoader::loadIcon(const QString &name) const +QThemeIconInfo QIconLoader::loadIcon(const QString &name) const { if (!themeName().isEmpty()) { QStringList visited; return findIconHelper(themeName(), name, visited); } - return QThemeIconEntries(); + return QThemeIconInfo(); } @@ -325,7 +349,7 @@ QIconLoaderEngine::QIconLoaderEngine(const QString& iconName) QIconLoaderEngine::~QIconLoaderEngine() { - qDeleteAll(m_entries); + qDeleteAll(m_info.entries); } QIconLoaderEngine::QIconLoaderEngine(const QIconLoaderEngine &other) @@ -353,17 +377,19 @@ bool QIconLoaderEngine::write(QDataStream &out) const bool QIconLoaderEngine::hasIcon() const { - return !(m_entries.isEmpty()); + return !(m_info.entries.isEmpty()); } // Lazily load the icon void QIconLoaderEngine::ensureLoaded() { if (!(QIconLoader::instance()->themeKey() == m_key)) { + qDeleteAll(m_info.entries); + m_info.entries.clear(); + m_info.iconName.clear(); - qDeleteAll(m_entries); - - m_entries = QIconLoader::instance()->loadIcon(m_iconName); + Q_ASSERT(m_info.entries.size() == 0); + m_info = QIconLoader::instance()->loadIcon(m_iconName); m_key = QIconLoader::instance()->themeKey(); } } @@ -372,7 +398,7 @@ void QIconLoaderEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) { QSize pixmapSize = rect.size(); -#if defined(Q_WS_MAC) +#if defined(Q_DEAD_CODE_FROM_QT4_MAC) pixmapSize *= qt_mac_get_scalefactor(); #endif painter->drawPixmap(rect, pixmap(pixmapSize, mode, state)); @@ -433,14 +459,14 @@ QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QSize &size) { int iconsize = qMin(size.width(), size.height()); - // Note that m_entries are sorted so that png-files + // Note that m_info.entries are sorted so that png-files // come first - const int numEntries = m_entries.size(); + const int numEntries = m_info.entries.size(); // Search for exact matches first for (int i = 0; i < numEntries; ++i) { - QIconLoaderEngineEntry *entry = m_entries.at(i); + QIconLoaderEngineEntry *entry = m_info.entries.at(i); if (directoryMatchesSize(entry->dir, iconsize)) { return entry; } @@ -450,7 +476,7 @@ QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QSize &size) int minimalSize = INT_MAX; QIconLoaderEngineEntry *closestMatch = 0; for (int i = 0; i < numEntries; ++i) { - QIconLoaderEngineEntry *entry = m_entries.at(i); + QIconLoaderEngineEntry *entry = m_info.entries.at(i); int distance = directorySizeDistance(entry->dir, iconsize); if (distance < minimalSize) { minimalSize = distance; @@ -554,13 +580,13 @@ void QIconLoaderEngine::virtual_hook(int id, void *data) { QIconEngine::AvailableSizesArgument &arg = *reinterpret_cast<QIconEngine::AvailableSizesArgument*>(data); - const int N = m_entries.size(); + const int N = m_info.entries.size(); QList<QSize> sizes; sizes.reserve(N); // Gets all sizes from the DirectoryInfo entries for (int i = 0; i < N; ++i) { - int size = m_entries.at(i)->dir.size; + int size = m_info.entries.at(i)->dir.size; sizes.append(QSize(size, size)); } arg.sizes.swap(sizes); // commit @@ -569,7 +595,7 @@ void QIconLoaderEngine::virtual_hook(int id, void *data) case QIconEngine::IconNameHook: { QString &name = *reinterpret_cast<QString*>(data); - name = m_iconName; + name = m_info.iconName; } break; default: diff --git a/src/gui/image/qiconloader_p.h b/src/gui/image/qiconloader_p.h index 50a6e6d3a7..8ee730f307 100644 --- a/src/gui/image/qiconloader_p.h +++ b/src/gui/image/qiconloader_p.h @@ -106,6 +106,12 @@ struct PixmapEntry : public QIconLoaderEngineEntry typedef QList<QIconLoaderEngineEntry*> QThemeIconEntries; +struct QThemeIconInfo +{ + QThemeIconEntries entries; + QString iconName; +}; + class QIconLoaderEngine : public QIconEngine { public: @@ -126,7 +132,7 @@ private: void virtual_hook(int id, void *data); QIconLoaderEngineEntry *entryForSize(const QSize &size); QIconLoaderEngine(const QIconLoaderEngine &other); - QThemeIconEntries m_entries; + QThemeIconInfo m_info; QString m_iconName; uint m_key; @@ -140,11 +146,11 @@ public: QIconTheme() : m_valid(false) {} QStringList parents() { return m_parents; } QVector<QIconDirInfo> keyList() { return m_keyList; } - QString contentDir() { return m_contentDir; } + QStringList contentDirs() { return m_contentDirs; } bool isValid() { return m_valid; } private: - QString m_contentDir; + QStringList m_contentDirs; QVector<QIconDirInfo> m_keyList; QStringList m_parents; bool m_valid; @@ -154,7 +160,7 @@ class Q_GUI_EXPORT QIconLoader { public: QIconLoader(); - QThemeIconEntries loadIcon(const QString &iconName) const; + QThemeIconInfo loadIcon(const QString &iconName) const; uint themeKey() const { return m_themeKey; } QString themeName() const { return m_userTheme.isEmpty() ? m_systemTheme : m_userTheme; } @@ -169,9 +175,9 @@ public: void ensureInitialized(); private: - QThemeIconEntries findIconHelper(const QString &themeName, - const QString &iconName, - QStringList &visited) const; + QThemeIconInfo findIconHelper(const QString &themeName, + const QString &iconName, + QStringList &visited) const; uint m_themeKey; bool m_supportsSvg; bool m_initialized; diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 887a7c29eb..ade30b9d77 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -47,7 +47,6 @@ #include <ctype.h> #include <stdlib.h> #include <limits.h> -#include <math.h> #include <qpa/qplatformpixmap.h> #include <private/qdrawhelper_p.h> #include <private/qmemrotate_p.h> @@ -653,7 +652,8 @@ bool QImageData::checkForAlphaPixels() const The following image formats are available in Qt. Values from Format_ARGB8565_Premultiplied to Format_ARGB4444_Premultiplied were added in Qt 4.4. Values Format_RGBX8888, Format_RGBA8888 and Format_RGBA8888_Premultiplied were added in Qt 5.2. Values Format_BGR30, Format_A2BGR30_Premultiplied, - Format_RGB30, Format_A2RGB30_Premultiplied were added in Qt 5.4. + Format_RGB30, Format_A2RGB30_Premultiplied were added in Qt 5.4. Format_Alpha8 and Format_Grayscale8 + were added in Qt 5.5. See the notes after the table. \value Format_Invalid The image is invalid. @@ -709,6 +709,8 @@ bool QImageData::checkForAlphaPixels() const \value Format_A2BGR30_Premultiplied The image is stored using a 32-bit premultiplied ABGR format (2-10-10-10). \value Format_RGB30 The image is stored using a 32-bit RGB format (x-10-10-10). \value Format_A2RGB30_Premultiplied The image is stored using a 32-bit premultiplied ARGB format (2-10-10-10). + \value Format_Alpha8 The image is stored using an 8-bit alpha only format. + \value Format_Grayscale8 The image is stored using an 8-bit grayscale format. \note Drawing into a QImage with QImage::Format_Indexed8 is not supported. @@ -2352,6 +2354,10 @@ bool QImage::allGray() const return false; } return true; + case Format_Alpha8: + return false; + case Format_Grayscale8: + return true; case Format_RGB32: case Format_ARGB32: case Format_ARGB32_Premultiplied: @@ -2405,9 +2411,9 @@ bool QImage::allGray() const /*! For 32-bit images, this function is equivalent to allGray(). - For 8-bpp images, this function returns \c true if color(i) is - QRgb(i, i, i) for all indexes of the color table; otherwise - returns \c false. + For color indexed images, this function returns \c true if + color(i) is QRgb(i, i, i) for all indexes of the color table; + otherwise returns \c false. \sa allGray(), {QImage#Image Formats}{Image Formats} */ @@ -2416,12 +2422,19 @@ bool QImage::isGrayscale() const if (!d) return false; + if (d->format == QImage::Format_Alpha8) + return false; + + if (d->format == QImage::Format_Grayscale8) + return true; + switch (depth()) { case 32: case 24: case 16: return allGray(); case 8: { + Q_ASSERT(d->format == QImage::Format_Indexed8); for (int i = 0; i < colorCount(); i++) if (d->colortable.at(i) != qRgb(i,i,i)) return false; @@ -2998,6 +3011,9 @@ QImage QImage::rgbSwapped_helper() const case NImageFormats: Q_ASSERT(false); break; + case Format_Alpha8: + case Format_Grayscale8: + return *this; case Format_Mono: case Format_MonoLSB: case Format_Indexed8: @@ -3084,6 +3100,9 @@ void QImage::rgbSwapped_inplace() case NImageFormats: Q_ASSERT(false); break; + case Format_Alpha8: + case Format_Grayscale8: + return; case Format_Mono: case Format_MonoLSB: case Format_Indexed8: @@ -4017,7 +4036,7 @@ void QImage::setAlphaChannel(const QImage &alphaChannel) return; // Slight optimization since alphachannels are returned as 8-bit grays. - if (alphaChannel.d->depth == 8 && alphaChannel.isGrayscale()) { + if (alphaChannel.format() == QImage::Format_Alpha8 ||( alphaChannel.d->depth == 8 && alphaChannel.isGrayscale())) { const uchar *src_data = alphaChannel.d->data; const uchar *dest_data = d->data; for (int y=0; y<h; ++y) { @@ -4075,9 +4094,13 @@ void QImage::setAlphaChannel(const QImage &alphaChannel) Most usecases for this function can be replaced with QPainter and using composition modes. + Note this returns a color-indexed image if you want the alpha channel in + the alpha8 format instead use convertToFormat(Format_Alpha8) on the source + image. + \warning This is an expensive function. - \sa setAlphaChannel(), hasAlphaChannel(), + \sa setAlphaChannel(), hasAlphaChannel(), convertToFormat(), {QPixmap#Pixmap Information}{Pixmap}, {QImage#Image Transformations}{Image Transformations} */ @@ -4087,6 +4110,9 @@ QImage QImage::alphaChannel() const if (!d) return QImage(); + if (d->format == QImage::Format_Alpha8) + return *this; + int w = d->width; int h = d->height; @@ -4264,6 +4290,8 @@ static QImage rotated90(const QImage &image) { reinterpret_cast<quint16*>(out.bits()), out.bytesPerLine()); break; + case QImage::Format_Alpha8: + case QImage::Format_Grayscale8: case QImage::Format_Indexed8: qt_memrotate270(reinterpret_cast<const quint8*>(image.bits()), w, h, image.bytesPerLine(), @@ -4330,6 +4358,8 @@ static QImage rotated270(const QImage &image) { reinterpret_cast<quint16*>(out.bits()), out.bytesPerLine()); break; + case QImage::Format_Alpha8: + case QImage::Format_Grayscale8: case QImage::Format_Indexed8: qt_memrotate90(reinterpret_cast<const quint8*>(image.bits()), w, h, image.bytesPerLine(), @@ -4481,24 +4511,17 @@ QImage QImage::transformed(const QTransform &matrix, Qt::TransformationMode mode dImage.d->dpmx = dotsPerMeterX(); dImage.d->dpmy = dotsPerMeterY(); - switch (bpp) { - // initizialize the data - case 8: - if (dImage.d->colortable.size() < 256) { - // colors are left in the color table, so pick that one as transparent - dImage.d->colortable.append(0x0); - memset(dImage.bits(), dImage.d->colortable.size() - 1, dImage.byteCount()); - } else { - memset(dImage.bits(), 0, dImage.byteCount()); - } - break; - case 1: - case 16: - case 24: - case 32: - memset(dImage.bits(), 0x00, dImage.byteCount()); - break; - } + // initizialize the data + if (d->format == QImage::Format_Indexed8) { + if (dImage.d->colortable.size() < 256) { + // colors are left in the color table, so pick that one as transparent + dImage.d->colortable.append(0x0); + memset(dImage.bits(), dImage.d->colortable.size() - 1, dImage.byteCount()); + } else { + memset(dImage.bits(), 0, dImage.byteCount()); + } + } else + memset(dImage.bits(), 0x00, dImage.byteCount()); if (target_format >= QImage::Format_RGB32) { // Prevent QPainter from applying devicePixelRatio corrections @@ -4942,6 +4965,32 @@ static Q_CONSTEXPR QPixelFormat pixelformats[] = { /*PREMULTIPLIED*/ QPixelFormat::Premultiplied, /*INTERPRETATION*/ QPixelFormat::UnsignedInteger, /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian), + //QImage::Format_Alpha8: + QPixelFormat(QPixelFormat::Alpha, + /*First*/ 0, + /*SECOND*/ 0, + /*THIRD*/ 0, + /*FOURTH*/ 0, + /*FIFTH*/ 0, + /*ALPHA*/ 8, + /*ALPHA USAGE*/ QPixelFormat::UsesAlpha, + /*ALPHA POSITION*/ QPixelFormat::AtBeginning, + /*PREMULTIPLIED*/ QPixelFormat::Premultiplied, + /*INTERPRETATION*/ QPixelFormat::UnsignedByte, + /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian), + //QImage::Format_Grayscale8: + QPixelFormat(QPixelFormat::Grayscale, + /*GRAY*/ 8, + /*SECOND*/ 0, + /*THIRD*/ 0, + /*FOURTH*/ 0, + /*FIFTH*/ 0, + /*ALPHA*/ 0, + /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha, + /*ALPHA POSITION*/ QPixelFormat::AtBeginning, + /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied, + /*INTERPRETATION*/ QPixelFormat::UnsignedByte, + /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian), }; Q_STATIC_ASSERT(sizeof(pixelformats) / sizeof(*pixelformats) == QImage::NImageFormats); diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h index 55b8690c77..8984af12d1 100644 --- a/src/gui/image/qimage.h +++ b/src/gui/image/qimage.h @@ -106,20 +106,16 @@ public: Format_RGBX8888, Format_RGBA8888, Format_RGBA8888_Premultiplied, -#if 0 - // reserved for future use - Format_RGB15, - Format_Grayscale16, - Format_Grayscale8, - Format_Grayscale4, - Format_Grayscale4LSB, - Format_Grayscale2, - Format_Grayscale2LSB -#endif Format_BGR30, Format_A2BGR30_Premultiplied, Format_RGB30, Format_A2RGB30_Premultiplied, + Format_Alpha8, + Format_Grayscale8, +#if 0 + // reserved for future use + Format_Grayscale16, +#endif #ifndef Q_QDOC NImageFormats #endif @@ -155,7 +151,7 @@ public: bool isNull() const; - int devType() const; + int devType() const Q_DECL_OVERRIDE; bool operator==(const QImage &) const; bool operator!=(const QImage &) const; @@ -288,7 +284,7 @@ public: #endif qint64 cacheKey() const; - QPaintEngine *paintEngine() const; + QPaintEngine *paintEngine() const Q_DECL_OVERRIDE; // Auxiliary data int dotsPerMeterX() const; @@ -321,7 +317,7 @@ public: #endif protected: - virtual int metric(PaintDeviceMetric metric) const; + virtual int metric(PaintDeviceMetric metric) const Q_DECL_OVERRIDE; QImage mirrored_helper(bool horizontal, bool vertical) const; QImage rgbSwapped_helper() const; void mirrored_inplace(bool horizontal, bool vertical); @@ -353,13 +349,9 @@ inline void QImage::setPixel(const QPoint &pt, uint index_or_rgb) { setPixel(pt. #if QT_DEPRECATED_SINCE(5, 0) -#if defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 406) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#elif defined(Q_CC_MSVC) -# pragma warning(push) -# pragma warning(disable: 4996) -#endif +QT_WARNING_PUSH +QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations") +QT_WARNING_DISABLE_MSVC(4996) inline QString QImage::text(const char* key, const char* lang) const { @@ -431,11 +423,7 @@ inline void QImage::setText(const char* key, const char* lang, const QString &s) setText(k, s); } -#if defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 406) -# pragma GCC diagnostic pop -#elif defined(Q_CC_MSVC) -# pragma warning(pop) -#endif +QT_WARNING_POP inline int QImage::numColors() const { diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index b2681f4261..0a4bf47c82 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -195,7 +195,7 @@ static bool convert_passthrough_inplace(QImageData *data, Qt::ImageConversionFla return true; } -static void convert_ARGB_to_ARGB_PM(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +static inline void convert_ARGB_to_ARGB_PM(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { Q_ASSERT(src->format == QImage::Format_ARGB32 || src->format == QImage::Format_RGBA8888); Q_ASSERT(dest->format == QImage::Format_ARGB32_Premultiplied || dest->format == QImage::Format_RGBA8888_Premultiplied); @@ -219,6 +219,15 @@ static void convert_ARGB_to_ARGB_PM(QImageData *dest, const QImageData *src, Qt: } } +#if QT_COMPILER_SUPPORTS_HERE(SSE4_1) && !defined(__SSE4_1__) +QT_FUNCTION_TARGET(SSE4_1) +static void convert_ARGB_to_ARGB_PM_sse4(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags flags) +{ + // Twice as fast autovectorized due to SSE4.1 PMULLD instructions. + convert_ARGB_to_ARGB_PM(dest, src, flags); +} +#endif + extern bool convert_ARGB_to_ARGB_PM_inplace_sse2(QImageData *data, Qt::ImageConversionFlags); #ifndef __SSE2__ @@ -232,7 +241,7 @@ static bool convert_ARGB_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConversio for (int i = 0; i < data->height; ++i) { const QRgb *end = rgb_data + data->width; while (rgb_data < end) { - *rgb_data = PREMUL(*rgb_data); + *rgb_data = qPremultiply(*rgb_data); ++rgb_data; } rgb_data += pad; @@ -312,7 +321,7 @@ static bool convert_ARGB_to_RGBA_inplace(QImageData *data, Qt::ImageConversionFl return true; } -static void convert_ARGB_to_RGBA_PM(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +static inline void convert_ARGB_to_RGBA_PM(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { Q_ASSERT(src->format == QImage::Format_ARGB32); Q_ASSERT(dest->format == QImage::Format_RGBA8888_Premultiplied); @@ -336,6 +345,15 @@ static void convert_ARGB_to_RGBA_PM(QImageData *dest, const QImageData *src, Qt: } } +#if QT_COMPILER_SUPPORTS_HERE(SSE4_1) && !defined(__SSE4_1__) +QT_FUNCTION_TARGET(SSE4_1) +static void convert_ARGB_to_RGBA_PM_sse4(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags flags) +{ + // Twice as fast autovectorized due to SSE4.1 PMULLD instructions. + convert_ARGB_to_RGBA_PM(dest, src, flags); +} +#endif + static void convert_RGBA_to_ARGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { Q_ASSERT(src->format == QImage::Format_RGBX8888 || src->format == QImage::Format_RGBA8888 || src->format == QImage::Format_RGBA8888_Premultiplied); @@ -1861,11 +1879,154 @@ static void convert_Mono_to_Indexed8(QImageData *dest, const QImageData *src, Qt } } +static void convert_Indexed8_to_Alpha8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_Indexed8); + Q_ASSERT(dest->format == QImage::Format_Alpha8); + + uchar translate[256]; + const QVector<QRgb> &colors = src->colortable; + bool simpleCase = (colors.size() == 256); + for (int i = 0; i < colors.size(); ++i) { + uchar alpha = qAlpha(colors[i]); + translate[i] = alpha; + simpleCase = simpleCase && (alpha == i); + } + + if (simpleCase) + memcpy(dest->data, src->data, src->bytes_per_line * src->height); + else { + int size = src->bytes_per_line * src->height; + for (int i = 0; i < size; ++i) { + dest->data[i] = translate[src->data[i]]; + } + } +} + +static void convert_Indexed8_to_Grayscale8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_Indexed8); + Q_ASSERT(dest->format == QImage::Format_Grayscale8); + + uchar translate[256]; + const QVector<QRgb> &colors = src->colortable; + bool simpleCase = (colors.size() == 256); + for (int i = 0; i < colors.size(); ++i) { + uchar gray = qGray(colors[i]); + translate[i] = gray; + simpleCase = simpleCase && (gray == i); + } + + if (simpleCase) + memcpy(dest->data, src->data, src->bytes_per_line * src->height); + else { + int size = src->bytes_per_line * src->height; + for (int i = 0; i < size; ++i) { + dest->data[i] = translate[src->data[i]]; + } + } +} + +static bool convert_Indexed8_to_Alpha8_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_Indexed8); + + // Just check if this is an Alpha8 in Indexed8 disguise. + const QVector<QRgb> &colors = data->colortable; + if (colors.size() != 256) + return false; + for (int i = 0; i < colors.size(); ++i) { + if (i != qAlpha(colors[i])) + return false; + } + + data->colortable.clear(); + data->format = QImage::Format_Alpha8; + + return true; +} + +static bool convert_Indexed8_to_Grayscale8_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_Indexed8); + + // Just check if this is a Grayscale8 in Indexed8 disguise. + const QVector<QRgb> &colors = data->colortable; + if (colors.size() != 256) + return false; + for (int i = 0; i < colors.size(); ++i) { + if (i != qGray(colors[i])) + return false; + } + + data->colortable.clear(); + data->format = QImage::Format_Grayscale8; + + return true; +} + +static void convert_Alpha8_to_Indexed8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_Alpha8); + Q_ASSERT(dest->format == QImage::Format_Indexed8); + + memcpy(dest->data, src->data, src->bytes_per_line * src->height); + + QVector<QRgb> colors(256); + for (int i=0; i<256; ++i) + colors[i] = qRgba(0, 0, 0, i); + + dest->colortable = colors; +} + +static void convert_Grayscale8_to_Indexed8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_Grayscale8); + Q_ASSERT(dest->format == QImage::Format_Indexed8); + + memcpy(dest->data, src->data, src->bytes_per_line * src->height); + + QVector<QRgb> colors(256); + for (int i=0; i<256; ++i) + colors[i] = qRgb(i, i, i); + + dest->colortable = colors; +} + +static bool convert_Alpha8_to_Indexed8_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_Alpha8); + + QVector<QRgb> colors(256); + for (int i=0; i<256; ++i) + colors[i] = qRgba(0, 0, 0, i); + + data->colortable = colors; + data->format = QImage::Format_Indexed8; + + return true; +} + +static bool convert_Grayscale8_to_Indexed8_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_Grayscale8); + + QVector<QRgb> colors(256); + for (int i=0; i<256; ++i) + colors[i] = qRgb(i, i, i); + + data->colortable = colors; + data->format = QImage::Format_Indexed8; + + return true; +} + + // first index source, second dest Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormats] = { { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, @@ -1886,7 +2047,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_Mono { @@ -1908,7 +2069,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_MonoLSB { @@ -1930,7 +2091,9 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, + convert_Indexed8_to_Alpha8, + convert_Indexed8_to_Grayscale8, }, // Format_Indexed8 { @@ -1957,6 +2120,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_RGB_to_RGB30<PixelOrderBGR>, convert_RGB_to_RGB30<PixelOrderRGB>, convert_RGB_to_RGB30<PixelOrderRGB>, + 0, 0 }, // Format_RGB32 { @@ -1983,6 +2147,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, convert_RGB_to_RGB30<PixelOrderRGB>, 0, + 0, 0 }, // Format_ARGB32 { @@ -2009,6 +2174,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_ARGB_to_A2RGB30<PixelOrderBGR>, convert_ARGB_PM_to_RGB30<PixelOrderRGB>, convert_ARGB_to_A2RGB30<PixelOrderRGB>, + 0, 0 }, // Format_ARGB32_Premultiplied { @@ -2030,7 +2196,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB16 { @@ -2052,7 +2218,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB8565_Premultiplied { @@ -2074,7 +2240,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB666 { @@ -2096,7 +2262,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB6666_Premultiplied { @@ -2118,7 +2284,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB555 { @@ -2140,7 +2306,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB8555_Premultiplied { @@ -2162,7 +2328,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB888 { @@ -2184,7 +2350,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB444 { @@ -2205,7 +2371,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB4444_Premultiplied { 0, @@ -2227,7 +2393,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, mask_alpha_converter_RGBx, mask_alpha_converter_RGBx, - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 }, // Format_RGBX8888 { 0, @@ -2254,7 +2420,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, #endif - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 }, // Format_RGBA8888 { @@ -2283,7 +2449,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, #endif - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 }, // Format_RGBA8888_Premultiplied { @@ -2309,7 +2475,8 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, convert_passthrough, convert_BGR30_to_RGB30, - convert_BGR30_to_RGB30 + convert_BGR30_to_RGB30, + 0, 0 }, // Format_BGR30 { 0, @@ -2334,7 +2501,8 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_A2RGB30_PM_to_RGB30, 0, 0, - convert_BGR30_to_RGB30 + convert_BGR30_to_RGB30, + 0, 0 }, // Format_BGR30A2_Premultiplied { 0, @@ -2360,6 +2528,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, convert_passthrough, + 0, 0 }, // Format_RGB30 { 0, @@ -2385,19 +2554,61 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_BGR30_to_RGB30, convert_A2RGB30_PM_to_RGB30, 0, + 0, + 0, }, // Format_RGB30A2_Premultiplied + { + 0, + 0, + 0, + convert_Alpha8_to_Indexed8, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, 0, 0, 0, 0, 0, 0 + }, // Format_Alpha8 + { + 0, + 0, + 0, + convert_Grayscale8_to_Indexed8, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, 0, 0, 0, 0, 0, 0 + } // Format_Grayscale8 }; InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats] = { { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_Mono { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_MonoLSB { 0, @@ -2418,7 +2629,9 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, + convert_Indexed8_to_Alpha8_inplace, + convert_Indexed8_to_Grayscale8_inplace, }, // Format_Indexed8 { 0, @@ -2439,7 +2652,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB32 { 0, @@ -2464,7 +2677,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, convert_ARGB_to_RGBA_inplace, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB32 { 0, @@ -2486,34 +2699,34 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, convert_ARGB_to_RGBA_inplace, - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 }, // Format_ARGB32_Premultiplied { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB16 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB8565_Premultiplied { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB666 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB6666_Premultiplied { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB555 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB8555_Premultiplied { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB888 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB444 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB4444_Premultiplied { 0, @@ -2535,7 +2748,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, convert_passthrough_inplace<QImage::Format_RGBA8888>, convert_passthrough_inplace<QImage::Format_RGBA8888_Premultiplied>, - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 }, // Format_RGBX8888 { 0, @@ -2557,7 +2770,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 }, // Format_RGBA8888 { 0, @@ -2579,7 +2792,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 }, // Format_RGBA8888_Premultiplied { 0, @@ -2604,7 +2817,8 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, convert_passthrough_inplace<QImage::Format_A2BGR30_Premultiplied>, convert_BGR30_to_RGB30_inplace, - convert_BGR30_to_RGB30_inplace + convert_BGR30_to_RGB30_inplace, + 0, 0 }, // Format_BGR30 { 0, @@ -2629,7 +2843,8 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma convert_A2RGB30_PM_to_RGB30_inplace, 0, 0, - convert_BGR30_to_RGB30_inplace + convert_BGR30_to_RGB30_inplace, + 0, 0 }, // Format_BGR30A2_Premultiplied { 0, @@ -2654,7 +2869,8 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma convert_BGR30_to_RGB30_inplace, convert_BGR30_to_RGB30_inplace, 0, - convert_passthrough_inplace<QImage::Format_A2RGB30_Premultiplied> + convert_passthrough_inplace<QImage::Format_A2RGB30_Premultiplied>, + 0, 0 }, // Format_RGB30 { 0, @@ -2679,8 +2895,61 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, convert_BGR30_to_RGB30_inplace, convert_A2RGB30_PM_to_RGB30_inplace, - 0 + 0, + 0, 0 }, // Format_RGB30A2_Premultiplied + { + 0, + 0, + 0, + convert_Alpha8_to_Indexed8_inplace, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, 0 + }, // Format_Alpha8 + { + 0, + 0, + 0, + convert_Grayscale8_to_Indexed8_inplace, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, 0 + } // Format_Grayscale8 }; void qInitImageConversions() @@ -2694,6 +2963,14 @@ void qInitImageConversions() } #endif +#if QT_COMPILER_SUPPORTS_HERE(SSE4_1) && !defined(__SSE4_1__) + if (qCpuHasFeature(SSE4_1)) { + qimage_converter_map[QImage::Format_ARGB32][QImage::Format_ARGB32_Premultiplied] = convert_ARGB_to_ARGB_PM_sse4; + qimage_converter_map[QImage::Format_RGBA8888][QImage::Format_RGBA8888_Premultiplied] = convert_ARGB_to_ARGB_PM_sse4; + qimage_converter_map[QImage::Format_ARGB32][QImage::Format_RGBA8888_Premultiplied] = convert_ARGB_to_RGBA_PM_sse4; + } +#endif + #if defined(__ARM_NEON__) && !defined(Q_PROCESSOR_ARM_64) extern void convert_RGB888_to_RGB32_neon(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags); qimage_converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB32_neon; diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h index 7e2d4305ef..47e68b14a5 100644 --- a/src/gui/image/qimage_p.h +++ b/src/gui/image/qimage_p.h @@ -131,6 +131,8 @@ inline int qt_depthForFormat(QImage::Format format) depth = 1; break; case QImage::Format_Indexed8: + case QImage::Format_Alpha8: + case QImage::Format_Grayscale8: depth = 8; break; case QImage::Format_RGB32: diff --git a/src/gui/image/qimageiohandler.cpp b/src/gui/image/qimageiohandler.cpp index 1ecf445d57..7e7f3295e9 100644 --- a/src/gui/image/qimageiohandler.cpp +++ b/src/gui/image/qimageiohandler.cpp @@ -153,6 +153,12 @@ \value SupportedSubTypes Image formats that support different saving variants should return a list of supported variant names (QList<QByteArray>) in this option. + + \value OptimizedWrite. A handler which supports this option + is expected to turn on optimization flags when writing. + + \value ProgressiveScanWrite. A handler which supports + this option is expected to write the image as a progressive scan image. */ /*! diff --git a/src/gui/image/qimageiohandler.h b/src/gui/image/qimageiohandler.h index 3b3c410e0c..1c906436fe 100644 --- a/src/gui/image/qimageiohandler.h +++ b/src/gui/image/qimageiohandler.h @@ -84,7 +84,9 @@ public: Animation, BackgroundColor, ImageFormat, - SupportedSubTypes + SupportedSubTypes, + OptimizedWrite, + ProgressiveScanWrite }; virtual QVariant option(ImageOption option) const; virtual void setOption(ImageOption option, const QVariant &value); diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp index a7a08a6fee..ad84b0a091 100644 --- a/src/gui/image/qimagereader.cpp +++ b/src/gui/image/qimagereader.cpp @@ -1290,7 +1290,7 @@ bool QImageReader::read(QImage *image) } // successful read; check for "@2x" file name suffix and set device pixel ratio. - static bool disable2xImageLoading = !qgetenv("QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING").isEmpty(); + static bool disable2xImageLoading = !qEnvironmentVariableIsEmpty("QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING"); if (!disable2xImageLoading && QFileInfo(fileName()).baseName().endsWith(QLatin1String("@2x"))) { image->setDevicePixelRatio(2.0); } diff --git a/src/gui/image/qimagewriter.cpp b/src/gui/image/qimagewriter.cpp index fa261df1a5..0e03c9b215 100644 --- a/src/gui/image/qimagewriter.cpp +++ b/src/gui/image/qimagewriter.cpp @@ -252,6 +252,8 @@ public: QString description; QString text; QByteArray subType; + bool optimizedWrite; + bool progressiveScanWrite; // error QImageWriter::ImageWriterError imageWriterError; @@ -271,6 +273,8 @@ QImageWriterPrivate::QImageWriterPrivate(QImageWriter *qq) quality = -1; compression = 0; gamma = 0.0; + optimizedWrite = false; + progressiveScanWrite = false; imageWriterError = QImageWriter::UnknownError; errorString = QImageWriter::tr("Unknown error"); @@ -555,6 +559,63 @@ QList<QByteArray> QImageWriter::supportedSubTypes() const } /*! + \since 5.5 + + This is an image format-specific function which sets the \a optimize flags when + writing images. For image formats that do not support setting an \a optimize flag, + this value is ignored. + + The default is false. + + \sa optimizedWrite() +*/ +void QImageWriter::setOptimizedWrite(bool optimize) +{ + d->optimizedWrite = optimize; +} + +/*! + \since 5.5 + + Returns whether optimization has been turned on for writing the image. + + \sa setOptimizedWrite() +*/ +bool QImageWriter::optimizedWrite() const +{ + return d->optimizedWrite; +} + +/*! + \since 5.5 + + This is an image format-specific function which turns on \a progressive scanning + when writing images. For image formats that do not support setting a \a progressive + scan flag, this value is ignored. + + The default is false. + + \sa progressiveScanWrite() +*/ + +void QImageWriter::setProgressiveScanWrite(bool progressive) +{ + d->progressiveScanWrite = progressive; +} + +/*! + \since 5.5 + + Returns whether the image should be written as a progressive image. + + \sa setProgressiveScanWrite() +*/ +bool QImageWriter::progressiveScanWrite() const +{ + return d->progressiveScanWrite; +} + +/*! \obsolete Use setText() instead. @@ -657,6 +718,10 @@ bool QImageWriter::write(const QImage &image) d->handler->setOption(QImageIOHandler::Description, d->description); if (!d->subType.isEmpty() && d->handler->supportsOption(QImageIOHandler::SubType)) d->handler->setOption(QImageIOHandler::SubType, d->subType); + if (d->handler->supportsOption(QImageIOHandler::OptimizedWrite)) + d->handler->setOption(QImageIOHandler::OptimizedWrite, d->optimizedWrite); + if (d->handler->supportsOption(QImageIOHandler::ProgressiveScanWrite)) + d->handler->setOption(QImageIOHandler::ProgressiveScanWrite, d->progressiveScanWrite); if (!d->handler->write(image)) return false; diff --git a/src/gui/image/qimagewriter.h b/src/gui/image/qimagewriter.h index f458a259aa..e070d3b3d6 100644 --- a/src/gui/image/qimagewriter.h +++ b/src/gui/image/qimagewriter.h @@ -83,6 +83,12 @@ public: QByteArray subType() const; QList<QByteArray> supportedSubTypes() const; + void setOptimizedWrite(bool optimize); + bool optimizedWrite() const; + + void setProgressiveScanWrite(bool progressive); + bool progressiveScanWrite() const; + // Obsolete as of 4.1 void setDescription(const QString &description); QString description() const; diff --git a/src/gui/image/qjpeghandler.cpp b/src/gui/image/qjpeghandler.cpp index 9cf9947b6c..b07e1e28d3 100644 --- a/src/gui/image/qjpeghandler.cpp +++ b/src/gui/image/qjpeghandler.cpp @@ -86,9 +86,7 @@ struct my_error_mgr : public jpeg_error_mgr { jmp_buf setjmp_buffer; }; -#if defined(Q_C_CALLBACKS) extern "C" { -#endif static void my_error_exit (j_common_ptr cinfo) { @@ -106,9 +104,7 @@ static void my_output_message(j_common_ptr cinfo) qWarning("%s", buffer); } -#if defined(Q_C_CALLBACKS) } -#endif static const int max_buf = 4096; @@ -123,9 +119,7 @@ public: my_jpeg_source_mgr(QIODevice *device); }; -#if defined(Q_C_CALLBACKS) extern "C" { -#endif static void qt_init_source(j_decompress_ptr) { @@ -185,9 +179,7 @@ static void qt_term_source(j_decompress_ptr cinfo) src->device->seek(src->device->pos() - src->bytes_in_buffer); } -#if defined(Q_C_CALLBACKS) } -#endif inline my_jpeg_source_mgr::my_jpeg_source_mgr(QIODevice *device) { @@ -220,7 +212,7 @@ inline static bool read_jpeg_format(QImage::Format &format, j_decompress_ptr cin bool result = true; switch (cinfo->output_components) { case 1: - format = QImage::Format_Indexed8; + format = QImage::Format_Grayscale8; break; case 3: case 4: @@ -240,7 +232,7 @@ static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info, QImage::Format format; switch (info->output_components) { case 1: - format = QImage::Format_Indexed8; + format = QImage::Format_Grayscale8; break; case 3: case 4: @@ -250,16 +242,9 @@ static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info, return false; // unsupported format } - if (dest->size() != size || dest->format() != format) { + if (dest->size() != size || dest->format() != format) *dest = QImage(size, format); - if (format == QImage::Format_Indexed8) { - dest->setColorCount(256); - for (int i = 0; i < 256; i++) - dest->setColor(i, qRgb(i,i,i)); - } - } - return !dest->isNull(); } @@ -465,9 +450,7 @@ public: }; -#if defined(Q_C_CALLBACKS) extern "C" { -#endif static void qt_init_destination(j_compress_ptr) { @@ -497,9 +480,7 @@ static void qt_term_destination(j_compress_ptr cinfo) (*cinfo->err->error_exit)((j_common_ptr)cinfo); } -#if defined(Q_C_CALLBACKS) } -#endif inline my_jpeg_destination_mgr::my_jpeg_destination_mgr(QIODevice *device) { @@ -545,11 +526,14 @@ static inline void set_text(const QImage &image, j_compress_ptr cinfo, const QSt } } -static bool write_jpeg_image(const QImage &image, QIODevice *device, volatile int sourceQuality, const QString &description) +static bool write_jpeg_image(const QImage &image, QIODevice *device, volatile int sourceQuality, const QString &description, bool optimize, bool progressive) { bool success = false; const QVector<QRgb> cmap = image.colorTable(); + if (image.format() == QImage::Format_Invalid || image.format() == QImage::Format_Alpha8) + return false; + struct jpeg_compress_struct cinfo; JSAMPROW row_pointer[1]; row_pointer[0] = 0; @@ -573,19 +557,23 @@ static bool write_jpeg_image(const QImage &image, QIODevice *device, volatile in cinfo.image_width = image.width(); cinfo.image_height = image.height(); - bool gray=false; + bool gray = false; switch (image.format()) { case QImage::Format_Mono: case QImage::Format_MonoLSB: case QImage::Format_Indexed8: gray = true; - for (int i = image.colorCount(); gray && i--;) { - gray = gray & (qRed(cmap[i]) == qGreen(cmap[i]) && - qRed(cmap[i]) == qBlue(cmap[i])); + for (int i = image.colorCount(); gray && i; i--) { + gray = gray & qIsGray(cmap[i-1]); } cinfo.input_components = gray ? 1 : 3; cinfo.in_color_space = gray ? JCS_GRAYSCALE : JCS_RGB; break; + case QImage::Format_Grayscale8: + gray = true; + cinfo.input_components = 1; + cinfo.in_color_space = JCS_GRAYSCALE; + break; default: cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; @@ -607,6 +595,11 @@ static bool write_jpeg_image(const QImage &image, QIODevice *device, volatile in cinfo.Y_density = (image.dotsPerMeterY()+50) / 100; } + if (optimize) + cinfo.optimize_coding = true; + + if (progressive) + jpeg_simple_progression(&cinfo); int quality = sourceQuality >= 0 ? qMin(int(sourceQuality),100) : 75; jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); @@ -670,6 +663,9 @@ static bool write_jpeg_image(const QImage &image, QIODevice *device, volatile in } } break; + case QImage::Format_Grayscale8: + memcpy(row, image.constScanLine(cinfo.next_scanline), w); + break; case QImage::Format_RGB888: memcpy(row, image.constScanLine(cinfo.next_scanline), w * 3); break; @@ -726,7 +722,7 @@ public: }; QJpegHandlerPrivate(QJpegHandler *qq) - : quality(75), exifOrientation(1), iod_src(0), state(Ready), q(qq) + : quality(75), exifOrientation(1), iod_src(0), state(Ready), optimize(false), progressive(false), q(qq) {} ~QJpegHandlerPrivate() @@ -759,6 +755,9 @@ public: State state; + bool optimize; + bool progressive; + QJpegHandler *q; }; @@ -1063,7 +1062,7 @@ bool QJpegHandler::read(QImage *image) bool QJpegHandler::write(const QImage &image) { - return write_jpeg_image(image, device(), d->quality, d->description); + return write_jpeg_image(image, device(), d->quality, d->description, d->optimize, d->progressive); } bool QJpegHandler::supportsOption(ImageOption option) const @@ -1074,7 +1073,9 @@ bool QJpegHandler::supportsOption(ImageOption option) const || option == ClipRect || option == Description || option == Size - || option == ImageFormat; + || option == ImageFormat + || option == OptimizedWrite + || option == ProgressiveScanWrite; } QVariant QJpegHandler::option(ImageOption option) const @@ -1097,6 +1098,10 @@ QVariant QJpegHandler::option(ImageOption option) const case ImageFormat: d->readJpegHeader(device()); return d->format; + case OptimizedWrite: + return d->optimize; + case ProgressiveScanWrite: + return d->progressive; default: break; } @@ -1122,6 +1127,12 @@ void QJpegHandler::setOption(ImageOption option, const QVariant &value) case Description: d->description = value.toString(); break; + case OptimizedWrite: + d->optimize = value.toBool(); + break; + case ProgressiveScanWrite: + d->progressive = value.toBool(); + break; default: break; } diff --git a/src/gui/image/qjpeghandler_p.h b/src/gui/image/qjpeghandler_p.h index 85b903bf44..12f2553f92 100644 --- a/src/gui/image/qjpeghandler_p.h +++ b/src/gui/image/qjpeghandler_p.h @@ -58,17 +58,17 @@ public: QJpegHandler(); ~QJpegHandler(); - bool canRead() const; - bool read(QImage *image); - bool write(const QImage &image); + bool canRead() const Q_DECL_OVERRIDE; + bool read(QImage *image) Q_DECL_OVERRIDE; + bool write(const QImage &image) Q_DECL_OVERRIDE; - QByteArray name() const; + QByteArray name() const Q_DECL_OVERRIDE; static bool canRead(QIODevice *device); - QVariant option(ImageOption option) const; - void setOption(ImageOption option, const QVariant &value); - bool supportsOption(ImageOption option) const; + QVariant option(ImageOption option) const Q_DECL_OVERRIDE; + void setOption(ImageOption option, const QVariant &value) Q_DECL_OVERRIDE; + bool supportsOption(ImageOption option) const Q_DECL_OVERRIDE; private: QJpegHandlerPrivate *d; diff --git a/src/gui/image/qmovie.h b/src/gui/image/qmovie.h index c1560fdab6..60078f9e98 100644 --- a/src/gui/image/qmovie.h +++ b/src/gui/image/qmovie.h @@ -58,7 +58,6 @@ class Q_GUI_EXPORT QMovie : public QObject { Q_OBJECT Q_DECLARE_PRIVATE(QMovie) - Q_ENUMS(MovieState CacheMode) Q_PROPERTY(int speed READ speed WRITE setSpeed) Q_PROPERTY(CacheMode cacheMode READ cacheMode WRITE setCacheMode) public: @@ -67,10 +66,12 @@ public: Paused, Running }; + Q_ENUM(MovieState) enum CacheMode { CacheNone, CacheAll }; + Q_ENUM(CacheMode) explicit QMovie(QObject *parent = 0); explicit QMovie(QIODevice *device, const QByteArray &format = QByteArray(), QObject *parent = 0); diff --git a/src/gui/image/qpaintengine_pic_p.h b/src/gui/image/qpaintengine_pic_p.h index ef8b5643d1..168be55927 100644 --- a/src/gui/image/qpaintengine_pic_p.h +++ b/src/gui/image/qpaintengine_pic_p.h @@ -62,10 +62,10 @@ public: QPicturePaintEngine(); ~QPicturePaintEngine(); - bool begin(QPaintDevice *pdev); - bool end(); + bool begin(QPaintDevice *pdev) Q_DECL_OVERRIDE; + bool end() Q_DECL_OVERRIDE; - void updateState(const QPaintEngineState &state); + void updateState(const QPaintEngineState &state) Q_DECL_OVERRIDE; void updatePen(const QPen &pen); void updateBrush(const QBrush &brush); @@ -80,23 +80,18 @@ public: void updateClipEnabled(bool enabled); void updateOpacity(qreal opacity); - void drawEllipse(const QRectF &rect); - void drawPath(const QPainterPath &path); - void drawPolygon(const QPointF *points, int numPoints, PolygonDrawMode mode); -#ifdef Q_NO_USING_KEYWORD - inline void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode) - { QPaintEngine::drawPolygon(points, pointCount, mode); } -#else + void drawEllipse(const QRectF &rect) Q_DECL_OVERRIDE; + void drawPath(const QPainterPath &path) Q_DECL_OVERRIDE; + void drawPolygon(const QPointF *points, int numPoints, PolygonDrawMode mode) Q_DECL_OVERRIDE; using QPaintEngine::drawPolygon; -#endif - void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr); - void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s); + void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) Q_DECL_OVERRIDE; + void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s) Q_DECL_OVERRIDE; void drawImage(const QRectF &r, const QImage &image, const QRectF &sr, - Qt::ImageConversionFlags flags = Qt::AutoColor); - void drawTextItem(const QPointF &p, const QTextItem &ti); + Qt::ImageConversionFlags flags = Qt::AutoColor) Q_DECL_OVERRIDE; + void drawTextItem(const QPointF &p, const QTextItem &ti) Q_DECL_OVERRIDE; - Type type() const { return Picture; } + Type type() const Q_DECL_OVERRIDE { return Picture; } protected: QPicturePaintEngine(QPaintEnginePrivate &dptr); diff --git a/src/gui/image/qpicture.cpp b/src/gui/image/qpicture.cpp index bb37461b4f..bdfb987567 100644 --- a/src/gui/image/qpicture.cpp +++ b/src/gui/image/qpicture.cpp @@ -450,8 +450,8 @@ public: QFakeDevice() { dpi_x = qt_defaultDpiX(); dpi_y = qt_defaultDpiY(); } void setDpiX(int dpi) { dpi_x = dpi; } void setDpiY(int dpi) { dpi_y = dpi; } - QPaintEngine *paintEngine() const { return 0; } - int metric(PaintDeviceMetric m) const + QPaintEngine *paintEngine() const Q_DECL_OVERRIDE { return 0; } + int metric(PaintDeviceMetric m) const Q_DECL_OVERRIDE { switch(m) { case PdmPhysicalDpiX: diff --git a/src/gui/image/qpicture.h b/src/gui/image/qpicture.h index 1ad20a4e70..2ce8b3b75e 100644 --- a/src/gui/image/qpicture.h +++ b/src/gui/image/qpicture.h @@ -55,7 +55,7 @@ public: bool isNull() const; - int devType() const; + int devType() const Q_DECL_OVERRIDE; uint size() const; const char* data() const; virtual void setData(const char* data, uint size); @@ -88,12 +88,12 @@ public: static QStringList inputFormatList(); static QStringList outputFormatList(); - QPaintEngine *paintEngine() const; + QPaintEngine *paintEngine() const Q_DECL_OVERRIDE; protected: QPicture(QPicturePrivate &data); - int metric(PaintDeviceMetric m) const; + int metric(PaintDeviceMetric m) const Q_DECL_OVERRIDE; private: bool exec(QPainter *p, QDataStream &ds, int i); diff --git a/src/gui/image/qpixmap.h b/src/gui/image/qpixmap.h index dce64bd2dd..ce3a42abc4 100644 --- a/src/gui/image/qpixmap.h +++ b/src/gui/image/qpixmap.h @@ -75,7 +75,7 @@ public: operator QVariant() const; bool isNull() const; - int devType() const; + int devType() const Q_DECL_OVERRIDE; int width() const; int height() const; @@ -154,7 +154,7 @@ public: bool isQBitmap() const; - QPaintEngine *paintEngine() const; + QPaintEngine *paintEngine() const Q_DECL_OVERRIDE; inline bool operator!() const { return isNull(); } @@ -164,7 +164,7 @@ public: #endif protected: - int metric(PaintDeviceMetric) const; + int metric(PaintDeviceMetric) const Q_DECL_OVERRIDE; static QPixmap fromImageInPlace(QImage &image, Qt::ImageConversionFlags flags = Qt::AutoColor); private: diff --git a/src/gui/image/qpixmap_blitter_p.h b/src/gui/image/qpixmap_blitter_p.h index ec6c1eb8e5..069efbf593 100644 --- a/src/gui/image/qpixmap_blitter_p.h +++ b/src/gui/image/qpixmap_blitter_p.h @@ -62,17 +62,17 @@ public: QBlittable *blittable() const; void setBlittable(QBlittable *blittable); - void resize(int width, int height); - int metric(QPaintDevice::PaintDeviceMetric metric) const; - void fill(const QColor &color); - QImage *buffer(); - QImage toImage() const; - bool hasAlphaChannel() const; - void fromImage(const QImage &image, Qt::ImageConversionFlags flags); - qreal devicePixelRatio() const; - void setDevicePixelRatio(qreal scaleFactor); - - QPaintEngine *paintEngine() const; + void resize(int width, int height) Q_DECL_OVERRIDE; + int metric(QPaintDevice::PaintDeviceMetric metric) const Q_DECL_OVERRIDE; + void fill(const QColor &color) Q_DECL_OVERRIDE; + QImage *buffer() Q_DECL_OVERRIDE; + QImage toImage() const Q_DECL_OVERRIDE; + bool hasAlphaChannel() const Q_DECL_OVERRIDE; + void fromImage(const QImage &image, Qt::ImageConversionFlags flags) Q_DECL_OVERRIDE; + qreal devicePixelRatio() const Q_DECL_OVERRIDE; + void setDevicePixelRatio(qreal scaleFactor) Q_DECL_OVERRIDE; + + QPaintEngine *paintEngine() const Q_DECL_OVERRIDE; void markRasterOverlay(const QRectF &); void markRasterOverlay(const QPointF &, const QTextItem &); diff --git a/src/gui/image/qpixmap_raster.cpp b/src/gui/image/qpixmap_raster.cpp index 65e7fb0096..9c9db1c9c1 100644 --- a/src/gui/image/qpixmap_raster.cpp +++ b/src/gui/image/qpixmap_raster.cpp @@ -203,9 +203,14 @@ void QRasterPlatformPixmap::fill(const QColor &color) pixel = qPremultiply(color.rgba()); const QPixelLayout *layout = &qPixelLayouts[image.format()]; layout->convertFromARGB32PM(&pixel, &pixel, 1, layout, 0); - } else { + } else if (image.format() == QImage::Format_Alpha8) { + pixel = qAlpha(color.rgba()); + } else if (image.format() == QImage::Format_Grayscale8) { + pixel = qGray(color.rgba()); + } else + { pixel = 0; - // ### what about 8 bits + // ### what about 8 bit indexed? } image.fill(pixel); diff --git a/src/gui/image/qpixmap_raster_p.h b/src/gui/image/qpixmap_raster_p.h index ffb4b591de..cbbd681314 100644 --- a/src/gui/image/qpixmap_raster_p.h +++ b/src/gui/image/qpixmap_raster_p.h @@ -56,28 +56,28 @@ public: QRasterPlatformPixmap(PixelType type); ~QRasterPlatformPixmap(); - QPlatformPixmap *createCompatiblePlatformPixmap() const; - - void resize(int width, int height); - bool fromData(const uchar *buffer, uint len, const char *format, Qt::ImageConversionFlags flags); - void fromImage(const QImage &image, Qt::ImageConversionFlags flags); - void fromImageInPlace(QImage &image, Qt::ImageConversionFlags flags); - void fromImageReader(QImageReader *imageReader, Qt::ImageConversionFlags flags); - - void copy(const QPlatformPixmap *data, const QRect &rect); - bool scroll(int dx, int dy, const QRect &rect); - void fill(const QColor &color); - bool hasAlphaChannel() const; - QImage toImage() const; - QImage toImage(const QRect &rect) const; - QPaintEngine* paintEngine() const; - QImage* buffer(); - qreal devicePixelRatio() const; - void setDevicePixelRatio(qreal scaleFactor); + QPlatformPixmap *createCompatiblePlatformPixmap() const Q_DECL_OVERRIDE; + + void resize(int width, int height) Q_DECL_OVERRIDE; + bool fromData(const uchar *buffer, uint len, const char *format, Qt::ImageConversionFlags flags) Q_DECL_OVERRIDE; + void fromImage(const QImage &image, Qt::ImageConversionFlags flags) Q_DECL_OVERRIDE; + void fromImageInPlace(QImage &image, Qt::ImageConversionFlags flags) Q_DECL_OVERRIDE; + void fromImageReader(QImageReader *imageReader, Qt::ImageConversionFlags flags) Q_DECL_OVERRIDE; + + void copy(const QPlatformPixmap *data, const QRect &rect) Q_DECL_OVERRIDE; + bool scroll(int dx, int dy, const QRect &rect) Q_DECL_OVERRIDE; + void fill(const QColor &color) Q_DECL_OVERRIDE; + bool hasAlphaChannel() const Q_DECL_OVERRIDE; + QImage toImage() const Q_DECL_OVERRIDE; + QImage toImage(const QRect &rect) const Q_DECL_OVERRIDE; + QPaintEngine* paintEngine() const Q_DECL_OVERRIDE; + QImage* buffer() Q_DECL_OVERRIDE; + qreal devicePixelRatio() const Q_DECL_OVERRIDE; + void setDevicePixelRatio(qreal scaleFactor) Q_DECL_OVERRIDE; protected: - int metric(QPaintDevice::PaintDeviceMetric metric) const; + int metric(QPaintDevice::PaintDeviceMetric metric) const Q_DECL_OVERRIDE; void createPixmapForImage(QImage &sourceImage, Qt::ImageConversionFlags flags, bool inPlace); void setImage(const QImage &image); QImage image; diff --git a/src/gui/image/qpixmapcache.cpp b/src/gui/image/qpixmapcache.cpp index 170a295cf8..d4b5cee74c 100644 --- a/src/gui/image/qpixmapcache.cpp +++ b/src/gui/image/qpixmapcache.cpp @@ -159,7 +159,7 @@ public: QPMCache(); ~QPMCache(); - void timerEvent(QTimerEvent *); + void timerEvent(QTimerEvent *) Q_DECL_OVERRIDE; bool insert(const QString& key, const QPixmap &pixmap, int cost); QPixmapCache::Key insert(const QPixmap &pixmap, int cost); bool replace(const QPixmapCache::Key &key, const QPixmap &pixmap, int cost); diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp index 17a0dd3eb9..c19bc52a97 100644 --- a/src/gui/image/qpnghandler.cpp +++ b/src/gui/image/qpnghandler.cpp @@ -157,10 +157,6 @@ public: }; -#if defined(Q_C_CALLBACKS) -extern "C" { -#endif - class QPNGImageWriter { public: explicit QPNGImageWriter(QIODevice*); @@ -190,6 +186,7 @@ private: float gamma; }; +extern "C" { static void CALLBACK_CALL_TYPE iod_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) { @@ -234,9 +231,7 @@ void CALLBACK_CALL_TYPE qpiw_flush_fn(png_structp /* png_ptr */) { } -#if defined(Q_C_CALLBACKS) } -#endif static void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, QSize scaledSize, bool *doScaledRead, float screen_gamma=0.0) @@ -295,6 +290,15 @@ void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, QSize scal png_set_swap_alpha(png_ptr); png_read_update_info(png_ptr, info_ptr); + } else if (bit_depth == 8 && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { + png_set_expand(png_ptr); + if (image.size() != QSize(width, height) || image.format() != QImage::Format_Grayscale8) { + image = QImage(width, height, QImage::Format_Grayscale8); + if (image.isNull()) + return; + } + + png_read_update_info(png_ptr, info_ptr); } else { if (bit_depth == 16) png_set_strip_16(png_ptr); @@ -483,17 +487,13 @@ static void read_image_scaled(QImage *outImage, png_structp png_ptr, png_infop i } -#if defined(Q_C_CALLBACKS) extern "C" { -#endif static void CALLBACK_CALL_TYPE qt_png_warning(png_structp /*png_ptr*/, png_const_charp message) { qWarning("libpng warning: %s", message); } -#if defined(Q_C_CALLBACKS) } -#endif void Q_INTERNAL_WIN_NO_THROW QPngHandlerPrivate::readPngTexts(png_info *info) @@ -666,6 +666,8 @@ QImage::Format QPngHandlerPrivate::readImageFormat() format = QImage::Format_Mono; } else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { format = QImage::Format_ARGB32; + } else if (bit_depth == 8 && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { + format = QImage::Format_Grayscale8; } else { format = QImage::Format_Indexed8; } @@ -857,6 +859,8 @@ bool Q_INTERNAL_WIN_NO_THROW QPNGImageWriter::writeImage(const QImage& image, vo else color_type = PNG_COLOR_TYPE_PALETTE; } + else if (image.format() == QImage::Format_Grayscale8) + color_type = PNG_COLOR_TYPE_GRAY; else if (image.hasAlphaChannel()) color_type = PNG_COLOR_TYPE_RGB_ALPHA; else @@ -955,6 +959,7 @@ bool Q_INTERNAL_WIN_NO_THROW QPNGImageWriter::writeImage(const QImage& image, vo case QImage::Format_Mono: case QImage::Format_MonoLSB: case QImage::Format_Indexed8: + case QImage::Format_Grayscale8: case QImage::Format_RGB32: case QImage::Format_ARGB32: case QImage::Format_RGB888: diff --git a/src/gui/image/qppmhandler.cpp b/src/gui/image/qppmhandler.cpp index 314abca9f0..e1c76cce7f 100644 --- a/src/gui/image/qppmhandler.cpp +++ b/src/gui/image/qppmhandler.cpp @@ -122,7 +122,7 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q case '2': // ascii PGM case '5': // raw PGM nbits = 8; - format = QImage::Format_Indexed8; + format = QImage::Format_Grayscale8; break; case '3': // ascii PPM case '6': // raw PPM @@ -200,13 +200,13 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q *p++ = b; } } else if (nbits == 8) { - if (mcc == maxc) { + if (mcc == 255) { while (n--) { *p++ = read_pbm_int(device); } } else { while (n--) { - *p++ = read_pbm_int(device) * maxc / mcc; + *p++ = read_pbm_int(device) * 255 / mcc; } } } else { // 32 bits @@ -233,14 +233,10 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q } } - if (nbits == 1) { // bitmap + if (format == QImage::Format_Mono) { outImage->setColorCount(2); - outImage->setColor(0, qRgb(255,255,255)); // white - outImage->setColor(1, qRgb(0,0,0)); // black - } else if (nbits == 8) { // graymap - outImage->setColorCount(maxc+1); - for (int i=0; i<=maxc; i++) - outImage->setColor(i, qRgb(i*255/maxc,i*255/maxc,i*255/maxc)); + outImage->setColor(0, qRgb(255,255,255)); // white + outImage->setColor(1, qRgb(0,0,0)); // black } return true; @@ -257,6 +253,8 @@ static bool write_pbm_image(QIODevice *out, const QImage &sourceImage, const QBy if (format == "pbm") { image = image.convertToFormat(QImage::Format_Mono); + } else if (gray) { + image = image.convertToFormat(QImage::Format_Grayscale8); } else { switch (image.format()) { case QImage::Format_Mono: @@ -317,63 +315,77 @@ static bool write_pbm_image(QIODevice *out, const QImage &sourceImage, const QBy str.append("255\n"); if (out->write(str, str.length()) != str.length()) return false; - QVector<QRgb> color = image.colorTable(); - uint bpl = w*(gray ? 1 : 3); - uchar *buf = new uchar[bpl]; - for (uint y=0; y<h; y++) { - uchar *b = image.scanLine(y); - uchar *p = buf; - uchar *end = buf+bpl; - if (gray) { - while (p < end) { - uchar g = (uchar)qGray(color[*b++]); - *p++ = g; + uint bpl = w * (gray ? 1 : 3); + uchar *buf = new uchar[bpl]; + if (image.format() == QImage::Format_Indexed8) { + QVector<QRgb> color = image.colorTable(); + for (uint y=0; y<h; y++) { + uchar *b = image.scanLine(y); + uchar *p = buf; + uchar *end = buf+bpl; + if (gray) { + while (p < end) { + uchar g = (uchar)qGray(color[*b++]); + *p++ = g; + } + } else { + while (p < end) { + QRgb rgb = color[*b++]; + *p++ = qRed(rgb); + *p++ = qGreen(rgb); + *p++ = qBlue(rgb); + } } - } else { - while (p < end) { - QRgb rgb = color[*b++]; - *p++ = qRed(rgb); - *p++ = qGreen(rgb); - *p++ = qBlue(rgb); + if (bpl != (uint)out->write((char*)buf, bpl)) + return false; + } + } else { + for (uint y=0; y<h; y++) { + uchar *b = image.scanLine(y); + uchar *p = buf; + uchar *end = buf + bpl; + if (gray) { + while (p < end) + *p++ = *b++; + } else { + while (p < end) { + uchar color = *b++; + *p++ = color; + *p++ = color; + *p++ = color; + } } + if (bpl != (uint)out->write((char*)buf, bpl)) + return false; } - if (bpl != (uint)out->write((char*)buf, bpl)) - return false; } delete [] buf; - } break; + } case 32: { - str.insert(1, gray ? '5' : '6'); + str.insert(1, '6'); str.append("255\n"); if (out->write(str, str.length()) != str.length()) return false; - uint bpl = w*(gray ? 1 : 3); + uint bpl = w * 3; uchar *buf = new uchar[bpl]; for (uint y=0; y<h; y++) { QRgb *b = (QRgb*)image.scanLine(y); uchar *p = buf; uchar *end = buf+bpl; - if (gray) { - while (p < end) { - uchar g = (uchar)qGray(*b++); - *p++ = g; - } - } else { - while (p < end) { - QRgb rgb = *b++; - *p++ = qRed(rgb); - *p++ = qGreen(rgb); - *p++ = qBlue(rgb); - } + while (p < end) { + QRgb rgb = *b++; + *p++ = qRed(rgb); + *p++ = qGreen(rgb); + *p++ = qBlue(rgb); } if (bpl != (uint)out->write((char*)buf, bpl)) return false; } delete [] buf; - } break; + } default: return false; @@ -488,11 +500,11 @@ QVariant QPpmHandler::option(ImageOption option) const switch (type) { case '1': // ascii PBM case '4': // raw PBM - format = QImage::Format_Mono; - break; + format = QImage::Format_Mono; + break; case '2': // ascii PGM case '5': // raw PGM - format = QImage::Format_Indexed8; + format = QImage::Format_Grayscale8; break; case '3': // ascii PPM case '6': // raw PPM |