Isham Mohamed
Isham Mohamed

Reputation: 2789

Create and Save images via RenderAsync() is not working for images chosen from an array randomly in Windows Phone 8.1

I am developing a small game for Windows Phone 8.1 and for that I use an array of image paths and chose one and make it as the background of a Grid and using RenderAsync() generate the Bitmap and save it to the device's Pictures folder.

My Image paths are correct and I use the following code in XAML to create the UI

<StackPanel>
    <Grid x:Name="ResultGrid" Margin="0,-26.667,0,-0.333" Visibility="Visible">
        <Grid.Background>
            <ImageBrush Stretch="Fill" ImageSource="Assets/result/b (3).png"/>
        </Grid.Background>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200*"/>
            <ColumnDefinition Width="200*"/>
        </Grid.ColumnDefinitions>
        <StackPanel x:Name="SuperHeroName" Margin="71,262,-22,212" Grid.Column="1">
            <StackPanel.Background>
                <ImageBrush Stretch="Fill" ImageSource="Assets/result/h (10).png"/>
            </StackPanel.Background>
        </StackPanel>
        <TextBlock x:Name="txtResultSharing" Margin="14,259,107,12" Grid.ColumnSpan="2" FontSize="48" Text="I have earned 78555 points in 8000 levels" TextWrapping="WrapWholeWords" Foreground="#FFA2A2A2" FontFamily="Buxton Sketch"/>
        <Image x:Name="AppLogo" Margin="130,586,10,2" Grid.Column="1" Source="/Assets/FULL LOGO.png"/>
        <TextBlock x:Name="txtResultSharing1" Margin="12,257,109,14" Grid.ColumnSpan="2" FontSize="48" Text="I have earned 78555 points in 8000 levels" TextWrapping="WrapWholeWords" Foreground="White" FontFamily="Buxton Sketch"/>
    </Grid>
</StackPanel>

and the code is

private async void boom()
{
    Random rnd = new Random();
    string[] heroImages = { "ms-appx:///Assets/result/h (1).png", 
                        "ms-appx:///Assets/result/h (2).png", 
                        "ms-appx:///Assets/result/h (3).png", 
                        "ms-appx:///Assets/result/h (4).png", 
                        "ms-appx:///Assets/result/h (5).png", 
                        "ms-appx:///Assets/result/h (6).png",
                        "ms-appx:///Assets/result/h (7).png",
                        "ms-appx:///Assets/result/h (8).png",
                        "ms-appx:///Assets/result/h (9).png",
                        "ms-appx:///Assets/result/h (10).png",
                        "ms-appx:///Assets/result/h (11).png",
                        "ms-appx:///Assets/result/h (12).png",
                        "ms-appx:///Assets/result/h (13).png",
                        "ms-appx:///Assets/result/h (14).png",
                        "ms-appx:///Assets/result/h (15).png",
                        "ms-appx:///Assets/result/h (16).png",
                        "ms-appx:///Assets/result/h (17).png",
                        "ms-appx:///Assets/result/h (18).png",
                        "ms-appx:///Assets/result/h (19).png",
                        "ms-appx:///Assets/result/h (20).png",
                        "ms-appx:///Assets/result/h (21).png",
                        "ms-appx:///Assets/result/h (22).png",
                        "ms-appx:///Assets/result/h (23).png" };
    var imageBrushT = new ImageBrush
    {
        ImageSource = new BitmapImage(new Uri(heroImages[rnd.Next(22)]))
    };
    SuperHeroName.Background = imageBrushT;

    string[] backImages = { "ms-appx:///Assets/result/b (1).png", 
                        "ms-appx:///Assets/result/b (2).png", 
                        "ms-appx:///Assets/result/b (3).png", 
                        "ms-appx:///Assets/result/b (5).png", 
                        "ms-appx:///Assets/result/b (6).png" };
    var imageBrushX = new ImageBrush
    {
        ImageSource = new BitmapImage(new Uri(backImages[rnd.Next(5)]))
    };
    ResultGrid.Background = imageBrushX;

    ResultGrid.UpdateLayout();


    int x = int.Parse(localSettings.Values["CurrLevel"].ToString());
    int y = int.Parse(localSettings.Values["CurrPoints"].ToString());
    txtResultSharing.Text = string.Format("I have earned {0} points in {1} levels", y.ToString(), x.ToString());
    txtResultSharing1.Text = string.Format("I have earned {0} points in {1} levels", y.ToString(), x.ToString());
    ResultGrid.Visibility = Visibility.Visible;
    ResultGrid.UpdateLayout();
    RenderTargetBitmap renderTargetBitmapZ = new RenderTargetBitmap();
    await renderTargetBitmapZ.RenderAsync(ResultGrid);
    var pixels = await renderTargetBitmapZ.GetPixelsAsync();            

    var file = await KnownFolders.PicturesLibrary.CreateFileAsync("picresult.jpg", CreationCollisionOption.ReplaceExisting);

    using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
    {
        var encoder = await
            BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
        byte[] bytes = pixels.ToArray();
        encoder.SetPixelData(BitmapPixelFormat.Bgra8,
                             BitmapAlphaMode.Ignore,
                             (uint)renderTargetBitmapZ.PixelWidth,
                             (uint)renderTargetBitmapZ.PixelHeight,
                             96, 96, bytes);
        await encoder.FlushAsync();
    }
}

