C#實現 word、pdf、ppt 轉為圖片

zhuweisky發表於2015-09-01

      office word文件、pdf文件、powerpoint幻燈片是非常常用的文件型別,在現實中經常有需求需要將它們轉換成圖片 -- 即將word、pdf、ppt文件的每一頁轉換成一張對應的圖片,就像先把這些文件列印出來,然後再掃描成圖片一樣。所以,類似這種將word、pdf、ppt轉換為圖片的工具,一般又稱之為“電子掃描器”,很高階的名字!

一.那些場合需要將word、pdf、ppt轉換為圖片?

     在我瞭解的情況中,通常有如下三種場景,有將word、pdf、ppt文件轉換成圖片的需求。

1. 防止文件被別人剽竊

      如果直接將word、pdf、ppt文件提供給他人,那麼他人就可以很容易的Copy整個文件的內容,然後稍作修改,就成為了他自己的東西。

      如果我們將文件轉換為圖片之後,再提供給他人,那麼,剽竊就不僅僅是Copy一下那麼容易了。

2. 節省紙張

      以前為了更好的做到第1點,都是將文件列印出來給別人看,很多文件看一遍就不用了,所以會浪費很多紙張、浪費墨水、消耗印表機和電力。

      在倡導低碳節能的今天,使用電子掃描器的意義就更大了。

3. 電子白板課件

      類似線上教學、遠端培訓這樣的系統中,老師使用課件(word、pdf、ppt等型別的文件)是基本的需求,課件與電子白板的結合方案一般是這樣的:將課件轉換成圖片,文件的每一頁對應著電子白板的每一頁,而得到的圖片,正是作為白板頁的背景圖片。這樣,老師就可以在課件圖片上進行標註、板書了。我們前段時間研究word、pdf、ppt文件轉圖片的技術,就是為了給OMCS的電子白板功能做一個擴充套件課件型別的Demo示例,讓其方便地支援word、pdf、ppt型別的課件。

二. 如何轉換?

      問一下度娘,可以找到很多很多類似將word轉換為圖片的文章,但是,真正好用的並不多,篩選是個花時間的過程。在這裡,我們直接把篩選的結果呈現出來,並且將其封裝成可以直接複用的Class,為以後有同樣需要的人節省時間。

