Начиная с Qt 5, существует встроенное официальное решение благодаря модулю QtGraphicalEffects
, и я очень удивлен, обнаружив, что никто не предоставил такое простое решение.
Среди других эффектов OpacityMask
это тип, который будет использоваться для этой цели.Идея состоит в том, чтобы замаскировать источник Image
с Rectangle
, который имеет правильно установленный radius
.Вот самый простой пример использования 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)
}
}
}
}
Этот минимальный код дает хороший результат для квадратных изображений, но он также учитывает неквадратные изображения через переменную adapt
.При установке флажка false
полученная маска всегда будет кругом, независимо от размера изображения.Это возможно благодаря использованию внешнего Item
, который заполняет источник и позволяет определять размер реальной маски (внутренней Rectangle
) по желанию. Очевидно, что вы можете избавиться от внешнего Item
, если просто нацелитесь на маску, которая заполняет источник, независимо от его соотношения сторон .
Вот изображение милого кота с квадратным форматом ( слева ), неквадратным форматом с adapt: true
( center ) и, наконец, не квадратнымформат и adapt: false
( вправо ):
Детали реализации этого решения очень похожи на детали шейдерана основе ответа в другом хороший ответ (ср. исходный код QML для OpacityMask
, который можно найти здесь - SourceProxy
просто возвращает правильно сформированный ShaderEffectSource
в
Если вы не хотите зависеть от модуля QtGraphicalEffects
(ну, на самом деле, от наличия OpacityMask.qml
), вы можете переопределить эффект с помощью шейдеров.Помимо уже предоставленного решения, другой подход заключается в использовании функций step
, smoothstep
и fwidth
.Вот код:
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;
}"
}
}
Аналогично первому подходу, свойства rounded
и adapt
добавлены для управления визуальным оформлением.эффекта, как описано выше.