简要说明

通过对示例图片分别运用 LomoFilterSketchFilter两个滤镜(Nokia Imaging SDK 内置),

来学习滤镜的基本使用和参数的设置。本工程的代码量比较少,也很容易理解。

版本 NokiaImagingSDK  1.0.272.0

 

下面是这个 demo 的完成步骤:

1)通过 Visual Studio 2012 新建一个Windows Phone 8 的工程,命名为“FilterParametersSample”:

Nokia Imaging SDK滤镜使用入门

 

2) 右键单击工程的“引用”,选择“管理 NuGet程序包”:

Nokia Imaging SDK滤镜使用入门

在右上角搜索框输入“Nokia Imaging SDK”,并安装该 SDK:

Nokia Imaging SDK滤镜使用入门

 

3)因为本次实验使用模拟器调试,所以需要在“配置管理器”选择“x86”(Visual Studio菜单 -> 生成 -> 配置管理器):

Nokia Imaging SDK滤镜使用入门

注:关于添加 Nokia Imaging SDK后 VS 的设置请参考:Download and add the libraries to the project

 

4)在项目的根目录下添加一张示例图片 “Sample.jpg”:

Nokia Imaging SDK滤镜使用入门

 

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 时,运行效果:

Nokia Imaging SDK滤镜使用入门

 

 

 

 

 

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;
        }
View Code

相关文章: