Click here to Skip to main content
Licence CPOL
First Posted 9 Oct 2008
Views 33,007
Downloads 584
Bookmarked 29 times

How to generate a WPF image and render it in a Webpage

By Drazzing | 9 Oct 2008 | Unedited contribution
WPF Image generation

1
1 vote, 14.3%
2
1 vote, 14.3%
3

4
5 votes, 71.4%
5
4.17/5 - 7 votes
μ 4.17, σa 2.19 [?]

Introduction

The following code example will show you how to generate a basic image with WPF and render it to a webpage. It will cover the major issues encountered during the development of this solution.

Background

During a project I worked on, we needed to generate an image that contained live data so that when we emailed our client base, an image was rendered from a snap shot of data within our database. This image was embedded into an email so that even if you opened it up a day late it would be live, relevant and data specific to the person reading it. The great thing about this solution is that you could even code your image to generate according to the time the email was open, so if your client opens it a week late you could offer him the current offers or specials.

Using the code

Bellow is a basic aspx web page that will host the binary output of the WPF application. You will need to create an STA thread so as to comunicate with the WPF project.

public partial class _Default : System.Web.UI.Page
{
 private Byte[] _bufferMain;
 public Byte[] BufferMain
{
 get { return _bufferMain; }
 set { _bufferMain = value; }
}
public void Page_Load(object sender, EventArgs e)
{
 if (!IsPostBack)
 {
  DisplayDialog();
  Response.Clear();
  Response.ContentType = @"image/jpeg";
  Response.BufferOutput = true;
  Response.BinaryWrite(BufferMain);
  Response.Flush();
 }
}
[STAThread]
public void DisplayDialog()
{
 try
 {
    Thread worker = new Thread(new ThreadStart(DisplayDialogInternal));
  worker.SetApartmentState(ApartmentState.STA);
  worker.Name = "DisplayDialog";
  worker.Start();
  worker.Join();
 }
catch (Exception exp)
{
 Response.Write(exp.ToString());
}
}
public void DisplayDialogInternal()
{
 try
 {
  string fileName = @"C:\TestWeb.jpg";
  RenderBookingGridImage image = new RenderBookingGridImage();
  //en-code image to transport 
  BufferMain = image.RenderImage("TESTVALUE");
  Stream st = new MemoryStream(BufferMain);
  //de-code view
  JpegBitmapDecoder jpeg = new JpegBitmapDecoder(st, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None);
  using (Stream stm = File.Create(fileName))
  {
   JpegBitmapEncoder encoder = new JpegBitmapEncoder();
   encoder.Frames.Add(jpeg.Frames[0]);
   encoder.Save(stm);
  }
 }
 catch (Exception exp)
 {
  ///ExceptionUtil.DisplayError(exp);
 }
}
}
        

The image will be generated via a WPF class but there are some really important issues that I encountered during this development proccess. When using canvas controls, you must Measure and Arrange the canvas before using it to render the image. If you do not do this you might get a blank canvas.

Bellow is the code need to render a image in the WPF project.

public Byte[] RenderImage(string passedInVar)

{

//ADDING CONTROLS VIA CODE >>>>>

TextBlock tb = new TextBlock();

tb.Width = (double)400;

tb.Height = (double)200;

tb.TextAlignment = TextAlignment.Center;

tb.Text = "Text added via code...";

tb.FontSize = (Double)30;

tb.Foreground = Brushes.Blue;

InnerCanvas.Children.Add(tb);

//When adding children you might need to update the layout for controls...

InnerCanvas.UpdateLayout();

 

//NB : You have to force the canvas to reload for it to

//re-render correctly when calling in from another source

Canvas canvas = (Canvas)this.FindName("InnerCanvas");

canvas.Measure(new Size((int)canvas.Width, (int)canvas.Height));

canvas.Arrange(new Rect(new Size((int)canvas.Width, (int)canvas.Height)));

int Height = ((int)(InnerCanvas.ActualHeight));

int Width = ((int)(InnerCanvas.ActualWidth));



RenderTargetBitmap rtb = new RenderTargetBitmap(Width, Height, 96, 96, PixelFormats.Pbgra32);

rtb.Render(InnerCanvas);

JpegBitmapEncoder jpg = new JpegBitmapEncoder();

jpg.Frames.Add(BitmapFrame.Create(rtb));

Byte[] tmpArry;

using (MemoryStream ms = new MemoryStream())

{

jpg.Save(ms);

tmpArry = ms.ToArray();

}

///NB : You need to clean up the thread manually

///as they will still reside in memory if they are not flagged 

///for termination....Thread count will go through the roof on

///the server if you dont invoke the following calls. 

if (jpg.Dispatcher.Thread.IsAlive)

{

jpg.Dispatcher.InvokeShutdown();

}

if (rtb.Dispatcher.Thread.IsAlive)

{

rtb.Dispatcher.InvokeShutdown();

}

 

jpg = null;

rtb = null;

return tmpArry;

}

Points of Interest

Threading in WPF created real havoc on our servers for some reason because, if you call a WPF application in a non-conventional way, it leaves running threads on the server. So be very careful when opening certain controls.

Make sure that the following is called when using any object that uses dispatchers.

.Dispatcher.InvokeShutdown()

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Drazzing

Software Developer (Senior)

United Kingdom United Kingdom

Member


Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralThe calling thread cannot access this object because a different thread owns it. Pinmembersanthosh07050:28 24 Feb '10  
GeneralRe: The calling thread cannot access this object because a different thread owns it. PinmemberTarun.K.S2:16 14 Mar '11  
GeneralExample code is rather bloated... PinmemberRandomEngy10:24 4 May '09  
GeneralRe: Example code is rather bloated... PinmemberShawn Rosewarne23:34 4 May '09  
Thanks for the suggestion.
RantSpeggeti code PinmemberThe Code Guru23:31 3 May '09  
QuestionIs this really such a good idea? PinmemberRoger Alsing1:47 14 Oct '08  
AnswerRe: Is this really such a good idea? PinmemberShawn Rosewarne2:11 14 Oct '08  
GeneralRe: Is this really such a good idea? PinmemberRoger Alsing3:35 14 Oct '08  
GeneralRe: Is this really such a good idea? PinmemberShawn Rosewarne4:13 14 Oct '08  
AnswerRe: Is this really such a good idea? PinmemberAlois Kraus5:57 14 Oct '08  
GeneralRe: Is this really such a good idea? PinmemberShawn Rosewarne0:09 15 Oct '08  
GeneralRe: Is this really such a good idea? PinmemberCole_S12:49 17 May '09  
General[Message Removed] Pinmemberhankjmatt0:48 14 Oct '08  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web04 | 2.5.120210.1 | Last Updated 9 Oct 2008
Article Copyright 2008 by Drazzing
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid