使用WritableBitmapEx从xaml控件创建位图图像

时间:2012-07-24 09:22:47

标签: windows-8 windows-runtime

如何使用WritableBitmapEx从xaml控件创建位图图像。在我的winRT应用程序中,我需要创建窗口的快照,以实现Pin to Tile(固定辅助磁贴)。我发现winRT中缺少WritableBitmap.render()。如何使用WritableBitmapEx实现此功能。

3 个答案:

答案 0 :(得分:9)

不知何故,他们错过了实现WriteableBitmap。Render()而我从听到它可能会出现在SDK的更高版本中,现在你的选择是使用WriteableBitmap并逐个像素地填充它控件的内容,也许是在WriteableBitmapEx的帮助下,或者使用DirectX,也许是在SharpDX的帮助下,SharpDX是一个可以在C#应用程序中使用的DirectX包装器。如果要渲染任何文本,则需要使用DirectX / Direct2D / DirectWrite。如果您的UI很简单,使用DirectX并不难。有一个样本似乎是开始here的好地方。

编辑*

然后还有一个WriteableBitmap.Render() extension method我开始在WinRT XAML Toolkit中实现,它对渲染可视树有一些有限但可能有用的支持。我计划在必要时扩展它以支持更多的UI元素。它目前支持典型的TextBlocks和具有纯色或渐变背景的形状。

编辑2 *

Windows 8.1添加了RenderTargetBitmap.RenderAsync() API,这非常有用,但它有一些限制,例如:它需要渲染的UI成为可视树的一部分(虽然它可以在隐藏的面板中),错过视频播放,DirectX内容,我也相信WebView内容。

答案 1 :(得分:2)

自问这个问题以来,WritableBitmapEx已经更新,现在支持WinRT - 所以它应该可以正常工作。

有很多演示用于展示这一点,并在以下网址回答了许多SO问题:https://gist.github.com/2834070

答案 2 :(得分:0)

我一直在使用Windows.Storage.Streams中的RandomAccessStreamReference类来创建位图。一个例子(这实际上是共享代码):

            var reference = RandomAccessStreamReference.CreateFromUri(new Uri(item.ImagePath.AbsoluteUri));
            request.Data.SetBitmap(reference);

另请注意,对于固定辅助磁贴,您可以在磁贴上传递徽标的URI,而无需创建实际的位图,只要徽标是应用包的一部分,如下所示:

        var uri = new Uri(item.TileImagePath.AbsoluteUri);

        var tile = new SecondaryTile(
                item.UniqueId,              // Tile ID
                item.ShortTitle,            // Tile short name
                item.Title,                 // Tile display name
                item.UniqueId,              // Activation argument
                TileOptions.ShowNameOnLogo, // Tile options
                uri                         // Tile logo URI
            );

        await tile.RequestCreateAsync();

最后,如果您要在辅助磁贴上使用的图像是在线而不是应用包的一部分,则必须先将其复制到本地,然后才能使用它。以下是一些代码:

        // This is the URI that you will then pass as the last parameter into 
        // the Secondary Tile constructor, like the code above:
        var logoUri = await GetLocalImageAsync(restaurant.ImagePath, restaurant.Key);

        // and here's the method that does the meat of the work:

    /// <summary>
    /// Copies an image from the internet (http protocol) locally to the AppData LocalFolder.
    /// This is used by some methods (like the SecondaryTile constructor) that do not support 
    /// referencing images over http but can reference them using the ms-appdata protocol.  
    /// </summary>
    /// <param name="internetUri">The path (URI) to the image on the internet</param>
    /// <param name="uniqueName">A unique name for the local file</param>
    /// <returns>Path to the image that has been copied locally</returns>
    private async Task<Uri> GetLocalImageAsync(string internetUri, string uniqueName)
    {
        if (string.IsNullOrEmpty(internetUri))
        {
            return null;
        }

        using (var response = await HttpWebRequest.CreateHttp(internetUri).GetResponseAsync())
        {
            using (var stream = response.GetResponseStream())
            {
                var desiredName = string.Format("{0}.jpg", uniqueName);
                var file = await ApplicationData.Current.LocalFolder.CreateFileAsync(desiredName, CreationCollisionOption.ReplaceExisting);

                using (var filestream = await file.OpenStreamForWriteAsync())
                {
                    await stream.CopyToAsync(filestream);
                    return new Uri(string.Format("ms-appdata:///local/{0}.jpg", uniqueName), UriKind.Absolute);
                }
            }
        }
    }