文档转换服务程序:
1、安装软件openoffice
下载最新版本3.4.1,及SDK3.4.1,openoffice默认安装在服务器上,SDK直接安装在开发本机上,安装后打开目录C:\Program Files\OpenOffice.org 3\Basis\sdk\cli
复制文件夹里的5个文件即可:
2、安装swftools-0.9.2
直接安装在开发本机,复制安装目录的pdf2swf.exe程序即可。
3、下载xpdf-chinese-simplified
下载字体:gkai00mp.rar,修改xpdf-chinese-simplified目录下的add-to-xpdfrc文件。将里面的路径设为自己的路径:
#----- begin Chinese Simplified support package (2011-sep-02) cidToUnicode Adobe-GB1 C:\xpdf-chinese-simplified\Adobe-GB1.cidToUnicode unicodeMap ISO-2022-CN C:\xpdf-chinese-simplified\ISO-2022-CN.unicodeMap unicodeMap EUC-CN C:\xpdf-chinese-simplified\EUC-CN.unicodeMap unicodeMap GBK C:\xpdf-chinese-simplified\GBK.unicodeMap cMapDir Adobe-GB1 C:\xpdf-chinese-simplified\CMap toUnicodeDir C:\xpdf-chinese-simplified\CMap fontDir C:\WINDOWS\Fonts displayCIDFontTT Adobe-GB1 C:\xpdf-chinese-simplified\CMap\gkai00mp.ttf #fontFileCC Adobe-GB1 /usr/..../gkai00mp.ttf #----- end Chinese Simplified support package
参照上面的代码,在调用pdf2swf命令中加入“ -s languagedir=D:\\xpdf\\xpdf-chinese-simplified ”参数。
String cmd = exePath + " \"" + fileDir + "\" -o \"" + filePath + "/" + fileName + ".swf\" -T 9 -s languagedir=c:\\xpdf-chinese-simplified";
这样乱码的问题就解决了。
4、开发winform程序
具体如何建项目不再阐述,笔者用的是VS2010,本程序工作流程:
a、 定时器1定时读取数据库---获取需要转换的文档信息
b、获取一次信息后,起动一个线程开始转换文档
c、定时器2定时获取转换状态及转换服务起动状态
d、定时器3定时记录转换用时
从数据库加载数据到dataGridView上不再阐述,这里重点谈谈C#如果调用openoffice和pdf2swf.exe进行转换。
首先定义全局变量:
//------------------------------
public static string WebDirectory;//网站根目录
public static string PDFProcesses;//openoffice程序目录
public static string LanguageDir;//xpdf-chinese-simplified目录
//------------------------------
新建该项目的App.config文件,内容如下:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0"/> </startup> <appSettings> <add key="AutoRun" value="true"/> <add key="ConnectionString" value=""/> <add key="WebDirectory" value="C:\WWW\"/> <add key="PDFProcesses" value="C:\Program Files\OpenOffice.org 3\program\soffice.exe"/> <add key="LanguageDir" value="C:\xpdf-chinese-simplified\"/> </appSettings> </configuration>
AutoRun为是否程序启动就进行转换; ConnectionString为数据库连接字符串,网站web.config中的是什么就复制什么。
<startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0"/> </startup>这个是必须的,否则无法启动openoffice程序,调试出错。
这样在程序初始化中获取这些参数:
public Form1() { InitializeComponent(); ld.ConnectionString = GetAppConfig("ConnectionString"); WebDirectory = GetAppConfig("WebDirectory"); PDFProcesses = GetAppConfig("PDFProcesses"); LanguageDir = GetAppConfig("LanguageDir"); }
public static string GetAppConfig(string AppKey) { try { string AppKeyValue; AppKeyValue = ConfigurationManager.AppSettings.Get(AppKey); return AppKeyValue; } catch (Exception ex) { throw ex; } }
新建ToPDF.cs文件,内容如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Diagnostics; using unoidl.com.sun.star.lang; using unoidl.com.sun.star.uno; using unoidl.com.sun.star.bridge; using unoidl.com.sun.star.frame; using unoidl.com.sun.star.text; using unoidl.com.sun.star.beans; using unoidl.com.sun.star.sheet; using unoidl.com.sun.star.container; using unoidl.com.sun.star.table; namespace ConvertPS { class ToPDF { private static Mutex _openOfficeLock = new Mutex(false, "OpenOfficeMutexLock-MiloradCavic"); string sourcePath, destinationPath; public ToPDF(string sPath, string dPath) { // // TODO: Add constructor logic here // sourcePath = sPath; destinationPath = dPath; } /// <summary> /// Converts document to PDF /// </summary> /// <param name="sourcePath">Path to document to convert(e.g: C:\test.doc)</param> /// <param name="destinationPath">Path on which to save PDF (e.g: C:\test.pdf)</param> /// <returns>Path to destination file if operation is successful, or Exception text if it is not</returns> public void Generate() { bool obtained = _openOfficeLock.WaitOne(60 * 1000, false); XComponent xComponent = null; try { if (!obtained) { throw new System.Exception(string.Format("Request for using OpenOffice wasn't served after {0} seconds. Aborting...", 30)); } sourcePath = PathConverter(sourcePath); destinationPath = PathConverter(destinationPath); // 載入文件前屬性設定,設定文件開啟時隱藏 PropertyValue[] loadDesc = new PropertyValue[1]; loadDesc[0] = new PropertyValue(); loadDesc[0].Name = "Hidden"; loadDesc[0].Value = new uno.Any(true); //Get a ComponentContext unoidl.com.sun.star.uno.XComponentContext xLocalContext = uno.util.Bootstrap.bootstrap(); //Get MultiServiceFactory unoidl.com.sun.star.lang.XMultiServiceFactory xRemoteFactory = (unoidl.com.sun.star.lang.XMultiServiceFactory)xLocalContext.getServiceManager(); //Get a CompontLoader XComponentLoader aLoader = (XComponentLoader)xRemoteFactory.createInstance("com.sun.star.frame.Desktop"); //Load the sourcefile //xComponent = aLoader.loadComponentFromURL(sourcePath, "_blank", 0, new unoidl.com.sun.star.beans.PropertyValue[0]); xComponent = aLoader.loadComponentFromURL(sourcePath, "_blank", 0, loadDesc); //Wait for loading while (xComponent == null) { System.Threading.Thread.Sleep(3000); } saveDocument(xComponent, destinationPath); xComponent.dispose(); //return destinationPath; } catch (System.Exception ex) { System.Windows.Forms.MessageBox.Show(ex.ToString()); //throw ex; } finally { Process[] pt = Process.GetProcessesByName("soffice.bin"); if (pt != null && pt.Length > 0) pt[0].Kill(); Process[] ps = Process.GetProcessesByName(Form1.PDFProcesses); if (ps != null && ps.Length > 0) ps[0].Kill(); //if (System.IO.File.Exists(sourcePath)) // File.Delete(sourcePath); if (obtained) _openOfficeLock.ReleaseMutex(); } } /// <summary> /// Saves the document. /// </summary> /// <param name="xComponent">The x component.</param> /// <param name="fileName">Name of the file.</param> private static void saveDocument(XComponent xComponent, string fileName) { unoidl.com.sun.star.beans.PropertyValue[] propertyValue = new unoidl.com.sun.star.beans.PropertyValue[2];//[1]; propertyValue[0] = new unoidl.com.sun.star.beans.PropertyValue(); //propertyValue[0].Name = "FilterName"; //propertyValue[0].Value = new uno.Any("writer_pdf_Export"); propertyValue[0].Name = "Overwrite"; propertyValue[0].Value = new uno.Any(true); // Setting the filter name propertyValue[1] = new PropertyValue(); propertyValue[1].Name = "FilterName"; propertyValue[1].Value = new uno.Any("writer_pdf_Export"); ((XStorable)xComponent).storeToURL(fileName, propertyValue); } /// <summary> /// Convert into OO file format /// </summary> /// <param name="file">The file.</param> /// <returns>The converted file</returns> private static string PathConverter(string file) { try { file = file.Replace(@"\", "/"); return "file:///" + file; } catch (System.Exception ex) { throw ex; } } } }
这段代码源自某仁兄的OpenOfficeConvert实例,表示感谢,这里分析一下他的几个实例:
笔者看完后分析得出,有两种转换方式:一种是调用SDK的库调用openoffice,一种是开启一个openoffice服务,连接服务进行转换(这种方法博客园有篇文章“仿百度文库方案【openoffice.org 3+swftools+flexpaper】”就是采用连接服务进行转换的方式,由于该方法后台采用的是java,而且用了JODConverter,JODConverter是一个java的OpenDucument文件转换器,可以进行许多文件格式的转换,它利用OpenOffice来进行转换工作,所以和asp.net一点关系也没有,未采用,如果读者感兴趣可参考该文进行实现)。本文采用第一种方法,在这里就需要引用刚才安装openofficeSDK的那5个包了,如果引用正确:
using unoidl.com.sun.star.lang; using unoidl.com.sun.star.uno; using unoidl.com.sun.star.bridge; using unoidl.com.sun.star.frame; using unoidl.com.sun.star.text; using unoidl.com.sun.star.beans; using unoidl.com.sun.star.sheet; using unoidl.com.sun.star.container; using unoidl.com.sun.star.table;
这里就没有问题了。
说明:此ToPDF类在原来的基础上作了修改,解决了启动openoffice(虽然使用了hidden)会打开界面的问题,表现为打开后又关闭。其中传入参数sPath为需要转换的文档地址,dPath为存放的地址。
新建ToSWF.cs文件,内容如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; namespace ConvertPS { class ToSWF { Process p = new Process(); public ToSWF(string cmdStr, string argsStr) { // // TODO: Add constructor logic here // ProcessStartInfo psi = new ProcessStartInfo(cmdStr, argsStr); psi.WindowStyle = ProcessWindowStyle.Hidden; p.StartInfo = psi; p.StartInfo.WorkingDirectory = Form1.WebDirectory + "SWFTools\\"; } public void Running() { p.Start(); p.WaitForExit(); p.Close();//关闭进程 p.Dispose();//释放资源 } } }
这个就比较简单,cmdStr为pdf2swf.exe程序地址,argsStr 为启动参数,即argsStr="-t " + sourcePath1 + " -T 9 -s languagedir="+Form1.LanguageDir+" -o " + targetPath; sourcePath1 为需要转换的pdf地址,targetPath为存放地址。
注意事项:
1、GetAppConfig(string AppKey)函数中用到了System.Configuration 命名空间,这个VS2010是不自带的,需要手动把System.configuration.dll文件放在bin-debug中。
2、线程内一般是不能操作界面控件的,所以在转换线程内,首先需要读取dataGridView的一行数据,得到文档地址,再启动openoffice,pdf2swf.exe进行转换,转换完成后需要更新该行的转换状态,表示转换成功与否,如图:
为了能够在线程内更新这些数据,必须使用容器来解决,将需要的数据存入容器,一般用变量,ArrayList,但这里有点特殊,更新的是表格的数据,而表格数据源用的是什么?是DataTable,笔者就用DataTable作这个容器,获取数据行就用:
DataTable dat; s_guid = dat.Rows[k]["Guid"].ToString(); //设置也一样 dat.Rows[k]["ZT"] = "转换成功";
而定时器2为了能够获取到正在转换的文档信息,故用ArrayList在线程内存入正在转换的文档信息。请注意ArrayList是可以存放任何类型的数据,一个数组也行。
3、为实现该程序后台自动启动,定时器采用服务程序类定时器,添加该控件即可。