1 Star 0 Fork 0

yjihrp / linux-html2pdf-demo

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

HTML 转 PDF 可行性调研

名称 语言 许可 系统 架构 主要依赖 自主开发 中文乱码 字体引用 CSS2 CSS3 SVG CANVAS 图片越界 表单
princexml java8、11 需要 win10 centos7 x86_64 prince 不支持 支持 支持 支持 支持
itext5、8 java8、11 AGPLV3 win10 centos7 x86_64 html2pdf 支持 支持 支持 支持 -
openpdf java8、11 LGPL2.1 MPL2.0 win10 centos7 x86_64 flying-saucer-pdf-openpdf 版本较新 支持 支持 支持
pdfbox java8、11 Apache2.0 LGPL2.1 win10 centos7 x86_64 openhtmltopdf-pdfbox2、3 版本升级? 支持 支持 支持
selenium java11+ Apache 2.0 win10 x86_64 selenium-java 4.16 firefox116 不支持 支持 支持 支持 支持 支持
selenium java11+ Apache 2.0 centos7 x86_64 selenium-java 4.16 不支持 支持 支持 支持 支持 支持
selenium python3.7.9 win10 x86_64 selenium4.11 firefox116 不支持 支持 支持 支持 支持 支持
selenium python3.8.18 centos7 x86_64 selenium4.16 firefox102 不支持 支持 支持 支持 支持 支持
selenium python3.6+ centos7 x86_64 selenium3.141 firefox102 - - - - - - - -
weasyprint python3.7.9 BSD win10 x86_64 gtk3+ 支持 支持 支持 支持
weasyprint python3.9.18 BSD stream9 x86_64 cairo,Pango,gtk2.6+ 支持 支持 支持 支持
xhtml2pdf python3.8+ stream9 x86_64 openssl1.1.1+ - - - - -

总结

名称 prince itext selenium openpdf pdfbox weasyprint
效果 1 1 1 0.5 0.5 0.5
授权 0 0 1 0 1 1
系统 0.5 1 1 1 1 0.5
架构 0.5 1 1 1 1 1
自主开发 0 0.5 0 1 1 1
总分 2 3.5 4 3.5 4.5 4

princexml

It’s quick and simple to convert HTML to PDF with Prince. HTML is seamlessly transformed into documents you can print

下载地址

Prince - Download Prince 15.2 (princexml.com)

包装库

  • java

  • C#

  • PHP

  • Node

  • Ruby

适配情况

系统名称 x86_64 arm64 说明
Windows -
Red Hat Enterprise Linux 7-9 -
Ubuntu 18-22
Debian GNU Linux 9-10 -
Debian GNU Linux 11-12
OpenSUSE -
MacOS
Alpine Linux -
Generic Linux
Free BSD -

主要依赖

        <dependency>
            <groupId>com.princexml</groupId>
            <artifactId>prince-java-wrapper</artifactId>
            <version>1.3.0</version>
        </dependency>

测试代码

        // 获取 java 版本
        String version = System.getProperty("java.specification.version");

        // 获取系统类型
        String platform = System.getProperty("os.name", "");
        platform = platform.toLowerCase().contains("window") ? "win" : "linux";

        // 当前程序目录
        String current = System.getProperty("user.dir");

        System.out.println(String.format("current=%s", current));

        // html 文件路径
        File index = Paths.get(current, "..", "index.html").toFile();
        if (!index.exists()) {
            System.out.println(String.format("file not exist,file=%s", index.getAbsolutePath()));
            return;
        }
        String command = Paths.get(current, "..", "prince-15.2-win64", "bin", "prince.exe").toString();
        if (OSInfo.getOSType() == OSInfo.OSType.LINUX) {
            command = "prince";
        }
        Prince prince = new Prince(command);
        // prince.setLog("/path/to/log.txt");
        // prince.addStyleSheet("/path/to/stylesheet.css");
        // prince.addScript("/path/to/script.js");
        prince.setJavaScript(true);

        try {
            // 转换 html 文件
            File file = Paths.get(current, String.format("java%s_%s.pdf", version, platform)).toFile();
            prince.convert(index.getAbsolutePath(), file.getAbsolutePath());
        } catch (IOException e) {
            e.printStackTrace();
        }

效果预览

java1.8_win.pdf

java11_linux.pdf

java 库

itext

![](D:\work\linux-html2pdf-demo\images\屏幕截图 2023-12-16 171211.png)

