目的


因为公司是做医疗相关软件的,所以经常和文档打交道,其中就包含了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 = ;
imageStamp.YIndent = aPdfPage.PageInfo.Height - ;
imageStamp.Height = ;
imageStamp.Width = ;
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();
page.AddImage(insertPageImgPath, page.Rect); pdfDocument.Save(outputPath);
}
} public void ToJpeg(string absoluteFilePath, string outputPath)
{
using (var pdfDocument = new Document(absoluteFilePath))
{
for(var i = ; i < pdfDocument.Pages.Count + ; 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();
JpegDevice jpegDevice = new JpegDevice(resolution, ); //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了(笑)。

Pdf文件处理组件对比(Aspose.Pdf,Spire.Pdf,iText7)的更多相关文章

  1. 【转】Python编程: 多个PDF文件合并以及网页上自动下载PDF文件

    1. 多个PDF文件合并1.1 需求描述有时候,我们下载了多个PDF文件, 但希望能把它们合并成一个PDF文件.例如:你下载的数个PDF文件资料或者电子发票,你可以使用python程序合并成一个PDF ...

  2. java操作office和pdf文件java读取word,excel和pdf文档内容

    在平常应用程序中,对office和pdf文档进行读取数据是比较常见的功能,尤其在很多web应用程序中.所以今天我们就简单来看一下Java对word.excel.pdf文件的读取.本篇博客只是讲解简单应 ...

  3. Salesforce随笔: 将Visualforce Page渲染为PDF文件(Render a Visualforce Page as a PDF File)

    参照 : Visualforce Developer Guide 第60页 <Render a Visualforce Page as a PDF File> 你可以用PDF渲染服务生成一 ...

  4. 【php导出pdf文件】php将html 导出成pdf文件(MPDF60),支持完美分页,注意是完美!!

    1.使用 MPDF60 包 2.防止中文乱码:修改MPDF/MPDF60/config.php中 $this->autoLangToFont = true; $this->autoScri ...

  5. Aspose.Pdf合并图片到PDF文件

    将图片和PDF文件合成为新的PDF文件,可以先将图片转换为PDF文件, 然后合成PDF即可, 将图片转换成PDF文件有如下方法: Aspose.Pdf.Document Aspose.Pdf.Gene ...

  6. C#如何在PDF文件添加图片印章

    文档中添加印章可以起一定的作用,比如,防止文件随意被使用,或者确保文档内容的安全性和权威性.C#添加图片印章其实也有很多实现方法,这里我使用的是免费的第三方软件Free Spire.PDF,向大家阐述 ...

  7. 如何给现有的PDF文件添加页码

    如何给现有的PDF文件添加页码 之前我写了如何打印PDF文件,有人qq问我怎样在打印时给PDF文件添加页码,的确,给PDF文件添加页码,可以帮助我们区分纸质档的PDF文件页面的先后顺序,方便我们对它的 ...

  8. C# 合并及拆分PDF文件

    C# 合并及拆分PDF文件 有时我们可能会遇到下图这样一种情况 — 我们需要的资料或教程被分成了几部分存放在多个PDF文件中,不管是阅读还是保存都不是很方便,这时我们肯定想要把这些PDF文件合并为一个 ...

  9. Pdf File Writer 中文应用(PDF文件编写器C#类库)

    该文由小居工作室(QQ:2482052910)    翻译并提供解答支持,原文地址:Pdf File Writer 中文应用(PDF文件编写器C#类库):http://www.cnblogs.com/ ...

随机推荐

  1. Java第十四周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. 2. 书面作业 1. MySQL数据库基本操作 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自 ...

  2. Optional变量初学者指南

    苹果三周前发布了Swift. 从那时起,我一直在阅读Swift的官方指南,并在Xcode 6测试版中使用. 我开始喜欢Swift的简单和语法. 与我的团队一起,我仍然在研究新的语言,并看看它与Obje ...

  3. 三分钟深入TT猫之故障转移

    结束了一周繁忙的工作,趁着周末,小编手中的键盘早已饥渴难耐了,想知道上期省略号中发生了什么有趣的故事么?且听小编娓娓道来,结尾有彩蛋. 目录 风月前场 梦回现实 模拟老鸨 会话机制 故障转移 总结 风 ...

  4. Servlet知识点大纲

    这是我整理的Servlet知识点大纲,可按照它的顺序来学习-..具体的内容在我的博客中都可以找到!

  5. 鸟哥Linux学习笔记05

    1,          文件系统通常会将 权限与属性放置到inode中,至于实际数据则放置到data block块中.另外还有一个超级块(superblock)会记录整个文件系统的整体内容,包括ino ...

  6. 部署maria数据库到linux(源码编译安装)

    maria数据库是mysql原作者另外开发的一个版本,使用方法和mysql一样,可以直接用mysql的库连接. 在这下载包并解压: https://mariadb.org/download/ 建立数据 ...

  7. getOutputStream() has already been called for this response

    错误日志里偶尔会有getOutputStream() has already been called for this response这个错误 最近发现了高概率复现条件,所以顺手解决了一下: 首先根 ...

  8. [LeetCode] 231 Power of Two && 326 Power of Three && 342 Power of Four

    这三道题目都是一个意思,就是判断一个数是否为2/3/4的幂,这几道题里面有通用的方法,也有各自的方法,我会分别讨论讨论. 原题地址:231 Power of Two:https://leetcode. ...

  9. XtraGrid滚轮翻页

    滚轮翻页与传动的翻页更为方便,经过本人一番探讨与琢磨终于在XtraGrid的GridView中实现了鼠标滚轮翻页. 我新建了一个组件继承原本的GridControl,在组件中添加了一个ImageLis ...

  10. 西邮linux兴趣小组2014纳新免试题(一)

    [第一关] 题目 0101001001100001011100100010000100011010000001110000000011001111100100000111001100000000000 ...