あなたは私があなたを歩いていくことになるだろういくつかの問題があります。
最初に、Document
オブジェクトは新しいPDFを扱うためのもので、既存のものを変更するものではありません。基本的にDocument
オブジェクトは、PDF仕様の根本的な部分を抽象化し、段落やリフロー可能なコンテンツなどのより高いレベルの作業を可能にするラッパークラスの束です。これらの抽象概念は、「段落」と考えるものを、段落を行間に関係なく一度に1行ずつ記述する生のコマンドに変換します。既存のドキュメントを扱うときに、テキストをリフローして、これらの抽象化が使用されないようにする方法を言う安全な方法はありません。
代わりにPdfStamper
オブジェクトを使用します。このオブジェクトを操作する際には、重複する可能性のあるコンテンツを操作する方法の2つの選択肢があります。新しいテキストが既存のコンテンツの上に書き込まれるか、テキストがその下に書き込まれます。インスタンス化されたPdfStamper
オブジェクトの2つのメソッド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
なステートメントは、後で自動的に私たちのためにこれを行いますが、それはまた、我々はここでそれを手動で行う必要がありので、ストリームを閉じます。)
もう一つの事を、決して、これまでMemoryStream
のGetBuffer()
メソッドを使用します。あなたの望みのように聞こえる(私も間違って使ったことがある)代わりにToArray()
を使いたい。 GetBuffer()
には、通常は破損したPDFを生成する初期化されていないバイトが含まれています。また、HTTPレスポンスストリームに書き込むのではなく、まずバイトを配列に保存しています。デバッグの観点からは、私はiTextSharpとSystem.IO
のコードをすべて終えて、それが正しいことを確認してから、生のバイト配列で必要なものを何でもします。私の場合は便利なので、私はそれらをディスクにWebサーバーを書いていませんが、あなたは同じように簡単にあなたの質問のタイトルの第二部は言う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'オブジェクトを使ってそうすることができると気づきました。各メソッドが何をしたか、それぞれのプロパティが何であるか、特定の状況でどのクラスを使用すべきかについてのクイックリファレンスドキュメントがありましたら幸いです。とにかくありがとうございました! –