Exporting Visifire Silverlight Chart as Image

Chirag

Exporting Silverlight charts to images has been the most coveted feature. In this tutorial, I am going to show you to export Visifire Silverlight chart as image from managed code. So before we start lets check out the live example below.

Get Microsoft Silverlight

Project Setup

Create a “Silverlight Application” project. Download the latest Visifire binaries from here. Extract the Zip file and add reference for the file named “SLVisifire.Charts.dll”. In this sample, I am going to use WriteableBitmap class in order to extract the pixel wise color information of the chart rendered inside Silverlight content. We will take help of JpegEncoder provided by a third party library called FJ.Core to encode the raster information to file stream.

Please download FJ.Core library from here and add the FJ.Core.dll as reference to the project.

Below are the steps that we are going to follow.

  1. Construct the Chart XAML inside MainPage.xaml.
  2. Exporting Chart as image.

Constructing Chart XAML

Open MainPage.xaml page, add a Chart and a button inside it as shown below:

<UserControl x:Class="SLSave2Image.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:vc="clr-namespace:Visifire.Charts;assembly=SLVisifire.Charts"
    mc:Ignorable="d" Width="500" Height="480">
    <Grid x:Name="LayoutRoot">
        <StackPanel>
            <vc:Chart Name="MyChart" Width="500" Height="300" Theme="Theme1">

                <vc:Chart.Titles>
                    <vc:Title Text="Visifire Chart"/>
                </vc:Chart.Titles>

                <vc:Chart.Series>
                    <vc:DataSeries RenderAs="Column" LabelEnabled="True">
                        <vc:DataSeries.DataPoints>
                            <vc:DataPoint AxisXLabel="Jan" YValue="35"/>
                            <vc:DataPoint AxisXLabel="Feb" YValue="32"/>
                            <vc:DataPoint AxisXLabel="Mar" YValue="27"/>
                            <vc:DataPoint AxisXLabel="Apr" YValue="17"/>
                            <vc:DataPoint AxisXLabel="May" YValue="16"/>
                        </vc:DataSeries.DataPoints>
                    </vc:DataSeries>
                </vc:Chart.Series>
            </vc:Chart>
            <Button Name="ButtonSave" Height="25" Width="160" Content="Save Chart" ></Button>
        </StackPanel>
    </Grid>
</UserControl>

Exporting Chart as image

Now open MainPage.xaml.cs page and add the following namespaces.

using FluxJpeg.Core;
using FluxJpeg.Core.Encoder;
using System.Windows.Media.Imaging;
using System.IO;
using Visifire.Charts;

Now attach an event handler for Click event of Button inside the Page constructor.

public MainPage()
{
    InitializeComponent();

    ButtonSave.Click += new RoutedEventHandler(ButtonSave_Click);
}

void ButtonSave_Click(object sender, RoutedEventArgs e)
{
    SaveToImage(MyChart);
}

Inside the ButtonSave event handler declare a function called SaveToImage() which will accept Chart as parameter as shown above.

Now inside the function definition, create a WriteableBitmap out of a Chart and collect the raster information from it. Then encode the raster information to file stream using JpegEncoder present in FJ.Core library as shown below. Finally save the file stream as image into hard drive.

/// <summary>
/// Save Visifire chart as Image
/// </summary>
/// <param name="Chart">Visifire.Charts.Chart</param>
private void SaveToImage(Chart chart)
{
    try
    {
        WriteableBitmap bitmap = new WriteableBitmap(chart, null);

        if (bitmap != null)
        {
            SaveFileDialog saveDlg = new SaveFileDialog();
            saveDlg.Filter = "JPEG Files (*.jpeg)|*.jpeg";
            saveDlg.DefaultExt = ".jpeg";

            if ((bool)saveDlg.ShowDialog())
            {
                using (Stream fs = saveDlg.OpenFile())
                {
                    MemoryStream stream = GetImageStream(bitmap);

                    //Get Bytes from memory stream and write into IO stream
                    byte[] binaryData = new Byte[stream.Length];
                    long bytesRead = stream.Read(binaryData, 0, (int)stream.Length);
                    fs.Write(binaryData, 0, binaryData.Length);
                }
            }
        }
    }
    catch(Exception ex)
    {
        System.Diagnostics.Debug.WriteLine("Note: Please make sure that Height and Width of the chart is set properly.");
        System.Diagnostics.Debug.WriteLine(ex.Message);
    }
}

