0

I'm trying to render some UIElements to a RenderTargetBitmap. I have an Image, that is moved around the base Element using a TranslateTransform. When I use RenderTargetTransform.RenderAsync, the Image is rendered without the transform.

I tried using Margin instead, but RenderTargetBitMap does not obey that either.

Can I make it actually use that transform?

Here's the code, the XAML part:

<Page
    x:Class="W8RT_POC.RTBTransform"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:W8RT_POC"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="50" />
        </Grid.RowDefinitions>

        <Grid x:Name="RenderGrid" Grid.Row="0"
              HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >

            <Image x:Name="RenderImage"
                   HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                   Source="Assets/Move_Normal.png" Stretch="Fill" RenderTransformOrigin="0.5,0.5" >
                <Image.RenderTransform>
                    <CompositeTransform TranslateX="100" TranslateY="100"/>
                </Image.RenderTransform>
            </Image>
        </Grid>

        <Button x:Name="GoButton" Content="GO" Grid.Row="1"
                HorizontalAlignment="Left" Click="GoButton_Click" />
    </Grid>
</Page>

... and the code behind:

using System;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

using System.Threading.Tasks;
using Windows.UI.Xaml.Media.Imaging;

namespace W8RT_POC
{
    public sealed partial class RTBTransform : Page
    {
        public RTBTransform()
        {
            this.InitializeComponent();
        }

        private async void GoButton_Click(object sender, RoutedEventArgs e)
        {
            RenderTargetBitmap rtb = new RenderTargetBitmap();
            // Fixed on Filip Skakun's comment. await rtb.RenderAsync(RenderGrid, (int)this.RenderGrid.Width, (int)this.RenderGrid.Height);
            await rtb.RenderAsync(RenderGrid, (int)this.RenderGrid.ActualWidth, (int)this.RenderGrid.ActualHeight);
            await SaveRenderTargetBitmap(rtb);
        }


        private async Task SaveRenderTargetBitmap(RenderTargetBitmap RtbToSave)
        {
            var picker = new Windows.Storage.Pickers.FileSavePicker();
            picker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary;
            picker.FileTypeChoices.Add("GIF file", new string[] { ".gif" });
            picker.DefaultFileExtension = ".gif";
            picker.SuggestedFileName = "Illustration " + DateTime.Now.ToString("yyyy.MM.dd HH:mm:ss");

            Windows.Storage.StorageFile file = await picker.PickSaveFileAsync();

            if (file != null)
            {
                Guid encoderId = Windows.Graphics.Imaging.BitmapEncoder.GifEncoderId;

                var bitmapPropertySet = new Windows.Graphics.Imaging.BitmapPropertySet();

                using (var writeStream = await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite))
                {
                    var encoder = await Windows.Graphics.Imaging.BitmapEncoder.CreateAsync(encoderId, writeStream);

                    byte[] pixels = await GetPixels(RtbToSave);

                    encoder.SetPixelData(
                        Windows.Graphics.Imaging.BitmapPixelFormat.Bgra8,
                        Windows.Graphics.Imaging.BitmapAlphaMode.Premultiplied,
                        (uint)RtbToSave.PixelWidth,
                        (uint)RtbToSave.PixelHeight,
                        96,
                        96,
                        pixels);

                    await encoder.FlushAsync();
                    using (var outputStream = writeStream.GetOutputStreamAt(0))
                    {
                        await outputStream.FlushAsync();
                    }
                } // using(writeStream)
            } // if (file != null)
        }


        private static async Task<byte[]> GetPixels(RenderTargetBitmap bitmap)
        {
            // Get pixels from the RenderTargetBitmap. See http://social.technet.microsoft.com/wiki/contents/articles/20648.using-the-rendertargetbitmap-in-windows-store-apps-with-xaml-and-c.aspx
            // Bytes are in BGRA8 format.
            Windows.Storage.Streams.IBuffer pixelBuffer = await bitmap.GetPixelsAsync();
            byte[] pixels = pixelBuffer.ToArray();
            return pixels;
        }
    }
}

This is what I see on screen (see tha black part left and top): screen content ... and this goes to the saved file (that is created by RenderTargetBitMap.RenderAsync): and this is the rendered result

BalintN
  • 141
  • 1
  • 7
  • I think I've seen some problems with transforms and never checked if they work at all, but Margins should work for sure. If they didn't work - no layout would work. Maybe there is some timing issue in your code and you render before everything's laid out? Can't say without seeing it. – Filip Skakun Aug 01 '14 at 20:28
  • @Filip Skakun: thanks Filip, I added sample code and images. However, I don't think it could be timing: the image itself is visible in the output, and I use "await" on the RenderAsync call itself. – BalintN Aug 02 '14 at 04:37
  • Note that your `RenderGrid` doesn't have `Width` or `Height` set so you should use `ActualWidth` and `ActualHeight` instead in the `rtb.RenderAsync()` call to use the actual dimensions. – Filip Skakun Aug 02 '14 at 04:56
  • @Filip Skakun: your comment is correct. However, fixing it did not fix the render behaior. – BalintN Aug 02 '14 at 14:23

0 Answers0