1. 方案一:使用Office COM元件

      (該方案不支援PDF文件,關於PDF轉圖片的方法,這裡有個很好的彙總,推薦給大家:PDF轉換成圖片的13種方案

      該方案的要求是使用者的電腦上必須安裝有微軟的Office,我們可以通過.NET與Office COM元件的互操作(Interop)來操作Office文件。

      該方案的原理是這樣的:通過COM互操作可以在記憶體中開啟Office文件,然後可以訪問文件的每一頁,並且支援將任意一頁的內容複製到貼上板(以圖的形式),這樣,我們再將貼上板上的內容儲存為圖片就搞定了。

      原理很簡單,實現程式碼稍微有點麻煩,如下所示:

    private Bitmap[] Scan4Word(string filePath)
    {          
        //複製目標檔案,後續將操作副本
        string tmpFilePath = AppDomain.CurrentDomain.BaseDirectory + "\\" + Path.GetFileName(filePath) + ".tmp";
        File.Copy(filePath, tmpFilePath);

        List<Bitmap> bmList = new List<Bitmap>();
        MSWord.ApplicationClass wordApplicationClass = new MSWord.ApplicationClass();
        wordApplicationClass.Visible = false;
        object missing = System.Reflection.Missing.Value;

        try
        {
            object readOnly = false;
            object filePathObject = tmpFilePath;

            MSWord.Document document = wordApplicationClass.Documents.Open(ref filePathObject, ref missing,
                ref readOnly, ref missing, ref missing, ref missing,
                ref missing, ref missing, ref missing, ref missing,
                ref missing, ref missing, ref missing, ref missing,
                ref missing, ref missing);

            bool finished = false; 
            while (!finished)
            {
                document.Content.CopyAsPicture(); //拷貝到貼上板
                System.Windows.Forms.IDataObject data = Clipboard.GetDataObject();
                if (data.GetDataPresent(DataFormats.MetafilePict))
                {
                    object obj = data.GetData(DataFormats.MetafilePict);
                    Metafile metafile = MetafileHelper.GetEnhMetafileOnClipboard(IntPtr.Zero); //從貼上板獲取資料
                    Bitmap bm = new Bitmap(metafile.Width, metafile.Height);
                    using (Graphics g = Graphics.FromImage(bm))
                    {
                        g.Clear(Color.White);
                        g.DrawImage(metafile, 0, 0, bm.Width, bm.Height);
                    }
                    bmList.Add(bm);
                    Clipboard.Clear();
                }       
                    
                object What = MSWord.WdGoToItem.wdGoToPage;
                object Which = MSWord.WdGoToDirection.wdGoToFirst;
                object startIndex = "1";
                document.ActiveWindow.Selection.GoTo(ref What, ref Which, ref missing, ref startIndex); // 轉到下一頁
                MSWord.Range start = document.ActiveWindow.Selection.Paragraphs[1].Range;
                MSWord.Range end = start.GoToNext(MSWord.WdGoToItem.wdGoToPage);
                finished = (start.Start == end.Start);
                if (finished) //最後一頁
                {
                    end.Start = document.Content.End;
                }

                object oStart = start.Start;
                object oEnd = end.Start;
                document.Range(ref oStart, ref oEnd).Delete(ref missing, ref missing); //處理完一頁,就刪除一頁。                    
            }               

            ((MSWord._Document)document).Close(ref missing, ref missing, ref missing);
            System.Runtime.InteropServices.Marshal.ReleaseComObject(document);

            return bmList.ToArray();
        }
        catch (Exception ex)
        {
            throw ex;
        }
        finally
        {
            wordApplicationClass.Quit(ref missing, ref missing, ref missing);
            System.Runtime.InteropServices.Marshal.ReleaseComObject(wordApplicationClass);
            File.Delete(tmpFilePath); //刪除臨時檔案
        }
    } 
COM方案

      上述的實現對於小的word文件很好用,但是,如果word文件很大,有很多頁,那麼,上述呼叫就會佔用很大的記憶體。

       如果是這種情況,那麼,可以將上面的實現改寫一下,沒得到一頁的圖片就將其儲存到硬碟,而不用在記憶體中儲存了。

       PPT轉為圖片也是用同樣的COM方式,文末會給出word和ppt轉圖片的COM實現的class下載。

2. 方案二:使用Aspose元件

       使用Aspose元件的好處是,不需要使用者的機器上安裝Office,也可以完成我們想要的功能。這個優勢實在是太明顯了,所以,這是最推薦的方案。而且,Aspose完全支援word、ppt、和pdf,甚至excel也沒問題。

       我們在演示如何擴充套件OMCS電子白板課件型別的示範Demo中,採用的就是Aspose元件,感覺很穩定很好用。下面的程式碼就摘自示範Demo中。

    public class Word2ImageConverter : IImageConverter
    {
        private bool cancelled = false;
        public event CbGeneric<int, int> ProgressChanged;
        public event CbGeneric ConvertSucceed;
        public event CbGeneric<string> ConvertFailed;

        public void Cancel()
        {
            if (this.cancelled)
            {
                return;
            }

            this.cancelled = true;
        }

        public void ConvertToImage(string originFilePath, string imageOutputDirPath)
        {
            this.cancelled = false;
            ConvertToImage(originFilePath, imageOutputDirPath, 0, 0, null, 200);
        }

        /// <summary>
        /// 將Word文件轉換為圖片      
        /// </summary>
        /// <param name="wordInputPath">Word檔案路徑</param>
        /// <param name="imageOutputDirPath">圖片輸出路徑,如果為空,預設值為Word所在路徑</param>      
        /// <param name="startPageNum">從PDF文件的第幾頁開始轉換,如果為0,預設值為1</param>
        /// <param name="endPageNum">從PDF文件的第幾頁開始停止轉換,如果為0,預設值為Word總頁數</param>
        /// <param name="imageFormat">設定所需圖片格式,如果為null,預設格式為PNG</param>
        /// <param name="resolution">設定圖片的畫素,數字越大越清晰,如果為0,預設值為128,建議最大值不要超過1024</param>
        private void ConvertToImage(string wordInputPath, string imageOutputDirPath, int startPageNum, int endPageNum, ImageFormat imageFormat, int resolution)
        {
            try
            {
                Aspose.Words.Document doc = new Aspose.Words.Document(wordInputPath);

                if (doc == null)
                {
                    throw new Exception("Word檔案無效或者Word檔案被加密!");
                }
                if (imageOutputDirPath.Trim().Length == 0)
                {
                    imageOutputDirPath = Path.GetDirectoryName(wordInputPath);
                }
                if (!Directory.Exists(imageOutputDirPath))
                {
                    Directory.CreateDirectory(imageOutputDirPath);
                }  
                if (startPageNum <= 0)
                {
                    startPageNum = 1;
                }
                if (endPageNum > doc.PageCount || endPageNum <= 0)
                {
                    endPageNum = doc.PageCount;
                }
                if (startPageNum > endPageNum)
                {
                    int tempPageNum = startPageNum; startPageNum = endPageNum; endPageNum = startPageNum;
                }
                if (imageFormat == null)
                {
                    imageFormat = ImageFormat.Png;
                }
                if (resolution <= 0)
                {
                    resolution = 128;
                }
                string imageName = Path.GetFileNameWithoutExtension(wordInputPath);
                ImageSaveOptions imageSaveOptions = new ImageSaveOptions(SaveFormat.Png);
                imageSaveOptions.Resolution = resolution;
                for (int i = startPageNum; i <= endPageNum; i++)
                {
                    if (this.cancelled)
                    {
                        break;
                    }
                    MemoryStream stream = new MemoryStream();
                    imageSaveOptions.PageIndex = i - 1;
                    string imgPath = Path.Combine(imageOutputDirPath, imageName) + "_" + i.ToString("000") + "." + imageFormat.ToString();
                    doc.Save(stream, imageSaveOptions);
                    Image img = Image.FromStream(stream);
                    Bitmap bm = ESBasic.Helpers.ImageHelper.Zoom(img, 0.6f);
                    bm.Save(imgPath, imageFormat);
                    img.Dispose();
                    stream.Dispose();
                    bm.Dispose();

                    System.Threading.Thread.Sleep(200);
                    if (this.ProgressChanged != null)
                    {
                        this.ProgressChanged(i - 1, endPageNum);
                    }
                }
                if (this.cancelled)
                {
                    return;
                }
                if (this.ConvertSucceed != null)
                {
                    this.ConvertSucceed();
                }
            }
            catch (Exception ex)
            {
                if (this.ConvertFailed != null)
                {
                    this.ConvertFailed(ex.Message);
                }
            }
        }
    } 

       程式碼相當簡潔。在原始碼中,我們提供了Word2ImageConverter 、Pdf2ImageConverter 、Ppt2ImageConverter來分別用於word文件、pdf文件、ppt幻燈片到圖片的轉換。

  有一點要注意的是,Aspose沒有直接提供ppt轉圖片的API,但是,它提供了將ppt轉為pdf的功能,所以,原始碼中實現ppt轉圖片是經過了pdf中轉的,即:先將ppt文件轉換為pdf文件,然後,在將pdf文件轉換成圖

三. 程式碼下載

1.方案一程式碼下載

      方案一使用的Office COM互操作實現的,支援將word文件和ppt文件轉成圖片,class原始碼下載:

      OfficeScanner.cs

2.方案二程式碼下載

       方案二的原始碼可以從我們的示範demo中提取(客戶端專案中的ImageConverters.cs檔案)。我們的示範demo用於模擬線上教育系統的場景:一個老師和N個學生進入同一個教室,所以,它們將看到同一個電子白板。老師可以上傳課件、開啟課件、在白板課件上標註、板書等。該Demo在開啟課件的時候,就用到了上面的將word、pdf、ppt轉換為圖片的功能。大家可以執行demo,看看具體的效果。

       白板課件Demo   

 執行Demo進行測試時,可按如下流程:

(1)啟動OMCS服務端。

(2)啟動第一個客戶端,選擇“老師”角色,登入進預設教室。

(3)再啟動多個客戶端,選擇“學生”角色,登入進預設教室。

(4)老師即可進行上傳課件、開啟課件、刪除課件、課件翻頁,在課件上標註、書寫,等等操作。  

老師端執行介面截圖:  

    

 

敬請了解:

ESFramework通訊框架     OMCS網路語音視訊框架     MFile語音視訊錄製元件    MCapture語音視訊採集元件  StriveEngine輕量級通訊引擎    OAUS 自動升級系統 

 

相關文章