C# 将画布转换为图像时,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

我正在尝试将UWP中的画布转换为图像(
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
    完成之前,使用
    可能会
    处理流的