找了很多方法都没搞定,然后在网上看到了有个帖子说改源码解决这个问题,但是经过测试还是没有搞定。
并且个人不建议改源码,然后自己研究源码,借鉴了他的思路,可以不用改源码即可解决中文问题。
第一部:
maven 引入依赖的jar包
<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>
根据ChunkCssApplier重写apply方法
@SuppressWarnings("deprecation") public class MyChunkCssApplier extends ChunkCssApplier { public static BaseFont chinessFont = null; static { try { // 中文支持,需要引入 itext-asian.jar chinessFont = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); } catch (Exception e) { e.printStackTrace(); } } /** * 判断是否存在中文 * @param str * @return */ private static boolean isChinese(String str){ if(str == null ){ return false; } //存在中文 String regex = ".*[\\u4e00-\\u9faf].*"; return Pattern.matches(regex, str); } /** * * 重写apply方法 */ @Override public Chunk apply(Chunk c, Tag t) { Font f = applyFontStyles(t); // 增加此段代码 如果中文 ,则返回中文字体 if (null != chinessFont && isChinese(c.getContent())) { f = new Font(chinessFont, f.getSize(), f.getStyle(), f.getColor()); } // 下面代码从源码中copy float size = f.getSize(); Map<String, String> rules = t.getCSS(); for (Entry<String, String> entry : rules.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); if (CSS.Property.FONT_STYLE.equalsIgnoreCase(key)) { if (value.equalsIgnoreCase(CSS.Value.OBLIQUE)) { c.setSkew(0, 12); } } else if (CSS.Property.LETTER_SPACING.equalsIgnoreCase(key)) { String letterSpacing = rules.get(CSS.Property.LETTER_SPACING); float letterSpacingValue = 0f; if (utils.isRelativeValue(value)) { letterSpacingValue = utils.parseRelativeValue(letterSpacing, f.getSize()); } else if (utils.isMetricValue(value)){ letterSpacingValue = utils.parsePxInCmMmPcToPt(letterSpacing); } c.setCharacterSpacing(letterSpacingValue); } else if (null != rules.get(CSS.Property.XFA_FONT_HORIZONTAL_SCALE)) { // only % allowed; need a catch block NumberFormatExc? c.setHorizontalScaling(Float.parseFloat(rules.get(CSS.Property.XFA_FONT_HORIZONTAL_SCALE).replace("%", "")) / 100); } } // following styles are separate from the for each loop, because they are based on font settings like size. if (null != rules.get(CSS.Property.VERTICAL_ALIGN)) { String value = rules.get(CSS.Property.VERTICAL_ALIGN); if (value.equalsIgnoreCase(CSS.Value.SUPER) || value.equalsIgnoreCase(CSS.Value.TOP) || value.equalsIgnoreCase(CSS.Value.TEXT_TOP)) { c.setTextRise((float) (size / 2 + 0.5)); } else if (value.equalsIgnoreCase(CSS.Value.SUB) || value.equalsIgnoreCase(CSS.Value.BOTTOM) || value.equalsIgnoreCase(CSS.Value.TEXT_BOTTOM)) { c.setTextRise(-size / 2); } else { c.setTextRise(utils.parsePxInCmMmPcToPt(value)); } } String xfaVertScale = rules.get(CSS.Property.XFA_FONT_VERTICAL_SCALE); if (null != xfaVertScale) { if (xfaVertScale.contains("%")) { size *= Float.parseFloat(xfaVertScale.replace("%", "")) / 100; c.setHorizontalScaling(100 / Float.parseFloat(xfaVertScale.replace("%", ""))); } } if (null != rules.get(CSS.Property.TEXT_DECORATION)) { String[] splitValues = rules.get(CSS.Property.TEXT_DECORATION).split("\\s+"); for (String value : splitValues) { if (CSS.Value.UNDERLINE.equalsIgnoreCase(value)) { c.setUnderline(null, 0.75f, 0, 0, -0.125f, PdfContentByte.LINE_CAP_BUTT); } if (CSS.Value.LINE_THROUGH.equalsIgnoreCase(value)) { c.setUnderline(null, 0.75f, 0, 0, 0.25f, PdfContentByte.LINE_CAP_BUTT); } } } if (null != rules.get(CSS.Property.BACKGROUND_COLOR)) { c.setBackground(HtmlUtilities.decodeColor(rules.get(CSS.Property.BACKGROUND_COLOR))); } f.setSize(size); c.setFont(f); Float leading = null; if(rules.get(CSS.Property.LINE_HEIGHT) != null) { String value = rules.get(CSS.Property.LINE_HEIGHT); if(utils.isNumericValue(value)) { leading = Float.parseFloat(value) * c.getFont().getSize(); } else if (utils.isRelativeValue(value)) { leading = utils.parseRelativeValue(value, c.getFont().getSize()); } else if (utils.isMetricValue(value)){ leading = utils.parsePxInCmMmPcToPt(value); } } if (leading != null) { c.setLineHeight(leading); } return c; } }
新增一个ParserHTML.java
/** * Hello world! * */ public class ParserHTML { public static final String HTML = "D:/test/hero.html"; public static final String DEST = "D:/test/hero.pdf"; // public static final String HTML = "resources/xml/hero2.html"; // public static final String DEST = "results/xmlworker/asian2.pdf"; /** * Creates a PDF with the words "Hello World" * @param file * @throws IOException * @throws DocumentException */ public void createPdf(String file) throws IOException, DocumentException { // step 1 Document document = new Document(); // step 2 PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file)); // step 3 document.open(); // step 4 // CSS CSSResolver cssResolver = new StyleAttrCSSResolver(); CssFile cssFile = XMLWorkerHelper.getCSS(new ByteArrayInputStream("body {font-family:tsc fming s tt}".getBytes())); cssResolver.addCss(cssFile); // 将ChunkCssApplier 设置为自定义的 CssAppliers cssAppliers = new CssAppliersImpl(); cssAppliers.setChunkCssAplier(new MyChunkCssApplier()); HtmlPipelineContext htmlContext = new HtmlPipelineContext(cssAppliers); htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory()); // Pipelines PdfWriterPipeline pdf = new PdfWriterPipeline(document, writer); HtmlPipeline html = new HtmlPipeline(htmlContext, pdf); CssResolverPipeline css = new CssResolverPipeline(cssResolver, html); // XML Worker XMLWorker worker = new XMLWorker(css, true); XMLParser p = new XMLParser(worker); p.parse(new FileInputStream(HTML), Charset.forName("UTF-8")); // step 5 document.close(); } /** * Main method */ public static void main(String[] args) throws IOException, DocumentException { File file = new File(DEST); file.getParentFile().mkdirs(); new ParserHTML().createPdf(DEST); } }
模板 hero.html
<p><span style="font-size:12.0pt; font-family:MS Mincho; color:red">長空abc</span> <span style="font-size:12.0pt; font-family:Times New Roman,serif">(Broken Sword),</span> <span style="font-size:12.0pt; font-family:MS Mincho">秦王殘劍</span> <span style="font-size:12.0pt; font-family:Times New Roman,serif">(Flying Snow),</span> <span style="font-size:12.0pt; font-family:MS Mincho">飛雪</span> <span style="font-size:12.0pt; font-family:Times New Roman,serif">(Moon), </span> <span style="font-size:12.0pt; font-family:MS Mincho">如月</span> <span style="font-size:12.0pt; font-family:Times New Roman,serif">(the King), and</span> <span style="font-size:12.0pt; font-family:MS Mincho">秦王</span> <span style="font-size:12.0pt; font-family:Times New Roman,serif">(Sky).</span></p>