qml - guia - qgis manual
Imagen esquinas redondeadas en QML. (7)
Para mi sorpresa, el componente Image
no tiene propiedad de radius
. Intenté emular las esquinas redondeadas colocando la imagen en un Rectangle
redondeado, pero no corta las esquinas.
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"
}
}
¿Cómo puedo crear una imagen con esquinas redondeadas correctamente?
Actualmente, QML solo admite el recorte rectangular, pero es posible que desee echar un vistazo a DeclarativeMaskedImage en el proyecto qt-components:
Cuando su fondo es un color sólido o cuando nunca está moviendo la imagen, una forma rápida de hacer esquinas redondeadas es superponer su Image
con otra (o con una BorderImage
) que solo dibuja las esquinas.
Cuando esto no es una opción, pero está utilizando OpenGL, otra forma es aplicar una máscara a la imagen a través de un sombreador de píxeles. Consulte http://blog.qt.digia.com/blog/2011/05/03/qml-shadereffectitem-on-qgraphicsview/ para ver un complemento que funciona sobre Qt 4.
Finalmente, también es posible escribir un QDeclarativeImageProvider
que preprocesa tu imagen para redondear las esquinas.
Este código te ayudaría
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"
}
}
Sé que llego un poco tarde a la fiesta, pero llegué aquí buscando en Google, así que pensé que ayudaría a las generaciones futuras :) QtGraphicalEffects OpacityMask debería hacer esto un poco más simple (tuve problemas con el enfoque de efecto de capa)
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
}
}
Si bien tanto la respuesta aceptada como la respuesta de @fury funcionaron igual de bien para mí (Qt 5.9.3), ambas dejaron algunas aberraciones en las esquinas cuando se aplicaron a imágenes rasterizadas (no tenían las que tenían SVG). Lo que me funcionó mejor en todos los casos fue aplicar la OpacityMask
a un elemento circundante, por ejemplo, como el rectángulo en la publicación 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"
}
}
Si tiene un fondo unicolor, puede dibujar con el borde de un rectángulo redondeado en la parte superior.
Image{
id:img
}
Rectangle { // rounded corners for img
anchors.fill: img
color: "transparent"
border.color: "blue" // color of background
border.width: 4
radius: 4
}
Una solución oficial incorporada existe a partir de Qt 5 gracias al módulo QtGraphicalEffects
y me sorprende bastante descubrir que nadie proporcionó una solución tan simple.
Entre los otros efectos, OpacityMask
es el tipo que se va a explotar para este propósito. La idea es enmascarar la Image
origen con un Rectangle
que tenga un radius
configurado correctamente. Aquí va el ejemplo más simple usando layering :
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)
}
}
}
}
Este código mínimo produce un buen resultado para las imágenes cuadradas, pero también tiene en cuenta las imágenes no cuadradas a través de la variable de adapt
. Al establecer la bandera en false
la máscara producida siempre será un círculo, independientemente del tamaño de la imagen. Esto es posible debido al uso de un Item
externo que llena la fuente y permite que la máscara real (el Rectangle
interior) tenga el tamaño deseado. Obviamente, puede deshacerse del Item
externo, si simplemente apunta a una máscara que llena la fuente, independientemente de su relación de aspecto .
Aquí hay una linda imagen de gato con un formato cuadrado ( izquierda ), un formato no cuadrado con adapt: true
( centro ) y, finalmente, un formato no cuadrado y adapt: false
( derecha ):
Los detalles de implementación de esta solución son muy similares a los de la respuesta basada en sombreado en la otra respuesta agradable (cfr. El código fuente QML para OpacityMask
que se puede encontrar here - SourceProxy
simplemente devuelve una fuente OpacityMask
bien formada para alimentar el efecto) .
Si no desea depender del módulo QtGraphicalEffects
(bueno, de la presencia de OpacityMask.qml
realidad), puede OpacityMask.qml
el efecto con shaders. Aparte de la solución ya provista, otro enfoque es utilizar las funciones step
, smoothstep
y fwidth
. Aquí está el código:
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;
}"
}
}
De manera similar al primer enfoque, se agregan propiedades rounded
y de adapt
para controlar la apariencia visual del efecto como se explicó anteriormente.