目的


因为公司是做医疗相关软件的,所以经常和文档打交道,其中就包含了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. 使用electron将应用程序加入到系统托盘

    博主电脑

  2. 移动商城第四篇【Controller配置、添加品牌之文件上传和数据校验】

    Controller层配置 编写SpringMVC的配置文件 springmvc.xml <?xml version="1.0" encoding="UTF-8&q ...

  3. Lucene第二篇【抽取工具类、索引库优化、分词器、高亮、摘要、排序、多条件搜索】

    对Lucene代码优化 我们再次看回我们上一篇快速入门写过的代码,我来截取一些有代表性的: 以下代码在把数据填充到索引库,和从索引库查询数据的时候,都出现了.是重复代码! Directory dire ...

  4. Spring第二篇【Core模块之快速入门、bean创建细节、创建对象】

    前言 上篇Spring博文主要引出了为啥我们需要使用Spring框架,以及大致了解了Spring是分为六大模块的-.本博文主要讲解Spring的core模块! 搭建配置环境 引入jar包 本博文主要是 ...

  5. mysql不能插入中文数据

    上次遇到的是向mysql插入中文数据,中文数据乱码了.这次直接就不能插入中文数据了!!!! 参考博文:http://blog.csdn.net/generalyy0/article/details/7 ...

  6. Srping - bean的依赖注入(Dependency injection)

    目录 1 概述 2 两种基本的依赖注入方式 2.1 构造函数方式 2.2Setter方式 3 其他依赖注入功能 3.1 <ref/>标签引用不同范围的bean 3.2 内部bean 3.3 ...

  7. Python生成器主要用法

    代码如下: #!/usr/bin/env python3 # -*- coding: utf-8 -*- __author__ = '人生入戏' def use(name): print(" ...

  8. java如何将html过滤为纯文本

    java开发中jsp页面可以嵌套很多插件就可以将html形式的文本直接转化为纯文本,但是如果你已经保存下来或者没有运用插件,这个额html形式的文本你该怎么转化为纯文本呢?有次我将公告保存了html形 ...

  9. StringBuffer的替换和反转和截取功能

    A:StringBuffer的替换功能 * public StringBuffer replace(int start,int end,String str): * 从start开始到end用str替 ...

  10. JQuery中关于浏览器兼容性的问题

      前  言 LIUWE JQuery是一个特别强大的javascript代码库,,它的操作DOM的能力是相当强大的,JQuery可以说是支持各大主流浏览器,但是随着时代的不断发展,浏览器是在不断的更 ...