本文告诉大家如何使用 Softwarebitmap 进行创建、修改保存图片。
在 UWP 使用底层的图像渲染就是使用 Softwarebitmap ,这个类提供直接数据修改,可以使用这个类进行软渲染。实际上 Softwarebitmap 和 WriteableBitmap 是差不多的。但是 Softwarebitmap 可以支持 WriteableBitmap 、 Direct3D 和代码修改。通过 Softwarebitmap 可以修改转换不同的像素格式和透明通道,支持低级修改像素。作为一个通用的底层类在很多性能要求比较高的地方用到,如 CapturedFrame、VideoFrame、FaceDetector。下面来告诉大家如何使用。
创建
下面来告诉大家如何读取文件,使用图片数据创建 Softwarebitmap 图片。
首先是需要使用 FileOpenPicker 拿到一张图片,如何读写文件参见:win10 UWP读写文件
因为很简单,下面直接拿到一张 jpg ,当然需要用户点击。下面代码是直接从微软文档复制的,我自己没运行,看起来大家可以直接使用。
因为需要拿到文件内容,需要使用 OpenAsync 方法获得随机访问流。随机访问流就是可以在随机的地方进行读写,和他不相同的是顺序流,也就是只能顺序读写。使用 BitmapDecoder.CreateAsync 创建一个图片解析,用来拿到图片
保存图片
上面和大家说如何读取文件,现在就可以把刚才读取的图片保存。保存需要用户选择保存在哪
使用 OpenAsync 方法打开文件,转换随机写入流写入数据。使用 BitmapEncoder.CreateAsync 创建 BitmapEncoder 。创建的函数第一个参数是 GUID 表示需要哪个格式,可以通过 BitmapEncoder 输入,下面代码就是把刚才读取的 jpg 图片转换为 Png 格式。
这个方法就是把 softwareBitmap 转换为 Stream 的方法
如果在保存需要对图片进行编辑,可以使用 BitmapTransform 进行变换,请看代码
因为不是所有的文件格式都支持缩略图,如果使用了创建新的图就需要 catch 不支持异常。
在转换图片需要调用 FlushAsync 保存图片。
现在在前台添加两个按钮,一个用于打开文件,另一个用来保存图片
随便选一个 jpg 文件,然后保存,可以看到保存了新的格式
在 UWP 可以使用上面的方法修改图片格式
上面代码只是简单使用,在创建 BitmapEncoder 可以传入 BitmapPropertySet 指定图片质量
其他的值请看 BitmapEncoder options reference
在 Image 控件使用
刚才的代码没有显示打开的图片,如果要把 SoftwareBitmap 在 Image 使用,就需要使用 SoftwareBitmapSource 转换,因为 Image 控件只支持 BGRA8 格式而且需要先计算透明值,在转换打开 SoftwareBitmap 静态函数 Convert 让格式在 Image 控件支持。
先在界面创建一个 Image 控件,然后在后台添加代码显示
尝试运行一下代码就可以看到显示图片在打开文件。
实际上通过 下面代码可以把 SoftwareBitmap 转 ImageBrush 显示
WriteableBitmap 转换
上面都是读写文件,如果已经使用了 WriteableBitmap 需要把他转换 SoftwareBitmap 可以使用 SoftwareBitmap 的静态函数 SoftwareBitmap.CreateCopyFromBuffer 转换。
通过读写像素
是不是看到上面的教程感觉这个博客很简单,我就来告诉大家很黑的方法,如果看到这里还没有关闭这个网页,那么现在关闭还是可以,不然我就来和大家说很黑科技的写法。
如果大家直接从 SoftwareBitmap 使用 Resharper 无论怎么点都无法找到读写像素的方法。但是我会告诉大家我自己创建了一个接口,使用这个接口就可以读写。
首先引用using System.Runtime.InteropServices;
然后创建接口
创建这个接口有什么用,先不告诉大家,因为用了不安全,需要在项目属性,生成,可以使用不安全
我来告诉大家如何从代码创建 SoftwareBitmap ,读写像素。
创建一个空白的 SoftwareBitmap 需要设置格式
使用 LockBuffer 可以拿到 buffer ,使用 buffer.CreateReference 可以拿到指针
然后就是不安全代码,本文的黑科技就是这个代码
把 reference 转换为我自己定义的接口,使用 GetBuffer 拿到数据指针。
这个的原理,本渣在这里不会说。
拿到了 dataInBytes 就是按照 BGRA 的顺序,但是还不知道图片的宽度用了多少个,而且图片如果是分层的,第 n 层是从哪个数据开始。为了知道指针的开始,就使用 BitmapBuffer 的方法
获取图层数量可以使用buffer.GetPlaneCount()
,因为第 0 个在这里是有的,所以直接使用
那么图片的宽使用多少个如何拿到,bufferLayout.StartIndex 就是拿到图层开始所在,bufferLayout.Stride 就是一行使用了多少 byte 。所以要访问第 i 行 j 列的像素就可以使用下面的代码
写入的方式就是直接给一个值,读取的方式就是去拿,方法很简单,下面来写一个渐变
转换 CanvasBitmap
使用 CanvasBitmap.CreateFromSoftwareBitmap
可以从 SoftwareBitmap 转换为 CanvasBitmap
需要注意,如果 SoftwareBitmap 的像素格式比较诡异,那么不一定能创建
sourceBitmap's BitmapPixelFormat | CanvasBitmap's Format |
---|
BitmapPixelFormat.Unknown | unsupported |
BitmapPixelFormat.Rgba16 | DirectXPixelFormat.R16G16B16A16UIntNormalized |
BitmapPixelFormat.Rgba8 | DirectXPixelFormat.R8G8B8A8UIntNormalized |
BitmapPixelFormat.Gray16 | unsupported |
BitmapPixelFormat.Gray8 | DirectXPixelFormat.A8UIntNormalized |
BitmapPixelFormat.Bgra8 | DirectXPixelFormat.B8G8R8A8UIntNormalized |
BitmapPixelFormat.Nv12 | unsupported |
BitmapPixelFormat.Yuy2 | unsupported |
参见:CanvasBitmap.CreateFromSoftwareBitmap Method
Create, edit, and save bitmap images - UWP app developer
原文链接: http://blog.lindexi.com/post/win10-uwp-%E5%A6%82%E4%BD%95%E5%88%9B%E5%BB%BA%E4%BF%AE%E6%94%B9%E4%BF%9D%E5%AD%98%E4%BD%8D%E5%9B%BE
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。
欢迎转载、使用、重新发布,但务必保留文章署名 林德熙 (包含链接: https://blog.lindexi.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我 联系。