在uwp开发中,有时候需要获取当前屏幕中的图像信息,但是又不适合直接截图保存,因为截图会保存整个屏幕的图像,而且,还需要用户会截屏操作。总之不适合获取屏幕中需要的图像信息。注意题目中的“需要的”。
意思是什么呢?就是我们可以获取当前屏幕中任意一个UIElement中的图像。废话不多说,还是以实战场景为例,因为自己最近就遇到了这种情况。
在做《简影UWP》的“电影台词”模块的时候,显示如下: 需求是:是用户点击保存图片,将会把图片和文字一块保存下来,查看的时候,也是当前显示的这样。
首先贴上前台代码:
可以看到,图片上面显示的文字是和图片分开的。文字是覆盖在图片上的,如果直接下载图片,将不会有文字,所以这不是我需要的结果。最简单的方法还是上面说的,直接获取如图所示的子Grid里面的图像信息,这样,就相当于将子Grid部分截图。这正是我需要的结果。
下来正式行动:
用到的类:RenderTargetBitmap 类。
RenderTargetBitmap类可以实现将UI元素转化为位图 ,即将UI元素截图,生成一张图片。与截图不同的是,它可以定义UIElement,这里,我只需要截图的是图片和文字部分,即上面的字Grid里面的图像信息。
要实现截图并保存到应用内存储,就先要定义文件名:
string desiredName =DateTime.Now.Ticks+".jpg";
再定义文件存储的位置,并创建文件。
StorageFolder applicationFolder = ApplicationData.Current.LocalFolder; StorageFolder folder=await applicationFolder.CreateFolderAsync("Pic", CreationCollisionOption.OpenIfExists); StorageFile saveFile = await folder.CreateFileAsync(desiredName, CreationCollisionOption.OpenIfExists);
接着实例化对象:
RenderTargetBitmap bitmap = new RenderTargetBitmap();
接下来,要指定获取哪个UIelement的图像信息,按照我上面需要的,就是子grid,给它取名PicGird.通过该方法即可指定要获取的位图
await bitmap.RenderAsync(PicGrid);
接着注意:调用RenderAsync方法的时候会初始化RenderTargetBitmap类的对象,但是RenderTargetBitmap类的对象本身并不能作为图片来进行存储,要生成图片文件需要获取到图片的二进制数据。如果你想要获取 DataTransferManager 操作(例如共享协定交换)的图像,或想要使用 Windows.Graphics.Imaging API 将效果应用到图像上或对图像进行转码,那么就需要用到像素数据。如果你想访问RenderTargetBitmap的Pixels数据,你需要在用RenderAsync这个方法将UIElement定义为 RenderTargetBitmap后,再调用RenderTargetBitmap的GetPixelsAsync方法来获得其Pixels数据。该方法返回的是一个IBuffer类型,里面存储的是二进制的位图数。这个IBuffer可以转换为一个Byte数组,数组里面的数据是以BGRA8格式存储的。所以需要获取像素信息:
var pixelBuffer =await bitmap.GetPixelsAsync();
并做如下转化:
using(var fileStream=await saveFile.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, fileStream);
encoder.SetPixelData(BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)bitmap.PixelWidth,
(uint) bitmap.PixelHeight,
DisplayInformation.GetForCurrentView().LogicalDpi,
DisplayInformation.GetForCurrentView().LogicalDpi,
pixelBuffer.ToArray());
await encoder.FlushAsync();
}
这样,就可以将UI元素转化为图片并保存了。
完整代码如下:
string desiredName =DateTime.Now.Ticks+".jpg";
StorageFolder applicationFolder = ApplicationData.Current.LocalFolder;
StorageFolder folder = await applicationFolder.CreateFolderAsync("Pic", CreationCollisionOption.OpenIfExists);
StorageFile saveFile = await folder.CreateFileAsync(desiredName, CreationCollisionOption.OpenIfExists);
RenderTargetBitmap bitmap = new RenderTargetBitmap();
await bitmap.RenderAsync(PicGrid);
var pixelBuffer =await bitmap.GetPixelsAsync();
using(var fileStream=await saveFile.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, fileStream);
encoder.SetPixelData(BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)bitmap.PixelWidth,
(uint) bitmap.PixelHeight,
DisplayInformation.GetForCurrentView().LogicalDpi,
DisplayInformation.GetForCurrentView().LogicalDpi,
pixelBuffer.ToArray());
await encoder.FlushAsync();
}
await new MessageDialog("保存成功").ShowAsync();
这样,就成功地将需要的图片保存下来了,可以去应用文件夹查看:用本地计算机部署,然后执行以上方法。这时候,进入应用存储路径,即如下路径的LocalState文件夹下。
进入以后,可以看到我在代码中创建的文件夹:
然后就可以看到刚才获取到的图片了:
可以看到,我已经成功的将图片保存到了应用存储内。而且上面还是有文字的。正是我要的效果:
最后一步,对于我的应用来说,就是怎么读取,截图一下,我处理读取保存的图片,并显示到界面上的方法:
后台:
前台:
我解释一下步骤:
首先是访问到文件夹路径,然后获取到这个文件夹下的所有文件集合,然后遍历,赋值给要绑定的对象,(这里注意文件夹路径和文件名和文件后缀,一起组成了整个文件的url,将这个url和image控件绑定即可),然后将对象添加进集合,最后将集合绑定到前台的gridview上。OK,大功告成。
最后,我测试一下。多保存几张图片,然后点击显示这个页面:
可以看到,成功地显示了我保存的所有图片。o-yes!
这样,整个保存的过程就完美结束了,如果大家有疑问,或者对uwp开发感兴趣,欢迎大家加入我的uwp开发交流群:193148992。共同学习交流。