Suche HTML-Komponente (2007, 2009...)
-
Wir suchen eine VCL-Komponente die folgendes beherrscht:
a) Kompatibel mit C++ Builder 2007, die aber noch aktiv weiterentwickelt wird (In Hinblick auf Umstieg von 2007 auf Beispielsweise 2009)
b) HTML-Anzeige und Druckvorschau (Bearbeitung ist nicht nötig)
c) Skalierung auf eine Druckseite
- Beliebig große HTML-Seite müssen auf eine Druckseite runterskaliert werden können
d) Möglichst direkter Export als PDF erlaubenKennt da jemand eine sinnvolle Komponente? (Bislang hatten wir diese Komponente im Einsatz. Sie wird aber nicht mehr weiterentwickelt und die HTML-Unterstützung ist für unsere Zwecke ungeeignet).
Eine Alternative wäre es, wenn jemand aus der IWebBrowser-Komponente (unsichtbare TCppWebBrowser-Komponente) eine komplette HTML-Seite ohne wesentlichen Schärfeverlust, unter Einhaltung der Seitenverhältnisse, skalliert in einen vorgegebenen Zielbereich eines Metafiles zeichnen könnte. Eine brauchbare Lösung würden wir uns auch etwas kosten lassen (Wir haben eine Lösung, die aber ein relativ unscharfes Bild liefert [Über Bereichsweise kopien in ein Bild und anschließende Skalierung in den Metafile]. Auf den Monitor mag es noch einigermaßen aussehen, auf dem Ausdruck wirkt es aber zu verpixelt). Bei Interesse liefere ich gerne genauere Angaben nach.
cu André
-
So etwas suche ich auch, schön wäre es wenn diese auf der Gecko-Engine aufsetzen würde.
-
~html schrieb:
So etwas suche ich auch, schön wäre es wenn diese auf der Gecko-Engine aufsetzen würde.
Das wäre an sich auch in Ordnung, nur das wir halt Benutzer haben die sich bereits mit der Installation eines neuen Browsers schwer tun, den IE hat aber jeder unserer Kunden von Haus aus.
-
asc schrieb:
Eine Alternative wäre es, wenn jemand aus der IWebBrowser-Komponente (unsichtbare TCppWebBrowser-Komponente) eine komplette HTML-Seite ohne wesentlichen Schärfeverlust, unter Einhaltung der Seitenverhältnisse, skalliert in einen vorgegebenen Zielbereich eines Metafiles zeichnen könnte.
Mit IWebBrowser geht das nicht ohne weiteres; das WebBrowser-Control muß ein Parent-Handle haben, um korrekt rendern zu können. (Frag mich nicht weshalb.)
// InternetExplorerRenderer.hpp #ifndef _INTERNETEXPLORERRENDERER_HPP #define _INTERNETEXPLORERRENDERER_HPP #include <SysUtils.hpp> #include <Forms.hpp> // Avoid including ShDocVw.hpp here. namespace Shdocvw { class DELPHICLASS TWebBrowser; }; class InternetExplorerRenderer { private: enum BrowserStatus { bsReady, bsBusy, bsFailed, }; void __fastcall WebBrowserDocumentComplete (TObject* ASender, const _di_IDispatch pDisp, OleVariant& URL); void __fastcall WebBrowserNavigateError (TObject *ASender, const _di_IDispatch pDisp, OleVariant& URL, OleVariant& Frame, OleVariant& StatusCode, WordBool& Cancel); HDC getDCFromMetafile (TGraphic* metafile); HDC getDCFromBitmap (TGraphic* bitmap); void doRenderHtmlPageToDC (String url, TGraphic* dest, HDC (__closure * dcGetter) (TGraphic*), DWORD timeout); TWebBrowser* webBrowser; TForm* renderForm; BrowserStatus bs; TCanvas* myCanvas; public: InternetExplorerRenderer (void) : webBrowser (0), renderForm (0), myCanvas (0), bs (bsReady) {} ~InternetExplorerRenderer (void); void renderHtmlPageToMetafile (String url, TMetafile* dest, DWORD timeout = 10000); void renderHtmlPageToBitmap (String url, Graphics::TBitmap* dest, DWORD timeout = 10000); }; #endif // _INTERNETEXPLORERRENDERER_HPP
// InternetExplorerRenderer.cpp #include <typeinfo> #include <SysUtils.hpp> #include <Forms.hpp> #include <SHDocVw.hpp> #include <MSHTML.hpp> #include <tchar.h> #pragma hdrstop #include "InternetExplorerRenderer.hpp" void raiseInterfaceException (const char* intfName) { throw EIntfCastError (_T ("Object does not support the '%s' interface"), ARRAYOFCONST ((String (intfName)))); } void raiseNullPointerException (void) { throw EInvalidPointer (_T ("Object reference is not bound to an object instance")); } template <typename DestIntf, typename SrcIntf> DelphiInterface <DestIntf> interface_cast (DelphiInterface <SrcIntf> src) { DelphiInterface <DestIntf> retval = src; if (!retval) { if (src) raiseInterfaceException (typeid (DestIntf).name ()); else raiseNullPointerException (); } return retval; } InternetExplorerRenderer::~InternetExplorerRenderer (void) { delete renderForm; } HDC InternetExplorerRenderer::getDCFromMetafile (TGraphic* metafile) { myCanvas = new TMetafileCanvas (&dynamic_cast <TMetafile&> (*metafile), NULL); return myCanvas->Handle; } HDC InternetExplorerRenderer::getDCFromBitmap (TGraphic* bitmap) { return dynamic_cast <Graphics::TBitmap&> (*bitmap).Canvas->Handle; } void __fastcall InternetExplorerRenderer::WebBrowserDocumentComplete (TObject* ASender, const _di_IDispatch pDisp, OleVariant& URL) { bs = bsReady; } void __fastcall InternetExplorerRenderer::WebBrowserNavigateError (TObject *ASender, const _di_IDispatch pDisp, OleVariant& URL, OleVariant& Frame, OleVariant& StatusCode, WordBool& Cancel) { Cancel = VARIANT_TRUE; bs = bsFailed; } void InternetExplorerRenderer::renderHtmlPageToMetafile (String url, TMetafile* dest, DWORD timeout) { // The canvas must be allocated "on demand" to make sure that the metafile // can be modified further before rendering (SetSize()). // Releasing the canvas enforces the draw operation. try { doRenderHtmlPageToDC (url, dest, getDCFromMetafile, timeout); } __finally { delete myCanvas; myCanvas = 0; } } void InternetExplorerRenderer::renderHtmlPageToBitmap (String url, Graphics::TBitmap* dest, DWORD timeout) { doRenderHtmlPageToDC (url, dest, getDCFromBitmap, timeout); } // http://weborama.blogspot.com/2004/09/mshtml-hosting-odds-ends.html void InternetExplorerRenderer::doRenderHtmlPageToDC (String url, TGraphic* dest, HDC (__closure * dcGetter) (TGraphic*), DWORD timeout) { // Note that we cannot use an invisible IWebBrowser because MSHTML refuses // to render a HTML page to an arbitrary DC if the container is not a control. if (!renderForm) { renderForm = new TForm (static_cast <TComponent*> (0)); webBrowser = new TWebBrowser (renderForm); webBrowser->ParentWindow = renderForm->Handle; webBrowser->OnDocumentComplete = this->WebBrowserDocumentComplete; webBrowser->OnNavigateError = WebBrowserNavigateError; } bs = bsBusy; webBrowser->Navigate (url); // Wait until OnDocumentComplete occurs. DWORD tick = GetTickCount (); while (bs == bsBusy) { if ((GetTickCount () - tick) > timeout) { webBrowser->Stop (); throw Exception (_T ("Loading timed out.")); } Application->ProcessMessages (); SwitchToThread (); } _di_IHTMLElement elem = interface_cast <IHTMLDocument2> (webBrowser->Document)->body; _di_IHTMLStyle style = elem->style; if (style) style->borderStyle = _T ("none"); // Disable scroll bars. _di_IHTMLBodyElement bodyelem = elem; if (bodyelem) bodyelem->scroll = _T ("no"); // Move the control outside of the visible area. _di_IHTMLElement2 elem2 = interface_cast <IHTMLElement2> (elem); int scrollWidth = elem2->scrollWidth, scrollHeight = elem2->scrollHeight; webBrowser->Width = scrollWidth + 10; webBrowser->Height = scrollHeight + 10; dest->SetSize (scrollWidth, scrollHeight); RECTL sourceRect = { 0, 0, scrollWidth, scrollHeight }; HRESULT result = interface_cast <IViewObject> (webBrowser->Document)->Draw ( DVASPECT_CONTENT, -1, NULL, NULL, NULL, dcGetter (dest), &sourceRect, &sourceRect, 0, 0); if (result != S_OK) throw EOleSysError ("", result, 0); }
-
audacia schrieb:
...
Leider konnte ich es jetzt erst ausprobieren. An sich entspricht der Code nahezu dem, den ich bereits verwendet hatte, nur das ich dieses Mal das ganze auf die IHTMLView->Draw Variante umgeschrieben habe.
Dabei habe ich aber andere Probleme. Der Metafile auf den ich schreiben will ist zum einen in der Regel größer, zum anderen hat dieser Seitenränder. Da ich keine sinnvolle Beschreibung gefunden habe wie man die Parameter für die IHTMLView->Draw entsprechend setzt ist das direkte Ergebnis nicht verwertbar (Ergebnis ist beispielsweise das ganze Bild in der linken oberen Ecke in der Druckvorschau, und auch wenn ich etwas skalieren kann, so bleibt es der gleiche kleine Ausgabebereich).
Aktueller Notbehelf ist ein Umweg über einen neuen Metafile, der exakt so groß ist wie der Browser, und ein anschließendes StretchDraw auf den Zielbereich. Das Ergebnis ist deutlich besser als die vorherige Bitmapvariante, aber könnte besser sein.
Weiß jemand ob und wie man sich den Umweg (StretchDraw) sparen kann? Bzw. ob man über die IViewObject-Schnittstelle auch eine skalierung auf einen größeren Zielbereich direkt erreichen kann (Aus der MSDN werde ich hier jedenfalls nicht schlau).
cu André