Приложение UWP зависает при преобразовании холста в изображение - PullRequest
0 голосов
/ 28 мая 2018

Я пытаюсь преобразовать холст в UWP в изображение (RenderTargetBitmap).У меня есть два варианта вернуть изображение конечному пользователю.

  1. StorageFile
  2. 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);
    }

Может кто-нибудь указать мне, что это вызвало?

1 Ответ

0 голосов
/ 28 мая 2018

Действительно кажется, что использование простого MemoryStream с AsRandomAccessStream не работает, хотя я не уверен в причине.Вместо этого вы можете использовать InMemoryRandomAccessStream, который будет работать должным образом.

Однако существует другая проблема, которая может быть источником проблем или, по крайней мере, приводить к сбою на моем компьютере:

//Render a bitmap image
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
   CoreDispatcherPriority.Normal, async () => 
   {
      await bitmap.RenderAsync(canvas, 1380, 800);
   });

Хотя кажется, что await будет ждать завершения вызова RenderAsync, этого, к сожалению, нет.Второй параметр - только DispatchedHandler.Этот делегат имеет следующую подпись:

public delegate void DispatchedHandler()

Как видите, возвращаемое значение Task отсутствует.Это означает, что он создаст async void лямбду.Лямбда начнет работать, и когда она достигнет RenderAsync, она начнет ее выполнять, но await *1019* может (и, скорее всего, ) закончить до 1024 * делает.Таким образом, вполне вероятно, что вы начнете выполнять bitmap.GetPixelAsync, пока bitmap все еще полностью пуст.

Чтобы это исправить, вы должны переместить код внутри лямбды:

//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
    }
});

Как видите, вы также должны переместить блок using для потока внутри лямбды, потому что, если бы он был снаружи, случилась бы та же самая судьба - using мог бы Dispose потока перед RenderAsync закончено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...