i want to render a web-page (i.e. TWebBrowser
) to a device context. i want to use Internet Explorer's layout engine to render content to a device context (i.e. metafile, pdf metafile).
Starting with Internet Explorer 9 the IHTMLElementRender
interface is no longer supported:
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.
To the point that they no longer mention that the DrawToDC method even exists:
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.
Note: I'm quoting all the documentation so that it can still be found when Microsoft finally removes it from MSDN altogether. Along with the interface declaration:
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
interfacei've tried converting to use the IViewObject
(e.g. 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;
The problem with this code is that it only renders the visible area of the browser (i.e. without scrolled content):
i need to render the entire web-page (e.g. for printing).
i tried changing the draw aspect from DVASPECT_CONTENT
(as this example does), to 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.
With the same result; rather than rendering the page, only the visible portion is rendered:
How can i ask the IE9 rendering engine to render?
i also tried using different indexes along with DVASPECT_DOCPRINT
. Although IViewObject
is not documented, maybe that's how you print different "pages":
view.Draw(DVASPECT_DOCPRINT, 1, ...);
view.Draw(DVASPECT_DOCPRINT, 2, ...);
view.Draw(DVASPECT_DOCPRINT, 3, ...);
...
view.Draw(DVASPECT_DOCPRINT, n, ...);
But the WebBrowser doesn't care what the index is; only rendering the current View
(which i suppose makes sense when using IViewObject
).
How do i render a browser to a device context?
Note: The question is tagged with delphi
, but there's nothing in this question that is delphi specific.
Update: i also tried other combinations of aspect and index:
view.Draw(DVASPECT_CONTENT, -1, ...);
view.Draw(DVASPECT_DOCPRINT, -1, ...);
view.Draw(DVASPECT_CONTENT, 0, ...);
view.Draw(DVASPECT_DOCPRINT, 0, ...);
Using IViewObject, you can create a screenshot of the current viewport. I use a trick to create a screenshot of a web page (without any frames) or a frame document.
Note that you should be careful of doing this when the document is extremely large.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With