/// <summary>
/// Get image MemoryStream from WriteableBitmap
/// </summary>
/// <param name="bitmap">WriteableBitmap</param>
/// <returns>MemoryStream</returns>
public static MemoryStream GetImageStream(WriteableBitmap bitmap)
{
    byte[][,] raster = ReadRasterInformation(bitmap);
    return EncodeRasterInformationToStream(raster, ColorSpace.RGB);
} 

/// <summary>
/// Reads raster information from WriteableBitmap
/// </summary>
/// <param name="bitmap">WriteableBitmap</param>
/// <returns>Array of bytes</returns>
public static byte[][,] ReadRasterInformation(WriteableBitmap bitmap)
{
    int width = bitmap.PixelWidth;
    int height = bitmap.PixelHeight;
    int bands = 3;
    byte[][,] raster = new byte[bands][,];

    for (int i = 0; i < bands; i++)
    {
        raster[i] = new byte[width, height];
    }

    for (int row = 0; row < height; row++)
    {
        for (int column = 0; column < width; column++)
        {
            int pixel = bitmap.Pixels[width * row + column];
            raster[0][column, row] = (byte)(pixel >> 16);
            raster[1][column, row] = (byte)(pixel >> 8);
            raster[2][column, row] = (byte)pixel;
        }
    }

    return raster;
}

/// <summary>
/// Encode raster information to MemoryStream
/// </summary>
/// <param name="raster">Raster information (Array of bytes)</param>
/// <param name="colorSpace">ColorSpace used</param>
/// <returns>MemoryStream</returns>
public static MemoryStream EncodeRasterInformationToStream(byte[][,] raster, ColorSpace colorSpace)
{
    ColorModel model = new ColorModel { colorspace = ColorSpace.RGB };
    FluxJpeg.Core.Image img = new FluxJpeg.Core.Image(model, raster);

    //Encode the Image as a JPEG
    MemoryStream stream = new MemoryStream();
    FluxJpeg.Core.Encoder.JpegEncoder encoder = new FluxJpeg.Core.Encoder.JpegEncoder(img, 100, stream);
    encoder.Encode();

    // Back to the start
    stream.Seek(0, SeekOrigin.Begin);

    return stream;
}

You can download the complete solution here

(Hat tip to Visifire user Sagi Karni, Intel Corp)

Cheers,
Team Visifire


