早上好,我是まさきん。
我想填一份健康保险的给付申请书,结果发现PDF里没法输入文字。它没有填写栏,是所谓的“扁平PDF”。我让AI按坐标把文字叠印上去,做成了可以打印的版本,这里把过程记下来。
※本文为发布时的信息,最新条件请以官方网站为准。
- 无法输入的PDF申请书,很多时候是不带填写栏(AcroForm)的“扁平PDF”
- 工具有3个:用 pdfplumber 取表格线的坐标,用 reportlab 画文字,负责叠加的是 pypdf
- 坐标原点在 pdfplumber 里是左上角,在 reportlab 里是左下角。上下相反,所以需要转换
- A4 约为595×842pt 。1pt是1/72英寸,坐标全部按这个单位来考虑
- 银行账号、亲笔签名、盖章这3处没有叠印,而是打印之后手写
碰上了没有填写栏的PDF
我做的是健康保险的给付申请书,也就是把自己先垫付的医疗费申请退回来的文件。制度的流程写在通过疗养费和医疗费补助拿回垫付医疗费的步骤里。
申请书是以PDF形式发放的。但是打开之后栏位点不了,哪里都没有可以打字的地方。表格一共有2张。
打印出来全部手写也是一个办法。话虽如此,同样的数字和期间要写好几处,还是有点麻烦。写错了就得重新打印。所以我决定,只把能打的部分交给AI来打。
扁平PDF的分辨方法
PDF申请书有2种:一种是嵌入了输入栏的,另一种只是把表格线当作图画画上去的。
Adobe的官方帮助里,把后者称为“flat form”,说明是作者没有添加输入栏的表单。这篇文章里就叫它扁平PDF。
分辨方法很简单。
- 打开PDF点击栏位。如果不出现光标,很可能就是扁平PDF
- 按Tab键,也不会从一个栏跳到下一个栏
- 请AI“查一下这个PDF有没有输入栏”
第3种可以用 pypdf 这个库来确认。只需调用官方文档里的 get_fields()。没有输入栏的话会返回 None。
from pypdf import PdfReader
reader = PdfReader("form.pdf")
print(reader.get_fields()) # 没有输入栏时为 None
我的申请书就是在这一步知道没有输入栏的。如果是有输入栏的PDF,就用不着这篇文章的方法了。正常地往栏里输入更可靠。
用到的工具有3个
让AI使用的工具,都是免费的Python库。分工很清晰。
| 工具 | 作用 | 这次用到的功能 |
|---|---|---|
| pdfplumber | 读取原PDF | 取表格线和矩形的坐标,把页面转成图片 |
| reportlab | 画出新的PDF | 在透明的纸上只放文字 |
| pypdf | 把PDF叠在一起 | 检查有没有输入栏,把文字那张纸叠到表格上 |
可以想象成一张透明胶片。在申请书上面放一张透明胶片,只在上面印上文字,再把两张贴合在一起。做的事情就只有这些。
原来的PDF本身并没有被改写。所以位置偏了的话,只重做透明胶片就行。我觉得这一点让人很轻松。
PDF的单位是点
坐标的单位是点(pt)。reportlab 的官方文档里写着,1pt是1/72英寸。
A4是210mm×297mm,换算成点 约为595×842pt 。我在手边把 reportlab 的A4常量打印出来,是595.28×841.89。
也就是说1mm约为2.83pt。栏的高度如果是8mm,大约就是23pt。把这个换算记在脑子里,就能对AI给出的数字有个大致判断。
步骤的全貌
流程分7个阶段。即使不是工程师,我想只要能跟上顺序就足够了。
- 确认PDF里有没有输入栏
- 取出表格线的坐标
- 确定放文字的单元格矩形
- 制作只载有文字的叠印用PDF
- 叠到原PDF上
- 转成图片用眼睛确认
- 打印并填写手写的部分
我做的是给AI智能体下指示和做确认,代码不是我自己写的。不过,我觉得最好还是知道它在做什么。因为位置偏了的时候,才知道该怀疑哪里。
取表格线的坐标
pdfplumber 会把页面上的图形以列表形式返回。按官方的说明,线是 .lines,矩形是 .rects。还有把矩形拆成4条边再和线合在一起的 .edges。
import pdfplumber
with pdfplumber.open("form.pdf") as pdf:
page = pdf.pages[0]
print(page.width, page.height)
for r in page.rects:
print(r["x0"], r["x1"], r["top"], r["bottom"])
x0 是左端,x1 是右端,两者都是到页面左端的距离。top 和 bottom 则是到页面上端的距离。
申请书里的表,有时不是用矩形,而是用一组线画出来的。这种时候就看 .lines 和 .edges,从竖线和横线的交点把单元格的矩形拼出来。
这是最不起眼、也最重要的一道工序。只要栏的左端、右端、上端、下端这4个数字定下来,之后就可以机械地往下做了。
制作叠印用的PDF
接下来用 reportlab 制作只有文字的PDF。要输出日文需要注册字体。官方文档里登载的是使用 UnicodeCIDFont 的方法。日文字体列了2种:明朝体的 HeiseiMin-W3 和黑体的 HeiseiKakuGo-W5。
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.cidfonts import UnicodeCIDFont
pdfmetrics.registerFont(UnicodeCIDFont("HeiseiKakuGo-W5"))
c = canvas.Canvas("overlay.pdf", pagesize=A4)
c.setFont("HeiseiKakuGo-W5", 10)
H = A4[1] # 页面的高度
x0, x1, bottom = 100, 300, 142 # 用pdfplumber取到的值
y = H - bottom + 6 # 上下翻转后稍微抬高一点
c.drawString(x0 + 4, y, "示例 太郎") # 左对齐
c.drawRightString(x1 - 4, y, "12,345") # 右对齐
c.showPage() # 如果有第2页就接着画
c.save()
姓名和数字当然都是示例。关键是 H - bottom 这一行,它把从上往下的距离换成了从下往上的距离。理由在后面的章节里写。
想把特定的字体嵌入PDF时,也可以用 TTFont,也就是指定手边的字体文件来注册的方法。如果想让打印出来的外观保持一致,选这个也许也是个办法。
叠到原PDF上并用图片确认
最后用 pypdf 把两者叠起来。用的是官方文档里作为“图章”介绍的 merge_page()。
from pypdf import PdfReader, PdfWriter
overlay = PdfReader("overlay.pdf")
writer = PdfWriter(clone_from="form.pdf")
for i, page in enumerate(writer.pages):
page.merge_page(overlay.pages[i])
writer.write("filled.pdf")
merge_page() 什么都不指定的话,就是叠在上面。加上 over=False 则变成垫在下面。这次是想把文字放在上面,所以保持原样就可以。
做好的PDF不要马上打印,先转成图片看一看。用 pdfplumber 的 to_image(resolution=150) 可以把页面变成PNG。有没有超出栏位,在这一步把所有的栏都看一遍。
调整固定支出,要做的事情也差不多:把数字拿出来,用眼睛确认,再修正偏差。我想通信费按这个顺序来看也比较容易推进。
坐标系是上下相反的
这项工作里最容易出错的,是坐标的方向。我把在官方文档里确认过的内容做成了表。
| 项目 | pdfplumber | reportlab |
|---|---|---|
| 原点 | 页面的左上角 | 页面的左下角 |
| 横向 | x0 x1 是到左端的距离 | x 向右增大 |
| 纵向 | top bottom 是到上端的距离 | y 向上增大 |
| 单位 | 点 | 点(1/72英寸) |
| 转换 | 直接读取 | y = 页面高度 − 从上往下的距离 |
pdfplumber 里还有 y0 和 y1 这两个值。它们是到页面下端的距离。所以用 y0 的话,不用做减法就能交给 reportlab。
不过,把 top 和 y0 混着用会乱。一开始就定好用哪一个,并且也告诉AI,这样应该比较好。比如干脆定成“按从上往下的距离来读,画的时候再翻转”。
- 如果文字出现在纸面上下相反的一侧,很可能是忘了翻转坐标
- 横向两边都以左端为基准,可以直接使用
- 纸张高度不要写死,用从原PDF读出来的值更放心
偏过一次的原因是读错了右端
其实文字偏过一次。原因出在某个填写栏右端的坐标上。AI把它读成了比正确位置更靠右。
单元格的矩形是放文字的基准。右端的数字不对,以它为基准的文字也会跟着动。这种偏差,把叠加的结果转成图片一看就能发现。
修正的办法很简单。把表格线的坐标重新读一遍,把单元格的右端换成正确的值,然后重新制作叠印用的PDF。
一般来说,申请书里的表格线条交错复杂。把相邻栏的线或外框的线错当成目标栏的边,是有可能发生的。所以坐标并不是“取到了就结束”。我认为它和用图片确认这道工序是成套的。
留给手写的3处
并不是全部都叠印了。下面这3处,我特意留了空。
| 栏 | 是否叠印 | 理由 |
|---|---|---|
| 姓名、期间、金额等栏 | 叠印了 | 打错可以在屏幕上改 |
| 银行账号 | 没有叠印 | 不想留在文件里 |
| 亲笔签名 | 没有叠印 | 因为是本人书写的栏 |
| 盖章 | 没有叠印 | 因为是打印之后才盖的 |
亲笔签名栏由本人亲手书写,这是一般的想法。印上去的名字不能代替亲笔签名。盖章也一样,要印到纸上之后再盖。
银行账号这一项,与其说是规则,不如说是我自己的判断。交给AI的数据里也好,生成的PDF里也好,我都不想留下它。数字不多,手写的负担也很小。
还有一个判断。贴着“严禁拆封”封条的文件,我没有打开就直接随信寄出,并在相应的栏里写了“如随附文件所示”。
- 哪些栏可以打印、哪些栏需要亲笔签名,要按申请对象的填写说明来确认
- 拿不准的话,先问过申请对象再打印
- 更正的方法也要遵照申请对象的规定
填写的值要和原件核对
交给AI来做,注意力很容易被位置对齐吸引过去。但是申请书里真正重要的,是内容里的数字。
我把填写的值和收据、明细单的扫描件做了对照,一项一项地确认金额和期间是否一致。这一步我把它留作由人眼来看的工序。
核对的思路和让AI用会计SaaS和邮件核对副业经费的那篇是一样的:有两个来源就互相比对。申请书也不例外。
把纸集中起来扫描的安排,练习题的批量扫描与分拣那篇文章也许可以参考。
个人信息的处理
申请书里装满了个人信息。让AI干活的时候,我觉得最好先定好交出去的范围。
- 如果只是取坐标,只要空白申请书的PDF就够了
- 填写的值,只把需要的项目另外交过去
- 像银行账号这样不交也行的东西就不交
- 生成的PDF和图片,提交完之后重新考虑存放的位置
尤其最后一点很容易忘。确认用的图片上,填好的内容原样都在。不要一直留在工作文件夹里才比较安心。
这篇文章里,我也没有写健康保险的名称和金额。写亲身经历的时候也好,筛选交出去的数据的时候也好,我认为思路是一样的。
也有不写代码的方法
读到这里,也许有人会觉得“我不会做到这个地步”。这种情况下,Adobe Acrobat 的“填写和签名”可以作为候选。
Adobe的官方帮助里,登载了往扁平表单里输入的方法,也就是使用 Acrobat Reader 的 Fill & Sign 工具。可以在表单的任意位置放置文字和符号。因为是用鼠标定位置,所以不需要考虑坐标。
表格只有1〜2张,要写的栏也不多。那样的话我觉得这个方法更快。让AI按坐标来打的方法,是在栏很多的时候才见效。要反复制作同一种格式的时候,应该也比较适合吧。
适合的人·不适合的人
我想适合的是下面这样的人。
- 觉得在手写的申请书上反复写同样的内容很麻烦的人
- 已经有让AI智能体操作文件的环境的人
- 今后还打算反复提交同一种格式申请书的人
另一方面,不适合的是这些情况。
- 栏只有几处,手写5分钟也能写完
- 申请对象要求手写,或者不允许对格式进行加工
- 抽不出时间做图片确认和原件核对
即使交给AI,确认仍然是留给人的工作。如果要省掉这一步,手写也许更安全。
- 是否确认了申请书的PDF里没有输入栏
- 是否按申请对象的填写说明,确认了哪些栏可以打印、哪些栏需要亲笔签名
- 坐标的方向是否统一为从上往下的距离或从下往上的距离
- 是否把叠加后的PDF转成图片,用眼睛看过所有的栏
- 是否把填写的值和收据、明细单的原件核对过
- 是否定好了银行账号等不交给AI的项目
- 打印后要手写的栏,是否记在了备忘里
常见问题
Q. 怎么分辨是不是无法输入的PDF?
点击栏位不出现光标的话,很可能是没有输入栏的PDF。可靠的做法是用 pypdf 的 get_fields() 来查。没有输入栏的话会返回 None。
Q. 不会编程也能用吗?
前提是让AI智能体来写代码。我自己也没有写。不过,图片确认和原件核对需要自己来做。
Q. 为什么文字会出现在上下颠倒的位置?
因为坐标的原点不同。pdfplumber 的原点在左上角,reportlab 的原点在左下角。用页面高度减去从上往下的距离,位置就对了。
Q. 日文出现乱码,或者显示不出来。
有可能是没有注册日文字体。在 reportlab 里可以用 UnicodeCIDFont 注册日文字体。要用手边的字体的话就是 TTFont。
Q. 扫描的纸质申请书也能用同样的方法吗?
扫描的PDF,很多时候整页是一张图片。这种情况下表格线并不是作为图形存在的,所以用 pdfplumber 取不到坐标。我想需要另想办法,从图片上测量栏的位置。
Q. 亲笔签名栏和盖章栏也可以打印吗?
亲笔签名栏由本人亲手书写,这是一般的想法。盖章也是在打印之后进行。具体怎么处理因申请对象而异,请确认一下填写说明。
Q. 打印出来位置偏了。
原因可能是打印时的缩放。如果设置成按纸张大小缩小,整体会稍微变小。这次是把原表格和文字叠成了一个PDF,所以表格线和文字会一起移动。把倍率设成实际大小会比较放心。
Q. 原来的PDF会被改写吗?
不会。是读取原PDF,把叠加的结果用另一个名字保存。位置偏了的话,只重做叠印用的PDF就行。
参考的官方信息
- pdfplumber README(关于坐标和 lines / rects / edges 的说明)
- ReportLab 用户指南 第2章 Graphics and Text with pdfgen
- ReportLab 用户指南 第3章 Fonts and encodings
- pypdf 文档 Adding a Stamp or Watermark to a PDF
- pypdf 文档 Interactions with PDF Forms
- Fill in forms, Adobe Acrobat Reader(Adobe 帮助)
- 在 Acrobat 中填写和签署 PDF 表单(Adobe 帮助)
总结
即使是没有填写栏的PDF,只要能取到表格线的坐标,就能把文字叠上去。绊住我的是读错了坐标。重新读一遍就能修好,所以用图片确认这道工序看来最好不要省。
申请书是邮寄出去的。能打的地方用打的,该手写的地方用手写。先把这条界线定好,做起来应该会从容一些吧。
手续上的工夫省下来之后,家庭开支的其他调整也能稍微顾得上了。像通信费这样每个月的固定支出,顺着这个势头看一次也许不错。
本文包含联盟营销广告。如果您通过本站链接申请相关商品或服务,我们可能会从合作企业获得报酬。此外,运营者是乐天集团的员工,也可能通过员工推荐计划获得报酬。文章内容与评价均基于运营者的真实体验与调查完成,与是否存在广告无关,但请您在阅读前了解上述关系。详情请参阅免责声明与联盟营销说明。 免责声明与联盟营销说明
本文包含机器翻译内容。正式条件请以乐天移动官方网站的多语言页面为准。
如果您对乐天移动的通信区域·信号状况有疑问,可以通过官方的 电波改善调查申请表 进行咨询。