c html 转 pdf,HTML 转 PDF
几种HTML转PDF工具的对比
工具
特点
html2image
简单html转化,对CSS的支持不好
itextpdf
需要自己写模板,可以动态填充
wkhtmltopdf
转化速度快,效果好
所以此处我们重点将wkhtmltopdf的使用做一个示例,完整的项目地址在末尾的链接处
使用
springboot是现在开发的主流框架,所以此处主要是示例在springboot项目中如何集成,其他项目请自行参考使用
准备
需要准备三个基础的文件,分别如下:
simsun.ttc:字体文件
wkhtmltopdf.exe:转换工具,window系统下使用,适用于64为系统,32位系统自行去官网下载对应版本
wkhtmltox:转换工具,Linux系统下使用,同样适用于64位系统
将以上三个文件拷贝到springboot的resources根目录,具体的文件可到文章末尾的项目地址链接中获取,如下图:
image
pom依赖
org.projectlombok
lombok
1.18.12
provided
junit
junit
4.12
test
commons-fileupload
commons-fileupload
1.3.1
net.java.dev.jna
jna
5.4.0
cn.hutool
hutool-all
5.4.0
新建工具类
import com.sun.jna.Platform;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemHeaders;
import org.apache.commons.fileupload.util.FileItemHeadersImpl;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import cn.hutool.core.io.FileUtil;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
/**
* Html转PDF的工具类
* @author zhongyj <1126834403@qq.com>
* @date 2020/8/29
*/
@Slf4j
public class Html2PdfUtils {
private static final File WK_HOME_DIR = FileUtil.file(FileUtil.getUserHomePath()+"/wkHome");
private static final File WK_TMP_DIR = FileUtil.file(FileUtil.getTmpDirPath()+"/wkTemp");
private static final File SIM_SUN_FONT_DIR = Platform.isLinux() ? FileUtil.file("/usr/share/fonts/chinese/TrueType")
: FileUtil.file("C:\\Windows\\Fonts");
private static File wkTool;
private static File simSunFont;
private static boolean canUse = true;
private static boolean able = true;
static {
log.info("Tools are only available for Windows 64 and Linux 64 platforms !!!");
boolean init = forceInit();
log.info("Tools init result: {}", init);
}
/**
* 初始化
* @return 是否初始化成功
*/
public static boolean forceInit() {
long initc = 0L;
if (!WK_HOME_DIR.exists()) {
able = WK_HOME_DIR.mkdirs();
}
log.info("{},check wkHomeDir ,result:{}", ++initc, able);
if (!WK_TMP_DIR.exists()) {
able = WK_TMP_DIR.mkdirs();
}
log.info("{},check wkTmpDir ,result:{}", ++initc, able);
if (!SIM_SUN_FONT_DIR.exists()) {
able = SIM_SUN_FONT_DIR.mkdirs();
}
log.info("{},check simsunFontDir ,result:{}", ++initc, able);
InputStream wkHtmlToxAsStream = null;
InputStream simSunAsStream = null;
if (able) {
wkHtmlToxAsStream = Platform.isLinux() ? Html2PdfUtils.class.getResourceAsStream("/wkhtmltox") : Html2PdfUtils.class.getResourceAsStream("/wkhtmltopdf.exe");
simSunAsStream = Html2PdfUtils.class.getResourceAsStream("/simsun.ttc");
}
if (null == wkHtmlToxAsStream || simSunAsStream == null) {
log.error("{},load wkHtmlToxAsStream :{},load simSunAsStream:{}", ++initc, null == wkHtmlToxAsStream, simSunAsStream == null);
able = false;
}
log.info("{},load wktool and font source ,result:{}", ++initc, able);
if (able) {
File font = new File(SIM_SUN_FONT_DIR, "simsun.ttc");
File wk = new File(WK_HOME_DIR, Platform.isLinux() ? "wkhtmltox" : "wkhtmltopdf.exe");
try {
if (!font.exists()) {
assert simSunAsStream != null;
able = 1 < Files.copy(simSunAsStream, font.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
log.info("{},copy font source to {},result:{}", ++initc, font.toPath(), able);
if (!wk.exists()) {
assert wkHtmlToxAsStream != null;
able = 1 < Files.copy(wkHtmlToxAsStream, wk.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
log.info("{},copy wktools source to {},result:{}", ++initc, font.toPath(), able);
if (able) {
wkTool = wk;
simSunFont = font;
}
} catch (IOException e) {
e.printStackTrace();
able = false;
log.error("{}, error when copy source : {} ", ++initc, e.getMessage());
}
}
if (able) {
if (Platform.isLinux()) {
boolean canExe = exePermissionCheck();
log.info("{},check run permission,result: {} ", ++initc, canExe ? "has permission" : "no permission");
if (!canExe) {
simpleExecCommand("chmod +x " + wkTool.getPath());
if (!exePermissionCheck()) {
log.error("{},add permission failed", ++initc);
able = false;
}
}
}
}
if (able) {
able = cleanTempDir();
}
if (able) {
log.info("{},init success!", ++initc);
} else {
log.info("{},init failed!", ++initc);
canUse = false;
}
return able;
}
public String getSimsunPath() {
log.info("world path:" + simSunFont.getPath());
return simSunFont.getPath();
}
public static Html2PdfUtils build() {
return new Html2PdfUtils();
}
private static boolean exePermissionCheck() {
String permissionLog = simpleExecCommand("ls -l " + wkTool.getPath());
return null != permissionLog && permissionLog.length() >= 10 && 120 == permissionLog.charAt(9);
}
private static boolean cleanTempDir() {
if (WK_TMP_DIR.exists()) {
canUse = deleteFiles(WK_TMP_DIR) ? WK_TMP_DIR.mkdirs() : canUse;
log.info("cleanTempDir,result:{} ", canUse);
} else {
canUse = WK_TMP_DIR.mkdirs();
}
return canUse;
}
public synchronized FileItem convertPdfFromText(String text, String fileName) {
cleanTempDir();
if (!canUse) {
log.info("tools crash,can invoke forceInit() method see reason !!!");
return null;
}
File html = new File(WK_TMP_DIR, fileName + ".html");
File pdf = new File(WK_TMP_DIR, fileName + ".pdf");
// 将html字符串写入到临时的html文件
FileUtil.writeUtf8String(text, html);
if (html.exists() && html.isFile()) {
log.info("exec html to pdf ,wktoolPath=>{}", wkTool.getPath());
simpleExecCommand(wkTool.getPath() + " " + html.getPath() + " " + pdf.getPath());
}
if (pdf.exists() && pdf.isFile()) {
try (FileInputStream fileInputStream = new FileInputStream(pdf); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
byte[] buffer = new byte[2014];
while (fileInputStream.read(buffer) != -1) {
byteArrayOutputStream.write(buffer);
}
byteArrayOutputStream.flush();
byte[] data = byteArrayOutputStream.toByteArray();
if (data.length > 0) {
log.info("html to pdf success ");
SimplePdfFileItem file = new SimplePdfFileItem(pdf, data, Files.probeContentType(pdf.toPath()), "file");
log.info("pdf size :{}", file.getSize());
return file;
}
} catch (IOException e) {
log.error("html to pdf failed");
e.printStackTrace();
return null;
}
}
log.info("html to pdf failed,no data");
return null;
}
private static boolean deleteFiles(File file) {
if (!file.exists()) {
log.info("del the file:{},is not exists", file.getPath());
return false;
}
if (file.isFile()) {
return file.delete();
}
File[] subFiles = file.listFiles();
if (null != subFiles && subFiles.length > 0) {
Arrays.asList(subFiles).forEach(Html2PdfUtils::deleteFiles);
}
return file.delete();
}
private static String simpleExecCommand(String cmd) {
try {
String[] linux = {"/bin/sh", "-c", cmd};
String[] windows = {"cmd", "/c", cmd};
String[] cmdA = Platform.isLinux() ? linux : windows;
Process process = Runtime.getRuntime().exec(cmdA);
LineNumberReader br = new LineNumberReader(new InputStreamReader(process.getInputStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
log.info(line);
sb.append(line).append("\n");
}
return sb.toString();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
@ToString
static class SimplePdfFileItem implements FileItem {
private static final long serialVersionUID = 2237570099615271025L;
public static final String DEFAULT_CHARSET = "ISO-8859-1";
private String fieldName;
private final String fileName;
private boolean isFormField;
private final byte[] cachedContent;
private final String contentType;
private final File dFosFile;
private FileItemHeaders headers;
public SimplePdfFileItem(File dFosFile, byte[] cachedContent, String contentType, String fieldName) {
this.fieldName = fieldName;
this.fileName = dFosFile.getName();
this.isFormField = false;
this.cachedContent = null == cachedContent || cachedContent.length < 1 ? new byte[0] : cachedContent;
this.contentType = contentType;
this.dFosFile = dFosFile;
this.headers = new FileItemHeadersImpl();
}
public SimplePdfFileItem(String fieldName, String fileName, boolean isFormField, byte[] cachedContent
, String contentType, File dFosFile, FileItemHeaders headers) {
this.fieldName = fieldName;
this.fileName = fileName;
this.isFormField = isFormField;
this.cachedContent = cachedContent;
this.contentType = contentType;
this.dFosFile = dFosFile;
this.headers = headers;
}
@Override
public InputStream getInputStream() throws IOException {
if (null == this.dFosFile) {
return new ByteArrayInputStream(this.cachedContent);
}
return new FileInputStream(dFosFile);
}
@Override
public String getContentType() {
return this.contentType;
}
@Override
public String getName() {
return this.fileName;
}
@Override
public boolean isInMemory() {
return this.cachedContent.length > 0;
}
@Override
public long getSize() {
return this.cachedContent.length;
}
@Override
public byte[] get() {
return this.cachedContent;
}
@Override
public String getString(String s) throws UnsupportedEncodingException {
return getString();
}
@Override
public String getString() {
return new String(cachedContent, StandardCharsets.UTF_8);
}
@Override
public void write(File file) throws Exception {
Files.write(file.toPath(), cachedContent, StandardOpenOption.CREATE);
}
@Override
public void delete() {
boolean delete = dFosFile.delete();
}
@Override
public String getFieldName() {
return this.fieldName;
}
@Override
public void setFieldName(String s) {
this.fieldName = s;
}
@Override
public boolean isFormField() {
return this.isFormField;
}
@Override
public void setFormField(boolean b) {
this.isFormField = b;
}
@Override
public OutputStream getOutputStream() throws IOException {
if (null == this.dFosFile) {
return new ByteArrayOutputStream(1024);
}
return new FileOutputStream(this.dFosFile);
}
@Override
public FileItemHeaders getHeaders() {
return this.headers;
}
@Override
public void setHeaders(FileItemHeaders fileItemHeaders) {
this.headers = fileItemHeaders;
}
}
}
转换
@Test
public void down() throws UnsupportedEncodingException {
String html = FileUtil.readUtf8String("E:\\入院记录.html");
FileItem sx = Html2PdfUtils.build().convertPdfFromText(html, "sx");
log.info(sx.toString());
byte[] bytes = sx.get();
FileUtil.writeBytes(bytes,new File("E:\\入院记录-1.pdf"));
}
c html 转 pdf,HTML 转 PDF相关推荐
- 如何编辑PDF文件,PDF编辑器如何使用
如何编辑PDF呢?其实大多数人都不知道该如何下手,部分人会选择将PDF文件转换成Word然后进行编辑,其实这种方法比较麻烦,大大拉低了我们的工作效率.如果想要提高工作效率更加快速的编辑PDF文件,就可 ...
- python pdf报告_Python实现html转换为pdf报告(生成pdf报告)功能示例
本文实例讲述了Python实现html转换为pdf报告(生成pdf报告)功能.分享给大家供大家参考,具体如下: 1.先说下html转换为pdf:其实支持直接生成,有三个函数pdfkit.f 安装pyt ...
- java pdf 书签_Java PDF书签——添加、编辑、删除、读取书签
本文介绍通过Java程序来操作PDF书签,根据对书签的不同操作要求,分以下情况来介绍: 1. 添加书签(包括添加一级书签.多级子书签) 3. 删除书签(包括删除所有书签.删除子书签等) 4. 读取书签 ...
- java 其他文件转pdf_java 其他文件转成pdf java生成pdf
java生成pdf需要用到的包pd4ml.jar 下载地址:http://download.csdn.net/detail/yanning1314/7124741 package com.cular. ...
- pdf各种处理 PDF 的实用代码:PyPDF2、PDFMiner、pdfplumber
你不懂得安排自己的人生,会有很多人帮你安排,他们需要你做的事. PDF文件我们经常用,尤其是这两个场景: 下载参考资料,如各类报告.文档 分享只读资料,方便传播同时保留源文件 场景和模块 所以,对于P ...
- linux 分割pdf,PDFBox分割PDF文档
在前一章中,我们已经看到了如何将JavaScript添加到PDF文档. 现在来学习如何将给定的PDF文档分成多个文档. 分割PDF文档中的页面 可以使用Splitter类将给定的PDF文档分割为多个P ...
- bmp转换tiff c++代码_如何用Java语言将图像转换为PDF?Spire.PDF for Java轻松搞定
对于开发人员,在日常工作中经常也会处理许多文档格式,将图像转换为PDF也是常有的事.那么,在Java语言开发中,如何将图像转换为PDF呢? Spire.PDF for Java支持将多种图像格式(例如 ...
- python数据生成pdf,Python生成pdf文件的方法
摘要:这篇Python开发技术栏目下的"Python生成pdf文件的方法",介绍的技术点是"python生成pdf文件.python生成pdf.生成pdf文件.Pytho ...
- PDF Expert使用教程:如何在Mac上使用PDF Expert编辑PDF
PDF Expert 是专为 Mac 而设计的 PDF 编辑应用,易用,强大.其界面简洁.人性,恰似它的 iOS 版本.PDF 即按即开,无论是小得像邮件附件,还是多得像 2000 多页的报告. 视频 ...
- PHP利用FPDI 制作PDF 档案 (php合并pdf, php签名pdf)
昨天研究如何在既有的PDF 档案上放入中文字,虽然找到支援中文的FPDF ,但是有些Unicode 字集我实在试不出如何显示(如:堃) . 我的同事建议我用图形来解决看看,以下就是我的实验过程(我用的 ...
最新文章
- 关于全国大学生智能汽车竞赛有关问题的建议
- 多个旅游网站被挂马 五一假期外出旅游应小心
- 前端学习(2755):配置tabber其他属性
- c++基础学习(08)--(继承、重载、多态、虚函数)
- Linux查看网卡带宽
- linux ssh非交互脚本,sshpass-Linux命令之非交互SSH
- Android底部菜单栏的两种实现方式 附完整源码
- 如何把图纸转换为t3格式_怎么把图纸转换成t3格式
- ①ESP8266-wifi模块使用方法
- Windows查找文件内容
- Aho-Corasick 算法
- 阿里巴巴校招实习面试
- 对闰年和平年计算均值
- VmWare16 安装图解
- Chino with Triangle ( 西工大程序设计创新实践基地春季选拔赛)树形dp
- 不看绝对血亏!mysql下载安装教程win10
- 华为云与阿里云那个好
- 为什么CAD输入文字时文字特别大但输入后就消失了?
- DDC EDID 介绍
- redis数据结构--hyperloglog
热门文章
- [CF592D]Super M
- (转载)Xcode 4.1/4.2/4.3 免证书(iDP)开发+真机调试+生成IPA全攻略
- 比特率 波特率 带宽与容量
- Java多线程实现-线程池
- 练习题|python常用模块
- C和指针 第十六章 标准函数库 本地跳转setjmp.h
- 关于代码整理重构小记
- 人人都能学会的python编程教程4:关系运算符与循环
- JavaWeb01-HTML篇笔记(一)
- 《树莓派Python编程入门与实战(第2版)》——2.2 使用Raspbian命令行