diff options
Diffstat (limited to 'src/gui/image/qimage.cpp')
-rw-r--r-- | src/gui/image/qimage.cpp | 2477 |
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); |