diff options
Diffstat (limited to 'src/gui/image')
-rw-r--r-- | src/gui/image/image.pri | 15 | ||||
-rw-r--r-- | src/gui/image/qbmphandler.cpp | 107 | ||||
-rw-r--r-- | src/gui/image/qimage.cpp | 2485 | ||||
-rw-r--r-- | src/gui/image/qimage.h | 15 | ||||
-rw-r--r-- | src/gui/image/qimage_compat.cpp (renamed from src/gui/image/qimage_avx.cpp) | 29 | ||||
-rw-r--r-- | src/gui/image/qimage_conversions.cpp | 2183 | ||||
-rw-r--r-- | src/gui/image/qimage_neon.cpp | 4 | ||||
-rw-r--r-- | src/gui/image/qimage_p.h | 13 | ||||
-rw-r--r-- | src/gui/image/qimagereader.cpp | 29 | ||||
-rw-r--r-- | src/gui/image/qjpeghandler.cpp | 10 | ||||
-rw-r--r-- | src/gui/image/qpixmap.cpp | 22 | ||||
-rw-r--r-- | src/gui/image/qpixmap.h | 7 | ||||
-rw-r--r-- | src/gui/image/qpixmap_raster.cpp | 11 | ||||
-rw-r--r-- | src/gui/image/qpixmap_raster_p.h | 1 | ||||
-rw-r--r-- | src/gui/image/qplatformpixmap.h | 9 | ||||
-rw-r--r-- | src/gui/image/qpnghandler.pri | 2 | ||||
-rw-r--r-- | src/gui/image/qxbmhandler.cpp | 24 |
17 files changed, 2613 insertions, 2353 deletions
diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri index bf4b5ddf01..bbdd0f3da7 100644 --- a/src/gui/image/image.pri +++ b/src/gui/image/image.pri @@ -32,6 +32,7 @@ HEADERS += \ SOURCES += \ image/qbitmap.cpp \ image/qimage.cpp \ + image/qimage_conversions.cpp \ image/qimageiohandler.cpp \ image/qimagereader.cpp \ image/qimagewriter.cpp \ @@ -54,6 +55,9 @@ SOURCES += \ win32:!winrt: SOURCES += image/qpixmap_win.cpp +NO_PCH_SOURCES += image/qimage_compat.cpp +false: SOURCES += $$NO_PCH_SOURCES # Hack for QtCreator + # Built-in image format support HEADERS += \ image/qbmphandler_p.h \ @@ -74,9 +78,12 @@ contains(QT_CONFIG, jpeg):include($$PWD/qjpeghandler.pri) contains(QT_CONFIG, gif):include($$PWD/qgifhandler.pri) # SIMD -NEON_SOURCES += image/qimage_neon.cpp -SSE2_SOURCES += image/qimage_sse2.cpp -SSSE3_SOURCES += image/qimage_ssse3.cpp -AVX_SOURCES += image/qimage_avx.cpp +contains(QT_CPU_FEATURES.$$QT_ARCH, neon) { + SOURCES += image/qimage_neon.cpp +} +contains(QT_CPU_FEATURES.$$QT_ARCH, sse2) { + SOURCES += image/qimage_sse2.cpp + SSSE3_SOURCES += image/qimage_ssse3.cpp +} MIPS_DSPR2_SOURCES += image/qimage_mips_dspr2.cpp MIPS_DSPR2_ASM += image/qimage_mips_dspr2_asm.S diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp index c03d9b8e5d..bb79a139b3 100644 --- a/src/gui/image/qbmphandler.cpp +++ b/src/gui/image/qbmphandler.cpp @@ -210,54 +210,15 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int uint red_mask = 0; uint green_mask = 0; uint blue_mask = 0; + uint alpha_mask = 0; int red_shift = 0; int green_shift = 0; int blue_shift = 0; + int alpha_shift = 0; int red_scale = 0; int green_scale = 0; int blue_scale = 0; - - int ncols = 0; - int depth = 0; - QImage::Format format; - switch (nbits) { - case 32: - case 24: - case 16: - depth = 32; - format = QImage::Format_RGB32; - break; - case 8: - case 4: - depth = 8; - format = QImage::Format_Indexed8; - break; - default: - depth = 1; - format = QImage::Format_Mono; - } - - if (bi.biHeight < 0) - h = -h; // support images with negative height - - if (image.size() != QSize(w, h) || image.format() != format) { - image = QImage(w, h, format); - if (image.isNull()) // could not create image - return false; - } - - if (depth != 32) { - ncols = bi.biClrUsed ? bi.biClrUsed : 1 << nbits; - if (ncols > 256) // sanity check - don't run out of mem if color table is broken - return false; - image.setColorCount(ncols); - } - - image.setDotsPerMeterX(bi.biXPelsPerMeter); - image.setDotsPerMeterY(bi.biYPelsPerMeter); - - if (!d->isSequential()) - d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap + int alpha_scale = 0; if (bi.biSize >= BMP_WIN4 || (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32))) { if (d->read((char *)&red_mask, sizeof(red_mask)) != sizeof(red_mask)) @@ -269,7 +230,6 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int // Read BMP v4+ header if (bi.biSize >= BMP_WIN4) { - int alpha_mask = 0; int CSType = 0; int gamma_red = 0; int gamma_green = 0; @@ -307,6 +267,49 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int } } + bool transp = (comp == BMP_BITFIELDS) && alpha_mask; + int ncols = 0; + int depth = 0; + QImage::Format format; + switch (nbits) { + case 32: + case 24: + case 16: + depth = 32; + format = transp ? QImage::Format_ARGB32 : QImage::Format_RGB32; + break; + case 8: + case 4: + depth = 8; + format = QImage::Format_Indexed8; + break; + default: + depth = 1; + format = QImage::Format_Mono; + } + + if (bi.biHeight < 0) + h = -h; // support images with negative height + + if (image.size() != QSize(w, h) || image.format() != format) { + image = QImage(w, h, format); + if (image.isNull()) // could not create image + return false; + } + + if (depth != 32) { + ncols = bi.biClrUsed ? bi.biClrUsed : 1 << nbits; + if (ncols > 256) // sanity check - don't run out of mem if color table is broken + return false; + image.setColorCount(ncols); + } + + image.setDotsPerMeterX(bi.biXPelsPerMeter); + image.setDotsPerMeterY(bi.biYPelsPerMeter); + + if (!d->isSequential()) + d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap + if (ncols > 0) { // read color table uchar rgb[4]; int rgb_len = t == BMP_OLD ? 3 : 4; @@ -324,6 +327,8 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int green_scale = 256 / ((green_mask >> green_shift) + 1); blue_shift = calc_shift(blue_mask); blue_scale = 256 / ((blue_mask >> blue_shift) + 1); + alpha_shift = calc_shift(alpha_mask); + alpha_scale = 256 / ((alpha_mask >> alpha_shift) + 1); } else if (comp == BMP_RGB && (nbits == 24 || nbits == 32)) { blue_mask = 0x000000ff; green_mask = 0x0000ff00; @@ -344,6 +349,13 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int blue_scale = 8; } +#if 0 + qDebug("Rmask: %08x Rshift: %08x Rscale:%08x", red_mask, red_shift, red_scale); + qDebug("Gmask: %08x Gshift: %08x Gscale:%08x", green_mask, green_shift, green_scale); + qDebug("Bmask: %08x Bshift: %08x Bscale:%08x", blue_mask, blue_shift, blue_scale); + qDebug("Amask: %08x Ashift: %08x Ascale:%08x", alpha_mask, alpha_shift, alpha_scale); +#endif + // offset can be bogus, be careful if (offset>=0 && startpos + offset > d->pos()) { if (!d->isSequential()) @@ -535,11 +547,14 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int b = buf24; while (p < end) { c = *(uchar*)b | (*(uchar*)(b+1)<<8); - if (nbits != 16) + if (nbits > 16) c |= *(uchar*)(b+2)<<16; - *p++ = qRgb(((c & red_mask) >> red_shift) * red_scale, + if (nbits > 24) + c |= *(uchar*)(b+3)<<24; + *p++ = qRgba(((c & red_mask) >> red_shift) * red_scale, ((c & green_mask) >> green_shift) * green_scale, - ((c & blue_mask) >> blue_shift) * blue_scale); + ((c & blue_mask) >> blue_shift) * blue_scale, + transp ? ((c & alpha_mask) >> alpha_shift) * alpha_scale : 0xff); b += nbits/8; } } diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 70fe7b783f..d6037fb2d6 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,2100 +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 - -#ifdef QT_COMPILER_SUPPORTS_MIPS_DSPR2 - extern bool convert_ARGB_to_ARGB_PM_inplace_mips_dspr2(QImageData *data, Qt::ImageConversionFlags); - inplace_converter_map[QImage::Format_ARGB32][QImage::Format_ARGB32_Premultiplied] = convert_ARGB_to_ARGB_PM_inplace_mips_dspr2; - 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. @@ -4008,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); @@ -4025,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); @@ -4131,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(); @@ -4810,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. @@ -4818,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(); @@ -4840,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. @@ -4934,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: @@ -4952,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: @@ -4965,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); @@ -4982,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; } /*! @@ -6433,10 +4420,12 @@ 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); + else if (format > QImage::Format_Indexed8 && newFormat > QImage::Format_Indexed8) + return convert_generic_inplace(this, newFormat, flags); else return false; } diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h index bc7f3729ad..e8f195c18e 100644 --- a/src/gui/image/qimage.h +++ b/src/gui/image/qimage.h @@ -245,8 +245,19 @@ public: static QMatrix trueMatrix(const QMatrix &, int w, int h); QImage transformed(const QTransform &matrix, Qt::TransformationMode mode = Qt::FastTransformation) const; static QTransform trueMatrix(const QTransform &, int w, int h); +#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QIMAGE_COMPAT_CPP) + QImage mirrored(bool horizontally = false, bool vertically = true) const & + { return mirrored_helper(horizontally, vertically); } + QImage &&mirrored(bool horizontally = false, bool vertically = true) && + { mirrored_inplace(horizontally, vertically); return qMove(*this); } + QImage rgbSwapped() const & + { return rgbSwapped_helper(); } + QImage &&rgbSwapped() && + { rgbSwapped_inplace(); return qMove(*this); } +#else QImage mirrored(bool horizontally = false, bool vertically = true) const; QImage rgbSwapped() const; +#endif void invertPixels(InvertMode = InvertRgb); @@ -298,6 +309,10 @@ public: protected: virtual int metric(PaintDeviceMetric metric) const; + QImage mirrored_helper(bool horizontal, bool vertical) const; + QImage rgbSwapped_helper() const; + void mirrored_inplace(bool horizontal, bool vertical); + void rgbSwapped_inplace(); private: friend class QWSOnScreenSurface; diff --git a/src/gui/image/qimage_avx.cpp b/src/gui/image/qimage_compat.cpp index d04ec5b3de..9886d392fb 100644 --- a/src/gui/image/qimage_avx.cpp +++ b/src/gui/image/qimage_compat.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2012 Intel Corporation +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtGui module of the Qt Toolkit. @@ -39,19 +39,24 @@ ** ****************************************************************************/ -#include <private/qsimd_p.h> +#ifdef QIMAGE_H +# error "This file cannot be used with precompiled headers" +#endif +#define QT_COMPILING_QIMAGE_COMPAT_CPP -#ifdef QT_COMPILER_SUPPORTS_AVX +#include "qimage.h" -#ifndef __AVX__ -#error "AVX not enabled in this file, cannot proceed" -#endif +QT_BEGIN_NAMESPACE -#define convert_ARGB_to_ARGB_PM_inplace_sse2 convert_ARGB_to_ARGB_PM_inplace_avx -#include "qimage_sse2.cpp" +// These implementations must be the same as the inline versions in qimage.h +QImage QImage::mirrored(bool horizontally, bool vertically) const +{ + return mirrored_helper(horizontally, vertically); +} -#define qt_convert_rgb888_to_rgb32_ssse3 qt_convert_rgb888_to_rgb32_avx -#define convert_RGB888_to_RGB32_ssse3 convert_RGB888_to_RGB32_avx -#include "qimage_ssse3.cpp" +QImage QImage::rgbSwapped() const +{ + return rgbSwapped_helper(); +} -#endif +QT_END_NAMESPACE diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp new file mode 100644 index 0000000000..9b79f4ccc0 --- /dev/null +++ b/src/gui/image/qimage_conversions.cpp @@ -0,0 +1,2183 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <private/qdrawhelper_p.h> +#include <private/qguiapplication_p.h> +#include <private/qsimd_p.h> + +#include <private/qimage_p.h> + +QT_BEGIN_NAMESPACE + +// 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; +} + +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; + } + } +} + +/***************************************************************************** + Internal routines for converting image depth. + *****************************************************************************/ + +// Cannot be used with indexed formats. +void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(dest->format > QImage::Format_Indexed8); + Q_ASSERT(src->format > QImage::Format_Indexed8); + 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; + } +} + +// Cannot be used with indexed formats or between formats with different pixel depths. +bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags) +{ + Q_ASSERT(dst_format > QImage::Format_Indexed8); + Q_ASSERT(data->format > QImage::Format_Indexed8); + if (data->depth != qt_depthForFormat(dst_format)) + return false; + + const int buffer_size = 2048; + uint buffer[buffer_size]; + const QPixelLayout *srcLayout = &qPixelLayouts[data->format]; + const QPixelLayout *destLayout = &qPixelLayouts[dst_format]; + + uchar *srcData = data->data; + + FetchPixelsFunc fetch = qFetchPixels[srcLayout->bpp]; + StorePixelsFunc store = qStorePixels[destLayout->bpp]; + + for (int y = 0; y < data->height; ++y) { + int x = 0; + while (x < data->width) { + int l = qMin(data->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(srcData, ptr, x, l); + x += l; + } + srcData += data->bytes_per_line; + } + data->format = dst_format; + return true; +} + +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; + } +} + +extern bool convert_ARGB_to_ARGB_PM_inplace_sse2(QImageData *data, Qt::ImageConversionFlags); + +#ifndef __SSE2__ +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; +} +#endif + +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. +// + +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; + } + } +} + +// first index source, second dest +Image_Converter qimage_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, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 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, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 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, + 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 + }, // 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 +}; + +InPlace_Image_Converter qimage_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, +#ifdef __SSE2__ + convert_ARGB_to_ARGB_PM_inplace_sse2, +#else + convert_ARGB_to_ARGB_PM_inplace, +#endif + 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() +{ +#if defined(__SSE2__) && defined(QT_COMPILER_SUPPORTS_SSSE3) + if (qCpuHasFeature(SSSE3)) { + extern void convert_RGB888_to_RGB32_ssse3(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags); + qimage_converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB32_ssse3; + qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB32_ssse3; + qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB32_ssse3; + } +#endif + +#ifdef __ARM_NEON__ + extern void convert_RGB888_to_RGB32_neon(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags); + qimage_converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB32_neon; + qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB32_neon; + qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB32_neon; +#endif + +#ifdef QT_COMPILER_SUPPORTS_MIPS_DSPR2 + extern bool convert_ARGB_to_ARGB_PM_inplace_mips_dspr2(QImageData *data, Qt::ImageConversionFlags); + inplace_converter_map[QImage::Format_ARGB32][QImage::Format_ARGB32_Premultiplied] = convert_ARGB_to_ARGB_PM_inplace_mips_dspr2; + return; +#endif +} + +QT_END_NAMESPACE diff --git a/src/gui/image/qimage_neon.cpp b/src/gui/image/qimage_neon.cpp index 1ac0a87272..60c2da6a58 100644 --- a/src/gui/image/qimage_neon.cpp +++ b/src/gui/image/qimage_neon.cpp @@ -43,7 +43,7 @@ #include <private/qimage_p.h> #include <private/qsimd_p.h> -#ifdef QT_COMPILER_SUPPORTS_NEON +#ifdef __ARM_NEON__ QT_BEGIN_NAMESPACE @@ -111,4 +111,4 @@ void convert_RGB888_to_RGB32_neon(QImageData *dest, const QImageData *src, Qt::I QT_END_NAMESPACE -#endif // QT_COMPILER_SUPPORTS_NEON +#endif // __ARM_NEON__ diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h index 36f117df60..81730b92f2 100644 --- a/src/gui/image/qimage_p.h +++ b/src/gui/image/qimage_p.h @@ -108,7 +108,20 @@ struct Q_GUI_EXPORT QImageData { // internal image data QPaintEngine *paintEngine; }; +typedef void (*Image_Converter)(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags); +typedef bool (*InPlace_Image_Converter)(QImageData *data, Qt::ImageConversionFlags); + +extern Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormats]; +extern InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats]; + +void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags); +bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags); + +void dither_to_Mono(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags, bool fromalpha); + void qInitImageConversions(); + +const uchar *qt_get_bitflip_array(); Q_GUI_EXPORT void qGamma_correct_back_to_linear_cs(QImage *image); inline int qt_depthForFormat(QImage::Format format) diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp index 636d86991b..091837b8b4 100644 --- a/src/gui/image/qimagereader.cpp +++ b/src/gui/image/qimagereader.cpp @@ -190,37 +190,36 @@ enum _qt_BuiltInFormatType { struct _qt_BuiltInFormatStruct { - _qt_BuiltInFormatType type; const char *extension; const char *mimeType; }; static const _qt_BuiltInFormatStruct _qt_BuiltInFormats[] = { #ifndef QT_NO_IMAGEFORMAT_PNG - {_qt_PngFormat, "png", "image/png"}, + {"png", "image/png"}, #endif #ifndef QT_NO_IMAGEFORMAT_JPEG - {_qt_JpgFormat, "jpg", "image/jpeg"}, - {_qt_JpegFormat, "jpeg", "image/jpeg"}, + {"jpg", "image/jpeg"}, + {"jpeg", "image/jpeg"}, #endif #ifdef QT_BUILTIN_GIF_READER - {_qt_GifFormat, "gif", "image/gif"}, + {"gif", "image/gif"}, #endif #ifndef QT_NO_IMAGEFORMAT_BMP - {_qt_BmpFormat, "bmp", "image/bmp"}, + {"bmp", "image/bmp"}, #endif #ifndef QT_NO_IMAGEFORMAT_PPM - {_qt_PpmFormat, "ppm", "image/x-portable-pixmap"}, - {_qt_PgmFormat, "pgm", "image/x-portable-graymap"}, - {_qt_PbmFormat, "pbm", "image/x-portable-bitmap"}, + {"ppm", "image/x-portable-pixmap"}, + {"pgm", "image/x-portable-graymap"}, + {"pbm", "image/x-portable-bitmap"}, #endif #ifndef QT_NO_IMAGEFORMAT_XBM - {_qt_XbmFormat, "xbm", "image/x-xbitmap"}, + {"xbm", "image/x-xbitmap"}, #endif #ifndef QT_NO_IMAGEFORMAT_XPM - {_qt_XpmFormat, "xpm", "image/x-xpixmap"}, + {"xpm", "image/x-xpixmap"}, #endif - {_qt_NoFormat, "", ""} + {"", ""} }; static QImageIOHandler *createReadHandlerHelper(QIODevice *device, @@ -423,10 +422,8 @@ static QImageIOHandler *createReadHandlerHelper(QIODevice *device, QByteArray subType; int numFormats = _qt_NumFormats; while (device && numFormats >= 0) { - const _qt_BuiltInFormatStruct *formatStruct = &_qt_BuiltInFormats[currentFormat]; - const qint64 pos = device->pos(); - switch (formatStruct->type) { + switch (currentFormat) { #ifndef QT_NO_IMAGEFORMAT_PNG case _qt_PngFormat: if (QPngHandler::canRead(device)) @@ -482,7 +479,7 @@ static QImageIOHandler *createReadHandlerHelper(QIODevice *device, if (handler) { #ifdef QIMAGEREADER_DEBUG - qDebug() << "QImageReader::createReadHandler: the" << formatStruct->extension + qDebug() << "QImageReader::createReadHandler: the" << _qt_BuiltInFormats[currentFormat].extension << "built-in handler can read this data"; #endif break; diff --git a/src/gui/image/qjpeghandler.cpp b/src/gui/image/qjpeghandler.cpp index 3f90bb42f0..bd358b7228 100644 --- a/src/gui/image/qjpeghandler.cpp +++ b/src/gui/image/qjpeghandler.cpp @@ -861,24 +861,18 @@ Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_avx(quint32 *dst, const QJpegHandler::QJpegHandler() : d(new QJpegHandlerPrivate(this)) { -#if defined(QT_COMPILER_SUPPORTS_NEON) +#if defined(__ARM_NEON__) // from qimage_neon.cpp if (qCpuHasFeature(NEON)) rgb888ToRgb32ConverterPtr = qt_convert_rgb888_to_rgb32_neon; -#endif // QT_COMPILER_SUPPORTS_NEON +#endif // __ARM_NEON__ #if defined(QT_COMPILER_SUPPORTS_SSSE3) // from qimage_ssse3.cpp if (false) { -# if defined(QT_COMPILER_SUPPORTS_AVX) - } else if (qCpuHasFeature(AVX)) { - rgb888ToRgb32ConverterPtr = qt_convert_rgb888_to_rgb32_avx; -# endif -# ifndef __AVX__ } else if (qCpuHasFeature(SSSE3)) { rgb888ToRgb32ConverterPtr = qt_convert_rgb888_to_rgb32_ssse3; -# endif } #endif // QT_COMPILER_SUPPORTS_SSSE3 } diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index 6dced54d20..86c4dfbdca 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -1617,6 +1617,28 @@ QPixmap QPixmap::fromImage(const QImage &image, Qt::ImageConversionFlags flags) } /*! + \fn QPixmap QPixmap::fromImage(QImage &&image, Qt::ImageConversionFlags flags) + \since 5.3 + \overload + + Converts the given \a image to a pixmap without copying if possible. +*/ + + +/*! + \internal +*/ +QPixmap QPixmap::fromImageInPlace(QImage &image, Qt::ImageConversionFlags flags) +{ + if (image.isNull()) + return QPixmap(); + + QScopedPointer<QPlatformPixmap> data(QGuiApplicationPrivate::platformIntegration()->createPlatformPixmap(QPlatformPixmap::PixmapType)); + data->fromImageInPlace(image, flags); + return QPixmap(data.take()); +} + +/*! \fn QPixmap QPixmap::fromImageReader(QImageReader *imageReader, Qt::ImageConversionFlags flags) Create a QPixmap from an image read directly from an \a imageReader. diff --git a/src/gui/image/qpixmap.h b/src/gui/image/qpixmap.h index f1fce03c80..0efd606283 100644 --- a/src/gui/image/qpixmap.h +++ b/src/gui/image/qpixmap.h @@ -131,6 +131,12 @@ public: QImage toImage() const; static QPixmap fromImage(const QImage &image, Qt::ImageConversionFlags flags = Qt::AutoColor); static QPixmap fromImageReader(QImageReader *imageReader, Qt::ImageConversionFlags flags = Qt::AutoColor); +#ifdef Q_COMPILER_RVALUE_REFS + static QPixmap fromImage(QImage &&image, Qt::ImageConversionFlags flags = Qt::AutoColor) + { + return fromImageInPlace(image, flags); + } +#endif bool load(const QString& fileName, const char *format = 0, Qt::ImageConversionFlags flags = Qt::AutoColor); bool loadFromData(const uchar *buf, uint len, const char* format = 0, Qt::ImageConversionFlags flags = Qt::AutoColor); @@ -167,6 +173,7 @@ public: protected: int metric(PaintDeviceMetric) const; + static QPixmap fromImageInPlace(QImage &image, Qt::ImageConversionFlags flags = Qt::AutoColor); private: QExplicitlySharedDataPointer<QPlatformPixmap> data; diff --git a/src/gui/image/qpixmap_raster.cpp b/src/gui/image/qpixmap_raster.cpp index f9a017c281..37259adcd2 100644 --- a/src/gui/image/qpixmap_raster.cpp +++ b/src/gui/image/qpixmap_raster.cpp @@ -135,11 +135,16 @@ bool QRasterPlatformPixmap::fromData(const uchar *buffer, uint len, const char * void QRasterPlatformPixmap::fromImage(const QImage &sourceImage, Qt::ImageConversionFlags flags) { - Q_UNUSED(flags); QImage image = sourceImage; createPixmapForImage(image, flags, /* inplace = */false); } +void QRasterPlatformPixmap::fromImageInPlace(QImage &sourceImage, + Qt::ImageConversionFlags flags) +{ + createPixmapForImage(sourceImage, flags, /* inplace = */true); +} + void QRasterPlatformPixmap::fromImageReader(QImageReader *imageReader, Qt::ImageConversionFlags flags) { @@ -182,7 +187,7 @@ void QRasterPlatformPixmap::fill(const QColor &color) if (alpha != 255) { if (!image.hasAlphaChannel()) { QImage::Format toFormat; -#if !(defined(QT_COMPILER_SUPPORTS_NEON) || defined(__SSE2__)) +#if !(defined(__ARM_NEON__) || defined(__SSE2__)) if (image.format() == QImage::Format_RGB16) toFormat = QImage::Format_ARGB8565_Premultiplied; else if (image.format() == QImage::Format_RGB666) @@ -311,7 +316,7 @@ void QRasterPlatformPixmap::createPixmapForImage(QImage &sourceImage, Qt::ImageC QImage::Format opaqueFormat = QNativeImage::systemFormat(); QImage::Format alphaFormat = QImage::Format_ARGB32_Premultiplied; -#if !defined(QT_COMPILER_SUPPORTS_NEON) && !defined(__SSE2__) +#if !defined(__ARM_NEON__) && !defined(__SSE2__) switch (opaqueFormat) { case QImage::Format_RGB16: alphaFormat = QImage::Format_ARGB8565_Premultiplied; diff --git a/src/gui/image/qpixmap_raster_p.h b/src/gui/image/qpixmap_raster_p.h index cef8821888..b273d65c9f 100644 --- a/src/gui/image/qpixmap_raster_p.h +++ b/src/gui/image/qpixmap_raster_p.h @@ -69,6 +69,7 @@ public: void resize(int width, int height); bool fromData(const uchar *buffer, uint len, const char *format, Qt::ImageConversionFlags flags); void fromImage(const QImage &image, Qt::ImageConversionFlags flags); + void fromImageInPlace(QImage &image, Qt::ImageConversionFlags flags); void fromImageReader(QImageReader *imageReader, Qt::ImageConversionFlags flags); void copy(const QPlatformPixmap *data, const QRect &rect); diff --git a/src/gui/image/qplatformpixmap.h b/src/gui/image/qplatformpixmap.h index 08e03f10bd..435811eb84 100644 --- a/src/gui/image/qplatformpixmap.h +++ b/src/gui/image/qplatformpixmap.h @@ -69,7 +69,8 @@ public: }; enum ClassId { RasterClass, DirectFBClass, - BlitterClass, CustomClass = 1024 }; + BlitterClass, Direct2DClass, + CustomClass = 1024 }; QPlatformPixmap(PixelType pixelType, int classId); virtual ~QPlatformPixmap(); @@ -79,6 +80,12 @@ public: virtual void resize(int width, int height) = 0; virtual void fromImage(const QImage &image, Qt::ImageConversionFlags flags) = 0; + virtual void fromImageInPlace(QImage &image, + Qt::ImageConversionFlags flags) + { + fromImage(image, flags); + } + virtual void fromImageReader(QImageReader *imageReader, Qt::ImageConversionFlags flags); diff --git a/src/gui/image/qpnghandler.pri b/src/gui/image/qpnghandler.pri index bedf23ff12..aca7e2c568 100644 --- a/src/gui/image/qpnghandler.pri +++ b/src/gui/image/qpnghandler.pri @@ -2,7 +2,7 @@ INCLUDEPATH *= $$PWD HEADERS += $$PWD/qpnghandler_p.h SOURCES += $$PWD/qpnghandler.cpp contains(QT_CONFIG, system-png) { - if(unix|win32-g++*): LIBS_PRIVATE += -lpng + if(unix|mingw): LIBS_PRIVATE += -lpng else:win32: LIBS += libpng.lib } else { diff --git a/src/gui/image/qxbmhandler.cpp b/src/gui/image/qxbmhandler.cpp index aceb6623ea..5311afd745 100644 --- a/src/gui/image/qxbmhandler.cpp +++ b/src/gui/image/qxbmhandler.cpp @@ -103,7 +103,7 @@ static bool read_xbm_header(QIODevice *device, int& w, int& h) // "#define .._height <num>" readBytes = device->readLine(buf, buflen); if (readBytes <= 0) - return false; + return false; buf[readBytes - 1] = '\0'; sbuf = QString::fromLatin1(buf); @@ -183,9 +183,9 @@ static bool read_xbm_image(QIODevice *device, QImage *outImage) static bool write_xbm_image(const QImage &sourceImage, QIODevice *device, const QString &fileName) { QImage image = sourceImage; - int w = image.width(); - int h = image.height(); - int i; + int w = image.width(); + int h = image.height(); + int i; QString s = fileName; // get file base name int msize = s.length() + 100; char *buf = new char[msize]; @@ -203,16 +203,16 @@ static bool write_xbm_image(const QImage &sourceImage, QIODevice *device, const bool invert = qGray(image.color(0)) < qGray(image.color(1)); char hexrep[16]; for (i=0; i<10; i++) - hexrep[i] = '0' + i; + hexrep[i] = '0' + i; for (i=10; i<16; i++) - hexrep[i] = 'a' -10 + i; + hexrep[i] = 'a' -10 + i; if (invert) { - char t; - for (i=0; i<8; i++) { - t = hexrep[15-i]; - hexrep[15-i] = hexrep[i]; - hexrep[i] = t; - } + char t; + for (i=0; i<8; i++) { + t = hexrep[15-i]; + hexrep[15-i] = hexrep[i]; + hexrep[i] = t; + } } int bcnt = 0; char *p = buf; |