2013-03-25 2 views
1

У меня есть шаблон PDF, созданный в LibreOffice, и я заполняю его с помощью AcroFields. В некоторых редких случаях я хотел бы скрыть определенное поле, поэтому я удаляю его с помощью метода RemoveField. Это граница, однако, остается там. Из того, что я искал в googled, похоже, что LibreOffice, вероятно, создает формы.ITextSharp 4.1.6 - Удалить существующую строку из PDF-шаблона

То, что я додумал до сих пор, это получить прямоугольник поля и накрыть его белым изображением. Однако проблема заключается в том, что клиентские планы создают шаблоны, используя фоновое изображение и/или другой цвет фона, чем белый, что делает мое текущее решение практически непригодным.

Вопрос в том, что есть - есть ли способ удалить границы? [например. путем доступа низкоуровневых объектную модель ITextSharp, или что-то подобное]

Большое спасибо заранее

ответ

2

Удаление отдельных объектов чертежа может получить немного сложнее, но это не невозможно. Самая сложная часть - решить, какие объекты вы хотите удалить. Ниже приведен пример кода для iTextSharp 4.1.6, который сначала создает 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 syntax, которые могут немного привыкнуть. См. Комментарии в коде для получения дополнительных вопросов.

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

WOW !!! Этот код помог мне достичь цели, которую я считал практически невозможной. Thanx миллион Крис !!! –

+1

@brunolau помните, что для метода исключения общего объекта вам придется распознавать гораздо больше рассматриваемого потока. Кроме того, вам также нужно будет проверить xobjects, а не только поток содержимого страницы. Представленный здесь код - это только стартер. – mkl

Смежные вопросы