Comments

  1. Burkovsky
    November 13th, 2009 | 7:32 am

    Hi,

    it is nice. I need also to generate jpg for reporting. Means without showing it to user (not in visual tree). Is there any way to achieve it?

    Regards,
    Ladislav

  2. Somnath
    November 13th, 2009 | 8:53 am

    Hi Burkovsky,

    [Means without showing it to user (not in visual tree).]

    What you don’t want to show to user? Save dialog box or the Chart?

    Regards,
    Somnath

  3. November 16th, 2009 | 4:44 pm

    All,

    Can you export an image of the chart if you are using VisiFire with a standard ASP.NET project?

    Thanks,
    Steven McWhorter

  4. Zhaobo
    November 27th, 2009 | 2:19 am

    Hi,
    Can you export an image of the chart if you are using VisiFire with a standard JSP project?

  5. vivek
    November 27th, 2009 | 3:16 am

    Hi,

    Unfortunately it is is not possible to export chart as image in an Asp.Net or JSP project. Currently you can do it in a Silverlight application only.
    We will add the above requested feature in our future releases. Please find out the similar post below:
    http://www.visifire.com/forums/index.php?showtopic=1485

  6. Francois
    January 5th, 2010 | 6:55 am

    Hi

    I have the same requirement, is it possible to create/render a chart on the server side using WPF not Silverlight.

    Regards

    F

    ——————————————————————————–

    Hi,

    it is nice. I need also to generate jpg for reporting. Means without showing it to user (not in visual tree). Is there any way to achieve it?

    Regards,
    Ladislav

  7. vivek
    January 5th, 2010 | 7:49 am

    Hi Francois,

    Yes you can generate an image from chart in WPF also. Please have a look at the documentation sample below.
    http://www.visifire.com/documentation/Visifire_Documentation/Common_Tasks/Exporting_Chart_toImage_using_Managed_Code_in_WPF.htm

  8. vivek
    January 5th, 2010 | 7:53 am

    Hi Ladislav,

    Can you please elaborate your query? Also it would be better if you can post your query in Visifire forums so that it will be helpful for others also.
    http://www.visifire.com/forums

  9. January 5th, 2010 | 11:55 am

    All,

    You can export an image in a standard ASP.NET project if you make your own SilverLight control and pass in the VisiFire XAML through JavaScript and deserialize the XAML into a chart object within the Silverlight control. Once you have the Chart rendered, you can follow the steps in the blog post to export the image.

    So you have two Silverlight controls on your ASP.NET form. One is VisiFire’s and the other is yours. Its basically the same as how the VisiFire works.

    Thanks,
    Steven McWhorter

  10. May 10th, 2010 | 9:27 am

    [...] von VisiFire Charts mit Silverlight 3 Von webjagger Das Beispiel aus dem VisiFire Forum funktioniert, wenn man’s nun noch so hinbiegen könnte, dass man die Images nicht auf dem [...]

  11. Dave
    June 8th, 2010 | 9:43 am

    Is it possible to use the Export function without prompting the user (the save file dialog). Id like to be able to then take that image and import to PPT slide without prompt.

  12. smaran
    July 1st, 2010 | 11:49 am

    How can i export the chart to a different size than it is visible on the page.

    1.Always only the chart rendered can be exported.I am not able to export a chart created in managed code.

    2.If the chart is made resizeable to screen then the exported image also changes. Not able to set size of chart.

  13. vivek
    July 2nd, 2010 | 1:21 am

    Hi,

    @Dave, If you are working with Silverlight then you have to export chart using save file dialog only. But if you are working with WPF, then you can export the chart without using save file dialog also. Please follow the documentation sample below:
    http://www.visifire.com/documentation/Visifire_Documentation/Common_Tasks/Exporting_Chart_toImage_using_Managed_Code_in_WPF.htm

    @smaran, If you are working with WPF, then you can export the chart without rendering it. Please check out the example present in the documentation below:
    http://www.visifire.com/documentation/Visifire_Documentation/Common_Tasks/Exporting_Chart_as_Image_without_Rendering.htm

    Regarding your second query, If you are working with Silverlight then the exported image size will be the same as chart size. But if you are working with WPF, you can save the chart image in a different size than the actual chart size. Please follow the documentation sample below:
    http://www.visifire.com/documentation/Visifire_Documentation/Common_Tasks/Exporting_Chart_toImage_using_Managed_Code_in_WPF.htm

    In this sample, you just have to set proper size and dpi values while creating a bitmap as shown below:
    RenderTargetBitmap renderBitmap = new RenderTargetBitmap( (int)surface.Width + 250, (int)surface.Height + 200, 120d, 120d, PixelFormats.Pbgra32);

  14. Dipti Patil
    July 14th, 2010 | 9:49 am

    Hi,

    I am using silverlight.
    I need to use visifire chart image in pdf file along with other details. [Currently I am creating pdf file in web application in .aspx file]
    Is there any way to do this?

  15. vivek
    July 15th, 2010 | 12:51 am
  16. Waqas Habib
    March 28th, 2011 | 7:22 am

    i want to export chart as image, i have done this. My problem is that before showing save dialog, i want to change my chart size dynamically.

    For Example

    onClick
    {
    chart.height=500;
    chart.width=800;

    // show save dialog
    }

    This save the chart with old size, not with the changed size.

  17. dave
    October 5th, 2011 | 4:09 am

    hi, im trying to save couple of charts that has transparent background. This solution makes the background black. is there any workaround for this scenario?

  18. vivek
    October 10th, 2011 | 3:28 am

    Dave,

    You must be trying to export the chart with transparent background as Jpg due to which you are getting a black background. Please note that Jpg doesn’t support transparency. You have to set some background color in chart. PNG supports transparency but unfortunately Visifire doesn’t support exporting chart as PNG. If you are working in WPF, then you will be able to save the chart with transparent background as PNG.

Leave a reply