文档转换服务程序:
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、为实现该程序后台自动启动,定时器采用服务程序类定时器,添加该控件即可。
如需转载,请尽量保留此申明,并在文章页面明显位置给出原文连接。谢谢!