Wednesday, 22 July 2015

Rendering Grid, Canvas into image in WPF application

In tutorial regarding populating images from local storage in wpf application we displayed images in grid. In this tutorial I want to demonstrate how to easily convert part of grid, canvas to bitmap and save it as jpeg image.

1. Modify XAML code from the previous tutorial. It should look like that.
 <Grid x:Name="MainFrame" ShowGridLines="True">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition Height="40"/>
        </Grid.RowDefinitions>
      
        <Grid x:Name="Photo1" Grid.Row="0" Margin="10" Grid.RowSpan="1"/>
        <Grid x:Name="Photo2" Grid.Row="1" Margin="10" Grid.RowSpan="1"/>
        <Grid x:Name="Photo3" Grid.Row="2" Margin="10" Grid.RowSpan="1"/>


          <Grid x:Name="PrintFooter" HorizontalAlignment="Right" Height="75" VerticalAlignment="Bottom" Width="100" Grid.Row="3">
            <Button Content="Print"  VerticalAlignment="Bottom" Margin="10" Width="75" Click="Button_Click_1" />
        </Grid>
       
    </Grid>

2. Write a method for Button_Click_1 - you can rename the component and method.


private void Button_Click_1(object sender, RoutedEventArgs e)
        {

// Hide print footer

            PrintFooter.Visibility = Visibility.Hidden;
            MemoryStream memstream = GenerateImage(MainFrame, (int)MainFrame.ActualWidth, (int)MainFrame.ActualHeight);


            // save Image

            using (FileStream fstream = File.OpenWrite(System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), string.Format("RemotePhoto\\{0}.{1}", Guid.NewGuid(), ImageFormat.Jpeg))))
            {
                memstream.WriteTo(fstream);
                fstream.Flush();
                fstream.Close();
            }
// Show print footer

            PrintFooter.Visibility = Visibility.Visible;
        }

public MemoryStream GenerateImage(Visual visual, int width, int height)
        {
            BitmapEncoder encoder = new JpegBitmapEncoder();
           
            if (encoder == null) return null;

            RenderTargetBitmap rtb = this.RenderVisualToBitmap(visual, width, height);
            MemoryStream file = new MemoryStream();
            encoder.Frames.Add(BitmapFrame.Create(rtb));
            encoder.Save(file);

            return file;
        }

public RenderTargetBitmap RenderVisualToBitmap(Visual visual, int width, int height)
        {
            RenderTargetBitmap rtb = new RenderTargetBitmap
                (width, height, 96, 96, PixelFormats.Default);
            rtb.Render(visual);
           
            BitmapSource bsource = rtb;
            
            return rtb;
        }



GenerateImage method will accept Visual component which in our case is grid. Using RenderVisualToBitmap method we are going to create RenderTargetBitmap object from Visual component.

New image should appear in your pictures under RemotePhoto folder, you can of course change the location as next print you make will include the image from the results which might look odd.