Image with radius in QML



  • Hi, how could I set rounded corners in an Image in QML? I tried simulated it with a rectangle behind but it didn't work. Any suggests?



  • There is no direct way to set rounded corner for Image. But as you think, we need some tricks. Rectangle behide the Image is not work, but you can try in front of the Image, set the Rectangle's color to "transparent", and set it's border and radius.



  • It is possible with the "QML Shaders":http://labs.qt.nokia.com/2011/05/03/qml-shadereffectitem-on-qgraphicsview/ plugin.

    @

    import QtQuick 1.0
    import Qt.labs.shaders 1.0

    Item {
    width: 600
    height: 300

    Rectangle {
        id: mask
        anchors.centerIn: parent
        width: 400
        height: 200
        radius: 20
    }
    
    Image {
        id: image
        anchors.fill: mask
        source: "test.jpg"
    }
    
    ShaderEffectSource {
        id: sourceMask
        smooth: true
        hideSource: true
        sourceItem: mask
    }
    ShaderEffectSource {
        id: sourceImage
        hideSource: true
        sourceItem: image
    }
    
    ShaderEffectItem {
        id: maskEffect
        anchors.fill: mask
    
        property variant sourceTexture: sourceImage
        property variant maskTexture: sourceMask
    
        vertexShader: "
            uniform highp mat4 qt_ModelViewProjectionMatrix;
            attribute highp vec4 qt_Vertex;
            attribute highp vec2 qt_MultiTexCoord0;
    
            varying highp vec2 qt_TexCoord;
    
            void main(void)
            {
                qt_TexCoord = qt_MultiTexCoord0;
                gl_Position =  qt_ModelViewProjectionMatrix * qt_Vertex;
            }
        "
    
        fragmentShader: "
            uniform lowp sampler2D sourceTexture;
            uniform lowp sampler2D maskTexture;
            varying highp vec2 qt_TexCoord;
    
            void main (void)
            {
                vec4 c = texture2D(sourceTexture, qt_TexCoord);
                vec4 m = texture2D(maskTexture, qt_TexCoord);
                gl_FragColor = vec4(c.rgb, m.a);
            }
        "
    }
    

    }
    @



  • Yes, fantastic :-)



  • Thank you for your answers!



  • Interesting approach, but to be honest, I don't think this kind of code is really what we should strive for in QML. It is not really readable, and also not really declarative.

    I'm sure your code produces a faster UI, but for simplicity, I would go for something like this:

    @

    import QtQuick 1.0

    Item {
    width: 600
    height: 300

    Rectangle {
        id: mask
        anchors.centerIn: parent
        width: 400
        height: 200
        radius: 20
    
        Image {
            id: image
            anchors.fill: parent
            source: "test.jpg"
        }
    }
    

    }
    @

    That should work as well, and is, IMHO, clearer to read.



  • At the beginning I tried with that code but it didn't work. The image is set over the rectangle hidding the round corners. I will try again but I think it doesn't work.

    If I nest, in the opposite way, the Rectangle inside the Image, it shows the border over the image but it doesn't hide the corners either.



  • Sorry, you probably need to enable clipping.

    @

    import QtQuick 1.0

    Item {
    width: 600
    height: 300

    Rectangle {
        id: mask
        anchors.centerIn: parent
        width: 400
        height: 200
        radius: 20
        clip: true
    
        Image {
            id: image
            anchors.fill: parent
            source: "test.jpg"
        }
    }
    

    }
    @

    Edit:
    On the other hand: the docs to state:
    [quote]Non-rectangular clipping regions are not supported for performance reasons.[/quote]

    So, perhaps a rounded rect will not clip properly after all.



  • I tried the code but it doesn't work. I copied it directly to qt and tried it.

    The same is happening, the image is over the rectangle. How to make it fit to the shape of the rectangle?



  • I am afraid, that the solution I proposed indeed does not work. Sorry for setting you on the wrong track.



  • Hello,
    I am trying the shader solution, but it gives me this error at runtime:
    @
    QGLShaderProgram::addShader: Program and shader are not associated with same context.
    QGLShaderProgram::addShader: Program and shader are not associated with same context.
    QGLShader::link: "Link Error: Vertex shader is missing.
    Link Error: Fragment shader is missing.
    "
    ShaderEffectItem: Shader compilation failed:
    "Link Error: Vertex shader is missing.
    Link Error: Fragment shader is missing.
    "
    QGLShader::link: "Link Error: Vertex shader is missing.
    Link Error: Fragment shader is missing.
    "
    QGLShaderProgram::uniformLocation( qt_ModelViewProjectionMatrix ): shader program is not linked
    QGLShaderProgram::addShader: Program and shader are not associated with same context.
    QGLShaderProgram::addShader: Program and shader are not associated with same context.
    QGLShader::link: "Link Error: Vertex shader is missing.
    @

    And this is the code I have used:
    @
    Item {
    width: 200
    height: 200
    //radius: 20
    //border.width: 6
    //border.color: "#ffea00"

    signal tapOnProfilePicture
    
    property alias profileImageSource: image.source
    
    
    Rectangle {
        id: mask
        anchors.centerIn: parent
        width: 200
        height: 200
        radius: 20
    }
    
    Image {
        id: image
        anchors.fill: mask
        source: "qrc:/images/profile-mask.png"
    }
    
    ShaderEffectSource {
        id: sourceMask
        smooth: true
        hideSource: true
        sourceItem: mask
    }
    ShaderEffectSource {
        id: sourceImage
        hideSource: true
        sourceItem: image
    }
    
    ShaderEffectItem {
        id: maskEffect
        anchors.fill: mask
    
        property variant sourceTexture: sourceImage
        property variant maskTexture: sourceMask
    
        vertexShader: "
           uniform highp mat4 qt_ModelViewProjectionMatrix;
           attribute highp vec4 qt_Vertex;
           attribute highp vec2 qt_MultiTexCoord0;
    
           varying highp vec2 qt_TexCoord;
    
           void main(void)
           {
               qt_TexCoord = qt_MultiTexCoord0;
               gl_Position =  qt_ModelViewProjectionMatrix * qt_Vertex;
           }
       "
    
        fragmentShader: "
           uniform lowp sampler2D sourceTexture;
           uniform lowp sampler2D maskTexture;
           varying highp vec2 qt_TexCoord;
    
           void main (void)
           {
               highp vec4 c = texture2D(sourceTexture, qt_TexCoord);
               highp vec4 m = texture2D(maskTexture, qt_TexCoord);
               gl_FragColor = vec4(c.rgb, m.a);
           }
       "
    }
    
    MouseArea {
        z: 10
        anchors.fill: parent
        onClicked: {
            tapOnProfilePicture()
        }
    }
    

    }
    @

    Notice I have added highp to vec4 declarations to avoid other errors.



  • Hi you can use an "OpacityMask":http://qt-project.org/doc/qt-5/qml-qtgraphicaleffects-opacitymask.html. Use a rounded image and mask your image with it.



  • [quote author="Brexis" date="1397022356"]Hi you can use an "OpacityMask":http://qt-project.org/doc/qt-5/qml-qtgraphicaleffects-opacitymask.html. Use a rounded image and mask your image with it.[/quote]

    Yes, that is a good solution!


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.