C#的Process類調用第三方插件實現PDF文件轉SWF文件

来源:http://www.cnblogs.com/pengze0902/archive/2016/11/24/6097498.html
-Advertisement-
Play Games

在項目開發過程中,有時會需要用到調用第三方程式實現本系統的某一些功能,例如本文中需要使用到的swftools插件,那麼如何在程式中使用這個插件,並且該插件是如何將PDF文件轉化為SWF文件的呢?接下來就會做一個簡單的介紹。 在.NET平臺中,對C#提供了一個操作對本地和遠程的訪問進程,使能夠啟動和停 ...


     在項目開發過程中,有時會需要用到調用第三方程式實現本系統的某一些功能,例如本文中需要使用到的swftools插件,那麼如何在程式中使用這個插件,並且該插件是如何將PDF文件轉化為SWF文件的呢?接下來就會做一個簡單的介紹。

    在.NET平臺中,對C#提供了一個操作對本地和遠程的訪問進程,使能夠啟動和停止系統進程。這個類就是System.Diagnostics.Process,我們首先來瞭解一下該類。

一.解析System.Diagnostics.Process類

      在C#中使用Process類可以提供對本地和遠程的訪問進程,使能夠啟動和停止系統進程,並且該類可以對系統進程進行管理。該類中的一些常用方法:Start() ,Kill(),    WaitForExit()等方法;StartInfo,FileName,CreateNoWindow等屬性。

    1.Start()方法:啟動(或重用)此 Process 組件的 StartInfo 屬性指定的進程資源,並將其與該組件關聯。如果啟動了進程資源,則為 true;如果沒有啟動新的進程資源(例如,如果重用了現有進程),則為 false。

     具體介紹一下該方法的實現代碼:

        /// <devdoc>
        ///    <para> 
