summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/image/qimage.cpp113
-rw-r--r--src/gui/image/qimage.h13
-rw-r--r--src/gui/painting/qdrawhelper.cpp21
-rw-r--r--tests/auto/gui/painting/qpainter/tst_qpainter.cpp103
4 files changed, 206 insertions, 44 deletions
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index 224043ca79..b35012d4fe 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -476,6 +476,10 @@ bool QImageData::checkForAlphaPixels() const
\snippet code/src_gui_image_qimage.cpp 1
\endtable
+ For images with more than 8-bit per color-channel. The methods
+ setPixelColor() and pixelColor() can be used to set and get
+ with QColor values.
+
QImage also provide the scanLine() function which returns a
pointer to the pixel data at the scanline with the given index,
and the bits() function which returns a pointer to the first pixel
@@ -2187,9 +2191,10 @@ int QImage::pixelIndex(int x, int y) const
If the \a position is not valid, the results are undefined.
\warning This function is expensive when used for massive pixel
- manipulations.
+ manipulations. Use constBits() or constScanLine() when many
+ pixels needs to be read.
- \sa setPixel(), valid(), {QImage#Pixel Manipulation}{Pixel
+ \sa setPixel(), valid(), constBits(), constScanLine(), {QImage#Pixel Manipulation}{Pixel
Manipulation}
*/
@@ -2239,25 +2244,23 @@ QRgb QImage::pixel(int x, int y) const
return *layout->convertToARGB32PM(&result, ptr, 1, layout, 0);
}
-
/*!
\fn void QImage::setPixel(const QPoint &position, uint index_or_rgb)
Sets the pixel index or color at the given \a position to \a
index_or_rgb.
- If the image's format is either monochrome or 8-bit, the given \a
+ If the image's format is either monochrome or paletted, the given \a
index_or_rgb value must be an index in the image's color table,
otherwise the parameter must be a QRgb value.
If \a position is not a valid coordinate pair in the image, or if
\a index_or_rgb >= colorCount() in the case of monochrome and
- 8-bit images, the result is undefined.
+ paletted images, the result is undefined.
\warning This function is expensive due to the call of the internal
\c{detach()} function called within; if performance is a concern, we
- recommend the use of \l{QImage::}{scanLine()} to access pixel data
- directly.
+ recommend the use of scanLine() or bits() to access pixel data directly.
\sa pixel(), {QImage#Pixel Manipulation}{Pixel Manipulation}
*/
@@ -2345,6 +2348,102 @@ void QImage::setPixel(int x, int y, uint index_or_rgb)
}
/*!
+ \fn QColor QImage::pixelColor(const QPoint &position) const
+ \since 5.6
+
+ Returns the color of the pixel at the given \a position as a QColor.
+
+ If the \a position is not valid, an invalid QColor is returned.
+
+ \warning This function is expensive when used for massive pixel
+ manipulations. Use constBits() or constScanLine() when many
+ pixels needs to be read.
+
+ \sa setPixel(), valid(), constBits(), constScanLine(), {QImage#Pixel Manipulation}{Pixel
+ Manipulation}
+*/
+
+/*!
+ \overload
+ \since 5.6
+
+ Returns the color of the pixel at coordinates (\a x, \a y) as a QColor.
+*/
+QColor QImage::pixelColor(int x, int y) const
+{
+ if (!d || x < 0 || x >= d->width || y < 0 || y >= height()) {
+ qWarning("QImage::pixelColor: coordinate (%d,%d) out of range", x, y);
+ return QColor();
+ }
+
+ const uchar * s = constScanLine(y);
+ switch (d->format) {
+ case Format_BGR30:
+ case Format_A2BGR30_Premultiplied:
+ return QColor(qConvertA2rgb30ToRgb64<PixelOrderBGR>(reinterpret_cast<const quint32 *>(s)[x]));
+ case Format_RGB30:
+ case Format_A2RGB30_Premultiplied:
+ return QColor(qConvertA2rgb30ToRgb64<PixelOrderRGB>(reinterpret_cast<const quint32 *>(s)[x]));
+ default:
+ return QColor(pixel(x, y));
+ }
+}
+
+/*!
+ \fn void QImage::setPixelColor(const QPoint &position, const QColor &color)
+ \since 5.6
+
+ Sets the color at the given \a position to \a color.
+
+ If \a position is not a valid coordinate pair in the image, or
+ the image's format is either monochrome or paletted, the result is undefined.
+
+ \warning This function is expensive due to the call of the internal
+ \c{detach()} function called within; if performance is a concern, we
+ recommend the use of scanLine() or bits() to access pixel data directly.
+
+ \sa pixel(), bits(), scanLine(), {QImage#Pixel Manipulation}{Pixel Manipulation}
+*/
+
+/*!
+ \overload
+ \since 5.6
+
+ Sets the pixel color at (\a x, \a y) to \a color.
+*/
+void QImage::setPixelColor(int x, int y, const QColor &color)
+{
+ if (!d || x < 0 || x >= width() || y < 0 || y >= height() || !color.isValid()) {
+ qWarning("QImage::setPixelColor: coordinate (%d,%d) out of range", x, y);
+ return;
+ }
+ // detach is called from within scanLine
+ uchar * s = scanLine(y);
+ switch (d->format) {
+ case Format_Mono:
+ case Format_MonoLSB:
+ case Format_Indexed8:
+ qWarning("QImage::setPixelColor: called on monochrome or indexed format");
+ return;
+ case Format_BGR30:
+ ((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderBGR>(color.rgba64()) | 0xc0000000;
+ return;
+ case Format_A2BGR30_Premultiplied:
+ ((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderBGR>(color.rgba64());
+ return;
+ case Format_RGB30:
+ ((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderRGB>(color.rgba64()) | 0xc0000000;
+ return;
+ case Format_A2RGB30_Premultiplied:
+ ((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderRGB>(color.rgba64());
+ return;
+ default:
+ setPixel(x, y, color.rgba());
+ return;
+ }
+}
+
+/*!
Returns \c true if all the colors in the image are shades of gray
(i.e. their red, green and blue components are equal); otherwise
false.
diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h
index 4ce99b9ab1..7751bbe3d3 100644
--- a/src/gui/image/qimage.h
+++ b/src/gui/image/qimage.h
@@ -34,10 +34,11 @@
#ifndef QIMAGE_H
#define QIMAGE_H
-#include <QtGui/qtransform.h>
-#include <QtGui/qpaintdevice.h>
+#include <QtGui/qcolor.h>
#include <QtGui/qrgb.h>
+#include <QtGui/qpaintdevice.h>
#include <QtGui/qpixelformat.h>
+#include <QtGui/qtransform.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qrect.h>
#include <QtCore/qstring.h>
@@ -219,6 +220,12 @@ public:
void setPixel(int x, int y, uint index_or_rgb);
void setPixel(const QPoint &pt, uint index_or_rgb);
+ QColor pixelColor(int x, int y) const;
+ QColor pixelColor(const QPoint &pt) const;
+
+ void setPixelColor(int x, int y, const QColor &c);
+ void setPixelColor(const QPoint &pt, const QColor &c);
+
QVector<QRgb> colorTable() const;
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
void setColorTable(const QVector<QRgb> &colors);
@@ -350,6 +357,8 @@ inline bool QImage::valid(const QPoint &pt) const { return valid(pt.x(), pt.y())
inline int QImage::pixelIndex(const QPoint &pt) const { return pixelIndex(pt.x(), pt.y());}
inline QRgb QImage::pixel(const QPoint &pt) const { return pixel(pt.x(), pt.y()); }
inline void QImage::setPixel(const QPoint &pt, uint index_or_rgb) { setPixel(pt.x(), pt.y(), index_or_rgb); }
+inline QColor QImage::pixelColor(const QPoint &pt) const { return pixelColor(pt.x(), pt.y()); }
+inline void QImage::setPixelColor(const QPoint &pt, const QColor &c) { setPixelColor(pt.x(), pt.y(), c); }
#if QT_DEPRECATED_SINCE(5, 0)
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index b6f06135cd..b2992a138e 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -4698,10 +4698,8 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
}
++spans;
}
- if (!alphaSpans) {
+ if (!alphaSpans)
op.destFetch = 0;
- op.destFetch64 = 0;
- }
}
}
}
@@ -4795,10 +4793,9 @@ void blend_color_generic_rgb64(int count, const QSpan *spans, void *userData)
int length = spans->len;
while (length) {
int l = qMin(buffer_size, length);
- QRgba64 *dest = op.destFetch64 ? op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
+ QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l);
op.funcSolid64(dest, l, color, spans->coverage);
- if (op.destStore64)
- op.destStore64(data->rasterBuffer, x, spans->y, dest, l);
+ op.destStore64(data->rasterBuffer, x, spans->y, dest, l);
length -= l;
x += l;
}
@@ -4987,7 +4984,7 @@ public:
bool isSupported() const
{
- return op.srcFetch64 && op.func64;
+ return op.srcFetch64 && op.func64 && op.destFetch64 && op.destStore64;
}
const QRgba64 *fetch(int x, int y, int len)
@@ -5108,10 +5105,9 @@ static void blend_untransformed_generic_rgb64(int count, const QSpan *spans, voi
while (length) {
int l = qMin(buffer_size, length);
const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, l);
- QRgba64 *dest = op.destFetch64 ? op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
+ QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l);
op.func64(dest, src, l, coverage);
- if (op.destStore64)
- op.destStore64(data->rasterBuffer, x, spans->y, dest, l);
+ op.destStore64(data->rasterBuffer, x, spans->y, dest, l);
x += l;
sx += l;
length -= l;
@@ -5353,10 +5349,9 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD
if (buffer_size < l)
l = buffer_size;
const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, l);
- QRgba64 *dest = op.destFetch64 ? op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
+ QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l);
op.func64(dest, src, l, coverage);
- if (op.destStore64)
- op.destStore64(data->rasterBuffer, x, spans->y, dest, l);
+ op.destStore64(data->rasterBuffer, x, spans->y, dest, l);
x += l;
sx += l;
length -= l;
diff --git a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp
index 10b79fdd0f..3c5fcba06e 100644
--- a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp
+++ b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp
@@ -203,6 +203,9 @@ private slots:
void gradientPixelFormat_data();
void gradientPixelFormat();
+ void gradientRgb30_data();
+ void gradientRgb30();
+
void fpe_pixmapTransform();
void fpe_zeroLengthLines();
void fpe_divByZero();
@@ -2451,36 +2454,50 @@ void tst_QPainter::setOpacity_data()
QTest::newRow("RGBx8888 on RGBx8888") << QImage::Format_RGBX8888
<< QImage::Format_RGBX8888;
- QTest::newRow("RGBA8888P on ARGB32P") << QImage::Format_RGBA8888_Premultiplied
+ QTest::newRow("RGBA8888P on ARGB32P") << QImage::Format_ARGB32_Premultiplied
+ << QImage::Format_RGBA8888_Premultiplied;
+
+ QTest::newRow("RGBx8888 on ARGB32P") << QImage::Format_ARGB32_Premultiplied
+ << QImage::Format_RGBX8888;
+
+ QTest::newRow("ARGB32P on RGBA8888P") << QImage::Format_RGBA8888_Premultiplied
<< QImage::Format_ARGB32_Premultiplied;
- QTest::newRow("RGBx8888 on ARGB32P") << QImage::Format_RGBX8888
- << QImage::Format_ARGB32_Premultiplied;
+ QTest::newRow("RGB32 on RGBx8888") << QImage::Format_RGBX8888
+ << QImage::Format_RGB32;
- QTest::newRow("ARGB32P on RGBA8888P") << QImage::Format_ARGB32_Premultiplied
- << QImage::Format_RGBA8888_Premultiplied;
+ QTest::newRow("RGB30 on RGB32") << QImage::Format_RGB32
+ << QImage::Format_BGR30;
+
+ QTest::newRow("BGR30 on ARGB32P") << QImage::Format_ARGB32_Premultiplied
+ << QImage::Format_BGR30;
- QTest::newRow("RGB32 on RGBx8888") << QImage::Format_RGB32
- << QImage::Format_RGBX8888;
+ QTest::newRow("A2RGB30P on ARGB32P") << QImage::Format_ARGB32_Premultiplied
+ << QImage::Format_A2BGR30_Premultiplied;
QTest::newRow("A2RGB30P on A2RGB30P") << QImage::Format_A2RGB30_Premultiplied
<< QImage::Format_A2RGB30_Premultiplied;
- QTest::newRow("ARGB32P on A2RGB30P") << QImage::Format_ARGB32_Premultiplied
- << QImage::Format_A2RGB30_Premultiplied;
+ QTest::newRow("ARGB32P on A2RGB30P") << QImage::Format_A2RGB30_Premultiplied
+ << QImage::Format_ARGB32_Premultiplied;
+ QTest::newRow("RGB32 on A2BGR30P") << QImage::Format_A2BGR30_Premultiplied
+ << QImage::Format_RGB32;
- QTest::newRow("RGB32 on A2BGR30P") << QImage::Format_ARGB32_Premultiplied
- << QImage::Format_A2BGR30_Premultiplied;
+ QTest::newRow("RGB30 on A2BGR30P") << QImage::Format_A2BGR30_Premultiplied
+ << QImage::Format_RGB30;
- QTest::newRow("A2RGB30P on A2BGR30P") << QImage::Format_A2RGB30_Premultiplied
- << QImage::Format_A2BGR30_Premultiplied;
+ QTest::newRow("A2RGB30P on A2BGR30P") << QImage::Format_A2BGR30_Premultiplied
+ << QImage::Format_A2RGB30_Premultiplied;
- QTest::newRow("ARGB32P on BGR30") << QImage::Format_ARGB32_Premultiplied
- << QImage::Format_BGR30;
+ QTest::newRow("ARGB32P on BGR30") << QImage::Format_BGR30
+ << QImage::Format_ARGB32_Premultiplied;
- QTest::newRow("ARGB32P on RGB30") << QImage::Format_A2RGB30_Premultiplied
- << QImage::Format_RGB30;
+ QTest::newRow("ARGB32P on RGB30") << QImage::Format_RGB30
+ << QImage::Format_ARGB32_Premultiplied;
+
+ QTest::newRow("A2RGB30P on RGB30") << QImage::Format_RGB30
+ << QImage::Format_A2RGB30_Premultiplied;
}
@@ -2562,7 +2579,7 @@ void tst_QPainter::drawhelper_blend_untransformed()
QImage expected(size - 2, size, destFormat);
p.begin(&expected);
p.fillRect(0, 0, expected.width(), expected.height(),
- QColor(dest.pixel(1, 0)));
+ dest.pixelColor(1, 0));
p.end();
const QImage subDest(dest.bits() + dest.depth() / 8,
@@ -2570,9 +2587,7 @@ void tst_QPainter::drawhelper_blend_untransformed()
dest.bytesPerLine(), dest.format());
if (dest.format() == QImage::Format_ARGB8565_Premultiplied ||
- dest.format() == QImage::Format_ARGB8555_Premultiplied ||
- dest.format() == QImage::Format_A2BGR30_Premultiplied ||
- dest.format() == QImage::Format_A2RGB30_Premultiplied ) {
+ dest.format() == QImage::Format_ARGB8555_Premultiplied) {
// Test skipped due to rounding errors...
continue;
}
@@ -2621,7 +2636,7 @@ void tst_QPainter::drawhelper_blend_tiled_untransformed()
QImage expected(size - 2, size, destFormat);
p.begin(&expected);
p.fillRect(0, 0, expected.width(), expected.height(),
- QColor(dest.pixel(1, 0)));
+ dest.pixelColor(1, 0));
p.end();
const QImage subDest(dest.bits() + dest.depth() / 8,
@@ -3937,6 +3952,38 @@ void tst_QPainter::gradientInterpolation()
}
}
+void tst_QPainter::gradientRgb30_data()
+{
+ QTest::addColumn<QColor>("stop0");
+ QTest::addColumn<QColor>("stop1");
+
+ QTest::newRow("white->black") << QColor(Qt::white) << QColor(Qt::black);
+ QTest::newRow("blue->black") << QColor(Qt::blue) << QColor(Qt::black);
+ QTest::newRow("white->red") << QColor(Qt::white) << QColor(Qt::red);
+}
+
+void tst_QPainter::gradientRgb30()
+{
+ QFETCH(QColor, stop0);
+ QFETCH(QColor, stop1);
+
+ QLinearGradient gradient(0, 0, 512, 1);
+ gradient.setColorAt(0.0, stop0);
+ gradient.setColorAt(1.0, stop1);
+
+ QImage image(512, 1, QImage::Format_RGB30);
+ QPainter painter(&image);
+ painter.fillRect(image.rect(), gradient);
+ painter.end();
+
+ for (int i = 0; i < 511; ++i) {
+ QColor p1 = image.pixelColor(i, 0);
+ QColor p2 = image.pixelColor(i + 1, 0);
+ QVERIFY(p1 != p2);
+ QVERIFY(qGray(p1.rgb()) >= qGray(p2.rgb()));
+ }
+}
+
void tst_QPainter::drawPolygon()
{
QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
@@ -4800,6 +4847,18 @@ void tst_QPainter::blendARGBonRGB_data()
<< QPainter::CompositionMode_SourceIn << qRgba(255, 0, 0, 127) << 125;
QTest::newRow("ARGB_PM source-in RGB666") << QImage::Format_RGB666 << QImage::Format_ARGB32_Premultiplied
<< QPainter::CompositionMode_SourceIn << qRgba(127, 0, 0, 127) << 125;
+ QTest::newRow("ARGB over RGB30") << QImage::Format_RGB30 << QImage::Format_ARGB32
+ << QPainter::CompositionMode_SourceOver << qRgba(255, 0, 0, 127) << 127;
+ QTest::newRow("ARGB_PM over RGB30") << QImage::Format_RGB30 << QImage::Format_ARGB32_Premultiplied
+ << QPainter::CompositionMode_SourceOver << qRgba(127, 0, 0, 127) << 127;
+ QTest::newRow("ARGB source RGB30") << QImage::Format_RGB30 << QImage::Format_ARGB32
+ << QPainter::CompositionMode_Source << qRgba(255, 0, 0, 127) << 127;
+ QTest::newRow("ARGB_PM source RGB30") << QImage::Format_RGB30 << QImage::Format_ARGB32_Premultiplied
+ << QPainter::CompositionMode_Source << qRgba(127, 0, 0, 127) << 127;
+ QTest::newRow("ARGB source-in RGB30") << QImage::Format_RGB30 << QImage::Format_ARGB32
+ << QPainter::CompositionMode_SourceIn << qRgba(255, 0, 0, 127) << 127;
+ QTest::newRow("ARGB_PM source-in RGB30") << QImage::Format_RGB30 << QImage::Format_ARGB32_Premultiplied
+ << QPainter::CompositionMode_SourceIn << qRgba(127, 0, 0, 127) << 127;
}
void tst_QPainter::blendARGBonRGB()