Print a Chart into a Byte Stream in VB.NET

Anyone of us could have met the need to be able to create a chart within a web page or a pdf. This article will explain how to build a chart using MSChart and save the output to a stream of bytes, this stream will be redirected to a generic handler, so we'll not use a webform. The same procedure can be used to display the chart in a pdf file, for example using iTextSharp. 

In this project we'll use Northwind database and Entity Data Model and to retrieve data from table orders, we want to display the orders by shipping country.

So we create a new ASP.NET empty project called "WebChartStream", add our database into App_Data and an Entity Model with Orders table mapped in it. 

Now is the time to write the class which will build the chart, so we add a new class called " ChartStream".

We need some imports, the System.Web.UI.DataVisualization.Charting is the MsChart reference while System.IO will be used to build the MemoryStream:

Imports System.IO

Imports System.Web

Imports System.Web.UI.DataVisualization.Charting

The private fields of the class

Private c3d As ChartArea3DStyle
Private db As NORTHWNDEntities
Private serie As Series
Private mchart As Chart

Variable c3d will be used to transform our chart in 3D visualization mode.

The main function of the class is

Public Function ToBytesStream() As Byte()

the output of this function is a steam of bytes, will use this stream to print our chart within the generic handler.

The LINQ to Entity query will select the Orders data grouped and ordered by ShipCountry field:

db = New NORTHWNDEntities
Dim query = From c In db.Orders _
Group c By c.ShipCountry Into g = Group _
Select New With {.Country = ShipCountry, .Orders = g}


Now we can create an instance of chart class and set title, size and the quality of the image, then we add a new chart area.

mchart = New Chart
With mchart
 
    ' Set size of chart
    .Width = 600
    .Height = 400

    ' Set image quality
    .RenderType = RenderType.ImageTag
    .AntiAliasing = AntiAliasingStyles.All
    .TextAntiAliasingQuality = TextAntiAliasingQuality.High

    ' Add title of the cart
    .Titles.Add("Orders by Countries")
    .Titles(0).Font = New System.Drawing.Font("Arial", 16.0F)
    ' Add area
    .ChartAreas.Add("orders")


The 3D view is made creating a ChartArea3DStyle object and setting the desired light style in it:

' Set 3D style
Dim c3d As New ChartArea3DStyle(.ChartAreas(0))
c3d.Enable3D = True
c3d.LightStyle = LightStyle.Realistic

Then we need some settings like Axis X and Y title, font size and type, etc., as you can see in the attached source files so we can omit this obvious part in this article.

The next interesting step is to add values to X and Y series, this is made through looping LINQ query and adding X and Y points to serie:
  serie = New Series

  ' Setting series style
  serie.IsValueShownAsLabel = True
  serie.ChartType = SeriesChartType.Column
  serie.Color = Drawing.Color.MediumPurple

  ' Set X and Y values
  For Each item In query

   serie.Points.AddXY(Convert.ToString(item.Country),Convert.ToDouble(item.Orders.Count))          
   serie.IsValueShownAsLabel = True
  
Next
  ' Add series to chart
  mchart.Series.Add(serie)


Finally we can store the chart into a png image and save it into a MemoryStream, then return the stream buffer to the function:

Chart.jpg

' Save chart image into a memory stream of bytes and return it as byte's array

        Using stream As New MemoryStream
            mchart.SaveImage(stream, ChartImageFormat.Png)
            
Return stream.GetBuffer
        End Using


Now that our class is ready to work we can add a new page in which the chart will be printed, will do this adding a new Generic Handler named GenericHandler.ashx.

The code within the generic handler is very easy, in the ProcessRequest context parameter we'll pass our stream of bytes and then we'll print it to the output through BinaryWrite method:

    Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
        Dim chart As New 
ChartStream
        context.Response.ContentType = "image/png"
        context.Response.BinaryWrite(chart.ToBytesStream)
 
    End Sub

Finally we can see our completed work and view the chart into the web page, run the attached project, click on GenericHandler.ashx link and view the result:


Another useful way to use this class is to print the chart within an iTextSharp pdf document, here a little example of how to use with it:

First we need to create an iTextSharp image and then fill it with our stream:

Dim
 img As iTextSharp.text.Image
img = iTextSharp.text.Image.GetInstance(chart.ToBytesStream)


Then we can add the image to a cell in a table and add the table to our document:

Dim
 table As New PdfPTable(1)
cell = New PdfPCell(img)
table.AddCell(cell)
doc.Add(table)

Now we are ready to print our pdf document.