c.gif 如何在程序中嵌入FOP c.gif c.gif
c.gif
c.gif
c.gif
c.gif
c.gif
内容:
c.gif
FOP使用方式
介绍
参考资料
关于作者
c.gif
c.gif

FOP 简介

马 路 (stevema@263.net)
2001 年 11 月

如何在程序中嵌入FOP?FOP是由James Tauber发起的一个开源项目,最初的目的是利用xsl-fo将xml文件转换成pdf文件。目前最新的版本是2001年9月29日发布的0.20.2,它可以将xml文件转换成pdf,mif,pcl,txt等多种格式以及直接输出到打印机,并且支持使用SVG描述图形。XML显然是最好的内容存储格式,而PDF是目前最流行的内容载体格式,FOP显然希望借助这种必然的XML to PDF需求,来推动xsl-fo规范的发展。虽然xsl-fo规范停滞不前,但利用FOP能使自己的程序具有将XML内容输出成PDF等流行格式的功能无疑是令人兴奋的。

FOP使用方式
FOP有3种使用方式,分别为命令行,程序嵌入,XT 嵌入,这里将主要介绍如何在程序中嵌入FOP功能。将XML文件转换为PDF实际上分为2步,第1步是利用XSLT将XML转换为XSL-FO,第2步是将XSL-FO转换为PDF。这里不想讲述XSLT和XSL-FO有关的知识(这方面的文档相当多),而只将讲述如何进行第2步的转换编程。

在程序中嵌入FOP
1. 范例simple.fo文件

<?xml version="1.0" encoding="utf-8"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"><fo:layout-master-set><fo:simple-page-master master-name="simple"page-height="29.7cm" page-width="21cm"margin-top="1cm" margin-bottom="2cm" margin-left="2.5cm" margin-right="2.5cm"><fo:region-body margin-top="3cm"/><fo:region-before extent="3cm"/><fo:region-after extent="1.5cm"/></fo:simple-page-master></fo:layout-master-set><fo:page-sequence master-name="simple"><fo:flow flow-name="xsl-region-body"><!-- Title --><fo:block font-size="18pt" font-family="sans-serif" line-height="24pt"space-after.optimum="15pt"background-color="blue"color="white"text-align="center"padding-top="3pt">FOP 0.20.2</fo:block><!-- Normal Text --><fo:block font-size="12pt" font-family="sans-serif" line-height="15pt"space-after.optimum="3pt"text-align="justify">
FOP is the world's first print formatter driven by XSL formatting objects.
It is a Java application that reads a formatting object tree and then turns it into a PDF document.</fo:block></fo:flow></fo:page-sequence>
</fo:root>

上述是一个很简单的fo文件,将显示两块文字,具体的fo语法请读者自己查看相应资料。

2. 简单调用FOP
FOP提供的所有对外调用接口都在org.apache.fop.apps下,其下的AWTStarter.class是一个用AWT写的转换结果预览程序,CommandLineStarter.class提供命令行使用方式,PrintStarter.class提供打印接口,XTDriver.class提供XT嵌入方式接口,Driver.class则是我们要在这里讨论的程序接口。下面这个程序foptest.java演示了FOP的最简单也是最常用的使用方式。

import java.io.*;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.apache.fop.apps.*;public class foptest {public static void main(String[] args) {try {Driver driver = new Driver();//设置要转换的fo文件名driver.setInputSource(new InputSource (args[0]));//设置输出文件名driver.setOutputStream(new FileOutputStream(args[1]));//设置转换类型//还可以为RENDER_PCL,RENDER_PS,RENDER_TXT,RENDER_MIFdriver.setRenderer(Driver.RENDER_PDF);//开始转换driver.run();}catch( Exception e ){e.printStackTrace();}}
}

上述程序将接受两个命令行参数,第一个参数是需要转换的fo文件名,第二个参数是输出文件名。在CLASSPATH中添加下述jar文件:
{FOP安装目录}\build\fop.jar
{FOP安装目录}\lib\batik.jar
{FOP安装目录}\lib\xalan-2.0.0.jar
{FOP安装目录}\lib\xerces-1.2.3.jar
{FOP安装目录}\lib\avalon-framework-4.0.jar
{FOP安装目录}\lib\logkit-1.0b4.jar
{FOP安装目录}\lib\jimi-1.0.jar
然后执行java foptest simple.fo simple.pdf

执行后产生的simple.pdf文件效果如下

fig1.gif

3. 显示中文
上面的演示程序段可以应付绝大部分转换编程的需要,不过对于国内用户来说,不可避免的需要产生中文PDF文件,让我们把上述simple.fo的标题从"FOP 0.20.2"改成"支持中文的FOP 0.20.2",不改动程序的情况下执行结果显示如下

fig2.gif

可以看到由于没有加入相应的字体支持,汉字被显示成了#。

东方字符的显示在FOP的早期版本中并不被支持,最早尝试对FOP打补丁以解决显示东方字符的是日本人。从FOP 0.16版本开始,他们在sourceforge上建立了一个jpfop项目来解决日文字符的显示问题,使用相同的方法也可以被用来显示中文字符。幸运的是,当前的FOP版本已经能很好的解决中文显示的问题,不再需要我们打补丁,下面是在FOP中使用中文的步骤:

  • 第一步,建立font metrics文件对于后缀为ttf的TrueType字体文件,我们可以执行以下命令来产生font metrics文件
    java org.apache.fop.fonts.apps.TTFReader C:\WINNT\Fonts\simkai.ttf simkai.xml
    这里simkai.xml就是我们为楷体产生的font metrics文件。
    对于Windows下的宋体来说,存在的是后缀为ttc的TrueType Collection文件,即包含多个TrueType的文件,这时首先要做的是得到这个Collection中所有TrueType的名字,执行以下命令(这个命令其实有错误):
    java org.apache.fop.fonts.apps.TTFReader C:\WINNT\Fonts\simsun.ttc simsun.xml

    产生输出如下:

    This is a TrueType collection file with2 fonts
    Containing the following fonts:
    SimSun
    NSimSun
    java.io.IOException: Failed to read fontat org.apache.fop.fonts.TTFFile.readFont(TTFFile.java:388)at org.apache.fop.fonts.apps.TTFReader.loadTTF(TTFReader.java:181)at org.apache.fop.fonts.apps.TTFReader.main(TTFReader.java:143)
    
    

    后面的异常是由于我们给的参数不对(因为ttc不是ttf字体文件)造成的,FOP开发小组知道这个问题,但是可能觉得无关痛痒而没去修正它。无论怎样,我们得到了我们要得到的结果,里面含的字体名为SimSun和NSimSun,通过以下命令为其中的SimSun字体产生font metrics文件:
    java org.apache.fop.fonts.apps.TTFReader -ttcname "SimSun" C:\WINNT\Fonts\simsun.ttc simsun.xml
    -ttcname后面指定需要从ttc文件中提取的字体名称

  • 第二步,登记上述字体

    在FOP主目录下的conf子目录下有一个userconfig.xml文件,为了方便,我们将它和上一步产生的simsun.xml,simkai.xml都拷贝到与我们的演示程序同一目录下。在userconfig.xml的最后几行有一个<fonts></fonts>标记区,我们在其中加入以下项:

    <font metrics-file="simsun.xml" kerning="yes" embed-file="c:\WINNT\fonts\simsun.ttc"><font-triplet name="mysimsun" style="normal" weight="normal"/></font><font metrics-file="simkai.xml" kerning="yes" embed-file="c:\WINNT\fonts\simkai.ttf"><font-triplet name="mysimkai" style="normal" weight="normal"/></font>
    
    

    其中metrics-file里可以设相对路径或绝对路径(因为我们这里在同一目录下,所以只需写文件名即可),font-triplet里的name可以自己自由设定,并不要求与字体名一样。设定这个名字后,在fo里就只能通过这个名字引用这个字体。

    为了演示中文显示,范例simplecn.fo文件为

    <?xml version="1.0" encoding="gb2312"?>
    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"><fo:layout-master-set><fo:simple-page-master master-name="simple"page-height="29.7cm" page-width="21cm"margin-top="1cm" margin-bottom="2cm" margin-left="2.5cm" margin-right="2.5cm"><fo:region-body margin-top="3cm"/><fo:region-before extent="3cm"/><fo:region-after extent="1.5cm"/></fo:simple-page-master></fo:layout-master-set><fo:page-sequence master-name="simple"><fo:flow flow-name="xsl-region-body"><fo:block font-size="18pt" font-family="mysimsun" line-height="24pt"text-align="center"padding-top="3pt">这是宋体</fo:block><fo:block font-size="18pt" font-family="mysimkai" line-height="24pt"text-align="center"padding-top="3pt">这是楷体</fo:block></fo:flow></fo:page-sequence>
    </fo:root>
    
    

    上述fo文件使用两种字体分别显示一行文字,注意在<fo:block>的属性中的font-family被我们设成userconfig.xml中相应的名字。

    由于需要读入userconfig.xml来得到字体信息,程序主体修改如下:

    Driver driver = new Driver();
    driver.setInputSource(new InputSource (args[0]));
    driver.setOutputStream(new FileOutputStream(args[1]));
    driver.setRenderer(Driver.RENDER_PDF);
    //读入配置(在Options的构造函数中完成)
    Options options = new Options(new File("userconfig.xml"));
    driver.run();
    

    这里在run之前一行读入配置(产生的Options的实例在以后没有用处),执行结果为:

    fig3.gif

总结
FOP从技术上说无疑是一个非常优秀的产品,但是目前它对用户的开发支持显然很欠缺。FOP的开发小组也意识到了这个问题,他们允诺在将来会建立一个专门的Web站点以及丰富它的文档。如果现在就想使用更方便的产品的话,你也可以考虑一些商用产品,如RenderX和X2P。

另外需要注意的是,今年8月推出的FOP 0.20.1版本非常的不好,不但一些范例无法运行,而且附带的源代码有若干错误,而这个9月29日推出的0.20.2RC版本有极大的改进,建议大家尽快升级到这个版本。

参考资料

  • FOP主站点 http://xml.apache.org/fop
  • FO规范 http://www.w3.org/TR/xsl/
关于作者:
马路,2000级清华大学计算机系研究生,目前在清华大学Java应用技术实验室学习。E-mail:stevema@263.net

如何在程序中嵌入FOP相关推荐

  1. 在windows程序中嵌入Lua脚本引擎--编写自己的Lua库

    在<在windows程序中嵌入Lua脚本引擎--建立一个简易的"云命令"执行的系统>一文中,我提到了使用Lua的ffi库,可以让我们像写C代码一样写lua程序.这是个非 ...

  2. 在windows程序中嵌入Lua脚本引擎--建立一个简易的“云命令”执行的系统

    在<在windows程序中嵌入Lua脚本引擎--使用VS IDE编译Luajit脚本引擎>开始处,我提到某公司被指责使用"云命令"暗杀一些软件.本文将讲述如何去模拟一个 ...

  3. 在windows程序中嵌入Lua脚本引擎--使用VS IDE编译Luajit脚本引擎

    前些天听到一个需求:某业务方需要我们帮忙清理用户电脑上的一些废弃文件.同事完成这个逻辑的方案便是在我们程序中加入了一个很"独立"的业务逻辑:检索和删除某个程序产生的废弃文件.试想, ...

  4. 在WinForm应用程序中嵌入WPF控件(转)

      我们知道,在WPF界面上添加WinForm的控件需要使用WindowsFormHost类.而在WinForm界面上添加WPF控件该如何做呢?有没有类似的类呢?明显是有的,ElementHost就是 ...

  5. 在JavaFX程序中嵌入Swing内容

    转载自  在JavaFX程序中嵌入Swing内容 本教程描述如何在JavaFX应用程序中嵌入Swing组件.本文将讨论线程限制并提供一个可运行的应用程序来说明在JavaFX应用程序中嵌入带HTML内容 ...

  6. 在python程序中嵌入浏览器_用Python中的wxPython实现最基本的浏览器功能

    通常,大多数应用程序通过保持 HTML 简单来解决大多数浏览器问题 ― 或者说,根据最低共同特性来编写.然而,即便如此,也仍然存在字体和布局的问题,发行新浏览器和升级现有浏览器时,也免不了测试应用程序 ...

  7. php 嵌入手机百度地图,C# 程序中嵌入百度地图

    本例是对WinForm中使用百度地图的简要介绍.百度地图目前支持Android开发,IOS开发,Web开发,服务接口,具体可以参照'百度地图开放平台'. [动态加载百度地图]涉及到的知识点:WebBr ...

  8. 在WinForm程序中嵌入ASP.NET[转]

    在WinForm程序中嵌入ASP.NET 现在的流行趋势是桌面程序Web化,Web程序桌面化,呵呵.最终目标就是你中有我,我中有你.例如MSN Explorer就是一个很好的展示,让用户在使用的时候分 ...

  9. MFC应用程序中嵌入一个谷歌cef浏览器

    声明:文章来自http://www.codeproject.com/Articles/1105945/Embedding-a-Chromium-browser-in-an-MFC-applicatio ...

最新文章

  1. 美团点评资深产品专家刘远飞:了解业务要弄清楚这三个问题
  2. k8s容器生命周期:指定启动、退出动作
  3. php fpm 统计,php实现fpm开启状态统计的方法
  4. js生成vCard,以及格式参数详细说明
  5. 【GDB调试学习笔记】Makefile多级目录生成可执行文件
  6. 牛人搜集的常用的资源类网站及68个各类资源网站汇总
  7. (转)中华英才网竞品分析报告2016
  8. 为什么4万月薪招聘不到赴日软件工程师?
  9. 深入理解操作系统——datalab-handout
  10. Stay hungry. Stay foolish.
  11. 方阵的特征值与特征向量
  12. 引起内存不能“read”的原因及“written”的解决方案
  13. Element ui中table标签上下滚动时表格错位
  14. 让某个应用以指定时间运行
  15. python中len字典_Python 字典(Dictionary) len()方法
  16. 照片秒变卡通风!教你用PaddleGAN快速生成你的专属卡通头像
  17. 点云表面积, 体积计算
  18. vivado 抓取信号:mark debug 和 ILA
  19. Linux访问Windows共享目录的方法——smbclient
  20. php代码审计【25】齐博CMS 无限制put 漏洞

热门文章

  1. linux上c语言hdc句柄,控制台窗口的绘图
  2. wxpython嵌入图片_将图片文件嵌入到wxpython代码中的实现方法
  3. combobox is not a function 问题解决
  4. 日志存储 elasticsearch vs clickhouse
  5. 最近在修改statusBar,添加几张图片.编译源码包时,一直提示无法找到R.drawable.xxxx必须手动编译下指定的图片文件生成R.
  6. 梳理项目的pom文件
  7. 智能一代云平台(二十四):已安装的Nginx上安装echo插件
  8. 知道吗?BAT去年在KDD上作为第一单位发表了12篇文章!(内附每篇文章解读)...
  9. 谷歌AI魔镜:看你手舞足蹈,就召唤出8万幅照片学你跳 | TensorFlow.js
  10. Zoox又融5亿美元!这家腾讯投资的无人车公司现在估值32亿美元