如果在应用中,如果想要给app 添加模糊滤镜,可能第一想到的是第三方类库,比如 Win2dlumia Imaging SDK 、WriteableBitmapEx,不可否认,这些类库功能强大,效果也挺多的。不足就是增加了生成包尺寸,由于增加了相应 dll  的引用,在 app运行时也会增加内存占用。如果只使用一种滤镜效果,建议直接添加几十行代码自己实现,这样开发、维护成本都会很少。并且由于 .net native 使得 uwp 的运算速度与 C++算法的运行速度没有差别了。

  这里只讨论高斯模糊滤镜,感觉这个滤镜在应用中适当的运用,会让页面形象生动,比如图片背景使用这个滤镜,会有一些磨砂玻璃的效果。针对高斯模糊的算法网上也有很多,这里使用戴震军

大哥的曾经移植过的 windows phone7 的算法。这里主要解决的就是 silverlight(wpf)中 WriteableBitmap 中图片数据 int[] 数组到 windows runtime(uwp)中 WriteableBitmap中 byte[] 的转换。

  Demo 的运行效果:

1)当不运用滤镜时 level 为 0(范围 0-40):

2)当 level 为 2时:

3)当 level 为 10时:

4)当 level 为 40时:

1、颜色值的分析:

1) 在 silverlight 或者 uwp 中,指定一个字体的前景色为绿色半透明:

  1. <TextBlock Text="节约用电" FontSize="30" Foreground="#8800FF00"/>

显示为:

则在前景色中颜色的设置信息:

2) 运算符概述:

<< 和 >> 为位移运算符,比如对于二进制来说  0010 << 2 (右移2位)的计算结果就是 1000,等于把十进制的 2 变成了 8

| 运算符为 “或”运算,比如对于二进制来说 0100 | 0010 的计算结果  0110,等于把十进制  4|2 变为了 6

2、分析 Silverlight 中 WriteableBitmap 对象中的 int[] 数组

对于 silverlight、wpf 平台上图片(jpg、png)的编辑 WriteablBitmap 对象中使用的 int[] 数组,每个 int 值同时包含了 A(alpha)、R(red)、G(green)、B(Blue)四个信息值,每个值的范围是 0~255。

1)在 silverlight中,获取图片像素数据( int[] 数组 ):

  1. // 100像素宽,100像素高
  2. WriteableBitmap bitmap = new WriteableBitmap(, );
  3.  
  4. // 获取表示位图 2D 纹理的数组。
  5. int[] data = bitmap.Pixels;

当然,这个 int[] 数组是一维数组,线性排列的。

3、分析 UWP 中 WriteableBitmap 类中的 byte[] 数组

对于 Windows Runtime (uwp) 中 WriteableBitmap 类来说,存储的图片数据为  byte[] 数组。

例如,获取一张图片中的像素数据(msdn 文档链接,WriteableBitmap):(WriteableBitmap 的图像源数据是基础像素缓冲区。WriteableBitmap.PixelBuffer不能直接写入)

  1. using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
  2. {
  3. BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fileStream);
  4. // Scale image to appropriate size
  5. BitmapTransform transform = new BitmapTransform() {
  6. ScaledWidth = Convert.ToUInt32(Scenario4WriteableBitmap.PixelWidth),
  7. ScaledHeight = Convert.ToUInt32(Scenario4WriteableBitmap.PixelHeight)
  8. };
  9. PixelDataProvider pixelData = await decoder.GetPixelDataAsync(
  10. BitmapPixelFormat.Bgra8, // WriteableBitmap 使用的是 BGRA 格式
  11. BitmapAlphaMode.Straight,
  12. transform,
  13. ExifOrientationMode.IgnoreExifOrientation, // This sample ignores Exif orientation
  14. ColorManagementMode.DoNotColorManage
  15. );
  16.  
  17. // 包含图片的解码数据。在呈现之前可以被修改
  18. byte[] sourcePixels = pixelData.DetachPixelData();
  19.  
  20. // 打开一个 image 的流,并且复制到 WriteableBitmap 的 pixel 缓冲区中
  21. using (Stream stream = writeableBitmap.PixelBuffer.AsStream())
  22. {
  23. await stream.WriteAsync(sourcePixels, , sourcePixels.Length);
  24. }
  25. }

