From d84a6eab5129ba29951a7ba6d82820b21cc9872e Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Fri, 14 Feb 2014 10:39:30 +0100 Subject: Add Grayscale8 and Alpha8 formats to QImage and drawing Extend the QImage format with two 8-bit grayscale and alpha formats. These formats have the advantage over Indexed8 that they have simpler conversion and can be rendered to by the raster engine. [ChangeLog][QtGui][QImage] Added support grayscale and alpha 8-bit formats which can also be rendered to. Change-Id: I4343c80a92a3dda196aa38d0c3ea251b094fc274 Reviewed-by: Gunnar Sletta --- src/gui/image/qbmphandler.cpp | 4 + src/gui/image/qimage.cpp | 99 +++++++--- src/gui/image/qimage.h | 16 +- src/gui/image/qimage_conversions.cpp | 337 ++++++++++++++++++++++++++++++----- src/gui/image/qimage_p.h | 2 + src/gui/image/qjpeghandler.cpp | 31 ++-- src/gui/image/qpixmap_raster.cpp | 9 +- src/gui/image/qpnghandler.cpp | 14 ++ src/gui/image/qppmhandler.cpp | 108 ++++++----- 9 files changed, 479 insertions(+), 141 deletions(-) (limited to 'src/gui/image') diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp index 036d0615e3..4a2f687bf1 100644 --- a/src/gui/image/qbmphandler.cpp +++ b/src/gui/image/qbmphandler.cpp @@ -812,6 +812,10 @@ bool QBmpHandler::write(const QImage &img) case QImage::Format_RGB30: image = img.convertToFormat(QImage::Format_RGB32); break; + case QImage::Format_Alpha8: + case QImage::Format_Grayscale8: + image = img.convertToFormat(QImage::Format_Indexed8); + break; default: image = img; } diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 5de686c1ea..fdaf13964b 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -661,7 +661,8 @@ bool QImageData::checkForAlphaPixels() const The following image formats are available in Qt. Values from Format_ARGB8565_Premultiplied to Format_ARGB4444_Premultiplied were added in Qt 4.4. Values Format_RGBX8888, Format_RGBA8888 and Format_RGBA8888_Premultiplied were added in Qt 5.2. Values Format_BGR30, Format_A2BGR30_Premultiplied, - Format_RGB30, Format_A2RGB30_Premultiplied were added in Qt 5.4. + Format_RGB30, Format_A2RGB30_Premultiplied were added in Qt 5.4. Format_Alpha8 and Format_Grayscale8 + were added in Qt 5.5. See the notes after the table. \value Format_Invalid The image is invalid. @@ -717,6 +718,8 @@ bool QImageData::checkForAlphaPixels() const \value Format_A2BGR30_Premultiplied The image is stored using a 32-bit premultiplied ABGR format (2-10-10-10). \value Format_RGB30 The image is stored using a 32-bit RGB format (x-10-10-10). \value Format_A2RGB30_Premultiplied The image is stored using a 32-bit premultiplied ARGB format (2-10-10-10). + \value Format_Alpha8 The image is stored using an 8-bit alpha only format. + \value Format_Grayscale8 The image is stored using an 8-bit grayscale format. \note Drawing into a QImage with QImage::Format_Indexed8 is not supported. @@ -2361,6 +2364,10 @@ bool QImage::allGray() const return false; } return true; + case Format_Alpha8: + return false; + case Format_Grayscale8: + return true; case Format_RGB32: case Format_ARGB32: case Format_ARGB32_Premultiplied: @@ -2414,9 +2421,9 @@ bool QImage::allGray() const /*! For 32-bit images, this function is equivalent to allGray(). - For 8-bpp images, this function returns \c true if color(i) is - QRgb(i, i, i) for all indexes of the color table; otherwise - returns \c false. + For color indexed images, this function returns \c true if + color(i) is QRgb(i, i, i) for all indexes of the color table; + otherwise returns \c false. \sa allGray(), {QImage#Image Formats}{Image Formats} */ @@ -2425,12 +2432,19 @@ bool QImage::isGrayscale() const if (!d) return false; + if (d->format == QImage::Format_Alpha8) + return false; + + if (d->format == QImage::Format_Grayscale8) + return true; + switch (depth()) { case 32: case 24: case 16: return allGray(); case 8: { + Q_ASSERT(d->format == QImage::Format_Indexed8); for (int i = 0; i < colorCount(); i++) if (d->colortable.at(i) != qRgb(i,i,i)) return false; @@ -3005,6 +3019,9 @@ QImage QImage::rgbSwapped_helper() const case NImageFormats: Q_ASSERT(false); break; + case Format_Alpha8: + case Format_Grayscale8: + return *this; case Format_Mono: case Format_MonoLSB: case Format_Indexed8: @@ -3091,6 +3108,9 @@ void QImage::rgbSwapped_inplace() case NImageFormats: Q_ASSERT(false); break; + case Format_Alpha8: + case Format_Grayscale8: + return; case Format_Mono: case Format_MonoLSB: case Format_Indexed8: @@ -4024,7 +4044,7 @@ void QImage::setAlphaChannel(const QImage &alphaChannel) return; // Slight optimization since alphachannels are returned as 8-bit grays. - if (alphaChannel.d->depth == 8 && alphaChannel.isGrayscale()) { + if (alphaChannel.format() == QImage::Format_Alpha8 ||( alphaChannel.d->depth == 8 && alphaChannel.isGrayscale())) { const uchar *src_data = alphaChannel.d->data; const uchar *dest_data = d->data; for (int y=0; yformat == QImage::Format_Alpha8) + return *this; + int w = d->width; int h = d->height; @@ -4168,6 +4195,7 @@ bool QImage::hasAlphaChannel() const || d->format == Format_RGBA8888_Premultiplied || d->format == Format_A2BGR30_Premultiplied || d->format == Format_A2RGB30_Premultiplied + || d->format == Format_Alpha8 || (d->has_alpha_clut && (d->format == Format_Indexed8 || d->format == Format_Mono || d->format == Format_MonoLSB))); @@ -4277,6 +4305,8 @@ static QImage rotated90(const QImage &image) { reinterpret_cast(out.bits()), out.bytesPerLine()); break; + case QImage::Format_Alpha8: + case QImage::Format_Grayscale8: case QImage::Format_Indexed8: qt_memrotate270(reinterpret_cast(image.bits()), w, h, image.bytesPerLine(), @@ -4343,6 +4373,8 @@ static QImage rotated270(const QImage &image) { reinterpret_cast(out.bits()), out.bytesPerLine()); break; + case QImage::Format_Alpha8: + case QImage::Format_Grayscale8: case QImage::Format_Indexed8: qt_memrotate90(reinterpret_cast(image.bits()), w, h, image.bytesPerLine(), @@ -4495,24 +4527,17 @@ QImage QImage::transformed(const QTransform &matrix, Qt::TransformationMode mode dImage.d->dpmy = dotsPerMeterY(); dImage.d->devicePixelRatio = devicePixelRatio(); - switch (bpp) { - // initizialize the data - case 8: - if (dImage.d->colortable.size() < 256) { - // colors are left in the color table, so pick that one as transparent - dImage.d->colortable.append(0x0); - memset(dImage.bits(), dImage.d->colortable.size() - 1, dImage.byteCount()); - } else { - memset(dImage.bits(), 0, dImage.byteCount()); - } - break; - case 1: - case 16: - case 24: - case 32: - memset(dImage.bits(), 0x00, dImage.byteCount()); - break; - } + // initizialize the data + if (d->format == QImage::Format_Indexed8) { + if (dImage.d->colortable.size() < 256) { + // colors are left in the color table, so pick that one as transparent + dImage.d->colortable.append(0x0); + memset(dImage.bits(), dImage.d->colortable.size() - 1, dImage.byteCount()); + } else { + memset(dImage.bits(), 0, dImage.byteCount()); + } + } else + memset(dImage.bits(), 0x00, dImage.byteCount()); if (target_format >= QImage::Format_RGB32) { QPainter p(&dImage); @@ -4948,6 +4973,32 @@ static Q_CONSTEXPR QPixelFormat pixelformats[] = { /*PREMULTIPLIED*/ QPixelFormat::Premultiplied, /*INTERPRETATION*/ QPixelFormat::UnsignedInteger, /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian), + //QImage::Format_Alpha8: + QPixelFormat(QPixelFormat::Alpha, + /*First*/ 0, + /*SECOND*/ 0, + /*THIRD*/ 0, + /*FOURTH*/ 0, + /*FIFTH*/ 0, + /*ALPHA*/ 8, + /*ALPHA USAGE*/ QPixelFormat::UsesAlpha, + /*ALPHA POSITION*/ QPixelFormat::AtBeginning, + /*PREMULTIPLIED*/ QPixelFormat::Premultiplied, + /*INTERPRETATION*/ QPixelFormat::UnsignedByte, + /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian), + //QImage::Format_Grayscale8: + QPixelFormat(QPixelFormat::Grayscale, + /*GRAY*/ 8, + /*SECOND*/ 0, + /*THIRD*/ 0, + /*FOURTH*/ 0, + /*FIFTH*/ 0, + /*ALPHA*/ 0, + /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha, + /*ALPHA POSITION*/ QPixelFormat::AtBeginning, + /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied, + /*INTERPRETATION*/ QPixelFormat::UnsignedByte, + /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian), }; Q_STATIC_ASSERT(sizeof(pixelformats) / sizeof(*pixelformats) == QImage::NImageFormats); diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h index 3e73462efc..fbbdb2e408 100644 --- a/src/gui/image/qimage.h +++ b/src/gui/image/qimage.h @@ -114,20 +114,16 @@ public: Format_RGBX8888, Format_RGBA8888, Format_RGBA8888_Premultiplied, -#if 0 - // reserved for future use - Format_RGB15, - Format_Grayscale16, - Format_Grayscale8, - Format_Grayscale4, - Format_Grayscale4LSB, - Format_Grayscale2, - Format_Grayscale2LSB -#endif Format_BGR30, Format_A2BGR30_Premultiplied, Format_RGB30, Format_A2RGB30_Premultiplied, + Format_Alpha8, + Format_Grayscale8, +#if 0 + // reserved for future use + Format_Grayscale16, +#endif #ifndef Q_QDOC NImageFormats #endif diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index 195b56afbe..2551a65605 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -1868,11 +1868,154 @@ static void convert_Mono_to_Indexed8(QImageData *dest, const QImageData *src, Qt } } +static void convert_Indexed8_to_Alpha8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_Indexed8); + Q_ASSERT(dest->format == QImage::Format_Alpha8); + + uchar translate[256]; + const QVector &colors = src->colortable; + bool simpleCase = (colors.size() == 256); + for (int i = 0; i < colors.size(); ++i) { + uchar alpha = qAlpha(colors[i]); + translate[i] = alpha; + simpleCase = simpleCase && (alpha == i); + } + + if (simpleCase) + memcpy(dest->data, src->data, src->bytes_per_line * src->height); + else { + int size = src->bytes_per_line * src->height; + for (int i = 0; i < size; ++i) { + dest->data[i] = translate[src->data[i]]; + } + } +} + +static void convert_Indexed8_to_Grayscale8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_Indexed8); + Q_ASSERT(dest->format == QImage::Format_Grayscale8); + + uchar translate[256]; + const QVector &colors = src->colortable; + bool simpleCase = (colors.size() == 256); + for (int i = 0; i < colors.size(); ++i) { + uchar gray = qGray(colors[i]); + translate[i] = gray; + simpleCase = simpleCase && (gray == i); + } + + if (simpleCase) + memcpy(dest->data, src->data, src->bytes_per_line * src->height); + else { + int size = src->bytes_per_line * src->height; + for (int i = 0; i < size; ++i) { + dest->data[i] = translate[src->data[i]]; + } + } +} + +static bool convert_Indexed8_to_Alpha8_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_Indexed8); + + // Just check if this is an Alpha8 in Indexed8 disguise. + const QVector &colors = data->colortable; + if (colors.size() != 256) + return false; + for (int i = 0; i < colors.size(); ++i) { + if (i != qAlpha(colors[i])) + return false; + } + + data->colortable.clear(); + data->format = QImage::Format_Alpha8; + + return true; +} + +static bool convert_Indexed8_to_Grayscale8_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_Indexed8); + + // Just check if this is a Grayscale8 in Indexed8 disguise. + const QVector &colors = data->colortable; + if (colors.size() != 256) + return false; + for (int i = 0; i < colors.size(); ++i) { + if (i != qGray(colors[i])) + return false; + } + + data->colortable.clear(); + data->format = QImage::Format_Grayscale8; + + return true; +} + +static void convert_Alpha8_to_Indexed8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_Alpha8); + Q_ASSERT(dest->format == QImage::Format_Indexed8); + + memcpy(dest->data, src->data, src->bytes_per_line * src->height); + + QVector colors(256); + for (int i=0; i<256; ++i) + colors[i] = qRgba(0, 0, 0, i); + + dest->colortable = colors; +} + +static void convert_Grayscale8_to_Indexed8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_Grayscale8); + Q_ASSERT(dest->format == QImage::Format_Indexed8); + + memcpy(dest->data, src->data, src->bytes_per_line * src->height); + + QVector colors(256); + for (int i=0; i<256; ++i) + colors[i] = qRgb(i, i, i); + + dest->colortable = colors; +} + +static bool convert_Alpha8_to_Indexed8_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_Alpha8); + + QVector colors(256); + for (int i=0; i<256; ++i) + colors[i] = qRgba(0, 0, 0, i); + + data->colortable = colors; + data->format = QImage::Format_Indexed8; + + return true; +} + +static bool convert_Grayscale8_to_Indexed8_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_Grayscale8); + + QVector colors(256); + for (int i=0; i<256; ++i) + colors[i] = qRgb(i, i, i); + + data->colortable = colors; + data->format = QImage::Format_Indexed8; + + return true; +} + + // 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, 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, @@ -1893,7 +2036,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_Mono { @@ -1915,7 +2058,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_MonoLSB { @@ -1937,7 +2080,9 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, + convert_Indexed8_to_Alpha8, + convert_Indexed8_to_Grayscale8, }, // Format_Indexed8 { @@ -1964,6 +2109,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_RGB_to_RGB30, convert_RGB_to_RGB30, convert_RGB_to_RGB30, + 0, 0 }, // Format_RGB32 { @@ -1990,6 +2136,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, convert_RGB_to_RGB30, 0, + 0, 0 }, // Format_ARGB32 { @@ -2016,6 +2163,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_ARGB_to_A2RGB30, convert_ARGB_PM_to_RGB30, convert_ARGB_to_A2RGB30, + 0, 0 }, // Format_ARGB32_Premultiplied { @@ -2037,7 +2185,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB16 { @@ -2059,7 +2207,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB8565_Premultiplied { @@ -2081,7 +2229,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB666 { @@ -2103,7 +2251,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB6666_Premultiplied { @@ -2125,7 +2273,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB555 { @@ -2147,7 +2295,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB8555_Premultiplied { @@ -2169,7 +2317,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB888 { @@ -2191,7 +2339,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB444 { @@ -2212,7 +2360,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB4444_Premultiplied { 0, @@ -2234,7 +2382,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, mask_alpha_converter_RGBx, mask_alpha_converter_RGBx, - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 }, // Format_RGBX8888 { 0, @@ -2259,9 +2407,9 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_ARGB_to_ARGB_PM, #else 0, - 0 + 0, #endif - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 }, // Format_RGBA8888 { @@ -2288,9 +2436,9 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat #else 0, 0, - 0 + 0, #endif - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 }, // Format_RGBA8888_Premultiplied { @@ -2316,7 +2464,8 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, convert_passthrough, convert_BGR30_to_RGB30, - convert_BGR30_to_RGB30 + convert_BGR30_to_RGB30, + 0, 0 }, // Format_BGR30 { 0, @@ -2341,7 +2490,8 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_A2RGB30_PM_to_RGB30, 0, 0, - convert_BGR30_to_RGB30 + convert_BGR30_to_RGB30, + 0, 0 }, // Format_BGR30A2_Premultiplied { 0, @@ -2367,6 +2517,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, convert_passthrough, + 0, 0 }, // Format_RGB30 { 0, @@ -2392,19 +2543,61 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_BGR30_to_RGB30, convert_A2RGB30_PM_to_RGB30, 0, + 0, + 0, }, // Format_RGB30A2_Premultiplied + { + 0, + 0, + 0, + convert_Alpha8_to_Indexed8, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, 0, 0, 0, 0, 0, 0 + }, // Format_Alpha8 + { + 0, + 0, + 0, + convert_Grayscale8_to_Indexed8, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, 0, 0, 0, 0, 0, 0 + } // Format_Grayscale8 }; 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, 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, 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, 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_MonoLSB { 0, @@ -2425,7 +2618,9 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, + convert_Indexed8_to_Alpha8_inplace, + convert_Indexed8_to_Grayscale8_inplace, }, // Format_Indexed8 { 0, @@ -2446,7 +2641,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB32 { 0, @@ -2471,7 +2666,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, convert_ARGB_to_RGBA_inplace, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB32 { 0, @@ -2493,34 +2688,34 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, convert_ARGB_to_RGBA_inplace, - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 }, // Format_ARGB32_Premultiplied { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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_RGB16 { - 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, 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, 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_RGB666 { - 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, 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, 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_RGB555 { - 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, 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, 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_RGB888 { - 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, 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, 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_ARGB4444_Premultiplied { 0, @@ -2542,7 +2737,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, convert_passthrough_inplace, convert_passthrough_inplace, - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 }, // Format_RGBX8888 { 0, @@ -2564,7 +2759,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 }, // Format_RGBA8888 { 0, @@ -2586,7 +2781,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 }, // Format_RGBA8888_Premultiplied { 0, @@ -2611,7 +2806,8 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, convert_passthrough_inplace, convert_BGR30_to_RGB30_inplace, - convert_BGR30_to_RGB30_inplace + convert_BGR30_to_RGB30_inplace, + 0, 0 }, // Format_BGR30 { 0, @@ -2636,7 +2832,8 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma convert_A2RGB30_PM_to_RGB30_inplace, 0, 0, - convert_BGR30_to_RGB30_inplace + convert_BGR30_to_RGB30_inplace, + 0, 0 }, // Format_BGR30A2_Premultiplied { 0, @@ -2661,7 +2858,8 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma convert_BGR30_to_RGB30_inplace, convert_BGR30_to_RGB30_inplace, 0, - convert_passthrough_inplace + convert_passthrough_inplace, + 0, 0 }, // Format_RGB30 { 0, @@ -2686,8 +2884,61 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, convert_BGR30_to_RGB30_inplace, convert_A2RGB30_PM_to_RGB30_inplace, - 0 + 0, + 0, 0 }, // Format_RGB30A2_Premultiplied + { + 0, + 0, + 0, + convert_Alpha8_to_Indexed8_inplace, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, 0 + }, // Format_Alpha8 + { + 0, + 0, + 0, + convert_Grayscale8_to_Indexed8_inplace, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, 0 + } // Format_Grayscale8 }; void qInitImageConversions() diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h index a22e207812..eb80f97c68 100644 --- a/src/gui/image/qimage_p.h +++ b/src/gui/image/qimage_p.h @@ -136,6 +136,8 @@ inline int qt_depthForFormat(QImage::Format format) depth = 1; break; case QImage::Format_Indexed8: + case QImage::Format_Alpha8: + case QImage::Format_Grayscale8: depth = 8; break; case QImage::Format_RGB32: diff --git a/src/gui/image/qjpeghandler.cpp b/src/gui/image/qjpeghandler.cpp index c1d3ff9a85..72ea24c4f8 100644 --- a/src/gui/image/qjpeghandler.cpp +++ b/src/gui/image/qjpeghandler.cpp @@ -228,7 +228,7 @@ inline static bool read_jpeg_format(QImage::Format &format, j_decompress_ptr cin bool result = true; switch (cinfo->output_components) { case 1: - format = QImage::Format_Indexed8; + format = QImage::Format_Grayscale8; break; case 3: case 4: @@ -248,7 +248,7 @@ static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info, QImage::Format format; switch (info->output_components) { case 1: - format = QImage::Format_Indexed8; + format = QImage::Format_Grayscale8; break; case 3: case 4: @@ -258,16 +258,9 @@ static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info, return false; // unsupported format } - if (dest->size() != size || dest->format() != format) { + if (dest->size() != size || dest->format() != format) *dest = QImage(size, format); - if (format == QImage::Format_Indexed8) { - dest->setColorCount(256); - for (int i = 0; i < 256; i++) - dest->setColor(i, qRgb(i,i,i)); - } - } - return !dest->isNull(); } @@ -558,6 +551,9 @@ static bool write_jpeg_image(const QImage &image, QIODevice *device, volatile in bool success = false; const QVector cmap = image.colorTable(); + if (image.format() == QImage::Format_Invalid || image.format() == QImage::Format_Alpha8) + return false; + struct jpeg_compress_struct cinfo; JSAMPROW row_pointer[1]; row_pointer[0] = 0; @@ -581,19 +577,23 @@ static bool write_jpeg_image(const QImage &image, QIODevice *device, volatile in cinfo.image_width = image.width(); cinfo.image_height = image.height(); - bool gray=false; + bool gray = false; switch (image.format()) { case QImage::Format_Mono: case QImage::Format_MonoLSB: case QImage::Format_Indexed8: gray = true; - for (int i = image.colorCount(); gray && i--;) { - gray = gray & (qRed(cmap[i]) == qGreen(cmap[i]) && - qRed(cmap[i]) == qBlue(cmap[i])); + for (int i = image.colorCount(); gray && i; i--) { + gray = gray & qIsGray(cmap[i-1]); } cinfo.input_components = gray ? 1 : 3; cinfo.in_color_space = gray ? JCS_GRAYSCALE : JCS_RGB; break; + case QImage::Format_Grayscale8: + gray = true; + cinfo.input_components = 1; + cinfo.in_color_space = JCS_GRAYSCALE; + break; default: cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; @@ -678,6 +678,9 @@ static bool write_jpeg_image(const QImage &image, QIODevice *device, volatile in } } break; + case QImage::Format_Grayscale8: + memcpy(row, image.constScanLine(cinfo.next_scanline), w); + break; case QImage::Format_RGB888: memcpy(row, image.constScanLine(cinfo.next_scanline), w * 3); break; diff --git a/src/gui/image/qpixmap_raster.cpp b/src/gui/image/qpixmap_raster.cpp index 639650dd89..2161a70464 100644 --- a/src/gui/image/qpixmap_raster.cpp +++ b/src/gui/image/qpixmap_raster.cpp @@ -211,9 +211,14 @@ void QRasterPlatformPixmap::fill(const QColor &color) pixel = qPremultiply(color.rgba()); const QPixelLayout *layout = &qPixelLayouts[image.format()]; layout->convertFromARGB32PM(&pixel, &pixel, 1, layout, 0); - } else { + } else if (image.format() == QImage::Format_Alpha8) { + pixel = qAlpha(color.rgba()); + } else if (image.format() == QImage::Format_Grayscale8) { + pixel = qGray(color.rgba()); + } else + { pixel = 0; - // ### what about 8 bits + // ### what about 8 bit indexed? } image.fill(pixel); diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp index 3ee9e200de..f77b5335f3 100644 --- a/src/gui/image/qpnghandler.cpp +++ b/src/gui/image/qpnghandler.cpp @@ -302,6 +302,15 @@ void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, QSize scal if (QSysInfo::ByteOrder == QSysInfo::BigEndian) png_set_swap_alpha(png_ptr); + png_read_update_info(png_ptr, info_ptr); + } else if (bit_depth == 8 && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { + png_set_expand(png_ptr); + if (image.size() != QSize(width, height) || image.format() != QImage::Format_Grayscale8) { + image = QImage(width, height, QImage::Format_Grayscale8); + if (image.isNull()) + return; + } + png_read_update_info(png_ptr, info_ptr); } else { if (bit_depth == 16) @@ -674,6 +683,8 @@ QImage::Format QPngHandlerPrivate::readImageFormat() format = QImage::Format_Mono; } else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { format = QImage::Format_ARGB32; + } else if (bit_depth == 8 && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { + format = QImage::Format_Grayscale8; } else { format = QImage::Format_Indexed8; } @@ -865,6 +876,8 @@ bool Q_INTERNAL_WIN_NO_THROW QPNGImageWriter::writeImage(const QImage& image, vo else color_type = PNG_COLOR_TYPE_PALETTE; } + else if (image.format() == QImage::Format_Grayscale8) + color_type = PNG_COLOR_TYPE_GRAY; else if (image.hasAlphaChannel()) color_type = PNG_COLOR_TYPE_RGB_ALPHA; else @@ -963,6 +976,7 @@ bool Q_INTERNAL_WIN_NO_THROW QPNGImageWriter::writeImage(const QImage& image, vo case QImage::Format_Mono: case QImage::Format_MonoLSB: case QImage::Format_Indexed8: + case QImage::Format_Grayscale8: case QImage::Format_RGB32: case QImage::Format_ARGB32: case QImage::Format_RGB888: diff --git a/src/gui/image/qppmhandler.cpp b/src/gui/image/qppmhandler.cpp index 64eaf7f19e..7f2ccb84a5 100644 --- a/src/gui/image/qppmhandler.cpp +++ b/src/gui/image/qppmhandler.cpp @@ -130,7 +130,7 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q case '2': // ascii PGM case '5': // raw PGM nbits = 8; - format = QImage::Format_Indexed8; + format = QImage::Format_Grayscale8; break; case '3': // ascii PPM case '6': // raw PPM @@ -208,13 +208,13 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q *p++ = b; } } else if (nbits == 8) { - if (mcc == maxc) { + if (mcc == 255) { while (n--) { *p++ = read_pbm_int(device); } } else { while (n--) { - *p++ = read_pbm_int(device) * maxc / mcc; + *p++ = read_pbm_int(device) * 255 / mcc; } } } else { // 32 bits @@ -241,14 +241,10 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q } } - if (nbits == 1) { // bitmap + if (format == QImage::Format_Mono) { outImage->setColorCount(2); - outImage->setColor(0, qRgb(255,255,255)); // white - outImage->setColor(1, qRgb(0,0,0)); // black - } else if (nbits == 8) { // graymap - outImage->setColorCount(maxc+1); - for (int i=0; i<=maxc; i++) - outImage->setColor(i, qRgb(i*255/maxc,i*255/maxc,i*255/maxc)); + outImage->setColor(0, qRgb(255,255,255)); // white + outImage->setColor(1, qRgb(0,0,0)); // black } return true; @@ -267,6 +263,8 @@ static bool write_pbm_image(QIODevice *out, const QImage &sourceImage, const QBy image = image.convertToFormat(QImage::Format_Mono); } else if (image.depth() == 1) { image = image.convertToFormat(QImage::Format_Indexed8); + } else if (gray) { + image = image.convertToFormat(QImage::Format_Grayscale8); } else { switch (image.format()) { case QImage::Format_RGB16: @@ -335,63 +333,77 @@ static bool write_pbm_image(QIODevice *out, const QImage &sourceImage, const QBy str.append("255\n"); if (out->write(str, str.length()) != str.length()) return false; - QVector color = image.colorTable(); - uint bpl = w*(gray ? 1 : 3); - uchar *buf = new uchar[bpl]; - for (uint y=0; y color = image.colorTable(); + for (uint y=0; ywrite((char*)buf, bpl)) + return false; + } + } else { + for (uint y=0; ywrite((char*)buf, bpl)) + return false; } - if (bpl != (uint)out->write((char*)buf, bpl)) - return false; } delete [] buf; - } break; + } case 32: { - str.insert(1, gray ? '5' : '6'); + str.insert(1, '6'); str.append("255\n"); if (out->write(str, str.length()) != str.length()) return false; - uint bpl = w*(gray ? 1 : 3); + uint bpl = w * 3; uchar *buf = new uchar[bpl]; for (uint y=0; ywrite((char*)buf, bpl)) return false; } delete [] buf; - } break; + } default: return false; @@ -506,11 +518,11 @@ QVariant QPpmHandler::option(ImageOption option) const switch (type) { case '1': // ascii PBM case '4': // raw PBM - format = QImage::Format_Mono; - break; + format = QImage::Format_Mono; + break; case '2': // ascii PGM case '5': // raw PGM - format = QImage::Format_Indexed8; + format = QImage::Format_Grayscale8; break; case '3': // ascii PPM case '6': // raw PPM -- cgit v1.2.3