文檔轉換服務程序:
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、爲實現該程序後臺自動啓動,定時器採用服務程序類定時器,添加該控件即可。
如需轉載,請儘量保留此申明,並在文章頁面明顯位置給出原文連接。謝謝!