WPF 'волшебство', инвертирующее кисть?

У меня есть градиент, который изменяет его цвета, я хочу текст в нем, должно всегда быть видимо.

Я довольно делающий это динамично, если существует какой-либо ресурс-поля; я хочу 'волшебную кисть', которая инвертирует цвет.

Какие-либо эксперименты?

10
задан CharlesB 4 May 2012 в 23:45
поделиться

2 ответа

Ну, инверсия цвета может быть сделана как растровый эффект, но есть более простой способ.

Создайте Grid, которая будет контейнером для 3 дочерних панелей так, чтобы эти дочерние панели полностью перекрывали друг друга:

Поместите текст там, где вы хотите, в панель, которая имеет Transparent фон (они имеют его по умолчанию). Назовите эту панель 'mask'.

Сделайте еще одну панель под названием "mainbackground" и задайте ей основной градиент в качестве фона. Расположите ее после панели "маска" так, чтобы она закрывала текст

Сделайте еще одну панель под названием "инвертированный фон" и задайте ей противоположный градиент. Для каждого значения цвета в основном градиенте дайте противоположное значение в этом (например, если один цвет #FF0000, поставьте #00FFFF). Вы можете анимировать этот градиент так же, как и первый, только с противоположными значениями. Затем установите OpacityMask этой панели на VisualBrush и установите VisualBrushes свойство Visual на {Binding ElementName=mask}.

<Grid>
    <Grid.Resources>
        <local:MyColorConverter x:Key="colorConverter" />
    </Grid.Resources>
    <Grid
        Name="mask">
        <TextBlock
            Name="mytext"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            FontSize="32"
            Foreground="White"
            FontWeight="Bold">Blah blah blah</TextBlock>
    </Grid>

    <Grid Name="mainbackground">
        <Grid.Background>
            <LinearGradientBrush
                ColorInterpolationMode="ScRgbLinearInterpolation"
                EndPoint="1,0">
                <GradientStop x:Name="stop1"
                    Color="#FF0000"
                    Offset="0" />
                <GradientStop x:Name="stop2"
                    Color="#00FF00"
                    Offset="0.5" />
                <GradientStop x:Name="stop3"
                    Color="#0000FF"
                    Offset="1" />
            </LinearGradientBrush>
        </Grid.Background>
    </Grid>

    <Grid Name="invertedforeground">
        <Grid.Background>
            <LinearGradientBrush
                ColorInterpolationMode="ScRgbLinearInterpolation"
                EndPoint="1,0">
                <GradientStop
                    Color="{Binding ElementName=stop1, Path=Color, Converter={StaticResource colorConverter}}"
                    Offset="0" />
                <GradientStop
                    Color="{Binding ElementName=stop2, Path=Color, Converter={StaticResource colorConverter}}"
                    Offset="0.5" />
                <GradientStop
                    Color="{Binding ElementName=stop3, Path=Color, Converter={StaticResource colorConverter}}"
                    Offset="1" />
            </LinearGradientBrush>
        </Grid.Background>
        <Grid.OpacityMask>
            <VisualBrush
                Visual="{Binding ElementName=mask}" />
        </Grid.OpacityMask>
    </Grid>
</Grid>

Возможно, вы можете использовать привязку и конвертеры значений, чтобы вам нужно было анимировать только один градиент, а другой просто следовал за ним.


Правка: Я попробовал установить инвертированную кисть Foreground для текста, но она прилипала к координатам TextBlock, поэтому я вернулся к предыдущему решению использовать текст в качестве OpacityMask.


Edit 2: Я добавил пример использования пользовательского IValueConverter и привязки цветов градиента текста к цветам исходного градиента. Можно также использовать привязку и конвертер где-нибудь выше, например, привязать свойство invertedforeground Background к свойству mainbackground Background, а конвертер принимает входную кисть градиента и возвращает другую кисть градиента (это позволяет создать градиент с конфигурацией, значительно отличающейся от исходной).

6
ответ дан 3 December 2019 в 23:12
поделиться

Джоэл дал отличный ответ о том, как выровнять градиентные кисти. Я хотел бы коснуться сложностей автоматического создания новой градиентной кисти, которая гарантированно будет видна на фоне старой.

В WPF цвета моделируются трехмерно, поскольку для определения цвета WPF требуется три числа (например, R / G / B или H / S / B), не считая альфа-компонента. Заданную градиентную заливку можно рассматривать как путь, переходящий от одной цветовой точки к другой в трехмерном цветовом пространстве. Для создания обратного градиента, который контрастирует в каждой точке, требуется создание дополнительного пути, который ни в одной точке не подходит «слишком близко» к исходному пути. «Слишком близко» для этой цели - это любые два цвета, которые трудно различить человеческому глазу. На самом деле это субъективно. Примерно 4% людей, страдающих дальтонизмом, будут иметь другое толкование слова «слишком близко», чем те, кто этого не делает.

Для человека, не страдающего дальтонизмом, когда разумно определено «слишком близко», всегда найдется множество путей, удовлетворяющих критериям. В этом случае необходимы дополнительные критерии, чтобы решить, какой из них «лучше».Например, должен ли текст максимально резко контрастировать с фоном или он должен иметь одинаковый общий оттенок большую часть времени?

С другой стороны, консервативное определение слова «слишком близко», учитывающее цветовое восприятие каждого. во внимание, например, «яркость должна отличаться не менее чем на 25%», возникнет противоположная проблема: единственный градиент, который удовлетворяет условию в каждой точке, должен фактически быть прерывистым, то есть он должен переходить от одного цвета к другому цвету в любой момент. однажды. Рассмотрим, например, простой градиент от черного к белому. Если задействована только яркость, контрастный фон должен иметь неоднородность, иначе в какой-то момент он будет совпадать.

По этим причинам создание общего алгоритма для создания контрастного фона - это больше искусство, чем наука. Можно использовать несколько алгоритмов, и разные алгоритмы будут подходить в разных ситуациях.

Для этой цели использовался простой алгоритм: сохранить оттенок и насыщенность такими же, как у градиента, и установить яркость на (яркость + 50%) по модулю 100% . Однако этот алгоритм в большинстве случаев не дает очень эстетичных результатов, и у него никогда не бывает отклонений яркости более чем на 50%. Модификация этого алгоритма заключается в инвертировании или смещении значений оттенка и насыщенности.

Еще более простой алгоритм вычисления контрастной яркости: яркость> 50%? 0%: 100% . Это также может иметь эстетические проблемы.

Суть в том, что нет единственного правильного ответа на инвертирование цветов градиента.Но если у вас есть алгоритм для этого, то можно использовать технику маски непрозрачности Джоэла вместе с привязкой и IValueConverter, который реализует ваш алгоритм.

8
ответ дан 3 December 2019 в 23:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: