[英]How to Invert Color of XAML PNG Images using C#?
我正在使用Visual Studio,C#,XAML,WPF。
在我的程序中,我有带有白色png图标的XAML按钮。
我想拥有它,所以你可以通过从ComboBox中选择主题来切换到带有黑色图标的主题。
不是创建一组新的黑色png图像,有没有办法使用XAML和C#我可以反转白色图标的颜色?
<Button x:Name="btnInfo" HorizontalAlignment="Left" Margin="10,233,0,0" VerticalAlignment="Top" Width="22" Height="22" Cursor="Hand" Click="buttonInfo_Click" Style="{DynamicResource ButtonSmall}">
<Image Source="Resources/Images/info.png" Width="5" Height="10" Stretch="Uniform" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="1,0,0,0"/>
</Button>
谢谢你提出这个问题。 它给了我一个学习新东西的机会。 :)
你的目标是,一旦你知道自己在做什么,就很容易实现。 WPF支持使用GPU着色器修改图像。 它们在运行时很快(因为它们在您的视频卡中执行)并且易于应用。 并且在所述目标反转颜色的情况下,也非常容易实现。
首先,您需要着色器代码。 着色器使用称为高级着色器语言 (HLSL)的语言编写。 这是一个HLSL“程序”,它将反转输入颜色:
sampler2D input : register(s0);
float4 main(float2 uv : TEXCOORD) : COLOR
{
float4 color = tex2D(input, uv);
float alpha = color.a;
color = 1 - color;
color.a = alpha;
color.rgb *= alpha;
return color;
}
但是,Visual Studio不直接处理这种代码。 您需要确保安装了DirectX SDK,它将为您提供用于编译着色器代码的fxc.exe编译器。
我用这个命令行编译了上面的代码:
fxc /T ps_3_0 /E main /Fo<my shader file>.ps <my shader file>.hlsl
当然,您将<my shader file>
替换为您的实际文件名。
(注意:我手动执行此操作,但您当然可以在项目中创建自定义构建操作以执行相同操作。)
然后,您可以在项目中包含.ps
文件,将“Build Action”设置为“Resource” 。
完成后,您现在需要创建将使用它的ShaderEffect
类。 看起来像这样:
class InvertEffect : ShaderEffect
{
private static readonly PixelShader _shader =
new PixelShader { UriSource = new Uri("pack://application:,,,/<my shader file>.ps") };
public InvertEffect()
{
PixelShader = _shader;
UpdateShaderValue(InputProperty);
}
public Brush Input
{
get { return (Brush)GetValue(InputProperty); }
set { SetValue(InputProperty, value); }
}
public static readonly DependencyProperty InputProperty =
ShaderEffect.RegisterPixelShaderSamplerProperty("Input", typeof(InvertEffect), 0);
}
以上代码的要点:
static readonly
字段。 由于.ps
文件作为资源包含在内,我可以使用pack:
scheme来引用它,如"pack://application:,,,/<my shader file>.ps"
。 同样,您需要将<my shader file>
替换为实际的文件名。 PixelShader
属性设置为着色器对象。 您还必须调用UpdateShaderValue()
来初始化着色器,对于用作着色器输入的每个属性(在这种情况下,只有一个)。 Input
属性是特殊的:它需要使用RegisterPixelShaderSamplerProperty()
来注册依赖项属性。 DependencyProperty.Register()
注册它们。 但是它们需要一个特殊的PropertyChangedCallback
值,通过调用ShaderEffect.PixelShaderConstantCallback()
获得该参数的着色器代码中声明的寄存器索引。 这里的所有都是它的!
只需将UIElement.Effect
属性设置为InvertEffect
类的实例,就可以在XAML中使用上述内容。 例如:
<Window x:Class="TestSO45093399PixelShader.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:l="clr-namespace:TestSO45093399PixelShader"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Rectangle Width="100" Height="100">
<Rectangle.Fill>
<LinearGradientBrush>
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
<Rectangle.Effect>
<l:InvertEffect/>
</Rectangle.Effect>
</Rectangle>
</Grid>
</Window>
当你运行它时,你会注意到即使渐变在左下角转换为白色的左上角定义为黑色,它也会以相反的方式显示,左上角为白色,下半部分为黑色。 -对。
最后,关于偶然的机会你想立即让它工作,并且无法访问fxc.exe编译器,这里是上面的一个版本,它具有嵌入Base64的编译着色器代码。 它很小,所以这是编译和包含着色器作为资源的实用替代方法。
class InvertEffect : ShaderEffect
{
private const string _kshaderAsBase64 =
@"AAP///7/HwBDVEFCHAAAAE8AAAAAA///AQAAABwAAAAAAQAASAAAADAAAAADAAAAAQACADgAAAAA
AAAAaW5wdXQAq6sEAAwAAQABAAEAAAAAAAAAcHNfM18wAE1pY3Jvc29mdCAoUikgSExTTCBTaGFk
ZXIgQ29tcGlsZXIgMTAuMQCrUQAABQAAD6AAAIA/AAAAAAAAAAAAAAAAHwAAAgUAAIAAAAOQHwAA
AgAAAJAACA+gQgAAAwAAD4AAAOSQAAjkoAIAAAMAAAeAAADkgQAAAKAFAAADAAgHgAAA/4AAAOSA
AQAAAgAICIAAAP+A//8AAA==";
private static readonly PixelShader _shader;
static InvertEffect()
{
_shader = new PixelShader();
_shader.SetStreamSource(new MemoryStream(Convert.FromBase64String(_kshaderAsBase64)));
}
public InvertEffect()
{
PixelShader = _shader;
UpdateShaderValue(InputProperty);
}
public Brush Input
{
get { return (Brush)GetValue(InputProperty); }
set { SetValue(InputProperty, value); }
}
public static readonly DependencyProperty InputProperty =
ShaderEffect.RegisterPixelShaderSamplerProperty("Input", typeof(InvertEffect), 0);
}
最后,我会注意到Bradley评论中提供的链接确实包含了大量这些着色器实现的效果。 那些实现了HLSL和ShaderEffect
对象的作者与我在这里展示的方式略有不同,所以如果你想看到其他效果的例子和实现它们的不同方法,那么浏览这些代码将是一个很好看的地方。
请享用!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.