I want to make a simple drawing app for children with C# for WinRT. The user can choose a picture and draw a little bit. But how can I save the image (together with the background)? There is no functionality to save the image with background.
可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
回答1:
I tried to use your library to render a Canvas into an image file but I got this error runtime: "Can't find component. (Exception from HRESULT: 0x88982F50)". Code looks like this:
//SAVE
private async void saveButton_Click(object sender, RoutedEventArgs e)
{
await SaveToFile();
}
public async Task SaveToFile()
{
var wb = new WriteableBitmap(1, 1);
await wb.Render(canvas);
Windows.Storage.Pickers.FileSavePicker save = new Windows.Storage.Pickers.FileSavePicker();
save.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.Desktop;
save.DefaultFileExtension = ".jpg";
save.FileTypeChoices.Add("JPG", new string[] { ".jpg" });
StorageFile filesave = await save.PickSaveFileAsync();
await wb.SaveToFile(filesave, Guid.NewGuid());
}
回答2:
If you draw your image into a WriteableBitmap
WinRT XAML Toolkit has some extension methods you can use to save the image:
using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Graphics.Imaging;
using Windows.Storage;
using Windows.UI.Xaml.Media.Imaging;
namespace WinRTXamlToolkit.Imaging
{
/// <summary>
/// Extension methods used for saving a WriteableBitmap to a file.
/// </summary>
public static class WriteableBitmapSaveExtensions
{
/// <summary>
/// Saves the WriteableBitmap to a png file with a unique file name.
/// </summary>
/// <param name="writeableBitmap">The writeable bitmap.</param>
/// <returns>The file the bitmap was saved to.</returns>
public static async Task<StorageFile> SaveToFile(
this WriteableBitmap writeableBitmap)
{
return await writeableBitmap.SaveToFile(
KnownFolders.PicturesLibrary,
string.Format(
"{0}_{1}.png",
DateTime.Now.ToString("yyyyMMdd_HHmmss_fff"),
Guid.NewGuid()),
CreationCollisionOption.GenerateUniqueName);
}
/// <summary>
/// Saves the WriteableBitmap to a png file in the given folder with a unique file name.
/// </summary>
/// <param name="writeableBitmap">The writeable bitmap.</param>
/// <param name="storageFolder">The storage folder.</param>
/// <returns>The file the bitmap was saved to.</returns>
public static async Task<StorageFile> SaveToFile(
this WriteableBitmap writeableBitmap,
StorageFolder storageFolder)
{
return await writeableBitmap.SaveToFile(
storageFolder,
string.Format(
"{0}_{1}.png",
DateTime.Now.ToString("yyyyMMdd_HHmmss_fff"),
Guid.NewGuid()),
CreationCollisionOption.GenerateUniqueName);
}
/// <summary>
/// Saves the WriteableBitmap to a file in the given folder with the given file name.
/// </summary>
/// <param name="writeableBitmap">The writeable bitmap.</param>
/// <param name="storageFolder">The storage folder.</param>
/// <param name="fileName">Name of the file.</param>
/// <param name="options">
/// The enum value that determines how responds if the fileName is the same
/// as the name of an existing file in the current folder. Defaults to ReplaceExisting.
/// </param>
/// <returns></returns>
public static async Task<StorageFile> SaveToFile(
this WriteableBitmap writeableBitmap,
StorageFolder storageFolder,
string fileName,
CreationCollisionOption options = CreationCollisionOption.ReplaceExisting)
{
StorageFile outputFile =
await storageFolder.CreateFileAsync(
fileName,
options);
Guid encoderId;
var ext = Path.GetExtension(fileName);
if (new[] { ".bmp", ".dib" }.Contains(ext))
{
encoderId = BitmapEncoder.BmpEncoderId;
}
else if (new[] { ".tiff", ".tif" }.Contains(ext))
{
encoderId = BitmapEncoder.TiffEncoderId;
}
else if (new[] { ".gif" }.Contains(ext))
{
encoderId = BitmapEncoder.TiffEncoderId;
}
else if (new[] { ".jpg", ".jpeg", ".jpe", ".jfif", ".jif" }.Contains(ext))
{
encoderId = BitmapEncoder.TiffEncoderId;
}
else if (new[] { ".hdp", ".jxr", ".wdp" }.Contains(ext))
{
encoderId = BitmapEncoder.JpegXREncoderId;
}
else //if (new [] {".png"}.Contains(ext))
{
encoderId = BitmapEncoder.PngEncoderId;
}
await writeableBitmap.SaveToFile(outputFile, encoderId);
return outputFile;
}
/// <summary>
/// Saves the WriteableBitmap to the given file with the specified BitmapEncoder ID.
/// </summary>
/// <param name="writeableBitmap">The writeable bitmap.</param>
/// <param name="outputFile">The output file.</param>
/// <param name="encoderId">The encoder id.</param>
/// <returns></returns>
public static async Task SaveToFile(
this WriteableBitmap writeableBitmap,
StorageFile outputFile,
Guid encoderId)
{
Stream stream = writeableBitmap.PixelBuffer.AsStream();
byte[] pixels = new byte[(uint)stream.Length];
await stream.ReadAsync(pixels, 0, pixels.Length);
using (var writeStream = await outputFile.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(encoderId, writeStream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Premultiplied,
(uint)writeableBitmap.PixelWidth,
(uint)writeableBitmap.PixelHeight,
96,
96,
pixels);
await encoder.FlushAsync();
using (var outputStream = writeStream.GetOutputStreamAt(0))
{
await outputStream.FlushAsync();
}
}
}
}
}
The toolkit also has some methods in the WinRTXamlToolkit.Composition
library to render text and shapes laid out with XAML UI into an image using Direct2D, but it is still in early stage of development and does not support rendering image controls or backgrounds yet.