Image coins arrondis en QML
a ma surprise, le Image
composant n'a pas d' radius
propriété. J'ai essayé d'émuler les coins arrondis en mettant l'image dans un arrondi Rectangle
, mais il ne coupe pas les coins.
Rectangle {
anchors.right: rectContentBg.left
anchors.top: rectContentBg.top
anchors.margins: 8
radius: 8
width: 64
height: 64
Image {
id: imgAuthor
opacity: 1
smooth: false
anchors.fill: parent
source: "qrc:/res/sample_avatar.jpg"
}
}
Comment puis-je créer une image avec des coins arrondis correctement?
7 réponses
une solution officielle intégrée existe à partir de Qt 5 grâce à la QtGraphicalEffects
module et je suis assez surpris de découvrir que personne n'a fourni une solution aussi simple.
Parmi les autres effets OpacityMask
est le type à exploiter à cet effet. L'idée est de masquer la source Image
avec un Rectangle
qui a correctement défini radius
. Voici l'exemple le plus simple en utilisant la superposition:
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)
}
}
}
}
ce code minimum produit un bon résultat pour des images carrées mais
il prend également en compte les images non carrées via le adapt
variable. Par le paramétrage de l'indicateur false
le produit masque sera toujours un cercle, quelle que soit la taille de l'image. C'est possible grâce à l'utilisation d'une externe Item
qui remplit la source et permet le réel masque (l'intérieur Rectangle
) à dimensionner s'il vous plaît. vous pouvez évidemment vous débarrasser de l'extérieur Item
, si vous visez simplement un masque qui remplit la source, indépendamment de son aspect ratio.
Voici une image de chat mignon avec un format carré (gauche), un format non carré avec adapt: true
( center) et enfin un format non carré et adapt: false
(droit):
les détails de mise en oeuvre de cette solution sont très similaires à ceux de la réponse basée sur shader dans l'autre belle réponse(cfr. le code source QML pour OpacityMask
qui peut être trouvé ici -SourceProxy
renvoie simplement unShaderEffectSource
pour nourrir l'effet).
si vous ne voulez pas dépendre du QtGraphicalEffects
module (bien, sur la présence de OpacityMask.qml
en fait), vous pouvez réimposer l'effet avec des shaders. En dehors de la solution déjà fournie une autre approche est d'utiliser step
,smoothstep
et fwidth
fonctions. Ici, c'est le 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;
}"
}
}
comme pour la première approche,rounded
et adapt
propriétés sont ajoutées pour contrôler l'aspect visuel de l'effet, comme discuté ci-dessus.
quand votre arrière-plan est d'une couleur unie ou quand vous ne déplacez jamais l'image, un moyen rapide pour faire des coins arrondis est de chevaucher votre Image
avec un autre (ou avec un BorderImage
) qui ne dessine que les coins.
quand ce n'est pas une option, mais que vous utilisez OpenGL, alors une autre façon est d'appliquer un masque à l'image à travers un pixel shader. Voir http://blog.qt.digia.com/blog/2011/05/03/qml-shadereffectitem-on-qgraphicsview/ pour un plugin qui fonctionne au-dessus de l'intervalle Qt 4.
enfin, il est aussi possible d'écrire un QDeclarativeImageProvider
qui pré-traite votre image pour faire les coins arrondis.
QML ne supporte actuellement que le découpage rectangulaire, mais vous pouvez jeter un oeil à DeclarativeMaskedImage dans le projet Qt-components:
si vous avez un fond unicolore, vous pouvez dessiner avec la bordure d'un rectangle arrondi sur le dessus.
Image{
id:img
}
Rectangle { // rounded corners for img
anchors.fill: img
color: "transparent"
border.color: "blue" // color of background
border.width: 4
radius: 4
}
ce code vous aiderait
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"
}
}
je sais que je suis un peu en retard à la fête, mais je suis arrivé ici en googling, donc j'ai pensé que je pourrais aider les générations futures:) Qtgraphaleffects OpacityMask devrait faire ceci un peu plus simplement (j'ai eu des problèmes avec l'approche de l'effet de couche)
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
}
}
alors que la réponse acceptée et celui de @fury fonctionnait aussi bien pour moi (Qt 5.9.3), ils ont tous les deux laissé quelques aberrations dans les coins lorsqu'ils étaient appliqués aux images matricielles (ils n'avaient pas ceux avec SVG). Ce qui a fonctionné le mieux pour moi dans tous les cas était d'appliquer le OpacityMask
à un objet environnant, par exemple comme le rectangle dans le poteau original.
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"
}
}