PDFSharp filling in form fields - c#

I would like to fill in form fields in a premade PDF doc, but I'm receiving a Null Refrence error with AcroForm when running.
string fileN4 = TextBox1.Text + " LOG.pdf";
File.Copy(Path.Combine(textBox4.Text + "\\", fileN4),
Path.Combine(Directory.GetCurrentDirectory(), fileN4), true);
// Open the file
PdfDocument document = PdfReader.Open(fileN4, PdfDocumentOpenMode.Modify);
PdfTextField currentField = (PdfTextField)(document.AcroForm.Fields["<CASENUM>"]);
//const
string caseName = TextBox1.Text;
PdfString caseNamePdfStr = new PdfString(caseName);
//set the value of this field
currentField.Value = caseNamePdfStr;
// Save the document...
document.Save(fileN4);
So PdfTextField currentField = (PdfTextField)(document.AcroForm.Fields["<CASENUM>"]); is where the error happens. It seams that AcroForm is not even recognizing the fields.
Another option would be a find and replace text in a PDF (without using itextsharp as cannot use due to licensing).
Any help would be awesome!

You also need this if you are attempting to populate PDF form fields, you also need to set the NeedsAppearances element to true. Otherwise the PDF will "hide" the values on the form. Here is the VB code.
If objPdfSharpDocument.AcroForm.Elements.ContainsKey("/NeedAppearances") = False Then
objPdfSharpDocument.AcroForm.Elements.Add("/NeedAppearances", New PdfSharp.Pdf.PdfBoolean(True))
Else
objPdfSharpDocument.AcroForm.Elements("/NeedAppearances") = New PdfSharp.Pdf.PdfBoolean(True)
End If

I've been working on this today and I've managed to create a working solution. I've pasted my working code below. The only real differences I can see between my code and the OP's is the following:
I included Marc Ferree's code to set NeedAppearances (+1 and Many thanks!!)
I set the Text property of the field using a String variable, and not the Value property using a PdfString.
Hopefully this will be of use to somebody trying to do the same.
string templateDocPath = Server.MapPath("~/Documents/MyTemplate.pdf");
PdfDocument myTemplate = PdfReader.Open(templateDocPath, PdfDocumentOpenMode.Modify);
PdfAcroForm form = myTemplate.AcroForm;
if (form.Elements.ContainsKey("/NeedAppearances"))
{
form.Elements["/NeedAppearances"] = new PdfSharp.Pdf.PdfBoolean(true);
}
else
{
form.Elements.Add("/NeedAppearances", new PdfSharp.Pdf.PdfBoolean(true));
}
PdfTextField testField = (PdfTextField)(form.Fields["TestField"]);
testField.Text = "012345";
myTemplate.Save(Server.MapPath("~/Documents/Amended.pdf")); // Save to new file.

