Copy into new document and fillout form in iText7 c# - c#

I have been trying to get a grip of iText7 c# with little luck.
My goal is:
Load a pdf (one page) with a form (multiple fields) as a template
Fill out the form, Flatten and copy the filled forms page to a new document
repeat #2 x number of times with different data
Save to Memory Stream
I have the different parts working , but i cant get it to work together
var memoryStream = new MemoryStream();
PdfReader reader = new PdfReader("untitled-1.pdf"); //Iput
PdfWriter writer = new PdfWriter(memoryStream); //output
PdfDocument pdfDoc = new PdfDocument(reader, writer);
PdfAcroForm form = PdfAcroForm.GetAcroForm(pdfDoc, true);
var fields = form.GetFormFields();
if(fields.ContainsKey("address")) {
fields["address"].SetValue("first\nlast");
}
form.FlattenFields();
pdfDoc.Close();
byte[] b = memoryStream.ToArray();
File.WriteAllBytes(#"t.pdf", b);
clone page:
// create clone page x times
PdfDocument pdfDoc = new PdfDocument(new PdfWriter("output.pdf").SetSmartMode(true));
pdfDoc.InitializeOutlines();
PdfDocument srcDoc;
for (int i = 0; i<5; i++) {
srcDoc = new PdfDocument(new PdfReader("untitled-1.pdf"));
// copy content to the resulting PDF
srcDoc.CopyPagesTo(1, srcDoc.GetNumberOfPages(), pdfDoc);
}
pdfDoc.Close();

got an idea just after writing this question. Here is one solution to this problem
Create a pdf-file with a form and a text field named address to use as template, save as untitled1-pdf.
This code will create an empty document and then for each user in users load and fill the field address whit the user.
The filled form will then be flatten and copied into the new document.
When all is done, the document will be saved as result.pdf
//b.
static void Main(string[] args)
{
List<string> users = new List<string> { "Peter", "john", "Carl" };
byte[] result = createPdf(users, "untitled-1.pdf");
File.WriteAllBytes(#"result.pdf", result);
}
public static byte[] createPdf(List<string> users,string templateFile)
{
// create clone page for each user in users
using (MemoryStream memoryStream = new MemoryStream())
{
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(memoryStream).SetSmartMode(true));
pdfDoc.InitializeOutlines();
PdfDocument srcDoc;
foreach (var u in users)
{
MemoryStream m = new MemoryStream(fillForm(u,templateFile));
srcDoc = new PdfDocument(new PdfReader(m));
// copy content to the resulting PDF
srcDoc.CopyPagesTo(1, srcDoc.GetNumberOfPages(), pdfDoc);
}
pdfDoc.Close();
return memoryStream.ToArray();
}
}
public static byte[] fillForm(string user,string templateFile)
{
using (var memoryStream = new MemoryStream())
{
PdfReader reader = new PdfReader(templateFile); //Iput
PdfWriter writer = new PdfWriter(memoryStream); //output
PdfDocument pdfDoc = new PdfDocument(reader, writer);
PdfAcroForm form = PdfAcroForm.GetAcroForm(pdfDoc, true);
var fields = form.GetFormFields();
if (fields.ContainsKey("address"))
{
fields["address"].SetValue(user);
}
form.FlattenFields();
pdfDoc.Close();
byte[] b = memoryStream.ToArray();
return b;
}
}

Related

iText7 PdfDocument save to two locations on disk

In the code below I want to be able to read in a PDF file and add some encryption and then resave the file. what is the best way to do that? I dont see a Save method in pdfDocument is there another object I should use?
PdfReader pdfReader = null;
byte[] bytesPassword = System.Text.ASCIIEncoding.UTF8.GetBytes("PassWord");
WriterProperties writerProperties = new WriterProperties();
PdfDocument pdfDocument = null;
using (MemoryStream ms = new MemoryStream())
{
pdfReader = new PdfReader(destFile);
writerProperties.SetStandardEncryption(null, bytesPassword, EncryptionConstants.ALLOW_PRINTING, EncryptionConstants.ENCRYPTION_AES_256);
pdfDocument = new PdfDocument(pdfReader, new PdfWriter(ms, writerProperties));
pdfDocument.Close();
}
//pdfDocument.Save(FilePath1)
//pdfDocument.Save(FilePath2)

htmlConverter in itext7 closes the pdf document before I want it to be closed in C#

I'm using iText7 to convert from HTML to PDF which runs perfectly
however this call:
HtmlConverter.ConvertToPdf(htmlStream, document);
will close the document after it's called but I don't want to close the document yet for the following reason
I wrote this function to write pages I'll be calling it in a loop
public static void WritePage(string htmlbody)
{
document.AddNewPage();
byte[] htmlByteArray = Encoding.UTF8.GetBytes(htmlbody);
MemoryStream htmlStream = new MemoryStream(htmlByteArray);
HtmlConverter.ConvertToPdf(htmlStream, document);
}
and after the loop is over I'll close the document my self
public static void CloseDocument()
{
document.Close();
}
this worked when I was using iText5 but now the convertToPdf will close the document.
I can read from that document and add it with the new page to a new document but I don't want to do that
I want to utilize the built in document.AddNewPage and after the document is fully constructed I'll close it myself
Thank you in advance
answer#1 is using PdfMerger and it is my preferred answer
public void createPdf(String baseUri, String[] src, String dest) throws IOException {
ConverterProperties properties = new ConverterProperties();
properties.setBaseUri(baseUri);
PdfWriter writer = new PdfWriter(dest);
PdfDocument pdf = new PdfDocument(writer);
PdfMerger merger = new PdfMerger(pdf);
for (String html : src) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfDocument temp = new PdfDocument(new PdfWriter(baos));
HtmlConverter.convertToPdf(new FileInputStream(html), temp, properties);
temp = new PdfDocument(
new PdfReader(new ByteArrayInputStream(baos.toByteArray())));
merger.merge(temp, 1, temp.getNumberOfPages());
temp.close();
}
pdf.close();}
answer#2 is converting the html to IElement List and adding that to the document like in follwoing code:
public void createPdf(String baseUri, String[] src, String dest) throws IOException {
ConverterProperties properties = new ConverterProperties();
properties.setBaseUri(baseUri);
PdfWriter writer = new PdfWriter(dest);
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf);
for (String html : src) {
List<IElement> elements =
HtmlConverter.convertToElements(new FileInputStream(html), properties);
for (IElement element : elements) {
document.add((IBlockElement)element);
}
}
document.close();}
Reference: https://developers.itextpdf.com/content/itext-7-converting-html-pdf-pdfhtml/chapter-7-frequently-asked-questions-about-pdfhtml/how-parse-multiple-html-files-one-pdf

