My task is to merge multiple pdf to single pdf and I can achieve the merger pdf but I am facing issue in the internal links (named destination) are missed up from second pdf where as its working in first pdf. My issues are similiar to the below post.
Pdf Merge Issue in ItextSharp (After Merging Pdfs don't retain their Values)
But I did not achieve this.
My code are below.
class Program
{
static void Main(string[] args)
{
Document document = new Document();
string[] fileNames = #"D:\PDF_Protect\ToMerge\Test\pdf1.pdf;D:\PDF_Protect\ToMerge\Test\pdf2.pdf;D:\PDF_Protect\ToMerge\Test\pdf3.pdf;".Split(';');
string outFile = #"D:\PDF_Protect\ToMerge\output\merged.pdf";
//merge one
PdfCopy pdf = new PdfCopy(document, new FileStream(outFile, FileMode.Create));
document.Open();
foreach (string fileName in fileNames)
{
PdfReader reader = new PdfReader(fileName);
reader.ConsolidateNamedDestinations();
var pdfDestination = new PdfDestination(PdfDestination.FIT);
//var pdfAction = PdfAction.GotoLocalPage(1, pdfDestination, pdf);
//pdf.SetOpenAction(pdfAction);
pdf.AddDocument(reader);
reader.Close();
}
document.Close();
}
}
Kindly guide me how to regenerate the links working throughout the merged pdf.
Related
I currently have a PdfReader and a PdfStamper that I am filling out the acrofields with. I now have to copy another pdf to the end of that form I have been filling out and when I do I lose the acrofield on the new form I copy over. Here is the code.
public static void addSectionThirteenPdf(PdfStamper stamper, Rectangle pageSize, int pageIndex){
PdfReader reader = new PdfReader(FacesContext.getCurrentInstance().getExternalContext().getResourceAsStream("/resources/documents/Section13.pdf"));
AcroFields fields = reader.getAcroFields();
fields.renameField("SecurityGuidancePage3", "SecurityGuidancePage" + pageIndex);
stamper.insertPage(pageIndex, pageSize);
stamper.replacePage(reader, 1, pageIndex);
}
The way that I am creating the original document is like this.
OutputStream output = FacesContext.getCurrentInstance().getExternalContext().getResponseOutputStream();
PdfReader pdfTemplate = new PdfReader(FacesContext.getCurrentInstance().getExternalContext().getResourceAsStream("/resources/documents/dd254.pdf"));
PdfStamper stamper = new PdfStamper(pdfTemplate, output);
stamper.setFormFlattening(true);
AcroFields fields = stamper.getAcroFields();
Is there a way to merge using the first piece of code and merge both of the acrofields together?
Depending on what you want exactly, different scenarios are possible, but in any case: you are doing it wrong. You should use either PdfCopy or PdfSmartCopy to merge documents.
The different scenarios are explained in the following video tutorial.
You can find most of the examples in the iText sandbox.
Merging different forms (having different fields)
If you want to merge different forms without flattening them, you should use PdfCopy as is done in the MergeForms example:
public void createPdf(String filename, PdfReader[] readers) throws IOException, DocumentException {
Document document = new Document();
PdfCopy copy = new PdfCopy(document, new FileOutputStream(filename));
copy.setMergeFields();
document.open();
for (PdfReader reader : readers) {
copy.addDocument(reader);
}
document.close();
for (PdfReader reader : readers) {
reader.close();
}
}
In this case, readers is an array of PdfReader instances containing different forms (with different field names), hence we use PdfCopy and we make sure that we don't forget to use the setMergeFields() method, or the fields won't be copied.
Merging identical forms (having identical fields)
In this case, we need to rename the fields, because we probably want different values on different pages. In PDF a field can only have a single value. If you merge identical forms, you have multiple visualizations of the same field, but each visualization will show the same value (because in reality, there is only one field).
Let's take a look at the MergeForms2 example:
public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
Document document = new Document();
PdfCopy copy = new PdfSmartCopy(document, new FileOutputStream(dest));
copy.setMergeFields();
document.open();
List<PdfReader> readers = new ArrayList<PdfReader>();
for (int i = 0; i < 3; ) {
PdfReader reader = new PdfReader(renameFields(src, ++i));
readers.add(reader);
copy.addDocument(reader);
}
document.close();
for (PdfReader reader : readers) {
reader.close();
}
}
public byte[] renameFields(String src, int i) throws IOException, DocumentException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, baos);
AcroFields form = stamper.getAcroFields();
Set<String> keys = new HashSet<String>(form.getFields().keySet());
for (String key : keys) {
form.renameField(key, String.format("%s_%d", key, i));
}
stamper.close();
reader.close();
return baos.toByteArray();
}
As you can see, the renameFields() method creates a new document in memory. That document is merged with other documents using PdfSmartCopy. If you'd use PdfCopy here, your document would be bloated (as we'll soon find out).
Merging flattened forms
In the FillFlattenMerge1, we fill out the forms using PdfStamper. The result is a PDF file that is kept in memory and that is merged using PdfCopy. While this example is fine if you'd merge different forms, this is actually an example on how not to do it (as explained in the video tutorial).
The FillFlattenMerge2 shows how to merge identical forms that are filled out and flattened correctly:
public void manipulatePdf(String src, String dest) throws DocumentException, IOException {
Document document = new Document();
PdfCopy copy = new PdfSmartCopy(document, new FileOutputStream(dest));
document.open();
ByteArrayOutputStream baos;
PdfReader reader;
PdfStamper stamper;
AcroFields fields;
StringTokenizer tokenizer;
BufferedReader br = new BufferedReader(new FileReader(DATA));
String line = br.readLine();
while ((line = br.readLine()) != null) {
// create a PDF in memory
baos = new ByteArrayOutputStream();
reader = new PdfReader(SRC);
stamper = new PdfStamper(reader, baos);
fields = stamper.getAcroFields();
tokenizer = new StringTokenizer(line, ";");
fields.setField("name", tokenizer.nextToken());
fields.setField("abbr", tokenizer.nextToken());
fields.setField("capital", tokenizer.nextToken());
fields.setField("city", tokenizer.nextToken());
fields.setField("population", tokenizer.nextToken());
fields.setField("surface", tokenizer.nextToken());
fields.setField("timezone1", tokenizer.nextToken());
fields.setField("timezone2", tokenizer.nextToken());
fields.setField("dst", tokenizer.nextToken());
stamper.setFormFlattening(true);
stamper.close();
reader.close();
// add the PDF to PdfCopy
reader = new PdfReader(baos.toByteArray());
copy.addDocument(reader);
reader.close();
}
br.close();
document.close();
}
These are three scenarios. Your question is too unclear for anyone but you to decide which scenario is the best fit for your needs. I suggest that you take the time to learn before you code. Watch the video, try the examples, and if you still have doubts, you'll be able to post a smarter question.
I currently have a PdfReader and a PdfStamper that I am filling out the acrofields with. I now have to copy another pdf to the end of that form I have been filling out and when I do I lose the acrofield on the new form I copy over. Here is the code.
public static void addSectionThirteenPdf(PdfStamper stamper, Rectangle pageSize, int pageIndex){
PdfReader reader = new PdfReader(FacesContext.getCurrentInstance().getExternalContext().getResourceAsStream("/resources/documents/Section13.pdf"));
AcroFields fields = reader.getAcroFields();
fields.renameField("SecurityGuidancePage3", "SecurityGuidancePage" + pageIndex);
stamper.insertPage(pageIndex, pageSize);
stamper.replacePage(reader, 1, pageIndex);
}
The way that I am creating the original document is like this.
OutputStream output = FacesContext.getCurrentInstance().getExternalContext().getResponseOutputStream();
PdfReader pdfTemplate = new PdfReader(FacesContext.getCurrentInstance().getExternalContext().getResourceAsStream("/resources/documents/dd254.pdf"));
PdfStamper stamper = new PdfStamper(pdfTemplate, output);
stamper.setFormFlattening(true);
AcroFields fields = stamper.getAcroFields();
Is there a way to merge using the first piece of code and merge both of the acrofields together?
Depending on what you want exactly, different scenarios are possible, but in any case: you are doing it wrong. You should use either PdfCopy or PdfSmartCopy to merge documents.
The different scenarios are explained in the following video tutorial.
You can find most of the examples in the iText sandbox.
Merging different forms (having different fields)
If you want to merge different forms without flattening them, you should use PdfCopy as is done in the MergeForms example:
public void createPdf(String filename, PdfReader[] readers) throws IOException, DocumentException {
Document document = new Document();
PdfCopy copy = new PdfCopy(document, new FileOutputStream(filename));
copy.setMergeFields();
document.open();
for (PdfReader reader : readers) {
copy.addDocument(reader);
}
document.close();
for (PdfReader reader : readers) {
reader.close();
}
}
In this case, readers is an array of PdfReader instances containing different forms (with different field names), hence we use PdfCopy and we make sure that we don't forget to use the setMergeFields() method, or the fields won't be copied.
Merging identical forms (having identical fields)
In this case, we need to rename the fields, because we probably want different values on different pages. In PDF a field can only have a single value. If you merge identical forms, you have multiple visualizations of the same field, but each visualization will show the same value (because in reality, there is only one field).
Let's take a look at the MergeForms2 example:
public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
Document document = new Document();
PdfCopy copy = new PdfSmartCopy(document, new FileOutputStream(dest));
copy.setMergeFields();
document.open();
List<PdfReader> readers = new ArrayList<PdfReader>();
for (int i = 0; i < 3; ) {
PdfReader reader = new PdfReader(renameFields(src, ++i));
readers.add(reader);
copy.addDocument(reader);
}
document.close();
for (PdfReader reader : readers) {
reader.close();
}
}
public byte[] renameFields(String src, int i) throws IOException, DocumentException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, baos);
AcroFields form = stamper.getAcroFields();
Set<String> keys = new HashSet<String>(form.getFields().keySet());
for (String key : keys) {
form.renameField(key, String.format("%s_%d", key, i));
}
stamper.close();
reader.close();
return baos.toByteArray();
}
As you can see, the renameFields() method creates a new document in memory. That document is merged with other documents using PdfSmartCopy. If you'd use PdfCopy here, your document would be bloated (as we'll soon find out).
Merging flattened forms
In the FillFlattenMerge1, we fill out the forms using PdfStamper. The result is a PDF file that is kept in memory and that is merged using PdfCopy. While this example is fine if you'd merge different forms, this is actually an example on how not to do it (as explained in the video tutorial).
The FillFlattenMerge2 shows how to merge identical forms that are filled out and flattened correctly:
public void manipulatePdf(String src, String dest) throws DocumentException, IOException {
Document document = new Document();
PdfCopy copy = new PdfSmartCopy(document, new FileOutputStream(dest));
document.open();
ByteArrayOutputStream baos;
PdfReader reader;
PdfStamper stamper;
AcroFields fields;
StringTokenizer tokenizer;
BufferedReader br = new BufferedReader(new FileReader(DATA));
String line = br.readLine();
while ((line = br.readLine()) != null) {
// create a PDF in memory
baos = new ByteArrayOutputStream();
reader = new PdfReader(SRC);
stamper = new PdfStamper(reader, baos);
fields = stamper.getAcroFields();
tokenizer = new StringTokenizer(line, ";");
fields.setField("name", tokenizer.nextToken());
fields.setField("abbr", tokenizer.nextToken());
fields.setField("capital", tokenizer.nextToken());
fields.setField("city", tokenizer.nextToken());
fields.setField("population", tokenizer.nextToken());
fields.setField("surface", tokenizer.nextToken());
fields.setField("timezone1", tokenizer.nextToken());
fields.setField("timezone2", tokenizer.nextToken());
fields.setField("dst", tokenizer.nextToken());
stamper.setFormFlattening(true);
stamper.close();
reader.close();
// add the PDF to PdfCopy
reader = new PdfReader(baos.toByteArray());
copy.addDocument(reader);
reader.close();
}
br.close();
document.close();
}
These are three scenarios. Your question is too unclear for anyone but you to decide which scenario is the best fit for your needs. I suggest that you take the time to learn before you code. Watch the video, try the examples, and if you still have doubts, you'll be able to post a smarter question.
I am new to using iTextSharp and working with Pdf files in general, but I think I'm on the right track.
I iterate through a list of pdf files, convert them to bytes, and push all of the resulting bytes into a byte array. From there I pass the byte array to concatAndAddContent() to merge all of the pdf's into a single large pdf. Currently I'm just getting the last pdf in the list (they seem to be overwriting)
public static byte[] concatAndAddContent(List<byte[]> pdfByteContent)
{
byte[] allBytes;
using (MemoryStream ms = new MemoryStream())
{
Document doc = new Document();
PdfWriter writer = PdfWriter.GetInstance(doc, ms);
doc.SetPageSize(PageSize.LETTER);
doc.Open();
PdfContentByte cb = writer.DirectContent;
PdfImportedPage page;
PdfReader reader;
foreach (byte[] p in pdfByteContent)
{
reader = new PdfReader(p);
int pages = reader.NumberOfPages;
// loop over document pages
for (int i = 1; i <= pages; i++)
{
doc.SetPageSize(PageSize.LETTER);
doc.NewPage();
page = writer.GetImportedPage(reader, i);
cb.AddTemplate(page, 0, 0);
}
}
doc.Close();
allBytes = ms.GetBuffer();
ms.Flush();
ms.Dispose();
}
return allBytes;
}
Above is the working code that results in a single pdf being created, and the rest of the files are being ignored. Any suggestions
This is pretty much just a C# version of Bruno's code here.
This is pretty much the simplest, safest and recommended way to merge PDF files. The PdfSmartCopy object is able to detect redundancies in the multiple files which can reduce file size some times. One of the overloads on it accepts a full PdfReader object which can be instantiated however you want.
public static byte[] concatAndAddContent(List<byte[]> pdfByteContent) {
using (var ms = new MemoryStream()) {
using (var doc = new Document()) {
using (var copy = new PdfSmartCopy(doc, ms)) {
doc.Open();
//Loop through each byte array
foreach (var p in pdfByteContent) {
//Create a PdfReader bound to that byte array
using (var reader = new PdfReader(p)) {
//Add the entire document instead of page-by-page
copy.AddDocument(reader);
}
}
doc.Close();
}
}
//Return just before disposing
return ms.ToArray();
}
}
List<byte[]> finallist= new List<byte[]>();
finallist.Add(concatAndAddContent(bytes));
System.IO.File.WriteAllBytes("path",finallist);
I have a PDF document and I need to add a text to the top of first page. This is not a watermark or stamp. It's an ordinary text.
How can I do this?
Maybe I need to parse my PDF document and create a new one adding text? But how to do this? how to parse existing pdf document into new one? without copying pages, because in this case the text will be in the first page and other content in the new one.
I have found this method. But it won't help, because it only copies pages to the new ones. And I'll get "textTextText" in the first page and other content in the new ones.
public void ExtractPage(string sourcePdfPath, string outputPdfPath,
int pageNumber, string password = "<span style="color: rgb(139, 0, 0);">")
{
PdfReader reader = null;
Document document = null;
PdfCopy pdfCopyProvider = null;
PdfImportedPage importedPage = null;
try
{
// Intialize a new PdfReader instance with the contents of the source Pdf file:
reader = new PdfReader(sourcePdfPath);
// Capture the correct size and orientation for the page:
document = new Document(reader.GetPageSizeWithRotation(pageNumber));
// Initialize an instance of the PdfCopyClass with the source
// document and an output file stream:
pdfCopyProvider = new PdfCopy(document,
new System.IO.FileStream(outputPdfPath, System.IO.FileMode.Create));
document.Open();
// Extract the desired page number:
importedPage = pdfCopyProvider.GetImportedPage(reader, pageNumber);
pdfCopyProvider.AddPage(importedPage);
document.Close();
reader.Close();
}
catch (Exception ex)
{
throw ex;
}
}
I need to add another page in a pdf file created using below code. the next page should also use the same template placed at path:
HostingEnvironment.MapPath("~/Content/InvoiceTemplate/invoiceTemplate.pdf")
I am using itextsharp library to create documents. Below is the code used to generate pdf.
public static void WriteInTemplate(List<Models.Statement> statementList)
{
string invoiceNumber = statementList.FirstOrDefault().Invoice.ToString().Trim();
string month = null;
string day = null;
string year = null;
PdfReader pdfReader = new PdfReader(HostingEnvironment.MapPath("~/Content/InvoiceTemplate/invoiceTemplate.pdf"));
FileStream fileStream = new FileStream(HostingEnvironment.MapPath("~/Content/reports/" + invoiceNumber + ".pdf"), FileMode.Create);
PdfStamper pdfStamper = new PdfStamper(pdfReader, fileStream);
AcroFields pdfFields = pdfStamper.AcroFields;
pdfFields.SetField("BillToCompany", statementList.FirstOrDefault().BillToCompany.ToString().Trim().ToUpper());
pdfFields.SetField("BillToContact", statementList.FirstOrDefault().BillToContact.ToString().Trim().ToUpper());
pdfFields.SetField("CustomerId", statementList.FirstOrDefault().Customer_ID);
pdfFields.SetField("InvoiceNumber", statementList.FirstOrDefault().Invoice.ToString().Trim());
pdfFields.SetField("JobNumber", statementList.FirstOrDefault().JobNumber.ToString().Trim());
pdfFields.SetField("Caller", statementList.FirstOrDefault().Caller.ToString().Trim());
pdfStamper.FormFlattening = true; // generate a flat PDF
pdfStamper.Close();
pdfReader.Close();
}
You need to create a PDFDocument and then merge the files that you create into it. There is a very good example of this in this link: Merge PDFs using ITextSharp.