ホームページ > ウェブフロントエンド > htmlチュートリアル > HtmlからPDFへの代替ソリューションの詳細な説明

HtmlからPDFへの代替ソリューションの詳細な説明

高洛峰
リリース: 2017-03-27 14:58:37
オリジナル
1842 人が閲覧しました

背景

このプロジェクトでは、HTML ページ (支払い結果) から PDF ドキュメントを生成する必要があります。このページには写真とテーブルがありますが、オープンソースのiTextSharpでは対応できないようです

いくつか検索した結果、URLまたはローカルHTMLのパスの指定をサポートするコマンドラインのオープンソース変換ツールであるwkhtmltopdfを見つけました。ファイルを試してみたところ、効果は良好でした。ブログ投稿の PDF をローカルにバックアップするためのツールも特別に作成しました。後で時間があるときにこのツールを共有します。 2日間テストを行ったところ、走行効果が思わしくなく、不明なエラーが発生しました。そして不思議なことに、テスト環境では問題がないのに、正式環境ではエラーが頻繁に発生します。最終的に、顧客はこのソリューションを諦めました

添付されているのは、WkhtmlToXSharp

C#
ラッパー ラッパー (P/Invoke を使用)の優れた Html から PDF への変換ライブラリ wkhtmltopdf ライブラリです*** さて、本題に入りましょう。別の解決策: フック
IE 印刷機能を呼び出し、XPS プリンタを使用し、最初に HTML ファイルを
Print

() に生成します。OK、実行すると、図に示すように、プリンタを選択するためのダイアログ ボックスが表示されます。 1. [印刷] をクリックすると、[名前を付けて保存] ダイアログ ボックスが表示され、xps パスを入力して保存すると (図 2)、xps ドキュメントが作成されます。

図 1: プリンターを選択します
另类解决Html to Pdf 的方案详解

図 2: xps パスを入力します

上記からわかるように、ここで印刷するには UI との対話が必要で、手動で [印刷] をクリックし、xps パスを入力します保存。
次に、インターネットで検索しました: ダイアログボックスを表示せずに xps ファイルを直接印刷して生成する方法 stackoverflow と codeproject をよく読みましたが、方法が見つかりませんでした。その後、偶然、Yuanzi の前任者の記事を読みました。フックメソッドと UI オートメーションを使用して、印刷と保存のアクションを完了しました。この解決策は実現可能だと思います另类解决Html to Pdf 的方案详解

次はコーディングしてみましょう

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

    //调用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 サイトの他の関連記事を参照してください。

関連ラベル:
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
関連するチュートリアル
人気のおすすめ
最新のコース
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート