Saturday, January 22, 2011

Convert Html to Image

I searched for free open source csharp to convert html to image. I found solution using:

WebBrowser (namespace System.Windows.Forms) code below is sample of conversion:


static byte[] CaptureWebPageBytesP(string body, int? width, int? height)
{
byte[] data;
// create a hidden web browser, which will navigate to the page
using (WebBrowser web = new WebBrowser())
{
web.ScrollBarsEnabled = false; // we don't want scrollbars on our image
web.ScriptErrorsSuppressed = true; // don't let any errors shine through
web.Navigate("about:blank");
// wait until the page is fully loaded
while (web.ReadyState != System.Windows.Forms.WebBrowserReadyState.Complete)
System.Windows.Forms.Application.DoEvents();
web.Document.Body.InnerHtml = body;

// set the size of our web browser to be the same size as the page
if (width == null)
width = web.Document.Body.ScrollRectangle.Width;
if (height == null)
height = web.Document.Body.ScrollRectangle.Height;
web.Width = width.Value;
web.Height = height.Value;
// a bitmap that we will draw to
using (System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(width.Value, height.Value))
{
// draw the web browser to the bitmap
web.DrawToBitmap(bmp, new Rectangle(web.Location.X, web.Location.Y, web.Width, web.Height));
// draw the web browser to the bitmap
using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
{
EncoderParameter qualityParam = null;
EncoderParameters encoderParams = null;
try
{
ImageCodecInfo imageCodec = null;
//imageCodec = getEncoderInfo("image/jpeg");
imageCodec = getEncoderInfo("image/bmp");

// Encoder parameter for image quality
qualityParam = new EncoderParameter(Encoder.Quality, 100L);

encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
bmp.Save(stream, imageCodec, encoderParams);
}
catch (Exception)
{
throw new Exception();
}
finally
{
if (encoderParams != null)
encoderParams.Dispose();
if (qualityParam != null)
qualityParam.Dispose();
}
bmp.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
stream.Position = 0;
data = new byte[stream.Length];
stream.Read(data, 0, (int)stream.Length);
}
}
}
return data;
}

But I faced problem when I try to use it without Window Forms (console application, aspnet, or windows service) It gave me error cannot be instantiated because the current thread is not in a single-threaded. To solve this error created STAThread like code below:

public static byte[] CaptureWebPageBytes(string body, int? width, int? height)
{
bool bDone = false;
byte[] data = null;
DateTime startDate = DateTime.Now;
DateTime endDate = DateTime.Now;

//sta thread to allow intiate WebBrowser
var staThread = new Thread(delegate()
{
data = CaptureWebPageBytesP(body, width, height);
bDone = true;
});
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start();
while (!bDone)
{
endDate = DateTime.Now;
TimeSpan tsp = endDate.Subtract(startDate);

Application.DoEvents();
if (tsp.Seconds > 50)
{
break;
}
}
staThread.Abort();
return data;
}


15 comments:

Unknown said...

Do you believe that I can use this on web(Asp)? I have an image and above that I have relative divs with text. Do you believe that this can help me?

Tarek Yehia Abd El Khalek said...

Yes you can use to convert html to image

Anonymous said...

Really Great! Thanks a lot

Anonymous said...

This does not work, after long time, it crashes, i am using vs 2008 and SQL Server 2008 R2

Tarek Yehia Abd El Khalek said...

Give me your code

Mustafa said...

thank you Tarek, great work

unal said...

hi tarek,

I wanna use this code fo rweb app. How can I convert this code for web???

Unknown said...

var th = new Thread(() =>
{
WebBrowser br2;
br2 = new WebBrowser
{
ScrollBarsEnabled = false,
ScriptErrorsSuppressed = true,
Size = size
};
br2.BringToFront();
br2.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(browser_DocumentCompleted);

br2.Navigate("about:blank");

br2.Document.Write(html);

Bitmap bitmap2 = GetBitmapFromControl(br2, size);
if (bitmap2 != null)
{
bitmap = bitmap2;
br = br2;
}

Application.Run();

});
th.SetApartmentState(ApartmentState.STA);
th.Start();

=>not working in aspx.net

Anonymous said...

Thank you - but how do you turn up the resolution for the captured page?


ImageCodecInfo imageCodec = null;
//imageCodec = getEncoderInfo("image/bmp");
imageCodec = GetEncoderInfo("image/jpeg");

// Encoder parameter for image quality
qualityParam = new EncoderParameter(Encoder.Quality, 100L);

encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;

This dosent seem to do me any good ?

Simit said...

Hi Tarek,

This is a wonderful piece of code.
Can we directly give the URL of webpage for getting its Image or we need to provide the HTML of that page?

Tarek Yehia Abd El Khalek said...

you can use page url instead of image by replacing this block
web.Navigate("about:blank");
// wait until the page is fully loaded
while (web.ReadyState != System.Windows.Forms.WebBrowserReadyState.Complete)
System.Windows.Forms.Application.DoEvents();
web.Document.Body.InnerHtml = body;

by
web.Navigate(your url);
while (web.ReadyState != System.Windows.Forms.WebBrowserReadyState.Complete)
System.Windows.Forms.Application.DoEvents();

Anonymous said...

Nice blog related to Convert HTML to Image. Really your blog is so informative. Thanks for sharing it with us!!


Convert Image

Anonymous said...

Great work - I had something similar that wasn't scaling properly - you saved me hours of frustration. Thanks

Arup said...

Image tag not working

Anonymous said...

Should we declare both methods in same class library in convert html to image