Reputation: 2450
How I can create bitmap image from xaml control using WritableBitmapEx. In my winRT application I need to create a snapshot of my window for implementing Pin to Tile(pinning secondary tile). I found WritableBitmap.render() is missing in winRT. How can I achieve this functionality by using WritableBitmapEx.
Upvotes: 4
Views: 5263
Reputation: 31724
Somehow they missed implementing WriteableBitmap.Render() and while from what I have been hearing it might come in a later version of the SDK, for now your options are to either use WriteableBitmap and populate it pixel by pixel with the content of your control, perhaps with the help of WriteableBitmapEx or alternatively use DirectX, perhaps with help of SharpDX which is a wrapper for DirectX that you can use in a C# app. You do need to use DirectX/Direct2D/DirectWrite if you want to render any text. It is not too hard to do with DirectX if your UI is simple. There is a sample that seems to be a good place to start here.
EDIT*
Then there is also a WriteableBitmap.Render() extension method I started implementing in WinRT XAML Toolkit that has a somewhat limited but potentially helpful support for rendering visual trees. I am planning to extend it to support more UI elements if necessary. It currently supports typical TextBlocks and shapes with solid color or gradient backgrounds.
EDIT 2*
Windows 8.1 adds RenderTargetBitmap.RenderAsync()
API, which is quite helpful, though it has some limitations e.g. it requires the rendered UI to be part of the visual tree (though it can be in a hidden panel), misses video playback, DirectX content and I believe WebView
content too.
Upvotes: 9
Reputation: 39290
WritableBitmapEx has been updated since this question was asked and now supports WinRT - so it should just work.
There is a fantastic amount of demo's to show this and answers a number of SO questions at: https://gist.github.com/2834070
Upvotes: 2
Reputation: 5225
I've been using the RandomAccessStreamReference class in Windows.Storage.Streams to create bitmaps. One example (this is actually code for sharing):
var reference = RandomAccessStreamReference.CreateFromUri(new Uri(item.ImagePath.AbsoluteUri));
request.Data.SetBitmap(reference);
Also keep in mind that for pinning secondary tiles, you can pass in a URI for the logo on the tile, without creating an actual bitmap, as long as the logo is part of your app package, like this:
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();
Finally, if your image that you want to use on the secondary tile is online rather than part of your app package, you will have to copy it locally before you can use it. Here is some code that does that:
// 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);
}
}
}
}
Upvotes: 0