Best way to create/fill-in printed forms and pdfs?

Viewed 48617

We have a C# application that must print complex forms. Things like multi-page government compliance forms that must be in a specific format. We can get PDF copies of these forms and create form fields, but aren't sure how to fill in this data and create a PDF that can be auto-printed and sent to our clients (they need paper copies).

Also, some of the forms are dynamic, in that certain pages must be repeated (for example, for an employee equal opportunity audit report we might need to include 5 copies of a page in the form if it holds 50 employees but the client has 250).

In general, what's the best way to populate and print these forms? Note that our application is C#-based, but any solution in any language/app is welcome (we're open to buying software or integrating with other frameworks if needed).

For example - what would something like TurboTax use to print out the hundreds of tax forms that it handles?

9 Answers

You can use a recently created Kevsoft.PDFtk package which wraps up PDFtk server.

var pdftk = new PDFtk();

var fieldData = new Dictionary<string, string>()
{
   ["Best Coding Website Box"] = "Stackoverflow",
   ["My Check Box"] = "Yes"
};

var result = await pdftk.FillFormAsync(
   pdfFile: await File.ReadAllBytesAsync("myForm.pdf"),
   fieldData: fieldData,
   flatten: false,
   dropXfa: false
);

if(result.Success)
{
    await File.WriteAllBytes($"{Guid.NewGuid()}.pdf", result.Result);
}

There's more sameples on the GitHub page - https://github.com/kevbite/Kevsoft.PDFtk

Also, there's extra information on this blog post - https://kevsoft.net/2021/05/16/filling-pdf-forms-for-free-with-dotnet-core-and-net-5.html

Kevsoft.PDFtk is licensed under MIT

PDFtk Server is licensed under GPLv2, however, if you're packaging up with an application to be distributed you can buy a redistribution license.

If your form is based on the AcroForm technology: Just use the itext7 to accomplish this task. Add it to your project by executing following command in your NuGet Package Manager Console:

Install-Package itext7

To write a specific form field, use code similar to this:

PdfReader reader = new PdfReader(src);
PdfWriter writer = new PdfWriter(dest);
PdfDocument pdfDoc = new PdfDocument(reader, writer);
var form = PdfAcroForm.GetAcroForm(pdfDoc, true);
var fields = form.GetFormFields();
fields.Get(key).SetValue(value);
form.FlattenFields();
pdfDoc.Close();

In this snippet, src is the source of a PDF file and dest is the path to the resulting PDF. The key corresponds with the name of a field in your template. The value corresponds with the value you want to fill in. If you want the form to keep its interactivity, you need to remove the form.flattenFields(); otherwise all form fields will be removed, resulting in a flat PDF.

Caution

Be aware, that itext7 is licenced under AGPL and isn't free for commercial use or closed source. (special thanks to @da_berni for this necessary information)

we use aspose.words and I see they have a PDF API as well.

As of 2020 FreeSpire.PDF looks interesting. Quoting from the site https://www.e-iceblue.com/Introduce/free-pdf-component.html:

Free Spire.PDF for .NET is a Community Edition of the Spire.PDF for .NET, which is a totally free PDF API for commercial and personal use. As a standalone .NET library, Free Spire.PDF for .NET enables developers to create, write, edit, convert, print, handle and read PDF files on any .NET( C#, VB.NET, ASP.NET, .NET Core) applications.

Apparently it's limited to 10 pages maximum.

  1. Print the PDF form (in high quality)
  2. Scan it (in high quality)
  3. Convert scanned file into a bitmap (*.dib)
  4. Using Visual C (VS 2010, programmatically)
    • set the page properties (i.e., prepare the page, device context, etc...)
    • create your fonts (as many as you like, of course)
    • set the page origin (top of page)
    • load and use StretchDIBits (or similar) to print the PDF page image
    • go to top of page
    • calculate your print position (pt.x and pt.y)
    • print using pDC->TextOut (or whatever else you want to use)

The above does work with any number of fields on any PDF page but requires some rudimentary knowledge of the underlying OS print processes. It gives you full control of the page and that does mean you can cross out, print over, etc.... you can do whatever you like.
I see no problem whatsoever in converting that to VS 2017 and C#. No library needed - just plain old fashioned coding by hand.

Try with this:

string Filepath = Server.MapPath("/AOF.pdf");
var pdfpath = Path.Combine(Filepath, "");
var Formcontent = ListFieldNames(Filepath);
Formcontent["Name_txt"] =  "T.Test" ;  FillForm(Formcontent); //  var pdfContents = FillForm(pdfpath, Formcontent);

public Dictionary<string, string> ListFieldNames(string Filepath)
{
    //PdfReader pdfReader = new PdfReader(pdfTemplate);
    //StringBuilder sb = new StringBuilder();
    //foreach(DictionaryEntry de in pdfReader.AcroFields.Fields)
    //{
    //    sb.Append(de.Key.ToString() + Environment.NewLine);
    //}
    var Fileds = new Dictionary<string, string>();
    PdfReader pdfReader = new PdfReader(Filepath);
    var reader = new PdfReader(pdfReader);
    foreach (var entry in reader.AcroFields.Fields)
        Fileds.Add(entry.Key.ToString(), string.Empty);
    reader.Close();
    return Fileds;
}

public byte[] FillForm(string pdfPath, Dictionary<string, string> formFieldMap)
{
    var output = new MemoryStream();
    var reader = new PdfReader(pdfPath);
    var stamper = new PdfStamper(reader, output);
    var formFields = stamper.AcroFields;
    foreach (var fieldName in formFieldMap.Keys)
        formFields.SetField(fieldName, formFieldMap[fieldName]);
    stamper.FormFlattening = true;
    stamper.Close();
    reader.Close();
    return output.ToArray();
}

public void FillForm(Dictionary<string, string> Formfiledmap)
{
    string pdfTemplate = Server.MapPath("/AOF.pdf");
    string newFile = @"C:\Users\USer\Desktop\completed_fw4.pdf";
    PdfReader pdfReader = new PdfReader(pdfTemplate);
    PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(newFile, FileMode.Create));
    AcroFields pdfFormFields = pdfStamper.AcroFields;
    foreach (var fieldName in Formfiledmap.Keys)
        pdfFormFields.SetField(fieldName, Formfiledmap[fieldName]);
    pdfStamper.FormFlattening = true;
    pdfStamper.Close();
}
Related