创建/填写打印表格和 pdf 的最佳方式?

发布于 2024-11-15 10:32:52 字数 368 浏览 5 评论 0原文

我们有一个必须打印复杂表单的 C# 应用程序。诸如必须采用特定格式的多页政府合规表格之类的东西。我们可以获得这些表单的 PDF 副本并创建表单字段,但不确定如何填写这些数据并创建可以自动打印并发送给我们的客户的 PDF(他们需要纸质副本)。

此外,某些表格是动态的,因为某些页面必须重复(例如,对于员工平等机会审计报告,如果拥有 50 名员工但客户有 250 名员工,我们可能需要在表格中包含 5 个页面副本) )。

一般来说,填充和打印这些表格的最佳方法是什么?请注意,我们的应用程序是基于 C# 的,但欢迎使用任何语言/应用程序的任何解决方案(如果需要,我们愿意购买软件或与其他框架集成)。

例如,像 TurboTax 这样的东西会使用什么来打印它处理的数百份税务表格?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

梦幻之岛 2024-11-22 10:32:52

这里有几个选项。

  1. FDF,表单数据格式。这是一个糟糕的规范文档,它只涵盖了 FDF 格式的一小部分(不常用的、复杂的)。 FDF 文件的生成相当简单,并且包含一堆字段/值对(并且可以保存列表选项和其他您不需要的更高级的东西)和文件关联。打开 FDF 会填充 PDF(通过与 acrobat/reader 的文件关联)。

这是一个示例(带有额外的空格以使其更具可读性):

%FDF-1.2
1 0 obj
<< /FDF
  << /Fields  [
    << /V (Communications Co.)/T (Address1)>>
    << /V (29 Communications Road)/T (Address2)>>
    << /V (Busyville)/T (City)>>
    << /V (USA)/T (Country)>>
    << /V (24 January 2000)/T (Date)>>
    << /V (Suzie Smith)/T (Name)>>
    << /V (\(807\) 221-9999)/T (PhoneNumber)>>
    << /V (777-11-8888)/T (SSN)>>
    << /V (NJ)/T (State)>>
  ]
  /F (TestForm.pdf)
  >>
>>
endobj
trailer
<<
  /Root 1 0 R
>>
%%EOF

“/V”表示字段值,“/T”是字段的标题。 “/F”是要填写的表格的路径。

有许多类似邮件合并的产品可以接收 FDF 和 PDF 并生成填充的 PDF 表单。前面提到的 iText(以及其他几个)可以通过编程方式执行此操作,其他应用程序有命令行。

在此环境中,任何可能需要重复的页面都应该是它自己的形式。合并表单可能相当困难。有几种方法,其中最简单的方法是“展平”字段,使它们只是页面内容(线条艺术和文本)...然后您就不再真正合并 PDF 表单了。

当然,如果您可以控制打印内容的顺序,则根本不需要合并表单。您可以按照正确的顺序打开/打印它们。

我记得Acrobat Pro的批处理命令可以导入FDF数据并打印。您需要做的就是生成适当的 FDF 文件,这主要是简单的字符串构建。

使用 FDF 假定您已经制作了 PDF 表单,只是等待填写。如果情况并非如此...

  1. 以编程方式生成 PDF 表单。我使用 iText(iTextSharp 的 Java 基础)来完成此操作,尽管有很多可用的各种语言的库。 iText[Sharp] 根据 AGPL(或商业)获得许可。使用 AGPL,任何有权访问您的输出的人都必须有权访问您的应用程序的源代码。 AGPL 与常规 GPL 一样“病毒式传播”。旧版本可在 MPL 下使用。

鉴于这完全是内部操作,并且您将打印 PDF,因此许可并不是什么大问题。

一旦生成表单模板然后直接或通过 FDF 填写它们,效率会高得多。

