优秀的编程知识分享平台

网站首页 > 技术文章 正文

WPF 对应用程序进行灰度设置(wps灰度)

nanyue 2024-07-25 05:47:09 技术文章 18 ℃

WPF 对应用程序进行灰度设置

控件名:GrayscaleEffect

作 者:WPFDevelopersOrg - 驚鏵

原文链接[1]:https://github.com/WPFDevelopersOrg/WPFDevelopers
简易源码[2]:https://github.com/yanjinhuagood/WPFApplicationGrayscale

  • 框架使用.NET4 至 .NET6

  • Visual Studio 2019;

  • 如果要实现灰度第一反是使用主题色更改,但是使用主题色需要重新配色比较慢,需 Effect 类派生以实现自定义位图效果,将使用ShaderEffect[3]进行更改灰度,从 ShaderEffect 类派生,以基于单个像素着色器实现自定义效果。

  • 必须安装 .NET Framework 3.5 sp1 或更高版本才能正常工作。

  • 需要安装DirectX SDK才能编译像素着色器效果。
    • PixelShader[4]从预编译的高级着色语言 (HLSL) 字节代码加载 。
    • 定义表示效果参数和基于表面输入的 Brush 依赖属性。使用其中 RegisterPixelShaderSamplerProperty[5] 一个重载将这些输入与 HLSL 字节码中引用的寄存器号相关联。
    • DirectX SDK[6]
    • 下载完成DirectX SDK安装完成。
  • 到安装目录下\Utilities\bin\x86执行以下命令,就会输出.ps文件。
  • Nuget 最新[7]Install-Package WPFDevelopers 1.1.0.2-preview3
  • 推荐使用Shazzam Shader Editor[8]进行编辑。

1) GrayscaleEffect.hlsl 代码如下:

