--- a/src/gui/image/qimage.cpp Tue Jul 06 15:10:48 2010 +0300
+++ b/src/gui/image/qimage.cpp Wed Aug 18 10:37:55 2010 +0300
@@ -58,6 +58,7 @@
#include <private/qmemrotate_p.h>
#include <private/qpixmapdata_p.h>
#include <private/qimagescale_p.h>
+#include <private/qsimd_p.h>
#include <qhash.h>
@@ -209,7 +210,7 @@
break;
}
- const int bytes_per_line = ((width * depth + 31) >> 5) << 2; // bytes per scanline (must be multiple of 8)
+ 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
@@ -272,6 +273,8 @@
switch (format) {
+ case QImage::Format_Mono:
+ case QImage::Format_MonoLSB:
case QImage::Format_Indexed8:
has_alpha_pixels = has_alpha_clut;
break;
@@ -2272,6 +2275,8 @@
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);
@@ -2296,6 +2301,209 @@
}
}
+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);
@@ -3445,6 +3653,116 @@
} // 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
+}
+
/*!
Returns a copy of the image in the given \a format.
@@ -3797,7 +4115,7 @@
}
break;
case Format_Indexed8:
- if (index_or_rgb > (uint)d->colortable.size()) {
+ if (index_or_rgb >= (uint)d->colortable.size()) {
qWarning("QImage::setPixel: Index %d out of range", index_or_rgb);
return;
}
@@ -4208,6 +4526,7 @@
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());
@@ -4300,6 +4619,7 @@
if (!d)
return QImage();
QImage maskImage(size(), QImage::Format_MonoLSB);
+ QIMAGE_SANITYCHECK_MEMORY(maskImage);
maskImage.fill(0);
uchar *s = maskImage.bits();
@@ -4360,6 +4680,7 @@
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)
@@ -4497,6 +4818,7 @@
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*)scanLine(i);
@@ -4510,6 +4832,7 @@
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*)scanLine(i);
@@ -4523,6 +4846,7 @@
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++) {
quint8 *p = (quint8*)scanLine(i);
const quint8 *end = p + d->width * sizeof(qargb8565);
@@ -4535,6 +4859,7 @@
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*>(scanLine(i));
@@ -4547,6 +4872,7 @@
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++) {
qargb6666 *q = reinterpret_cast<qargb6666*>(res.scanLine(i));
const qargb6666 *p = reinterpret_cast<const qargb6666*>(scanLine(i));
@@ -4559,6 +4885,7 @@
break;
case Format_RGB555:
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*)scanLine(i);
@@ -4572,6 +4899,7 @@
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++) {
quint8 *p = (quint8*)scanLine(i);
const quint8 *end = p + d->width * sizeof(qargb8555);
@@ -4584,6 +4912,7 @@
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 = reinterpret_cast<quint8*>(res.scanLine(i));
const quint8 *p = reinterpret_cast<const quint8*>(scanLine(i));
@@ -4599,6 +4928,7 @@
break;
case Format_RGB444:
res = QImage(d->width, d->height, d->format);
+ QIMAGE_SANITYCHECK_MEMORY(res);
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));
@@ -4613,6 +4943,7 @@
break;
case Format_ARGB4444_Premultiplied:
res = QImage(d->width, d->height, d->format);
+ QIMAGE_SANITYCHECK_MEMORY(res);
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));
@@ -4812,7 +5143,7 @@
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(), {Format of the QDataStream Operators}
+ \sa QImage::save(), {Serializing Qt Data Types}
*/
QDataStream &operator<<(QDataStream &s, const QImage &image)
@@ -4838,7 +5169,7 @@
Reads an image from the given \a stream and stores it in the given
\a image.
- \sa QImage::load(), {Format of the QDataStream Operators}
+ \sa QImage::load(), {Serializing Qt Data Types}
*/
QDataStream &operator>>(QDataStream &s, QImage &image)
@@ -6261,6 +6592,18 @@
return matrix * QTransform().translate(-delta.x(), -delta.y());
}
+bool QImageData::convertInPlace(QImage::Format newFormat, Qt::ImageConversionFlags flags)
+{
+ if (format == newFormat)
+ return true;
+
+ 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