原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。
生成的效果
生成效果的方法:我主要是通過參考Shazzam Shader Editor來編寫HLSL像素著色器。
HLSL(High Level Shader Language,高級著色器語言)是Direct3D著色器模型所需的一種語言。WPF不僅支持Direct3D 9,還支持使用HLSL來創建著色器。雖然可以使用多種編輯器來編寫HLSL,但Shazzam Shader Editor是一款專為WPF設計的編輯器,它專門用於實現像素著色器。使用Shazzam可以簡化將像素著色器集成到WPF項目中所需的各種手動操作。(關於如何使用Shazzam,可線上查找詳細教程。)
在我的項目中,我根據所需的效果生成相應的.PS和.CS文件,並將這些文件添加到類庫中。接著,我會在具體的項目中引入這個庫來實現效果
項目實現細節
開發環境
- 使用的MVVM庫:CommunityToolkit.Mvvm
- 目標框架:.NET 8.0
- 開發工具:Visual Studio 2022
使用的樣式庫
項目中採用了AduSkin樣式庫。個人建議:我不特別推薦使用AduSkin,主要是因為它缺乏官方文檔,需要通過查看源代碼來學習使用。此外,一些樣式的命名與源代碼中的不一致,這可能會導致一些困惑。(備註:我最初選擇使用AduSkin是因為其UI設計在網路上獲得了好評,儘管某些效果確實很吸引人,但缺少文檔導致使用上的不便。)
項目結構概述
項目在構建過程中,考慮到幾種特效之間存在一些共同的重覆元素,如圖片展示和圖片導入功能,因此我將這些共用功能模塊化。
- 操作區域的定製化:對於每種不同的特效,操作區的需求也不盡相同。在Common控制項中,我使用了Option控制項來進行替代,以便於在外部進行定製。
- 特效的動態調整:每種特效的具體實現都有所不同,因此我設定了一個獨立的屬性
ImageEffect
,允許從外部動態修改。 - 公共控制項:
CommonEffectControl
作為一個公共控制項,用於整合圖片顯示和圖片導入的共通功能。
具體引用的步驟
需要添加命令空間
xmlns:common="clr-namespace:CT.WPF.MagicEffects.Demo.UserControls.Common"
前臺代碼
查看代碼 <common:CommonEffectControl ImageEffect="{Binding SelectedOrdinary.ObjectShaderEffect}">
<common:CommonEffectControl.Option>
<StackPanel Orientation="Vertical">
<Border BorderBrush="Transparent" BorderThickness="0">
<Skin:MetroScrollViewer ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListView
Width="240"
Height="550"
BorderThickness="0"
ItemsSource="{Binding Ordinarys}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
SelectedItem="{Binding SelectedOrdinary, Mode=TwoWay}"
SelectionMode="Single">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel
MinHeight="110"
VerticalAlignment="Center"
Orientation="Vertical">
<Viewbox
Width="99"
Height="78"
Margin="2">
<Image Effect="{Binding ObjectShaderEffect}" Source="{Binding Path=Main.SelectedImagePath, Source={StaticResource Locator}}" />
</Viewbox>
<TextBlock
HorizontalAlignment="Center"
FontSize="14"
Foreground="{Binding RelativeSource={RelativeSource AncestorType={x:Type Skin:MetroWindow}}, Path=BorderBrush, Mode=TwoWay}"
Text="{Binding Title}"
TextWrapping="Wrap" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
</Skin:MetroScrollViewer>
</Border>
</StackPanel>
</common:CommonEffectControl.Option>
</common:CommonEffectControl>
ViewModel部分
查看代碼 partial class OrdinaryEffectViewModel : ObservableObject {
public OrdinaryEffectViewModel() {
Ordinarys = new ObservableCollection<Ordinarys> {
new Ordinarys(){ Title="灰度", ObjectShaderEffect= new GrayScaleEffect ()},
new Ordinarys(){ Title="位移", ObjectShaderEffect= new DirectionalBlurEffect ()},
new Ordinarys(){ Title="老電影", ObjectShaderEffect= new OldMovieEffect ()},
new Ordinarys(){ Title="銳化", ObjectShaderEffect= new SharpenEffect ()},
};
}
[ObservableProperty]
private ObservableCollection<Ordinarys> ordinarys;
[ObservableProperty]
private Ordinarys selectedOrdinary;
}
model部分
查看代碼 partial class Ordinarys : ObservableObject {
[ObservableProperty]
private string? title;
[ObservableProperty]
private ShaderEffect? objectShaderEffect;
}
還有攝像頭濾鏡覆蓋的效果歡迎大家體驗!!!
已經發佈nuget:dotnet add package MagicEffects --version 1.0.0
github:CT.WPF.MagicEffects