Image rounded corners in QML

前端 未结 7 1079
遇见更好的自我
遇见更好的自我 2020-12-14 06:25

To my surprise, the Image component has no radius property. I tried emulating the rounded corners by putting the image in a rounded Rectangle

相关标签:
7条回答
  • 2020-12-14 06:33

    I know I'm a little late to the party, but I got here by googling, so thought I'd help future generations :) QtGraphicalEffects OpacityMask should do this a bit more simply (I had issues with the layer effect approach)

    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
        }
    }
    
    0 讨论(0)
  • 2020-12-14 06:34

    QML currently supports only rectangular clipping, but you might want to take a look at DeclarativeMaskedImage in qt-components project:

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

    0 讨论(0)
  • 2020-12-14 06:37

    While both the accepted answer and the one from @fury worked equally well for me (Qt 5.9.3), they both left some aberrations in the corners when applied to raster images (didn't have those with SVG). What worked best for me in all cases was to apply the OpacityMask to a surrounding item, e.g. like the rectangle in the original post.

    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"
        }
    }
    
    0 讨论(0)
  • 2020-12-14 06:41

    This code would help you

    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"
        }
    }
    
    0 讨论(0)
  • 2020-12-14 06:43

    A built-in official solution exists as of Qt 5 thanks to the QtGraphicalEffects module and I'm quite surprised to find out that no one provided such simple solution.

    Among the other effects OpacityMask is the type to be exploited for this purpose. The idea is to mask the source Image with a Rectangle that has a correctly set radius. Here goes the simplest example using 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)
                }
            }
        }
    }
    

    This minimum code produces a nice result for square images but it also takes in account non-square images via the adapt variable. By setting the flag to false the produced mask will always be a circle, regardless of the image size. That is possible due to the usage of an external Item which fills the source and allows the real mask (the inner Rectangle) to be sized at please. You can obviously get rid of the external Item, if you simply aim to a mask that fills the source, regardless of the its aspect ratio.

    Here is a cute cat image with a square format (left), a non-square format with adapt: true (center) and finally a non-square format and adapt: false (right):

    The implementation details of this solution are very similar to those of the shader-based answer in the other nice answer (cfr. the QML source code for OpacityMask that can be found here - SourceProxy simply returns a well-formed ShaderEffectSource to feed the effect).

    If you don't want to depend on the QtGraphicalEffects module (well, on the presence of OpacityMask.qml actually), you can reimplement the effect with shaders. Apart from the already provided solution another approach is to use step, smoothstep and fwidth functions. Here is the code:

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

    Similarly to the first approach, rounded and adapt properties are added to control the visual appearance of the effect as discussed above.

    0 讨论(0)
  • 2020-12-14 06:44

    If you have a unicolor background, you can draw with the border of a rounded rectangle on top.

    Image{
        id:img
    }
    Rectangle { // rounded corners for img
        anchors.fill: img
        color: "transparent"
        border.color: "blue" // color of background
        border.width: 4
        radius: 4
    }
    
    0 讨论(0)
提交回复
热议问题