Inplace versions of QImage rgbSwapped() and mirrored() for rvalue refs

Adds inplace version of QImage::rgbSwapped() and QImage::mirrored() that
can be used on temporary QImage objects when supported by the compiler.

[ChangeLog][QtGui][QImage]Rvalue qualified mirrored and rgbSwapped methods for inline conversions
Change-Id: I4ffb658bf620dfc472d9db14c1aa70291c1fd842
Reviewed-by: Gunnar Sletta <gunnar.sletta@jollamobile.com>
This commit is contained in:
Allan Sandfeld Jensen 2014-01-03 14:46:07 +01:00 committed by The Qt Project
parent af9910e450
commit b28764c641
6 changed files with 589 additions and 139 deletions

View File

@ -54,6 +54,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 \

View File

@ -1105,8 +1105,7 @@ void QImage::detach()
if (d->ref.load() != 1 || d->ro_data)
*this = copy();
if (d)
++d->detach_no;
++d->detach_no;
}
}
@ -4791,6 +4790,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.
@ -4799,7 +4799,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 = bitflip[*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();
@ -4821,92 +4883,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.
@ -4915,67 +4965,9 @@ QImage QImage::mirrored(bool horizontal, bool vertical) const
\sa {QImage#Image Transformations}{Image Transformations}
*/
QImage QImage::rgbSwapped() const
{
if (isNull())
return *this;
QImage res;
switch (d->format) {
case Format_Invalid:
case NImageFormats:
Q_ASSERT(false);
return res;
case Format_Mono:
case Format_MonoLSB:
case Format_Indexed8:
res = copy();
for (int i = 0; i < res.d->colortable.size(); i++) {
QRgb c = res.d->colortable.at(i);
res.d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00));
}
return res;
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
res = QImage(d->width, d->height, d->format);
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;
while (p < end) {
*q = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00);
p++;
q++;
}
}
return res;
case Format_RGB16:
res = QImage(d->width, d->height, d->format);
QIMAGE_SANITYCHECK_MEMORY(res);
for (int i = 0; i < d->height; i++) {
ushort *q = (ushort*)res.scanLine(i);
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);
p++;
q++;
}
}
return res;
default:
break;
}
res = QImage(d->width, d->height, d->format);
QIMAGE_SANITYCHECK_MEMORY(res);
const QPixelLayout *layout = &qPixelLayouts[d->format];
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];
@ -4986,12 +4978,12 @@ QImage QImage::rgbSwapped() const
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);
for (int i = 0; i < height; ++i) {
uchar *q = dst->scanLine(i);
const uchar *p = src->constScanLine(i);
int x = 0;
while (x < d->width) {
int l = qMin(d->width - x, buffer_size);
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;
@ -5004,9 +4996,135 @@ QImage QImage::rgbSwapped() const
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);
break;
case Format_Mono:
case Format_MonoLSB:
case Format_Indexed8:
res = copy();
for (int i = 0; i < res.d->colortable.size(); i++) {
QRgb c = res.d->colortable.at(i);
res.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
res = QImage(d->width, d->height, d->format);
QIMAGE_SANITYCHECK_MEMORY(res);
for (int i = 0; i < d->height; i++) {
uint *q = (uint*)res.scanLine(i);
const uint *p = (const uint*)constScanLine(i);
const uint *end = p + d->width;
while (p < end) {
uint c = *p;
*q = ((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00);
p++;
q++;
}
}
break;
case Format_RGB16:
res = QImage(d->width, d->height, d->format);
QIMAGE_SANITYCHECK_MEMORY(res);
for (int i = 0; i < d->height; i++) {
ushort *q = (ushort*)res.scanLine(i);
const ushort *p = (const ushort*)constScanLine(i);
const ushort *end = p + d->width;
while (p < end) {
ushort c = *p;
*q = ((c << 11) & 0xf800) | ((c >> 11) & 0x1f) | (c & 0x07e0);
p++;
q++;
}
}
break;
default:
res = QImage(d->width, d->height, d->format);
rgbSwapped_generic(d->width, d->height, this, &res, &qPixelLayouts[d->format]);
break;
}
return res;
}
/*!
\internal
*/
void QImage::rgbSwapped_inplace()
{
if (isNull())
return;
detach();
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++;
}
}
break;
default:
rgbSwapped_generic(d->width, d->height, this, this, &qPixelLayouts[d->format]);
break;
}
}
/*!
Loads an image from the file with the given \a fileName. Returns \c true if
the image was successfully loaded; otherwise invalidates the image

View File

@ -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;

View File

@ -0,0 +1,62 @@
/****************************************************************************
**
** 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.
**
** $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$
**
****************************************************************************/
#ifdef QIMAGE_H
# error "This file cannot be used with precompiled headers"
#endif
#define QT_COMPILING_QIMAGE_COMPAT_CPP
#include "qimage.h"
QT_BEGIN_NAMESPACE
// 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);
}
QImage QImage::rgbSwapped() const
{
return rgbSwapped_helper();
}
QT_END_NAMESPACE

