Windows 8.1 Store App内截屏

在开发Windows Store App中,对应用程序进行截图是经常面临的一个问题。但是由于API的限制,我们没有办法对Windows Store App进行截屏。不过,Windows 8.1的出现带来了新的希望:

Rendering the XAML tree to a bitmap

WebView for JavaScirpt

接下来我将要用简单的代码来演示一下这两个新的API。

Rendering the XAML tree to a bitmap

Windows 8.1的runtime在Windows.UI.Xaml.Media.Imaging中新加入了RenderTargetBitmap,而这里有两个非常重要的方法:

RenderTargetBitmap.RenderAsync:把UIElement渲染成图片。

RenderTargetBitmap.GetPixelsAsync:把RenderTargetBitmap图片保存成BGRA8格式的流文件。

下面是在XAML render to bitmap 示例中找的一份C#代码,具体的代码可以在示例中下载:

Render XAML Tree to image source

    1: RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
    2: await renderTargetBitmap.RenderAsync(RenderedGrid);
    3: RenderedImage.Source = renderTargetBitmap;

Render XAML Tree to file

    1: // Render to an image at the current system scale and retrieve pixel contents
    2: RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
    3: await renderTargetBitmap.RenderAsync(RenderedGrid);
    4: var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();
    5:  
    6: var savePicker = new FileSavePicker();
    7: savePicker.DefaultFileExtension = ".png";
    8: savePicker.FileTypeChoices.Add(".png", new List<string> { ".png" });
    9: savePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
   10: savePicker.SuggestedFileName = "snapshot.png";
   11:  
   12: // Prompt the user to select a file
   13: var saveFile = await savePicker.PickSaveFileAsync();
   14:  
   15: // Verify the user selected a file
   16: if (saveFile == null)
   17:     return;
   18:  
   19: // Encode the image to the selected file on disk
   20: using (var fileStream = await saveFile.OpenAsync(FileAccessMode.ReadWrite))
   21: {
   22:      var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, fileStream);
   23:  
   24:      encoder.SetPixelData(
   25:     BitmapPixelFormat.Bgra8,
   26:     BitmapAlphaMode.Ignore,
   27:     (uint)renderTargetBitmap.PixelWidth,
   28:     (uint)renderTargetBitmap.PixelHeight,
   29:     DisplayInformation.GetForCurrentView().LogicalDpi,
   30:     DisplayInformation.GetForCurrentView().LogicalDpi,
   31:     pixelBuffer.ToArray());
   32:  
   33:      await encoder.FlushAsync();
   34: }

WebView for JavaScript

Windows 8.1在WebView控件中做了很多改动,例如新加了GoBack, GoForward, Stop,Refresh, CanGoBackCanGoForward。之后我们也不需要再用JavaScript的方法去实现相同的结果了。新的属性的增加使得WebView变得更加的强大。之后我再详细说明这些变化。

这里我将要介绍一下CapturePreviewToStreamAsync,这个方法使得在Windows Store App中通过Javascript截屏变为可能。

下面代码是介绍如何使用CapturePreviewToStreamAsync去截屏:

    1: <body>
    2:     <p>Content goes here</p>
    3:     <input type="url" id="urlField" />
    4:     <button id="goOrStopButton">Go</button>
    5:     <button id="captureToImage">capture</button>
    6:     <div>
    7:         <x-ms-webview id="webview" style="width:1000px;height:800px"></x-ms-webview>
    8:     </div>
    9: </body>
    1: var page = WinJS.UI.Pages.define("default.html", {
    2:     ready: function (element, options) {
    3:         document.getElementById("goOrStopButton").addEventListener("click", goToUrl, false);
    4:         document.getElementById("captureToImage").addEventListener("click", captureToImage, false);
    5:         var webviewControl = document.getElementById("webview");
    6:         webviewControl.navigate("https://go.microsoft.com/fwlink/?LinkId=294155");
    7:     }
    8: });
    9:  
   10: function goToUrl() {
   11:     var destinationUrl = document.getElementById("urlField").value;
   12:     try {
   13:         document.getElementById("webview").navigate(destinationUrl);
   14:     } catch (error) {
   15:         WinJS.log && WinJS.log("\"" + destinationUrl + "\" is not a valid absolute URL.\n", "sdksample", "error");
   16:         return;
   17:     }
   18: }
   19:  
   20: function captureToImage() {
   21:     var webviewControl = document.getElementById("webview");
   22:     Windows.Storage.ApplicationData.current.localFolder.createFileAsync("test.png", ndows.Storage.CreationCollisionOption.replaceExisting).then(function (file) {
   23:         file.openAsync(Windows.Storage.FileAccessMode.readWrite).then(function (stream) {
   24:             var captureOperation = webviewControl.capturePreviewToBlobAsync();
   25:             captureOperation.oncomplete = function (completeEvent) {
   26:                 var inputStream = completeEvent.target.result.msDetachStream();
   27:                 Windows.Storage.Streams.RandomAccessStream.copyAsync(inputStream, stream).then(function () {
   28:                     stream.flushAsync().done(function () {
   29:                         inputStream.close();
   30:                         stream.close();
   31:                     });
   32:                 });
   33:             };
   34:             captureOperation.start();
   35:         });
   36:     });
   37: }

剩下的过程就非常简单了:通过innerHTML property获取到HTML,然后再获取WebView就可以了。

English Version:

https://blogs.msdn.com/b/lighthouse/archive/2013/10/18/capturing-snapshot-in-windows-8-1-store-app.aspx