簡要說明:html
經過對示例圖片分別運用 LomoFilter和SketchFilter兩個濾鏡(Nokia Imaging SDK 內置),安全
來學習濾鏡的基本使用和參數的設置。本工程的代碼量比較少,也很容易理解。異步
版本 NokiaImagingSDK 1.0.272.0async
下面是這個 demo 的完成步驟:ide
1)經過 Visual Studio 2012 新建一個Windows Phone 8 的工程,命名爲「FilterParametersSample」:函數
2) 右鍵單擊工程的「引用」,選擇「管理 NuGet程序包」:學習
在右上角搜索框輸入「Nokia Imaging SDK」,並安裝該 SDK:spa
3)由於本次實驗使用模擬器調試,因此須要在「配置管理器」選擇「x86」(Visual Studio菜單 -> 生成 -> 配置管理器):線程
注:關於添加 Nokia Imaging SDK後 VS 的設置請參考:Download and add the libraries to the project3d
4)在項目的根目錄下添加一張示例圖片 「Sample.jpg」:
5)在 MainPage.xaml 頁面中添加一個 Image 控件(顯示原圖)和兩個 Button 控件,單擊 Button 後,分別跳轉
到 LomoFilterPage.xaml 和 SketchFilterPage.xaml頁面。用下面的 XAML 替換掉 MainPage 頁面中名爲 LayoutRoot 的 grid:
<!--LayoutRoot 是包含全部頁面內容的根網格--> <Grid x:Name="LayoutRoot" Background="Transparent"> <Image Source="/Sample.jpg" Margin="117,82,89,231"/> <Button Content="LomoFilter" HorizontalAlignment="Left" Margin="25,669,0,0" VerticalAlignment="Top"
Width="209" Click="LomoFilter_Button_Click"/> <Button Content="Sketch" HorizontalAlignment="Left" Margin="239,669,0,0"
VerticalAlignment="Top" Width="205" Click="SketchFilter_Button_Click"/> </Grid>
在 MainPage.xaml.cs 頁面添加相應的按鈕事件:
// Lomo (自由濾鏡) private void LomoFilter_Button_Click(object sender, RoutedEventArgs e) { NavigationService.Navigate(new Uri("/Pages/LomoFilterPage.xaml", UriKind.Relative)); } // Sketch 素描濾鏡
private void SketchFilter_Button_Click(object sender, RoutedEventArgs e) { NavigationService.Navigate(new Uri("/Pages/SketchFilterPage.xaml", UriKind.Relative)); }
6)新建一個名爲「Pages」的文件夾,在頁面中分別添加兩個頁面:
LomoFilterPage.xaml 和 SketchFilterPage.xaml,分別用來處理 Lomo 濾鏡和 Sketch濾鏡。
7)首先打開 SketchFilterPage.xaml 頁面,在 XAML 頁面添加一個 Image 控件和兩個RadioButton 控件,
分別用來顯示預覽圖和切換濾鏡模式:
<Grid x:Name="LayoutRoot" Background="Transparent" Tap="LayoutRoot_Tap"> <Image x:Name="PreviewImage"/> <Grid x:Name="gridControls" VerticalAlignment="Bottom" Background="#44ffffff" > <Grid.Resources> <Style TargetType="TextBlock"> <Setter Property="Margin" Value="20,0,0,0"/> <Setter Property="Foreground" Value="#ffffffff"/> <Setter Property="FontWeight" Value="ExtraBold"/> </Style> </Grid.Resources> <Grid.RowDefinitions> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> </Grid.RowDefinitions> <TextBlock Text="素描模式:"/> <StackPanel Orientation="Horizontal" Grid.Row="1" Background="{StaticResource PhoneAccentBrush}"> <RadioButton Content="Gray" GroupName="Mode" Checked="Gray_RadioButton_Checked"/> <RadioButton Content="Color" GroupName="Mode" Checked="Color_RadioButton_Checked"/> </StackPanel> </Grid> </Grid>
上面的 gridControls 用來做爲「操做面板」,當單擊 LayoutRoot 控件時,切換它的隱藏和顯示:
// 切換控制面板 private void LayoutRoot_Tap(object sender, System.Windows.Input.GestureEventArgs e) { e.Handled = true; if (gridControls.Visibility == System.Windows.Visibility.Collapsed) { gridControls.Visibility = System.Windows.Visibility.Visible; } else { gridControls.Visibility = System.Windows.Visibility.Collapsed; } }
8)另外在 SketchFilterPage.xaml.cs 頁面中,聲明三個變量:
// 使用濾鏡 SketchMode _sketchMode = SketchMode.Gray; Stream _imageStreamOrigin;// 保存圖片的原始數據 WriteableBitmap _writeBitmap; //輸出結果
9)在構造函數中,讀取示例圖片的流,用來稍後添加濾鏡:
public SketchFilterPage() { InitializeComponent(); // 獲取 xap 包中的 圖片 StreamResourceInfo StreamInfo = App.GetResourceStream(new Uri("Sample.jpg", UriKind.Relative)); // 先把未通過濾鏡處理的示例圖片顯示出來 BitmapImage bitmapImage = new BitmapImage(); bitmapImage.SetSource(StreamInfo.Stream); _writeBitmap = new WriteableBitmap(bitmapImage); PreviewImage.Source = _writeBitmap; // 保存示例圖片的流,用於接下來添加濾鏡 _imageStreamOrigin = StreamInfo.Stream; }
10)添加兩個 RadioButton 的 Checked 事件,用來爲圖片運用不一樣的濾鏡效果:
// 灰色 private void Gray_RadioButton_Checked(object sender, RoutedEventArgs e) { _sketchMode = SketchMode.Gray; CreatePreviewImage(); } // 彩色 private void Color_RadioButton_Checked(object sender, RoutedEventArgs e) { _sketchMode = SketchMode.Color; CreatePreviewImage(); }
11)最後添加 CreatePreviewImage() 方法,對圖片運用濾鏡效果:
public async void CreatePreviewImage() { if (_imageStreamOrigin == null || _writeBitmap == null) { return; } _imageStreamOrigin.Position = 0; // 運用這個濾鏡效果 var filters = new IFilter[] { new SketchFilter(_sketchMode) }; using (var source = new StreamImageSource(_imageStreamOrigin)) using (var filterEffect = new FilterEffect(source) { Filters = filters }) using (var renderer = new WriteableBitmapRenderer(filterEffect, _writeBitmap)) { await renderer.RenderAsync(); PreviewImage.Source = _writeBitmap; } }
12)當分別點擊「草圖濾鏡」(SketchFilter)的兩個 RadioButton 時,運行效果:
13) 接下來在LomoFilterPage.xaml 頁面中,給示例圖片添加 LomoFilter:
和上面同樣,首先添加一個 Image 控件,用來顯示圖片預覽;而後添加兩個 Silder控件,分別調整濾鏡的亮度、
飽和度;最後添加兩組 RadioButton控件,分別用來調整濾鏡的「光暈」模式和「顏色風格」,相應的 XAML以下:
<!--LayoutRoot 是包含全部頁面內容的根網格--> <Grid x:Name="LayoutRoot" Background="Transparent" Tap="LayoutRoot_Tap"> <Image x:Name="PreviewImage"/> <Grid x:Name="gridControls" Visibility="Collapsed" VerticalAlignment="Bottom" Background="#44ffffff" > <Grid.Resources> <Style TargetType="TextBlock"> <Setter Property="Margin" Value="20,0,0,0"/> <Setter Property="Foreground" Value="#ffffffff"/> <Setter Property="FontWeight" Value="ExtraBold"/> </Style> </Grid.Resources> <Grid.RowDefinitions> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> </Grid.RowDefinitions> <TextBlock Text="亮度:"/> <Slider Grid.Row="1" Value="0.5" Minimum="0" Maximum="1" ValueChanged="brightnessSlider_ValueChanged"/> <TextBlock Grid.Row="2" Text="飽和度:"/> <Slider Grid.Row="3" Value="0.5" Minimum="0" Maximum="1" ValueChanged="saturationSlider_ValueChanged"/> <TextBlock Grid.Row="4" Text="光暈:"/> <StackPanel Orientation="Horizontal" Grid.Row="5"> <RadioButton Content="Low" GroupName="LomoVignetting" Checked="lowRadioButton_Checked"/> <RadioButton Content="Medium" GroupName="LomoVignetting" Checked="medRadioButton_Checked"/> <RadioButton Content="High" GroupName="LomoVignetting" Checked="highRadioButton_Checked"/> </StackPanel> <TextBlock Grid.Row="6" Text="風格:"/> <StackPanel Orientation="Horizontal" Grid.Row="7"> <RadioButton Content="Red" GroupName="Style" Checked="Red_RadioButton_Checked"/> <RadioButton Content="Green" GroupName="Style" Checked="Green_RadioButton_Checked"/> <RadioButton Content="Blue" GroupName="Style" Checked="Blue_RadioButton_Checked"/> <RadioButton Content="Yellow" GroupName="Style" Checked="Yellow_RadioButton_Checked"/> </StackPanel> </Grid> </Grid>
14)在相應的 C# 頁面,首先聲明 6個變量,分別保存原始圖片流,和濾鏡的設置參數:
// 使用濾鏡 double _brightness = 0.5; double _saturation = 0.5; LomoVignetting _lomoVignetting = LomoVignetting.Medium; //光暈 LomoStyle _lomoStyle = LomoStyle.Neutral; Stream _imageStreamOrigin;// 保存圖片的原始數據 WriteableBitmap _writeBitmap;// 輸出結果
15)在構造函數中,首先讀取示例圖片的流,顯示未通過濾鏡處理的圖片:
public LomoFilterPage() { InitializeComponent(); // 獲取 xap 包中的 圖片 StreamResourceInfo StreamInfo = App.GetResourceStream(new Uri("Sample.jpg", UriKind.Relative)); // 先把未通過濾鏡處理的示例圖片顯示出來 BitmapImage bitmapImage = new BitmapImage(); bitmapImage.SetSource(StreamInfo.Stream); _writeBitmap = new WriteableBitmap(bitmapImage); PreviewImage.Source = _writeBitmap; // 保存示例圖片的流,用於接下來添加濾鏡 _imageStreamOrigin = StreamInfo.Stream; }
16)而後定義一個修改濾鏡的方法,每當 Silder 控件或者 RadioButton 控件修改濾鏡參數的時候,調用一次這個方法:
public async void CreatePreviewImage() { if (_imageStreamOrigin == null || _writeBitmap == null) { return; } _imageStreamOrigin.Position = 0; // 運用這個濾鏡效果 var filters = new IFilter[] { new LomoFilter(_brightness, _saturation, _lomoVignetting, _lomoStyle) }; using (var source = new StreamImageSource(_imageStreamOrigin)) using (var filterEffect = new FilterEffect(source) { Filters = filters }) using (var renderer = new WriteableBitmapRenderer(filterEffect, _writeBitmap)) { await renderer.RenderAsync(); PreviewImage.Source = _writeBitmap; } }
改進上面 CreatePreviewImage() 方法:
由於在給圖片運用濾鏡效果的時候,好比在拖動 Silder 的過程當中,由於上一次方法調用尚未完成,
也就是當代碼執行到 await renderer.RenderAsync(); 時,異步線程的操做尚未執行完,下一次
代碼再次執行,就可能會引起 線程安全 的問題,因此用一個小技巧修改一下上面的代碼,使用一個全局
的 IsBusying 布爾值,控制線程的調用:
bool IsBusying = false; public async void CreatePreviewImage() { if (_imageStreamOrigin == null || _writeBitmap == null) { return; } if (IsBusying) { return; // 若是正在運用一組參數,則返回 } IsBusying = true; _imageStreamOrigin.Position = 0; // 運用這個濾鏡效果 var filters = new IFilter[] { new LomoFilter(_brightness, _saturation, _lomoVignetting, _lomoStyle) }; using (var source = new StreamImageSource(_imageStreamOrigin)) using (var filterEffect = new FilterEffect(source) { Filters = filters }) using (var renderer = new WriteableBitmapRenderer(filterEffect, _writeBitmap)) { await renderer.RenderAsync(); //Windows.Foundation.IAsyncOperation<WriteableBitmap> ia = renderer.RenderAsync(); //ia.Cancel(); PreviewImage.Source = _writeBitmap; } IsBusying = false; }
固然,在調用複雜的狀況時,可使用 System.Threading.Semaphore 類 來限制訪問同一資源的線程數量,
或者 System.Threading.AutoResetEvent 控制線程的事件執行。
17)下面添加 SIider 和 RadioButton 控件的事件觸發的代碼,下面的代碼雖然比較多,但很容易理解:
#region 參數調整 private void brightnessSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { _brightness = 1.0 - e.NewValue; CreatePreviewImage(); } private void saturationSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { _saturation = e.NewValue; CreatePreviewImage(); } protected void lowRadioButton_Checked(object sender, System.Windows.RoutedEventArgs e) { _lomoVignetting = LomoVignetting.Low; CreatePreviewImage(); } protected void medRadioButton_Checked(object sender, System.Windows.RoutedEventArgs e) { _lomoVignetting = LomoVignetting.Medium; CreatePreviewImage(); } protected void highRadioButton_Checked(object sender, System.Windows.RoutedEventArgs e) { _lomoVignetting = LomoVignetting.High; CreatePreviewImage(); } private void Red_RadioButton_Checked(object sender, RoutedEventArgs e) { _lomoStyle = LomoStyle.Red; CreatePreviewImage(); } private void Green_RadioButton_Checked(object sender, RoutedEventArgs e) { _lomoStyle = LomoStyle.Green; CreatePreviewImage(); } private void Blue_RadioButton_Checked(object sender, RoutedEventArgs e) { _lomoStyle = LomoStyle.Blue; CreatePreviewImage(); } private void Yellow_RadioButton_Checked(object sender, RoutedEventArgs e) { _lomoStyle = LomoStyle.Yellow; CreatePreviewImage(); } #endregion
18)運行工程:
19) 總結:本實驗代碼量比較少,也很容易理解。有關 Nokia Imaging SDK 濾鏡使用流程,請參考相關文檔。
工程下載連接: http://pan.baidu.com/s/1eXV4q
在運行源代碼時,會出現一個編譯錯誤: Nokia Imaging SDK does not support the AnyCPU target platform.
由於 Nokia Imaging SDK 支持託管代碼和本地代碼,因此在編譯前須要進行設置:
1)在模擬器上運行時:菜單 -> 生成 -> 配置管理器 -> 活動解決方案平臺 -> x86 2)在真機上運行時: 菜單 -> 生成 -> 配置管理器 -> 活動解決方案平臺 -> ARM