首页 文章

QML中的图像圆角

提问于
浏览
30

令我惊讶的是, Image 组件没有 radius 属性 . 我尝试通过将图像放在圆形的 Rectangle 中来模拟圆角,但它不会剪切角落 .

Rectangle {
    anchors.right: rectContentBg.left
    anchors.top: rectContentBg.top
    anchors.margins: 8

    radius: 8

    width: 64
    height: 64

    Image {
        id: imgAuthor

        opacity: 1
        smooth: false

        anchors.fill: parent

        source: "qrc:/res/sample_avatar.jpg"
    }
}

如何正确创建圆角图像?

7 回答

  • 5

    由于 QtGraphicalEffects 模块,在Qt 5中存在内置的官方解决方案,我很惊讶地发现没有人提供这样简单的解决方案 .

    在其他效果中, OpacityMask 是为此目的而被利用的类型 . 我的想法是使用 Rectangle 屏蔽源 Image ,该 Rectangle 已正确设置 radius . 这是使用layering的最简单的例子:

    Image {
        id: img
        property bool rounded: true
        property bool adapt: true
    
        layer.enabled: rounded
        layer.effect: OpacityMask {
            maskSource: Item {
                width: img.width
                height: img.height
                Rectangle {
                    anchors.centerIn: parent
                    width: img.adapt ? img.width : Math.min(img.width, img.height)
                    height: img.adapt ? img.height : width
                    radius: Math.min(width, height)
                }
            }
        }
    }
    

    这个最小代码为方形图像产生了很好的结果,但它也通过 adapt 变量考虑了非方形图像 . 通过将标志设置为 false ,无论图像大小如何,生成的蒙版始终为圆形 . 这是可能的,因为使用外部 Item 填充源并允许真正的掩码(内部 Rectangle )在适当的大小 . 你可以显然摆脱外部的 Item ,如果你只是瞄准一个填充源的面具,无论它的纵横比如何 .

    这是一个可爱的猫图像,方形格式( left ),非方格式 adapt: truecenter ),最后是非方格式和 adapt: falseright ):

    enter image description here

    这个解决方案的实现细节非常类似于其他nice answer中基于着色器的答案(cfr . 可以找到 OpacityMask 的QML源代码here - SourceProxy 只返回格式正确的 ShaderEffectSource 来提供效果) .

    如果您不想依赖 QtGraphicalEffects 模块(实际上,在存在 OpacityMask.qml 的情况下),您可以使用着色器重新实现效果 . 除了已经提供的解决方案,另一种方法是使用stepsmoothstepfwidth函数 . 这是代码:

    import QtQuick 2.5
    
    Image {
        id: image
    
        property bool rounded: true
        property bool adapt: true
    
        layer.enabled: rounded
        layer.effect: ShaderEffect {
            property real adjustX: image.adapt ? Math.max(width / height, 1) : 1
            property real adjustY: image.adapt ? Math.max(1 / (width / height), 1) : 1
    
            fragmentShader: "
            #ifdef GL_ES
                precision lowp float;
            #endif // GL_ES
            varying highp vec2 qt_TexCoord0;
            uniform highp float qt_Opacity;
            uniform lowp sampler2D source;
            uniform lowp float adjustX;
            uniform lowp float adjustY;
    
            void main(void) {
                lowp float x, y;
                x = (qt_TexCoord0.x - 0.5) * adjustX;
                y = (qt_TexCoord0.y - 0.5) * adjustY;
                float delta = adjustX != 1.0 ? fwidth(y) / 2.0 : fwidth(x) / 2.0;
                gl_FragColor = texture2D(source, qt_TexCoord0).rgba
                    * step(x * x + y * y, 0.25)
                    * smoothstep((x * x + y * y) , 0.25 + delta, 0.25)
                    * qt_Opacity;
            }"
        }
    }
    

    enter image description here

    与第一种方法类似,添加 roundedadapt 属性以控制效果的视觉外观,如上所述 .

  • 5

    当您的背景是纯色或者您从未移动图像时,快速制作圆角的方法是将 Image 与仅绘制角落的另一个(或BorderImage)重叠 .

    如果这不是一个选项,但您使用的是OpenGL,那么另一种方法是通过像素着色器将遮罩应用于图像 . 有关在Qt 4之上工作的插件,请参阅http://blog.qt.digia.com/blog/2011/05/03/qml-shadereffectitem-on-qgraphicsview/ .

    最后,还可以编写一个预处理图像的QDeclarativeImageProvider来使角落变圆 .

  • 39

    QML目前仅支持矩形剪切,但您可能需要查看qt-components项目中的DeclarativeMaskedImage:

    http://qt.gitorious.org/qt-components/qt-components/blobs/master/src/symbian/sdeclarativemaskedimage.h

  • 4

    如果您有单色背景,则可以使用顶部圆角矩形的边框进行绘制 .

    Image{
        id:img
    }
    Rectangle { // rounded corners for img
        anchors.fill: img
        color: "transparent"
        border.color: "blue" // color of background
        border.width: 4
        radius: 4
    }
    
  • 2

    这段代码可以帮到你

    Rectangle {
        width: 200
        height: 200
    
        color: "transparent"
    
        //this Rectangle is needed to keep the source image's fillMode
        Rectangle {
            id: imageSource
    
            anchors.fill: parent
            Image {
                anchors.fill: parent
                source: "your_image_file_path"
    
                fillMode: Image.PreserveAspectCrop
            }
            visible: false
    
            layer.enabled: true
        }
    
        Rectangle {
            id: maskLayer
            anchors.fill: parent
            radius: parent.width / 2
    
            color: "red"
    
            border.color: "black"
    
            layer.enabled: true
            layer.samplerName: "maskSource"
            layer.effect: ShaderEffect {
    
                property var colorSource: imageSource
                fragmentShader: "
                    uniform lowp sampler2D colorSource;
                    uniform lowp sampler2D maskSource;
                    uniform lowp float qt_Opacity;
                    varying highp vec2 qt_TexCoord0;
                    void main() {
                        gl_FragColor =
                            texture2D(colorSource, qt_TexCoord0)
                            * texture2D(maskSource, qt_TexCoord0).a
                            * qt_Opacity;
                    }
                "
            }
    
        }
    
        // only draw border line
        Rectangle {
            anchors.fill: parent
    
            radius: parent.width / 2
    
            border.color: "black"
            border.width: 2
    
            color: "transparent"
        }
    }
    
  • 7

    我知道我参加派对有点晚了,但是我通过谷歌搜索来到这里,所以我想我会帮助后代:) QtGraphicalEffects OpacityMask应该更简单地做到这一点(我有层效应方法的问题)

    Image {
        id: imgAuthor
    
        width: 64
        height: 64
    
        source: "qrc:/res/sample_avatar.jpg"
    
        visible: false // this is needed or the corners of the image will be visible underneath the opacity mask
    }
    
    OpacityMask {
        anchors.fill: imgAuthor
        source: imgAuthor
        maskSource: Rectangle {
            width: imgAuthor.width
            height: imgAuthor.height
            radius: 8
            visible: false // this also needs to be invisible or it will cover up the image
        }
    }
    
  • 5

    虽然接受的答案和the one from @fury对我来说同样有效(Qt 5.9.3),但是当应用于光栅图像(没有SVG的那些)时,它们都在角落中留下了一些像差 . 在所有情况下最适合我的是将 OpacityMask 应用于周围的项目,例如喜欢原帖中的矩形 .

    Rectangle {
        id: root;
        anchors.right: rectContentBg.left
        anchors.top: rectContentBg.top
        anchors.margins: 8
    
        radius: 8
    
        width: 64
        height: 64
    
        // apply rounded corners mask
        layer.enabled: true
        layer.effect: OpacityMask {
            maskSource: Rectangle {
                x: root.x; y: root.y
                width: root.width
                height: root.height
                radius: root.radius
            }
        }
    
        Image {
            id: imgAuthor
            opacity: 1
            smooth: false
            anchors.fill: parent
            source: "qrc:/res/sample_avatar.jpg"
        }
    }
    

相关问题