This code shows the correct Image in the display when I press the show button and that is enter image description here when I open and see the saved image (ie picresult.jpg)file it shows without the super hero image and the background image. It shows only the logo, and text. (ie, it does not save the images that are randomly chosen from the array but it shows them without any problem)

Please help me

Upvotes: 0

Views: 616

Answers (1)

Bret Bentzinger
Bret Bentzinger

Reputation: 376

Problem is that you are trying to render the grid to the bitmap right after you create the images, which may not have drawn yet. In fact because of what you are seeing it looks like they haven't.
Pre-load the images when your class is constructed:

heroImages = new BitmapImage[3];
heroImages[0] = new BitmapImage(new Uri("ms-appx:///Assets/Image1.png"));
heroImages[1] = new BitmapImage(new Uri("ms-appx:///Assets/Image2.jpg"));
heroImages[2] = new BitmapImage(new Uri("ms-appx:///Assets/Image3.jpg"));

backImages = new BitmapImage[5];
backImages[0] = new BitmapImage(new Uri("ms-appx:///Assets/Image1.png"));
backImages[1] = new BitmapImage(new Uri("ms-appx:///Assets/Image2.jpg"));
backImages[2] = new BitmapImage(new Uri("ms-appx:///Assets/Image3.jpg"));
backImages[3] = new BitmapImage(new Uri("ms-appx:///Assets/Image1.png"));
backImages[4] = new BitmapImage(new Uri("ms-appx:///Assets/Image2.jpg"));

Move your code to a function:

private async Task DrawToFile()
{
    RenderTargetBitmap renderTargetBitmapZ = new RenderTargetBitmap();
    await renderTargetBitmapZ.RenderAsync(ResultGrid);
    var pixels = await renderTargetBitmapZ.GetPixelsAsync();

    var file = await KnownFolders.PicturesLibrary.CreateFileAsync("picresult.jpg", CreationCollisionOption.ReplaceExisting);

    using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
    {
        var encoder = await
            BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
        byte[] bytes = pixels.ToArray();
        encoder.SetPixelData(BitmapPixelFormat.Bgra8,
                             BitmapAlphaMode.Ignore,
                             (uint)renderTargetBitmapZ.PixelWidth,
                             (uint)renderTargetBitmapZ.PixelHeight,
                             96, 96, bytes);
        await encoder.FlushAsync();
    }
}

Then set up a DispatcherTimer somewhere in the Class as follows:

DispatcherTimer _timer;  //  member of class

//  Add Following to constructor
_timer = new DispatcherTimer();
_timer.Interval = new TimeSpan(0, 0, 1);  // 1 second
_timer.Tick += _timer_Tick;

//  Timer Routine
void _timer_Tick(object sender, object e)
{
    _timer.Stop();
    DrawToFile();
}

And Finally Start your timer after your RenderGrid.UpdateLayout() call:

txtResultSharing.Text = string.Format("I have earned {0} points in {1} levels", y.ToString(), x.ToString());
txtResultSharing1.Text = string.Format("I have earned {0} points in {1} levels", y.ToString(), x.ToString());
ResultGrid.Visibility = Visibility.Visible;
ResultGrid.UpdateLayout();

_timer.Start();

This will give the UI 1 second to draw the images before you try and save them to the file. Should work.

Upvotes: 2

Related Questions