Скопируйте аннотации PDF через С#

У меня есть поток (файл PDF с аннотациями) и еще один поток (тот же файл PDF без аннотаций). Я использую потоки, потому что мне нужно выполнять эти операции в памяти. Мне нужно скопировать аннотации из первого документа в другой. Аннотации могут быть разными: комментарии, выделение и другие. Так что лучше копировать аннотации без разбора.

Можете ли вы посоветовать мне какую-нибудь полезную библиотеку PDF для .NET? И некоторый образец для этой проблемы.


person Mykhail Galushko    schedule 30.07.2010    source источник


Ответы (2)


Я использую ITextSharp, который разветвлен от IText (реализация Java для редактирования PDF).

http://sourceforge.net/projects/itextsharp/

http://itextpdf.com/

Изменить - это то, что вам нужно сделать (не проверено, но должно быть близко):

using System;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;

// return processed stream (a new MemoryStream) 
public Stream copyAnnotations(Stream sourcePdfStream, Stream destinationPdfStream)
{
    // Create new document (IText)
    Document outdoc = new Document(PageSize.A4);

    // Seek to Stream start and create Reader for input PDF
    m.Seek(0, SeekOrigin.Begin);
    PdfReader inputPdfReader = new PdfReader(sourcePdfStream);

    // Seek to Stream start and create Reader for destination PDF
    m.Seek(0, SeekOrigin.Begin);
    PdfReader destinationPdfReader = new PdfReader(destinationPdfStream);

    // Create a PdfWriter from for new a pdf destination stream
    // You should write into a new stream here!
    Stream processedPdf = new MemoryStream();
    PdfWriter pdfw = PdfWriter.GetInstance(outdoc, processedPdf);

    // do not close stream if we've read everything
    pdfw.CloseStream = false;

    // Open document
    outdoc.Open();

    // get number of pages
    int numPagesIn = inputPdfReader.NumberOfPages;
    int numPagesOut = destinationPdfReader.NumberOfPages;

    int max = numPagesIn;

    // Process max number of pages
    if (max<numPagesOut)
    {
        throw new Exception("Impossible - different number of pages");
    }
    int i = 0;

    // Process Pdf pages
    while (i < max)
    {
        // Import pages from corresponding reader
        PdfImportedPage pageIn = writer.inputPdfReader(reader, i);
        PdfImportedPage pageOut = writer.destinationPdfReader(reader, i);

        // Get named destinations (annotations
        List<Annotations> toBeAdded = ParseInAndOutAndGetAnnotations(pageIn, pageOut);

        // add your annotations
        foreach (Annotation anno in toBeAdded) pageOut.Add(anno);

        // Add processed page to output PDFWriter
        outdoc.Add(pageOut);
    }

    // PDF creation finished
    outdoc.Close();

    // your new destination stream is processedPdf
    return processedPdf;
}

Реализация ParseInAndOutAndGetAnnotations(pageIn, pageOut) должна отражать ваши аннотации.

Вот хороший пример с аннотациями: http://www.java2s.com/Open-Source/Java-Document/PDF/pdf-itext/com/lowagie/text/pdf/internal/PdfAnnotationsImp.java.htm< /а>

person Andreas Rehm    schedule 30.07.2010
comment
Я пытался использовать ITextSharp, но не нашел хорошего примера для копирования аннотаций. - person Mykhail Galushko; 30.07.2010
comment
Я добавил небольшой образец - вам нужно его адаптировать - это просто добавление аннотации. С помощью iTextSharp легко анализировать каждую страницу — это то, что вам нужно сделать. - person Andreas Rehm; 30.07.2010
comment
Спасибо большое за помощь. iTextSharp — отличная библиотека, но иногда не хватает примеров. - person Mykhail Galushko; 01.08.2010
comment
можешь проверить свой код? Вам не хватает нескольких переменных замедлений - person Christian Payne; 28.02.2011
comment
Фактическая реализация ParseInAndOutAndGetAnnotations отсутствует, а ссылка, на которую он указывает, мертва, так что никак не угадать реализацию метода. - person Peter Staev; 23.06.2016

Вы можете использовать этот пример для iTextSharp, чтобы решить вашу проблему (этот пример копирует список файлов PDF с аннотациями в новый файл PDF):

var output = new MemoryStream();

using (var document = new Document(PageSize.A4, 70f, 70f, 20f, 20f))
{
    var readers = new List<PdfReader>();
    var writer = PdfWriter.GetInstance(document, output);

    writer.CloseStream = false;

    document.Open();

    const Int32 requiredWidth = 500;
    const Int32 zeroBottom = 647;
    const Int32 left = 50;

    Action<String, Action> inlcudePdfInDocument = (filename, e) =>
    {
         var reader = new PdfReader(filename);
         readers.Add(reader);

         var pageCount = reader.NumberOfPages;
         for (var i = 0; i < pageCount; i++)
         { 
             e?.Invoke();
             var imp = writer.GetImportedPage(reader, (i + 1));

             var scale = requiredWidth / imp.Width;
             var height = imp.Height * scale;

             writer.DirectContent.AddTemplate(imp, scale, 0, 0, scale, left, zeroBottom - height);

             var annots = reader.GetPageN(i + 1).GetAsArray(PdfName.ANNOTS);
             if (annots != null && annots.Size != 0)
             {
                 foreach (var a in annots)
                 {
                     var newannot = new PdfAnnotation(writer, new Rectangle(0, 0));
                     var annotObj = (PdfDictionary) PdfReader.GetPdfObject(a);
                     newannot.PutAll(annotObj);
                     var rect = newannot.GetAsArray(PdfName.RECT);
                     rect[0] = new PdfNumber(((PdfNumber)rect[0]).DoubleValue * scale + left); // Left
                     rect[1] = new PdfNumber(((PdfNumber)rect[1]).DoubleValue * scale); // top
                     rect[2] = new PdfNumber(((PdfNumber)rect[2]).DoubleValue * scale + left); // right
                     rect[3] = new PdfNumber(((PdfNumber)rect[3]).DoubleValue * scale); // bottom
                     writer.AddAnnotation(newannot);
                 }
             }

             document.NewPage();
         }

     }

    foreach (var apprPdf in pdfs)
    {
        document.NewPage();

        inlcudePdfInDocument(apprPdf.Pdf, null);
    }

    document.Close();
    readers.ForEach(x => x.Close());
}

output.Position = 0;
return output;

PdfReader имеет конструктор, который принимает массив байтов, поэтому вы можете адаптировать его для MemoryStream.

person Andrei    schedule 13.04.2017
comment
Похоже, это работает только для простых аннотаций, которые не ссылаются на дополнительные косвенные объекты. - person mkl; 14.04.2017