How to render Html content into JPG/JPEG image in best quality (WinForms)

How to save Html to JPG/JPEG Image and how to save it in best quality?

On recent project, I had a tasks to:

  1. Save result of Html page to JPG image
  2. To do that in best possible quality

Both tasks sounds trivial, but I did not find quite satisfying solutions, so, I came up with one bellow.

First, you need WebBrowser control – it is basicaly wrapper around ActiveX Internet Explorer interface.

Once when Html content is ready (local or remote), ask control to call your procedure upon completion:

webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);

and start render your content:

webBrowser1.Navigate( UriToRender )

In DocumentCompletedEventHandler, call your routine for rendering content to image:

void webBrowser1_DocumentCompleted(object sender, 
WebBrowserDocumentCompletedEventArgs e)
{
  if( GetImageFromHtml(currentFile, webBrowser1) )
  {
     toolStripStatusLabel1.Text = "Image saved.";
  }
  else
  {
     toolStripStatusLabel1.Text = "Sorry, there was problem with saving.";
  }
}

And here is code for rendering Html to image:

/// <summary>
/// Method for saving Html content into image
/// </summary>
/// <param name="imageName">File name of image</param>
/// <param name="webBrowser">Target WebBrowser control to query for content</param>
/// <returns>True if save was succesfull</returns>
/// <seealso cref="System.Windows.Forms.WebBrowser" />

public bool GetImageFromHtml(string imageName, WebBrowser webBrowser)
{
  if (webBrowser.Document == null)
  {
     return false;
  }

  Cursor current = Cursor;
  Cursor = Cursors.WaitCursor;

  // Give time to WebBrowser control to finish rendering of document
  Thread.Sleep(200);

  try
  {

     // save old width / height
     Size originalSize = new Size(webBrowser1.Width, webBrowser1.Height);
     
     // Change to full scroll size
     int scrollHeight = webBrowser.Document.Body.ScrollRectangle.Height;
     int scrollWidth = webBrowser.Document.Body.ScrollRectangle.Width;
     
     Bitmap image = new Bitmap(scrollWidth, scrollHeight);
     webBrowser.Size = new Size(scrollWidth, scrollHeight);
     
     // Draw to image
     webBrowser.DrawToBitmap(image, webBrowser.ClientRectangle);
     webBrowser.Size = originalSize;

     // Old one with bad quality:
     // image.Save(imageName, ImageFormat.Jpeg);

     // Save in full quality
     SaveJPG(image, imageName, 100);

     return true;
  }

  catch { return false; }

  finally {  Cursor = current; }
}

Usual Image.Save method saves image in number of formats; however, quality is some default (bad) quality; and I needed more control over it. So, here are methods which allow that kind of control:

/// <summary>
/// Gets codec info by given mimeType
/// </summary>
/// <param name="mimeType">mimeType to lookup for</param>
/// <returns>ImageCodecInfo if all ok or null</returns>

public static ImageCodecInfo GetCodecInfo(String mimeType)
{
  ImageCodecInfo[] encoders;
  encoders = ImageCodecInfo.GetImageEncoders();
  for (int iterator = 0; iterator < encoders.Length; ++iterator)
  {
     if (encoders[iterator].MimeType == mimeType)
        return encoders[iterator];
  }
  return null;
}

/// <summary>
/// Save an Image to JPEG with given compression quality
/// </summary>
/// <param name="image">Image to save</param>
/// <param name="imageName">File name to store image</param>
/// <param name="quality">Quality parameter: 0 - lowest quality, smallest size, 
/// 100 - max quality and size</param>
/// <returns>True if save was succesfull</returns>

public static bool SaveJPG(Image image, string imageName, long qual)
{
  EncoderParameters eps = new EncoderParameters(1);
  eps.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qual);
  ImageCodecInfo ici = GetCodecInfo("image/jpeg");

  if(ici == null) { return false; }

  image.Save(imageName, ici, eps);
  return true;
} 

Now you can select jpeg image quality and render html the way you like.

Digg!