7.2.3 使用RenderTargetBitmap類生成圖片
RenderTargetBitmap類可以將可視化對象轉換為位圖,也就是說它可以將任意的UIElement以位圖的形式呈現。那么我們在實際的編程中通常會利用RenderTargetBitmap類來對UI界面進行截圖操作,比如把程序的界面或者某個控件的外觀生成一張圖片。
使用RenderTargetBitmap類生成圖片一般有兩種用途,一種是直接把生成的圖片在當前的頁面上進行展示,還有一種用途是把生成的圖片當作文件存儲起來,或者通過某種分享方式把圖片文件分享出去。那么第二種用途的編程實現肯定是在第一種的編程實現的基礎上來實現的,所以我們首先看一下第一種情況的實現,如何把截圖在當前的界面上展示。
使用RenderTargetBitmap類生成圖片的操作主要是依賴於RenderTargetBitmap類的RenderAsync方法。RenderAsync方法有兩個重載:RenderAsync(UIElement) 和 RenderAsync(UIElement, Int32, Int32),可在后者處指定要與源可視化樹的自然大小不同的所需圖像源尺寸,沒有設置則是按照元素的原始大小生成圖片。RenderAsync方法被設計為異步方法,因此無法保證與UI源進行精確的框架同步,但大多數情況下都足夠及時。由於 RenderTargetBitmap是ImageSource的子類,因此,可以將其用作Image元素或 ImageBrush畫筆的圖像源。
下面給出生成程序截圖的示例:通過點擊屏幕來生成當前程序界面的截圖,並把截圖用Image控件展示出來,每次的點擊都產生一個最新的截圖並進行展示。
代碼清單7-9:生成程序截圖(源代碼:第7章\Examples_7_9)
MainPage.xaml文件主要代碼 ------------------------------------------------------------------------------------------------------------------ <!--注冊PointerReleased 事件用於捕獲屏幕的單擊操作,並在時間處理程序中生成圖片--> <Grid x:Name="root" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" PointerReleased="Grid_PointerReleased"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,35,0,28"> <TextBlock Text="我的應用程序" FontSize="20" /> <TextBlock Text="點擊截屏" FontSize="60" /> </StackPanel> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" > <!--該圖片控件用於展示截圖圖片效果--> <Image x:Name="img" /> </Grid> </Grid>
MainPage.xaml.cs文件主要代碼 ------------------------------------------------------------------------------------------------------------------ // 指針釋放的事件處理程序 private async void Grid_PointerReleased(object sender, PointerRoutedEventArgs e) { // 創建一個RenderTargetBitmap對象,對界面中的Grid控件root生成圖片 RenderTargetBitmap bitmap = new RenderTargetBitmap(); await bitmap.RenderAsync(root); // 把圖片展現出來 img.Source = bitmap; }
7.2.4 存儲生成的圖片文件
在上文我們講解了如何把程序界面截圖出來放到Image控件上展示,那么我們接下來將繼續介紹如何把截圖出來的圖片保存到程序存儲里面。在我們調用RenderAsync方法的時候會初始化RenderTargetBitmap類的對象,但是RenderTargetBitmap類的對象本身並不能作為圖片來進行存儲,要生成圖片文件需要獲取到圖片的二進制數據。如果你想要獲取 DataTransferManager 操作(例如共享協定交換)的圖像,或想要使用 Windows.Graphics.Imaging API 將效果應用到圖像上或對圖像進行轉碼,那么就需要用到像素數據。如果你想訪問RenderTargetBitmap的Pixels數據,你需要在用RenderAsync這個方法將UIElement定義為 RenderTargetBitmap后,再調用RenderTargetBitmap的GetPixelsAsync方法來獲得其Pixels數據。該方法返回的是一個IBuffer類型,里面存儲的是二進制的位圖數。這個IBuffer可以轉換為一個Byte數組,數組里面的數據是以BGRA8格式存儲的。
以下代碼示例如何從一個RenderTargetBitmap對象中獲得以byte數組類型存儲的像素數。需要特別注意的是IBuffer實例調用的ToArray方法是一個擴展方法,你需要在你的項目中加入System.Runtime.InteropServices.WindowsRuntime這個命名空間。
var bitmap = new RenderTargetBitmap();
await bitmap.RenderAsync(elementToRender);
IBuffer pixelBuffer = await bitmap.GetPixelsAsync();
byte[] pixels = pixelBuffer.ToArray();
那么在獲取到了圖像的二進制數據之后,如果要把二進制的數據生成圖片文件,需要使用到BitmapEncoder類。BitmapEncoder類包含創建、編輯和保存圖像的各種方法。創建圖片文件首先需要調用BitmapEncoder類CreateAsync方法,來使用文件的流來創建一個BitmapEncoder對象,然后再使用BitmapEncoder類的SetPixelData設置圖像有關幀的像素數據。SetPixelData的方法參數如下:
SetPixelData(BitmapPixelFormat pixelFormat, BitmapAlphaMode alphaMode, uint width, uint height, double dpiX, double dpiY, byte[] pixels)
其中,pixelFormat表示像素數據的像素格式;alphaMode表示像素數據的alpha模式;width表示像素數據的寬度(以像素為單位);height表示像素數據的高度(以像素為單位);dpiX表示像素數據的水平分辨率(以每英寸點數為單位);dpiY表示像素數據的垂直分辨率(以每英寸點數為單位);pixels表示像素數據。此方法是同步的,因為直到調用 FlushAsync、GoToNextFrameAsync 或 GoToNextFrameAsync(IIterable(IKeyValuePair)) 才會提交數據。此方法將所有像素數據視為sRGB 顏色空間中的像素數據。
下面給出保存截圖文件的示例:先使用RenderTargetBitmap類生成程序界面的截圖,然后再將截圖的二進制數據生成圖片文件存儲到程序存儲中。
代碼清單7-10:保存截圖文件(源代碼:第7章\Examples_7_10)
MainPage.xaml文件主要代碼 ------------------------------------------------------------------------------------------------------------------ <Grid x:Name="root" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> ……省略若干代碼 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <StackPanel> <Button x:Name="bt_save" Content="存儲生成的圖片" Click="bt_save_Click"></Button> <Button x:Name="bt_show" Content="展示存儲的圖片" Click="bt_show_Click"></Button> <ScrollViewer BorderBrush="Red" BorderThickness="2" Height="350"> <Image x:Name="img" /> </ScrollViewer> </StackPanel> </Grid> </Grid>
MainPage.xaml.cs文件主要代碼 ------------------------------------------------------------------------------------------------------------------ // 按鈕事件生成圖片並保存到程序的存儲里面 private async void bt_save_Click(object sender, RoutedEventArgs e) { // 生成RenderTargetBitmap對象 RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap(); await renderTargetBitmap.RenderAsync(root); // 獲取圖像的二進制數據 var pixelBuffer = await renderTargetBitmap.GetPixelsAsync(); // 創建程序文件存儲 IStorageFolder applicationFolder = ApplicationData.Current.LocalFolder; IStorageFile saveFile = await applicationFolder.CreateFileAsync("snapshot.png", CreationCollisionOption.OpenIfExists); // 把圖片的二進制數據寫入文件存儲 using (var fileStream = await saveFile.OpenAsync(FileAccessMode.ReadWrite)) { var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, fileStream); encoder.SetPixelData( BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)renderTargetBitmap.PixelWidth, (uint)renderTargetBitmap.PixelHeight, DisplayInformation.GetForCurrentView().LogicalDpi, DisplayInformation.GetForCurrentView().LogicalDpi, pixelBuffer.ToArray()); await encoder.FlushAsync(); } } // 展示程序存儲圖片的按鈕事件 private void bt_show_Click(object sender, RoutedEventArgs e) { // “ms-appdata:///local”表示是程序存儲的根目錄 BitmapImage bitmapImage = new BitmapImage(new Uri("ms-appdata:///local/snapshot.png", UriKind.Absolute)); img.Source = bitmapImage; }
本文來源於《深入淺出Windows Phone 8.1 應用開發》
WP8.1 Runtime文章列表:http://www.cnblogs.com/linzheng/p/3998037.html
源代碼下載:http://vdisk.weibo.com/s/zt_pyrfNHb99O
歡迎關注我的微博@WP林政 微信公眾號:wp開發(號:wpkaifa)
WP8.1技術交流群:372552293