나는 당신을 데려다 줄 문제를 가지고 있습니다.
먼저 Document
개체는 새로운 PDF 작업에만 사용되며 기존 PDF는 수정하지 않습니다. 기본적으로 Document
개체는 PDF 사양의 기본 부분을 추상화하고 단락 및 리플 로우 가능한 콘텐츠와 같은 상위 수준의 작업을 수행 할 수있게 해주는 래퍼 클래스 모음입니다. 이러한 추상화는 "단락"에 대한 생각을 선간에 관계가없는 한 번에 한 단락을 쓰는 원시 명령으로 바꿉니다. 기존 문서로 작업 할 때 텍스트를 리플 로우하는 방법을 말하는 안전한 방법은 없으므로 이러한 추상화는 사용되지 않습니다.
대신 PdfStamper
개체를 사용하려고합니다. 이 객체로 작업 할 때 잠재적으로 중복되는 내용으로 작업하는 방법에 대해 두 가지 선택 사항이 있습니다. 새 텍스트가 기존 내용 위에 쓰여 지거나 텍스트가 그 아래에 쓰여집니다. 인스턴스화 된 PdfStamper
개체의 GetOverContent()
또는 GetUnderContent()
의 두 메서드는 PdfContentByte
개체를 반환하고 텍스트를 쓸 수 있습니다.
수동으로 또는 ColumnText
개체를 통해 텍스트를 작성하는 두 가지 주요 방법이 있습니다. HTML을 완성했다면 ColumnText
객체는 큰 고정 위치 단일 행, 단일 열 <TABLE>
을 사용한다고 생각할 수 있습니다. ColumnText
의 장점은 Paragraph
과 같은 상위 수준의 추상화를 사용할 수 있다는 것입니다.
위의 내용을 보여주는 iTextSharp 5.1.2.0을 대상으로하는 전체 C# 2010 WinForms 응용 프로그램은 다음과 같습니다. 질문에 대해서는 코드 주석을 참조하십시오. 이것을 ASP.Net으로 쉽게 변환 할 수 있어야합니다. MemoryStream
대 FileStream
에 대한 두 번째 문제에 관해서는
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();
}
}
}
당신이 iTextSharp 내 거의 모든 (실제로 모든 내가 아는 한) 메서드 메서드 시그니처를 보면 당신은 그들 모두가 걸릴 것을 볼 수 있습니다 FileStream
개체가 아니라 Stream
개체입니다. iTextSharp 외부에서도이 내용을 볼 수 있다면 MemoryStream
객체를 포함하는 Stream
의 하위 클래스를 전달할 수 있다는 것을 의미합니다. 다른 모든 객체는 동일하게 유지됩니다.
아래 코드는 위의 코드를 약간 수정 한 것입니다. 나는 그것을 짧게 만들기 위해 대부분의 주석을 제거했다. 주된 변화는 FileStream
대신 MemoryStream
을 사용하고 있다는 것입니다. 또한 원시 이진 데이터에 액세스하기 전에 PdfStamper
개체를 닫을 필요가있을 때 PDF가 끝나면 합니다 (using
한 Statment가 자동으로 나중에 우리를 위해이 작업을 수행 할뿐만 아니라 우리가 여기 수동으로 할 필요가 있으므로 스트림을 닫습니다.)
또 다른 일을 결코, 이제까지 MemoryStream
의 GetBuffer()
방법을 사용합니다. 원하는 것처럼 들리지만 실수로 그것을 사용했습니다. 대신 ToArray()
을 사용하고 싶습니다. GetBuffer()
에는 일반적으로 손상된 PDF를 생성하는 초기화되지 않은 바이트가 포함됩니다.또한 HTTP 응답 스트림에 쓰는 대신 바이트를 먼저 배열에 저장합니다. 디버깅 관점에서이 모든 iTextSharp 및 System.IO
코드를 완료하고 올바른지 확인한 다음 원시 바이트 배열 원하는 모든 수행 할 수 있습니다. 내 경우에는 내가 디스크에 쓰고있어 편리 있도록 웹 서버가없는하지만 당신은 그냥 쉽게 부를 수 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);
}
오, 이런, 'Document'와'PdfStamper' 객체가 무엇인지 설명해 주셔서 감사합니다! 나는이 설명들을 어디서나 찾을 수 없었다. 'PdfReader' 객체에 이미지를 추가하는 방법을 찾으려고했지만, 예제에서'PdfStamper' 객체와'PdfContentByte' 객체를 사용하여 그렇게 할 수 있다는 것을 깨달았습니다. 각 방법이 무엇을했는지, 각 속성이 무엇인지, 특정 상황에서 어떤 클래스가 사용되어야하는지에 대한 빠른 참조 문서가 있었으면 좋겠다. 아무튼 감사 해요! –