C# 将画布转换为图像时,UWP应用程序挂起
我正在尝试将UWP中的画布转换为图像(C# 将画布转换为图像时,UWP应用程序挂起,c#,uwp,C#,Uwp,我正在尝试将UWP中的画布转换为图像(RenderTargetBitmap)。我有两个选项将图像返回给最终用户 StorageFile System.IO.Stream 当我使用存储文件时,一切正常但是当我使用内存流时,应用程序挂起。我创建了一个简单的示例来重现这个问题 <Grid Background="White" Name ="Main_Grid"> <Button Content="UIToImage" Margin="141,159,0,0" Vertical
RenderTargetBitmap
)。我有两个选项将图像返回给最终用户
StorageFile
System.IO.Stream
<Grid Background="White" Name ="Main_Grid">
<Button Content="UIToImage" Margin="141,159,0,0" VerticalAlignment="Top" Click="UIToImageAsync"></Button>
</Grid>
private async void UIToImageAsync(object sender, RoutedEventArgs e)
{
//Pick a folder
var folder = KnownFolders.PicturesLibrary;
var storageFile = await folder.CreateFileAsync("Output.png", CreationCollisionOption.ReplaceExisting);
//using (var inputImgStream = await storageFile.OpenStreamForWriteAsync())//this works
using (var inputImgStream = new MemoryStream())//this doesn't work
{
//Draw a line
Windows.UI.Xaml.Shapes.Path path = new Windows.UI.Xaml.Shapes.Path();
DrawShape(path);
//The canvas to hold the above shape - line
var canvas = new Canvas();
//Add canvas to the grid in XAML
Main_Grid.Children.Add(canvas);
canvas.Children.Add(path);
//Draw the canvas to the image
RenderTargetBitmap bitmap = null;
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
bitmap = new RenderTargetBitmap();
canvas.Height = 800;
canvas.Width = 1380;
canvas.RenderTransform = new TranslateTransform { X = 1, Y = 100
};
});
//Render a bitmap image
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,async () =>
{
await bitmap.RenderAsync(canvas, 1380, 800);
});
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, inputImgStream.AsRandomAccessStream());// I suspect passing the MemoryStream is the issue. While 'StorageFile' is used there are no issues.
IBuffer pixelBuffer = await bitmap.GetPixelsAsync();
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)bitmap.PixelWidth,
(uint)bitmap.PixelHeight,
DisplayInformation.GetForCurrentView().LogicalDpi,
DisplayInformation.GetForCurrentView().LogicalDpi,
pixelBuffer.ToArray());
await encoder.FlushAsync(); // The application hangs here
}
}
private void DrawShape(Windows.UI.Xaml.Shapes.Path path)
{
PathGeometry lineGeometry = new PathGeometry();
PathFigure lineFigure = new PathFigure();
LineSegment lineSegment = new LineSegment();
lineFigure.StartPoint = new Point(100, 100);
lineSegment.Point = new Point(200, 200);
lineFigure.Segments.Add(lineSegment);
path.Data = lineGeometry;
SolidColorBrush strokeBrush = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 255, 0, 0));
path.Stroke = strokeBrush;
path.StrokeThickness = 5;
lineGeometry.Figures.Add(lineFigure);
}
专用异步void UIToImageAsync(对象发送方,RoutedEventTarget e)
{
//选择一个文件夹
var folder=KnownFolders.PicturesLibrary;
var storageFile=wait folder.CreateFileAsync(“Output.png”,CreationCollisionOption.ReplaceExisting);
//使用(var-inputImgStream=await-storageFile.OpenStreamForWriteAsync())//这是可行的
使用(var inputImgStream=new MemoryStream())//这不起作用
{
//划一条线
Windows.UI.Xaml.Shapes.Path Path=新建Windows.UI.Xaml.Shapes.Path();
牵引形状(路径);
//用于固定上述造型线的画布
var canvas=newcanvas();
//在XAML中将画布添加到网格
主网格.Children.Add(画布);
canvas.Children.Add(路径);
//将画布绘制到图像
RenderTargetBitmap位图=空;
等待CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,()=>
{
位图=新的RenderTargetBitmap();
帆布。高度=800;
画布宽度=1380;
canvas.RenderTransform=新的TranslateTransform{X=1,Y=100
};
});
//渲染位图图像
等待CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,async()=>
{
等待位图.RenderAsync(canvas,1380800);
});
var encoder=await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId,inputImgStream.AsRandomAccessStream());//我怀疑传递MemoryStream是个问题。使用“StorageFile”时,没有问题。
IBuffer pixelBuffer=等待位图。GetPixelsAsync();
编码器.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode。忽略,
(uint)bitmap.PixelWidth,
(uint)bitmap.PixelHeight,
DisplayInformation.GetForCurrentView().LogicalDpi,
DisplayInformation.GetForCurrentView().LogicalDpi,
pixelBuffer.ToArray());
wait encoder.FlushAsync();//应用程序挂起在这里
}
}
私有void DrawShape(Windows.UI.Xaml.Shapes.Path)
{
PathGeometry lineGeometry=新的PathGeometry();
PathFigure lineFigure=新的PathFigure();
LineSegment LineSegment=新线段();
lineFigure.StartPoint=新点(100100);
线段点=新点(200200);
lineFigure.Segments.Add(线段);
path.Data=线几何体;
SolidColorBrush strokeBrush=新的SolidColorBrush(Windows.UI.Color.FromArgb(255,255,0,0));
路径笔划=笔划刷;
path.StrokeThickness=5;
线条几何.图形.添加(线条图形);
}
有人能告诉我是什么导致了这种情况吗?使用简单的
MemoryStream
和AsRandomAccessStream
似乎不起作用,尽管我不确定原因。相反,您可以在MemoryRandomAccessStream中使用,它将按预期工作
然而,还有另一个问题,这可能是问题的根源,或者至少是它导致它在我的机器上崩溃:
//Render a bitmap image
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
CoreDispatcherPriority.Normal, async () =>
{
await bitmap.RenderAsync(canvas, 1380, 800);
});
尽管wait
似乎会等待RenderAsync
调用完成,但不幸的是,它没有完成。第二个参数只是一个DispatchedHandler
。该代表有以下签名:
public delegate void DispatchedHandler()
如您所见,没有任务
返回值。这意味着它将只创建一个异步void
lambda。lambda将开始运行,当它到达RenderAsync
时,它将开始执行它,但是RunAsync
的wait
可能(并且很可能将)在RunAsync
之前完成。因此,当位图
仍然完全为空时,很可能会开始执行位图.GetPixelAsync
要解决此问题,应将代码移到lambda中:
//Render a bitmap image
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
await bitmap.RenderAsync(canvas, 1380, 800);
using (var inputImgStream = new InMemoryRandomAccessStream()) //this doesn't work
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId,
inputImgStream
); // I suspect passing the MemoryStream is the issue. While 'StorageFile' is used there are no issues.
IBuffer pixelBuffer = await bitmap.GetPixelsAsync();
Debug.WriteLine($"Capacity = {pixelBuffer.Capacity}, Length={pixelBuffer.Length}");
var pixelArray = pixelBuffer.ToArray();
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint) bitmap.PixelWidth,
(uint) bitmap.PixelHeight,
DisplayInformation.GetForCurrentView().LogicalDpi,
DisplayInformation.GetForCurrentView().LogicalDpi,
pixelArray
);
await encoder.FlushAsync(); // The application hangs here
}
});
如您所见,还必须在lambda内部移动流的using
块,因为如果它在外部,同样的命运也会发生-在RenderAsync
完成之前,使用的可能会处理流的