I got stuck with this same problem earlier today. However, I think the source code has ?updated, so if you try the method above you are going to get a NullExceptionError. Instead, for TextField you need to generate a PdfString and use testfield.Value instead of .text. Here's an example.
static PdfAccess()
{
Pdf.PdfDocument doc = Pdf.IO.PdfReader.Open(#"C:\...\ Contract.pdf", Pdf.IO.PdfDocumentOpenMode.Modify);
Pdf.AcroForms.PdfAcroForm form = doc.AcroForm;
if (form.Elements.ContainsKey("/NeedAppearances"))
{
form.Elements["/NeedAppearances"] = new PdfSharp.Pdf.PdfBoolean(true);
}
else
{
form.Elements.Add("/NeedAppearances", new PdfSharp.Pdf.PdfBoolean(true));
}
var name = (Pdf.AcroForms.PdfTextField)(form.Fields["Email"]);
name.Value = new Pdf.PdfString("ramiboy");
doc.Save(#"C:\...\ Contract.pdf");
doc.Close();

I have just experienced something similar to this. The first pdf file I opened did not contain acroform data and resulted in a null exception as described above. The issue is not with the opening of the pdf but the reference to the Acroform member variable having a value of null. You can test your pdf using the following code example:
OpenFileDialog ofd = new OpenFileDialog();
if (ofd.ShowDialog() == DialogResult.OK)
{
PdfDocument _document = null;
try
{
_document = PdfReader.Open(ofd.FileName, PdfDocumentOpenMode.Modify);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message,"FATAL");
//do any cleanup and return
return;
}
if (_document != null)
{
if (_document.AcroForm != null)
{
MessageBox.Show("Acroform is object","SUCCEEDED");
//pass acroform to some function for processing
_document.Save(#"C:\temp\newcopy.pdf");
}
else
{
MessageBox.Show("Acroform is null","FAILED");
}
}
else
{
MessageBox.Show("Uknown error opening document","FAILED");
}
}
ADENDUM
I also noticed the key in this line of code should not have angle brackets
document.AcroForm.Fields["<CASENUM>"]
Change it to
document.AcroForm.Fields["CASENUM"]

The solution to overcome the NullReferenceException is to open your pre-made
PDF with Adobe Acrobat and give your form fields a default value, by changing their property-type to be something other than null.

Have you tried putting the current directory in when you try to open it?
Change
PdfDocument document = PdfReader.Open(fileN4, PdfDocumentOpenMode.Modify);
to
PdfDocument document = PdfReader.Open(Path.Combine(Directory.GetCurrentDirectory(), fileN4), PdfDocumentOpenMode.Modify);
I'm pretty sure that PdfReader will need a full file path, although I only use ASPOSE for pdf creation.

Related

Change text of label in PDF

I have problems with editing fields inside of an PDF document.
I created a simple invoice with OpenOffice and added some fields via the form creation tool. I exported it as PDF with forms after that.
One of the fields I want to change is named "{Firma}" and I want to fill this field with a string.
Below is a short example-code which doesnt seem to work, the field "{Firma}" in the output-file is still empty.
public static void ReplacePdfForm()
{
string fileNameExisting = #".\template\templaterechnung.pdf";
string fileNameNew = #".\rechnung.pdf";
using (var existingFileStream = new FileStream(fileNameExisting, FileMode.Open))
using (var newFileStream = new FileStream(fileNameNew, FileMode.Create))
{
// Open existing PDF
var pdfTemplate = new PdfReader(existingFileStream);
// PdfStamper, (PDF to be changed)
var pdfInvoice = new PdfStamper(pdfTemplate, newFileStream);
AcroFields fields = pdfInvoice.AcroFields;
// set form fields
fields.SetField("{Firma}", "Test1");
pdfInvoice.FormFlattening = true;
pdfInvoice.FreeTextFlattening = true;
pdfInvoice.Close();
pdfTemplate.Close();
}
}
(I have some more fields which also don't change but I deleted them from code because they behave the same way.)
Thanks in advance.
EDIT:
Here's my PDF: http://www.file-upload.net/download-11071404/templaterechnung.pdf.html
EDIT2:
This is how I set the property in OpenOffice:
When creating a form with Open Office, Open Office adds a parameter to the PDF instructing software processing the PDF not to create any appearance streams, but to leave it up to the PDF viewer to create those appearances.
This works as long as the form remains interactive, but as soon as you flatten the form, no appearances are created at all.
You can work around this problem by adding the following line:
fields.GenerateAppearances = true;
This way, you force iTextSharp to generate the appearances.

AcroForm PDF to normal PDF in c#

I have an Acroform PDF (a PDF which can be edited) but I'm using an API to sign the PDF which requires that the PDF is a normal one and never an Acroform one.
Is there any way to transform an AcroForm PDF to a normal one?
I tried making it Read-Only but even though it cannot be edited it still is an Acroform PDF.
In answer to my comment, I assume you are using iTextSharp, even though you do not specify. Using iTextSharp, I believe you need to Flatten the form when you are done. Here is a simple example:
public void GeneratePDF(string filePath, List<PDFField> modifiedFields)
{
var pdfReader = new PdfReader(filePath);
var folderStructure = filePath.Split('\\');
if (folderStructure.Length == 0) return;
var currentFileName = folderStructure.Last();
var newFilePath = string.Format("{0}{1}", Constants.SaveFormsPath,
currentFileName.Replace(".pdf", DateTime.Now.ToString("MMddyyhhmmss") + ".pdf"));
var pdfStamper = new PdfStamper(pdfReader, new FileStream(newFilePath, FileMode.Create));
foreach (var field in modifiedFields.Where(f=>f.Value != null))
{
pdfStamper.AcroFields.SetField(field.Name, field.Value);
}
pdfStamper.FormFlattening = true;
pdfStamper.Close();
}
Ignoring the parts about the filename, it boils down to passing in some key value list regarding the field values to set. This could be where you do your signature piece, and then setting the FormFlattening property on the stamper to true.
Here is another SO post where they used a similiar technique for a slightly different issue, it may be of help: How to flatten already filled out PDF form using iTextSharp

Convert a Word (DOCX) file to a PDF in C# on cloud environment

I have generated a word file using Open Xml and I need to send it as attachment in a email with pdf format but I cannot save any physical pdf or word file on disk because I develop my application in cloud environment(CRM online).
I found only way is "Aspose Word to .Net".
http://www.aspose.com/docs/display/wordsnet/How+to++Convert+a+Document+to+a+Byte+Array But it is too expensive.
Then I found a solution is to convert word to html, then convert html to pdf. But there is a picture in my word. And I cannot resolve the issue.
The most accurate conversion from DOCX to PDF is going to be through Word. Your best option for that is setting up a server with OWAS (Office Web Apps Server) and doing your conversion through that.
You'll need to set up a WOPI endpoint on your application server and call:
/wv/WordViewer/request.pdf?WOPISrc={WopiUrl}&type=downloadpdf
OR
/wv/WordViewer/request.pdf?WOPISrc={WopiUrl}&type=printpdf
Alternatively you could try and do it using OneDrive and Word Online, but you'll need to work out the parameters Word Online uses as well as whether that's permitted within the Ts & Cs.
You can try Gnostice XtremeDocumentStudio .NET.
Converting From DOCX To PDF Using XtremeDocumentStudio .NET
http://www.gnostice.com/goto.asp?id=24900&t=convert_docx_to_pdf_using_xdoc.net
In the published article, conversion has been demonstrated to save to a physical file. You can use documentConverter.ConvertToStream method to convert a document to a Stream as shown below in the code snippet.
DocumentConverter documentConverter = new DocumentConverter();
// input can be a FilePath, Stream, list of FilePaths or list of Streams
Object input = "InputDocument.docx";
string outputFileFormat = "pdf";
ConversionMode conversionMode = ConversionMode.ConvertToSeperateFiles;
List<Stream> outputStreams = documentConverter.ConvertToStream(input, outputFileFormat, conversionMode);
Disclaimer: I work for Gnostice.
If you wanna convert bytes array, then to use Metamorphosis:
string docxPath = #"example.docx";
string pdfPath = Path.ChangeExtension(docxPath, ".pdf");
byte[] docx = File.ReadAllBytes(docxPath);
// Convert DOCX to PDF in memory
byte[] pdf = p.DocxToPdfConvertByte(docx);
if (pdf != null)
{
// Save the PDF document to a file for a viewing purpose.
File.WriteAllBytes(pdfPath, pdf);
System.Diagnostics.Process.Start(pdfPath);
}
else
{
System.Console.WriteLine("Conversion failed!");
Console.ReadLine();
}
I have recently used SautinSoft 'Document .Net' library to convert docx to pdf in my React(frontend), .NET core(micro services- backend) application. It only take 15 seconds to generate a pdf having 23 pages. This 15 seconds includes getting data from database, then merging data with docx template and then converting it to pdf. The code has deployed to azure Linux box and works fine.
https://sautinsoft.com/products/document/
Sample code
public string GeneratePDF(PDFDocumentModel document)
{
byte[] output = null;
using (var outputStream = new MemoryStream())
{
// Create single pdf.
DocumentCore singlePDF = new DocumentCore();
var documentCores = new List<DocumentCore>();
foreach (var section in document.Sections)
{
documentCores.Add(GenerateDocument(section));
}
foreach (var dc in documentCores)
{
// Create import session.
ImportSession session = new ImportSession(dc, singlePDF, StyleImportingMode.KeepSourceFormatting);
// Loop through all sections in the source document.
foreach (Section sourceSection in dc.Sections)
{
// Because we are copying a section from one document to another,
// it is required to import the Section into the destination document.
// This adjusts any document-specific references to styles, bookmarks, etc.
// Importing a element creates a copy of the original element, but the copy
// is ready to be inserted into the destination document.
Section importedSection = singlePDF.Import<Section>(sourceSection, true, session);
// First section start from new page.
if (dc.Sections.IndexOf(sourceSection) == 0)
importedSection.PageSetup.SectionStart = SectionStart.NewPage;
// Now the new section can be appended to the destination document.
singlePDF.Sections.Add(importedSection);
//Paging
HeaderFooter footer = new HeaderFooter(singlePDF, HeaderFooterType.FooterDefault);
// Create a new paragraph to insert a page numbering.
// So that, our page numbering looks as: Page N of M.
Paragraph par = new Paragraph(singlePDF);
par.ParagraphFormat.Alignment = HorizontalAlignment.Center;
CharacterFormat cf = new CharacterFormat() { FontName = "Consolas", Size = 11.0 };
par.Content.Start.Insert("Page ", cf.Clone());
// Page numbering is a Field.
Field fPage = new Field(singlePDF, FieldType.Page);
fPage.CharacterFormat = cf.Clone();
par.Content.End.Insert(fPage.Content);
par.Content.End.Insert(" of ", cf.Clone());
Field fPages = new Field(singlePDF, FieldType.NumPages);
fPages.CharacterFormat = cf.Clone();
par.Content.End.Insert(fPages.Content);
footer.Blocks.Add(par);
importedSection.HeadersFooters.Add(footer);
}
}
var pdfOptions = new PdfSaveOptions();
pdfOptions.Compression = false;
pdfOptions.EmbedAllFonts = false;
pdfOptions.EmbeddedImagesFormat = PdfSaveOptions.EmbImagesFormat.Png;
pdfOptions.EmbeddedJpegQuality = 100;
//dont allow editing after population, also ensures content can be printed.
pdfOptions.PreserveFormFields = false;
pdfOptions.PreserveContentControls = false;
if (!string.IsNullOrEmpty(document.PdfProperties.Title))
{
singlePDF.Document.Properties.BuiltIn[BuiltInDocumentProperty.Title] = document.PdfProperties.Title;
}
if (!string.IsNullOrEmpty(document.PdfProperties.Author))
{
singlePDF.Document.Properties.BuiltIn[BuiltInDocumentProperty.Author] = document.PdfProperties.Author;
}
if (!string.IsNullOrEmpty(document.PdfProperties.Subject))
{
singlePDF.Document.Properties.BuiltIn[BuiltInDocumentProperty.Subject] = document.PdfProperties.Subject;
}
singlePDF.Save(outputStream, pdfOptions);
output = outputStream.ToArray();
}
return Convert.ToBase64String(output);
}

Create PDF by copying it from template with PdfCopy (lost of data)

I'm trying to create a new pdf file based on another one using PdfCopy.
Everything work fine during generation and the generated file can be opened without any problem on my desktop, but the file seems to be corrupted and isn't accepted by the service that I must use :
SignService error when calling 'sign', probably caused by a bad file format.
I noticed that the generated pdf is always ligther than the original template, so i compared the template version with the generated one. There are some big parts of missing data, especially a whole bunch of xml. I guess PdfCopy does not copying every of my original pdf but i cannot figured out what am i missing.
here is my method :
byte[] completedDocument = null;
string originalUri = Path.Combine(this.PdfPath, pdfName);
string generatedUri = Path.Combine(this.PdfGeneratedPath, generatedPdfName);
using(MemoryStream streamCompleted = new MemoryStream())
{
using(Document doc = new Document())
{
PdfCopy copy = new PdfCopy(doc, streamCompleted);
copy.PdfVersion = PdfWriter.VERSION_1_6;
doc.Open();
copy.Open();
byte[] mergedDocument = null;
PdfReader pdfReader = new PdfReader(originalUri);
int pdfPageNumber = pdfReader.NumberOfPages;
using(MemoryStream streamTemplate = new MemoryStream())
{
using (PdfStamper pdfStamper = new PdfStamper(pdfReader, streamTemplate))
{
AcroFields acrofields = pdfStamper.AcroFields;
foreach (KeyValuePair<string, AcroFields.Item> field in acrofields.Fields)
{
string data;
if (pdfFieldsValues.TryGetValue(field.Key, out data))
{
if (data == null)
{
data = string.Empty;
}
acrofields.SetField(field.Key, data);
}
}
pdfStamper.FormFlattening = true;
pdfStamper.Writer.CloseStream = false;
}
mergedDocument = streamTemplate.ToArray();
}
pdfReader = new PdfReader(mergedDocument);
for (int page = 1; page <= pdfPageNumber; page++)
{
if (!excludedPages.Any(s => s == page))
{
copy.AddPage(copy.GetImportedPage(pdfReader, page));
}
}
doc.Close();
copy.Close();
}
completedDocument = streamCompleted.ToArray();
}
File.WriteAllBytes(generatedUri, completedDocument);
I tried to upload the "mergedDocument" rather than the "completedDocument" and my service accepting it, so i'm pretty sure it has something to do with this part :
for (int page = 1; page <= pdfPageNumber; page++)
{
if (!excludedPages.Any(s => s == page))
{
copy.AddPage(copy.GetImportedPage(pdfReader, page));
}
}
Or pdfCopy init
You start with a form. You fill out the form and you flatten it. By flattening it, you deliberately throw away all interactivity. I'm surprised that you're surprised that the file is getting smaller: you're throwing away the form infrastructure!
You then upload the flattened file to some service unknown to us. This service complains:
SignService error when calling 'sign', probably caused by a bad file format.
As we don't know which service you are talking about, we can only guess. An educated guess would be that the original form contains a signature field that needs to be signed by a signing service.
Obviously that field is gone: you flattened the form! I may be wrong, but I assume that the service also tries to read the fields you filled out, but that won't be possible either as you throw away all interactivity. Please remove the following line:
pdfStamper.FormFlattening = true;
Then there's Chris' comment: it seems that you're using PdfCopy. If you're using an old version of iTextSharp (before iText 5.5.1), you shouldn't expect the form to be preserved. If you are using a recent version, you should instruct PdfCopy to preserve the form (but that line is missing). You don't need to ask 'how do I preserve the form?' because you shouldn't be using PdfCopy anyway.
You only need PdfStamper. You already use PdfStamper to fill out the fields, now you can also use the selectPages() method to select the pages you want to keep (or to exclude the ones you want to remove).
Finally, it is unclear what you mean when you write:
There are some big parts of missing data, especially a whole bunch of xml.
Are you saying that the form isn't a pure AcroForm, but that it also contains an XFA stream? If so, then you most definitely can't use PdfCopy.

ITextSharp PDFTemplate FormFlattening removes filled data

I am porting an existing app from Java to C#. The original app used the IText library to fill PDF form templates and save them as new PDF's. My C# code (example) below:
string templateFilename = #"C:\Templates\test.pdf";
string outputFilename = #"C:\Output\demo.pdf";
using (var existingFileStream = new FileStream(templateFilename, FileMode.Open))
{
using (var newFileStream = new FileStream(outputFilename, FileMode.Create))
{
var pdfReader = new PdfReader(existingFileStream);
var stamper = new PdfStamper(pdfReader, newFileStream);
var form = stamper.AcroFields;
var fieldKeys = form.Fields.Keys;
foreach (string fieldKey in fieldKeys)
{
form.SetField(fieldKey, "REPLACED!");
}
stamper.FormFlattening = true;
stamper.Close();
pdfReader.Close();
}
}
All works well only if I ommit the
stamper.FormFlattening = true;
line, but then the forms are visible as...forms.
When I add the this line, any values set to the form fields are lost, resulting in a blank form. I would really appreciate any advice.
Most likely you can resolve this when using iTextSharp 5.4.4 (or later) by forcing iTextSharp to generate appearances for the form fields. In your example code:
var form = stamper.AcroFields;
form.GenerateAppearances = true;
Resolved the issue by using a previous version of ITextSharp (5.4.3). Not sure what the cause is though...
I found a working solution for this for any och the newer iTextSharp.
The way we do it was:
1- Create a copy of the pdf temmplate.
2- populate the copy with data.
3- FormFlatten = true and setFullCompression
4- Combine some of the PDFs to a new document.
5- Move the new combined document and then remove the temp.
This way we got the issue with removed input and if we skipped the "formflatten" it looked ok.
However when we moved the "FormFlatten = true" from step 3 and added it as a seperate step after the moving etc was complete, it worked perfectly.
Hope I explained somewhat ok :)
In your PDF File, change the property to Visible, the Default value is Visible but not printable.

Categories