主要依赖

        <dependency>
            <!-- 会自动引用 itext 其他库,kernel,commons,io,forms,layout,svg,styled-xml-parser -->
            <groupId>com.itextpdf</groupId>
            <artifactId>html2pdf</artifactId>
            <version>5.0.2</version>
        </dependency>

![](D:\work\linux-html2pdf-demo\images\屏幕截图 2023-12-16 172507.png)

测试代码

        // 获取 java 版本
        String version = System.getProperty("java.specification.version");

        // 获取系统类型
        String platform = System.getProperty("os.name", "");
        platform = platform.toLowerCase().contains("window") ? "win" : "linux";

        // 当前程序目录
        String current = System.getProperty("user.dir");

        System.out.println(String.format("current=%s", current));

        // html 文件路径
        File index = Paths.get(current, "..", "index.html").toFile();
        if (!index.exists()) {
            System.out.println(String.format("file not exist,file=%s", index.getAbsolutePath()));
            return;
        }

        try {
            // 保存 pdf 文件路径
            File file = Paths.get(current, String.format("java%s_%s.pdf", version, platform)).toFile();

            // 转换设置
            ConverterProperties options = new ConverterProperties();

            // 设置根目录类型
            String baseUri = Paths.get(current, "..").toUri().toString();
            options.setBaseUri(baseUri);

            // 设置字体
            FontProvider fontProvider = new FontProvider();
            fontProvider.addStandardPdfFonts();
            fontProvider.addSystemFonts();
            options.setFontProvider(fontProvider);

            // 转换 html 文件
            HtmlConverter.convertToPdf(index, file, options);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

效果预览

java1.8_win.pdf

java11_linux.pdf

openpdf

主要依赖

        <dependency>
            <!-- 将 html 转换为 xml 工具库 -->
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.17.1</version>
        </dependency>

        <dependency>
            <!-- 第三方 openpdf 包装库,提供 html 转 pdf 功能 -->
            <groupId>org.xhtmlrenderer</groupId>
            <artifactId>flying-saucer-pdf-openpdf</artifactId>
            <version>9.3.1</version>
        </dependency>

测试代码

        // 获取 java 版本
        String version = System.getProperty("java.specification.version");

        // 获取系统类型
        String platform = System.getProperty("os.name", "");
        platform = platform.toLowerCase().contains("window") ? "win" : "linux";

        // 当前程序目录
        String current = System.getProperty("user.dir");

        System.out.println(String.format("current=%s", current));

        // html 文件路径
        File index = Paths.get(current, "..", "index.html").toFile();
        if (!index.exists()) {
            System.out.println(String.format("file not exist,file=%s", index.getAbsolutePath()));
            return;
        }

        try {
            Document document = Jsoup.parse(index, "UTF-8");
            // 补全标记
            document.outputSettings().syntax(Document.OutputSettings.Syntax.xml);

            ITextRenderer render = new ITextRenderer();
            ITextFontResolver fontResolver = render.getFontResolver();

            File[] fonts = Paths.get(current, "..", "fonts").toFile().listFiles();
            for (File item : fonts) {
                // 应该这样添加字体
                fontResolver.addFont(item.getAbsolutePath(), BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            }

            SharedContext sharedContext = render.getSharedContext();
            sharedContext.setPrint(true);
            sharedContext.setInteractive(false);
            sharedContext.getTextRenderer().setSmoothingThreshold(0);

            // 自定义图片解析
            // sharedContext.setReplacedElementFactory(new ReplacedElementFactoryImpl());

            // 指定根目录,这里需要 URL 格式
            // file:/D:/work/linux-html2pdf-demo/openpdf-demo/../
            String baseUrl = Paths.get(current, "..").toUri().toURL().toString();
            render.setDocumentFromString(document.html(), baseUrl);
            render.layout();

            File file = Paths.get(current, String.format("java%s_%s.pdf", version, platform)).toFile();
            FileOutputStream stream = new FileOutputStream(file);
            render.createPDF(stream);
            stream.close();

            System.out.println(String.format("file=%s", file.getAbsolutePath()));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

效果预览

java1.8_win.pdf

java11_linux.pdf

pdfbox

主要依赖

        <!-- 将 html 转换为 xml 工具库 -->
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.17.1</version>
        </dependency>

        <!-- 第三方 pdfbox 包装库,提供 html 转 pdf 功能 -->
        <dependency>
            <groupId>com.openhtmltopdf</groupId>
            <artifactId>openhtmltopdf-pdfbox</artifactId>
            <version>1.0.10</version>
        </dependency>

测试代码

        // 获取 java 版本
        String version = System.getProperty("java.specification.version");

        // 获取系统类型
        String platform = System.getProperty("os.name", "");
        platform = platform.toLowerCase().contains("window") ? "win" : "linux";

        // 当前程序目录
        String current = System.getProperty("user.dir");

        System.out.println(String.format("current=%s", current));

        // html 文件路径
        File index = Paths.get(current, "..", "index.html").toFile();
        if (!index.exists()) {
            System.out.println(String.format("file not exist,file=%s", index.getAbsolutePath()));
            return;
        }

        try {
            Document doc = Jsoup.parse(index, "UTF-8");
            // 补全标记
            doc.outputSettings().syntax(Document.OutputSettings.Syntax.xml);

            File file = Paths.get(current, String.format("java%s_%s.pdf", version, platform)).toFile();
            FileOutputStream stream = new FileOutputStream(file);

            PdfRendererBuilder builder = new PdfRendererBuilder();

            // NOTE 字体问题,文档中出现过的字段,需要手动加载字体
            builder.useFont(Paths.get(current, "..", "fonts", "simsun.ttc").toFile(), "SimSun");
            builder.useFont(Paths.get(current, "..", "fonts", "msyh.ttc").toFile(), "font-test");
            builder.useFont(Paths.get(current, "..", "fonts", "msyh.ttc").toFile(), "Microsoft YaHei UI");

            // NOTE 设置根目录
            String baseUrl = Paths.get(current, "..").toUri().toString();
            builder.withHtmlContent(doc.html(), baseUrl);

            builder.toStream(stream);
            builder.run();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

效果预览

java1.8_win.pdf

java11_linux.pdf

实用工具

# 查看 pdf 内部结构
java -jar pdfbox-app debug path-to-pdf/test.pdf
java -jar debugger-app path-to-pdf/test.pdf

selenium

Selenium 通过使用 WebDriver 支持市场上所有主流浏览器的自动化。 Webdriver 是一个 API 和协议,它定义了一个语言中立的接口,用于控制 web 浏览器的行为。 每个浏览器都有一个特定的 WebDriver 实现,称为驱动程序。 驱动程序是负责委派给浏览器的组件,并处理与 Selenium 和浏览器之间的通信。

这种分离是有意识地努力让浏览器供应商为其浏览器的实现负责的一部分。 Selenium 在可能的情况下使用这些第三方驱动程序, 但是在这些驱动程序不存在的情况下,它也提供了由项目自己维护的驱动程序。

Selenium 框架通过一个面向用户的界面将所有这些部分连接在一起, 该界面允许透明地使用不同的浏览器后端, 从而实现跨浏览器和跨平台自动化。

# selenium 驱动
https://selenium-python.readthedocs.io/installation.html#drivers
https://selenium-python.readthedocs.io/api.html

-i http://172.16.51.188:8081/repository/pypi/simple --trusted-host 172.16.51.188

主要依赖

        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>4.16.1</version>
        </dependency>

测试代码

        // 获取 java 版本
        String version = System.getProperty("java.specification.version");

        // 获取系统类型
        String platform = System.getProperty("os.name", "");
        platform = platform.toLowerCase().contains("window") ? "win" : "linux";

        // 当前程序目录
        String current = System.getProperty("user.dir");

        System.out.println("current:" + current);

        // firefox 运行参数配置
        FirefoxOptions options = new FirefoxOptions();
        // 无头模式
        options.addArguments("--headless");
        // 最大化
        options.addArguments("--start-maximized");

        FirefoxDriver browser = new FirefoxDriver(options);

        Path url = Paths.get(current, "..", "index.html");
        System.out.println("url:" + url.toString());

        // NOTE 要使用 file 协议
        browser.get(String.format("file://%s", url.toString()));

        // 打印设置
        PrintOptions print = new PrintOptions();
        Pdf pdf = browser.print(print);

        // pdf base64 内容
        String content = pdf.getContent();
        // 解码内容
        Base64.Decoder decoder = Base64.getDecoder();
        byte[] buffer = decoder.decode(content);

        try {
            // 将 byte 写入文件
            Path file = Paths.get(String.format("java%s_%s.pdf", version, platform));
            Files.write(file, buffer);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            browser.quit();
        }

效果预览

java11_linux.pdf

java11_win.pdf

python 库

selenium

Selenium 通过使用 WebDriver 支持市场上所有主流浏览器的自动化。 Webdriver 是一个 API 和协议,它定义了一个语言中立的接口,用于控制 web 浏览器的行为。 每个浏览器都有一个特定的 WebDriver 实现,称为驱动程序。 驱动程序是负责委派给浏览器的组件,并处理与 Selenium 和浏览器之间的通信。

主要依赖

pip install selenium -i http://172.16.51.188:8081/repository/pypi/simple --trusted-host 172.16.51.188

测试代码

import os
import sys
import base64

from selenium import webdriver

platform = 'win' if sys.platform == 'win32' else 'linux'

current = os.path.abspath(os.path.dirname(__file__))

options = webdriver.FirefoxOptions()

options.add_argument('--headless')
options.add_argument("--start-maximized")

# options.add_argument('--disable-gpu')

browser = webdriver.Firefox(options=options)
browser.get(
    'file://{}'.format(os.path.join(current, '..', 'index.html'))
)

data = browser.print_page()
buffer = base64.b64decode(data)

version = sys.version_info
file = os.path.join(
    current, 'python{}{}{}_{}.pdf'.format(
        version.major,
        version.minor,
        version.micro,
        platform

    )
)
with open(file, 'wb') as fd:
    fd.write(buffer)

browser.quit()

效果预览

python379_win.pdf

python3818_linux.pdf

weasyprint

WeasyPrint 能在 Linux, macOS and Windows 多平台支持,因为WeasyPrint需要依赖cairo, Pango 和 GDK-PixBuf ,所以这些软件需要独立安装

环境要求

  • Python ≥ 3.7.0

    手动编译 3.8.18

  • Pango ≥ 1.44.0

    centos7 默认是 1.43 手动编译 1.45.5 版本 安装编译工具 meson

    # centos7 默认 0.55.1;
    yum install meson

    编译时依赖检查失败 glib2.6+ 猜测需要 高版本的系统

  • pydyf ≥ 0.6.0

  • CFFI ≥ 0.6

  • html5lib ≥ 1.1

  • tinycss2 ≥ 1.0.0

  • cssselect2 ≥ 0.1

  • Pyphen ≥ 0.9.1

  • Pillow ≥ 9.1.0

  • fontTools ≥ 4.0.0

stream-9 虚拟机

# linux 环境依赖

yum install pango gcc python3-devel gcc-c++ zlib-devel libjpeg-devel openjpeg2-devel libffi-devel

# windows 环境依赖

需要安装 gtk3 https://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer/releases/tag/2022-01-04

# 使用命令,有乱码问题
weasyprint index.html wessy.pdf

代码测试,见测试代码

xhtml2pdf

基于 ReportLab、html5lib、PyPDF2 等 Python 模块构建的 HTML 到 PDF 转换模块。能够很好的支持 HTML5 、CSS2.1 和部分 CSS3 语法。

因为是基于 Report Lab 模块进行的开发,其对中文的支持在某些环境下会有问题。而且由于开发人员的变更,模块的功能出现了一些断层

环境要求

  • Python 3.8+
  • openssl 1.1.1+
  • 172.16.51.88
# openssl 编译
wget --no-check-certificate https://www.openssl.org/source/openssl-1.1.1w.tar.gz
./config --prefix=/usr/local/openssl-1.1.1w
tar -xvf openssl-1.1.1w.tar.gz
cd openssl-1.1.1w
make -j4
make -j4 install

# 重新编译 python 以支持 openssl 1.1.1w
./configure --prefix=/usr/local/python38 --with-openssl=/usr/local/openssl-1.1.1w/
make -j4
make -j4 install

# 验证 python 关联 openssl 版本
import ssl
print(ssl.OPENSSL_VERSION)

# 安装
pip install xhtml2pdf -i http://172.16.51.188:8081/repository/pypi/simple --trusted-host 172.16.51.188

# 测试,有乱码问题,没有代码实现过
xhtml2pdf index.html xhtml.pdf

空文件

简介

linux HTML 转 PDF demo 展开 收起
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
1
https://gitee.com/yjihrp/linux-html2pdf-demo.git
git@gitee.com:yjihrp/linux-html2pdf-demo.git
yjihrp
linux-html2pdf-demo
linux-html2pdf-demo
master

搜索帮助