同样,对于 1)中描述 100X100 的图片的数据存储,因为一个 int 可以包含 4个 byte位的信息,所以对于  100x100 的 int[] 数组值,也就是 10000个 int值组成。当转换为 byte[] 数组值时,数组长度扩大四倍,变为 100x100x4 = 40000个 byte值。并且 byte 值是按照 B、G、R、A 的顺序排列:

4、int[] 与 byte[] 的互相转换

因为戴震军大哥移植的滤镜算法为 windows phone7 的工程,所以图片数据的计算是采用 silverlight中 int[] 数组的计算方式,所以这里我只做了两件事,一个是把  uwp 工程中源 WriteableBitmap 对象中 byte[] 数组的存储方式,转换为 silverlight 中的 int[] 数组的存储方式,然后对图片数据进行添加滤镜算法的处理,当处理完成时,再把处理结果 int[] 数组的数据再转换为 uwp 中 WriteableBitmap 的 byte[] 数组的存储方式:

1)uwp 中 byte[] 数组,转换为 silverlight 的 int[] 数组:

  1. // 把 uwp 的 WriteableBitmap 对象的 PixelBuffer属性(IBuffer)转换为 byte[] 数组
  2. byte[] colorBytes = BufferToBytes(image.PixelBuffer);
  3.  
  4. // 转换为 silverlight 的 int[] 数组时,长度为 byte[] 数组的四分之一
  5. colorArray = new int[colorBytes.Length / ];
  6.  
  7. int a,r, g, b;
  8. int i = ; // 通过 i 自加,来遍历 byte[] 整个数组
  9.  
  10. // 通过图片的宽、高,分别设置 int[] 数组中每个像素的 ARGB 信息
  11. for (int y = ; y < height; y++)
  12. {
  13. for (int x = ; x < width; x++)
  14. {
  15. // int[] 数组的索引
  16. int index = y * width + x;
  17. b = colorBytes[i++]; // Blue
  18. g = colorBytes[i++]; // Green
  19. r = colorBytes[i++]; // Red
  20. a = colorBytes[i++]; // Alpha
  21. colorArray[index] = (a << ) | (r << ) | (g << ) | b; // 4个 byte值存储为一个 int 值
  22. }
  23. }

2)当把上面的图片数据,添加高斯模糊滤镜效果之后,把 silverlight 中 int[] 数组的计算结果,转换为 uwp 的 byte[] 数组:

  1. // 拷贝
  2. WriteableBitmap new_bitmap = await Utility.BitmapClone(wb);
  3.  
  4. // 添加高斯滤镜效果
  5. MyImage mi = new MyImage(new_bitmap);
  6. GaussianBlurFilter filter = new GaussianBlurFilter();
  7. filter.Sigma = level;
  8. filter.process(mi);
  9.  
  10. // 图片添加完滤镜的 int[] 数组
  11. int[] array = mi.colorArray;
  12.  
  13. // byte[] 数组的长度是 int[] 数组的 4倍
  14. byte[] result = new byte[array.Length * ];
  15.  
  16. // 通过自加,来遍历 byte[] 数组中的值
  17. int j = ;
  18. for (int i = ; i < array.Length; i++)
  19. {
  20. // 同时把 int 值中 a、r、g、b 的排列方式,转换为 byte数组中 b、g、r、a 的存储方式
  21. result[j++] = (byte)(array[i]); // Blue
  22. result[j++] = (byte)(array[i] >> ); // Green
  23. result[j++] = (byte)(array[i] >> ); // Red
  24. result[j++] = (byte)(array[i] >> ); // Alpha
  25. }
  26.  
  27. // Open a stream to copy the image contents to the WriteableBitmap's pixel buffer
  28. using (Stream stream = new_bitmap.PixelBuffer.AsStream())
  29. {
  30. await stream.WriteAsync(result, , result.Length);
  31. }
  32.  
  33. img.Source = new_bitmap;// 把最终 WriteableBitmap 对象赋值给 Image 控件

5、代码中会用到的自定义帮助类:

  1. namespace BlurEffect_demo
  2. {
  3. class Utility
  4. {
  5. /// <summary>
  6. /// WriteableBitmap 的拷贝
  7. /// </summary>
  8. /// <param name="bitmap">原</param>
  9. /// <returns></returns>
  10. public static async Task<WriteableBitmap> BitmapClone(WriteableBitmap bitmap)
  11. {
  12. WriteableBitmap result = new WriteableBitmap(bitmap.PixelWidth, bitmap.PixelHeight);
  13.  
  14. byte[] sourcePixels = Get_WriteableBitmap_bytes(bitmap);
  15.  
  16. //byte[] resultPixels = new byte[sourcePixels.Length];
  17.  
  18. //sourcePixels.CopyTo(resultPixels, 0);
  19.  
  20. using (Stream resultStream = result.PixelBuffer.AsStream())
  21. {
  22. await resultStream.WriteAsync(sourcePixels, , sourcePixels.Length);
  23. }
  24. return result;
  25. }
  26.  
  27. /// <summary>
  28. /// 获取 WriteableBitmap 对象中的 byte[] 数组数据
  29. /// </summary>
  30. public static byte[] Get_WriteableBitmap_bytes(WriteableBitmap bitmap)
  31. {
  32. // 获取对直接缓冲区的访问,WriteableBitmap 的每个像素都写入直接缓冲区。
  33. IBuffer bitmapBuffer = bitmap.PixelBuffer;
  34.  
  35. //byte[] sourcePixels = new byte[bitmapBuffer.Length];
  36. //Windows.Security.Cryptography.CryptographicBuffer.CopyToByteArray(bitmapBuffer, out sourcePixels);
  37. //bitmapBuffer.CopyTo(sourcePixels);
  38.  
  39. using (var dataReader = DataReader.FromBuffer(bitmapBuffer))
  40. {
  41. var bytes = new byte[bitmapBuffer.Capacity];
  42. dataReader.ReadBytes(bytes);
  43. return bytes;
  44. }
  45. }
  46. }
  47. }

6、高斯滤镜算法这里就不列出来了,具体可以参考 demo 工程

工程地址:link

参考阅读:

1)戴震军 :

blog : http://www.cnblogs.com/daizhj

github : https://github.com/daizhenjun/ImageFilterForWindowsPhone

2)WriteableBitmap.PixelBuffer property :https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.media.imaging.writeablebitmap.pixelbuffer.aspx

3)WriteableBitmap class : https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.media.imaging.writeablebitmap.aspx

4)WriteableBitmapEx : http://writeablebitmapex.codeplex.com/releases/view/612952

5)Getting Pixels of an Element(WriteableBitmap) // https://social.msdn.microsoft.com/Forums/en-US/39b3c702-caed-47e4-b7d3-b51d75cbca9b/getting-pixels-of-an-element-writeablebitmap?forum=winappswithcsharp

6) Windows 8 WriteableBitmap Pixel Arrays in C# and C++ : http://www.tuicool.com/articles/fQNvUz

7) 各种流转换 : http://www.cnblogs.com/hebeiDGL/p/3428743.html

8) XAML images sample : https://code.msdn.microsoft.com/windowsapps/0f5d56ae-5e57-48e1-9cd9-993115b027b9/

9) 重新想象 Windows 8 Store Apps (29) - 图片处理 : http://www.cnblogs.com/webabcd/archive/2013/05/27/3101069.html