/// <see cref='System.Diagnostics.Process'/>如果過程資源被重用而不是啟動,重用的進程與此相關聯<see cref ='System.Diagnostics.Process'/>零件。
/// </para>
/// </devdoc>
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] 
        public bool Start() {
            Close(); 
            ProcessStartInfo startInfo = StartInfo; 
            if (startInfo.FileName.Length == 0)
                throw new InvalidOperationException(SR.GetString(SR.FileNameMissing)); 

            if (startInfo.UseShellExecute) {
#if !FEATURE_PAL
                return StartWithShellExecuteEx(startInfo); 
#else
                throw new InvalidOperationException(SR.GetString(SR.net_perm_invalid_val, "StartInfo.UseShellExecute", true)); 
#endif // !FEATURE_PAL 
            } else {
                return StartWithCreateProcess(startInfo); 
            }
        }

     2.Kill()方法:立即停止關聯的進程。Kill 強制終止進程,Kill 方法將非同步執行。 在調用 Kill 方法後,請調用 WaitForExit 方法等待進程退出,或者檢查 HasExited 屬性以確定進程是否已經退出。

     具體介紹一下該方法的實現代碼:

  [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        public void Kill() { 
            SafeProcessHandle handle = null;
            try {
                handle = GetProcessHandle(NativeMethods.PROCESS_TERMINATE);
                if (!NativeMethods.TerminateProcess(handle, -1)) 
                    throw new Win32Exception();
            } 
            finally { 
                ReleaseProcessHandle(handle);
            } 
        }
 SafeProcessHandle GetProcessHandle(int access) {
            return GetProcessHandle(access, true); 
        }

        /// <devdoc>
        /// 獲取進程的短期句柄,具有給定的訪問許可權。
         ///如果句柄存儲在當前進程對象中,則使用它。
         ///註意,我們存儲在當前進程對象中的句柄將具有我們需要的所有訪問許可權。
        /// </devdoc> 
        /// <internalonly/> 
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] 
        SafeProcessHandle GetProcessHandle(int access, bool throwIfExited) {
            Debug.WriteLineIf(processTracing.TraceVerbose, "GetProcessHandle(access = 0x" + access.ToString("X8", CultureInfo.InvariantCulture) + ", throwIfExited = " + throwIfExited + ")");
#if DEBUG
            if (processTracing.TraceVerbose) { 
                StackFrame calledFrom = new StackTrace(true).GetFrame(0);
                Debug.WriteLine("   called from " + calledFrom.GetFileName() + ", line " + calledFrom.GetFileLineNumber()); 
            } 
#endif
            if (haveProcessHandle) { 
                if (throwIfExited) {
                    //因為hasProcessHandle是true,我們知道我們有進程句柄

                     //打開時至少要有SYNCHRONIZE訪問,所以我們可以等待它
                     // zero timeout以查看進程是否已退出。

                    ProcessWaitHandle waitHandle = null;
                    try { 
                        waitHandle = new ProcessWaitHandle(m_processHandle); 
                        if (waitHandle.WaitOne(0, false)) {
                            if (haveProcessId) 
                                throw new InvalidOperationException(SR.GetString(SR.ProcessHasExited, processId.ToString(CultureInfo.CurrentCulture)));
                            else
                                throw new InvalidOperationException(SR.GetString(SR.ProcessHasExitedNoId));
                        } 
                    }
                    finally { 
                        if( waitHandle != null) { 
                            waitHandle.Close();
                        } 
                    }
                }
                return m_processHandle;
            } 
            else {
                EnsureState(State.HaveId | State.IsLocal); 
                SafeProcessHandle handle = SafeProcessHandle.InvalidHandle; 
#if !FEATURE_PAL
                handle = ProcessManager.OpenProcess(processId, access, throwIfExited); 
#else
                IntPtr pseudohandle = NativeMethods.GetCurrentProcess();
                // Get a real handle
                if (!NativeMethods.DuplicateHandle (new HandleRef(this, pseudohandle), 
                                                    new HandleRef(this, pseudohandle),
                                                    new HandleRef(this, pseudohandle), 
                                                    out handle, 
                                                    0,
                                                    false, 
                                                    NativeMethods.DUPLICATE_SAME_ACCESS |
                                                    NativeMethods.DUPLICATE_CLOSE_SOURCE)) {
                    throw new Win32Exception();
                } 
#endif // !FEATURE_PAL
                if (throwIfExited && (access & NativeMethods.PROCESS_QUERY_INFORMATION) != 0) { 
                    if (NativeMethods.GetExitCodeProcess(handle, out exitCode) && exitCode != NativeMethods.STILL_ACTIVE) { 
                        throw new InvalidOperationException(SR.GetString(SR.ProcessHasExited, processId.ToString(CultureInfo.CurrentCulture)));
                    } 
                }
                return handle;
            }
 
        }

     3.WaitForExit()方法:指示<see cref ='System.Diagnostics.Process'/>組件等待指定的毫秒數,以使相關聯的進程退出。

        具體介紹一下該方法的實現代碼:

 public bool WaitForExit(int milliseconds) { 
            SafeProcessHandle handle = null; 
         bool exited;
            ProcessWaitHandle processWaitHandle = null; 
            try {
                handle = GetProcessHandle(NativeMethods.SYNCHRONIZE, false);
                if (handle.IsInvalid) {
                    exited = true; 
                }
                else { 
                    processWaitHandle = new ProcessWaitHandle(handle); 
                    if( processWaitHandle.WaitOne(milliseconds, false)) {
                        exited = true; 
                        signaled = true;
                    }
                    else {
                        exited = false; 
                        signaled = false;
                    } 
                } 
            }
            finally { 
                if( processWaitHandle != null) {
                    processWaitHandle.Close();
                }
 
                // If we have a hard timeout, we cannot wait for the streams
                if( output != null && milliseconds == -1) { 
                    output.WaitUtilEOF(); 
                }
 
                if( error != null && milliseconds == -1) {
                    error.WaitUtilEOF();
                }
 
                ReleaseProcessHandle(handle);
 
            } 

            if (exited && watchForExit) { 
                RaiseOnExited();
            }
            
            return exited; 
        }
 internal ProcessWaitHandle( SafeProcessHandle processHandle): base() {
            SafeWaitHandle waitHandle = null; 
            bool succeeded = NativeMethods.DuplicateHandle(
                new HandleRef(this, NativeMethods.GetCurrentProcess()), 
                processHandle, 
                new HandleRef(this, NativeMethods.GetCurrentProcess()),
                out waitHandle, 
                0,
                false,
                NativeMethods.DUPLICATE_SAME_ACCESS);
 
            if (!succeeded) {
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 
            } 

            this.SafeWaitHandle = waitHandle; 
        }

     4.StartInfo屬性:獲取或設置要傳遞給 Process 的 Start 方法的屬性。StartInfo 表示用於啟動進程的一組參數。 調用 Start 時,StartInfo 用於指定要啟動的進程。 唯一必須設置的 StartInfo 成員是 FileName 屬性。

     具體介紹一下該方法的實現代碼:

 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), MonitoringDescription(SR.ProcessStartInfo)] 
        public ProcessStartInfo StartInfo {
            get { 
                if (startInfo == null) { 
                    startInfo = new ProcessStartInfo(this);
                } 
                return startInfo;
            }
            [ResourceExposure(ResourceScope.Machine)]
            set { 
                if (value == null) {
                    throw new ArgumentNullException("value"); 
                } 
                startInfo = value;
            } 
        }

     5.CreateNoWindow屬性:獲取或設置指示是否在新視窗中啟動該進程的值。

        具體介紹一下該方法的實現代碼:

 [
        DefaultValue(false),
        MonitoringDescription(SR.ProcessCreateNoWindow),
        NotifyParentProperty(true) 
        ]
        public bool CreateNoWindow { 
            get { return createNoWindow; } 
            set { createNoWindow = value; }
        } 

    以上簡單介紹了該類的三種常用方法和兩種常用屬性,在實際的開發項目中無須對每個屬性方法和屬性的底層實現做全面的瞭解,但建議在學習該類的時候,適當的瞭解一下某一些類的方法實現,有助於我們很好的掌握該類。

