Search code examples
imageqmlqt5scaletransform

Scaling an image in QML while cropping to a rectangle's size


I have a fixed size yellow QML rectangle, and I am scaling an image inside it.

When this happens, my image eventually becomes bigger than my yellow rectangle (obviously). But when that happens, I want my image to be painted only inside the rectangle and not extend over it.

This is my code:

import QtQuick 2.1
import QtQuick.Controls 1.0

Rectangle{
    width: 1500
    height: 1100
    color: "red"
    
    Rectangle {
        width: 900
        height: 500
        color: "yellow"
    
        Component.onCompleted: init()
        
        Image {
            id: imagenCentro
            width: 800
            height: 400
            fillMode: Image.PreserveAspectCrop
            source: "http://www.bizh2o.com/wp-content/uploads/2015/02/shopping.jpg"
            smooth: true
            z: parent.z+1
            opacity: 0.7
        }

        NumberAnimation {
            id: animacion
            target: imagenCentro
            property: "scale"
            to: 1.5
            easing.type: Easing.InOutQuad
        }

        function init(){
            imagenCentro.scale = 1
            animacion.duration = 5000
            animacion.start()
        }
           
    }

}

Thanks.


Solution

  • Set clip to true on the yellow rectangle:

    import QtQuick 2.1
    import QtQuick.Controls 1.0
    
    Rectangle {
        width: 1500
        height: 1100
        color: "red"
    
        Rectangle {
            width: 900
            height: 500
            color: "yellow"
            clip: true
    
            Component.onCompleted: init()
    
            Image {
                id: imagenCentro
                width: 800
                height: 400
                fillMode: Image.PreserveAspectCrop
                source: "http://www.bizh2o.com/wp-content/uploads/2015/02/shopping.jpg"
                smooth: true
                z: parent.z + 1
                opacity: 0.7
            }
    
            NumberAnimation {
                id: animacion
                target: imagenCentro
                property: "scale"
                to: 1.5
                easing.type: Easing.InOutQuad
            }
    
            function init() {
                imagenCentro.scale = 1
                animacion.duration = 5000
                animacion.start()
            }
        }
    }
    

    Note that clip does come with performance penalties:

    Clipping is disabled by default, and should only be enabled when required.

    Clipping is a visual effect, NOT an optimization. It increases (rather than reduces) complexity for the renderer. If clipping is enabled, an item will clip its own painting, as well as the painting of its children, to its bounding rectangle. This stops the renderer from being able to reorder the drawing order of elements freely, resulting in a sub-optimal best-case scene graph traversal.

    Clipping inside a delegate is especially bad and should be avoided at all costs.