Изображение округлых углов в QML
К моему удивлению, компонент Image
не имеет свойства radius
. Я попытался имитировать закругленные углы, поместив изображение в закругленный Rectangle
, но он не закрепил углы.
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"
}
}
Как создать изображение с закругленными углами правильно?
Ответы
Ответ 1
Встроенное официальное решение существует с Qt 5 благодаря модулю QtGraphicalEffects
, и я очень удивлен, узнав, что никто не предоставил такое простое решение.
Среди других эффектов OpacityMask
- тип, который будет использоваться для этой цели. Идея состоит в том, чтобы замаскировать источник Image
с помощью Rectangle
, который имеет правильно установленный radius
. Вот простейший пример, используя layerering:
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
( справа):
![введите описание изображения здесь]()
Детали реализации этого решения очень похожи на данные ответа на основе шейдера в другом хорошем ответе (cfr. исходный код 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
для контроля визуального внешнего вида эффекта, как обсуждалось выше.
Ответ 2
Когда ваш фон является сплошным цветом или когда вы никогда не перемещаете изображение, быстрый способ сделать закругленные углы - это совместить ваш Image
с другим (или с BorderImage
), который только рисует углы.
Если это не опция, но вы используете OpenGL, тогда другой способ - применить маску к изображению через пиксельный шейдер. См. http://blog.qt.digia.com/blog/2011/05/03/qml-shadereffectitem-on-qgraphicsview/ для плагина, который работает поверх Qt 4.
Наконец, также можно написать QDeclarativeImageProvider
, который предварительно обрабатывает ваше изображение, чтобы закруглить углы.
Ответ 3
В настоящее время QML поддерживает только прямоугольное обрезание, но вы можете захотеть взглянуть на DeclarativeMaskedImage в проекте qt-components:
http://qt.gitorious.org/qt-components/qt-components/blobs/master/src/symbian/sdeclarativemaskedimage.h
Ответ 4
Если у вас есть одноцветный фон, вы можете рисовать с границей закругленного прямоугольника сверху.
Image{
id:img
}
Rectangle { // rounded corners for img
anchors.fill: img
color: "transparent"
border.color: "blue" // color of background
border.width: 4
radius: 4
}
Ответ 5
Этот код поможет вам
Rectangle {
width: 200
height: 200
color: "transparent"
//this Rectangle is needed to keep the source image 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"
}
}
Ответ 6
Я знаю, что немного опаздываю на вечеринку, но я попал сюда по поиску в Google, поэтому подумал, что буду помогать будущим поколениям:) QtGraphicalEffects OpacityMask должен сделать это немного проще (у меня были проблемы с подходом уровня эффекта )
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
}
}
Ответ 7
Хотя и принятый ответ, и тот из @fury работал одинаково хорошо для меня (Qt 5.9.3), они оба оставили некоторые аберрации в углах, когда они применяются для растровых изображений (у них не было SVG). То, что работало лучше всего для меня во всех случаях, заключалось в том, чтобы применить OpacityMask
к окружающему элементу, например. как прямоугольник в исходном сообщении.
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"
}
}