1. 程式人生 > >java完成HTML轉PDF wkhtmltopdf

java完成HTML轉PDF wkhtmltopdf

為什麼使用wkhtmltopdf

HTML轉PDF的實現方式有很多,但是轉換出來的PDF的質量又好有壞。之前試過IText和一些其他的工具,但是不是格式亂了就是由於標籤書寫不規範(沒有結尾標籤)導致轉換出來的效果都不太滿意,最後發現wkhtmltopdf轉換格式什麼基本沒有問題而且使用也是比較簡單就使用wkhtmltopdf。

第一步 下載安裝

官網地址:https://wkhtmltopdf.org/downloads.html

根據自己的系統來選擇安裝包。

第二步 配置環境變數

安裝完成之後找到安裝路徑,將其配置到環境變數中,方便使用。

配置完成環境變數之後就可以測試一下了。

看看轉換效果。

可以看到轉換效果是非常不錯的。

第三步 程式碼呼叫wkhtmltopdf進行轉換

輔助程式碼

package fangrong.com.cn.common.utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class HtmlToPdfInterceptor extends Thread {
    private InputStream is;

    public HtmlToPdfInterceptor(InputStream is) {
        this.is = is;
    }

    public void run() {
        try {
            InputStreamReader isr = new InputStreamReader(is, "utf-8");
            BufferedReader br = new BufferedReader(isr);
            String line = null;
            while ((line = br.readLine()) != null) {
                System.out.println(line.toString()); //輸出轉換進度等內容
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

轉換程式碼

package fangrong.com.cn.common.utils;


import java.io.File;

/**
 * Input表單或JavaScript指令碼支援:--enable-forms,下面這些是網友整理的引數說明
 * wkhtmltopdf [OPTIONS]... <input file> [More input files] <output file>
 * 常規選項
 * --allow <path>                  允許載入從指定的資料夾中的檔案或檔案(可重複)
 * --book*                         設定一會列印一本書的時候,通常設定的選項
 * --collate                       列印多份副本時整理
 * --cookie <name> <value>         設定一個額外的cookie(可重複)
 * --cookie-jar <path>             讀取和寫入的Cookie,並在提供的cookie jar檔案
 * --copies <number>               影印列印成pdf檔案數(預設為1)
 * --cover* <url>                  使用HTML檔案作為封面。它會帶頁首和頁尾的TOC之前插入
 * --custom-header <name> <value>  設定一個附加的HTTP頭(可重複)
 * --debug-javascript              顯示的javascript除錯輸出
 * --default-header*               新增一個預設的頭部,與頁面的左邊的名稱,頁面數到右邊,例如: --header-left '[webpage]' --header-right '[page]/[toPage]'  --header-line
 * --disable-external-links*       禁止生成連結到遠端網頁
 * --disable-internal-links*       禁止使用本地連結
 * --disable-javascript            禁止讓網頁執行JavaScript
 * --disable-pdf-compression*      禁止在PDF物件使用無失真壓縮
 * --disable-smart-shrinking*      禁止使用WebKit的智慧戰略收縮,使畫素/ DPI比沒有不變
 * --disallow-local-file-access    禁止允許轉換的本地檔案讀取其他本地檔案,除非explecitily允許用 --allow
 * --dpi <dpi>                     顯式更改DPI(這對基於X11的系統沒有任何影響)
 * --enable-plugins                啟用已安裝的外掛(如Flash
 * --encoding <encoding>           設定預設的文字編碼
 * --extended-help                 顯示更廣泛的幫助,詳細介紹了不常見的命令開關
 * --forms*                        開啟HTML表單欄位轉換為PDF表單域
 * --grayscale                     PDF格式將在灰階產生
 * --help                          Display help
 * --htmldoc                       輸出程式HTML幫助
 * --ignore-load-errors            忽略claimes載入過程中已經遇到了一個錯誤頁面
 * --lowquality                    產生低品質的PDF/ PS。有用縮小結果文件的空間
 * --manpage                       輸出程式手冊頁
 * --margin-bottom <unitreal>      設定頁面下邊距 (default 10mm)
 * --margin-left <unitreal>        將左邊頁邊距 (default 10mm)
 * --margin-right <unitreal>       設定頁面右邊距 (default 10mm)
 * --margin-top <unitreal>         設定頁面上邊距 (default 10mm)
 * --minimum-font-size             <)
 * --no-background                 不列印背景
 * --orientation <orientation>     設定方向為橫向或縱向
 * --page-height <unitreal>        頁面高度 (default unit millimeter)
 * --page-offset* <offset>         設定起始頁碼 (default )
 * --page-size <size>              設定紙張大小: A4, Letter, etc.
 * --page-width <unitreal>         頁面寬度 (default unit millimeter)
 * --password <password>           HTTP驗證密碼
 * --post <name> <value>           Add an additional post field (repeatable)
 * --post-file <name> <path>       Post an aditional file (repeatable)
 * --print-media-type*             使用的列印介質型別,而不是螢幕
 * --proxy <proxy>                 使用代理
 * --quiet                         Be less verbose
 * --read-args-from-stdin          讀取標準輸入的命令列引數
 * --readme                        輸出程式自述
 * --redirect-delay <msec>         等待幾毫秒為JS-重定向(default )
 * --replace* <name> <value>       替換名稱,值的頁首和頁尾(可重複)
 * --stop-slow-scripts             停止執行緩慢的JavaScripts
 * --title <text>                  生成的PDF檔案的標題(第一個文件的標題使用,如果沒有指定)
 * --toc*                          插入的內容的表中的檔案的開頭
 * --use-xserver*                  使用X伺服器(一些外掛和其他的東西沒有X11可能無法正常工作)
 * --user-style-sheet <url>        指定使用者的樣式表,載入在每一頁中
 * --username <username>           HTTP認證的使用者名稱
 * --version                       輸出版本資訊退出
 * --zoom                          <)
 * <p>
 * 頁首和頁尾選項
 * --header-center*    <text>  (設定在中心位置的頁首內容)
 * --header-font-name* <name>  (default Arial)(設定頁首的字型名稱)
 * --header-font-size* <size>  (設定頁首的字型大小)
 * --header-html*      <url>   (新增一個HTML頁首,後面是網址)
 * --header-left*      <text>  (左對齊的頁首文字)
 * --header-line*              (顯示一條線在頁首下)
 * --header-right*     <text>  (右對齊頁首文字)
 * --header-spacing*   <real>  (設定頁首和內容的距離,預設0)
 * --footer-center*    <text>  (設定在中心位置的頁尾內容)
 * --footer-font-name* <name>  (設定頁尾的字型名稱)
 * --footer-font-size* <size>  (設定頁尾的字型大小default )
 * --footer-html*      <url>   (新增一個HTML頁尾,後面是網址)
 * --footer-left*      <text>  (左對齊的頁尾文字)
 * --footer-line*              顯示一條線在頁尾內容上)
 * --footer-right*     <text>  (右對齊頁尾文字)
 * --footer-spacing*   <real>  (設定頁尾和內容的距離)
 * <p>
 * 頁尾和頁首
 * [page]       由當前正在列印的頁的數目代替
 * [frompage]   由要列印的第一頁的數量取代
 * [topage]     由最後一頁要列印的數量取代
 * [webpage]    通過正在列印的頁面的URL替換
 * [section]    由當前節的名稱替換
 * [subsection] 由當前小節的名稱替換
 * [date]       由當前日期系統的本地格式取代
 * [time]       由當前時間,系統的本地格式取代
 * <p>
 * 輪廓選項
 * --dump-outline  <file>  轉儲目錄到一個檔案
 * --outline               顯示目錄(文章中h1,h2來定)
 * --outline-depth <level> 設定目錄的深度(預設為4)
 * <p>
 * 表內容選項中
 * --toc-depth*              <level>  Set the depth of the toc (default)
 * --toc-disable-back-links*          Do not link from section header to toc
 * --toc-disable-links*               Do not link from toc to sections
 * --toc-font-name*          <name>   Set the font used for the toc (default Arial)
 * --toc-header-font-name*   <name>   The font of the toc header (if unset use --toc-font-name)
 * --toc-header-font-size*   <size>   The font size of the toc header (default)
 * --toc-header-text*        <text>   The header text of the toc (default Table Of Contents)
 * --toc-l1-font-size*       <size>   Set the font size on level of the toc (default)
 * --toc-l1-indentation*     <num>    Set indentation on level of the toc (default)
 * --toc-l2-font-size*       <size>   Set the font size on level of the toc (default)
 * --toc-l2-indentation*     <num>    Set indentation on level of the toc (default)
 * --toc-l3-font-size*       <size>   Set the font size on level of the toc (default)
 * --toc-l3-indentation*     <num>    Set indentation on level of the toc (default)
 * --toc-l4-font-size*       <size>   Set the font size on level of the toc (default)
 * --toc-l4-indentation*     <num>    Set indentation on level of the toc (default)
 * --toc-l5-font-size*       <size>   Set the font size on level of the toc (default)
 * --toc-l5-indentation*     <num>    Set indentation on level of the toc (default)
 * --toc-l6-font-size*       <size>   Set the font size on level of the toc (default)
 * --toc-l6-indentation*     <num>    Set indentation on level of the toc (default)
 * --toc-l7-font-size*       <size>   Set the font size on level of the toc (default)
 * --toc-l7-indentation*     <num>    Set indentation on level of the toc (default)
 * --toc-no-dots*                     Do not use dots, in the toc
 * ------------------------------------------------------------------------------------------------------------
 */
public class HtmlToPdf {

    /**
     * html轉pdf
     *
     * @param srcPath  html路徑,可以是硬碟上的路徑,也可以是網路路徑
     * @param file pdf檔案
     * @return 轉換成功返回true
     */
    public static boolean convert(String srcPath, File file) {

        File parent = file.getParentFile();
        // 如果pdf儲存路徑不存在,則建立路徑
        if (!parent.exists()) {
            parent.mkdirs();
        }
        StringBuilder cmd = new StringBuilder();
        String toPdfTool;
        if (System.getProperty("os.name").indexOf("Windows") == -1) { // 根據系統
            // 非windows 系統
            toPdfTool = "/usr/local/bin/wkhtmltopdf";
        } else {
            toPdfTool = "D:/htmlTopdf/wkhtmltopdf/bin/wkhtmltopdf.exe";
        }
	// 這裡可以拼接頁首頁尾等引數 引數詳情在上方
        cmd.append(toPdfTool);
        cmd.append(" ");
        cmd.append(srcPath);
        cmd.append(" ");
        cmd.append(file.getAbsolutePath());

        boolean result = true;
        try {
            Process proc = Runtime.getRuntime().exec(cmd.toString());
            HtmlToPdfInterceptor error = new HtmlToPdfInterceptor(proc.getErrorStream());
            HtmlToPdfInterceptor output = new HtmlToPdfInterceptor(proc.getInputStream());
            error.start();
            output.start();
            proc.waitFor();
        } catch (Exception e) {
            result = false;
            e.printStackTrace();
        }
        return result;
    }
}

到此整合完成。

使用過程中碰到的的一些坑

這些坑主要是出現在Linux環境下的

  • 亂碼問題

一般亂碼的主要原因就是因為Linux中沒有simsun的字型,將C:\Windows\Fonts中的simsun.ttc拷貝到linux伺服器/usr/share/fonts/目錄下,下次再生成pdf就正常了

  • Docker容器中的java程式無法呼叫到Linux本地的wkhtmltopdf指令碼

關於這一個目前並未找到有效的解決方案,只能採用最笨的方法,再docker中裝了一套Linux系統來解決這個問題。如果各位有好的解決