我正在尝试制作网页图像,但有些页面将我显示为白页。我还尝试将应用程序的可执行文件添加到注册表中的FEATURE_BROWSER_EMULATION
部分,但是无法正常工作。
[编辑]我更改了脚本,但是当我使用window.onload()
时,仅由0
调用的Java脚本和vb脚本组成的页面仍显示白色图像,其高度设置为browser.Document.Body.ScrollRectangle.Height
。
我在IE中启用了JavaScript,但没有发现不同。
private void makepicture(Uri url)
{
using (WebBrowser browser = new WebBrowser())
{
browser.ScrollBarsEnabled = false;
browser.ScriptErrorsSuppressed = true;
browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(DocumentCompleted);
browser.Navigate(url, null, null, "User-Agent: User agent");
while (browser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
}
}
private void DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser browser = sender as WebBrowser;
if (browser.ReadyState != WebBrowserReadyState.Complete) return;
browser.ClientSize = new Size(browser.Document.Body.ScrollRectangle.Width, browser.Document.Body.ScrollRectangle.Height);
using (Bitmap bitmap = new Bitmap(browser.ClientSize.Width, browser.ClientSize.Height))
{
browser.DrawToBitmap(bitmap, new System.Drawing.Rectangle(0, 0, browser.ClientSize.Width, browser.ClientSize.Height));
using (MemoryStream stream = new MemoryStream())
{
bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
byte[] bytes = stream.ToArray();
picbytes = bytes;
}
}
}
public static Bitmap ByteToImage(byte[] blob)
{
MemoryStream mStream = new MemoryStream();
byte[] pData = blob;
mStream.Write(pData, 0, Convert.ToInt32(pData.Length));
Bitmap bm = new Bitmap(mStream, false);
mStream.Dispose();
return bm;
}
尝试这样设置用户代理
browser.Navigate(url, null, null, "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0");
为了打印WebBrowser控件的HTML内容,需要考虑以下几点:
一个文档可能(将)包含一个以上的子文档,通常包含在Frames / IFrames中。每个IFrame都有其自己的Document:加载IFrame中包含的Document时,会重新生成DocumentCompleted
。这意味着当WebBrowser导航到URL时,该事件可以并且将引发多次。
这里的注释进一步说明:How to get an HtmlElement value inside Frames/IFrames?
WebBrowser的托管属性并不总是反映DOM的实际值。例如,完成渲染后,Html文档的实际尺寸不会在任何地方反映出来,因此我们需要从DOM自己获取这些度量。当前DOM呈现的尺寸由以下引用:
[WebBrowser].Document.DomDocument.documentElement.scrollHeight;
[WebBrowser].Document.DomDocument.documentElement.scrollWidth;
参见:Measuring Element Dimension and Location with CSSOM in Windows Internet Explorer
WebBrowser控件DrawToBitmap()方法是从Control
派生的,但实际上并未像我们期望的那样实现。其他控件也是如此:使用此方法时,RichTextBox可以打印空白内容。
首先,订阅WebBrowser控件的DocumentCompleted
事件。
A Dictionary<Uri, Bitmap>
在这里用于存储表示在会话中访问的URL的HTML内容的位图。引发DocumentCompleted
事件时,如果以前从未访问过当前URL,则会向Dictionary中添加一个新元素。如果已经存储了URL,则我们将更新相关的Bitmap对象,因此在集合中仅存在Html文档的最新快照。
我正在使用支持类来处理位图的创建,并声明用于从当前ISurfacePresenter生成位图的本机COM接口。由于WebBrowser控件是forced,以便将VIEW_OBJECT_COMPOSITION_MODE_LEGACY
用作所有站点的CompositionMode,因此内部GetPrintBitmap在这种情况下将调用IViewObject Interface Draw()
方法,所以我们也这样做。
要打印当前HTML文档的内容(所有内容),请调用DrawContent(WebBrowser browser)
类的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;
docSize.Height = Math.Max(Math.Min(docSize.Height, 32750), 1);
docSize.Width = Math.Max(Math.Min(docSize.Width, 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;
}
}
}