現象
默認安裝的Confluence在使用導出pdf時,如果頁面包含有非英文字符,例如中文,日文,韓文等,相應位置就會出現#字符.
分析
通過查看Confluence的相關文件,可以了解到Confluence是使用FOP(http://xmlgraphics.apache.org/fop/)來輸出pdf文件的,使用的是FOP Version 0.20.5.
FOP 0.20.5功能相對還是比較弱,例如
? 1.不支持多種字體的組合,也就是不支持font-family="sans-serif,宋體"這種方式,
? ?結果就是每段都要指定,否則就只能用一種了,對于confluence來說就很不好了...
? ?
? 2.不支持程序處理斜體,黑體,這樣就要求字體支持黑體,斜體才能實現黑體斜體的效果.
??? 結果就是中文字體都沒有黑體,斜體,無法直接實現中文的黑體,斜體了
???
???
???
我們再看看Confluence的導出功能,Confluence的導出功能是在WEB-INF\classes\importExportSubsystemContext.xml里面定義的,
<bean id="pdfExporter" class="com.atlassian.confluence.importexport.impl.PdfExporter" singleton="false"> |
??
通過
查看PdfExporter這個文件,我們可以了解,Confluence是把字體配置信息寫在了類里面,外部無法直接配置.Confluence的字體配置是使用了Verdana,Verdana字體有四種方式:普通,黑體,斜體,黑體+斜體,這是一種英文的字體,支持英文是沒問題的,但是無法支持中文.
通過查看程序,我們還可以知道Confluence是通過固定的fo模板導出pdf的,模板分別為:WEB-INF\classes\com\atlassian\confluence\pages\Page.pdfexport.vm,Page-hierarchy.pdfexport.vm,Space.pdfexport.vm,通過查看這些模板文件,我們可以看到:
?<fo:flow flow-name="xsl-region-body" font-family="Verdana" font-size="11pt" text-align="justify"> |
?
類似的語句,也就是說Confluence默認使用這個字體輸出pdf文件.
不完美的解決方案
因為Verdana?不支持中文,所以我們必須修改這些處理,下面的解決的方案雖然不是完美的,但是也部分解決了導出pdf的問題.
方案缺點:
?1.不支持多語言,例如對日文,韓文等的支持:期待FOP支持字體組合,或者Confluence支持字體配置
?2.使用固定字體,例如宋體:期望Confluence支持字體配置
?3.不能支持黑體,斜體(變通方法:通過使用黑體代替宋體的黑體,可以支持黑體) :期望有中文字體支持黑體,斜體,或者FOP內部提供支持
?4.英文的黑體,斜體也和中文一樣了:bold使用黑體,斜體不支持了.
?
方案步驟:
1.下載FOP 0.20.5,解壓,閱讀文檔
2.使用FOP的ttfreader生成字體的xml文件,例如微軟提供的宋體,黑體,或者你喜歡的其他字體,以下均已宋體和黑體為例
?
? 注意:FOP自帶的Xalan 2.4.1版本在windows下運行生成xml文件時有點問題,換為confluence自帶的2.7.0問題消失.
?
? 把fop.bat復制為ttfreader.bat,修改文件最后一行為:
java -cp "%LOCALCLASSPATH%" org.apache.fop.fonts.apps.TTFReader %1 %2 %3 %4 %5 %6 %7 %8? |
?并且把xalan的jar改為2.7.0的jar.
?
? 或者直接使用命令行方式也可,自己拼接吧.
?
? ttfreader -ttcname "SimSun" C:\WINNT\Fonts\simsun.ttc simsun.xml????????
? ttfreader C:\WINNT\Fonts\simhei.ttf simhei.xml???????????????????????????????????????
生成了2個字體的文件,把xml文件和2個字體文件復制到confluence的WEB-INF\classes\fonts目錄下.
3.修改PdfExporter
?為了簡單,我們使用繼承的方法生成一個新的類,例如:
package com.jscud.confluence.importexport.impl; import java.util.ArrayList; import java.util.List; import org.apache.fop.configuration.*;
import com.atlassian.confluence.importexport.impl.PdfExporter; public class ScudPdfExporter extends PdfExporter {
??? public ScudPdfExporter() ??? { ??????? List fonts = new ArrayList(); ??????? CustomFontInfo font_info = new CustomFontInfo(null, "fonts/verdana.xml", true, createFontTriplets( ??????????????????????? "Verdana", "normal", "normal"), "fonts/verdana.ttf"); ??????? fonts.add(font_info); ??????? font_info = new CustomFontInfo(null, "fonts/verdanab.xml", true, createFontTriplets("Verdana", ??????????????????????? "bold", "normal"), "fonts/verdanab.ttf"); ??????? fonts.add(font_info); ??????? font_info = new CustomFontInfo(null, "fonts/verdanai.xml", true, createFontTriplets("Verdana", ??????????????????????? "normal", "italic"), "fonts/verdanai.ttf"); ??????? fonts.add(font_info); ??????? font_info = new CustomFontInfo(null, "fonts/verdanaz.xml", true, createFontTriplets("Verdana", ??????????????????????? "bold", "italic"), "fonts/verdanaz.ttf"); ??????? fonts.add(font_info); ??????? ??????? font_info = new CustomFontInfo(null, "fonts/simsun.xml", true, createFontTriplets("SimSun","normal","normal"), ??????????????????????? "fonts/simsun.ttc"); ??????? fonts.add(font_info); ??????? ??????? font_info = new CustomFontInfo(null, "fonts/simhei.xml", true, createFontTriplets("SimSun", ??????????????????????? "bold", "normal"), "fonts/simhei.ttf"); ??????? fonts.add(font_info); ??????? font_info = new CustomFontInfo(null, "fonts/simsun.xml", true, createFontTriplets("SimSun","normal","italic"), ??????? "fonts/simsun.ttc"); ??????? ??????? fonts.add(font_info); ??????? ??????? font_info = new CustomFontInfo(null, "fonts/simhei.xml", true, createFontTriplets("SimSun", ??????????????????????? "bold", "italic"), "fonts/simhei.ttf"); ??????? fonts.add(font_info); ??????? Configuration.put("fonts", fonts, 0); ??????? ??????? ??? } ??? private List createFontTriplets(String name, String weight, String style) ??? { ??????? List triplets = new ArrayList(); ??????? triplets.add(new FontTriplet(name, weight, style)); ??????? return triplets; ??? } ??? ??? /** ???? * create font Triplets. ???? * ???? * main for chinese font ,not had bold,italic support. ???? * ???? * @param name font name ???? * @return font triplets ???? */ ??? protected List createScudFontTriplets(String name) ??? { ??????? List triplets = new ArrayList(); ??????? triplets.add(new FontTriplet(name, "normal","normal")); ??????? triplets.add(new FontTriplet(name, "bold","normal")); ??????? triplets.add(new FontTriplet(name, "normal","italic")); ??????? triplets.add(new FontTriplet(name, "bold","italic")); ??????? return triplets; ??? } } |
?
編譯此類,并把類復制到Confluence的對應目錄下.
?
然后修改前面提到的importExportSubsystemContext.xml,修改對應的一行為
<bean id="pdfExporter" class="com.jscud.confluence.importexport.impl.ScudPdfExporter" singleton="false"> |
(再次體會到依賴注射的好處啊)
4.修改前面提到的模板文件的字體設置
<fo:flow flow-name="xsl-region-body" font-family="Verdana" font-size="11pt" text-align="justify">
改為
<fo:flow flow-name="xsl-region-body" font-family="SimSun" font-size="11pt" text-align="justify">
?
注意:模板文件中還有一些地方的字體設置要改,自己挖掘吧,不改的話,可能會出現###哦
?
5.修正生成pdf時的中文換行問題
? 我們還需要修改模板文件里面的:
? <fo:page-sequence master-reference="all-pages">
? 改為
? <fo:page-sequence master-reference="all-pages" language="zh">
?
? 這樣中文文字換行就沒問題了
?
?
6.重啟web application
? 試試導出pdf,看到中文了吧
?
?
說明
? 1.本人第一次接觸FOP,感覺是個好東西,不過非常不了解,也許相對上面提到的方法還有更好的方法來解決,如果你知道,請不吝指教.
? 2.Confluence的國際化還有很長的路要走,不過我也沒怎么研究過...沒源碼就是不好研究
?