html转化为base64编码的pdf文件

安装转化工具

本演示是在windows11上进行的

通过网盘分享的文件:wkhtmltopdf.zip

链接: https://pan.baidu.com/s/1RX6biSPAXZxuP9J01lLGTA?pwd=tawt 提取码: tawt

配置环境变量

引入依赖

java 复制代码
<dependency>
    <groupId>com.openhtmltopdf</groupId>
    <artifactId>openhtmltopdf-core</artifactId>
    <version>1.0.10</version>
</dependency>
<!-- PDFBox 后端(必须) -->
<dependency>
    <groupId>com.openhtmltopdf</groupId>
    <artifactId>openhtmltopdf-pdfbox</artifactId>
    <version>1.0.10</version>
</dependency>

编写工具类

java 复制代码
package org.dromara.pdfScriptPlugs.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.codec.binary.Base64;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;

/**
 *
 */
@Slf4j
public class HtmlToPdfUtils {

    public static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");

    /**
     * html转化为pdf文件
     *
     * @param htmlContent
     * @return String base64编码的文件
     * @throws IOException
     */
    public static String convertHtmlToPdfBase64(String htmlContent) throws IOException {
        LocalDateTime start = LocalDateTime.now();
        Process process = null;
        try {
            long t0 = System.currentTimeMillis();
            ProcessBuilder pb = new ProcessBuilder("wkhtmltopdf", "--encoding", "utf-8", "-", "-");
            // 建议显式设置工作目录或环境变量,避免某些机器上找不到字体/配置时变慢
            // pb.directory(new File("/tmp"));

            process = pb.start();
            long t1 = System.currentTimeMillis();

            // 1. 异步消费 stderr,避免缓冲区写满阻塞
            final InputStream errorStream = process.getErrorStream();
            Thread stderrGobbler = new Thread(() -> {
                try (InputStream es = errorStream) {
                    byte[] buf = new byte[4096];
                    while (es.read(buf) != -1) {
                        // String s = new String(buf, 0, len, StandardCharsets.UTF_8);
                        // log.debug("wkhtmltopdf stderr: {}", s);
                    }
                } catch (IOException e) {
                    log.warn("Error reading wkhtmltopdf stderr", e);
                }
            }, "wkhtmltopdf-stderr-gobbler");
            stderrGobbler.setDaemon(true);
            stderrGobbler.start();

            // 2. 写入 HTML 到 stdin
            try (OutputStream stdin = process.getOutputStream()) {
                byte[] data = htmlContent.getBytes(StandardCharsets.UTF_8);
                stdin.write(data);
                stdin.flush();
            }
            long t2 = System.currentTimeMillis();

            // 3. 读取 stdout 中的 PDF
            try (InputStream inputStream = process.getInputStream();
                 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(32 * 1024)) {

                byte[] buffer = new byte[8192];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
                long t3 = System.currentTimeMillis();

                // 4. 等待进程结束并检查退出码(带超时)
                boolean finished = process.waitFor(30, TimeUnit.SECONDS);
                if (!finished) {
                    process.destroyForcibly();
                    throw new RuntimeException("wkhtmltopdf 转换超时(>30s)");
                }
                String base64 = Base64.encodeBase64String(outputStream.toByteArray());
                long t4 = System.currentTimeMillis();
                log.info("convertHtmlToPdfBase64 success, total cost={} ms", (t4 - t0));
                return base64;
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("wkhtmltopdf 转换被中断");
        } catch (IOException e) {
            throw new RuntimeException("html转pdf异常: " + e.getMessage());
        } finally {
            if (process != null && process.isAlive()) {
                process.destroy();
            }
            log.info("convertHtmlToPdfBase64 end: {}", LocalDateTime.now().format(formatter));
        }
    }

    public static byte[] core(String htmlContent) throws IOException {
        LocalDateTime start = LocalDateTime.now();
        Process process = null;
        long t0 = System.currentTimeMillis();
        ProcessBuilder pb = new ProcessBuilder("wkhtmltopdf", "--encoding", "utf-8", "-", "-");

        process = pb.start();
        long t1 = System.currentTimeMillis();

        final InputStream errorStream = process.getErrorStream();
        Thread stderrGobbler = new Thread(() -> {
            try (InputStream es = errorStream) {
                byte[] buf = new byte[4096];
                while (es.read(buf) != -1) {
                }
            } catch (IOException e) {
                log.warn("Error reading wkhtmltopdf stderr", e);
            }
        }, "wkhtmltopdf-stderr-gobbler");
        stderrGobbler.setDaemon(true);
        stderrGobbler.start();

        // 2. 写入 HTML 到 stdin
        try (OutputStream stdin = process.getOutputStream()) {
            byte[] data = htmlContent.getBytes(StandardCharsets.UTF_8);
            stdin.write(data);
            stdin.flush();
        }
        long t2 = System.currentTimeMillis();

        // 3. 读取 stdout 中的 PDF
        try (InputStream inputStream = process.getInputStream();
             ByteArrayOutputStream outputStream = new ByteArrayOutputStream(32 * 1024)) {

            byte[] buffer = new byte[8192];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            long t3 = System.currentTimeMillis();

            // 4. 等待进程结束
            boolean finished = process.waitFor(30, TimeUnit.SECONDS);
            if (!finished) {
                process.destroyForcibly();
                throw new RuntimeException("wkhtmltopdf 转换超时(>30s)");
            }
            return outputStream.toByteArray();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("wkhtmltopdf 转换被中断");
        } catch (IOException e) {
            throw new RuntimeException("html转pdf异常: " + e.getMessage());
        } finally {
            if (process != null && process.isAlive()) {
                process.destroy();
            }
            log.info("convertHtmlToPdfBase64 end: {}", LocalDateTime.now().format(formatter));
        }
    }
}

测试转化效果

java 复制代码
import org.dromara.pdfScriptPlugs.utils.HtmlToPdfUtils;

import java.io.IOException;

/**
 * @Author: zhouhai
 * @Date: 2026/01/09
 */
public class Test {
    public static void main(String[] args) {
        try {
            String htmlContent = "<html><body><h1>Hello, World!</h1></body></html>";
            System.out.println( HtmlToPdfUtils.convertHtmlToPdfBase64(htmlContent));
        } catch (IOException e) {

        }
    }
}

效果

base64 复制代码
23:07:49.471 [main] INFO org.dromara.pdfScriptPlugs.utils.HtmlToPdfUtils -- convertHtmlToPdfBase64 success, total cost=1298 ms
23:07:49.475 [main] INFO org.dromara.pdfScriptPlugs.utils.HtmlToPdfUtils -- convertHtmlToPdfBase64 end: 2026-01-09 23:07:49.475
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Ge/D3P6/qlTzW3IKhP8qo39szeUdF5Habx/nWsKeehN/C9p/TzX3CnZWA7s078X7R2ivPZVR29/fKm5Hj+N+x4xjznHKcdpxznGf44LjzH4S7rDn4/7KVua8wNCQxvHZ9e57ypwX8NzJQ8T397SCV2om/2zvg5V99pT4QuLpbP+IlDkJ+V/muTIZCmVuZHN0cmVhbQplbmRvYmoKMjAgMCBvYmoKNDgzOQplbmRvYmoKMTggMCBvYmoKPDwgL1R5cGUgL0ZvbnQKL1N1YnR5cGUgL0NJREZvbnRUeXBlMgovQmFzZUZvbnQgL1RpbWVzTmV3Um9tYW5Cb2xkCi9DSURTeXN0ZW1JbmZvIDw8IC9SZWdpc3RyeSAoQWRvYmUpIC9PcmRlcmluZyAoSWRlbnRpdHkpIC9TdXBwbGVtZW50IDAgPj4KL0ZvbnREZXNjcmlwdG9yIDE2IDAgUgovQ0lEVG9HSURNYXAgL0lkZW50aXR5Ci9XIFswIFs2OTcgNjk3IDM5OCAyNDkgNDQ4IDIyNCAyMjQgODk2IDM5OCA0OTggMjk4IF0KXQo+PgplbmRvYmoKMTkgMCBvYmoKPDwgL0xlbmd0aCA0MzQgPj4Kc3RyZWFtCi9DSURJbml0IC9Qcm9jU2V0IGZpbmRyZXNvdXJjZSBiZWdpbgoxMiBkaWN0IGJlZ2luCmJlZ2luY21hcAovQ0lEU3lzdGVtSW5mbyA8PCAvUmVnaXN0cnkgKEFkb2JlKSAvT3JkZXJpbmcgKFVDUykgL1N1cHBsZW1lbnQgMCA+PiBkZWYKL0NNYXBOYW1lIC9BZG9iZS1JZGVudGl0eS1VQ1MgZGVmCi9DTWFwVHlwZSAyIGRlZgoxIGJlZ2luY29kZXNwYWNlcmFuZ2UKPDAwMDA+IDxGRkZGPgplbmRjb2Rlc3BhY2VyYW5nZQoyIGJlZ2luYmZyYW5nZQo8MDAwMD4gPDAwMDA+IDwwMDAwPgo8MDAwMT4gPDAwMEE+IFs8MDA0OD4gPDAwNjU+IDwwMDZDPiA8MDA2Rj4gPDAwMkM+IDwwMDIwPiA8MDA1Nz4gPDAwNzI+IDwwMDY0PiA8MDAyMT4gXQplbmRiZnJhbmdlCmVuZGNtYXAKQ01hcE5hbWUgY3VycmVudGRpY3QgL0NNYXAgZGVmaW5lcmVzb3VyY2UgcG9wCmVuZAplbmQKCmVuZHN0cmVhbQplbmRvYmoKNiAwIG9iago8PCAvVHlwZSAvRm9udAovU3VidHlwZSAvVHlwZTAKL0Jhc2VGb250IC9UaW1lc05ld1JvbWFuQm9sZAovRW5jb2RpbmcgL0lkZW50aXR5LUgKL0Rlc2NlbmRhbnRGb250cyBbMTggMCBSXQovVG9Vbmljb2RlIDE5IDAgUj4+CmVuZG9iagoyIDAgb2JqCjw8Ci9UeXBlIC9QYWdlcwovS2lkcyAKWwo1IDAgUgpdCi9Db3VudCAxCi9Qcm9jU2V0IFsvUERGIC9UZXh0IC9JbWFnZUIgL0ltYWdlQ10KPj4KZW5kb2JqCnhyZWYKMCAyMQowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMDAwMDkgMDAwMDAgbiAKMDAwMDAwNzM2NyAwMDAwMCBuIAowMDAwMDAwMTYzIDAwMDAwIG4gCjAwMDAwMDAyNTggMDAwMDAgbiAKMDAwMDAwMDY1MSAwMDAwMCBuIAowMDAwMDA3MjI0IDAwMDAwIG4gCjAwMDAwMDAyOTUgMDAwMDAgbiAKMDAwMDAwMDMzOCAwMDAwMCBuIAowMDAwMDAwNDg3IDAwMDAwIG4gCjAwMDAwMDAzNzkgMDAwMDAgbiAKMDAwMDAwMDU0OSAwMDAwMCBuIAowMDAwMDAwOTU4IDAwMDAwIG4gCjAwMDAwMDEyNDcgMDAwMDAgbiAKMDAwMDAwMDc3MiAwMDAwMCBuIAowMDAwMDAwOTM4IDAwMDAwIG4gCjAwMDAwMDEyNjcgMDAwMDAgbiAKMDAwMDAwMTUyNSAwMDAwMCBuIAowMDAwMDA2NDc3IDAwMDAwIG4gCjAwMDAwMDY3MzggMDAwMDAgbiAKMDAwMDAwNjQ1NiAwMDAwMCBuIAp0cmFpbGVyCjw8Ci9TaXplIDIxCi9JbmZvIDEgMCBSCi9Sb290IDExIDAgUgo+PgpzdGFydHhyZWYKNzQ2NQolJUVPRgo=
相关推荐
天荒地老笑话么9 小时前
IntelliJ IDEA 运行 Tomcat 报错:Please, configure Web Facet first!
java·前端·tomcat·intellij-idea
神色自若9 小时前
vue3 带tabs的后台管理系统,切换tab标签后,共用界面带参数缓存界面状态
前端·vue3
мо仙堡杠把子ご灬9 小时前
微前端架构实践:避免Vuex模块重复注册的崩溃陷阱
前端
叫我:松哥9 小时前
基于机器学习的地震风险评估与可视化系统,采用Flask后端与Bootstrap前端,系统集成DBSCAN空间聚类算法与随机森林算法
前端·算法·机器学习·flask·bootstrap·echarts·聚类
呆头鸭L9 小时前
用vue3+ts+elementPlus+vite搭建electron桌面端应用
前端·vue.js·electron
aPurpleBerry9 小时前
React Hooks(数据驱动、副作用、状态传递、状态派生)
前端·react.js·前端框架
IT_陈寒9 小时前
2025年React生态最新趋势:我从Redux迁移到Zustand后性能提升40%的心得
前端·人工智能·后端
前端小臻9 小时前
react没有双向数据绑定是怎么实现数据实时变更的
前端·javascript·react.js
困惑阿三9 小时前
CSS 动效交互实验室
前端·css