Reputation: 515
I have a stream (PDF file with annotations) and another stream (the same PDF file without annotations). I use streams because I need to execute this operations in memory. I need to copy annotations from first document to another. Annotations can be different: comments, highlighting and other. So it is better to copy annotations without parsing it.
Can you advice me some helpful PDF library for .NET? And some sample for this problem.
Upvotes: 3
Views: 5226
Reputation: 119
You can use this example for iTextSharp to approach your problem (this example copies a list of pdf files with annotations into a new pdf file):
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 has a constructor that takes an array of bytes so you can adapt it for MemoryStream.
Upvotes: 2
Reputation: 2232
I'm using ITextSharp which is forked from IText (a java implemenation fpr pdf editing).
http://sourceforge.net/projects/itextsharp/
Edit - this is what you need to do (untested but shoul be close):
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;
}
The implementation of ParseInAndOutAndGetAnnotations(pageIn, pageOut) needs to reflect your annotations.
Here is a good example with annotations: http://www.java2s.com/Open-Source/Java-Document/PDF/pdf-itext/com/lowagie/text/pdf/internal/PdfAnnotationsImp.java.htm
Upvotes: 0