HLSL 语言编写的像素着色器(Pixel Shader)代码:


  1. 对输入纹理进行采样得到每个像素的颜色值。

    1. 对每个像素的 R、G、B 值进行除以 A 值操作,以避免由于透明度不同而产生的颜色变化。

    1. 对每个像素的亮度进行调整,通过修改 brightness 参数来控制亮度。

    1. 将每个像素转换为灰度值。

    1. 对转换后的每个像素的 R、G、B 值进行进一步的处理,通过修改 factor 参数来控制调整效果。

    1. 返回调整后的像素颜色值。
  • sampler2D:纹理采样器类型,用于从纹理中提取像素颜色信息。
  • register():用于定义常量寄存器和纹理寄存器等,类似于 C++ 中的变量声明。
  • float:浮点数类型。
  • TEXCOORD:纹理坐标通道类型,表示 UV 坐标数据。
  • COLOR:输出颜色类型,表示最终渲染的像素颜色信息。
  • tex2D():采样纹理函数,用于从纹理中提取指定纹理坐标处的像素颜色值。
  • sqrt():开方函数,用于计算灰度值。
  • float4 result:表示颜色值的四维向量类型。result.rresult.gresult.bresult.a 分别表示 RGB 值和 Alpha 值。
  • sampler2D implicitInput : register(s0);
    float factor : register(c0);

    /// <summary>The brightness offset.</summary>
    /// <minValue>-1</minValue>
    /// <maxValue>1</maxValue>
    /// <defaultValue>0</defaultValue>
    float brightness : register(c1);

    float4 main(float2 uv : TEXCOORD) : COLOR
    {
    float4 pixelColor = tex2D(implicitInput, uv);
    pixelColor.rgb /= pixelColor.a;

    // Apply brightness.
    pixelColor.rgb += brightness;

    // Return final pixel color.
    pixelColor.rgb *= pixelColor.a;

    float4 color = pixelColor;

    float pr = .299;
    float pg = .587;
    float pb = .114;

    float gray = sqrt(color.r * color.r * pr + color.g * color.g * pg + color.b * color.b * pb);

    float4 result;
    result.r = (color.r - gray) * factor + gray;
    result.g = (color.g - gray) * factor + gray;
    result.b = (color.b - gray) * factor + gray;
    result.a = color.a;

    return result;
    }

    2)执行命令 代码如下:

     fxc /T ps_2_0 /Fo E:\GrayscaleEffect\GrayscaleEffect.ps E:\GrayscaleEffect\GrayscaleEffect.hlsl

    3)得到以下文件

    4)新建GrayscaleEffect.cs 代码如下:

    • 继承自ShaderEffect类,并使用像素着色器(Pixel Shader)来实现灰度效果。

    • 在代码中定义了三个依赖属性,分别是InputFactorBrightness。其中:

    • Input属性表示作为着色器输入的Brush对象,可以是任何可用的画刷类型。

    • Factor属性表示灰度效果的因子。

    • Brightness属性表示效果的亮度。

    通过在构造函数中创建像素着色器对象,并将其设置为PixelShader属性,以及使用UpdateShaderValue方法更新着色器属性的值,完成特效的初始化工作。

    using System;
    using System.Windows;
    using System.Windows.Media;
    using System.Windows.Media.Effects;

    namespace WPFDevelopers
    {
    public class GrayscaleEffect : ShaderEffect
    {
    /// <summary>
    /// Identifies the Input property.
    /// </summary>
    public static readonly DependencyProperty InputProperty = RegisterPixelShaderSamplerProperty("Input", typeof(GrayscaleEffect), 0);

    /// <summary>
    /// Identifies the Factor property.
    /// </summary>
    public static readonly DependencyProperty FactorProperty = DependencyProperty.Register("Factor", typeof(double), typeof(GrayscaleEffect), new UIPropertyMetadata(0D, PixelShaderConstantCallback(0)));

    /// <summary>
    /// Identifies the Brightness property.
    /// </summary>
    public static readonly DependencyProperty BrightnessProperty = DependencyProperty.Register("Brightness", typeof(double), typeof(GrayscaleEffect), new UIPropertyMetadata(0D, PixelShaderConstantCallback(1)));

    /// <summary>
    /// Creates a new instance of the <see cref="GrayscaleEffect"/> class.
    /// </summary>
    public GrayscaleEffect()
    {
    var pixelShader = new PixelShader();
    pixelShader.UriSource = new Uri("WPFDevelopers;component/Effects/GrayscaleEffect.ps", UriKind.Relative);

    PixelShader = pixelShader;

    UpdateShaderValue(InputProperty);
    UpdateShaderValue(FactorProperty);
    UpdateShaderValue(BrightnessProperty);
    }

    /// <summary>
    /// Gets or sets the <see cref="Brush"/> used as input for the shader.
    /// </summary>
    public Brush Input
    {
    get => ((Brush)(GetValue(InputProperty)));
    set => SetValue(InputProperty, value);
    }

    /// <summary>
    /// Gets or sets the factor used in the shader.
    /// </summary>
    public double Factor
    {
    get => ((double)(GetValue(FactorProperty)));
    set => SetValue(FactorProperty, value);
    }

    /// <summary>
    /// Gets or sets the brightness of the effect.
    /// </summary>
    public double Brightness
    {
    get => ((double)(GetValue(BrightnessProperty)));
    set => SetValue(BrightnessProperty, value);
    }
    }
    }

    5)使用Window.Xaml 代码如下,默认原色:

    <wd:Window x:Class="WPFDevelopers.Samples.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:wd="https://github.com/WPFDevelopersOrg/WPFDevelopers">

    <wd:Window.Effect>
    <wd:GrayscaleEffect x:Name="grayscaleEffect" Factor="1"/>
    </wd:Window.Effect>
    <TextBlock Text="开启程序灰度" FontSize="20" Margin="0,20,0,0"/>
    <ToggleButton Margin="10" Name="tbGrayscale"
    Checked="tbGrayscale_Checked"
    Unchecked="tbGrayscale_Unchecked"
    HorizontalAlignment="Left"/>

    6)使用Window.Xaml.cs 灰度代码如下:

    private void tbGrayscale_Checked(object sender, RoutedEventArgs e)
    {
    Create(0);
    }
    void Create(double to)
    {
    var sineEase = new SineEase() { EasingMode = EasingMode.EaseOut };
    var doubleAnimation = new DoubleAnimation
    {
    To = to,
    Duration = TimeSpan.FromMilliseconds(1000),
    EasingFunction = sineEase
    };
    grayscaleEffect.BeginAnimation(GrayscaleEffect.FactorProperty, doubleAnimation);
    }
    private void tbGrayscale_Unchecked(object sender, RoutedEventArgs e)
    {
    Create(1);
    }

    参考资料

    [1]

    原文链接: https://github.com/WPFDevelopersOrg/WPFDevelopers

    [2]

    简易源码: https://github.com/yanjinhuagood/WPFApplicationGrayscale

    [3]

    ShaderEffect: https://learn.microsoft.com/zh-cn/dotnet/api/system.windows.media.effects.shadereffect?view=windowsdesktop-7.0

    [4]

    PixelShader: https://learn.microsoft.com/zh-cn/dotnet/api/system.windows.media.effects.pixelshader?view=windowsdesktop-7.0

    [5]

    RegisterPixelShaderSamplerProperty: https://learn.microsoft.com/zh-cn/dotnet/api/system.windows.media.effects.shadereffect.registerpixelshadersamplerproperty?view=windowsdesktop-7.0

    [6]

    DirectX SDK: https://www.microsoft.com/zh-cn/download/details.aspx?id=6812

    [7]

    Nuget : https://www.nuget.org/packages/WPFDevelopers/

    [8]

    Shazzam Shader Editor: https://github.com/JohanLarsson/Shazzam


    Tags:

    最近发表
    标签列表