Чтобы напечатать содержимое Html элемента управления WebBrowser, необходимо учесть несколько моментов:
- Нам нужно использовать DocumentCompleted WebBrowser событие для определения того, когда текущий документ загружается и отображается
Один документ может (будет) содержать более одного вложенного документа, обычно содержащегося внутри фреймов / фреймов. Каждый IFrame содержит свой собственный документ: при загрузке документа, содержащегося в IFrame, значение DocumentCompleted
возвращается. Это означает, что событие может и будет вызываться несколько раз, когда WebBrowser переходит к URL-адресу.
Примечания здесь объясняют больше: Как получить значение HtmlElement внутри Frames / IFrames?
Управляемые свойства WebBrowser не всегда отражайте реальные ценности DOM. Например, фактические размеры документа Html, когда рендеринг завершен, нигде не отражаются, поэтому нам нужно получить эти меры из DOM самостоятельно. На текущие размеры, отображаемые в DOM, ссылаются:
[WebBrowser].Document.DomDocument.documentElement.scrollHeight;
[WebBrowser].Document.DomDocument.documentElement.scrollWidth;
См .: Измерение размера и местоположения элемента с помощью CSSOM в Windows Inte rnet Explorer
Элемент управления WebBrowser DrawToBitmap () метод получен из Control
, но на самом деле он не реализован, как мы могли ожидать. То же самое относится и к другим элементам управления: известно, что RichTextBox печатает пустой контент при использовании этого метода.
- A Html Размер документа может превышать максимальный размер, поддерживаемый растровым изображением. Существует также более тонкий предел памяти: объект растрового изображения должен хранить свое содержимое в непрерывном пространстве памяти, поэтому ограничение размера растрового изображения на самом деле сложно предопределить и может вызвать исключения, когда мы можем этого не ожидать.
- Для функции эмуляции элемента управления WebBrowser должно быть установлено значение Inte rnet Explorer 11. См .:
Как получить элемент управления WebBrowser для отображения современного содержимого?
Проблема эмуляции элемента управления веб-браузера (FEATURE_BROWSER_EMULATION)
Для продолжения сначала подпишитесь на событие DocumentCompleted
элемента управления WebBrowser.
A Dictionary<Uri, Bitmap>
используется здесь для хранения растрового изображения, представляющего Html содержимое URL-адресов, посещенных в сеансе.
Когда возникает событие DocumentCompleted
, мы добавляем новый элемент словаря, когда текущий URL никогда ранее не посещался.
Если Uri
уже сохранен, мы обновили связанный растровый объект, поэтому в нем присутствует только самый последний снимок документа Html. Коллекция.
Я использую класс поддержки для обработки создания растровых изображений и для объявления собственного COM-интерфейса, используемого для создания растрового изображения из текущего ISurfacePresenter .
Поскольку элемент управления WebBrowser заставил использовать VIEW_OBJECT_COMPOSITION_MODE_LEGACY
в качестве CompositionMode для всех сайтов, внутренний GetPrintBitmap вызывает метод IViewObject Interface Draw()
в этом мы тоже.
Чтобы напечатать содержимое (все содержимое) текущего Html документа, вызовите DrawContent(WebBrowser browser)
stati c метод WebBrowserExtender
класс:
Dictionary<Uri, Bitmap> browserShots = new Dictionary<Uri, Bitmap>();
private void browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
var browser = sender as WebBrowser;
if (browser.ReadyState != WebBrowserReadyState.Complete) return;
var bitmap = WebBrowserExtender.DrawContent(browser);
if (bitmap != null) {
if (!browserShots.ContainsKey(browser.Url)) {
browserShots.Add(browser.Url, bitmap);
}
else {
browserShots[browser.Url]?.Dispose();
browserShots[browser.Url] = bitmap;
}
// Show the Bitmap in a PictureBox control, eventually
[PictureBox].Image = browserShots[browser.Url];
}
}
Класс поддержки WebBrowserExtender :
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class WebBrowserExtender
{
public static Bitmap DrawContent(WebBrowser browser)
{
if (browser.Document == null) return null;
Size docSize = Size.Empty;
Graphics g = null;
var hDc = IntPtr.Zero;
try {
docSize.Height = (int)((dynamic)browser.Document.DomDocument).documentElement.scrollHeight;
docSize.Width = (int)((dynamic)browser.Document.DomDocument).documentElement.scrollWidth;
var screenWidth = Screen.FromHandle(browser.Handle).Bounds.Width;
docSize.Width = Math.Max(Math.Min(docSize.Width, screenWidth), 1);
docSize.Height = Math.Max(Math.Min(docSize.Height, 32750), 1);
var previousSize = browser.ClientSize;
browser.ClientSize = new Size(docSize.Width, docSize.Height);
var bitmap = new Bitmap(docSize.Width, docSize.Height, PixelFormat.Format32bppArgb);
g = Graphics.FromImage(bitmap);
var rect = new RECT(0, 0, bitmap.Width, bitmap.Height);
hDc = g.GetHdc();
var view = browser.ActiveXInstance as IViewObject;
view.Draw(1, -1, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, hDc, ref rect, IntPtr.Zero, IntPtr.Zero, 0);
browser.ClientSize = previousSize;
return bitmap;
}
catch {
// This catch block is like this on purpose: nothing to do here
return null;
}
finally {
if (hDc != null) g?.ReleaseHdc(hDc);
g?.Dispose();
}
}
[ComImport]
[Guid("0000010D-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IViewObject
{
void Draw(uint dwAspect, int lindex, IntPtr pvAspect, [In] IntPtr ptd,
IntPtr hdcTargetDev, IntPtr hdcDraw, ref RECT lprcBounds,
[In] IntPtr lprcWBounds, IntPtr pfnContinue, uint dwContinue);
}
[StructLayout(LayoutKind.Sequential, Pack = 4)]
struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
public RECT(int left, int top, int width, int height)
{
Left = left; Top = top; Right = width; Bottom = height;
}
}
}
Вот как это работает:
Полный документ захвачен. Конечно, растровое изображение также может быть ограничено указанным максимальным / минимальным размером c, чтобы захватить только часть документа Html.
:
Пример проекта WinForms на Google Диске.