There are several options here.

  1. FDF, Form Data Format. And that's a terrible spec document, it only covers a small (infrequently used, complicated) part of the FDF format. FDF files are fairly trivial to generate, and contain a pile of field/value pairs (and can hold list options, and other fancier stuff you won't need) and a file association. Opening the FDF fills the PDF (via a file association with acrobat/reader).

Here's a sample (with extra whitespace to make it more readable):

%FDF-1.2
1 0 obj
<< /FDF
  << /Fields  [
    << /V (Communications Co.)/T (Address1)>>
    << /V (29 Communications Road)/T (Address2)>>
    << /V (Busyville)/T (City)>>
    << /V (USA)/T (Country)>>
    << /V (24 January 2000)/T (Date)>>
    << /V (Suzie Smith)/T (Name)>>
    << /V (\(807\) 221-9999)/T (PhoneNumber)>>
    << /V (777-11-8888)/T (SSN)>>
    << /V (NJ)/T (State)>>
  ]
  /F (TestForm.pdf)
  >>
>>
endobj
trailer
<<
  /Root 1 0 R
>>
%%EOF

"/V" indicates a field value, "/T" is a field's title. "/F" is the path to the form to be filled.

There are a number of mail-merge-esque products floating around that can take in an FDF and PDF and produce a filled PDF form. The aforementioned iText (and several others) can do this programmatically, other apps have command lines.

Any page that might need to be repeated should be it's own form in this environment. Merging forms can be Quite Hard. There are a couple approaches, the easiest of them being to "flatten" the fields so they are just page contents (line art & text)... then you're not really merging PDF forms any more.

Of course if you can control the order in which things are printed, you needn't merge the forms at all. You could just open/print them in the correct order.

As I recall, Acrobat Pro's batch commands can import FDF data and print. All you'd need to do would be to generate the appropriate FDF files, which is mostly trivial string building.

Using FDF presumes you have the PDF forms already made, just waiting to be filled out. If that's not the case...

  1. Generate your PDF forms programmatically. I do this with iText (the Java basis of iTextSharp), though there are quite a few libraries available in various languages. iText[Sharp] is licensed under the AGPL (or commercially). With AGPL, anyone with access to your OUTPUT must have access to the source of your application. AGPL is just as "viral" as the regular GPL. Older versions were available under the MPL.

Given that this is strictly internal and that you'll be printing the PDFs, the licensing isn't much of an issue.

It would be considerably more efficient to generate your form templates once then fill them in... either directly or via FDF.

¢蛋碎的人ぎ生 2024-11-22 10:32:52

您可以使用最近创建的 Kevsoft.PDFtk 包来封装 PDFtk 服务器。

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);
}

GitHub 页面上还有更多相同内容 - https://github.com/kevbite/Kevsoft.PDFtk

另外,这篇博文还提供了额外的信息 - https:// /kevsoft.net/2021/05/16/filling-pdf-forms-for-free-with-dotnet-core-and-net-5.html

Kevsoft.PDFtk 已获得 MIT 许可

