iTextSharp操作PDF
最终版iTextSharp 5.5: https://github.com/itext/itextsharp ,已经被 iText 7代替。
一、介绍
iTextSharp:是一个从JAVA项目iText衍生的.Net版本的开源项目。iText是一个PDF库,可让您创建,移植,检查和维护可移植文档格式(PDF)的文档,从而使您可以轻松地向软件项目添加PDF功能。我们甚至提供文档来帮助您进行编码。
可以操作PDF的库还有
- PDFsharp :PDFsharp是一个开源.NET库,它可以通过任何.NET语言轻松地动态创建和处理PDF文档。相同的绘图例程可用于创建PDF文档,在屏幕上绘图或将输出发送到任何打印机。
https://www.nuget.org/packages/PDFsharp/ - Aspose.PDF:用于.NET的Aspose.PDF是PDF文档创建和处理组件,它使您的.NET应用程序无需使用Adobe Acrobat即可读取,编写和处理现有的PDF文档。它还允许您创建表单并管理嵌入PDF文档中的表单字段。
https://www.nuget.org/packages/Aspose.PDF/ - Spire.PDF:Spire.PDF for .NET是一个通用的PDF库,使软件开发人员可以在自己的.NET应用程序中生成,编辑,阅读和操作PDF文件。作为独立的PDF组件,Spire.PDF for .NET无需安装Adobe Acrobat,即可为用户提供令人难以置信的丰富功能。
https://www.nuget.org/packages/Spire.PDF/ - Rotativa:是一个提供免费API的框架,用于提供在ASP.NET MVC应用程序中打印PDF文档的极其简单的方法。Rotativa基于wkhtmltopdf工具,用于在HTML中创建一个在浏览器中呈现的PDF文档。
https://www.nuget.org/packages/Rotativa/
二、使用
1.下载安装组件
首先下载该组件并添加引用,这里是使用VS自带的NuGet来进行安装的,键项目选择管理NuGet程序包,搜索iTextSharp选择合适版本安装即可,安装完成会自动添加引用。
iTextSharp最新版本为5.5.13.1
2、创建文档
在使用的文件里面引入命名空间
using iTextSharp.text; using iTextSharp.text.pdf;
Document对象:页面对象,就像是HTML里面的页面对象一样,用于操作页面内容和格式。通过Document对象的实例来操作内存中的pdf文件。
Document document = new Document();
(1)自定义文档的大小和边距
Document对象默认的文档大小是A4(也就是210毫米x297毫米,或是8.26英尺x11.69英尺),页边距默认都是半英尺。
很多时候,你并不希望通过默认设置创建默认大小,默认边距的PDF文档,所以iTextSharp允许你自定义这些设置,所以Document对象还提供了其他两个构造函数:
public Document(iTextSharp.text.Rectangle pageSize); public Document(iTextSharp.text.Rectangle pageSize, float, float, float, float);
第一个构造函数可以这样使用:
var doc = new Document(PageSize.A5);
PageSize类包含了一系列Rectangle对象代表了大多数纸张的大小,从A0到A10,B0到B10,legal,分类账,信封,明信片,剪报等,如果PageSize类内的纸张大小无法满足你的需求,你可以自定义一个Rectangle对象,对其设置值后作为参数传给Document构造函数:
var doc = new Document(new Rectangle(100f, 300f));
上面代码中,创建的PDF文档为100像素宽,300像素长,因为是72像素/英尺,所以这个文档并不大,实际上为1.39 英尺 x 4.17 英尺.
第二个构造函数以Rectangle和四个float类型的数字作为参数允许你通过float类型的变量自定义页边距,同样,单位是像素,默认半英尺的像素为36像素。
Document document = new Document(new Rectangle(1000, 500), 10, 10, 120, 80);
(2)设置文档的背景色
如果你使用PageSize类的构造函数,或者是自定义Rectangle,你还可以为文档设置背景色。这个设置可以通过RGB颜色值,或是CMYK值。设置文档的背景色,通过Rectangle对象的BackgroundColorproperty进行设置:
r.BackgroundColor = new CMYKColor(25, 90, 25, 0); r.BackgroundColor = new Color(191, 64, 124);
3、保存文档
PdfWriter对象:用于将Document对象写入PDF文件。
将内存中的Document对象保存到硬盘中,使用PdfWriter类来实现这个功能:
Document document = new Document(new Rectangle(1000, 500), 10, 10, 120, 80); PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(@"D:\aa.pdf", FileMode.Create)); //先打开文档,往里写一段内容,最后关闭文档 document.Open(); document.Add(new iTextSharp.text.Paragraph("Hello World! Hello People! Hello Sky! Hello Sun! Hello Moon! Hello Stars!")); document.Close(); writer.Close();
4、设置字体
iTextSharp默认支持14种字体,分别为:Courier, Courier Bold, Courier Italic, Courier Bold and Italic, Helvetica, Helvetica Bold, Helvetica Italic, Helvetica Bold and Italic, Times New Roman, Times Roman Bold, Times Roman Italic, Times Roman Bold and Italic, Symbol, ZapfDingBats®。
iTextSharp的默认字体为Helvetica, 12pt,黑色,也就是所谓的正常(Normal)字体。
iTextSharp提供了3种主要方式来设置字体:
- 一种是使用BaseFont.CreateFont()方法,BaseFont.CreateFont()有很多局限性,表现在仅仅是生成一个新的字体定义。
下面的代码创建了一个BaseFont对象并且使用内置的constant值来设置字体类型和编码类型。在是否将字体嵌入PDF中选择了False以减少PDF的大小使用BaseFont来创建一个新的Font对象。
下一行代码进一步从字体大小,字体风格,颜色来设置字体,当然,我们依然使用内置的constant类型值,然后,将上述风格字体加入段落: - 第二种方法是使用FontFactory.GetFont()方法。返回一个你可以直接操作的Font对象。并且提供了14种不同的重载来给你提供更多选项。包括:字体,颜色, 风格,是否嵌入,编码以及缓存等。
每次你调用FontFactory.GetFont()时都会返回一个新的对象。这个方法对于字体的设置可以对任何在iTextSharp中注册的字体进行生效。
在iTextSharp中注册的字体包括windows字体的默认目录,这个目录一般为”C:/WINDOWS/Fonts”,如果你想知道哪些字体在iTextSharp中已注册,FontFactory.RegisteredFonts将会告诉你答案,查看这个列表对于我们想获得确切的字体名称尤为重要。
下面的一些方法使用iTextSharp的Color对象的constant值来设置字体颜色,还有诸如使用SetColor()方法传入RGB值或是New一个Color对象传入。通常情况下,我们都可以传入int值作为字体风格参数,或者使用SetStyle()方法传入一个字符串。 - 第三种方法是直接生成一个新的Font对象。
有时候你会遇到在WEB服务器上你没有权限安装字体,这时你必须显式在iTextSharp中注册字体了。
下面代码中你也许会注意到字体文件是嵌入PDF中的(BaseFont.EMBEDDED),因为很多情况下你创建的PDF中的字体在用户的电脑上并不存在。
BaseFont bfTimes = BaseFont.CreateFont(BaseFont.TIMES_ROMAN, BaseFont.CP1252, false); Font times = new Font(bfTimes, 12, iTextSharp.text.Font.ITALIC, iTextSharp.text.BaseColor.RED); document.Add(new iTextSharp.text.Paragraph("Hello World!", times));
int totalfonts = FontFactory.RegisterDirectory("C:\\WINDOWS\\Fonts"); StringBuilder sb = new StringBuilder(); foreach (string fontname in FontFactory.RegisteredFonts) { sb.Append(fontname + "\n"); } document.Add(new Paragraph("All Fonts:\n" + sb.ToString())); Font arial = FontFactory.GetFont("Arial", 28, iTextSharp.text.BaseColor.GRAY); Font verdana = FontFactory.GetFont("Verdana", 16, Font.BOLDITALIC, new iTextSharp.text.BaseColor(125, 88, 15)); Font palatino = FontFactory.GetFont("palatino linotype italique", BaseFont.CP1252, BaseFont.EMBEDDED, 10, Font.ITALIC, iTextSharp.text.BaseColor.GREEN); Font smallfont = FontFactory.GetFont("Arial", 7); Font x = FontFactory.GetFont("nina fett"); x.Size = 10; x.SetStyle("Italic");
BaseFont customfont = BaseFont.CreateFont("./myspecial.ttf", BaseFont.CP1252, BaseFont.EMBEDDED); Font font = new Font(customfont, 12); string s = "My expensive custom font."; doc.Add(new Paragraph(s, font));
4.设置PDF文档信息,利用Document对象。
document.AddTitle("这里是标题"); document.AddSubject("主题"); document.AddKeywords("关键字"); document.AddCreator("创建者"); document.AddAuthor("作者");
5、利用块,短语,段落添加文本
- 块(Chunks)是容纳文本的最小容器,就像ASP.Net中的<asp:Label>一样,可以使用”\n”或者Environment.NewLine,或者Chunk.NEWLINE作为给Chunk对象赋值的一部分。Chunk有一系列方法允许你为文本设置样式,比如setUnderLine(), setBackGround(), 和 setTextRise()以及一些构造函数来设置字体类型以及风格。
- 短语(Phrase)是比Chunk大一级的容器,Phrase可以理解为一组Chunk,并且会在长度超过文档宽度后自动换行,每一行之间的行距(测量方法其实是每行底部之间的距离)是字体大小的1.5倍,因为在iTextSharp行距之间的举例是12pt,所以下面代码之间的行距为16pt.你可以在Phrase初始化的时候设置字体和行距.当然也可以通过其多种构造函数重载来在初始化时为Phrase添加内容.
- 段落(Paragraphs)是用的最多的类是.Paragraph其实是一组有序Phrase和Chunk的集合。Paragraph派生于Phrase,所以和Phrase一样,Paragraph也会在长度超过文档长度时自动换行。不仅如此,Paragraph和Paragraph之间也会自动空一行(就像文字处理软件那样)。
下面代码中,我会将格式化的文本通过Chunk和Phrase来添加到Paragraphs中:每一个设置了风格样式的字体都需要包含在一个Chunk中,然后再将Chunk添加到Phrase来确保文字会自动换行,最后,所有Phrase和Chunk都会被添加到Paragraph对象中。还可以通过Paragraph.setAlignment()设置Paragraph的对齐方式,这个方法接受一个String类型的参数,可以是"Left", "Center", "Justify",和 "Right".下面是设置p.setAlignment("Justify");居中的显示效果:
string text = @"The result can be seen below, which shows the text having been written to the document but it looks a mess. Chunks have no concept of how to force a new . "; text = text.Replace(Environment.NewLine, String.Empty).Replace(" ", String.Empty); Font courier = FontFactory.GetFont(BaseFont.COURIER, 12f); courier.Color = BaseColor.GRAY; Chunk beginning = new Chunk(text, courier); Phrase p1 = new Phrase(beginning); Chunk ending = new Chunk("You can of course force a newline using \"", courier); Phrase p2 = new Phrase(); p2.Add(ending); Paragraph p = new Paragraph(); p.Add(p1); p.Add(p2); document.Add(p);
6、列表
在iTextSharp中列表的创建是通过iTextSharp.text.List对象实现的。列表实质上是iTextSharp.text.ListItem的集合.也就是由ListItem组成的数组.ListItem继承了Paragraph对象(而Paragraph对象继承于Phrase,Phrase又继承于Arraylist),所以生成的每一个List都会自动换行.就如同List在HTML分为<ul>和<ol>一样,iTextSharp中列表同样分为有序列表和无序列表.下面我们来直接看如何生成列表的代码:
第一件事是创建一个List对象,并传入一个布尔类型的参数告诉List生成的是有序或无序列表.默认是False(也就是无序列表), 第二个参数(float类型)传入List的构造函数,用于将每一个列表项的缩进设置成10(也就是列表符号和列表项第一个字符的距离。).然后我通过SetListSymbol方法将列表项符号改成更传统的”.”,最后我将整个列表向右缩进30然后为List加入了5个项。第一个项是通过匿名函数传入String参数类型来创建ListItem并传入,从第二个开始,则是直接传入String类型的参数.最后是创建一个Paragraph对象和list对象共同传入document。
如果你使用有序列表并将罗马数字作为标识,你可以使用RomanList类。
List list = new List(List.UNORDERED, 10f); list.SetListSymbol("\u2022"); list.IndentationLeft = 30f; list.Add(new ListItem("One")); list.Add("Two"); list.Add("Three"); list.Add("Four"); list.Add("Five"); Paragraph para = new Paragraph(); para.Add("Lists"); document.Add(para); document.Add(list);
5.向PDF里面添加图片。
Fimg为图片路径,创建一个iTextSharp.text.Image对象,将该对象添加到文档里面。SetAbsolutePosition方法是设置图片出现的位置。
在iTextSharp中使用Image.GetInstance()方法创建图片有很多种方式许最常用的方式是传文件的路径名:
string imgurl = @System.Web.HttpContext.Current.Server.MapPath(Fimg); iTextSharp.text.Image img = iTextSharp.text.Image.GetInstance(imgurl); img.SetAbsolutePosition(0, 0); writer.DirectContent.AddImage(img);
设置图片的属性和方法
Image jpg = Image.GetInstance("Sunset.jpg"); Paragraph paragraph = new Paragraph(@"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Suspendisse blandit blandit turpis. Nam in lectus ut dolor consectetuer bibendum. Morbi neque ipsum, laoreet id; dignissim et, viverra id, mauris. Nulla mauris elit, consectetuer sit amet, accumsan eget, congue ac, libero. Vivamus suscipit. Nunc dignissim consectetuer lectus. Fusce elit nisi; commodo non, facilisis quis, hendrerit eu, dolor? Suspendisse eleifend nisi ut magna. Phasellus id lectus! Vivamus laoreet enim et dolor. Integer arcu mauris, ultricies vel, porta quis, venenatis at, libero. Donec nibh est, adipiscing et, ullamcorper vitae, placerat at, diam. Integer ac turpis vel ligula rutrum auctor! Morbi egestas erat sit amet diam. Ut ut ipsum? Aliquam non sem. Nulla risus eros, mollis quis, blandit ut; luctus eget, urna. Vestibulum vestibulum dapibus erat. Proin egestas leo a metus?"); paragraph.Alignment = Element.ALIGN_JUSTIFIED; jpg.ScaleToFit(250f, 250f); jpg.Alignment = Image.TEXTWRAP | Image.ALIGN_RIGHT; jpg.IndentationLeft = 9f; jpg.SpacingAfter = 9f; jpg.BorderWidthTop = 36f; jpg.BorderColorTop = BaseColor.WHITE; jpg.Border = Rectangle.BOX; jpg.BorderColor = BaseColor.YELLOW; jpg.BorderWidth = 5f; document.Add(jpg); document.Add(paragraph);
6.向PDF里面添加表格,表格对象为PdfTable对象。
iTextSharp中表格元素的命名方式和HTML与CSS中非常类似。iTextSharp提供了多个类用于创建表格,为了不让读者产生混淆,这里我使用PdfPTable这个专门为在PDF中创建表格的类,下面代码展示了如何创建一个表格并将其加入PDF中:
PdfPTable table = new PdfPTable(3);//为pdfpTable的构造函数传入整数3,pdfpTable被初始化为一个三列的表格 PdfPCell cell = new PdfPCell(new Phrase("Header spanning 3 columns")); cell.Colspan = 3; cell.HorizontalAlignment = 1; //0=Left, 1=Centre, 2=Right table.AddCell(cell); table.AddCell("Col 1 Row 1"); table.AddCell("Col 2 Row 1"); table.AddCell("Col 3 Row 1"); table.AddCell("Col 1 Row 2"); table.AddCell("Col 2 Row 2"); table.AddCell("Col 3 Row 2"); document.Add(table);
为pdfpTabled添加单元格有多种方式,第一个单元格是通过PdfPCell对象添加进去的,PdfPCell的构造函数接受一个Phrase对象作为参数,然后将Cell的colspan设置为3,这样这个单元格占了整个一行.就像HTML中表格那样,单元格的水平对齐方式使用了三个值中的一个(译者:左对齐,居中,右对齐),这三个值我加在了注释中。后面的单元格我都通过AddCell方法加入,最后文档的效果如下:
下面的示例一开始被初始化为两列的表格,然后设置了表格的固定宽度,然后对每一列设置相对宽度为别为整个表格的三分之一和三分之二。如果你想将宽度设置为5分之一和是5分之四,只需要将参数分别改为1f和4f.如果你想设置每列的绝对宽度,只需要将列宽度和表格的总宽度传入
PdfPTable table = new PdfPTable(2); //actual width of table in points table.TotalWidth = 216f; //fix the absolute width of the table table.LockedWidth = true; //relative col widths in proportions - 1/3 and 2/3 float[] widths = new float[] { 1f, 2f }; table.SetWidths(widths); table.HorizontalAlignment = 0;
该类的构造函数可以设置表格的列数,new float[] { 180, 140, 140, 160, 180, 140, 194 }里面是每列的宽度,也可在构造函数里面直接写列数如:new PdfPTable(3);
接下来需要将单元格扔到表格里面,单元格为PdfPCell对象,构造函数里面可以写入单元格要显示的文本信息,其中fontb为字体,如果是显示中文必须创建中文字体:
BaseFont bsFont = BaseFont.CreateFont(@System.Web.HttpContext.Current.Server.MapPath("./upload/fonts/MSYH.TTC") + ",0", BaseFont.IDENTITY_H, BaseFont.EMBEDDED); Font fontb = new Font(bsFont, Tab_Content_FontSize, Font.BOLD, new BaseColor(0xFF, 0xFF, 0xFF));
单元格创建出来扔到表格中排列方式类似与HTML里面的流式布局,没有行一说,所以造的单元格数量和列数相挂钩才能显示正确。
PdfPTable tablerow1 = new PdfPTable(new float[] { 180, 140, 140, 160, 180, 140, 194 }); tablerow1.TotalWidth = 1000; //表格宽度 tablerow1.LockedWidth = true; //造单元格 PdfPCell cell11 = new PdfPCell(new Paragraph("单元格内容", fontb)); cell11.HorizontalAlignment = 1; cell11.PaddingBottom = 10; cell11.PaddingTop = 10; cell11.BorderColor = borderColor; cell11.SetLeading(1.2f, 1.2f); tablerow1.AddCell(cell11);//将单元格添加到表格中 document.Add(tablerow1);//将表格添加到pdf文档中
单元格格式可以进行设置:
- HorizontalAlignment:代表单元格内文本的对齐方式
- PaddingBottom和PaddingTop:为单元格内间距(下,上)
- BorderColor:边框颜色
- SetLeading():该方法设置单元格内多行文本的行间距
PdfPTable table = new PdfPTable(3); table.AddCell("Cell 1"); PdfPCell cell = new PdfPCell(new Phrase("Cell 2", FontFactory.GetFont(BaseFont.COURIER, 12f, Font.NORMAL, BaseColor.YELLOW))); cell.BackgroundColor = new BaseColor(0, 150, 0); cell.BorderColor = new BaseColor(255, 242, 0); cell.Border = Rectangle.BOTTOM_BORDER | Rectangle.TOP_BORDER; cell.BorderWidthBottom = 3f; cell.BorderWidthTop = 3f; cell.PaddingBottom = 10f; cell.PaddingLeft = 20f; cell.PaddingTop = 4f; table.AddCell(cell); table.AddCell("Cell 3"); document.Add(table);
7.图像和文本的绝对位置
将文本放到页面指定位置PdfContentByte。
PdfContent对象可以通过在使用Writer对象中使用getDirectContent()方法来得到该对象。
PdfContentByte cb = writer.DirectContent; Phrase txt = new Phrase("测试文本", fontb); ColumnText.ShowTextAligned(cb, Element.ALIGN_LEFT, txt, 425, 460, 0);
我们可以使用诸如moveTo和lineTo方法移动到页面上当前位置然后画一条直线到其他位置。例如
cb.LineWidth=10f; cb.moveTo(100,700); cb.lineTo(200,800); cb.stroke();
8.创建新的页面
如果想要创建出新一页的话需要使用代码:
document.NewPage();
如果创建的新页面需要重新开始计算页数的话,在创建新页面之前:
document.ResetPageCount();
9.添加页眉页脚及水印
添加页眉页脚及水印,页脚需要显示页数,如果正常添加很简单,但需求里面要求有背景色,有水印,而且背景色在最底层,水印在上层,文字表格等在最上层,处理这个需求是整个iTextSharp最难的地方。
先分析一下,如果在创建Rectangle对象的时候添加背景色,那么接下来加水印有两种可选情况:
1.水印加在内容下面,可选,但水印会加到背景色的下面导致水印不显示。
2.水印加在内容上面,不可选,水印会覆盖最上层的文字,实现的效果不好。
为了解决这个问题,找到了iTextSharp提供的一个接口IPdfPageEvent及PdfPageEventHelper,该接口里面有一个方法可以实现,该方法为:OnEndPage当页面创建完成时触发执行。
那么就利用这个方法来实现:先添加背景色,再添加水印,添加在内容下方即可。
实现该方法需要一个类来实现接口:
public class IsHandF : PdfPageEventHelper, IPdfPageEvent { /// <summary> /// 创建页面完成时发生 /// </summary> public override void OnEndPage(PdfWriter writer, Document document) { base.OnEndPage(writer, document); //页眉页脚使用字体 BaseFont bsFont = BaseFont.CreateFont(@System.Web.HttpContext.Current.Server.MapPath("./upload/fonts/MSYH.TTC") + ",0", BaseFont.IDENTITY_H, BaseFont.EMBEDDED); iTextSharp.text.Font fontheader = new iTextSharp.text.Font(bsFont, 30, iTextSharp.text.Font.BOLD); iTextSharp.text.Font fontfooter = new iTextSharp.text.Font(bsFont, 20, iTextSharp.text.Font.BOLD); //水印文件地址 string syurl = "./upload/images/sys/black.png"; //获取文件流 PdfContentByte cbs = writer.DirectContent;
cbs.SetCharacterSpacing(1.3f); //设置文字显示时的字间距 Phrase header = new Phrase("页眉", fontheader); Phrase footer = new Phrase(writer.PageNumber.ToString(), fontfooter); //writer.PageNumber.ToString()为页码。 //页眉显示的位置 ColumnText.ShowTextAligned(cbs, Element.ALIGN_CENTER, header, document.Right / 2, document.Top + 40, 0); //页脚显示的位置 ColumnText.ShowTextAligned(cbs, Element.ALIGN_CENTER, footer, document.Right / 2, document.Bottom - 40, 0); //添加背景色及水印,在内容下方添加 PdfContentByte cba = writer.DirectContentUnder; //背景色 Bitmap bmp = new Bitmap(1263, 893); Graphics g = Graphics.FromImage(bmp); Color c = Color.FromArgb(0x33ff33); SolidBrush b = new SolidBrush(c);//这里修改颜色 g.FillRectangle(b, 0, 0, 1263, 893); System.Drawing.Image ig = bmp; iTextSharp.text.Image img = iTextSharp.text.Image.GetInstance(ig, new BaseColor(0xFF, 0xFF, 0xFF)); img.SetAbsolutePosition(0, 0); cba.AddImage(img); //水印 iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(@System.Web.HttpContext.Current.Server.MapPath(syurl)); image.RotationDegrees = 30;//旋转角度 PdfGState gs = new PdfGState(); gs.FillOpacity = 0.1f;//透明度 cba.SetGState(gs); int x = -1000; for (int j = 0; j < 15; j++) { x = x + 180; int a = x; int y = -170; for (int i = 0; i < 10; i++) { a = a + 180; y = y + 180; image.SetAbsolutePosition(a, y); cba.AddImage(image); } } } }
该类创建完成后,在需要添加页眉页脚水印的页面代码位置添加如下代码,整个文档生成过程中添加一次即可,确保该事件可以触发,添加该代码后在剩余的页面都会触发生成页眉页脚:
writer.PageEvent = new IsHandF();
posted on 2020-06-18 09:52 springsnow 阅读(8137) 评论(0) 编辑 收藏 举报