ホームページ > 記事 > ウェブフロントエンド > HtmlからPDFへの代替ソリューションの詳細な説明
このプロジェクトでは、HTML ページ (支払い結果) から PDF ドキュメントを生成する必要があります。このページには写真とテーブルがありますが、オープンソースのiTextSharpでは対応できないようです
いくつか検索した結果、URLまたはローカルHTMLのパスの指定をサポートするコマンドラインのオープンソース変換ツールであるwkhtmltopdfを見つけました。ファイルを試してみたところ、効果は良好でした。ブログ投稿の PDF をローカルにバックアップするためのツールも特別に作成しました。後で時間があるときにこのツールを共有します。 2日間テストを行ったところ、走行効果が思わしくなく、不明なエラーが発生しました。そして不思議なことに、テスト環境では問題がないのに、正式環境ではエラーが頻繁に発生します。最終的に、顧客はこのソリューションを諦めました
添付されているのは、WkhtmlToXSharpC#
ラッパー ラッパー (P/Invoke を使用)の優れた Html から PDF への変換ライブラリ wkhtmltopdf ライブラリです*** さて、本題に入りましょう。別の解決策: フック
IE 印刷機能を呼び出し、XPS プリンタを使用し、最初に HTML ファイルを
Print
図 2: xps パスを入力します
上記からわかるように、ここで印刷するには UI との対話が必要で、手動で [印刷] をクリックし、xps パスを入力します保存。
次に、インターネットで検索しました: ダイアログボックスを表示せずに xps ファイルを直接印刷して生成する方法 stackoverflow と codeproject をよく読みましたが、方法が見つかりませんでした。その後、偶然、Yuanzi の前任者の記事を読みました。フックメソッドと UI オートメーションを使用して、印刷と保存のアクションを完了しました。この解決策は実現可能だと思います
//调用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; }次のステップは、xps を PDF に変換することです。 Spire.Pdf を使用すると、公式デモがあります。ここではこれ以上説明しません
写真と真実があります
XPS の自動選択に関するフックコードが完了していません
Document ライターさん、お願いします私にアドバイスを!
以上がHtmlからPDFへの代替ソリューションの詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。