summaryrefslogtreecommitdiffstats
path: root/src/gui/image
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /src/gui/image
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/gui/image')
-rw-r--r--src/gui/image/image.pri115
-rw-r--r--src/gui/image/qbitmap.cpp411
-rw-r--r--src/gui/image/qbitmap.h109
-rw-r--r--src/gui/image/qbmphandler.cpp837
-rw-r--r--src/gui/image/qbmphandler_p.h117
-rw-r--r--src/gui/image/qgifhandler.cpp1214
-rw-r--r--src/gui/image/qgifhandler.pri4
-rw-r--r--src/gui/image/qgifhandler_p.h96
-rw-r--r--src/gui/image/qicon.cpp1258
-rw-r--r--src/gui/image/qicon.h162
-rw-r--r--src/gui/image/qicon_p.h139
-rw-r--r--src/gui/image/qiconengine.cpp324
-rw-r--r--src/gui/image/qiconengine.h104
-rw-r--r--src/gui/image/qiconengineplugin.cpp171
-rw-r--r--src/gui/image/qiconengineplugin.h104
-rw-r--r--src/gui/image/qiconloader.cpp570
-rw-r--r--src/gui/image/qiconloader_p.h192
-rw-r--r--src/gui/image/qimage.cpp6717
-rw-r--r--src/gui/image/qimage.h374
-rw-r--r--src/gui/image/qimage_neon.cpp114
-rw-r--r--src/gui/image/qimage_p.h154
-rw-r--r--src/gui/image/qimage_sse2.cpp109
-rw-r--r--src/gui/image/qimage_ssse3.cpp149
-rw-r--r--src/gui/image/qimageiohandler.cpp570
-rw-r--r--src/gui/image/qimageiohandler.h152
-rw-r--r--src/gui/image/qimagepixmapcleanuphooks.cpp163
-rw-r--r--src/gui/image/qimagepixmapcleanuphooks_p.h103
-rw-r--r--src/gui/image/qimagereader.cpp1515
-rw-r--r--src/gui/image/qimagereader.h147
-rw-r--r--src/gui/image/qimagewriter.cpp734
-rw-r--r--src/gui/image/qimagewriter.h116
-rw-r--r--src/gui/image/qjpeghandler.cpp915
-rw-r--r--src/gui/image/qjpeghandler.pri10
-rw-r--r--src/gui/image/qjpeghandler_p.h76
-rw-r--r--src/gui/image/qmnghandler.cpp497
-rw-r--r--src/gui/image/qmnghandler.pri10
-rw-r--r--src/gui/image/qmnghandler_p.h83
-rw-r--r--src/gui/image/qmovie.cpp1089
-rw-r--r--src/gui/image/qmovie.h177
-rw-r--r--src/gui/image/qnativeimage.cpp315
-rw-r--r--src/gui/image/qnativeimage_p.h109
-rw-r--r--src/gui/image/qnativeimagehandleprovider_p.h69
-rw-r--r--src/gui/image/qpaintengine_pic.cpp539
-rw-r--r--src/gui/image/qpaintengine_pic_p.h122
-rw-r--r--src/gui/image/qpicture.cpp1999
-rw-r--r--src/gui/image/qpicture.h204
-rw-r--r--src/gui/image/qpicture_p.h169
-rw-r--r--src/gui/image/qpictureformatplugin.cpp139
-rw-r--r--src/gui/image/qpictureformatplugin.h94
-rw-r--r--src/gui/image/qpixmap.cpp2297
-rw-r--r--src/gui/image/qpixmap.h335
-rw-r--r--src/gui/image/qpixmap_blitter.cpp310
-rw-r--r--src/gui/image/qpixmap_blitter_p.h166
-rw-r--r--src/gui/image/qpixmap_mac.cpp1195
-rw-r--r--src/gui/image/qpixmap_mac_p.h134
-rw-r--r--src/gui/image/qpixmap_qpa.cpp49
-rw-r--r--src/gui/image/qpixmap_qws.cpp160
-rw-r--r--src/gui/image/qpixmap_raster.cpp492
-rw-r--r--src/gui/image/qpixmap_raster_p.h107
-rw-r--r--src/gui/image/qpixmap_s60.cpp1040
-rw-r--r--src/gui/image/qpixmap_s60_p.h141
-rw-r--r--src/gui/image/qpixmap_win.cpp477
-rw-r--r--src/gui/image/qpixmap_x11.cpp2419
-rw-r--r--src/gui/image/qpixmap_x11_p.h156
-rw-r--r--src/gui/image/qpixmapcache.cpp680
-rw-r--r--src/gui/image/qpixmapcache.h102
-rw-r--r--src/gui/image/qpixmapcache_p.h103
-rw-r--r--src/gui/image/qpixmapdata.cpp290
-rw-r--r--src/gui/image/qpixmapdata_p.h180
-rw-r--r--src/gui/image/qpixmapdatafactory.cpp115
-rw-r--r--src/gui/image/qpixmapdatafactory_p.h81
-rw-r--r--src/gui/image/qpixmapfilter.cpp1382
-rw-r--r--src/gui/image/qpixmapfilter_p.h196
-rw-r--r--src/gui/image/qpnghandler.cpp991
-rw-r--r--src/gui/image/qpnghandler.pri10
-rw-r--r--src/gui/image/qpnghandler_p.h88
-rw-r--r--src/gui/image/qppmhandler.cpp533
-rw-r--r--src/gui/image/qppmhandler_p.h98
-rw-r--r--src/gui/image/qtiffhandler.cpp665
-rw-r--r--src/gui/image/qtiffhandler.pri10
-rw-r--r--src/gui/image/qtiffhandler_p.h78
-rw-r--r--src/gui/image/qvolatileimage.cpp318
-rw-r--r--src/gui/image/qvolatileimage_p.h101
-rw-r--r--src/gui/image/qvolatileimagedata.cpp114
-rw-r--r--src/gui/image/qvolatileimagedata_p.h97
-rw-r--r--src/gui/image/qvolatileimagedata_symbian.cpp474
-rw-r--r--src/gui/image/qxbmhandler.cpp361
-rw-r--r--src/gui/image/qxbmhandler_p.h95
-rw-r--r--src/gui/image/qxpmhandler.cpp1295
-rw-r--r--src/gui/image/qxpmhandler_p.h100
90 files changed, 41695 insertions, 0 deletions
diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri
new file mode 100644
index 0000000000..72738c9fa8
--- /dev/null
+++ b/src/gui/image/image.pri
@@ -0,0 +1,115 @@
+# -*-mode:sh-*-
+# Qt image handling
+
+# Qt kernel module
+
+HEADERS += \
+ image/qbitmap.h \
+ image/qicon.h \
+ image/qicon_p.h \
+ image/qiconloader_p.h \
+ image/qiconengine.h \
+ image/qiconengineplugin.h \
+ image/qimage.h \
+ image/qimage_p.h \
+ image/qimageiohandler.h \
+ image/qimagereader.h \
+ image/qimagewriter.h \
+ image/qmovie.h \
+ image/qnativeimage_p.h \
+ image/qpaintengine_pic_p.h \
+ image/qpicture.h \
+ image/qpicture_p.h \
+ image/qpictureformatplugin.h \
+ image/qpixmap.h \
+ image/qpixmap_raster_p.h \
+ image/qpixmap_blitter_p.h \
+ image/qpixmapcache.h \
+ image/qpixmapcache_p.h \
+ image/qpixmapdata_p.h \
+ image/qpixmapdatafactory_p.h \
+ image/qpixmapfilter_p.h \
+ image/qimagepixmapcleanuphooks_p.h \
+ image/qvolatileimage_p.h \
+ image/qvolatileimagedata_p.h \
+ image/qnativeimagehandleprovider_p.h
+
+SOURCES += \
+ image/qbitmap.cpp \
+ image/qicon.cpp \
+ image/qiconloader.cpp \
+ image/qimage.cpp \
+ image/qimageiohandler.cpp \
+ image/qimagereader.cpp \
+ image/qimagewriter.cpp \
+ image/qpaintengine_pic.cpp \
+ image/qpicture.cpp \
+ image/qpictureformatplugin.cpp \
+ image/qpixmap.cpp \
+ image/qpixmapcache.cpp \
+ image/qpixmapdata.cpp \
+ image/qpixmapdatafactory.cpp \
+ image/qpixmapfilter.cpp \
+ image/qiconengine.cpp \
+ image/qiconengineplugin.cpp \
+ image/qmovie.cpp \
+ image/qpixmap_raster.cpp \
+ image/qpixmap_blitter.cpp \
+ image/qnativeimage.cpp \
+ image/qimagepixmapcleanuphooks.cpp \
+ image/qvolatileimage.cpp
+
+win32 {
+ SOURCES += image/qpixmap_win.cpp
+}
+else:embedded {
+ SOURCES += image/qpixmap_qws.cpp
+}
+else:qpa {
+ SOURCES += image/qpixmap_qpa.cpp
+}
+else:x11 {
+ HEADERS += image/qpixmap_x11_p.h
+ SOURCES += image/qpixmap_x11.cpp
+}
+else:mac {
+ HEADERS += image/qpixmap_mac_p.h
+ SOURCES += image/qpixmap_mac.cpp
+}
+else:symbian {
+ HEADERS += image/qpixmap_s60_p.h
+ SOURCES += image/qpixmap_s60.cpp
+}
+
+!symbian|contains(S60_VERSION, 3.1)|contains(S60_VERSION, 3.2) {
+ SOURCES += image/qvolatileimagedata.cpp
+}
+else {
+ SOURCES += image/qvolatileimagedata_symbian.cpp
+}
+
+# Built-in image format support
+HEADERS += \
+ image/qbmphandler_p.h \
+ image/qppmhandler_p.h \
+ image/qxbmhandler_p.h \
+ image/qxpmhandler_p.h
+
+SOURCES += \
+ image/qbmphandler.cpp \
+ image/qppmhandler.cpp \
+ image/qxbmhandler.cpp \
+ image/qxpmhandler.cpp
+
+!contains(QT_CONFIG, no-png):include($$PWD/qpnghandler.pri)
+else:DEFINES *= QT_NO_IMAGEFORMAT_PNG
+
+contains(QT_CONFIG, jpeg):include($$PWD/qjpeghandler.pri)
+contains(QT_CONFIG, mng):include($$PWD/qmnghandler.pri)
+contains(QT_CONFIG, tiff):include($$PWD/qtiffhandler.pri)
+contains(QT_CONFIG, gif):include($$PWD/qgifhandler.pri)
+
+# SIMD
+NEON_SOURCES += image/qimage_neon.cpp
+SSE2_SOURCES += image/qimage_sse2.cpp
+SSSE3_SOURCES += image/qimage_ssse3.cpp
diff --git a/src/gui/image/qbitmap.cpp b/src/gui/image/qbitmap.cpp
new file mode 100644
index 0000000000..260b397140
--- /dev/null
+++ b/src/gui/image/qbitmap.cpp
@@ -0,0 +1,411 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qbitmap.h"
+#include "qpixmapdata_p.h"
+#include "qimage.h"
+#include "qvariant.h"
+#include <qpainter.h>
+#include <private/qgraphicssystem_p.h>
+#include <private/qapplication_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QBitmap
+ \brief The QBitmap class provides monochrome (1-bit depth) pixmaps.
+
+ \ingroup painting
+ \ingroup shared
+
+ The QBitmap class is a monochrome off-screen paint device used
+ mainly for creating custom QCursor and QBrush objects,
+ constructing QRegion objects, and for setting masks for pixmaps
+ and widgets.
+
+ QBitmap is a QPixmap subclass ensuring a depth of 1, except for
+ null objects which have a depth of 0. If a pixmap with a depth
+ greater than 1 is assigned to a bitmap, the bitmap will be
+ dithered automatically.
+
+ Use the QColor objects Qt::color0 and Qt::color1 when drawing on a
+ QBitmap object (or a QPixmap object with depth 1).
+
+ Painting with Qt::color0 sets the bitmap bits to 0, and painting
+ with Qt::color1 sets the bits to 1. For a bitmap, 0-bits indicate
+ background (or transparent pixels) and 1-bits indicate foreground
+ (or opaque pixels). Use the clear() function to set all the bits
+ to Qt::color0. Note that using the Qt::black and Qt::white colors
+ make no sense because the QColor::pixel() value is not necessarily
+ 0 for black and 1 for white.
+
+ The QBitmap class provides the transformed() function returning a
+ transformed copy of the bitmap; use the QTransform argument to
+ translate, scale, shear, and rotate the bitmap. In addition,
+ QBitmap provides the static fromData() function which returns a
+ bitmap constructed from the given \c uchar data, and the static
+ fromImage() function returning a converted copy of a QImage
+ object.
+
+ Just like the QPixmap class, QBitmap is optimized by the use of
+ implicit data sharing. For more information, see the \l {Implicit
+ Data Sharing} documentation.
+
+ \sa QPixmap, QImage, QImageReader, QImageWriter
+*/
+
+/*! \typedef QBitmap::DataPtr
+ \internal
+ */
+
+/*!
+ Constructs a null bitmap.
+
+ \sa QPixmap::isNull()
+*/
+QBitmap::QBitmap()
+ : QPixmap(QSize(0, 0), QPixmapData::BitmapType)
+{
+}
+
+/*!
+ \fn QBitmap::QBitmap(int width, int height)
+
+ Constructs a bitmap with the given \a width and \a height. The pixels
+ inside are uninitialized.
+
+ \sa clear()
+*/
+
+QBitmap::QBitmap(int w, int h)
+ : QPixmap(QSize(w, h), QPixmapData::BitmapType)
+{
+}
+
+/*!
+ Constructs a bitmap with the given \a size. The pixels in the
+ bitmap are uninitialized.
+
+ \sa clear()
+*/
+
+QBitmap::QBitmap(const QSize &size)
+ : QPixmap(size, QPixmapData::BitmapType)
+{
+}
+
+/*!
+ \fn QBitmap::clear()
+
+ Clears the bitmap, setting all its bits to Qt::color0.
+*/
+
+/*!
+ Constructs a bitmap that is a copy of the given \a pixmap.
+
+ If the pixmap has a depth greater than 1, the resulting bitmap
+ will be dithered automatically.
+
+ \sa QPixmap::depth(), fromImage(), fromData()
+*/
+
+QBitmap::QBitmap(const QPixmap &pixmap)
+{
+ QBitmap::operator=(pixmap);
+}
+
+/*!
+ \fn QBitmap::QBitmap(const QImage &image)
+
+ Constructs a bitmap that is a copy of the given \a image.
+
+ Use the static fromImage() function instead.
+*/
+
+/*!
+ Constructs a bitmap from the file specified by the given \a
+ fileName. If the file does not exist, or has an unknown format,
+ the bitmap becomes a null bitmap.
+
+ The \a fileName and \a format parameters are passed on to the
+ QPixmap::load() function. If the file format uses more than 1 bit
+ per pixel, the resulting bitmap will be dithered automatically.
+
+ \sa QPixmap::isNull(), QImageReader::imageFormat()
+*/
+
+QBitmap::QBitmap(const QString& fileName, const char *format)
+ : QPixmap(QSize(0, 0), QPixmapData::BitmapType)
+{
+ load(fileName, format, Qt::MonoOnly);
+}
+
+/*!
+ \overload
+
+ Assigns the given \a pixmap to this bitmap and returns a reference
+ to this bitmap.
+
+ If the pixmap has a depth greater than 1, the resulting bitmap
+ will be dithered automatically.
+
+ \sa QPixmap::depth()
+ */
+
+QBitmap &QBitmap::operator=(const QPixmap &pixmap)
+{
+ if (pixmap.isNull()) { // a null pixmap
+ QBitmap bm(0, 0);
+ QBitmap::operator=(bm);
+ } else if (pixmap.depth() == 1) { // 1-bit pixmap
+ QPixmap::operator=(pixmap); // shallow assignment
+ } else { // n-bit depth pixmap
+ QImage image;
+ image = pixmap.toImage(); // convert pixmap to image
+ *this = fromImage(image); // will dither image
+ }
+ return *this;
+}
+
+
+#ifdef QT3_SUPPORT
+QBitmap::QBitmap(int w, int h, const uchar *bits, bool isXbitmap)
+{
+ *this = fromData(QSize(w, h), bits, isXbitmap ? QImage::Format_MonoLSB : QImage::Format_Mono);
+}
+
+
+QBitmap::QBitmap(const QSize &size, const uchar *bits, bool isXbitmap)
+{
+ *this = fromData(size, bits, isXbitmap ? QImage::Format_MonoLSB : QImage::Format_Mono);
+}
+#endif
+
+/*!
+ Destroys the bitmap.
+*/
+QBitmap::~QBitmap()
+{
+}
+
+/*!
+ \fn void QBitmap::swap(QBitmap &other)
+ \since 4.8
+
+ Swaps bitmap \a other with this bitmap. This operation is very
+ fast and never fails.
+*/
+
+/*!
+ Returns the bitmap as a QVariant.
+*/
+QBitmap::operator QVariant() const
+{
+ return QVariant(QVariant::Bitmap, this);
+}
+
+/*!
+ \fn QBitmap &QBitmap::operator=(const QImage &image)
+ \overload
+
+ Converts the given \a image to a bitmap, and assigns the result to
+ this bitmap. Returns a reference to the bitmap.
+
+ Use the static fromImage() function instead.
+*/
+
+/*!
+ Returns a copy of the given \a image converted to a bitmap using
+ the specified image conversion \a flags.
+
+ \sa fromData()
+*/
+QBitmap QBitmap::fromImage(const QImage &image, Qt::ImageConversionFlags flags)
+{
+ if (image.isNull())
+ return QBitmap();
+
+ QImage img = image.convertToFormat(QImage::Format_MonoLSB, flags);
+
+ // make sure image.color(0) == Qt::color0 (white)
+ // and image.color(1) == Qt::color1 (black)
+ const QRgb c0 = QColor(Qt::black).rgb();
+ const QRgb c1 = QColor(Qt::white).rgb();
+ if (img.color(0) == c0 && img.color(1) == c1) {
+ img.invertPixels();
+ img.setColor(0, c1);
+ img.setColor(1, c0);
+ }
+
+ QGraphicsSystem* gs = QApplicationPrivate::graphicsSystem();
+ QScopedPointer<QPixmapData> data(gs ? gs->createPixmapData(QPixmapData::BitmapType)
+ : QGraphicsSystem::createDefaultPixmapData(QPixmapData::BitmapType));
+
+ data->fromImage(img, flags | Qt::MonoOnly);
+ return QPixmap(data.take());
+}
+
+/*!
+ Constructs a bitmap with the given \a size, and sets the contents to
+ the \a bits supplied.
+
+ The bitmap data has to be byte aligned and provided in in the bit
+ order specified by \a monoFormat. The mono format must be either
+ QImage::Format_Mono or QImage::Format_MonoLSB. Use
+ QImage::Format_Mono to specify data on the XBM format.
+
+ \sa fromImage()
+
+*/
+QBitmap QBitmap::fromData(const QSize &size, const uchar *bits, QImage::Format monoFormat)
+{
+ Q_ASSERT(monoFormat == QImage::Format_Mono || monoFormat == QImage::Format_MonoLSB);
+
+ QImage image(size, monoFormat);
+ image.setColor(0, QColor(Qt::color0).rgb());
+ image.setColor(1, QColor(Qt::color1).rgb());
+
+ // Need to memcpy each line separatly since QImage is 32bit aligned and
+ // this data is only byte aligned...
+ int bytesPerLine = (size.width() + 7) / 8;
+ for (int y = 0; y < size.height(); ++y)
+ memcpy(image.scanLine(y), bits + bytesPerLine * y, bytesPerLine);
+ return QBitmap::fromImage(image);
+}
+
+/*!
+ Returns a copy of this bitmap, transformed according to the given
+ \a matrix.
+
+ \sa QPixmap::transformed()
+ */
+QBitmap QBitmap::transformed(const QTransform &matrix) const
+{
+ QBitmap bm = QPixmap::transformed(matrix);
+ return bm;
+}
+
+/*!
+ \overload
+ \obsolete
+
+ This convenience function converts the \a matrix to a QTransform
+ and calls the overloaded function.
+*/
+QBitmap QBitmap::transformed(const QMatrix &matrix) const
+{
+ return transformed(QTransform(matrix));
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ \fn QBitmap QBitmap::xForm(const QMatrix &matrix) const
+
+ Returns a copy of this bitmap, transformed according to the given
+ \a matrix.
+
+ Use transformed() instead.
+*/
+
+/*!
+ \fn QBitmap::QBitmap(const QSize &size, bool clear)
+
+ Constructs a bitmap with the given \a size. If \a clear is true,
+ the bits are initialized to Qt::color0.
+
+ Use the corresponding QBitmap() constructor instead, and then call
+ the clear() function if the \a clear parameter is true.
+*/
+
+/*!
+ \fn QBitmap::QBitmap(int width, int height, bool clear)
+
+ Constructs a bitmap with the given \a width and \a height. If \a
+ clear is true, the bits are initialized to Qt::color0.
+
+ Use the corresponding QBitmap() constructor instead, and then call
+ the clear() function if the \a clear parameter is true.
+*/
+
+/*!
+ \fn QBitmap::QBitmap(int width, int height, const uchar *bits, bool isXbitmap)
+
+ Constructs a bitmap with the given \a width and \a height, and
+ sets the contents to the \a bits supplied. The \a isXbitmap flag
+ should be true if \a bits was generated by the X11 bitmap
+ program.
+
+ Use the static fromData() function instead. If \a isXbitmap is
+ true, use the default bit order(QImage_FormatMonoLSB) otherwise
+ use QImage::Format_Mono.
+
+ \omit
+ The X bitmap bit order is little endian. The QImage
+ documentation discusses bit order of monochrome images. Opposed to
+ QImage, the data has to be byte aligned.
+
+ Example (creates an arrow bitmap):
+ \snippet doc/src/snippets/code/src_gui_image_qbitmap.cpp 0
+ \endomit
+*/
+
+
+/*!
+ \fn QBitmap::QBitmap(const QSize &size, const uchar *bits, bool isXbitmap)
+
+ \overload
+
+ Constructs a bitmap with the given \a size, and sets the contents
+ to the \a bits supplied. The \a isXbitmap flag should be true if
+ \a bits was generated by the X11 bitmap program.
+
+ \omit
+ The X bitmap bit order is little endian. The QImage documentation
+ discusses bit order of monochrome images.
+ \endomit
+
+ Use the static fromData() function instead. If \a isXbitmap is
+ true, use the default bit order(QImage_FormatMonoLSB) otherwise
+ use QImage::Format_Mono.
+*/
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/gui/image/qbitmap.h b/src/gui/image/qbitmap.h
new file mode 100644
index 0000000000..f1771e3e43
--- /dev/null
+++ b/src/gui/image/qbitmap.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBITMAP_H
+#define QBITMAP_H
+
+#include <QtGui/qpixmap.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QVariant;
+
+class Q_GUI_EXPORT QBitmap : public QPixmap
+{
+public:
+ QBitmap();
+ QBitmap(const QPixmap &);
+ QBitmap(int w, int h);
+ explicit QBitmap(const QSize &);
+ explicit QBitmap(const QString &fileName, const char *format=0);
+ ~QBitmap();
+
+ QBitmap &operator=(const QPixmap &);
+ inline void swap(QBitmap &other) { QPixmap::swap(other); } // prevent QBitmap<->QPixmap swaps
+ operator QVariant() const;
+
+ inline void clear() { fill(Qt::color0); }
+
+ static QBitmap fromImage(const QImage &image, Qt::ImageConversionFlags flags = Qt::AutoColor);
+ static QBitmap fromData(const QSize &size, const uchar *bits,
+ QImage::Format monoFormat = QImage::Format_MonoLSB);
+
+ QBitmap transformed(const QMatrix &) const;
+ QBitmap transformed(const QTransform &matrix) const;
+#ifdef QT3_SUPPORT
+ inline QT3_SUPPORT_CONSTRUCTOR QBitmap(int w, int h, bool clear);
+ inline QT3_SUPPORT_CONSTRUCTOR QBitmap(const QSize &, bool clear);
+ QT3_SUPPORT_CONSTRUCTOR QBitmap(int w, int h, const uchar *bits, bool isXbitmap=false);
+ QT3_SUPPORT_CONSTRUCTOR QBitmap(const QSize &, const uchar *bits, bool isXbitmap=false);
+ inline QT3_SUPPORT QBitmap xForm(const QMatrix &matrix) const { return transformed(QTransform(matrix)); }
+ QT3_SUPPORT_CONSTRUCTOR QBitmap(const QImage &image) { *this = fromImage(image); }
+ QT3_SUPPORT QBitmap &operator=(const QImage &image) { *this = fromImage(image); return *this; }
+#endif
+
+ typedef QExplicitlySharedDataPointer<QPixmapData> DataPtr;
+};
+Q_DECLARE_SHARED(QBitmap)
+
+#ifdef QT3_SUPPORT
+inline QBitmap::QBitmap(int w, int h, bool clear)
+ : QPixmap(QSize(w, h), 1)
+{
+ if (clear) this->clear();
+}
+
+inline QBitmap::QBitmap(const QSize &size, bool clear)
+ : QPixmap(size, 1)
+{
+ if (clear) this->clear();
+}
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QBITMAP_H
diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp
new file mode 100644
index 0000000000..6dea9d9917
--- /dev/null
+++ b/src/gui/image/qbmphandler.cpp
@@ -0,0 +1,837 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qbmphandler_p.h"
+
+#ifndef QT_NO_IMAGEFORMAT_BMP
+
+#include <qimage.h>
+#include <qvariant.h>
+#include <qvector.h>
+
+QT_BEGIN_NAMESPACE
+
+static void swapPixel01(QImage *image) // 1-bpp: swap 0 and 1 pixels
+{
+ int i;
+ if (image->depth() == 1 && image->colorCount() == 2) {
+ register uint *p = (uint *)image->bits();
+ int nbytes = image->byteCount();
+ for (i=0; i<nbytes/4; i++) {
+ *p = ~*p;
+ p++;
+ }
+ uchar *p2 = (uchar *)p;
+ for (i=0; i<(nbytes&3); i++) {
+ *p2 = ~*p2;
+ p2++;
+ }
+ QRgb t = image->color(0); // swap color 0 and 1
+ image->setColor(0, image->color(1));
+ image->setColor(1, t);
+ }
+}
+
+/*
+ QImageIO::defineIOHandler("BMP", "^BM", 0,
+ read_bmp_image, write_bmp_image);
+*/
+
+/*****************************************************************************
+ BMP (DIB) image read/write functions
+ *****************************************************************************/
+
+const int BMP_FILEHDR_SIZE = 14; // size of BMP_FILEHDR data
+
+static QDataStream &operator>>(QDataStream &s, BMP_FILEHDR &bf)
+{ // read file header
+ s.readRawData(bf.bfType, 2);
+ s >> bf.bfSize >> bf.bfReserved1 >> bf.bfReserved2 >> bf.bfOffBits;
+ return s;
+}
+
+static QDataStream &operator<<(QDataStream &s, const BMP_FILEHDR &bf)
+{ // write file header
+ s.writeRawData(bf.bfType, 2);
+ s << bf.bfSize << bf.bfReserved1 << bf.bfReserved2 << bf.bfOffBits;
+ return s;
+}
+
+
+const int BMP_OLD = 12; // old Windows/OS2 BMP size
+const int BMP_WIN = 40; // new Windows BMP size
+const int BMP_OS2 = 64; // new OS/2 BMP size
+
+const int BMP_RGB = 0; // no compression
+const int BMP_RLE8 = 1; // run-length encoded, 8 bits
+const int BMP_RLE4 = 2; // run-length encoded, 4 bits
+const int BMP_BITFIELDS = 3; // RGB values encoded in data as bit-fields
+
+
+static QDataStream &operator>>(QDataStream &s, BMP_INFOHDR &bi)
+{
+ s >> bi.biSize;
+ if (bi.biSize == BMP_WIN || bi.biSize == BMP_OS2) {
+ s >> bi.biWidth >> bi.biHeight >> bi.biPlanes >> bi.biBitCount;
+ s >> bi.biCompression >> bi.biSizeImage;
+ s >> bi.biXPelsPerMeter >> bi.biYPelsPerMeter;
+ s >> bi.biClrUsed >> bi.biClrImportant;
+ }
+ else { // probably old Windows format
+ qint16 w, h;
+ s >> w >> h >> bi.biPlanes >> bi.biBitCount;
+ bi.biWidth = w;
+ bi.biHeight = h;
+ bi.biCompression = BMP_RGB; // no compression
+ bi.biSizeImage = 0;
+ bi.biXPelsPerMeter = bi.biYPelsPerMeter = 0;
+ bi.biClrUsed = bi.biClrImportant = 0;
+ }
+ return s;
+}
+
+static QDataStream &operator<<(QDataStream &s, const BMP_INFOHDR &bi)
+{
+ s << bi.biSize;
+ s << bi.biWidth << bi.biHeight;
+ s << bi.biPlanes;
+ s << bi.biBitCount;
+ s << bi.biCompression;
+ s << bi.biSizeImage;
+ s << bi.biXPelsPerMeter << bi.biYPelsPerMeter;
+ s << bi.biClrUsed << bi.biClrImportant;
+ return s;
+}
+
+static int calc_shift(int mask)
+{
+ int result = 0;
+ while (mask && !(mask & 1)) {
+ result++;
+ mask >>= 1;
+ }
+ return result;
+}
+
+static bool read_dib_fileheader(QDataStream &s, BMP_FILEHDR &bf)
+{
+ // read BMP file header
+ s >> bf;
+ if (s.status() != QDataStream::Ok)
+ return false;
+
+ // check header
+ if (qstrncmp(bf.bfType,"BM",2) != 0)
+ return false;
+
+ return true;
+}
+
+static bool read_dib_infoheader(QDataStream &s, BMP_INFOHDR &bi)
+{
+ s >> bi; // read BMP info header
+ if (s.status() != QDataStream::Ok)
+ return false;
+
+ int nbits = bi.biBitCount;
+ int comp = bi.biCompression;
+ if (!(nbits == 1 || nbits == 4 || nbits == 8 || nbits == 16 || nbits == 24 || nbits == 32) ||
+ bi.biPlanes != 1 || comp > BMP_BITFIELDS)
+ return false; // weird BMP image
+ if (!(comp == BMP_RGB || (nbits == 4 && comp == BMP_RLE4) ||
+ (nbits == 8 && comp == BMP_RLE8) || ((nbits == 16 || nbits == 32) && comp == BMP_BITFIELDS)))
+ return false; // weird compression type
+
+ return true;
+}
+
+static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int startpos, QImage &image)
+{
+ QIODevice* d = s.device();
+ if (d->atEnd()) // end of stream/file
+ return false;
+#if 0
+ qDebug("offset...........%d", offset);
+ qDebug("startpos.........%d", startpos);
+ qDebug("biSize...........%d", bi.biSize);
+ qDebug("biWidth..........%d", bi.biWidth);
+ qDebug("biHeight.........%d", bi.biHeight);
+ qDebug("biPlanes.........%d", bi.biPlanes);
+ qDebug("biBitCount.......%d", bi.biBitCount);
+ qDebug("biCompression....%d", bi.biCompression);
+ qDebug("biSizeImage......%d", bi.biSizeImage);
+ qDebug("biXPelsPerMeter..%d", bi.biXPelsPerMeter);
+ qDebug("biYPelsPerMeter..%d", bi.biYPelsPerMeter);
+ qDebug("biClrUsed........%d", bi.biClrUsed);
+ qDebug("biClrImportant...%d", bi.biClrImportant);
+#endif
+ int w = bi.biWidth, h = bi.biHeight, nbits = bi.biBitCount;
+ int t = bi.biSize, comp = bi.biCompression;
+ int red_mask = 0;
+ int green_mask = 0;
+ int blue_mask = 0;
+ int red_shift = 0;
+ int green_shift = 0;
+ int blue_shift = 0;
+ int red_scale = 0;
+ int green_scale = 0;
+ int blue_scale = 0;
+
+ int ncols = 0;
+ int depth = 0;
+ QImage::Format format;
+ switch (nbits) {
+ case 32:
+ case 24:
+ case 16:
+ depth = 32;
+ format = QImage::Format_RGB32;
+ break;
+ case 8:
+ case 4:
+ depth = 8;
+ format = QImage::Format_Indexed8;
+ break;
+ default:
+ depth = 1;
+ format = QImage::Format_Mono;
+ }
+
+ if (bi.biHeight < 0)
+ h = -h; // support images with negative height
+
+ if (image.size() != QSize(w, h) || image.format() != format) {
+ image = QImage(w, h, format);
+ if (image.isNull()) // could not create image
+ return false;
+ }
+
+ if (depth != 32) {
+ ncols = bi.biClrUsed ? bi.biClrUsed : 1 << nbits;
+ if (ncols > 256) // sanity check - don't run out of mem if color table is broken
+ return false;
+ image.setColorCount(ncols);
+ }
+
+ image.setDotsPerMeterX(bi.biXPelsPerMeter);
+ image.setDotsPerMeterY(bi.biYPelsPerMeter);
+
+ if (!d->isSequential())
+ d->seek(startpos + BMP_FILEHDR_SIZE + bi.biSize); // goto start of colormap
+
+ if (ncols > 0) { // read color table
+ uchar rgb[4];
+ int rgb_len = t == BMP_OLD ? 3 : 4;
+ for (int i=0; i<ncols; i++) {
+ if (d->read((char *)rgb, rgb_len) != rgb_len)
+ return false;
+ image.setColor(i, qRgb(rgb[2],rgb[1],rgb[0]));
+ if (d->atEnd()) // truncated file
+ return false;
+ }
+ } else if (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32)) {
+ if (d->read((char *)&red_mask, sizeof(red_mask)) != sizeof(red_mask))
+ return false;
+ if (d->read((char *)&green_mask, sizeof(green_mask)) != sizeof(green_mask))
+ return false;
+ if (d->read((char *)&blue_mask, sizeof(blue_mask)) != sizeof(blue_mask))
+ return false;
+ red_shift = calc_shift(red_mask);
+ red_scale = 256 / ((red_mask >> red_shift) + 1);
+ green_shift = calc_shift(green_mask);
+ green_scale = 256 / ((green_mask >> green_shift) + 1);
+ blue_shift = calc_shift(blue_mask);
+ blue_scale = 256 / ((blue_mask >> blue_shift) + 1);
+ } else if (comp == BMP_RGB && (nbits == 24 || nbits == 32)) {
+ blue_mask = 0x000000ff;
+ green_mask = 0x0000ff00;
+ red_mask = 0x00ff0000;
+ blue_shift = 0;
+ green_shift = 8;
+ red_shift = 16;
+ blue_scale = green_scale = red_scale = 1;
+ } else if (comp == BMP_RGB && nbits == 16) {
+ blue_mask = 0x001f;
+ green_mask = 0x03e0;
+ red_mask = 0x7c00;
+ blue_shift = 0;
+ green_shift = 2;
+ red_shift = 7;
+ red_scale = 1;
+ green_scale = 1;
+ blue_scale = 8;
+ }
+
+ // offset can be bogus, be careful
+ if (offset>=0 && startpos + offset > d->pos()) {
+ if (!d->isSequential())
+ d->seek(startpos + offset); // start of image data
+ }
+
+ int bpl = image.bytesPerLine();
+ uchar *data = image.bits();
+
+ if (nbits == 1) { // 1 bit BMP image
+ while (--h >= 0) {
+ if (d->read((char*)(data + h*bpl), bpl) != bpl)
+ break;
+ }
+ if (ncols == 2 && qGray(image.color(0)) < qGray(image.color(1)))
+ swapPixel01(&image); // pixel 0 is white!
+ }
+
+ else if (nbits == 4) { // 4 bit BMP image
+ int buflen = ((w+7)/8)*4;
+ uchar *buf = new uchar[buflen];
+ if (comp == BMP_RLE4) { // run length compression
+ int x=0, y=0, c, i;
+ quint8 b;
+ register uchar *p = data + (h-1)*bpl;
+ const uchar *endp = p + w;
+ while (y < h) {
+ if (!d->getChar((char *)&b))
+ break;
+ if (b == 0) { // escape code
+ if (!d->getChar((char *)&b) || b == 1) {
+ y = h; // exit loop
+ } else switch (b) {
+ case 0: // end of line
+ x = 0;
+ y++;
+ p = data + (h-y-1)*bpl;
+ break;
+ case 2: // delta (jump)
+ {
+ quint8 tmp;
+ d->getChar((char *)&tmp);
+ x += tmp;
+ d->getChar((char *)&tmp);
+ y += tmp;
+ }
+
+ // Protection
+ if ((uint)x >= (uint)w)
+ x = w-1;
+ if ((uint)y >= (uint)h)
+ y = h-1;
+
+ p = data + (h-y-1)*bpl + x;
+ break;
+ default: // absolute mode
+ // Protection
+ if (p + b > endp)
+ b = endp-p;
+
+ i = (c = b)/2;
+ while (i--) {
+ d->getChar((char *)&b);
+ *p++ = b >> 4;
+ *p++ = b & 0x0f;
+ }
+ if (c & 1) {
+ unsigned char tmp;
+ d->getChar((char *)&tmp);
+ *p++ = tmp >> 4;
+ }
+ if ((((c & 3) + 1) & 2) == 2)
+ d->getChar(0); // align on word boundary
+ x += c;
+ }
+ } else { // encoded mode
+ // Protection
+ if (p + b > endp)
+ b = endp-p;
+
+ i = (c = b)/2;
+ d->getChar((char *)&b); // 2 pixels to be repeated
+ while (i--) {
+ *p++ = b >> 4;
+ *p++ = b & 0x0f;
+ }
+ if (c & 1)
+ *p++ = b >> 4;
+ x += c;
+ }
+ }
+ } else if (comp == BMP_RGB) { // no compression
+ memset(data, 0, h*bpl);
+ while (--h >= 0) {
+ if (d->read((char*)buf,buflen) != buflen)
+ break;
+ register uchar *p = data + h*bpl;
+ uchar *b = buf;
+ for (int i=0; i<w/2; i++) { // convert nibbles to bytes
+ *p++ = *b >> 4;
+ *p++ = *b++ & 0x0f;
+ }
+ if (w & 1) // the last nibble
+ *p = *b >> 4;
+ }
+ }
+ delete [] buf;
+ }
+
+ else if (nbits == 8) { // 8 bit BMP image
+ if (comp == BMP_RLE8) { // run length compression
+ int x=0, y=0;
+ quint8 b;
+ register uchar *p = data + (h-1)*bpl;
+ const uchar *endp = p + w;
+ while (y < h) {
+ if (!d->getChar((char *)&b))
+ break;
+ if (b == 0) { // escape code
+ if (!d->getChar((char *)&b) || b == 1) {
+ y = h; // exit loop
+ } else switch (b) {
+ case 0: // end of line
+ x = 0;
+ y++;
+ p = data + (h-y-1)*bpl;
+ break;
+ case 2: // delta (jump)
+ // Protection
+ if ((uint)x >= (uint)w)
+ x = w-1;
+ if ((uint)y >= (uint)h)
+ y = h-1;
+
+ {
+ quint8 tmp;
+ d->getChar((char *)&tmp);
+ x += tmp;
+ d->getChar((char *)&tmp);
+ y += tmp;
+ }
+ p = data + (h-y-1)*bpl + x;
+ break;
+ default: // absolute mode
+ // Protection
+ if (p + b > endp)
+ b = endp-p;
+
+ if (d->read((char *)p, b) != b)
+ return false;
+ if ((b & 1) == 1)
+ d->getChar(0); // align on word boundary
+ x += b;
+ p += b;
+ }
+ } else { // encoded mode
+ // Protection
+ if (p + b > endp)
+ b = endp-p;
+
+ char tmp;
+ d->getChar(&tmp);
+ memset(p, tmp, b); // repeat pixel
+ x += b;
+ p += b;
+ }
+ }
+ } else if (comp == BMP_RGB) { // uncompressed
+ while (--h >= 0) {
+ if (d->read((char *)data + h*bpl, bpl) != bpl)
+ break;
+ }
+ }
+ }
+
+ else if (nbits == 16 || nbits == 24 || nbits == 32) { // 16,24,32 bit BMP image
+ register QRgb *p;
+ QRgb *end;
+ uchar *buf24 = new uchar[bpl];
+ int bpl24 = ((w*nbits+31)/32)*4;
+ uchar *b;
+ int c;
+
+ while (--h >= 0) {
+ p = (QRgb *)(data + h*bpl);
+ end = p + w;
+ if (d->read((char *)buf24,bpl24) != bpl24)
+ break;
+ b = buf24;
+ while (p < end) {
+ c = *(uchar*)b | (*(uchar*)(b+1)<<8);
+ if (nbits != 16)
+ c |= *(uchar*)(b+2)<<16;
+ *p++ = qRgb(((c & red_mask) >> red_shift) * red_scale,
+ ((c & green_mask) >> green_shift) * green_scale,
+ ((c & blue_mask) >> blue_shift) * blue_scale);
+ b += nbits/8;
+ }
+ }
+ delete[] buf24;
+ }
+
+ if (bi.biHeight < 0) {
+ // Flip the image
+ uchar *buf = new uchar[bpl];
+ h = -bi.biHeight;
+ for (int y = 0; y < h/2; ++y) {
+ memcpy(buf, data + y*bpl, bpl);
+ memcpy(data + y*bpl, data + (h-y-1)*bpl, bpl);
+ memcpy(data + (h-y-1)*bpl, buf, bpl);
+ }
+ delete [] buf;
+ }
+
+ return true;
+}
+
+// this is also used in qmime_win.cpp
+bool qt_write_dib(QDataStream &s, QImage image)
+{
+ int nbits;
+ int bpl_bmp;
+ int bpl = image.bytesPerLine();
+
+ QIODevice* d = s.device();
+ if (!d->isWritable())
+ return false;
+
+ if (image.depth() == 8 && image.colorCount() <= 16) {
+ bpl_bmp = (((bpl+1)/2+3)/4)*4;
+ nbits = 4;
+ } else if (image.depth() == 32) {
+ bpl_bmp = ((image.width()*24+31)/32)*4;
+ nbits = 24;
+#ifdef Q_WS_QWS
+ } else if (image.depth() == 1 || image.depth() == 8) {
+ // Qt for Embedded Linux doesn't word align.
+ bpl_bmp = ((image.width()*image.depth()+31)/32)*4;
+ nbits = image.depth();
+#endif
+ } else {
+ bpl_bmp = bpl;
+ nbits = image.depth();
+ }
+
+ BMP_INFOHDR bi;
+ bi.biSize = BMP_WIN; // build info header
+ bi.biWidth = image.width();
+ bi.biHeight = image.height();
+ bi.biPlanes = 1;
+ bi.biBitCount = nbits;
+ bi.biCompression = BMP_RGB;
+ bi.biSizeImage = bpl_bmp*image.height();
+ bi.biXPelsPerMeter = image.dotsPerMeterX() ? image.dotsPerMeterX()
+ : 2834; // 72 dpi default
+ bi.biYPelsPerMeter = image.dotsPerMeterY() ? image.dotsPerMeterY() : 2834;
+ bi.biClrUsed = image.colorCount();
+ bi.biClrImportant = image.colorCount();
+ s << bi; // write info header
+ if (s.status() != QDataStream::Ok)
+ return false;
+
+ if (image.depth() != 32) { // write color table
+ uchar *color_table = new uchar[4*image.colorCount()];
+ uchar *rgb = color_table;
+ QVector<QRgb> c = image.colorTable();
+ for (int i=0; i<image.colorCount(); i++) {
+ *rgb++ = qBlue (c[i]);
+ *rgb++ = qGreen(c[i]);
+ *rgb++ = qRed (c[i]);
+ *rgb++ = 0;
+ }
+ if (d->write((char *)color_table, 4*image.colorCount()) == -1) {
+ delete [] color_table;
+ return false;
+ }
+ delete [] color_table;
+ }
+
+ if (image.format() == QImage::Format_MonoLSB)
+ image = image.convertToFormat(QImage::Format_Mono);
+
+ int y;
+
+ if (nbits == 1 || nbits == 8) { // direct output
+#ifdef Q_WS_QWS
+ // Qt for Embedded Linux doesn't word align.
+ int pad = bpl_bmp - bpl;
+ char padding[4];
+#endif
+ for (y=image.height()-1; y>=0; y--) {
+ if (d->write((char*)image.scanLine(y), bpl) == -1)
+ return false;
+#ifdef Q_WS_QWS
+ if (d->write(padding, pad) == -1)
+ return false;
+#endif
+ }
+ return true;
+ }
+
+ uchar *buf = new uchar[bpl_bmp];
+ uchar *b, *end;
+ register uchar *p;
+
+ memset(buf, 0, bpl_bmp);
+ for (y=image.height()-1; y>=0; y--) { // write the image bits
+ if (nbits == 4) { // convert 8 -> 4 bits
+ p = image.scanLine(y);
+ b = buf;
+ end = b + image.width()/2;
+ while (b < end) {
+ *b++ = (*p << 4) | (*(p+1) & 0x0f);
+ p += 2;
+ }
+ if (image.width() & 1)
+ *b = *p << 4;
+ } else { // 32 bits
+ QRgb *p = (QRgb *)image.scanLine(y);
+ QRgb *end = p + image.width();
+ b = buf;
+ while (p < end) {
+ *b++ = qBlue(*p);
+ *b++ = qGreen(*p);
+ *b++ = qRed(*p);
+ p++;
+ }
+ }
+ if (bpl_bmp != d->write((char*)buf, bpl_bmp)) {
+ delete[] buf;
+ return false;
+ }
+ }
+ delete[] buf;
+ return true;
+}
+
+// this is also used in qmime_win.cpp
+bool qt_read_dib(QDataStream &s, QImage &image)
+{
+ BMP_INFOHDR bi;
+ if (!read_dib_infoheader(s, bi))
+ return false;
+ return read_dib_body(s, bi, -1, -BMP_FILEHDR_SIZE, image);
+}
+
+QBmpHandler::QBmpHandler()
+ : state(Ready)
+{
+}
+
+bool QBmpHandler::readHeader()
+{
+ state = Error;
+
+ QIODevice *d = device();
+ QDataStream s(d);
+ startpos = d->pos();
+
+ // Intel byte order
+ s.setByteOrder(QDataStream::LittleEndian);
+
+ // read BMP file header
+ if (!read_dib_fileheader(s, fileHeader))
+ return false;
+
+ // read BMP info header
+ if (!read_dib_infoheader(s, infoHeader))
+ return false;
+
+ state = ReadHeader;
+ return true;
+}
+
+bool QBmpHandler::canRead() const
+{
+ if (state == Ready && !canRead(device()))
+ return false;
+
+ if (state != Error) {
+ setFormat("bmp");
+ return true;
+ }
+
+ return false;
+}
+
+bool QBmpHandler::canRead(QIODevice *device)
+{
+ if (!device) {
+ qWarning("QBmpHandler::canRead() called with 0 pointer");
+ return false;
+ }
+
+ char head[2];
+ if (device->peek(head, sizeof(head)) != sizeof(head))
+ return false;
+
+ return (qstrncmp(head, "BM", 2) == 0);
+}
+
+bool QBmpHandler::read(QImage *image)
+{
+ if (state == Error)
+ return false;
+
+ if (!image) {
+ qWarning("QBmpHandler::read: cannot read into null pointer");
+ return false;
+ }
+
+ if (state == Ready && !readHeader()) {
+ state = Error;
+ return false;
+ }
+
+ QIODevice *d = device();
+ QDataStream s(d);
+
+ // Intel byte order
+ s.setByteOrder(QDataStream::LittleEndian);
+
+ // read image
+ if (!read_dib_body(s, infoHeader, fileHeader.bfOffBits, startpos, *image))
+ return false;
+
+ state = Ready;
+ return true;
+}
+
+bool QBmpHandler::write(const QImage &img)
+{
+ QImage image;
+ switch (img.format()) {
+ case QImage::Format_ARGB8565_Premultiplied:
+ case QImage::Format_ARGB8555_Premultiplied:
+ case QImage::Format_ARGB6666_Premultiplied:
+ case QImage::Format_ARGB4444_Premultiplied:
+ image = img.convertToFormat(QImage::Format_ARGB32);
+ break;
+ case QImage::Format_RGB16:
+ case QImage::Format_RGB888:
+ case QImage::Format_RGB666:
+ case QImage::Format_RGB555:
+ case QImage::Format_RGB444:
+ image = img.convertToFormat(QImage::Format_RGB32);
+ break;
+ default:
+ image = img;
+ }
+
+ QIODevice *d = device();
+ QDataStream s(d);
+ BMP_FILEHDR bf;
+ int bpl_bmp;
+ int bpl = image.bytesPerLine();
+
+ // Code partially repeated in qt_write_dib
+ if (image.depth() == 8 && image.colorCount() <= 16) {
+ bpl_bmp = (((bpl+1)/2+3)/4)*4;
+ } else if (image.depth() == 32) {
+ bpl_bmp = ((image.width()*24+31)/32)*4;
+ } else {
+ bpl_bmp = bpl;
+ }
+
+ // Intel byte order
+ s.setByteOrder(QDataStream::LittleEndian);
+
+ // build file header
+ memcpy(bf.bfType, "BM", 2);
+
+ // write file header
+ bf.bfReserved1 = 0;
+ bf.bfReserved2 = 0;
+ bf.bfOffBits = BMP_FILEHDR_SIZE + BMP_WIN + image.colorCount() * 4;
+ bf.bfSize = bf.bfOffBits + bpl_bmp*image.height();
+ s << bf;
+
+ // write image
+ return qt_write_dib(s, image);
+}
+
+bool QBmpHandler::supportsOption(ImageOption option) const
+{
+ return option == Size
+ || option == ImageFormat;
+}
+
+QVariant QBmpHandler::option(ImageOption option) const
+{
+ if (option == Size) {
+ if (state == Error)
+ return QVariant();
+ if (state == Ready && !const_cast<QBmpHandler*>(this)->readHeader())
+ return QVariant();
+ return QSize(infoHeader.biWidth, infoHeader.biHeight);
+ } else if (option == ImageFormat) {
+ if (state == Error)
+ return QVariant();
+ if (state == Ready && !const_cast<QBmpHandler*>(this)->readHeader())
+ return QVariant();
+ QImage::Format format;
+ switch (infoHeader.biBitCount) {
+ case 32:
+ case 24:
+ case 16:
+ format = QImage::Format_RGB32;
+ break;
+ case 8:
+ case 4:
+ format = QImage::Format_Indexed8;
+ break;
+ default:
+ format = QImage::Format_Mono;
+ }
+ return format;
+ }
+ return QVariant();
+}
+
+void QBmpHandler::setOption(ImageOption option, const QVariant &value)
+{
+ Q_UNUSED(option);
+ Q_UNUSED(value);
+}
+
+QByteArray QBmpHandler::name() const
+{
+ return "bmp";
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_IMAGEFORMAT_BMP
diff --git a/src/gui/image/qbmphandler_p.h b/src/gui/image/qbmphandler_p.h
new file mode 100644
index 0000000000..3bf08e8395
--- /dev/null
+++ b/src/gui/image/qbmphandler_p.h
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBMPHANDLER_P_H
+#define QBMPHANDLER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "QtGui/qimageiohandler.h"
+
+#ifndef QT_NO_IMAGEFORMAT_BMP
+
+QT_BEGIN_NAMESPACE
+
+struct BMP_FILEHDR { // BMP file header
+ char bfType[2]; // "BM"
+ qint32 bfSize; // size of file
+ qint16 bfReserved1;
+ qint16 bfReserved2;
+ qint32 bfOffBits; // pointer to the pixmap bits
+};
+
+struct BMP_INFOHDR { // BMP information header
+ qint32 biSize; // size of this struct
+ qint32 biWidth; // pixmap width
+ qint32 biHeight; // pixmap height
+ qint16 biPlanes; // should be 1
+ qint16 biBitCount; // number of bits per pixel
+ qint32 biCompression; // compression method
+ qint32 biSizeImage; // size of image
+ qint32 biXPelsPerMeter; // horizontal resolution
+ qint32 biYPelsPerMeter; // vertical resolution
+ qint32 biClrUsed; // number of colors used
+ qint32 biClrImportant; // number of important colors
+};
+
+class QBmpHandler : public QImageIOHandler
+{
+public:
+ QBmpHandler();
+ bool canRead() const;
+ bool read(QImage *image);
+ bool write(const QImage &image);
+
+ QByteArray name() const;
+
+ static bool canRead(QIODevice *device);
+
+ QVariant option(ImageOption option) const;
+ void setOption(ImageOption option, const QVariant &value);
+ bool supportsOption(ImageOption option) const;
+
+private:
+ bool readHeader();
+ enum State {
+ Ready,
+ ReadHeader,
+ Error
+ };
+ State state;
+ BMP_FILEHDR fileHeader;
+ BMP_INFOHDR infoHeader;
+ int startpos;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_IMAGEFORMAT_BMP
+
+#endif // QBMPHANDLER_P_H
diff --git a/src/gui/image/qgifhandler.cpp b/src/gui/image/qgifhandler.cpp
new file mode 100644
index 0000000000..7cb7373b44
--- /dev/null
+++ b/src/gui/image/qgifhandler.cpp
@@ -0,0 +1,1214 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+** WARNING:
+** A separate license from Unisys may be required to use the gif
+** reader. See http://www.unisys.com/about__unisys/lzw/
+** for information from Unisys
+**
+****************************************************************************/
+
+#include "qgifhandler_p.h"
+
+#include <qimage.h>
+#include <qiodevice.h>
+#include <qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+#define Q_TRANSPARENT 0x00ffffff
+
+// avoid going through QImage::scanLine() which calls detach
+#define FAST_SCAN_LINE(bits, bpl, y) (bits + (y) * bpl)
+
+
+/*
+ Incremental image decoder for GIF image format.
+
+ This subclass of QImageFormat decodes GIF format images,
+ including animated GIFs. Internally in
+*/
+
+class QGIFFormat {
+public:
+ QGIFFormat();
+ ~QGIFFormat();
+
+ int decode(QImage *image, const uchar* buffer, int length,
+ int *nextFrameDelay, int *loopCount);
+ static void scan(QIODevice *device, QVector<QSize> *imageSizes, int *loopCount);
+
+ bool newFrame;
+ bool partialNewFrame;
+
+private:
+ void fillRect(QImage *image, int x, int y, int w, int h, QRgb col);
+ inline QRgb color(uchar index) const;
+
+ // GIF specific stuff
+ QRgb* globalcmap;
+ QRgb* localcmap;
+ QImage backingstore;
+ unsigned char hold[16];
+ bool gif89;
+ int count;
+ int ccount;
+ int expectcount;
+ enum State {
+ Header,
+ LogicalScreenDescriptor,
+ GlobalColorMap,
+ LocalColorMap,
+ Introducer,
+ ImageDescriptor,
+ TableImageLZWSize,
+ ImageDataBlockSize,
+ ImageDataBlock,
+ ExtensionLabel,
+ GraphicControlExtension,
+ ApplicationExtension,
+ NetscapeExtensionBlockSize,
+ NetscapeExtensionBlock,
+ SkipBlockSize,
+ SkipBlock,
+ Done,
+ Error
+ } state;
+ int gncols;
+ int lncols;
+ int ncols;
+ int lzwsize;
+ bool lcmap;
+ int swidth, sheight;
+ int width, height;
+ int left, top, right, bottom;
+ enum Disposal { NoDisposal, DoNotChange, RestoreBackground, RestoreImage };
+ Disposal disposal;
+ bool disposed;
+ int trans_index;
+ bool gcmap;
+ int bgcol;
+ int interlace;
+ int accum;
+ int bitcount;
+
+ enum { max_lzw_bits=12 }; // (poor-compiler's static const int)
+
+ int code_size, clear_code, end_code, max_code_size, max_code;
+ int firstcode, oldcode, incode;
+ short* table[2];
+ short* stack;
+ short *sp;
+ bool needfirst;
+ int x, y;
+ int frame;
+ bool out_of_bounds;
+ bool digress;
+ void nextY(unsigned char *bits, int bpl);
+ void disposePrevious(QImage *image);
+};
+
+/*!
+ Constructs a QGIFFormat.
+*/
+QGIFFormat::QGIFFormat()
+{
+ globalcmap = 0;
+ localcmap = 0;
+ lncols = 0;
+ gncols = 0;
+ disposal = NoDisposal;
+ out_of_bounds = false;
+ disposed = true;
+ frame = -1;
+ state = Header;
+ count = 0;
+ lcmap = false;
+ newFrame = false;
+ partialNewFrame = false;
+ table[0] = 0;
+ table[1] = 0;
+ stack = 0;
+}
+
+/*!
+ Destroys a QGIFFormat.
+*/
+QGIFFormat::~QGIFFormat()
+{
+ if (globalcmap) delete[] globalcmap;
+ if (localcmap) delete[] localcmap;
+ delete [] stack;
+}
+
+void QGIFFormat::disposePrevious(QImage *image)
+{
+ if (out_of_bounds) {
+ // flush anything that survived
+ // ### Changed: QRect(0, 0, swidth, sheight)
+ }
+
+ // Handle disposal of previous image before processing next one
+
+ if (disposed) return;
+
+ int l = qMin(swidth-1,left);
+ int r = qMin(swidth-1,right);
+ int t = qMin(sheight-1,top);
+ int b = qMin(sheight-1,bottom);
+
+ switch (disposal) {
+ case NoDisposal:
+ break;
+ case DoNotChange:
+ break;
+ case RestoreBackground:
+ if (trans_index>=0) {
+ // Easy: we use the transparent color
+ fillRect(image, l, t, r-l+1, b-t+1, Q_TRANSPARENT);
+ } else if (bgcol>=0) {
+ // Easy: we use the bgcol given
+ fillRect(image, l, t, r-l+1, b-t+1, color(bgcol));
+ } else {
+ // Impossible: We don't know of a bgcol - use pixel 0
+ QRgb *bits = (QRgb*)image->bits();
+ fillRect(image, l, t, r-l+1, b-t+1, bits[0]);
+ }
+ // ### Changed: QRect(l, t, r-l+1, b-t+1)
+ break;
+ case RestoreImage: {
+ if (frame >= 0) {
+ for (int ln=t; ln<=b; ln++) {
+ memcpy(image->scanLine(ln)+l,
+ backingstore.scanLine(ln-t),
+ (r-l+1)*sizeof(QRgb));
+ }
+ // ### Changed: QRect(l, t, r-l+1, b-t+1)
+ }
+ }
+ }
+ disposal = NoDisposal; // Until an extension says otherwise.
+
+ disposed = true;
+}
+
+/*!
+ This function decodes some data into image changes.
+
+ Returns the number of bytes consumed.
+*/
+int QGIFFormat::decode(QImage *image, const uchar *buffer, int length,
+ int *nextFrameDelay, int *loopCount)
+{
+ // We are required to state that
+ // "The Graphics Interchange Format(c) is the Copyright property of
+ // CompuServe Incorporated. GIF(sm) is a Service Mark property of
+ // CompuServe Incorporated."
+
+ if (!stack) {
+ stack = new short[(1 << max_lzw_bits) * 4];
+ table[0] = &stack[(1 << max_lzw_bits) * 2];
+ table[1] = &stack[(1 << max_lzw_bits) * 3];
+ }
+
+ image->detach();
+ int bpl = image->bytesPerLine();
+ unsigned char *bits = image->bits();
+
+#define LM(l, m) (((m)<<8)|l)
+ digress = false;
+ const int initial = length;
+ while (!digress && length) {
+ length--;
+ unsigned char ch=*buffer++;
+ switch (state) {
+ case Header:
+ hold[count++]=ch;
+ if (count==6) {
+ // Header
+ gif89=(hold[3]!='8' || hold[4]!='7');
+ state=LogicalScreenDescriptor;
+ count=0;
+ }
+ break;
+ case LogicalScreenDescriptor:
+ hold[count++]=ch;
+ if (count==7) {
+ // Logical Screen Descriptor
+ swidth=LM(hold[0], hold[1]);
+ sheight=LM(hold[2], hold[3]);
+ gcmap=!!(hold[4]&0x80);
+ //UNUSED: bpchan=(((hold[4]&0x70)>>3)+1);
+ //UNUSED: gcmsortflag=!!(hold[4]&0x08);
+ gncols=2<<(hold[4]&0x7);
+ bgcol=(gcmap) ? hold[5] : -1;
+ //aspect=hold[6] ? double(hold[6]+15)/64.0 : 1.0;
+
+ trans_index = -1;
+ count=0;
+ ncols=gncols;
+ if (gcmap) {
+ ccount=0;
+ state=GlobalColorMap;
+ globalcmap = new QRgb[gncols+1]; // +1 for trans_index
+ globalcmap[gncols] = Q_TRANSPARENT;
+ } else {
+ state=Introducer;
+ }
+ }
+ break;
+ case GlobalColorMap: case LocalColorMap:
+ hold[count++]=ch;
+ if (count==3) {
+ QRgb rgb = qRgb(hold[0], hold[1], hold[2]);
+ if (state == LocalColorMap) {
+ if (ccount < lncols)
+ localcmap[ccount] = rgb;
+ } else {
+ globalcmap[ccount] = rgb;
+ }
+ if (++ccount >= ncols) {
+ if (state == LocalColorMap)
+ state=TableImageLZWSize;
+ else
+ state=Introducer;
+ }
+ count=0;
+ }
+ break;
+ case Introducer:
+ hold[count++]=ch;
+ switch (ch) {
+ case ',':
+ state=ImageDescriptor;
+ break;
+ case '!':
+ state=ExtensionLabel;
+ break;
+ case ';':
+ // ### Changed: QRect(0, 0, swidth, sheight)
+ state=Done;
+ break;
+ default:
+ digress=true;
+ // Unexpected Introducer - ignore block
+ state=Error;
+ }
+ break;
+ case ImageDescriptor:
+ hold[count++]=ch;
+ if (count==10) {
+ int newleft=LM(hold[1], hold[2]);
+ int newtop=LM(hold[3], hold[4]);
+ int newwidth=LM(hold[5], hold[6]);
+ int newheight=LM(hold[7], hold[8]);
+
+ // disbelieve ridiculous logical screen sizes,
+ // unless the image frames are also large.
+ if (swidth/10 > qMax(newwidth,200))
+ swidth = -1;
+ if (sheight/10 > qMax(newheight,200))
+ sheight = -1;
+
+ if (swidth <= 0)
+ swidth = newleft + newwidth;
+ if (sheight <= 0)
+ sheight = newtop + newheight;
+
+ QImage::Format format = trans_index >= 0 ? QImage::Format_ARGB32 : QImage::Format_RGB32;
+ if (image->isNull()) {
+ (*image) = QImage(swidth, sheight, format);
+ bpl = image->bytesPerLine();
+ bits = image->bits();
+ memset(bits, 0, image->byteCount());
+ }
+
+ disposePrevious(image);
+ disposed = false;
+
+ left = newleft;
+ top = newtop;
+ width = newwidth;
+ height = newheight;
+
+ right=qMax(0, qMin(left+width, swidth)-1);
+ bottom=qMax(0, qMin(top+height, sheight)-1);
+ lcmap=!!(hold[9]&0x80);
+ interlace=!!(hold[9]&0x40);
+ //bool lcmsortflag=!!(hold[9]&0x20);
+ lncols=lcmap ? (2<<(hold[9]&0x7)) : 0;
+ if (lncols) {
+ if (localcmap)
+ delete [] localcmap;
+ localcmap = new QRgb[lncols+1];
+ localcmap[lncols] = Q_TRANSPARENT;
+ ncols = lncols;
+ } else {
+ ncols = gncols;
+ }
+ frame++;
+ if (frame == 0) {
+ if (left || top || width<swidth || height<sheight) {
+ // Not full-size image - erase with bg or transparent
+ if (trans_index >= 0) {
+ fillRect(image, 0, 0, swidth, sheight, color(trans_index));
+ // ### Changed: QRect(0, 0, swidth, sheight)
+ } else if (bgcol>=0) {
+ fillRect(image, 0, 0, swidth, sheight, color(bgcol));
+ // ### Changed: QRect(0, 0, swidth, sheight)
+ }
+ }
+ }
+
+ if (disposal == RestoreImage) {
+ int l = qMin(swidth-1,left);
+ int r = qMin(swidth-1,right);
+ int t = qMin(sheight-1,top);
+ int b = qMin(sheight-1,bottom);
+ int w = r-l+1;
+ int h = b-t+1;
+
+ if (backingstore.width() < w
+ || backingstore.height() < h) {
+ // We just use the backing store as a byte array
+ backingstore = QImage(qMax(backingstore.width(), w),
+ qMax(backingstore.height(), h),
+ QImage::Format_RGB32);
+ memset(bits, 0, image->byteCount());
+ }
+ const int dest_bpl = backingstore.bytesPerLine();
+ unsigned char *dest_data = backingstore.bits();
+ for (int ln=0; ln<h; ln++) {
+ memcpy(FAST_SCAN_LINE(dest_data, dest_bpl, ln),
+ FAST_SCAN_LINE(bits, bpl, t+ln) + l, w*sizeof(QRgb));
+ }
+ }
+
+ count=0;
+ if (lcmap) {
+ ccount=0;
+ state=LocalColorMap;
+ } else {
+ state=TableImageLZWSize;
+ }
+ x = left;
+ y = top;
+ accum = 0;
+ bitcount = 0;
+ sp = stack;
+ firstcode = oldcode = 0;
+ needfirst = true;
+ out_of_bounds = left>=swidth || y>=sheight;
+ }
+ break;
+ case TableImageLZWSize: {
+ lzwsize=ch;
+ if (lzwsize > max_lzw_bits) {
+ state=Error;
+ } else {
+ code_size=lzwsize+1;
+ clear_code=1<<lzwsize;
+ end_code=clear_code+1;
+ max_code_size=2*clear_code;
+ max_code=clear_code+2;
+ int i;
+ for (i=0; i<clear_code; i++) {
+ table[0][i]=0;
+ table[1][i]=i;
+ }
+ state=ImageDataBlockSize;
+ }
+ count=0;
+ break;
+ } case ImageDataBlockSize:
+ expectcount=ch;
+ if (expectcount) {
+ state=ImageDataBlock;
+ } else {
+ state=Introducer;
+ digress = true;
+ newFrame = true;
+ }
+ break;
+ case ImageDataBlock:
+ count++;
+ accum|=(ch<<bitcount);
+ bitcount+=8;
+ while (bitcount>=code_size && state==ImageDataBlock) {
+ int code=accum&((1<<code_size)-1);
+ bitcount-=code_size;
+ accum>>=code_size;
+
+ if (code==clear_code) {
+ if (!needfirst) {
+ code_size=lzwsize+1;
+ max_code_size=2*clear_code;
+ max_code=clear_code+2;
+ }
+ needfirst=true;
+ } else if (code==end_code) {
+ bitcount = -32768;
+ // Left the block end arrive
+ } else {
+ if (needfirst) {
+ firstcode=oldcode=code;
+ if (!out_of_bounds && image->height() > y && firstcode!=trans_index)
+ ((QRgb*)FAST_SCAN_LINE(bits, bpl, y))[x] = color(firstcode);
+ x++;
+ if (x>=swidth) out_of_bounds = true;
+ needfirst=false;
+ if (x>=left+width) {
+ x=left;
+ out_of_bounds = left>=swidth || y>=sheight;
+ nextY(bits, bpl);
+ }
+ } else {
+ incode=code;
+ if (code>=max_code) {
+ *sp++=firstcode;
+ code=oldcode;
+ }
+ while (code>=clear_code+2) {
+ if (code >= max_code) {
+ state = Error;
+ return -1;
+ }
+ *sp++=table[1][code];
+ if (code==table[0][code]) {
+ state=Error;
+ return -1;
+ }
+ if (sp-stack>=(1<<(max_lzw_bits))*2) {
+ state=Error;
+ return -1;
+ }
+ code=table[0][code];
+ }
+ if (code < 0) {
+ state = Error;
+ return -1;
+ }
+
+ *sp++=firstcode=table[1][code];
+ code=max_code;
+ if (code<(1<<max_lzw_bits)) {
+ table[0][code]=oldcode;
+ table[1][code]=firstcode;
+ max_code++;
+ if ((max_code>=max_code_size)
+ && (max_code_size<(1<<max_lzw_bits)))
+ {
+ max_code_size*=2;
+ code_size++;
+ }
+ }
+ oldcode=incode;
+ const int h = image->height();
+ const QRgb *map = lcmap ? localcmap : globalcmap;
+ QRgb *line = 0;
+ if (!out_of_bounds && h > y)
+ line = (QRgb*)FAST_SCAN_LINE(bits, bpl, y);
+ while (sp>stack) {
+ const uchar index = *(--sp);
+ if (!out_of_bounds && h > y && index!=trans_index) {
+ if (index > ncols)
+ line[x] = Q_TRANSPARENT;
+ else
+ line[x] = map ? map[index] : 0;
+ }
+ x++;
+ if (x>=swidth) out_of_bounds = true;
+ if (x>=left+width) {
+ x=left;
+ out_of_bounds = left>=swidth || y>=sheight;
+ nextY(bits, bpl);
+ if (!out_of_bounds && h > y)
+ line = (QRgb*)FAST_SCAN_LINE(bits, bpl, y);
+ }
+ }
+ }
+ }
+ }
+ partialNewFrame = true;
+ if (count==expectcount) {
+ count=0;
+ state=ImageDataBlockSize;
+ }
+ break;
+ case ExtensionLabel:
+ switch (ch) {
+ case 0xf9:
+ state=GraphicControlExtension;
+ break;
+ case 0xff:
+ state=ApplicationExtension;
+ break;
+#if 0
+ case 0xfe:
+ state=CommentExtension;
+ break;
+ case 0x01:
+ break;
+#endif
+ default:
+ state=SkipBlockSize;
+ }
+ count=0;
+ break;
+ case ApplicationExtension:
+ if (count<11) hold[count]=ch;
+ count++;
+ if (count==hold[0]+1) {
+ if (qstrncmp((char*)(hold+1), "NETSCAPE", 8)==0) {
+ // Looping extension
+ state=NetscapeExtensionBlockSize;
+ } else {
+ state=SkipBlockSize;
+ }
+ count=0;
+ }
+ break;
+ case NetscapeExtensionBlockSize:
+ expectcount=ch;
+ count=0;
+ if (expectcount) state=NetscapeExtensionBlock;
+ else state=Introducer;
+ break;
+ case NetscapeExtensionBlock:
+ if (count<3) hold[count]=ch;
+ count++;
+ if (count==expectcount) {
+ *loopCount = hold[1]+hold[2]*256;
+ state=SkipBlockSize; // Ignore further blocks
+ }
+ break;
+ case GraphicControlExtension:
+ if (count<5) hold[count]=ch;
+ count++;
+ if (count==hold[0]+1) {
+ disposePrevious(image);
+ disposal=Disposal((hold[1]>>2)&0x7);
+ //UNUSED: waitforuser=!!((hold[1]>>1)&0x1);
+ int delay=count>3 ? LM(hold[2], hold[3]) : 1;
+ // IE and mozilla use a minimum delay of 10. With the minimum delay of 10
+ // we are compatible to them and avoid huge loads on the app and xserver.
+ *nextFrameDelay = (delay < 2 ? 10 : delay) * 10;
+
+ bool havetrans=hold[1]&0x1;
+ trans_index = havetrans ? hold[4] : -1;
+
+ count=0;
+ state=SkipBlockSize;
+ }
+ break;
+ case SkipBlockSize:
+ expectcount=ch;
+ count=0;
+ if (expectcount) state=SkipBlock;
+ else state=Introducer;
+ break;
+ case SkipBlock:
+ count++;
+ if (count==expectcount) state=SkipBlockSize;
+ break;
+ case Done:
+ digress=true;
+ /* Netscape ignores the junk, so we do too.
+ length++; // Unget
+ state=Error; // More calls to this is an error
+ */
+ break;
+ case Error:
+ return -1; // Called again after done.
+ }
+ }
+ return initial-length;
+}
+
+/*!
+ Scans through the data stream defined by \a device and returns the image
+ sizes found in the stream in the \a imageSizes vector.
+*/
+void QGIFFormat::scan(QIODevice *device, QVector<QSize> *imageSizes, int *loopCount)
+{
+ if (!device)
+ return;
+
+ qint64 oldPos = device->pos();
+ if (!device->seek(0))
+ return;
+
+ int colorCount = 0;
+ int localColorCount = 0;
+ int globalColorCount = 0;
+ int colorReadCount = 0;
+ bool localColormap = false;
+ bool globalColormap = false;
+ int count = 0;
+ int blockSize = 0;
+ int imageWidth = 0;
+ int imageHeight = 0;
+ bool done = false;
+ uchar hold[16];
+ State state = Header;
+
+ const int readBufferSize = 40960; // 40k read buffer
+ QByteArray readBuffer(device->read(readBufferSize));
+
+ if (readBuffer.isEmpty()) {
+ device->seek(oldPos);
+ return;
+ }
+
+ // This is a specialized version of the state machine from decode(),
+ // which doesn't do any image decoding or mallocing, and has an
+ // optimized way of skipping SkipBlocks, ImageDataBlocks and
+ // Global/LocalColorMaps.
+
+ while (!readBuffer.isEmpty()) {
+ int length = readBuffer.size();
+ const uchar *buffer = (const uchar *) readBuffer.constData();
+ while (!done && length) {
+ length--;
+ uchar ch = *buffer++;
+ switch (state) {
+ case Header:
+ hold[count++] = ch;
+ if (count == 6) {
+ state = LogicalScreenDescriptor;
+ count = 0;
+ }
+ break;
+ case LogicalScreenDescriptor:
+ hold[count++] = ch;
+ if (count == 7) {
+ imageWidth = LM(hold[0], hold[1]);
+ imageHeight = LM(hold[2], hold[3]);
+ globalColormap = !!(hold[4] & 0x80);
+ globalColorCount = 2 << (hold[4] & 0x7);
+ count = 0;
+ colorCount = globalColorCount;
+ if (globalColormap) {
+ int colorTableSize = 3 * globalColorCount;
+ if (length >= colorTableSize) {
+ // skip the global color table in one go
+ length -= colorTableSize;
+ buffer += colorTableSize;
+ state = Introducer;
+ } else {
+ colorReadCount = 0;
+ state = GlobalColorMap;
+ }
+ } else {
+ state=Introducer;
+ }
+ }
+ break;
+ case GlobalColorMap:
+ case LocalColorMap:
+ hold[count++] = ch;
+ if (count == 3) {
+ if (++colorReadCount >= colorCount) {
+ if (state == LocalColorMap)
+ state = TableImageLZWSize;
+ else
+ state = Introducer;
+ }
+ count = 0;
+ }
+ break;
+ case Introducer:
+ hold[count++] = ch;
+ switch (ch) {
+ case 0x2c:
+ state = ImageDescriptor;
+ break;
+ case 0x21:
+ state = ExtensionLabel;
+ break;
+ case 0x3b:
+ state = Done;
+ break;
+ default:
+ done = true;
+ state = Error;
+ }
+ break;
+ case ImageDescriptor:
+ hold[count++] = ch;
+ if (count == 10) {
+ int newLeft = LM(hold[1], hold[2]);
+ int newTop = LM(hold[3], hold[4]);
+ int newWidth = LM(hold[5], hold[6]);
+ int newHeight = LM(hold[7], hold[8]);
+
+ if (imageWidth/10 > qMax(newWidth,200))
+ imageWidth = -1;
+ if (imageHeight/10 > qMax(newHeight,200))
+ imageHeight = -1;
+
+ if (imageWidth <= 0)
+ imageWidth = newLeft + newWidth;
+ if (imageHeight <= 0)
+ imageHeight = newTop + newHeight;
+
+ *imageSizes << QSize(imageWidth, imageHeight);
+
+ localColormap = !!(hold[9] & 0x80);
+ localColorCount = localColormap ? (2 << (hold[9] & 0x7)) : 0;
+ if (localColorCount)
+ colorCount = localColorCount;
+ else
+ colorCount = globalColorCount;
+
+ count = 0;
+ if (localColormap) {
+ int colorTableSize = 3 * localColorCount;
+ if (length >= colorTableSize) {
+ // skip the local color table in one go
+ length -= colorTableSize;
+ buffer += colorTableSize;
+ state = TableImageLZWSize;
+ } else {
+ colorReadCount = 0;
+ state = LocalColorMap;
+ }
+ } else {
+ state = TableImageLZWSize;
+ }
+ }
+ break;
+ case TableImageLZWSize:
+ if (ch > max_lzw_bits)
+ state = Error;
+ else
+ state = ImageDataBlockSize;
+ count = 0;
+ break;
+ case ImageDataBlockSize:
+ blockSize = ch;
+ if (blockSize) {
+ if (length >= blockSize) {
+ // we can skip the block in one go
+ length -= blockSize;
+ buffer += blockSize;
+ count = 0;
+ } else {
+ state = ImageDataBlock;
+ }
+ } else {
+ state = Introducer;
+ }
+ break;
+ case ImageDataBlock:
+ ++count;
+ if (count == blockSize) {
+ count = 0;
+ state = ImageDataBlockSize;
+ }
+ break;
+ case ExtensionLabel:
+ switch (ch) {
+ case 0xf9:
+ state = GraphicControlExtension;
+ break;
+ case 0xff:
+ state = ApplicationExtension;
+ break;
+ default:
+ state = SkipBlockSize;
+ }
+ count = 0;
+ break;
+ case ApplicationExtension:
+ if (count < 11)
+ hold[count] = ch;
+ ++count;
+ if (count == hold[0] + 1) {
+ if (qstrncmp((char*)(hold+1), "NETSCAPE", 8) == 0)
+ state=NetscapeExtensionBlockSize;
+ else
+ state=SkipBlockSize;
+ count = 0;
+ }
+ break;
+ case GraphicControlExtension:
+ if (count < 5)
+ hold[count] = ch;
+ ++count;
+ if (count == hold[0] + 1) {
+ count = 0;
+ state = SkipBlockSize;
+ }
+ break;
+ case NetscapeExtensionBlockSize:
+ blockSize = ch;
+ count = 0;
+ if (blockSize)
+ state = NetscapeExtensionBlock;
+ else
+ state = Introducer;
+ break;
+ case NetscapeExtensionBlock:
+ if (count < 3)
+ hold[count] = ch;
+ count++;
+ if (count == blockSize) {
+ *loopCount = LM(hold[1], hold[2]);
+ state = SkipBlockSize;
+ }
+ break;
+ case SkipBlockSize:
+ blockSize = ch;
+ count = 0;
+ if (blockSize) {
+ if (length >= blockSize) {
+ // we can skip the block in one go
+ length -= blockSize;
+ buffer += blockSize;
+ } else {
+ state = SkipBlock;
+ }
+ } else {
+ state = Introducer;
+ }
+ break;
+ case SkipBlock:
+ ++count;
+ if (count == blockSize)
+ state = SkipBlockSize;
+ break;
+ case Done:
+ done = true;
+ break;
+ case Error:
+ device->seek(oldPos);
+ return;
+ }
+ }
+ readBuffer = device->read(readBufferSize);
+ }
+ device->seek(oldPos);
+ return;
+}
+
+void QGIFFormat::fillRect(QImage *image, int col, int row, int w, int h, QRgb color)
+{
+ if (w>0) {
+ for (int j=0; j<h; j++) {
+ QRgb *line = (QRgb*)image->scanLine(j+row);
+ for (int i=0; i<w; i++)
+ *(line+col+i) = color;
+ }
+ }
+}
+
+void QGIFFormat::nextY(unsigned char *bits, int bpl)
+{
+ int my;
+ switch (interlace) {
+ case 0: // Non-interlaced
+ // if (!out_of_bounds) {
+ // ### Changed: QRect(left, y, right - left + 1, 1);
+ // }
+ y++;
+ break;
+ case 1: {
+ int i;
+ my = qMin(7, bottom-y);
+ // Don't dup with transparency
+ if (trans_index < 0) {
+ for (i=1; i<=my; i++) {
+ memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb),
+ (right-left+1)*sizeof(QRgb));
+ }
+ }
+
+ // if (!out_of_bounds) {
+ // ### Changed: QRect(left, y, right - left + 1, my + 1);
+ // }
+// if (!out_of_bounds)
+// qDebug("consumer->changed(QRect(%d, %d, %d, %d))", left, y, right-left+1, my+1);
+ y+=8;
+ if (y>bottom) {
+ interlace++; y=top+4;
+ if (y > bottom) { // for really broken GIFs with bottom < 5
+ interlace=2;
+ y = top + 2;
+ if (y > bottom) { // for really broken GIF with bottom < 3
+ interlace = 0;
+ y = top + 1;
+ }
+ }
+ }
+ } break;
+ case 2: {
+ int i;
+ my = qMin(3, bottom-y);
+ // Don't dup with transparency
+ if (trans_index < 0) {
+ for (i=1; i<=my; i++) {
+ memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb),
+ (right-left+1)*sizeof(QRgb));
+ }
+ }
+
+ // if (!out_of_bounds) {
+ // ### Changed: QRect(left, y, right - left + 1, my + 1);
+ // }
+ y+=8;
+ if (y>bottom) {
+ interlace++; y=top+2;
+ // handle broken GIF with bottom < 3
+ if (y > bottom) {
+ interlace = 3;
+ y = top + 1;
+ }
+ }
+ } break;
+ case 3: {
+ int i;
+ my = qMin(1, bottom-y);
+ // Don't dup with transparency
+ if (trans_index < 0) {
+ for (i=1; i<=my; i++) {
+ memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb),
+ (right-left+1)*sizeof(QRgb));
+ }
+ }
+ // if (!out_of_bounds) {
+ // ### Changed: QRect(left, y, right - left + 1, my + 1);
+ // }
+ y+=4;
+ if (y>bottom) { interlace++; y=top+1; }
+ } break;
+ case 4:
+ // if (!out_of_bounds) {
+ // ### Changed: QRect(left, y, right - left + 1, 1);
+ // }
+ y+=2;
+ }
+
+ // Consume bogus extra lines
+ if (y >= sheight) out_of_bounds=true; //y=bottom;
+}
+
+inline QRgb QGIFFormat::color(uchar index) const
+{
+ if (index == trans_index || index > ncols)
+ return Q_TRANSPARENT;
+
+ QRgb *map = lcmap ? localcmap : globalcmap;
+ return map ? map[index] : 0;
+}
+
+//-------------------------------------------------------------------------
+//-------------------------------------------------------------------------
+//-------------------------------------------------------------------------
+
+QGifHandler::QGifHandler()
+{
+ gifFormat = new QGIFFormat;
+ nextDelay = 100;
+ loopCnt = -1;
+ frameNumber = -1;
+ scanIsCached = false;
+}
+
+QGifHandler::~QGifHandler()
+{
+ delete gifFormat;
+}
+
+// Does partial decode if necessary, just to see if an image is coming
+
+bool QGifHandler::imageIsComing() const
+{
+ const int GifChunkSize = 4096;
+
+ while (!gifFormat->partialNewFrame) {
+ if (buffer.isEmpty()) {
+ buffer += device()->read(GifChunkSize);
+ if (buffer.isEmpty())
+ break;
+ }
+
+ int decoded = gifFormat->decode(&lastImage, (const uchar *)buffer.constData(), buffer.size(),
+ &nextDelay, &loopCnt);
+ if (decoded == -1)
+ break;
+ buffer.remove(0, decoded);
+ }
+ return gifFormat->partialNewFrame;
+}
+
+bool QGifHandler::canRead() const
+{
+ if (canRead(device()) || imageIsComing()) {
+ setFormat("gif");
+ return true;
+ }
+
+ return false;
+}
+
+bool QGifHandler::canRead(QIODevice *device)
+{
+ if (!device) {
+ qWarning("QGifHandler::canRead() called with no device");
+ return false;
+ }
+
+ char head[6];
+ if (device->peek(head, sizeof(head)) == sizeof(head))
+ return qstrncmp(head, "GIF87a", 6) == 0
+ || qstrncmp(head, "GIF89a", 6) == 0;
+ return false;
+}
+
+bool QGifHandler::read(QImage *image)
+{
+ const int GifChunkSize = 4096;
+
+ while (!gifFormat->newFrame) {
+ if (buffer.isEmpty()) {
+ buffer += device()->read(GifChunkSize);
+ if (buffer.isEmpty())
+ break;
+ }
+
+ int decoded = gifFormat->decode(&lastImage, (const uchar *)buffer.constData(), buffer.size(),
+ &nextDelay, &loopCnt);
+ if (decoded == -1)
+ break;
+ buffer.remove(0, decoded);
+ }
+ if (gifFormat->newFrame || (gifFormat->partialNewFrame && device()->atEnd())) {
+ *image = lastImage;
+ ++frameNumber;
+ gifFormat->newFrame = false;
+ gifFormat->partialNewFrame = false;
+ return true;
+ }
+
+ return false;
+}
+
+bool QGifHandler::write(const QImage &image)
+{
+ Q_UNUSED(image);
+ return false;
+}
+
+bool QGifHandler::supportsOption(ImageOption option) const
+{
+ if (!device() || device()->isSequential())
+ return option == Animation;
+ else
+ return option == Size
+ || option == Animation;
+}
+
+QVariant QGifHandler::option(ImageOption option) const
+{
+ if (option == Size) {
+ if (!scanIsCached) {
+ QGIFFormat::scan(device(), &imageSizes, &loopCnt);
+ scanIsCached = true;
+ }
+ // before the first frame is read, or we have an empty data stream
+ if (frameNumber == -1)
+ return (imageSizes.count() > 0) ? QVariant(imageSizes.at(0)) : QVariant();
+ // after the last frame has been read, the next size is undefined
+ if (frameNumber >= imageSizes.count() - 1)
+ return QVariant();
+ // and the last case: the size of the next frame
+ return imageSizes.at(frameNumber + 1);
+ } else if (option == Animation) {
+ return true;
+ }
+ return QVariant();
+}
+
+void QGifHandler::setOption(ImageOption option, const QVariant &value)
+{
+ Q_UNUSED(option);
+ Q_UNUSED(value);
+}
+
+int QGifHandler::nextImageDelay() const
+{
+ return nextDelay;
+}
+
+int QGifHandler::imageCount() const
+{
+ if (!scanIsCached) {
+ QGIFFormat::scan(device(), &imageSizes, &loopCnt);
+ scanIsCached = true;
+ }
+ return imageSizes.count();
+}
+
+int QGifHandler::loopCount() const
+{
+ if (!scanIsCached) {
+ QGIFFormat::scan(device(), &imageSizes, &loopCnt);
+ scanIsCached = true;
+ }
+
+ if (loopCnt == 0)
+ return -1;
+ else if (loopCnt == -1)
+ return 0;
+ else
+ return loopCnt;
+}
+
+int QGifHandler::currentImageNumber() const
+{
+ return frameNumber;
+}
+
+QByteArray QGifHandler::name() const
+{
+ return "gif";
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/image/qgifhandler.pri b/src/gui/image/qgifhandler.pri
new file mode 100644
index 0000000000..6eb0751372
--- /dev/null
+++ b/src/gui/image/qgifhandler.pri
@@ -0,0 +1,4 @@
+# common to plugin and built-in forms
+INCLUDEPATH *= $$PWD
+HEADERS += $$PWD/qgifhandler_p.h
+SOURCES += $$PWD/qgifhandler.cpp
diff --git a/src/gui/image/qgifhandler_p.h b/src/gui/image/qgifhandler_p.h
new file mode 100644
index 0000000000..0ea4ccfc38
--- /dev/null
+++ b/src/gui/image/qgifhandler_p.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+** WARNING:
+** A separate license from Unisys may be required to use the gif
+** reader. See http://www.unisys.com/about__unisys/lzw/
+** for information from Unisys
+**
+****************************************************************************/
+
+#ifndef QGIFHANDLER_P_H
+#define QGIFHANDLER_P_H
+
+#include <QtGui/qimageiohandler.h>
+#include <QtGui/qimage.h>
+#include <QtCore/qbytearray.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGIFFormat;
+class QGifHandler : public QImageIOHandler
+{
+public:
+ QGifHandler();
+ ~QGifHandler();
+
+ bool canRead() const;
+ bool read(QImage *image);
+ bool write(const QImage &image);
+
+ QByteArray name() const;
+
+ static bool canRead(QIODevice *device);
+
+ QVariant option(ImageOption option) const;
+ void setOption(ImageOption option, const QVariant &value);
+ bool supportsOption(ImageOption option) const;
+
+ int imageCount() const;
+ int loopCount() const;
+ int nextImageDelay() const;
+ int currentImageNumber() const;
+
+private:
+ bool imageIsComing() const;
+ QGIFFormat *gifFormat;
+ QString fileName;
+ mutable QByteArray buffer;
+ mutable QImage lastImage;
+
+ mutable int nextDelay;
+ mutable int loopCnt;
+ int frameNumber;
+ mutable QVector<QSize> imageSizes;
+ mutable bool scanIsCached;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGIFHANDLER_P_H
diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp
new file mode 100644
index 0000000000..7182062e59
--- /dev/null
+++ b/src/gui/image/qicon.cpp
@@ -0,0 +1,1258 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qicon.h"
+#include "qicon_p.h"
+#include "qiconengine.h"
+#include "qiconengineplugin.h"
+#include "private/qfactoryloader_p.h"
+#include "private/qiconloader_p.h"
+#include "qapplication.h"
+#include "qstyleoption.h"
+#include "qpainter.h"
+#include "qfileinfo.h"
+#include "qstyle.h"
+#include "qpixmapcache.h"
+#include "qvariant.h"
+#include "qcache.h"
+#include "qdebug.h"
+#include "private/qguiplatformplugin_p.h"
+
+#ifdef Q_WS_MAC
+#include <private/qt_mac_p.h>
+#include <private/qt_cocoa_helpers_mac_p.h>
+#endif
+
+#ifdef Q_WS_X11
+#include "private/qt_x11_p.h"
+#include "private/qkde_p.h"
+#endif
+
+#include "private/qstylehelper_p.h"
+
+#ifndef QT_NO_ICON
+QT_BEGIN_NAMESPACE
+
+/*!
+ \enum QIcon::Mode
+
+ This enum type describes the mode for which a pixmap is intended
+ to be used. The currently defined modes are:
+
+ \value Normal
+ Display the pixmap when the user is
+ not interacting with the icon, but the
+ functionality represented by the icon is available.
+ \value Disabled
+ Display the pixmap when the
+ functionality represented by the icon is not available.
+ \value Active
+ Display the pixmap when the
+ functionality represented by the icon is available and
+ the user is interacting with the icon, for example, moving the
+ mouse over it or clicking it.
+ \value Selected
+ Display the pixmap when the item represented by the icon is
+ selected.
+*/
+
+/*!
+ \enum QIcon::State
+
+ This enum describes the state for which a pixmap is intended to be
+ used. The \e state can be:
+
+ \value Off Display the pixmap when the widget is in an "off" state
+ \value On Display the pixmap when the widget is in an "on" state
+*/
+
+static QBasicAtomicInt serialNumCounter = Q_BASIC_ATOMIC_INITIALIZER(1);
+
+static void qt_cleanup_icon_cache();
+typedef QCache<QString, QIcon> IconCache;
+Q_GLOBAL_STATIC_WITH_INITIALIZER(IconCache, qtIconCache, qAddPostRoutine(qt_cleanup_icon_cache))
+
+static void qt_cleanup_icon_cache()
+{
+ qtIconCache()->clear();
+}
+
+QIconPrivate::QIconPrivate()
+ : engine(0), ref(1),
+ serialNum(serialNumCounter.fetchAndAddRelaxed(1)),
+ detach_no(0),
+ engine_version(2),
+ v1RefCount(0)
+{
+}
+
+QPixmapIconEngine::QPixmapIconEngine()
+{
+}
+
+QPixmapIconEngine::QPixmapIconEngine(const QPixmapIconEngine &other)
+ : QIconEngineV2(other), pixmaps(other.pixmaps)
+{
+}
+
+QPixmapIconEngine::~QPixmapIconEngine()
+{
+}
+
+void QPixmapIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
+{
+ QSize pixmapSize = rect.size();
+#if defined(Q_WS_MAC)
+ pixmapSize *= qt_mac_get_scalefactor();
+#endif
+ painter->drawPixmap(rect, pixmap(pixmapSize, mode, state));
+}
+
+static inline int area(const QSize &s) { return s.width() * s.height(); }
+
+// returns the smallest of the two that is still larger than or equal to size.
+static QPixmapIconEngineEntry *bestSizeMatch( const QSize &size, QPixmapIconEngineEntry *pa, QPixmapIconEngineEntry *pb)
+{
+ int s = area(size);
+ if (pa->size == QSize() && pa->pixmap.isNull()) {
+ pa->pixmap = QPixmap(pa->fileName);
+ pa->size = pa->pixmap.size();
+ }
+ int a = area(pa->size);
+ if (pb->size == QSize() && pb->pixmap.isNull()) {
+ pb->pixmap = QPixmap(pb->fileName);
+ pb->size = pb->pixmap.size();
+ }
+ int b = area(pb->size);
+ int res = a;
+ if (qMin(a,b) >= s)
+ res = qMin(a,b);
+ else
+ res = qMax(a,b);
+ if (res == a)
+ return pa;
+ return pb;
+}
+
+QPixmapIconEngineEntry *QPixmapIconEngine::tryMatch(const QSize &size, QIcon::Mode mode, QIcon::State state)
+{
+ QPixmapIconEngineEntry *pe = 0;
+ for (int i = 0; i < pixmaps.count(); ++i)
+ if (pixmaps.at(i).mode == mode && pixmaps.at(i).state == state) {
+ if (pe)
+ pe = bestSizeMatch(size, &pixmaps[i], pe);
+ else
+ pe = &pixmaps[i];
+ }
+ return pe;
+}
+
+
+QPixmapIconEngineEntry *QPixmapIconEngine::bestMatch(const QSize &size, QIcon::Mode mode, QIcon::State state, bool sizeOnly)
+{
+ QPixmapIconEngineEntry *pe = tryMatch(size, mode, state);
+ while (!pe){
+ QIcon::State oppositeState = (state == QIcon::On) ? QIcon::Off : QIcon::On;
+ if (mode == QIcon::Disabled || mode == QIcon::Selected) {
+ QIcon::Mode oppositeMode = (mode == QIcon::Disabled) ? QIcon::Selected : QIcon::Disabled;
+ if ((pe = tryMatch(size, QIcon::Normal, state)))
+ break;
+ if ((pe = tryMatch(size, QIcon::Active, state)))
+ break;
+ if ((pe = tryMatch(size, mode, oppositeState)))
+ break;
+ if ((pe = tryMatch(size, QIcon::Normal, oppositeState)))
+ break;
+ if ((pe = tryMatch(size, QIcon::Active, oppositeState)))
+ break;
+ if ((pe = tryMatch(size, oppositeMode, state)))
+ break;
+ if ((pe = tryMatch(size, oppositeMode, oppositeState)))
+ break;
+ } else {
+ QIcon::Mode oppositeMode = (mode == QIcon::Normal) ? QIcon::Active : QIcon::Normal;
+ if ((pe = tryMatch(size, oppositeMode, state)))
+ break;
+ if ((pe = tryMatch(size, mode, oppositeState)))
+ break;
+ if ((pe = tryMatch(size, oppositeMode, oppositeState)))
+ break;
+ if ((pe = tryMatch(size, QIcon::Disabled, state)))
+ break;
+ if ((pe = tryMatch(size, QIcon::Selected, state)))
+ break;
+ if ((pe = tryMatch(size, QIcon::Disabled, oppositeState)))
+ break;
+ if ((pe = tryMatch(size, QIcon::Selected, oppositeState)))
+ break;
+ }
+
+ if (!pe)
+ return pe;
+ }
+
+ if (sizeOnly ? (pe->size.isNull() || !pe->size.isValid()) : pe->pixmap.isNull()) {
+ pe->pixmap = QPixmap(pe->fileName);
+ if (!pe->pixmap.isNull())
+ pe->size = pe->pixmap.size();
+ }
+
+ return pe;
+}
+
+QPixmap QPixmapIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
+{
+ QPixmap pm;
+ QPixmapIconEngineEntry *pe = bestMatch(size, mode, state, false);
+ if (pe)
+ pm = pe->pixmap;
+
+ if (pm.isNull()) {
+ int idx = pixmaps.count();
+ while (--idx >= 0) {
+ if (pe == &pixmaps[idx]) {
+ pixmaps.remove(idx);
+ break;
+ }
+ }
+ if (pixmaps.isEmpty())
+ return pm;
+ else
+ return pixmap(size, mode, state);
+ }
+
+ QSize actualSize = pm.size();
+ if (!actualSize.isNull() && (actualSize.width() > size.width() || actualSize.height() > size.height()))
+ actualSize.scale(size, Qt::KeepAspectRatio);
+
+ QString key = QLatin1Literal("qt_")
+ % HexString<quint64>(pm.cacheKey())
+ % HexString<uint>(pe->mode)
+ % HexString<quint64>(QApplication::palette().cacheKey())
+ % HexString<uint>(actualSize.width())
+ % HexString<uint>(actualSize.height());
+
+ if (mode == QIcon::Active) {
+ if (QPixmapCache::find(key % HexString<uint>(mode), pm))
+ return pm; // horray
+ if (QPixmapCache::find(key % HexString<uint>(QIcon::Normal), pm)) {
+ QStyleOption opt(0);
+ opt.palette = QApplication::palette();
+ QPixmap active = QApplication::style()->generatedIconPixmap(QIcon::Active, pm, &opt);
+ if (pm.cacheKey() == active.cacheKey())
+ return pm;
+ }
+ }
+
+ if (!QPixmapCache::find(key % HexString<uint>(mode), pm)) {
+ if (pm.size() != actualSize)
+ pm = pm.scaled(actualSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+ if (pe->mode != mode && mode != QIcon::Normal) {
+ QStyleOption opt(0);
+ opt.palette = QApplication::palette();
+ QPixmap generated = QApplication::style()->generatedIconPixmap(mode, pm, &opt);
+ if (!generated.isNull())
+ pm = generated;
+ }
+ QPixmapCache::insert(key % HexString<uint>(mode), pm);
+ }
+ return pm;
+}
+
+QSize QPixmapIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state)
+{
+ QSize actualSize;
+ if (QPixmapIconEngineEntry *pe = bestMatch(size, mode, state, true))
+ actualSize = pe->size;
+
+ if (actualSize.isNull())
+ return actualSize;
+
+ if (!actualSize.isNull() && (actualSize.width() > size.width() || actualSize.height() > size.height()))
+ actualSize.scale(size, Qt::KeepAspectRatio);
+ return actualSize;
+}
+
+void QPixmapIconEngine::addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state)
+{
+ if (!pixmap.isNull()) {
+ QPixmapIconEngineEntry *pe = tryMatch(pixmap.size(), mode, state);
+ if(pe && pe->size == pixmap.size()) {
+ pe->pixmap = pixmap;
+ pe->fileName.clear();
+ } else {
+ pixmaps += QPixmapIconEngineEntry(pixmap, mode, state);
+ }
+ }
+}
+
+void QPixmapIconEngine::addFile(const QString &fileName, const QSize &_size, QIcon::Mode mode, QIcon::State state)
+{
+ if (!fileName.isEmpty()) {
+ QSize size = _size;
+ QPixmap pixmap;
+
+ QString abs = fileName;
+ if (fileName.at(0) != QLatin1Char(':'))
+ abs = QFileInfo(fileName).absoluteFilePath();
+
+ for (int i = 0; i < pixmaps.count(); ++i) {
+ if (pixmaps.at(i).mode == mode && pixmaps.at(i).state == state) {
+ QPixmapIconEngineEntry *pe = &pixmaps[i];
+ if(size == QSize()) {
+ pixmap = QPixmap(abs);
+ size = pixmap.size();
+ }
+ if (pe->size == QSize() && pe->pixmap.isNull()) {
+ pe->pixmap = QPixmap(pe->fileName);
+ pe->size = pe->pixmap.size();
+ }
+ if(pe->size == size) {
+ pe->pixmap = pixmap;
+ pe->fileName = abs;
+ return;
+ }
+ }
+ }
+ QPixmapIconEngineEntry e(abs, size, mode, state);
+ e.pixmap = pixmap;
+ pixmaps += e;
+ }
+}
+
+QString QPixmapIconEngine::key() const
+{
+ return QLatin1String("QPixmapIconEngine");
+}
+
+QIconEngineV2 *QPixmapIconEngine::clone() const
+{
+ return new QPixmapIconEngine(*this);
+}
+
+bool QPixmapIconEngine::read(QDataStream &in)
+{
+ int num_entries;
+ QPixmap pm;
+ QString fileName;
+ QSize sz;
+ uint mode;
+ uint state;
+
+ in >> num_entries;
+ for (int i=0; i < num_entries; ++i) {
+ if (in.atEnd()) {
+ pixmaps.clear();
+ return false;
+ }
+ in >> pm;
+ in >> fileName;
+ in >> sz;
+ in >> mode;
+ in >> state;
+ if (pm.isNull()) {
+ addFile(fileName, sz, QIcon::Mode(mode), QIcon::State(state));
+ } else {
+ QPixmapIconEngineEntry pe(fileName, sz, QIcon::Mode(mode), QIcon::State(state));
+ pe.pixmap = pm;
+ pixmaps += pe;
+ }
+ }
+ return true;
+}
+
+bool QPixmapIconEngine::write(QDataStream &out) const
+{
+ int num_entries = pixmaps.size();
+ out << num_entries;
+ for (int i=0; i < num_entries; ++i) {
+ if (pixmaps.at(i).pixmap.isNull())
+ out << QPixmap(pixmaps.at(i).fileName);
+ else
+ out << pixmaps.at(i).pixmap;
+ out << pixmaps.at(i).fileName;
+ out << pixmaps.at(i).size;
+ out << (uint) pixmaps.at(i).mode;
+ out << (uint) pixmaps.at(i).state;
+ }
+ return true;
+}
+
+void QPixmapIconEngine::virtual_hook(int id, void *data)
+{
+ switch (id) {
+ case QIconEngineV2::AvailableSizesHook: {
+ QIconEngineV2::AvailableSizesArgument &arg =
+ *reinterpret_cast<QIconEngineV2::AvailableSizesArgument*>(data);
+ arg.sizes.clear();
+ for (int i = 0; i < pixmaps.size(); ++i) {
+ QPixmapIconEngineEntry &pe = pixmaps[i];
+ if (pe.size == QSize() && pe.pixmap.isNull()) {
+ pe.pixmap = QPixmap(pe.fileName);
+ pe.size = pe.pixmap.size();
+ }
+ if (pe.mode == arg.mode && pe.state == arg.state && !pe.size.isEmpty())
+ arg.sizes.push_back(pe.size);
+ }
+ break;
+ }
+ default:
+ QIconEngineV2::virtual_hook(id, data);
+ }
+}
+
+#ifndef QT_NO_LIBRARY
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+ (QIconEngineFactoryInterface_iid, QLatin1String("/iconengines"), Qt::CaseInsensitive))
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loaderV2,
+ (QIconEngineFactoryInterfaceV2_iid, QLatin1String("/iconengines"), Qt::CaseInsensitive))
+#endif
+
+
+
+/*!
+ \class QIcon
+
+ \brief The QIcon class provides scalable icons in different modes
+ and states.
+
+ \ingroup painting
+ \ingroup shared
+
+
+ A QIcon can generate smaller, larger, active, and disabled pixmaps
+ from the set of pixmaps it is given. Such pixmaps are used by Qt
+ widgets to show an icon representing a particular action.
+
+ The simplest use of QIcon is to create one from a QPixmap file or
+ resource, and then use it, allowing Qt to work out all the required
+ icon styles and sizes. For example:
+
+ \snippet doc/src/snippets/code/src_gui_image_qicon.cpp 0
+
+ To undo a QIcon, simply set a null icon in its place:
+
+ \snippet doc/src/snippets/code/src_gui_image_qicon.cpp 1
+
+ Use the QImageReader::supportedImageFormats() and
+ QImageWriter::supportedImageFormats() functions to retrieve a
+ complete list of the supported file formats.
+
+ When you retrieve a pixmap using pixmap(QSize, Mode, State), and no
+ pixmap for this given size, mode and state has been added with
+ addFile() or addPixmap(), then QIcon will generate one on the
+ fly. This pixmap generation happens in a QIconEngineV2. The default
+ engine scales pixmaps down if required, but never up, and it uses
+ the current style to calculate a disabled appearance. By using
+ custom icon engines, you can customize every aspect of generated
+ icons. With QIconEnginePluginV2 it is possible to register different
+ icon engines for different file suffixes, making it possible for
+ third parties to provide additional icon engines to those included
+ with Qt.
+
+ \note Since Qt 4.2, an icon engine that supports SVG is included.
+
+ \section1 Making Classes that Use QIcon
+
+ If you write your own widgets that have an option to set a small
+ pixmap, consider allowing a QIcon to be set for that pixmap. The
+ Qt class QToolButton is an example of such a widget.
+
+ Provide a method to set a QIcon, and when you draw the icon, choose
+ whichever pixmap is appropriate for the current state of your widget.
+ For example:
+ \snippet doc/src/snippets/code/src_gui_image_qicon.cpp 2
+
+ You might also make use of the \c Active mode, perhaps making your
+ widget \c Active when the mouse is over the widget (see \l
+ QWidget::enterEvent()), while the mouse is pressed pending the
+ release that will activate the function, or when it is the currently
+ selected item. If the widget can be toggled, the "On" mode might be
+ used to draw a different icon.
+
+ \img icon.png QIcon
+
+ \sa {fowler}{GUI Design Handbook: Iconic Label}, {Icons Example}
+*/
+
+
+/*!
+ Constructs a null icon.
+*/
+QIcon::QIcon()
+ : d(0)
+{
+}
+
+/*!
+ Constructs an icon from a \a pixmap.
+ */
+QIcon::QIcon(const QPixmap &pixmap)
+ :d(0)
+{
+ addPixmap(pixmap);
+}
+
+/*!
+ Constructs a copy of \a other. This is very fast.
+*/
+QIcon::QIcon(const QIcon &other)
+ :d(other.d)
+{
+ if (d)
+ d->ref.ref();
+}
+
+/*!
+ Constructs an icon from the file with the given \a fileName. The
+ file will be loaded on demand.
+
+ If \a fileName contains a relative path (e.g. the filename only)
+ the relevant file must be found relative to the runtime working
+ directory.
+
+ The file name can be either refer to an actual file on disk or to
+ one of the application's embedded resources. See the
+ \l{resources.html}{Resource System} overview for details on how to
+ embed images and other resource files in the application's
+ executable.
+
+ Use the QImageReader::supportedImageFormats() and
+ QImageWriter::supportedImageFormats() functions to retrieve a
+ complete list of the supported file formats.
+*/
+QIcon::QIcon(const QString &fileName)
+ : d(0)
+{
+ addFile(fileName);
+}
+
+
+/*!
+ Creates an icon with a specific icon \a engine. The icon takes
+ ownership of the engine.
+*/
+QIcon::QIcon(QIconEngine *engine)
+ :d(new QIconPrivate)
+{
+ d->engine_version = 1;
+ d->engine = engine;
+ d->v1RefCount = new QAtomicInt(1);
+}
+
+/*!
+ Creates an icon with a specific icon \a engine. The icon takes
+ ownership of the engine.
+*/
+QIcon::QIcon(QIconEngineV2 *engine)
+ :d(new QIconPrivate)
+{
+ d->engine_version = 2;
+ d->engine = engine;
+}
+
+/*!
+ Destroys the icon.
+*/
+QIcon::~QIcon()
+{
+ if (d && !d->ref.deref())
+ delete d;
+}
+
+/*!
+ Assigns the \a other icon to this icon and returns a reference to
+ this icon.
+*/
+QIcon &QIcon::operator=(const QIcon &other)
+{
+ if (other.d)
+ other.d->ref.ref();
+ if (d && !d->ref.deref())
+ delete d;
+ d = other.d;
+ return *this;
+}
+
+/*!
+ \fn void QIcon::swap(QIcon &other)
+ \since 4.8
+
+ Swaps icon \a other with this icon. This operation is very
+ fast and never fails.
+*/
+
+/*!
+ Returns the icon as a QVariant.
+*/
+QIcon::operator QVariant() const
+{
+ return QVariant(QVariant::Icon, this);
+}
+
+/*! \obsolete
+
+ Returns a number that identifies the contents of this
+ QIcon object. Distinct QIcon objects can have
+ the same serial number if they refer to the same contents
+ (but they don't have to). Also, the serial number of
+ a QIcon object may change during its lifetime.
+
+ Use cacheKey() instead.
+
+ A null icon always has a serial number of 0.
+
+ Serial numbers are mostly useful in conjunction with caching.
+
+ \sa QPixmap::serialNumber()
+*/
+
+int QIcon::serialNumber() const
+{
+ return d ? d->serialNum : 0;
+}
+
+/*!
+ Returns a number that identifies the contents of this QIcon
+ object. Distinct QIcon objects can have the same key if
+ they refer to the same contents.
+ \since 4.3
+
+ The cacheKey() will change when the icon is altered via
+ addPixmap() or addFile().
+
+ Cache keys are mostly useful in conjunction with caching.
+
+ \sa QPixmap::cacheKey()
+*/
+qint64 QIcon::cacheKey() const
+{
+ if (!d)
+ return 0;
+ return (((qint64) d->serialNum) << 32) | ((qint64) (d->detach_no));
+}
+
+/*!
+ Returns a pixmap with the requested \a size, \a mode, and \a
+ state, generating one if necessary. The pixmap might be smaller than
+ requested, but never larger.
+
+ \sa actualSize(), paint()
+*/
+QPixmap QIcon::pixmap(const QSize &size, Mode mode, State state) const
+{
+ if (!d)
+ return QPixmap();
+ return d->engine->pixmap(size, mode, state);
+}
+
+/*!
+ \fn QPixmap QIcon::pixmap(int w, int h, Mode mode = Normal, State state = Off) const
+
+ \overload
+
+ Returns a pixmap of size QSize(\a w, \a h). The pixmap might be smaller than
+ requested, but never larger.
+*/
+
+/*!
+ \fn QPixmap QIcon::pixmap(int extent, Mode mode = Normal, State state = Off) const
+
+ \overload
+
+ Returns a pixmap of size QSize(\a extent, \a extent). The pixmap might be smaller
+ than requested, but never larger.
+*/
+
+/*! Returns the actual size of the icon for the requested \a size, \a
+ mode, and \a state. The result might be smaller than requested, but
+ never larger.
+
+ \sa pixmap(), paint()
+*/
+QSize QIcon::actualSize(const QSize &size, Mode mode, State state) const
+{
+ if (!d)
+ return QSize();
+ return d->engine->actualSize(size, mode, state);
+}
+
+
+/*!
+ Uses the \a painter to paint the icon with specified \a alignment,
+ required \a mode, and \a state into the rectangle \a rect.
+
+ \sa actualSize(), pixmap()
+*/
+void QIcon::paint(QPainter *painter, const QRect &rect, Qt::Alignment alignment, Mode mode, State state) const
+{
+ if (!d || !painter)
+ return;
+ QRect alignedRect = QStyle::alignedRect(painter->layoutDirection(), alignment, d->engine->actualSize(rect.size(), mode, state), rect);
+ d->engine->paint(painter, alignedRect, mode, state);
+}
+
+/*!
+ \fn void QIcon::paint(QPainter *painter, int x, int y, int w, int h, Qt::Alignment alignment,
+ Mode mode, State state) const
+
+ \overload
+
+ Paints the icon into the rectangle QRect(\a x, \a y, \a w, \a h).
+*/
+
+/*!
+ Returns true if the icon is empty; otherwise returns false.
+
+ An icon is empty if it has neither a pixmap nor a filename.
+
+ Note: Even a non-null icon might not be able to create valid
+ pixmaps, eg. if the file does not exist or cannot be read.
+*/
+bool QIcon::isNull() const
+{
+ return !d;
+}
+
+/*!\internal
+ */
+bool QIcon::isDetached() const
+{
+ return !d || d->ref == 1;
+}
+
+/*! \internal
+ */
+void QIcon::detach()
+{
+ if (d) {
+ if (d->ref != 1) {
+ QIconPrivate *x = new QIconPrivate;
+ if (d->engine_version > 1) {
+ QIconEngineV2 *engine = static_cast<QIconEngineV2 *>(d->engine);
+ x->engine = engine->clone();
+ } else {
+ x->engine = d->engine;
+ x->v1RefCount = d->v1RefCount;
+ x->v1RefCount->ref();
+ }
+ x->engine_version = d->engine_version;
+ if (!d->ref.deref())
+ delete d;
+ d = x;
+ }
+ ++d->detach_no;
+ }
+}
+
+/*!
+ Adds \a pixmap to the icon, as a specialization for \a mode and
+ \a state.
+
+ Custom icon engines are free to ignore additionally added
+ pixmaps.
+
+ \sa addFile()
+*/
+void QIcon::addPixmap(const QPixmap &pixmap, Mode mode, State state)
+{
+ if (pixmap.isNull())
+ return;
+ if (!d) {
+ d = new QIconPrivate;
+ d->engine = new QPixmapIconEngine;
+ } else {
+ detach();
+ }
+ d->engine->addPixmap(pixmap, mode, state);
+}
+
+
+/*! Adds an image from the file with the given \a fileName to the
+ icon, as a specialization for \a size, \a mode and \a state. The
+ file will be loaded on demand. Note: custom icon engines are free
+ to ignore additionally added pixmaps.
+
+ If \a fileName contains a relative path (e.g. the filename only)
+ the relevant file must be found relative to the runtime working
+ directory.
+
+ The file name can be either refer to an actual file on disk or to
+ one of the application's embedded resources. See the
+ \l{resources.html}{Resource System} overview for details on how to
+ embed images and other resource files in the application's
+ executable.
+
+ Use the QImageReader::supportedImageFormats() and
+ QImageWriter::supportedImageFormats() functions to retrieve a
+ complete list of the supported file formats.
+
+ Note: When you add a non-empty filename to a QIcon, the icon becomes
+ non-null, even if the file doesn't exist or points to a corrupt file.
+
+ \sa addPixmap()
+ */
+void QIcon::addFile(const QString &fileName, const QSize &size, Mode mode, State state)
+{
+ if (fileName.isEmpty())
+ return;
+ if (!d) {
+#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
+ QFileInfo info(fileName);
+ QString suffix = info.suffix();
+ if (!suffix.isEmpty()) {
+ // first try version 2 engines..
+ if (QIconEngineFactoryInterfaceV2 *factory = qobject_cast<QIconEngineFactoryInterfaceV2*>(loaderV2()->instance(suffix))) {
+ if (QIconEngine *engine = factory->create(fileName)) {
+ d = new QIconPrivate;
+ d->engine = engine;
+ }
+ }
+ // ..then fall back and try to load version 1 engines
+ if (!d) {
+ if (QIconEngineFactoryInterface *factory = qobject_cast<QIconEngineFactoryInterface*>(loader()->instance(suffix))) {
+ if (QIconEngine *engine = factory->create(fileName)) {
+ d = new QIconPrivate;
+ d->engine = engine;
+ d->engine_version = 1;
+ d->v1RefCount = new QAtomicInt(1);
+ }
+ }
+ }
+ }
+#endif
+ // ...then fall back to the default engine
+ if (!d) {
+ d = new QIconPrivate;
+ d->engine = new QPixmapIconEngine;
+ }
+ } else {
+ detach();
+ }
+ d->engine->addFile(fileName, size, mode, state);
+}
+
+/*!
+ \since 4.5
+
+ Returns a list of available icon sizes for the specified \a mode and
+ \a state.
+*/
+QList<QSize> QIcon::availableSizes(Mode mode, State state) const
+{
+ if (!d || !d->engine || d->engine_version < 2)
+ return QList<QSize>();
+ QIconEngineV2 *engine = static_cast<QIconEngineV2*>(d->engine);
+ return engine->availableSizes(mode, state);
+}
+
+/*!
+ \since 4.7
+
+ Returns the name used to create the icon, if available.
+
+ Depending on the way the icon was created, it may have an associated
+ name. This is the case for icons created with fromTheme() or icons
+ using a QIconEngine which supports the QIconEngineV2::IconNameHook.
+
+ \sa fromTheme(), QIconEngine
+*/
+QString QIcon::name() const
+{
+ if (!d || !d->engine || d->engine_version < 2)
+ return QString();
+ QIconEngineV2 *engine = static_cast<QIconEngineV2*>(d->engine);
+ return engine->iconName();
+}
+
+/*!
+ \since 4.6
+
+ Sets the search paths for icon themes to \a paths.
+ \sa themeSearchPaths(), fromTheme(), setThemeName()
+*/
+void QIcon::setThemeSearchPaths(const QStringList &paths)
+{
+ QIconLoader::instance()->setThemeSearchPath(paths);
+}
+
+/*!
+ \since 4.6
+
+ Returns the search paths for icon themes.
+
+ The default value will depend on the platform:
+
+ On X11, the search path will use the XDG_DATA_DIRS environment
+ variable if available.
+
+ By default all platforms will have the resource directory
+ \c{:\icons} as a fallback. You can use "rcc -project" to generate a
+ resource file from your icon theme.
+
+ \sa setThemeSearchPaths(), fromTheme(), setThemeName()
+*/
+QStringList QIcon::themeSearchPaths()
+{
+ return QIconLoader::instance()->themeSearchPaths();
+}
+
+/*!
+ \since 4.6
+
+ Sets the current icon theme to \a name.
+
+ The \a name should correspond to a directory name in the
+ themeSearchPath() containing an index.theme
+ file describing it's contents.
+
+ \sa themeSearchPaths(), themeName()
+*/
+void QIcon::setThemeName(const QString &name)
+{
+ QIconLoader::instance()->setThemeName(name);
+}
+
+/*!
+ \since 4.6
+
+ Returns the name of the current icon theme.
+
+ On X11, the current icon theme depends on your desktop
+ settings. On other platforms it is not set by default.
+
+ \sa setThemeName(), themeSearchPaths(), fromTheme(),
+ hasThemeIcon()
+*/
+QString QIcon::themeName()
+{
+ return QIconLoader::instance()->themeName();
+}
+
+/*!
+ \since 4.6
+
+ Returns the QIcon corresponding to \a name in the current
+ icon theme. If no such icon is found in the current theme
+ \a fallback is returned instead.
+
+ The latest version of the freedesktop icon specification and naming
+ specification can be obtained here:
+
+ \list
+ \o \l{http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html}
+ \o \l{http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html}
+ \endlist
+
+ To fetch an icon from the current icon theme:
+
+ \snippet doc/src/snippets/code/src_gui_image_qicon.cpp 3
+
+ Or if you want to provide a guaranteed fallback for platforms that
+ do not support theme icons, you can use the second argument:
+
+ \snippet doc/src/snippets/code/src_gui_image_qicon.cpp 4
+
+ \note By default, only X11 will support themed icons. In order to
+ use themed icons on Mac and Windows, you will have to bundle a
+ compliant theme in one of your themeSearchPaths() and set the
+ appropriate themeName().
+
+ \sa themeName(), setThemeName(), themeSearchPaths()
+*/
+QIcon QIcon::fromTheme(const QString &name, const QIcon &fallback)
+{
+ QIcon icon;
+
+ if (qtIconCache()->contains(name)) {
+ icon = *qtIconCache()->object(name);
+ } else {
+ QIcon *cachedIcon = new QIcon(new QIconLoaderEngine(name));
+ qtIconCache()->insert(name, cachedIcon);
+ icon = *cachedIcon;
+ }
+
+ // Note the qapp check is to allow lazy loading of static icons
+ // Supporting fallbacks will not work for this case.
+ if (qApp && icon.availableSizes().isEmpty())
+ return fallback;
+
+ return icon;
+}
+
+/*!
+ \since 4.6
+
+ Returns true if there is an icon available for \a name in the
+ current icon theme, otherwise returns false.
+
+ \sa themeSearchPaths(), fromTheme(), setThemeName()
+*/
+bool QIcon::hasThemeIcon(const QString &name)
+{
+ QIcon icon = fromTheme(name);
+
+ return !icon.isNull();
+}
+
+
+/*****************************************************************************
+ QIcon stream functions
+ *****************************************************************************/
+#if !defined(QT_NO_DATASTREAM)
+/*!
+ \fn QDataStream &operator<<(QDataStream &stream, const QIcon &icon)
+ \relates QIcon
+ \since 4.2
+
+ Writes the given \a icon to the given \a stream as a PNG
+ image. If the icon contains more than one image, all images will
+ be written to the stream. Note that writing the stream to a file
+ will not produce a valid image file.
+*/
+
+QDataStream &operator<<(QDataStream &s, const QIcon &icon)
+{
+ if (s.version() >= QDataStream::Qt_4_3) {
+ if (icon.isNull()) {
+ s << QString();
+ } else {
+ if (icon.d->engine_version > 1) {
+ QIconEngineV2 *engine = static_cast<QIconEngineV2 *>(icon.d->engine);
+ s << engine->key();
+ engine->write(s);
+ } else {
+ // not really supported
+ qWarning("QIcon: Cannot stream QIconEngine. Use QIconEngineV2 instead.");
+ }
+ }
+ } else if (s.version() == QDataStream::Qt_4_2) {
+ if (icon.isNull()) {
+ s << 0;
+ } else {
+ QPixmapIconEngine *engine = static_cast<QPixmapIconEngine *>(icon.d->engine);
+ int num_entries = engine->pixmaps.size();
+ s << num_entries;
+ for (int i=0; i < num_entries; ++i) {
+ s << engine->pixmaps.at(i).pixmap;
+ s << engine->pixmaps.at(i).fileName;
+ s << engine->pixmaps.at(i).size;
+ s << (uint) engine->pixmaps.at(i).mode;
+ s << (uint) engine->pixmaps.at(i).state;
+ }
+ }
+ } else {
+ s << QPixmap(icon.pixmap(22,22));
+ }
+ return s;
+}
+
+/*!
+ \fn QDataStream &operator>>(QDataStream &stream, QIcon &icon)
+ \relates QIcon
+ \since 4.2
+
+ Reads an image, or a set of images, from the given \a stream into
+ the given \a icon.
+*/
+
+QDataStream &operator>>(QDataStream &s, QIcon &icon)
+{
+ if (s.version() >= QDataStream::Qt_4_3) {
+ icon = QIcon();
+ QString key;
+ s >> key;
+ if (key == QLatin1String("QPixmapIconEngine")) {
+ icon.d = new QIconPrivate;
+ QIconEngineV2 *engine = new QPixmapIconEngine;
+ icon.d->engine = engine;
+ engine->read(s);
+ } else if (key == QLatin1String("QIconLoaderEngine")) {
+ icon.d = new QIconPrivate;
+ QIconEngineV2 *engine = new QIconLoaderEngine();
+ icon.d->engine = engine;
+ engine->read(s);
+#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
+ } else if (QIconEngineFactoryInterfaceV2 *factory = qobject_cast<QIconEngineFactoryInterfaceV2*>(loaderV2()->instance(key))) {
+ if (QIconEngineV2 *engine= factory->create()) {
+ icon.d = new QIconPrivate;
+ icon.d->engine = engine;
+ engine->read(s);
+ }
+#endif
+ }
+ } else if (s.version() == QDataStream::Qt_4_2) {
+ icon = QIcon();
+ int num_entries;
+ QPixmap pm;
+ QString fileName;
+ QSize sz;
+ uint mode;
+ uint state;
+
+ s >> num_entries;
+ for (int i=0; i < num_entries; ++i) {
+ s >> pm;
+ s >> fileName;
+ s >> sz;
+ s >> mode;
+ s >> state;
+ if (pm.isNull())
+ icon.addFile(fileName, sz, QIcon::Mode(mode), QIcon::State(state));
+ else
+ icon.addPixmap(pm, QIcon::Mode(mode), QIcon::State(state));
+ }
+ } else {
+ QPixmap pm;
+ s >> pm;
+ icon.addPixmap(pm);
+ }
+ return s;
+}
+
+#endif //QT_NO_DATASTREAM
+
+
+#ifdef QT3_SUPPORT
+
+static int widths[2] = { 22, 32 };
+static int heights[2] = { 22, 32 };
+
+static QSize pixmapSizeHelper(QIcon::Size which)
+{
+ int i = 0;
+ if (which == QIcon::Large)
+ i = 1;
+ return QSize(widths[i], heights[i]);
+}
+
+/*!
+ \enum QIcon::Size
+ \compat
+
+ \value Small Use QStyle::pixelMetric(QStyle::PM_SmallIconSize) instead.
+ \value Large Use QStyle::pixelMetric(QStyle::PM_LargeIconSize) instead.
+ \value Automatic N/A.
+*/
+
+/*!
+ Use pixmap(QSize(...), \a mode, \a state), where the first
+ argument is an appropriate QSize instead of a \l Size value.
+
+ \sa pixmapSize()
+*/
+QPixmap QIcon::pixmap(Size size, Mode mode, State state) const
+{ return pixmap(pixmapSizeHelper(size), mode, state); }
+
+/*!
+ Use pixmap(QSize(...), mode, \a state), where the first argument
+ is an appropriate QSize instead of a \l Size value, and the
+ second argument is QIcon::Normal or QIcon::Disabled, depending on
+ the value of \a enabled.
+
+ \sa pixmapSize()
+*/
+QPixmap QIcon::pixmap(Size size, bool enabled, State state) const
+{ return pixmap(pixmapSizeHelper(size), enabled ? Normal : Disabled, state); }
+
+/*!
+ Use one of the other pixmap() overloads.
+*/
+QPixmap QIcon::pixmap() const
+{ return pixmap(pixmapSizeHelper(Small), Normal, Off); }
+
+/*!
+ The pixmap() function now takes a QSize instead of a QIcon::Size,
+ so there is no need for this function in new code.
+*/
+void QIcon::setPixmapSize(Size which, const QSize &size)
+{
+ int i = 0;
+ if (which == Large)
+ i = 1;
+ widths[i] = size.width();
+ heights[i] = size.height();
+}
+
+/*!
+ Use QStyle::pixelMetric() with QStyle::PM_SmallIconSize or
+ QStyle::PM_LargeIconSize as the first argument, depending on \a
+ which.
+*/
+QSize QIcon::pixmapSize(Size which)
+{
+ return pixmapSizeHelper(which);
+}
+
+/*!
+ \fn void QIcon::reset(const QPixmap &pixmap, Size size)
+
+ Use the constructor that takes a QPixmap and operator=().
+*/
+
+/*!
+ \fn void QIcon::setPixmap(const QPixmap &pixmap, Size size, Mode mode, State state)
+
+ Use addPixmap(\a pixmap, \a mode, \a state) instead. The \a size
+ parameter is ignored.
+*/
+
+/*!
+ \fn void QIcon::setPixmap(const QString &fileName, Size size, Mode mode, State state)
+
+ Use addFile(\a fileName, \a mode, \a state) instead. The \a size
+ parameter is ignored.
+*/
+
+#endif // QT3_SUPPORT
+
+/*!
+ \fn DataPtr &QIcon::data_ptr()
+ \internal
+*/
+
+/*!
+ \typedef QIcon::DataPtr
+ \internal
+*/
+
+QT_END_NAMESPACE
+#endif //QT_NO_ICON
diff --git a/src/gui/image/qicon.h b/src/gui/image/qicon.h
new file mode 100644
index 0000000000..170559182b
--- /dev/null
+++ b/src/gui/image/qicon.h
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QICON_H
+#define QICON_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qlist.h>
+#include <QtGui/qpixmap.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QIconPrivate;
+class QIconEngine;
+class QIconEngineV2;
+
+class Q_GUI_EXPORT QIcon
+{
+public:
+ enum Mode { Normal, Disabled, Active, Selected };
+ enum State { On, Off };
+
+ QIcon();
+ QIcon(const QPixmap &pixmap);
+ QIcon(const QIcon &other);
+ explicit QIcon(const QString &fileName); // file or resource name
+ explicit QIcon(QIconEngine *engine);
+ explicit QIcon(QIconEngineV2 *engine);
+ ~QIcon();
+ QIcon &operator=(const QIcon &other);
+#ifdef Q_COMPILER_RVALUE_REFS
+ inline QIcon &operator=(QIcon &&other)
+ { qSwap(d, other.d); return *this; }
+#endif
+ inline void swap(QIcon &other) { qSwap(d, other.d); }
+
+ operator QVariant() const;
+
+ QPixmap pixmap(const QSize &size, Mode mode = Normal, State state = Off) const;
+ inline QPixmap pixmap(int w, int h, Mode mode = Normal, State state = Off) const
+ { return pixmap(QSize(w, h), mode, state); }
+ inline QPixmap pixmap(int extent, Mode mode = Normal, State state = Off) const
+ { return pixmap(QSize(extent, extent), mode, state); }
+
+ QSize actualSize(const QSize &size, Mode mode = Normal, State state = Off) const;
+
+ QString name() const;
+
+ void paint(QPainter *painter, const QRect &rect, Qt::Alignment alignment = Qt::AlignCenter, Mode mode = Normal, State state = Off) const;
+ inline void paint(QPainter *painter, int x, int y, int w, int h, Qt::Alignment alignment = Qt::AlignCenter, Mode mode = Normal, State state = Off) const
+ { paint(painter, QRect(x, y, w, h), alignment, mode, state); }
+
+ bool isNull() const;
+ bool isDetached() const;
+ void detach();
+
+ int serialNumber() const;
+ qint64 cacheKey() const;
+
+ void addPixmap(const QPixmap &pixmap, Mode mode = Normal, State state = Off);
+ void addFile(const QString &fileName, const QSize &size = QSize(), Mode mode = Normal, State state = Off);
+
+ QList<QSize> availableSizes(Mode mode = Normal, State state = Off) const;
+
+ static QIcon fromTheme(const QString &name, const QIcon &fallback = QIcon());
+ static bool hasThemeIcon(const QString &name);
+
+ static QStringList themeSearchPaths();
+ static void setThemeSearchPaths(const QStringList &searchpath);
+
+ static QString themeName();
+ static void setThemeName(const QString &path);
+
+
+#ifdef QT3_SUPPORT
+ enum Size { Small, Large, Automatic = Small };
+ static QT3_SUPPORT void setPixmapSize(Size which, const QSize &size);
+ static QT3_SUPPORT QSize pixmapSize(Size which);
+ inline QT3_SUPPORT void reset(const QPixmap &pixmap, Size /*size*/) { *this = QIcon(pixmap); }
+ inline QT3_SUPPORT void setPixmap(const QPixmap &pixmap, Size, Mode mode = Normal, State state = Off)
+ { addPixmap(pixmap, mode, state); }
+ inline QT3_SUPPORT void setPixmap(const QString &fileName, Size, Mode mode = Normal, State state = Off)
+ { addPixmap(QPixmap(fileName), mode, state); }
+ QT3_SUPPORT QPixmap pixmap(Size size, Mode mode, State state = Off) const;
+ QT3_SUPPORT QPixmap pixmap(Size size, bool enabled, State state = Off) const;
+ QT3_SUPPORT QPixmap pixmap() const;
+#endif
+
+ Q_DUMMY_COMPARISON_OPERATOR(QIcon)
+
+private:
+ QIconPrivate *d;
+#if !defined(QT_NO_DATASTREAM)
+ friend Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QIcon &);
+ friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QIcon &);
+#endif
+
+public:
+ typedef QIconPrivate * DataPtr;
+ inline DataPtr &data_ptr() { return d; }
+};
+
+Q_DECLARE_SHARED(QIcon)
+Q_DECLARE_TYPEINFO(QIcon, Q_MOVABLE_TYPE);
+
+#if !defined(QT_NO_DATASTREAM)
+Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QIcon &);
+Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QIcon &);
+#endif
+
+#ifdef QT3_SUPPORT
+typedef QIcon QIconSet;
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QICON_H
diff --git a/src/gui/image/qicon_p.h b/src/gui/image/qicon_p.h
new file mode 100644
index 0000000000..0bf7e65cc1
--- /dev/null
+++ b/src/gui/image/qicon_p.h
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QICON_P_H
+#define QICON_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qlist.h>
+#include <QtGui/qpixmap.h>
+#include <QtGui/qicon.h>
+#include <QtGui/qiconengine.h>
+
+#ifndef QT_NO_ICON
+QT_BEGIN_NAMESPACE
+
+class QIconPrivate
+{
+public:
+ QIconPrivate();
+
+ ~QIconPrivate() {
+ if (engine_version == 1) {
+ if (!v1RefCount->deref()) {
+ delete engine;
+ delete v1RefCount;
+ }
+ } else if (engine_version == 2) {
+ delete engine;
+ }
+ }
+
+ QIconEngine *engine;
+
+ QAtomicInt ref;
+ int serialNum;
+ int detach_no;
+ int engine_version;
+
+ QAtomicInt *v1RefCount;
+};
+
+
+struct QPixmapIconEngineEntry
+{
+ QPixmapIconEngineEntry():mode(QIcon::Normal), state(QIcon::Off){}
+ QPixmapIconEngineEntry(const QPixmap &pm, QIcon::Mode m = QIcon::Normal, QIcon::State s = QIcon::Off)
+ :pixmap(pm), size(pm.size()), mode(m), state(s){}
+ QPixmapIconEngineEntry(const QString &file, const QSize &sz = QSize(), QIcon::Mode m = QIcon::Normal, QIcon::State s = QIcon::Off)
+ :fileName(file), size(sz), mode(m), state(s){}
+ QPixmap pixmap;
+ QString fileName;
+ QSize size;
+ QIcon::Mode mode;
+ QIcon::State state;
+ bool isNull() const {return (fileName.isEmpty() && pixmap.isNull()); }
+};
+
+
+
+class QPixmapIconEngine : public QIconEngineV2 {
+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);
+ 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);
+
+ // v2 functions
+ QString key() const;
+ QIconEngineV2 *clone() const;
+ bool read(QDataStream &in);
+ bool write(QDataStream &out) const;
+ void virtual_hook(int id, void *data);
+
+private:
+ QPixmapIconEngineEntry *tryMatch(const QSize &size, QIcon::Mode mode, QIcon::State state);
+ QVector<QPixmapIconEngineEntry> pixmaps;
+
+ friend QDataStream &operator<<(QDataStream &s, const QIcon &icon);
+ friend class QIconThemeEngine;
+};
+
+QT_END_NAMESPACE
+#endif //QT_NO_ICON
+#endif // QICON_P_H
diff --git a/src/gui/image/qiconengine.cpp b/src/gui/image/qiconengine.cpp
new file mode 100644
index 0000000000..6168a83940
--- /dev/null
+++ b/src/gui/image/qiconengine.cpp
@@ -0,0 +1,324 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qiconengine.h"
+#include "qpainter.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QIconEngine
+
+ \brief The QIconEngine class provides an abstract base class for QIcon renderers.
+
+ \ingroup painting
+
+ \bold {Use QIconEngineV2 instead.}
+
+ An icon engine provides the rendering functions for a QIcon. Each icon has a
+ corresponding icon engine that is responsible for drawing the icon with a
+ requested size, mode and state.
+
+ The icon is rendered by the paint() function, and the icon can additionally be
+ obtained as a pixmap with the pixmap() function (the default implementation
+ simply uses paint() to achieve this). The addPixmap() function can be used to
+ add new pixmaps to the icon engine, and is used by QIcon to add specialized
+ custom pixmaps.
+
+ The paint(), pixmap(), and addPixmap() functions are all virtual, and can
+ therefore be reimplemented in subclasses of QIconEngine.
+
+ \sa QIconEngineV2, QIconEnginePlugin
+
+*/
+
+/*!
+ \fn virtual void QIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) = 0;
+
+ Uses the given \a painter to paint the icon with the required \a mode and
+ \a state into the rectangle \a rect.
+*/
+
+/*! Returns the actual size of the icon the engine provides for the
+ requested \a size, \a mode and \a state. The default implementation
+ returns the given \a size.
+ */
+QSize QIconEngine::actualSize(const QSize &size, QIcon::Mode /*mode*/, QIcon::State /*state*/)
+{
+ return size;
+}
+
+
+/*!
+ Destroys the icon engine.
+ */
+QIconEngine::~QIconEngine()
+{
+}
+
+
+/*!
+ Returns the icon as a pixmap with the required \a size, \a mode,
+ and \a state. The default implementation creates a new pixmap and
+ calls paint() to fill it.
+*/
+QPixmap QIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
+{
+ QPixmap pm(size);
+ {
+ QPainter p(&pm);
+ paint(&p, QRect(QPoint(0,0),size), mode, state);
+ }
+ return pm;
+}
+
+/*!
+ Called by QIcon::addPixmap(). Adds a specialized \a pixmap for the given
+ \a mode and \a state. The default pixmap-based engine stores any supplied
+ pixmaps, and it uses them instead of scaled pixmaps if the size of a pixmap
+ matches the size of icon requested. Custom icon engines that implement
+ scalable vector formats are free to ignores any extra pixmaps.
+ */
+void QIconEngine::addPixmap(const QPixmap &/*pixmap*/, QIcon::Mode /*mode*/, QIcon::State /*state*/)
+{
+}
+
+
+/*! Called by QIcon::addFile(). Adds a specialized pixmap from the
+ file with the given \a fileName, \a size, \a mode and \a state. The
+ default pixmap-based engine stores any supplied file names, and it
+ loads the pixmaps on demand instead of using scaled pixmaps if the
+ size of a pixmap matches the size of icon requested. Custom icon
+ engines that implement scalable vector formats are free to ignores
+ any extra files.
+ */
+void QIconEngine::addFile(const QString &/*fileName*/, const QSize &/*size*/, QIcon::Mode /*mode*/, QIcon::State /*state*/)
+{
+}
+
+
+
+// version 2 functions
+
+
+/*!
+ \class QIconEngineV2
+
+ \brief The QIconEngineV2 class provides an abstract base class for QIcon renderers.
+
+ \ingroup painting
+ \since 4.3
+
+ An icon engine renders \l{QIcon}s. With icon engines, you can
+ customize icons. Qt provides a default engine that makes icons
+ adhere to the current style by scaling the icons and providing a
+ disabled appearance.
+
+ An engine is installed on an icon either through a QIcon
+ constructor or through a QIconEnginePluginV2. The plugins are used
+ by Qt if a specific engine is not given when the icon is created.
+ See the QIconEngineV2 class description to learn how to create
+ icon engine plugins.
+
+ An icon engine provides the rendering functions for a QIcon. Each
+ icon has a corresponding icon engine that is responsible for drawing
+ the icon with a requested size, mode and state.
+
+ QIconEngineV2 extends the API of QIconEngine to allow streaming of
+ the icon engine contents, and should be used instead of QIconEngine
+ for implementing new icon engines.
+
+ \sa QIconEnginePluginV2
+
+*/
+
+/*!
+ \enum QIconEngineV2::IconEngineHook
+ \since 4.5
+
+ These enum values are used for virtual_hook() to allow additional
+ queries to icon engine without breaking binary compatibility.
+
+ \value AvailableSizesHook Allows to query the sizes of the
+ contained pixmaps for pixmap-based engines. The \a data argument
+ of the virtual_hook() function is a AvailableSizesArgument pointer
+ that should be filled with icon sizes. Engines that work in terms
+ of a scalable, vectorial format normally return an empty list.
+
+ \value IconNameHook Allows to query the name used to create the
+ icon, for example when instantiating an icon using
+ QIcon::fromTheme().
+
+ \sa virtual_hook()
+ */
+
+/*!
+ \class QIconEngineV2::AvailableSizesArgument
+ \since 4.5
+
+ This struct represents arguments to virtual_hook() function when
+ \a id parameter is QIconEngineV2::AvailableSizesHook.
+
+ \sa virtual_hook(), QIconEngineV2::IconEngineHook
+ */
+
+/*!
+ \variable QIconEngineV2::AvailableSizesArgument::mode
+ \brief the requested mode of an image.
+
+ \sa QIcon::Mode
+*/
+
+/*!
+ \variable QIconEngineV2::AvailableSizesArgument::state
+ \brief the requested state of an image.
+
+ \sa QIcon::State
+*/
+
+/*!
+ \variable QIconEngineV2::AvailableSizesArgument::sizes
+
+ \brief image sizes that are available with specified \a mode and
+ \a state. This is an output parameter and is filled after call to
+ virtual_hook(). Engines that work in terms of a scalable,
+ vectorial format normally return an empty list.
+*/
+
+
+/*!
+ Returns a key that identifies this icon engine.
+ */
+QString QIconEngineV2::key() const
+{
+ return QString();
+}
+
+/*!
+ Returns a clone of this icon engine.
+ */
+QIconEngineV2 *QIconEngineV2::clone() const
+{
+ return 0;
+}
+
+/*!
+ Reads icon engine contents from the QDataStream \a in. Returns
+ true if the contents were read; otherwise returns false.
+
+ QIconEngineV2's default implementation always return false.
+ */
+bool QIconEngineV2::read(QDataStream &)
+{
+ return false;
+}
+
+/*!
+ Writes the contents of this engine to the QDataStream \a out.
+ Returns true if the contents were written; otherwise returns false.
+
+ QIconEngineV2's default implementation always return false.
+ */
+bool QIconEngineV2::write(QDataStream &) const
+{
+ return false;
+}
+
+/*!
+ \since 4.5
+
+ Additional method to allow extending QIconEngineV2 without
+ adding new virtual methods (and without breaking binary compatibility).
+ The actual action and format of \a data depends on \a id argument
+ which is in fact a constant from IconEngineHook enum.
+
+ \sa IconEngineHook
+*/
+void QIconEngineV2::virtual_hook(int id, void *data)
+{
+ switch (id) {
+ case QIconEngineV2::AvailableSizesHook: {
+ QIconEngineV2::AvailableSizesArgument &arg =
+ *reinterpret_cast<QIconEngineV2::AvailableSizesArgument*>(data);
+ arg.sizes.clear();
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+/*!
+ \since 4.5
+
+ Returns sizes of all images that are contained in the engine for the
+ specific \a mode and \a state.
+
+ \note This is a helper method and the actual work is done by
+ virtual_hook() method, hence this method depends on icon engine support
+ and may not work with all icon engines.
+ */
+QList<QSize> QIconEngineV2::availableSizes(QIcon::Mode mode, QIcon::State state)
+{
+ AvailableSizesArgument arg;
+ arg.mode = mode;
+ arg.state = state;
+ virtual_hook(QIconEngineV2::AvailableSizesHook, reinterpret_cast<void*>(&arg));
+ return arg.sizes;
+}
+
+/*!
+ \since 4.7
+
+ Returns the name used to create the engine, if available.
+
+ \note This is a helper method and the actual work is done by
+ virtual_hook() method, hence this method depends on icon engine support
+ and may not work with all icon engines.
+ */
+QString QIconEngineV2::iconName()
+{
+ QString name;
+ virtual_hook(QIconEngineV2::IconNameHook, reinterpret_cast<void*>(&name));
+ return name;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/image/qiconengine.h b/src/gui/image/qiconengine.h
new file mode 100644
index 0000000000..12caea8a20
--- /dev/null
+++ b/src/gui/image/qiconengine.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QICONENGINE_H
+#define QICONENGINE_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qlist.h>
+#include <QtGui/qicon.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class Q_GUI_EXPORT QIconEngine
+{
+public:
+ virtual ~QIconEngine();
+ virtual void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) = 0;
+ virtual QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state);
+ virtual QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state);
+
+ virtual void addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state);
+ virtual void addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state);
+
+#if 0
+ virtual int frameCount(QIcon::Mode fromMode, QIcon::State fromState, QIcon::Mode toMode, QIcon::State toState);
+ virtual void paintFrame(QPainter *painter, const QRect &rect, int frameNumber, QIcon::Mode fromMode, QIcon::State fromState, QIcon::Mode toMode, QIcon::State toState);
+#endif
+};
+
+// ### Qt 5: move the below into QIconEngine
+class Q_GUI_EXPORT QIconEngineV2 : public QIconEngine
+{
+public:
+ virtual QString key() const;
+ virtual QIconEngineV2 *clone() const;
+ virtual bool read(QDataStream &in);
+ virtual bool write(QDataStream &out) const;
+ virtual void virtual_hook(int id, void *data);
+
+public:
+ enum IconEngineHook { AvailableSizesHook = 1, IconNameHook };
+
+ struct AvailableSizesArgument
+ {
+ QIcon::Mode mode;
+ QIcon::State state;
+ QList<QSize> sizes;
+ };
+
+ // ### Qt 5: make this function const and virtual.
+ QList<QSize> availableSizes(QIcon::Mode mode = QIcon::Normal,
+ QIcon::State state = QIcon::Off);
+
+ // ### Qt 5: make this function const and virtual.
+ QString iconName();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QICONENGINE_H
diff --git a/src/gui/image/qiconengineplugin.cpp b/src/gui/image/qiconengineplugin.cpp
new file mode 100644
index 0000000000..7c8c3a3c1a
--- /dev/null
+++ b/src/gui/image/qiconengineplugin.cpp
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qiconengineplugin.h"
+#include "qiconengine.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QIconEnginePlugin
+ \brief The QIconEnginePlugin class provides an abstract base for custom QIconEngine plugins.
+
+ \ingroup plugins
+
+ \bold {Use QIconEnginePluginV2 instead.}
+
+ The icon engine plugin is a simple plugin interface that makes it easy to
+ create custom icon engines that can be loaded dynamically into applications
+ through QIcon. QIcon uses the file or resource name's suffix to determine
+ what icon engine to use.
+
+ Writing a icon engine plugin is achieved by subclassing this base class,
+ reimplementing the pure virtual functions keys() and create(), and
+ exporting the class with the Q_EXPORT_PLUGIN2() macro.
+
+ \sa {How to Create Qt Plugins}
+*/
+
+/*!
+ \fn QStringList QIconEnginePlugin::keys() const
+
+ Returns a list of icon engine keys that this plugin supports. The keys correspond
+ to the suffix of the file or resource name used when the plugin was created.
+ Keys are case insensitive.
+
+ \sa create()
+*/
+
+/*!
+ \fn QIconEngine* QIconEnginePlugin::create(const QString& filename)
+
+ Creates and returns a QIconEngine object for the icon with the given
+ \a filename.
+
+ \sa keys()
+*/
+
+/*!
+ Constructs a icon engine plugin with the given \a parent. This is invoked
+ automatically by the Q_EXPORT_PLUGIN2() macro.
+*/
+QIconEnginePlugin::QIconEnginePlugin(QObject *parent)
+ : QObject(parent)
+{
+}
+
+/*!
+ Destroys the icon engine plugin.
+
+ You never have to call this explicitly. Qt destroys a plugin
+ automatically when it is no longer used.
+*/
+QIconEnginePlugin::~QIconEnginePlugin()
+{
+}
+
+// version 2
+
+/*!
+ \class QIconEnginePluginV2
+ \brief The QIconEnginePluginV2 class provides an abstract base for custom QIconEngineV2 plugins.
+
+ \ingroup plugins
+ \since 4.3
+
+ Icon engine plugins produces \l{QIconEngine}s for \l{QIcon}s; an
+ icon engine is used to render the icon. The keys that identifies
+ the engines the plugin can create are suffixes of
+ icon filenames; they are returned by keys(). The create() function
+ receives the icon filename to return an engine for; it should
+ return 0 if it cannot produce an engine for the file.
+
+ Writing an icon engine plugin is achieved by inheriting
+ QIconEnginePluginV2, reimplementing keys() and create(), and
+ adding the Q_EXPORT_PLUGIN2() macro.
+
+ You should ensure that you do not duplicate keys. Qt will query
+ the plugins for icon engines in the order in which the plugins are
+ found during plugin search (see the plugins \l{How to Create Qt
+ Plugins}{overview document}).
+
+ \sa {How to Create Qt Plugins}
+*/
+
+/*!
+ \fn QStringList QIconEnginePluginV2::keys() const
+
+ Returns a list of icon engine keys that this plugin supports. The keys correspond
+ to the suffix of the file or resource name used when the plugin was created.
+ Keys are case insensitive.
+
+ \sa create()
+*/
+
+/*!
+ \fn QIconEngineV2* QIconEnginePluginV2::create(const QString& filename = QString())
+
+ Creates and returns a QIconEngine object for the icon with the given
+ \a filename.
+
+ \sa keys()
+*/
+
+/*!
+ Constructs a icon engine plugin with the given \a parent. This is invoked
+ automatically by the Q_EXPORT_PLUGIN2() macro.
+*/
+QIconEnginePluginV2::QIconEnginePluginV2(QObject *parent)
+ : QObject(parent)
+{
+}
+
+/*!
+ Destroys the icon engine plugin.
+
+ You never have to call this explicitly. Qt destroys a plugin
+ automatically when it is no longer used.
+*/
+QIconEnginePluginV2::~QIconEnginePluginV2()
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/image/qiconengineplugin.h b/src/gui/image/qiconengineplugin.h
new file mode 100644
index 0000000000..e892a38f7b
--- /dev/null
+++ b/src/gui/image/qiconengineplugin.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QICONENGINEPLUGIN_H
+#define QICONENGINEPLUGIN_H
+
+#include <QtCore/qplugin.h>
+#include <QtCore/qfactoryinterface.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QIconEngine;
+class QIconEngineV2;
+
+struct Q_GUI_EXPORT QIconEngineFactoryInterface : public QFactoryInterface
+{
+ virtual QIconEngine *create(const QString &filename) = 0;
+};
+
+#define QIconEngineFactoryInterface_iid \
+ "com.trolltech.Qt.QIconEngineFactoryInterface"
+Q_DECLARE_INTERFACE(QIconEngineFactoryInterface, QIconEngineFactoryInterface_iid)
+
+class Q_GUI_EXPORT QIconEnginePlugin : public QObject, public QIconEngineFactoryInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QIconEngineFactoryInterface:QFactoryInterface)
+public:
+ QIconEnginePlugin(QObject *parent = 0);
+ ~QIconEnginePlugin();
+
+ virtual QStringList keys() const = 0;
+ virtual QIconEngine *create(const QString &filename) = 0;
+};
+
+// ### Qt 5: remove version 2
+struct Q_GUI_EXPORT QIconEngineFactoryInterfaceV2 : public QFactoryInterface
+{
+ virtual QIconEngineV2 *create(const QString &filename = QString()) = 0;
+};
+
+#define QIconEngineFactoryInterfaceV2_iid \
+ "com.trolltech.Qt.QIconEngineFactoryInterfaceV2"
+Q_DECLARE_INTERFACE(QIconEngineFactoryInterfaceV2, QIconEngineFactoryInterfaceV2_iid)
+
+class Q_GUI_EXPORT QIconEnginePluginV2 : public QObject, public QIconEngineFactoryInterfaceV2
+{
+ Q_OBJECT
+ Q_INTERFACES(QIconEngineFactoryInterfaceV2:QFactoryInterface)
+public:
+ QIconEnginePluginV2(QObject *parent = 0);
+ ~QIconEnginePluginV2();
+
+ virtual QStringList keys() const = 0;
+ virtual QIconEngineV2 *create(const QString &filename = QString()) = 0;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QICONENGINEPLUGIN_H
diff --git a/src/gui/image/qiconloader.cpp b/src/gui/image/qiconloader.cpp
new file mode 100644
index 0000000000..0a42f0af78
--- /dev/null
+++ b/src/gui/image/qiconloader.cpp
@@ -0,0 +1,570 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QT_NO_ICON
+#include <private/qiconloader_p.h>
+
+#include <private/qapplication_p.h>
+#include <private/qicon_p.h>
+#include <private/qguiplatformplugin_p.h>
+
+#include <QtGui/QIconEnginePlugin>
+#include <QtGui/QPixmapCache>
+#include <QtGui/QIconEngine>
+#include <QtGui/QStyleOption>
+#include <QtCore/QList>
+#include <QtCore/QHash>
+#include <QtCore/QDir>
+#include <QtCore/QSettings>
+#include <QtGui/QPainter>
+
+#ifdef Q_WS_MAC
+#include <private/qt_cocoa_helpers_mac_p.h>
+#endif
+
+#ifdef Q_WS_X11
+#include <private/qt_x11_p.h>
+#endif
+
+#include <private/qstylehelper_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QIconLoader, iconLoaderInstance)
+
+/* Theme to use in last resort, if the theme does not have the icon, neither the parents */
+static QString fallbackTheme()
+{
+#ifdef Q_WS_X11
+ if (X11->desktopEnvironment == DE_GNOME) {
+ return QLatin1String("gnome");
+ } else if (X11->desktopEnvironment == DE_KDE) {
+ return X11->desktopVersion >= 4
+ ? QString::fromLatin1("oxygen")
+ : QString::fromLatin1("crystalsvg");
+ } else {
+ return QLatin1String("hicolor");
+ }
+#endif
+ return QString();
+}
+
+QIconLoader::QIconLoader() :
+ m_themeKey(1), m_supportsSvg(false), m_initialized(false)
+{
+}
+
+// We lazily initialize the loader to make static icons
+// work. Though we do not officially support this.
+void QIconLoader::ensureInitialized()
+{
+ if (!m_initialized) {
+ m_initialized = true;
+
+ Q_ASSERT(qApp);
+
+ m_systemTheme = qt_guiPlatformPlugin()->systemIconThemeName();
+ if (m_systemTheme.isEmpty())
+ m_systemTheme = fallbackTheme();
+#ifndef QT_NO_LIBRARY
+ QFactoryLoader iconFactoryLoader(QIconEngineFactoryInterfaceV2_iid,
+ QLatin1String("/iconengines"),
+ Qt::CaseInsensitive);
+ if (iconFactoryLoader.keys().contains(QLatin1String("svg")))
+ m_supportsSvg = true;
+#endif //QT_NO_LIBRARY
+ }
+}
+
+QIconLoader *QIconLoader::instance()
+{
+ return iconLoaderInstance();
+}
+
+// Queries the system theme and invalidates existing
+// icons if the theme has changed.
+void QIconLoader::updateSystemTheme()
+{
+ // Only change if this is not explicitly set by the user
+ if (m_userTheme.isEmpty()) {
+ QString theme = qt_guiPlatformPlugin()->systemIconThemeName();
+ if (theme.isEmpty())
+ theme = fallbackTheme();
+ if (theme != m_systemTheme) {
+ m_systemTheme = theme;
+ invalidateKey();
+ }
+ }
+}
+
+void QIconLoader::setThemeName(const QString &themeName)
+{
+ m_userTheme = themeName;
+ invalidateKey();
+}
+
+void QIconLoader::setThemeSearchPath(const QStringList &searchPaths)
+{
+ m_iconDirs = searchPaths;
+ themeList.clear();
+ invalidateKey();
+}
+
+QStringList QIconLoader::themeSearchPaths() const
+{
+ if (m_iconDirs.isEmpty()) {
+ m_iconDirs = qt_guiPlatformPlugin()->iconThemeSearchPaths();
+ // Always add resource directory as search path
+ m_iconDirs.append(QLatin1String(":/icons"));
+ }
+ return m_iconDirs;
+}
+
+QIconTheme::QIconTheme(const QString &themeName)
+ : m_valid(false)
+{
+ QFile themeIndex;
+
+ QList <QIconDirInfo> keyList;
+ QStringList iconDirs = QIcon::themeSearchPaths();
+ 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;
+ }
+ }
+#ifndef QT_NO_SETTINGS
+ if (themeIndex.exists()) {
+ const QSettings indexReader(themeIndex.fileName(), QSettings::IniFormat);
+ QStringListIterator keyIterator(indexReader.allKeys());
+ while (keyIterator.hasNext()) {
+
+ const QString key = keyIterator.next();
+ if (key.endsWith(QLatin1String("/Size"))) {
+ // Note the QSettings ini-format does not accept
+ // slashes in key names, hence we have to cheat
+ if (int size = indexReader.value(key).toInt()) {
+ QString directoryKey = key.left(key.size() - 5);
+ QIconDirInfo dirInfo(directoryKey);
+ dirInfo.size = size;
+ QString type = indexReader.value(directoryKey +
+ QLatin1String("/Type")
+ ).toString();
+
+ if (type == QLatin1String("Fixed"))
+ dirInfo.type = QIconDirInfo::Fixed;
+ else if (type == QLatin1String("Scalable"))
+ dirInfo.type = QIconDirInfo::Scalable;
+ else
+ dirInfo.type = QIconDirInfo::Threshold;
+
+ dirInfo.threshold = indexReader.value(directoryKey +
+ QLatin1String("/Threshold"),
+ 2).toInt();
+
+ dirInfo.minSize = indexReader.value(directoryKey +
+ QLatin1String("/MinSize"),
+ size).toInt();
+
+ dirInfo.maxSize = indexReader.value(directoryKey +
+ QLatin1String("/MaxSize"),
+ size).toInt();
+ m_keyList.append(dirInfo);
+ }
+ }
+ }
+
+ // Parent themes provide fallbacks for missing icons
+ m_parents = indexReader.value(
+ QLatin1String("Icon Theme/Inherits")).toStringList();
+
+ // Ensure a default platform fallback for all themes
+ if (m_parents.isEmpty())
+ m_parents.append(fallbackTheme());
+
+ // Ensure that all themes fall back to hicolor
+ if (!m_parents.contains(QLatin1String("hicolor")))
+ m_parents.append(QLatin1String("hicolor"));
+ }
+#endif //QT_NO_SETTINGS
+}
+
+QThemeIconEntries QIconLoader::findIconHelper(const QString &themeName,
+ const QString &iconName,
+ QStringList &visited) const
+{
+ QThemeIconEntries entries;
+ Q_ASSERT(!themeName.isEmpty());
+
+ QPixmap pixmap;
+
+ // Used to protect against potential recursions
+ visited << themeName;
+
+ QIconTheme theme = themeList.value(themeName);
+ if (!theme.isValid()) {
+ theme = QIconTheme(themeName);
+ if (!theme.isValid())
+ theme = QIconTheme(fallbackTheme());
+
+ themeList.insert(themeName, theme);
+ }
+
+ QString contentDir = theme.contentDir() + QLatin1Char('/');
+ QList<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);
+ }
+ }
+
+ if (entries.isEmpty()) {
+ const QStringList parents = theme.parents();
+ // Search recursively through inherited themes
+ for (int i = 0 ; i < parents.size() ; ++i) {
+
+ const QString parentTheme = parents.at(i).trimmed();
+
+ if (!visited.contains(parentTheme)) // guard against recursion
+ entries = findIconHelper(parentTheme, iconName, visited);
+
+ if (!entries.isEmpty()) // success
+ break;
+ }
+ }
+ return entries;
+}
+
+QThemeIconEntries QIconLoader::loadIcon(const QString &name) const
+{
+ if (!themeName().isEmpty()) {
+ QStringList visited;
+ return findIconHelper(themeName(), name, visited);
+ }
+
+ return QThemeIconEntries();
+}
+
+
+// -------- Icon Loader Engine -------- //
+
+
+QIconLoaderEngine::QIconLoaderEngine(const QString& iconName)
+ : m_iconName(iconName), m_key(0)
+{
+}
+
+QIconLoaderEngine::~QIconLoaderEngine()
+{
+ while (!m_entries.isEmpty())
+ delete m_entries.takeLast();
+ Q_ASSERT(m_entries.size() == 0);
+}
+
+QIconLoaderEngine::QIconLoaderEngine(const QIconLoaderEngine &other)
+ : QIconEngineV2(other),
+ m_iconName(other.m_iconName),
+ m_key(0)
+{
+}
+
+QIconEngineV2 *QIconLoaderEngine::clone() const
+{
+ return new QIconLoaderEngine(*this);
+}
+
+bool QIconLoaderEngine::read(QDataStream &in) {
+ in >> m_iconName;
+ return true;
+}
+
+bool QIconLoaderEngine::write(QDataStream &out) const
+{
+ out << m_iconName;
+ return true;
+}
+
+bool QIconLoaderEngine::hasIcon() const
+{
+ return !(m_entries.isEmpty());
+}
+
+// Lazily load the icon
+void QIconLoaderEngine::ensureLoaded()
+{
+
+ iconLoaderInstance()->ensureInitialized();
+
+ if (!(iconLoaderInstance()->themeKey() == m_key)) {
+
+ while (!m_entries.isEmpty())
+ delete m_entries.takeLast();
+
+ Q_ASSERT(m_entries.size() == 0);
+ m_entries = iconLoaderInstance()->loadIcon(m_iconName);
+ m_key = iconLoaderInstance()->themeKey();
+ }
+}
+
+void QIconLoaderEngine::paint(QPainter *painter, const QRect &rect,
+ QIcon::Mode mode, QIcon::State state)
+{
+ QSize pixmapSize = rect.size();
+#if defined(Q_WS_MAC)
+ pixmapSize *= qt_mac_get_scalefactor();
+#endif
+ painter->drawPixmap(rect, pixmap(pixmapSize, mode, state));
+}
+
+/*
+ * This algorithm is defined by the freedesktop spec:
+ * http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
+ */
+static bool directoryMatchesSize(const QIconDirInfo &dir, int iconsize)
+{
+ if (dir.type == QIconDirInfo::Fixed) {
+ return dir.size == iconsize;
+
+ } else if (dir.type == QIconDirInfo::Scalable) {
+ return dir.size <= dir.maxSize &&
+ iconsize >= dir.minSize;
+
+ } else if (dir.type == QIconDirInfo::Threshold) {
+ return iconsize >= dir.size - dir.threshold &&
+ iconsize <= dir.size + dir.threshold;
+ }
+
+ Q_ASSERT(1); // Not a valid value
+ return false;
+}
+
+/*
+ * This algorithm is defined by the freedesktop spec:
+ * http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
+ */
+static int directorySizeDistance(const QIconDirInfo &dir, int iconsize)
+{
+ if (dir.type == QIconDirInfo::Fixed) {
+ return qAbs(dir.size - iconsize);
+
+ } else if (dir.type == QIconDirInfo::Scalable) {
+ if (iconsize < dir.minSize)
+ return dir.minSize - iconsize;
+ else if (iconsize > dir.maxSize)
+ return iconsize - dir.maxSize;
+ else
+ return 0;
+
+ } else if (dir.type == QIconDirInfo::Threshold) {
+ if (iconsize < dir.size - dir.threshold)
+ return dir.minSize - iconsize;
+ else if (iconsize > dir.size + dir.threshold)
+ return iconsize - dir.maxSize;
+ else return 0;
+ }
+
+ Q_ASSERT(1); // Not a valid value
+ return INT_MAX;
+}
+
+QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QSize &size)
+{
+ int iconsize = qMin(size.width(), size.height());
+
+ // Note that m_entries are sorted so that png-files
+ // come first
+
+ // Search for exact matches first
+ for (int i = 0; i < m_entries.count(); ++i) {
+ QIconLoaderEngineEntry *entry = m_entries.at(i);
+ if (directoryMatchesSize(entry->dir, iconsize)) {
+ return entry;
+ }
+ }
+
+ // Find the minimum distance icon
+ int minimalSize = INT_MAX;
+ QIconLoaderEngineEntry *closestMatch = 0;
+ for (int i = 0; i < m_entries.count(); ++i) {
+ QIconLoaderEngineEntry *entry = m_entries.at(i);
+ int distance = directorySizeDistance(entry->dir, iconsize);
+ if (distance < minimalSize) {
+ minimalSize = distance;
+ closestMatch = entry;
+ }
+ }
+ return closestMatch;
+}
+
+/*
+ * Returns the actual icon size. For scalable svg's this is equivalent
+ * to the requested size. Otherwise the closest match is returned but
+ * we can never return a bigger size than the requested size.
+ *
+ */
+QSize QIconLoaderEngine::actualSize(const QSize &size, QIcon::Mode mode,
+ QIcon::State state)
+{
+ ensureLoaded();
+
+ QIconLoaderEngineEntry *entry = entryForSize(size);
+ if (entry) {
+ const QIconDirInfo &dir = entry->dir;
+ if (dir.type == QIconDirInfo::Scalable)
+ return size;
+ else {
+ int result = qMin<int>(dir.size, qMin(size.width(), size.height()));
+ return QSize(result, result);
+ }
+ }
+ return QIconEngineV2::actualSize(size, mode, state);
+}
+
+QPixmap PixmapEntry::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
+{
+ Q_UNUSED(state);
+
+ // Ensure that basePixmap is lazily initialized before generating the
+ // key, otherwise the cache key is not unique
+ if (basePixmap.isNull())
+ basePixmap.load(filename);
+
+ int actualSize = qMin(size.width(), size.height());
+
+ QString key = QLatin1Literal("$qt_theme_")
+ % HexString<qint64>(basePixmap.cacheKey())
+ % HexString<int>(mode)
+ % HexString<qint64>(qApp->palette().cacheKey())
+ % HexString<int>(actualSize);
+
+ QPixmap cachedPixmap;
+ if (QPixmapCache::find(key, &cachedPixmap)) {
+ return cachedPixmap;
+ } else {
+ QStyleOption opt(0);
+ opt.palette = qApp->palette();
+ cachedPixmap = qApp->style()->generatedIconPixmap(mode, basePixmap, &opt);
+ QPixmapCache::insert(key, cachedPixmap);
+ }
+ return cachedPixmap;
+}
+
+QPixmap ScalableEntry::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
+{
+ if (svgIcon.isNull())
+ svgIcon = QIcon(filename);
+
+ // Simply reuse svg icon engine
+ return svgIcon.pixmap(size, mode, state);
+}
+
+QPixmap QIconLoaderEngine::pixmap(const QSize &size, QIcon::Mode mode,
+ QIcon::State state)
+{
+ ensureLoaded();
+
+ QIconLoaderEngineEntry *entry = entryForSize(size);
+ if (entry)
+ return entry->pixmap(size, mode, state);
+
+ return QPixmap();
+}
+
+QString QIconLoaderEngine::key() const
+{
+ return QLatin1String("QIconLoaderEngine");
+}
+
+void QIconLoaderEngine::virtual_hook(int id, void *data)
+{
+ ensureLoaded();
+
+ switch (id) {
+ case QIconEngineV2::AvailableSizesHook:
+ {
+ QIconEngineV2::AvailableSizesArgument &arg
+ = *reinterpret_cast<QIconEngineV2::AvailableSizesArgument*>(data);
+ const QList<QIconDirInfo> directoryKey = iconLoaderInstance()->theme().keyList();
+ arg.sizes.clear();
+
+ // Gets all sizes from the DirectoryInfo entries
+ for (int i = 0 ; i < m_entries.size() ; ++i) {
+ int size = m_entries.at(i)->dir.size;
+ arg.sizes.append(QSize(size, size));
+ }
+ }
+ break;
+ case QIconEngineV2::IconNameHook:
+ {
+ QString &name = *reinterpret_cast<QString*>(data);
+ name = m_iconName;
+ }
+ break;
+ default:
+ QIconEngineV2::virtual_hook(id, data);
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_ICON
diff --git a/src/gui/image/qiconloader_p.h b/src/gui/image/qiconloader_p.h
new file mode 100644
index 0000000000..00a3976b40
--- /dev/null
+++ b/src/gui/image/qiconloader_p.h
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDESKTOPICON_P_H
+#define QDESKTOPICON_P_H
+
+#ifndef QT_NO_ICON
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/QIcon>
+#include <QtGui/QIconEngine>
+#include <QtGui/QPixmapCache>
+#include <private/qicon_p.h>
+#include <private/qfactoryloader_p.h>
+#include <QtCore/QHash>
+
+QT_BEGIN_NAMESPACE
+
+class QIconLoader;
+
+struct QIconDirInfo
+{
+ enum Type { Fixed, Scalable, Threshold };
+ QIconDirInfo(const QString &_path = QString()) :
+ path(_path),
+ size(0),
+ maxSize(0),
+ minSize(0),
+ threshold(0),
+ type(Threshold) {}
+ QString path;
+ short size;
+ short maxSize;
+ short minSize;
+ short threshold;
+ Type type : 4;
+};
+
+class QIconLoaderEngineEntry
+ {
+public:
+ virtual ~QIconLoaderEngineEntry() {}
+ virtual QPixmap pixmap(const QSize &size,
+ QIcon::Mode mode,
+ QIcon::State state) = 0;
+ QString filename;
+ QIconDirInfo dir;
+ static int count;
+};
+
+struct ScalableEntry : public QIconLoaderEngineEntry
+{
+ QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state);
+ QIcon svgIcon;
+};
+
+struct PixmapEntry : public QIconLoaderEngineEntry
+{
+ QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state);
+ QPixmap basePixmap;
+};
+
+typedef QList<QIconLoaderEngineEntry*> QThemeIconEntries;
+
+class QIconLoaderEngine : public QIconEngineV2
+{
+public:
+ QIconLoaderEngine(const QString& iconName = QString());
+ ~QIconLoaderEngine();
+
+ void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state);
+ QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state);
+ QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state);
+ QIconEngineV2 *clone() const;
+ bool read(QDataStream &in);
+ bool write(QDataStream &out) const;
+
+private:
+ QString key() const;
+ bool hasIcon() const;
+ void ensureLoaded();
+ void virtual_hook(int id, void *data);
+ QIconLoaderEngineEntry *entryForSize(const QSize &size);
+ QIconLoaderEngine(const QIconLoaderEngine &other);
+ QThemeIconEntries m_entries;
+ QString m_iconName;
+ uint m_key;
+
+ friend class QIconLoader;
+};
+
+class QIconTheme
+{
+public:
+ QIconTheme(const QString &name);
+ QIconTheme() : m_valid(false) {}
+ QStringList parents() { return m_parents; }
+ QList <QIconDirInfo> keyList() { return m_keyList; }
+ QString contentDir() { return m_contentDir; }
+ bool isValid() { return m_valid; }
+
+private:
+ QString m_contentDir;
+ QList <QIconDirInfo> m_keyList;
+ QStringList m_parents;
+ bool m_valid;
+};
+
+class QIconLoader : public QObject
+{
+public:
+ QIconLoader();
+ QThemeIconEntries loadIcon(const QString &iconName) const;
+ uint themeKey() const { return m_themeKey; }
+
+ QString themeName() const { return m_userTheme.isEmpty() ? m_systemTheme : m_userTheme; }
+ void setThemeName(const QString &themeName);
+ QIconTheme theme() { return themeList.value(themeName()); }
+ void setThemeSearchPath(const QStringList &searchPaths);
+ QStringList themeSearchPaths() const;
+ QIconDirInfo dirInfo(int dirindex);
+ static QIconLoader *instance();
+ void updateSystemTheme();
+ void invalidateKey() { m_themeKey++; }
+ void ensureInitialized();
+
+private:
+ QThemeIconEntries findIconHelper(const QString &themeName,
+ const QString &iconName,
+ QStringList &visited) const;
+ uint m_themeKey;
+ bool m_supportsSvg;
+ bool m_initialized;
+
+ mutable QString m_userTheme;
+ mutable QString m_systemTheme;
+ mutable QStringList m_iconDirs;
+ mutable QHash <QString, QIconTheme> themeList;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDESKTOPICON_P_H
+
+#endif //QT_NO_ICON
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
new file mode 100644
index 0000000000..50b372ea63
--- /dev/null
+++ b/src/gui/image/qimage.cpp
@@ -0,0 +1,6717 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qimage.h"
+#include "qdatastream.h"
+#include "qbuffer.h"
+#include "qmap.h"
+#include "qmatrix.h"
+#include "qtransform.h"
+#include "qimagereader.h"
+#include "qimagewriter.h"
+#include "qstringlist.h"
+#include "qvariant.h"
+#include "qimagepixmapcleanuphooks_p.h"
+#include <ctype.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <math.h>
+#include <private/qdrawhelper_p.h>
+#include <private/qmemrotate_p.h>
+#include <private/qpixmapdata_p.h>
+#include <private/qimagescale_p.h>
+#include <private/qsimd_p.h>
+
+#include <qhash.h>
+
+#include <private/qpaintengine_raster_p.h>
+
+#include <private/qimage_p.h>
+#include <private/qfont_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static inline bool checkPixelSize(const QImage::Format format)
+{
+ switch (format) {
+ case QImage::Format_ARGB8565_Premultiplied:
+ return (sizeof(qargb8565) == 3);
+ case QImage::Format_RGB666:
+ return (sizeof(qrgb666) == 3);
+ case QImage::Format_ARGB6666_Premultiplied:
+ return (sizeof(qargb6666) == 3);
+ case QImage::Format_RGB555:
+ return (sizeof(qrgb555) == 2);
+ case QImage::Format_ARGB8555_Premultiplied:
+ return (sizeof(qargb8555) == 3);
+ case QImage::Format_RGB888:
+ return (sizeof(qrgb888) == 3);
+ case QImage::Format_RGB444:
+ return (sizeof(qrgb444) == 2);
+ case QImage::Format_ARGB4444_Premultiplied:
+ return (sizeof(qargb4444) == 2);
+ default:
+ return true;
+ }
+}
+
+#if defined(Q_CC_DEC) && defined(__alpha) && (__DECCXX_VER-0 >= 50190001)
+#pragma message disable narrowptr
+#endif
+
+
+#define QIMAGE_SANITYCHECK_MEMORY(image) \
+ if ((image).isNull()) { \
+ qWarning("QImage: out of memory, returning null image"); \
+ return QImage(); \
+ }
+
+
+static QImage rotated90(const QImage &src);
+static QImage rotated180(const QImage &src);
+static QImage rotated270(const QImage &src);
+
+// ### Qt 5: remove
+Q_GUI_EXPORT qint64 qt_image_id(const QImage &image)
+{
+ return image.cacheKey();
+}
+
+const QVector<QRgb> *qt_image_colortable(const QImage &image)
+{
+ return &image.d->colortable;
+}
+
+QBasicAtomicInt qimage_serial_number = Q_BASIC_ATOMIC_INITIALIZER(1);
+
+QImageData::QImageData()
+ : ref(0), width(0), height(0), depth(0), nbytes(0), data(0),
+#ifdef QT3_SUPPORT
+ jumptable(0),
+#endif
+ format(QImage::Format_ARGB32), bytes_per_line(0),
+ ser_no(qimage_serial_number.fetchAndAddRelaxed(1)),
+ detach_no(0),
+ dpmx(qt_defaultDpiX() * 100 / qreal(2.54)),
+ dpmy(qt_defaultDpiY() * 100 / qreal(2.54)),
+ offset(0, 0), own_data(true), ro_data(false), has_alpha_clut(false),
+ is_cached(false), paintEngine(0)
+{
+}
+
+/*! \fn QImageData * QImageData::create(const QSize &size, QImage::Format format, int numColors)
+
+ \internal
+
+ Creates a new image data.
+ Returns 0 if invalid parameters are give or anything else failed.
+*/
+QImageData * QImageData::create(const QSize &size, QImage::Format format, int numColors)
+{
+ if (!size.isValid() || numColors < 0 || format == QImage::Format_Invalid)
+ return 0; // invalid parameter(s)
+
+ if (!checkPixelSize(format)) {
+ qWarning("QImageData::create(): Invalid pixel size for format %i",
+ format);
+ return 0;
+ }
+
+ uint width = size.width();
+ uint height = size.height();
+ uint depth = qt_depthForFormat(format);
+
+ switch (format) {
+ case QImage::Format_Mono:
+ case QImage::Format_MonoLSB:
+ numColors = 2;
+ break;
+ case QImage::Format_Indexed8:
+ numColors = qBound(0, numColors, 256);
+ break;
+ default:
+ numColors = 0;
+ break;
+ }
+
+ const int bytes_per_line = ((width * depth + 31) >> 5) << 2; // bytes per scanline (must be multiple of 4)
+
+ // sanity check for potential overflows
+ if (INT_MAX/depth < width
+ || bytes_per_line <= 0
+ || height <= 0
+ || INT_MAX/uint(bytes_per_line) < height
+ || INT_MAX/sizeof(uchar *) < uint(height))
+ return 0;
+
+ QScopedPointer<QImageData> d(new QImageData);
+ d->colortable.resize(numColors);
+ if (depth == 1) {
+ d->colortable[0] = QColor(Qt::black).rgba();
+ d->colortable[1] = QColor(Qt::white).rgba();
+ } else {
+ for (int i = 0; i < numColors; ++i)
+ d->colortable[i] = 0;
+ }
+
+ d->width = width;
+ d->height = height;
+ d->depth = depth;
+ d->format = format;
+ d->has_alpha_clut = false;
+ d->is_cached = false;
+
+ d->bytes_per_line = bytes_per_line;
+
+ d->nbytes = d->bytes_per_line*height;
+ d->data = (uchar *)malloc(d->nbytes);
+
+ if (!d->data) {
+ return 0;
+ }
+
+ d->ref.ref();
+ return d.take();
+
+}
+
+QImageData::~QImageData()
+{
+ if (is_cached)
+ QImagePixmapCleanupHooks::executeImageHooks((((qint64) ser_no) << 32) | ((qint64) detach_no));
+ delete paintEngine;
+ if (data && own_data)
+ free(data);
+#ifdef QT3_SUPPORT
+ if (jumptable)
+ free(jumptable);
+ jumptable = 0;
+#endif
+ data = 0;
+}
+
+
+bool QImageData::checkForAlphaPixels() const
+{
+ bool has_alpha_pixels = false;
+
+ switch (format) {
+
+ case QImage::Format_Mono:
+ case QImage::Format_MonoLSB:
+ case QImage::Format_Indexed8:
+ has_alpha_pixels = has_alpha_clut;
+ break;
+
+ case QImage::Format_ARGB32:
+ case QImage::Format_ARGB32_Premultiplied: {
+ uchar *bits = data;
+ for (int y=0; y<height && !has_alpha_pixels; ++y) {
+ for (int x=0; x<width; ++x)
+ has_alpha_pixels |= (((uint *)bits)[x] & 0xff000000) != 0xff000000;
+ bits += bytes_per_line;
+ }
+ } break;
+
+ case QImage::Format_ARGB8555_Premultiplied:
+ case QImage::Format_ARGB8565_Premultiplied: {
+ uchar *bits = data;
+ uchar *end_bits = data + bytes_per_line;
+
+ for (int y=0; y<height && !has_alpha_pixels; ++y) {
+ while (bits < end_bits) {
+ has_alpha_pixels |= bits[0] != 0;
+ bits += 3;
+ }
+ bits = end_bits;
+ end_bits += bytes_per_line;
+ }
+ } break;
+
+ case QImage::Format_ARGB6666_Premultiplied: {
+ uchar *bits = data;
+ uchar *end_bits = data + bytes_per_line;
+
+ for (int y=0; y<height && !has_alpha_pixels; ++y) {
+ while (bits < end_bits) {
+ has_alpha_pixels |= (bits[0] & 0xfc) != 0;
+ bits += 3;
+ }
+ bits = end_bits;
+ end_bits += bytes_per_line;
+ }
+ } break;
+
+ case QImage::Format_ARGB4444_Premultiplied: {
+ uchar *bits = data;
+ uchar *end_bits = data + bytes_per_line;
+
+ for (int y=0; y<height && !has_alpha_pixels; ++y) {
+ while (bits < end_bits) {
+ has_alpha_pixels |= (bits[0] & 0xf0) != 0;
+ bits += 2;
+ }
+ bits = end_bits;
+ end_bits += bytes_per_line;
+ }
+ } break;
+
+ default:
+ break;
+ }
+
+ return has_alpha_pixels;
+}
+
+/*!
+ \class QImage
+
+ \ingroup painting
+ \ingroup shared
+
+ \reentrant
+
+ \brief The QImage class provides a hardware-independent image
+ representation that allows direct access to the pixel data, and
+ can be used as a paint device.
+
+ Qt provides four classes for handling image data: QImage, QPixmap,
+ QBitmap and QPicture. QImage is designed and optimized for I/O,
+ and for direct pixel access and manipulation, while QPixmap is
+ designed and optimized for showing images on screen. QBitmap is
+ only a convenience class that inherits QPixmap, ensuring a
+ depth of 1. Finally, the QPicture class is a paint device that
+ records and replays QPainter commands.
+
+ Because QImage is a QPaintDevice subclass, QPainter can be used to
+ draw directly onto images. When using QPainter on a QImage, the
+ painting can be performed in another thread than the current GUI
+ thread.
+
+ The QImage class supports several image formats described by the
+ \l Format enum. These include monochrome, 8-bit, 32-bit and
+ alpha-blended images which are available in all versions of Qt
+ 4.x.
+
+ QImage provides a collection of functions that can be used to
+ obtain a variety of information about the image. There are also
+ several functions that enables transformation of the image.
+
+ QImage objects can be passed around by value since the QImage
+ class uses \l{Implicit Data Sharing}{implicit data
+ sharing}. QImage objects can also be streamed and compared.
+
+ \note If you would like to load QImage objects in a static build of Qt,
+ refer to the \l{How To Create Qt Plugins#Static Plugins}{Plugin HowTo}.
+
+ \warning Painting on a QImage with the format
+ QImage::Format_Indexed8 is not supported.
+
+ \tableofcontents
+
+ \section1 Reading and Writing Image Files
+
+ QImage provides several ways of loading an image file: The file
+ can be loaded when constructing the QImage object, or by using the
+ load() or loadFromData() functions later on. QImage also provides
+ the static fromData() function, constructing a QImage from the
+ given data. When loading an image, the file name can either refer
+ to an actual file on disk or to one of the application's embedded
+ resources. See \l{The Qt Resource System} overview for details
+ on how to embed images and other resource files in the
+ application's executable.
+
+ Simply call the save() function to save a QImage object.
+
+ The complete list of supported file formats are available through
+ the QImageReader::supportedImageFormats() and
+ QImageWriter::supportedImageFormats() functions. New file formats
+ can be added as plugins. By default, Qt supports the following
+ formats:
+
+ \table
+ \header \o Format \o Description \o Qt's support
+ \row \o BMP \o Windows Bitmap \o Read/write
+ \row \o GIF \o Graphic Interchange Format (optional) \o Read
+ \row \o JPG \o Joint Photographic Experts Group \o Read/write
+ \row \o JPEG \o Joint Photographic Experts Group \o Read/write
+ \row \o PNG \o Portable Network Graphics \o Read/write
+ \row \o PBM \o Portable Bitmap \o Read
+ \row \o PGM \o Portable Graymap \o Read
+ \row \o PPM \o Portable Pixmap \o Read/write
+ \row \o TIFF \o Tagged Image File Format \o Read/write
+ \row \o XBM \o X11 Bitmap \o Read/write
+ \row \o XPM \o X11 Pixmap \o Read/write
+ \endtable
+
+ \section1 Image Information
+
+ QImage provides a collection of functions that can be used to
+ obtain a variety of information about the image:
+
+ \table
+ \header
+ \o \o Available Functions
+
+ \row
+ \o Geometry
+ \o
+
+ The size(), width(), height(), dotsPerMeterX(), and
+ dotsPerMeterY() functions provide information about the image size
+ and aspect ratio.
+
+ The rect() function returns the image's enclosing rectangle. The
+ valid() function tells if a given pair of coordinates is within
+ this rectangle. The offset() function returns the number of pixels
+ by which the image is intended to be offset by when positioned
+ relative to other images, which also can be manipulated using the
+ setOffset() function.
+
+ \row
+ \o Colors
+ \o
+
+ The color of a pixel can be retrieved by passing its coordinates
+ to the pixel() function. The pixel() function returns the color
+ as a QRgb value indepedent of the image's format.
+
+ In case of monochrome and 8-bit images, the colorCount() and
+ colorTable() functions provide information about the color
+ components used to store the image data: The colorTable() function
+ returns the image's entire color table. To obtain a single entry,
+ use the pixelIndex() function to retrieve the pixel index for a
+ given pair of coordinates, then use the color() function to
+ retrieve the color. Note that if you create an 8-bit image
+ manually, you have to set a valid color table on the image as
+ well.
+
+ The hasAlphaChannel() function tells if the image's format
+ respects the alpha channel, or not. The allGray() and
+ isGrayscale() functions tell whether an image's colors are all
+ shades of gray.
+
+ See also the \l {QImage#Pixel Manipulation}{Pixel Manipulation}
+ and \l {QImage#Image Transformations}{Image Transformations}
+ sections.
+
+ \row
+ \o Text
+ \o
+
+ The text() function returns the image text associated with the
+ given text key. An image's text keys can be retrieved using the
+ textKeys() function. Use the setText() function to alter an
+ image's text.
+
+ \row
+ \o Low-level information
+ \o
+
+ The depth() function returns the depth of the image. The supported
+ depths are 1 (monochrome), 8, 16, 24 and 32 bits. The
+ bitPlaneCount() function tells how many of those bits that are
+ used. For more information see the
+ \l {QImage#Image Formats}{Image Formats} section.
+
+ The format(), bytesPerLine(), and byteCount() functions provide
+ low-level information about the data stored in the image.
+
+ The cacheKey() function returns a number that uniquely
+ identifies the contents of this QImage object.
+ \endtable
+
+ \section1 Pixel Manipulation
+
+ The functions used to manipulate an image's pixels depend on the
+ image format. The reason is that monochrome and 8-bit images are
+ index-based and use a color lookup table, while 32-bit images
+ store ARGB values directly. For more information on image formats,
+ see the \l {Image Formats} section.
+
+ In case of a 32-bit image, the setPixel() function can be used to
+ alter the color of the pixel at the given coordinates to any other
+ color specified as an ARGB quadruplet. To make a suitable QRgb
+ value, use the qRgb() (adding a default alpha component to the
+ given RGB values, i.e. creating an opaque color) or qRgba()
+ function. For example:
+
+ \table
+ \header
+ \o {2,1}32-bit
+ \row
+ \o \inlineimage qimage-32bit_scaled.png
+ \o
+ \snippet doc/src/snippets/code/src_gui_image_qimage.cpp 0
+ \endtable
+
+ In case of a 8-bit and monchrome images, the pixel value is only
+ an index from the image's color table. So the setPixel() function
+ can only be used to alter the color of the pixel at the given
+ coordinates to a predefined color from the image's color table,
+ i.e. it can only change the pixel's index value. To alter or add a
+ color to an image's color table, use the setColor() function.
+
+ An entry in the color table is an ARGB quadruplet encoded as an
+ QRgb value. Use the qRgb() and qRgba() functions to make a
+ suitable QRgb value for use with the setColor() function. For
+ example:
+
+ \table
+ \header
+ \o {2,1} 8-bit
+ \row
+ \o \inlineimage qimage-8bit_scaled.png
+ \o
+ \snippet doc/src/snippets/code/src_gui_image_qimage.cpp 1
+ \endtable
+
+ QImage also provide the scanLine() function which returns a
+ pointer to the pixel data at the scanline with the given index,
+ and the bits() function which returns a pointer to the first pixel
+ data (this is equivalent to \c scanLine(0)).
+
+ \section1 Image Formats
+
+ Each pixel stored in a QImage is represented by an integer. The
+ size of the integer varies depending on the format. QImage
+ supports several image formats described by the \l Format
+ enum.
+
+ Monochrome images are stored using 1-bit indexes into a color table
+ with at most two colors. There are two different types of
+ monochrome images: big endian (MSB first) or little endian (LSB
+ first) bit order.
+
+ 8-bit images are stored using 8-bit indexes into a color table,
+ i.e. they have a single byte per pixel. The color table is a
+ QVector<QRgb>, and the QRgb typedef is equivalent to an unsigned
+ int containing an ARGB quadruplet on the format 0xAARRGGBB.
+
+ 32-bit images have no color table; instead, each pixel contains an
+ QRgb value. There are three different types of 32-bit images
+ storing RGB (i.e. 0xffRRGGBB), ARGB and premultiplied ARGB
+ values respectively. In the premultiplied format the red, green,
+ and blue channels are multiplied by the alpha component divided by
+ 255.
+
+ An image's format can be retrieved using the format()
+ function. Use the convertToFormat() functions to convert an image
+ into another format. The allGray() and isGrayscale() functions
+ tell whether a color image can safely be converted to a grayscale
+ image.
+
+ \section1 Image Transformations
+
+ QImage supports a number of functions for creating a new image
+ that is a transformed version of the original: The
+ createAlphaMask() function builds and returns a 1-bpp mask from
+ the alpha buffer in this image, and the createHeuristicMask()
+ function creates and returns a 1-bpp heuristic mask for this
+ image. The latter function works by selecting a color from one of
+ the corners, then chipping away pixels of that color starting at
+ all the edges.
+
+ The mirrored() function returns a mirror of the image in the
+ desired direction, the scaled() returns a copy of the image scaled
+ to a rectangle of the desired measures, and the rgbSwapped() function
+ constructs a BGR image from a RGB image.
+
+ The scaledToWidth() and scaledToHeight() functions return scaled
+ copies of the image.
+
+ The transformed() function returns a copy of the image that is
+ transformed with the given transformation matrix and
+ transformation mode: Internally, the transformation matrix is
+ adjusted to compensate for unwanted translation,
+ i.e. transformed() returns the smallest image containing all
+ transformed points of the original image. The static trueMatrix()
+ function returns the actual matrix used for transforming the
+ image.
+
+ There are also functions for changing attributes of an image
+ in-place:
+
+ \table
+ \header \o Function \o Description
+ \row
+ \o setDotsPerMeterX()
+ \o Defines the aspect ratio by setting the number of pixels that fit
+ horizontally in a physical meter.
+ \row
+ \o setDotsPerMeterY()
+ \o Defines the aspect ratio by setting the number of pixels that fit
+ vertically in a physical meter.
+ \row
+ \o fill()
+ \o Fills the entire image with the given pixel value.
+ \row
+ \o invertPixels()
+ \o Inverts all pixel values in the image using the given InvertMode value.
+ \row
+ \o setColorTable()
+ \o Sets the color table used to translate color indexes. Only
+ monochrome and 8-bit formats.
+ \row
+ \o setColorCount()
+ \o Resizes the color table. Only monochrome and 8-bit formats.
+
+ \endtable
+
+ \section1 Legal Information
+
+ For smooth scaling, the transformed() functions use code based on
+ smooth scaling algorithm by Daniel M. Duley.
+
+ \legalese
+ Copyright (C) 2004, 2005 Daniel M. Duley
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ \endlegalese
+
+ \sa QImageReader, QImageWriter, QPixmap, QSvgRenderer, {Image Composition Example},
+ {Image Viewer Example}, {Scribble Example}, {Pixelator Example}
+*/
+
+/*!
+ \enum QImage::Endian
+ \compat
+
+ This enum type is used to describe the endianness of the CPU and
+ graphics hardware. It is provided here for compatibility with earlier versions of Qt.
+
+ Use the \l Format enum instead. The \l Format enum specify the
+ endianess for monchrome formats, but for other formats the
+ endianess is not relevant.
+
+ \value IgnoreEndian Endianness does not matter. Useful for some
+ operations that are independent of endianness.
+ \value BigEndian Most significant bit first or network byte order, as on SPARC, PowerPC, and Motorola CPUs.
+ \value LittleEndian Least significant bit first or little endian byte order, as on Intel x86.
+*/
+
+/*!
+ \enum QImage::InvertMode
+
+ This enum type is used to describe how pixel values should be
+ inverted in the invertPixels() function.
+
+ \value InvertRgb Invert only the RGB values and leave the alpha
+ channel unchanged.
+
+ \value InvertRgba Invert all channels, including the alpha channel.
+
+ \sa invertPixels()
+*/
+
+/*!
+ \enum QImage::Format
+
+ The following image formats are available in Qt. Values greater
+ than QImage::Format_RGB16 were added in Qt 4.4. See the notes
+ after the table.
+
+ \value Format_Invalid The image is invalid.
+ \value Format_Mono The image is stored using 1-bit per pixel. Bytes are
+ packed with the most significant bit (MSB) first.
+ \value Format_MonoLSB The image is stored using 1-bit per pixel. Bytes are
+ packed with the less significant bit (LSB) first.
+
+ \value Format_Indexed8 The image is stored using 8-bit indexes
+ into a colormap.
+
+ \value Format_RGB32 The image is stored using a 32-bit RGB format (0xffRRGGBB).
+
+ \value Format_ARGB32 The image is stored using a 32-bit ARGB
+ format (0xAARRGGBB).
+
+ \value Format_ARGB32_Premultiplied The image is stored using a premultiplied 32-bit
+ ARGB format (0xAARRGGBB), i.e. the red,
+ green, and blue channels are multiplied
+ by the alpha component divided by 255. (If RR, GG, or BB
+ has a higher value than the alpha channel, the results are
+ undefined.) Certain operations (such as image composition
+ using alpha blending) are faster using premultiplied ARGB32
+ than with plain ARGB32.
+
+ \value Format_RGB16 The image is stored using a 16-bit RGB format (5-6-5).
+
+ \value Format_ARGB8565_Premultiplied The image is stored using a
+ premultiplied 24-bit ARGB format (8-5-6-5).
+ \value Format_RGB666 The image is stored using a 24-bit RGB format (6-6-6).
+ The unused most significant bits is always zero.
+ \value Format_ARGB6666_Premultiplied The image is stored using a
+ premultiplied 24-bit ARGB format (6-6-6-6).
+ \value Format_RGB555 The image is stored using a 16-bit RGB format (5-5-5).
+ The unused most significant bit is always zero.
+ \value Format_ARGB8555_Premultiplied The image is stored using a
+ premultiplied 24-bit ARGB format (8-5-5-5).
+ \value Format_RGB888 The image is stored using a 24-bit RGB format (8-8-8).
+ \value Format_RGB444 The image is stored using a 16-bit RGB format (4-4-4).
+ The unused bits are always zero.
+ \value Format_ARGB4444_Premultiplied The image is stored using a
+ premultiplied 16-bit ARGB format (4-4-4-4).
+
+ \note Drawing into a QImage with QImage::Format_Indexed8 is not
+ supported.
+
+ \note Do not render into ARGB32 images using QPainter. Using
+ QImage::Format_ARGB32_Premultiplied is significantly faster.
+
+ \sa format(), convertToFormat()
+*/
+
+/*****************************************************************************
+ QImage member functions
+ *****************************************************************************/
+
+// table to flip bits
+static const uchar bitflip[256] = {
+ /*
+ open OUT, "| fmt";
+ for $i (0..255) {
+ print OUT (($i >> 7) & 0x01) | (($i >> 5) & 0x02) |
+ (($i >> 3) & 0x04) | (($i >> 1) & 0x08) |
+ (($i << 7) & 0x80) | (($i << 5) & 0x40) |
+ (($i << 3) & 0x20) | (($i << 1) & 0x10), ", ";
+ }
+ close OUT;
+ */
+ 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
+ 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
+ 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
+ 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
+ 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
+ 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
+ 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
+ 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
+ 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
+ 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
+ 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
+ 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
+ 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
+ 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
+ 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
+ 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255
+};
+
+const uchar *qt_get_bitflip_array() // called from QPixmap code
+{
+ return bitflip;
+}
+
+#if defined(QT3_SUPPORT)
+static QImage::Format formatFor(int depth, QImage::Endian bitOrder)
+{
+ QImage::Format format;
+ if (depth == 1) {
+ format = bitOrder == QImage::BigEndian ? QImage::Format_Mono : QImage::Format_MonoLSB;
+ } else if (depth == 8) {
+ format = QImage::Format_Indexed8;
+ } else if (depth == 32) {
+ format = QImage::Format_RGB32;
+ } else if (depth == 24) {
+ format = QImage::Format_RGB888;
+ } else if (depth == 16) {
+ format = QImage::Format_RGB16;
+ } else {
+ qWarning("QImage: Depth %d not supported", depth);
+ format = QImage::Format_Invalid;
+ }
+ return format;
+}
+#endif
+
+/*!
+ Constructs a null image.
+
+ \sa isNull()
+*/
+
+QImage::QImage()
+ : QPaintDevice()
+{
+ d = 0;
+}
+
+/*!
+ Constructs an image with the given \a width, \a height and \a
+ format.
+
+ A \l{isNull()}{null} image will be returned if memory cannot be allocated.
+
+ \warning This will create a QImage with uninitialized data. Call
+ fill() to fill the image with an appropriate pixel value before
+ drawing onto it with QPainter.
+*/
+QImage::QImage(int width, int height, Format format)
+ : QPaintDevice()
+{
+ d = QImageData::create(QSize(width, height), format, 0);
+}
+
+/*!
+ Constructs an image with the given \a size and \a format.
+
+ A \l{isNull()}{null} image is returned if memory cannot be allocated.
+
+ \warning This will create a QImage with uninitialized data. Call
+ fill() to fill the image with an appropriate pixel value before
+ drawing onto it with QPainter.
+*/
+QImage::QImage(const QSize &size, Format format)
+ : QPaintDevice()
+{
+ d = QImageData::create(size, format, 0);
+}
+
+
+
+QImageData *QImageData::create(uchar *data, int width, int height, int bpl, QImage::Format format, bool readOnly)
+{
+ QImageData *d = 0;
+
+ if (format == QImage::Format_Invalid)
+ return d;
+
+ if (!checkPixelSize(format)) {
+ qWarning("QImageData::create(): Invalid pixel size for format %i",
+ format);
+ return 0;
+ }
+
+ const int depth = qt_depthForFormat(format);
+ const int calc_bytes_per_line = ((width * depth + 31)/32) * 4;
+ const int min_bytes_per_line = (width * depth + 7)/8;
+
+ if (bpl <= 0)
+ bpl = calc_bytes_per_line;
+
+ if (width <= 0 || height <= 0 || !data
+ || INT_MAX/sizeof(uchar *) < uint(height)
+ || INT_MAX/uint(depth) < uint(width)
+ || bpl <= 0
+ || height <= 0
+ || bpl < min_bytes_per_line
+ || INT_MAX/uint(bpl) < uint(height))
+ return d; // invalid parameter(s)
+
+ d = new QImageData;
+ d->ref.ref();
+
+ d->own_data = false;
+ d->ro_data = readOnly;
+ d->data = data;
+ d->width = width;
+ d->height = height;
+ d->depth = depth;
+ d->format = format;
+
+ d->bytes_per_line = bpl;
+ d->nbytes = d->bytes_per_line * height;
+
+ return d;
+}
+
+/*!
+ Constructs an image with the given \a width, \a height and \a
+ format, that uses an existing memory buffer, \a data. The \a width
+ and \a height must be specified in pixels, \a data must be 32-bit aligned,
+ and each scanline of data in the image must also be 32-bit aligned.
+
+ The buffer must remain valid throughout the life of the
+ QImage. The image does not delete the buffer at destruction.
+
+ If \a format is an indexed color format, the image color table is
+ initially empty and must be sufficiently expanded with
+ setColorCount() or setColorTable() before the image is used.
+*/
+QImage::QImage(uchar* data, int width, int height, Format format)
+ : QPaintDevice()
+{
+ d = QImageData::create(data, width, height, 0, format, false);
+}
+
+/*!
+ Constructs an image with the given \a width, \a height and \a
+ format, that uses an existing read-only memory buffer, \a
+ data. The \a width and \a height must be specified in pixels, \a
+ data must be 32-bit aligned, and each scanline of data in the
+ image must also be 32-bit aligned.
+
+ The buffer must remain valid throughout the life of the QImage and
+ all copies that have not been modified or otherwise detached from
+ the original buffer. The image does not delete the buffer at
+ destruction.
+
+ If \a format is an indexed color format, the image color table is
+ initially empty and must be sufficiently expanded with
+ setColorCount() or setColorTable() before the image is used.
+
+ Unlike the similar QImage constructor that takes a non-const data buffer,
+ this version will never alter the contents of the buffer. For example,
+ calling QImage::bits() will return a deep copy of the image, rather than
+ the buffer passed to the constructor. This allows for the efficiency of
+ constructing a QImage from raw data, without the possibility of the raw
+ data being changed.
+*/
+QImage::QImage(const uchar* data, int width, int height, Format format)
+ : QPaintDevice()
+{
+ d = QImageData::create(const_cast<uchar*>(data), width, height, 0, format, true);
+}
+
+/*!
+ Constructs an image with the given \a width, \a height and \a
+ format, that uses an existing memory buffer, \a data. The \a width
+ and \a height must be specified in pixels. \a bytesPerLine
+ specifies the number of bytes per line (stride).
+
+ The buffer must remain valid throughout the life of the
+ QImage. The image does not delete the buffer at destruction.
+
+ If \a format is an indexed color format, the image color table is
+ initially empty and must be sufficiently expanded with
+ setColorCount() or setColorTable() before the image is used.
+*/
+QImage::QImage(uchar *data, int width, int height, int bytesPerLine, Format format)
+ :QPaintDevice()
+{
+ d = QImageData::create(data, width, height, bytesPerLine, format, false);
+}
+
+
+/*!
+ Constructs an image with the given \a width, \a height and \a
+ format, that uses an existing memory buffer, \a data. The \a width
+ and \a height must be specified in pixels. \a bytesPerLine
+ specifies the number of bytes per line (stride).
+
+ The buffer must remain valid throughout the life of the
+ QImage. The image does not delete the buffer at destruction.
+
+ If \a format is an indexed color format, the image color table is
+ initially empty and must be sufficiently expanded with
+ setColorCount() or setColorTable() before the image is used.
+
+ Unlike the similar QImage constructor that takes a non-const data buffer,
+ this version will never alter the contents of the buffer. For example,
+ calling QImage::bits() will return a deep copy of the image, rather than
+ the buffer passed to the constructor. This allows for the efficiency of
+ constructing a QImage from raw data, without the possibility of the raw
+ data being changed.
+*/
+
+QImage::QImage(const uchar *data, int width, int height, int bytesPerLine, Format format)
+ :QPaintDevice()
+{
+ d = QImageData::create(const_cast<uchar*>(data), width, height, bytesPerLine, format, true);
+}
+
+/*!
+ Constructs an image and tries to load the image from the file with
+ the given \a fileName.
+
+ The loader attempts to read the image using the specified \a
+ format. If the \a format is not specified (which is the default),
+ the loader probes the file for a header to guess the file format.
+
+ If the loading of the image failed, this object is a null image.
+
+ The file name can either refer to an actual file on disk or to one
+ of the application's embedded resources. See the
+ \l{resources.html}{Resource System} overview for details on how to
+ embed images and other resource files in the application's
+ executable.
+
+ \sa isNull(), {QImage#Reading and Writing Image Files}{Reading and Writing Image Files}
+*/
+
+QImage::QImage(const QString &fileName, const char *format)
+ : QPaintDevice()
+{
+ d = 0;
+ load(fileName, format);
+}
+
+/*!
+ Constructs an image and tries to load the image from the file with
+ the given \a fileName.
+
+ The loader attempts to read the image using the specified \a
+ format. If the \a format is not specified (which is the default),
+ the loader probes the file for a header to guess the file format.
+
+ If the loading of the image failed, this object is a null image.
+
+ The file name can either refer to an actual file on disk or to one
+ of the application's embedded resources. See the
+ \l{resources.html}{Resource System} overview for details on how to
+ embed images and other resource files in the application's
+ executable.
+
+ You can disable this constructor by defining \c
+ QT_NO_CAST_FROM_ASCII when you compile your applications. This can
+ be useful, for example, if you want to ensure that all
+ user-visible strings go through QObject::tr().
+
+ \sa QString::fromAscii(), isNull(), {QImage#Reading and Writing
+ Image Files}{Reading and Writing Image Files}
+*/
+#ifndef QT_NO_CAST_FROM_ASCII
+QImage::QImage(const char *fileName, const char *format)
+ : QPaintDevice()
+{
+ // ### Qt 5: if you remove the QImage(const QByteArray &) QT3_SUPPORT
+ // constructor, remove this constructor as well. The constructor here
+ // exists so that QImage("foo.png") compiles without ambiguity.
+ d = 0;
+ load(QString::fromAscii(fileName), format);
+}
+#endif
+
+#ifndef QT_NO_IMAGEFORMAT_XPM
+extern bool qt_read_xpm_image_or_array(QIODevice *device, const char * const *source, QImage &image);
+
+/*!
+ Constructs an image from the given \a xpm image.
+
+ Make sure that the image is a valid XPM image. Errors are silently
+ ignored.
+
+ Note that it's possible to squeeze the XPM variable a little bit
+ by using an unusual declaration:
+
+ \snippet doc/src/snippets/code/src_gui_image_qimage.cpp 2
+
+ The extra \c const makes the entire definition read-only, which is
+ slightly more efficient (e.g., when the code is in a shared
+ library) and able to be stored in ROM with the application.
+*/
+
+QImage::QImage(const char * const xpm[])
+ : QPaintDevice()
+{
+ d = 0;
+ if (!xpm)
+ return;
+ if (!qt_read_xpm_image_or_array(0, xpm, *this))
+ // Issue: Warning because the constructor may be ambigious
+ qWarning("QImage::QImage(), XPM is not supported");
+}
+#endif // QT_NO_IMAGEFORMAT_XPM
+
+/*!
+ \fn QImage::QImage(const QByteArray &data)
+
+ Use the static fromData() function instead.
+
+ \oldcode
+ QByteArray data;
+ ...
+ QImage image(data);
+ \newcode
+ QByteArray data;
+ ...
+ QImage image = QImage::fromData(data);
+ \endcode
+*/
+
+
+/*!
+ Constructs a shallow copy of the given \a image.
+
+ For more information about shallow copies, see the \l {Implicit
+ Data Sharing} documentation.
+
+ \sa copy()
+*/
+
+QImage::QImage(const QImage &image)
+ : QPaintDevice()
+{
+ if (image.paintingActive()) {
+ d = 0;
+ operator=(image.copy());
+ } else {
+ d = image.d;
+ if (d)
+ d->ref.ref();
+ }
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ \fn QImage::QImage(int width, int height, int depth, int numColors, Endian bitOrder)
+
+ Constructs an image with the given \a width, \a height, \a depth,
+ \a numColors colors and \a bitOrder.
+
+ Use the constructor that accepts a width, a height and a format
+ (i.e. specifying the depth and bit order), in combination with the
+ setColorCount() function, instead.
+
+ \oldcode
+ QImage image(width, height, depth, numColors);
+ \newcode
+ QImage image(width, height, format);
+
+ // For 8 bit images the default number of colors is 256. If
+ // another number of colors is required it can be specified
+ // using the setColorCount() function.
+ image.setColorCount(numColors);
+ \endcode
+*/
+
+QImage::QImage(int w, int h, int depth, int colorCount, Endian bitOrder)
+ : QPaintDevice()
+{
+ d = QImageData::create(QSize(w, h), formatFor(depth, bitOrder), colorCount);
+}
+
+/*!
+ Constructs an image with the given \a size, \a depth, \a numColors
+ and \a bitOrder.
+
+ Use the constructor that accepts a size and a format
+ (i.e. specifying the depth and bit order), in combination with the
+ setColorCount() function, instead.
+
+ \oldcode
+ QSize mySize(width, height);
+ QImage image(mySize, depth, numColors);
+ \newcode
+ QSize mySize(width, height);
+ QImage image(mySize, format);
+
+ // For 8 bit images the default number of colors is 256. If
+ // another number of colors is required it can be specified
+ // using the setColorCount() function.
+ image.setColorCount(numColors);
+ \endcode
+*/
+QImage::QImage(const QSize& size, int depth, int numColors, Endian bitOrder)
+ : QPaintDevice()
+{
+ d = QImageData::create(size, formatFor(depth, bitOrder), numColors);
+}
+
+/*!
+ \fn QImage::QImage(uchar* data, int width, int height, int depth, const QRgb* colortable, int numColors, Endian bitOrder)
+
+ Constructs an image with the given \a width, \a height, depth, \a
+ colortable, \a numColors and \a bitOrder, that uses an existing
+ memory buffer, \a data.
+
+ Use the constructor that accepts a uchar pointer, a width, a
+ height and a format (i.e. specifying the depth and bit order), in
+ combination with the setColorTable() function, instead.
+
+ \oldcode
+ uchar *myData;
+ QRgb *myColorTable;
+
+ QImage image(myData, width, height, depth,
+ myColorTable, numColors, IgnoreEndian);
+ \newcode
+ uchar *myData;
+ QVector<QRgb> myColorTable;
+
+ QImage image(myData, width, height, format);
+ image.setColorTable(myColorTable);
+ \endcode
+*/
+QImage::QImage(uchar* data, int w, int h, int depth, const QRgb* colortable, int numColors, Endian bitOrder)
+ : QPaintDevice()
+{
+ d = 0;
+ Format f = formatFor(depth, bitOrder);
+ if (f == Format_Invalid)
+ return;
+
+ const int bytes_per_line = ((w*depth+31)/32)*4; // bytes per scanline
+ if (w <= 0 || h <= 0 || numColors < 0 || !data
+ || INT_MAX/sizeof(uchar *) < uint(h)
+ || INT_MAX/uint(depth) < uint(w)
+ || bytes_per_line <= 0
+ || INT_MAX/uint(bytes_per_line) < uint(h))
+ return; // invalid parameter(s)
+ d = new QImageData;
+ d->ref.ref();
+
+ d->own_data = false;
+ d->data = data;
+ d->width = w;
+ d->height = h;
+ d->depth = depth;
+ d->format = f;
+ if (depth == 32)
+ numColors = 0;
+
+ d->bytes_per_line = bytes_per_line;
+ d->nbytes = d->bytes_per_line * h;
+ if (colortable) {
+ d->colortable.resize(numColors);
+ for (int i = 0; i < numColors; ++i)
+ d->colortable[i] = colortable[i];
+ } else if (numColors) {
+ setColorCount(numColors);
+ }
+}
+
+#ifdef Q_WS_QWS
+
+/*!
+ \fn QImage::QImage(uchar* data, int width, int height, int depth, int bytesPerLine, const QRgb* colortable, int numColors, Endian bitOrder)
+
+ Constructs an image with the given \a width, \a height, \a depth,
+ \a bytesPerLine, \a colortable, \a numColors and \a bitOrder, that
+ uses an existing memory buffer, \a data. The image does not delete
+ the buffer at destruction.
+
+ \warning This constructor is only available in Qt for Embedded Linux.
+
+ The data has to be 32-bit aligned, and each scanline of data in the image
+ must also be 32-bit aligned, so it's no longer possible to specify a custom
+ \a bytesPerLine value.
+*/
+QImage::QImage(uchar* data, int w, int h, int depth, int bpl, const QRgb* colortable, int numColors, Endian bitOrder)
+ : QPaintDevice()
+{
+ d = 0;
+ Format f = formatFor(depth, bitOrder);
+ if (f == Format_Invalid)
+ return;
+ if (!data || w <= 0 || h <= 0 || depth <= 0 || numColors < 0
+ || INT_MAX/sizeof(uchar *) < uint(h)
+ || INT_MAX/uint(depth) < uint(w)
+ || bpl <= 0
+ || INT_MAX/uint(bpl) < uint(h))
+ return; // invalid parameter(s)
+
+ d = new QImageData;
+ d->ref.ref();
+ d->own_data = false;
+ d->data = data;
+ d->width = w;
+ d->height = h;
+ d->depth = depth;
+ d->format = f;
+ if (depth == 32)
+ numColors = 0;
+ d->bytes_per_line = bpl;
+ d->nbytes = d->bytes_per_line * h;
+ if (colortable) {
+ d->colortable.resize(numColors);
+ for (int i = 0; i < numColors; ++i)
+ d->colortable[i] = colortable[i];
+ } else if (numColors) {
+ setColorCount(numColors);
+ }
+}
+#endif // Q_WS_QWS
+#endif // QT3_SUPPORT
+
+/*!
+ Destroys the image and cleans up.
+*/
+
+QImage::~QImage()
+{
+ if (d && !d->ref.deref())
+ delete d;
+}
+
+/*!
+ Assigns a shallow copy of the given \a image to this image and
+ returns a reference to this image.
+
+ For more information about shallow copies, see the \l {Implicit
+ Data Sharing} documentation.
+
+ \sa copy(), QImage()
+*/
+
+QImage &QImage::operator=(const QImage &image)
+{
+ if (image.paintingActive()) {
+ operator=(image.copy());
+ } else {
+ if (image.d)
+ image.d->ref.ref();
+ if (d && !d->ref.deref())
+ delete d;
+ d = image.d;
+ }
+ return *this;
+}
+
+/*!
+ \fn void QImage::swap(QImage &other)
+ \since 4.8
+
+ Swaps image \a other with this image. This operation is very
+ fast and never fails.
+*/
+
+/*!
+ \internal
+*/
+int QImage::devType() const
+{
+ return QInternal::Image;
+}
+
+/*!
+ Returns the image as a QVariant.
+*/
+QImage::operator QVariant() const
+{
+ return QVariant(QVariant::Image, this);
+}
+
+/*!
+ \internal
+
+ If multiple images share common data, this image makes a copy of
+ the data and detaches itself from the sharing mechanism, making
+ sure that this image is the only one referring to the data.
+
+ Nothing is done if there is just a single reference.
+
+ \sa copy(), isDetached(), {Implicit Data Sharing}
+*/
+void QImage::detach()
+{
+ if (d) {
+ if (d->is_cached && d->ref == 1)
+ QImagePixmapCleanupHooks::executeImageHooks(cacheKey());
+
+ if (d->ref != 1 || d->ro_data)
+ *this = copy();
+
+ if (d)
+ ++d->detach_no;
+ }
+}
+
+
+/*!
+ \fn QImage QImage::copy(int x, int y, int width, int height) const
+ \overload
+
+ The returned image is copied from the position (\a x, \a y) in
+ this image, and will always have the given \a width and \a height.
+ In areas beyond this image, pixels are set to 0.
+
+*/
+
+/*!
+ \fn QImage QImage::copy(const QRect& rectangle) const
+
+ Returns a sub-area of the image as a new image.
+
+ The returned image is copied from the position (\a
+ {rectangle}.x(), \a{rectangle}.y()) in this image, and will always
+ have the size of the given \a rectangle.
+
+ In areas beyond this image, pixels are set to 0. For 32-bit RGB
+ images, this means black; for 32-bit ARGB images, this means
+ transparent black; for 8-bit images, this means the color with
+ index 0 in the color table which can be anything; for 1-bit
+ images, this means Qt::color0.
+
+ If the given \a rectangle is a null rectangle the entire image is
+ copied.
+
+ \sa QImage()
+*/
+QImage QImage::copy(const QRect& r) const
+{
+ if (!d)
+ return QImage();
+
+ if (r.isNull()) {
+ QImage image(d->width, d->height, d->format);
+ if (image.isNull())
+ return image;
+
+ // Qt for Embedded Linux can create images with non-default bpl
+ // make sure we don't crash.
+ if (image.d->nbytes != d->nbytes) {
+ int bpl = image.bytesPerLine();
+ for (int i = 0; i < height(); i++)
+ memcpy(image.scanLine(i), scanLine(i), bpl);
+ } else
+ memcpy(image.bits(), bits(), d->nbytes);
+ image.d->colortable = d->colortable;
+ image.d->dpmx = d->dpmx;
+ image.d->dpmy = d->dpmy;
+ image.d->offset = d->offset;
+ image.d->has_alpha_clut = d->has_alpha_clut;
+#ifndef QT_NO_IMAGE_TEXT
+ image.d->text = d->text;
+#endif
+ return image;
+ }
+
+ int x = r.x();
+ int y = r.y();
+ int w = r.width();
+ int h = r.height();
+
+ int dx = 0;
+ int dy = 0;
+ if (w <= 0 || h <= 0)
+ return QImage();
+
+ QImage image(w, h, d->format);
+ if (image.isNull())
+ return image;
+
+ if (x < 0 || y < 0 || x + w > d->width || y + h > d->height) {
+ // bitBlt will not cover entire image - clear it.
+ image.fill(0);
+ if (x < 0) {
+ dx = -x;
+ x = 0;
+ }
+ if (y < 0) {
+ dy = -y;
+ y = 0;
+ }
+ }
+
+ image.d->colortable = d->colortable;
+
+ int pixels_to_copy = qMax(w - dx, 0);
+ if (x > d->width)
+ pixels_to_copy = 0;
+ else if (pixels_to_copy > d->width - x)
+ pixels_to_copy = d->width - x;
+ int lines_to_copy = qMax(h - dy, 0);
+ if (y > d->height)
+ lines_to_copy = 0;
+ else if (lines_to_copy > d->height - y)
+ lines_to_copy = d->height - y;
+
+ bool byteAligned = true;
+ if (d->format == Format_Mono || d->format == Format_MonoLSB)
+ byteAligned = !(dx & 7) && !(x & 7) && !(pixels_to_copy & 7);
+
+ if (byteAligned) {
+ const uchar *src = d->data + ((x * d->depth) >> 3) + y * d->bytes_per_line;
+ uchar *dest = image.d->data + ((dx * d->depth) >> 3) + dy * image.d->bytes_per_line;
+ const int bytes_to_copy = (pixels_to_copy * d->depth) >> 3;
+ for (int i = 0; i < lines_to_copy; ++i) {
+ memcpy(dest, src, bytes_to_copy);
+ src += d->bytes_per_line;
+ dest += image.d->bytes_per_line;
+ }
+ } else if (d->format == Format_Mono) {
+ const uchar *src = d->data + y * d->bytes_per_line;
+ uchar *dest = image.d->data + dy * image.d->bytes_per_line;
+ for (int i = 0; i < lines_to_copy; ++i) {
+ for (int j = 0; j < pixels_to_copy; ++j) {
+ if (src[(x + j) >> 3] & (0x80 >> ((x + j) & 7)))
+ dest[(dx + j) >> 3] |= (0x80 >> ((dx + j) & 7));
+ else
+ dest[(dx + j) >> 3] &= ~(0x80 >> ((dx + j) & 7));
+ }
+ src += d->bytes_per_line;
+ dest += image.d->bytes_per_line;
+ }
+ } else { // Format_MonoLSB
+ Q_ASSERT(d->format == Format_MonoLSB);
+ const uchar *src = d->data + y * d->bytes_per_line;
+ uchar *dest = image.d->data + dy * image.d->bytes_per_line;
+ for (int i = 0; i < lines_to_copy; ++i) {
+ for (int j = 0; j < pixels_to_copy; ++j) {
+ if (src[(x + j) >> 3] & (0x1 << ((x + j) & 7)))
+ dest[(dx + j) >> 3] |= (0x1 << ((dx + j) & 7));
+ else
+ dest[(dx + j) >> 3] &= ~(0x1 << ((dx + j) & 7));
+ }
+ src += d->bytes_per_line;
+ dest += image.d->bytes_per_line;
+ }
+ }
+
+ image.d->dpmx = dotsPerMeterX();
+ image.d->dpmy = dotsPerMeterY();
+ image.d->offset = offset();
+ image.d->has_alpha_clut = d->has_alpha_clut;
+#ifndef QT_NO_IMAGE_TEXT
+ image.d->text = d->text;
+#endif
+ return image;
+}
+
+
+/*!
+ \fn bool QImage::isNull() const
+
+ Returns true if it is a null image, otherwise returns false.
+
+ A null image has all parameters set to zero and no allocated data.
+*/
+bool QImage::isNull() const
+{
+ return !d;
+}
+
+/*!
+ \fn int QImage::width() const
+
+ Returns the width of the image.
+
+ \sa {QImage#Image Information}{Image Information}
+*/
+int QImage::width() const
+{
+ return d ? d->width : 0;
+}
+
+/*!
+ \fn int QImage::height() const
+
+ Returns the height of the image.
+
+ \sa {QImage#Image Information}{Image Information}
+*/
+int QImage::height() const
+{
+ return d ? d->height : 0;
+}
+
+/*!
+ \fn QSize QImage::size() const
+
+ Returns the size of the image, i.e. its width() and height().
+
+ \sa {QImage#Image Information}{Image Information}
+*/
+QSize QImage::size() const
+{
+ return d ? QSize(d->width, d->height) : QSize(0, 0);
+}
+
+/*!
+ \fn QRect QImage::rect() const
+
+ Returns the enclosing rectangle (0, 0, width(), height()) of the
+ image.
+
+ \sa {QImage#Image Information}{Image Information}
+*/
+QRect QImage::rect() const
+{
+ return d ? QRect(0, 0, d->width, d->height) : QRect();
+}
+
+/*!
+ Returns the depth of the image.
+
+ The image depth is the number of bits used to store a single
+ pixel, also called bits per pixel (bpp).
+
+ The supported depths are 1, 8, 16, 24 and 32.
+
+ \sa bitPlaneCount(), convertToFormat(), {QImage#Image Formats}{Image Formats},
+ {QImage#Image Information}{Image Information}
+
+*/
+int QImage::depth() const
+{
+ return d ? d->depth : 0;
+}
+
+/*!
+ \obsolete
+ \fn int QImage::numColors() const
+
+ Returns the size of the color table for the image.
+
+ \sa setColorCount()
+*/
+int QImage::numColors() const
+{
+ return d ? d->colortable.size() : 0;
+}
+
+/*!
+ \since 4.6
+ \fn int QImage::colorCount() const
+
+ Returns the size of the color table for the image.
+
+ Notice that colorCount() returns 0 for 32-bpp images because these
+ images do not use color tables, but instead encode pixel values as
+ ARGB quadruplets.
+
+ \sa setColorCount(), {QImage#Image Information}{Image Information}
+*/
+int QImage::colorCount() const
+{
+ return d ? d->colortable.size() : 0;
+}
+
+
+#ifdef QT3_SUPPORT
+/*!
+ \fn QImage::Endian QImage::bitOrder() const
+
+ Returns the bit order for the image. If it is a 1-bpp image, this
+ function returns either QImage::BigEndian or
+ QImage::LittleEndian. Otherwise, this function returns
+ QImage::IgnoreEndian.
+
+ Use the format() function instead for the monochrome formats. For
+ non-monochrome formats the bit order is irrelevant.
+*/
+
+/*!
+ Returns a pointer to the scanline pointer table. This is the
+ beginning of the data block for the image.
+ Returns 0 in case of an error.
+
+ Use the bits() or scanLine() function instead.
+*/
+uchar **QImage::jumpTable()
+{
+ if (!d)
+ return 0;
+ detach();
+
+ // in case detach() ran out of memory..
+ if (!d)
+ return 0;
+
+ if (!d->jumptable) {
+ d->jumptable = (uchar **)malloc(d->height*sizeof(uchar *));
+ if (!d->jumptable)
+ return 0;
+ uchar *data = d->data;
+ int height = d->height;
+ uchar **p = d->jumptable;
+ while (height--) {
+ *p++ = data;
+ data += d->bytes_per_line;
+ }
+ }
+ return d->jumptable;
+}
+
+/*!
+ \overload
+*/
+const uchar * const *QImage::jumpTable() const
+{
+ if (!d)
+ return 0;
+ if (!d->jumptable) {
+ d->jumptable = (uchar **)malloc(d->height*sizeof(uchar *));
+ if (!d->jumptable)
+ return 0;
+ uchar *data = d->data;
+ int height = d->height;
+ uchar **p = d->jumptable;
+ while (height--) {
+ *p++ = data;
+ data += d->bytes_per_line;
+ }
+ }
+ return d->jumptable;
+}
+#endif
+
+/*!
+ Sets the color table used to translate color indexes to QRgb
+ values, to the specified \a colors.
+
+ When the image is used, the color table must be large enough to
+ have entries for all the pixel/index values present in the image,
+ otherwise the results are undefined.
+
+ \sa colorTable(), setColor(), {QImage#Image Transformations}{Image
+ Transformations}
+*/
+void QImage::setColorTable(const QVector<QRgb> colors)
+{
+ if (!d)
+ return;
+ detach();
+
+ // In case detach() ran out of memory
+ if (!d)
+ return;
+
+ d->colortable = colors;
+ d->has_alpha_clut = false;
+ for (int i = 0; i < d->colortable.size(); ++i) {
+ if (qAlpha(d->colortable.at(i)) != 255) {
+ d->has_alpha_clut = true;
+ break;
+ }
+ }
+}
+
+/*!
+ Returns a list of the colors contained in the image's color table,
+ or an empty list if the image does not have a color table
+
+ \sa setColorTable(), colorCount(), color()
+*/
+QVector<QRgb> QImage::colorTable() const
+{
+ return d ? d->colortable : QVector<QRgb>();
+}
+
+
+/*!
+ \obsolete
+ Returns the number of bytes occupied by the image data.
+
+ \sa byteCount()
+*/
+int QImage::numBytes() const
+{
+ return d ? d->nbytes : 0;
+}
+
+/*!
+ \since 4.6
+ Returns the number of bytes occupied by the image data.
+
+ \sa bytesPerLine(), bits(), {QImage#Image Information}{Image
+ Information}
+*/
+int QImage::byteCount() const
+{
+ return d ? d->nbytes : 0;
+}
+
+/*!
+ Returns the number of bytes per image scanline.
+
+ This is equivalent to byteCount() / height().
+
+ \sa scanLine()
+*/
+int QImage::bytesPerLine() const
+{
+ return (d && d->height) ? d->nbytes / d->height : 0;
+}
+
+
+/*!
+ Returns the color in the color table at index \a i. The first
+ color is at index 0.
+
+ The colors in an image's color table are specified as ARGB
+ quadruplets (QRgb). Use the qAlpha(), qRed(), qGreen(), and
+ qBlue() functions to get the color value components.
+
+ \sa setColor(), pixelIndex(), {QImage#Pixel Manipulation}{Pixel
+ Manipulation}
+*/
+QRgb QImage::color(int i) const
+{
+ Q_ASSERT(i < colorCount());
+ return d ? d->colortable.at(i) : QRgb(uint(-1));
+}
+
+/*!
+ \fn void QImage::setColor(int index, QRgb colorValue)
+
+ Sets the color at the given \a index in the color table, to the
+ given to \a colorValue. The color value is an ARGB quadruplet.
+
+ If \a index is outside the current size of the color table, it is
+ expanded with setColorCount().
+
+ \sa color(), colorCount(), setColorTable(), {QImage#Pixel Manipulation}{Pixel
+ Manipulation}
+*/
+void QImage::setColor(int i, QRgb c)
+{
+ if (!d)
+ return;
+ if (i < 0 || d->depth > 8 || i >= 1<<d->depth) {
+ qWarning("QImage::setColor: Index out of bound %d", i);
+ return;
+ }
+ detach();
+
+ // In case detach() run out of memory
+ if (!d)
+ return;
+
+ if (i >= d->colortable.size())
+ setColorCount(i+1);
+ d->colortable[i] = c;
+ d->has_alpha_clut |= (qAlpha(c) != 255);
+}
+
+/*!
+ Returns a pointer to the pixel data at the scanline with index \a
+ i. The first scanline is at index 0.
+
+ The scanline data is aligned on a 32-bit boundary.
+
+ \warning If you are accessing 32-bpp image data, cast the returned
+ pointer to \c{QRgb*} (QRgb has a 32-bit size) and use it to
+ read/write the pixel value. You cannot use the \c{uchar*} pointer
+ directly, because the pixel format depends on the byte order on
+ the underlying platform. Use qRed(), qGreen(), qBlue(), and
+ qAlpha() to access the pixels.
+
+ \sa bytesPerLine(), bits(), {QImage#Pixel Manipulation}{Pixel
+ Manipulation}, constScanLine()
+*/
+uchar *QImage::scanLine(int i)
+{
+ if (!d)
+ return 0;
+
+ detach();
+
+ // In case detach() ran out of memory
+ if (!d)
+ return 0;
+
+ return d->data + i * d->bytes_per_line;
+}
+
+/*!
+ \overload
+*/
+const uchar *QImage::scanLine(int i) const
+{
+ if (!d)
+ return 0;
+
+ Q_ASSERT(i >= 0 && i < height());
+ return d->data + i * d->bytes_per_line;
+}
+
+
+/*!
+ Returns a pointer to the pixel data at the scanline with index \a
+ i. The first scanline is at index 0.
+
+ The scanline data is aligned on a 32-bit boundary.
+
+ Note that QImage uses \l{Implicit Data Sharing} {implicit data
+ sharing}, but this function does \e not perform a deep copy of the
+ shared pixel data, because the returned data is const.
+
+ \sa scanLine(), constBits()
+ \since 4.7
+*/
+const uchar *QImage::constScanLine(int i) const
+{
+ if (!d)
+ return 0;
+
+ Q_ASSERT(i >= 0 && i < height());
+ return d->data + i * d->bytes_per_line;
+}
+
+/*!
+ Returns a pointer to the first pixel data. This is equivalent to
+ scanLine(0).
+
+ Note that QImage uses \l{Implicit Data Sharing} {implicit data
+ sharing}. This function performs a deep copy of the shared pixel
+ data, thus ensuring that this QImage is the only one using the
+ current return value.
+
+ \sa scanLine(), byteCount(), constBits()
+*/
+uchar *QImage::bits()
+{
+ if (!d)
+ return 0;
+ detach();
+
+ // In case detach ran out of memory...
+ if (!d)
+ return 0;
+
+ return d->data;
+}
+
+/*!
+ \overload
+
+ Note that QImage uses \l{Implicit Data Sharing} {implicit data
+ sharing}, but this function does \e not perform a deep copy of the
+ shared pixel data, because the returned data is const.
+*/
+const uchar *QImage::bits() const
+{
+ return d ? d->data : 0;
+}
+
+
+/*!
+ Returns a pointer to the first pixel data.
+
+ Note that QImage uses \l{Implicit Data Sharing} {implicit data
+ sharing}, but this function does \e not perform a deep copy of the
+ shared pixel data, because the returned data is const.
+
+ \sa bits(), constScanLine()
+ \since 4.7
+*/
+const uchar *QImage::constBits() const
+{
+ return d ? d->data : 0;
+}
+
+/*!
+ \fn void QImage::reset()
+
+ Resets all image parameters and deallocates the image data.
+
+ Assign a null image instead.
+
+ \oldcode
+ QImage image;
+ image.reset();
+ \newcode
+ QImage image;
+ image = QImage();
+ \endcode
+*/
+
+/*!
+ \fn void QImage::fill(uint pixelValue)
+
+ Fills the entire image with the given \a pixelValue.
+
+ If the depth of this image is 1, only the lowest bit is used. If
+ you say fill(0), fill(2), etc., the image is filled with 0s. If
+ you say fill(1), fill(3), etc., the image is filled with 1s. If
+ the depth is 8, the lowest 8 bits are used and if the depth is 16
+ the lowest 16 bits are used.
+
+ Note: QImage::pixel() returns the color of the pixel at the given
+ coordinates while QColor::pixel() returns the pixel value of the
+ underlying window system (essentially an index value), so normally
+ you will want to use QImage::pixel() to use a color from an
+ existing image or QColor::rgb() to use a specific color.
+
+ \sa depth(), {QImage#Image Transformations}{Image Transformations}
+*/
+
+void QImage::fill(uint pixel)
+{
+ if (!d)
+ return;
+
+ detach();
+
+ // In case detach() ran out of memory
+ if (!d)
+ return;
+
+ if (d->depth == 1 || d->depth == 8) {
+ int w = d->width;
+ if (d->depth == 1) {
+ if (pixel & 1)
+ pixel = 0xffffffff;
+ else
+ pixel = 0;
+ w = (w + 7) / 8;
+ } else {
+ pixel &= 0xff;
+ }
+ qt_rectfill<quint8>(d->data, pixel, 0, 0,
+ w, d->height, d->bytes_per_line);
+ return;
+ } else if (d->depth == 16) {
+ qt_rectfill<quint16>(reinterpret_cast<quint16*>(d->data), pixel,
+ 0, 0, d->width, d->height, d->bytes_per_line);
+ return;
+ } else if (d->depth == 24) {
+ qt_rectfill<quint24>(reinterpret_cast<quint24*>(d->data), pixel,
+ 0, 0, d->width, d->height, d->bytes_per_line);
+ return;
+ }
+
+ if (d->format == Format_RGB32)
+ pixel |= 0xff000000;
+
+ qt_rectfill<uint>(reinterpret_cast<uint*>(d->data), pixel,
+ 0, 0, d->width, d->height, d->bytes_per_line);
+}
+
+
+/*!
+ \fn void QImage::fill(Qt::GlobalColor color)
+
+ \overload
+
+ \since 4.8
+ */
+
+void QImage::fill(Qt::GlobalColor color)
+{
+ fill(QColor(color));
+}
+
+
+
+/*!
+ \fn void QImage::fill(Qt::GlobalColor color)
+
+ \overload
+
+ Fills the entire image with the given \a color.
+
+ If the depth of the image is 1, the image will be filled with 1 if
+ \a color equals Qt::color1; it will otherwise be filled with 0.
+
+ If the depth of the image is 8, the image will be filled with the
+ index corresponding the \a color in the color table if present; it
+ will otherwise be filled with 0.
+
+ \since 4.8
+*/
+
+void QImage::fill(const QColor &color)
+{
+ if (!d)
+ return;
+ detach();
+
+ // In case we run out of memory
+ if (!d)
+ return;
+
+ if (d->depth == 32) {
+ uint pixel = color.rgba();
+ if (d->format == QImage::Format_ARGB32_Premultiplied)
+ pixel = PREMUL(pixel);
+ fill((uint) pixel);
+
+ } else if (d->depth == 16 && d->format == QImage::Format_RGB16) {
+ qrgb565 p(color.rgba());
+ fill((uint) p.rawValue());
+
+ } else if (d->depth == 1) {
+ if (color == Qt::color1)
+ fill((uint) 1);
+ else
+ fill((uint) 0);
+
+ } else if (d->depth == 8) {
+ uint pixel = 0;
+ for (int i=0; i<d->colortable.size(); ++i) {
+ if (color.rgba() == d->colortable.at(i)) {
+ pixel = i;
+ break;
+ }
+ }
+ fill(pixel);
+
+ } else {
+ QPainter p(this);
+ p.setCompositionMode(QPainter::CompositionMode_Source);
+ p.fillRect(rect(), color);
+ }
+
+}
+
+
+
+
+
+
+/*!
+ Inverts all pixel values in the image.
+
+ The given invert \a mode only have a meaning when the image's
+ depth is 32. The default \a mode is InvertRgb, which leaves the
+ alpha channel unchanged. If the \a mode is InvertRgba, the alpha
+ bits are also inverted.
+
+ Inverting an 8-bit image means to replace all pixels using color
+ index \e i with a pixel using color index 255 minus \e i. The same
+ is the case for a 1-bit image. Note that the color table is \e not
+ changed.
+
+ \sa {QImage#Image Transformations}{Image Transformations}
+*/
+
+void QImage::invertPixels(InvertMode mode)
+{
+ if (!d)
+ return;
+
+ detach();
+
+ // In case detach() ran out of memory
+ if (!d)
+ return;
+
+ if (depth() != 32) {
+ // number of used bytes pr line
+ int bpl = (d->width * d->depth + 7) / 8;
+ int pad = d->bytes_per_line - bpl;
+ uchar *sl = d->data;
+ for (int y=0; y<d->height; ++y) {
+ for (int x=0; x<bpl; ++x)
+ *sl++ ^= 0xff;
+ sl += pad;
+ }
+ } else {
+ quint32 *p = (quint32*)d->data;
+ quint32 *end = (quint32*)(d->data + d->nbytes);
+ uint xorbits = (mode == InvertRgba) ? 0xffffffff : 0x00ffffff;
+ while (p < end)
+ *p++ ^= xorbits;
+ }
+}
+
+/*!
+ \fn void QImage::invertPixels(bool invertAlpha)
+
+ Use the invertPixels() function that takes a QImage::InvertMode
+ parameter instead.
+*/
+
+/*! \fn QImage::Endian QImage::systemByteOrder()
+
+ Determines the host computer byte order. Returns
+ QImage::LittleEndian (LSB first) or QImage::BigEndian (MSB first).
+
+ This function is no longer relevant for QImage. Use QSysInfo
+ instead.
+*/
+
+// Windows defines these
+#if defined(write)
+# undef write
+#endif
+#if defined(close)
+# undef close
+#endif
+#if defined(read)
+# undef read
+#endif
+
+/*!
+ \obsolete
+ Resizes the color table to contain \a numColors entries.
+
+ \sa setColorCount()
+*/
+
+void QImage::setNumColors(int numColors)
+{
+ setColorCount(numColors);
+}
+
+/*!
+ \since 4.6
+ Resizes the color table to contain \a colorCount entries.
+
+ If the color table is expanded, all the extra colors will be set to
+ transparent (i.e qRgba(0, 0, 0, 0)).
+
+ When the image is used, the color table must be large enough to
+ have entries for all the pixel/index values present in the image,
+ otherwise the results are undefined.
+
+ \sa colorCount(), colorTable(), setColor(), {QImage#Image
+ Transformations}{Image Transformations}
+*/
+
+void QImage::setColorCount(int colorCount)
+{
+ if (!d) {
+ qWarning("QImage::setColorCount: null image");
+ return;
+ }
+
+ detach();
+
+ // In case detach() ran out of memory
+ if (!d)
+ return;
+
+ if (colorCount == d->colortable.size())
+ return;
+ if (colorCount <= 0) { // use no color table
+ d->colortable = QVector<QRgb>();
+ return;
+ }
+ int nc = d->colortable.size();
+ d->colortable.resize(colorCount);
+ for (int i = nc; i < colorCount; ++i)
+ d->colortable[i] = 0;
+}
+
+/*!
+ Returns the format of the image.
+
+ \sa {QImage#Image Formats}{Image Formats}
+*/
+QImage::Format QImage::format() const
+{
+ return d ? d->format : Format_Invalid;
+}
+
+
+#ifdef QT3_SUPPORT
+/*!
+ Returns true if alpha buffer mode is enabled; otherwise returns
+ false.
+
+ Use the hasAlphaChannel() function instead.
+
+*/
+bool QImage::hasAlphaBuffer() const
+{
+ if (!d)
+ return false;
+
+ switch (d->format) {
+ case Format_ARGB32:
+ case Format_ARGB32_Premultiplied:
+ case Format_ARGB8565_Premultiplied:
+ case Format_ARGB8555_Premultiplied:
+ case Format_ARGB6666_Premultiplied:
+ case Format_ARGB4444_Premultiplied:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/*!
+ Enables alpha buffer mode if \a enable is true, otherwise disables
+ it. The alpha buffer is used to set a mask when a QImage is
+ translated to a QPixmap.
+
+ If a monochrome or indexed 8-bit image has alpha channels in their
+ color tables they will automatically detect that they have an
+ alpha channel, so this function is not required. To force alpha
+ channels on 32-bit images, use the convertToFormat() function.
+*/
+
+void QImage::setAlphaBuffer(bool enable)
+{
+ if (!d
+ || d->format == Format_Mono
+ || d->format == Format_MonoLSB
+ || d->format == Format_Indexed8)
+ return;
+ if (enable && (d->format == Format_ARGB32 ||
+ d->format == Format_ARGB32_Premultiplied ||
+ d->format == Format_ARGB8565_Premultiplied ||
+ d->format == Format_ARGB6666_Premultiplied ||
+ d->format == Format_ARGB8555_Premultiplied ||
+ d->format == Format_ARGB4444_Premultiplied))
+ {
+ return;
+ }
+ if (!enable && (d->format == Format_RGB32 ||
+ d->format == Format_RGB555 ||
+ d->format == Format_RGB666 ||
+ d->format == Format_RGB888 ||
+ d->format == Format_RGB444))
+ {
+ return;
+ }
+ detach();
+ d->format = (enable ? Format_ARGB32 : Format_RGB32);
+}
+
+
+/*!
+ \fn bool QImage::create(int width, int height, int depth, int numColors, Endian bitOrder)
+
+ Sets the image \a width, \a height, \a depth, its number of colors
+ (in \a numColors), and bit order. Returns true if successful, or
+ false if the parameters are incorrect or if memory cannot be
+ allocated.
+
+ The \a width and \a height is limited to 32767. \a depth must be
+ 1, 8, or 32. If \a depth is 1, \a bitOrder must be set to
+ either QImage::LittleEndian or QImage::BigEndian. For other depths
+ \a bitOrder must be QImage::IgnoreEndian.
+
+ This function allocates a color table and a buffer for the image
+ data. The image data is not initialized. The image buffer is
+ allocated as a single block that consists of a table of scanLine()
+ pointers (jumpTable()) and the image data (bits()).
+
+ Use a QImage constructor instead.
+*/
+bool QImage::create(int width, int height, int depth, int numColors, Endian bitOrder)
+{
+ if (d && !d->ref.deref())
+ delete d;
+ d = QImageData::create(QSize(width, height), formatFor(depth, bitOrder), numColors);
+ return true;
+}
+
+/*!
+ \fn bool QImage::create(const QSize& size, int depth, int numColors, Endian bitOrder)
+ \overload
+
+ The width and height are specified in the \a size argument.
+
+ Use a QImage constructor instead.
+*/
+bool QImage::create(const QSize& size, int depth, int numColors, QImage::Endian bitOrder)
+{
+ if (d && !d->ref.deref())
+ delete d;
+ d = QImageData::create(size, formatFor(depth, bitOrder), numColors);
+ return true;
+}
+#endif // QT3_SUPPORT
+
+/*****************************************************************************
+ Internal routines for converting image depth.
+ *****************************************************************************/
+
+typedef void (*Image_Converter)(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
+
+typedef bool (*InPlace_Image_Converter)(QImageData *data, Qt::ImageConversionFlags);
+
+static void convert_ARGB_to_ARGB_PM(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(src->format == QImage::Format_ARGB32);
+ Q_ASSERT(dest->format == QImage::Format_ARGB32_Premultiplied);
+ Q_ASSERT(src->width == dest->width);
+ Q_ASSERT(src->height == dest->height);
+
+ const int src_pad = (src->bytes_per_line >> 2) - src->width;
+ const int dest_pad = (dest->bytes_per_line >> 2) - dest->width;
+ const QRgb *src_data = (QRgb *) src->data;
+ QRgb *dest_data = (QRgb *) dest->data;
+
+ for (int i = 0; i < src->height; ++i) {
+ const QRgb *end = src_data + src->width;
+ while (src_data < end) {
+ *dest_data = PREMUL(*src_data);
+ ++src_data;
+ ++dest_data;
+ }
+ src_data += src_pad;
+ dest_data += dest_pad;
+ }
+}
+
+static bool convert_ARGB_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(data->format == QImage::Format_ARGB32);
+
+ const int pad = (data->bytes_per_line >> 2) - data->width;
+ QRgb *rgb_data = (QRgb *) data->data;
+
+ 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;
+ }
+ rgb_data += pad;
+ }
+ data->format = QImage::Format_ARGB32_Premultiplied;
+ return true;
+}
+
+static bool convert_indexed8_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(data->format == QImage::Format_Indexed8);
+ const int depth = 32;
+
+ const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2;
+ const int nbytes = dst_bytes_per_line * data->height;
+ uchar *const newData = (uchar *)realloc(data->data, nbytes);
+ if (!newData)
+ return false;
+
+ data->data = newData;
+
+ // start converting from the end because the end image is bigger than the source
+ uchar *src_data = newData + data->nbytes; // end of src
+ quint32 *dest_data = (quint32 *) (newData + nbytes); // end of dest > end of src
+ const int width = data->width;
+ const int src_pad = data->bytes_per_line - width;
+ const int dest_pad = (dst_bytes_per_line >> 2) - width;
+ if (data->colortable.size() == 0) {
+ data->colortable.resize(256);
+ for (int i = 0; i < 256; ++i)
+ data->colortable[i] = qRgb(i, i, i);
+ } else {
+ for (int i = 0; i < data->colortable.size(); ++i)
+ data->colortable[i] = PREMUL(data->colortable.at(i));
+
+ // Fill the rest of the table in case src_data > colortable.size()
+ const int oldSize = data->colortable.size();
+ const QRgb lastColor = data->colortable.at(oldSize - 1);
+ data->colortable.insert(oldSize, 256 - oldSize, lastColor);
+ }
+
+ for (int i = 0; i < data->height; ++i) {
+ src_data -= src_pad;
+ dest_data -= dest_pad;
+ for (int pixI = 0; pixI < width; ++pixI) {
+ --src_data;
+ --dest_data;
+ *dest_data = data->colortable.at(*src_data);
+ }
+ }
+
+ data->colortable = QVector<QRgb>();
+ data->format = QImage::Format_ARGB32_Premultiplied;
+ data->bytes_per_line = dst_bytes_per_line;
+ data->depth = depth;
+ data->nbytes = nbytes;
+
+ return true;
+}
+
+static bool convert_indexed8_to_RGB_inplace(QImageData *data, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(data->format == QImage::Format_Indexed8);
+ const int depth = 32;
+
+ const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2;
+ const int nbytes = dst_bytes_per_line * data->height;
+ uchar *const newData = (uchar *)realloc(data->data, nbytes);
+ if (!newData)
+ return false;
+
+ data->data = newData;
+
+ // start converting from the end because the end image is bigger than the source
+ uchar *src_data = newData + data->nbytes;
+ quint32 *dest_data = (quint32 *) (newData + nbytes);
+ const int width = data->width;
+ const int src_pad = data->bytes_per_line - width;
+ const int dest_pad = (dst_bytes_per_line >> 2) - width;
+ if (data->colortable.size() == 0) {
+ data->colortable.resize(256);
+ for (int i = 0; i < 256; ++i)
+ data->colortable[i] = qRgb(i, i, i);
+ } else {
+ // Fill the rest of the table in case src_data > colortable.size()
+ const int oldSize = data->colortable.size();
+ const QRgb lastColor = data->colortable.at(oldSize - 1);
+ data->colortable.insert(oldSize, 256 - oldSize, lastColor);
+ }
+
+ for (int i = 0; i < data->height; ++i) {
+ src_data -= src_pad;
+ dest_data -= dest_pad;
+ for (int pixI = 0; pixI < width; ++pixI) {
+ --src_data;
+ --dest_data;
+ *dest_data = (quint32) data->colortable.at(*src_data);
+ }
+ }
+
+ data->colortable = QVector<QRgb>();
+ data->format = QImage::Format_RGB32;
+ data->bytes_per_line = dst_bytes_per_line;
+ data->depth = depth;
+ data->nbytes = nbytes;
+
+ return true;
+}
+
+static bool convert_indexed8_to_RGB16_inplace(QImageData *data, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(data->format == QImage::Format_Indexed8);
+ const int depth = 16;
+
+ const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2;
+ const int nbytes = dst_bytes_per_line * data->height;
+ uchar *const newData = (uchar *)realloc(data->data, nbytes);
+ if (!newData)
+ return false;
+
+ data->data = newData;
+
+ // start converting from the end because the end image is bigger than the source
+ uchar *src_data = newData + data->nbytes;
+ quint16 *dest_data = (quint16 *) (newData + nbytes);
+ const int width = data->width;
+ const int src_pad = data->bytes_per_line - width;
+ const int dest_pad = (dst_bytes_per_line >> 1) - width;
+
+ quint16 colorTableRGB16[256];
+ if (data->colortable.isEmpty()) {
+ for (int i = 0; i < 256; ++i)
+ colorTableRGB16[i] = qt_colorConvert<quint16, quint32>(qRgb(i, i, i), 0);
+ } else {
+ // 1) convert the existing colors to RGB16
+ const int tableSize = data->colortable.size();
+ for (int i = 0; i < tableSize; ++i)
+ colorTableRGB16[i] = qt_colorConvert<quint16, quint32>(data->colortable.at(i), 0);
+ data->colortable = QVector<QRgb>();
+
+ // 2) fill the rest of the table in case src_data > colortable.size()
+ const quint16 lastColor = colorTableRGB16[tableSize - 1];
+ for (int i = tableSize; i < 256; ++i)
+ colorTableRGB16[i] = lastColor;
+ }
+
+ for (int i = 0; i < data->height; ++i) {
+ src_data -= src_pad;
+ dest_data -= dest_pad;
+ for (int pixI = 0; pixI < width; ++pixI) {
+ --src_data;
+ --dest_data;
+ *dest_data = colorTableRGB16[*src_data];
+ }
+ }
+
+ data->format = QImage::Format_RGB16;
+ data->bytes_per_line = dst_bytes_per_line;
+ data->depth = depth;
+ data->nbytes = nbytes;
+
+ return true;
+}
+
+static bool convert_RGB_to_RGB16_inplace(QImageData *data, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(data->format == QImage::Format_RGB32);
+ const int depth = 16;
+
+ const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2;
+ const int src_bytes_per_line = data->bytes_per_line;
+ quint32 *src_data = (quint32 *) data->data;
+ quint16 *dst_data = (quint16 *) data->data;
+
+ for (int i = 0; i < data->height; ++i) {
+ qt_memconvert(dst_data, src_data, data->width);
+ src_data = (quint32 *) (((char*)src_data) + src_bytes_per_line);
+ dst_data = (quint16 *) (((char*)dst_data) + dst_bytes_per_line);
+ }
+ data->format = QImage::Format_RGB16;
+ data->bytes_per_line = dst_bytes_per_line;
+ data->depth = depth;
+ data->nbytes = dst_bytes_per_line * data->height;
+ uchar *const newData = (uchar *)realloc(data->data, data->nbytes);
+ if (newData) {
+ data->data = newData;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static void convert_ARGB_PM_to_ARGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied);
+ Q_ASSERT(dest->format == QImage::Format_ARGB32);
+ Q_ASSERT(src->width == dest->width);
+ Q_ASSERT(src->height == dest->height);
+
+ const int src_pad = (src->bytes_per_line >> 2) - src->width;
+ const int dest_pad = (dest->bytes_per_line >> 2) - dest->width;
+ const QRgb *src_data = (QRgb *) src->data;
+ QRgb *dest_data = (QRgb *) dest->data;
+
+ for (int i = 0; i < src->height; ++i) {
+ const QRgb *end = src_data + src->width;
+ while (src_data < end) {
+ *dest_data = INV_PREMUL(*src_data);
+ ++src_data;
+ ++dest_data;
+ }
+ src_data += src_pad;
+ dest_data += dest_pad;
+ }
+}
+
+static void convert_ARGB_PM_to_RGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied);
+ Q_ASSERT(dest->format == QImage::Format_RGB32);
+ Q_ASSERT(src->width == dest->width);
+ Q_ASSERT(src->height == dest->height);
+
+ const int src_pad = (src->bytes_per_line >> 2) - src->width;
+ const int dest_pad = (dest->bytes_per_line >> 2) - dest->width;
+ const QRgb *src_data = (QRgb *) src->data;
+ QRgb *dest_data = (QRgb *) dest->data;
+
+ for (int i = 0; i < src->height; ++i) {
+ const QRgb *end = src_data + src->width;
+ while (src_data < end) {
+ *dest_data = 0xff000000 | INV_PREMUL(*src_data);
+ ++src_data;
+ ++dest_data;
+ }
+ src_data += src_pad;
+ dest_data += dest_pad;
+ }
+}
+
+static void swap_bit_order(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(src->format == QImage::Format_Mono || src->format == QImage::Format_MonoLSB);
+ Q_ASSERT(dest->format == QImage::Format_Mono || dest->format == QImage::Format_MonoLSB);
+ Q_ASSERT(src->width == dest->width);
+ Q_ASSERT(src->height == dest->height);
+ Q_ASSERT(src->nbytes == dest->nbytes);
+ Q_ASSERT(src->bytes_per_line == dest->bytes_per_line);
+
+ dest->colortable = src->colortable;
+
+ const uchar *src_data = src->data;
+ const uchar *end = src->data + src->nbytes;
+ uchar *dest_data = dest->data;
+ while (src_data < end) {
+ *dest_data = bitflip[*src_data];
+ ++src_data;
+ ++dest_data;
+ }
+}
+
+static void mask_alpha_converter(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(src->width == dest->width);
+ Q_ASSERT(src->height == dest->height);
+
+ const int src_pad = (src->bytes_per_line >> 2) - src->width;
+ const int dest_pad = (dest->bytes_per_line >> 2) - dest->width;
+ const uint *src_data = (const uint *)src->data;
+ uint *dest_data = (uint *)dest->data;
+
+ for (int i = 0; i < src->height; ++i) {
+ const uint *end = src_data + src->width;
+ while (src_data < end) {
+ *dest_data = *src_data | 0xff000000;
+ ++src_data;
+ ++dest_data;
+ }
+ src_data += src_pad;
+ dest_data += dest_pad;
+ }
+}
+
+static QVector<QRgb> fix_color_table(const QVector<QRgb> &ctbl, QImage::Format format)
+{
+ QVector<QRgb> colorTable = ctbl;
+ if (format == QImage::Format_RGB32) {
+ // check if the color table has alpha
+ for (int i = 0; i < colorTable.size(); ++i)
+ if (qAlpha(colorTable.at(i) != 0xff))
+ colorTable[i] = colorTable.at(i) | 0xff000000;
+ } else if (format == QImage::Format_ARGB32_Premultiplied) {
+ // check if the color table has alpha
+ for (int i = 0; i < colorTable.size(); ++i)
+ colorTable[i] = PREMUL(colorTable.at(i));
+ }
+ return colorTable;
+}
+
+//
+// dither_to_1: Uses selected dithering algorithm.
+//
+
+static void dither_to_Mono(QImageData *dst, const QImageData *src,
+ Qt::ImageConversionFlags flags, bool fromalpha)
+{
+ Q_ASSERT(src->width == dst->width);
+ Q_ASSERT(src->height == dst->height);
+ Q_ASSERT(dst->format == QImage::Format_Mono || dst->format == QImage::Format_MonoLSB);
+
+ dst->colortable.clear();
+ dst->colortable.append(0xffffffff);
+ dst->colortable.append(0xff000000);
+
+ enum { Threshold, Ordered, Diffuse } dithermode;
+
+ if (fromalpha) {
+ if ((flags & Qt::AlphaDither_Mask) == Qt::DiffuseAlphaDither)
+ dithermode = Diffuse;
+ else if ((flags & Qt::AlphaDither_Mask) == Qt::OrderedAlphaDither)
+ dithermode = Ordered;
+ else
+ dithermode = Threshold;
+ } else {
+ if ((flags & Qt::Dither_Mask) == Qt::ThresholdDither)
+ dithermode = Threshold;
+ else if ((flags & Qt::Dither_Mask) == Qt::OrderedDither)
+ dithermode = Ordered;
+ else
+ dithermode = Diffuse;
+ }
+
+ int w = src->width;
+ int h = src->height;
+ int d = src->depth;
+ uchar gray[256]; // gray map for 8 bit images
+ bool use_gray = (d == 8);
+ if (use_gray) { // make gray map
+ if (fromalpha) {
+ // Alpha 0x00 -> 0 pixels (white)
+ // Alpha 0xFF -> 1 pixels (black)
+ for (int i = 0; i < src->colortable.size(); i++)
+ gray[i] = (255 - (src->colortable.at(i) >> 24));
+ } else {
+ // Pixel 0x00 -> 1 pixels (black)
+ // Pixel 0xFF -> 0 pixels (white)
+ for (int i = 0; i < src->colortable.size(); i++)
+ gray[i] = qGray(src->colortable.at(i));
+ }
+ }
+
+ uchar *dst_data = dst->data;
+ int dst_bpl = dst->bytes_per_line;
+ const uchar *src_data = src->data;
+ int src_bpl = src->bytes_per_line;
+
+ switch (dithermode) {
+ case Diffuse: {
+ QScopedArrayPointer<int> lineBuffer(new int[w * 2]);
+ int *line1 = lineBuffer.data();
+ int *line2 = lineBuffer.data() + w;
+ int bmwidth = (w+7)/8;
+
+ int *b1, *b2;
+ int wbytes = w * (d/8);
+ register const uchar *p = src->data;
+ const uchar *end = p + wbytes;
+ b2 = line2;
+ if (use_gray) { // 8 bit image
+ while (p < end)
+ *b2++ = gray[*p++];
+ } else { // 32 bit image
+ if (fromalpha) {
+ while (p < end) {
+ *b2++ = 255 - (*(uint*)p >> 24);
+ p += 4;
+ }
+ } else {
+ while (p < end) {
+ *b2++ = qGray(*(uint*)p);
+ p += 4;
+ }
+ }
+ }
+ for (int y=0; y<h; y++) { // for each scan line...
+ int *tmp = line1; line1 = line2; line2 = tmp;
+ bool not_last_line = y < h - 1;
+ if (not_last_line) { // calc. grayvals for next line
+ p = src->data + (y+1)*src->bytes_per_line;
+ end = p + wbytes;
+ b2 = line2;
+ if (use_gray) { // 8 bit image
+ while (p < end)
+ *b2++ = gray[*p++];
+ } else { // 24 bit image
+ if (fromalpha) {
+ while (p < end) {
+ *b2++ = 255 - (*(uint*)p >> 24);
+ p += 4;
+ }
+ } else {
+ while (p < end) {
+ *b2++ = qGray(*(uint*)p);
+ p += 4;
+ }
+ }
+ }
+ }
+
+ int err;
+ uchar *p = dst->data + y*dst->bytes_per_line;
+ memset(p, 0, bmwidth);
+ b1 = line1;
+ b2 = line2;
+ int bit = 7;
+ for (int x=1; x<=w; x++) {
+ if (*b1 < 128) { // black pixel
+ err = *b1++;
+ *p |= 1 << bit;
+ } else { // white pixel
+ err = *b1++ - 255;
+ }
+ if (bit == 0) {
+ p++;
+ bit = 7;
+ } else {
+ bit--;
+ }
+ if (x < w)
+ *b1 += (err*7)>>4; // spread error to right pixel
+ if (not_last_line) {
+ b2[0] += (err*5)>>4; // pixel below
+ if (x > 1)
+ b2[-1] += (err*3)>>4; // pixel below left
+ if (x < w)
+ b2[1] += err>>4; // pixel below right
+ }
+ b2++;
+ }
+ }
+ } break;
+ case Ordered: {
+
+ memset(dst->data, 0, dst->nbytes);
+ if (d == 32) {
+ for (int i=0; i<h; i++) {
+ const uint *p = (const uint *)src_data;
+ const uint *end = p + w;
+ uchar *m = dst_data;
+ int bit = 7;
+ int j = 0;
+ if (fromalpha) {
+ while (p < end) {
+ if ((*p++ >> 24) >= qt_bayer_matrix[j++&15][i&15])
+ *m |= 1 << bit;
+ if (bit == 0) {
+ m++;
+ bit = 7;
+ } else {
+ bit--;
+ }
+ }
+ } else {
+ while (p < end) {
+ if ((uint)qGray(*p++) < qt_bayer_matrix[j++&15][i&15])
+ *m |= 1 << bit;
+ if (bit == 0) {
+ m++;
+ bit = 7;
+ } else {
+ bit--;
+ }
+ }
+ }
+ dst_data += dst_bpl;
+ src_data += src_bpl;
+ }
+ } else
+ /* (d == 8) */ {
+ for (int i=0; i<h; i++) {
+ const uchar *p = src_data;
+ const uchar *end = p + w;
+ uchar *m = dst_data;
+ int bit = 7;
+ int j = 0;
+ while (p < end) {
+ if ((uint)gray[*p++] < qt_bayer_matrix[j++&15][i&15])
+ *m |= 1 << bit;
+ if (bit == 0) {
+ m++;
+ bit = 7;
+ } else {
+ bit--;
+ }
+ }
+ dst_data += dst_bpl;
+ src_data += src_bpl;
+ }
+ }
+ } break;
+ default: { // Threshold:
+ memset(dst->data, 0, dst->nbytes);
+ if (d == 32) {
+ for (int i=0; i<h; i++) {
+ const uint *p = (const uint *)src_data;
+ const uint *end = p + w;
+ uchar *m = dst_data;
+ int bit = 7;
+ if (fromalpha) {
+ while (p < end) {
+ if ((*p++ >> 24) >= 128)
+ *m |= 1 << bit; // Set mask "on"
+ if (bit == 0) {
+ m++;
+ bit = 7;
+ } else {
+ bit--;
+ }
+ }
+ } else {
+ while (p < end) {
+ if (qGray(*p++) < 128)
+ *m |= 1 << bit; // Set pixel "black"
+ if (bit == 0) {
+ m++;
+ bit = 7;
+ } else {
+ bit--;
+ }
+ }
+ }
+ dst_data += dst_bpl;
+ src_data += src_bpl;
+ }
+ } else
+ if (d == 8) {
+ for (int i=0; i<h; i++) {
+ const uchar *p = src_data;
+ const uchar *end = p + w;
+ uchar *m = dst_data;
+ int bit = 7;
+ while (p < end) {
+ if (gray[*p++] < 128)
+ *m |= 1 << bit; // Set mask "on"/ pixel "black"
+ if (bit == 0) {
+ m++;
+ bit = 7;
+ } else {
+ bit--;
+ }
+ }
+ dst_data += dst_bpl;
+ src_data += src_bpl;
+ }
+ }
+ }
+ }
+
+ if (dst->format == QImage::Format_MonoLSB) {
+ // need to swap bit order
+ uchar *sl = dst->data;
+ int bpl = (dst->width + 7) * dst->depth / 8;
+ int pad = dst->bytes_per_line - bpl;
+ for (int y=0; y<dst->height; ++y) {
+ for (int x=0; x<bpl; ++x) {
+ *sl = bitflip[*sl];
+ ++sl;
+ }
+ sl += pad;
+ }
+ }
+}
+
+static void convert_X_to_Mono(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags)
+{
+ dither_to_Mono(dst, src, flags, false);
+}
+
+static void convert_ARGB_PM_to_Mono(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags)
+{
+ QScopedPointer<QImageData> tmp(QImageData::create(QSize(src->width, src->height), QImage::Format_ARGB32));
+ convert_ARGB_PM_to_ARGB(tmp.data(), src, flags);
+ dither_to_Mono(dst, tmp.data(), flags, false);
+}
+
+//
+// convert_32_to_8: Converts a 32 bits depth (true color) to an 8 bit
+// image with a colormap. If the 32 bit image has more than 256 colors,
+// we convert the red,green and blue bytes into a single byte encoded
+// as 6 shades of each of red, green and blue.
+//
+// if dithering is needed, only 1 color at most is available for alpha.
+//
+struct QRgbMap {
+ inline QRgbMap() : used(0) { }
+ uchar pix;
+ uchar used;
+ QRgb rgb;
+};
+
+static void convert_RGB_to_Indexed8(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags)
+{
+ Q_ASSERT(src->format == QImage::Format_RGB32 || src->format == QImage::Format_ARGB32);
+ Q_ASSERT(dst->format == QImage::Format_Indexed8);
+ Q_ASSERT(src->width == dst->width);
+ Q_ASSERT(src->height == dst->height);
+
+ bool do_quant = (flags & Qt::DitherMode_Mask) == Qt::PreferDither
+ || src->format == QImage::Format_ARGB32;
+ uint alpha_mask = src->format == QImage::Format_RGB32 ? 0xff000000 : 0;
+
+ const int tablesize = 997; // prime
+ QRgbMap table[tablesize];
+ int pix=0;
+
+ if (!dst->colortable.isEmpty()) {
+ QVector<QRgb> ctbl = dst->colortable;
+ dst->colortable.resize(256);
+ // Preload palette into table.
+ // Almost same code as pixel insertion below
+ for (int i = 0; i < dst->colortable.size(); ++i) {
+ // Find in table...
+ QRgb p = ctbl.at(i) | alpha_mask;
+ int hash = p % tablesize;
+ for (;;) {
+ if (table[hash].used) {
+ if (table[hash].rgb == p) {
+ // Found previous insertion - use it
+ break;
+ } else {
+ // Keep searching...
+ if (++hash == tablesize) hash = 0;
+ }
+ } else {
+ // Cannot be in table
+ Q_ASSERT (pix != 256); // too many colors
+ // Insert into table at this unused position
+ dst->colortable[pix] = p;
+ table[hash].pix = pix++;
+ table[hash].rgb = p;
+ table[hash].used = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ if ((flags & Qt::DitherMode_Mask) != Qt::PreferDither) {
+ dst->colortable.resize(256);
+ const uchar *src_data = src->data;
+ uchar *dest_data = dst->data;
+ for (int y = 0; y < src->height; y++) { // check if <= 256 colors
+ const QRgb *s = (const QRgb *)src_data;
+ uchar *b = dest_data;
+ for (int x = 0; x < src->width; ++x) {
+ QRgb p = s[x] | alpha_mask;
+ int hash = p % tablesize;
+ for (;;) {
+ if (table[hash].used) {
+ if (table[hash].rgb == (p)) {
+ // Found previous insertion - use it
+ break;
+ } else {
+ // Keep searching...
+ if (++hash == tablesize) hash = 0;
+ }
+ } else {
+ // Cannot be in table
+ if (pix == 256) { // too many colors
+ do_quant = true;
+ // Break right out
+ x = src->width;
+ y = src->height;
+ } else {
+ // Insert into table at this unused position
+ dst->colortable[pix] = p;
+ table[hash].pix = pix++;
+ table[hash].rgb = p;
+ table[hash].used = 1;
+ }
+ break;
+ }
+ }
+ *b++ = table[hash].pix; // May occur once incorrectly
+ }
+ src_data += src->bytes_per_line;
+ dest_data += dst->bytes_per_line;
+ }
+ }
+ int numColors = do_quant ? 256 : pix;
+
+ dst->colortable.resize(numColors);
+
+ if (do_quant) { // quantization needed
+
+#define MAX_R 5
+#define MAX_G 5
+#define MAX_B 5
+#define INDEXOF(r,g,b) (((r)*(MAX_G+1)+(g))*(MAX_B+1)+(b))
+
+ for (int rc=0; rc<=MAX_R; rc++) // build 6x6x6 color cube
+ for (int gc=0; gc<=MAX_G; gc++)
+ for (int bc=0; bc<=MAX_B; bc++)
+ dst->colortable[INDEXOF(rc,gc,bc)] = 0xff000000 | qRgb(rc*255/MAX_R, gc*255/MAX_G, bc*255/MAX_B);
+
+ const uchar *src_data = src->data;
+ uchar *dest_data = dst->data;
+ if ((flags & Qt::Dither_Mask) == Qt::ThresholdDither) {
+ for (int y = 0; y < src->height; y++) {
+ const QRgb *p = (const QRgb *)src_data;
+ const QRgb *end = p + src->width;
+ uchar *b = dest_data;
+
+ while (p < end) {
+#define DITHER(p,m) ((uchar) ((p * (m) + 127) / 255))
+ *b++ =
+ INDEXOF(
+ DITHER(qRed(*p), MAX_R),
+ DITHER(qGreen(*p), MAX_G),
+ DITHER(qBlue(*p), MAX_B)
+ );
+#undef DITHER
+ p++;
+ }
+ src_data += src->bytes_per_line;
+ dest_data += dst->bytes_per_line;
+ }
+ } else if ((flags & Qt::Dither_Mask) == Qt::DiffuseDither) {
+ int* line1[3];
+ int* line2[3];
+ int* pv[3];
+ QScopedArrayPointer<int> lineBuffer(new int[src->width * 9]);
+ line1[0] = lineBuffer.data();
+ line2[0] = lineBuffer.data() + src->width;
+ line1[1] = lineBuffer.data() + src->width * 2;
+ line2[1] = lineBuffer.data() + src->width * 3;
+ line1[2] = lineBuffer.data() + src->width * 4;
+ line2[2] = lineBuffer.data() + src->width * 5;
+ pv[0] = lineBuffer.data() + src->width * 6;
+ pv[1] = lineBuffer.data() + src->width * 7;
+ pv[2] = lineBuffer.data() + src->width * 8;
+
+ int endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian);
+ for (int y = 0; y < src->height; y++) {
+ const uchar* q = src_data;
+ const uchar* q2 = y < src->height - 1 ? q + src->bytes_per_line : src->data;
+ uchar *b = dest_data;
+ for (int chan = 0; chan < 3; chan++) {
+ int *l1 = (y&1) ? line2[chan] : line1[chan];
+ int *l2 = (y&1) ? line1[chan] : line2[chan];
+ if (y == 0) {
+ for (int i = 0; i < src->width; i++)
+ l1[i] = q[i*4+chan+endian];
+ }
+ if (y+1 < src->height) {
+ for (int i = 0; i < src->width; i++)
+ l2[i] = q2[i*4+chan+endian];
+ }
+ // Bi-directional error diffusion
+ if (y&1) {
+ for (int x = 0; x < src->width; x++) {
+ int pix = qMax(qMin(5, (l1[x] * 5 + 128)/ 255), 0);
+ int err = l1[x] - pix * 255 / 5;
+ pv[chan][x] = pix;
+
+ // Spread the error around...
+ if (x + 1< src->width) {
+ l1[x+1] += (err*7)>>4;
+ l2[x+1] += err>>4;
+ }
+ l2[x]+=(err*5)>>4;
+ if (x>1)
+ l2[x-1]+=(err*3)>>4;
+ }
+ } else {
+ for (int x = src->width; x-- > 0;) {
+ int pix = qMax(qMin(5, (l1[x] * 5 + 128)/ 255), 0);
+ int err = l1[x] - pix * 255 / 5;
+ pv[chan][x] = pix;
+
+ // Spread the error around...
+ if (x > 0) {
+ l1[x-1] += (err*7)>>4;
+ l2[x-1] += err>>4;
+ }
+ l2[x]+=(err*5)>>4;
+ if (x + 1 < src->width)
+ l2[x+1]+=(err*3)>>4;
+ }
+ }
+ }
+ if (endian) {
+ for (int x = 0; x < src->width; x++) {
+ *b++ = INDEXOF(pv[0][x],pv[1][x],pv[2][x]);
+ }
+ } else {
+ for (int x = 0; x < src->width; x++) {
+ *b++ = INDEXOF(pv[2][x],pv[1][x],pv[0][x]);
+ }
+ }
+ src_data += src->bytes_per_line;
+ dest_data += dst->bytes_per_line;
+ }
+ } else { // OrderedDither
+ for (int y = 0; y < src->height; y++) {
+ const QRgb *p = (const QRgb *)src_data;
+ const QRgb *end = p + src->width;
+ uchar *b = dest_data;
+
+ int x = 0;
+ while (p < end) {
+ uint d = qt_bayer_matrix[y & 15][x & 15] << 8;
+
+#define DITHER(p, d, m) ((uchar) ((((256 * (m) + (m) + 1)) * (p) + (d)) >> 16))
+ *b++ =
+ INDEXOF(
+ DITHER(qRed(*p), d, MAX_R),
+ DITHER(qGreen(*p), d, MAX_G),
+ DITHER(qBlue(*p), d, MAX_B)
+ );
+#undef DITHER
+
+ p++;
+ x++;
+ }
+ src_data += src->bytes_per_line;
+ dest_data += dst->bytes_per_line;
+ }
+ }
+
+ if (src->format != QImage::Format_RGB32
+ && src->format != QImage::Format_RGB16) {
+ const int trans = 216;
+ Q_ASSERT(dst->colortable.size() > trans);
+ dst->colortable[trans] = 0;
+ QScopedPointer<QImageData> mask(QImageData::create(QSize(src->width, src->height), QImage::Format_Mono));
+ dither_to_Mono(mask.data(), src, flags, true);
+ uchar *dst_data = dst->data;
+ const uchar *mask_data = mask->data;
+ for (int y = 0; y < src->height; y++) {
+ for (int x = 0; x < src->width ; x++) {
+ if (!(mask_data[x>>3] & (0x80 >> (x & 7))))
+ dst_data[x] = trans;
+ }
+ mask_data += mask->bytes_per_line;
+ dst_data += dst->bytes_per_line;
+ }
+ dst->has_alpha_clut = true;
+ }
+
+#undef MAX_R
+#undef MAX_G
+#undef MAX_B
+#undef INDEXOF
+
+ }
+}
+
+static void convert_ARGB_PM_to_Indexed8(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags)
+{
+ QScopedPointer<QImageData> tmp(QImageData::create(QSize(src->width, src->height), QImage::Format_ARGB32));
+ convert_ARGB_PM_to_ARGB(tmp.data(), src, flags);
+ convert_RGB_to_Indexed8(dst, tmp.data(), flags);
+}
+
+static void convert_ARGB_to_Indexed8(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags)
+{
+ convert_RGB_to_Indexed8(dst, src, flags);
+}
+
+static void convert_Indexed8_to_X32(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(src->format == QImage::Format_Indexed8);
+ Q_ASSERT(dest->format == QImage::Format_RGB32
+ || dest->format == QImage::Format_ARGB32
+ || dest->format == QImage::Format_ARGB32_Premultiplied);
+ Q_ASSERT(src->width == dest->width);
+ Q_ASSERT(src->height == dest->height);
+
+ QVector<QRgb> colorTable = fix_color_table(src->colortable, dest->format);
+ if (colorTable.size() == 0) {
+ colorTable.resize(256);
+ for (int i=0; i<256; ++i)
+ colorTable[i] = qRgb(i, i, i);
+ }
+
+ int w = src->width;
+ const uchar *src_data = src->data;
+ uchar *dest_data = dest->data;
+ int tableSize = colorTable.size() - 1;
+ for (int y = 0; y < src->height; y++) {
+ uint *p = (uint *)dest_data;
+ const uchar *b = src_data;
+ uint *end = p + w;
+
+ while (p < end)
+ *p++ = colorTable.at(qMin<int>(tableSize, *b++));
+
+ src_data += src->bytes_per_line;
+ dest_data += dest->bytes_per_line;
+ }
+}
+
+static void convert_Mono_to_X32(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(src->format == QImage::Format_Mono || src->format == QImage::Format_MonoLSB);
+ Q_ASSERT(dest->format == QImage::Format_RGB32
+ || dest->format == QImage::Format_ARGB32
+ || dest->format == QImage::Format_ARGB32_Premultiplied);
+ Q_ASSERT(src->width == dest->width);
+ Q_ASSERT(src->height == dest->height);
+
+ QVector<QRgb> colorTable = fix_color_table(src->colortable, dest->format);
+
+ // Default to black / white colors
+ if (colorTable.size() < 2) {
+ if (colorTable.size() == 0)
+ colorTable << 0xff000000;
+ colorTable << 0xffffffff;
+ }
+
+ const uchar *src_data = src->data;
+ uchar *dest_data = dest->data;
+ if (src->format == QImage::Format_Mono) {
+ for (int y = 0; y < dest->height; y++) {
+ register uint *p = (uint *)dest_data;
+ for (int x = 0; x < dest->width; x++)
+ *p++ = colorTable.at((src_data[x>>3] >> (7 - (x & 7))) & 1);
+
+ src_data += src->bytes_per_line;
+ dest_data += dest->bytes_per_line;
+ }
+ } else {
+ for (int y = 0; y < dest->height; y++) {
+ register uint *p = (uint *)dest_data;
+ for (int x = 0; x < dest->width; x++)
+ *p++ = colorTable.at((src_data[x>>3] >> (x & 7)) & 1);
+
+ src_data += src->bytes_per_line;
+ dest_data += dest->bytes_per_line;
+ }
+ }
+}
+
+
+static void convert_Mono_to_Indexed8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(src->format == QImage::Format_Mono || src->format == QImage::Format_MonoLSB);
+ Q_ASSERT(dest->format == QImage::Format_Indexed8);
+ Q_ASSERT(src->width == dest->width);
+ Q_ASSERT(src->height == dest->height);
+
+ QVector<QRgb> ctbl = src->colortable;
+ if (ctbl.size() > 2) {
+ ctbl.resize(2);
+ } else if (ctbl.size() < 2) {
+ if (ctbl.size() == 0)
+ ctbl << 0xff000000;
+ ctbl << 0xffffffff;
+ }
+ dest->colortable = ctbl;
+ dest->has_alpha_clut = src->has_alpha_clut;
+
+
+ const uchar *src_data = src->data;
+ uchar *dest_data = dest->data;
+ if (src->format == QImage::Format_Mono) {
+ for (int y = 0; y < dest->height; y++) {
+ register uchar *p = dest_data;
+ for (int x = 0; x < dest->width; x++)
+ *p++ = (src_data[x>>3] >> (7 - (x & 7))) & 1;
+ src_data += src->bytes_per_line;
+ dest_data += dest->bytes_per_line;
+ }
+ } else {
+ for (int y = 0; y < dest->height; y++) {
+ register uchar *p = dest_data;
+ for (int x = 0; x < dest->width; x++)
+ *p++ = (src_data[x>>3] >> (x & 7)) & 1;
+ src_data += src->bytes_per_line;
+ dest_data += dest->bytes_per_line;
+ }
+ }
+}
+
+#define CONVERT_DECL(DST, SRC) \
+ static void convert_##SRC##_to_##DST(QImageData *dest, \
+ const QImageData *src, \
+ Qt::ImageConversionFlags) \
+ { \
+ qt_rectconvert<DST, SRC>(reinterpret_cast<DST*>(dest->data), \
+ reinterpret_cast<const SRC*>(src->data), \
+ 0, 0, src->width, src->height, \
+ dest->bytes_per_line, src->bytes_per_line); \
+ }
+
+CONVERT_DECL(quint32, quint16)
+CONVERT_DECL(quint16, quint32)
+CONVERT_DECL(quint32, qargb8565)
+CONVERT_DECL(qargb8565, quint32)
+CONVERT_DECL(quint32, qrgb555)
+CONVERT_DECL(qrgb666, quint32)
+CONVERT_DECL(quint32, qrgb666)
+CONVERT_DECL(qargb6666, quint32)
+CONVERT_DECL(quint32, qargb6666)
+CONVERT_DECL(qrgb555, quint32)
+#if !defined(Q_WS_QWS) || (defined(QT_QWS_DEPTH_15) && defined(QT_QWS_DEPTH_16))
+CONVERT_DECL(quint16, qrgb555)
+CONVERT_DECL(qrgb555, quint16)
+#endif
+CONVERT_DECL(quint32, qrgb888)
+CONVERT_DECL(qrgb888, quint32)
+CONVERT_DECL(quint32, qargb8555)
+CONVERT_DECL(qargb8555, quint32)
+CONVERT_DECL(quint32, qrgb444)
+CONVERT_DECL(qrgb444, quint32)
+CONVERT_DECL(quint32, qargb4444)
+CONVERT_DECL(qargb4444, quint32)
+#undef CONVERT_DECL
+#define CONVERT_PTR(DST, SRC) convert_##SRC##_to_##DST
+
+/*
+ Format_Invalid,
+ Format_Mono,
+ Format_MonoLSB,
+ Format_Indexed8,
+ Format_RGB32,
+ Format_ARGB32,
+ Format_ARGB32_Premultiplied,
+ Format_RGB16,
+ Format_ARGB8565_Premultiplied,
+ Format_RGB666,
+ Format_ARGB6666_Premultiplied,
+ Format_RGB555,
+ Format_ARGB8555_Premultiplied,
+ Format_RGB888
+ Format_RGB444
+ Format_ARGB4444_Premultiplied
+*/
+
+
+// first index source, second dest
+static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormats] =
+{
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ {
+ 0,
+ 0,
+ swap_bit_order,
+ convert_Mono_to_Indexed8,
+ convert_Mono_to_X32,
+ convert_Mono_to_X32,
+ convert_Mono_to_X32,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ }, // Format_Mono
+
+ {
+ 0,
+ swap_bit_order,
+ 0,
+ convert_Mono_to_Indexed8,
+ convert_Mono_to_X32,
+ convert_Mono_to_X32,
+ convert_Mono_to_X32,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ }, // Format_MonoLSB
+
+ {
+ 0,
+ convert_X_to_Mono,
+ convert_X_to_Mono,
+ 0,
+ convert_Indexed8_to_X32,
+ convert_Indexed8_to_X32,
+ convert_Indexed8_to_X32,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ }, // Format_Indexed8
+
+ {
+ 0,
+ convert_X_to_Mono,
+ convert_X_to_Mono,
+ convert_RGB_to_Indexed8,
+ 0,
+ mask_alpha_converter,
+ mask_alpha_converter,
+ CONVERT_PTR(quint16, quint32),
+ CONVERT_PTR(qargb8565, quint32),
+ CONVERT_PTR(qrgb666, quint32),
+ CONVERT_PTR(qargb6666, quint32),
+ CONVERT_PTR(qrgb555, quint32),
+ CONVERT_PTR(qargb8555, quint32),
+ CONVERT_PTR(qrgb888, quint32),
+ CONVERT_PTR(qrgb444, quint32),
+ CONVERT_PTR(qargb4444, quint32)
+ }, // Format_RGB32
+
+ {
+ 0,
+ convert_X_to_Mono,
+ convert_X_to_Mono,
+ convert_ARGB_to_Indexed8,
+ mask_alpha_converter,
+ 0,
+ convert_ARGB_to_ARGB_PM,
+ CONVERT_PTR(quint16, quint32),
+ CONVERT_PTR(qargb8565, quint32),
+ CONVERT_PTR(qrgb666, quint32),
+ CONVERT_PTR(qargb6666, quint32),
+ CONVERT_PTR(qrgb555, quint32),
+ CONVERT_PTR(qargb8555, quint32),
+ CONVERT_PTR(qrgb888, quint32),
+ CONVERT_PTR(qrgb444, quint32),
+ CONVERT_PTR(qargb4444, quint32)
+ }, // Format_ARGB32
+
+ {
+ 0,
+ convert_ARGB_PM_to_Mono,
+ convert_ARGB_PM_to_Mono,
+ convert_ARGB_PM_to_Indexed8,
+ convert_ARGB_PM_to_RGB,
+ convert_ARGB_PM_to_ARGB,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ }, // Format_ARGB32_Premultiplied
+
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ CONVERT_PTR(quint32, quint16),
+ CONVERT_PTR(quint32, quint16),
+ CONVERT_PTR(quint32, quint16),
+ 0,
+ 0,
+ 0,
+ 0,
+#if !defined(Q_WS_QWS) || (defined(QT_QWS_DEPTH_15) && defined(QT_QWS_DEPTH_16))
+ CONVERT_PTR(qrgb555, quint16),
+#else
+ 0,
+#endif
+ 0,
+ 0,
+ 0,
+ 0
+ }, // Format_RGB16
+
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ CONVERT_PTR(quint32, qargb8565),
+ CONVERT_PTR(quint32, qargb8565),
+ CONVERT_PTR(quint32, qargb8565),
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ }, // Format_ARGB8565_Premultiplied
+
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ CONVERT_PTR(quint32, qrgb666),
+ CONVERT_PTR(quint32, qrgb666),
+ CONVERT_PTR(quint32, qrgb666),
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ }, // Format_RGB666
+
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ CONVERT_PTR(quint32, qargb6666),
+ CONVERT_PTR(quint32, qargb6666),
+ CONVERT_PTR(quint32, qargb6666),
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ }, // Format_ARGB6666_Premultiplied
+
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ CONVERT_PTR(quint32, qrgb555),
+ CONVERT_PTR(quint32, qrgb555),
+ CONVERT_PTR(quint32, qrgb555),
+#if !defined(Q_WS_QWS) || (defined(QT_QWS_DEPTH_15) && defined(QT_QWS_DEPTH_16))
+ CONVERT_PTR(quint16, qrgb555),
+#else
+ 0,
+#endif
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ }, // Format_RGB555
+
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ CONVERT_PTR(quint32, qargb8555),
+ CONVERT_PTR(quint32, qargb8555),
+ CONVERT_PTR(quint32, qargb8555),
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ }, // Format_ARGB8555_Premultiplied
+
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ CONVERT_PTR(quint32, qrgb888),
+ CONVERT_PTR(quint32, qrgb888),
+ CONVERT_PTR(quint32, qrgb888),
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ }, // Format_RGB888
+
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ CONVERT_PTR(quint32, qrgb444),
+ CONVERT_PTR(quint32, qrgb444),
+ CONVERT_PTR(quint32, qrgb444),
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ }, // Format_RGB444
+
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ CONVERT_PTR(quint32, qargb4444),
+ CONVERT_PTR(quint32, qargb4444),
+ CONVERT_PTR(quint32, qargb4444),
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ } // Format_ARGB4444_Premultiplied
+};
+
+static InPlace_Image_Converter 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
+ }, // Format_Mono
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ }, // Format_MonoLSB
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ convert_indexed8_to_RGB_inplace,
+ convert_indexed8_to_ARGB_PM_inplace,
+ convert_indexed8_to_RGB16_inplace,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ }, // Format_Indexed8
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ convert_RGB_to_RGB16_inplace,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ }, // Format_ARGB32
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ convert_ARGB_to_ARGB_PM_inplace,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ }, // Format_ARGB32
+ {
+ 0, 0, 0, 0, 0, 0, 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
+ }, // Format_RGB16
+ {
+ 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
+ }, // Format_RGB666
+ {
+ 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
+ }, // Format_RGB555
+ {
+ 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
+ }, // Format_RGB888
+ {
+ 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
+ } // Format_ARGB4444_Premultiplied
+};
+
+void qInitImageConversions()
+{
+ const uint features = qDetectCPUFeatures();
+ Q_UNUSED(features);
+
+#ifdef QT_HAVE_SSE2
+ if (features & SSE2) {
+ extern bool convert_ARGB_to_ARGB_PM_inplace_sse2(QImageData *data, Qt::ImageConversionFlags);
+ inplace_converter_map[QImage::Format_ARGB32][QImage::Format_ARGB32_Premultiplied] = convert_ARGB_to_ARGB_PM_inplace_sse2;
+ }
+#endif
+#ifdef QT_HAVE_SSSE3
+ if (features & SSSE3) {
+ extern void convert_RGB888_to_RGB32_ssse3(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
+ converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB32_ssse3;
+ converter_map[QImage::Format_RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB32_ssse3;
+ converter_map[QImage::Format_RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB32_ssse3;
+ }
+#endif
+#ifdef QT_HAVE_NEON
+ if (features & NEON) {
+ extern void convert_RGB888_to_RGB32_neon(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
+ converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB32_neon;
+ converter_map[QImage::Format_RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB32_neon;
+ converter_map[QImage::Format_RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB32_neon;
+ }
+#endif
+}
+
+void qGamma_correct_back_to_linear_cs(QImage *image)
+{
+ extern uchar qt_pow_rgb_gamma[256];
+
+ // gamma correct the pixels back to linear color space...
+ int h = image->height();
+ int w = image->width();
+
+ for (int y=0; y<h; ++y) {
+ uint *pixels = (uint *) image->scanLine(y);
+ for (int x=0; x<w; ++x) {
+ uint p = pixels[x];
+ uint r = qt_pow_rgb_gamma[qRed(p)];
+ uint g = qt_pow_rgb_gamma[qGreen(p)];
+ uint b = qt_pow_rgb_gamma[qBlue(p)];
+ pixels[x] = (r << 16) | (g << 8) | b | 0xff000000;
+ }
+ }
+}
+
+/*!
+ Returns a copy of the image in the given \a format.
+
+ The specified image conversion \a flags control how the image data
+ is handled during the conversion process.
+
+ \sa {QImage#Image Format}{Image Format}
+*/
+QImage QImage::convertToFormat(Format format, Qt::ImageConversionFlags flags) const
+{
+ if (!d || d->format == format)
+ return *this;
+
+ if (format == Format_Invalid || d->format == Format_Invalid)
+ return QImage();
+
+ const Image_Converter *converterPtr = &converter_map[d->format][format];
+ Image_Converter converter = *converterPtr;
+ if (converter) {
+ QImage image(d->width, d->height, format);
+
+ QIMAGE_SANITYCHECK_MEMORY(image);
+
+ image.setDotsPerMeterY(dotsPerMeterY());
+ image.setDotsPerMeterX(dotsPerMeterX());
+
+#if !defined(QT_NO_IMAGE_TEXT)
+ image.d->text = d->text;
+#endif // !QT_NO_IMAGE_TEXT
+
+ converter(image.d, d, flags);
+ return image;
+ }
+
+ Q_ASSERT(format != QImage::Format_ARGB32);
+ Q_ASSERT(d->format != QImage::Format_ARGB32);
+
+ QImage image = convertToFormat(Format_ARGB32, flags);
+ return image.convertToFormat(format, flags);
+}
+
+
+
+static inline int pixel_distance(QRgb p1, QRgb p2) {
+ int r1 = qRed(p1);
+ int g1 = qGreen(p1);
+ int b1 = qBlue(p1);
+ int a1 = qAlpha(p1);
+
+ int r2 = qRed(p2);
+ int g2 = qGreen(p2);
+ int b2 = qBlue(p2);
+ int a2 = qAlpha(p2);
+
+ return abs(r1 - r2) + abs(g1 - g2) + abs(b1 - b2) + abs(a1 - a2);
+}
+
+static inline int closestMatch(QRgb pixel, const QVector<QRgb> &clut) {
+ int idx = 0;
+ int current_distance = INT_MAX;
+ for (int i=0; i<clut.size(); ++i) {
+ int dist = pixel_distance(pixel, clut.at(i));
+ if (dist < current_distance) {
+ current_distance = dist;
+ idx = i;
+ }
+ }
+ return idx;
+}
+
+static QImage convertWithPalette(const QImage &src, QImage::Format format,
+ const QVector<QRgb> &clut) {
+ QImage dest(src.size(), format);
+ dest.setColorTable(clut);
+
+#if !defined(QT_NO_IMAGE_TEXT)
+ QString textsKeys = src.text();
+ QStringList textKeyList = textsKeys.split(QLatin1Char('\n'), QString::SkipEmptyParts);
+ foreach (const QString &textKey, textKeyList) {
+ QStringList textKeySplitted = textKey.split(QLatin1String(": "));
+ dest.setText(textKeySplitted[0], textKeySplitted[1]);
+ }
+#endif // !QT_NO_IMAGE_TEXT
+
+ int h = src.height();
+ int w = src.width();
+
+ QHash<QRgb, int> cache;
+
+ if (format == QImage::Format_Indexed8) {
+ for (int y=0; y<h; ++y) {
+ QRgb *src_pixels = (QRgb *) src.scanLine(y);
+ uchar *dest_pixels = (uchar *) dest.scanLine(y);
+ for (int x=0; x<w; ++x) {
+ int src_pixel = src_pixels[x];
+ int value = cache.value(src_pixel, -1);
+ if (value == -1) {
+ value = closestMatch(src_pixel, clut);
+ cache.insert(src_pixel, value);
+ }
+ dest_pixels[x] = (uchar) value;
+ }
+ }
+ } else {
+ QVector<QRgb> table = clut;
+ table.resize(2);
+ for (int y=0; y<h; ++y) {
+ QRgb *src_pixels = (QRgb *) src.scanLine(y);
+ for (int x=0; x<w; ++x) {
+ int src_pixel = src_pixels[x];
+ int value = cache.value(src_pixel, -1);
+ if (value == -1) {
+ value = closestMatch(src_pixel, table);
+ cache.insert(src_pixel, value);
+ }
+ dest.setPixel(x, y, value);
+ }
+ }
+ }
+
+ return dest;
+}
+
+/*!
+ \overload
+
+ Returns a copy of the image converted to the given \a format,
+ using the specified \a colorTable.
+
+ Conversion from 32 bit to 8 bit indexed is a slow operation and
+ will use a straightforward nearest color approach, with no
+ dithering.
+*/
+QImage QImage::convertToFormat(Format format, const QVector<QRgb> &colorTable, Qt::ImageConversionFlags flags) const
+{
+ if (d->format == format)
+ return *this;
+
+ if (format <= QImage::Format_Indexed8 && depth() == 32) {
+ return convertWithPalette(*this, format, colorTable);
+ }
+
+ const Image_Converter *converterPtr = &converter_map[d->format][format];
+ Image_Converter converter = *converterPtr;
+ if (!converter)
+ return QImage();
+
+ QImage image(d->width, d->height, format);
+ QIMAGE_SANITYCHECK_MEMORY(image);
+
+#if !defined(QT_NO_IMAGE_TEXT)
+ image.d->text = d->text;
+#endif // !QT_NO_IMAGE_TEXT
+
+ converter(image.d, d, flags);
+ return image;
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ Converts the depth (bpp) of the image to the given \a depth and
+ returns the converted image. The original image is not changed.
+ Returns this image if \a depth is equal to the image depth, or a
+ null image if this image cannot be converted. The \a depth
+ argument must be 1, 8 or 32. If the image needs to be modified to
+ fit in a lower-resolution result (e.g. converting from 32-bit to
+ 8-bit), use the \a flags to specify how you'd prefer this to
+ happen.
+
+ Use the convertToFormat() function instead.
+*/
+
+QImage QImage::convertDepth(int depth, Qt::ImageConversionFlags flags) const
+{
+ if (!d || d->depth == depth)
+ return *this;
+
+ Format format = formatFor (depth, QImage::LittleEndian);
+ return convertToFormat(format, flags);
+}
+#endif
+
+/*!
+ \fn bool QImage::valid(const QPoint &pos) const
+
+ Returns true if \a pos is a valid coordinate pair within the
+ image; otherwise returns false.
+
+ \sa rect(), QRect::contains()
+*/
+
+/*!
+ \overload
+
+ Returns true if QPoint(\a x, \a y) is a valid coordinate pair
+ within the image; otherwise returns false.
+*/
+bool QImage::valid(int x, int y) const
+{
+ return d
+ && x >= 0 && x < d->width
+ && y >= 0 && y < d->height;
+}
+
+/*!
+ \fn int QImage::pixelIndex(const QPoint &position) const
+
+ Returns the pixel index at the given \a position.
+
+ If \a position is not valid, or if the image is not a paletted
+ image (depth() > 8), the results are undefined.
+
+ \sa valid(), depth(), {QImage#Pixel Manipulation}{Pixel Manipulation}
+*/
+
+/*!
+ \overload
+
+ Returns the pixel index at (\a x, \a y).
+*/
+int QImage::pixelIndex(int x, int y) const
+{
+ if (!d || x < 0 || x >= d->width || y < 0 || y >= height()) {
+ qWarning("QImage::pixelIndex: coordinate (%d,%d) out of range", x, y);
+ return -12345;
+ }
+ const uchar * s = scanLine(y);
+ switch(d->format) {
+ case Format_Mono:
+ return (*(s + (x >> 3)) >> (7- (x & 7))) & 1;
+ case Format_MonoLSB:
+ return (*(s + (x >> 3)) >> (x & 7)) & 1;
+ case Format_Indexed8:
+ return (int)s[x];
+ default:
+ qWarning("QImage::pixelIndex: Not applicable for %d-bpp images (no palette)", d->depth);
+ }
+ return 0;
+}
+
+
+/*!
+ \fn QRgb QImage::pixel(const QPoint &position) const
+
+ Returns the color of the pixel at the given \a position.
+
+ If the \a position is not valid, the results are undefined.
+
+ \warning This function is expensive when used for massive pixel
+ manipulations.
+
+ \sa setPixel(), valid(), {QImage#Pixel Manipulation}{Pixel
+ Manipulation}
+*/
+
+/*!
+ \overload
+
+ Returns the color of the pixel at coordinates (\a x, \a y).
+*/
+QRgb QImage::pixel(int x, int y) const
+{
+ if (!d || x < 0 || x >= d->width || y < 0 || y >= height()) {
+ qWarning("QImage::pixel: coordinate (%d,%d) out of range", x, y);
+ return 12345;
+ }
+ const uchar * s = scanLine(y);
+ switch(d->format) {
+ case Format_Mono:
+ return d->colortable.at((*(s + (x >> 3)) >> (7- (x & 7))) & 1);
+ case Format_MonoLSB:
+ return d->colortable.at((*(s + (x >> 3)) >> (x & 7)) & 1);
+ case Format_Indexed8:
+ return d->colortable.at((int)s[x]);
+ case Format_ARGB8565_Premultiplied:
+ return qt_colorConvert<quint32, qargb8565>(reinterpret_cast<const qargb8565*>(s)[x], 0);
+ case Format_RGB666:
+ return qt_colorConvert<quint32, qrgb666>(reinterpret_cast<const qrgb666*>(s)[x], 0);
+ case Format_ARGB6666_Premultiplied:
+ return qt_colorConvert<quint32, qargb6666>(reinterpret_cast<const qargb6666*>(s)[x], 0);
+ case Format_RGB555:
+ return qt_colorConvert<quint32, qrgb555>(reinterpret_cast<const qrgb555*>(s)[x], 0);
+ case Format_ARGB8555_Premultiplied:
+ return qt_colorConvert<quint32, qargb8555>(reinterpret_cast<const qargb8555*>(s)[x], 0);
+ case Format_RGB888:
+ return qt_colorConvert<quint32, qrgb888>(reinterpret_cast<const qrgb888*>(s)[x], 0);
+ case Format_RGB444:
+ return qt_colorConvert<quint32, qrgb444>(reinterpret_cast<const qrgb444*>(s)[x], 0);
+ case Format_ARGB4444_Premultiplied:
+ return qt_colorConvert<quint32, qargb4444>(reinterpret_cast<const qargb4444*>(s)[x], 0);
+ case Format_RGB16:
+ return qt_colorConvert<quint32, quint16>(reinterpret_cast<const quint16*>(s)[x], 0);
+ default:
+ return ((QRgb*)s)[x];
+ }
+}
+
+
+/*!
+ \fn void QImage::setPixel(const QPoint &position, uint index_or_rgb)
+
+ Sets the pixel index or color at the given \a position to \a
+ index_or_rgb.
+
+ If the image's format is either monochrome or 8-bit, the given \a
+ index_or_rgb value must be an index in the image's color table,
+ otherwise the parameter must be a QRgb value.
+
+ If \a position is not a valid coordinate pair in the image, or if
+ \a index_or_rgb >= colorCount() in the case of monochrome and
+ 8-bit images, the result is undefined.
+
+ \warning This function is expensive due to the call of the internal
+ \c{detach()} function called within; if performance is a concern, we
+ recommend the use of \l{QImage::}{scanLine()} to access pixel data
+ directly.
+
+ \sa pixel(), {QImage#Pixel Manipulation}{Pixel Manipulation}
+*/
+
+/*!
+ \overload
+
+ Sets the pixel index or color at (\a x, \a y) to \a index_or_rgb.
+*/
+void QImage::setPixel(int x, int y, uint index_or_rgb)
+{
+ if (!d || x < 0 || x >= width() || y < 0 || y >= height()) {
+ qWarning("QImage::setPixel: coordinate (%d,%d) out of range", x, y);
+ return;
+ }
+ // detach is called from within scanLine
+ uchar * s = scanLine(y);
+ const quint32p p = quint32p::fromRawData(index_or_rgb);
+ switch(d->format) {
+ case Format_Mono:
+ case Format_MonoLSB:
+ if (index_or_rgb > 1) {
+ qWarning("QImage::setPixel: Index %d out of range", index_or_rgb);
+ } else if (format() == Format_MonoLSB) {
+ if (index_or_rgb==0)
+ *(s + (x >> 3)) &= ~(1 << (x & 7));
+ else
+ *(s + (x >> 3)) |= (1 << (x & 7));
+ } else {
+ if (index_or_rgb==0)
+ *(s + (x >> 3)) &= ~(1 << (7-(x & 7)));
+ else
+ *(s + (x >> 3)) |= (1 << (7-(x & 7)));
+ }
+ break;
+ case Format_Indexed8:
+ if (index_or_rgb >= (uint)d->colortable.size()) {
+ qWarning("QImage::setPixel: Index %d out of range", index_or_rgb);
+ return;
+ }
+ s[x] = index_or_rgb;
+ break;
+ case Format_RGB32:
+ //make sure alpha is 255, we depend on it in qdrawhelper for cases
+ // when image is set as a texture pattern on a qbrush
+ ((uint *)s)[x] = uint(255 << 24) | index_or_rgb;
+ break;
+ case Format_ARGB32:
+ case Format_ARGB32_Premultiplied:
+ ((uint *)s)[x] = index_or_rgb;
+ break;
+ case Format_RGB16:
+ ((quint16 *)s)[x] = qt_colorConvert<quint16, quint32p>(p, 0);
+ break;
+ case Format_ARGB8565_Premultiplied:
+ ((qargb8565*)s)[x] = qt_colorConvert<qargb8565, quint32p>(p, 0);
+ break;
+ case Format_RGB666:
+ ((qrgb666*)s)[x] = qt_colorConvert<qrgb666, quint32p>(p, 0);
+ break;
+ case Format_ARGB6666_Premultiplied:
+ ((qargb6666*)s)[x] = qt_colorConvert<qargb6666, quint32p>(p, 0);
+ break;
+ case Format_RGB555:
+ ((qrgb555*)s)[x] = qt_colorConvert<qrgb555, quint32p>(p, 0);
+ break;
+ case Format_ARGB8555_Premultiplied:
+ ((qargb8555*)s)[x] = qt_colorConvert<qargb8555, quint32p>(p, 0);
+ break;
+ case Format_RGB888:
+ ((qrgb888*)s)[x] = qt_colorConvert<qrgb888, quint32p>(p, 0);
+ break;
+ case Format_RGB444:
+ ((qrgb444*)s)[x] = qt_colorConvert<qrgb444, quint32p>(p, 0);
+ break;
+ case Format_ARGB4444_Premultiplied:
+ ((qargb4444*)s)[x] = qt_colorConvert<qargb4444, quint32p>(p, 0);
+ break;
+ case Format_Invalid:
+ case NImageFormats:
+ Q_ASSERT(false);
+ }
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ Converts the bit order of the image to the given \a bitOrder and
+ returns the converted image. The original image is not changed.
+ Returns this image if the given \a bitOrder is equal to the image
+ current bit order, or a null image if this image cannot be
+ converted.
+
+ Use convertToFormat() instead.
+*/
+
+QImage QImage::convertBitOrder(Endian bitOrder) const
+{
+ if (!d || isNull() || d->depth != 1 || !(bitOrder == BigEndian || bitOrder == LittleEndian))
+ return QImage();
+
+ if ((d->format == Format_Mono && bitOrder == BigEndian)
+ || (d->format == Format_MonoLSB && bitOrder == LittleEndian))
+ return *this;
+
+ QImage image(d->width, d->height, d->format == Format_Mono ? Format_MonoLSB : Format_Mono);
+
+ const uchar *data = d->data;
+ const uchar *end = data + d->nbytes;
+ uchar *ndata = image.d->data;
+ while (data < end)
+ *ndata++ = bitflip[*data++];
+
+ image.setDotsPerMeterX(dotsPerMeterX());
+ image.setDotsPerMeterY(dotsPerMeterY());
+
+ image.d->colortable = d->colortable;
+ return image;
+}
+#endif
+/*!
+ Returns true if all the colors in the image are shades of gray
+ (i.e. their red, green and blue components are equal); otherwise
+ false.
+
+ Note that this function is slow for images without color table.
+
+ \sa isGrayscale()
+*/
+bool QImage::allGray() const
+{
+ if (!d)
+ return true;
+
+ if (d->depth == 32) {
+ int p = width()*height();
+ const QRgb* b = (const QRgb*)bits();
+ while (p--)
+ if (!qIsGray(*b++))
+ return false;
+ } else if (d->depth == 16) {
+ int p = width()*height();
+ const ushort* b = (const ushort *)bits();
+ while (p--)
+ if (!qIsGray(qt_colorConvert<quint32, quint16>(*b++, 0)))
+ return false;
+ } else if (d->format == QImage::Format_RGB888) {
+ int p = width()*height();
+ const qrgb888* b = (const qrgb888 *)bits();
+ while (p--)
+ if (!qIsGray(qt_colorConvert<quint32, qrgb888>(*b++, 0)))
+ return false;
+ } else {
+ if (d->colortable.isEmpty())
+ return true;
+ for (int i = 0; i < colorCount(); i++)
+ if (!qIsGray(d->colortable.at(i)))
+ return false;
+ }
+ return true;
+}
+
+/*!
+ For 32-bit images, this function is equivalent to allGray().
+
+ For 8-bpp images, this function returns true if color(i) is
+ QRgb(i, i, i) for all indexes of the color table; otherwise
+ returns false.
+
+ \sa allGray(), {QImage#Image Formats}{Image Formats}
+*/
+bool QImage::isGrayscale() const
+{
+ if (!d)
+ return false;
+
+ switch (depth()) {
+ case 32:
+ case 24:
+ case 16:
+ return allGray();
+ case 8: {
+ for (int i = 0; i < colorCount(); i++)
+ if (d->colortable.at(i) != qRgb(i,i,i))
+ return false;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/*!
+ \fn QImage QImage::smoothScale(int width, int height, Qt::AspectRatioMode mode) const
+
+ Use scaled() instead.
+
+ \oldcode
+ QImage image;
+ image.smoothScale(width, height, mode);
+ \newcode
+ QImage image;
+ image.scaled(width, height, mode, Qt::SmoothTransformation);
+ \endcode
+*/
+
+/*!
+ \fn QImage QImage::smoothScale(const QSize &size, Qt::AspectRatioMode mode) const
+ \overload
+
+ Use scaled() instead.
+
+ \oldcode
+ QImage image;
+ image.smoothScale(size, mode);
+ \newcode
+ QImage image;
+ image.scaled(size, mode, Qt::SmoothTransformation);
+ \endcode
+*/
+
+/*!
+ \fn QImage QImage::scaled(int width, int height, Qt::AspectRatioMode aspectRatioMode,
+ Qt::TransformationMode transformMode) const
+ \overload
+
+ Returns a copy of the image scaled to a rectangle with the given
+ \a width and \a height according to the given \a aspectRatioMode
+ and \a transformMode.
+
+ If either the \a width or the \a height is zero or negative, this
+ function returns a null image.
+*/
+
+/*!
+ \fn QImage QImage::scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode,
+ Qt::TransformationMode transformMode) const
+
+ Returns a copy of the image scaled to a rectangle defined by the
+ given \a size according to the given \a aspectRatioMode and \a
+ transformMode.
+
+ \image qimage-scaling.png
+
+ \list
+ \i If \a aspectRatioMode is Qt::IgnoreAspectRatio, the image
+ is scaled to \a size.
+ \i If \a aspectRatioMode is Qt::KeepAspectRatio, the image is
+ scaled to a rectangle as large as possible inside \a size, preserving the aspect ratio.
+ \i If \a aspectRatioMode is Qt::KeepAspectRatioByExpanding,
+ the image is scaled to a rectangle as small as possible
+ outside \a size, preserving the aspect ratio.
+ \endlist
+
+ If the given \a size is empty, this function returns a null image.
+
+ \sa isNull(), {QImage#Image Transformations}{Image
+ Transformations}
+*/
+QImage QImage::scaled(const QSize& s, Qt::AspectRatioMode aspectMode, Qt::TransformationMode mode) const
+{
+ if (!d) {
+ qWarning("QImage::scaled: Image is a null image");
+ return QImage();
+ }
+ if (s.isEmpty())
+ return QImage();
+
+ QSize newSize = size();
+ newSize.scale(s, aspectMode);
+ if (newSize == size())
+ return *this;
+
+ QTransform wm = QTransform::fromScale((qreal)newSize.width() / width(), (qreal)newSize.height() / height());
+ QImage img = transformed(wm, mode);
+ return img;
+}
+
+/*!
+ \fn QImage QImage::scaledToWidth(int width, Qt::TransformationMode mode) const
+
+ Returns a scaled copy of the image. The returned image is scaled
+ to the given \a width using the specified transformation \a
+ mode.
+
+ This function automatically calculates the height of the image so
+ that its aspect ratio is preserved.
+
+ If the given \a width is 0 or negative, a null image is returned.
+
+ \sa {QImage#Image Transformations}{Image Transformations}
+*/
+QImage QImage::scaledToWidth(int w, Qt::TransformationMode mode) const
+{
+ if (!d) {
+ qWarning("QImage::scaleWidth: Image is a null image");
+ return QImage();
+ }
+ if (w <= 0)
+ return QImage();
+
+ qreal factor = (qreal) w / width();
+ QTransform wm = QTransform::fromScale(factor, factor);
+ return transformed(wm, mode);
+}
+
+/*!
+ \fn QImage QImage::scaledToHeight(int height, Qt::TransformationMode mode) const
+
+ Returns a scaled copy of the image. The returned image is scaled
+ to the given \a height using the specified transformation \a
+ mode.
+
+ This function automatically calculates the width of the image so that
+ the ratio of the image is preserved.
+
+ If the given \a height is 0 or negative, a null image is returned.
+
+ \sa {QImage#Image Transformations}{Image Transformations}
+*/
+QImage QImage::scaledToHeight(int h, Qt::TransformationMode mode) const
+{
+ if (!d) {
+ qWarning("QImage::scaleHeight: Image is a null image");
+ return QImage();
+ }
+ if (h <= 0)
+ return QImage();
+
+ qreal factor = (qreal) h / height();
+ QTransform wm = QTransform::fromScale(factor, factor);
+ return transformed(wm, mode);
+}
+
+
+/*!
+ \fn QMatrix QImage::trueMatrix(const QMatrix &matrix, int width, int height)
+
+ Returns the actual matrix used for transforming an image with the
+ given \a width, \a height and \a matrix.
+
+ When transforming an image using the transformed() function, the
+ transformation matrix is internally adjusted to compensate for
+ unwanted translation, i.e. transformed() returns the smallest
+ image containing all transformed points of the original image.
+ This function returns the modified matrix, which maps points
+ correctly from the original image into the new image.
+
+ \sa transformed(), {QImage#Image Transformations}{Image
+ Transformations}
+*/
+QMatrix QImage::trueMatrix(const QMatrix &matrix, int w, int h)
+{
+ return trueMatrix(QTransform(matrix), w, h).toAffine();
+}
+
+/*!
+ Returns a copy of the image that is transformed using the given
+ transformation \a matrix and transformation \a mode.
+
+ The transformation \a matrix is internally adjusted to compensate
+ for unwanted translation; i.e. the image produced is the smallest
+ image that contains all the transformed points of the original
+ image. Use the trueMatrix() function to retrieve the actual matrix
+ used for transforming an image.
+
+ \sa trueMatrix(), {QImage#Image Transformations}{Image
+ Transformations}
+*/
+QImage QImage::transformed(const QMatrix &matrix, Qt::TransformationMode mode) const
+{
+ return transformed(QTransform(matrix), mode);
+}
+
+/*!
+ Builds and returns a 1-bpp mask from the alpha buffer in this
+ image. Returns a null image if the image's format is
+ QImage::Format_RGB32.
+
+ The \a flags argument is a bitwise-OR of the
+ Qt::ImageConversionFlags, and controls the conversion
+ process. Passing 0 for flags sets all the default options.
+
+ The returned image has little-endian bit order (i.e. the image's
+ format is QImage::Format_MonoLSB), which you can convert to
+ big-endian (QImage::Format_Mono) using the convertToFormat()
+ function.
+
+ \sa createHeuristicMask(), {QImage#Image Transformations}{Image
+ Transformations}
+*/
+QImage QImage::createAlphaMask(Qt::ImageConversionFlags flags) const
+{
+ if (!d || d->format == QImage::Format_RGB32)
+ return QImage();
+
+ if (d->depth == 1) {
+ // A monochrome pixmap, with alpha channels on those two colors.
+ // Pretty unlikely, so use less efficient solution.
+ return convertToFormat(Format_Indexed8, flags).createAlphaMask(flags);
+ }
+
+ QImage mask(d->width, d->height, Format_MonoLSB);
+ if (!mask.isNull())
+ dither_to_Mono(mask.d, d, flags, true);
+ return mask;
+}
+
+#ifndef QT_NO_IMAGE_HEURISTIC_MASK
+/*!
+ Creates and returns a 1-bpp heuristic mask for this image.
+
+ The function works by selecting a color from one of the corners,
+ then chipping away pixels of that color starting at all the edges.
+ The four corners vote for which color is to be masked away. In
+ case of a draw (this generally means that this function is not
+ applicable to the image), the result is arbitrary.
+
+ The returned image has little-endian bit order (i.e. the image's
+ format is QImage::Format_MonoLSB), which you can convert to
+ big-endian (QImage::Format_Mono) using the convertToFormat()
+ function.
+
+ If \a clipTight is true (the default) the mask is just large
+ enough to cover the pixels; otherwise, the mask is larger than the
+ data pixels.
+
+ Note that this function disregards the alpha buffer.
+
+ \sa createAlphaMask(), {QImage#Image Transformations}{Image
+ Transformations}
+*/
+
+QImage QImage::createHeuristicMask(bool clipTight) const
+{
+ if (!d)
+ return QImage();
+
+ if (d->depth != 32) {
+ QImage img32 = convertToFormat(Format_RGB32);
+ return img32.createHeuristicMask(clipTight);
+ }
+
+#define PIX(x,y) (*((QRgb*)scanLine(y)+x) & 0x00ffffff)
+
+ int w = width();
+ int h = height();
+ QImage m(w, h, Format_MonoLSB);
+ QIMAGE_SANITYCHECK_MEMORY(m);
+ m.setColorCount(2);
+ m.setColor(0, QColor(Qt::color0).rgba());
+ m.setColor(1, QColor(Qt::color1).rgba());
+ m.fill(0xff);
+
+ QRgb background = PIX(0,0);
+ if (background != PIX(w-1,0) &&
+ background != PIX(0,h-1) &&
+ background != PIX(w-1,h-1)) {
+ background = PIX(w-1,0);
+ if (background != PIX(w-1,h-1) &&
+ background != PIX(0,h-1) &&
+ PIX(0,h-1) == PIX(w-1,h-1)) {
+ background = PIX(w-1,h-1);
+ }
+ }
+
+ int x,y;
+ bool done = false;
+ uchar *ypp, *ypc, *ypn;
+ while(!done) {
+ done = true;
+ ypn = m.scanLine(0);
+ ypc = 0;
+ for (y = 0; y < h; y++) {
+ ypp = ypc;
+ ypc = ypn;
+ ypn = (y == h-1) ? 0 : m.scanLine(y+1);
+ QRgb *p = (QRgb *)scanLine(y);
+ for (x = 0; x < w; x++) {
+ // slowness here - it's possible to do six of these tests
+ // together in one go. oh well.
+ if ((x == 0 || y == 0 || x == w-1 || y == h-1 ||
+ !(*(ypc + ((x-1) >> 3)) & (1 << ((x-1) & 7))) ||
+ !(*(ypc + ((x+1) >> 3)) & (1 << ((x+1) & 7))) ||
+ !(*(ypp + (x >> 3)) & (1 << (x & 7))) ||
+ !(*(ypn + (x >> 3)) & (1 << (x & 7)))) &&
+ ( (*(ypc + (x >> 3)) & (1 << (x & 7)))) &&
+ ((*p & 0x00ffffff) == background)) {
+ done = false;
+ *(ypc + (x >> 3)) &= ~(1 << (x & 7));
+ }
+ p++;
+ }
+ }
+ }
+
+ if (!clipTight) {
+ ypn = m.scanLine(0);
+ ypc = 0;
+ for (y = 0; y < h; y++) {
+ ypp = ypc;
+ ypc = ypn;
+ ypn = (y == h-1) ? 0 : m.scanLine(y+1);
+ QRgb *p = (QRgb *)scanLine(y);
+ for (x = 0; x < w; x++) {
+ if ((*p & 0x00ffffff) != background) {
+ if (x > 0)
+ *(ypc + ((x-1) >> 3)) |= (1 << ((x-1) & 7));
+ if (x < w-1)
+ *(ypc + ((x+1) >> 3)) |= (1 << ((x+1) & 7));
+ if (y > 0)
+ *(ypp + (x >> 3)) |= (1 << (x & 7));
+ if (y < h-1)
+ *(ypn + (x >> 3)) |= (1 << (x & 7));
+ }
+ p++;
+ }
+ }
+ }
+
+#undef PIX
+
+ return m;
+}
+#endif //QT_NO_IMAGE_HEURISTIC_MASK
+
+/*!
+ Creates and returns a mask for this image based on the given \a
+ color value. If the \a mode is MaskInColor (the default value),
+ all pixels matching \a color will be opaque pixels in the mask. If
+ \a mode is MaskOutColor, all pixels matching the given color will
+ be transparent.
+
+ \sa createAlphaMask(), createHeuristicMask()
+*/
+
+QImage QImage::createMaskFromColor(QRgb color, Qt::MaskMode mode) const
+{
+ if (!d)
+ return QImage();
+ QImage maskImage(size(), QImage::Format_MonoLSB);
+ QIMAGE_SANITYCHECK_MEMORY(maskImage);
+ maskImage.fill(0);
+ uchar *s = maskImage.bits();
+
+ if (depth() == 32) {
+ for (int h = 0; h < d->height; h++) {
+ const uint *sl = (uint *) scanLine(h);
+ for (int w = 0; w < d->width; w++) {
+ if (sl[w] == color)
+ *(s + (w >> 3)) |= (1 << (w & 7));
+ }
+ s += maskImage.bytesPerLine();
+ }
+ } else {
+ for (int h = 0; h < d->height; h++) {
+ for (int w = 0; w < d->width; w++) {
+ if ((uint) pixel(w, h) == color)
+ *(s + (w >> 3)) |= (1 << (w & 7));
+ }
+ s += maskImage.bytesPerLine();
+ }
+ }
+ if (mode == Qt::MaskOutColor)
+ maskImage.invertPixels();
+ return maskImage;
+}
+
+
+/*
+ This code is contributed by Philipp Lang,
+ GeneriCom Software Germany (www.generi.com)
+ under the terms of the QPL, Version 1.0
+*/
+
+/*!
+ \fn QImage QImage::mirror(bool horizontal, bool vertical) const
+
+ Use mirrored() instead.
+*/
+
+/*!
+ Returns a mirror of the image, mirrored in the horizontal and/or
+ the vertical direction depending on whether \a horizontal and \a
+ vertical are set to true or false.
+
+ Note that the original image is not changed.
+
+ \sa {QImage#Image Transformations}{Image Transformations}
+*/
+QImage QImage::mirrored(bool horizontal, bool vertical) const
+{
+ if (!d)
+ return QImage();
+
+ if ((d->width <= 1 && d->height <= 1) || (!horizontal && !vertical))
+ return *this;
+
+ int w = d->width;
+ int h = d->height;
+ // Create result image, copy colormap
+ QImage result(d->width, d->height, d->format);
+ QIMAGE_SANITYCHECK_MEMORY(result);
+
+ // check if we ran out of of memory..
+ if (!result.d)
+ return QImage();
+
+ result.d->colortable = d->colortable;
+ result.d->has_alpha_clut = d->has_alpha_clut;
+
+ if (depth() == 1)
+ w = (w+7)/8;
+ int dxi = horizontal ? -1 : 1;
+ int dxs = horizontal ? w-1 : 0;
+ int dyi = vertical ? -1 : 1;
+ int dy = vertical ? h-1: 0;
+
+ // 1 bit, 8 bit
+ if (d->depth == 1 || d->depth == 8) {
+ for (int sy = 0; sy < h; sy++, dy += dyi) {
+ quint8* ssl = (quint8*)(d->data + sy*d->bytes_per_line);
+ quint8* dsl = (quint8*)(result.d->data + dy*result.d->bytes_per_line);
+ int dx = dxs;
+ for (int sx = 0; sx < w; sx++, dx += dxi)
+ dsl[dx] = ssl[sx];
+ }
+ }
+ // 16 bit
+ else if (d->depth == 16) {
+ for (int sy = 0; sy < h; sy++, dy += dyi) {
+ quint16* ssl = (quint16*)(d->data + sy*d->bytes_per_line);
+ quint16* dsl = (quint16*)(result.d->data + dy*result.d->bytes_per_line);
+ int dx = dxs;
+ for (int sx = 0; sx < w; sx++, dx += dxi)
+ dsl[dx] = ssl[sx];
+ }
+ }
+ // 24 bit
+ else if (d->depth == 24) {
+ for (int sy = 0; sy < h; sy++, dy += dyi) {
+ quint24* ssl = (quint24*)(d->data + sy*d->bytes_per_line);
+ quint24* dsl = (quint24*)(result.d->data + dy*result.d->bytes_per_line);
+ int dx = dxs;
+ for (int sx = 0; sx < w; sx++, dx += dxi)
+ dsl[dx] = ssl[sx];
+ }
+ }
+ // 32 bit
+ else if (d->depth == 32) {
+ for (int sy = 0; sy < h; sy++, dy += dyi) {
+ quint32* ssl = (quint32*)(d->data + sy*d->bytes_per_line);
+ quint32* dsl = (quint32*)(result.d->data + dy*result.d->bytes_per_line);
+ int dx = dxs;
+ for (int sx = 0; sx < w; sx++, dx += dxi)
+ dsl[dx] = ssl[sx];
+ }
+ }
+
+ // special handling of 1 bit images for horizontal mirroring
+ if (horizontal && d->depth == 1) {
+ int shift = width() % 8;
+ for (int y = h-1; y >= 0; y--) {
+ quint8* a0 = (quint8*)(result.d->data + y*d->bytes_per_line);
+ // Swap bytes
+ quint8* a = a0+dxs;
+ while (a >= a0) {
+ *a = bitflip[*a];
+ a--;
+ }
+ // Shift bits if unaligned
+ if (shift != 0) {
+ a = a0+dxs;
+ quint8 c = 0;
+ if (format() == Format_MonoLSB) {
+ while (a >= a0) {
+ quint8 nc = *a << shift;
+ *a = (*a >> (8-shift)) | c;
+ --a;
+ c = nc;
+ }
+ } else {
+ while (a >= a0) {
+ quint8 nc = *a >> shift;
+ *a = (*a << (8-shift)) | c;
+ --a;
+ c = nc;
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/*!
+ \fn QImage QImage::swapRGB() const
+
+ Use rgbSwapped() instead.
+
+ \omit
+ Returns a QImage in which the values of the red and blue
+ components of all pixels have been swapped, effectively converting
+ an RGB image to an BGR image. The original QImage is not changed.
+ \endomit
+*/
+
+/*!
+ Returns a QImage in which the values of the red and blue
+ components of all pixels have been swapped, effectively converting
+ an RGB image to an BGR image.
+
+ The original QImage is not changed.
+
+ \sa {QImage#Image Transformations}{Image Transformations}
+*/
+QImage QImage::rgbSwapped() const
+{
+ if (isNull())
+ return *this;
+ QImage res;
+ switch (d->format) {
+ case Format_Invalid:
+ case NImageFormats:
+ Q_ASSERT(false);
+ break;
+ case Format_Mono:
+ case Format_MonoLSB:
+ case Format_Indexed8:
+ res = copy();
+ for (int i = 0; i < res.d->colortable.size(); i++) {
+ QRgb c = res.d->colortable.at(i);
+ res.d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00));
+ }
+ break;
+ case Format_RGB32:
+ case Format_ARGB32:
+ case Format_ARGB32_Premultiplied:
+ res = QImage(d->width, d->height, d->format);
+ QIMAGE_SANITYCHECK_MEMORY(res);
+ for (int i = 0; i < d->height; i++) {
+ uint *q = (uint*)res.scanLine(i);
+ uint *p = (uint*)constScanLine(i);
+ uint *end = p + d->width;
+ while (p < end) {
+ *q = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00);
+ p++;
+ q++;
+ }
+ }
+ break;
+ case Format_RGB16:
+ res = QImage(d->width, d->height, d->format);
+ QIMAGE_SANITYCHECK_MEMORY(res);
+ for (int i = 0; i < d->height; i++) {
+ ushort *q = (ushort*)res.scanLine(i);
+ const ushort *p = (const ushort*)constScanLine(i);
+ const ushort *end = p + d->width;
+ while (p < end) {
+ *q = ((*p << 11) & 0xf800) | ((*p >> 11) & 0x1f) | (*p & 0x07e0);
+ p++;
+ q++;
+ }
+ }
+ break;
+ case Format_ARGB8565_Premultiplied:
+ res = QImage(d->width, d->height, d->format);
+ QIMAGE_SANITYCHECK_MEMORY(res);
+ for (int i = 0; i < d->height; i++) {
+ const quint8 *p = constScanLine(i);
+ quint8 *q = res.scanLine(i);
+ const quint8 *end = p + d->width * sizeof(qargb8565);
+ while (p < end) {
+ q[0] = p[0];
+ q[1] = (p[1] & 0xe0) | (p[2] >> 3);
+ q[2] = (p[2] & 0x07) | (p[1] << 3);
+ p += sizeof(qargb8565);
+ q += sizeof(qargb8565);
+ }
+ }
+ break;
+ case Format_RGB666:
+ res = QImage(d->width, d->height, d->format);
+ QIMAGE_SANITYCHECK_MEMORY(res);
+ for (int i = 0; i < d->height; i++) {
+ qrgb666 *q = reinterpret_cast<qrgb666*>(res.scanLine(i));
+ const qrgb666 *p = reinterpret_cast<const qrgb666*>(constScanLine(i));
+ const qrgb666 *end = p + d->width;
+ while (p < end) {
+ const QRgb rgb = quint32(*p++);
+ *q++ = qRgb(qBlue(rgb), qGreen(rgb), qRed(rgb));
+ }
+ }
+ break;
+ case Format_ARGB6666_Premultiplied:
+ res = QImage(d->width, d->height, d->format);
+ QIMAGE_SANITYCHECK_MEMORY(res);
+ for (int i = 0; i < d->height; i++) {
+ const quint8 *p = constScanLine(i);
+ const quint8 *end = p + d->width * sizeof(qargb6666);
+ quint8 *q = res.scanLine(i);
+ while (p < end) {
+ q[0] = (p[1] >> 4) | ((p[2] & 0x3) << 4) | (p[0] & 0xc0);
+ q[1] = (p[1] & 0xf) | (p[0] << 4);
+ q[2] = (p[2] & 0xfc) | ((p[0] >> 4) & 0x3);
+ p += sizeof(qargb6666);
+ q += sizeof(qargb6666);
+ }
+ }
+ break;
+ case Format_RGB555:
+ res = QImage(d->width, d->height, d->format);
+ QIMAGE_SANITYCHECK_MEMORY(res);
+ for (int i = 0; i < d->height; i++) {
+ quint16 *q = (quint16*)res.scanLine(i);
+ const quint16 *p = (const quint16*)constScanLine(i);
+ const quint16 *end = p + d->width;
+ while (p < end) {
+ *q = ((*p << 10) & 0x7c00) | ((*p >> 10) & 0x1f) | (*p & 0x3e0);
+ p++;
+ q++;
+ }
+ }
+ break;
+ case Format_ARGB8555_Premultiplied:
+ res = QImage(d->width, d->height, d->format);
+ QIMAGE_SANITYCHECK_MEMORY(res);
+ for (int i = 0; i < d->height; i++) {
+ const quint8 *p = constScanLine(i);
+ quint8 *q = res.scanLine(i);
+ const quint8 *end = p + d->width * sizeof(qargb8555);
+ while (p < end) {
+ q[0] = p[0];
+ q[1] = (p[1] & 0xe0) | (p[2] >> 2);
+ q[2] = (p[2] & 0x03) | ((p[1] << 2) & 0x7f);
+ p += sizeof(qargb8555);
+ q += sizeof(qargb8555);
+ }
+ }
+ break;
+ case Format_RGB888:
+ res = QImage(d->width, d->height, d->format);
+ QIMAGE_SANITYCHECK_MEMORY(res);
+ for (int i = 0; i < d->height; i++) {
+ quint8 *q = res.scanLine(i);
+ const quint8 *p = constScanLine(i);
+ const quint8 *end = p + d->width * sizeof(qrgb888);
+ while (p < end) {
+ q[0] = p[2];
+ q[1] = p[1];
+ q[2] = p[0];
+ q += sizeof(qrgb888);
+ p += sizeof(qrgb888);
+ }
+ }
+ break;
+ case Format_RGB444:
+ case Format_ARGB4444_Premultiplied:
+ res = QImage(d->width, d->height, d->format);
+ QIMAGE_SANITYCHECK_MEMORY(res);
+ for (int i = 0; i < d->height; i++) {
+ quint16 *q = reinterpret_cast<quint16*>(res.scanLine(i));
+ const quint16 *p = reinterpret_cast<const quint16*>(constScanLine(i));
+ const quint16 *end = p + d->width;
+ while (p < end) {
+ *q = (*p & 0xf0f0) | ((*p & 0x0f) << 8) | ((*p & 0xf00) >> 8);
+ p++;
+ q++;
+ }
+ }
+ break;
+ }
+ return res;
+}
+
+/*!
+ Loads an image from the file with the given \a fileName. Returns true if
+ the image was successfully loaded; otherwise returns false.
+
+ The loader attempts to read the image using the specified \a format, e.g.,
+ PNG or JPG. If \a format is not specified (which is the default), the
+ loader probes the file for a header to guess the file format.
+
+ The file name can either refer to an actual file on disk or to one
+ of the application's embedded resources. See the
+ \l{resources.html}{Resource System} overview for details on how to
+ embed images and other resource files in the application's
+ executable.
+
+ \sa {QImage#Reading and Writing Image Files}{Reading and Writing Image Files}
+*/
+
+bool QImage::load(const QString &fileName, const char* format)
+{
+ if (fileName.isEmpty())
+ return false;
+
+ QImage image = QImageReader(fileName, format).read();
+ if (!image.isNull()) {
+ operator=(image);
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \overload
+
+ This function reads a QImage from the given \a device. This can,
+ for example, be used to load an image directly into a QByteArray.
+*/
+
+bool QImage::load(QIODevice* device, const char* format)
+{
+ QImage image = QImageReader(device, format).read();
+ if(!image.isNull()) {
+ operator=(image);
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \fn bool QImage::loadFromData(const uchar *data, int len, const char *format)
+
+ Loads an image from the first \a len bytes of the given binary \a
+ data. Returns true if the image was successfully loaded; otherwise
+ returns false.
+
+ The loader attempts to read the image using the specified \a format, e.g.,
+ PNG or JPG. If \a format is not specified (which is the default), the
+ loader probes the file for a header to guess the file format.
+
+ \sa {QImage#Reading and Writing Image Files}{Reading and Writing Image Files}
+*/
+
+bool QImage::loadFromData(const uchar *data, int len, const char *format)
+{
+ QImage image = fromData(data, len, format);
+ if (!image.isNull()) {
+ operator=(image);
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \fn bool QImage::loadFromData(const QByteArray &data, const char *format)
+
+ \overload
+
+ Loads an image from the given QByteArray \a data.
+*/
+
+/*!
+ \fn QImage QImage::fromData(const uchar *data, int size, const char *format)
+
+ Constructs a QImage from the first \a size bytes of the given
+ binary \a data. The loader attempts to read the image using the
+ specified \a format. If \a format is not specified (which is the default),
+ the loader probes the file for a header to guess the file format.
+ binary \a data. The loader attempts to read the image, either using the
+ optional image \a format specified or by determining the image format from
+ the data.
+
+ If \a format is not specified (which is the default), the loader probes the
+ file for a header to determine the file format. If \a format is specified,
+ it must be one of the values returned by QImageReader::supportedImageFormats().
+
+ If the loading of the image fails, the image returned will be a null image.
+
+ \sa load(), save(), {QImage#Reading and Writing Image Files}{Reading and Writing Image Files}
+ */
+
+QImage QImage::fromData(const uchar *data, int size, const char *format)
+{
+ QByteArray a = QByteArray::fromRawData(reinterpret_cast<const char *>(data), size);
+ QBuffer b;
+ b.setData(a);
+ b.open(QIODevice::ReadOnly);
+ return QImageReader(&b, format).read();
+}
+
+/*!
+ \fn QImage QImage::fromData(const QByteArray &data, const char *format)
+
+ \overload
+
+ Loads an image from the given QByteArray \a data.
+*/
+
+/*!
+ Saves the image to the file with the given \a fileName, using the
+ given image file \a format and \a quality factor. If \a format is
+ 0, QImage will attempt to guess the format by looking at \a fileName's
+ suffix.
+
+ The \a quality factor must be in the range 0 to 100 or -1. Specify
+ 0 to obtain small compressed files, 100 for large uncompressed
+ files, and -1 (the default) to use the default settings.
+
+ Returns true if the image was successfully saved; otherwise
+ returns false.
+
+ \sa {QImage#Reading and Writing Image Files}{Reading and Writing
+ Image Files}
+*/
+bool QImage::save(const QString &fileName, const char *format, int quality) const
+{
+ if (isNull())
+ return false;
+ QImageWriter writer(fileName, format);
+ return d->doImageIO(this, &writer, quality);
+}
+
+/*!
+ \overload
+
+ This function writes a QImage to the given \a device.
+
+ This can, for example, be used to save an image directly into a
+ QByteArray:
+
+ \snippet doc/src/snippets/image/image.cpp 0
+*/
+
+bool QImage::save(QIODevice* device, const char* format, int quality) const
+{
+ if (isNull())
+ return false; // nothing to save
+ QImageWriter writer(device, format);
+ return d->doImageIO(this, &writer, quality);
+}
+
+/* \internal
+*/
+
+bool QImageData::doImageIO(const QImage *image, QImageWriter *writer, int quality) const
+{
+ if (quality > 100 || quality < -1)
+ qWarning("QPixmap::save: Quality out of range [-1, 100]");
+ if (quality >= 0)
+ writer->setQuality(qMin(quality,100));
+ return writer->write(*image);
+}
+
+/*****************************************************************************
+ QImage stream functions
+ *****************************************************************************/
+#if !defined(QT_NO_DATASTREAM)
+/*!
+ \fn QDataStream &operator<<(QDataStream &stream, const QImage &image)
+ \relates QImage
+
+ Writes the given \a image to the given \a stream as a PNG image,
+ or as a BMP image if the stream's version is 1. Note that writing
+ the stream to a file will not produce a valid image file.
+
+ \sa QImage::save(), {Serializing Qt Data Types}
+*/
+
+QDataStream &operator<<(QDataStream &s, const QImage &image)
+{
+ if (s.version() >= 5) {
+ if (image.isNull()) {
+ s << (qint32) 0; // null image marker
+ return s;
+ } else {
+ s << (qint32) 1;
+ // continue ...
+ }
+ }
+ QImageWriter writer(s.device(), s.version() == 1 ? "bmp" : "png");
+ writer.write(image);
+ return s;
+}
+
+/*!
+ \fn QDataStream &operator>>(QDataStream &stream, QImage &image)
+ \relates QImage
+
+ Reads an image from the given \a stream and stores it in the given
+ \a image.
+
+ \sa QImage::load(), {Serializing Qt Data Types}
+*/
+
+QDataStream &operator>>(QDataStream &s, QImage &image)
+{
+ if (s.version() >= 5) {
+ qint32 nullMarker;
+ s >> nullMarker;
+ if (!nullMarker) {
+ image = QImage(); // null image
+ return s;
+ }
+ }
+ image = QImageReader(s.device(), 0).read();
+ return s;
+}
+#endif // QT_NO_DATASTREAM
+
+
+#ifdef QT3_SUPPORT
+/*!
+ \fn QImage QImage::convertDepthWithPalette(int depth, QRgb* palette, int palette_count, Qt::ImageConversionFlags flags) const
+
+ Returns an image with the given \a depth, using the \a
+ palette_count colors pointed to by \a palette. If \a depth is 1 or
+ 8, the returned image will have its color table ordered in the
+ same way as \a palette.
+
+ If the image needs to be modified to fit in a lower-resolution
+ result (e.g. converting from 32-bit to 8-bit), use the \a flags to
+ specify how you'd prefer this to happen.
+
+ Note: currently no closest-color search is made. If colors are
+ found that are not in the palette, the palette may not be used at
+ all. This result should not be considered valid because it may
+ change in future implementations.
+
+ Currently inefficient for non-32-bit images.
+
+ Use the convertToFormat() function in combination with the
+ setColorTable() function instead.
+*/
+QImage QImage::convertDepthWithPalette(int d, QRgb* palette, int palette_count, Qt::ImageConversionFlags flags) const
+{
+ Format f = formatFor(d, QImage::LittleEndian);
+ QVector<QRgb> colortable;
+ for (int i = 0; i < palette_count; ++i)
+ colortable.append(palette[i]);
+ return convertToFormat(f, colortable, flags);
+}
+
+/*!
+ \relates QImage
+
+ Copies a block of pixels from \a src to \a dst. The pixels
+ copied from source (src) are converted according to
+ \a flags if it is incompatible with the destination
+ (\a dst).
+
+ \a sx, \a sy is the top-left pixel in \a src, \a dx, \a dy is the
+ top-left position in \a dst and \a sw, \a sh is the size of the
+ copied block. The copying is clipped if areas outside \a src or \a
+ dst are specified. If \a sw is -1, it is adjusted to
+ src->width(). Similarly, if \a sh is -1, it is adjusted to
+ src->height().
+
+ Currently inefficient for non 32-bit images.
+
+ Use copy() or QPainter::drawImage() instead.
+*/
+void bitBlt(QImage *dst, int dx, int dy, const QImage *src, int sx, int sy, int sw, int sh,
+ Qt::ImageConversionFlags flags)
+{
+ if (dst->isNull() || src->isNull())
+ return;
+ QPainter p(dst);
+ p.drawImage(QPoint(dx, dy), *src, QRect(sx, sy, sw, sh), flags);
+}
+#endif
+
+/*!
+ \fn bool QImage::operator==(const QImage & image) const
+
+ Returns true if this image and the given \a image have the same
+ contents; otherwise returns false.
+
+ The comparison can be slow, unless there is some obvious
+ difference (e.g. different size or format), in which case the
+ function will return quickly.
+
+ \sa operator=()
+*/
+
+bool QImage::operator==(const QImage & i) const
+{
+ // same object, or shared?
+ if (i.d == d)
+ return true;
+ if (!i.d || !d)
+ return false;
+
+ // obviously different stuff?
+ if (i.d->height != d->height || i.d->width != d->width || i.d->format != d->format)
+ return false;
+
+ if (d->format != Format_RGB32) {
+ if (d->format >= Format_ARGB32) { // all bits defined
+ const int n = d->width * d->depth / 8;
+ if (n == d->bytes_per_line && n == i.d->bytes_per_line) {
+ if (memcmp(bits(), i.bits(), d->nbytes))
+ return false;
+ } else {
+ for (int y = 0; y < d->height; ++y) {
+ if (memcmp(scanLine(y), i.scanLine(y), n))
+ return false;
+ }
+ }
+ } else {
+ const int w = width();
+ const int h = height();
+ const QVector<QRgb> &colortable = d->colortable;
+ const QVector<QRgb> &icolortable = i.d->colortable;
+ for (int y=0; y<h; ++y) {
+ for (int x=0; x<w; ++x) {
+ if (colortable[pixelIndex(x, y)] != icolortable[i.pixelIndex(x, y)])
+ return false;
+ }
+ }
+ }
+ } else {
+ //alpha channel undefined, so we must mask it out
+ for(int l = 0; l < d->height; l++) {
+ int w = d->width;
+ const uint *p1 = reinterpret_cast<const uint*>(scanLine(l));
+ const uint *p2 = reinterpret_cast<const uint*>(i.scanLine(l));
+ while (w--) {
+ if ((*p1++ & 0x00ffffff) != (*p2++ & 0x00ffffff))
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+
+/*!
+ \fn bool QImage::operator!=(const QImage & image) const
+
+ Returns true if this image and the given \a image have different
+ contents; otherwise returns false.
+
+ The comparison can be slow, unless there is some obvious
+ difference, such as different widths, in which case the function
+ will return quickly.
+
+ \sa operator=()
+*/
+
+bool QImage::operator!=(const QImage & i) const
+{
+ return !(*this == i);
+}
+
+
+
+
+/*!
+ Returns the number of pixels that fit horizontally in a physical
+ meter. Together with dotsPerMeterY(), this number defines the
+ intended scale and aspect ratio of the image.
+
+ \sa setDotsPerMeterX(), {QImage#Image Information}{Image
+ Information}
+*/
+int QImage::dotsPerMeterX() const
+{
+ return d ? qRound(d->dpmx) : 0;
+}
+
+/*!
+ Returns the number of pixels that fit vertically in a physical
+ meter. Together with dotsPerMeterX(), this number defines the
+ intended scale and aspect ratio of the image.
+
+ \sa setDotsPerMeterY(), {QImage#Image Information}{Image
+ Information}
+*/
+int QImage::dotsPerMeterY() const
+{
+ return d ? qRound(d->dpmy) : 0;
+}
+
+/*!
+ Sets the number of pixels that fit horizontally in a physical
+ meter, to \a x.
+
+ Together with dotsPerMeterY(), this number defines the intended
+ scale and aspect ratio of the image, and determines the scale
+ at which QPainter will draw graphics on the image. It does not
+ change the scale or aspect ratio of the image when it is rendered
+ on other paint devices.
+
+ \sa dotsPerMeterX(), {QImage#Image Information}{Image Information}
+*/
+void QImage::setDotsPerMeterX(int x)
+{
+ if (!d || !x)
+ return;
+ detach();
+
+ if (d)
+ d->dpmx = x;
+}
+
+/*!
+ Sets the number of pixels that fit vertically in a physical meter,
+ to \a y.
+
+ Together with dotsPerMeterX(), this number defines the intended
+ scale and aspect ratio of the image, and determines the scale
+ at which QPainter will draw graphics on the image. It does not
+ change the scale or aspect ratio of the image when it is rendered
+ on other paint devices.
+
+ \sa dotsPerMeterY(), {QImage#Image Information}{Image Information}
+*/
+void QImage::setDotsPerMeterY(int y)
+{
+ if (!d || !y)
+ return;
+ detach();
+
+ if (d)
+ d->dpmy = y;
+}
+
+/*!
+ \fn QPoint QImage::offset() const
+
+ Returns the number of pixels by which the image is intended to be
+ offset by when positioning relative to other images.
+
+ \sa setOffset(), {QImage#Image Information}{Image Information}
+*/
+QPoint QImage::offset() const
+{
+ return d ? d->offset : QPoint();
+}
+
+
+/*!
+ \fn void QImage::setOffset(const QPoint& offset)
+
+ Sets the number of pixels by which the image is intended to be
+ offset by when positioning relative to other images, to \a offset.
+
+ \sa offset(), {QImage#Image Information}{Image Information}
+*/
+void QImage::setOffset(const QPoint& p)
+{
+ if (!d)
+ return;
+ detach();
+
+ if (d)
+ d->offset = p;
+}
+#ifndef QT_NO_IMAGE_TEXT
+
+/*!
+ Returns the text keys for this image.
+
+ You can use these keys with text() to list the image text for a
+ certain key.
+
+ \sa text()
+*/
+QStringList QImage::textKeys() const
+{
+ return d ? QStringList(d->text.keys()) : QStringList();
+}
+
+/*!
+ Returns the image text associated with the given \a key. If the
+ specified \a key is an empty string, the whole image text is
+ returned, with each key-text pair separated by a newline.
+
+ \sa setText(), textKeys()
+*/
+QString QImage::text(const QString &key) const
+{
+ if (!d)
+ return QString();
+
+ if (!key.isEmpty())
+ return d->text.value(key);
+
+ QString tmp;
+ foreach (const QString &key, d->text.keys()) {
+ if (!tmp.isEmpty())
+ tmp += QLatin1String("\n\n");
+ tmp += key + QLatin1String(": ") + d->text.value(key).simplified();
+ }
+ return tmp;
+}
+
+/*!
+ \fn void QImage::setText(const QString &key, const QString &text)
+
+ Sets the image text to the given \a text and associate it with the
+ given \a key.
+
+ If you just want to store a single text block (i.e., a "comment"
+ or just a description), you can either pass an empty key, or use a
+ generic key like "Description".
+
+ The image text is embedded into the image data when you
+ call save() or QImageWriter::write().
+
+ Not all image formats support embedded text. You can find out
+ if a specific image or format supports embedding text
+ by using QImageWriter::supportsOption(). We give an example:
+
+ \snippet doc/src/snippets/image/supportedformat.cpp 0
+
+ You can use QImageWriter::supportedImageFormats() to find out
+ which image formats are available to you.
+
+ \sa text(), textKeys()
+*/
+void QImage::setText(const QString &key, const QString &value)
+{
+ if (!d)
+ return;
+ detach();
+
+ if (d)
+ d->text.insert(key, value);
+}
+
+/*!
+ \fn QString QImage::text(const char* key, const char* language) const
+ \obsolete
+
+ Returns the text recorded for the given \a key in the given \a
+ language, or in a default language if \a language is 0.
+
+ Use text() instead.
+
+ The language the text is recorded in is no longer relevant since
+ the text is always set using QString and UTF-8 representation.
+*/
+QString QImage::text(const char* key, const char* lang) const
+{
+ if (!d)
+ return QString();
+ QString k = QString::fromAscii(key);
+ if (lang && *lang)
+ k += QLatin1Char('/') + QString::fromAscii(lang);
+ return d->text.value(k);
+}
+
+/*!
+ \fn QString QImage::text(const QImageTextKeyLang& keywordAndLanguage) const
+ \overload
+ \obsolete
+
+ Returns the text recorded for the given \a keywordAndLanguage.
+
+ Use text() instead.
+
+ The language the text is recorded in is no longer relevant since
+ the text is always set using QString and UTF-8 representation.
+*/
+QString QImage::text(const QImageTextKeyLang& kl) const
+{
+ if (!d)
+ return QString();
+ QString k = QString::fromAscii(kl.key);
+ if (!kl.lang.isEmpty())
+ k += QLatin1Char('/') + QString::fromAscii(kl.lang);
+ return d->text.value(k);
+}
+
+/*!
+ \obsolete
+
+ Returns the language identifiers for which some texts are
+ recorded. Note that if you want to iterate over the list, you
+ should iterate over a copy.
+
+ The language the text is recorded in is no longer relevant since
+ the text is always set using QString and UTF-8 representation.
+*/
+QStringList QImage::textLanguages() const
+{
+ if (!d)
+ return QStringList();
+ QStringList keys = textKeys();
+ QStringList languages;
+ for (int i = 0; i < keys.size(); ++i) {
+ int index = keys.at(i).indexOf(QLatin1Char('/'));
+ if (index > 0)
+ languages += keys.at(i).mid(index+1);
+ }
+
+ return languages;
+}
+
+/*!
+ \obsolete
+
+ Returns a list of QImageTextKeyLang objects that enumerate all the
+ texts key/language pairs set for this image.
+
+ Use textKeys() instead.
+
+ The language the text is recorded in is no longer relevant since
+ the text is always set using QString and UTF-8 representation.
+*/
+QList<QImageTextKeyLang> QImage::textList() const
+{
+ QList<QImageTextKeyLang> imageTextKeys;
+ if (!d)
+ return imageTextKeys;
+ QStringList keys = textKeys();
+ for (int i = 0; i < keys.size(); ++i) {
+ int index = keys.at(i).indexOf(QLatin1Char('/'));
+ if (index > 0) {
+ QImageTextKeyLang tkl;
+ tkl.key = keys.at(i).left(index).toAscii();
+ tkl.lang = keys.at(i).mid(index+1).toAscii();
+ imageTextKeys += tkl;
+ }
+ }
+
+ return imageTextKeys;
+}
+
+/*!
+ \fn void QImage::setText(const char* key, const char* language, const QString& text)
+ \obsolete
+
+ Sets the image text to the given \a text and associate it with the
+ given \a key. The text is recorded in the specified \a language,
+ or in a default language if \a language is 0.
+
+ Use setText() instead.
+
+ The language the text is recorded in is no longer relevant since
+ the text is always set using QString and UTF-8 representation.
+
+ \omit
+ Records string \a for the keyword \a key. The \a key should be
+ a portable keyword recognizable by other software - some suggested
+ values can be found in
+ \l{http://www.libpng.org/pub/png/spec/1.2/png-1.2-pdg.html#C.Anc-text}
+ {the PNG specification}. \a s can be any text. \a lang should
+ specify the language code (see
+ \l{http://www.rfc-editor.org/rfc/rfc1766.txt}{RFC 1766}) or 0.
+ \endomit
+*/
+void QImage::setText(const char* key, const char* lang, const QString& s)
+{
+ if (!d)
+ return;
+ detach();
+
+ // In case detach() ran out of memory
+ if (!d)
+ return;
+
+ QString k = QString::fromAscii(key);
+ if (lang && *lang)
+ k += QLatin1Char('/') + QString::fromAscii(lang);
+ d->text.insert(k, s);
+}
+
+#endif // QT_NO_IMAGE_TEXT
+
+/*
+ Sets the image bits to the \a pixmap contents and returns a
+ reference to the image.
+
+ If the image shares data with other images, it will first
+ dereference the shared data.
+
+ Makes a call to QPixmap::convertToImage().
+*/
+
+/*! \fn QImage::Endian QImage::systemBitOrder()
+
+ Determines the bit order of the display hardware. Returns
+ QImage::LittleEndian (LSB first) or QImage::BigEndian (MSB first).
+
+ This function is no longer relevant for QImage. Use QSysInfo
+ instead.
+*/
+
+
+/*!
+ \internal
+
+ Used by QPainter to retrieve a paint engine for the image.
+*/
+
+QPaintEngine *QImage::paintEngine() const
+{
+ if (!d)
+ return 0;
+
+ if (!d->paintEngine) {
+ d->paintEngine = new QRasterPaintEngine(const_cast<QImage *>(this));
+ }
+
+ return d->paintEngine;
+}
+
+
+/*!
+ \internal
+
+ Returns the size for the specified \a metric on the device.
+*/
+int QImage::metric(PaintDeviceMetric metric) const
+{
+ if (!d)
+ return 0;
+
+ switch (metric) {
+ case PdmWidth:
+ return d->width;
+ break;
+
+ case PdmHeight:
+ return d->height;
+ break;
+
+ case PdmWidthMM:
+ return qRound(d->width * 1000 / d->dpmx);
+ break;
+
+ case PdmHeightMM:
+ return qRound(d->height * 1000 / d->dpmy);
+ break;
+
+ case PdmNumColors:
+ return d->colortable.size();
+ break;
+
+ case PdmDepth:
+ return d->depth;
+ break;
+
+ case PdmDpiX:
+ return qRound(d->dpmx * 0.0254);
+ break;
+
+ case PdmDpiY:
+ return qRound(d->dpmy * 0.0254);
+ break;
+
+ case PdmPhysicalDpiX:
+ return qRound(d->dpmx * 0.0254);
+ break;
+
+ case PdmPhysicalDpiY:
+ return qRound(d->dpmy * 0.0254);
+ break;
+
+ default:
+ qWarning("QImage::metric(): Unhandled metric type %d", metric);
+ break;
+ }
+ return 0;
+}
+
+
+
+/*****************************************************************************
+ QPixmap (and QImage) helper functions
+ *****************************************************************************/
+/*
+ This internal function contains the common (i.e. platform independent) code
+ to do a transformation of pixel data. It is used by QPixmap::transform() and by
+ QImage::transform().
+
+ \a trueMat is the true transformation matrix (see QPixmap::trueMatrix()) and
+ \a xoffset is an offset to the matrix.
+
+ \a msbfirst specifies for 1bpp images, if the MSB or LSB comes first and \a
+ depth specifies the colordepth of the data.
+
+ \a dptr is a pointer to the destination data, \a dbpl specifies the bits per
+ line for the destination data, \a p_inc is the offset that we advance for
+ every scanline and \a dHeight is the height of the destination image.
+
+ \a sprt is the pointer to the source data, \a sbpl specifies the bits per
+ line of the source data, \a sWidth and \a sHeight are the width and height of
+ the source data.
+*/
+
+#undef IWX_MSB
+#define IWX_MSB(b) if (trigx < maxws && trigy < maxhs) { \
+ if (*(sptr+sbpl*(trigy>>12)+(trigx>>15)) & \
+ (1 << (7-((trigx>>12)&7)))) \
+ *dptr |= b; \
+ } \
+ trigx += m11; \
+ trigy += m12;
+ // END OF MACRO
+#undef IWX_LSB
+#define IWX_LSB(b) if (trigx < maxws && trigy < maxhs) { \
+ if (*(sptr+sbpl*(trigy>>12)+(trigx>>15)) & \
+ (1 << ((trigx>>12)&7))) \
+ *dptr |= b; \
+ } \
+ trigx += m11; \
+ trigy += m12;
+ // END OF MACRO
+#undef IWX_PIX
+#define IWX_PIX(b) if (trigx < maxws && trigy < maxhs) { \
+ if ((*(sptr+sbpl*(trigy>>12)+(trigx>>15)) & \
+ (1 << (7-((trigx>>12)&7)))) == 0) \
+ *dptr &= ~b; \
+ } \
+ trigx += m11; \
+ trigy += m12;
+ // END OF MACRO
+bool qt_xForm_helper(const QTransform &trueMat, int xoffset, int type, int depth,
+ uchar *dptr, int dbpl, int p_inc, int dHeight,
+ const uchar *sptr, int sbpl, int sWidth, int sHeight)
+{
+ int m11 = int(trueMat.m11()*4096.0);
+ int m12 = int(trueMat.m12()*4096.0);
+ int m21 = int(trueMat.m21()*4096.0);
+ int m22 = int(trueMat.m22()*4096.0);
+ int dx = qRound(trueMat.dx()*4096.0);
+ int dy = qRound(trueMat.dy()*4096.0);
+
+ int m21ydx = dx + (xoffset<<16) + (m11 + m21) / 2;
+ int m22ydy = dy + (m12 + m22) / 2;
+ uint trigx;
+ uint trigy;
+ uint maxws = sWidth<<12;
+ uint maxhs = sHeight<<12;
+
+ for (int y=0; y<dHeight; y++) { // for each target scanline
+ trigx = m21ydx;
+ trigy = m22ydy;
+ uchar *maxp = dptr + dbpl;
+ if (depth != 1) {
+ switch (depth) {
+ case 8: // 8 bpp transform
+ while (dptr < maxp) {
+ if (trigx < maxws && trigy < maxhs)
+ *dptr = *(sptr+sbpl*(trigy>>12)+(trigx>>12));
+ trigx += m11;
+ trigy += m12;
+ dptr++;
+ }
+ break;
+
+ case 16: // 16 bpp transform
+ while (dptr < maxp) {
+ if (trigx < maxws && trigy < maxhs)
+ *((ushort*)dptr) = *((ushort *)(sptr+sbpl*(trigy>>12) +
+ ((trigx>>12)<<1)));
+ trigx += m11;
+ trigy += m12;
+ dptr++;
+ dptr++;
+ }
+ break;
+
+ case 24: // 24 bpp transform
+ while (dptr < maxp) {
+ if (trigx < maxws && trigy < maxhs) {
+ const uchar *p2 = sptr+sbpl*(trigy>>12) + ((trigx>>12)*3);
+ dptr[0] = p2[0];
+ dptr[1] = p2[1];
+ dptr[2] = p2[2];
+ }
+ trigx += m11;
+ trigy += m12;
+ dptr += 3;
+ }
+ break;
+
+ case 32: // 32 bpp transform
+ while (dptr < maxp) {
+ if (trigx < maxws && trigy < maxhs)
+ *((uint*)dptr) = *((uint *)(sptr+sbpl*(trigy>>12) +
+ ((trigx>>12)<<2)));
+ trigx += m11;
+ trigy += m12;
+ dptr += 4;
+ }
+ break;
+
+ default: {
+ return false;
+ }
+ }
+ } else {
+ switch (type) {
+ case QT_XFORM_TYPE_MSBFIRST:
+ while (dptr < maxp) {
+ IWX_MSB(128);
+ IWX_MSB(64);
+ IWX_MSB(32);
+ IWX_MSB(16);
+ IWX_MSB(8);
+ IWX_MSB(4);
+ IWX_MSB(2);
+ IWX_MSB(1);
+ dptr++;
+ }
+ break;
+ case QT_XFORM_TYPE_LSBFIRST:
+ while (dptr < maxp) {
+ IWX_LSB(1);
+ IWX_LSB(2);
+ IWX_LSB(4);
+ IWX_LSB(8);
+ IWX_LSB(16);
+ IWX_LSB(32);
+ IWX_LSB(64);
+ IWX_LSB(128);
+ dptr++;
+ }
+ break;
+# if defined(Q_WS_WIN)
+ case QT_XFORM_TYPE_WINDOWSPIXMAP:
+ while (dptr < maxp) {
+ IWX_PIX(128);
+ IWX_PIX(64);
+ IWX_PIX(32);
+ IWX_PIX(16);
+ IWX_PIX(8);
+ IWX_PIX(4);
+ IWX_PIX(2);
+ IWX_PIX(1);
+ dptr++;
+ }
+ break;
+# endif
+ }
+ }
+ m21ydx += m21;
+ m22ydy += m22;
+ dptr += p_inc;
+ }
+ return true;
+}
+#undef IWX_MSB
+#undef IWX_LSB
+#undef IWX_PIX
+
+/*!
+ \fn QImage QImage::xForm(const QMatrix &matrix) const
+
+ Use transformed() instead.
+
+ \oldcode
+ QImage image;
+ ...
+ image.xForm(matrix);
+ \newcode
+ QImage image;
+ ...
+ image.transformed(matrix);
+ \endcode
+*/
+
+/*! \obsolete
+ Returns a number that identifies the contents of this
+ QImage object. Distinct QImage objects can only have the same
+ serial number if they refer to the same contents (but they don't
+ have to).
+
+ Use cacheKey() instead.
+
+ \warning The serial number doesn't necessarily change when the
+ image is altered. This means that it may be dangerous to use
+ it as a cache key.
+
+ \sa operator==()
+*/
+
+int QImage::serialNumber() const
+{
+ if (!d)
+ return 0;
+ else
+ return d->ser_no;
+}
+
+/*!
+ Returns a number that identifies the contents of this QImage
+ object. Distinct QImage objects can only have the same key if they
+ refer to the same contents.
+
+ The key will change when the image is altered.
+*/
+qint64 QImage::cacheKey() const
+{
+ if (!d)
+ return 0;
+ else
+ return (((qint64) d->ser_no) << 32) | ((qint64) d->detach_no);
+}
+
+/*!
+ \internal
+
+ Returns true if the image is detached; otherwise returns false.
+
+ \sa detach(), {Implicit Data Sharing}
+*/
+
+bool QImage::isDetached() const
+{
+ return d && d->ref == 1;
+}
+
+
+/*!
+ \obsolete
+ Sets the alpha channel of this image to the given \a alphaChannel.
+
+ If \a alphaChannel is an 8 bit grayscale image, the intensity values are
+ written into this buffer directly. Otherwise, \a alphaChannel is converted
+ to 32 bit and the intensity of the RGB pixel values is used.
+
+ Note that the image will be converted to the Format_ARGB32_Premultiplied
+ format if the function succeeds.
+
+ Use one of the composition modes in QPainter::CompositionMode instead.
+
+ \warning This function is expensive.
+
+ \sa alphaChannel(), {QImage#Image Transformations}{Image
+ Transformations}, {QImage#Image Formats}{Image Formats}
+*/
+
+void QImage::setAlphaChannel(const QImage &alphaChannel)
+{
+ if (!d)
+ return;
+
+ int w = d->width;
+ int h = d->height;
+
+ if (w != alphaChannel.d->width || h != alphaChannel.d->height) {
+ qWarning("QImage::setAlphaChannel: "
+ "Alpha channel must have same dimensions as the target image");
+ return;
+ }
+
+ if (d->paintEngine && d->paintEngine->isActive()) {
+ qWarning("QImage::setAlphaChannel: "
+ "Unable to set alpha channel while image is being painted on");
+ return;
+ }
+
+ if (d->format == QImage::Format_ARGB32_Premultiplied)
+ detach();
+ else
+ *this = convertToFormat(QImage::Format_ARGB32_Premultiplied);
+
+ if (isNull())
+ return;
+
+ // Slight optimization since alphachannels are returned as 8-bit grays.
+ if (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) {
+ const uchar *src = src_data;
+ QRgb *dest = (QRgb *)dest_data;
+ for (int x=0; x<w; ++x) {
+ int alpha = *src;
+ int destAlpha = qt_div_255(alpha * qAlpha(*dest));
+ *dest = ((destAlpha << 24)
+ | (qt_div_255(qRed(*dest) * alpha) << 16)
+ | (qt_div_255(qGreen(*dest) * alpha) << 8)
+ | (qt_div_255(qBlue(*dest) * alpha)));
+ ++dest;
+ ++src;
+ }
+ src_data += alphaChannel.d->bytes_per_line;
+ dest_data += d->bytes_per_line;
+ }
+
+ } else {
+ const QImage sourceImage = alphaChannel.convertToFormat(QImage::Format_RGB32);
+ const uchar *src_data = sourceImage.d->data;
+ const uchar *dest_data = d->data;
+ for (int y=0; y<h; ++y) {
+ const QRgb *src = (const QRgb *) src_data;
+ QRgb *dest = (QRgb *) dest_data;
+ for (int x=0; x<w; ++x) {
+ int alpha = qGray(*src);
+ int destAlpha = qt_div_255(alpha * qAlpha(*dest));
+ *dest = ((destAlpha << 24)
+ | (qt_div_255(qRed(*dest) * alpha) << 16)
+ | (qt_div_255(qGreen(*dest) * alpha) << 8)
+ | (qt_div_255(qBlue(*dest) * alpha)));
+ ++dest;
+ ++src;
+ }
+ src_data += sourceImage.d->bytes_per_line;
+ dest_data += d->bytes_per_line;
+ }
+ }
+}
+
+
+/*!
+ \obsolete
+
+ Returns the alpha channel of the image as a new grayscale QImage in which
+ each pixel's red, green, and blue values are given the alpha value of the
+ original image. The color depth of the returned image is 8-bit.
+
+ You can see an example of use of this function in QPixmap's
+ \l{QPixmap::}{alphaChannel()}, which works in the same way as
+ this function on QPixmaps.
+
+ Most usecases for this function can be replaced with QPainter and
+ using composition modes.
+
+ \warning This is an expensive function.
+
+ \sa setAlphaChannel(), hasAlphaChannel(),
+ {QPixmap#Pixmap Information}{Pixmap},
+ {QImage#Image Transformations}{Image Transformations}
+*/
+
+QImage QImage::alphaChannel() const
+{
+ if (!d)
+ return QImage();
+
+ int w = d->width;
+ int h = d->height;
+
+ QImage image(w, h, Format_Indexed8);
+ image.setColorCount(256);
+
+ // set up gray scale table.
+ for (int i=0; i<256; ++i)
+ image.setColor(i, qRgb(i, i, i));
+
+ if (!hasAlphaChannel()) {
+ image.fill(255);
+ return image;
+ }
+
+ if (d->format == Format_Indexed8) {
+ const uchar *src_data = d->data;
+ uchar *dest_data = image.d->data;
+ for (int y=0; y<h; ++y) {
+ const uchar *src = src_data;
+ uchar *dest = dest_data;
+ for (int x=0; x<w; ++x) {
+ *dest = qAlpha(d->colortable.at(*src));
+ ++dest;
+ ++src;
+ }
+ src_data += d->bytes_per_line;
+ dest_data += image.d->bytes_per_line;
+ }
+ } else {
+ QImage alpha32 = *this;
+ if (d->format != Format_ARGB32 && d->format != Format_ARGB32_Premultiplied)
+ alpha32 = convertToFormat(Format_ARGB32);
+
+ const uchar *src_data = alpha32.d->data;
+ uchar *dest_data = image.d->data;
+ for (int y=0; y<h; ++y) {
+ const QRgb *src = (const QRgb *) src_data;
+ uchar *dest = dest_data;
+ for (int x=0; x<w; ++x) {
+ *dest = qAlpha(*src);
+ ++dest;
+ ++src;
+ }
+ src_data += alpha32.d->bytes_per_line;
+ dest_data += image.d->bytes_per_line;
+ }
+ }
+
+ return image;
+}
+
+/*!
+ Returns true if the image has a format that respects the alpha
+ channel, otherwise returns false.
+
+ \sa {QImage#Image Information}{Image Information}
+*/
+bool QImage::hasAlphaChannel() const
+{
+ return d && (d->format == Format_ARGB32_Premultiplied
+ || d->format == Format_ARGB32
+ || d->format == Format_ARGB8565_Premultiplied
+ || d->format == Format_ARGB8555_Premultiplied
+ || d->format == Format_ARGB6666_Premultiplied
+ || d->format == Format_ARGB4444_Premultiplied
+ || (d->has_alpha_clut && (d->format == Format_Indexed8
+ || d->format == Format_Mono
+ || d->format == Format_MonoLSB)));
+}
+
+
+/*!
+ \since 4.7
+ Returns the number of bit planes in the image.
+
+ The number of bit planes is the number of bits of color and
+ transparency information for each pixel. This is different from
+ (i.e. smaller than) the depth when the image format contains
+ unused bits.
+
+ \sa depth(), format(), {QImage#Image Formats}{Image Formats}
+*/
+int QImage::bitPlaneCount() const
+{
+ if (!d)
+ return 0;
+ int bpc = 0;
+ switch (d->format) {
+ case QImage::Format_Invalid:
+ break;
+ case QImage::Format_RGB32:
+ bpc = 24;
+ break;
+ case QImage::Format_RGB666:
+ bpc = 18;
+ break;
+ case QImage::Format_RGB555:
+ bpc = 15;
+ break;
+ case QImage::Format_ARGB8555_Premultiplied:
+ bpc = 23;
+ break;
+ case QImage::Format_RGB444:
+ bpc = 12;
+ break;
+ default:
+ bpc = qt_depthForFormat(d->format);
+ break;
+ }
+ return bpc;
+}
+
+
+#ifdef QT3_SUPPORT
+#if defined(Q_WS_X11)
+QT_BEGIN_INCLUDE_NAMESPACE
+#include <private/qt_x11_p.h>
+QT_END_INCLUDE_NAMESPACE
+#endif
+
+QImage::Endian QImage::systemBitOrder()
+{
+#if defined(Q_WS_X11)
+ return BitmapBitOrder(X11->display) == MSBFirst ? BigEndian : LittleEndian;
+#else
+ return BigEndian;
+#endif
+}
+#endif
+
+/*!
+ \fn QImage QImage::copy(const QRect &rect, Qt::ImageConversionFlags flags) const
+ \compat
+
+ Use copy() instead.
+*/
+
+/*!
+ \fn QImage QImage::copy(int x, int y, int w, int h, Qt::ImageConversionFlags flags) const
+ \compat
+
+ Use copy() instead.
+*/
+
+/*!
+ \fn QImage QImage::scaleWidth(int w) const
+ \compat
+
+ Use scaledToWidth() instead.
+*/
+
+/*!
+ \fn QImage QImage::scaleHeight(int h) const
+ \compat
+
+ Use scaledToHeight() instead.
+*/
+
+static QImage smoothScaled(const QImage &source, int w, int h) {
+ QImage src = source;
+ if (src.format() == QImage::Format_ARGB32)
+ src = src.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ else if (src.depth() < 32) {
+ if (src.hasAlphaChannel())
+ src = src.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ else
+ src = src.convertToFormat(QImage::Format_RGB32);
+ }
+
+ return qSmoothScaleImage(src, w, h);
+}
+
+
+static QImage rotated90(const QImage &image) {
+ QImage out(image.height(), image.width(), image.format());
+ if (image.colorCount() > 0)
+ out.setColorTable(image.colorTable());
+ int w = image.width();
+ int h = image.height();
+ switch (image.format()) {
+ case QImage::Format_RGB32:
+ case QImage::Format_ARGB32:
+ case QImage::Format_ARGB32_Premultiplied:
+ qt_memrotate270(reinterpret_cast<const quint32*>(image.bits()),
+ w, h, image.bytesPerLine(),
+ reinterpret_cast<quint32*>(out.bits()),
+ out.bytesPerLine());
+ break;
+ case QImage::Format_RGB666:
+ case QImage::Format_ARGB6666_Premultiplied:
+ case QImage::Format_ARGB8565_Premultiplied:
+ case QImage::Format_ARGB8555_Premultiplied:
+ case QImage::Format_RGB888:
+ qt_memrotate270(reinterpret_cast<const quint24*>(image.bits()),
+ w, h, image.bytesPerLine(),
+ reinterpret_cast<quint24*>(out.bits()),
+ out.bytesPerLine());
+ break;
+ case QImage::Format_RGB555:
+ case QImage::Format_RGB16:
+ case QImage::Format_ARGB4444_Premultiplied:
+ qt_memrotate270(reinterpret_cast<const quint16*>(image.bits()),
+ w, h, image.bytesPerLine(),
+ reinterpret_cast<quint16*>(out.bits()),
+ out.bytesPerLine());
+ break;
+ case QImage::Format_Indexed8:
+ qt_memrotate270(reinterpret_cast<const quint8*>(image.bits()),
+ w, h, image.bytesPerLine(),
+ reinterpret_cast<quint8*>(out.bits()),
+ out.bytesPerLine());
+ break;
+ default:
+ for (int y=0; y<h; ++y) {
+ if (image.colorCount())
+ for (int x=0; x<w; ++x)
+ out.setPixel(h-y-1, x, image.pixelIndex(x, y));
+ else
+ for (int x=0; x<w; ++x)
+ out.setPixel(h-y-1, x, image.pixel(x, y));
+ }
+ break;
+ }
+ return out;
+}
+
+
+static QImage rotated180(const QImage &image) {
+ return image.mirrored(true, true);
+}
+
+
+static QImage rotated270(const QImage &image) {
+ QImage out(image.height(), image.width(), image.format());
+ if (image.colorCount() > 0)
+ out.setColorTable(image.colorTable());
+ int w = image.width();
+ int h = image.height();
+ switch (image.format()) {
+ case QImage::Format_RGB32:
+ case QImage::Format_ARGB32:
+ case QImage::Format_ARGB32_Premultiplied:
+ qt_memrotate90(reinterpret_cast<const quint32*>(image.bits()),
+ w, h, image.bytesPerLine(),
+ reinterpret_cast<quint32*>(out.bits()),
+ out.bytesPerLine());
+ break;
+ case QImage::Format_RGB666:
+ case QImage::Format_ARGB6666_Premultiplied:
+ case QImage::Format_ARGB8565_Premultiplied:
+ case QImage::Format_ARGB8555_Premultiplied:
+ case QImage::Format_RGB888:
+ qt_memrotate90(reinterpret_cast<const quint24*>(image.bits()),
+ w, h, image.bytesPerLine(),
+ reinterpret_cast<quint24*>(out.bits()),
+ out.bytesPerLine());
+ break;
+ case QImage::Format_RGB555:
+ case QImage::Format_RGB16:
+ case QImage::Format_ARGB4444_Premultiplied:
+ qt_memrotate90(reinterpret_cast<const quint16*>(image.bits()),
+ w, h, image.bytesPerLine(),
+ reinterpret_cast<quint16*>(out.bits()),
+ out.bytesPerLine());
+ break;
+ case QImage::Format_Indexed8:
+ qt_memrotate90(reinterpret_cast<const quint8*>(image.bits()),
+ w, h, image.bytesPerLine(),
+ reinterpret_cast<quint8*>(out.bits()),
+ out.bytesPerLine());
+ break;
+ default:
+ for (int y=0; y<h; ++y) {
+ if (image.colorCount())
+ for (int x=0; x<w; ++x)
+ out.setPixel(y, w-x-1, image.pixelIndex(x, y));
+ else
+ for (int x=0; x<w; ++x)
+ out.setPixel(y, w-x-1, image.pixel(x, y));
+ }
+ break;
+ }
+ return out;
+}
+
+/*!
+ Returns a copy of the image that is transformed using the given
+ transformation \a matrix and transformation \a mode.
+
+ The transformation \a matrix is internally adjusted to compensate
+ for unwanted translation; i.e. the image produced is the smallest
+ image that contains all the transformed points of the original
+ image. Use the trueMatrix() function to retrieve the actual matrix
+ used for transforming an image.
+
+ Unlike the other overload, this function can be used to perform perspective
+ transformations on images.
+
+ \sa trueMatrix(), {QImage#Image Transformations}{Image
+ Transformations}
+*/
+
+QImage QImage::transformed(const QTransform &matrix, Qt::TransformationMode mode ) const
+{
+ if (!d)
+ return QImage();
+
+ // source image data
+ int ws = width();
+ int hs = height();
+
+ // target image data
+ int wd;
+ int hd;
+
+ // compute size of target image
+ QTransform mat = trueMatrix(matrix, ws, hs);
+ bool complex_xform = false;
+ bool scale_xform = false;
+ if (mat.type() <= QTransform::TxScale) {
+ if (mat.type() == QTransform::TxNone) // identity matrix
+ return *this;
+ else if (mat.m11() == -1. && mat.m22() == -1.)
+ return rotated180(*this);
+
+ if (mode == Qt::FastTransformation) {
+ hd = qRound(qAbs(mat.m22()) * hs);
+ wd = qRound(qAbs(mat.m11()) * ws);
+ } else {
+ hd = int(qAbs(mat.m22()) * hs + 0.9999);
+ wd = int(qAbs(mat.m11()) * ws + 0.9999);
+ }
+ scale_xform = true;
+ } else {
+ if (mat.type() <= QTransform::TxRotate && mat.m11() == 0 && mat.m22() == 0) {
+ if (mat.m12() == 1. && mat.m21() == -1.)
+ return rotated90(*this);
+ else if (mat.m12() == -1. && mat.m21() == 1.)
+ return rotated270(*this);
+ }
+
+ QPolygonF a(QRectF(0, 0, ws, hs));
+ a = mat.map(a);
+ QRect r = a.boundingRect().toAlignedRect();
+ wd = r.width();
+ hd = r.height();
+ complex_xform = true;
+ }
+
+ if (wd == 0 || hd == 0)
+ return QImage();
+
+ // Make use of the optimized algorithm when we're scaling
+ if (scale_xform && mode == Qt::SmoothTransformation) {
+ if (mat.m11() < 0.0F && mat.m22() < 0.0F) { // horizontal/vertical flip
+ return smoothScaled(mirrored(true, true), wd, hd);
+ } else if (mat.m11() < 0.0F) { // horizontal flip
+ return smoothScaled(mirrored(true, false), wd, hd);
+ } else if (mat.m22() < 0.0F) { // vertical flip
+ return smoothScaled(mirrored(false, true), wd, hd);
+ } else { // no flipping
+ return smoothScaled(*this, wd, hd);
+ }
+ }
+
+ int bpp = depth();
+
+ int sbpl = bytesPerLine();
+ const uchar *sptr = bits();
+
+ QImage::Format target_format = d->format;
+
+ if (complex_xform || mode == Qt::SmoothTransformation) {
+ if (d->format < QImage::Format_RGB32 || !hasAlphaChannel()) {
+ switch(d->format) {
+ case QImage::Format_RGB16:
+ target_format = Format_ARGB8565_Premultiplied;
+ break;
+ case QImage::Format_RGB555:
+ target_format = Format_ARGB8555_Premultiplied;
+ break;
+ case QImage::Format_RGB666:
+ target_format = Format_ARGB6666_Premultiplied;
+ break;
+ case QImage::Format_RGB444:
+ target_format = Format_ARGB4444_Premultiplied;
+ break;
+ default:
+ target_format = Format_ARGB32_Premultiplied;
+ break;
+ }
+ }
+ }
+
+ QImage dImage(wd, hd, target_format);
+ QIMAGE_SANITYCHECK_MEMORY(dImage);
+
+ if (target_format == QImage::Format_MonoLSB
+ || target_format == QImage::Format_Mono
+ || target_format == QImage::Format_Indexed8) {
+ dImage.d->colortable = d->colortable;
+ dImage.d->has_alpha_clut = d->has_alpha_clut | complex_xform;
+ }
+
+ 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;
+ }
+
+ if (target_format >= QImage::Format_RGB32) {
+ QPainter p(&dImage);
+ if (mode == Qt::SmoothTransformation) {
+ p.setRenderHint(QPainter::Antialiasing);
+ p.setRenderHint(QPainter::SmoothPixmapTransform);
+ }
+ p.setTransform(mat);
+ p.drawImage(QPoint(0, 0), *this);
+ } else {
+ bool invertible;
+ mat = mat.inverted(&invertible); // invert matrix
+ if (!invertible) // error, return null image
+ return QImage();
+
+ // create target image (some of the code is from QImage::copy())
+ int type = format() == Format_Mono ? QT_XFORM_TYPE_MSBFIRST : QT_XFORM_TYPE_LSBFIRST;
+ int dbpl = dImage.bytesPerLine();
+ qt_xForm_helper(mat, 0, type, bpp, dImage.bits(), dbpl, 0, hd, sptr, sbpl, ws, hs);
+ }
+ return dImage;
+}
+
+/*!
+ \fn QTransform QImage::trueMatrix(const QTransform &matrix, int width, int height)
+
+ Returns the actual matrix used for transforming an image with the
+ given \a width, \a height and \a matrix.
+
+ When transforming an image using the transformed() function, the
+ transformation matrix is internally adjusted to compensate for
+ unwanted translation, i.e. transformed() returns the smallest
+ image containing all transformed points of the original image.
+ This function returns the modified matrix, which maps points
+ correctly from the original image into the new image.
+
+ Unlike the other overload, this function creates transformation
+ matrices that can be used to perform perspective
+ transformations on images.
+
+ \sa transformed(), {QImage#Image Transformations}{Image
+ Transformations}
+*/
+
+QTransform QImage::trueMatrix(const QTransform &matrix, int w, int h)
+{
+ const QRectF rect(0, 0, w, h);
+ const QRect mapped = matrix.mapRect(rect).toAlignedRect();
+ const QPoint delta = mapped.topLeft();
+ return matrix * QTransform().translate(-delta.x(), -delta.y());
+}
+
+bool QImageData::convertInPlace(QImage::Format newFormat, Qt::ImageConversionFlags flags)
+{
+ if (format == newFormat)
+ return true;
+
+ // No in-place conversion if we have to detach
+ if (ref > 1)
+ return false;
+
+ const InPlace_Image_Converter *const converterPtr = &inplace_converter_map[format][newFormat];
+ InPlace_Image_Converter converter = *converterPtr;
+ if (converter)
+ return converter(this, flags);
+ else
+ return false;
+}
+
+/*!
+ \typedef QImage::DataPtr
+ \internal
+*/
+
+/*!
+ \fn DataPtr & QImage::data_ptr()
+ \internal
+*/
+
+QT_END_NAMESPACE
diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h
new file mode 100644
index 0000000000..496fe93c54
--- /dev/null
+++ b/src/gui/image/qimage.h
@@ -0,0 +1,374 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIMAGE_H
+#define QIMAGE_H
+
+#include <QtGui/qtransform.h>
+#include <QtGui/qpaintdevice.h>
+#include <QtGui/qrgb.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QIODevice;
+class QStringList;
+class QMatrix;
+class QTransform;
+class QVariant;
+template <class T> class QList;
+template <class T> class QVector;
+
+struct QImageData;
+class QImageDataMisc; // internal
+#ifndef QT_NO_IMAGE_TEXT
+class Q_GUI_EXPORT QImageTextKeyLang {
+public:
+ QImageTextKeyLang(const char* k, const char* l) : key(k), lang(l) { }
+ QImageTextKeyLang() { }
+
+ QByteArray key;
+ QByteArray lang;
+
+ bool operator< (const QImageTextKeyLang& other) const
+ { return key < other.key || (key==other.key && lang < other.lang); }
+ bool operator== (const QImageTextKeyLang& other) const
+ { return key==other.key && lang==other.lang; }
+ inline bool operator!= (const QImageTextKeyLang &other) const
+ { return !operator==(other); }
+};
+#endif //QT_NO_IMAGE_TEXT
+
+
+class Q_GUI_EXPORT QImage : public QPaintDevice
+{
+public:
+ enum InvertMode { InvertRgb, InvertRgba };
+ enum Format {
+ Format_Invalid,
+ Format_Mono,
+ Format_MonoLSB,
+ Format_Indexed8,
+ Format_RGB32,
+ Format_ARGB32,
+ Format_ARGB32_Premultiplied,
+ Format_RGB16,
+ Format_ARGB8565_Premultiplied,
+ Format_RGB666,
+ Format_ARGB6666_Premultiplied,
+ Format_RGB555,
+ Format_ARGB8555_Premultiplied,
+ Format_RGB888,
+ Format_RGB444,
+ Format_ARGB4444_Premultiplied,
+#if 0
+ // reserved for future use
+ Format_RGB15,
+ Format_Grayscale16,
+ Format_Grayscale8,
+ Format_Grayscale4,
+ Format_Grayscale4LSB,
+ Format_Grayscale2,
+ Format_Grayscale2LSB
+#endif
+#ifndef qdoc
+ NImageFormats
+#endif
+ };
+
+ QImage();
+ QImage(const QSize &size, Format format);
+ QImage(int width, int height, Format format);
+ QImage(uchar *data, int width, int height, Format format);
+ QImage(const uchar *data, int width, int height, Format format);
+ QImage(uchar *data, int width, int height, int bytesPerLine, Format format);
+ QImage(const uchar *data, int width, int height, int bytesPerLine, Format format);
+
+#ifndef QT_NO_IMAGEFORMAT_XPM
+ explicit QImage(const char * const xpm[]);
+#endif
+ explicit QImage(const QString &fileName, const char *format = 0);
+#ifndef QT_NO_CAST_FROM_ASCII
+ explicit QImage(const char *fileName, const char *format = 0);
+#endif
+
+ QImage(const QImage &);
+ ~QImage();
+
+ QImage &operator=(const QImage &);
+#ifdef Q_COMPILER_RVALUE_REFS
+ inline QImage &operator=(QImage &&other)
+ { qSwap(d, other.d); return *this; }
+#endif
+ inline void swap(QImage &other) { qSwap(d, other.d); }
+
+ bool isNull() const;
+
+ int devType() const;
+
+ bool operator==(const QImage &) const;
+ bool operator!=(const QImage &) const;
+ operator QVariant() const;
+ void detach();
+ bool isDetached() const;
+
+ QImage copy(const QRect &rect = QRect()) const;
+ inline QImage copy(int x, int y, int w, int h) const
+ { return copy(QRect(x, y, w, h)); }
+
+ Format format() const;
+
+ QImage convertToFormat(Format f, Qt::ImageConversionFlags flags = Qt::AutoColor) const Q_REQUIRED_RESULT;
+ QImage convertToFormat(Format f, const QVector<QRgb> &colorTable, Qt::ImageConversionFlags flags = Qt::AutoColor) const Q_REQUIRED_RESULT;
+
+ int width() const;
+ int height() const;
+ QSize size() const;
+ QRect rect() const;
+
+ int depth() const;
+#ifdef QT_DEPRECATED
+ QT_DEPRECATED int numColors() const;
+#endif
+ int colorCount() const;
+ int bitPlaneCount() const;
+
+ QRgb color(int i) const;
+ void setColor(int i, QRgb c);
+#ifdef QT_DEPRECATED
+ QT_DEPRECATED void setNumColors(int);
+#endif
+ void setColorCount(int);
+
+ bool allGray() const;
+ bool isGrayscale() const;
+
+ uchar *bits();
+ const uchar *bits() const;
+ const uchar *constBits() const;
+#ifdef QT_DEPRECATED
+ QT_DEPRECATED int numBytes() const;
+#endif
+ int byteCount() const;
+
+ uchar *scanLine(int);
+ const uchar *scanLine(int) const;
+ const uchar *constScanLine(int) const;
+ int bytesPerLine() const;
+
+ bool valid(int x, int y) const;
+ bool valid(const QPoint &pt) const;
+
+ int pixelIndex(int x, int y) const;
+ int pixelIndex(const QPoint &pt) const;
+
+ QRgb pixel(int x, int y) const;
+ QRgb pixel(const QPoint &pt) const;
+
+ void setPixel(int x, int y, uint index_or_rgb);
+ void setPixel(const QPoint &pt, uint index_or_rgb);
+
+ QVector<QRgb> colorTable() const;
+ void setColorTable(const QVector<QRgb> colors);
+
+ void fill(uint pixel);
+ void fill(const QColor &color);
+ void fill(Qt::GlobalColor color);
+
+
+ bool hasAlphaChannel() const;
+ void setAlphaChannel(const QImage &alphaChannel);
+ QImage alphaChannel() const;
+ QImage createAlphaMask(Qt::ImageConversionFlags flags = Qt::AutoColor) const;
+#ifndef QT_NO_IMAGE_HEURISTIC_MASK
+ QImage createHeuristicMask(bool clipTight = true) const;
+#endif
+ QImage createMaskFromColor(QRgb color, Qt::MaskMode mode = Qt::MaskInColor) const;
+
+ inline QImage scaled(int w, int h, Qt::AspectRatioMode aspectMode = Qt::IgnoreAspectRatio,
+ Qt::TransformationMode mode = Qt::FastTransformation) const
+ { return scaled(QSize(w, h), aspectMode, mode); }
+ QImage scaled(const QSize &s, Qt::AspectRatioMode aspectMode = Qt::IgnoreAspectRatio,
+ Qt::TransformationMode mode = Qt::FastTransformation) const;
+ QImage scaledToWidth(int w, Qt::TransformationMode mode = Qt::FastTransformation) const;
+ QImage scaledToHeight(int h, Qt::TransformationMode mode = Qt::FastTransformation) const;
+ QImage transformed(const QMatrix &matrix, Qt::TransformationMode mode = Qt::FastTransformation) const;
+ static QMatrix trueMatrix(const QMatrix &, int w, int h);
+ QImage transformed(const QTransform &matrix, Qt::TransformationMode mode = Qt::FastTransformation) const;
+ static QTransform trueMatrix(const QTransform &, int w, int h);
+ QImage mirrored(bool horizontally = false, bool vertically = true) const;
+ QImage rgbSwapped() const;
+ void invertPixels(InvertMode = InvertRgb);
+
+
+ bool load(QIODevice *device, const char* format);
+ bool load(const QString &fileName, const char* format=0);
+ bool loadFromData(const uchar *buf, int len, const char *format = 0);
+ inline bool loadFromData(const QByteArray &data, const char* aformat=0)
+ { return loadFromData(reinterpret_cast<const uchar *>(data.constData()), data.size(), aformat); }
+
+ bool save(const QString &fileName, const char* format=0, int quality=-1) const;
+ bool save(QIODevice *device, const char* format=0, int quality=-1) const;
+
+ static QImage fromData(const uchar *data, int size, const char *format = 0);
+ inline static QImage fromData(const QByteArray &data, const char *format = 0)
+ { return fromData(reinterpret_cast<const uchar *>(data.constData()), data.size(), format); }
+
+ int serialNumber() const;
+ qint64 cacheKey() const;
+
+ QPaintEngine *paintEngine() const;
+
+ // Auxiliary data
+ int dotsPerMeterX() const;
+ int dotsPerMeterY() const;
+ void setDotsPerMeterX(int);
+ void setDotsPerMeterY(int);
+ QPoint offset() const;
+ void setOffset(const QPoint&);
+#ifndef QT_NO_IMAGE_TEXT
+ QStringList textKeys() const;
+ QString text(const QString &key = QString()) const;
+ void setText(const QString &key, const QString &value);
+
+ // The following functions are obsolete as of 4.1
+ QString text(const char* key, const char* lang=0) const;
+ QList<QImageTextKeyLang> textList() const;
+ QStringList textLanguages() const;
+ QString text(const QImageTextKeyLang&) const;
+ void setText(const char* key, const char* lang, const QString&);
+#endif
+
+#ifdef QT3_SUPPORT
+ enum Endian { BigEndian, LittleEndian, IgnoreEndian };
+ QT3_SUPPORT_CONSTRUCTOR QImage(int width, int height, int depth, int numColors=0, Endian bitOrder=IgnoreEndian);
+ QT3_SUPPORT_CONSTRUCTOR QImage(const QSize&, int depth, int numColors=0, Endian bitOrder=IgnoreEndian);
+ QT3_SUPPORT_CONSTRUCTOR QImage(uchar *data, int w, int h, int depth, const QRgb *colortable, int numColors, Endian bitOrder);
+#ifdef Q_WS_QWS
+ QT3_SUPPORT_CONSTRUCTOR QImage(uchar *data, int w, int h, int depth, int pbl, const QRgb *colortable, int numColors, Endian bitOrder);
+#endif
+ inline QT3_SUPPORT Endian bitOrder() const {
+ Format f = format();
+ return f == Format_Mono ? BigEndian : (f == Format_MonoLSB ? LittleEndian : IgnoreEndian);
+ }
+ QT3_SUPPORT QImage convertDepth(int, Qt::ImageConversionFlags flags = Qt::AutoColor) const;
+ QT3_SUPPORT QImage convertDepthWithPalette(int, QRgb* p, int pc, Qt::ImageConversionFlags flags = Qt::AutoColor) const;
+ QT3_SUPPORT QImage convertBitOrder(Endian) const;
+ QT3_SUPPORT bool hasAlphaBuffer() const;
+ QT3_SUPPORT void setAlphaBuffer(bool);
+ QT3_SUPPORT uchar **jumpTable();
+ QT3_SUPPORT const uchar * const *jumpTable() const;
+ inline QT3_SUPPORT void reset() { *this = QImage(); }
+ static inline QT3_SUPPORT Endian systemByteOrder()
+ { return QSysInfo::ByteOrder == QSysInfo::BigEndian ? BigEndian : LittleEndian; }
+ inline QT3_SUPPORT QImage swapRGB() const { return rgbSwapped(); }
+ inline QT3_SUPPORT QImage mirror(bool horizontally = false, bool vertically = true) const
+ { return mirrored(horizontally, vertically); }
+ QT3_SUPPORT bool create(const QSize&, int depth, int numColors=0, Endian bitOrder=IgnoreEndian);
+ QT3_SUPPORT bool create(int width, int height, int depth, int numColors=0, Endian bitOrder=IgnoreEndian);
+ inline QT3_SUPPORT QImage xForm(const QMatrix &matrix) const { return transformed(QTransform(matrix)); }
+ inline QT3_SUPPORT QImage smoothScale(int w, int h, Qt::AspectRatioMode mode = Qt::IgnoreAspectRatio) const
+ { return scaled(QSize(w, h), mode, Qt::SmoothTransformation); }
+ inline QImage QT3_SUPPORT smoothScale(const QSize &s, Qt::AspectRatioMode mode = Qt::IgnoreAspectRatio) const
+ { return scaled(s, mode, Qt::SmoothTransformation); }
+ inline QT3_SUPPORT QImage scaleWidth(int w) const { return scaledToWidth(w); }
+ inline QT3_SUPPORT QImage scaleHeight(int h) const { return scaledToHeight(h); }
+ inline QT3_SUPPORT void invertPixels(bool invertAlpha) { invertAlpha ? invertPixels(InvertRgba) : invertPixels(InvertRgb); }
+ inline QT3_SUPPORT QImage copy(int x, int y, int w, int h, Qt::ImageConversionFlags) const
+ { return copy(QRect(x, y, w, h)); }
+ inline QT3_SUPPORT QImage copy(const QRect &rect, Qt::ImageConversionFlags) const
+ { return copy(rect); }
+ static QT3_SUPPORT Endian systemBitOrder();
+ inline QT3_SUPPORT_CONSTRUCTOR QImage(const QByteArray &data)
+ { d = 0; *this = QImage::fromData(data); }
+#endif
+
+protected:
+ virtual int metric(PaintDeviceMetric metric) const;
+
+private:
+ friend class QWSOnScreenSurface;
+ QImageData *d;
+
+ friend class QRasterPixmapData;
+ friend class QBlittablePixmapData;
+ friend class QPixmapCacheEntry;
+ friend Q_GUI_EXPORT qint64 qt_image_id(const QImage &image);
+ friend const QVector<QRgb> *qt_image_colortable(const QImage &image);
+
+public:
+ typedef QImageData * DataPtr;
+ inline DataPtr &data_ptr() { return d; }
+};
+
+Q_DECLARE_SHARED(QImage)
+Q_DECLARE_TYPEINFO(QImage, Q_MOVABLE_TYPE);
+
+// Inline functions...
+
+Q_GUI_EXPORT_INLINE bool QImage::valid(const QPoint &pt) const { return valid(pt.x(), pt.y()); }
+Q_GUI_EXPORT_INLINE int QImage::pixelIndex(const QPoint &pt) const { return pixelIndex(pt.x(), pt.y());}
+Q_GUI_EXPORT_INLINE QRgb QImage::pixel(const QPoint &pt) const { return pixel(pt.x(), pt.y()); }
+Q_GUI_EXPORT_INLINE void QImage::setPixel(const QPoint &pt, uint index_or_rgb) { setPixel(pt.x(), pt.y(), index_or_rgb); }
+
+// QImage stream functions
+
+#if !defined(QT_NO_DATASTREAM)
+Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QImage &);
+Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QImage &);
+#endif
+
+#ifdef QT3_SUPPORT
+Q_GUI_EXPORT QT3_SUPPORT void bitBlt(QImage* dst, int dx, int dy, const QImage* src,
+ int sx=0, int sy=0, int sw=-1, int sh=-1, Qt::ImageConversionFlags flags = Qt::AutoColor);
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QIMAGE_H
diff --git a/src/gui/image/qimage_neon.cpp b/src/gui/image/qimage_neon.cpp
new file mode 100644
index 0000000000..89b4bab038
--- /dev/null
+++ b/src/gui/image/qimage_neon.cpp
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qimage.h>
+#include <private/qimage_p.h>
+#include <private/qsimd_p.h>
+
+#ifdef QT_HAVE_NEON
+
+QT_BEGIN_NAMESPACE
+
+Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_neon(quint32 *dst, const uchar *src, int len)
+{
+ if (!len)
+ return;
+
+ const quint32 *const end = dst + len;
+
+ // align dst on 64 bits
+ const int offsetToAlignOn8Bytes = (reinterpret_cast<quintptr>(dst) >> 2) & 0x1;
+ for (int i = 0; i < offsetToAlignOn8Bytes; ++i) {
+ *dst++ = qRgb(src[0], src[1], src[2]);
+ src += 3;
+ }
+
+ if ((len - offsetToAlignOn8Bytes) >= 8) {
+ const quint32 *const simdEnd = end - 7;
+ register uint8x8_t fullVector asm ("d3") = vdup_n_u8(0xff);
+ do {
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ asm volatile (
+ "vld3.8 { d4, d5, d6 }, [%[SRC]] !\n\t"
+ "vst4.8 { d3, d4, d5, d6 }, [%[DST],:64] !\n\t"
+ : [DST]"+r" (dst), [SRC]"+r" (src)
+ : "w"(fullVector)
+ : "memory", "d4", "d5", "d6"
+ );
+#else
+ asm volatile (
+ "vld3.8 { d0, d1, d2 }, [%[SRC]] !\n\t"
+ "vswp d0, d2\n\t"
+ "vst4.8 { d0, d1, d2, d3 }, [%[DST],:64] !\n\t"
+ : [DST]"+r" (dst), [SRC]"+r" (src)
+ : "w"(fullVector)
+ : "memory", "d0", "d1", "d2"
+ );
+#endif
+ } while (dst < simdEnd);
+ }
+
+ while (dst != end) {
+ *dst++ = qRgb(src[0], src[1], src[2]);
+ src += 3;
+ }
+}
+
+void convert_RGB888_to_RGB32_neon(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(src->format == QImage::Format_RGB888);
+ Q_ASSERT(dest->format == QImage::Format_RGB32 || dest->format == QImage::Format_ARGB32 || dest->format == QImage::Format_ARGB32_Premultiplied);
+ Q_ASSERT(src->width == dest->width);
+ Q_ASSERT(src->height == dest->height);
+
+ const uchar *src_data = (uchar *) src->data;
+ quint32 *dest_data = (quint32 *) dest->data;
+
+ for (int i = 0; i < src->height; ++i) {
+ qt_convert_rgb888_to_rgb32_neon(dest_data, src_data, src->width);
+ src_data += src->bytes_per_line;
+ dest_data = (quint32 *)((uchar*)dest_data + dest->bytes_per_line);
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_HAVE_NEON
diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h
new file mode 100644
index 0000000000..db6620b39c
--- /dev/null
+++ b/src/gui/image/qimage_p.h
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIMAGE_P_H
+#define QIMAGE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+#include <QVector>
+
+#ifndef QT_NO_IMAGE_TEXT
+#include <QMap>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QImageWriter;
+
+struct Q_GUI_EXPORT QImageData { // internal image data
+ QImageData();
+ ~QImageData();
+ static QImageData *create(const QSize &size, QImage::Format format, int numColors = 0);
+ static QImageData *create(uchar *data, int w, int h, int bpl, QImage::Format format, bool readOnly);
+
+ QAtomicInt ref;
+
+ int width;
+ int height;
+ int depth;
+ int nbytes; // number of bytes data
+ QVector<QRgb> colortable;
+ uchar *data;
+#ifdef QT3_SUPPORT
+ uchar **jumptable;
+#endif
+ QImage::Format format;
+ int bytes_per_line;
+ int ser_no; // serial number
+ int detach_no;
+
+ qreal dpmx; // dots per meter X (or 0)
+ qreal dpmy; // dots per meter Y (or 0)
+ QPoint offset; // offset in pixels
+
+ uint own_data : 1;
+ uint ro_data : 1;
+ uint has_alpha_clut : 1;
+ uint is_cached : 1;
+
+ bool checkForAlphaPixels() const;
+
+ // Convert the image in-place, minimizing memory reallocation
+ // Return false if the conversion cannot be done in-place.
+ bool convertInPlace(QImage::Format newFormat, Qt::ImageConversionFlags);
+
+#ifndef QT_NO_IMAGE_TEXT
+ QMap<QString, QString> text;
+#endif
+ bool doImageIO(const QImage *image, QImageWriter* io, int quality) const;
+
+ QPaintEngine *paintEngine;
+};
+
+void qInitImageConversions();
+Q_GUI_EXPORT void qGamma_correct_back_to_linear_cs(QImage *image);
+
+inline int qt_depthForFormat(QImage::Format format)
+{
+ int depth = 0;
+ switch(format) {
+ case QImage::Format_Invalid:
+ case QImage::NImageFormats:
+ Q_ASSERT(false);
+ case QImage::Format_Mono:
+ case QImage::Format_MonoLSB:
+ depth = 1;
+ break;
+ case QImage::Format_Indexed8:
+ depth = 8;
+ break;
+ case QImage::Format_RGB32:
+ case QImage::Format_ARGB32:
+ case QImage::Format_ARGB32_Premultiplied:
+ depth = 32;
+ break;
+ case QImage::Format_RGB555:
+ case QImage::Format_RGB16:
+ case QImage::Format_RGB444:
+ case QImage::Format_ARGB4444_Premultiplied:
+ depth = 16;
+ break;
+ case QImage::Format_RGB666:
+ case QImage::Format_ARGB6666_Premultiplied:
+ case QImage::Format_ARGB8565_Premultiplied:
+ case QImage::Format_ARGB8555_Premultiplied:
+ case QImage::Format_RGB888:
+ depth = 24;
+ break;
+ }
+ return depth;
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/gui/image/qimage_sse2.cpp b/src/gui/image/qimage_sse2.cpp
new file mode 100644
index 0000000000..e9bbb6fa36
--- /dev/null
+++ b/src/gui/image/qimage_sse2.cpp
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qimage.h"
+#include <private/qimage_p.h>
+#include <private/qsimd_p.h>
+#include <private/qdrawhelper_p.h>
+#include <private/qdrawingprimitive_sse2_p.h>
+
+#ifdef QT_HAVE_SSE2
+
+QT_BEGIN_NAMESPACE
+
+bool convert_ARGB_to_ARGB_PM_inplace_sse2(QImageData *data, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(data->format == QImage::Format_ARGB32);
+
+ // extra pixels on each line
+ const int spare = data->width & 3;
+ // width in pixels of the pad at the end of each line
+ const int pad = (data->bytes_per_line >> 2) - data->width;
+ const int iter = data->width >> 2;
+ int height = data->height;
+
+ const __m128i alphaMask = _mm_set1_epi32(0xff000000);
+ const __m128i nullVector = _mm_setzero_si128();
+ const __m128i half = _mm_set1_epi16(0x80);
+ const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
+
+ __m128i *d = reinterpret_cast<__m128i*>(data->data);
+ while (height--) {
+ const __m128i *end = d + iter;
+
+ for (; d != end; ++d) {
+ const __m128i srcVector = _mm_loadu_si128(d);
+ const __m128i srcVectorAlpha = _mm_and_si128(srcVector, alphaMask);
+ if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, alphaMask)) == 0xffff) {
+ // opaque, data is unchanged
+ } else if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, nullVector)) == 0xffff) {
+ // fully transparent
+ _mm_storeu_si128(d, nullVector);
+ } else {
+ __m128i alphaChannel = _mm_srli_epi32(srcVector, 24);
+ alphaChannel = _mm_or_si128(alphaChannel, _mm_slli_epi32(alphaChannel, 16));
+
+ __m128i result;
+ BYTE_MUL_SSE2(result, srcVector, alphaChannel, colorMask, half);
+ result = _mm_or_si128(_mm_andnot_si128(alphaMask, result), srcVectorAlpha);
+ _mm_storeu_si128(d, result);
+ }
+ }
+
+ QRgb *p = reinterpret_cast<QRgb*>(d);
+ QRgb *pe = p+spare;
+ for (; p != pe; ++p) {
+ if (*p < 0x00ffffff)
+ *p = 0;
+ else if (*p < 0xff000000)
+ *p = PREMUL(*p);
+ }
+
+ d = reinterpret_cast<__m128i*>(p+pad);
+ }
+
+ data->format = QImage::Format_ARGB32_Premultiplied;
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_HAVE_SSE2
diff --git a/src/gui/image/qimage_ssse3.cpp b/src/gui/image/qimage_ssse3.cpp
new file mode 100644
index 0000000000..81e817eb73
--- /dev/null
+++ b/src/gui/image/qimage_ssse3.cpp
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qimage.h>
+#include <private/qimage_p.h>
+#include <private/qsimd_p.h>
+
+#ifdef QT_HAVE_SSSE3
+
+QT_BEGIN_NAMESPACE
+
+// Convert a scanline of RGB888 (src) to RGB32 (dst)
+// src must be at least len * 3 bytes
+// dst must be at least len * 4 bytes
+Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_ssse3(quint32 *dst, const uchar *src, int len)
+{
+ quint32 *const end = dst + len;
+
+ // Prologue, align dst to 16 bytes. The alignment is done on dst because it has 4 store()
+ // for each 3 load() of src.
+ const int offsetToAlignOn16Bytes = (4 - ((reinterpret_cast<quintptr>(dst) >> 2) & 0x3)) & 0x3;
+ const int prologLength = qMin(len, offsetToAlignOn16Bytes);
+
+ for (int i = 0; i < prologLength; ++i) {
+ *dst++ = qRgb(src[0], src[1], src[2]);
+ src += 3;
+ }
+
+ // Mask the 4 first colors of the RGB888 vector
+ const __m128i shuffleMask = _mm_set_epi8(0xff, 9, 10, 11, 0xff, 6, 7, 8, 0xff, 3, 4, 5, 0xff, 0, 1, 2);
+
+ // Mask the 4 last colors of a RGB888 vector with an offset of 1 (so the last 3 bytes are RGB)
+ const __m128i shuffleMaskEnd = _mm_set_epi8(0xff, 13, 14, 15, 0xff, 10, 11, 12, 0xff, 7, 8, 9, 0xff, 4, 5, 6);
+
+ // Mask to have alpha = 0xff
+ const __m128i alphaMask = _mm_set1_epi32(0xff000000);
+
+ __m128i *inVectorPtr = (__m128i *)src;
+ __m128i *dstVectorPtr = (__m128i *)dst;
+
+ const int simdRoundCount = (len - prologLength) / 16; // one iteration in the loop converts 16 pixels
+ for (int i = 0; i < simdRoundCount; ++i) {
+ /*
+ RGB888 has 5 pixels per vector, + 1 byte from the next pixel. The idea here is
+ to load vectors of RGB888 and use palignr to select a vector out of two vectors.
+
+ After 3 loads of RGB888 and 3 stores of RGB32, we have 4 pixels left in the last
+ vector of RGB888, we can mask it directly to get a last store or RGB32. After that,
+ the first next byte is a R, and we can loop for the next 16 pixels.
+
+ The conversion itself is done with a byte permutation (pshufb).
+ */
+ __m128i firstSrcVector = _mm_lddqu_si128(inVectorPtr);
+ __m128i outputVector = _mm_shuffle_epi8(firstSrcVector, shuffleMask);
+ _mm_store_si128(dstVectorPtr, _mm_or_si128(outputVector, alphaMask));
+ ++inVectorPtr;
+ ++dstVectorPtr;
+
+ // There are 4 unused bytes left in srcVector, we need to load the next 16 bytes
+ // and load the next input with palignr
+ __m128i secondSrcVector = _mm_lddqu_si128(inVectorPtr);
+ __m128i srcVector = _mm_alignr_epi8(secondSrcVector, firstSrcVector, 12);
+ outputVector = _mm_shuffle_epi8(srcVector, shuffleMask);
+ _mm_store_si128(dstVectorPtr, _mm_or_si128(outputVector, alphaMask));
+ ++inVectorPtr;
+ ++dstVectorPtr;
+ firstSrcVector = secondSrcVector;
+
+ // We now have 8 unused bytes left in firstSrcVector
+ secondSrcVector = _mm_lddqu_si128(inVectorPtr);
+ srcVector = _mm_alignr_epi8(secondSrcVector, firstSrcVector, 8);
+ outputVector = _mm_shuffle_epi8(srcVector, shuffleMask);
+ _mm_store_si128(dstVectorPtr, _mm_or_si128(outputVector, alphaMask));
+ ++inVectorPtr;
+ ++dstVectorPtr;
+
+ // There are now 12 unused bytes in firstSrcVector.
+ // We can mask them directly, almost there.
+ outputVector = _mm_shuffle_epi8(secondSrcVector, shuffleMaskEnd);
+ _mm_store_si128(dstVectorPtr, _mm_or_si128(outputVector, alphaMask));
+ ++dstVectorPtr;
+ }
+ src = (uchar *)inVectorPtr;
+ dst = (quint32 *)dstVectorPtr;
+
+ while (dst != end) {
+ *dst++ = qRgb(src[0], src[1], src[2]);
+ src += 3;
+ }
+}
+
+void convert_RGB888_to_RGB32_ssse3(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(src->format == QImage::Format_RGB888);
+ Q_ASSERT(dest->format == QImage::Format_RGB32 || dest->format == QImage::Format_ARGB32 || dest->format == QImage::Format_ARGB32_Premultiplied);
+ Q_ASSERT(src->width == dest->width);
+ Q_ASSERT(src->height == dest->height);
+
+ const uchar *src_data = (uchar *) src->data;
+ quint32 *dest_data = (quint32 *) dest->data;
+
+ for (int i = 0; i < src->height; ++i) {
+ qt_convert_rgb888_to_rgb32_ssse3(dest_data, src_data, src->width);
+ src_data += src->bytes_per_line;
+ dest_data = (quint32 *)((uchar*)dest_data + dest->bytes_per_line);
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_HAVE_SSSE3
diff --git a/src/gui/image/qimageiohandler.cpp b/src/gui/image/qimageiohandler.cpp
new file mode 100644
index 0000000000..da1d236998
--- /dev/null
+++ b/src/gui/image/qimageiohandler.cpp
@@ -0,0 +1,570 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QImageIOHandler
+ \brief The QImageIOHandler class defines the common image I/O
+ interface for all image formats in Qt.
+ \reentrant
+
+ Qt uses QImageIOHandler for reading and writing images through
+ QImageReader and QImageWriter. You can also derive from this class
+ to write your own image format handler using Qt's plugin mechanism.
+
+ Call setDevice() to assign a device to the handler, and
+ setFormat() to assign a format to it. One QImageIOHandler may
+ support more than one image format. canRead() returns true if an
+ image can be read from the device, and read() and write() return
+ true if reading or writing an image was completed successfully.
+
+ QImageIOHandler also has support for animations formats, through
+ the functions loopCount(), imageCount(), nextImageDelay() and
+ currentImageNumber().
+
+ In order to determine what options an image handler supports, Qt
+ will call supportsOption() and setOption(). Make sure to
+ reimplement these functions if you can provide support for any of
+ the options in the ImageOption enum.
+
+ To write your own image handler, you must at least reimplement
+ canRead() and read(). Then create a QImageIOPlugin that
+ can create the handler. Finally, install your plugin, and
+ QImageReader and QImageWriter will then automatically load the
+ plugin, and start using it.
+
+ \sa QImageIOPlugin, QImageReader, QImageWriter
+*/
+
+/*! \enum QImageIOHandler::ImageOption
+
+ This enum describes the different options supported by
+ QImageIOHandler. Some options are used to query an image for
+ properties, and others are used to toggle the way in which an
+ image should be written.
+
+ \value Size The original size of an image. A handler that supports
+ this option is expected to read the size of the image from the
+ image metadata, and return this size from option() as a QSize.
+
+ \value ClipRect The clip rect, or ROI (Region Of Interest). A
+ handler that supports this option is expected to only read the
+ provided QRect area from the original image in read(), before any
+ other transformation is applied.
+
+ \value ScaledSize The scaled size of the image. A handler that
+ supports this option is expected to scale the image to the
+ provided size (a QSize), after applying any clip rect
+ transformation (ClipRect). If the handler does not support this
+ option, QImageReader will perform the scaling after the image has
+ been read.
+
+ \value ScaledClipRect The scaled clip rect (or ROI, Region Of
+ Interest) of the image. A handler that supports this option is
+ expected to apply the provided clip rect (a QRect), after applying
+ any scaling (ScaleSize) or regular clipping (ClipRect). If the
+ handler does not support this option, QImageReader will apply the
+ scaled clip rect after the image has been read.
+
+ \value Description The image description. Some image formats,
+ such as GIF and PNG, allow embedding of text
+ or comments into the image data (e.g., for storing copyright
+ information). It's common that the text is stored in key-value
+ pairs, but some formats store all text in one continuous block.
+ QImageIOHandler returns the text as one
+ QString, where keys and values are separated by a ':', and
+ keys-value pairs are separated by two newlines (\\n\\n). For example,
+ "Title: Sunset\\n\\nAuthor: Jim Smith\\nSarah Jones\\n\\n". Formats that
+ store text in a single block can use "Description" as the key.
+
+ \value CompressionRatio The compression ratio of the image data. A
+ handler that supports this option is expected to set its
+ compression rate depending on the value of this option (an int)
+ when writing.
+
+ \value Gamma The gamma level of the image. A handler that supports
+ this option is expected to set the image gamma level depending on
+ the value of this option (a float) when writing.
+
+ \value Quality The quality level of the image. A handler that
+ supports this option is expected to set the image quality level
+ depending on the value of this option (an int) when writing.
+
+ \value Name The name of the image. A handler that supports this
+ option is expected to read the name from the image metadata and
+ return this as a QString, or when writing an image it is expected
+ to store the name in the image metadata.
+
+ \value SubType The subtype of the image. A handler that supports
+ this option can use the subtype value to help when reading and
+ writing images. For example, a PPM handler may have a subtype
+ value of "ppm" or "ppmraw".
+
+ \value IncrementalReading A handler that supports this option is
+ expected to read the image in several passes, as if it was an
+ animation. QImageReader will treat the image as an animation.
+
+ \value Endianness The endianness of the image. Certain image
+ formats can be stored as BigEndian or LittleEndian. A handler that
+ supports Endianness uses the value of this option to determine how
+ the image should be stored.
+
+ \value Animation Image formats that support animation return
+ true for this value in supportsOption(); otherwise, false is returned.
+
+ \value BackgroundColor Certain image formats allow the
+ background color to be specified. A handler that supports
+ BackgroundColor initializes the background color to this option
+ (a QColor) when reading an image.
+
+ \value ImageFormat The image's data format returned by the handler.
+ This can be any of the formats listed in QImage::Format.
+*/
+
+/*!
+ \class QImageIOPlugin
+ \brief The QImageIOPlugin class defines an interface for writing
+ an image format plugin.
+ \reentrant
+
+ \ingroup plugins
+
+ QImageIOPlugin is a factory for creating QImageIOHandler objects,
+ which are used internally by QImageReader and QImageWriter to add
+ support for different image formats to Qt.
+
+ Writing an image I/O plugin is achieved by subclassing this
+ base class, reimplementing the pure virtual functions capabilities(),
+ create(), and keys(), and exporting the class with the
+ Q_EXPORT_PLUGIN2() macro. See \l{How to Create Qt Plugins} for details.
+
+ An image format plugin can support three capabilities: reading (\l
+ CanRead), writing (\l CanWrite) and \e incremental reading (\l
+ CanReadIncremental). Reimplement capabilities() in you subclass to
+ expose the capabilities of your image format.
+
+ create() should create an instance of your QImageIOHandler
+ subclass, with the provided device and format properly set, and
+ return this handler. You must also reimplement keys() so that Qt
+ knows which image formats your plugin supports.
+
+ Different plugins can support different capabilities. For example,
+ you may have one plugin that supports reading the GIF format, and
+ another that supports writing. Qt will select the correct plugin
+ for the job, depending on the return value of capabilities(). If
+ several plugins support the same capability, Qt will select one
+ arbitrarily.
+
+ \sa QImageIOHandler, {How to Create Qt Plugins}
+*/
+
+/*!
+ \enum QImageIOPlugin::Capability
+
+ This enum describes the capabilities of a QImageIOPlugin.
+
+ \value CanRead The plugin can read images.
+ \value CanWrite The plugin can write images.
+ \value CanReadIncremental The plugin can read images incrementally.
+*/
+
+/*!
+ \class QImageIOHandlerFactoryInterface
+ \brief The QImageIOHandlerFactoryInterface class provides the factory
+ interface for QImageIOPlugin.
+ \reentrant
+
+ \internal
+
+ \sa QImageIOPlugin
+*/
+
+#include "qimageiohandler.h"
+
+#include <qbytearray.h>
+#include <qimage.h>
+#include <qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QIODevice;
+
+class QImageIOHandlerPrivate
+{
+ Q_DECLARE_PUBLIC(QImageIOHandler)
+public:
+ QImageIOHandlerPrivate(QImageIOHandler *q);
+ virtual ~QImageIOHandlerPrivate();
+
+ QIODevice *device;
+ mutable QByteArray format;
+
+ QImageIOHandler *q_ptr;
+};
+
+QImageIOHandlerPrivate::QImageIOHandlerPrivate(QImageIOHandler *q)
+{
+ device = 0;
+ q_ptr = q;
+}
+
+QImageIOHandlerPrivate::~QImageIOHandlerPrivate()
+{
+}
+
+/*!
+ Constructs a QImageIOHandler object.
+*/
+QImageIOHandler::QImageIOHandler()
+ : d_ptr(new QImageIOHandlerPrivate(this))
+{
+}
+
+/*! \internal
+
+ Constructs a QImageIOHandler object, using the private member \a
+ dd.
+*/
+QImageIOHandler::QImageIOHandler(QImageIOHandlerPrivate &dd)
+ : d_ptr(&dd)
+{
+}
+
+/*!
+ Destructs the QImageIOHandler object.
+*/
+QImageIOHandler::~QImageIOHandler()
+{
+}
+
+/*!
+ Sets the device of the QImageIOHandler to \a device. The image
+ handler will use this device when reading and writing images.
+
+ The device can only be set once and must be set before calling
+ canRead(), read(), write(), etc. If you need to read multiple
+ files, construct multiple instances of the appropriate
+ QImageIOHandler subclass.
+
+ \sa device()
+*/
+void QImageIOHandler::setDevice(QIODevice *device)
+{
+ Q_D(QImageIOHandler);
+ d->device = device;
+}
+
+/*!
+ Returns the device currently assigned to the QImageIOHandler. If
+ not device has been assigned, 0 is returned.
+*/
+QIODevice *QImageIOHandler::device() const
+{
+ Q_D(const QImageIOHandler);
+ return d->device;
+}
+
+/*!
+ Sets the format of the QImageIOHandler to \a format. The format is
+ most useful for handlers that support multiple image formats.
+
+ \sa format()
+*/
+void QImageIOHandler::setFormat(const QByteArray &format)
+{
+ Q_D(QImageIOHandler);
+ d->format = format;
+}
+
+/*!
+ Sets the format of the QImageIOHandler to \a format. The format is
+ most useful for handlers that support multiple image formats.
+
+ This function is declared const so that it can be called from canRead().
+
+ \sa format()
+*/
+void QImageIOHandler::setFormat(const QByteArray &format) const
+{
+ Q_D(const QImageIOHandler);
+ d->format = format;
+}
+
+/*!
+ Returns the format that is currently assigned to
+ QImageIOHandler. If no format has been assigned, an empty string
+ is returned.
+
+ \sa setFormat()
+*/
+QByteArray QImageIOHandler::format() const
+{
+ Q_D(const QImageIOHandler);
+ return d->format;
+}
+
+/*!
+ \fn bool QImageIOHandler::read(QImage *image)
+
+ Read an image from the device, and stores it in \a image.
+ Returns true if the image is successfully read; otherwise returns
+ false.
+
+ For image formats that support incremental loading, and for animation
+ formats, the image handler can assume that \a image points to the
+ previous frame.
+
+ \sa canRead()
+*/
+
+/*!
+ \fn bool QImageIOHandler::canRead() const
+
+ Returns true if an image can be read from the device (i.e., the
+ image format is supported, the device can be read from and the
+ initial header information suggests that the image can be read);
+ otherwise returns false.
+
+ When reimplementing canRead(), make sure that the I/O device
+ (device()) is left in its original state (e.g., by using peek()
+ rather than read()).
+
+ \sa read(), QIODevice::peek()
+*/
+
+/*!
+ \obsolete
+
+ Use format() instead.
+*/
+
+QByteArray QImageIOHandler::name() const
+{
+ return format();
+}
+
+/*!
+ Writes the image \a image to the assigned device. Returns true on
+ success; otherwise returns false.
+
+ The default implementation does nothing, and simply returns false.
+*/
+bool QImageIOHandler::write(const QImage &image)
+{
+ Q_UNUSED(image);
+ return false;
+}
+
+/*!
+ Sets the option \a option with the value \a value.
+
+ \sa option(), ImageOption
+*/
+void QImageIOHandler::setOption(ImageOption option, const QVariant &value)
+{
+ Q_UNUSED(option);
+ Q_UNUSED(value);
+}
+
+/*!
+ Returns the value assigned to \a option as a QVariant. The type of
+ the value depends on the option. For example, option(Size) returns
+ a QSize variant.
+
+ \sa setOption(), supportsOption()
+*/
+QVariant QImageIOHandler::option(ImageOption option) const
+{
+ Q_UNUSED(option);
+ return QVariant();
+}
+
+/*!
+ Returns true if the QImageIOHandler supports the option \a option;
+ otherwise returns false. For example, if the QImageIOHandler
+ supports the \l Size option, supportsOption(Size) must return
+ true.
+
+ \sa setOption(), option()
+*/
+bool QImageIOHandler::supportsOption(ImageOption option) const
+{
+ Q_UNUSED(option);
+ return false;
+}
+
+/*!
+ For image formats that support animation, this function returns
+ the sequence number of the current image in the animation. If
+ this function is called before any image is read(), -1 is
+ returned. The number of the first image in the sequence is 0.
+
+ If the image format does not support animation, 0 is returned.
+
+ \sa read()
+*/
+int QImageIOHandler::currentImageNumber() const
+{
+ return 0;
+}
+
+/*!
+ Returns the rect of the current image. If no rect is defined for the
+ image, and empty QRect() is returned.
+
+ This function is useful for animations, where only parts of the frame
+ may be updated at a time.
+*/
+QRect QImageIOHandler::currentImageRect() const
+{
+ return QRect();
+}
+
+/*!
+ For image formats that support animation, this function returns
+ the number of images in the animation. If the image format does
+ not support animation, or if it is unable to determine the number
+ of images, 0 is returned.
+
+ The default implementation returns 1 if canRead() returns true;
+ otherwise 0 is returned.
+*/
+int QImageIOHandler::imageCount() const
+{
+ return canRead() ? 1 : 0;
+}
+
+/*!
+ For image formats that support animation, this function jumps to the
+ next image.
+
+ The default implementation does nothing, and returns false.
+*/
+bool QImageIOHandler::jumpToNextImage()
+{
+ return false;
+}
+
+/*!
+ For image formats that support animation, this function jumps to the image
+ whose sequence number is \a imageNumber. The next call to read() will
+ attempt to read this image.
+
+ The default implementation does nothing, and returns false.
+*/
+bool QImageIOHandler::jumpToImage(int imageNumber)
+{
+ Q_UNUSED(imageNumber);
+ return false;
+}
+
+/*!
+ For image formats that support animation, this function returns
+ the number of times the animation should loop. If the image format
+ does not support animation, 0 is returned.
+*/
+int QImageIOHandler::loopCount() const
+{
+ return 0;
+}
+
+/*!
+ For image formats that support animation, this function returns
+ the number of milliseconds to wait until reading the next
+ image. If the image format does not support animation, 0 is
+ returned.
+*/
+int QImageIOHandler::nextImageDelay() const
+{
+ return 0;
+}
+
+/*!
+ Constructs an image plugin with the given \a parent. This is
+ invoked automatically by the Q_EXPORT_PLUGIN2() macro.
+*/
+QImageIOPlugin::QImageIOPlugin(QObject *parent)
+ : QObject(parent)
+{
+}
+
+/*!
+ Destroys the picture format plugin.
+
+ You never have to call this explicitly. Qt destroys a plugin
+ automatically when it is no longer used.
+*/
+QImageIOPlugin::~QImageIOPlugin()
+{
+}
+
+/*! \fn QImageIOPlugin::capabilities(QIODevice *device, const QByteArray &format) const
+
+ Returns the capabilities on the plugin, based on the data in \a
+ device and the format \a format. For example, if the
+ QImageIOHandler supports the BMP format, and the data in the
+ device starts with the characters "BM", this function should
+ return \l CanRead. If \a format is "bmp" and the handler supports
+ both reading and writing, this function should return \l CanRead |
+ \l CanWrite.
+*/
+
+/*!
+ \fn QImageIOPlugin::keys() const
+
+ Returns the list of image keys this plugin supports.
+
+ These keys are usually the names of the image formats that are implemented
+ in the plugin (e.g., "jpg" or "gif").
+
+ \sa capabilities()
+*/
+
+/*!
+ \fn QImageIOHandler *QImageIOPlugin::create(QIODevice *device, const QByteArray &format) const
+
+ Creates and returns a QImageIOHandler subclass, with \a device
+ and \a format set. The \a format must come from the list returned by keys().
+ Format names are case sensitive.
+
+ \sa keys()
+*/
+
+QT_END_NAMESPACE
diff --git a/src/gui/image/qimageiohandler.h b/src/gui/image/qimageiohandler.h
new file mode 100644
index 0000000000..05e1853f97
--- /dev/null
+++ b/src/gui/image/qimageiohandler.h
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIMAGEIOHANDLER_H
+#define QIMAGEIOHANDLER_H
+
+#include <QtCore/qplugin.h>
+#include <QtCore/qfactoryinterface.h>
+#include <QtCore/qscopedpointer.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QImage;
+class QRect;
+class QSize;
+class QVariant;
+
+class QImageIOHandlerPrivate;
+class Q_GUI_EXPORT QImageIOHandler
+{
+ Q_DECLARE_PRIVATE(QImageIOHandler)
+public:
+ QImageIOHandler();
+ virtual ~QImageIOHandler();
+
+ void setDevice(QIODevice *device);
+ QIODevice *device() const;
+
+ void setFormat(const QByteArray &format);
+ void setFormat(const QByteArray &format) const;
+ QByteArray format() const;
+
+ virtual QByteArray name() const;
+
+ virtual bool canRead() const = 0;
+ virtual bool read(QImage *image) = 0;
+ virtual bool write(const QImage &image);
+
+ enum ImageOption {
+ Size,
+ ClipRect,
+ Description,
+ ScaledClipRect,
+ ScaledSize,
+ CompressionRatio,
+ Gamma,
+ Quality,
+ Name,
+ SubType,
+ IncrementalReading,
+ Endianness,
+ Animation,
+ BackgroundColor,
+ ImageFormat
+ };
+ virtual QVariant option(ImageOption option) const;
+ virtual void setOption(ImageOption option, const QVariant &value);
+ virtual bool supportsOption(ImageOption option) const;
+
+ // incremental loading
+ virtual bool jumpToNextImage();
+ virtual bool jumpToImage(int imageNumber);
+ virtual int loopCount() const;
+ virtual int imageCount() const;
+ virtual int nextImageDelay() const;
+ virtual int currentImageNumber() const;
+ virtual QRect currentImageRect() const;
+
+protected:
+ QImageIOHandler(QImageIOHandlerPrivate &dd);
+ QScopedPointer<QImageIOHandlerPrivate> d_ptr;
+private:
+ Q_DISABLE_COPY(QImageIOHandler)
+};
+
+struct Q_GUI_EXPORT QImageIOHandlerFactoryInterface : public QFactoryInterface
+{
+ virtual QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const = 0;
+};
+
+#define QImageIOHandlerFactoryInterface_iid "com.trolltech.Qt.QImageIOHandlerFactoryInterface"
+Q_DECLARE_INTERFACE(QImageIOHandlerFactoryInterface, QImageIOHandlerFactoryInterface_iid)
+
+class Q_GUI_EXPORT QImageIOPlugin : public QObject, public QImageIOHandlerFactoryInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QImageIOHandlerFactoryInterface:QFactoryInterface)
+public:
+ explicit QImageIOPlugin(QObject *parent = 0);
+ virtual ~QImageIOPlugin();
+
+ enum Capability {
+ CanRead = 0x1,
+ CanWrite = 0x2,
+ CanReadIncremental = 0x4
+ };
+ Q_DECLARE_FLAGS(Capabilities, Capability)
+
+ virtual Capabilities capabilities(QIODevice *device, const QByteArray &format) const = 0;
+ virtual QStringList keys() const = 0;
+ virtual QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const = 0;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QImageIOPlugin::Capabilities)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QIMAGEIOHANDLER_H
diff --git a/src/gui/image/qimagepixmapcleanuphooks.cpp b/src/gui/image/qimagepixmapcleanuphooks.cpp
new file mode 100644
index 0000000000..cd7b4682b7
--- /dev/null
+++ b/src/gui/image/qimagepixmapcleanuphooks.cpp
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qimagepixmapcleanuphooks_p.h"
+#include "private/qpixmapdata_p.h"
+#include "private/qimage_p.h"
+
+
+QT_BEGIN_NAMESPACE
+
+// Legacy, single instance hooks: ### Qt 5: remove
+typedef void (*_qt_pixmap_cleanup_hook)(int);
+typedef void (*_qt_pixmap_cleanup_hook_64)(qint64);
+typedef void (*_qt_image_cleanup_hook)(int);
+Q_GUI_EXPORT _qt_pixmap_cleanup_hook qt_pixmap_cleanup_hook = 0;
+Q_GUI_EXPORT _qt_pixmap_cleanup_hook_64 qt_pixmap_cleanup_hook_64 = 0;
+Q_GUI_EXPORT _qt_image_cleanup_hook qt_image_cleanup_hook = 0;
+Q_GUI_EXPORT _qt_image_cleanup_hook_64 qt_image_cleanup_hook_64 = 0;
+
+Q_GLOBAL_STATIC(QImagePixmapCleanupHooks, qt_image_and_pixmap_cleanup_hooks)
+
+QImagePixmapCleanupHooks *QImagePixmapCleanupHooks::instance()
+{
+ return qt_image_and_pixmap_cleanup_hooks();
+}
+
+void QImagePixmapCleanupHooks::addPixmapDataModificationHook(_qt_pixmap_cleanup_hook_pmd hook)
+{
+ pixmapModificationHooks.append(hook);
+}
+
+void QImagePixmapCleanupHooks::addPixmapDataDestructionHook(_qt_pixmap_cleanup_hook_pmd hook)
+{
+ pixmapDestructionHooks.append(hook);
+}
+
+
+void QImagePixmapCleanupHooks::addImageHook(_qt_image_cleanup_hook_64 hook)
+{
+ imageHooks.append(hook);
+}
+
+void QImagePixmapCleanupHooks::removePixmapDataModificationHook(_qt_pixmap_cleanup_hook_pmd hook)
+{
+ pixmapModificationHooks.removeAll(hook);
+}
+
+void QImagePixmapCleanupHooks::removePixmapDataDestructionHook(_qt_pixmap_cleanup_hook_pmd hook)
+{
+ pixmapDestructionHooks.removeAll(hook);
+}
+
+void QImagePixmapCleanupHooks::removeImageHook(_qt_image_cleanup_hook_64 hook)
+{
+ imageHooks.removeAll(hook);
+}
+
+void QImagePixmapCleanupHooks::executePixmapDataModificationHooks(QPixmapData* pmd)
+{
+ QImagePixmapCleanupHooks *h = qt_image_and_pixmap_cleanup_hooks();
+ // the global destructor for the pixmap and image hooks might have
+ // been called already if the app is "leaking" global
+ // pixmaps/images
+ if (!h)
+ return;
+ for (int i = 0; i < h->pixmapModificationHooks.count(); ++i)
+ h->pixmapModificationHooks[i](pmd);
+
+ if (qt_pixmap_cleanup_hook_64)
+ qt_pixmap_cleanup_hook_64(pmd->cacheKey());
+}
+
+void QImagePixmapCleanupHooks::executePixmapDataDestructionHooks(QPixmapData* pmd)
+{
+ QImagePixmapCleanupHooks *h = qt_image_and_pixmap_cleanup_hooks();
+ // the global destructor for the pixmap and image hooks might have
+ // been called already if the app is "leaking" global
+ // pixmaps/images
+ if (!h)
+ return;
+ for (int i = 0; i < h->pixmapDestructionHooks.count(); ++i)
+ h->pixmapDestructionHooks[i](pmd);
+
+ if (qt_pixmap_cleanup_hook_64)
+ qt_pixmap_cleanup_hook_64(pmd->cacheKey());
+}
+
+void QImagePixmapCleanupHooks::executeImageHooks(qint64 key)
+{
+ for (int i = 0; i < qt_image_and_pixmap_cleanup_hooks()->imageHooks.count(); ++i)
+ qt_image_and_pixmap_cleanup_hooks()->imageHooks[i](key);
+
+ if (qt_image_cleanup_hook_64)
+ qt_image_cleanup_hook_64(key);
+}
+
+
+void QImagePixmapCleanupHooks::enableCleanupHooks(QPixmapData *pixmapData)
+{
+ pixmapData->is_cached = true;
+}
+
+void QImagePixmapCleanupHooks::enableCleanupHooks(const QPixmap &pixmap)
+{
+ enableCleanupHooks(const_cast<QPixmap &>(pixmap).data_ptr().data());
+}
+
+void QImagePixmapCleanupHooks::enableCleanupHooks(const QImage &image)
+{
+ const_cast<QImage &>(image).data_ptr()->is_cached = true;
+}
+
+bool QImagePixmapCleanupHooks::isImageCached(const QImage &image)
+{
+ return const_cast<QImage &>(image).data_ptr()->is_cached;
+}
+
+bool QImagePixmapCleanupHooks::isPixmapCached(const QPixmap &pixmap)
+{
+ return const_cast<QPixmap&>(pixmap).data_ptr().data()->is_cached;
+}
+
+
+
+QT_END_NAMESPACE
diff --git a/src/gui/image/qimagepixmapcleanuphooks_p.h b/src/gui/image/qimagepixmapcleanuphooks_p.h
new file mode 100644
index 0000000000..aa6a986f08
--- /dev/null
+++ b/src/gui/image/qimagepixmapcleanuphooks_p.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIMAGEPIXMAP_CLEANUPHOOKS_P_H
+#define QIMAGEPIXMAP_CLEANUPHOOKS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/qpixmap.h>
+
+QT_BEGIN_NAMESPACE
+
+typedef void (*_qt_image_cleanup_hook_64)(qint64);
+typedef void (*_qt_pixmap_cleanup_hook_pmd)(QPixmapData*);
+
+
+class QImagePixmapCleanupHooks;
+
+class Q_GUI_EXPORT QImagePixmapCleanupHooks
+{
+public:
+ static QImagePixmapCleanupHooks *instance();
+
+ static void enableCleanupHooks(const QImage &image);
+ static void enableCleanupHooks(const QPixmap &pixmap);
+ static void enableCleanupHooks(QPixmapData *pixmapData);
+
+ static bool isImageCached(const QImage &image);
+ static bool isPixmapCached(const QPixmap &pixmap);
+
+ // Gets called when a pixmap data is about to be modified:
+ void addPixmapDataModificationHook(_qt_pixmap_cleanup_hook_pmd);
+
+ // Gets called when a pixmap data is about to be destroyed:
+ void addPixmapDataDestructionHook(_qt_pixmap_cleanup_hook_pmd);
+
+ // Gets called when an image is about to be modified or destroyed:
+ void addImageHook(_qt_image_cleanup_hook_64);
+
+ void removePixmapDataModificationHook(_qt_pixmap_cleanup_hook_pmd);
+ void removePixmapDataDestructionHook(_qt_pixmap_cleanup_hook_pmd);
+ void removeImageHook(_qt_image_cleanup_hook_64);
+
+ static void executePixmapDataModificationHooks(QPixmapData*);
+ static void executePixmapDataDestructionHooks(QPixmapData*);
+ static void executeImageHooks(qint64 key);
+
+private:
+ QList<_qt_image_cleanup_hook_64> imageHooks;
+ QList<_qt_pixmap_cleanup_hook_pmd> pixmapModificationHooks;
+ QList<_qt_pixmap_cleanup_hook_pmd> pixmapDestructionHooks;
+};
+
+QT_END_NAMESPACE
+
+#endif // QIMAGEPIXMAP_CLEANUPHOOKS_P_H
diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp
new file mode 100644
index 0000000000..0a0dc35988
--- /dev/null
+++ b/src/gui/image/qimagereader.cpp
@@ -0,0 +1,1515 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QIMAGEREADER_DEBUG
+
+/*!
+ \class QImageReader
+ \brief The QImageReader class provides a format independent interface
+ for reading images from files or other devices.
+
+ \reentrant
+ \ingroup painting
+ \ingroup io
+
+ The most common way to read images is through QImage and QPixmap's
+ constructors, or by calling QImage::load() and
+ QPixmap::load(). QImageReader is a specialized class which gives
+ you more control when reading images. For example, you can read an
+ image into a specific size by calling setScaledSize(), and you can
+ select a clip rect, effectively loading only parts of an image, by
+ calling setClipRect(). Depending on the underlying support in the
+ image format, this can save memory and speed up loading of images.
+
+ To read an image, you start by constructing a QImageReader object.
+ Pass either a file name or a device pointer, and the image format
+ to QImageReader's constructor. You can then set several options,
+ such as the clip rect (by calling setClipRect()) and scaled size
+ (by calling setScaledSize()). canRead() returns the image if the
+ QImageReader can read the image (i.e., the image format is
+ supported and the device is open for reading). Call read() to read
+ the image.
+
+ If any error occurs when reading the image, read() will return a
+ null QImage. You can then call error() to find the type of error
+ that occurred, or errorString() to get a human readable
+ description of what went wrong.
+
+ Call supportedImageFormats() for a list of formats that
+ QImageReader can read. QImageReader supports all built-in image
+ formats, in addition to any image format plugins that support
+ reading.
+
+ QImageReader autodetects the image format by default, by looking at the
+ provided (optional) format string, the file name suffix, and the data
+ stream contents. You can enable or disable this feature, by calling
+ setAutoDetectImageFormat().
+
+ \sa QImageWriter, QImageIOHandler, QImageIOPlugin
+*/
+
+/*!
+ \enum QImageReader::ImageReaderError
+
+ This enum describes the different types of errors that can occur
+ when reading images with QImageReader.
+
+ \value FileNotFoundError QImageReader was used with a file name,
+ but not file was found with that name. This can also happen if the
+ file name contained no extension, and the file with the correct
+ extension is not supported by Qt.
+
+ \value DeviceError QImageReader encountered a device error when
+ reading the image. You can consult your particular device for more
+ details on what went wrong.
+
+ \value UnsupportedFormatError Qt does not support the requested
+ image format.
+
+ \value InvalidDataError The image data was invalid, and
+ QImageReader was unable to read an image from it. The can happen
+ if the image file is damaged.
+
+ \value UnknownError An unknown error occurred. If you get this
+ value after calling read(), it is most likely caused by a bug in
+ QImageReader.
+*/
+#include "qimagereader.h"
+
+#include <qbytearray.h>
+#ifdef QIMAGEREADER_DEBUG
+#include <qdebug.h>
+#endif
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qimage.h>
+#include <qimageiohandler.h>
+#include <qlist.h>
+#include <qrect.h>
+#include <qset.h>
+#include <qsize.h>
+#include <qcolor.h>
+#include <qvariant.h>
+
+// factory loader
+#include <qcoreapplication.h>
+#include <private/qfactoryloader_p.h>
+
+// image handlers
+#include <private/qbmphandler_p.h>
+#include <private/qppmhandler_p.h>
+#include <private/qxbmhandler_p.h>
+#include <private/qxpmhandler_p.h>
+#ifndef QT_NO_IMAGEFORMAT_PNG
+#include <private/qpnghandler_p.h>
+#endif
+#ifndef QT_NO_IMAGEFORMAT_JPEG
+#include <private/qjpeghandler_p.h>
+#endif
+#ifndef QT_NO_IMAGEFORMAT_MNG
+#include <private/qmnghandler_p.h>
+#endif
+#ifndef QT_NO_IMAGEFORMAT_TIFF
+#include <private/qtiffhandler_p.h>
+#endif
+#ifdef QT_BUILTIN_GIF_READER
+#include <private/qgifhandler_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_LIBRARY
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+ (QImageIOHandlerFactoryInterface_iid, QLatin1String("/imageformats")))
+#endif
+
+enum _qt_BuiltInFormatType {
+#ifndef QT_NO_IMAGEFORMAT_PNG
+ _qt_PngFormat,
+#endif
+#ifndef QT_NO_IMAGEFORMAT_JPEG
+ _qt_JpgFormat,
+#endif
+#ifndef QT_NO_IMAGEFORMAT_MNG
+ _qt_MngFormat,
+#endif
+#ifndef QT_NO_IMAGEFORMAT_TIFF
+ _qt_TifFormat,
+#endif
+#ifdef QT_BUILTIN_GIF_READER
+ _qt_GifFormat,
+#endif
+ _qt_BmpFormat,
+#ifndef QT_NO_IMAGEFORMAT_PPM
+ _qt_PpmFormat,
+ _qt_PgmFormat,
+ _qt_PbmFormat,
+#endif
+#ifndef QT_NO_IMAGEFORMAT_XBM
+ _qt_XbmFormat,
+#endif
+#ifndef QT_NO_IMAGEFORMAT_XPM
+ _qt_XpmFormat,
+#endif
+ _qt_NumFormats,
+ _qt_NoFormat = -1
+};
+
+struct _qt_BuiltInFormatStruct
+{
+ _qt_BuiltInFormatType type;
+ const char *extension;
+};
+
+static const _qt_BuiltInFormatStruct _qt_BuiltInFormats[] = {
+#ifndef QT_NO_IMAGEFORMAT_PNG
+ {_qt_PngFormat, "png"},
+#endif
+#ifndef QT_NO_IMAGEFORMAT_JPEG
+ {_qt_JpgFormat, "jpg"},
+#endif
+#ifndef QT_NO_IMAGEFORMAT_MNG
+ {_qt_MngFormat, "mng"},
+#endif
+#ifndef QT_NO_IMAGEFORMAT_TIFF
+ {_qt_TifFormat, "tif"},
+#endif
+#ifdef QT_BUILTIN_GIF_READER
+ {_qt_GifFormat, "gif"},
+#endif
+ {_qt_BmpFormat, "bmp"},
+#ifndef QT_NO_IMAGEFORMAT_PPM
+ {_qt_PpmFormat, "ppm"},
+ {_qt_PgmFormat, "pgm"},
+ {_qt_PbmFormat, "pbm"},
+#endif
+#ifndef QT_NO_IMAGEFORMAT_XBM
+ {_qt_XbmFormat, "xbm"},
+#endif
+#ifndef QT_NO_IMAGEFORMAT_XPM
+ {_qt_XpmFormat, "xpm"},
+#endif
+ {_qt_NoFormat, ""}
+};
+
+static QImageIOHandler *createReadHandlerHelper(QIODevice *device,
+ const QByteArray &format,
+ bool autoDetectImageFormat,
+ bool ignoresFormatAndExtension)
+{
+ if (!autoDetectImageFormat && format.isEmpty())
+ return 0;
+
+ QByteArray form = format.toLower();
+ QImageIOHandler *handler = 0;
+
+#ifndef QT_NO_LIBRARY
+ // check if we have plugins that support the image format
+ QFactoryLoader *l = loader();
+ QStringList keys = l->keys();
+#endif
+ QByteArray suffix;
+
+#ifdef QIMAGEREADER_DEBUG
+ qDebug() << "QImageReader::createReadHandler( device =" << (void *)device << ", format =" << format << "),"
+ << keys.size() << "plugins available: " << keys;
+#endif
+
+#ifndef QT_NO_LIBRARY
+ int suffixPluginIndex = -1;
+ if (device && format.isEmpty() && autoDetectImageFormat && !ignoresFormatAndExtension) {
+ // if there's no format, see if \a device is a file, and if so, find
+ // the file suffix and find support for that format among our plugins.
+ // this allows plugins to override our built-in handlers.
+ if (QFile *file = qobject_cast<QFile *>(device)) {
+#ifdef QIMAGEREADER_DEBUG
+ qDebug() << "QImageReader::createReadHandler: device is a file:" << file->fileName();
+#endif
+ if (!(suffix = QFileInfo(file->fileName()).suffix().toLower().toLatin1()).isEmpty()) {
+ int index = keys.indexOf(QString::fromLatin1(suffix));
+ if (index != -1) {
+#ifdef QIMAGEREADER_DEBUG
+ qDebug() << "QImageReader::createReadHandler: suffix recognized; the"
+ << suffix << "plugin might be able to read this";
+#endif
+ suffixPluginIndex = index;
+ }
+ }
+ }
+ }
+#endif // QT_NO_LIBRARY
+
+ QByteArray testFormat = !form.isEmpty() ? form : suffix;
+
+ if (ignoresFormatAndExtension)
+ testFormat = QByteArray();
+
+#ifndef QT_NO_LIBRARY
+ if (suffixPluginIndex != -1) {
+ // check if the plugin that claims support for this format can load
+ // from this device with this format.
+ const qint64 pos = device ? device->pos() : 0;
+ QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(l->instance(QString::fromLatin1(suffix)));
+ if (plugin && plugin->capabilities(device, testFormat) & QImageIOPlugin::CanRead) {
+ handler = plugin->create(device, testFormat);
+#ifdef QIMAGEREADER_DEBUG
+ qDebug() << "QImageReader::createReadHandler: using the" << suffix
+ << "plugin";
+#endif
+ }
+ if (device && !device->isSequential())
+ device->seek(pos);
+ }
+
+ if (!handler && !testFormat.isEmpty() && !ignoresFormatAndExtension) {
+ // check if any plugin supports the format (they are not allowed to
+ // read from the device yet).
+ const qint64 pos = device ? device->pos() : 0;
+
+ if (autoDetectImageFormat) {
+ for (int i = 0; i < keys.size(); ++i) {
+ if (i != suffixPluginIndex) {
+ QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(l->instance(keys.at(i)));
+ if (plugin && plugin->capabilities(device, testFormat) & QImageIOPlugin::CanRead) {
+#ifdef QIMAGEREADER_DEBUG
+ qDebug() << "QImageReader::createReadHandler: the" << keys.at(i) << "plugin can read this format";
+#endif
+ handler = plugin->create(device, testFormat);
+ break;
+ }
+ }
+ }
+ } else {
+ QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(l->instance(QLatin1String(testFormat)));
+ if (plugin && plugin->capabilities(device, testFormat) & QImageIOPlugin::CanRead) {
+#ifdef QIMAGEREADER_DEBUG
+ qDebug() << "QImageReader::createReadHandler: the" << testFormat << "plugin can read this format";
+#endif
+ handler = plugin->create(device, testFormat);
+ }
+ }
+ if (device && !device->isSequential())
+ device->seek(pos);
+ }
+
+#endif // QT_NO_LIBRARY
+
+ // if we don't have a handler yet, check if we have built-in support for
+ // the format
+ if (!handler && !testFormat.isEmpty()) {
+ if (false) {
+#ifndef QT_NO_IMAGEFORMAT_PNG
+ } else if (testFormat == "png") {
+ handler = new QPngHandler;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_JPEG
+ } else if (testFormat == "jpg" || testFormat == "jpeg") {
+ handler = new QJpegHandler;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_MNG
+ } else if (testFormat == "mng") {
+ handler = new QMngHandler;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_TIFF
+ } else if (testFormat == "tif" || testFormat == "tiff") {
+ handler = new QTiffHandler;
+#endif
+#ifdef QT_BUILTIN_GIF_READER
+ } else if (testFormat == "gif") {
+ handler = new QGifHandler;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_BMP
+ } else if (testFormat == "bmp") {
+ handler = new QBmpHandler;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_XPM
+ } else if (testFormat == "xpm") {
+ handler = new QXpmHandler;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_XBM
+ } else if (testFormat == "xbm") {
+ handler = new QXbmHandler;
+ handler->setOption(QImageIOHandler::SubType, testFormat);
+#endif
+#ifndef QT_NO_IMAGEFORMAT_PPM
+ } else if (testFormat == "pbm" || testFormat == "pbmraw" || testFormat == "pgm"
+ || testFormat == "pgmraw" || testFormat == "ppm" || testFormat == "ppmraw") {
+ handler = new QPpmHandler;
+ handler->setOption(QImageIOHandler::SubType, testFormat);
+#endif
+ }
+
+#ifdef QIMAGEREADER_DEBUG
+ if (handler)
+ qDebug() << "QImageReader::createReadHandler: using the built-in handler for" << testFormat;
+#endif
+ }
+
+#ifndef QT_NO_LIBRARY
+ if (!handler && (autoDetectImageFormat || ignoresFormatAndExtension)) {
+ // check if any of our plugins recognize the file from its contents.
+ const qint64 pos = device ? device->pos() : 0;
+ for (int i = 0; i < keys.size(); ++i) {
+ if (i != suffixPluginIndex) {
+ QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(l->instance(keys.at(i)));
+ if (plugin && plugin->capabilities(device, QByteArray()) & QImageIOPlugin::CanRead) {
+ handler = plugin->create(device, testFormat);
+#ifdef QIMAGEREADER_DEBUG
+ qDebug() << "QImageReader::createReadHandler: the" << keys.at(i) << "plugin can read this data";
+#endif
+ break;
+ }
+ }
+ }
+ if (device && !device->isSequential())
+ device->seek(pos);
+ }
+#endif // QT_NO_LIBRARY
+
+ if (!handler && (autoDetectImageFormat || ignoresFormatAndExtension)) {
+ // check if any of our built-in handlers recognize the file from its
+ // contents.
+ int currentFormat = 0;
+ if (!suffix.isEmpty()) {
+ // If reading from a file with a suffix, start testing our
+ // built-in handler for that suffix first.
+ for (int i = 0; i < _qt_NumFormats; ++i) {
+ if (_qt_BuiltInFormats[i].extension == suffix) {
+ currentFormat = i;
+ break;
+ }
+ }
+ }
+
+ QByteArray subType;
+ int numFormats = _qt_NumFormats;
+ while (device && numFormats >= 0) {
+ const _qt_BuiltInFormatStruct *formatStruct = &_qt_BuiltInFormats[currentFormat];
+
+ const qint64 pos = device->pos();
+ switch (formatStruct->type) {
+#ifndef QT_NO_IMAGEFORMAT_PNG
+ case _qt_PngFormat:
+ if (QPngHandler::canRead(device))
+ handler = new QPngHandler;
+ break;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_JPEG
+ case _qt_JpgFormat:
+ if (QJpegHandler::canRead(device))
+ handler = new QJpegHandler;
+ break;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_MNG
+ case _qt_MngFormat:
+ if (QMngHandler::canRead(device))
+ handler = new QMngHandler;
+ break;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_TIFF
+ case _qt_TifFormat:
+ if (QTiffHandler::canRead(device))
+ handler = new QTiffHandler;
+ break;
+#endif
+#ifdef QT_BUILTIN_GIF_READER
+ case _qt_GifFormat:
+ if (QGifHandler::canRead(device))
+ handler = new QGifHandler;
+ break;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_BMP
+ case _qt_BmpFormat:
+ if (QBmpHandler::canRead(device))
+ handler = new QBmpHandler;
+ break;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_XPM
+ case _qt_XpmFormat:
+ if (QXpmHandler::canRead(device))
+ handler = new QXpmHandler;
+ break;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_PPM
+ case _qt_PbmFormat:
+ case _qt_PgmFormat:
+ case _qt_PpmFormat:
+ if (QPpmHandler::canRead(device, &subType)) {
+ handler = new QPpmHandler;
+ handler->setOption(QImageIOHandler::SubType, subType);
+ }
+ break;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_XBM
+ case _qt_XbmFormat:
+ if (QXbmHandler::canRead(device))
+ handler = new QXbmHandler;
+ break;
+#endif
+ default:
+ break;
+ }
+ if (!device->isSequential())
+ device->seek(pos);
+
+ if (handler) {
+#ifdef QIMAGEREADER_DEBUG
+ qDebug() << "QImageReader::createReadHandler: the" << formatStruct->extension
+ << "built-in handler can read this data";
+#endif
+ break;
+ }
+
+ --numFormats;
+ ++currentFormat;
+ currentFormat %= _qt_NumFormats;
+ }
+ }
+
+ if (!handler) {
+#ifdef QIMAGEREADER_DEBUG
+ qDebug() << "QImageReader::createReadHandler: no handlers found. giving up.";
+#endif
+ // no handler: give up.
+ return 0;
+ }
+
+ handler->setDevice(device);
+ if (!form.isEmpty())
+ handler->setFormat(form);
+ return handler;
+}
+
+class QImageReaderPrivate
+{
+public:
+ QImageReaderPrivate(QImageReader *qq);
+ ~QImageReaderPrivate();
+
+ // device
+ QByteArray format;
+ bool autoDetectImageFormat;
+ bool ignoresFormatAndExtension;
+ QIODevice *device;
+ bool deleteDevice;
+ QImageIOHandler *handler;
+ bool initHandler();
+
+ // image options
+ QRect clipRect;
+ QSize scaledSize;
+ QRect scaledClipRect;
+ int quality;
+ QMap<QString, QString> text;
+ void getText();
+
+ // error
+ QImageReader::ImageReaderError imageReaderError;
+ QString errorString;
+
+ QImageReader *q;
+};
+
+/*!
+ \internal
+*/
+QImageReaderPrivate::QImageReaderPrivate(QImageReader *qq)
+ : autoDetectImageFormat(true), ignoresFormatAndExtension(false)
+{
+ device = 0;
+ deleteDevice = false;
+ handler = 0;
+ quality = -1;
+ imageReaderError = QImageReader::UnknownError;
+
+ q = qq;
+}
+
+/*!
+ \internal
+*/
+QImageReaderPrivate::~QImageReaderPrivate()
+{
+ if (deleteDevice)
+ delete device;
+ delete handler;
+}
+
+/*!
+ \internal
+*/
+bool QImageReaderPrivate::initHandler()
+{
+ // check some preconditions
+ if (!device || (!deleteDevice && !device->isOpen() && !device->open(QIODevice::ReadOnly))) {
+ imageReaderError = QImageReader::DeviceError;
+ errorString = QLatin1String(QT_TRANSLATE_NOOP(QImageReader, "Invalid device"));
+ return false;
+ }
+
+ // probe the file extension
+ if (deleteDevice && !device->isOpen() && !device->open(QIODevice::ReadOnly) && autoDetectImageFormat) {
+ QList<QByteArray> extensions = QImageReader::supportedImageFormats();
+ if (!format.isEmpty()) {
+ // Try the most probable extension first
+ int currentFormatIndex = extensions.indexOf(format.toLower());
+ if (currentFormatIndex > 0)
+ extensions.swap(0, currentFormatIndex);
+ }
+
+ int currentExtension = 0;
+
+ QFile *file = static_cast<QFile *>(device);
+ QString fileName = file->fileName();
+
+ do {
+ file->setFileName(fileName + QLatin1Char('.')
+ + QString::fromLatin1(extensions.at(currentExtension++).constData()));
+ file->open(QIODevice::ReadOnly);
+ } while (!file->isOpen() && currentExtension < extensions.size());
+
+ if (!device->isOpen()) {
+ imageReaderError = QImageReader::FileNotFoundError;
+ errorString = QLatin1String(QT_TRANSLATE_NOOP(QImageReader, "File not found"));
+ file->setFileName(fileName); // restore the old file name
+ return false;
+ }
+ }
+
+ // assign a handler
+ if (!handler && (handler = createReadHandlerHelper(device, format, autoDetectImageFormat, ignoresFormatAndExtension)) == 0) {
+ imageReaderError = QImageReader::UnsupportedFormatError;
+ errorString = QLatin1String(QT_TRANSLATE_NOOP(QImageReader, "Unsupported image format"));
+ return false;
+ }
+ return true;
+}
+
+/*!
+ \internal
+*/
+void QImageReaderPrivate::getText()
+{
+ if (!text.isEmpty() || (!handler && !initHandler()) || !handler->supportsOption(QImageIOHandler::Description))
+ return;
+ foreach (QString pair, handler->option(QImageIOHandler::Description).toString().split(
+ QLatin1String("\n\n"))) {
+ int index = pair.indexOf(QLatin1Char(':'));
+ if (index >= 0 && pair.indexOf(QLatin1Char(' ')) < index) {
+ text.insert(QLatin1String("Description"), pair.simplified());
+ } else {
+ QString key = pair.left(index);
+ text.insert(key, pair.mid(index + 2).simplified());
+ }
+ }
+}
+
+/*!
+ Constructs an empty QImageReader object. Before reading an image,
+ call setDevice() or setFileName().
+*/
+QImageReader::QImageReader()
+ : d(new QImageReaderPrivate(this))
+{
+}
+
+/*!
+ Constructs a QImageReader object with the device \a device and the
+ image format \a format.
+*/
+QImageReader::QImageReader(QIODevice *device, const QByteArray &format)
+ : d(new QImageReaderPrivate(this))
+{
+ d->device = device;
+ d->format = format;
+}
+
+/*!
+ Constructs a QImageReader object with the file name \a fileName
+ and the image format \a format.
+
+ \sa setFileName()
+*/
+QImageReader::QImageReader(const QString &fileName, const QByteArray &format)
+ : d(new QImageReaderPrivate(this))
+{
+ QFile *file = new QFile(fileName);
+ d->device = file;
+ d->deleteDevice = true;
+ d->format = format;
+}
+
+/*!
+ Destructs the QImageReader object.
+*/
+QImageReader::~QImageReader()
+{
+ delete d;
+}
+
+/*!
+ Sets the format QImageReader will use when reading images, to \a
+ format. \a format is a case insensitive text string. Example:
+
+ \snippet doc/src/snippets/code/src_gui_image_qimagereader.cpp 0
+
+ You can call supportedImageFormats() for the full list of formats
+ QImageReader supports.
+
+ \sa format()
+*/
+void QImageReader::setFormat(const QByteArray &format)
+{
+ d->format = format;
+}
+
+/*!
+ Returns the format QImageReader uses for reading images.
+
+ You can call this function after assigning a device to the
+ reader to determine the format of the device. For example:
+
+ \snippet doc/src/snippets/code/src_gui_image_qimagereader.cpp 1
+
+ If the reader cannot read any image from the device (e.g., there is no
+ image there, or the image has already been read), or if the format is
+ unsupported, this function returns an empty QByteArray().
+
+ \sa setFormat(), supportedImageFormats()
+*/
+QByteArray QImageReader::format() const
+{
+ if (d->format.isEmpty()) {
+ if (!d->initHandler())
+ return QByteArray();
+ return d->handler->canRead() ? d->handler->format() : QByteArray();
+ }
+
+ return d->format;
+}
+
+/*!
+ If \a enabled is true, image format autodetection is enabled; otherwise,
+ it is disabled. By default, autodetection is enabled.
+
+ QImageReader uses an extensive approach to detecting the image format;
+ firstly, if you pass a file name to QImageReader, it will attempt to
+ detect the file extension if the given file name does not point to an
+ existing file, by appending supported default extensions to the given file
+ name, one at a time. It then uses the following approach to detect the
+ image format:
+
+ \list
+
+ \o Image plugins are queried first, based on either the optional format
+ string, or the file name suffix (if the source device is a file). No
+ content detection is done at this stage. QImageReader will choose the
+ first plugin that supports reading for this format.
+
+ \o If no plugin supports the image format, Qt's built-in handlers are
+ checked based on either the optional format string, or the file name
+ suffix.
+
+ \o If no capable plugins or built-in handlers are found, each plugin is
+ tested by inspecting the content of the data stream.
+
+ \o If no plugins could detect the image format based on data contents,
+ each built-in image handler is tested by inspecting the contents.
+
+ \o Finally, if all above approaches fail, QImageReader will report failure
+ when trying to read the image.
+
+ \endlist
+
+ By disabling image format autodetection, QImageReader will only query the
+ plugins and built-in handlers based on the format string (i.e., no file
+ name extensions are tested).
+
+ \sa QImageIOHandler::canRead(), QImageIOPlugin::capabilities()
+*/
+void QImageReader::setAutoDetectImageFormat(bool enabled)
+{
+ d->autoDetectImageFormat = enabled;
+}
+
+/*!
+ Returns true if image format autodetection is enabled on this image
+ reader; otherwise returns false. By default, autodetection is enabled.
+
+ \sa setAutoDetectImageFormat()
+*/
+bool QImageReader::autoDetectImageFormat() const
+{
+ return d->autoDetectImageFormat;
+}
+
+
+/*!
+ If \a ignored is set to true, then the image reader will ignore
+ specified formats or file extensions and decide which plugin to
+ use only based on the contents in the datastream.
+
+ Setting this flag means that all image plugins gets loaded. Each
+ plugin will read the first bytes in the image data and decide if
+ the plugin is compatible or not.
+
+ This also disables auto detecting the image format.
+
+ \sa decideFormatFromContent()
+*/
+
+void QImageReader::setDecideFormatFromContent(bool ignored)
+{
+ d->ignoresFormatAndExtension = ignored;
+}
+
+
+/*!
+ Returns whether the image reader should decide which plugin to use
+ only based on the contents of the datastream rather than on the file
+ extension.
+
+ \sa setDecideFormatFromContent()
+*/
+
+bool QImageReader::decideFormatFromContent() const
+{
+ return d->ignoresFormatAndExtension;
+}
+
+
+/*!
+ Sets QImageReader's device to \a device. If a device has already
+ been set, the old device is removed from QImageReader and is
+ otherwise left unchanged.
+
+ If the device is not already open, QImageReader will attempt to
+ open the device in \l QIODevice::ReadOnly mode by calling
+ open(). Note that this does not work for certain devices, such as
+ QProcess, QTcpSocket and QUdpSocket, where more logic is required
+ to open the device.
+
+ \sa device(), setFileName()
+*/
+void QImageReader::setDevice(QIODevice *device)
+{
+ if (d->device && d->deleteDevice)
+ delete d->device;
+ d->device = device;
+ d->deleteDevice = false;
+ delete d->handler;
+ d->handler = 0;
+ d->text.clear();
+}
+
+/*!
+ Returns the device currently assigned to QImageReader, or 0 if no
+ device has been assigned.
+*/
+QIODevice *QImageReader::device() const
+{
+ return d->device;
+}
+
+/*!
+ Sets the file name of QImageReader to \a fileName. Internally,
+ QImageReader will create a QFile object and open it in \l
+ QIODevice::ReadOnly mode, and use this when reading images.
+
+ If \a fileName does not include a file extension (e.g., .png or .bmp),
+ QImageReader will cycle through all supported extensions until it finds
+ a matching file.
+
+ \sa fileName(), setDevice(), supportedImageFormats()
+*/
+void QImageReader::setFileName(const QString &fileName)
+{
+ setDevice(new QFile(fileName));
+ d->deleteDevice = true;
+}
+
+/*!
+ If the currently assigned device is a QFile, or if setFileName()
+ has been called, this function returns the name of the file
+ QImageReader reads from. Otherwise (i.e., if no device has been
+ assigned or the device is not a QFile), an empty QString is
+ returned.
+
+ \sa setFileName(), setDevice()
+*/
+QString QImageReader::fileName() const
+{
+ QFile *file = qobject_cast<QFile *>(d->device);
+ return file ? file->fileName() : QString();
+}
+
+/*!
+ \since 4.2
+
+ This is an image format specific function that sets the quality
+ level of the image to \a quality. For image formats that do not
+ support setting the quality, this value is ignored.
+
+ The value range of \a quality depends on the image format. For
+ example, the "jpeg" format supports a quality range from 0 (low
+ quality, high compression) to 100 (high quality, low compression).
+
+ \sa quality()
+*/
+void QImageReader::setQuality(int quality)
+{
+ d->quality = quality;
+}
+
+/*!
+ \since 4.2
+
+ Returns the quality level of the image.
+
+ \sa setQuality()
+*/
+int QImageReader::quality() const
+{
+ return d->quality;
+}
+
+
+/*!
+ Returns the size of the image, without actually reading the image
+ contents.
+
+ If the image format does not support this feature, this function returns
+ an invalid size. Qt's built-in image handlers all support this feature,
+ but custom image format plugins are not required to do so.
+
+ \sa QImageIOHandler::ImageOption, QImageIOHandler::option(), QImageIOHandler::supportsOption()
+*/
+QSize QImageReader::size() const
+{
+ if (!d->initHandler())
+ return QSize();
+
+ if (d->handler->supportsOption(QImageIOHandler::Size))
+ return d->handler->option(QImageIOHandler::Size).toSize();
+
+ return QSize();
+}
+
+/*!
+ \since 4.5
+
+ Returns the format of the image, without actually reading the image
+ contents. The format describes the image format \l QImageReader::read()
+ returns, not the format of the actual image.
+
+ If the image format does not support this feature, this function returns
+ an invalid format.
+
+ \sa QImageIOHandler::ImageOption, QImageIOHandler::option(), QImageIOHandler::supportsOption()
+*/
+QImage::Format QImageReader::imageFormat() const
+{
+ if (!d->initHandler())
+ return QImage::Format_Invalid;
+
+ if (d->handler->supportsOption(QImageIOHandler::ImageFormat))
+ return (QImage::Format)d->handler->option(QImageIOHandler::ImageFormat).toInt();
+
+ return QImage::Format_Invalid;
+}
+
+/*!
+ \since 4.1
+
+ Returns the text keys for this image. You can use
+ these keys with text() to list the image text for
+ a certain key.
+
+ Support for this option is implemented through
+ QImageIOHandler::Description.
+
+ \sa text(), QImageWriter::setText(), QImage::textKeys()
+*/
+QStringList QImageReader::textKeys() const
+{
+ d->getText();
+ return d->text.keys();
+}
+
+/*!
+ \since 4.1
+
+ Returns the image text associated with \a key.
+
+ Support for this option is implemented through
+ QImageIOHandler::Description.
+
+ \sa textKeys(), QImageWriter::setText()
+*/
+QString QImageReader::text(const QString &key) const
+{
+ d->getText();
+ return d->text.value(key);
+}
+
+/*!
+ Sets the image clip rect (also known as the ROI, or Region Of
+ Interest) to \a rect. The coordinates of \a rect are relative to
+ the untransformed image size, as returned by size().
+
+ \sa clipRect(), setScaledSize(), setScaledClipRect()
+*/
+void QImageReader::setClipRect(const QRect &rect)
+{
+ d->clipRect = rect;
+}
+
+/*!
+ Returns the clip rect (also known as the ROI, or Region Of
+ Interest) of the image. If no clip rect has been set, an invalid
+ QRect is returned.
+
+ \sa setClipRect()
+*/
+QRect QImageReader::clipRect() const
+{
+ return d->clipRect;
+}
+
+/*!
+ Sets the scaled size of the image to \a size. The scaling is
+ performed after the initial clip rect, but before the scaled clip
+ rect is applied. The algorithm used for scaling depends on the
+ image format. By default (i.e., if the image format does not
+ support scaling), QImageReader will use QImage::scale() with
+ Qt::SmoothScaling.
+
+ \sa scaledSize(), setClipRect(), setScaledClipRect()
+*/
+void QImageReader::setScaledSize(const QSize &size)
+{
+ d->scaledSize = size;
+}
+
+/*!
+ Returns the scaled size of the image.
+
+ \sa setScaledSize()
+*/
+QSize QImageReader::scaledSize() const
+{
+ return d->scaledSize;
+}
+
+/*!
+ Sets the scaled clip rect to \a rect. The scaled clip rect is the
+ clip rect (also known as ROI, or Region Of Interest) that is
+ applied after the image has been scaled.
+
+ \sa scaledClipRect(), setScaledSize()
+*/
+void QImageReader::setScaledClipRect(const QRect &rect)
+{
+ d->scaledClipRect = rect;
+}
+
+/*!
+ Returns the scaled clip rect of the image.
+
+ \sa setScaledClipRect()
+*/
+QRect QImageReader::scaledClipRect() const
+{
+ return d->scaledClipRect;
+}
+
+/*!
+ \since 4.1
+
+ Sets the background color to \a color.
+ Image formats that support this operation are expected to
+ initialize the background to \a color before reading an image.
+
+ \sa backgroundColor(), read()
+*/
+void QImageReader::setBackgroundColor(const QColor &color)
+{
+ if (!d->initHandler())
+ return;
+ if (d->handler->supportsOption(QImageIOHandler::BackgroundColor))
+ d->handler->setOption(QImageIOHandler::BackgroundColor, color);
+}
+
+/*!
+ \since 4.1
+
+ Returns the background color that's used when reading an image.
+ If the image format does not support setting the background color
+ an invalid color is returned.
+
+ \sa setBackgroundColor(), read()
+*/
+QColor QImageReader::backgroundColor() const
+{
+ if (!d->initHandler())
+ return QColor();
+ if (d->handler->supportsOption(QImageIOHandler::BackgroundColor))
+ return qvariant_cast<QColor>(d->handler->option(QImageIOHandler::BackgroundColor));
+ return QColor();
+}
+
+/*!
+ \since 4.1
+
+ Returns true if the image format supports animation;
+ otherwise, false is returned.
+
+ \sa QMovie::supportedFormats()
+*/
+bool QImageReader::supportsAnimation() const
+{
+ if (!d->initHandler())
+ return false;
+ if (d->handler->supportsOption(QImageIOHandler::Animation))
+ return d->handler->option(QImageIOHandler::Animation).toBool();
+ return false;
+}
+
+/*!
+ Returns true if an image can be read for the device (i.e., the
+ image format is supported, and the device seems to contain valid
+ data); otherwise returns false.
+
+ canRead() is a lightweight function that only does a quick test to
+ see if the image data is valid. read() may still return false
+ after canRead() returns true, if the image data is corrupt.
+
+ For images that support animation, canRead() returns false when
+ all frames have been read.
+
+ \sa read(), supportedImageFormats()
+*/
+bool QImageReader::canRead() const
+{
+ if (!d->initHandler())
+ return false;
+
+ return d->handler->canRead();
+}
+
+/*!
+ Reads an image from the device. On success, the image that was
+ read is returned; otherwise, a null QImage is returned. You can
+ then call error() to find the type of error that occurred, or
+ errorString() to get a human readable description of the error.
+
+ For image formats that support animation, calling read()
+ repeatedly will return the next frame. When all frames have been
+ read, a null image will be returned.
+
+ \sa canRead(), supportedImageFormats(), supportsAnimation(), QMovie
+*/
+QImage QImageReader::read()
+{
+ // Because failed image reading might have side effects, we explicitly
+ // return a null image instead of the image we've just created.
+ QImage image;
+ return read(&image) ? image : QImage();
+}
+
+/*!
+ \overload
+
+ Reads an image from the device into \a image, which must point to a
+ QImage. Returns true on success; otherwise, returns false.
+
+ If \a image has same format and size as the image data that is about to be
+ read, this function may not need to allocate a new image before
+ reading. Because of this, it can be faster than the other read() overload,
+ which always constructs a new image; especially when reading several
+ images with the same format and size.
+
+ \snippet doc/src/snippets/code/src_gui_image_qimagereader.cpp 2
+
+ For image formats that support animation, calling read() repeatedly will
+ return the next frame. When all frames have been read, a null image will
+ be returned.
+
+ \sa canRead(), supportedImageFormats(), supportsAnimation(), QMovie
+*/
+bool QImageReader::read(QImage *image)
+{
+ if (!image) {
+ qWarning("QImageReader::read: cannot read into null pointer");
+ return false;
+ }
+
+ if (!d->handler && !d->initHandler())
+ return false;
+
+ // set the handler specific options.
+ if (d->handler->supportsOption(QImageIOHandler::ScaledSize) && d->scaledSize.isValid()) {
+ if ((d->handler->supportsOption(QImageIOHandler::ClipRect) && !d->clipRect.isNull())
+ || d->clipRect.isNull()) {
+ // Only enable the ScaledSize option if there is no clip rect, or
+ // if the handler also supports ClipRect.
+ d->handler->setOption(QImageIOHandler::ScaledSize, d->scaledSize);
+ }
+ }
+ if (d->handler->supportsOption(QImageIOHandler::ClipRect) && !d->clipRect.isNull())
+ d->handler->setOption(QImageIOHandler::ClipRect, d->clipRect);
+ if (d->handler->supportsOption(QImageIOHandler::ScaledClipRect) && !d->scaledClipRect.isNull())
+ d->handler->setOption(QImageIOHandler::ScaledClipRect, d->scaledClipRect);
+ if (d->handler->supportsOption(QImageIOHandler::Quality))
+ d->handler->setOption(QImageIOHandler::Quality, d->quality);
+
+ // read the image
+ if (!d->handler->read(image)) {
+ d->imageReaderError = InvalidDataError;
+ d->errorString = QLatin1String(QT_TRANSLATE_NOOP(QImageReader, "Unable to read image data"));
+ return false;
+ }
+
+ // provide default implementations for any unsupported image
+ // options
+ if (d->handler->supportsOption(QImageIOHandler::ClipRect) && !d->clipRect.isNull()) {
+ if (d->handler->supportsOption(QImageIOHandler::ScaledSize) && d->scaledSize.isValid()) {
+ if (d->handler->supportsOption(QImageIOHandler::ScaledClipRect) && !d->scaledClipRect.isNull()) {
+ // all features are supported by the handler; nothing to do.
+ } else {
+ // the image is already scaled, so apply scaled clipping.
+ if (!d->scaledClipRect.isNull())
+ *image = image->copy(d->scaledClipRect);
+ }
+ } else {
+ if (d->handler->supportsOption(QImageIOHandler::ScaledClipRect) && !d->scaledClipRect.isNull()) {
+ // supports scaled clipping but not scaling, most
+ // likely a broken handler.
+ } else {
+ if (d->scaledSize.isValid()) {
+ *image = image->scaled(d->scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+ }
+ if (d->scaledClipRect.isValid()) {
+ *image = image->copy(d->scaledClipRect);
+ }
+ }
+ }
+ } else {
+ if (d->handler->supportsOption(QImageIOHandler::ScaledSize) && d->scaledSize.isValid()) {
+ // in this case, there's nothing we can do. if the
+ // plugin supports scaled size but not ClipRect, then
+ // we have to ignore ClipRect."
+
+ if (d->handler->supportsOption(QImageIOHandler::ScaledClipRect) && !d->scaledClipRect.isNull()) {
+ // nothing to do (ClipRect is ignored!)
+ } else {
+ // provide all workarounds.
+ if (d->scaledClipRect.isValid()) {
+ *image = image->copy(d->scaledClipRect);
+ }
+ }
+ } else {
+ if (d->handler->supportsOption(QImageIOHandler::ScaledClipRect) && !d->scaledClipRect.isNull()) {
+ // this makes no sense; a handler that supports
+ // ScaledClipRect but not ScaledSize is broken, and we
+ // can't work around it.
+ } else {
+ // provide all workarounds.
+ if (d->clipRect.isValid())
+ *image = image->copy(d->clipRect);
+ if (d->scaledSize.isValid())
+ *image = image->scaled(d->scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+ if (d->scaledClipRect.isValid())
+ *image = image->copy(d->scaledClipRect);
+ }
+ }
+ }
+
+ return true;
+}
+
+/*!
+ For image formats that support animation, this function steps over the
+ current image, returning true if successful or false if there is no
+ following image in the animation.
+
+ The default implementation calls read(), then discards the resulting
+ image, but the image handler may have a more efficient way of implementing
+ this operation.
+
+ \sa jumpToImage(), QImageIOHandler::jumpToNextImage()
+*/
+bool QImageReader::jumpToNextImage()
+{
+ if (!d->initHandler())
+ return false;
+ return d->handler->jumpToNextImage();
+}
+
+/*!
+ For image formats that support animation, this function skips to the image
+ whose sequence number is \a imageNumber, returning true if successful
+ or false if the corresponding image cannot be found.
+
+ The next call to read() will attempt to read this image.
+
+ \sa jumpToNextImage(), QImageIOHandler::jumpToImage()
+*/
+bool QImageReader::jumpToImage(int imageNumber)
+{
+ if (!d->initHandler())
+ return false;
+ return d->handler->jumpToImage(imageNumber);
+}
+
+/*!
+ For image formats that support animation, this function returns the number
+ of times the animation should loop. If this function returns -1, it can
+ either mean the animation should loop forever, or that an error occurred.
+ If an error occurred, canRead() will return false.
+
+ \sa supportsAnimation(), QImageIOHandler::loopCount(), canRead()
+*/
+int QImageReader::loopCount() const
+{
+ if (!d->initHandler())
+ return -1;
+ return d->handler->loopCount();
+}
+
+/*!
+ For image formats that support animation, this function returns the total
+ number of images in the animation. If the format does not support
+ animation, 0 is returned.
+
+ This function returns -1 if an error occurred.
+
+ \sa supportsAnimation(), QImageIOHandler::imageCount(), canRead()
+*/
+int QImageReader::imageCount() const
+{
+ if (!d->initHandler())
+ return -1;
+ return d->handler->imageCount();
+}
+
+/*!
+ For image formats that support animation, this function returns the number
+ of milliseconds to wait until displaying the next frame in the animation.
+ If the image format doesn't support animation, 0 is returned.
+
+ This function returns -1 if an error occurred.
+
+ \sa supportsAnimation(), QImageIOHandler::nextImageDelay(), canRead()
+*/
+int QImageReader::nextImageDelay() const
+{
+ if (!d->initHandler())
+ return -1;
+ return d->handler->nextImageDelay();
+}
+
+/*!
+ For image formats that support animation, this function returns the
+ sequence number of the current frame. If the image format doesn't support
+ animation, 0 is returned.
+
+ This function returns -1 if an error occurred.
+
+ \sa supportsAnimation(), QImageIOHandler::currentImageNumber(), canRead()
+*/
+int QImageReader::currentImageNumber() const
+{
+ if (!d->initHandler())
+ return -1;
+ return d->handler->currentImageNumber();
+}
+
+/*!
+ For image formats that support animation, this function returns
+ the rect for the current frame. Otherwise, a null rect is returned.
+
+ \sa supportsAnimation(), QImageIOHandler::currentImageRect()
+*/
+QRect QImageReader::currentImageRect() const
+{
+ if (!d->initHandler())
+ return QRect();
+ return d->handler->currentImageRect();
+}
+
+/*!
+ Returns the type of error that occurred last.
+
+ \sa ImageReaderError, errorString()
+*/
+QImageReader::ImageReaderError QImageReader::error() const
+{
+ return d->imageReaderError;
+}
+
+/*!
+ Returns a human readable description of the last error that
+ occurred.
+
+ \sa error()
+*/
+QString QImageReader::errorString() const
+{
+ if (d->errorString.isEmpty())
+ return QLatin1String(QT_TRANSLATE_NOOP(QImageReader, "Unknown error"));
+ return d->errorString;
+}
+
+/*!
+ \since 4.2
+
+ Returns true if the reader supports \a option; otherwise returns
+ false.
+
+ Different image formats support different options. Call this function to
+ determine whether a certain option is supported by the current format. For
+ example, the PNG format allows you to embed text into the image's metadata
+ (see text()), and the BMP format allows you to determine the image's size
+ without loading the whole image into memory (see size()).
+
+ \snippet doc/src/snippets/code/src_gui_image_qimagereader.cpp 3
+
+ \sa QImageWriter::supportsOption()
+*/
+bool QImageReader::supportsOption(QImageIOHandler::ImageOption option) const
+{
+ if (!d->initHandler())
+ return false;
+ return d->handler->supportsOption(option);
+}
+
+/*!
+ If supported, this function returns the image format of the file
+ \a fileName. Otherwise, an empty string is returned.
+*/
+QByteArray QImageReader::imageFormat(const QString &fileName)
+{
+ QFile file(fileName);
+ if (!file.open(QFile::ReadOnly))
+ return QByteArray();
+
+ return imageFormat(&file);
+}
+
+/*!
+ If supported, this function returns the image format of the device
+ \a device. Otherwise, an empty string is returned.
+
+ \sa QImageReader::autoDetectImageFormat()
+*/
+QByteArray QImageReader::imageFormat(QIODevice *device)
+{
+ QByteArray format;
+ QImageIOHandler *handler = createReadHandlerHelper(device, format, /* autoDetectImageFormat = */ true, false);
+ if (handler) {
+ if (handler->canRead())
+ format = handler->format();
+ delete handler;
+ }
+ return format;
+}
+
+/*!
+ Returns the list of image formats supported by QImageReader.
+
+ By default, Qt can read the following formats:
+
+ \table
+ \header \o Format \o Description
+ \row \o BMP \o Windows Bitmap
+ \row \o GIF \o Graphic Interchange Format (optional)
+ \row \o JPG \o Joint Photographic Experts Group
+ \row \o JPEG \o Joint Photographic Experts Group
+ \row \o MNG \o Multiple-image Network Graphics
+ \row \o PNG \o Portable Network Graphics
+ \row \o PBM \o Portable Bitmap
+ \row \o PGM \o Portable Graymap
+ \row \o PPM \o Portable Pixmap
+ \row \o TIFF \o Tagged Image File Format
+ \row \o XBM \o X11 Bitmap
+ \row \o XPM \o X11 Pixmap
+ \row \o SVG \o Scalable Vector Graphics
+ \endtable
+
+ Reading and writing SVG files is supported through Qt's
+ \l{QtSvg Module}{SVG Module}.
+
+ To configure Qt with GIF support, pass \c -qt-gif to the \c
+ configure script or check the appropriate option in the graphical
+ installer.
+
+ Note that the QApplication instance must be created before this function is
+ called.
+
+ \sa setFormat(), QImageWriter::supportedImageFormats(), QImageIOPlugin
+*/
+QList<QByteArray> QImageReader::supportedImageFormats()
+{
+ QSet<QByteArray> formats;
+ for (int i = 0; i < _qt_NumFormats; ++i)
+ formats << _qt_BuiltInFormats[i].extension;
+
+#ifndef QT_NO_LIBRARY
+ QFactoryLoader *l = loader();
+ QStringList keys = l->keys();
+
+ for (int i = 0; i < keys.count(); ++i) {
+ QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(l->instance(keys.at(i)));
+ if (plugin && plugin->capabilities(0, keys.at(i).toLatin1()) & QImageIOPlugin::CanRead)
+ formats << keys.at(i).toLatin1();
+ }
+#endif // QT_NO_LIBRARY
+
+ QList<QByteArray> sortedFormats;
+ for (QSet<QByteArray>::ConstIterator it = formats.constBegin(); it != formats.constEnd(); ++it)
+ sortedFormats << *it;
+
+ qSort(sortedFormats);
+ return sortedFormats;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/image/qimagereader.h b/src/gui/image/qimagereader.h
new file mode 100644
index 0000000000..cdac4555ca
--- /dev/null
+++ b/src/gui/image/qimagereader.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIMAGEREADER_H
+#define QIMAGEREADER_H
+
+#include <QtCore/qbytearray.h>
+#include <QtGui/qimage.h>
+#include <QtGui/qimageiohandler.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QColor;
+class QIODevice;
+class QRect;
+class QSize;
+class QStringList;
+
+class QImageReaderPrivate;
+class Q_GUI_EXPORT QImageReader
+{
+public:
+ enum ImageReaderError {
+ UnknownError,
+ FileNotFoundError,
+ DeviceError,
+ UnsupportedFormatError,
+ InvalidDataError
+ };
+
+ QImageReader();
+ explicit QImageReader(QIODevice *device, const QByteArray &format = QByteArray());
+ explicit QImageReader(const QString &fileName, const QByteArray &format = QByteArray());
+ ~QImageReader();
+
+ void setFormat(const QByteArray &format);
+ QByteArray format() const;
+
+ void setAutoDetectImageFormat(bool enabled);
+ bool autoDetectImageFormat() const;
+
+ void setDecideFormatFromContent(bool ignored);
+ bool decideFormatFromContent() const;
+
+ void setDevice(QIODevice *device);
+ QIODevice *device() const;
+
+ void setFileName(const QString &fileName);
+ QString fileName() const;
+
+ QSize size() const;
+
+ QImage::Format imageFormat() const;
+
+ QStringList textKeys() const;
+ QString text(const QString &key) const;
+
+ void setClipRect(const QRect &rect);
+ QRect clipRect() const;
+
+ void setScaledSize(const QSize &size);
+ QSize scaledSize() const;
+
+ void setQuality(int quality);
+ int quality() const;
+
+ void setScaledClipRect(const QRect &rect);
+ QRect scaledClipRect() const;
+
+ void setBackgroundColor(const QColor &color);
+ QColor backgroundColor() const;
+
+ bool supportsAnimation() const;
+
+ bool canRead() const;
+ QImage read();
+ bool read(QImage *image);
+
+ bool jumpToNextImage();
+ bool jumpToImage(int imageNumber);
+ int loopCount() const;
+ int imageCount() const;
+ int nextImageDelay() const;
+ int currentImageNumber() const;
+ QRect currentImageRect() const;
+
+ ImageReaderError error() const;
+ QString errorString() const;
+
+ bool supportsOption(QImageIOHandler::ImageOption option) const;
+
+ static QByteArray imageFormat(const QString &fileName);
+ static QByteArray imageFormat(QIODevice *device);
+ static QList<QByteArray> supportedImageFormats();
+
+private:
+ Q_DISABLE_COPY(QImageReader)
+ QImageReaderPrivate *d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QIMAGEREADER_H
diff --git a/src/gui/image/qimagewriter.cpp b/src/gui/image/qimagewriter.cpp
new file mode 100644
index 0000000000..504260aa47
--- /dev/null
+++ b/src/gui/image/qimagewriter.cpp
@@ -0,0 +1,734 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QImageWriter
+ \brief The QImageWriter class provides a format independent interface
+ for writing images to files or other devices.
+
+ \reentrant
+ \ingroup painting
+ \ingroup io
+
+ QImageWriter supports setting format specific options, such as the
+ gamma level, compression level and quality, prior to storing the
+ image. If you do not need such options, you can use QImage::save()
+ or QPixmap::save() instead.
+
+ To store an image, you start by constructing a QImageWriter
+ object. Pass either a file name or a device pointer, and the
+ image format to QImageWriter's constructor. You can then set
+ several options, such as the gamma level (by calling setGamma())
+ and quality (by calling setQuality()). canWrite() returns true if
+ QImageWriter can write the image (i.e., the image format is
+ supported and the device is open for writing). Call write() to
+ write the image to the device.
+
+ If any error occurs when writing the image, write() will return
+ false. You can then call error() to find the type of error that
+ occurred, or errorString() to get a human readable description of
+ what went wrong.
+
+ Call supportedImageFormats() for a list of formats that
+ QImageWriter can write. QImageWriter supports all built-in image
+ formats, in addition to any image format plugins that support
+ writing.
+
+ \sa QImageReader, QImageIOHandler, QImageIOPlugin
+*/
+
+/*!
+ \enum QImageWriter::ImageWriterError
+
+ This enum describes errors that can occur when writing images with
+ QImageWriter.
+
+ \value DeviceError QImageWriter encountered a device error when
+ writing the image data. Consult your device for more details on
+ what went wrong.
+
+ \value UnsupportedFormatError Qt does not support the requested
+ image format.
+
+ \value UnknownError An unknown error occurred. If you get this
+ value after calling write(), it is most likely caused by a bug in
+ QImageWriter.
+*/
+
+#include "qimagewriter.h"
+
+#include <qbytearray.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qimageiohandler.h>
+#include <qset.h>
+#include <qvariant.h>
+
+// factory loader
+#include <qcoreapplication.h>
+#include <private/qfactoryloader_p.h>
+
+// image handlers
+#include <private/qbmphandler_p.h>
+#include <private/qppmhandler_p.h>
+#include <private/qxbmhandler_p.h>
+#include <private/qxpmhandler_p.h>
+#ifndef QT_NO_IMAGEFORMAT_PNG
+#include <private/qpnghandler_p.h>
+#endif
+#ifndef QT_NO_IMAGEFORMAT_JPEG
+#include <private/qjpeghandler_p.h>
+#endif
+#ifndef QT_NO_IMAGEFORMAT_MNG
+#include <private/qmnghandler_p.h>
+#endif
+#ifndef QT_NO_IMAGEFORMAT_TIFF
+#include <private/qtiffhandler_p.h>
+#endif
+#ifdef QT_BUILTIN_GIF_READER
+#include <private/qgifhandler_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_LIBRARY
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+ (QImageIOHandlerFactoryInterface_iid, QLatin1String("/imageformats")))
+#endif
+
+static QImageIOHandler *createWriteHandlerHelper(QIODevice *device,
+ const QByteArray &format)
+{
+ QByteArray form = format.toLower();
+ QByteArray suffix;
+ QImageIOHandler *handler = 0;
+
+#ifndef QT_NO_LIBRARY
+ // check if any plugins can write the image
+ QFactoryLoader *l = loader();
+ QStringList keys = l->keys();
+ int suffixPluginIndex = -1;
+#endif
+
+ if (device && format.isEmpty()) {
+ // if there's no format, see if \a device is a file, and if so, find
+ // the file suffix and find support for that format among our plugins.
+ // this allows plugins to override our built-in handlers.
+ if (QFile *file = qobject_cast<QFile *>(device)) {
+ if (!(suffix = QFileInfo(file->fileName()).suffix().toLower().toLatin1()).isEmpty()) {
+#ifndef QT_NO_LIBRARY
+ int index = keys.indexOf(QString::fromLatin1(suffix));
+ if (index != -1)
+ suffixPluginIndex = index;
+#endif
+ }
+ }
+ }
+
+ QByteArray testFormat = !form.isEmpty() ? form : suffix;
+
+#ifndef QT_NO_LIBRARY
+ if (suffixPluginIndex != -1) {
+ // when format is missing, check if we can find a plugin for the
+ // suffix.
+ QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(l->instance(QString::fromLatin1(suffix)));
+ if (plugin && (plugin->capabilities(device, suffix) & QImageIOPlugin::CanWrite))
+ handler = plugin->create(device, suffix);
+ }
+#endif // QT_NO_LIBRARY
+
+ // check if any built-in handlers can write the image
+ if (!handler && !testFormat.isEmpty()) {
+ if (false) {
+#ifndef QT_NO_IMAGEFORMAT_PNG
+ } else if (testFormat == "png") {
+ handler = new QPngHandler;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_JPEG
+ } else if (testFormat == "jpg" || testFormat == "jpeg") {
+ handler = new QJpegHandler;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_MNG
+ } else if (testFormat == "mng") {
+ handler = new QMngHandler;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_TIFF
+ } else if (testFormat == "tif" || testFormat == "tiff") {
+ handler = new QTiffHandler;
+#endif
+#ifdef QT_BUILTIN_GIF_READER
+ } else if (testFormat == "gif") {
+ handler = new QGifHandler;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_BMP
+ } else if (testFormat == "bmp") {
+ handler = new QBmpHandler;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_XPM
+ } else if (testFormat == "xpm") {
+ handler = new QXpmHandler;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_XBM
+ } else if (testFormat == "xbm") {
+ handler = new QXbmHandler;
+ handler->setOption(QImageIOHandler::SubType, testFormat);
+#endif
+#ifndef QT_NO_IMAGEFORMAT_PPM
+ } else if (testFormat == "pbm" || testFormat == "pbmraw" || testFormat == "pgm"
+ || testFormat == "pgmraw" || testFormat == "ppm" || testFormat == "ppmraw") {
+ handler = new QPpmHandler;
+ handler->setOption(QImageIOHandler::SubType, testFormat);
+#endif
+ }
+ }
+
+#ifndef QT_NO_LIBRARY
+ if (!testFormat.isEmpty()) {
+ for (int i = 0; i < keys.size(); ++i) {
+ QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(l->instance(keys.at(i)));
+ if (plugin && (plugin->capabilities(device, testFormat) & QImageIOPlugin::CanWrite)) {
+ delete handler;
+ handler = plugin->create(device, testFormat);
+ break;
+ }
+ }
+ }
+#endif // QT_NO_LIBRARY
+
+ if (!handler)
+ return 0;
+
+ handler->setDevice(device);
+ if (!testFormat.isEmpty())
+ handler->setFormat(testFormat);
+ return handler;
+}
+
+class QImageWriterPrivate
+{
+public:
+ QImageWriterPrivate(QImageWriter *qq);
+
+ // device
+ QByteArray format;
+ QIODevice *device;
+ bool deleteDevice;
+ QImageIOHandler *handler;
+
+ // image options
+ int quality;
+ int compression;
+ float gamma;
+ QString description;
+ QString text;
+
+ // error
+ QImageWriter::ImageWriterError imageWriterError;
+ QString errorString;
+
+ QImageWriter *q;
+};
+
+/*!
+ \internal
+*/
+QImageWriterPrivate::QImageWriterPrivate(QImageWriter *qq)
+{
+ device = 0;
+ deleteDevice = false;
+ handler = 0;
+ quality = -1;
+ compression = 0;
+ gamma = 0.0;
+ imageWriterError = QImageWriter::UnknownError;
+ errorString = QT_TRANSLATE_NOOP(QImageWriter, QLatin1String("Unknown error"));
+
+ q = qq;
+}
+
+/*!
+ Constructs an empty QImageWriter object. Before writing, you must
+ call setFormat() to set an image format, then setDevice() or
+ setFileName().
+*/
+QImageWriter::QImageWriter()
+ : d(new QImageWriterPrivate(this))
+{
+}
+
+/*!
+ Constructs a QImageWriter object using the device \a device and
+ image format \a format.
+*/
+QImageWriter::QImageWriter(QIODevice *device, const QByteArray &format)
+ : d(new QImageWriterPrivate(this))
+{
+ d->device = device;
+ d->format = format;
+}
+
+/*!
+ Constructs a QImageWriter objects that will write to a file with
+ the name \a fileName, using the image format \a format. If \a
+ format is not provided, QImageWriter will detect the image format
+ by inspecting the extension of \a fileName.
+*/
+QImageWriter::QImageWriter(const QString &fileName, const QByteArray &format)
+ : d(new QImageWriterPrivate(this))
+{
+ QFile *file = new QFile(fileName);
+ d->device = file;
+ d->deleteDevice = true;
+ d->format = format;
+}
+
+/*!
+ Destructs the QImageWriter object.
+*/
+QImageWriter::~QImageWriter()
+{
+ if (d->deleteDevice)
+ delete d->device;
+ delete d->handler;
+ delete d;
+}
+
+/*!
+ Sets the format QImageWriter will use when writing images, to \a
+ format. \a format is a case insensitive text string. Example:
+
+ \snippet doc/src/snippets/code/src_gui_image_qimagewriter.cpp 0
+
+ You can call supportedImageFormats() for the full list of formats
+ QImageWriter supports.
+
+ \sa format()
+*/
+void QImageWriter::setFormat(const QByteArray &format)
+{
+ d->format = format;
+}
+
+/*!
+ Returns the format QImageWriter uses for writing images.
+
+ \sa setFormat()
+*/
+QByteArray QImageWriter::format() const
+{
+ return d->format;
+}
+
+/*!
+ Sets QImageWriter's device to \a device. If a device has already
+ been set, the old device is removed from QImageWriter and is
+ otherwise left unchanged.
+
+ If the device is not already open, QImageWriter will attempt to
+ open the device in \l QIODevice::WriteOnly mode by calling
+ open(). Note that this does not work for certain devices, such as
+ QProcess, QTcpSocket and QUdpSocket, where more logic is required
+ to open the device.
+
+ \sa device(), setFileName()
+*/
+void QImageWriter::setDevice(QIODevice *device)
+{
+ if (d->device && d->deleteDevice)
+ delete d->device;
+
+ d->device = device;
+ d->deleteDevice = false;
+ delete d->handler;
+ d->handler = 0;
+}
+
+/*!
+ Returns the device currently assigned to QImageWriter, or 0 if no
+ device has been assigned.
+*/
+QIODevice *QImageWriter::device() const
+{
+ return d->device;
+}
+
+/*!
+ Sets the file name of QImageWriter to \a fileName. Internally,
+ QImageWriter will create a QFile and open it in \l
+ QIODevice::WriteOnly mode, and use this file when writing images.
+
+ \sa fileName(), setDevice()
+*/
+void QImageWriter::setFileName(const QString &fileName)
+{
+ setDevice(new QFile(fileName));
+ d->deleteDevice = true;
+}
+
+/*!
+ If the currently assigned device is a QFile, or if setFileName()
+ has been called, this function returns the name of the file
+ QImageWriter writes to. Otherwise (i.e., if no device has been
+ assigned or the device is not a QFile), an empty QString is
+ returned.
+
+ \sa setFileName(), setDevice()
+*/
+QString QImageWriter::fileName() const
+{
+ QFile *file = qobject_cast<QFile *>(d->device);
+ return file ? file->fileName() : QString();
+}
+
+/*!
+ This is an image format specific function that sets the quality
+ level of the image to \a quality. For image formats that do not
+ support setting the quality, this value is ignored.
+
+ The value range of \a quality depends on the image format. For
+ example, the "jpeg" format supports a quality range from 0 (low
+ quality, high compression) to 100 (high quality, low compression).
+
+ \sa quality()
+*/
+void QImageWriter::setQuality(int quality)
+{
+ d->quality = quality;
+}
+
+/*!
+ Returns the quality level of the image.
+
+ \sa setQuality()
+*/
+int QImageWriter::quality() const
+{
+ return d->quality;
+}
+
+/*!
+ This is an image format specific function that set the compression
+ of an image. For image formats that do not support setting the
+ compression, this value is ignored.
+
+ The value range of \a compression depends on the image format. For
+ example, the "tiff" format supports two values, 0(no compression) and
+ 1(LZW-compression).
+
+ \sa compression()
+*/
+void QImageWriter::setCompression(int compression)
+{
+ d->compression = compression;
+}
+
+/*!
+ Returns the compression of the image.
+
+ \sa setCompression()
+*/
+int QImageWriter::compression() const
+{
+ return d->compression;
+}
+
+/*!
+ This is an image format specific function that sets the gamma
+ level of the image to \a gamma. For image formats that do not
+ support setting the gamma level, this value is ignored.
+
+ The value range of \a gamma depends on the image format. For
+ example, the "png" format supports a gamma range from 0.0 to 1.0.
+
+ \sa quality()
+*/
+void QImageWriter::setGamma(float gamma)
+{
+ d->gamma = gamma;
+}
+
+/*!
+ Returns the gamma level of the image.
+
+ \sa setGamma()
+*/
+float QImageWriter::gamma() const
+{
+ return d->gamma;
+}
+
+/*!
+ \obsolete
+
+ Use setText() instead.
+
+ This is an image format specific function that sets the
+ description of the image to \a description. For image formats that
+ do not support setting the description, this value is ignored.
+
+ The contents of \a description depends on the image format.
+
+ \sa description()
+*/
+void QImageWriter::setDescription(const QString &description)
+{
+ d->description = description;
+}
+
+/*!
+ \obsolete
+
+ Use QImageReader::text() instead.
+
+ Returns the description of the image.
+
+ \sa setDescription()
+*/
+QString QImageWriter::description() const
+{
+ return d->description;
+}
+
+/*!
+ \since 4.1
+
+ Sets the image text associated with the key \a key to
+ \a text. This is useful for storing copyright information
+ or other information about the image. Example:
+
+ \snippet doc/src/snippets/code/src_gui_image_qimagewriter.cpp 1
+
+ If you want to store a single block of data
+ (e.g., a comment), you can pass an empty key, or use
+ a generic key like "Description".
+
+ The key and text will be embedded into the
+ image data after calling write().
+
+ Support for this option is implemented through
+ QImageIOHandler::Description.
+
+ \sa QImage::setText(), QImageReader::text()
+*/
+void QImageWriter::setText(const QString &key, const QString &text)
+{
+ if (!d->description.isEmpty())
+ d->description += QLatin1String("\n\n");
+ d->description += key.simplified() + QLatin1String(": ") + text.simplified();
+}
+
+/*!
+ Returns true if QImageWriter can write the image; i.e., the image
+ format is supported and the assigned device is open for reading.
+
+ \sa write(), setDevice(), setFormat()
+*/
+bool QImageWriter::canWrite() const
+{
+ if (d->device && !d->handler && (d->handler = createWriteHandlerHelper(d->device, d->format)) == 0) {
+ d->imageWriterError = QImageWriter::UnsupportedFormatError;
+ d->errorString = QT_TRANSLATE_NOOP(QImageWriter,
+ QLatin1String("Unsupported image format"));
+ return false;
+ }
+ if (d->device && !d->device->isOpen())
+ d->device->open(QIODevice::WriteOnly);
+ if (!d->device || !d->device->isWritable()) {
+ d->imageWriterError = QImageWriter::DeviceError;
+ d->errorString = QT_TRANSLATE_NOOP(QImageWriter,
+ QLatin1String("Device not writable"));
+ return false;
+ }
+ return true;
+}
+
+/*!
+ Writes the image \a image to the assigned device or file
+ name. Returns true on success; otherwise returns false. If the
+ operation fails, you can call error() to find the type of error
+ that occurred, or errorString() to get a human readable
+ description of the error.
+
+ \sa canWrite(), error(), errorString()
+*/
+bool QImageWriter::write(const QImage &image)
+{
+ if (!canWrite())
+ return false;
+
+ if (d->handler->supportsOption(QImageIOHandler::Quality))
+ d->handler->setOption(QImageIOHandler::Quality, d->quality);
+ if (d->handler->supportsOption(QImageIOHandler::CompressionRatio))
+ d->handler->setOption(QImageIOHandler::CompressionRatio, d->compression);
+ if (d->handler->supportsOption(QImageIOHandler::Gamma))
+ d->handler->setOption(QImageIOHandler::Gamma, d->gamma);
+ if (!d->description.isEmpty() && d->handler->supportsOption(QImageIOHandler::Description))
+ d->handler->setOption(QImageIOHandler::Description, d->description);
+
+ if (!d->handler->write(image))
+ return false;
+ if (QFile *file = qobject_cast<QFile *>(d->device))
+ file->flush();
+ return true;
+}
+
+/*!
+ Returns the type of error that last occurred.
+
+ \sa ImageWriterError, errorString()
+*/
+QImageWriter::ImageWriterError QImageWriter::error() const
+{
+ return d->imageWriterError;
+}
+
+/*!
+ Returns a human readable description of the last error that occurred.
+
+ \sa error()
+*/
+QString QImageWriter::errorString() const
+{
+ return d->errorString;
+}
+
+/*!
+ \since 4.2
+
+ Returns true if the writer supports \a option; otherwise returns
+ false.
+
+ Different image formats support different options. Call this function to
+ determine whether a certain option is supported by the current format. For
+ example, the PNG format allows you to embed text into the image's metadata
+ (see text()).
+
+ \snippet doc/src/snippets/code/src_gui_image_qimagewriter.cpp 2
+
+ Options can be tested after the writer has been associated with a format.
+
+ \sa QImageReader::supportsOption(), setFormat()
+*/
+bool QImageWriter::supportsOption(QImageIOHandler::ImageOption option) const
+{
+ if (!d->handler && (d->handler = createWriteHandlerHelper(d->device, d->format)) == 0) {
+ d->imageWriterError = QImageWriter::UnsupportedFormatError;
+ d->errorString = QT_TRANSLATE_NOOP(QImageWriter,
+ QLatin1String("Unsupported image format"));
+ return false;
+ }
+
+ return d->handler->supportsOption(option);
+}
+
+/*!
+ Returns the list of image formats supported by QImageWriter.
+
+ By default, Qt can write the following formats:
+
+ \table
+ \header \o Format \o Description
+ \row \o BMP \o Windows Bitmap
+ \row \o JPG \o Joint Photographic Experts Group
+ \row \o JPEG \o Joint Photographic Experts Group
+ \row \o PNG \o Portable Network Graphics
+ \row \o PPM \o Portable Pixmap
+ \row \o TIFF \o Tagged Image File Format
+ \row \o XBM \o X11 Bitmap
+ \row \o XPM \o X11 Pixmap
+ \endtable
+
+ Reading and writing SVG files is supported through Qt's
+ \l{QtSvg Module}{SVG Module}.
+
+ Note that the QApplication instance must be created before this function is
+ called.
+
+ \sa setFormat(), QImageReader::supportedImageFormats(), QImageIOPlugin
+*/
+QList<QByteArray> QImageWriter::supportedImageFormats()
+{
+ QSet<QByteArray> formats;
+ formats << "bmp";
+#ifndef QT_NO_IMAGEFORMAT_PPM
+ formats << "ppm";
+#endif
+#ifndef QT_NO_IMAGEFORMAT_XBM
+ formats << "xbm";
+#endif
+#ifndef QT_NO_IMAGEFORMAT_XPM
+ formats << "xpm";
+#endif
+#ifndef QT_NO_IMAGEFORMAT_PNG
+ formats << "png";
+#endif
+#ifndef QT_NO_IMAGEFORMAT_JPEG
+ formats << "jpg" << "jpeg";
+#endif
+#ifndef QT_NO_IMAGEFORMAT_MNG
+ formats << "mng";
+#endif
+#ifndef QT_NO_IMAGEFORMAT_TIFF
+ formats << "tif" << "tiff";
+#endif
+#ifdef QT_BUILTIN_GIF_READER
+ formats << "gif";
+#endif
+
+#ifndef QT_NO_LIBRARY
+ QFactoryLoader *l = loader();
+ QStringList keys = l->keys();
+ for (int i = 0; i < keys.count(); ++i) {
+ QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(l->instance(keys.at(i)));
+ if (plugin && (plugin->capabilities(0, keys.at(i).toLatin1()) & QImageIOPlugin::CanWrite) != 0)
+ formats << keys.at(i).toLatin1();
+ }
+#endif // QT_NO_LIBRARY
+
+ QList<QByteArray> sortedFormats;
+ for (QSet<QByteArray>::ConstIterator it = formats.constBegin(); it != formats.constEnd(); ++it)
+ sortedFormats << *it;
+
+ qSort(sortedFormats);
+ return sortedFormats;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/image/qimagewriter.h b/src/gui/image/qimagewriter.h
new file mode 100644
index 0000000000..5e1b9bf677
--- /dev/null
+++ b/src/gui/image/qimagewriter.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIMAGEWRITER_H
+#define QIMAGEWRITER_H
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qlist.h>
+#include <QtGui/qimageiohandler.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QIODevice;
+class QImage;
+
+class QImageWriterPrivate;
+class Q_GUI_EXPORT QImageWriter
+{
+public:
+ enum ImageWriterError {
+ UnknownError,
+ DeviceError,
+ UnsupportedFormatError
+ };
+
+ QImageWriter();
+ explicit QImageWriter(QIODevice *device, const QByteArray &format);
+ explicit QImageWriter(const QString &fileName, const QByteArray &format = QByteArray());
+ ~QImageWriter();
+
+ void setFormat(const QByteArray &format);
+ QByteArray format() const;
+
+ void setDevice(QIODevice *device);
+ QIODevice *device() const;
+
+ void setFileName(const QString &fileName);
+ QString fileName() const;
+
+ void setQuality(int quality);
+ int quality() const;
+
+ void setCompression(int compression);
+ int compression() const;
+
+ void setGamma(float gamma);
+ float gamma() const;
+
+ // Obsolete as of 4.1
+ void setDescription(const QString &description);
+ QString description() const;
+
+ void setText(const QString &key, const QString &text);
+
+ bool canWrite() const;
+ bool write(const QImage &image);
+
+ ImageWriterError error() const;
+ QString errorString() const;
+
+ bool supportsOption(QImageIOHandler::ImageOption option) const;
+
+ static QList<QByteArray> supportedImageFormats();
+
+private:
+ Q_DISABLE_COPY(QImageWriter)
+ QImageWriterPrivate *d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QIMAGEWRITER_H
diff --git a/src/gui/image/qjpeghandler.cpp b/src/gui/image/qjpeghandler.cpp
new file mode 100644
index 0000000000..d57e0c1244
--- /dev/null
+++ b/src/gui/image/qjpeghandler.cpp
@@ -0,0 +1,915 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qjpeghandler_p.h"
+
+#include <qimage.h>
+#include <qvariant.h>
+#include <qvector.h>
+#include <qbuffer.h>
+#include <private/qsimd_p.h>
+
+#include <stdio.h> // jpeglib needs this to be pre-included
+#include <setjmp.h>
+
+#ifdef FAR
+#undef FAR
+#endif
+
+// including jpeglib.h seems to be a little messy
+extern "C" {
+// mingw includes rpcndr.h but does not define boolean
+#if defined(Q_OS_WIN) && defined(Q_CC_GNU)
+# if defined(__RPCNDR_H__) && !defined(boolean)
+ typedef unsigned char boolean;
+# define HAVE_BOOLEAN
+# endif
+#endif
+
+#define XMD_H // shut JPEGlib up
+#if defined(Q_OS_UNIXWARE)
+# define HAVE_BOOLEAN // libjpeg under Unixware seems to need this
+#endif
+#include <jpeglib.h>
+#ifdef const
+# undef const // remove crazy C hackery in jconfig.h
+#endif
+}
+
+QT_BEGIN_NAMESPACE
+
+void QT_FASTCALL convert_rgb888_to_rgb32_C(quint32 *dst, const uchar *src, int len)
+{
+ // Expand 24->32 bpp.
+ for (int i = 0; i < len; ++i) {
+ *dst++ = qRgb(src[0], src[1], src[2]);
+ src += 3;
+ }
+}
+
+typedef void (QT_FASTCALL *Rgb888ToRgb32Converter)(quint32 *dst, const uchar *src, int len);
+
+static Rgb888ToRgb32Converter rgb888ToRgb32ConverterPtr = convert_rgb888_to_rgb32_C;
+
+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)
+{
+ my_error_mgr* myerr = (my_error_mgr*) cinfo->err;
+ char buffer[JMSG_LENGTH_MAX];
+ (*cinfo->err->format_message)(cinfo, buffer);
+ qWarning("%s", buffer);
+ longjmp(myerr->setjmp_buffer, 1);
+}
+
+#if defined(Q_C_CALLBACKS)
+}
+#endif
+
+
+static const int max_buf = 4096;
+
+struct my_jpeg_source_mgr : public jpeg_source_mgr {
+ // Nothing dynamic - cannot rely on destruction over longjump
+ QIODevice *device;
+ JOCTET buffer[max_buf];
+ const QBuffer *memDevice;
+
+public:
+ my_jpeg_source_mgr(QIODevice *device);
+};
+
+#if defined(Q_C_CALLBACKS)
+extern "C" {
+#endif
+
+static void qt_init_source(j_decompress_ptr)
+{
+}
+
+static boolean qt_fill_input_buffer(j_decompress_ptr cinfo)
+{
+ my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src;
+ qint64 num_read = 0;
+ if (src->memDevice) {
+ src->next_input_byte = (const JOCTET *)(src->memDevice->data().constData() + src->memDevice->pos());
+ num_read = src->memDevice->data().size() - src->memDevice->pos();
+ src->device->seek(src->memDevice->data().size());
+ } else {
+ src->next_input_byte = src->buffer;
+ num_read = src->device->read((char*)src->buffer, max_buf);
+ }
+ if (num_read <= 0) {
+ // Insert a fake EOI marker - as per jpeglib recommendation
+ src->next_input_byte = src->buffer;
+ src->buffer[0] = (JOCTET) 0xFF;
+ src->buffer[1] = (JOCTET) JPEG_EOI;
+ src->bytes_in_buffer = 2;
+ } else {
+ src->bytes_in_buffer = num_read;
+ }
+#if defined(Q_OS_UNIXWARE)
+ return B_TRUE;
+#else
+ return true;
+#endif
+}
+
+static void qt_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
+{
+ my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src;
+
+ // `dumb' implementation from jpeglib
+
+ /* Just a dumb implementation for now. Could use fseek() except
+ * it doesn't work on pipes. Not clear that being smart is worth
+ * any trouble anyway --- large skips are infrequent.
+ */
+ if (num_bytes > 0) {
+ while (num_bytes > (long) src->bytes_in_buffer) { // Should not happen in case of memDevice
+ num_bytes -= (long) src->bytes_in_buffer;
+ (void) qt_fill_input_buffer(cinfo);
+ /* note we assume that qt_fill_input_buffer will never return false,
+ * so suspension need not be handled.
+ */
+ }
+ src->next_input_byte += (size_t) num_bytes;
+ src->bytes_in_buffer -= (size_t) num_bytes;
+ }
+}
+
+static void qt_term_source(j_decompress_ptr cinfo)
+{
+ my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src;
+ if (!src->device->isSequential())
+ 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)
+{
+ jpeg_source_mgr::init_source = qt_init_source;
+ jpeg_source_mgr::fill_input_buffer = qt_fill_input_buffer;
+ jpeg_source_mgr::skip_input_data = qt_skip_input_data;
+ jpeg_source_mgr::resync_to_restart = jpeg_resync_to_restart;
+ jpeg_source_mgr::term_source = qt_term_source;
+ this->device = device;
+ memDevice = qobject_cast<QBuffer *>(device);
+ bytes_in_buffer = 0;
+ next_input_byte = buffer;
+}
+
+
+inline static bool read_jpeg_size(int &w, int &h, j_decompress_ptr cinfo)
+{
+ (void) jpeg_calc_output_dimensions(cinfo);
+
+ w = cinfo->output_width;
+ h = cinfo->output_height;
+ return true;
+}
+
+#define HIGH_QUALITY_THRESHOLD 50
+
+inline static bool read_jpeg_format(QImage::Format &format, j_decompress_ptr cinfo)
+{
+
+ bool result = true;
+ switch (cinfo->output_components) {
+ case 1:
+ format = QImage::Format_Indexed8;
+ break;
+ case 3:
+ case 4:
+ format = QImage::Format_RGB32;
+ break;
+ default:
+ result = false;
+ break;
+ }
+ cinfo->output_scanline = cinfo->output_height;
+ return result;
+}
+
+static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info,
+ const QSize& size)
+{
+ QImage::Format format;
+ switch (info->output_components) {
+ case 1:
+ format = QImage::Format_Indexed8;
+ break;
+ case 3:
+ case 4:
+ format = QImage::Format_RGB32;
+ break;
+ default:
+ return false; // unsupported 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();
+}
+
+static bool read_jpeg_image(QImage *outImage,
+ QSize scaledSize, QRect scaledClipRect,
+ QRect clipRect, int inQuality, j_decompress_ptr info, struct my_error_mgr* err )
+{
+ if (!setjmp(err->setjmp_buffer)) {
+ // -1 means default quality.
+ int quality = inQuality;
+ if (quality < 0)
+ quality = 75;
+
+ // If possible, merge the scaledClipRect into either scaledSize
+ // or clipRect to avoid doing a separate scaled clipping pass.
+ // Best results are achieved by clipping before scaling, not after.
+ if (!scaledClipRect.isEmpty()) {
+ if (scaledSize.isEmpty() && clipRect.isEmpty()) {
+ // No clipping or scaling before final clip.
+ clipRect = scaledClipRect;
+ scaledClipRect = QRect();
+ } else if (scaledSize.isEmpty()) {
+ // Clipping, but no scaling: combine the clip regions.
+ scaledClipRect.translate(clipRect.topLeft());
+ clipRect = scaledClipRect.intersected(clipRect);
+ scaledClipRect = QRect();
+ } else if (clipRect.isEmpty()) {
+ // No clipping, but scaling: if we can map back to an
+ // integer pixel boundary, then clip before scaling.
+ if ((info->image_width % scaledSize.width()) == 0 &&
+ (info->image_height % scaledSize.height()) == 0) {
+ int x = scaledClipRect.x() * info->image_width /
+ scaledSize.width();
+ int y = scaledClipRect.y() * info->image_height /
+ scaledSize.height();
+ int width = (scaledClipRect.right() + 1) *
+ info->image_width / scaledSize.width() - x;
+ int height = (scaledClipRect.bottom() + 1) *
+ info->image_height / scaledSize.height() - y;
+ clipRect = QRect(x, y, width, height);
+ scaledSize = scaledClipRect.size();
+ scaledClipRect = QRect();
+ }
+ } else {
+ // Clipping and scaling: too difficult to figure out,
+ // and not a likely use case, so do it the long way.
+ }
+ }
+
+ // Determine the scale factor to pass to libjpeg for quick downscaling.
+ if (!scaledSize.isEmpty()) {
+ if (clipRect.isEmpty()) {
+ info->scale_denom =
+ qMin(info->image_width / scaledSize.width(),
+ info->image_height / scaledSize.height());
+ } else {
+ info->scale_denom =
+ qMin(clipRect.width() / scaledSize.width(),
+ clipRect.height() / scaledSize.height());
+ }
+ if (info->scale_denom < 2) {
+ info->scale_denom = 1;
+ } else if (info->scale_denom < 4) {
+ info->scale_denom = 2;
+ } else if (info->scale_denom < 8) {
+ info->scale_denom = 4;
+ } else {
+ info->scale_denom = 8;
+ }
+ info->scale_num = 1;
+ if (!clipRect.isEmpty()) {
+ // Correct the scale factor so that we clip accurately.
+ // It is recommended that the clip rectangle be aligned
+ // on an 8-pixel boundary for best performance.
+ while (info->scale_denom > 1 &&
+ ((clipRect.x() % info->scale_denom) != 0 ||
+ (clipRect.y() % info->scale_denom) != 0 ||
+ (clipRect.width() % info->scale_denom) != 0 ||
+ (clipRect.height() % info->scale_denom) != 0)) {
+ info->scale_denom /= 2;
+ }
+ }
+ }
+
+ // If high quality not required, use fast decompression
+ if( quality < HIGH_QUALITY_THRESHOLD ) {
+ info->dct_method = JDCT_IFAST;
+ info->do_fancy_upsampling = FALSE;
+ }
+
+ (void) jpeg_calc_output_dimensions(info);
+
+ // Determine the clip region to extract.
+ QRect imageRect(0, 0, info->output_width, info->output_height);
+ QRect clip;
+ if (clipRect.isEmpty()) {
+ clip = imageRect;
+ } else if (info->scale_denom == info->scale_num) {
+ clip = clipRect.intersected(imageRect);
+ } else {
+ // The scale factor was corrected above to ensure that
+ // we don't miss pixels when we scale the clip rectangle.
+ clip = QRect(clipRect.x() / int(info->scale_denom),
+ clipRect.y() / int(info->scale_denom),
+ clipRect.width() / int(info->scale_denom),
+ clipRect.height() / int(info->scale_denom));
+ clip = clip.intersected(imageRect);
+ }
+
+ // Allocate memory for the clipped QImage.
+ if (!ensureValidImage(outImage, info, clip.size()))
+ longjmp(err->setjmp_buffer, 1);
+
+ // Avoid memcpy() overhead if grayscale with no clipping.
+ bool quickGray = (info->output_components == 1 &&
+ clip == imageRect);
+ if (!quickGray) {
+ // Ask the jpeg library to allocate a temporary row.
+ // The library will automatically delete it for us later.
+ // The libjpeg docs say we should do this before calling
+ // jpeg_start_decompress(). We can't use "new" here
+ // because we are inside the setjmp() block and an error
+ // in the jpeg input stream would cause a memory leak.
+ JSAMPARRAY rows = (info->mem->alloc_sarray)
+ ((j_common_ptr)info, JPOOL_IMAGE,
+ info->output_width * info->output_components, 1);
+
+ (void) jpeg_start_decompress(info);
+
+ while (info->output_scanline < info->output_height) {
+ int y = int(info->output_scanline) - clip.y();
+ if (y >= clip.height())
+ break; // We've read the entire clip region, so abort.
+
+ (void) jpeg_read_scanlines(info, rows, 1);
+
+ if (y < 0)
+ continue; // Haven't reached the starting line yet.
+
+ if (info->output_components == 3) {
+ uchar *in = rows[0] + clip.x() * 3;
+ QRgb *out = (QRgb*)outImage->scanLine(y);
+ rgb888ToRgb32ConverterPtr(out, in, clip.width());
+ } else if (info->out_color_space == JCS_CMYK) {
+ // Convert CMYK->RGB.
+ uchar *in = rows[0] + clip.x() * 4;
+ QRgb *out = (QRgb*)outImage->scanLine(y);
+ for (int i = 0; i < clip.width(); ++i) {
+ int k = in[3];
+ *out++ = qRgb(k * in[0] / 255, k * in[1] / 255,
+ k * in[2] / 255);
+ in += 4;
+ }
+ } else if (info->output_components == 1) {
+ // Grayscale.
+ memcpy(outImage->scanLine(y),
+ rows[0] + clip.x(), clip.width());
+ }
+ }
+ } else {
+ // Load unclipped grayscale data directly into the QImage.
+ (void) jpeg_start_decompress(info);
+ while (info->output_scanline < info->output_height) {
+ uchar *row = outImage->scanLine(info->output_scanline);
+ (void) jpeg_read_scanlines(info, &row, 1);
+ }
+ }
+
+ if (info->output_scanline == info->output_height)
+ (void) jpeg_finish_decompress(info);
+
+ if (info->density_unit == 1) {
+ outImage->setDotsPerMeterX(int(100. * info->X_density / 2.54));
+ outImage->setDotsPerMeterY(int(100. * info->Y_density / 2.54));
+ } else if (info->density_unit == 2) {
+ outImage->setDotsPerMeterX(int(100. * info->X_density));
+ outImage->setDotsPerMeterY(int(100. * info->Y_density));
+ }
+
+ if (scaledSize.isValid() && scaledSize != clip.size()) {
+ *outImage = outImage->scaled(scaledSize, Qt::IgnoreAspectRatio, quality >= HIGH_QUALITY_THRESHOLD ? Qt::SmoothTransformation : Qt::FastTransformation);
+ }
+
+ if (!scaledClipRect.isEmpty())
+ *outImage = outImage->copy(scaledClipRect);
+ return !outImage->isNull();
+ }
+ else
+ return false;
+}
+
+struct my_jpeg_destination_mgr : public jpeg_destination_mgr {
+ // Nothing dynamic - cannot rely on destruction over longjump
+ QIODevice *device;
+ JOCTET buffer[max_buf];
+
+public:
+ my_jpeg_destination_mgr(QIODevice *);
+};
+
+
+#if defined(Q_C_CALLBACKS)
+extern "C" {
+#endif
+
+static void qt_init_destination(j_compress_ptr)
+{
+}
+
+static boolean qt_empty_output_buffer(j_compress_ptr cinfo)
+{
+ my_jpeg_destination_mgr* dest = (my_jpeg_destination_mgr*)cinfo->dest;
+
+ int written = dest->device->write((char*)dest->buffer, max_buf);
+ if (written == -1)
+ (*cinfo->err->error_exit)((j_common_ptr)cinfo);
+
+ dest->next_output_byte = dest->buffer;
+ dest->free_in_buffer = max_buf;
+
+#if defined(Q_OS_UNIXWARE)
+ return B_TRUE;
+#else
+ return true;
+#endif
+}
+
+static void qt_term_destination(j_compress_ptr cinfo)
+{
+ my_jpeg_destination_mgr* dest = (my_jpeg_destination_mgr*)cinfo->dest;
+ qint64 n = max_buf - dest->free_in_buffer;
+
+ qint64 written = dest->device->write((char*)dest->buffer, n);
+ if (written == -1)
+ (*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)
+{
+ jpeg_destination_mgr::init_destination = qt_init_destination;
+ jpeg_destination_mgr::empty_output_buffer = qt_empty_output_buffer;
+ jpeg_destination_mgr::term_destination = qt_term_destination;
+ this->device = device;
+ next_output_byte = buffer;
+ free_in_buffer = max_buf;
+}
+
+
+static bool write_jpeg_image(const QImage &image, QIODevice *device, int sourceQuality)
+{
+ bool success = false;
+ const QVector<QRgb> cmap = image.colorTable();
+
+ struct jpeg_compress_struct cinfo;
+ JSAMPROW row_pointer[1];
+ row_pointer[0] = 0;
+
+ struct my_jpeg_destination_mgr *iod_dest = new my_jpeg_destination_mgr(device);
+ struct my_error_mgr jerr;
+
+ cinfo.err = jpeg_std_error(&jerr);
+ jerr.error_exit = my_error_exit;
+
+ if (!setjmp(jerr.setjmp_buffer)) {
+ // WARNING:
+ // this if loop is inside a setjmp/longjmp branch
+ // do not create C++ temporaries here because the destructor may never be called
+ // if you allocate memory, make sure that you can free it (row_pointer[0])
+ jpeg_create_compress(&cinfo);
+
+ cinfo.dest = iod_dest;
+
+ cinfo.image_width = image.width();
+ cinfo.image_height = image.height();
+
+ 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]));
+ }
+ cinfo.input_components = gray ? 1 : 3;
+ cinfo.in_color_space = gray ? JCS_GRAYSCALE : JCS_RGB;
+ break;
+ default:
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+ }
+
+ jpeg_set_defaults(&cinfo);
+
+ qreal diffInch = qAbs(image.dotsPerMeterX()*2.54/100. - qRound(image.dotsPerMeterX()*2.54/100.))
+ + qAbs(image.dotsPerMeterY()*2.54/100. - qRound(image.dotsPerMeterY()*2.54/100.));
+ qreal diffCm = (qAbs(image.dotsPerMeterX()/100. - qRound(image.dotsPerMeterX()/100.))
+ + qAbs(image.dotsPerMeterY()/100. - qRound(image.dotsPerMeterY()/100.)))*2.54;
+ if (diffInch < diffCm) {
+ cinfo.density_unit = 1; // dots/inch
+ cinfo.X_density = qRound(image.dotsPerMeterX()*2.54/100.);
+ cinfo.Y_density = qRound(image.dotsPerMeterY()*2.54/100.);
+ } else {
+ cinfo.density_unit = 2; // dots/cm
+ cinfo.X_density = (image.dotsPerMeterX()+50) / 100;
+ cinfo.Y_density = (image.dotsPerMeterY()+50) / 100;
+ }
+
+
+ int quality = sourceQuality >= 0 ? qMin(sourceQuality,100) : 75;
+#if defined(Q_OS_UNIXWARE)
+ jpeg_set_quality(&cinfo, quality, B_TRUE /* limit to baseline-JPEG values */);
+ jpeg_start_compress(&cinfo, B_TRUE);
+#else
+ jpeg_set_quality(&cinfo, quality, true /* limit to baseline-JPEG values */);
+ jpeg_start_compress(&cinfo, true);
+#endif
+
+ row_pointer[0] = new uchar[cinfo.image_width*cinfo.input_components];
+ int w = cinfo.image_width;
+ while (cinfo.next_scanline < cinfo.image_height) {
+ uchar *row = row_pointer[0];
+ switch (image.format()) {
+ case QImage::Format_Mono:
+ case QImage::Format_MonoLSB:
+ if (gray) {
+ const uchar* data = image.constScanLine(cinfo.next_scanline);
+ if (image.format() == QImage::Format_MonoLSB) {
+ for (int i=0; i<w; i++) {
+ bool bit = !!(*(data + (i >> 3)) & (1 << (i & 7)));
+ row[i] = qRed(cmap[bit]);
+ }
+ } else {
+ for (int i=0; i<w; i++) {
+ bool bit = !!(*(data + (i >> 3)) & (1 << (7 -(i & 7))));
+ row[i] = qRed(cmap[bit]);
+ }
+ }
+ } else {
+ const uchar* data = image.constScanLine(cinfo.next_scanline);
+ if (image.format() == QImage::Format_MonoLSB) {
+ for (int i=0; i<w; i++) {
+ bool bit = !!(*(data + (i >> 3)) & (1 << (i & 7)));
+ *row++ = qRed(cmap[bit]);
+ *row++ = qGreen(cmap[bit]);
+ *row++ = qBlue(cmap[bit]);
+ }
+ } else {
+ for (int i=0; i<w; i++) {
+ bool bit = !!(*(data + (i >> 3)) & (1 << (7 -(i & 7))));
+ *row++ = qRed(cmap[bit]);
+ *row++ = qGreen(cmap[bit]);
+ *row++ = qBlue(cmap[bit]);
+ }
+ }
+ }
+ break;
+ case QImage::Format_Indexed8:
+ if (gray) {
+ const uchar* pix = image.constScanLine(cinfo.next_scanline);
+ for (int i=0; i<w; i++) {
+ *row = qRed(cmap[*pix]);
+ ++row; ++pix;
+ }
+ } else {
+ const uchar* pix = image.constScanLine(cinfo.next_scanline);
+ for (int i=0; i<w; i++) {
+ *row++ = qRed(cmap[*pix]);
+ *row++ = qGreen(cmap[*pix]);
+ *row++ = qBlue(cmap[*pix]);
+ ++pix;
+ }
+ }
+ break;
+ case QImage::Format_RGB888:
+ memcpy(row, image.constScanLine(cinfo.next_scanline), w * 3);
+ break;
+ case QImage::Format_RGB32:
+ case QImage::Format_ARGB32:
+ case QImage::Format_ARGB32_Premultiplied:
+ {
+ const QRgb* rgb = (const QRgb*)image.constScanLine(cinfo.next_scanline);
+ for (int i=0; i<w; i++) {
+ *row++ = qRed(*rgb);
+ *row++ = qGreen(*rgb);
+ *row++ = qBlue(*rgb);
+ ++rgb;
+ }
+ }
+ break;
+ default:
+ {
+ // (Testing shows that this way is actually faster than converting to RGB888 + memcpy)
+ QImage rowImg = image.copy(0, cinfo.next_scanline, w, 1).convertToFormat(QImage::Format_RGB32);
+ const QRgb* rgb = (const QRgb*)rowImg.constScanLine(0);
+ for (int i=0; i<w; i++) {
+ *row++ = qRed(*rgb);
+ *row++ = qGreen(*rgb);
+ *row++ = qBlue(*rgb);
+ ++rgb;
+ }
+ }
+ break;
+ }
+ jpeg_write_scanlines(&cinfo, row_pointer, 1);
+ }
+
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+ success = true;
+ } else {
+ jpeg_destroy_compress(&cinfo);
+ success = false;
+ }
+
+ delete iod_dest;
+ delete [] row_pointer[0];
+ return success;
+}
+
+class QJpegHandlerPrivate
+{
+public:
+ enum State {
+ Ready,
+ ReadHeader,
+ Error
+ };
+
+ QJpegHandlerPrivate(QJpegHandler *qq)
+ : quality(75), iod_src(0), state(Ready), q(qq)
+ {}
+
+ ~QJpegHandlerPrivate()
+ {
+ if(iod_src)
+ {
+ jpeg_destroy_decompress(&info);
+ delete iod_src;
+ iod_src = 0;
+ }
+ }
+
+ bool readJpegHeader(QIODevice*);
+ bool read(QImage *image);
+
+ int quality;
+ QVariant size;
+ QImage::Format format;
+ QSize scaledSize;
+ QRect scaledClipRect;
+ QRect clipRect;
+ struct jpeg_decompress_struct info;
+ struct my_jpeg_source_mgr * iod_src;
+ struct my_error_mgr err;
+
+ State state;
+
+ QJpegHandler *q;
+};
+
+/*!
+ \internal
+*/
+bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
+{
+ if(state == Ready)
+ {
+ state = Error;
+ iod_src = new my_jpeg_source_mgr(device);
+
+ jpeg_create_decompress(&info);
+ info.src = iod_src;
+ info.err = jpeg_std_error(&err);
+ err.error_exit = my_error_exit;
+
+ if (!setjmp(err.setjmp_buffer)) {
+ #if defined(Q_OS_UNIXWARE)
+ (void) jpeg_read_header(&info, B_TRUE);
+ #else
+ (void) jpeg_read_header(&info, true);
+ #endif
+
+ int width = 0;
+ int height = 0;
+ read_jpeg_size(width, height, &info);
+ size = QSize(width, height);
+
+ format = QImage::Format_Invalid;
+ read_jpeg_format(format, &info);
+ state = ReadHeader;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if(state == Error)
+ return false;
+ return true;
+}
+
+bool QJpegHandlerPrivate::read(QImage *image)
+{
+ if(state == Ready)
+ readJpegHeader(q->device());
+
+ if(state == ReadHeader)
+ {
+ bool success = read_jpeg_image(image, scaledSize, scaledClipRect, clipRect, quality, &info, &err);
+ state = success ? Ready : Error;
+ return success;
+ }
+
+ return false;
+
+}
+
+QJpegHandler::QJpegHandler()
+ : d(new QJpegHandlerPrivate(this))
+{
+ const uint features = qDetectCPUFeatures();
+ Q_UNUSED(features);
+#if defined(QT_HAVE_NEON)
+ // from qimage_neon.cpp
+ Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_neon(quint32 *dst, const uchar *src, int len);
+
+ if (features & NEON)
+ rgb888ToRgb32ConverterPtr = qt_convert_rgb888_to_rgb32_neon;
+#endif // QT_HAVE_NEON
+#if defined(QT_HAVE_SSSE3)
+ // from qimage_ssse3.cpp
+ Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_ssse3(quint32 *dst, const uchar *src, int len);
+
+ if (features & SSSE3)
+ rgb888ToRgb32ConverterPtr = qt_convert_rgb888_to_rgb32_ssse3;
+#endif // QT_HAVE_SSSE3
+}
+
+QJpegHandler::~QJpegHandler()
+{
+ delete d;
+}
+
+bool QJpegHandler::canRead() const
+{
+ if(d->state == QJpegHandlerPrivate::Ready && !canRead(device()))
+ return false;
+
+ if (d->state != QJpegHandlerPrivate::Error) {
+ setFormat("jpeg");
+ return true;
+ }
+
+ return false;
+}
+
+bool QJpegHandler::canRead(QIODevice *device)
+{
+ if (!device) {
+ qWarning("QJpegHandler::canRead() called with no device");
+ return false;
+ }
+
+ char buffer[2];
+ if (device->peek(buffer, 2) != 2)
+ return false;
+ return uchar(buffer[0]) == 0xff && uchar(buffer[1]) == 0xd8;
+}
+
+bool QJpegHandler::read(QImage *image)
+{
+ if (!canRead())
+ return false;
+ return d->read(image);
+}
+
+bool QJpegHandler::write(const QImage &image)
+{
+ return write_jpeg_image(image, device(), d->quality);
+}
+
+bool QJpegHandler::supportsOption(ImageOption option) const
+{
+ return option == Quality
+ || option == ScaledSize
+ || option == ScaledClipRect
+ || option == ClipRect
+ || option == Size
+ || option == ImageFormat;
+}
+
+QVariant QJpegHandler::option(ImageOption option) const
+{
+ switch(option) {
+ case Quality:
+ return d->quality;
+ case ScaledSize:
+ return d->scaledSize;
+ case ScaledClipRect:
+ return d->scaledClipRect;
+ case ClipRect:
+ return d->clipRect;
+ case Size:
+ d->readJpegHeader(device());
+ return d->size;
+ case ImageFormat:
+ d->readJpegHeader(device());
+ return d->format;
+ default:
+ return QVariant();
+ }
+}
+
+void QJpegHandler::setOption(ImageOption option, const QVariant &value)
+{
+ switch(option) {
+ case Quality:
+ d->quality = value.toInt();
+ break;
+ case ScaledSize:
+ d->scaledSize = value.toSize();
+ break;
+ case ScaledClipRect:
+ d->scaledClipRect = value.toRect();
+ break;
+ case ClipRect:
+ d->clipRect = value.toRect();
+ break;
+ default:
+ break;
+ }
+}
+
+QByteArray QJpegHandler::name() const
+{
+ return "jpeg";
+}
+
+
+
+
+QT_END_NAMESPACE
diff --git a/src/gui/image/qjpeghandler.pri b/src/gui/image/qjpeghandler.pri
new file mode 100644
index 0000000000..3cb35c95ed
--- /dev/null
+++ b/src/gui/image/qjpeghandler.pri
@@ -0,0 +1,10 @@
+# common to plugin and built-in forms
+INCLUDEPATH *= $$PWD
+HEADERS += $$PWD/qjpeghandler_p.h
+SOURCES += $$PWD/qjpeghandler.cpp
+contains(QT_CONFIG, system-jpeg) {
+ if(unix|win32-g++*): LIBS += -ljpeg
+ else:win32: LIBS += libjpeg.lib
+} else {
+ include($$PWD/../../3rdparty/libjpeg.pri)
+}
diff --git a/src/gui/image/qjpeghandler_p.h b/src/gui/image/qjpeghandler_p.h
new file mode 100644
index 0000000000..0bd7894482
--- /dev/null
+++ b/src/gui/image/qjpeghandler_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**