summaryrefslogtreecommitdiffstats
path: root/src/gui/image/qimage.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/image/qimage.cpp')
-rw-r--r--src/gui/image/qimage.cpp2477
1 files changed, 235 insertions, 2242 deletions
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index 12ab5eaffa..944dd04b8c 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -715,42 +715,6 @@ bool QImageData::checkForAlphaPixels() const
QImage member functions
*****************************************************************************/
-// table to flip bits
-static const uchar bitflip[256] = {
- /*
- open OUT, "| fmt";
- for $i (0..255) {
- print OUT (($i >> 7) & 0x01) | (($i >> 5) & 0x02) |
- (($i >> 3) & 0x04) | (($i >> 1) & 0x08) |
- (($i << 7) & 0x80) | (($i << 5) & 0x40) |
- (($i << 3) & 0x20) | (($i << 1) & 0x10), ", ";
- }
- close OUT;
- */
- 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
- 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
- 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
- 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
- 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
- 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
- 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
- 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
- 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
- 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
- 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
- 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
- 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
- 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
- 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
- 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255
-};
-
-const uchar *qt_get_bitflip_array() // called from QPixmap code
-{
- return bitflip;
-}
-
-
/*!
Constructs a null image.
@@ -1105,8 +1069,7 @@ void QImage::detach()
if (d->ref.load() != 1 || d->ro_data)
*this = copy();
- if (d)
- ++d->detach_no;
+ ++d->detach_no;
}
}
@@ -1898,2094 +1861,6 @@ QImage::Format QImage::format() const
return d ? d->format : Format_Invalid;
}
-
-
-/*****************************************************************************
- Internal routines for converting image depth.
- *****************************************************************************/
-
-typedef void (*Image_Converter)(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
-
-typedef bool (*InPlace_Image_Converter)(QImageData *data, Qt::ImageConversionFlags);
-
-static void convert_ARGB_to_ARGB_PM(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
-{
- Q_ASSERT(src->format == QImage::Format_ARGB32 || src->format == QImage::Format_RGBA8888);
- Q_ASSERT(dest->format == QImage::Format_ARGB32_Premultiplied || dest->format == QImage::Format_RGBA8888_Premultiplied);
- Q_ASSERT(src->width == dest->width);
- Q_ASSERT(src->height == dest->height);
-
- const int src_pad = (src->bytes_per_line >> 2) - src->width;
- const int dest_pad = (dest->bytes_per_line >> 2) - dest->width;
- const QRgb *src_data = (QRgb *) src->data;
- QRgb *dest_data = (QRgb *) dest->data;
-
- for (int i = 0; i < src->height; ++i) {
- const QRgb *end = src_data + src->width;
- while (src_data < end) {
- *dest_data = PREMUL(*src_data);
- ++src_data;
- ++dest_data;
- }
- src_data += src_pad;
- dest_data += dest_pad;
- }
-}
-
-static bool convert_ARGB_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConversionFlags)
-{
- Q_ASSERT(data->format == QImage::Format_ARGB32);
-
- const int pad = (data->bytes_per_line >> 2) - data->width;
- QRgb *rgb_data = (QRgb *) data->data;
-
- for (int i = 0; i < data->height; ++i) {
- const QRgb *end = rgb_data + data->width;
- while (rgb_data < end) {
- *rgb_data = PREMUL(*rgb_data);
- ++rgb_data;
- }
- rgb_data += pad;
- }
- data->format = QImage::Format_ARGB32_Premultiplied;
- return true;
-}
-
-static void convert_ARGB_to_RGBx(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
-{
- Q_ASSERT(src->format == QImage::Format_ARGB32);
- Q_ASSERT(dest->format == QImage::Format_RGBX8888);
- 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 quint32 *src_data = (quint32 *) src->data;
- quint32 *dest_data = (quint32 *) dest->data;
-
- for (int i = 0; i < src->height; ++i) {
- const quint32 *end = src_data + src->width;
- while (src_data < end) {
- *dest_data = ARGB2RGBA(0xff000000 | *src_data);
- ++src_data;
- ++dest_data;
- }
- src_data += src_pad;
- dest_data += dest_pad;
- }
-}
-
-static void convert_ARGB_to_RGBA(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
-{
- Q_ASSERT(src->format == QImage::Format_ARGB32 || src->format == QImage::Format_ARGB32_Premultiplied);
- Q_ASSERT(dest->format == QImage::Format_RGBA8888 || dest->format == QImage::Format_RGBA8888_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 quint32 *src_data = (quint32 *) src->data;
- quint32 *dest_data = (quint32 *) dest->data;
-
- for (int i = 0; i < src->height; ++i) {
- const quint32 *end = src_data + src->width;
- while (src_data < end) {
- *dest_data = ARGB2RGBA(*src_data);
- ++src_data;
- ++dest_data;
- }
- src_data += src_pad;
- dest_data += dest_pad;
- }
-}
-
-static bool convert_ARGB_to_RGBA_inplace(QImageData *data, Qt::ImageConversionFlags)
-{
- Q_ASSERT(data->format == QImage::Format_ARGB32 || data->format == QImage::Format_ARGB32_Premultiplied);
-
- const int pad = (data->bytes_per_line >> 2) - data->width;
- quint32 *rgb_data = (quint32 *) data->data;
-
- for (int i = 0; i < data->height; ++i) {
- const quint32 *end = rgb_data + data->width;
- while (rgb_data < end) {
- *rgb_data = ARGB2RGBA(*rgb_data);
- ++rgb_data;
- }
- rgb_data += pad;
- }
- if (data->format == QImage::Format_ARGB32)
- data->format = QImage::Format_RGBA8888;
- else
- data->format = QImage::Format_RGBA8888_Premultiplied;
- return true;
-}
-
-static void convert_ARGB_to_RGBA_PM(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
-{
- Q_ASSERT(src->format == QImage::Format_ARGB32);
- Q_ASSERT(dest->format == QImage::Format_RGBA8888_Premultiplied);
- 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 quint32 *src_data = (quint32 *) src->data;
- quint32 *dest_data = (quint32 *) dest->data;
-
- for (int i = 0; i < src->height; ++i) {
- const quint32 *end = src_data + src->width;
- while (src_data < end) {
- *dest_data = ARGB2RGBA(PREMUL(*src_data));
- ++src_data;
- ++dest_data;
- }
- src_data += src_pad;
- dest_data += dest_pad;
- }
-}
-
-static void convert_RGBA_to_ARGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
-{
- Q_ASSERT(src->format == QImage::Format_RGBX8888 || src->format == QImage::Format_RGBA8888 || src->format == QImage::Format_RGBA8888_Premultiplied);
- Q_ASSERT(dest->format == QImage::Format_ARGB32 || 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 quint32 *src_data = (quint32 *) src->data;
- quint32 *dest_data = (quint32 *) dest->data;
-
- for (int i = 0; i < src->height; ++i) {
- const quint32 *end = src_data + src->width;
- while (src_data < end) {
- *dest_data = RGBA2ARGB(*src_data);
- ++src_data;
- ++dest_data;
- }
- src_data += src_pad;
- dest_data += dest_pad;
- }
-}
-
-static bool convert_RGBA_to_ARGB_inplace(QImageData *data, Qt::ImageConversionFlags)
-{
- Q_ASSERT(data->format == QImage::Format_RGBX8888 || data->format == QImage::Format_RGBA8888 || data->format == QImage::Format_RGBA8888_Premultiplied);
-
- 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 = RGBA2ARGB(*rgb_data);
- ++rgb_data;
- }
- rgb_data += pad;
- }
- if (data->format == QImage::Format_RGBA8888_Premultiplied)
- data->format = QImage::Format_ARGB32_Premultiplied;
- else if (data->format == QImage::Format_RGBX8888)
- data->format = QImage::Format_RGB32;
- else
- data->format = QImage::Format_ARGB32;
- return true;
-}
-
-static void convert_RGBA_to_ARGB_PM(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
-{
- Q_ASSERT(src->format == QImage::Format_RGBA8888);
- 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 quint32 *src_data = (quint32 *) src->data;
- quint32 *dest_data = (quint32 *) dest->data;
-
- for (int i = 0; i < src->height; ++i) {
- const quint32 *end = src_data + src->width;
- while (src_data < end) {
- *dest_data = PREMUL(RGBA2ARGB(*src_data));
- ++src_data;
- ++dest_data;
- }
- src_data += src_pad;
- dest_data += dest_pad;
- }
-}
-
-static bool convert_RGBA_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConversionFlags)
-{
- Q_ASSERT(data->format == QImage::Format_RGBA8888);
-
- 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(RGBA2ARGB(*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] = qConvertRgb32To16(qRgb(i, i, i));
- } else {
- // 1) convert the existing colors to RGB16
- const int tableSize = data->colortable.size();
- for (int i = 0; i < tableSize; ++i)
- colorTableRGB16[i] = qConvertRgb32To16(data->colortable.at(i));
- 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) {
- for (int j = 0; j < data->width; ++j)
- dst_data[j] = qConvertRgb32To16(src_data[j]);
- 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 || src->format == QImage::Format_RGBA8888_Premultiplied);
- Q_ASSERT(dest->format == QImage::Format_ARGB32 || dest->format == QImage::Format_RGBA8888);
- 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 || src->format == QImage::Format_RGBA8888_Premultiplied);
- Q_ASSERT(dest->format == QImage::Format_RGB32 || dest->format == QImage::Format_RGBX8888);
- 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 convert_ARGB_PM_to_RGBx(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
-{
- Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied);
- Q_ASSERT(dest->format == QImage::Format_RGBX8888);
- 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 = ARGB2RGBA(0xff000000 | INV_PREMUL(*src_data));
- ++src_data;
- ++dest_data;
- }
- src_data += src_pad;
- dest_data += dest_pad;
- }
-}
-
-static void convert_ARGB_PM_to_RGBA(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
-{
- Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied);
- Q_ASSERT(dest->format == QImage::Format_RGBA8888);
- 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 = ARGB2RGBA(INV_PREMUL(*src_data));
- ++src_data;
- ++dest_data;
- }
- src_data += src_pad;
- dest_data += dest_pad;
- }
-}
-
-static void convert_RGBA_to_RGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
-{
- Q_ASSERT(src->format == QImage::Format_RGBA8888 || src->format == QImage::Format_RGBX8888);
- 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 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 = RGBA2ARGB(*src_data) | 0xff000000;
- ++src_data;
- ++dest_data;
- }
- src_data += src_pad;
- dest_data += dest_pad;
- }
-}
-
-static void convert_RGB_to_RGBA(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
-{
- Q_ASSERT(src->format == QImage::Format_RGB32);
- Q_ASSERT(dest->format == QImage::Format_RGBX8888 || dest->format == QImage::Format_RGBA8888 || dest->format == QImage::Format_RGBA8888_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 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 = ARGB2RGBA(*src_data | 0xff000000);
- ++src_data;
- ++dest_data;
- }
- src_data += src_pad;
- dest_data += dest_pad;
- }
-}
-
-static void convert_RGBA_PM_to_ARGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
-{
- Q_ASSERT(src->format == QImage::Format_RGBA8888_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(RGBA2ARGB(*src_data));
- ++src_data;
- ++dest_data;
- }
- src_data += src_pad;
- dest_data += dest_pad;
- }
-}
-
-static void convert_RGBA_PM_to_RGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
-{
- Q_ASSERT(src->format == QImage::Format_RGBA8888_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(RGBA2ARGB(*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 void mask_alpha_converter_RGBx(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags flags)
-{
-#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
- return mask_alpha_converter(dest, src, flags);
-#else
- Q_UNUSED(flags);
- 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 | 0x000000ff;
- ++src_data;
- ++dest_data;
- }
- src_data += src_pad;
- dest_data += dest_pad;
- }
-#endif
-}
-
-static QVector<QRgb> fix_color_table(const QVector<QRgb> &ctbl, QImage::Format format)
-{
- QVector<QRgb> colorTable = ctbl;
- if (format == QImage::Format_RGB32) {
- // check if the color table has alpha
- for (int i = 0; i < colorTable.size(); ++i)
- if (qAlpha(colorTable.at(i) != 0xff))
- colorTable[i] = colorTable.at(i) | 0xff000000;
- } else if (format == QImage::Format_ARGB32_Premultiplied) {
- // check if the color table has alpha
- for (int i = 0; i < colorTable.size(); ++i)
- colorTable[i] = PREMUL(colorTable.at(i));
- }
- return colorTable;
-}
-
-//
-// dither_to_1: Uses selected dithering algorithm.
-//
-
-static void dither_to_Mono(QImageData *dst, const QImageData *src,
- Qt::ImageConversionFlags flags, bool fromalpha)
-{
- Q_ASSERT(src->width == dst->width);
- Q_ASSERT(src->height == dst->height);
- Q_ASSERT(dst->format == QImage::Format_Mono || dst->format == QImage::Format_MonoLSB);
-
- dst->colortable.clear();
- dst->colortable.append(0xffffffff);
- dst->colortable.append(0xff000000);
-
- enum { Threshold, Ordered, Diffuse } dithermode;
-
- if (fromalpha) {
- if ((flags & Qt::AlphaDither_Mask) == Qt::DiffuseAlphaDither)
- dithermode = Diffuse;
- else if ((flags & Qt::AlphaDither_Mask) == Qt::OrderedAlphaDither)
- dithermode = Ordered;
- else
- dithermode = Threshold;
- } else {
- if ((flags & Qt::Dither_Mask) == Qt::ThresholdDither)
- dithermode = Threshold;
- else if ((flags & Qt::Dither_Mask) == Qt::OrderedDither)
- dithermode = Ordered;
- else
- dithermode = Diffuse;
- }
-
- int w = src->width;
- int h = src->height;
- int d = src->depth;
- uchar gray[256]; // gray map for 8 bit images
- bool use_gray = (d == 8);
- if (use_gray) { // make gray map
- if (fromalpha) {
- // Alpha 0x00 -> 0 pixels (white)
- // Alpha 0xFF -> 1 pixels (black)
- for (int i = 0; i < src->colortable.size(); i++)
- gray[i] = (255 - (src->colortable.at(i) >> 24));
- } else {
- // Pixel 0x00 -> 1 pixels (black)
- // Pixel 0xFF -> 0 pixels (white)
- for (int i = 0; i < src->colortable.size(); i++)
- gray[i] = qGray(src->colortable.at(i));
- }
- }
-
- uchar *dst_data = dst->data;
- int dst_bpl = dst->bytes_per_line;
- const uchar *src_data = src->data;
- int src_bpl = src->bytes_per_line;
-
- switch (dithermode) {
- case Diffuse: {
- QScopedArrayPointer<int> lineBuffer(new int[w * 2]);
- int *line1 = lineBuffer.data();
- int *line2 = lineBuffer.data() + w;
- int bmwidth = (w+7)/8;
-
- int *b1, *b2;
- int wbytes = w * (d/8);
- const uchar *p = src->data;
- const uchar *end = p + wbytes;
- b2 = line2;
- if (use_gray) { // 8 bit image
- while (p < end)
- *b2++ = gray[*p++];
- } else { // 32 bit image
- if (fromalpha) {
- while (p < end) {
- *b2++ = 255 - (*(uint*)p >> 24);
- p += 4;
- }
- } else {
- while (p < end) {
- *b2++ = qGray(*(uint*)p);
- p += 4;
- }
- }
- }
- for (int y=0; y<h; y++) { // for each scan line...
- int *tmp = line1; line1 = line2; line2 = tmp;
- bool not_last_line = y < h - 1;
- if (not_last_line) { // calc. grayvals for next line
- p = src->data + (y+1)*src->bytes_per_line;
- end = p + wbytes;
- b2 = line2;
- if (use_gray) { // 8 bit image
- while (p < end)
- *b2++ = gray[*p++];
- } else { // 24 bit image
- if (fromalpha) {
- while (p < end) {
- *b2++ = 255 - (*(uint*)p >> 24);
- p += 4;
- }
- } else {
- while (p < end) {
- *b2++ = qGray(*(uint*)p);
- p += 4;
- }
- }
- }
- }
-
- int err;
- uchar *p = dst->data + y*dst->bytes_per_line;
- memset(p, 0, bmwidth);
- b1 = line1;
- b2 = line2;
- int bit = 7;
- for (int x=1; x<=w; x++) {
- if (*b1 < 128) { // black pixel
- err = *b1++;
- *p |= 1 << bit;
- } else { // white pixel
- err = *b1++ - 255;
- }
- if (bit == 0) {
- p++;
- bit = 7;
- } else {
- bit--;
- }
- if (x < w)
- *b1 += (err*7)>>4; // spread error to right pixel
- if (not_last_line) {
- b2[0] += (err*5)>>4; // pixel below
- if (x > 1)
- b2[-1] += (err*3)>>4; // pixel below left
- if (x < w)
- b2[1] += err>>4; // pixel below right
- }
- b2++;
- }
- }
- } break;
- case Ordered: {
-
- memset(dst->data, 0, dst->nbytes);
- if (d == 32) {
- for (int i=0; i<h; i++) {
- const uint *p = (const uint *)src_data;
- const uint *end = p + w;
- uchar *m = dst_data;
- int bit = 7;
- int j = 0;
- if (fromalpha) {
- while (p < end) {
- if ((*p++ >> 24) >= qt_bayer_matrix[j++&15][i&15])
- *m |= 1 << bit;
- if (bit == 0) {
- m++;
- bit = 7;
- } else {
- bit--;
- }
- }
- } else {
- while (p < end) {
- if ((uint)qGray(*p++) < qt_bayer_matrix[j++&15][i&15])
- *m |= 1 << bit;
- if (bit == 0) {
- m++;
- bit = 7;
- } else {
- bit--;
- }
- }
- }
- dst_data += dst_bpl;
- src_data += src_bpl;
- }
- } else
- /* (d == 8) */ {
- for (int i=0; i<h; i++) {
- const uchar *p = src_data;
- const uchar *end = p + w;
- uchar *m = dst_data;
- int bit = 7;
- int j = 0;
- while (p < end) {
- if ((uint)gray[*p++] < qt_bayer_matrix[j++&15][i&15])
- *m |= 1 << bit;
- if (bit == 0) {
- m++;
- bit = 7;
- } else {
- bit--;
- }
- }
- dst_data += dst_bpl;
- src_data += src_bpl;
- }
- }
- } break;
- default: { // Threshold:
- memset(dst->data, 0, dst->nbytes);
- if (d == 32) {
- for (int i=0; i<h; i++) {
- const uint *p = (const uint *)src_data;
- const uint *end = p + w;
- uchar *m = dst_data;
- int bit = 7;
- if (fromalpha) {
- while (p < end) {
- if ((*p++ >> 24) >= 128)
- *m |= 1 << bit; // Set mask "on"
- if (bit == 0) {
- m++;
- bit = 7;
- } else {
- bit--;
- }
- }
- } else {
- while (p < end) {
- if (qGray(*p++) < 128)
- *m |= 1 << bit; // Set pixel "black"
- if (bit == 0) {
- m++;
- bit = 7;
- } else {
- bit--;
- }
- }
- }
- dst_data += dst_bpl;
- src_data += src_bpl;
- }
- } else
- if (d == 8) {
- for (int i=0; i<h; i++) {
- const uchar *p = src_data;
- const uchar *end = p + w;
- uchar *m = dst_data;
- int bit = 7;
- while (p < end) {
- if (gray[*p++] < 128)
- *m |= 1 << bit; // Set mask "on"/ pixel "black"
- if (bit == 0) {
- m++;
- bit = 7;
- } else {
- bit--;
- }
- }
- dst_data += dst_bpl;
- src_data += src_bpl;
- }
- }
- }
- }
-
- if (dst->format == QImage::Format_MonoLSB) {
- // need to swap bit order
- uchar *sl = dst->data;
- int bpl = (dst->width + 7) * dst->depth / 8;
- int pad = dst->bytes_per_line - bpl;
- for (int y=0; y<dst->height; ++y) {
- for (int x=0; x<bpl; ++x) {
- *sl = bitflip[*sl];
- ++sl;
- }
- sl += pad;
- }
- }
-}
-
-static void convert_X_to_Mono(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags)
-{
- dither_to_Mono(dst, src, flags, false);
-}
-
-static void convert_ARGB_PM_to_Mono(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags)
-{
- QScopedPointer<QImageData> tmp(QImageData::create(QSize(src->width, src->height), QImage::Format_ARGB32));
- convert_ARGB_PM_to_ARGB(tmp.data(), src, flags);
- dither_to_Mono(dst, tmp.data(), flags, false);
-}
-
-//
-// convert_32_to_8: Converts a 32 bits depth (true color) to an 8 bit
-// image with a colormap. If the 32 bit image has more than 256 colors,
-// we convert the red,green and blue bytes into a single byte encoded
-// as 6 shades of each of red, green and blue.
-//
-// if dithering is needed, only 1 color at most is available for alpha.
-//
-struct QRgbMap {
- inline QRgbMap() : used(0) { }
- uchar pix;
- uchar used;
- QRgb rgb;
-};
-
-static void convert_RGB_to_Indexed8(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags)
-{
- Q_ASSERT(src->format == QImage::Format_RGB32 || src->format == QImage::Format_ARGB32);
- Q_ASSERT(dst->format == QImage::Format_Indexed8);
- Q_ASSERT(src->width == dst->width);
- Q_ASSERT(src->height == dst->height);
-
- bool do_quant = (flags & Qt::DitherMode_Mask) == Qt::PreferDither
- || src->format == QImage::Format_ARGB32;
- uint alpha_mask = src->format == QImage::Format_RGB32 ? 0xff000000 : 0;
-
- const int tablesize = 997; // prime
- QRgbMap table[tablesize];
- int pix=0;
-
- if (!dst->colortable.isEmpty()) {
- QVector<QRgb> ctbl = dst->colortable;
- dst->colortable.resize(256);
- // Preload palette into table.
- // Almost same code as pixel insertion below
- for (int i = 0; i < dst->colortable.size(); ++i) {
- // Find in table...
- QRgb p = ctbl.at(i) | alpha_mask;
- int hash = p % tablesize;
- for (;;) {
- if (table[hash].used) {
- if (table[hash].rgb == p) {
- // Found previous insertion - use it
- break;
- } else {
- // Keep searching...
- if (++hash == tablesize) hash = 0;
- }
- } else {
- // Cannot be in table
- Q_ASSERT (pix != 256); // too many colors
- // Insert into table at this unused position
- dst->colortable[pix] = p;
- table[hash].pix = pix++;
- table[hash].rgb = p;
- table[hash].used = 1;
- break;
- }
- }
- }
- }
-
- if ((flags & Qt::DitherMode_Mask) != Qt::PreferDither) {
- dst->colortable.resize(256);
- const uchar *src_data = src->data;
- uchar *dest_data = dst->data;
- for (int y = 0; y < src->height; y++) { // check if <= 256 colors
- const QRgb *s = (const QRgb *)src_data;
- uchar *b = dest_data;
- for (int x = 0; x < src->width; ++x) {
- QRgb p = s[x] | alpha_mask;
- int hash = p % tablesize;
- for (;;) {
- if (table[hash].used) {
- if (table[hash].rgb == (p)) {
- // Found previous insertion - use it
- break;
- } else {
- // Keep searching...
- if (++hash == tablesize) hash = 0;
- }
- } else {
- // Cannot be in table
- if (pix == 256) { // too many colors
- do_quant = true;
- // Break right out
- x = src->width;
- y = src->height;
- } else {
- // Insert into table at this unused position
- dst->colortable[pix] = p;
- table[hash].pix = pix++;
- table[hash].rgb = p;
- table[hash].used = 1;
- }
- break;
- }
- }
- *b++ = table[hash].pix; // May occur once incorrectly
- }
- src_data += src->bytes_per_line;
- dest_data += dst->bytes_per_line;
- }
- }
- int numColors = do_quant ? 256 : pix;
-
- dst->colortable.resize(numColors);
-
- if (do_quant) { // quantization needed
-
-#define MAX_R 5
-#define MAX_G 5
-#define MAX_B 5
-#define INDEXOF(r,g,b) (((r)*(MAX_G+1)+(g))*(MAX_B+1)+(b))
-
- for (int rc=0; rc<=MAX_R; rc++) // build 6x6x6 color cube
- for (int gc=0; gc<=MAX_G; gc++)
- for (int bc=0; bc<=MAX_B; bc++)
- dst->colortable[INDEXOF(rc,gc,bc)] = 0xff000000 | qRgb(rc*255/MAX_R, gc*255/MAX_G, bc*255/MAX_B);
-
- const uchar *src_data = src->data;
- uchar *dest_data = dst->data;
- if ((flags & Qt::Dither_Mask) == Qt::ThresholdDither) {
- for (int y = 0; y < src->height; y++) {
- const QRgb *p = (const QRgb *)src_data;
- const QRgb *end = p + src->width;
- uchar *b = dest_data;
-
- while (p < end) {
-#define DITHER(p,m) ((uchar) ((p * (m) + 127) / 255))
- *b++ =
- INDEXOF(
- DITHER(qRed(*p), MAX_R),
- DITHER(qGreen(*p), MAX_G),
- DITHER(qBlue(*p), MAX_B)
- );
-#undef DITHER
- p++;
- }
- src_data += src->bytes_per_line;
- dest_data += dst->bytes_per_line;
- }
- } else if ((flags & Qt::Dither_Mask) == Qt::DiffuseDither) {
- int* line1[3];
- int* line2[3];
- int* pv[3];
- QScopedArrayPointer<int> lineBuffer(new int[src->width * 9]);
- line1[0] = lineBuffer.data();
- line2[0] = lineBuffer.data() + src->width;
- line1[1] = lineBuffer.data() + src->width * 2;
- line2[1] = lineBuffer.data() + src->width * 3;
- line1[2] = lineBuffer.data() + src->width * 4;
- line2[2] = lineBuffer.data() + src->width * 5;
- pv[0] = lineBuffer.data() + src->width * 6;
- pv[1] = lineBuffer.data() + src->width * 7;
- pv[2] = lineBuffer.data() + src->width * 8;
-
- int endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian);
- for (int y = 0; y < src->height; y++) {
- const uchar* q = src_data;
- const uchar* q2 = y < src->height - 1 ? q + src->bytes_per_line : src->data;
- uchar *b = dest_data;
- for (int chan = 0; chan < 3; chan++) {
- int *l1 = (y&1) ? line2[chan] : line1[chan];
- int *l2 = (y&1) ? line1[chan] : line2[chan];
- if (y == 0) {
- for (int i = 0; i < src->width; i++)
- l1[i] = q[i*4+chan+endian];
- }
- if (y+1 < src->height) {
- for (int i = 0; i < src->width; i++)
- l2[i] = q2[i*4+chan+endian];
- }
- // Bi-directional error diffusion
- if (y&1) {
- for (int x = 0; x < src->width; x++) {
- int pix = qMax(qMin(5, (l1[x] * 5 + 128)/ 255), 0);
- int err = l1[x] - pix * 255 / 5;
- pv[chan][x] = pix;
-
- // Spread the error around...
- if (x + 1< src->width) {
- l1[x+1] += (err*7)>>4;
- l2[x+1] += err>>4;
- }
- l2[x]+=(err*5)>>4;
- if (x>1)
- l2[x-1]+=(err*3)>>4;
- }
- } else {
- for (int x = src->width; x-- > 0;) {
- int pix = qMax(qMin(5, (l1[x] * 5 + 128)/ 255), 0);
- int err = l1[x] - pix * 255 / 5;
- pv[chan][x] = pix;
-
- // Spread the error around...
- if (x > 0) {
- l1[x-1] += (err*7)>>4;
- l2[x-1] += err>>4;
- }
- l2[x]+=(err*5)>>4;
- if (x + 1 < src->width)
- l2[x+1]+=(err*3)>>4;
- }
- }
- }
- if (endian) {
- for (int x = 0; x < src->width; x++) {
- *b++ = INDEXOF(pv[0][x],pv[1][x],pv[2][x]);
- }
- } else {
- for (int x = 0; x < src->width; x++) {
- *b++ = INDEXOF(pv[2][x],pv[1][x],pv[0][x]);
- }
- }
- src_data += src->bytes_per_line;
- dest_data += dst->bytes_per_line;
- }
- } else { // OrderedDither
- for (int y = 0; y < src->height; y++) {
- const QRgb *p = (const QRgb *)src_data;
- const QRgb *end = p + src->width;
- uchar *b = dest_data;
-
- int x = 0;
- while (p < end) {
- uint d = qt_bayer_matrix[y & 15][x & 15] << 8;
-
-#define DITHER(p, d, m) ((uchar) ((((256 * (m) + (m) + 1)) * (p) + (d)) >> 16))
- *b++ =
- INDEXOF(
- DITHER(qRed(*p), d, MAX_R),
- DITHER(qGreen(*p), d, MAX_G),
- DITHER(qBlue(*p), d, MAX_B)
- );
-#undef DITHER
-
- p++;
- x++;
- }
- src_data += src->bytes_per_line;
- dest_data += dst->bytes_per_line;
- }
- }
-
- if (src->format != QImage::Format_RGB32
- && src->format != QImage::Format_RGB16) {
- const int trans = 216;
- Q_ASSERT(dst->colortable.size() > trans);
- dst->colortable[trans] = 0;
- QScopedPointer<QImageData> mask(QImageData::create(QSize(src->width, src->height), QImage::Format_Mono));
- dither_to_Mono(mask.data(), src, flags, true);
- uchar *dst_data = dst->data;
- const uchar *mask_data = mask->data;
- for (int y = 0; y < src->height; y++) {
- for (int x = 0; x < src->width ; x++) {
- if (!(mask_data[x>>3] & (0x80 >> (x & 7))))
- dst_data[x] = trans;
- }
- mask_data += mask->bytes_per_line;
- dst_data += dst->bytes_per_line;
- }
- dst->has_alpha_clut = true;
- }
-
-#undef MAX_R
-#undef MAX_G
-#undef MAX_B
-#undef INDEXOF
-
- }
-}
-
-static void convert_ARGB_PM_to_Indexed8(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags)
-{
- QScopedPointer<QImageData> tmp(QImageData::create(QSize(src->width, src->height), QImage::Format_ARGB32));
- convert_ARGB_PM_to_ARGB(tmp.data(), src, flags);
- convert_RGB_to_Indexed8(dst, tmp.data(), flags);
-}
-
-static void convert_ARGB_to_Indexed8(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags)
-{
- convert_RGB_to_Indexed8(dst, src, flags);
-}
-
-static void convert_Indexed8_to_X32(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
-{
- Q_ASSERT(src->format == QImage::Format_Indexed8);
- Q_ASSERT(dest->format == QImage::Format_RGB32
- || dest->format == QImage::Format_ARGB32
- || dest->format == QImage::Format_ARGB32_Premultiplied);
- Q_ASSERT(src->width == dest->width);
- Q_ASSERT(src->height == dest->height);
-
- QVector<QRgb> colorTable = fix_color_table(src->colortable, dest->format);
- if (colorTable.size() == 0) {
- colorTable.resize(256);
- for (int i=0; i<256; ++i)
- colorTable[i] = qRgb(i, i, i);
- }
-
- int w = src->width;
- const uchar *src_data = src->data;
- uchar *dest_data = dest->data;
- int tableSize = colorTable.size() - 1;
- for (int y = 0; y < src->height; y++) {
- uint *p = (uint *)dest_data;
- const uchar *b = src_data;
- uint *end = p + w;
-
- while (p < end)
- *p++ = colorTable.at(qMin<int>(tableSize, *b++));
-
- src_data += src->bytes_per_line;
- dest_data += dest->bytes_per_line;
- }
-}
-
-static void convert_Mono_to_X32(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
-{
- Q_ASSERT(src->format == QImage::Format_Mono || src->format == QImage::Format_MonoLSB);
- Q_ASSERT(dest->format == QImage::Format_RGB32
- || dest->format == QImage::Format_ARGB32
- || dest->format == QImage::Format_ARGB32_Premultiplied);
- Q_ASSERT(src->width == dest->width);
- Q_ASSERT(src->height == dest->height);
-
- QVector<QRgb> colorTable = fix_color_table(src->colortable, dest->format);
-
- // Default to black / white colors
- if (colorTable.size() < 2) {
- if (colorTable.size() == 0)
- colorTable << 0xff000000;
- colorTable << 0xffffffff;
- }
-
- const uchar *src_data = src->data;
- uchar *dest_data = dest->data;
- if (src->format == QImage::Format_Mono) {
- for (int y = 0; y < dest->height; y++) {
- 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++) {
- 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++) {
- 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++) {
- 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;
- }
- }
-}
-
-// Cannot be used with indexed formats.
-static void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
-{
- const int buffer_size = 2048;
- uint buffer[buffer_size];
- const QPixelLayout *srcLayout = &qPixelLayouts[src->format];
- const QPixelLayout *destLayout = &qPixelLayouts[dest->format];
- const uchar *srcData = src->data;
- uchar *destData = dest->data;
-
- FetchPixelsFunc fetch = qFetchPixels[srcLayout->bpp];
- StorePixelsFunc store = qStorePixels[destLayout->bpp];
-
- for (int y = 0; y < src->height; ++y) {
- int x = 0;
- while (x < src->width) {
- int l = qMin(src->width - x, buffer_size);
- const uint *ptr = fetch(buffer, srcData, x, l);
- ptr = srcLayout->convertToARGB32PM(buffer, ptr, l, srcLayout, 0);
- ptr = destLayout->convertFromARGB32PM(buffer, ptr, l, destLayout, 0);
- store(destData, ptr, x, l);
- x += l;
- }
- srcData += src->bytes_per_line;
- destData += dest->bytes_per_line;
- }
-}
-
-
-// first index source, second dest
-static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormats] =
-{
- {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- },
- {
- 0,
- 0,
- swap_bit_order,
- convert_Mono_to_Indexed8,
- convert_Mono_to_X32,
- convert_Mono_to_X32,
- convert_Mono_to_X32,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
- }, // Format_Mono
-
- {
- 0,
- swap_bit_order,
- 0,
- convert_Mono_to_Indexed8,
- convert_Mono_to_X32,
- convert_Mono_to_X32,
- convert_Mono_to_X32,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
- }, // Format_MonoLSB
-
- {
- 0,
- convert_X_to_Mono,
- convert_X_to_Mono,
- 0,
- convert_Indexed8_to_X32,
- convert_Indexed8_to_X32,
- convert_Indexed8_to_X32,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
- }, // Format_Indexed8
-
- {
- 0,
- convert_X_to_Mono,
- convert_X_to_Mono,
- convert_RGB_to_Indexed8,
- 0,
- mask_alpha_converter,
- mask_alpha_converter,
- convert_generic,
- convert_generic,
- convert_generic,
- convert_generic,
- convert_generic,
- convert_generic,
- convert_generic,
- convert_generic,
- convert_generic,
- convert_RGB_to_RGBA,
- convert_RGB_to_RGBA,
- convert_RGB_to_RGBA
- }, // Format_RGB32
-
- {
- 0,
- convert_X_to_Mono,
- convert_X_to_Mono,
- convert_ARGB_to_Indexed8,
- mask_alpha_converter,
- 0,
- convert_ARGB_to_ARGB_PM,
- convert_generic,
- convert_generic,
- convert_generic,
- convert_generic,
- convert_generic,
- convert_generic,
- convert_generic,
- convert_generic,
- convert_generic,
- convert_ARGB_to_RGBx,
- convert_ARGB_to_RGBA,
- convert_ARGB_to_RGBA_PM,
- }, // Format_ARGB32
-
- {
- 0,
- convert_ARGB_PM_to_Mono,
- convert_ARGB_PM_to_Mono,
- convert_ARGB_PM_to_Indexed8,
- convert_ARGB_PM_to_RGB,
- convert_ARGB_PM_to_ARGB,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- convert_ARGB_PM_to_RGBx,
- convert_ARGB_PM_to_RGBA,
- convert_ARGB_to_RGBA,
- }, // Format_ARGB32_Premultiplied
-
- {
- 0,
- 0,
- 0,
- 0,
- convert_generic,
- convert_generic,
- convert_generic,
- 0,
- 0,
- 0,
- 0,
-#if defined(QT_QWS_DEPTH_15) && defined(QT_QWS_DEPTH_16)
- convert_generic,
-#else
- 0,
-#endif
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
- }, // Format_RGB16
-
- {
- 0,
- 0,
- 0,
- 0,
- convert_generic,
- convert_generic,
- convert_generic,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
- }, // Format_ARGB8565_Premultiplied
-
- {
- 0,
- 0,
- 0,
- 0,
- convert_generic,
- convert_generic,
- convert_generic,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
- }, // Format_RGB666
-
- {
- 0,
- 0,
- 0,
- 0,
- convert_generic,
- convert_generic,
- convert_generic,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
- }, // Format_ARGB6666_Premultiplied
-
- {
- 0,
- 0,
- 0,
- 0,
- convert_generic,
- convert_generic,
- convert_generic,
-#if defined(QT_QWS_DEPTH_15) && defined(QT_QWS_DEPTH_16)
- convert_generic,
-#else
- 0,
-#endif
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
- }, // Format_RGB555
-
- {
- 0,
- 0,
- 0,
- 0,
- convert_generic,
- convert_generic,
- convert_generic,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
- }, // Format_ARGB8555_Premultiplied
-
- {
- 0,
- 0,
- 0,
- 0,
- convert_generic,
- convert_generic,
- convert_generic,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
- }, // Format_RGB888
-
- {
- 0,
- 0,
- 0,
- 0,
- convert_generic,
- convert_generic,
- convert_generic,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
- }, // Format_RGB444
-
- {
- 0,
- 0,
- 0,
- 0,
- convert_generic,
- convert_generic,
- convert_generic,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
- }, // Format_ARGB4444_Premultiplied
- {
- 0,
- 0,
- 0,
- 0,
- convert_RGBA_to_RGB,
- convert_RGBA_to_ARGB,
- convert_RGBA_to_ARGB_PM,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- mask_alpha_converter_RGBx,
- mask_alpha_converter_RGBx,
- }, // Format_RGBX8888
- {
- 0,
- 0,
- 0,
- 0,
- convert_RGBA_to_RGB,
- convert_RGBA_to_ARGB,
- convert_RGBA_to_ARGB_PM,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- mask_alpha_converter_RGBx,
-#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
- 0,
- convert_ARGB_to_ARGB_PM,
-#else
- 0,
- 0
-#endif
- }, // Format_RGBA8888
-
- {
- 0,
- 0,
- 0,
- 0,
- convert_RGBA_PM_to_RGB,
- convert_RGBA_PM_to_ARGB,
- convert_RGBA_to_ARGB,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
-#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
- convert_ARGB_PM_to_RGB,
- convert_ARGB_PM_to_ARGB,
- 0,
-#else
- 0,
- 0,
- 0
-#endif
- } // Format_RGBA8888_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, 0, 0, 0, 0, 0, 0
- }, // Format_Mono
- {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- }, // 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,
- 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,
- 0,
- 0,
- 0,
- }, // Format_RGB32
- {
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- convert_ARGB_to_ARGB_PM_inplace,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- convert_ARGB_to_RGBA_inplace,
- 0,
- }, // Format_ARGB32
- {
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- convert_ARGB_to_RGBA_inplace
- }, // Format_ARGB32_Premultiplied
- {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- }, // Format_RGB16
- {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- }, // Format_ARGB8565_Premultiplied
- {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- }, // Format_RGB666
- {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- }, // Format_ARGB6666_Premultiplied
- {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- }, // Format_RGB555
- {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- }, // Format_ARGB8555_Premultiplied
- {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- }, // Format_RGB888
- {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- }, // Format_RGB444
- {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- }, // Format_ARGB4444_Premultiplied
- {
- 0,
- 0,
- 0,
- 0,
- 0,
- convert_RGBA_to_ARGB_inplace,
- convert_RGBA_to_ARGB_inplace,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- }, // Format_RGBX8888
- {
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- convert_RGBA_to_ARGB_inplace,
- convert_RGBA_to_ARGB_PM_inplace,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- }, // Format_RGBA8888
- {
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- convert_RGBA_to_ARGB_inplace,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- } // Format_RGBA8888_Premultiplied
-};
-
-void qInitImageConversions()
-{
-#ifdef QT_COMPILER_SUPPORTS_AVX
- if (qCpuHasFeature(AVX)) {
- extern bool convert_ARGB_to_ARGB_PM_inplace_avx(QImageData *data, Qt::ImageConversionFlags);
- inplace_converter_map[QImage::Format_ARGB32][QImage::Format_ARGB32_Premultiplied] = convert_ARGB_to_ARGB_PM_inplace_avx;
-
- extern void convert_RGB888_to_RGB32_avx(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
- converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB32_avx;
- converter_map[QImage::Format_RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB32_avx;
- converter_map[QImage::Format_RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB32_avx;
- return;
- }
-#endif
-
-#if defined(QT_COMPILER_SUPPORTS_SSE2) && !defined(__AVX__)
- if (qCpuHasFeature(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;
-#ifdef QT_COMPILER_SUPPORTS_SSSE3
- if (qCpuHasFeature(SSSE3)) {
- extern void convert_RGB888_to_RGB32_ssse3(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
- converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB32_ssse3;
- converter_map[QImage::Format_RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB32_ssse3;
- converter_map[QImage::Format_RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB32_ssse3;
- }
-#endif
- return;
- }
-#endif // SSE2
-
-#ifdef QT_COMPILER_SUPPORTS_NEON
- if (qCpuHasFeature(NEON)) {
- extern void convert_RGB888_to_RGB32_neon(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
- converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB32_neon;
- converter_map[QImage::Format_RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB32_neon;
- converter_map[QImage::Format_RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB32_neon;
- return;
- }
-#endif
-}
-
-extern const uchar *qt_pow_rgb_gamma();
-
-void qGamma_correct_back_to_linear_cs(QImage *image)
-{
- const QDrawHelperGammaTables *tables = QGuiApplicationPrivate::instance()->gammaTables();
- if (!tables)
- return;
- const uchar *gamma = tables->qt_pow_rgb_gamma;
- // gamma correct the pixels back to linear color space...
- int h = image->height();
- int w = image->width();
-
- for (int y=0; y<h; ++y) {
- uint *pixels = (uint *) image->scanLine(y);
- for (int x=0; x<w; ++x) {
- uint p = pixels[x];
- uint r = gamma[qRed(p)];
- uint g = gamma[qGreen(p)];
- uint b = gamma[qBlue(p)];
- pixels[x] = (r << 16) | (g << 8) | b | 0xff000000;
- }
- }
-}
-
/*!
Returns a copy of the image in the given \a format.
@@ -4002,8 +1877,9 @@ QImage QImage::convertToFormat(Format format, Qt::ImageConversionFlags flags) co
if (format == Format_Invalid || d->format == Format_Invalid)
return QImage();
- const Image_Converter *converterPtr = &converter_map[d->format][format];
- Image_Converter converter = *converterPtr;
+ Image_Converter converter = qimage_converter_map[d->format][format];
+ if (!converter && format > QImage::Format_Indexed8 && d->format > QImage::Format_Indexed8)
+ converter = convert_generic;
if (converter) {
QImage image(d->width, d->height, format);
@@ -4019,15 +1895,13 @@ QImage QImage::convertToFormat(Format format, Qt::ImageConversionFlags flags) co
return image;
}
+ // Convert indexed formats over ARGB32 to the final format.
Q_ASSERT(format != QImage::Format_ARGB32);
Q_ASSERT(d->format != QImage::Format_ARGB32);
- QImage image = convertToFormat(Format_ARGB32, flags);
- return image.convertToFormat(format, flags);
+ return convertToFormat(Format_ARGB32, flags).convertToFormat(format, flags);
}
-
-
static inline int pixel_distance(QRgb p1, QRgb p2) {
int r1 = qRed(p1);
int g1 = qGreen(p1);
@@ -4125,7 +1999,7 @@ QImage QImage::convertToFormat(Format format, const QVector<QRgb> &colorTable, Q
return convertWithPalette(*this, format, colorTable);
}
- const Image_Converter *converterPtr = &converter_map[d->format][format];
+ const Image_Converter *converterPtr = &qimage_converter_map[d->format][format];
Image_Converter converter = *converterPtr;
if (!converter)
return QImage();
@@ -4804,6 +2678,7 @@ QImage QImage::createMaskFromColor(QRgb color, Qt::MaskMode mode) const
*/
/*!
+ \fn QImage QImage::mirrored(bool horizontal = false, bool vertical = true) const
Returns a mirror of the image, mirrored in the horizontal and/or
the vertical direction depending on whether \a horizontal and \a
vertical are set to true or false.
@@ -4812,7 +2687,69 @@ QImage QImage::createMaskFromColor(QRgb color, Qt::MaskMode mode) const
\sa {QImage#Image Transformations}{Image Transformations}
*/
-QImage QImage::mirrored(bool horizontal, bool vertical) const
+
+template<typename T>
+inline void mirrored_helper_loop(int w, int h, int dxi, int dxs, int dyi, int dy, const uchar* sdata, uchar* ddata, int sbpl, int dbpl)
+{
+ for (int sy = 0; sy < h; sy++, dy += dyi) {
+ const T* ssl = (T*)(sdata + sy*sbpl);
+ T* dsl = (T*)(ddata + dy*dbpl);
+ int dx = dxs;
+ for (int sx = 0; sx < w; sx++, dx += dxi)
+ dsl[dx] = ssl[sx];
+ }
+}
+
+template<typename T>
+inline void mirrored_helper_loop_inplace(int w, int h, int dxi, int dxs, int dyi, int dy, uchar* sdata, int sbpl)
+{
+ for (int sy = 0; sy < h; sy++, dy += dyi) {
+ T* ssl = (T*)(sdata + sy*sbpl);
+ T* dsl = (T*)(sdata + dy*sbpl);
+ int dx = dxs;
+ for (int sx = 0; sx < w; sx++, dx += dxi)
+ std::swap(dsl[dx], ssl[sx]);
+ }
+}
+
+inline void mirror_horizonal_bitmap(int w, int h, int dxs, uchar* data, int bpl, bool monolsb)
+{
+ int shift = w % 8;
+ for (int y = h-1; y >= 0; y--) {
+ quint8* a0 = (quint8*)(data + y*bpl);
+ // Swap bytes
+ quint8* a = a0+dxs;
+ while (a >= a0) {
+ *a = qt_get_bitflip_array()[*a];
+ a--;
+ }
+ // Shift bits if unaligned
+ if (shift != 0) {
+ a = a0+dxs;
+ quint8 c = 0;
+ if (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;
+ }
+ }
+ }
+ }
+}
+
+/*!
+ \internal
+*/
+QImage QImage::mirrored_helper(bool horizontal, bool vertical) const
{
if (!d)
return QImage();
@@ -4834,92 +2771,80 @@ QImage QImage::mirrored(bool horizontal, bool vertical) const
result.d->has_alpha_clut = d->has_alpha_clut;
result.d->devicePixelRatio = d->devicePixelRatio;
- if (depth() == 1)
+ if (d->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;
+ int dys = vertical ? h-1 : 0;
// 1 bit, 8 bit
- if (d->depth == 1 || d->depth == 8) {
- for (int sy = 0; sy < h; sy++, dy += dyi) {
- quint8* ssl = (quint8*)(d->data + sy*d->bytes_per_line);
- quint8* dsl = (quint8*)(result.d->data + dy*result.d->bytes_per_line);
- int dx = dxs;
- for (int sx = 0; sx < w; sx++, dx += dxi)
- dsl[dx] = ssl[sx];
- }
- }
+ if (d->depth == 1 || d->depth == 8)
+ mirrored_helper_loop<quint8>(w, h, dxi, dxs, dyi, dys, d->data, result.d->data, d->bytes_per_line, result.d->bytes_per_line);
// 16 bit
- else if (d->depth == 16) {
- for (int sy = 0; sy < h; sy++, dy += dyi) {
- quint16* ssl = (quint16*)(d->data + sy*d->bytes_per_line);
- quint16* dsl = (quint16*)(result.d->data + dy*result.d->bytes_per_line);
- int dx = dxs;
- for (int sx = 0; sx < w; sx++, dx += dxi)
- dsl[dx] = ssl[sx];
- }
- }
+ else if (d->depth == 16)
+ mirrored_helper_loop<quint16>(w, h, dxi, dxs, dyi, dys, d->data, result.d->data, d->bytes_per_line, result.d->bytes_per_line);
// 24 bit
- else if (d->depth == 24) {
- for (int sy = 0; sy < h; sy++, dy += dyi) {
- quint24* ssl = (quint24*)(d->data + sy*d->bytes_per_line);
- quint24* dsl = (quint24*)(result.d->data + dy*result.d->bytes_per_line);
- int dx = dxs;
- for (int sx = 0; sx < w; sx++, dx += dxi)
- dsl[dx] = ssl[sx];
- }
- }
+ else if (d->depth == 24)
+ mirrored_helper_loop<quint24>(w, h, dxi, dxs, dyi, dys, d->data, result.d->data, d->bytes_per_line, result.d->bytes_per_line);
// 32 bit
- else if (d->depth == 32) {
- for (int sy = 0; sy < h; sy++, dy += dyi) {
- quint32* ssl = (quint32*)(d->data + sy*d->bytes_per_line);
- quint32* dsl = (quint32*)(result.d->data + dy*result.d->bytes_per_line);
- int dx = dxs;
- for (int sx = 0; sx < w; sx++, dx += dxi)
- dsl[dx] = ssl[sx];
- }
- }
+ else if (d->depth == 32)
+ mirrored_helper_loop<quint32>(w, h, dxi, dxs, dyi, dys, d->data, result.d->data, d->bytes_per_line, result.d->bytes_per_line);
// special handling of 1 bit images for horizontal mirroring
- if (horizontal && d->depth == 1) {
- int shift = width() % 8;
- for (int y = h-1; y >= 0; y--) {
- quint8* a0 = (quint8*)(result.d->data + y*d->bytes_per_line);
- // Swap bytes
- quint8* a = a0+dxs;
- while (a >= a0) {
- *a = bitflip[*a];
- a--;
- }
- // Shift bits if unaligned
- if (shift != 0) {
- a = a0+dxs;
- quint8 c = 0;
- if (format() == Format_MonoLSB) {
- while (a >= a0) {
- quint8 nc = *a << shift;
- *a = (*a >> (8-shift)) | c;
- --a;
- c = nc;
- }
- } else {
- while (a >= a0) {
- quint8 nc = *a >> shift;
- *a = (*a << (8-shift)) | c;
- --a;
- c = nc;
- }
- }
- }
- }
- }
-
+ if (horizontal && d->depth == 1)
+ mirror_horizonal_bitmap(d->width, d->height, dxs, result.d->data, result.d->bytes_per_line, d->format == Format_MonoLSB);
return result;
}
/*!
+ \internal
+*/
+void QImage::mirrored_inplace(bool horizontal, bool vertical)
+{
+ if (!d)
+ return;
+
+ if ((d->width <= 1 && d->height <= 1) || (!horizontal && !vertical))
+ return;
+
+ detach();
+
+ int w = d->width;
+ int h = d->height;
+
+ if (d->depth == 1)
+ w = (w+7)/8;
+ int dxi = horizontal ? -1 : 1;
+ int dxs = horizontal ? w-1 : 0;
+ int dyi = vertical ? -1 : 1;
+ int dys = vertical ? h-1 : 0;
+
+ if (vertical)
+ h = h/2;
+ else if (horizontal)
+ w = w/2;
+
+ // 1 bit, 8 bit
+ if (d->depth == 1 || d->depth == 8)
+ mirrored_helper_loop_inplace<quint8>(w, h, dxi, dxs, dyi, dys, d->data, d->bytes_per_line);
+ // 16 bit
+ else if (d->depth == 16)
+ mirrored_helper_loop_inplace<quint16>(w, h, dxi, dxs, dyi, dys, d->data, d->bytes_per_line);
+ // 24 bit
+ else if (d->depth == 24)
+ mirrored_helper_loop_inplace<quint24>(w, h, dxi, dxs, dyi, dys, d->data, d->bytes_per_line);
+ // 32 bit
+ else if (d->depth == 32)
+ mirrored_helper_loop_inplace<quint32>(w, h, dxi, dxs, dyi, dys, d->data, d->bytes_per_line);
+
+ // special handling of 1 bit images for horizontal mirroring
+ if (horizontal && d->depth == 1)
+ mirror_horizonal_bitmap(d->width, d->height, dxs, d->data, d->bytes_per_line, d->format == Format_MonoLSB);
+}
+
+/*!
+ \fn QImage QImage::rgbSwapped() const
Returns a QImage in which the values of the red and blue
components of all pixels have been swapped, effectively converting
an RGB image to an BGR image.
@@ -4928,16 +2853,54 @@ QImage QImage::mirrored(bool horizontal, bool vertical) const
\sa {QImage#Image Transformations}{Image Transformations}
*/
-QImage QImage::rgbSwapped() const
+
+inline void rgbSwapped_generic(int width, int height, const QImage *src, QImage *dst, const QPixelLayout* layout)
+{
+ Q_ASSERT(layout->redWidth == layout->blueWidth);
+ FetchPixelsFunc fetch = qFetchPixels[layout->bpp];
+ StorePixelsFunc store = qStorePixels[layout->bpp];
+
+ const uint redBlueMask = (1 << layout->redWidth) - 1;
+ const uint alphaGreenMask = (((1 << layout->alphaWidth) - 1) << layout->alphaShift)
+ | (((1 << layout->greenWidth) - 1) << layout->greenShift);
+
+ const int buffer_size = 2048;
+ uint buffer[buffer_size];
+ for (int i = 0; i < height; ++i) {
+ uchar *q = dst->scanLine(i);
+ const uchar *p = src->constScanLine(i);
+ int x = 0;
+ while (x < width) {
+ int l = qMin(width - x, buffer_size);
+ const uint *ptr = fetch(buffer, p, x, l);
+ for (int j = 0; j < l; ++j) {
+ uint red = (ptr[j] >> layout->redShift) & redBlueMask;
+ uint blue = (ptr[j] >> layout->blueShift) & redBlueMask;
+ buffer[j] = (ptr[j] & alphaGreenMask)
+ | (red << layout->blueShift)
+ | (blue << layout->redShift);
+ }
+ store(q, buffer, x, l);
+ x += l;
+ }
+ }
+}
+
+/*!
+ \internal
+*/
+QImage QImage::rgbSwapped_helper() const
{
if (isNull())
return *this;
+
QImage res;
+
switch (d->format) {
case Format_Invalid:
case NImageFormats:
Q_ASSERT(false);
- return res;
+ break;
case Format_Mono:
case Format_MonoLSB:
case Format_Indexed8:
@@ -4946,7 +2909,7 @@ QImage QImage::rgbSwapped() const
QRgb c = res.d->colortable.at(i);
res.d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00));
}
- return res;
+ break;
case Format_RGB32:
case Format_ARGB32:
case Format_ARGB32_Premultiplied:
@@ -4959,15 +2922,16 @@ QImage QImage::rgbSwapped() const
QIMAGE_SANITYCHECK_MEMORY(res);
for (int i = 0; i < d->height; i++) {
uint *q = (uint*)res.scanLine(i);
- uint *p = (uint*)constScanLine(i);
- uint *end = p + d->width;
+ const uint *p = (const uint*)constScanLine(i);
+ const uint *end = p + d->width;
while (p < end) {
- *q = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00);
+ uint c = *p;
+ *q = ((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00);
p++;
q++;
}
}
- return res;
+ break;
case Format_RGB16:
res = QImage(d->width, d->height, d->format);
QIMAGE_SANITYCHECK_MEMORY(res);
@@ -4976,48 +2940,77 @@ QImage QImage::rgbSwapped() const
const ushort *p = (const ushort*)constScanLine(i);
const ushort *end = p + d->width;
while (p < end) {
- *q = ((*p << 11) & 0xf800) | ((*p >> 11) & 0x1f) | (*p & 0x07e0);
+ ushort c = *p;
+ *q = ((c << 11) & 0xf800) | ((c >> 11) & 0x1f) | (c & 0x07e0);
p++;
q++;
}
}
- return res;
+ break;
default:
+ res = QImage(d->width, d->height, d->format);
+ rgbSwapped_generic(d->width, d->height, this, &res, &qPixelLayouts[d->format]);
break;
}
+ return res;
+}
- res = QImage(d->width, d->height, d->format);
- QIMAGE_SANITYCHECK_MEMORY(res);
- const QPixelLayout *layout = &qPixelLayouts[d->format];
- Q_ASSERT(layout->redWidth == layout->blueWidth);
- FetchPixelsFunc fetch = qFetchPixels[layout->bpp];
- StorePixelsFunc store = qStorePixels[layout->bpp];
+/*!
+ \internal
+*/
+void QImage::rgbSwapped_inplace()
+{
+ if (isNull())
+ return;
- const uint redBlueMask = (1 << layout->redWidth) - 1;
- const uint alphaGreenMask = (((1 << layout->alphaWidth) - 1) << layout->alphaShift)
- | (((1 << layout->greenWidth) - 1) << layout->greenShift);
+ detach();
- const int buffer_size = 2048;
- uint buffer[buffer_size];
- for (int i = 0; i < d->height; ++i) {
- uchar *q = res.scanLine(i);
- const uchar *p = constScanLine(i);
- int x = 0;
- while (x < d->width) {
- int l = qMin(d->width - x, buffer_size);
- const uint *ptr = fetch(buffer, p, x, l);
- for (int j = 0; j < l; ++j) {
- uint red = (ptr[j] >> layout->redShift) & redBlueMask;
- uint blue = (ptr[j] >> layout->blueShift) & redBlueMask;
- buffer[j] = (ptr[j] & alphaGreenMask)
- | (red << layout->blueShift)
- | (blue << layout->redShift);
+ switch (d->format) {
+ case Format_Invalid:
+ case NImageFormats:
+ Q_ASSERT(false);
+ break;
+ case Format_Mono:
+ case Format_MonoLSB:
+ case Format_Indexed8:
+ for (int i = 0; i < d->colortable.size(); i++) {
+ QRgb c = d->colortable.at(i);
+ d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00));
+ }
+ break;
+ case Format_RGB32:
+ case Format_ARGB32:
+ case Format_ARGB32_Premultiplied:
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ case Format_RGBX8888:
+ case Format_RGBA8888:
+ case Format_RGBA8888_Premultiplied:
+#endif
+ for (int i = 0; i < d->height; i++) {
+ uint *p = (uint*)scanLine(i);
+ uint *end = p + d->width;
+ while (p < end) {
+ uint c = *p;
+ *p = ((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00);
+ p++;
+ }
+ }
+ break;
+ case Format_RGB16:
+ for (int i = 0; i < d->height; i++) {
+ ushort *p = (ushort*)scanLine(i);
+ ushort *end = p + d->width;
+ while (p < end) {
+ ushort c = *p;
+ *p = ((c << 11) & 0xf800) | ((c >> 11) & 0x1f) | (c & 0x07e0);
+ p++;
}
- store(q, buffer, x, l);
- x += l;
}
+ break;
+ default:
+ rgbSwapped_generic(d->width, d->height, this, this, &qPixelLayouts[d->format]);
+ break;
}
- return res;
}
/*!
@@ -6427,7 +4420,7 @@ bool QImageData::convertInPlace(QImage::Format newFormat, Qt::ImageConversionFla
if (ref.load() > 1)
return false;
- const InPlace_Image_Converter *const converterPtr = &inplace_converter_map[format][newFormat];
+ const InPlace_Image_Converter *const converterPtr = &qimage_inplace_converter_map[format][newFormat];
InPlace_Image_Converter converter = *converterPtr;
if (converter)
return converter(this, flags);