.如何實現PDF文件轉化為SWF文件

   在項目如果需要將PDF文件轉換為SWF文件,可以在項目中引入Swftools插件,該插件的主要功能:PDF到SWF轉換器。 每頁生成一幀。 使您能夠在Flash Movie中擁有完全格式化的文本,包括表格,公式,圖形等。 它基於Derek B. Noonburg的xpdf PDF解析器。

  簡單介紹一下該插件的常用參數:

  -h , –help                      Print short help message and exit              列印幫助信息    

  -V , –version                Print version info and exit                        列印版本號 

  -o , –output file.swf         Direct output to file.swf. If file.swf contains ‘13568621′ (file13568630.swf), then each page指定輸出的swf文件名

  -P , –password password       Use password for deciphering the pdf.指定打開pdf的密碼 

  -z , –zlib                    Use Flash 6 (MX) zlib compression.使用Flash 6的zlib壓縮機制 

  -i , –ignore                  Allows pdf2swf to change the draw order of the pdf. This may make the generated允許程式修改pdf的繪製順序,可能會導致結果與原來有差異 

    以上是幾種常用的參數,具體擦參數列表詳見:http://www.swftools.org/。

   對實現本次操作的類和插件做了一個簡單的介紹,接下來提供一個具體實現該功能的操作方法:

        /// <summary>
        /// PDF格式轉為SWF
        /// </summary>
        /// <param name="pdfPathParameter">原視頻文件地址,如/a/b/c.pdf</param>
        /// <param name="swfPathParameter">生成後的FLV文件地址,如/a/b/c.swf</param>
        /// <param name="beginpage">轉換開始頁</param>
        /// <param name="endpage">轉換結束頁</param>
        /// <param name="photoQuality">照片質量</param>
        /// <returns></returns>
        public static bool PdfConversionSwf(string pdfPathParameter, string swfPathParameter, int beginpage, int endpage, int photoQuality)
        {
            if (string.IsNullOrEmpty(pdfPathParameter))
            {
                throw new ArgumentNullException(pdfPathParameter);
            }
            if (string.IsNullOrEmpty(swfPathParameter))
            {
                throw new ArgumentNullException(swfPathParameter);
            }
            if (endpage < beginpage)
            {
                throw new ArgumentException("起始頁數大於結束頁數");
            }
            if (photoQuality <= 0)
            {
                throw new ArgumentException("照片質量錯誤");
            }
            var exe = HttpContext.Current.Server.MapPath("~/tools/swftools-2013-04-09-1007.exe");
            var pdfPath = HttpContext.Current.Server.MapPath(pdfPathParameter);
            var swfPath = HttpContext.Current.Server.MapPath(swfPathParameter);
            Process p = null;
            try
            {
                if (!File.Exists(exe) || !File.Exists(pdfPath))
                {
                    return false;
                }
                if (File.Exists(swfPath))
                {
                    File.Delete(swfPath);
                }
                var sb = new StringBuilder();
                sb.Append(" \"" + pdfPath + "\"");
                sb.Append(" -o \"" + swfPath + "\"");
                sb.Append(" -s flashversion=9");
                sb.Append(" -s disablelinks");
                if (endpage > GetPageCount(pdfPath))
                {
                    endpage = GetPageCount(pdfPath);
                }
                sb.Append(" -p " + "\"" + beginpage + "" + "-" + endpage + "\"");
                //SWF中的圖片質量
                sb.Append(" -j " + photoQuality);
                var command = sb.ToString();
                //Process提供對本地和遠程的訪問進程,使能夠啟動和停止系統進程。
                p = new Process
                {
                    StartInfo =
                    {
                        FileName = exe,
                        Arguments = command,
                        WorkingDirectory = HttpContext.Current.Server.MapPath("~/Bin/"),
                        UseShellExecute = false,
                        RedirectStandardError = true,
                        CreateNoWindow = false
                    }
                };
                //啟動線程
                p.Start();
                //開始非同步讀取
                p.BeginErrorReadLine();
                //等待完成
                p.WaitForExit();
                //開始同步讀取
                //p.StandardError.ReadToEnd();               
                if (!File.Exists(swfPath))
                    return false;
                return true;
            }
            catch (IOException ioex)
            {
                throw new IOException(ioex.Message);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            finally
            {
                if (p != null)
                {
                    //關閉進程
                    p.Close();
                    //釋放資源
                    p.Dispose();
                }
            }

        }

三.小結

   在本文中介紹了在C#中如何操作外部程式和線程的類System.Diagnostics.Process,並介紹了該類的一些常用方法的底層實現代碼,如果需要對該類進行詳細的瞭解,可以根據MSDN和.NET底層源碼的相關註釋和文章進行細緻的學習。在介紹完實現操作的類的同時,也對Swftools插件做了一個說明,併列舉了相關的參數,如果在項目中有較高的要求,可以根據官方提供的API文檔進行重構。

   在項目開發中,任何一個功能是無法做法完成所有的功能,在編碼功能時,只能儘可能的考慮到方法的通用性,在理解了某一個類和某一個插件的基本原理和使用方法後,可以根據對應的API進行添加新功能。

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這幾天在Python程式員的微信訂閱號中總是見到yield的關鍵字,才想起來在C#中也是有yield,但是只是知道有,從來沒有瞭解過他的用法,今天有時間就來看看是怎麼使用的。剛開始肯定就是搜索一下用法了,找到兩篇說明示例,一是 C# 中的"yield"使用,第二個是MSDN的官方api yield( ...
  • 這篇文章主要介紹了C#中AS和IS關鍵字的用法的相關資料,需要的朋友可以參考下 ...
  • 頁面引用相應的js以及css 因為SpreaJS是用jquery操作的所以要引用一個jquery的js,第二個js以及最後的css是SpreaJS本身需要引用的,第三個js是做列印才會用到的。 html里只需要放一個div就可以了,相當於SpreaJS的容器。 <div id="ss" style= ...
  • 一、前言 1.0、由於沒有寫過那種通用爬蟲的框架,就四處搜了一下,也找到很多資料,這裡就採用了其中一個大神介紹的框架模式。具體引用地址我忘記了,這裡就不貼出來了。 2.0、之前說的驗證碼模塊也停了,到時候集合在這個分類一面一起說 二、正文 2.1、框架設計圖 2.2、由上面這張圖可以看出各個模塊之間 ...
  • 感謝您的閱讀。喜歡的、有用的就請大哥大嫂們高抬貴手“推薦一下”吧!你的精神支持是博主強大的寫作動力以及轉載收藏動力。歡迎轉載! 版權聲明:本文原創發表於 【請點擊連接前往】 ,未經作者同意必須保留此段聲明!如有問題請聯繫我,侵立刪,謝謝! 我的博客:http://www.cnblogs.com/GJ ...
  • 完善了下 文件中的文件及文件夾中的複製!如果有更優解決方案請不吝指教 protected void FileDepthCopy(string source, string target) { if (Directory.Exists(source))//判斷源文件是否存在 { if (!Direct ...
  • 常用的一些開源組件整理: 導出Excel報表的插件:NOPI.dll(基於微軟OpenXml實現)開源的作業調度和自動任務框架:Quartz.NET用於大數據搜索引擎的全文檢索框架:Lucene.net微軟針對企業級應用開發的最佳實踐組件:Enterprise Library 5.0國外一個牛人寫的 ...
  • MVVM是一個比較熱門的開發框架,儘管已經出現很久了,仍然比較受歡迎。MVVM框架包括: M:Model;Model指的是數據模型,例如你要在頁面展示聯繫人信息,那麼Model就是聯繫人的模型,包括聯繫人的名字,電話號碼,頭像等。。。 V:View;View指的是展示的頁面,比如你所現在看到的這篇文 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...