QML change image color
Asked Answered
I

5

29

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.)

Ivanaivanah answered 30/5, 2013 at 14:45 Comment(0)
L
37

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

Lottery answered 31/3, 2014 at 12:40 Comment(5)
Documentation available : Qt ColorOverlay QMLCailean
ColorOverlay does not exist in QT 6.Barri
The entire QtGraphicalEffects module has been removed from Qt 6. They are no longer working on it and are relicensing over to BSD, ShaderEffects is likely the best workaround ATM if Qt 6 is required @AmirSaniyanJairia
GraphicalEffects is now available again with changes in Qt 6.1 though under a different module now: here Components like ColorOverlay are modified slightly, such as not having a samples property anymoreLoesch
Warning, I found that combining Qt5Compat.GraphicalEffects and Qt6 on TI AM335x ARM boards causing the QSGRenderThread to crash. So maybe better just find some Qt6-based solutions.Prescription
A
8

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.

Archduchy answered 4/3, 2016 at 15:47 Comment(0)
R
7

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
    }
}
Returnable answered 26/2, 2019 at 15:45 Comment(0)
A
3

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

IconImage{
     source: "qrc:/yourImage.svg"
     color: "red"
}
Arana answered 10/4, 2023 at 15:50 Comment(3)
Hi Saysdf, is that a Qt Quick control? I can't see it mentioned in the Qt 6.5 docs.Filch
@Filch As far as I know it is still not documented feature which is pretty sad as it is the best solution in terms of layout design.Irradiance
Works in Qt 6.6, except that you can't use fillMode: Image.PreserveAspectFit, which can be used with the standard Image element.Krypton
G
2

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!

Glasser answered 12/7, 2022 at 4:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.