(一)——总体思路
当下国内外文档分享平台成为热门应用,其中文档在线浏览几乎成为文档分享平台必备功能,本文针对类似百度文库的多种文档在线浏览技术提出了三种解决方案。文档在线浏览本质上是将多种可在线预览文档转换成Flash(SWF)格式,再通过Flash Player播放器播放SWF文件。Flexpaper是一个开源的在线文档显示组件,可以播放SWF文件。因此,下面先分析如何将文档转换为SWF。
SWFTools是一种与Adobe Flash(swf)文件工作的实用工具包,主要包括用于读取、编译以及生成swf文件的程序。其中,PDF2SWF工具,可以将PDF文件转换成SWF文件。那么只需要将文档转换成PDF,再利用PDF2SWF转换PDF为SWF则解决问题。
转换常用Office文档为PDF格式,目前主要有三种方案:利用Jacob或者JCom调用MS Office或者WPS Office API,利用JODConverter调用OpenOffice.org服务,调用虚拟打印机转换文档为PDF。由于笔者目前没有实现Java下调用虚拟打印打印文件为PDF格式的方法,因此在这里不做介绍。图1-1显示了笔者实现的三种方案:
图1-1 文档转换总体方案
注:
参考资料:http://www.cnblogs.com/flashlm/archive/2010/11/22/document-preview-online.html#2268089
(二))——利用Jacob调用MS Office转换文档为PDF
Jacob是Java与COM组件桥接的缩写,即JAVA-COM Bridge。通过使用Jacob类库,我们可以很方便地在Java程序中调用COM自动化组件。Jacob最初是由美国人Dan Alder在Inventure公司担任CTO时编写的,目的是为了方便众多的程序员在Java2虚拟机上,调用Win32平台上COM自动化服务器中的组件。当Jacob项目以开源的方式在网络上公布以后,越来越多的人开始参与项目的研发与改进中去。
Jacob类库中只有两个包:com.jacob.activex和com.jacob.com。com.jacob.activex包建立在com.jacob.com基础之上,主要包含了ActiveXComponent类。com.jacob.com中有一个非常基础的类JacobObject,该包中比较常用的两个类Dispatch和Variant便是继承自JacobObject。
Dispatch类代表COM自动化组件中的对象,提供了访问COM对象的API。Dispatch类中常用的方法有:
ActiveXComponent类继承自Dispatch类,在内部封装了Dispatch对象,使用该类加载COM组件。 并且提供了访问COM组件对象的属性和方法的接口。ActiveXComponent类提供了比Dispatch类更方便的获取属性和设置属性的方法:getProperty( ),setProperty( )。
Variant类映射COM对象中的Variant数据结构,提供Java和COM的数据交互。其本质就是一种数据类型,可以被转换成任何数据类型,如int,String,甚至Dispatch对象。
Microsoft Office2007之前的Office版本并没有提供转换文档为PDF格式的支持,另外,Office2007还需要安装有Microsoft Save as PDF or XPS插件才支持PDF格式转换,而Office2010不需要安装插件则自带有转换Office文档为PDF格式的API。因此,建议使用Office 2010。
通过查询MSDN Office 2010开发人员手册,经过分析后得出图2-1所示的Office COM对象模型:
图2-1 Office COM对象模型
Microsoft Office中每个应用程序中都包含一个Application对象,但是每个应用程序中的文档对象却不一样,Word中Documents对象代表Word应用程序中所有打开的word文档集合,Document对象代表一篇word文档。详细的文档对象结构如图2-1所示。其中Document,Workbook,Presentation中的SaveAs或者ExportAsFixedFormat方法可用于将文档转换为PDF。
算法流程图如2-2所示:
图2-2 Jacob调用MS Office COM组件转换文档为PDF算法流程
第一步,对于Office文档,不同格式的文档需要加载不同的COM组件,例如Word文件需要加载Word COM组件。Jacob中加载COM组件是利用ActiveXComponent类,例如,加载Word COM自动化组件:
//Word.Application代表COM OLE编程标识,可查询MSDN得到 ActiveXComponent app = new ActiveXComponent("Word.Application"); //设置Word不可见 app.setProperty("Visible",false);
第二步,获得文档对象集合,Word中Documents对象代表Word应用程序中所有打开的Word文档,范例如下:
//调用Application对象的Documents属性,获得Documents对象 Dispatch docs = app.getProperty("Documents").toDispatch();
第三步,打开文件,并执行转换。Word范例如下:
Dispatch doc = Dispatch.call(docs, "Open",//调用Documents对象的Open方法 inputFile,// 输入文件路径全名 false, //ConfirmConversions,设置为false表示不显示转换框 true//ReadOnly ); Dispatch.call(doc,//要转换的文档 "SaveAS", pdfFile,//要保存的PDF文件名 wdFormatPDF//转换后的文件格式宏,值为17,可查询MSDN得到 );
第四步,关闭应用程序。Word范例:
//关闭打开的Word文件 Dispatch.call(doc, "Close", false//设置不保存改变); //关闭Word应用程序 app.invoke("Quit",0);
转换Word文档为PDF格式的详细代码如下:
public static void word2PDF(String inputFile,String pdfFile){ //打开word应用程序 ActiveXComponent app = new ActiveXComponent("Word.Application"); //设置word不可见 app.setProperty("Visible", false); //获得word中所有打开的文档,返回Documents对象 Dispatch docs = app.getProperty("Documents").toDispatch(); //调用Documents对象中Open方法打开文档,并返回打开的文档对象Document Dispatch doc = Dispatch.call(docs, "Open", inputFile, false, true ).toDispatch(); //调用Document对象的SaveAs方法,将文档保存为pdf格式 /* Dispatch.call(doc, "SaveAs", pdfFile, wdFormatPDF //word保存为pdf格式宏,值为17 ); */ Dispatch.call(doc, "ExportAsFixedFormat", pdfFile, wdFormatPDF //word保存为pdf格式宏,值为17 ); //关闭文档 Dispatch.call(doc, "Close",false); //关闭word应用程序 app.invoke("Quit", 0); }
JCom是日本的一个开源项目,其目的同前面介绍的Jacob一样也是为了让Java程序能够访问Windows平台上的COM组件。利用JCom,可以在Java中控制几乎所有的COM对象,而且它还带有一些用于Excel操作的强大的辅助类。
使用Jcom主要用到ReleaseManager和IDispatch类。ReleaseManager类相当于一个容器,管理机器上的COM组件。配合IDispatch类可以创建COM组件对象。例如创建Excel应用程序的COM对象:
ReleaseManager rmExcel = new ReleaseManager( ); IDispatch excelApp = new IDispatch(rmExcel,”Excel.Application”);
另外,在程序结束的最后阶段需要调用ReleaseManager类中的release( )方法对创建的ReleaseManager进行资源释放,以免内存溢出。
IDispatch类和Jacob中的Dispatch类相似,代表着COM组件对象,提供了访问微软COM组件对象的属性和方法的接口。IDispatch类中常用的方法如下:
get( )方法:获取COM组件对象的属性,返回一个java.lang.Object类型值。
put( )方法:设置COM组件对象的属性,不返回值。
invoke( )方法:调用COM组件对象的方法,返回一个java.lang.Object类型值。不推荐使用,建议使用method方法。
method( )方法:和invoke( )方法功能一样。
JCom是日本人开发的一个开源项目,和Jacob类似,其也是用来调用COM自动化组件。自然JDK的运行环境也是必不可少。JCom也可以利用Microsoft Office API转换文档,那么需要安装Microsoft Office2007或者以上版本,同时Office2007仍需要安装有Microsoft Save as PDF or XPS插件。JCom除了调用Microsoft Office API转换文档为PDF格式的方法之外,还可以利用Adobe Acrobat软件的CreatePDF函数直接将Office格式的文档转换为PDF。因此,如果需要使用Adobe Acrobat转换文档,需要再安装有Adobe Acrobat软件。
下载JCom包,将其解压缩后,提取其中的jcom.jar包配置到Java项目的类路径中,同时也需要将其中的jcom.dll文件放置到windows系统System32目录下,如果不想污染System32目录中的dll文件,也可以将其放置到本机JDK安装目录下的bin文件夹中。
类似Jacob转换文档为PDF,转换Word为PDF格式的代码如下:
public static void word2PDF(String inputFile,String pdfFile){ ReleaseManager rm = null; IDispatch app = null; try { rm = new ReleaseManager(); app = new IDispatch(rm, "Word.Application");//启动word app.put("Visible", false); //设置word不可见 IDispatch docs = (IDispatch) app.get("Documents"); //获得word中所有打开的文档 IDispatch doc = (IDispatch) docs.method("Open", new Object[]{inputFile,false,true});//打开文档 doc.method("SaveAs", new Object[]{pdfFile,17});//转换文档为pdf格式 doc.method("Close", new Object[]{false}); app.method("Quit", null); } catch (Exception e) { e.printStackTrace(); } finally { try { app=null; rm.release(); rm = null; } catch (Exception e) { e.printStackTrace(); } } }
除了调用MS Office转换文档为PDF的方法之外,还可以调用Adobe Acrobat API转换Office文档为PDF格式,下面是JCom的实现方法,当然也可以用Jacob实现,这里就不做研究了。
1 public void convert2PDF(String inputFile, String pdfFile) { 2 3 4 ReleaseManager rm = new ReleaseManager(); 5 IDispatch app; 6 try { 7 app = new IDispatch(rm, "PDFMakerAPI.PDFMakerApp"); 8 app.method("CreatePDF",new Object[]{inputFile,pdfFile}); 9 System.out.println("conversion completed!"); 10 } catch (JComException e) { 11 e.printStackTrace(); 12 }finally{ 13 app=null; 14 rm.release(); 15 rm = null; 16 } 17 18 }
(四)—— 利用JODConverter调用OpenOffice.org服务转换文档为PDF
JODConverter,是一个Java的OpenDocument文件转换器,可以进行许多文件格式的转换。它依赖于OpenOffice.org或者LibreOffice提供的服务来进行转换,它能将Microsoft Office文档(Word,Excel,PowerPoint)转换为PDF格式。
你可以将JODConverter内嵌在Java应用程序里,也可以单独作为命令行由脚本调用,更可以应用为网页程序或者Web Service以供网络应用。
(1) 转换文档范例:
OfficeManager officeManager = new DefaultOfficeManagerConfiguration( ).buildOfficeManager( ); //启动OpenOffice服务 officeManager.start( ); //执行转换 OfficeDocumentConverter converter = new OfficeDocumentConverter(officeManager); converter.convert(new File(“test.odt”), new File(“test.pdf”)); //停止服务 officeManager.stop( );
(2) 主要类说明:
OfficeManager是一个接口,主要定义了三个方法:
DefaultOfficeManagerConfiguration是一个实现了OfficeManager接口的实体类,其提供了相关方法配置OpenOffice.org,比如:
public DefaultOfficeManagerConfiguration setOfficeHome(String officeHome)设置OpenOffice.org或者LibreOffice安装目录,windows下默认值为” C:\Program Files\OpenOffice.org 3”(LibreOffice进行相应更改),因此如果OpenOffice.org安装在别的目录,必须设置此项。
public DefaultOfficeManagerConfiguration setConnectionProtocol(OfficeConnectionProtocol conn)设置连接协议,确定使用管道通信,还是socekt通信。
pubcli DefaultOfficeManagerConfiguration setTemplateProfileDir(File templateProfileDir)设定临时目录。
除以上几个方法之外,DefaultOfficeManagerConfiguration还提供了别的配置OpenOffice.org的方法,具体方法可以查询JODConverter API手册。配置完之后,必须要执行方法buildOfficeManager(),实现真正的配置。
OfficeDocumentConverter中主要包含convert方法,该方法实际上调用的是实现OfficeManager接口的类中的execute方法。
算法流程图如图4-1所示:
图4-1 JODConverter调用OpenOffice服务转换文档为PDF算法
第一步,启动OpenOffice服务。例如,首先设定DefaultOfficeManagerConfiguration相关参数来配置OpenOffice,并得到OfficeManager。调用OfficeManager实现类的start方法启动服务。
第二步,转换文档。例如,初始化OfficeDocumentConverter,调用其convert方法执行转换。
第三步,停止OpenOffice服务。例如,调用OfficeManager实现类的stop方法停止方法。
JODConverter是一个开源文档转换工具,既可以应用于Linux平台,也可其应用于Windows平台。其基于OpenOffice.org或者LibreOffice。因此,文档转换服务器上必须安装有OpenOffice或者LibreOffice。
目前最新版本的JODConverter为JODConverter3.0,它要求JDK1.5以上的Java环境,同时还需要OpenOffice.org 3.x版本。本文基于最新版本3.0设计实现,如果是版本为2,则有不同的实现。(版本2需要手动启动OpenOffice.org服务,或者创建Windows服务设置为开机启动,而版本3提供了开启服务的接口,因此笔者用的是版本3)
package com.converter.pdfConverter; import java.io.File; import java.io.FileNotFoundException; import org.artofsolving.jodconverter.OfficeDocumentConverter; import org.artofsolving.jodconverter.office.DefaultOfficeManagerConfiguration; import org.artofsolving.jodconverter.office.OfficeManager; import com.converter.utils.FileUtils; public class OpenOfficePDFConverter implements PDFConverter{ private static OfficeManager officeManager; private static String OFFICE_HOME = "D:\\Program Files\\OpenOffice.org 3"; private static int port[] = {8100}; public void convert2PDF(String inputFile, String pdfFile) { if(inputFile.endsWith(".txt")){ String odtFile = FileUtils.getFilePrefix(inputFile)+".odt"; if(new File(odtFile).exists()){ System.out.println("odt文件已存在!"); inputFile = odtFile; }else{ try { FileUtils.copyFile(inputFile,odtFile); inputFile = odtFile; } catch (FileNotFoundException e) { System.out.println("文档不存在!"); e.printStackTrace(); } } } startService(); System.out.println("进行文档转换转换:" + inputFile + " --> " + pdfFile); OfficeDocumentConverter converter = new OfficeDocumentConverter(officeManager); converter.convert(new File(inputFile),new File(pdfFile)); stopService(); System.out.println(); } public void convert2PDF(String inputFile) { String pdfFile = FileUtils.getFilePrefix(inputFile)+".pdf"; convert2PDF(inputFile,pdfFile); } public static void startService(){ DefaultOfficeManagerConfiguration configuration = new DefaultOfficeManagerConfiguration(); try { System.out.println("准备启动服务...."); configuration.setOfficeHome(OFFICE_HOME);//设置OpenOffice.org安装目录 configuration.setPortNumbers(port); //设置转换端口,默认为8100 configuration.setTaskExecutionTimeout(1000 * 60 * 5L);//设置任务执行超时为5分钟 configuration.setTaskQueueTimeout(1000 * 60 * 60 * 24L);//设置任务队列超时为24小时 officeManager = configuration.buildOfficeManager(); officeManager.start(); //启动服务 System.out.println("office转换服务启动成功!"); } catch (Exception ce) { System.out.println("office转换服务启动失败!详细信息:" + ce); } } public static void stopService(){ System.out.println("关闭office转换服务...."); if (officeManager != null) { officeManager.stop(); } System.out.println("关闭office转换成功!"); } }
仿百度文库解决方案(五)——利用SWFTools转换PDF文档为SWF
SWFTools工具包中的PDF2SWF工具可用来将PDF格式文件转换成SWF格式。使用下面的命令可以将pdf文件转换为单页swf文件。
pdf2swf pdfPath –o swfPath –T 9 –f。
pdf2swf为pdf2swf二进制命令的绝对路径;pdfpath为要进行转换的PDF文件的绝对路径;swfPath为转换后swf文件的路径;-T 9 用来设定转换的swf版本为9,这样设置是因为某些版本的swf文件并不能用flexpaper正常显示出来;-f在转换的文档每页中插入一帧,提高转换后文档的稳定性。
每个Java应用程序都有一个Runtime类实例,使应用程序能够与其运行的环境相连接。应用程序不能创建自己的Runtime类实例,可以通过Runtime类的getRuntime方法获得当前运行时。获得Runtime类实例之后,即可以调用该类的exec方法创建一个新的进程来执行制定的字符串命令。因此,可以利用exec方法来调用之前所述的PDF2SWF命令来完成PDF至SWF文件的转换。
实现利用SWFTools转换PDF文件为SWF格式的算法流程如5-1所示:
第一步,创建PDF2SWF转换命令字符串。
第二步,获得当前运行时Runtime,调用第一步中设定好的转换命令,进行转换。
图5-1 利用SWFTools转换PDF文档为SWF流程
实现代码如下:
注:
仿百度文库解决方案(六)——利用FlexPaper显示Flash(SWF)
FlexPaper是一个开源轻量级的文档浏览组件,被设计和比如PDF2SWF库(包含于SWFTools)一起工作,使得在网页上,Adobe Flex以及别的基于Flash的应用程序中显示和交互PDF文件成为可能。即,使得在没有安装PDF阅读器软件的情况下浏览PDF文件成为可能。FlexPaper项目同时提供了Flex库和独立的Flash版本。
FlexPaper在google code上的项目地址为http://code.google.com/p/flexpaper/。目前,FlexPaper最新的flash版本为FlexPaper_1.5.1_flash.zip。
下载、解压后,可以看到如图6-1显示的目录:
图6-1 FlexPaper压缩包目录
主要文件,文件夹说明:
examples文件夹:存放FlexPaper使用的例子
js文件夹:存放FlexPaper调用的js文件
php文件夹:存放php使用FlexPaper的例子
index.html:例子主页
FlexPaperViewer.swf:FlexPaper的核心文件
playerProductInstall.swf:如果客户端浏览器的flashplayer版本过低,将嵌入此swf文件
SwfFile(String):需要使用FlexPaper打开的文档
Scale(Number):初始化缩放比例,参数值应该是大于零的整数(1=100%)
ZoomTransition(String):FlexPaper中缩放样式,它使用和Tweener一样的样式,默认参数值为easeOut,其他可选值包括:easenone,easeout,linear,easeoutquad
ZoomTime(Number):从一个缩放比例变为另外一个缩放比例需要花费的时间,该参数值应该为0或更大
ZoomInterval(Number):缩放比例之间间隔,默认值为0.1,该值应该为正数
FitPageOnLoad(Boolean):初始化时自适应页面,与使用工具栏上的适应页面按钮同样的效果
FitWidthOnLoad(Boolean):初始化时自适应页面宽度,与工具栏上的适应宽度按钮同样的效果
localeChain(String):设置地区(语言),目前支持一下语言:
en_US (English)
fr_FR (French)
zh_CN (Chinese,Simple)
es_ES (Spanish)
pt_BR (Brazilian Portugese)
ru_RU (Russian)
fi_FN (FInnish)
de_DE (German)
nl_NL (Netherlands)
tr_TR (Turkish)
se_SE (Swedish)
pt_PT (Portugese)
el_EL (Greek)
da_DN (Danish)
cz_CS (Czech)
it_IT (Italian)
pl_PL (Polish)
pv_FN (Finish)
hu_HU (Hungarian)
FullScreenAsMaxWindow(Boolean):当设置为true时,单击全拼按钮会打开一个FlexPaper最大化的新窗口而不是全屏,当由于flash播放器因为安全而禁止全屏,而使用flexpaper作为独立的flash播放器的时候设置为true是个优先选择
ProgressiveLoading(Boolean):当设置为true时,展示文档时不会加载完整个文档,而是逐步加载,但是需要将文档中转化为9以上的版本(使用pdf2swf的时候使用-T 9标签)
MaxZoomSize(Number):设置最大的缩放比例
MinZoomSize(Number):设置最小的缩放比例
SearchMatchAll(Boolean):设置为true时,单击搜索所有符合条件的地方高亮显示
InitViewMode(String):设置启动模式如“Portrait”或“TowPage”
ViewModeToolsVisible(Boolean):工具栏上是否显示样式选择框
ZoomToolsVisible(Boolean):工具栏上时候显示缩放工具
NavToolsVisible(Boolean):工具栏上是否显示导航工具
CursorToolsVisible(Boolean):工具栏上是否显示光标工具
SearchToolsVisible(Boolean):工具栏上是否显示搜索工具
创建html页面test.html,代码如下:
<html> <head> <title>Flexpaper例子title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script type="text/javascript" src="js/flexpaper_flash.js">script> head> <body> <div style="position:absolute;left:10px;top:10px;"> <a id="viewerPlaceHolder" style="width:680px;height:480px;display:block">a> <script type="text/javascript"> var fp = new FlexPaperViewer( 'FlexPaperViewer', /* 对应FlexPaperViewer.swf文件*/ 'viewerPlaceHolder', { config : { SwfFile : 'Paper.swf', Scale : 0.6, ZoomTransition : 'easeOut', ZoomTime : 0.5, ZoomInterval : 0.2, FitPageOnLoad : true, FitWidthOnLoad : true, FullScreenAsMaxWindow : false, ProgressiveLoading : false, MinZoomSize : 0.2, MaxZoomSize : 5, SearchMatchAll : false, InitViewMode : 'Portrait', ViewModeToolsVisible : true, ZoomToolsVisible : true, NavToolsVisible : true, CursorToolsVisible : true, SearchToolsVisible : true, localeChain: 'zh_CN' }}); script>
test.html文件以及需要的js,swf文件组织结构如图6-2所示:
图6-2 test.html文件组织结构
显示Paper.swf文件的效果如图6-3所示:
图6-3 FlexPaper下显示Paper.swf效果
转载说明:本文系作者原创,转载时请注明文章出处:肖恩也有梦想 博客园,请尊重作者的劳动成果,谢谢!