itextpdf将html转成pdf,包含中文字体以及中文换行

    技术2022-07-14  65

    1、maven文件下载

        <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>

    2、重写Breaker.java文件,用于中文换行

          新建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;是为了中文代码换行。

    Processed: 0.009, SQL: 9