helene
helene

Reputation: 1251

QML change image color

I searched for how to colorize an image (with the format svg or png ...).

I tried covering my image with a rectangle that fills the image, but as my image is not a rectangle it colorizes the whole rectangle and not just the image.

Is it possible to change image color with qml? Alternatively, is it possible to change the color on qt (with C++) with QPixmap then integrate the QPixmap on QML Item?

Thank you for your help. (If there is no solution, I will have to load a different image to the same basic image with different color.)

Upvotes: 29

Views: 28335

Answers (5)

Saysdf
Saysdf

Reputation: 41

Work around is using IconImage. It has color: I Found it in Qt 6.5.0

IconImage{
     source: "qrc:/yourImage.svg"
     color: "red"
}

Upvotes: 4

Stephen Quan
Stephen Quan

Reputation: 25871

I also went looking for a non-QtGraphicalEffects solution and found a solution by using the icon property as follows:

  • icon.source - for setting the SVG image
  • icon.color - for changing the color of the SVG image
  • icon.width - for changing the width of the SVG image
  • icon.height - for changing the height of the SVG image

Some controls have the icon property such as Button, ItemDelegate and MenuItem.

In the following code, we implement AppIcon as a customized version of Button so that the only thing that remains is the icon rendering. We remove the button styling and the button size, it is clipped to just render the icon itself. Because we have customized the Button we can expose the clicked signal and the pressed property.

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Page {
    ColumnLayout {
        anchors.centerIn: parent
        AppIcon {
            Layout.alignment: Qt.AlignHCenter
            icon.source: "biking-32.svg"
            icon.color: pressed ? "orange" : "red"
            onClicked: status.text = "red clicked"
        }
        AppIcon {
            Layout.alignment: Qt.AlignHCenter
            Layout.preferredWidth: 64
            Layout.preferredHeight: 64
            icon.source: "biking-32.svg"
            icon.color: pressed ? "orange" : "blue"
            onClicked: status.text = "blue clicked"
        }
        AppIcon {
            Layout.alignment: Qt.AlignHCenter
            Layout.preferredWidth: 96
            Layout.preferredHeight: 96
            icon.source: "biking-32.svg"
            icon.color: pressed ? "orange" : "green"
            onClicked: status.text = "green clicked"
        }
        Text {
            id: status
            text: "click on an image"
        }
    }
}

//AppIcon.qml
import QtQuick
import QtQuick.Controls
Item {
    id: appIcon
    implicitWidth: 32
    implicitHeight: 32
    property alias icon: btn.icon
    property alias pressed: btn.pressed
    signal clicked()
    Button {
        id: btn
        anchors.centerIn: parent
        background: Item { }
        icon.width: parent.width
        icon.height: parent.height
        onClicked: appIcon.clicked()
    }
}

//biking-32.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M16 5.5A2.5 2.5 0 1 1 18.5 8 2.498 2.498 0 0 1 16 5.5zm-1.042 19.02a1.545 1.545 0 0 0 1.021 1.688c.73.104 1.23-.25 1.452-1.211.034-.145 1.173-6.518 1.173-6.518l-3.979-2.146 2.823-4.087L19.498 15H24a1 1 0 0 0 0-2h-3.498l-2.434-3.27a1.63 1.63 0 0 0-.48-.551.995.995 0 0 0-.11-.083l-1.107-.765a1.685 1.685 0 0 0-2.194.595l-4.09 6.534a1 1 0 0 0 .367 1.408l5.114 2.8zM29.8 24.5a5.3 5.3 0 1 1-5.3-5.3 5.3 5.3 0 0 1 5.3 5.3zm-1.8 0a3.5 3.5 0 1 0-3.5 3.5 3.504 3.504 0 0 0 3.5-3.5zm-15.2 0a5.3 5.3 0 1 1-5.3-5.3 5.3 5.3 0 0 1 5.3 5.3zm-1.8 0A3.5 3.5 0 1 0 7.5 28a3.504 3.504 0 0 0 3.5-3.5z"/><path fill="none" d="M0 0h32v32H0z"/></svg>

You can Try it Online!

Upvotes: 3

Nikolai Saiko
Nikolai Saiko

Reputation: 1708

In Qt 5 (from 5.2) you may use ColorOverlay as follows:

import QtQuick 2.0
import QtGraphicalEffects 1.0

Item {
    width: 300
    height: 300

    Image {
        id: bug
        source: "images/butterfly.png"
        sourceSize: Qt.size(parent.width, parent.height)
        smooth: true
        visible: false
    }

    ColorOverlay {
        anchors.fill: bug
        source: bug
        color: "#ff0000"  // make image like it lays under red glass 
    }
 }

In Qt 6 module QtGraphicalEffects (which includes ColorOverlay) was removed because of licensing issues.

In Qt 6.1 GraphicalEffects is now available again, as @SCP3008 commented below

Upvotes: 37

CN.Hu
CN.Hu

Reputation: 135

You can also use Colorize

And the difference with ColorOverlay is: Colorize can really change the color of a image with HSL, it is more suitable for me. ColorOverlay is similar to what happens when a colorized glass is put on top of a grayscale image with RGBA.

import QtQuick 2.12
import QtGraphicalEffects 1.12

Item {
    width: 300
    height: 300

    Image {
        id: bug
        source: "images/bug.jpg"
        sourceSize: Qt.size(parent.width, parent.height)
        smooth: true
        visible: false
    }

    Colorize {
        anchors.fill: bug
        source: bug
        hue: 0.0
        saturation: 0.5
        lightness: -0.2
    }
}

Upvotes: 7

Paweł Krakowiak
Paweł Krakowiak

Reputation: 368

You can replace your image color using ShaderEffect.

ShaderEffect {
    property variant src: yourImage

    property real r: yourColor.r * yourColor.a
    property real g: yourColor.g * yourColor.a
    property real b: yourColor.b * yourColor.a

    width: yourImage.width
    height: yourImage.height

    vertexShader: "
        uniform highp mat4 qt_Matrix;
        attribute highp vec4 qt_Vertex;
        attribute highp vec2 qt_MultiTexCoord0;
        varying highp vec2 coord;

        void main() {
            coord = qt_MultiTexCoord0;
            gl_Position = qt_Matrix * qt_Vertex;
        }
    "

    fragmentShader: "
        varying highp vec2 coord;
        uniform sampler2D src;

        uniform lowp float r;
        uniform lowp float g;
        uniform lowp float b;

        void main() {
            lowp vec4 clr = texture2D(src, coord);
            lowp float avg = (clr.r + clr.g + clr.b) / 3.;
            gl_FragColor = vec4(r * avg, g * avg, b * avg, clr.a);
        }
    "
}

The above code turns your image into the grayscaled one and then applies your color.

Upvotes: 8

Related Questions