Extjs上傳附件實戰開發,實現批量上傳及在線預覽功能(三)

文檔轉換服務程序:

      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、爲實現該程序後臺自動啓動,定時器採用服務程序類定時器,添加該控件即可。

 

作者:kunoy
申明:作者寫博是爲了總結經驗,和交流學習之用。
如需轉載,請儘量保留此申明,並在文章頁面明顯位置給出原文連接。謝謝!


 

發佈了33 篇原創文章 · 獲贊 87 · 訪問量 40萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章