PDFtk Server 根据 GPLv2 获得许可,但是,如果您要打包要分发的应用程序,则可以购买重新分发许可证。

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(
quot;{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.

彩虹直至黑白 2024-11-22 10:32:52

如果您的表单基于 AcroForm 技术:只需使用 itext7 即可完成此任务。通过在 NuGet 包管理器控制台中执行以下命令将其添加到您的项目中:

安装包itext7

要编写特定的表单字段,请使用类似于以下的代码:

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();

在此代码段中,src 是 PDF 文件的源,dest 是 PDF 文件的路径生成的 PDF。 key 与模板中字段的名称相对应。 value 与您要填写的值相对应。如果您希望表单保持交互性,则需要删除 form.flattenFields(); 否则所有表单字段将被删除,从而生成平面 PDF。

警告

请注意,itext7 已获得 AGPL 许可,并且不能免费用于商业用途或封闭源代码。 (特别感谢@da_berni提供了这些必要的信息)

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)

梦年海沫深 2024-11-22 10:32:52

您可以尝试Docotic.Pdf Library。该库允许在现有文档中填写表格、导入和导出 FDF 数据,以及修改现有文档并从头开始创建表格。

几个示例:

如何填写现有内容表格

如何将FDF导入PDF文档

<一href="https://github.com/BitMiracle/Docotic.Pdf.Samples/tree/master/Samples/Forms%20and%20Annotations/TextFields" rel="nofollow noreferrer">如何创建文本字段

Docotic .Pdf 附带商业和免费许可证。

You may try Docotic.Pdf Library. This library allows to fill in forms in existing documents, import and export FDF data, as well modify existing documents and create forms from scratch.

Several samples:

How to fill in existing forms

How to import FDF to PDF document

How to create text fields

Docotic.Pdf comes with commercial and free licenses.

淡紫姑娘! 2024-11-22 10:32:52

截至 2020 年,FreeSpire.PDF 看起来很有趣。引用自网站 https://www.e-iceblue.com/ Introduce/free-pdf-component.html

Free Spire.PDF for .NET 是 Spire.PDF for .NET 的社区版,它是一个完全免费的 PDF API,可供商业和个人使用。作为一个独立的 .NET 库,Free Spire.PDF for .NET 使开发人员能够在任何 .NET(C#、VB.NET、ASP.NET、.NET Core)上创建、编写、编辑、转换、打印、处理和读取 PDF 文件)应用程序。

显然它最多限制为 10 页。

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.

回梦 2024-11-22 10:32:52

我们使用 aspose.words,我看到他们也有一个 PDF API

表单字段处理
Aspose.PDF for .NET 提供了向 PDF 文档添加表单字段的功能,即:您可以在 PDF 文档中动态生成表单字段。只需按照表格或自定义定位对表单字段的位置进行排序,表单字段每次都会放置在准确的位置。

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

Form Field Processing
Aspose.PDF for .NET offers the capabilities to add form fields to the PDF document, that is; you can dynamically generate form fields in PDF documents. Just order the position of the form fields as per a table or by custom positioning, and the form fields will be placed in the exact position every time.

滴情不沾 2024-11-22 10:32:52

您问题的部分答案是您应该探索“ItextSharp”库,它是一个开源库,在创建 PDF 文件时很有用。

http://sourceforge.net/projects/itextsharp/

Partial answer to your question is that you should explore "ItextSharp" library which is an open source library and is useful in creating PDF files.

http://sourceforge.net/projects/itextsharp/

慈悲佛祖 2024-11-22 10:32:52

因为这里缺少它:也可以使用 pdfSharp 将值添加到字段中。要了解如何操作,请查看以下链接:填写表单字段创建 Acroform/添加表单元素

Because it is missing here: also with pdfSharp it is possible to add values into fields. To see how, take a look at these links: Fill form fields and Create Acroform/add form element

允世 2024-11-22 10:32:52
  1. 打印 PDF 表单(高质量)
  2. 扫描(高质量)
  3. 将扫描文件转换为位图 (*.dib)
  4. 使用 Visual C(VS 2010,以编程方式)
    • 设置页面属性(即准备页面、设备上下文等...)
    • 创建您的字体(当然,您喜欢多少就多少)
    • 设置页面原点(页面顶部)
    • 加载并使用 StretchDIBits(或类似工具)来打印 PDF 页面图像
    • 转到页面顶部
    • 计算您的打印位置(pt.x 和 pt.y)
    • 使用 pDC->TextOut 进行打印(或您想要使用的任何其他内容)

以上确实适用于任何数字任何 PDF 页面上的字段,但需要
有关底层操作系统打印流程的一些基本知识。
它使您可以完全控制页面,这确实意味着您可以划掉、打印等等......您可以做任何您喜欢的事情。
我认为将其转换为 VS 2017 和 C# 没有任何问题。
不需要库——只需简单的老式手工编码。

  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.

凯凯我们等你回来 2024-11-22 10:32:52

尝试用这个:

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();
}

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();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文