Wrox Home  
Search P2P Archive for: Go

  Return to Index  

aspx thread: FW: Dynamic Image Generation with ASP.NET...


Message #1 by Scott Guthrie <scottgu@m...> on Sun, 14 Jan 2001 19:37:12 -0800
Reposting from a post I did on the ASPNGBeta listserv

(http://www.asplists.com/asplists/aspngbeta.asp) in case some people aren't

on it.



Thanks,



Scott



------------------------



>  -----Original Message-----

> From: 	Scott Guthrie  

> Sent:	Sunday, January 14, 2001 2:00 PM

> To:	'aspngbeta@l...'

> Subject:	Dynamic Image Generation with ASP.NET...

> 

> One of the neat features that you can now leverage with .NET is the

> ability to easily generate dynamic images from code -- which you can then

> either save to disk or directly stream back to a browser client with

> ASP.NET.  

> 

> The functionality to generate images with .NET is encapsulated within the

> System.Drawing namespace.  It provides built-in support for generating

> images with a numer of file formats including: JPEG, GIF, PNG, TIFF, BMP,

> PhotoCD, FlashPIX, WMF, EMF and EXIF.  Note that there are no license

> issues to worry about with any of these file formats -- our implementation

> of each format is license free (including for GIF images).

> 

> The general mechanism through which you generate these graphics images is

> by constructing a BitMap object which provides an in-memory representation

> of your image.  You can then call its "Save" method to either save it to

> disk -- or stream it out to any .NET output stream.  Because ASP.NET

> exposes a .NET OutputStream via the Response.OutputStream property -- this

> means you can stream the image contents directly to the browser (without

> ever having to save it to disk).

> 

> For example, to do this in VB you would write code like:

> 

>         ' Create In-Memory BitMap of JPEG

>         Dim MyChartEngine as New ChartEngine

>         Dim StockBitMap as BitMap = MyChartEngine.DrawChart(600, 400,

> myChartData)

> 

>         ' Render BitMap Stream Back To Browser

>         StockBitMap.Save(Response.OutputStream, ImageFormat.JPEG)

> 

> If you are using an ASPX page to do this, you will want to make sure you

> set the appropriate HTTP ContentType header as well (so that the browser

> client doesn't interpret the page's content as html -- but rather as an

> image).  You can do this either via setting the Response.ContentType

> property through code, or via the new "ContentType" attribute that you can

> set on the top-level page directive:

> 

>        <%@ Page Language="VB" ContentType="image/jpeg" %>

> 

> Note that the output caching features of ASP.NET work for both textual

> content -- as well as for binary output.  As such, if you are dynamically

> generating an image from a page, you can easily leverage the output cache

> directive to avoid having to regenerate the image on each request (note:

> image generation can be expensive -- so this is highly recommended).  For

> example, the below directive could be used to output cache the generated

> image for a 60 second interval:

> 

>        <%@ Page Language="VB" ContentType="image/jpeg" %>

>        <%@ OutputCache Duration="60" %>

> 

> For a complete sample of how to use image generation, I've included a

> simple stock chart generation sample below (note that the stock prices

> aren't real -- just wishful thinking on my part :-).  The sample uses a

> custom "ChartEngine" class that helps encapsulate the logic required to

> build up a generic chart.  You should be able to use this helper component

> to do any custom charting of your own -- it is definitely not limited to

> just stock data. 

> 

> Feel free to use any of the code however you want (and like with all my

> other samples -- feel free to post elsewhere as well as to use for

> articles, other samples, etc).

> 

> Thanks,

> 

> Scott

> 

> -------------------------------------------------------------------------

> Instructions:

> -------------------------------------------------------------------------

> 

> To run the sample, copy/paste/save the below files into an IIS Application

> VRoot.  Then type the below statements into a command line:

> 

>      mkdir bin

>      csc /t:library /out:bin\chartgen.dll ChartEngine.cs /r:System.Web.dll

> /r:System.Winforms.dll /r:System.Drawing.dll /r:System.dll

> 

> Once the chartengine helper utility is compiled, hit the StockPicker.aspx

> page to run the sample (note that this in turn sets up a <img> tag to

> point to the ImageGenerator_VB.aspx page that does the actual image

> generation work).

> 

> --------------------------------------------------------------------------

> StockPicker.aspx:

> --------------------------------------------------------------------------

> 

> <script language="VB" runat=server>

> 

>    Sub ChartBtn_Click(Sender as Object, E as EventArgs) 

>       

>       chart.ImageUrl = "ImageGenerator_Vb.aspx?"

>       chart.Visible = true

> 

>       For i=0 to Stocks.Items.Count-1

>          If (Stocks.Items(i).Selected = true) Then

>              chart.ImageUrl = chart.ImageUrl & "symbols=" &

> Stocks.Items(i).Value & "&"

>          End If

>       Next

> 

>    End Sub

> 

> </script>

> 

> <html>

>    <body>

>       <form runat=server>

> 

>          <h1>Scott's Stock Picker</h1>

> 

>          <asp:checkboxlist id="Stocks" runat=server>

>              <asp:listitem>MSFT</asp:listitem>

>              <asp:listitem>SUN</asp:listitem>

>          </asp:checkboxlist>

> 

>          <asp:button text="Chart Your Selected Stocks"

> OnClick="ChartBtn_Click" runat=server/>

>          <hr>

>          <asp:Image id="chart" ImageUrl="" Visible=false runat=server/>

> 

>       </form>

>    </body>

> </html>

> 

> --------------------------------------------------------------------------

> ImageGenerator_VB.aspx:

> --------------------------------------------------------------------------

> 

> <%@ Page Language="VB" ContentType="image/jpeg" %>

> <%@ Import Namespace="System.Drawing" %>

> <%@ Import Namespace="System.Drawing.Drawing2D" %>

> <%@ Import Namespace="System.Drawing.Imaging" %>

> <%@ Import Namespace="ChartGenerator" %>

> <%@ OutputCache Duration="10" %>

> 

> <script language="VB" runat=server>

> 

>     Function GetStockDetails(Symbol as String) as ChartLine 

> 

>         Dim myChartLine as new ChartLine

> 

>         if (symbol = "msft") then

> 

>             Dim StockValues() as Single = { 60, 110, 120, 180, 185, 190,

> 240, 290 }

> 

>             myChartLine.Width = 5

>             myChartLine.Color = Color.Blue

>             myChartLine.LineStyle = DashStyle.Solid

>             myChartLine.Title = "Microsoft Corp. (MSFT)"

>             myChartLine.Symbol = "MSFT"

>             myChartLine.Values = StockValues

>             return myChartLine

> 

>         elseif (symbol = "sun") then

> 

>             Dim StockValues() as Single = { 180, 155, 125, 60, 25, 15, 10,

> 3 }

> 

>             myChartLine.Width = 5

>             myChartLine.Color = Color.Red

>             myChartLine.LineStyle = DashStyle.Dot

>             myChartLine.Title = "Sun Corp. (Sun)"

>             myChartLine.Symbol = "Sun"

>             myChartLine.Values = StockValues

>             return myChartLine

> 

>         end if

> 

>         return nothing

> 

>     End Function

> 

>     Sub Page_Load(Sender as Object, E as EventArgs) 

> 

>         ' Generate Chart Data For Image....

>         Dim XAxes() as String = { "9:00AM", "9:30AM", "10:00AM",

> "11:00AM", "12:00AM", "1:00PM", "1:30PM" }

>         

>         Dim MyChartData as New ChartData

>         MyChartData.YTickSize = 20

>         MyChartData.YMax = 250

>         MyChartData.YMin = 0

>         MyChartData.XAxisTitles = XAxes

> 

>         Dim Symbols() as String = Request.QueryString.GetValues("symbols")

> 

>         if (Not Symbols = Nothing) then

> 

>            for i=0 to Symbols.Length-1

> 

>               Dim stockValue as ChartLine 

> GetStockDetails(symbols(i).ToLower)

> 

>               If (stockValue <> nothing) then

>                  myChartData.Lines.Add(stockValue)

>               End if

> 

>            Next 

> 

>         end if

> 

>         ' Create In-Memory BitMap of JPEG

>         Dim MyChartEngine as New ChartEngine

>         Dim StockBitMap as BitMap = MyChartEngine.DrawChart(600, 400,

> myChartData)

> 

>         ' Render BitMap Stream Back To Client

>         StockBitMap.Save(Response.OutputStream, ImageFormat.JPEG)

>     

>      End Sub

> 

> </script>

> 

> --------------------------------------------------------------------------

> ChartEngine.cs:

> --------------------------------------------------------------------------

> 

> using System.WinForms;

> using System.Collections;

> using System.Collections.Bases;

> using System.Drawing;

> using System.Drawing.Drawing2D;

> using System.Drawing.Imaging;

> using System.ComponentModel;

> using System;

> using System.IO;

> 

> namespace ChartGenerator  {

> 

>     //Core Line Data structure 

>     public struct LineData {

>         public float[] LineValues  ;

>         public string LineTitle ;

>         public string LineSymbol ;

>     }

> 

>     //Line Data plus display style information 

>     public class ChartLine {

> 

>         private Color lineColor ;

>         private LineData lineData ;

>         private DashStyle lineStyle ;

>         private int lineWidth  ;

> 

>         //Constructors

>         public ChartLine() :base() {}

> 

>         public ChartLine(LineData lineData) :base() {

>             this.lineData = lineData;

>         }

> 

>         //Properties

>         public Color Color { 

>             get { return lineColor ; }

>             set { lineColor = value ; }

>         }

> 

>         public DashStyle LineStyle {

>             get { return lineStyle ; }

>             set { lineStyle = value ; }

>         }

>         

>         public string Symbol {

>             get { return lineData.LineSymbol ; }

>             set { lineData.LineSymbol = value ; }

>         }

> 

>         public string Title {

>             get { return lineData.LineTitle ; }

>             set { lineData.LineTitle = value ; }

>         }

> 

>         public float[] Values {

>             get { return lineData.LineValues ; }

>             set { lineData.LineValues = value ; }

>         }

> 

>         public int Width { 

>             get { return lineWidth ; }

>             set { lineWidth = value ; }

>         }

> 

>         //Methods

>         public void SetLineData(LineData lineData) {

>             this.lineData = lineData;

>         }

>     }

> 

>     //Chart Data structure

>     public class ChartData {

> 

>         private float yTickSize;

>         private float yMax;

>         private float yMin;

>         private string[] xAxisTitles ;

>         private ChartLineList lines = new ChartLineList();

>         private Color gridColor=Color.Blue;

>         private bool showHGridLines=true;

>         private bool showVGridLines=true;

> 

>         //Properties

>         public float YTickSize {

>             get { return yTickSize ; }

>             set { yTickSize = value ; }

>         }

> 

>         public float YMax {

>             get { return yMax ; }

>             set { yMax = value ; }

>         }

> 

>         public float YMin {

>             get { return yMin ; }

>             set { yMin = value ; }

>         }

> 

>         public string[] XAxisTitles {

>             get { return xAxisTitles ; }

>             set { xAxisTitles = value ; }

>         }

> 

>         public ChartLineList Lines {

>             get { return lines ; }

>             set { lines = value ; }

>         }

> 

>         public Color GridColor {

>             get { return gridColor ; }

>             set { gridColor = value ; }

>         }

> 

>         public bool ShowHGridLines {

>             get { return showHGridLines ; }

>             set { showHGridLines = value ; }

>         }

> 

>         public bool ShowVGridLines {

>             get { return showVGridLines ; }

>             set { showVGridLines = value ; }

>         }

> 

>         //Collection of Chart Lines

>         public class ChartLineList : TypedCollectionBase {

> 

>             public ChartLine this[int index] {

>                get {

>                    return (ChartLine)(List[index]);

>                }

>                set {

>                    List[index] = value;

>                }

>             }

> 

>             public int Add(ChartLine value) {

>                return List.Add(value);

>             }

> 

>             public void Insert(int index, ChartLine value) {

>                List.Insert(index, value);

>             }

> 

>             public int IndexOf(ChartLine value) {

>                return List.IndexOf(value);

>             }

> 

>             public bool Contains(ChartLine value) {

>                return List.Contains(value);

>             }

> 

>             public void Remove(ChartLine value) {

>                List.Remove(value);

>             }

> 

>             public void CopyTo(ChartLine[] array, int index) {

>                List.CopyTo(array, index);

>             }

>        }    

>     }

> 

>     //Charting Engine - draws a chart based on the given ChartData

>     public class ChartEngine {

> 

>         private ChartData chartData ;

> 

>         private float left;

>         private float right;

>         private float top;

>         private float bottom;

> 

>         private float tickCount;

>         private float yCount;   

>         private float hspacing;

>         private float vspacing;

> 

>         private Graphics g;

>         private Rectangle r;

>         private Color backColor;

>         private Color foreColor;

>         private Font baseFont;

>         private Font legendFont;

>         private RectangleF legendRect;

> 

>         public ChartEngine() {

>         }                           

> 

>         public Bitmap DrawChart(int width, int height, ChartData

> chartData) {

> 

>            Bitmap newBitmap = new

> Bitmap(width,height,PixelFormat.Format32bppARGB);

>            Graphics g = Graphics.FromImage(newBitmap);

>         

>            Rectangle r = new Rectangle(0, 0, width, height);

>            Color myForeColor = Color.Black;

>            Color myBackColor = Color.White;

>            Font myFont = new Font("Arial", 10);

> 

>            this.DrawChart(g, r, myBackColor, myForeColor, myFont,

> chartData);

> 

>            return newBitmap;

>         }

> 

>         public void DrawChart(Graphics g, Rectangle r, Color backColor,

> Color foreColor, Font baseFont, ChartData chartData) {

> 

>             this.chartData = chartData;

>             this.g = g;

>             this.r = r;

>             this.backColor = backColor;

>             this.foreColor = foreColor;

>             this.baseFont = baseFont;

>             this.legendFont = new Font(baseFont.FontFamily, (baseFont.Size

> * 2/3), baseFont.Style | FontStyle.Bold);

> 

> 

>             g.SmoothingMode = SmoothingMode.AntiAlias;

> 

>             CalculateChartDimensions();

>             

>             DrawBackground();

>             InternalDrawChart() ;

>         }

> 

>         private void CalculateChartDimensions() {

> 

>             right = r.Width - 5;

>             top = 5 * baseFont.Size ;

>             bottom = r.Height - baseFont.Size * 2;

> 

>             tickCount = chartData.YMin ;

>             yCount = (chartData.YMax-chartData.YMin) / chartData.YTickSize

> ;

>             hspacing = (bottom-top) / yCount;

>             vspacing = (right) / chartData.XAxisTitles.Length;

> 

>             //Left depends on width of text - for simplicities sake assume

> that largest yvalue is the biggest

>             //Take into account the first X Axis title

>             float maxYTextSize 

> g.MeasureString(chartData.YMax.ToString(), baseFont).Width;

>             float firstXTitle = g.MeasureString(chartData.XAxisTitles[0],

> baseFont).Width;

> 

>             left = (maxYTextSize > firstXTitle) ? maxYTextSize :

> firstXTitle ;

>             left = r.X + left + 5 ;

> 

>             //Calculate size of legend box 

> 

>             float maxLegendWidth = 0 ;

>             float maxLegendHeight = 0 ;

> 

>             //Work out size of biggest legend 

>             foreach (ChartLine cl in chartData.Lines) {

>                 float currentWidth = g.MeasureString(cl.Title,

> legendFont).Width;

>                 float currentHeight = g.MeasureString(cl.Title,

> legendFont).Height;

>                 maxLegendWidth = (maxLegendWidth > currentWidth) ?

> maxLegendWidth : currentWidth ;

>                 maxLegendHeight = (maxLegendHeight > currentHeight) ?

> maxLegendHeight : currentHeight ;

>             }

> 

>             legendRect = new RectangleF(r.X+2, r.Y+2, maxLegendWidth + 25

> + 5, ((maxLegendHeight+2)*chartData.Lines.Count) + 3) ;

>         }

> 

>         private void DrawBackground() {

>             LinearGradientBrush b = new LinearGradientBrush(r,

> Color.SteelBlue, backColor,LinearGradientMode.Horizontal);

>             g.FillRectangle(b, r);

>             b.Dispose();

>         }

> 

>         private void InternalDrawChart() {

> 

>             DrawGrid() ;

> 

>             foreach (ChartLine cl in chartData.Lines) {

>                 DrawLine(cl);

>             }

> 

>             DrawLegend() ;

> 

>             //Draw time on chart

>             string timeString = "Generated:" +

> DateTime.Now.ToLongTimeString() ;

>             SizeF textsize = g.MeasureString(timeString,baseFont);

>             g.DrawString(timeString, baseFont, new SolidBrush(foreColor),

> r.Width - textsize.Width - 5, textsize.Height * 2 / 3) ;

>         }                       

> 

>         private  void DrawGrid() {

> 

>             Pen gridPen = new Pen(chartData.GridColor) ;

> 

>             //Vertical - include tick desc's

>             if (chartData.ShowVGridLines) {

>                 for (int i = 0 ; (vspacing * i) < right; i++) {

>                     float x = left + (vspacing *i);           

>                     string desc = chartData.XAxisTitles[i];

>                     g.DrawLine(gridPen, x,top,x,bottom

> +(baseFont.Size*1/3));

>                     SizeF textsize = g.MeasureString(desc,baseFont);

>                     g.DrawString(desc, baseFont, new

> SolidBrush(chartData.GridColor), x-(textsize.Width/2), bottom +

> (baseFont.Size*2/3)) ;

>                 }

>             }

> 

>             //Horizontal

>             if (chartData.ShowHGridLines) {

>                 for (float i = bottom ; i > top; i-=hspacing) {

>                     string desc = tickCount.ToString();

>                     tickCount+=chartData.YTickSize;

>                     g.DrawLine(gridPen, right, i, left-3, i);

>                     SizeF textsize = g.MeasureString(desc,baseFont);

>                     g.DrawString(desc, baseFont, new

> SolidBrush(chartData.GridColor), left-textsize.Width - 3, i -

> (textsize.Height/2)) ;

>                 }

>             }

>         }

> 

>         private void DrawLine(ChartLine chartLine) {

> 

>             Pen linePen = new Pen(chartLine.Color);

>             linePen.StartCap = LineCap.Round;

>             linePen.EndCap = LineCap.Round;

>             linePen.Width = chartLine.Width ;

>             linePen.DashStyle = chartLine.LineStyle;

> 

>             PointF[] Values = new PointF[chartLine.Values.Length];

>             float scale = hspacing / chartData.YTickSize ;

> 

>             for (int i = 0 ; i < chartLine.Values.Length; i++) {

>                 float x = left + vspacing * i;           

>                 Values[i] = new PointF(x,

> bottom-chartLine.Values[i]*scale);

>             }

> 

>             g.DrawLines(linePen, Values);

>         } 

> 

>         private void DrawLegend() {

> 

>             //Draw Legend Box 

>             ControlPaint.DrawBorder(g, (Rectangle)legendRect,

> SystemColors.WindowFrame, ButtonBorderStyle.Solid);

>             LinearGradientBrush b = new LinearGradientBrush(legendRect,

> backColor, Color.SteelBlue, LinearGradientMode.Horizontal);

>             r.Inflate(-1, -1);

>             g.FillRectangle(b, legendRect);

>             b.Dispose();

> 

>             float startY = 5; 

> 

>             foreach (ChartLine cl in chartData.Lines) {

>                 Pen p = new Pen(cl.Color) ;

>                 p.Width = p.Width*4;

>                 SizeF textsize = g.MeasureString(cl.Title, legendFont);

>                 float lineY = startY + textsize.Height / 2 ;

>                 g.DrawLine(p, r.X + 7, lineY, r.X + 25, lineY);

>                 g.DrawString(cl.Title, legendFont, new

> SolidBrush(foreColor), r.X + 30, startY);

>                 startY += (textsize.Height+2);

>             }

>         }

>     }

> }

> 

> 

> 

> 


  Return to Index