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:
parent
af9910e450
commit
b28764c641
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
62
src/gui/image/qimage_compat.cpp
Normal file
62
src/gui/image/qimage_compat.cpp
Normal 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
|
@ -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/*
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user