公司需求:HTML+CSS3(CSS样式是直接写在HTML文件当中)转换为PDF文件,并上传阿里云OSS供用户下载
。
本身这个需求并不难,功能做完后不管是PDF质量还是生成速度都还不错,其中也遇到某些CSS样式不支持的问题,都用其他支持的样式替代
接下来问题就出现了,文本中突然出现竖行文本CSS样式标签为:writing-mode,生成的PDF中文本并没有竖行显示,明显是itext解析时并不认识这个标签。
由于业务逻辑要求,不可采用控制文本区宽度强制文字换行和其他物理方式来实现,目前查了大量资料,所有在HTML转换PDF这个问题上,对CSS都不太友好。
后试过用Java调用虚拟打印机、先转word在转pdf、wkhtmltopdf、html2pdf等均没成功
总结来说当html中出现竖行文本时,转换PDF希望所见即所得。
现在求助有这方面经验的大神能给点解决思路,或者实现方式,小弟在此不胜感激,后面附上源码。
org.freemarker
freemarker
2.3.23
org.apache.pdfbox
pdfbox
2.0.2
org.xhtmlrenderer
flying-saucer-pdf-itext5
9.1.6
net.sf.jtidy
jtidy
r938
com.aliyun.oss
aliyun-sdk-oss
2.7.0
@Override
public void createPDF(HttpServletRequest request,String bookId) {
Book book = bookDao.get(bookId);
List
* html生成pdf
* @param ftlPath ftl模板目录路径
* @param ftlName ftl模板名称
* @param outputPath pdf输出路径
* @param outputName pdf输出名称
* @param htmlString html源码
* @param watermark 是否添加水印【true-添加、false=不添加】
* @return
public static boolean createPDF(String ftlPath,String ftlName,String outputPath,String outputName,String htmlString,boolean watermark) {
FileOutputStream os = null;
try {
// 创建一个freemarker.template.Configuration实例,它是存储 FreeMarker
Configuration cf = new Configuration(Configuration.VERSION_2_3_22); // 指定版本号
cf.setDirectoryForTemplateLoading(new File(ftlPath)); // 设置模板目录
cf.setDefaultEncoding("UTF-8"); // 设置默认编码格式
Template temp = cf.getTemplate(ftlName+".ftl"); // 从设置的目录中获得模板
// html转换为xhtml
ByteArrayInputStream inputStream = new ByteArrayInputStream(htmlString.getBytes("UTF-8"));
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
// 使用jtidy解析
Tidy tidy = new Tidy(); // 实例化Tidy对象
tidy.setInputEncoding("UTF-8"); // 设置输入
tidy.setQuiet(false); // 如果是true 不输出注释,警告和错误信息
tidy.setShowWarnings(false); // 不显示警告信息
tidy.setIndentContent(false); // 缩进适当的标签内容。
tidy.setSmartIndent(false); // 内容缩进
tidy.setIndentAttributes(false);
tidy.setPrintBodyOnly(true); // 只输出body内部的内容
tidy.setWraplen(1024); // 多长换行
tidy.setXHTML(true); // 输出为xhtml
tidy.setTrimEmptyElements(false); // 不输出空元素
tidy.setMakeClean(false); // 去掉没用的标签
tidy.setWord2000(false); // 清洗word2000的内容
tidy.setErrout(new PrintWriter(System.out)); // 设置错误输出信息
tidy.parse(inputStream, outputStream);
// 从模板生成html文件
String fileHtml = "hzSur.html";
File file = new File(fileHtml);
if (!file.exists()) {
file.createNewFile();
}
// 是否构造水印模板
String htmlWatermark = "";
if(watermark) {
htmlWatermark = "";
for (int i = 0; i < 10; i++) {
htmlWatermark += "";
}
htmlWatermark +="";
}
// 将数据写入模板
Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file),"UTF-8"));
Map product = new HashMap();
product.put("htmlWatermark", htmlWatermark);
product.put("htmlString", outputStream.toString());
temp.process(product, out);
out.close();
// 定义输出目录路径及文件名称
File outDir =new File(outputPath);
outDir.mkdirs();
ITextRenderer renderer = new ITextRenderer();
os = new FileOutputStream(outputPath+"/"+outputName+".pdf");
renderer.setDocument(new File(fileHtml).toURI().toURL().toString());
// 获取中文字体
ITextFontResolver fontResolver = renderer.getFontResolver();
fontResolver.addFont(ftlPath+"/MSYH.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
fontResolver.addFont(ftlPath+"/SIMSUN.TTC", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
fontResolver.addFont(ftlPath+"/SIMSUN.TTC", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
fontResolver.addFont(ftlPath+"/STKAITI.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
fontResolver.addFont(ftlPath+"/SIMLI.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
fontResolver.addFont(ftlPath+"/simfang.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
fontResolver.addFont(ftlPath+"/FZSTK.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
fontResolver.addFont(ftlPath+"/FZYTK.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
fontResolver.addFont(ftlPath+"/simhei.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
fontResolver.addFont(ftlPath+"/SIMYOU.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
// 输出
renderer.layout();
renderer.createPDF(os);
renderer.finishPDF();
renderer = null;
os.close();
return true;
} catch (Exception e) {
System.out.println(e);
e.printStackTrace();
return false;
}
}