Qt源码分析--QImage(6)

59 篇文章 1 订阅
37 篇文章 1 订阅
本文档详细介绍了QImage类的scaled()和transformed()两个方法,用于图像的缩放和复杂变换。scaled()方法根据指定的比例模式和变换模式调整图像大小,而transformed()则允许进行更复杂的透视变换。此外,还展示了rgbSwapped_helper()方法,用于将图像的RGB颜色通道进行交换。这些函数广泛应用于图像处理和显示中。
摘要由CSDN通过智能技术生成

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天天进步2015

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值