Подтвердить что ты не робот

Изображение округлых углов в 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"
    }
}

Как создать изображение с закругленными углами правильно?

4b9b3361

Ответ 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, который предварительно обрабатывает ваше изображение, чтобы закруглить углы.

Ответ 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"
    }
}