13、在 uwp应用中,给图片添加高斯模糊滤镜效果(一)的更多相关文章

  1. javascript随机将第一个dom中的图片添加到第二个div中去

    javascript随机将第一个dom中的图片添加到第二个div中去,此代码的是一个简单的例子,将第一个div中的五张图片中,提取随机两张显示到第二个div中. <!DOCTYPE html P ...

  2. VS2010中 为图片添加背景图片

    很简单的东西,嘿嘿 void CTestDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage( ...

  3. html中给图片添加热点

    <img src="images/index/top1.jpg" width="248" height="512" usemap=&q ...

  4. Java 添加、删除、格式化Word中的图片

    本文介绍使用Spire.Cloud.SDK for Java提供的ImagesApi接口来操作Word中的图片.具体可通过addImage()方法添加图片.deleteImage()方法删除图片.up ...

  5. R语言 如何为图片添加文字说明(转载)

    转载:(中文翻译者)[http://blog.csdn.net/chen790646223/article/details/49766659] (原文链接)[http://datascienceplu ...

  6. netbeans中给jpanl添加背景图片制定代码的理解——匿名内部类继承父类

    此测试是为了仿照在netbeans中给jpanl添加背景图片的制定代码的执行过程 在JpDemo中定义了个Car类的数据类型,但在给其赋值对象时使用了匿名内部类,继承了Car类,是其子类,并重写了父类 ...

  7. Java 添加、替换、删除PDF中的图片

    概述 本文介绍通过java程序向PDF文档添加图片,以及替换和删除PDF中已有的图片.另外,关于图片的操作还可参考设置PDF 图片背景.设置PDF图片水印.读取PDF中的图片.将PDF保存为图片等文章 ...

  8. Java 添加、提取PDF中的图片

    Spire.Cloud.SDK for Java提供了PdfImagesApi接口可用于添加图片到PDF文档addImage().提取PDF中的图片extractImages(),具体操作步骤和Jav ...

  9. c# Winform中如何把图片添加到resources中

    我们在Winform项目中中需要插入图片资源,但是新建的项目中找不到Resources文件夹,怎么才能出现呢? 1:双击项目下的Resources.resx,出现视图 2:单击"添加资源&q ...

随机推荐

  1. inno setup介绍及官方网站地址

    使 用 笔 记 1.Inno Setup 是什么?Inno Setup 是一个免费的 Windows 安装程序制作软件.第一次发表是在 1997 年,Inno Setup 今天在功能设置和稳定性上的竞 ...

  2. motto4

    有时候,你不能太固执,因为这样子对你不利,应该懂得变通才行. 你要知道,语言是表达思想的工具.你不说,别人怎么知道你的思想呢?你又怎么了解他人的思想呢?

  3. 漫长Appium之路(一)——从黑苹果到虚拟机

    作为一名普普通通的实习生,我也开始习惯折腾一般的生活了.部门应该最近是要搞个iOS自动化测试工具,我从最开始说起吧. 应该是上上上周五.主管找到我,说要装一个黑苹果,要我尽快把黑苹果能支持的硬件配置给 ...

  4. [Effective JavaScript 笔记]第53条:保持一致的约定

    对于api使用者来说,你所使用的命名和函数签名是最能产生普遍影响的决策.这些约定很重要具有巨大的影响力.它建立了基本的词汇和使用它们的应用程序的惯用法.库的使用者必须学会阅读和使用这些.一致的约定可以 ...

  5. Unity3D研究院之自制批量关联材质与贴图插件

    原地址:http://www.xuanyusong.com/archives/2314 美术做过的模型导出fbx,美术把Fbx和贴图文件给了程序,程序把Fbx导入工程可能会出现贴图和材质没有关联上的问 ...

  6. JAVA经典算法40题及解答

    JAVA经典算法40题 [程序1]   题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第四个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 1.程序分 ...

  7. 如何修改git的当前登录信息

    (文章是从我的个人主页上粘贴过来的,大家也可以访问我的主页 www.iwangzheng.com) 之前用的大师的git登录名,后来开通了自己的,需要换成自己的,其实修改方式很简单. $vim .gi ...

  8. HLG2062(make,heap问题)

    最小的n个和 Time Limit: 1000 MS Memory Limit: 32768 K Total Submit: 129(37 users) Total Accepted: 35(29 u ...

  9. yum 配置

    1.配置yum本地源 # mount /dev/cdrom /mnt/ # vim /etc/yum.repos.d/rhel-source.repo 1 [rhel-source] 2 name=R ...

  10. 又一款linux提权辅助工具

    又一款linux提权辅助工具 – Linux_Exploit_Suggester 2013-09-06 10:34 1455人阅读 评论(0) 收藏 举报 https://github.com/Pen ...