How to read marge fillable pdf data using itextsharp

I have two fillable pdf files and did the code to merge those pdfs into one single pdf. Below is my code for that.
public void PDFSplit()
{
List<string> files=new List<string>();
files.Add(Server.MapPath("~/Template/sample_pdf.pdf"));
files.Add(Server.MapPath("~/Template/temp/sample_pdf.pdf"));
//call method
Merge(files, Server.MapPath("~/Template/sample_pdf_123.pdf"));
}
//Merge pdf
public void Merge(List<String> InFiles, String OutFile)
{
using (FileStream stream = new FileStream(OutFile, FileMode.Create))
using (iTextSharp.text.Document doc = new iTextSharp.text.Document())
using (PdfCopy pdf = new PdfCopy(doc, stream))
{
doc.Open();
PdfReader reader = null;
PdfImportedPage page = null;
InFiles.ForEach(file =>
{
reader = new PdfReader(file);
for (int i = 0; i < reader.NumberOfPages; i++)
{
page = pdf.GetImportedPage(reader, i + 1);
pdf.AddPage(page);
}
pdf.FreeReader(reader);
reader.Close();
});
}
}
The code is working fine, but the problem is when I am trying to read that new generated merged file, it's not showing fields using AcroFields.
//To read pdf data
PdfReader reader = null;
reader = new PdfReader(Server.MapPath("~/Template/sample_pdf_123.pdf"));
AcroFields pdfFormFields = reader.AcroFields;
You are unable to marge fallible PDF files because you are using an old version of iText. Please upgrade to iText 7 for .NET and read the iText 7 jump-start tutorial, more specifically chapter 6 where it says:
Merging forms
This is how it's done:
PdfDocument destPdfDocument = new PdfDocument(new PdfWriter(dest));
PdfDocument[] sources = new PdfDocument[] {
new PdfDocument(new PdfReader(SRC1)),
new PdfDocument(new PdfReader(SRC2)) };
PdfPageFormCopier formCopier = new PdfPageFormCopier();
foreach (PdfDocument sourcePdfDocument in sources) {
sourcePdfDocument.CopyPagesTo(1,
sourcePdfDocument.GetNumberOfPages(), destPdfDocument, formCopier);
sourcePdfDocument.Close();
}
destPdfDocument.Close();

pdf stamper, pdfEventHandler not working when trying to add page number on the pdf document using itext

I am using itext to generate a pdf document but I am trying to use the existing solutions to add page number to the pdf document that is being generated but none of them seems to be working for me.
I tried using something like
using (MemoryStream stream = new MemoryStream())
{
PdfReader reader = new PdfReader(bytes);
using (PdfStamper stamper = new PdfStamper(reader, stream))
{
int pages = reader.NumberOfPages;
for (int i = 1; i <= pages; i++)
but my code doesnt recognize PdfStamper and asks me to create a class.
Similarly, I tried using
MemoryStream ms = new MemoryStream();
PdfReader reader = new PdfReader(pdf);
int n = reader.NumberOfPages;
Rectangle psize = reader.GetPageSize(1);
There is error on .NumberOfPages and .GetPageSize.
I also tried creating a separate PageEventHandler class but the problem remains same.
Right now, I am able to generate pdf but I want to add page number and I have a code like
private MemoryStream MakeDocument(Application application)
{
MemoryStream ms = new MemoryStream();
PdfWriter writer = new PdfWriter(ms);
PdfDocument pdfDocument = new PdfDocument(writer);
using (var document = new Document(pdfDocument))
{
var sections = new List<IDocumentSection>
{
new Header(),
new Projects(application.Projects),
//Footer
};
foreach (var section in sections)
section.AddTo(document);
Rectangle pageSize;
PdfCanvas canvas;
int n = pdfDocument.GetNumberOfPages();
for (int i = 1; i <= n; i++)
{
PdfPage page = pdfDocument.GetPage(i);
pageSize = page.GetPageSize();
canvas = new PdfCanvas(page);
canvas.BeginText()
.SetFontAndSize(PdfFontFactory.CreateFont(FontConstants.HELVETICA), 7)
.MoveText(pageSize.GetWidth() / 2 - 7, 10)
.ShowText(i.ToString())
.ShowText(" of ")
.ShowText(n.ToString())
.EndText();
}
}
return ms;
var outputStream = MakeDocument(application);
var response = new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new ByteArrayContent(outputStream.ToArray())
};
response.Content.Headers.Add("Content-Type", "application/pdf");
return response;
But it is complaining at GetPageSize
Object reference not set to an instance of an object. Even if I set page size as A4, it starts to complain at canvas = new PdfCanvas(page);
It seems that you are using iText 7. Or rather, that's what I assume when I see:
PdfWriter writer = new PdfWriter(ms);
PdfDocument pdfDocument = new PdfDocument(writer);
Document document = new Document(pdfDocument);
The PdfStamper class is an iText 5 class. It doesn't exist in iText 7. See Chapter 5 of the jump-start tutorial. You probably want something like this:
MemoryStream stream = new MemoryStream();
PdfWriter writer = new PdfWriter(stream);
PdfReader reader = new PdfReader(bytes);
PdfDocument pdfDoc = new PdfDocument(reader, writer);
Document document = new Document(pdfDoc);
Rectangle pageSize;
PdfCanvas canvas;
int n = pdfDoc.GetNumberOfPages();
for (int i = 1; i <= n; i++) {
PdfPage page = pdfDoc.GetPage(i);
pageSize = page.GetPageSize();
canvas = new PdfCanvas(page);
// draw page numbers on the canvas
}
pdfDoc.close();
If you aren't using iText 7, then there's something wrong in your question. In that case you should clarify what you mean when you use the concepts PdfStamper and PdfEventHandler in the same sentence, because that doesn't make any sense.

How to add Bookmarks to PDF when Merging in Itext7

I am trying to create a program that merges several pdfs and has a bookmark to each of them.
My starting method is :
private Byte[] MergePdfForms(Dictionary<string, Stream> files)
{
var dest = new MemoryStream();
PdfDocument pdf = new PdfDocument(new PdfWriter(dest));
PdfMerger merger = new PdfMerger(pdf);
foreach (var keyValuePair in files)
{
//TODO add bookmark to this page
PdfDocument firstSourcePdf = new PdfDocument(new PdfReader(keyValuePair.Value));
merger.Merge(firstSourcePdf, 1, firstSourcePdf.GetNumberOfPages());
firstSourcePdf.Close();
}
pdf.Close();
return dest.ToArray();
}
I have tried things like
pdf.InitializeOutlines();
pdf.AddNamedDestination("Test Bookmark", pdf.GetLastPage().GetPdfObject());
Which doesn't create any bookmarks.
Take a look at the example here: http://developers.itextpdf.com/examples/merging-pdf-documents/clone-merging-documents-bookmarks
private byte[] MergePdfForms(Dictionary<string, Stream> files)
{
var dest = new MemoryStream();
PdfDocument pdf = new PdfDocument(new PdfWriter(dest));
PdfMerger merger = new PdfMerger(pdf);
PdfOutline rootOutline = pdf.GetOutlines(false);
PdfOutline helloWorld = rootOutline.AddOutline("Root");
int pages = 1;
foreach (var keyValuePair in files)
{
var firstSourcePdf = new PdfDocument(new PdfReader(keyValuePair.Value));
var subPages = firstSourcePdf.GetNumberOfPages();
merger.Merge(firstSourcePdf, 1, subPages);
firstSourcePdf.Close();
var link1 = helloWorld.AddOutline(keyValuePair.Key);
link1.AddDestination(PdfExplicitDestination.CreateFit(pdf.GetPage(pages)));
pages += subPages;
}
pdf.Close();
return dest.ToArray();
}

Categories