Heim > Artikel > Web-Frontend > Ausführliche Erklärung alternativer Lösungen von HTML zu PDF
Das Projekt erfordert die Generierung eines PDF-Dokuments aus einer HTML-Seite (Zahlungsergebnis). Die Seite enthält Bilder und Tabellen, und es scheint, dass das Open-Source-Programm iTextSharp damit nicht zurechtkommt.
Nach einigem Suchen habe ich wkhtmltopdf gefunden, ein Open-Source-Befehlszeilen-Konvertierungstool, das dies unterstützt Angabe von URL oder lokalem HTML. Der Pfad von Datei hat nach dem Test gut funktioniert. Ich habe auch speziell ein Tool mit wkhtmltopdf geschrieben, um das PDF der Blog-Gartenbeiträge lokal zu sichern Habe später Zeit
Aber, senden Nach zwei Testtagen für Kunden waren die Laufergebnisse nicht ideal und es traten einige unbekannte Fehler auf. Merkwürdig ist, dass es in der Testumgebung keine Probleme gab, aber häufig Fehler auftraten im offiziellen Umfeld. Schließlich gab der Kunde diese Lösung auf
Angehängter WkhtmlToXSharp C# Wrapper-Wrapper (mit P/Invoke) für die hervorragende HTML-zu-PDF-Konvertierungsbibliothek wkhtmltopdf-Bibliothek.
* **
OK, kommen wir zum Punkt, eine alternative Lösung: Hook
Neues WinForm-Projekt, in das WebBrowser-Steuerelement ziehen, der Code gibt die URL zum lokalen HTML-Dateipfad an, warten, bis das Dokument geladen ist, WebBrowser.Drucken(); OK, ausführen, ein Dialogfeld zur Auswahl eines Druckers wird angezeigt, wie in Abbildung 1 dargestellt. Nachdem Sie auf „Drucken“ geklickt haben, wird ein Dialogfeld zum Speichern unter angezeigt. Geben Sie den XPS-Pfad ein und speichern Sie ihn (Abbildung 2). Sie erhalten ein XPS-Dokument.
Bild 1: Drucker auswählen
Bild 2: XPS-Pfad eingeben
Wie Sie oben sehen können , Das Drucken hier erfordert eine Interaktion mit der Benutzeroberfläche. Klicken Sie manuell auf Drucken und geben Sie den XPS-Pfad zum Speichern ein.
Als nächstes habe ich im Internet gesucht: Wie man XPS-Dateien direkt druckt und generiert, ohne das Dialogfeld anzuzeigen. Ich habe viel über Stackoverflow und Codeproject gelesen, konnte aber keinen Weg finden. Später habe ich versehentlich einen Artikel von Yuanzi gelesen und die Hook-Methode und die UI-Automatisierung verwendet, um die Druck- und Speicheraktionen abzuschließen.
Als nächstes codieren wir es
//调用WebBrowser.Print的代码就忽略了,直接看钩子 IntPtr hwndDialog; string pathFile; EnumBrowserFileSaveType saveType; // Imports of the User32 DLL. [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, int lParam); [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern IntPtr GetDlgItem(IntPtr hWnd, int nIDDlgItem); [DllImport("user32.dll", CharSet = CharSet.Auto)] static extern private bool SetWindowText(IntPtr hWnd, string lpString); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool IsWindowVisible(IntPtr hWnd); //Win32 Api定义 [DllImport("user32.dll")] static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("user32.dll")] static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfeter, string lpszClass, string lpszWindow); [DllImport("user32.dll")] static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, String lParam); [DllImport("user32.dll")] static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); //Win32消息定义 const uint WM_SETTEXT = 0x000c; const uint WM_IME_KEYDOWN = 0x0290; const uint WM_LBUTTONDOWN = 0x0201; const uint WM_LBUTTONUP = 0x0202; // The thread procedure performs the message loop and place the data public void ThreadProc() { int maxRetry = 10; int retry = 0; IntPtr hWndPrint = FindWindow("#32770", "打印"); IntPtr hWnd = FindWindow("#32770", "文件另存为"); if (hWnd != IntPtr.Zero) { log.InfoFormat("got saveas dialog handle. Printer Dialog skipped."); } else { Thread.Sleep(200); hWndPrint = FindWindow("#32770", "打印"); //这里有时候获取不到window,所以加了Sleep,多试几次 while (hWndPrint == IntPtr.Zero && retry < maxRetry) { Thread.Sleep(200); log.InfoFormat("retry get Print dialog handle.retry:{0}", retry); hWndPrint = FindWindow("#32770", "打印"); retry++; } if (hWndPrint == IntPtr.Zero) { //wait 1 second,retry again Thread.Sleep(1000); hWndPrint = FindWindow("#32770", "打印"); } if (hWndPrint == IntPtr.Zero) { log.InfoFormat("Did not get Print dialog handle.retry:{0}", retry); return; } log.InfoFormat("got Print dialog handle.retry:{0}", retry); //select printer dialog IntPtr hChildP; hChildP = IntPtr.Zero; hChildP = FindWindowEx(hWndPrint, IntPtr.Zero, "Button", "打印(&P)"); // 向保存按钮发送2个消息,以模拟click消息,借此来按下保存按钮 PostMessage(hChildP, WM_LBUTTONDOWN, IntPtr.Zero, IntPtr.Zero); PostMessage(hChildP, WM_LBUTTONUP, IntPtr.Zero, IntPtr.Zero); Application.DoEvents(); } //hWnd = FindWindow("#32770", null); hWnd = FindWindow("#32770", "文件另存为"); //To avoid race condition, we are forcing this thread to wait until Saveas dialog is displayed. retry = 0; while ((!IsWindowVisible(hWnd) || hWnd == IntPtr.Zero) && retry < maxRetry) { Thread.Sleep(200); log.InfoFormat("retry get saveas dialog handle.retry:{0}", retry); hWnd = FindWindow("#32770", null); retry++; Application.DoEvents(); } log.InfoFormat("got saveas dialog handle.retry:{0}", retry); if (hWnd == IntPtr.Zero) { //wait 1 second,retry again Thread.Sleep(1000); hWnd = FindWindow("#32770", "文件另存为"); } if (hWnd == IntPtr.Zero) { return; } Application.DoEvents(); IntPtr hChild; // 由于输入框被多个控件嵌套,因此需要一级一级的往控件内找到输入框 hChild = FindWindowEx(hWnd, IntPtr.Zero, "DUIViewWndClassName", String.Empty); hChild = FindWindowEx(hChild, IntPtr.Zero, "DirectUIHWND", String.Empty); hChild = FindWindowEx(hChild, IntPtr.Zero, "FloatNotifySink", String.Empty); hChild = FindWindowEx(hChild, IntPtr.Zero, "ComboBox", String.Empty); hChild = FindWindowEx(hChild, IntPtr.Zero, "Edit", String.Empty); // File name edit control // 向输入框发送消息,填充目标xps文件名 SendMessage(hChild, WM_SETTEXT, IntPtr.Zero, pathFile); // 等待1秒钟 System.Threading.Thread.Sleep(1000); // 找到对话框内的保存按钮 hChild = IntPtr.Zero; hChild = FindWindowEx(hWnd, IntPtr.Zero, "Button", "保存(&S)"); // 向保存按钮发送2个消息,以模拟click消息,借此来按下保存按钮 PostMessage(hChild, WM_LBUTTONDOWN, IntPtr.Zero, IntPtr.Zero); PostMessage(hChild, WM_LBUTTONUP, IntPtr.Zero, IntPtr.Zero); // Clean up GUI - we have clicked save button. //GC is going to do that cleanup job, so we are OK Application.DoEvents(); //Terminate the thread. return; }
Weiter Bezüglich der Konvertierung von XPS in PDF habe ich Spire.Pdf verwendet, es gibt eine offizielle Demo, hier keine weitere Erklärung
Es gibt Bilder und die Wahrheit
Das obige ist der detaillierte Inhalt vonAusführliche Erklärung alternativer Lösungen von HTML zu PDF. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!