<dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.9</version> </dependency> <dependency> <groupId>com.itextpdf.tool</groupId> <artifactId>xmlworker</artifactId> <version>5.5.9</version> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext-asian</artifactId> <version>5.2.0</version> </dependency> <dependency> <groupId>org.xhtmlrenderer</groupId> <artifactId>flying-saucer-pdf-itext5</artifactId> <version>9.0.3</version> </dependency>
新建org.xhtmlrenderer.layout文件夹,新建一个java文件,将以下内容粘贴进去
package org.xhtmlrenderer.layout;
/* * Breaker.java * Copyright (c) 2004, 2005 Torbj�rn Gannholm, * Copyright (c) 2005 Wisconsin Court System * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ import org.xhtmlrenderer.css.constants.IdentValue; import org.xhtmlrenderer.css.style.CalculatedStyle; import org.xhtmlrenderer.render.FSFont; /** * A utility class that scans the text of a single inline box, looking for the * next break point. * @author Torbj�rn Gannholm */ public class Breaker { public static void breakFirstLetter(LayoutContext c, LineBreakContext context, int avail, CalculatedStyle style) { FSFont font = style.getFSFont(c); context.setEnd(getFirstLetterEnd(context.getMaster(), context.getStart())); context.setWidth(c.getTextRenderer().getWidth( c.getFontContext(), font, context.getCalculatedSubstring())); if (context.getWidth() > avail) { context.setNeedsNewLine(true); context.setUnbreakable(true); } } private static int getFirstLetterEnd(String text, int start) { int i = start; while (i < text.length()) { char c = text.charAt(i); int type = Character.getType(c); if (type == Character.START_PUNCTUATION || type == Character.END_PUNCTUATION || type == Character.INITIAL_QUOTE_PUNCTUATION || type == Character.FINAL_QUOTE_PUNCTUATION || type == Character.OTHER_PUNCTUATION) { i++; } else { break; } } if (i < text.length()) { i++; } return i; } public static void breakText(LayoutContext c, LineBreakContext context, int avail, CalculatedStyle style) { FSFont font = style.getFSFont(c); IdentValue whitespace = style.getWhitespace(); // ====== handle nowrap if (whitespace == IdentValue.NOWRAP) { context.setEnd(context.getLast()); context.setWidth(c.getTextRenderer().getWidth( c.getFontContext(), font, context.getCalculatedSubstring())); return; } //check if we should break on the next newline if (whitespace == IdentValue.PRE || whitespace == IdentValue.PRE_WRAP || whitespace == IdentValue.PRE_LINE) { int n = context.getStartSubstring().indexOf(WhitespaceStripper.EOL); if (n > -1) { context.setEnd(context.getStart() + n + 1); context.setWidth(c.getTextRenderer().getWidth( c.getFontContext(), font, context.getCalculatedSubstring())); context.setNeedsNewLine(true); context.setEndsOnNL(true); } else if (whitespace == IdentValue.PRE) { context.setEnd(context.getLast()); context.setWidth(c.getTextRenderer().getWidth( c.getFontContext(), font, context.getCalculatedSubstring())); } } //check if we may wrap if (whitespace == IdentValue.PRE || (context.isNeedsNewLine() && context.getWidth() <= avail)) { return; } context.setEndsOnNL(false); String currentString = context.getStartSubstring(); int left = 0; // int right = currentString.indexOf(WhitespaceStripper.SPACE, left + 1); int right = getStrRight(currentString,left); int lastWrap = 0; int graphicsLength = 0; int lastGraphicsLength = 0; while (right > 0 && graphicsLength <= avail) { lastGraphicsLength = graphicsLength; graphicsLength += c.getTextRenderer().getWidth( c.getFontContext(), font, currentString.substring(left, right)); lastWrap = left; left = right; // right = currentString.indexOf(WhitespaceStripper.SPACE, left + 1); right = getStrRight(currentString,left+1); } if (graphicsLength <= avail) { //try for the last bit too! lastWrap = left; lastGraphicsLength = graphicsLength; graphicsLength += c.getTextRenderer().getWidth( c.getFontContext(), font, currentString.substring(left)); } if (graphicsLength <= avail) { context.setWidth(graphicsLength); context.setEnd(context.getMaster().length()); //It fit! return; } context.setNeedsNewLine(true); if (lastWrap != 0) {//found a place to wrap context.setEnd(context.getStart() + lastWrap); context.setWidth(lastGraphicsLength); } else {//unbreakable string if (left == 0) { left = currentString.length(); } context.setEnd(context.getStart() + left); context.setUnbreakable(true); if (left == currentString.length()) { context.setWidth(c.getTextRenderer().getWidth( c.getFontContext(), font, context.getCalculatedSubstring())); } else { context.setWidth(graphicsLength); } } return; } private static boolean isChinese(char c) { Character.UnicodeBlock ub = Character.UnicodeBlock.of(c); if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) { return true; } return false; } private static int getStrRight(String s,int left){ if(left>=s.length()) return -1; char[] ch = s.toCharArray(); for(int i = left;i<ch.length;i++){ if(isChinese(ch[i]) || ' ' == ch[i]){ return i==0?i+1:i; } } return -1; } }
3、html转换pdf代码
/** * 文件格式转换工具类 * * @author lz * * 2020-07-01 上午10:52:22 */ public class FileTypeConvertUtil {
/** * 将HTML转成PD格式的文件。html文件的格式比较严格 * @param htmlFile * @param pdfFile * @throws Exception */ public static void html2pdf(String content, String pdfFile) throws Exception { OutputStream os = new FileOutputStream(pdfFile); ITextRenderer renderer = new ITextRenderer(); StringBuffer html = new StringBuffer(); content = content.replace("宋体", "SimSun"); content = content.replace("黑体", "SimHei"); content = content.replace("微软雅黑", "Microsoft YaHei"); content = content.replace("微软正黑体", "Microsoft JhengHei"); content = content.replace("新宋体", "NSimSun"); content = content.replace("仿宋", "FangSong"); content = content.replace("楷体", "KaiTi"); content = content.replace("仿宋_GB2312", "FangSong_GB2312"); content = content.replace("楷体_GB2312", "KaiTi_GB2312"); content = content.replace("font-family:"", "font-family:SimSun;"); content = content.replace("font-family:""", "font-family:SimSun;"); // DOCTYPE 必需写否则类似于 这样的字符解析会出现错误 html.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"); html.append("<html xmlns=\"http://www.w3.org/1999/xhtml\">").append("<head>") .append("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />") .append("<meta name=\"viewport\" content=\"initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width\"/>") .append("<link rel=\"stylesheet\" href=\"https://static.loyalvalleycapital.com/web/css/frame.css\"/>") .append("<style type=\"text/css\" mce_bogus=\"1\">" + "body {font-family: 宋体;} " + "table { border-collapse: collapse; table-layout: fixed;word-break:break-strict;font-size: 10px; width: 100%;text-align: center;widths:\"50;10;40\"}" + "td {word-break:break-all;word-wrap : break-word; } " + "@page { size:210mm 297mm;margin: 0.25in; -fs-flow-bottom: \"footer\"; -fs-flow-left: \"left\"; -fs-flow-right: \"right\"; padding: 1em; } " + "#footer { font-size: 90%; font-style: italic; position: absolute; top: 0; left: 0; -fs-move-to-flow: \"footer\"; } " + "#pagenumber:before { content: counter(page); } #pagecount:before {content: counter(pages); }</style>") .append("</head>") .append("<body style = \"font-family: SimSun;\">" + "<div style=\"width: 700px;\"><div id=\"footer\" style=\"\"> Page <span id=\"pagenumber\"/> of <span id=\"pagecount\"/> </div>") .append("<div class='inner' style='width:698px;overflow-x:auto;font-size:14px;color:#333;font-family:微软雅黑;line-height:2;'>"); html.append("<div>"+content+"</div></div></div>"); html.append("</body></html>");
renderer.setDocumentFromString(html.toString());
ITextFontResolver fontResolver = renderer.getFontResolver(); if("linux".equals(getCurrentOperatingSystem())){ fontResolver.addFont("/usr/share/fonts/chiness/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.EMBEDDED); }else{ fontResolver.addFont("C:/Windows/Fonts/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); fontResolver.addFont("C:/Windows/Fonts/simfang.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); fontResolver.addFont("C:/Windows/Fonts/simhei.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); fontResolver.addFont("C:/Windows/Fonts/msyh.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); fontResolver.addFont("C:/Windows/Fonts/msyhbd.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); fontResolver.addFont("C:/Windows/Fonts/simkai.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); fontResolver.addFont("C:/Windows/Fonts/STKAITI.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); fontResolver.addFont("C:/Windows/Fonts/STLITI.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); fontResolver.addFont("C:/Windows/Fonts/仿宋_GB2312.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); fontResolver.addFont("C:/Windows/Fonts/楷体_GB2312.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); }
renderer.layout(); renderer.createPDF(os); os.close();
System.out.println("create pdf done!!");
}
public static String getCurrentOperatingSystem(){ String os = System.getProperty("os.name").toLowerCase(); System.out.println("---------当前操作系统是-----------" + os); return os; }
public static void main(String[] args) { String content = "html内容"; String pdfFile = "d:/testoone.pdf"; try { FileTypeConvertUtil.html2pdf(content, pdfFile); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } }
备注:html里面需要添加上一下代码
html.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"); html.append("<html xmlns=\"http://www.w3.org/1999/xhtml\">").append("<head>") .append("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />")
table的样式需要添加table-layout: fixed;word-break:break-strict;是为了中文代码换行。