1

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

4

1 回答 1

2

删除单个绘图对象可能会有些棘手,但并非不可能。最困难的部分是决定要删除哪些对象。下面是一些针对 iTextSharp 4.1.6 的示例代码,它首先创建一个带有两个矩形的 PDF,然后基于第一个 PDF 创建第二个 PDF,其中一个矩形被删除。您需要应用您的逻辑来确定要删除的矩形。您可能实际上没有矩形,而是恰好形成矩形的线条,在这种情况下,您也需要稍微修改代码。

第一点只是在桌面上创建一个带有两个矩形的基本 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();
}

下一部分是更复杂的部分。我鼓励您Console.WriteLine(tokenizer.StringValue);在循环内部进行操作while以查看所有 PDF 命令。您会注意到他们使用RPN 语法,这可能需要一点时间来使用。有关更多问题,请参阅代码中的注释。

//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();
于 2013-03-26T13:49:23.740 回答