ITextSharp 4.1.6 - Remove existing line from PDF Template

会有一股神秘感。 提交于 2019-11-28 11:07:01

问题


I have a PDF template created in LibreOffice and I'm filling it in using AcroFields. In some rare cases I'd like to hide a particular field, thus I remove it using RemoveField method. It's border however stays in there. From what I've googled it seems it's probably the way LibreOffice creates the forms.

What I've came up with so far was to get the rectangle of the field and cover it with white image. Problem however is, customer plans creating templates using background image and/or other background color than white making my current solution almost unusable

The question therefore is - is there some way I could remove the borders? [e.g. by accessing some low-level object model of ITextSharp, or something like that]

Thanks a lot in advance


回答1:


Removing individual drawing objects can get a little tricky but its not impossible. The hardest part is deciding which objects that you want to remove. Below is some sample code targetting iTextSharp 4.1.6 that first creates a PDF with two rectangles and then creates a second PDF based on the first with one of the rectangles removed. You'll need to apply your logic to figure out which rectangle you want to remove. Its possible that you don't actually have rectangles but lines that happen to form a rectangle, in that case you'll need to modify the code a bit, too.

This first bit just creates a basic PDF on the desktop with two rectangles:

//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();
}

This next part is the more complicated part. I encourage you to do a Console.WriteLine(tokenizer.StringValue); inside of the while loop to see all of the PDF commands. You'll notice that they use RPN syntax which can take a little getting used. See the comments in the code for more questions.

//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();


来源:https://stackoverflow.com/questions/15622855/itextsharp-4-1-6-remove-existing-line-from-pdf-template

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!