#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 <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 <qhash.h>
#ifdef QT_RASTER_IMAGEENGINE
#include <private/qpaintengine_raster_p.h>
#else
#include <qpaintengine.h>
#endif
#include <private/qimage_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(); \
}
typedef void (*_qt_image_cleanup_hook)(int);
Q_GUI_EXPORT _qt_image_cleanup_hook qt_image_cleanup_hook = 0;
typedef void (*_qt_image_cleanup_hook_64)(qint64);
Q_GUI_EXPORT _qt_image_cleanup_hook_64 qt_image_cleanup_hook_64 = 0;
static QImage rotated90(const QImage &src);
static QImage rotated180(const QImage &src);
static QImage rotated270(const QImage &src);
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;
}
extern int qt_defaultDpiX();
extern int qt_defaultDpiY();
QBasicAtomicInt qimage_serial_number = Q_BASIC_ATOMIC_INITIALIZER(1);
QImageData::QImageData()
{
ser_no = qimage_serial_number.fetchAndAddRelaxed(1);
detach_no = 0;
ref = 0;
width = height = depth = 0;
nbytes = 0;
data = 0;
own_data = true;
ro_data = false;
has_alpha_clut = false;
#ifdef QT3_SUPPORT
jumptable = 0;
#endif
bytes_per_line = 0;
format = QImage::Format_ARGB32;
dpmx = qt_defaultDpiX() * 100 / qreal(2.54);
dpmy = qt_defaultDpiY() * 100 / qreal(2.54);
offset = QPoint(0,0);
paintEngine = 0;
}
static int 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;
}
QImageData * QImageData::create(const QSize &size, QImage::Format format, int numColors)
{
if (!size.isValid() || numColors < 0 || format == QImage::Format_Invalid)
return 0;
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 = 0;
switch(format) {
case QImage::NImageFormats:
case QImage::Format_Invalid:
Q_ASSERT(false);
case QImage::Format_Mono:
case QImage::Format_MonoLSB:
depth = 1;
numColors = 2;
break;
case QImage::Format_Indexed8:
depth = 8;
numColors = qMin(numColors, 256);
numColors = qMax(0, numColors);
break;
case QImage::Format_RGB32:
case QImage::Format_ARGB32:
case QImage::Format_ARGB32_Premultiplied:
depth = 32;
numColors = 0;
break;
case QImage::Format_RGB555:
case QImage::Format_RGB16:
case QImage::Format_RGB444:
case QImage::Format_ARGB4444_Premultiplied:
depth = 16;
numColors = 0;
break;
case QImage::Format_ARGB6666_Premultiplied:
case QImage::Format_RGB666:
case QImage::Format_ARGB8565_Premultiplied:
case QImage::Format_ARGB8555_Premultiplied:
case QImage::Format_RGB888:
depth = 24;
numColors = 0;
break;
}
const int bytes_per_line = ((width * depth + 31) >> 5) << 2;
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;
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->bytes_per_line = bytes_per_line;
d->nbytes = d->bytes_per_line*height;
d->data = (uchar *)malloc(d->nbytes);
if (!d->data) {
delete d;
return 0;
}
d->ref.ref();
return d;
}
QImageData::~QImageData()
{
if (qt_image_cleanup_hook_64)
qt_image_cleanup_hook_64((((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;
}
static const uchar bitflip[256] = {
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()
{
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
00776 QImage::QImage()
: QPaintDevice()
{
d = 0;
}
00790 QImage::QImage(int width, int height, Format format)
: QPaintDevice()
{
d = QImageData::create(QSize(width, height), format, 0);
}
00803 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 = 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;
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;
}
00870 QImage::QImage(uchar* data, int width, int height, Format format)
: QPaintDevice()
{
d = QImageData::create(data, width, height, 0, format, false);
}
00899 QImage::QImage(const uchar* data, int width, int height, Format format)
: QPaintDevice()
{
d = QImageData::create(const_cast<uchar*>(data), width, height, 0, format, true);
}
00918 QImage::QImage(uchar *data, int width, int height, int bytesPerLine, Format format)
:QPaintDevice()
{
d = QImageData::create(data, width, height, bytesPerLine, format, false);
}
00946 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);
}
00971 QImage::QImage(const QString &fileName, const char *format)
: QPaintDevice()
{
d = 0;
load(fileName, format);
}
#ifndef QT_NO_CAST_FROM_ASCII
01003 QImage::QImage(const char *fileName, const char *format)
: QPaintDevice()
{
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);
01033 QImage::QImage(const char * const xpm[])
: QPaintDevice()
{
d = 0;
if (!xpm)
return;
if (!qt_read_xpm_image_or_array(0, xpm, *this))
qWarning("QImage::QImage(), XPM is not supported");
}
#endif // QT_NO_IMAGEFORMAT_XPM
01071 QImage::QImage(const QImage &image)
: QPaintDevice()
{
d = image.d;
if (d)
d->ref.ref();
}
#ifdef QT3_SUPPORT
QImage::QImage(int w, int h, int depth, int numColors, Endian bitOrder)
: QPaintDevice()
{
d = QImageData::create(QSize(w, h), formatFor(depth, bitOrder), numColors);
}
QImage::QImage(const QSize& size, int depth, int numColors, Endian bitOrder)
: QPaintDevice()
{
d = QImageData::create(size, formatFor(depth, bitOrder), numColors);
}
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;
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;
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) {
setNumColors(numColors);
}
}
#ifdef Q_WS_QWS
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;
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) {
setNumColors(numColors);
}
}
#endif // Q_WS_QWS
#endif // QT3_SUPPORT
01255 QImage::~QImage()
{
if (d && !d->ref.deref())
delete d;
}
01271 QImage &QImage::operator=(const QImage &image)
{
if (image.d)
image.d->ref.ref();
if (d && !d->ref.deref())
delete d;
d = image.d;
return *this;
}
01284 int QImage::devType() const
{
return QInternal::Image;
}
01292 QImage::operator QVariant() const
{
return QVariant(QVariant::Image, this);
}
01308 void QImage::detach()
{
if (d) {
if (qt_image_cleanup_hook_64 && d->ref == 1)
qt_image_cleanup_hook_64(cacheKey());
if (d->ref != 1 || d->ro_data)
*this = copy();
if (d)
++d->detach_no;
}
}
01353 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;
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) {
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 {
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;
}
01482 bool QImage::isNull() const
{
return !d;
}
01494 int QImage::width() const
{
return d ? d->width : 0;
}
01506 int QImage::height() const
{
return d ? d->height : 0;
}
01518 QSize QImage::size() const
{
return d ? QSize(d->width, d->height) : QSize();
}
01531 QRect QImage::rect() const
{
return d ? QRect(0, 0, d->width, d->height) : QRect();
}
01548 int QImage::depth() const
{
return d ? d->depth : 0;
}
01564 int QImage::numColors() const
{
return d ? d->colortable.size() : 0;
}
#ifdef QT3_SUPPORT
uchar **QImage::jumpTable()
{
if (!d)
return 0;
detach();
if (!d->jumptable) {
d->jumptable = (uchar **)malloc(d->height*sizeof(uchar *));
uchar *data = d->data;
int height = d->height;
uchar **p = d->jumptable;
while (height--) {
*p++ = data;
data += d->bytes_per_line;
}
}
return d->jumptable;
}
const uchar * const *QImage::jumpTable() const
{
if (!d)
return 0;
if (!d->jumptable) {
d->jumptable = (uchar **)malloc(d->height*sizeof(uchar *));
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
01640 void QImage::setColorTable(const QVector<QRgb> colors)
{
if (!d)
return;
detach();
d->colortable = colors;
d->has_alpha_clut = false;
for (int i = 0; i < d->colortable.size(); ++i)
d->has_alpha_clut |= (qAlpha(d->colortable.at(i)) != 255);
}
01657 QVector<QRgb> QImage::colorTable() const
{
return d ? d->colortable : QVector<QRgb>();
}
01669 int QImage::numBytes() const
{
return d ? d->nbytes : 0;
}
01681 int QImage::bytesPerLine() const
{
return (d && d->height) ? d->nbytes / d->height : 0;
}
01698 QRgb QImage::color(int i) const
{
Q_ASSERT(i < numColors());
return d ? d->colortable.at(i) : QRgb(uint(-1));
}
01716 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();
if (i >= d->colortable.size())
setNumColors(i+1);
d->colortable[i] = c;
d->has_alpha_clut |= (qAlpha(c) != 255);
}
01747 uchar *QImage::scanLine(int i)
{
detach();
Q_ASSERT(i >= 0 && i < height());
return d->data + i * d->bytes_per_line;
}
01757 const uchar *QImage::scanLine(int i) const
{
Q_ASSERT(i >= 0 && i < height());
return d->data + i * d->bytes_per_line;
}
01775 uchar *QImage::bits()
{
if (!d)
return 0;
detach();
return d->data;
}
01790 const uchar *QImage::bits() const
{
return d ? d->data : 0;
}
01833 void QImage::fill(uint pixel)
{
if (!d)
return;
detach();
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);
}
01886 void QImage::invertPixels(InvertMode mode)
{
if (!d)
return;
detach();
if (depth() != 32) {
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;
}
}
#if defined(write)
# undef write
#endif
#if defined(close)
# undef close
#endif
#if defined(read)
# undef read
#endif
01952 void QImage::setNumColors(int numColors)
{
if (!d) {
qWarning("QImage::setNumColors: null image");
return;
}
detach();
if (numColors == d->colortable.size())
return;
if (numColors <= 0) {
d->colortable = QVector<QRgb>();
return;
}
int nc = d->colortable.size();
d->colortable.resize(numColors);
for (int i = nc; i < numColors; ++i)
d->colortable[i] = 0;
}
01977 QImage::Format QImage::format() const
{
return d ? d->format : Format_Invalid;
}
#ifdef QT3_SUPPORT
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;
}
}
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);
}
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;
}
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
typedef void (*Image_Converter)(QImageData *dest, const QImageData *src, 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 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) {
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) {
for (int i = 0; i < colorTable.size(); ++i)
colorTable[i] = PREMUL(colorTable.at(i));
}
return colorTable;
}
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];
bool use_gray = (d == 8);
if (use_gray) {
if (fromalpha) {
for (int i = 0; i < src->colortable.size(); i++)
gray[i] = (255 - (src->colortable.at(i) >> 24));
} else {
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: {
int *line1 = new int[w];
int *line2 = new int[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) {
while (p < end)
*b2++ = gray[*p++];
} else {
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++) {
int *tmp = line1; line1 = line2; line2 = tmp;
bool not_last_line = y < h - 1;
if (not_last_line) {
p = src->data + (y+1)*src->bytes_per_line;
end = p + wbytes;
b2 = line2;
if (use_gray) {
while (p < end)
*b2++ = gray[*p++];
} else {
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) {
err = *b1++;
*p |= 1 << bit;
} else {
err = *b1++ - 255;
}
if (bit == 0) {
p++;
bit = 7;
} else {
bit--;
}
if (x < w)
*b1 += (err*7)>>4;
if (not_last_line) {
b2[0] += (err*5)>>4;
if (x > 1)
b2[-1] += (err*3)>>4;
if (x < w)
b2[1] += err>>4;
}
b2++;
}
}
delete [] line1;
delete [] line2;
} 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
{
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: {
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;
if (bit == 0) {
m++;
bit = 7;
} else {
bit--;
}
}
} else {
while (p < end) {
if (qGray(*p++) < 128)
*m |= 1 << bit;
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;
if (bit == 0) {
m++;
bit = 7;
} else {
bit--;
}
}
dst_data += dst_bpl;
src_data += src_bpl;
}
}
}
}
if (dst->format == QImage::Format_MonoLSB) {
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)
{
QImageData *tmp = QImageData::create(QSize(src->width, src->height), QImage::Format_ARGB32);
convert_ARGB_PM_to_ARGB(tmp, src, flags);
dither_to_Mono(dst, tmp, flags, false);
delete tmp;
}
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;
QRgbMap table[tablesize];
int pix=0;
if (!dst->colortable.isEmpty()) {
QVector<QRgb> ctbl = dst->colortable;
dst->colortable.resize(256);
for (int i = 0; i < dst->colortable.size(); ++i) {
QRgb p = ctbl.at(i) | alpha_mask;
int hash = p % tablesize;
for (;;) {
if (table[hash].used) {
if (table[hash].rgb == p) {
break;
} else {
if (++hash == tablesize) hash = 0;
}
} else {
Q_ASSERT (pix != 256);
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++) {
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)) {
break;
} else {
if (++hash == tablesize) hash = 0;
}
} else {
if (pix == 256) {
do_quant = true;
x = src->width;
y = src->height;
} else {
dst->colortable[pix] = p;
table[hash].pix = pix++;
table[hash].rgb = p;
table[hash].used = 1;
}
break;
}
}
*b++ = table[hash].pix;
}
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) {
#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++)
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];
line1[0] = new int[src->width];
line2[0] = new int[src->width];
line1[1] = new int[src->width];
line2[1] = new int[src->width];
line1[2] = new int[src->width];
line2[2] = new int[src->width];
pv[0] = new int[src->width];
pv[1] = new int[src->width];
pv[2] = new int[src->width];
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];
}
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;
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;
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;
}
delete [] line1[0];
delete [] line2[0];
delete [] line1[1];
delete [] line2[1];
delete [] line1[2];
delete [] line2[2];
delete [] pv[0];
delete [] pv[1];
delete [] pv[2];
} else {
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;
QImageData *mask = QImageData::create(QSize(src->width, src->height), QImage::Format_Mono);
dither_to_Mono(mask, 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;
delete mask;
}
#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)
{
QImageData *tmp = QImageData::create(QSize(src->width, src->height), QImage::Format_ARGB32);
convert_ARGB_PM_to_ARGB(tmp, src, flags);
convert_RGB_to_Indexed8(dst, tmp, flags);
delete tmp;
}
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);
int w = src->width;
const uchar *src_data = src->data;
uchar *dest_data = dest->data;
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(*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);
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
static const 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
},
{
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
},
{
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
},
{
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)
},
{
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)
},
{
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
},
{
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
},
{
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
},
{
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
},
{
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
},
{
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
},
{
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
},
{
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
},
{
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
},
{
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
}
};
03287 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 (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;
}
03412 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
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
03476 bool QImage::valid(int x, int y) const
{
return d
&& x >= 0 && x < d->width
&& y >= 0 && y < d->height;
}
03499 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;
}
03536 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];
}
}
03601 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;
}
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:
((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
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
03720 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 < numColors(); i++)
if (!qIsGray(d->colortable.at(i)))
return false;
}
return true;
}
03762 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 < numColors(); i++)
if (d->colortable.at(i) != qRgb(i,i,i))
return false;
return true;
}
}
return false;
}
03850 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 copy();
QImage img;
QTransform wm;
wm.scale((qreal)newSize.width() / width(), (qreal)newSize.height() / height());
img = transformed(wm, mode);
return img;
}
03885 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();
QTransform wm;
qreal factor = (qreal) w / width();
wm.scale(factor, factor);
return transformed(wm, mode);
}
03914 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();
QTransform wm;
qreal factor = (qreal) h / height();
wm.scale(factor, factor);
return transformed(wm, mode);
}
03946 QMatrix QImage::trueMatrix(const QMatrix &matrix, int w, int h)
{
return trueMatrix(QTransform(matrix), w, h).toAffine();
}
03964 QImage QImage::transformed(const QMatrix &matrix, Qt::TransformationMode mode) const
{
return transformed(QTransform(matrix), mode);
}
03986 QImage QImage::createAlphaMask(Qt::ImageConversionFlags flags) const
{
if (!d || d->format == QImage::Format_RGB32)
return QImage();
if (d->depth == 1) {
return convertToFormat(Format_Indexed8, flags).createAlphaMask(flags);
}
QImage mask(d->width, d->height, Format_MonoLSB);
dither_to_Mono(mask.d, d, flags, true);
return mask;
}
#ifndef QT_NO_IMAGE_HEURISTIC_MASK
04027 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);
m.setNumColors(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++) {
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
04129 QImage QImage::createMaskFromColor(QRgb color, Qt::MaskMode mode) const
{
QImage maskImage(size(), QImage::Format_MonoLSB);
for (int w = 0; w < width(); w++) {
for (int h = 0; h < height(); h++) {
if ((uint) pixel(w, h) == color)
maskImage.setPixel(w, h, Qt::color1);
else
maskImage.setPixel(w, h, Qt::color0);
}
}
if (mode == Qt::MaskOutColor)
maskImage.invertPixels();
return maskImage;
}
04167 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;
QImage result(d->width, d->height, d->format);
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;
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];
}
}
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];
}
}
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];
}
}
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];
}
}
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);
quint8* a = a0+dxs;
while (a >= a0) {
*a = bitflip[*a];
a--;
}
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;
}
04288 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);
for (int i = 0; i < d->height; i++) {
uint *q = (uint*)res.scanLine(i);
uint *p = (uint*)scanLine(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);
for (int i = 0; i < d->height; i++) {
ushort *q = (ushort*)res.scanLine(i);
const ushort *p = (const ushort*)scanLine(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);
for (int i = 0; i < d->height; i++) {
quint8 *p = (quint8*)scanLine(i);
const quint8 *end = p + d->width * sizeof(qargb8565);
while (p < end) {
quint16 *q = reinterpret_cast<quint16*>(p + 1);
*q = ((*q << 11) & 0xf800) | ((*q >> 11) & 0x1f) | (*q & 0x07e0);
p += sizeof(qargb8565);
}
}
break;
case Format_RGB666:
res = QImage(d->width, d->height, d->format);
for (int i = 0; i < d->height; i++) {
qrgb666 *q = reinterpret_cast<qrgb666*>(res.scanLine(i));
const qrgb666 *p = reinterpret_cast<const qrgb666*>(scanLine(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);
for (int i = 0; i < d->height; i++) {
qargb6666 *q = reinterpret_cast<qargb6666*>(res.scanLine(i));
const qargb6666 *p = reinterpret_cast<const qargb6666*>(scanLine(i));
const qargb6666 *end = p + d->width;
while (p < end) {
const QRgb rgb = quint32(*p++);
*q++ = qRgba(qBlue(rgb), qGreen(rgb), qRed(rgb), qAlpha(rgb));
}
}
break;
case Format_RGB555:
res = QImage(d->width, d->height, d->format);
for (int i = 0; i < d->height; i++) {
ushort *q = (ushort*)res.scanLine(i);
const ushort *p = (const ushort*)scanLine(i);
const ushort *end = p + d->width;
while (p < end) {
*q = ((*p << 10) & 0x7800) | ((*p >> 10) & 0x1f) | (*p & 0x83e0);
p++;
q++;
}
}
break;
case Format_ARGB8555_Premultiplied:
res = QImage(d->width, d->height, d->format);
for (int i = 0; i < d->height; i++) {
quint8 *p = (quint8*)scanLine(i);
const quint8 *end = p + d->width * sizeof(qargb8555);
while (p < end) {
quint16 *q = reinterpret_cast<quint16*>(p + 1);
*q = ((*q << 10) & 0x7800) | ((*q >> 10) & 0x1f) | (*q & 0x83e0);
p += sizeof(qargb8555);
}
}
break;
case Format_RGB888:
res = QImage(d->width, d->height, d->format);
for (int i = 0; i < d->height; i++) {
quint8 *q = reinterpret_cast<quint8*>(res.scanLine(i));
const quint8 *p = reinterpret_cast<const quint8*>(scanLine(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:
res = QImage(d->width, d->height, d->format);
for (int i = 0; i < d->height; i++) {
quint8 *q = reinterpret_cast<quint8*>(res.scanLine(i));
const quint8 *p = reinterpret_cast<const quint8*>(scanLine(i));
const quint8 *end = p + d->width * sizeof(qrgb444);
while (p < end) {
q[0] = (p[0] & 0xf0) | ((p[1] & 0x0f) << 8);
q[1] = ((p[0] & 0x0f) >> 8) | (p[1] & 0xf0);
q += sizeof(qrgb444);
p += sizeof(qrgb444);
}
}
break;
case Format_ARGB4444_Premultiplied:
res = QImage(d->width, d->height, d->format);
for (int i = 0; i < d->height; i++) {
quint8 *q = reinterpret_cast<quint8*>(res.scanLine(i));
const quint8 *p = reinterpret_cast<const quint8*>(scanLine(i));
const quint8 *end = p + d->width * sizeof(qargb4444);
while (p < end) {
q[0] = (p[0] & 0xf0) | ((p[1] & 0x0f) << 8);
q[1] = ((p[0] & 0x0f) >> 8) | (p[1] & 0xf0);
q += sizeof(qargb4444);
p += sizeof(qargb4444);
}
}
break;
}
return res;
}
04460 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;
}
04480 bool QImage::load(QIODevice* device, const char* format)
{
QImage image = QImageReader(device, format).read();
if(!image.isNull()) {
operator=(image);
return true;
}
return false;
}
04504 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;
}
04535 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();
}
04568 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);
}
04587 bool QImage::save(QIODevice* device, const char* format, int quality) const
{
if (isNull())
return false;
QImageWriter writer(device, format);
return d->doImageIO(this, &writer, quality);
}
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);
}
#if !defined(QT_NO_DATASTREAM)
04622 QDataStream &operator<<(QDataStream &s, const QImage &image)
{
if (s.version() >= 5) {
if (image.isNull()) {
s << (qint32) 0;
return s;
} else {
s << (qint32) 1;
}
}
QImageWriter writer(s.device(), s.version() == 1 ? "bmp" : "png");
writer.write(image);
return s;
}
04648 QDataStream &operator>>(QDataStream &s, QImage &image)
{
if (s.version() >= 5) {
qint32 nullMarker;
s >> nullMarker;
if (!nullMarker) {
image = QImage();
return s;
}
}
image = QImageReader(s.device(), 0).read();
return s;
}
#endif
#ifdef QT3_SUPPORT
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);
}
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
04738 bool QImage::operator==(const QImage & i) const
{
if (i.d == d)
return true;
if (!i.d || !d)
return false;
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->colortable != i.d->colortable)
return false;
if (d->format >= Format_ARGB32) {
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 {
int w = width();
int h = height();
for (int y=0; y<h; ++y) {
for (int x=0; x<w; ++x) {
if (pixelIndex(x, y) != i.pixelIndex(x, y))
return false;
}
}
}
} else {
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;
}
04803 bool QImage::operator!=(const QImage & i) const
{
return !(*this == i);
}
04819 int QImage::dotsPerMeterX() const
{
return d ? qRound(d->dpmx) : 0;
}
04832 int QImage::dotsPerMeterY() const
{
return d ? qRound(d->dpmy) : 0;
}
04847 void QImage::setDotsPerMeterX(int x)
{
if (!d || !x)
return;
detach();
d->dpmx = x;
}
04865 void QImage::setDotsPerMeterY(int y)
{
if (!d || !y)
return;
detach();
d->dpmy = y;
}
04881 QPoint QImage::offset() const
{
return d ? d->offset : QPoint();
}
04895 void QImage::setOffset(const QPoint& p)
{
if (!d)
return;
detach();
d->offset = p;
}
#ifndef QT_NO_IMAGE_TEXT
04912 QStringList QImage::textKeys() const
{
return d ? QStringList(d->text.keys()) : QStringList();
}
04924 QString QImage::text(const QString &key) const
{
if (!d)
return QString();
if (!key.isEmpty())
return d->text.value(key);
QString tmp;
foreach (QString key, d->text.keys()) {
if (!tmp.isEmpty())
tmp += QLatin1String("\n\n");
tmp += key + QLatin1String(": ") + d->text.value(key).simplified();
}
return tmp;
}
04965 void QImage::setText(const QString &key, const QString &value)
{
if (!d)
return;
detach();
d->text.insert(key, value);
}
04985 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);
}
05007 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);
}
05027 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;
}
05053 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;
}
05095 void QImage::setText(const char* key, const char* lang, const QString& s)
{
if (!d)
return;
detach();
QString k = QString::fromAscii(key);
if (lang && *lang)
k += QLatin1Char('/') + QString::fromAscii(lang);
d->text.insert(k, s);
}
#endif // QT_NO_IMAGE_TEXT
05134 QPaintEngine *QImage::paintEngine() const
{
if (!d)
return 0;
#ifdef QT_RASTER_IMAGEENGINE
if (!d->paintEngine) {
d->paintEngine = new QRasterPaintEngine();
}
#endif
return d->paintEngine;
}
05153 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;
}
#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;
#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;
#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;
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++) {
trigx = m21ydx;
trigy = m22ydy;
uchar *maxp = dptr + dbpl;
if (depth != 1) {
switch (depth) {
case 8:
while (dptr < maxp) {
if (trigx < maxws && trigy < maxhs)
*dptr = *(sptr+sbpl*(trigy>>12)+(trigx>>12));
trigx += m11;
trigy += m12;
dptr++;
}
break;
case 16:
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:
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:
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
05419 int QImage::serialNumber() const
{
if (!d)
return 0;
else
return d->ser_no;
}
05434 qint64 QImage::cacheKey() const
{
if (!d)
return 0;
else
return (((qint64) d->ser_no) << 32) | ((qint64) d->detach_no);
}
05450 bool QImage::isDetached() const
{
return d && d->ref == 1;
}
05471 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;
}
detach();
*this = convertToFormat(QImage::Format_ARGB32_Premultiplied);
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;
}
}
}
05548 QImage QImage::alphaChannel() const
{
if (!d)
return QImage();
int w = d->width;
int h = d->height;
QImage image(w, h, Format_Indexed8);
image.setNumColors(256);
for (int i=0; i<256; ++i)
image.setColor(i, qRgb(i, i, i));
if (d->format == Format_Indexed8 && hasAlphaChannel()) {
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 if (d->format == Format_ARGB32 || d->format == Format_ARGB32_Premultiplied) {
const uchar *src_data = 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 += d->bytes_per_line;
dest_data += image.d->bytes_per_line;
}
} else {
image.fill(255);
}
return image;
}
05604 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)));
}
#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
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.numColors() > 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.numColors())
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.numColors() > 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.numColors())
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;
}
05807 QImage QImage::transformed(const QTransform &matrix, Qt::TransformationMode mode ) const
{
if (!d)
return QImage();
int ws = width();
int hs = height();
int wd;
int hd;
QTransform mat = trueMatrix(matrix, ws, hs);
bool complex_xform = false;
bool scale_xform = false;
if (mat.type() <= QTransform::TxScale) {
if (mat.type() == QTransform::TxNone)
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();
if (scale_xform && mode == Qt::SmoothTransformation) {
if (mat.m11() < 0.0F && mat.m22() < 0.0F) {
return smoothScaled(mirrored(true, true), wd, hd);
} else if (mat.m11() < 0.0F) {
return smoothScaled(mirrored(true, false), wd, hd);
} else if (mat.m22() < 0.0F) {
return smoothScaled(mirrored(false, true), wd, hd);
} else {
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)
target_format = Format_ARGB32_Premultiplied;
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) {
case 8:
if (dImage.d->colortable.size() < 256) {
dImage.d->colortable.append(0x0);
memset(dImage.bits(), dImage.d->colortable.size() - 1, dImage.numBytes());
} else {
memset(dImage.bits(), 0, dImage.numBytes());
}
break;
case 1:
case 16:
case 24:
case 32:
memset(dImage.bits(), 0x00, dImage.numBytes());
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);
if (!invertible)
return QImage();
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;
}
05955 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());
}
QT_END_NAMESPACE