View File

@ -4,5 +4,6 @@ TARGET = tst_qimage
SOURCES += tst_qimage.cpp
QT += core-private gui-private testlib
contains(QT_CONFIG, c++11): CONFIG += c++11
TESTDATA += images/*

View File

@ -149,6 +149,17 @@ private slots:
void rgbSwapped_data();
void rgbSwapped();
void mirrored_data();
void mirrored();
void inplaceRgbSwapped_data();
void inplaceRgbSwapped();
void inplaceMirrored_data();
void inplaceMirrored();
void inplaceDoubleConversion();
void deepCopyWhenPaintingActive();
void scaled_QTBUG19157();
@ -2106,6 +2117,246 @@ void tst_QImage::rgbSwapped()
QCOMPARE(memcmp(image.constBits(), imageSwappedTwice.constBits(), image.byteCount()), 0);
}
void tst_QImage::mirrored_data()
{
QTest::addColumn<QImage::Format>("format");
QTest::addColumn<bool>("swap_vertical");
QTest::addColumn<bool>("swap_horizontal");
QTest::newRow("Format_RGB32, vertical") << QImage::Format_RGB32 << true << false;
QTest::newRow("Format_ARGB32, vertical") << QImage::Format_ARGB32 << true << false;
QTest::newRow("Format_ARGB32_Premultiplied, vertical") << QImage::Format_ARGB32_Premultiplied << true << false;
QTest::newRow("Format_RGB16, vertical") << QImage::Format_RGB16 << true << false;
QTest::newRow("Format_ARGB8565_Premultiplied, vertical") << QImage::Format_ARGB8565_Premultiplied << true << false;
QTest::newRow("Format_ARGB6666_Premultiplied, vertical") << QImage::Format_ARGB6666_Premultiplied << true << false;
QTest::newRow("Format_ARGB4444_Premultiplied, vertical") << QImage::Format_ARGB4444_Premultiplied << true << false;
QTest::newRow("Format_RGB666, vertical") << QImage::Format_RGB666 << true << false;
QTest::newRow("Format_RGB555, vertical") << QImage::Format_RGB555 << true << false;
QTest::newRow("Format_ARGB8555_Premultiplied, vertical") << QImage::Format_ARGB8555_Premultiplied << true << false;
QTest::newRow("Format_RGB888, vertical") << QImage::Format_RGB888 << true << false;
QTest::newRow("Format_RGB444, vertical") << QImage::Format_RGB444 << true << false;
QTest::newRow("Format_RGBX8888, vertical") << QImage::Format_RGBX8888 << true << false;
QTest::newRow("Format_RGBA8888_Premultiplied, vertical") << QImage::Format_RGBA8888_Premultiplied << true << false;
QTest::newRow("Format_Indexed8, vertical") << QImage::Format_Indexed8 << true << false;
QTest::newRow("Format_Mono, vertical") << QImage::Format_Mono << true << false;
QTest::newRow("Format_ARGB32_Premultiplied, horizontal") << QImage::Format_ARGB32_Premultiplied << false << true;
QTest::newRow("Format_RGB888, horizontal") << QImage::Format_RGB888 << false << true;
QTest::newRow("Format_RGB16, horizontal") << QImage::Format_RGB16 << false << true;
QTest::newRow("Format_Indexed8, horizontal") << QImage::Format_Indexed8 << false << true;
QTest::newRow("Format_Mono, horizontal") << QImage::Format_Mono << false << true;
QTest::newRow("Format_ARGB32_Premultiplied, horizontal+vertical") << QImage::Format_ARGB32_Premultiplied << true << true;
QTest::newRow("Format_RGB888, horizontal+vertical") << QImage::Format_RGB888 << true << true;
QTest::newRow("Format_RGB16, horizontal+vertical") << QImage::Format_RGB16 << true << true;
QTest::newRow("Format_Indexed8, horizontal+vertical") << QImage::Format_Indexed8 << true << true;
QTest::newRow("Format_Mono, horizontal+vertical") << QImage::Format_Mono << true << true;
}
void tst_QImage::mirrored()
{
QFETCH(QImage::Format, format);
QFETCH(bool, swap_vertical);
QFETCH(bool, swap_horizontal);
QImage image(16, 16, format);
switch (format) {
case QImage::Format_Mono:
for (int i = 0; i < image.height(); ++i) {
ushort* scanLine = (ushort*)image.scanLine(i);
*scanLine = (i % 2) ? 0x5555U : 0xCCCCU;
}
break;
case QImage::Format_Indexed8:
for (int i = 0; i < image.height(); ++i) {
for (int j = 0; j < image.width(); ++j) {
image.setColor(i*16+j, qRgb(j*16, i*16, 0));
image.setPixel(j, i, i*16+j);
}
}
break;
default:
for (int i = 0; i < image.height(); ++i)
for (int j = 0; j < image.width(); ++j)
image.setPixel(j, i, qRgb(j*16, i*16, 0));
break;
}
QImage imageMirrored = image.mirrored(swap_horizontal, swap_vertical);
for (int i = 0; i < image.height(); ++i) {
int mirroredI = swap_vertical ? (image.height() - i - 1) : i;
for (int j = 0; j < image.width(); ++j) {
QRgb referenceColor = image.pixel(j, i);
int mirroredJ = swap_horizontal ? (image.width() - j - 1) : j;
QRgb mirroredColor = imageMirrored.pixel(mirroredJ, mirroredI);
QCOMPARE(mirroredColor, referenceColor);
}
}
QImage imageMirroredTwice = imageMirrored.mirrored(swap_horizontal, swap_vertical);
QCOMPARE(image, imageMirroredTwice);
if (format != QImage::Format_Mono)
QCOMPARE(memcmp(image.constBits(), imageMirroredTwice.constBits(), image.byteCount()), 0);
else {
for (int i = 0; i < image.height(); ++i)
for (int j = 0; j < image.width(); ++j)
QCOMPARE(image.pixel(j,i), imageMirroredTwice.pixel(j,i));
}
}
void tst_QImage::inplaceRgbSwapped_data()
{
QTest::addColumn<QImage::Format>("format");
QTest::newRow("Format_ARGB32_Premultiplied") << QImage::Format_ARGB32_Premultiplied;
QTest::newRow("Format_RGBA8888") << QImage::Format_RGBA8888;
QTest::newRow("Format_RGB888") << QImage::Format_RGB888;
QTest::newRow("Format_RGB16") << QImage::Format_RGB16;
QTest::newRow("Format_Indexed8") << QImage::Format_Indexed8;
}
void tst_QImage::inplaceRgbSwapped()
{
#if defined(Q_COMPILER_REF_QUALIFIERS)
QFETCH(QImage::Format, format);
QImage image(64, 1, format);
image.fill(0);
QVector<QRgb> testColor(image.width());
for (int i = 0; i < image.width(); ++i)
testColor[i] = qRgb(i * 2, i * 3, 255 - i * 4);
if (format == QImage::Format_Indexed8) {
for (int i = 0; i < image.width(); ++i) {
image.setColor(i, testColor[i]);
image.setPixel(i, 0, i);
}
} else {
for (int i = 0; i < image.width(); ++i)
image.setPixel(i, 0, testColor[i]);
}
const uchar* orginalPtr = image.constScanLine(0);
QImage imageSwapped = std::move(image).rgbSwapped();
for (int i = 0; i < imageSwapped.width(); ++i) {
QRgb referenceColor = testColor[i];
QRgb swappedColor = imageSwapped.pixel(i, 0);
QCOMPARE(qRed(swappedColor) & 0xf8, qBlue(referenceColor) & 0xf8);
QCOMPARE(qGreen(swappedColor) & 0xf8, qGreen(referenceColor) & 0xf8);
QCOMPARE(qBlue(swappedColor) & 0xf8, qRed(referenceColor) & 0xf8);
}
QCOMPARE(imageSwapped.constScanLine(0), orginalPtr);
#endif
}
void tst_QImage::inplaceMirrored_data()
{
QTest::addColumn<QImage::Format>("format");
QTest::addColumn<bool>("swap_vertical");
QTest::addColumn<bool>("swap_horizontal");
QTest::newRow("Format_ARGB32, vertical") << QImage::Format_ARGB32 << true << false;
QTest::newRow("Format_RGB888, vertical") << QImage::Format_RGB888 << true << false;
QTest::newRow("Format_RGB16, vertical") << QImage::Format_RGB16 << true << false;
QTest::newRow("Format_Indexed8, vertical") << QImage::Format_Indexed8 << true << false;
QTest::newRow("Format_Mono, vertical") << QImage::Format_Mono << true << false;
QTest::newRow("Format_ARGB32, horizontal") << QImage::Format_ARGB32 << false << true;
QTest::newRow("Format_RGB888, horizontal") << QImage::Format_RGB888 << false << true;
QTest::newRow("Format_RGB16, horizontal") << QImage::Format_RGB16 << false << true;
QTest::newRow("Format_Indexed8, horizontal") << QImage::Format_Indexed8 << false << true;
QTest::newRow("Format_Mono, horizontal") << QImage::Format_Mono << false << true;
QTest::newRow("Format_ARGB32, horizontal+vertical") << QImage::Format_ARGB32 << true << true;
QTest::newRow("Format_RGB888, horizontal+vertical") << QImage::Format_RGB888 << true << true;
QTest::newRow("Format_RGB16, horizontal+vertical") << QImage::Format_RGB16 << true << true;
QTest::newRow("Format_Indexed8, horizontal+vertical") << QImage::Format_Indexed8 << true << true;
QTest::newRow("Format_Mono, horizontal+vertical") << QImage::Format_Mono << true << true;
}
void tst_QImage::inplaceMirrored()
{
#if defined(Q_COMPILER_REF_QUALIFIERS)
QFETCH(QImage::Format, format);
QFETCH(bool, swap_vertical);
QFETCH(bool, swap_horizontal);
QImage image(16, 16, format);
switch (format) {
case QImage::Format_Mono:
for (int i = 0; i < image.height(); ++i) {
ushort* scanLine = (ushort*)image.scanLine(i);
*scanLine = (i % 2) ? 0x0fffU : 0xf000U;
}
break;
case QImage::Format_Indexed8:
for (int i = 0; i < image.height(); ++i) {
for (int j = 0; j < image.width(); ++j) {
image.setColor(i*16+j, qRgb(j*16, i*16, 0));
image.setPixel(j, i, i*16+j);
}
}
break;
default:
for (int i = 0; i < image.height(); ++i)
for (int j = 0; j < image.width(); ++j)
image.setPixel(j, i, qRgb(j*16, i*16, 0));
}
const uchar* originalPtr = image.constScanLine(0);
QImage imageMirrored = std::move(image).mirrored(swap_horizontal, swap_vertical);
if (format != QImage::Format_Mono) {
for (int i = 0; i < imageMirrored.height(); ++i) {
int mirroredI = swap_vertical ? (imageMirrored.height() - i - 1) : i;
for (int j = 0; j < imageMirrored.width(); ++j) {
int mirroredJ = swap_horizontal ? (imageMirrored.width() - j - 1) : j;
QRgb mirroredColor = imageMirrored.pixel(mirroredJ, mirroredI);
QCOMPARE(qRed(mirroredColor) & 0xF8, j * 16);
QCOMPARE(qGreen(mirroredColor) & 0xF8, i * 16);
}
}
} else {
for (int i = 0; i < imageMirrored.height(); ++i) {
ushort* scanLine = (ushort*)imageMirrored.scanLine(i);
ushort expect;
if (swap_vertical && swap_horizontal)
expect = (i % 2) ? 0x000fU : 0xfff0U;
else if (swap_vertical)
expect = (i % 2) ? 0xf000U : 0x0fffU;
else
expect = (i % 2) ? 0xfff0U : 0x000fU;
QCOMPARE(*scanLine, expect);
}
}
QCOMPARE(imageMirrored.constScanLine(0), originalPtr);
#endif
}
void tst_QImage::inplaceDoubleConversion()
{
#if defined(Q_COMPILER_REF_QUALIFIERS)
QImage image1(32, 32, QImage::Format_ARGB32);
QImage image2(32, 32, QImage::Format_ARGB32);
image1.fill(0);
image2.fill(0);
const uchar* originalPtr1 = image1.constScanLine(0);
const uchar* originalPtr2 = image2.constScanLine(0);
QCOMPARE(std::move(image1).rgbSwapped().mirrored().constScanLine(0), originalPtr1);
QCOMPARE(std::move(image2).mirrored().rgbSwapped().constScanLine(0), originalPtr2);
#endif
}
void tst_QImage::deepCopyWhenPaintingActive()
{
QImage image(64, 64, QImage::Format_ARGB32_Premultiplied);