Skip to content

Instantly share code, notes, and snippets.

@mccoder
Created March 1, 2010 18:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mccoder/318611 to your computer and use it in GitHub Desktop.
Save mccoder/318611 to your computer and use it in GitHub Desktop.
<h1>
<a href="http://www.gotdotnet.ru/blogs/alexeylyubko/7205/" >Рендеринг HTML в Bitmap</a>
</h1>
<strong>Автор</strong>: Sveer<br/>
<strong>Дата публикации</strong>: 28.2.2010 16:07<br/>
<strong>Categories</strong>: howto, htmltobitmap, html rendering<br/>
<br/>В процессе рефакторинга проекта <noindex>
<a rel="nofollow" href="http://qrpr.ru/" >QRPR</a>
</noindex> накопал много небольших, но полезных вспомогательных блоков. Решил начать ими делиться и возобновить блог :) <p>Ищите под тегом HOWTO :)</p> <p>
<strong>Задача:</strong> <br/>
</p> <p>Есть HTML, который может содержать и картинки и текст и разлисное форматирование. необходимо получить его представление в виде Картинки (Bitmap).</p> <p>
<strong>Решение:</strong>
</p> <p>Для этих целей есть несколько способов:</p> <p>1 - использовать Движок <noindex>
<a rel="nofollow" href="http://webkit.org/" >WebKit</a>
</noindex>, собрать его, воспользоваться оберткой <noindex>
<a rel="nofollow" href="http://webkitdotnet.sourceforge.net/" >WebKit для .NET</a>
</noindex>. На этом мы остановились, замерив время подгрузки WebKit в наше ASP.NET приложение.</p> <p>2 - использовать COM-компонент WebBrowser. </p> <p>Базовое описание такого решения есть на <noindex>
<a rel="nofollow" href="http://www.codeproject.com/KB/graphics/IECapture.aspx" >CodeProject</a>
</noindex>, но нам оно не подошло, т.к. нужна была отдельная библиотека и возможность использования в ASP.NET</p> <p>Это решение я и опишу.</p> <p>Шаги по использованию очень просты:</p> <ul>
<li>Создаем объект WebBrowser</li>
<li>Загружаем в него HTML</li>
<li>Ждем окончания рендеринга</li>
<li>Изменяем размер компонента под наши нужды (в нашем случае необхоидмо чтобы строки не переносились без &lt;BR&gt;</li>
<li>Ждем окончания рендеринга</li>
<li>Сохраняем содержимое окна компонента с помощью интерфейса IHTMLElementRender2</li>
</ul>
<p>При этом важно понимать, в каком потоке будет использоваться этот компонент, т.к. WebBrowser должен работать в потоке STA!</p> <p>Необходимо подключить компонент mshtml, чтобы мы могли использовать интерфейсы </p> <p>Затем объявляем интерфейс, которй будем использовать для рендеринга</p> <p/>
<div class="blog-code-box" >
<pre class="csharp" >[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("3050F669-98B5-11CF-BB82-00AA00BDCE0B")]
public interface IHTMLElementRender2
{
void DrawToDC(IntPtr hdc);
void SetDocumentPrinter(string bstrPrinterName, ref _RemotableHandle hdc);
}</pre>
</div> <br/>
<p>Затем мы реализовали варианты выхова рендеринга. Вы можете явно указать, запустить ли его в отдельном потоке и ждать окончания или же текущий уже является STAThread и можно запускать рендеринг в нем.</p> <p/>
<div class="blog-code-box" >
<pre class="csharp" >public static Bitmap RenderHTML (string html, bool atSTAThread)
{
RenderInfo ri = new RenderInfo() { Html = html, Result=null };
if (!atSTAThread) //Запускаем в отдельном потоке
Renderer(ri);
else
{
System.Threading.Thread th = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(Renderer));
th.SetApartmentState(System.Threading.ApartmentState.STA);
th.Start(ri);
//Ждем окончания
if (!th.Join(55000))
{ LogWriter(ex, QRPRErrorLevel.ErrorM2); }
}
return ri.Result;
}</pre>
</div> <br/>
Подготовка к рендерингу идет в методе Renderer: <br/>
<p/>
<div class="blog-code-box" >
<pre class="csharp" >private static void Renderer(object obj)
{
try
{
RenderInfo ri = (RenderInfo)obj;
WebBrowser webBrowser = new WebBrowser();
webBrowser.ScrollBarsEnabled = true;
webBrowser.DocumentText = "" + ri.Html + "";
while (webBrowser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
//Выставляем блииинный Web-броузер чтобы правильно отображать.
webBrowser.Size = new Size(webBrowser.Document.Body.ScrollRectangle.Width, webBrowser.Document.Body.ScrollRectangle.Height);
while (webBrowser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
webBrowser.ScrollBarsEnabled = false;
Rectangle rec = webBrowser.Document.Body.ClientRectangle;
ri.Result = GetBitmap(webBrowser, rec.Size.Width, rec.Size.Height);
}
catch(Exception ex) {
LogWriter(ex,QRPRErrorLevel.ErrorM2);
}
}
</pre>
</div> И сам рендеринг HTML! <p>
<br/>
</p>
<div class="blog-code-box" >
<pre class="csharp" >//Основной рендеринг HTML
private static Bitmap GetBitmap(WebBrowser webBrowser, int width, int height)
{
IHTMLDocument2 rawDoc = (IHTMLDocument2)webBrowser.Document.DomDocument;
IHTMLElement rawBody = rawDoc.body;
IHTMLElementRender2 render = (IHTMLElementRender2)rawBody;
Bitmap bitmap = new Bitmap(width, height);
Rectangle bitmapRect = new Rectangle(0, 0, width, height);
webBrowser.DrawToBitmap(bitmap, bitmapRect);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
IntPtr graphicshdc = graphics.GetHdc();
render.DrawToDC(graphicshdc);
graphics.ReleaseHdc(graphicshdc);
#if DEBUG
//При отладке отрисовываем еще и прямоугольник
//graphics.DrawRectangle(Pens.Black, bitmapRect);
//graphics.Save();
#endif
graphics.Dispose();
return bitmap;
}
}
</pre>
</div> <p>
<br/>
Исходный код библиотеки можно <noindex>
<a rel="nofollow" href="http://it-arts.com/projects/renderhtmltobitmap.aspx" >скачать с it arts</a>
</noindex>
</p> <br/>
<br/>
[Рендеринг HTML в Bitmap] http://www.gotdotnet.ru/blogs/alexeylyubko/7205/
Автор : Sveer
Дата публикации : 28.2.2010 16:07
Categories : howto, htmltobitmap, html rendering
В процессе рефакторинга проекта
[QRPR] http://qrpr.ru/
накопал много небольших, но полезных вспомогательных блоков. Решил начать ими делиться и возобновить блог :)
Ищите под тегом HOWTO :)
Задача:
Есть HTML, который может содержать и картинки и текст и разлисное форматирование. необходимо получить его представление в виде Картинки (Bitmap).
Решение:
Для этих целей есть несколько способов:
1 - использовать Движок
[WebKit] http://webkit.org/
, собрать его, воспользоваться оберткой
[WebKit для .NET] http://webkitdotnet.sourceforge.net/
. На этом мы остановились, замерив время подгрузки WebKit в наше ASP.NET приложение.
2 - использовать COM-компонент WebBrowser.
Базовое описание такого решения есть на
[CodeProject] http://www.codeproject.com/KB/graphics/IECapture.aspx
, но нам оно не подошло, т.к. нужна была отдельная библиотека и возможность использования в ASP.NET
Это решение я и опишу.
Шаги по использованию очень просты:
* Создаем объект WebBrowser
* Загружаем в него HTML
* Ждем окончания рендеринга
* Изменяем размер компонента под наши нужды (в нашем случае необхоидмо чтобы строки не переносились без &lt;BR&gt;
* Ждем окончания рендеринга
* Сохраняем содержимое окна компонента с помощью интерфейса IHTMLElementRender2
При этом важно понимать, в каком потоке будет использоваться этот компонент, т.к. WebBrowser должен работать в потоке STA!
Необходимо подключить компонент mshtml, чтобы мы могли использовать интерфейсы
Затем объявляем интерфейс, которй будем использовать для рендеринга
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("3050F669-98B5-11CF-BB82-00AA00BDCE0B")]
public interface IHTMLElementRender2
{
void DrawToDC(IntPtr hdc);
void SetDocumentPrinter(string bstrPrinterName, ref _RemotableHandle hdc);
}
Затем мы реализовали варианты выхова рендеринга. Вы можете явно указать, запустить ли его в отдельном потоке и ждать окончания или же текущий уже является STAThread и можно запускать рендеринг в нем.
public static Bitmap RenderHTML (string html, bool atSTAThread)
{
RenderInfo ri = new RenderInfo() { Html = html, Result=null };
if (!atSTAThread) //Запускаем в отдельном потоке
Renderer(ri);
else
{
System.Threading.Thread th = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(Renderer));
th.SetApartmentState(System.Threading.ApartmentState.STA);
th.Start(ri);
//Ждем окончания
if (!th.Join(55000))
{ LogWriter(ex, QRPRErrorLevel.ErrorM2); }
}
return ri.Result;
}
Подготовка к рендерингу идет в методе Renderer:
private static void Renderer(object obj)
{
try
{
RenderInfo ri = (RenderInfo)obj;
WebBrowser webBrowser = new WebBrowser();
webBrowser.ScrollBarsEnabled = true;
webBrowser.DocumentText = "" + ri.Html + "";
while (webBrowser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
//Выставляем блииинный Web-броузер чтобы правильно отображать.
webBrowser.Size = new Size(webBrowser.Document.Body.ScrollRectangle.Width, webBrowser.Document.Body.ScrollRectangle.Height);
while (webBrowser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
webBrowser.ScrollBarsEnabled = false;
Rectangle rec = webBrowser.Document.Body.ClientRectangle;
ri.Result = GetBitmap(webBrowser, rec.Size.Width, rec.Size.Height);
}
catch(Exception ex) {
LogWriter(ex,QRPRErrorLevel.ErrorM2);
}
}
И сам рендеринг HTML!
//Основной рендеринг HTML
private static Bitmap GetBitmap(WebBrowser webBrowser, int width, int height)
{
IHTMLDocument2 rawDoc = (IHTMLDocument2)webBrowser.Document.DomDocument;
IHTMLElement rawBody = rawDoc.body;
IHTMLElementRender2 render = (IHTMLElementRender2)rawBody;
Bitmap bitmap = new Bitmap(width, height);
Rectangle bitmapRect = new Rectangle(0, 0, width, height);
webBrowser.DrawToBitmap(bitmap, bitmapRect);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
IntPtr graphicshdc = graphics.GetHdc();
render.DrawToDC(graphicshdc);
graphics.ReleaseHdc(graphicshdc);
#if DEBUG
//При отладке отрисовываем еще и прямоугольник
//graphics.DrawRectangle(Pens.Black, bitmapRect);
//graphics.Save();
#endif
graphics.Dispose();
return bitmap;
}
}
Исходный код библиотеки можно
[скачать с it arts] http://it-arts.com/projects/renderhtmltobitmap.aspx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment