造假记:手写字迹仿真

奈何 2020 年了,全中国都脱贫了,我竟然还在大学本科遇到了以 抄写 课文为教学方针语言老师。

自愿 为前提的抄写对学习的帮助个人是认同的,也曾从中受益过。

而全盘一致的任务性抄写我是反感的,不吃这一套的我,寻思着这教学方针对我没用啊,甚至于 抄写=浪费时间

换在之前的学校我很有可能就不理会(不交了),可这里是本科,能拿的绩点还是得尽量拿一下呀。要是不交的话这种老师势必记仇最后影响到绩点。

没办法,于是奔着抄写不如学习新技能的心态,开始在网上寻找 字迹仿真 解决方案。

众里寻他千百度,蓦然回首,谁知方案竟在阑珊处。

最初就尝试 英文 Google 寻找开源方案〔毕竟开源社区,人多力量大,活力足〕,没想到有效方案最后还是在知乎话题里找到的。

寻找期间,在类似于 stackflow 的社区中看到一个中国人的类似提问,下面的外国人还非常困惑为什么需要电子化仿真字迹,觉得多此一举,似乎这是个中国特色需求啊。🤔

使用场景:

除了上述我的需求外,还看到了下面这些其他人的使用场景,觉得挺适合的。

  • 淘宝随快递包裹的好评定制感谢信

  • 写入党申请书等繁琐的官僚公文,如果可以提交电子版的话

  • 扫描版会议记录

仿真难点和原理

难点

字体仿真的难点在于如何模仿人写字的不稳定性,不稳定性主要有如下体现:

  • 重复字:同样的字,同样的笔画,却神态各异(字体大小,笔画长短)
  • 工整性偏移:每个字之间的间距,每一行字之间的行距,每一字的行高,也不尽相同。

原理

了解难点的体现后,仿真原理自然就是针对这些不稳定的体现进行模拟,通常是使用计算机中的随机函数,对 行高 字间距 行间距 字体大小 字体类型 的值在一定范围内进行随机变动。

一些优秀的仿真算法:还可以在每个 笔画 的基础上进行 角度旋转 的随机偏移,比如方案二

方案介绍:

方案导览

这里总结归纳了 3 种方案,其中 2 种适合一般人,第二种适合有一定计算机知识基础的人使用。三种方案各有所长,本人选用的是 中英文仿真度都不错 的第二种方案。

方案一: 免费,新手友好,中英文效果良好。

方案二: 免费,需要一定的计算机基础,中英文效果优秀,能自定义背景 (稿纸)。

方案三: 收费,新手友好,中文效果良好,英文效果不佳,能对稿纸进行仿真。

方案加强版

以上 3 种方案都逃不开要选择一款合适的 手写字体,再合适的字体都不如自己亲手写的字体,这里给 字迹仿真需求高和追求完美的使用者一个 自创字体 方案.

思路:

使用方正出品的一款名叫 手迹造字 的 app,把常用汉字写一遍,然后导出自己的字体。

方案来源:如何让打印出来的字体看起来像手写的? - 六翼的回答 - 知乎
手迹造字官网


方案一:Word 文档宏函数

本方案原文:如何让打印出来的字体看起来像手写的? - UncleSugar的回答 - 知乎

原文已经生动有趣详细的介绍了一番,这里就其中的 重点宏代码 进行一下说明。

  1. 保证系统中已经安装你所选择的 仿真字体 [1]
  2. 字体大小建议为 15 左右,以符合实际。[2]

剩下的 行间距 行高 字间距 字高 等仿真参数在代码中有备注,根据自己的实际情况进行修改就好。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
Attribute VB_Name = "NewMacros"
Sub 手写字体()
'
' 手写字体 宏
'
'

Dim R_Character As Range


Dim FontSize(5)
' 字体大小在5个值之间进行波动,可以改写
FontSize(1) = "14"
FontSize(2) = "14.5"
FontSize(3) = "15"
FontSize(4) = "15.5"
FontSize(5) = "16"


Dim FontName(3)
'字体名称在三种字体之间进行波动,可改写,但需要保证系统拥有下列字体
FontName(1) = "陈静的字完整版"
FontName(2) = "萌妹子体"
FontName(3) = "李国夫手写体"

Dim ParagraphSpace(5)
'行间距 在一定以下值中均等分布,可改写
ParagraphSpace(1) = "12"
ParagraphSpace(2) = "13"
ParagraphSpace(3) = "20"
ParagraphSpace(4) = "7"
ParagraphSpace(5) = "12"

'不懂原理的话,不建议修改下列代码

For Each R_Character In ActiveDocument.Characters

VBA.Randomize

R_Character.Font.Name = FontName(Int(VBA.Rnd * 3) + 1)
'字体名称随机函数
R_Character.Font.Size = FontSize(Int(VBA.Rnd * 5) + 1)
'字体大小随机函数
R_Character.Font.Position = Int(VBA.Rnd * 3) + 1
'字体位置上下浮动量
R_Character.Font.Spacing = 0
'字符间距

Next

Application.ScreenUpdating = True


For Each Cur_Paragraph In ActiveDocument.Paragraphs

Cur_Paragraph.LineSpacing = ParagraphSpace(Int(VBA.Rnd * 5) + 1)
'行高随机函数

Next
Application.ScreenUpdating = True

End Sub

方案二:开源 Python 手写模拟库

导览

亮点

  • 中文字符可以笔画偏移,达到 笔画级别的仿真
  • 可以对接 api 适合开发上层软件

使用要点

  • 无需修改 font_size=100 的值,即使要修改也推荐从 80 开始尝试。
  • 文字需要手动在代码中换行,因此建议把 background 中的 size 背景大小调大一些,避免超出范围
  • 修改仿真参数一定要了解 排版关系图

其他只介绍 Windows 系统下的使用要点,需要在 Linux 环境使用的都是大神,看官方 Tutorial 即可。

环境要求:
  • 安装 Python 完整版,并添加到环境变量
要点细节:
  • 由于是 Windows 系统,路径写法和 Python 库有所不同,见下:

    • 头部追加 import os 以导入 os 库

    • 字体路径应修改为如下形式:

      1
      2
      3
      4
      # 修改前
      font=ImageFont.truetype("path/to/my/font.ttf"),
      # 修改后,注意路径前有个 r
      font=ImageFont.truetype(r"D:\Users\Bingo\Desktop\font.ttf"),
    • 最后一行代码文件保存代码 im.save 修改成如下的 2 行:

      1
      2
      3
      4
      5
      # 修改前:
      im.save("path/to/my/output/{}.webp".format(i))
      # 修改后
      os.chdir(r'D:\Users\admin\Desktop')
      im.save("Handwrite-{}.webp".format(i))

实操成效

效果图

选用 青松手写体1.ttf 生成,效果图如下:

青松手写体1 效果图

代码详情

具体代码如下,点击展开
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

# coding: utf-8
from PIL import Image, ImageFont
import os
from handright import Template, handwrite

text = """
窗前明月光
疑是地上霜
举头望明月
低头思故乡
----------
我方向你方报实盘,在我方时间7月10日星期一下午5时以前答复有效
我方向你方报实盘,在我方时间星期二上午11时以前回复有效
我方向你方报实盘,在自本日起一周之内你方回复有效
我方报盘……(各项交易条件)……以我方最后确认为准
我方向你方报盘,以未售出为准
我方向你方报盘,以先售为条件
我方向你方报盘,此报盘如有变化不另行通知
此盘5日内不接受,就撤销
------------------
1. We offer you firm subject to reply by 5 p. m. our time, Monday, July 10
2. We offer you firm subject to reply here by 1l a.m., Tuesday our time
3. We offer you firm subject to your reply here within one week from today
4. We are ready to sell…
5. We offer subject to our final confirmation
6. We make you an offer subject to the goods being unsold
7. We submit you this offer subject to prior sale
8. We offer you subject to change without notice
9. This offer must be withdrawn if not accepted within 5 days
----------------------
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
----------------------
般油应内许表青常保九极影而什先,识点支内学是-周品调秤护。 料图素真所克所号论组之,反指家物取霸8体枪。 阶作今化走天开不义片,格决系统第报行革,命做四度革进原变两,根芳原到级都式。 子型强声如传子,安容则听具教,者西安好约,O呆高争均。 件越内且军叫收维严样按统观,专管这争本已D盯吵豆西。 受性素就开候与度称众消,适则说步特历会众量,少程弦至实京设认足。 照手入加文持些去将地,万还建此什问取与关整,在能Z杠置伶芹运。 设品知马式华,关队本多,报F县米。 青却采非则系历,置争题器平族石,家X地发权几。 当用毛土果究以确并,更交真表处立接展,去标L科劳扯出。 力五联干区把自,太只及准军程,小V式级肃。 响前连统已等量照么头,声口他料决基布改解,难此M至料至米战。 状三为时设给果光得每,电选或下角道相九听,自压豆屈委气整常。 深油器个能时无用队,信式定所且点式见拉,消辰世极条有并。 期更好管立内习制电强要研,龙术的教O才增处积。 观增海石少受九活住起,生日保片员发的运,论院孤农导两将速。
"""

