Using Microsoft's Chart Controls In An ASP.NET Application: Exporting Charts

Introduction

The Chart Web control makes it easy to display a chart in an ASP.NET web page - simply drag the Chart control onto the page, set a few properties and either bind it to
a data source control or write a few lines of code that get and bind the data of interest. When a page with a Chart control is visited by a user, the Chart control renders
an <img> element on the page that displays the rendered chart.

The Chart control is great for displaying a chart on a web page, but what if a user wants to view that chart offline, or send the chart to a colleague? In an earlier
installment, Programmatically Generating Chart Images, we examined a number of ways to generate
the chart image programmatically. This technique is useful if you want to modify the chart image before displaying it (to, say, add a watermark) or if you want
to send the chart to a recipient via email. This technique can also be used to allow the visitor to export the chart image into an alternative format.

This article shows how to let users export a chart from a web page to an alternative format. Specifically, we'll look at adding an "Export" button to the chart web page
that, when clicked, exports the chart displayed in the web page to either an image file that can be downloaded or as a PDF file. Read on to learn more!

An Quick Review On Programmatically Rendering the Chart Image

As noted in the Introduction, displaying a chart in a web page is a fairly simple and straightforward process thanks to the Chart control. Thanks to the Chart control,
displaying a chart in a web page is boiled down to a few simple steps: add the Chart control to the page; configure its properties; and specify the data to bind to the
chart. When the page is visited, the Chart control handles the actual work of plotting the data, generating an image file that displays the plotted data, and
rendering an <img> element in the web page to display that image.

While having the chart image automatically created by the Chart control is desired when displaying a standard chart in a web page, for more intricate scenarios we may
need the ability to programmatically create the chart image ourselves. In Programmatically Generating Chart Images
we looked at two such scenarios that warranted programmatically generating the chart's image:

When the chart image needs to be modified before being displayed, or

When the chart image needs to be displayed or provided to the user in some alternative format or medium.

Generating the chart image is easy enough thanks to the Chart class's SaveImage method, which saves the chart image to a file or a stream.
To save the chart image to a file, use:

myChart.SaveImage(filePath, format)

For example, to save the chart image as a PNG image to the Images folder in your web application you would use the following code:

' VB
Using imgStream As New MemoryStream()myChart.SaveImage(imgStream, ChartImageFormat.Png)

... Work with stream data ...
End Using

Once you have the chart image in a stream you can modify it as needed before returning it to the visitor. If you do not want to modify the chart image but just stream
it directly to the client, you can save the chart image to the Response.OutputStream stream directly.

Creating an Exporting Demo

The download available at the end of this article includes two new demos. Both demos render the same user interface, namely a web page with two DropDownList controls
and a Chart Web control. The visitor can choose a category and order year from the DropDownLists; doing so refreshes the page and displays a chart depicting the total
sales per product in the selected category for the selected year. Beneath these two DropDownLists is an Export button that, when clicked, prompts the user to save
the exported chart to their hard drive. The Export button in the first demo we'll look at exports the chart as an image file; the second demo exports the chart as a PDF
file.

The screen shot below shows the first demo when viewed through a browser. Here, the visitor has opted to view the sales for Meat/Poultry in 1997. Beneath these
drop-down lists is the "Export Chart to Image" button, and beneath that is the chart showing the sales figures for the specified category and year.

Again, the idea here is that when the user clicks the Export button they are prompted whether to open or save the image (or PDF), as the dialog box below shows.

Note that both demos plot the chart using K. Scott Allen's
ChartBuilder class, which provides a simple API for
plotting the points in a chart. This class was first examined in the Plotting Chart Data installment.
The markup and code used to display the chart is not discussed in this article; refer to the download available at the end of this article for the actual code. Instead,
we'll focus our attention on how to export a chart as an image and as a PDF.

Sending Content to the Client and Raising a File Download Dialog Box

When the user clicks the Export button in either demo, there is a postback - the browser submits the form, re-requesting the web page and the web server sends back some
content to the browser. Typically, the web server returns HTML to the browser, which is then displayed. When the user clicks the Export button, however, we don't want
to send HTML, but rather the binary contents of the chart export image or PDF file. What's more, when returning this binary data we want the browser to display a
File Download dialog box rather than displaying the returned content in the browser window. We'll talk about how to return the exported image or PDF content to the
browser in a moment, but first let's discuss how to prompt the browser to show the File Download dialog box.

Whenever a web server returns content to a browser - whether it's HTML or the binary contents of an image, say - the web server may include information in addition to
the requested content. This additional information is supplied through HTTP headers. The web server automatically adds several HTTP headers on our behalf, but
we can specify the values for these headers or add additional ones with a bit of code.

One HTTP header is the Content-Type header, which tells the browser what type of content is being returned. For example, when returning HTML, the server
returns a Content-Type header with the value text/html. When returning a GIF image file, the server returns a Content-Type header
with the value image/gif. These Content-Type header values are referred to as MIME
Media Types and are maintained by the Internet Assigned Numbers Authority. By default, an ASP.NET page returns a
Content-Type header of text/html, but you can change this header value by using the
Response.ContentType property.

