The Spark of Thinking

Focus on Eclipse Tools.

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  3 随笔 :: 27 文章 :: 4 评论 :: 0 Trackbacks

现象

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

 

posted on 2006-07-24 10:31 The Spark of Thinking 阅读(1761) 评论(0)  编辑  收藏

只有注册用户登录后才能发表评论。


网站导航: