Pdf文件處理組件對比(Aspose.Pdf,Spire.Pdf,iText7)


目的


 

因為公司是做醫療相關軟件的,所以經常和文檔打交道,其中就包含了Pdf。醫院的Pdf(通常是他們的報告)都千奇百怪,而我們一直以來都是在用一些免費且可能已經沒人維護了的組件來處理Pdf,所以就經常出現Pdf轉亂碼,甚至直接異常的情況。跟公司管理層反應了很久,終於答應掏腰包采購一款Pdf的處理組件,並且交由我來預研。稍微調查了一下后,最終商業組件選中了 Aspose,Spire還有Leadtool這三家公司的產品,另外由於iTextSharp作為開源的Pdf處理組件太有名,所以我也把它的重寫版——iText7加入了對比的列表中,寫了一個可以方便執行的Demo項目,想了想,為了那些同樣需要Pdf相關資料的同學,也為了c# 系的開源生態,把這個項目特意整理了一下,發到了Github上,並且寫了一些簡單的使用說明。

 

GitHub的地址請戳 這里

概述


 

本項目主要以常見的五種Pdf處理來進行預研,包括“Pdf轉Jpeg”,“Pdf轉txt”,“Xps轉Pdf”,“將jpeg作為插頁插入到Pdf中”,“加水印”。

在對上面提出的四種組件進行充分調查后,直接否定了LeadTool,因為文檔太少,轉化質量也不行,官網下下來的Sample也亂得要死,所以本項目只包含了三個組件的實現 Aspose.Pdf,Spire.Pdf,iText7。

這里不得不提的就是iText雖然很有名,但功能還是不全的,至少我翻遍了文檔也沒找到把Pdf轉圖片和把Xps轉Pdf這兩個功能,如果有知道的同學麻煩留言說一聲。

 

再來看看項目的設計,整個項目功能很簡單,都是基於以上五個功能來實現的,所以我定出了這幾個功能的接口,然后所有功能組件都基於這個接口可以靈活拓展不同的處理組件,下面的代碼片段是功能接口的定義。

    public interface IPdfComponentFunc
    {
        string ComponentName { get; }
        void ToJpeg(string absoluteFilePath, string outputPath);
        void ToTxt(string absoluteFilePath, string outputPath);
        void FromXps(string absoluteFilePath, string outputPath);
        void InsertPage(string absoluteFilePath, string outputPath);
        void AddWaterprint(string absoluteFilePath, string outputPath);
    }

 

功能相信看名字就知道了,然后接下來是三個不同組件的代碼實現。

Aspose.Pdf(由於試用版只能轉4頁,一怒之下搞了個破解版)

    public class AsposePdfComponent : IPdfComponentFunc
    {
        public string ComponentName => "Aspose.Pdf";

        private const string Key = "PExpY2Vuc2U+DQogIDxEYXRhPg0KICAgIDxMaWNlbnNlZFRvPlNoYW5naGFpIEh1ZHVuIEluZm9ybWF0aW9uIFRlY2hub2xvZ3kgQ28uLCBMdGQ8L0xpY2Vuc2VkVG8+DQogICAgPEVtYWlsVG8+MzE3NzAxODA5QHFxLmNvbTwvRW1haWxUbz4NCiAgICA8TGljZW5zZVR5cGU+RGV2ZWxvcGVyIE9FTTwvTGljZW5zZVR5cGU+DQogICAgPExpY2Vuc2VOb3RlPkxpbWl0ZWQgdG8gMSBkZXZlbG9wZXIsIHVubGltaXRlZCBwaHlzaWNhbCBsb2NhdGlvbnM8L0xpY2Vuc2VOb3RlPg0KICAgIDxPcmRlcklEPjE2MDkwMjAwNDQwMDwvT3JkZXJJRD4NCiAgICA8VXNlcklEPjI2NjE2NjwvVXNlcklEPg0KICAgIDxPRU0+VGhpcyBpcyBhIHJlZGlzdHJpYnV0YWJsZSBsaWNlbnNlPC9PRU0+DQogICAgPFByb2R1Y3RzPg0KICAgICAgPFByb2R1Y3Q+QXNwb3NlLlRvdGFsIGZvciAuTkVUPC9Qcm9kdWN0Pg0KICAgIDwvUHJvZHVjdHM+DQogICAgPEVkaXRpb25UeXBlPkVudGVycHJpc2U8L0VkaXRpb25UeXBlPg0KICAgIDxTZXJpYWxOdW1iZXI+NzM4MDNhYmUtYzZkMi00MTY3LTg2MTgtN2I0NDViNDRmOGY0PC9TZXJpYWxOdW1iZXI+DQogICAgPFN1YnNjcmlwdGlvbkV4cGlyeT4yMDE3MDkwNzwvU3Vic2NyaXB0aW9uRXhwaXJ5Pg0KICAgIDxMaWNlbnNlVmVyc2lvbj4zLjA8L0xpY2Vuc2VWZXJzaW9uPg0KICAgIDxMaWNlbnNlSW5zdHJ1Y3Rpb25zPmh0dHA6Ly93d3cuYXNwb3NlLmNvbS9jb3Jwb3JhdGUvcHVyY2hhc2UvbGljZW5zZS1pbnN0cnVjdGlvbnMuYXNweDwvTGljZW5zZUluc3RydWN0aW9ucz4NCiAgPC9EYXRhPg0KICA8U2lnbmF0dXJlPm5LNVVUR3dZMWVJSEtIV0d2NW5sQUxXUy81bDEzWkFuamlvdnlBcGNqQis0ZjNGbm5yOWhjeUlzazlvVzQySWp0ZFYra2JHZlNSMUV4OUozSGlkaThCeE43aHFiR1BERXNaWGo2RlYxaGl1N2MxWmUyNEp3VGc2UnpsNUNJRHY1YVhxbDQyczBkSGw4eXpreDRBM2RTTU5KTzRiQ094a2V2OFBiOWxSaUc3ST08L1NpZ25hdHVyZT4NCjwvTGljZW5zZT4=";
        private static Stream LStream = (Stream)new MemoryStream(Convert.FromBase64String(Key));
        public AsposePdfComponent()
        {
            SetPdfLicense();
        }

        public void SetPdfLicense()
        {
            var l = new Aspose.Pdf.License();
            //l.SetLicense(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Aspose.Total.lic"));
            l.SetLicense(LStream);
        }


        public void AddWaterprint(string absoluteFilePath, string outputPath)
        {
            var watermarkImgPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DefaultResource", "waterMarkImg.jpeg");
            using (var pdfDocument = new Document(absoluteFilePath))
            using (BackgroundArtifact background = new BackgroundArtifact())
            {
                foreach (Page aPdfPage in pdfDocument.Pages)
                {
                    ImageStamp imageStamp = new ImageStamp(watermarkImgPath);
                    imageStamp.XIndent = 300;
                    imageStamp.YIndent = aPdfPage.PageInfo.Height - 200;
                    imageStamp.Height = 81;
                    imageStamp.Width = 80;
                    aPdfPage.AddStamp(imageStamp);
                }


                pdfDocument.Save(outputPath);
            }
        }

        public void FromXps(string absoluteFilePath, string outputPath)
        {
            // Instantiate LoadOption object using XPS load option
            Aspose.Pdf.LoadOptions options = new XpsLoadOptions();

            // Create document object 
            Aspose.Pdf.Document document = new Aspose.Pdf.Document(absoluteFilePath, options);

            // Save the resultant PDF document
            document.Save(outputPath);
        }

        public void InsertPage(string absoluteFilePath, string outputPath)
        {
            var insertPageImgPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DefaultResource","insertPage.jpeg");
            using (var pdfDocument = new Document(absoluteFilePath))
            using (BackgroundArtifact background = new BackgroundArtifact())
            {
                // Add a new page to document object
                Page page = pdfDocument.Pages.Insert(2);
                page.AddImage(insertPageImgPath, page.Rect);

                pdfDocument.Save(outputPath);
            }
        }

        public void ToJpeg(string absoluteFilePath, string outputPath)
        {
            using (var pdfDocument = new Document(absoluteFilePath))
            {
                for(var i = 1; i < pdfDocument.Pages.Count + 1; i++)
                {

                    using (FileStream imageStream = new FileStream(Path.Combine(outputPath, i.ToString() + ".jpeg"), FileMode.Create))
                    {
                        //Quality [0-100], 100 is Maximum
                        //create Resolution object
                        Resolution resolution = new Resolution(300);
                        JpegDevice jpegDevice = new JpegDevice(resolution, 100);

                        //convert a particular page and save the image to stream
                        jpegDevice.Process(pdfDocument.Pages[i], imageStream);

                        //close stream
                        imageStream.Close();
                    }
                }
            }
        }

        public void ToTxt(string absoluteFilePath, string outputPath)
        {
            var txtAbsorber = new TextAbsorber();
            using (var pdfDocument = new Document(absoluteFilePath))
            {
                pdfDocument.Pages.Accept(txtAbsorber);
                File.WriteAllText(outputPath, txtAbsorber.Text);
            }
        }
    }

 

不想代碼篇幅太長,所以另外兩個組件的代碼實現不貼了。

當你每實現一個接口,程序都會自動把它添加到組件(UseComponent)的下拉列表中,如下圖所示。

 

 

 

因為考慮現在開源生態國際化,所以都寫的英文,本人比較懶,也就沒做多語言。

Demo使用方法Github上都有寫明,這里只貼一下運行后的界面圖

使用組件:Aspose,執行次數:10,耗時:27473 毫秒

 

 

 

 結尾語


 

簡單地說下我這邊的一個預研結果,我這里測試了一堆以前有問題的Pdf,最終發現:

Aspose.Pdf:1,從Xps轉到Pdf的功能存在某些缺陷問題,有些Xps文檔直接拋了異常。2,轉Pdf到Image的功能對系統字體庫有依賴,如果缺少Pdf文件的字體,轉出來都是亂碼。已經聯系他們的技術團隊看是否能改善 這兩個問題,我就會選用它,目前在我這邊印象最好。

Spire.Pdf:1,Pdf轉Image的速度要比Aspose快,不過遺憾的是,帶有圖片的Pdf轉Image直接拋了異常。2,轉Txt的格式比起Aspose要差很多,但內容沒什么毛病。

iText7:1,跟Spire一樣,帶圖片的Pdf處理起來直接拋異常,而且iText沒有Xps轉Pdf和轉Jpeg功能(我翻遍了文檔沒發現)

 

值得一提的是,速度最快的是iText7,雖然它功能不全,其次是Spire,不過Aspose轉出來的東西很少會出問題,Txt的格式基本還原Pdf的原格式,反觀Spire和iText這點就很不好,全部密密麻麻排一塊去了。

 

這里只實現了我覺得比較好的三個組件來對比,如果有同學有其他更好的組件麻煩推薦下,我可以添加到組件中去,你也可以直接到Github上去Fork這份代碼然后拓展自己的組件進行研究。

最近把自己網站重構成了.net core2.0,真的感覺到微軟的良苦用心,微軟都這么推行開源了,作為從c#出身,現在卻在帶Web組的人只希望C#系的開源生態能越來越好,不然我就要投奔NodeJs了(笑)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM