Measurement Studio for .NET Languages

cancel
Showing results for 
Search instead for 
Did you mean: 

wpf graph export to image

Solved!
Go to solution

How to export WPF graph to vector or raster image?

0 Kudos
Message 1 of 20
(13,288 Views)

You can use a RenderTargetBitmap to convert a WPF visual into a bitmap, and a BitmapEncoder to save an in-memory bitmap image to disk.


Here is an example adapted from How to: Encode a Visual to an Image File that saves a graph to a PNG file:


    // Save control to bitmap.
    Rect bounds = LayoutInformation.GetLayoutSlot( graph );
    var bitmap = new RenderTargetBitmap( (int)bounds.Width, (int)bounds.Height, 96, 96, PixelFormats.Pbgra32 );
    bitmap.Render( graph );

    // Save bitmap to disk.
    string path = ...;
    var encoder = new PngBitmapEncoder { Frames = { BitmapFrame.Create( bitmap ) } };
    using( Stream stream = File.Create( path ) )
        encoder.Save( stream );

~ Paul H
Message 2 of 20
(13,276 Views)

This works indeed, but image quality is low. How can I render high-resolution image from the graph? If I make it very big in XAML, then it's cut in resulting image as it doesn't fit to the screen.

0 Kudos
Message 3 of 20
(13,244 Views)

The easiest way I know would be to manually layout the control and wait for it to update before saving it to a bitmap:


    // Force graph to larger display size.
    const int size = 1000;
    Rect bounds = new Rect( 0, 0, size, size );
    graph.Measure( bounds.Size );
    graph.Arrange( bounds );

    // Wait for WPF layout system to update graph.
    Dispatcher.BeginInvoke( new Action( delegate {
        // Save graph to bitmap.
        RenderTargetBitmap rtb = new RenderTargetBitmap( size, size, 96, 96, PixelFormats.Pbgra32 );
        rtb.Render( graph );

        // Return graph to previous size.
        ((UIElement)graph.Parent).InvalidateMeasure( );

        // Save bitmap to disk.
        PngBitmapEncoder png = new PngBitmapEncoder { Frames = { BitmapFrame.Create( rtb ) } };
        using( Stream stream = File.Create( path ) )
            png.Save( stream );
    } ), DispatcherPriority.Background );

~ Paul H
0 Kudos
Message 4 of 20
(13,238 Views)

I even defined this size in XAML. Problem is that when graph is larger than application window, then bitmap is cut (only visible graph part is on image).

0 Kudos
Message 5 of 20
(13,223 Views)

Hi EugeneM,

 

Can you attach a screenshot of the entire application window? I'm not sure what I'm looking at in your screenshot. 

National Instruments
Applications Engineer
0 Kudos
Message 6 of 20
(13,199 Views)

this wasn't screenshot but generated png

 

there is screenshot of application

0 Kudos
Message 7 of 20
(13,193 Views)

Hi EugeneM,

 

Try scaling the image to render at a higher quality. You can use the BitmapCache.RenderAtScale Property to force a higher resolution. See the sample XAML snippet below. Let me know if this gets you headed in the right direction!

 

<Rectangle>
     <Rectangle.Fill>
          <VisualBrush x:Name="visual1" Visual="{Binding ElementName=graph1}"/>
     </Rectangle.Fill>
     <Rectangle.CacheMode>
          <BitmapCache RenderAtScale="6"/>
     </Rectangle.CacheMode>
</Rectangle>

 

Regards,

 

Alexandra

National Instruments
Applications Engineer
0 Kudos
Message 8 of 20
(13,175 Views)
Solution
Accepted by topic author eugenem

If you want to define the size of the control in XAML, then you will need put it in a panel that does not clip the size of its children, like a Canvas:


    <Canvas>
        <Graph x:Name="graph" Width="1000" Height="1000" />
    </Canvas>


Using this XAML with the original bitmap save snippet should produce an unclipped image measuring a thousand pixels on each side.

~ Paul H
Message 9 of 20
(13,150 Views)

Hi, Paul!

 

Much better indeed. The only problem that PNG from such graph is slightly cut on sides

0 Kudos
Message 10 of 20
(13,146 Views)