個々の描画オブジェクトを削除するのは少し難しいかもしれませんが、不可能ではありません。最も難しいのは、削除するオブジェクトを決定することです。以下は、iTextSharp 4.1.6を対象としたサンプルコードです。最初に2つの長方形を含むPDFを作成し、次に、長方形の1つを削除した最初のPDFに基づいて2番目のPDFを作成します。ロジックを適用して、削除する長方形を特定する必要があります。実際には長方形ではなく、たまたま長方形を形成する線がある可能性があります。その場合は、コードも少し変更する必要があります。
この最初のビットは、デスクトップ上に2つの長方形を持つ基本的なPDFを作成するだけです。
//Create a file on the desktop with two rectangles
var file1 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "File1.pdf");
using (var fs = new FileStream(file1, FileMode.Create, FileAccess.Write, FileShare.None)) {
var doc = new Document();
var writer = PdfWriter.GetInstance(doc, fs);
doc.Open();
var cb = writer.DirectContent;
//Draw two rectangles
cb.SaveState();
cb.SetColorStroke(iTextSharp.text.Color.RED);
cb.Rectangle(40, 60, 200, 100);
cb.Stroke();
cb.RestoreState();
cb.SaveState();
cb.SetColorStroke(iTextSharp.text.Color.BLUE);
cb.Rectangle(500, 80, 90, 50);
cb.Stroke();
cb.RestoreState();
doc.Close();
}
この次の部分は、より複雑な部分です。すべてのPDFコマンドを表示するにConsole.WriteLine(tokenizer.StringValue);
は、ループの内側を実行することをお勧めします。少し慣れるのに時間がかかるRPN構文while
を使用していることに気付くでしょう。その他の質問については、コードのコメントを参照してください。
//Bind a reader to our first file
var reader = new PdfReader(file1);
//Get the first page (this would normally be done in a loop)
var page = reader.GetPageN(1);
//Get the "contents" of that page
var objectReference = (PdfIndirectReference)page.Get(PdfName.CONTENTS);
//Get the actual stream of the "contents"
var stream = (PRStream)PdfReader.GetPdfObject(objectReference);
//Get the raw bytes of the stream
var streamBytes = PdfReader.GetStreamBytes(stream);
//Convert the bytes to actual PDF tokens/commands
var tokenizer = new PRTokeniser(new RandomAccessFileOrArray(streamBytes));
//We're going to re-append each token to this below buffer and remove the ones that we don't want
List<string> newBuf = new List<string>();
//Loop through each PDf token
while (tokenizer.NextToken()) {
//Add them to our master buffer
newBuf.Add(tokenizer.StringValue);
//The "Other" token is used for most commands, so if we're on "Other" and the current command is "re" which is rectangle
if (
tokenizer.TokenType == PRTokeniser.TK_OTHER && //The "Other" token is used for most commands
newBuf[newBuf.Count - 1] == "re" && //re is the rectangle command
newBuf[newBuf.Count - 5] == "40" //PDFs use RPN syntax so the red rectangle command was "40 60 200 100 re"
) {
newBuf.RemoveRange(newBuf.Count - 5, 5); //If the above conditions were met remove the last 5 commands
}
}
//Convert our array to a string with newlines between each token, convert that to an ASCII byte array and push that back into the stream (erasing the current contents)
stream.SetData(System.Text.Encoding.ASCII.GetBytes(String.Join("\n", newBuf.ToArray())));
//Create a new file with the rectangle removed
var file2 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "File2.pdf");
using (var fs = new FileStream(file2, FileMode.Create, FileAccess.Write, FileShare.None)) {
//Bind a stamper to our read above which has the altered stream
var stamper = new PdfStamper(reader, fs);
//Loop through each page
int total = reader.NumberOfPages;
for (int i = 1; i <= total; i++) {
//Push the content over page by page
reader.SetPageContent(i, reader.GetPageContent(i));
}
stamper.Close();
}
reader.Close();