summaryrefslogtreecommitdiffstats
path: root/src/gui/image/qimage.cpp
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@digia.com>2014-01-03 14:46:07 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-01-08 18:08:47 +0100
commitb28764c641e4fef19d5e800b7537439fb2054914 (patch)
treeec179914c4d94d59490c2a978dbae4b24f353cad /src/gui/image/qimage.cpp
parentaf9910e450ae0374cb4d1479d416469c9f800b73 (diff)
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>
Diffstat (limited to 'src/gui/image/qimage.cpp')
-rw-r--r--src/gui/image/qimage.cpp338
1 files changed, 228 insertions, 110 deletions
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index 61d524841d..27068020cd 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -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,16 +4965,54 @@ QImage QImage::mirrored(bool horizontal, bool vertical) const
\sa {QImage#Image Transformations}{Image Transformations}
*/
-QImage QImage::rgbSwapped() const
+
+inline void rgbSwapped_generic(int width, int height, const QImage *src, QImage *dst, const QPixelLayout* layout)
+{
+ Q_ASSERT(layout->redWidth == layout->blueWidth);
+ FetchPixelsFunc fetch = qFetchPixels[layout->bpp];
+ StorePixelsFunc store = qStorePixels[layout->bpp];
+
+ const uint redBlueMask = (1 << layout->redWidth) - 1;
+ const uint alphaGreenMask = (((1 << layout->alphaWidth) - 1) << layout->alphaShift)
+ | (((1 << layout->greenWidth) - 1) << layout->greenShift);
+
+ const int buffer_size = 2048;
+ uint buffer[buffer_size];
+ for (int i = 0; i < height; ++i) {
+ uchar *q = dst->scanLine(i);
+ const uchar *p = src->constScanLine(i);
+ int x = 0;
+ while (x < width) {
+ int l = qMin(width - x, buffer_size);
+ const uint *ptr = fetch(buffer, p, x, l);
+ for (int j = 0; j < l; ++j) {
+ uint red = (ptr[j] >> layout->redShift) & redBlueMask;
+ uint blue = (ptr[j] >> layout->blueShift) & redBlueMask;
+ buffer[j] = (ptr[j] & alphaGreenMask)
+ | (red << layout->blueShift)
+ | (blue << layout->redShift);
+ }
+ store(q, buffer, x, l);
+ x += l;
+ }
+ }
+}
+
+/*!
+ \internal
+*/
+QImage QImage::rgbSwapped_helper() const
{
if (isNull())
return *this;
+
QImage res;
+
switch (d->format) {
case Format_Invalid:
case NImageFormats:
Q_ASSERT(false);
- return res;
+ break;
case Format_Mono:
case Format_MonoLSB:
case Format_Indexed8:
@@ -4933,7 +5021,7 @@ QImage QImage::rgbSwapped() const
QRgb c = res.d->colortable.at(i);
res.d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00));
}
- return res;
+ break;
case Format_RGB32:
case Format_ARGB32:
case Format_ARGB32_Premultiplied:
@@ -4946,15 +5034,16 @@ QImage QImage::rgbSwapped() const
QIMAGE_SANITYCHECK_MEMORY(res);
for (int i = 0; i < d->height; i++) {
uint *q = (uint*)res.scanLine(i);
- uint *p = (uint*)constScanLine(i);
- uint *end = p + d->width;
+ const uint *p = (const uint*)constScanLine(i);
+ const uint *end = p + d->width;
while (p < end) {
- *q = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00);
+ uint c = *p;
+ *q = ((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00);
p++;
q++;
}
}
- return res;
+ break;
case Format_RGB16:
res = QImage(d->width, d->height, d->format);
QIMAGE_SANITYCHECK_MEMORY(res);
@@ -4963,48 +5052,77 @@ QImage QImage::rgbSwapped() const
const ushort *p = (const ushort*)constScanLine(i);
const ushort *end = p + d->width;
while (p < end) {
- *q = ((*p << 11) & 0xf800) | ((*p >> 11) & 0x1f) | (*p & 0x07e0);
+ ushort c = *p;
+ *q = ((c << 11) & 0xf800) | ((c >> 11) & 0x1f) | (c & 0x07e0);
p++;
q++;
}
}
- return res;
+ break;
default:
+ res = QImage(d->width, d->height, d->format);
+ rgbSwapped_generic(d->width, d->height, this, &res, &qPixelLayouts[d->format]);
break;
}
+ return res;
+}
- res = QImage(d->width, d->height, d->format);
- QIMAGE_SANITYCHECK_MEMORY(res);
- const QPixelLayout *layout = &qPixelLayouts[d->format];
- Q_ASSERT(layout->redWidth == layout->blueWidth);
- FetchPixelsFunc fetch = qFetchPixels[layout->bpp];
- StorePixelsFunc store = qStorePixels[layout->bpp];
+/*!
+ \internal
+*/
+void QImage::rgbSwapped_inplace()
+{
+ if (isNull())
+ return;
- const uint redBlueMask = (1 << layout->redWidth) - 1;
- const uint alphaGreenMask = (((1 << layout->alphaWidth) - 1) << layout->alphaShift)
- | (((1 << layout->greenWidth) - 1) << layout->greenShift);
+ detach();
- const int buffer_size = 2048;
- uint buffer[buffer_size];
- for (int i = 0; i < d->height; ++i) {
- uchar *q = res.scanLine(i);
- const uchar *p = constScanLine(i);
- int x = 0;
- while (x < d->width) {
- int l = qMin(d->width - x, buffer_size);
- const uint *ptr = fetch(buffer, p, x, l);
- for (int j = 0; j < l; ++j) {
- uint red = (ptr[j] >> layout->redShift) & redBlueMask;
- uint blue = (ptr[j] >> layout->blueShift) & redBlueMask;
- buffer[j] = (ptr[j] & alphaGreenMask)
- | (red << layout->blueShift)
- | (blue << layout->redShift);
+ switch (d->format) {
+ case Format_Invalid:
+ case NImageFormats:
+ Q_ASSERT(false);
+ break;
+ case Format_Mono:
+ case Format_MonoLSB:
+ case Format_Indexed8:
+ for (int i = 0; i < d->colortable.size(); i++) {
+ QRgb c = d->colortable.at(i);
+ d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00));
+ }
+ break;
+ case Format_RGB32:
+ case Format_ARGB32:
+ case Format_ARGB32_Premultiplied:
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ case Format_RGBX8888:
+ case Format_RGBA8888:
+ case Format_RGBA8888_Premultiplied:
+#endif
+ for (int i = 0; i < d->height; i++) {
+ uint *p = (uint*)scanLine(i);
+ uint *end = p + d->width;
+ while (p < end) {
+ uint c = *p;
+ *p = ((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00);
+ p++;
}
- store(q, buffer, x, l);
- x += l;
}
+ 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;
}
- return res;
}
/*!