现象
默认安装的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的国际化还有很长的路要走,不过我也没怎么研究过...没源码就是不好研究