delphi - 如何将 WebBrowser 渲染到设备上下文?

标签 delphi winapi internet-explorer-9 rendering delphi-5

我想将网页(即TWebBrowser)渲染到设备上下文。我想使用 Internet Explorer 的布局引擎将内容呈现到设备上下文(即元文件、pdf 元文件)。

<小时/>

从 Internet Explorer 9 开始,IHTMLElementRender 接口(interface)不再受支持:

IHTMLElementRender interface

Use this interface to draw the contents of an element to a specified device context, normally a printer.

Members
The IHTMLElementRender interface inherits from the IUnknown interface but does not have additional members.

以至于他们不再提及 DrawToDC method甚至存在:

IHTMLElementRender::DrawToDC Method

Deprecated. Draws the contents of the element to the specified device context.

Syntax

HRESULT DrawToDC(
     HDC hDC
);

Parameters

  • hDC
    [in] An HDC specifying the device to be drawn to, typically a printer.

Return Value

Returns S_OK if successful, or an error value otherwise.

Remarks

As of Windows Internet Explorer 9, this method is deprecated and should not be used.

With some printers, running IHTMLElementRender::DrawToDC may cause problems. You can ensure that IHTMLElementRender::DrawToDC works properly on all printers by running IHTMLElementRender::SetDocumentPrinter method first, and then passing the modified device context to IHTMLElementRender::DrawToDC.

注意:我引用了所有文档,以便当 Microsoft 最终将其从 MSDN 中完全删除时仍然可以找到它。连同接口(interface)声明:

IHTMLElementRender = interface(IUnknown)
   ['{3050F669-98B5-11CF-BB82-00AA00BDCE0B}']
   function DrawToDC(hdc: HDC): HResult; stdcall;
   function SetDocumentPrinter(const bstrPrinterName: WideString; hdc: HDC): HResult; stdcall;
end;
<小时/>

使用IViewObject接口(interface)

我尝试转换为使用 IViewObject (例如 How to render HTML element without using web browser? ):

procedure RenderWebBrowserToMetafile(Browser: TWebBrowser; Metafilename: string);
var
    view: IViewObject;
    m: TMetafile;
    mc: TMetafileCanvas;
    w, h: Integer;
    r: TRect;
    dpix: Integer;
    dpiy: Integer;
    dc: HDC;
begin
    w := WebBrowserScrollWidth(Browser);
    h := WebBrowserScrollHeightStrict(Browser);

    //96dpi screen to 300dpi metafile (destined for printer)
    dc := GetDC(0);
    try
        dpix := GetDeviceCaps(GetDC(0), LOGPIXELSX);
        dpiy := GetDeviceCaps(GetDC(0), LOGPIXELSY);
    finally
        ReleaseDC(0, dc);
    end;
    w := MulDiv(w, 300, dpix);
    h := MulDiv(h, 300, dpiy);

    view := Browser.Document as IViewObject;

    m := TMetafile.Create;
    try
        m.Width := w;
        m.Height := h;
        r := Rect(0, 0, w, h);

        mc := TMetafileCanvas.Create(m, 0);
        try
            view.Draw(
                    DVASPECT_CONTENT, //draw aspect
                    1, //index
                    nil, //pAspectInfo
                    nil, //pDVTargetDevice
                    0, //Target Device Context
                    mc.handle, //hdcDraw
                    @r, //target Bounds
                    @w, //window bounds (for metafiles)
                    nil, //continue function
                    0); //continue value
        finally
            mc.Free;
        end;
        m.SaveToFile(Metafilename);
    finally
        m.Free;
    end;
end;

此代码的问题在于它仅呈现浏览器的可见区域(即没有滚动内容):

我需要渲染整个网页(例如用于打印)。

我尝试更改 draw aspect来自DVASPECT_CONTENT (如 this example 所示),至 DVASPECT_DOCPRINT:

DVASPECT_DOCPRINT
Provides a representation of the object on the screen as though it were printed to a printer using the Print command from the File menu. The described data may represent a sequence of pages.

结果相同;只渲染可见部分,而不是渲染页面:

如何让 IE9 渲染引擎进行渲染?

<小时/>

我还尝试使用不同的索引以及DVASPECT_DOCPRINT。虽然 IViewObject 没有记录,也许这就是打印不同“页面”的方式:

view.Draw(DVASPECT_DOCPRINT, 1, ...);
view.Draw(DVASPECT_DOCPRINT, 2, ...);
view.Draw(DVASPECT_DOCPRINT, 3, ...);
...
view.Draw(DVASPECT_DOCPRINT, n, ...);

但是 Web 浏览器并不关心索引是什么;它只关心索引是什么。仅渲染当前的View(我认为在使用IViewObject时这是有意义的)。

如何将浏览器渲染到设备上下文?

注意:该问题标有 delphi,但该问题中没有任何 delphi 特定内容。

<小时/>

更新:我还尝试了方面索引的其他组合:

view.Draw(DVASPECT_CONTENT, -1, ...);
view.Draw(DVASPECT_DOCPRINT, -1, ...);
view.Draw(DVASPECT_CONTENT, 0, ...);
view.Draw(DVASPECT_DOCPRINT, 0, ...);

最佳答案

使用 IViewObject,您可以创建当前视口(viewport)的屏幕截图。我使用一个技巧来创建网页(没有任何框架)或框架文档的屏幕截图。

  1. 使用scrollWidth/scrollHeight/scrollLeft/scrollTop计算完整文档大小(检查IHtmlDocument2和IHtmlDocument3接口(interface))
  2. 锁定窗口更新并将文档调整为计算出的完整尺寸
  3. 使用 IViewObject 创建快照(上面的代码似乎没问题)
  4. 将文档恢复至原始大小并解锁窗口更新

请注意当文档非常大时,您应该小心执行此操作。

关于delphi - 如何将 WebBrowser 渲染到设备上下文?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10884088/

相关文章:

delphi - 调用一个名称由另一个过程设置的过程(通过事件)

c++ - 以某种方式可以从 HANDLE 获得 HMODULE?

html - IE9 渲染问题 - 空白条(水平线)

internet-explorer-9 - 有人知道为什么 IE9 typeof console.log 报告 "object",其他人报告 "function"吗?

css - IE9 - 打印时 CSS 失败

delphi - 如何使用通用 TList List 属性

delphi - 为什么 Delphi 无法推断参数 TEnumerable<T> 的类型?

windows - 如何获取当前运行的实际窗口的标题?

c++ - 关于我的教科书示例中的 GDI 映射

java - 使用 JNI 时 CryptUnprotectData 返回 false