When the server specifies a MIME Media Type that the browser knows how to display, the content is opened within the browser. For example, if you point your
browser to an image file or a PDF file that file will be loaded directly within the browser. If, instead, you want to prompt the user with a File Download dialog box to
allow them to save the file to their hard drive or to open it in an external viewer, you must add a Content-Disposition HTTP header with a value that
specifies the content should be treated like an attachment; you can also provide a suggested file name to save the file as.

Exporting Charts as PNG Images

When a user visits either of the export demos, a chart is displayed showing the annual sales for those products in the selected category and year. To export the chart
data the user must click the Export button. From the user's perspective, clicking the Export button causes their browser to display a File Download dialog box, allowing
them to save (or open) the exported image or PDF file.

As the page developer implementing this functionality, all we need to do is create a Click event handler for the Export button and write a few lines of
code. In this event handler we need to do the following things:

Specify the content type. When exporting the chart as a PNG image the content type is image/png; for PDF files its application/pdf.

Add a Content-Disposition HTTP header so that the browser will display a File Download dialog box instead of opening the exported chart directly in the browser.

Render the chart (if needed). Since my demos plot the chart's points programmatically we need to re-plot them on every postback.

Indicate that the data to send to the client has ended by calling Response.End(). This ensures that the HTML of the web page is not also included in
the export data sent to the client.

When exporting the chart as an image, step 4 is quite simple - we can call the Chart control's SaveImage method with Response.OutputStream
as the first input parameter. This generates the chart image and writes it directly to the output returned to the client.

The following code implements the five steps detailed above. Here, chtSalesByCategory is the ID of the Chart control:

'STEP 4: Generate the exported content and send it to the client
chtSalesByCategory.SaveImage(Response.OutputStream, ChartImageFormat.Png)

'STEP 5: Indicate that the data to send to the client has ended
Response.End()

That's all there is to it! With this code in place, clicking the "Export Chart to Image" button causes a postback. On postback, the ASP.NET page generates the chart image
and sends its binary contents back to the client along with a Content-Type HTTP header of image/png and a Content-Disposition header
with the value attachment;filename=CategoryName-Year.png. This prompts the browser to display the File Download dialog box, allowing the user
to save the image or open it with the program his computer is configured to use to view PNG files.

Exporting Charts as PDF Files

Due to their cross-platform support and free reader program, PDF files are a popular file format for exporting data. There are a variety of .NET libraries available to
programmatically create PDF documents. A popular one is iTextSharp, which is the .NET version of the
Java-based iText PDF library.

Part of iTextSharp's popularity stems from the fact that it's open source. However, it's important to
keep in mind that starting with version 5.0, iTextSharp is released under the GNU Affero General Public License (AGPL) version 3.
This license requires that any application that uses iTextSharp must also be released under the same license and that you must make your application's source code
freely available (like iTextSharp's is). You can optionally buy a license to be released from the AGPL.
While version 5.0 (and beyond) is released under the more restrictive AGPL, previous versions were released under the
GNU Lesser General Public License (LGPL), which allows the use of iTextSharp within an application
without requiring that the application also be released under the LGPL. In other words, by using version 4 or earlier, you can use iTextSharp in your web application
without having to buy a license and without having to release your web application's source code. (The download available at the end of the article uses iTextSharp
version 4.1.6.) Now that we have that out of the way, let's look at using iTextSharp to export charts to a PDF file.

Exporting a chart to a PDF file involves the same five steps as exporting a chart as an image. The primary difference is that step 4 - generating the exported content and sending
it to the client - is a trifle more involved when exporting to PDF. When exporting a chart as an image we could just call the Chart control's SaveImage
method and blast the chart image file contents directly to the Response.OutputStream stream. When exporting as a PDF, however, we need to create a PDF
document, add the chart image to the PDF document, and then send the binary contents of that PDF document to the client via the Response.OutputStream stream.
Other than this difference (and some other minor differences like the value of the Content-Type header), the exporting code is identical.

'Scale the Image object to fit within the boundary of the PDF document and add it
img.ScaleToFit(doc.PageSize.Width - (doc.LeftMargin + doc.RightMargin), _
doc.PageSize.Height - (doc.TopMargin + doc.BottomMargin))
doc.Add(img)
End Using
Finally
doc.Close()
End Try

'STEP 5: Indicate that the data to send to the client has ended
Response.End()

That's all there is to it! Granted, the export PDF is bland and brain dead simple - as the screen shot below shows, the PDF contains nothing but the chart image, sized
to fit within the PDF document's margins. But with a bit of extra code you could certainly gussy up the PDF to include additional text, a table of data used to built
the chart, and other information.

Conclusion

The Chart control makes it easy to display charts within a web page, but with a bit of code it's possible to generate the underlying chart image, which can then be
exported. In this article we reviewed how to programmatically generate a chart image and then examined the steps necessary to export data to the browser so that the
user is presented with a File Download dialog box rather than having the content displayed directly within the browser. We then put these two capabilities together,
allowing the user to export a chart as either a PNG image or as a PDF file.