template = Template(
background=Image.new(mode="1", size=(3000, 3000), color=1),
font_size=60,
font=ImageFont.truetype(r"D:\Users\Bingo\Desktop\青松手写体1.ttf"),
line_spacing=65,
fill=0, # 字体“颜色”
left_margin=100,
top_margin=100,
right_margin=100,
bottom_margin=100,
word_spacing=3,
line_spacing_sigma=2, # 行间距随机扰动
font_size_sigma=3, # 字体大小随机扰动
word_spacing_sigma=0, # 字间距随机扰动
end_chars=",。", # 防止特定字符因排版算法的自动换行而出现在行首
perturb_x_sigma=1, # 笔画横向偏移随机扰动
perturb_y_sigma=1, # 笔画纵向偏移随机扰动
perturb_theta_sigma=0.05, # 笔画旋转偏移随机扰动
)
images = handwrite(text, template)
for i, im in enumerate(images):
assert isinstance(im, Image.Image)
im.show()
os.chdir(r'D:\Users\Bingo\Desktop')
im.save("Dici-s-Handwrite-1{}.webp".format(i))

方案三:收费的萝卜工坊

简介

这是一个在百度发现的 收费方案,为避免广告嫌疑放在了最后,链接也不放了,亲们搜一下就有了。

使用感受:
  • 个人对比感觉对中文字迹的支持尚可,对 英文不佳
  • 非要使用这个生成英文自己的话,优先尝试 3号字体5号字体 ;次选 7号字体(粗体)4号字体
亮点
  • 在于上手简单,有在线可视化效果预览,可以很容易的修改纸张样式,达到字体和纸张双仿真。
注意付费使用的坑

虽然可以预览效果,但是只能预览一页,所以最好把一些特殊文字都放在第一页,对仿真效果有充分的认可后,在进行付费下载全部。


白嫖大法

这里提供一个白嫖的 Idea ,给喜欢这个方案效果的你 或者 只会用这个方案的你。

白嫖前提:PS 的基本操作!

白嫖思路:
  1. 把需要白嫖的手写内容放在文档的第一页,生成预览效果。
  2. 鼠标右键预览效果图片,把图片另存为至电脑中。
  3. PS 打开该图片,使用最上方工具栏中的 选择--->色彩范围,选择提取水印的颜色,选择适当的容差。
  4. 删除水印选区,图片到处到本地。
  5. 恭喜:白嫖成功。
  6. 如此反复 1-5 步,制作剩下的文档字迹仿真。

我的制作过程、成品展示

在使用 方案二 我贴出的代码生成的实操效果图基础上,使用 Photoshop 进行稿纸仿真并与电子版字迹融合。

制作过程

  1. 用 PS 打开电子版字迹,菜单栏 选择 —> 色彩范围,选取电子稿的底色(白色),删除背景选区,制成 字迹层 透明图。 后期学习 PS 发现,白色背景部分无需制成透明图,使用 正片叠底 即可透明化 (也就是 Step 4 )。
  2. 导入一张自己拍的真实稿纸图作为 底层 背景图。
  3. Ctrl + T ,适当调整电子版字迹透明图大小与稿纸大小吻合。
  4. 调整字迹层:90% 透明度,60% 填充,正交叠底
  5. 制成
  6. 选择一个适中的图片质量导出成品图 (低质量图片有助于隐藏瑕疵,并在一定程度上促进仿真效果)

成品展示

成品一

其实这是失败的一张图,左下角手上有 电子字迹 ,同时大拇指指甲的高度容纳了4行英文,这是不太实际的。

欢迎大家跳到 成品二 进行赏阅

手写展示

成品二

注解与参考

参考

前人栽树后人乘凉…

注解


  1. 代码 21- 26 行处 ↩︎

  2. 代码 11- 17 行处 ↩︎

在线乞讨😋,Donate comment here.

欢迎关注我的其它发布渠道