У меня есть градиент, который изменяет его цвета, я хочу текст в нем, должно всегда быть видимо.
Я довольно делающий это динамично, если существует какой-либо ресурс-поля; я хочу 'волшебную кисть', которая инвертирует цвет.
Какие-либо эксперименты?
Ну, инверсия цвета может быть сделана как растровый эффект, но есть более простой способ.
Создайте 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
, а конвертер принимает входную кисть градиента и возвращает другую кисть градиента (это позволяет создать градиент с конфигурацией, значительно отличающейся от исходной).
Джоэл дал отличный ответ о том, как выровнять градиентные кисти. Я хотел бы коснуться сложностей автоматического создания новой градиентной кисти, которая гарантированно будет видна на фоне старой.
В WPF цвета моделируются трехмерно, поскольку для определения цвета WPF требуется три числа (например, R / G / B или H / S / B), не считая альфа-компонента. Заданную градиентную заливку можно рассматривать как путь, переходящий от одной цветовой точки к другой в трехмерном цветовом пространстве. Для создания обратного градиента, который контрастирует в каждой точке, требуется создание дополнительного пути, который ни в одной точке не подходит «слишком близко» к исходному пути. «Слишком близко» для этой цели - это любые два цвета, которые трудно различить человеческому глазу. На самом деле это субъективно. Примерно 4% людей, страдающих дальтонизмом, будут иметь другое толкование слова «слишком близко», чем те, кто этого не делает.
Для человека, не страдающего дальтонизмом, когда разумно определено «слишком близко», всегда найдется множество путей, удовлетворяющих критериям. В этом случае необходимы дополнительные критерии, чтобы решить, какой из них «лучше».Например, должен ли текст максимально резко контрастировать с фоном или он должен иметь одинаковый общий оттенок большую часть времени?
С другой стороны, консервативное определение слова «слишком близко», учитывающее цветовое восприятие каждого. во внимание, например, «яркость должна отличаться не менее чем на 25%», возникнет противоположная проблема: единственный градиент, который удовлетворяет условию в каждой точке, должен фактически быть прерывистым, то есть он должен переходить от одного цвета к другому цвету в любой момент. однажды. Рассмотрим, например, простой градиент от черного к белому. Если задействована только яркость, контрастный фон должен иметь неоднородность, иначе в какой-то момент он будет совпадать.
По этим причинам создание общего алгоритма для создания контрастного фона - это больше искусство, чем наука. Можно использовать несколько алгоритмов, и разные алгоритмы будут подходить в разных ситуациях.
Для этой цели использовался простой алгоритм: сохранить оттенок и насыщенность такими же, как у градиента, и установить яркость на (яркость + 50%) по модулю 100%
. Однако этот алгоритм в большинстве случаев не дает очень эстетичных результатов, и у него никогда не бывает отклонений яркости более чем на 50%. Модификация этого алгоритма заключается в инвертировании или смещении значений оттенка и насыщенности.
Еще более простой алгоритм вычисления контрастной яркости: яркость> 50%? 0%: 100%
. Это также может иметь эстетические проблемы.
Суть в том, что нет единственного правильного ответа на инвертирование цветов градиента.Но если у вас есть алгоритм для этого, то можно использовать технику маски непрозрачности Джоэла вместе с привязкой и IValueConverter, который реализует ваш алгоритм.