zhiyiYo / PyQt-Fluent-Widgets

A fluent design widgets library based on C++ Qt/PyQt/PySide. Make Qt Great Again.
https://qfluentwidgets.com
GNU General Public License v3.0
5.61k stars 541 forks source link

能否让缩放后的图片清晰一些 #339

Closed nuthx closed 1 year ago

nuthx commented 1 year ago

PySide6对缩放的兼容不佳,大图缩放后会模糊 网上有一些方式可以让缩放后的图片实现不错的效果,不知能否加入到后面的版本中

大概对比一下三种方法的效果,供参考

方法一:没做圆角,效果完美

self.image = QLabel()
self.image.setFixedSize(150, 210)
self.image.setPixmap(QPixmap("image/1.jpg"))
self.image.setScaledContents(True)

方法二:可以圆角,但过于锐化,有锯齿

class RoundedLabel(QLabel):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setFixedSize(150, 210)
        self.setPixmap(QPixmap("image/1.jpg"))
        self.setScaledContents(True)

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        radius = 6.0
        path = QPainterPath()
        path.addRoundedRect(self.rect(), radius, radius)
        painter.setClipPath(path)
        painter.drawPixmap(self.rect(), self.pixmap())

self.image = RoundedLabel()

方法三:皮肤自带方法,可以圆角,但模糊

from qfluentwidgets import ImageLabel

self.image = ImageLabel("image/1.jpg")
self.image.scaledToHeight(200)
self.image.setBorderRadius(6, 6, 6, 6)

从左到右分别是一二三的效果:

1
zhiyiYo commented 1 year ago

麻烦提供下图片,我测试一下

nuthx commented 1 year ago

示例图片是这张: https://lain.bgm.tv/pic/cover/l/aa/64/316247_Yd3F5.jpg

但实际上任何一张图片只要缩放就会变得模糊,无论大图缩小还是小图放大 方法一可以清晰的展示,但是没有圆角效果 所以能否将集成方法一到ImageLabel类中呢?

zhiyiYo commented 1 year ago

看了一下 QLabel 源代码:


        QPixmap pix;
        if (d->scaledcontents) {
            // cr 是标签大小
            QSize scaledSize = cr.size() * devicePixelRatioF();
            if (!d->scaledpixmap || d->scaledpixmap->size() != scaledSize) {
                if (!d->cachedimage)
                    d->cachedimage = new QImage(d->pixmap->toImage());
                delete d->scaledpixmap;
                QImage scaledImage =
                    d->cachedimage->scaled(scaledSize,
                                           Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
                d->scaledpixmap = new QPixmap(QPixmap::fromImage(std::move(scaledImage)));
                d->scaledpixmap->setDevicePixelRatio(devicePixelRatioF());
            }
            pix = *d->scaledpixmap;
        } else
            pix = *d->pixmap;

        QStyleOption opt;
        opt.initFrom(this);
        if (!isEnabled())
            pix = style->generatedIconPixmap(QIcon::Disabled, pix, &opt);

        style->drawItemPixmap(&painter, cr, align, pix);

void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment,
                            const QPixmap &pixmap) const
{
    qreal scale = pixmap.devicePixelRatio();
    QRect aligned = alignedRect(QGuiApplication::layoutDirection(), QFlag(alignment), pixmap.size() / scale, rect);
    QRect inter = aligned.intersected(rect);
    painter->drawPixmap(inter.x(), inter.y(), pixmap, inter.x() - aligned.x(), inter.y() - aligned.y(), qRound(inter.width() * scale), qRound(inter.height() *scale));
}
zhiyiYo commented 1 year ago

这样就 ok 了:

class RoundedLabel(QLabel):
    def __init__(self, imagePath, parent=None):
        super().__init__(parent)
        self.setFixedSize(150, 210)
        self.setPixmap(QPixmap(imagePath))

    def paintEvent(self, e):
        painter = QPainter(self)
        painter.setRenderHints(QPainter.Antialiasing)

        pixmap = self.pixmap().scaled(
            self.size()*self.devicePixelRatioF(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation)

        radius = 6.0
        path = QPainterPath()
        path.addRoundedRect(QRectF(self.rect()), radius, radius)
        painter.setClipPath(path)
        painter.drawPixmap(self.rect(), pixmap)
zhiyiYo commented 1 year ago

从左到右分别是 RoundedLabelImageLabelQLabel image

nuthx commented 1 year ago

可行,虽然没看懂,但跑起来效果完美,感谢大佬!