Java解決Itext pdf中文不顯示問題

JJXI11發表於2016-04-29
最近在專案需要,需要將html內容轉換成pdf的檔案,採用itextpdf總是不顯示中文。
找了很多方法都沒搞定,然後在網上看到了有個帖子說改原始碼解決這個問題,但是經過測試還是沒有搞定。
並且個人不建議改原始碼,然後自己研究原始碼,借鑑了他的思路,可以不用改原始碼即可解決中文問題。

第一部:
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>

相關文章