1.scaled()
QImage scaled(int w, int h, Qt::AspectRatioMode aspectMode = Qt::IgnoreAspectRatio,
Qt::TransformationMode mode = Qt::FastTransformation) const
{ return scaled(QSize(w, h), aspectMode, mode); }
/*!
\fn QImage QImage::scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode,
Qt::TransformationMode transformMode) const
Returns a copy of the image scaled to a rectangle defined by the
given \a size according to the given \a aspectRatioMode and \a
transformMode.
\image qimage-scaling.png
\list
\li If \a aspectRatioMode is Qt::IgnoreAspectRatio, the image
is scaled to \a size.
\li If \a aspectRatioMode is Qt::KeepAspectRatio, the image is
scaled to a rectangle as large as possible inside \a size, preserving the aspect ratio.
\li If \a aspectRatioMode is Qt::KeepAspectRatioByExpanding,
the image is scaled to a rectangle as small as possible
outside \a size, preserving the aspect ratio.
\endlist
If the given \a size is empty, this function returns a null image.
\sa isNull(), {QImage#Image Transformations}{Image
Transformations}
*/
QImage QImage::scaled(const QSize& s, Qt::AspectRatioMode aspectMode, Qt::TransformationMode mode) const
{
if (!d) {
qWarning("QImage::scaled: Image is a null image");
return QImage();
}
if (s.isEmpty())
return QImage();
QSize newSize = size();
newSize.scale(s, aspectMode);
newSize.rwidth() = qMax(newSize.width(), 1);
newSize.rheight() = qMax(newSize.height(), 1);
if (newSize == size())
return *this;
Q_TRACE_SCOPE(QImage_scaled, s, aspectMode, mode);
QTransform wm = QTransform::fromScale((qreal)newSize.width() / width(), (qreal)newSize.height() / height());
QImage img = transformed(wm, mode);
return img;
}
/*!
Returns a copy of the image that is transformed using the given
transformation \a matrix and transformation \a mode.
The returned image will normally have the same {Image Formats}{format} as
the original image. However, a complex transformation may result in an
image where not all pixels are covered by the transformed pixels of the
original image. In such cases, those background pixels will be assigned a
transparent color value, and the transformed image will be given a format
with an alpha channel, even if the orginal image did not have that.
The transformation \a matrix is internally adjusted to compensate
for unwanted translation; i.e. the image produced is the smallest
image that contains all the transformed points of the original
image. Use the trueMatrix() function to retrieve the actual matrix
used for transforming an image.
Unlike the other overload, this function can be used to perform perspective
transformations on images.
\sa trueMatrix(), {QImage#Image Transformations}{Image
Transformations}
*/
QImage QImage::transformed(const QTransform &matrix, Qt::TransformationMode mode ) const
{
if (!d)
return QImage();
Q_TRACE_SCOPE(QImage_transformed, matrix, mode);
// source image data
const int ws = width();
const int hs = height();
// target image data
int wd;
int hd;
// compute size of target image
QTransform mat = trueMatrix(matrix, ws, hs);
bool complex_xform = false;
bool scale_xform = false;
bool nonpaintable_scale_xform = false;
if (mat.type() <= QTransform::TxScale) {
if (mat.type() == QTransform::TxNone) // identity matrix
return *this;
else if (mat.m11() == -1. && mat.m22() == -1.)
return rotated180(*this);
if (mode == Qt::FastTransformation) {
hd = qRound(qAbs(mat.m22()) * hs);
wd = qRound(qAbs(mat.m11()) * ws);
} else {
hd = int(qAbs(mat.m22()) * hs + 0.9999);
wd = int(qAbs(mat.m11()) * ws + 0.9999);
}
scale_xform = true;
// The paint-based scaling is only bilinear, and has problems
// with scaling smoothly more than 2x down.
if (hd * 2 < hs || wd * 2 < ws)
nonpaintable_scale_xform = true;
} else {
if (mat.type() <= QTransform::TxRotate && mat.m11() == 0 && mat.m22() == 0) {
if (mat.m12() == 1. && mat.m21() == -1.)
return rotated90(*this);
else if (mat.m12() == -1. && mat.m21() == 1.)
return rotated270(*this);
}
QPolygonF a(QRectF(0, 0, ws, hs));
a = mat.map(a);
QRect r = a.boundingRect().toAlignedRect();
wd = r.width();
hd = r.height();
complex_xform = true;
}
if (wd == 0 || hd == 0)
return QImage();
if (scale_xform && mode == Qt::SmoothTransformation) {
switch (format()) {
case QImage::Format_RGB32:
case QImage::Format_ARGB32_Premultiplied:
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
case QImage::Format_RGBX8888:
#endif
case QImage::Format_RGBA8888_Premultiplied:
#if QT_CONFIG(raster_64bit)
case QImage::Format_RGBX64:
case QImage::Format_RGBA64_Premultiplied:
#endif
// Use smoothScaled for scaling when we can do so without conversion.
if (mat.m11() > 0.0F && mat.m22() > 0.0F)
return smoothScaled(wd, hd);
break;
default:
break;
}
// Otherwise only use it when the scaling factor demands it, or the image is large enough to scale multi-threaded
if (nonpaintable_scale_xform
#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
|| (ws * hs) >= (1<<20)
#endif
) {
if (mat.m11() < 0.0F && mat.m22() < 0.0F) { // horizontal/vertical flip
return smoothScaled(wd, hd).mirrored(true, true).convertToFormat(format());
} else if (mat.m11() < 0.0F) { // horizontal flip
return smoothScaled(wd, hd).mirrored(true, false).convertToFormat(format());
} else if (mat.m22() < 0.0F) { // vertical flip
return smoothScaled(wd, hd).mirrored(false, true).convertToFormat(format());
} else { // no flipping
return smoothScaled(wd, hd).convertToFormat(format());
}
}
}
int bpp = depth();
qsizetype sbpl = bytesPerLine();
const uchar *sptr = bits();
QImage::Format target_format = d->format;
if (complex_xform || mode == Qt::SmoothTransformation) {
if (d->format < QImage::Format_RGB32 || (!hasAlphaChannel() && complex_xform)) {
target_format = qt_alphaVersion(d->format);
}
}
QImage dImage(wd, hd, target_format);
QIMAGE_SANITYCHECK_MEMORY(dImage);
if (target_format == QImage::Format_MonoLSB
|| target_format == QImage::Format_Mono
|| target_format == QImage::Format_Indexed8) {
dImage.d->colortable = d->colortable;
dImage.d->has_alpha_clut = d->has_alpha_clut | complex_xform;
}
// initizialize the data
if (target_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.d->nbytes);
} else {
memset(dImage.bits(), 0, dImage.d->nbytes);
}
} else
memset(dImage.bits(), 0x00, dImage.d->nbytes);
if (target_format >= QImage::Format_RGB32) {
// Prevent QPainter from applying devicePixelRatio corrections
const QImage sImage = (devicePixelRatio() != 1) ? QImage(constBits(), width(), height(), format()) : *this;
Q_ASSERT(sImage.devicePixelRatio() == 1);
Q_ASSERT(sImage.devicePixelRatio() == dImage.devicePixelRatio());
QPainter p(&dImage);
if (mode == Qt::SmoothTransformation) {
p.setRenderHint(QPainter::Antialiasing);
p.setRenderHint(QPainter::SmoothPixmapTransform);
}
p.setTransform(mat);
p.drawImage(QPoint(0, 0), sImage);
} else {
bool invertible;
mat = mat.inverted(&invertible); // invert matrix
if (!invertible) // error, return null image
return QImage();
// create target image (some of the code is from QImage::copy())
int type = format() == Format_Mono ? QT_XFORM_TYPE_MSBFIRST : QT_XFORM_TYPE_LSBFIRST;
qsizetype dbpl = dImage.bytesPerLine();
qt_xForm_helper(mat, 0, type, bpp, dImage.bits(), dbpl, 0, hd, sptr, sbpl, ws, hs);
}
copyMetadata(dImage.d, d);
return dImage;
}
调用transformed进行转换。
2. rgbSwapped()
QImage QImage::rgbSwapped_helper() const
{
if (isNull())
return *this;
Q_TRACE_SCOPE(QImage_rgbSwapped_helper);
QImage res;
switch (d->format) {
case Format_Invalid:
case NImageFormats:
Q_ASSERT(false);
break;
case Format_Alpha8:
case Format_Grayscale8:
case Format_Grayscale16:
return *this;
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_RGBX8888:
case Format_RGBA8888:
case Format_RGBA8888_Premultiplied:
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
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) & 0xff000000) | ((c >> 16) & 0xff00) | (c & 0x00ff00ff);
p++;
q++;
}
}
break;
#else
// On little-endian rgba8888 is abgr32 and can use same rgb-swap as argb32
Q_FALLTHROUGH();
#endif
case Format_RGB32:
case Format_ARGB32:
case Format_ARGB32_Premultiplied:
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);
QIMAGE_SANITYCHECK_MEMORY(res);
rgbSwapped_generic(d->width, d->height, this, &res, &qPixelLayouts[d->format]);
break;
}
copyMetadata(res.d, d);
return res;
}
QImage QImage::copy(const QRect& r) const
{
Q_TRACE_SCOPE(QImage_copy, r);
if (!d)
return QImage();
if (r.isNull()) {
QImage image(d->width, d->height, d->format);
if (image.isNull())
return image;
// Qt for Embedded Linux can create images with non-default bpl
// make sure we don't crash.
if (image.d->nbytes != d->nbytes) {
qsizetype bpl = qMin(bytesPerLine(), image.bytesPerLine());
for (int i = 0; i < height(); i++)
memcpy(image.scanLine(i), scanLine(i), bpl);
} else
memcpy(image.bits(), bits(), d->nbytes);
image.d->colortable = d->colortable;
image.d->offset = d->offset;
image.d->has_alpha_clut = d->has_alpha_clut;
copyMetadata(image.d, d);
return image;
}
int x = r.x();
int y = r.y();
int w = r.width();
int h = r.height();
int dx = 0;
int dy = 0;
if (w <= 0 || h <= 0)
return QImage();
QImage image(w, h, d->format);
if (image.isNull())
return image;
if (x < 0 || y < 0 || x + w > d->width || y + h > d->height) {
// bitBlt will not cover entire image - clear it.
image.fill(0);
if (x < 0) {
dx = -x;
x = 0;
}
if (y < 0) {
dy = -y;
y = 0;
}
}
image.d->colortable = d->colortable;
int pixels_to_copy = qMax(w - dx, 0);
if (x > d->width)
pixels_to_copy = 0;
else if (pixels_to_copy > d->width - x)
pixels_to_copy = d->width - x;
int lines_to_copy = qMax(h - dy, 0);
if (y > d->height)
lines_to_copy = 0;
else if (lines_to_copy > d->height - y)
lines_to_copy = d->height - y;
bool byteAligned = true;
if (d->format == Format_Mono || d->format == Format_MonoLSB)
byteAligned = !(dx & 7) && !(x & 7) && !(pixels_to_copy & 7);
if (byteAligned) {
const uchar *src = d->data + ((x * d->depth) >> 3) + y * d->bytes_per_line;
uchar *dest = image.d->data + ((dx * d->depth) >> 3) + dy * image.d->bytes_per_line;
const qsizetype bytes_to_copy = (qsizetype(pixels_to_copy) * d->depth) >> 3;
for (int i = 0; i < lines_to_copy; ++i) {
memcpy(dest, src, bytes_to_copy);
src += d->bytes_per_line;
dest += image.d->bytes_per_line;
}
} else if (d->format == Format_Mono) {
const uchar *src = d->data + y * d->bytes_per_line;
uchar *dest = image.d->data + dy * image.d->bytes_per_line;
for (int i = 0; i < lines_to_copy; ++i) {
for (int j = 0; j < pixels_to_copy; ++j) {
if (src[(x + j) >> 3] & (0x80 >> ((x + j) & 7)))
dest[(dx + j) >> 3] |= (0x80 >> ((dx + j) & 7));
else
dest[(dx + j) >> 3] &= ~(0x80 >> ((dx + j) & 7));
}
src += d->bytes_per_line;
dest += image.d->bytes_per_line;
}
} else { // Format_MonoLSB
Q_ASSERT(d->format == Format_MonoLSB);
const uchar *src = d->data + y * d->bytes_per_line;
uchar *dest = image.d->data + dy * image.d->bytes_per_line;
for (int i = 0; i < lines_to_copy; ++i) {
for (int j = 0; j < pixels_to_copy; ++j) {
if (src[(x + j) >> 3] & (0x1 << ((x + j) & 7)))
dest[(dx + j) >> 3] |= (0x1 << ((dx + j) & 7));
else
dest[(dx + j) >> 3] &= ~(0x1 << ((dx + j) & 7));
}
src += d->bytes_per_line;
dest += image.d->bytes_per_line;
}
}
copyMetadata(image.d, d);
image.d->offset = offset();
image.d->has_alpha_clut = d->has_alpha_clut;
return image;
}