org.xhtmlrenderer
flying-saucer-pdf-itext5
9.0.3
2、重写Breaker.java文件,用于中文换行
新建org.xhtmlrenderer.layout文件夹,新建一个java文件,将以下内容粘贴进去
package org.xhtmlrenderer.layout;
* Breaker.java
* 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) {
} else {
break;
if (i < text.length()) {
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;是为了中文代码换行。
1、core-renderer.jar该jar包修改过中文不换行问题
public static String getConversionHtmlCode(String linkcss,String htmlCode,String title){
String css = "";
css +="<style>";
css +="table{";
css +=" border-collapse: collapse;";
css +=" font-size: 15px;";
css +=" width: 98%;";
css +="}";
css +="";
css +="td{";
css +=" border: 1px solid #ddd;";
css +=" text-align: left;";
css +=" white-space: nowrap";
css +="}";
css +="th{";
css +=" border: 1px solid #ddd;";
css +=" text-align: left;";
css +="}";
css +="</style>";
String html = "<html><head>"+css+"</head><body margin:0;margin-top: 15px;margin-bottom: 15px; text-align: center; font-family:SimSun;\" >"+ title+""+ htmlCode + "</body></html>";
System.out.println("html:"+html);
return html;
本项目中就使用了iText库进行写的PDF文件到服务器,所以就没有写Flying Saucer库下的实例方法了。的HTIM字符串、也是直接上代码,简单易懂、相信大家都能看的懂得、对应的包一定要导入正确,否则会报错呦!不过需要注意的是,你在应用第三方库是,导包一定要导入正确,否则会有一些方法是无法使用的。Flying Saucer库下的可以看:2.1和2.2代码实例。iText库下的可以看:1.1和1.2代码实例。iText库下的可以看:1.3代码实例。的HTML的字符串时、我们直接上代码,简单易懂、
修改导出的ftl模板
在table中加入样式, 设置固定宽度,设置换行
CSS:width="800px" style="table-layout:fixed; word-wrap:break-word; word-break:break-all"
th加入样式style="text-align: center;width:10%;"
解决itext生成pdf文件时中文换行的问题,由于使用低版本的flying saucer,不支持中文换行,本文给出了在不更改jar包的前提下的,可实施的解决方案。问题描述之前的文章提到了笔者使用itext+f lying saucer+freemarker生成pdf的实现方案,项目中所有的报表功能早期都使用了这种方案,由于flying saucer的版本的jar包不支持中文字符的自动换行,之前的功...
在利用itext将html文件转化为pdf文件的过程中,需要适当的调整字体,下面介绍字体的使用样式:字体支持的样式 itext核心库中主要支持一下几个各种的字体文件:.AFM/.PFB/.TTF/.otf/.ttc/.wof 2. 利用DefaultFontProvider 只是支持 14 Standard Type 1 fonts and 12 fonts 主要字体...
首先,当然是找到能够解析PDF的完美组件,百度和谷歌不约而同的告诉我们。IText是王道。而目前开源的组件中,Itext的确是一个First Choice,如果各位单纯是做把图片转成PDF或者自己写了Velocity或者FreeMarker模板生成了HTML是非常推荐直接用Itext来进行的。
下面就是用Flying Saucer(xhtmlrendere)来实现的代码:
loading......
中文换行修改好后的jar:http://download.csdn.net/download/weixin_36795183/9983888
pdf.JS http://download.csdn.net/download/weixin_36795183/9983904
一:遇到的问题;
1、 中文不支持
2、 中文不换行
3、 如何显示
4、 不显示签章
二:生成(根据html字符串来生成pdf,方便我们的替换)
下边是应用itext进行编写的生成pdf代码(这里要支持中文需要导入相应的iTextAsia
iText7是一个Java库,用于生成PDF文档。iText7提供了从HTML到PDF的转换功能,可以通过以下步骤将HTML转换为PDF并解决中文乱码问题:
添加iText7依赖
在您的项目中添加以下依赖项:
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itex...