如何检测 PDF 文档中的签名行然后插入签名?
How do I detect a signature line in a PDF document and then insert a signature?
上周我被要求为盲人构建一个应用程序以编程方式填写 PDF 文档。他遇到的问题是,如果文档中的字段没有正确标记,那么他就无法将他的签名和其他信息放入文档的正确位置。
我的第一个方法是尝试使用 iTextSharp 阅读文档,然后将他的签名插入到最有可能是签名框的字段中:
public string[] MassFieldEdit(IDictionary<string, string> userData, string originalDocument, string edittedDocument, bool flatten)
{
PdfReader reader = new PdfReader(originalDocument);
reader.SelectPages("1-" + reader.NumberOfPages.ToString());
using (PdfStamper stamper = new PdfStamper(reader, new FileStream(edittedDocument, FileMode.Create)))
{
AcroFields form = stamper.AcroFields;
ICollection<string> fieldKeys = form.Fields.Keys;
List<string> leftover = new List<string>(fieldKeys);
foreach (string fieldKey in fieldKeys)
{
foreach (KeyValuePair<string, string> s in user)
{
//Replace Form field with my custom data
if (fieldKey.ToLower().Contains(s.Key.ToLower()))
{
form.SetField(fieldKey, s.Value);
leftover.Remove(fieldKey);
}
}
}
//The below will make sure the fields are not editable in
//the output PDF.
stamper.FormFlattening = flatten;
return leftover.ToArray();
}
}
它的工作原理是采用一个字典集,键是一个单词或短语,对照 PDF 字段检查它,然后如果该字段与键中的单词或短语匹配,则将值插入到字段中。
The signature box before my program edits it.
The signature box after.
但我现在遇到的问题是,如果不存在字段,那么虽然它可能在虚线旁边有“在这里签名”,但如果不知道虚线的确切位置,就无法将文本插入虚线上线是,我的用户 select 也不能是虚线,因为那违背了程序的要点。
我看了很多以前的问题和答案,包括:
- How to convert PDF to WORD in c#
- ITextSharp insert text to an existing pdf
我需要一种方法来检测签名行,然后将他的名字插入到签名行中,这比在字段名称上大打出手更有把握。在存在正确标记的字段的情况下,以及在签名行可能不过是一行“在此处签名”的文本的情况下。
稳健的解决方案(又名 "hard work solution")
- 实施 IEventListener (iText7 class)
- 使用 IEventListener 获取文本渲染指令和线条绘制操作的通知
- 呈现指令并不总是以逻辑(阅读)顺序出现。通过为这些对象实施比较器来解决这个问题
- 根据比较器排序
- 使用语言检测来确定语言(n-gram 方法很简单,但应该足够了)
- 字典攻击。查找以文档编写的任何语言表示 "sign here" 的所有单词(因此第 5 步)
- 如果有多个候选者,或没有候选者,使用线渲染指令寻找臭名昭著的可能候选者"dotted line"
这种方法并不容易,但是有很多关于识别pdf文件中结构元素的研究。特别是,如果您 运行 google 学者搜索,您会发现大量有用的文章,其中人们尝试检测表格、列表、段落等。
上周我被要求为盲人构建一个应用程序以编程方式填写 PDF 文档。他遇到的问题是,如果文档中的字段没有正确标记,那么他就无法将他的签名和其他信息放入文档的正确位置。
我的第一个方法是尝试使用 iTextSharp 阅读文档,然后将他的签名插入到最有可能是签名框的字段中:
public string[] MassFieldEdit(IDictionary<string, string> userData, string originalDocument, string edittedDocument, bool flatten)
{
PdfReader reader = new PdfReader(originalDocument);
reader.SelectPages("1-" + reader.NumberOfPages.ToString());
using (PdfStamper stamper = new PdfStamper(reader, new FileStream(edittedDocument, FileMode.Create)))
{
AcroFields form = stamper.AcroFields;
ICollection<string> fieldKeys = form.Fields.Keys;
List<string> leftover = new List<string>(fieldKeys);
foreach (string fieldKey in fieldKeys)
{
foreach (KeyValuePair<string, string> s in user)
{
//Replace Form field with my custom data
if (fieldKey.ToLower().Contains(s.Key.ToLower()))
{
form.SetField(fieldKey, s.Value);
leftover.Remove(fieldKey);
}
}
}
//The below will make sure the fields are not editable in
//the output PDF.
stamper.FormFlattening = flatten;
return leftover.ToArray();
}
}
它的工作原理是采用一个字典集,键是一个单词或短语,对照 PDF 字段检查它,然后如果该字段与键中的单词或短语匹配,则将值插入到字段中。
The signature box before my program edits it.
The signature box after.
但我现在遇到的问题是,如果不存在字段,那么虽然它可能在虚线旁边有“在这里签名”,但如果不知道虚线的确切位置,就无法将文本插入虚线上线是,我的用户 select 也不能是虚线,因为那违背了程序的要点。
我看了很多以前的问题和答案,包括:
- How to convert PDF to WORD in c#
- ITextSharp insert text to an existing pdf
我需要一种方法来检测签名行,然后将他的名字插入到签名行中,这比在字段名称上大打出手更有把握。在存在正确标记的字段的情况下,以及在签名行可能不过是一行“在此处签名”的文本的情况下。
稳健的解决方案(又名 "hard work solution")
- 实施 IEventListener (iText7 class)
- 使用 IEventListener 获取文本渲染指令和线条绘制操作的通知
- 呈现指令并不总是以逻辑(阅读)顺序出现。通过为这些对象实施比较器来解决这个问题
- 根据比较器排序
- 使用语言检测来确定语言(n-gram 方法很简单,但应该足够了)
- 字典攻击。查找以文档编写的任何语言表示 "sign here" 的所有单词(因此第 5 步)
- 如果有多个候选者,或没有候选者,使用线渲染指令寻找臭名昭著的可能候选者"dotted line"
这种方法并不容易,但是有很多关于识别pdf文件中结构元素的研究。特别是,如果您 运行 google 学者搜索,您会发现大量有用的文章,其中人们尝试检测表格、列表、段落等。