原文地址:Create/Read Advance PDF Report using iTextSharp in C# .NET: Part I By Debopam Pal, 27 Nov 2013html
到PDF原文介绍了iTextSharp这个类库,并演示了一些基本的操做,基本属于入门级别的,惋惜做者并无在编写后续的文章。java
刚好本身也在学习这个类库,想实现一个导出ASPX页面到PDF的功能,如做者所说,网上找到的示例好多都是针对旧版本iTextSharp编写的,还有些驴唇不对马嘴,并且,不少照抄的连验证都省了,一点价值都没有。这篇文章算是详实的入门文章,实例也都基本操做了一遍实现没有问题。c#
ps.:第一次翻译老外的文章,英语水平通常,有些地方词不达意,还望海涵,若是出入但愿帮忙指出。api
下面内容是在更新版本后添加的:
最近我一直在寻找一个高级的工具来建立复杂的PDF报告用在C#.NET中,我找到了iTextSharp
.主要的问题是iTextSharp
.缺少文档。好吧,有少许的C#代码例子,可是那些对初学者来讲是不够的而且这些示例代码都是创建在iTextSharp
的旧版本上,在最新版本上有不少变化。因此,对初学者来讲转换旧版本到新版本比较困难。此外,我认为假如我写一篇关于iTextSharp
的文章,它能帮助我同时也能做为往后的参考,我将为每个功能点书写示例。老实说,在这篇文章,我编写的全部示例,你都能在《iText in Action, Second Edition》这本书的第一节找到,这本书是针对Java开发者编写的。我将在个人文章中解释[从java到c#]这本书余下章节的全部的示例.因此,若是有人对这个库(iTextSharp
)感兴趣,这里将是一个好的开始。ruby
想知道关于(iTextSharp
)的更多细节,能够经过他们的官方网站了解app
或者 你能够从下面这个SourceForge的连接下载DLL,而后参照下面步骤:ide
iTextSharp.text
iTextSharp.text.pdf
System.IO.FileStream
对象: FileStream fs = new FileStream("Chapter1_Example1.pdf", FileMode.Create, FileAccess.Write, FileShare.None);
iTextSharp.text.Document
对象:Document doc = new Document();
iTextSharp.text.pdf.PdfWriter
对象: 它有助于把Document书写到特定的FileStream:PdfWriter writer = PdfWriter.GetInstance(doc, fs);
doc.Open();
doc.Add(new Paragraph("Hello World"));
doc.Close();
建立一个特定大小的页面,咱们须要建立一个iTextSharp.text.Rectangle
对象同时传递一个页面大小的参数到它的构造函数里面,下面是定义页面大小的方法:函数
iTextSharp
里面页面大小的单位是‘point。72point=1英寸。假设咱们须要一个宽度=2英寸&高度=10英寸的PDF文件,那么咱们须要144pt&72pt,让咱们看下该怎么作: Rectangle rec = new Rectangle(144, 720);
iTextSharp.text.PageSize
类定义: Rectangle rec2 = new Rectangle(PageSize.A4);下面是内建的版面大小。. 完整的页面大小说明连接 Documentation of Page Size:
_11X17
A0
A1
A10
A2
A3
A4
A4_LANDSCAPE
A5
A6
A7
A8
A9
ARCH_A
ARCH_B
ARCH_C
ARCH_D
ARCH_E
B0
B1
B10
B2
B3
B4
B5
B6
B7
B8
B9
CROWN_OCTAVO
CROWN_QUARTO
DEMY_OCTAVO
DEMY_QUARTO
EXECUTIVE
FLSA
FLSE
HALFLETTER
ID_1
ID_2
ID_3
LARGE_CROWN_OCTAVO
LARGE_CROWN_QUARTO
LEDGER
LEGAL
LEGAL_LANDSCAPE
LETTER
LETTER_LANDSCAPE
NOTE
PENGUIN_LARGE_PAPERBACK
PENGUIN_SMALL_PAPERBACK
POSTCARD
ROYAL_OCTAVO
ROYAL_QUARTO
SMALL_PAPERBACK
TABLOID
Rectangle rec3 = new Rectangle(PageSize.A4.Rotate());
如今,把刚刚的这个 iTextSharp.text.Rectangle
对象 (任意一个)也就是上面的 'rec',或者 'rec2'或者 'rec3'加入iTextSharp.text.Document
's 的构造函数中:工具
Document doc = new Document(rec);
有几种方式来设置背景色:oop
iTextSharp.text.BaseColor
. 实例化BaseColor 采用System.Drawing.Color (.NET)对象或者你也能够用传递RGB值的形式来定义: rec.BackgroundColor = new BaseColor(System.Drawing.Color.WhiteSmoke);
iTextSharp.text.pdf.CMYKColor
. CMYKColor 经过传递 CMYK 值的方式来构造: rec2.BackgroundColor = new CMYKColor(25, 90, 25, 0);
页边距能够像设置版面大小同样来定义
加入咱们设置以下的页边距:
因此咱们须要分别设置页面的 Left, Right, Top, Bottom 页边距使用point单位,由于咱们知道 iTextSharp
中是使用point做为单位的,而且 72 points = 1 inch.
实现以下:
Document doc = new Document(PageSize.A4, 36, 72, 108, 180);
Alignment
是iTextSharp.text.Paragraph
对象的属性. iTextSharp
提供了各类对齐方式. 能够经过iTextSharp.text.Element
类设置对其.如下是iTextSharp提供的对齐方式:
ALIGN_BASELINE
[^]ALIGN_BOTTOM
[^]ALIGN_CENTER
[^]ALIGN_JUSTIFIED
[^]ALIGN_JUSTIFIED_ALL
[^]ALIGN_LEFT
[^]ALIGN_MIDDLE
[^]ALIGN_RIGHT
[^]ALIGN_TOP
[^]ALIGN_UNDEFINED
[^]咱们已经知道在 iTextSharp.text.Document
的构造函数中须要iTextSharp.text.Paragraph
对象,因此在建立Paragraph对象之后咱们能够设置它的对齐方式,咱们能够在Document建立过程把Prargraph传递进去.
实现以下:
Paragraph para = new Paragraph("Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World"); // Setting paragraph's text alignment using iTextSharp.text.Element class para.Alignment = Element.ALIGN_JUSTIFIED; // Adding this 'para' to the Document object doc.Add(para);
下面这些PDF文档的元信息 你能够经过iTextSharp.text.Document
建立的对象doc
(上文的doc)里面的方法来设置:
下面是他们的一些实现:
// Setting Document properties e.g. // 1. Title // 2. Subject // 3. Keywords // 4. Creator // 5. Author // 6. Header doc.AddTitle("Hello World example"); doc.AddSubject("This is an Example 4 of Chapter 1 of Book 'iText in Action'"); doc.AddKeywords("Metadata, iTextSharp 5.4.4, Chapter 1, Tutorial"); doc.AddCreator("iTextSharp 5.4.4"); doc.AddAuthor("Debopam Pal"); doc.AddHeader("Nothing", "No Header");
如今,打开一个PDF文档后,右键->属性,你会看到刚才设置的信息:
咱们能够经过iTextSharp.text.Document
的NewPage()
方法建立新页面,咱们来建立5个PDF文档(页面) :
for (int i = 1; i <= 5; i++) { doc.NewPage(); doc.Add(new Paragraph(string.Format("This is a page {0}", i))); }
咱们可使用iTextSharp.text.pdf.PdfReader
对象读取一个PDF文档,而后使用 iTextSharp.text.pdf.PdfStamper
对象来把它写到另外一个PDF文档。实现以下:
string originalFile = "Original.pdf"; string copyOfOriginal = "Copy.pdf"; using (FileStream fs = new FileStream(originalFile, FileMode.Create, FileAccess.Write, FileShare.None)) using (Document doc = new Document(PageSize.LETTER)) using (PdfWriter writer = PdfWriter.GetInstance(doc, fs)) { doc.Open(); doc.Add(new Paragraph("Hi! I'm Original")); doc.Close(); } PdfReader reader = new PdfReader(originalFile); using (FileStream fs = new FileStream(copyOfOriginal, FileMode.Create, FileAccess.Write, FileShare.None)) // Creating iTextSharp.text.pdf.PdfStamper object to write // Data from iTextSharp.text.pdf.PdfReader object to FileStream object using (PdfStamper stamper = new PdfStamper(reader, fs)) { }
再iTextSharp
中,PDF文档建立后能够添加水印,在这里我将使用iTextSharp.text.pdf.PdfLayer
为已有的PDF文档(Original.pdf
)添加水印。实现以下:
string watermarkedFile = "Watermarked.pdf"; // Creating watermark on a separate layer // Creating iTextSharp.text.pdf.PdfReader object to read the Existing PDF Document PdfReader reader1 = new PdfReader(originalFile); using (FileStream fs = new FileStream(watermarkedFile, FileMode.Create, FileAccess.Write, FileShare.None)) // Creating iTextSharp.text.pdf.PdfStamper object to write Data from iTextSharp.text.pdf.PdfReader object to FileStream object using (PdfStamper stamper = new PdfStamper(reader1, fs)) { // Getting total number of pages of the Existing Document int pageCount = reader1.NumberOfPages; // Create New Layer for Watermark PdfLayer layer = new PdfLayer("WatermarkLayer", stamper.Writer); // Loop through each Page for (int i = 1; i <= pageCount; i++) { // Getting the Page Size Rectangle rect = reader1.GetPageSize(i); // Get the ContentByte object PdfContentByte cb = stamper.GetUnderContent(i); // Tell the cb that the next commands should be "bound" to this new layer cb.BeginLayer(layer); cb.SetFontAndSize(BaseFont.CreateFont( BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED), 50); PdfGState gState = new PdfGState(); gState.FillOpacity = 0.25f; cb.SetGState(gState); cb.SetColorFill(BaseColor.BLACK); cb.BeginText(); cb.ShowTextAligned(PdfContentByte.ALIGN_CENTER, watermarkText, rect.Width / 2, rect.Height / 2, 45f); cb.EndText(); // Close the layer cb.EndLayer(); } }
实现结果以下:
Whenever we add Layer in PDF Document, then the content of the Layer resides under OCG
Group. So if I remove this Layer we can remove the content of the Layer also e.g. here it is Watermark Text. To remove all the Layers from PDF Document, you have to remove OCG Group completely from the Document usingreader.Catalog.Remove(PdfName.OCPROPERTIES)
. Now follow the Steps below to remove the Watermark Text from Layer:
iTextSharp.text.pdf.PdfReader
's objectiTextSharp.text.pdf.PdfDictionary
's object using GetPageN(int pageNumber)
method of iTextSharp.text.pdf.PdfReader
's object.iTextSharp.text.pdf.PdfArray
's object usingGetAsArray(PdfName.CONTENTS)
method of iTextSharp.text.pdf.PdfDictionary
's objectiTextSharp.text.pdf.PRStream
's object usingGetAsStream(int arrayIndex)
method of iTextSharp.text.pdf.PdfArray
's objectGetStreamBytes(PRStream stream)
ofiTextSharp.text.pdf.PdfReader
classSystem.Text.Encoding.ASCII.GetString(byte[] bytes)
methodWatermarked Text
. If found then remove it by giving it zero length and zero data using two methods: Put()
& SetData()
of iTextSharp.text.pdf.PRStream
classreader
to a new document usingiTextSharp.text.pdf.PdfStamper
's object Lets Implement it:
// Removing the layer created above // 1. First we bind a reader to the watermarked file // 2. Then strip out a branch of things // 3. Finally use a simple stamper to write out the edited reader PdfReader reader2 = new PdfReader(watermarkedFile); // NOTE: This will destroy all layers in the Document, only use if you don't have any addtional layers // Remove the OCG group completely from the Document: reader2.Catalog.Remove(PdfName.OCPROPERTIES); // Clean up the reader, optional reader2.RemoveUnusedObjects(); // Placeholder variables PRStream stream; string content; PdfDictionary page; PdfArray contentArray; // Get the number of pages int pageCount2 = reader2.NumberOfPages; // Loop through each page for (int i = 1; i <= pageCount2; i++) { // Get the page page = reader2.GetPageN(i); // Get the raw content contentArray = page.GetAsArray(PdfName.CONTENTS); if (contentArray != null) { // Loop through content for (int j = 0; j < contentArray.Size; j++) { stream = (PRStream)contentArray.GetAsStream(j); // Convert to a String, NOTE: you might need a different encoding here content = System.Text.Encoding.ASCII.GetString(PdfReader.GetStreamBytes(stream)); //Look for the OCG token in the stream as well as our watermarked text if (content.IndexOf("/OC") >= 0 && content.IndexOf(watermarkText) >= 0) { //Remove it by giving it zero length and zero data stream.Put(PdfName.LENGTH, new PdfNumber(0)); stream.SetData(new byte[0]); } } } } // Write the content out using (FileStream fs = new FileStream(unwatermarkedFile, FileMode.Create, FileAccess.Write, FileShare.None)) using (PdfStamper stamper = new PdfStamper(reader2, fs)) { }
Now, we already know that, watermark cannot be add during Page creation, it have to add after document creation. So, I've created a class PDFWriterEvents
which implements the interface iTextSharp.text.pdf.IPdfPageEvent
and modify the event OnStartPage
. This interface contains a set of events from the Openning & to Closing the PDF Document. The events are following:
public void OnOpenDocument(PdfWriter writer, Document document)
public void OnCloseDocument(PdfWriter writer, Document document)
public void OnStartPage(PdfWriter writer, Document document)
public void OnEndPage(PdfWriter writer, Document document)
public void OnParagraph(PdfWriter writer, Document document, float paragraphPosition)
public void OnParagraphEnd(PdfWriter writer, Document document, float paragraphPosition)
public void OnChapter(PdfWriter writer, Document document, float paragraphPosition, Paragraph title)
public void OnChapterEnd(PdfWriter writer, Document document, float paragraphPosition)
public void OnSection(PdfWriter writer, Document document, float paragraphPosition, int depth, Paragraph title)
public void OnSectionEnd(PdfWriter writer, Document document, float paragraphPosition)
public void OnGenericTag(PdfWriter writer, Document document, Rectangle rect, String text)
You may modify other events accroding to your needs which occured against a particular action. Let see the which I've created:
// Creating Watermark inside OnStartPage Event by implementing IPdfPageEvent interface // So that, dusring Page Creation, Watermark will be create class PDFWriterEvents : IPdfPageEvent { string watermarkText; float fontSize = 80f; float xPosition = 300f; float yPosition = 800f; float angle = 45f; public PDFWriterEvents(string watermarkText, float fontSize = 80f, float xPosition = 300f, float yPosition = 400f, float angle = 45f) { this.watermarkText = watermarkText; this.xPosition = xPosition; this.yPosition = yPosition; this.angle = angle; } public void OnOpenDocument(PdfWriter writer, Document document) { } public void OnCloseDocument(PdfWriter writer, Document document) { } public void OnStartPage(PdfWriter writer, Document document) { try { PdfContentByte cb = writer.DirectContentUnder; BaseFont baseFont = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.EMBEDDED); cb.BeginText(); cb.SetColorFill(BaseColor.LIGHT_GRAY); cb.SetFontAndSize(baseFont, fontSize); cb.ShowTextAligned(PdfContentByte.ALIGN_CENTER, watermarkText, xPosition, yPosition, angle); cb.EndText(); } catch (DocumentException docEx) { throw docEx; } } public void OnEndPage(PdfWriter writer, Document document) { } public void OnParagraph(PdfWriter writer, Document document, float paragraphPosition) { } public void OnParagraphEnd(PdfWriter writer, Document document, float paragraphPosition) { } public void OnChapter(PdfWriter writer, Document document, float paragraphPosition, Paragraph title) { } public void OnChapterEnd(PdfWriter writer, Document document, float paragraphPosition) { } public void OnSection(PdfWriter writer, Document document, float paragraphPosition, int depth, Paragraph title) { } public void OnSectionEnd(PdfWriter writer, Document document, float paragraphPosition) { } public void OnGenericTag(PdfWriter writer, Document document, Rectangle rect, String text) { } }
Lets see how & when you use the object of this class:
using (FileStream fs = new FileStream( "Watermark_During_Page_Creation.pdf", FileMode.Create, FileAccess.Write, FileShare.None)) using (Document doc = new Document(PageSize.LETTER)) using (PdfWriter writer = PdfWriter.GetInstance(doc, fs)) { writer.PageEvent = new PDFWriterEvents("This is a Test"); doc.Open(); doc.Add(new Paragraph("This is a page 1")); doc.Close(); }
See, OnStartPage
event called during adding a new paragraph. So I don't need to add watermark later
We can create PDF File in memory by creatig System.IO.MemorySystem
's object. Lets see:
using (MemoryStream ms = new MemoryStream()) using(Document document = new Document(PageSize.A4, 25, 25, 30, 30)) using(PdfWriter writer = PdfWriter.GetInstance(document, ms)) { document.Open(); document.Add(new Paragraph("Hello World")); document.Close(); writer.Close(); ms.Close(); Response.ContentType = "pdf/application"; Response.AddHeader("content-disposition", "attachment;filename=First_PDF_document.pdf"); Response.OutputStream.Write(ms.GetBuffer(), 0, ms.GetBuffer().Length); }
The values of the different ViewerPreferences
were originally stored in iTextSharp.text.pdf.PdfWriter
class as an integer constant. You can set the ViewerPreferences
by following two ways:
ViewerPreferences
of iTextSharp.text.pdf.PdfWriter
class. To know all theViewerPreferences
and its purpose, please read this first. E.g.- writer.ViewerPreferences = PdfWriter.HideMenubar;
AddViewerPreference(PdfName key, PdfObject value)
ofiTextSharp.text.pdf.PdfWriter
's object. To know which value
is appropiate for which key
, read thisfirst. E.g.- writer.AddViewerPreference(PdfName.HIDEMENUBAR, new PdfBoolean(true));
By SetEncryption()
method of iTextSharp.text.pdf.PdfWriter
's object, we can encrypt a PDF document. Read full documentation of this method here. To know all the encryption types, click here. E.g.-
writer.SetEncryption(PdfWriter.STRENGTH40BITS, null, null, PdfWriter.ALLOW_COPY);
Please download the source code for detail. I hope you'll understand as the source code is documented. If any doubt, just post your comment below. Thank you.
25th Nov, 2013: PART-I Release. PART-II will release soon
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)