(UWP) Сохранить сетку как png

Я разрабатываю приложение UWP, в котором есть Grid с дочерними элементами, Image и TextBlock. У меня есть 2 вещи, которых я хотел бы достичь, и мне нужна помощь.

  1. Как сохранить элемент Grid вместе с его дочерним содержимым в виде изображения (желательно PNG) в локальной папке с предопределенным именем?

  2. Как мне восстановить это сохраненное изображение, а затем включить его в качестве вложения, чтобы поделиться с другими совместимыми приложениями?

Пример:

    <StackPanel Orientation="Vertical">
        <Grid Name="myGrid"
              HorizontalAlignment="Stretch"
              Background="Black">

            <Image Name="myImage"
                   Source="Assets/image1.png"
                   Stretch="Uniform"/>

            <TextBlock Name="myTextBlock"
                       HorizontalAlignment="Center"
                       VerticalAlignment="Center"
                       TextWrapping="Wrap"
                       Text="Sample user text"/>
        </Grid>

        <Button Name="saveButton"
                Content="Save"
                Margin="10,10,0,0"
                Click="saveButton_Click" />

        <Button Name="shareButton"
                Content="Share"
                Margin="10,10,0,0"
                Click="shareButton_Click" />
    </StackPanel>

РЕДАКТИРОВАТЬ: пробовал этот фрагмент кода внутри события saveButton_Click. Кажется, не работает.

    RenderTargetBitmap rtb = new RenderTargetBitmap();
    await rtb.RenderAsync(myGrid);

    var pixelBuffer = await rtb.GetPixelsAsync();
    var pixels = pixelBuffer.ToArray();

    var displayInformation = DisplayInformation.GetForCurrentView();

    var stream = new InMemoryRandomAccessStream();
    var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
    encoder.SetPixelData(BitmapPixelFormat.Bgra8,
                         BitmapAlphaMode.Premultiplied,
                         (uint)rtb.PixelWidth,
                         (uint)rtb.PixelHeight,
                         displayInformation.RawDpiX,
                         displayInformation.RawDpiY,
                         pixels);

    await encoder.FlushAsync();
    stream.Seek(0);

    FileStream filestream = File.Create("C:\\Users\\pcUser\\Desktop\\testimage.png", (int)stream.Size);

EDIT2: пробовал этот бит кода. Кажется, что это работает, но я получаю только черное изображение, вероятно, потому, что оно сохраняет только myGrid, а не детский контент.

    RenderTargetBitmap rtb = new RenderTargetBitmap();
    await rtb.RenderAsync(quoteGrid);

    var pixelBuffer = await rtb.GetPixelsAsync();
    var pixels = pixelBuffer.ToArray();

    var displayInformation = DisplayInformation.GetForCurrentView();

    var stream = new InMemoryRandomAccessStream();
    var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
    encoder.SetPixelData(BitmapPixelFormat.Bgra8,
                         BitmapAlphaMode.Premultiplied,
                         (uint)rtb.PixelWidth,
                         (uint)rtb.PixelHeight,
                         displayInformation.RawDpiX,
                         displayInformation.RawDpiY,
                         pixels);

    await encoder.FlushAsync();
    stream.Seek(0);

    var wbm = new WriteableBitmap(rtb.PixelWidth, rtb.PixelHeight);
    await wbm.SetSourceAsync(stream);

    StorageFolder folder = ApplicationData.Current.LocalFolder;
    if (folder != null)
    {
        StorageFile file = await folder.CreateFileAsync("testImage" + ".png", CreationCollisionOption.ReplaceExisting);
        using (var storageStream = await file.OpenAsync(FileAccessMode.ReadWrite))
        {
            encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, storageStream);
            var pixelStream = wbm.PixelBuffer.AsStream();
            await pixelStream.ReadAsync(pixels, 0, pixels.Length);
            encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied, (uint)wbm.PixelWidth, (uint)wbm.PixelHeight, displayInformation.RawDpiX, displayInformation.RawDpiY, new byte[pixelStream.Length]);
            await encoder.FlushAsync();
        }
    }

person Trancol    schedule 28.12.2016    source источник
comment
Похоже, вы можете использовать класс RenderTargetBitmap в пространстве имен Windows.UI.Xaml.Media.Imaging для выполнения шага 1. В первой части этого руководства он хорошо рассматривается: metulev.com/render-xaml-to-image-and-more   -  person Lincoln Green    schedule 28.12.2016
comment
@LincolnGreen Тогда как мне сохранить объект RenderTargetBitmap? Я новичок в программировании для Windows.   -  person Trancol    schedule 28.12.2016
comment
Просто сохраните поток в файл   -  person Christian Klemm    schedule 28.12.2016
comment
Обновил мой пост с дополнительными кодами. Пожалуйста ознакомтесь.   -  person Trancol    schedule 28.12.2016
comment
Вызовите File.Create без аргумента размера буфера - затем просто выполните stream.CopyTo (filestream);   -  person Lincoln Green    schedule 28.12.2016
comment
@LincolnGreen, похоже, тоже не работает. Я обновил свой пост кодом, который работает наполовину.   -  person Trancol    schedule 28.12.2016


Ответы (1)


Как сохранить элемент Grid вместе с его дочерним содержимым в виде изображения (желательно PNG) в локальной папке с предопределенным именем?

Я проверил ваш код. Вам не нужно было использовать WriteableBitmap, просто передайте файловый поток в метод BitmapEncoder.CreateAsync. Пожалуйста, проверьте следующий код для деталей:

private async void saveButton_Click(object sender, RoutedEventArgs e)
{
        RenderTargetBitmap rtb = new RenderTargetBitmap();
        await rtb.RenderAsync(myGrid);

        var pixelBuffer = await rtb.GetPixelsAsync();
        var pixels = pixelBuffer.ToArray();
        var displayInformation = DisplayInformation.GetForCurrentView();
        var file = await ApplicationData.Current.LocalFolder.CreateFileAsync("testImage" + ".png", CreationCollisionOption.ReplaceExisting);
        using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
        {
            var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
            encoder.SetPixelData(BitmapPixelFormat.Bgra8,
                                 BitmapAlphaMode.Premultiplied,
                                 (uint)rtb.PixelWidth,
                                 (uint)rtb.PixelHeight,
                                 displayInformation.RawDpiX,
                                 displayInformation.RawDpiY,
                                 pixels);
            await encoder.FlushAsync();
        }
}

Как мне восстановить это сохраненное изображение, а затем включить его в качестве вложения, чтобы поделиться с другими совместимыми приложениями?

В вашем случае вы сохраняете изображение в локальной папке. Поэтому, если вы хотите его получить, вам нужно будет использовать API хранилища. Например:

var file = await ApplicationData.Current.LocalFolder.GetFileAsync("testImage.png");

По поводу «включить его как вложение для совместного использования с другим совместимым приложением» вы можете обратиться к официальному Пример приложения для совместного использования источника контента.

person Xie Steven    schedule 28.12.2016
comment
Работает отлично! Большое спасибо! - person Trancol; 29.12.2016