Bạn có một vài vấn đề mà tôi sẽ cố gắng hướng dẫn bạn.
Đầu tiên, đối tượng Document
chỉ để làm việc với các tệp PDF mới chứ không phải sửa đổi các tệp hiện có. Về cơ bản, đối tượng Document
là một loạt các lớp trình bao bọc trừu tượng ra các phần cơ bản của thông số PDF và cho phép bạn làm việc với các thứ cấp cao hơn như đoạn văn và nội dung có thể chỉnh sửa lại. Những sự trừu tượng này biến những gì bạn nghĩ về "đoạn văn" thành các câu lệnh thô mà viết đoạn văn một dòng vào một thời điểm không có mối quan hệ giữa các dòng. Khi làm việc với một tài liệu hiện có, không có cách nào an toàn để nói cách chỉnh lại văn bản để những trừu tượng này không được sử dụng.
Thay vào đó bạn muốn sử dụng đối tượng PdfStamper
. Khi làm việc với đối tượng này, bạn có hai lựa chọn về cách làm việc với nội dung chồng chéo tiềm ẩn, hoặc văn bản mới của bạn được viết trên đầu nội dung hiện có hoặc văn bản của bạn được viết bên dưới nội dung đó. Hai phương thức GetOverContent()
hoặc GetUnderContent()
đối tượng được hiển thị tức thời PdfStamper
sẽ trả lại đối tượng PdfContentByte
mà sau đó bạn có thể viết văn bản.
Có hai cách chính để viết văn bản, theo cách thủ công hoặc thông qua đối tượng ColumnText
. Nếu bạn đã thực hiện HTML, bạn có thể nghĩ đến đối tượng ColumnText
khi sử dụng hàng đơn vị cố định lớn, cột đơn <TABLE>
. Lợi thế của ColumnText
là bạn có thể sử dụng các phép trừu tượng mức cao hơn như Paragraph
.
Dưới đây là công việc đầy đủ C# 2010 WinForms nhắm mục tiêu iTextSharp 5.1.2.0 hiển thị phần trên. Xem các bình luận mã cho bất kỳ câu hỏi nào. Nó sẽ được khá dễ dàng để chuyển đổi này để ASP.Net.
using System;
using System.IO;
using System.Windows.Forms;
using iTextSharp.text;
using iTextSharp.text.pdf;
namespace WindowsFormsApplication1 {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
string existingFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "file1.pdf");
string newFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "file2.pdf");
using (FileStream fs = new FileStream(existingFile, 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("This is a test"));
doc.Close();
}
}
}
//Bind a PdfReader to our first document
PdfReader reader = new PdfReader(existingFile);
//Create a new stream for our output file (this could be a MemoryStream, too)
using (FileStream fs = new FileStream(newFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
//Use a PdfStamper to bind our source file with our output file
using (PdfStamper stamper = new PdfStamper(reader, fs)) {
//In case of conflict we want our new text to be written "on top" of any existing content
//Get the "Over" state for page 1
PdfContentByte cb = stamper.GetOverContent(1);
//Begin text command
cb.BeginText();
//Set the font information
cb.SetFontAndSize(BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1250, false), 16f);
//Position the cursor for drawing
cb.MoveText(50, 50);
//Write some text
cb.ShowText("This was added manually");
//End text command
cb.EndText();
//Create a new ColumnText object to write to
ColumnText ct = new ColumnText(cb);
//Create a single column who's lower left corner is at 100x100 and upper right is at 500x200
ct.SetSimpleColumn(100,100,500,200);
//Add a higher level object
ct.AddElement(new Paragraph("This was added using ColumnText"));
//Flush the text buffer
ct.Go();
}
}
this.Close();
}
}
}
Đối với vấn đề thứ hai của bạn về FileStream
vs MemoryStream
, nếu bạn nhìn vào chữ ký phương pháp cho hầu hết (trên thực tế tất cả như xa như tôi biết) phương pháp trong iTextSharp bạn sẽ thấy rằng tất cả họ đều mất một đối tượng Stream
và không chỉ là đối tượng FileStream
. Bất cứ lúc nào bạn nhìn thấy điều này, ngay cả bên ngoài iTextSharp, điều này có nghĩa là bạn có thể chuyển vào bất kỳ lớp con nào của Stream
bao gồm đối tượng MemoryStream
, mọi thứ khác vẫn giữ nguyên.
Mã bên dưới là phiên bản được sửa đổi một chút của phiên bản ở trên. Tôi đã xóa hầu hết các nhận xét để làm cho nhận xét ngắn hơn. Thay đổi chính là chúng tôi đang sử dụng MemoryStream
thay vì FileStream
. Ngoài ra, khi chúng ta hoàn thành PDF khi cần phải đóng đối tượng PdfStamper
trước khi truy cập dữ liệu nhị phân thô. (Các using
statment sẽ làm điều này cho chúng tôi tự động sau này nhưng nó cũng đóng dòng vì vậy chúng tôi cần phải làm điều đó bằng tay ở đây.)
Một điều khác, không bao giờ, sử dụng phương pháp GetBuffer()
của MemoryStream
. Nghe có vẻ giống như những gì bạn muốn (và tôi đã nhầm lẫn sử dụng nó), nhưng thay vào đó bạn muốn sử dụng ToArray()
. GetBuffer()
bao gồm các byte chưa được khởi tạo thường tạo ra các tệp PDF bị hỏng.Ngoài ra, thay vì viết vào luồng HTTP Response tôi đang lưu các byte vào mảng trước. Từ một phối cảnh gỡ lỗi, điều này cho phép tôi hoàn thành tất cả mã iTextSharp và System.IO
của mình và đảm bảo rằng nó là chính xác, sau đó làm bất cứ điều gì tôi muốn với mảng byte thô. Trong trường hợp của tôi, tôi không có một máy chủ web tiện dụng vì vậy tôi đang viết chúng vào đĩa nhưng bạn có thể chỉ là một cách dễ dàng gọi Response.BinaryWrite(bytes)
string existingFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "file1.pdf");
string newFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "file2.pdf");
PdfReader reader = new PdfReader(existingFile);
byte[] bytes;
using(MemoryStream ms = new MemoryStream()){
using (PdfStamper stamper = new PdfStamper(reader, ms)) {
PdfContentByte cb = stamper.GetOverContent(1);
ColumnText ct = new ColumnText(cb);
ct.SetSimpleColumn(100,100,500,200);
ct.AddElement(new Paragraph("This was added using ColumnText"));
ct.Go();
//Flush the PdfStamper's buffer
stamper.Close();
//Get the raw bytes of the PDF
bytes = ms.ToArray();
}
}
//Do whatever you want with the bytes
//Below I'm writing them to disk but you could also write them to the output buffer, too
using (FileStream fs = new FileStream(newFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
fs.Write(bytes, 0, bytes.Length);
}
Ôi chúa ơi, cảm ơn bạn rất nhiều vì đã giải thích các đối tượng 'Tài liệu' và' PdfStamper' là gì! Tôi không thể tìm thấy những lời giải thích này ở đâu cả. Tôi đã cố gắng tìm hiểu làm thế nào để thêm một hình ảnh vào một đối tượng 'PdfReader', nhưng từ ví dụ của bạn, tôi nhận ra rằng tôi có thể làm như vậy bằng cách sử dụng một đối tượng' PdfStamper' và một đối tượng 'PdfContentByte'. Muốn có một tài liệu tham khảo nhanh về những gì mỗi phương pháp đã làm, những gì mỗi tài sản là cho, và những gì các lớp học nên được sử dụng trong các trường hợp nhất định. Dù sao thì cũng cám ơn bạn! –