时间水印最大的坑不是取时间,是「宽度会变」。 补零做对、定位靠边,它就不抖;居中定位则会肉眼可见地左右晃。
上一节的 x、y 表达式让文字能动,这一节让文字「每帧都不一样」。 两者合起来,就是监控画面上那个一直在跳的时间戳。
一、六种时刻,各量一次宽度
文字 渲染宽度 与最宽的差
07:53:01 96.0 0.0 11:11:11 96.0 0.0 09:00:59 96.0 0.0 23:59:59 96.0 0.0 7:53:01 82.0 14.0 7:5:1 54.0 42.0
前四行宽度一个像素都不差——微软雅黑自带的数字本来就是等宽的。 所以让宽度变的不是数字本身,而是「不补零」。
少一位就少 14 像素,少两位少 42 像素——这个量级足够肉眼看见。 很多人的时间水印「一跳一跳」,根子就在这里。
二、宽度会变,位置就会抖
定位写法 宽度变化时怎么表现
x=10 左边固定,右边伸缩,不抖 x=w-tw-10 右边固定,左边伸缩,不抖 x=(w-tw)/2 两边都动,肉眼可见地左右晃
第三行是最容易踩的:居中定位配一张每秒都在变的文字, 水印会一直小幅左右跳。单看一帧没问题,播起来很扎眼。
前两行也不是完全不动——它们只是把抖动挪到了另一侧。 想彻底不抖,还得把字宽也固定住。
三、补零加等宽字体:让宽度彻底不动
字体 四种时刻的宽度 差值
微软雅黑 96 ~ 96 0.0 Consolas 104 ~ 104 0.0
两行的差值都是 0,但结论不能推广——雅黑的数字只是「碰巧等宽」。 换一个数字宽度不一的字体(不少手写体、艺术体都这样),补零也救不回来。
Consolas 是「保证等宽」的选择,雅黑是「碰巧等宽」。 这就是监控画面上的时间戳几乎都用等宽字体的原因:不是为了好看,是为了不抖。
四、命令行的写法
-vf "drawtext=text='%{localtime}':fontsize=24:fontcolor=white:x=10:y=10"
%{localtime} 是每帧现取系统时间,不是开播时取一次。
所以录下来的视频里,时间戳会跟着真实时间走。
要固定格式得写 %{localtime\:%H\\:%M\\:%S}。
里面的冒号还要再转义一层——这是「滤镜参数」套「模板语法」造成的双重转义。
五、动手 Demo:量宽度,找抖动来源
把六种时刻的字符串各渲染一遍,量出真实宽度。 再换一个等宽字体做对照,看宽度能不能彻底不动。
from PIL import ImageFont
def widths(fn):
f = ImageFont.truetype(u"C:/Windows/Fonts/" + fn, 24)
return [(s, f.getlength(s)) for s in
(u"07:53:01", u"11:11:11", u"09:00:59",
u"23:59:59", u"7:53:01", u"7:5:1")]
for s, w in widths(u"msyh.ttc"):
print(u"%-10s %.1f" % (s, w))
for fn in (u"msyh.ttc", u"consola.ttf"):
f = ImageFont.truetype(u"C:/Windows/Fonts/" + fn, 24)
ws = [f.getlength(s) for s in
(u"07:53:01", u"11:11:11", u"09:00:59", u"23:59:59")]
print(u"%-12s %.0f ~ %.0f 差 %.1f"
% (fn, min(ws), max(ws), max(ws) - min(ws)))
实跑输出:
--------------------------------------------------------------------
6.3.6 drawtext 添加系统时间水印——宽度会变这件事
--------------------------------------------------------------------
**① 六种时刻,各渲染一遍量宽度**
文字 渲染宽度 与最宽的差
----------------------------------------
07:53:01 96.0 0.0
11:11:11 96.0 0.0
09:00:59 96.0 0.0
23:59:59 96.0 0.0
7:53:01 82.0 14.0
7:5:1 54.0 42.0
**前四行的宽度一个像素都不差——微软雅黑自带的数字本来就是等宽的。**
**所以让宽度变的不是数字本身,而是「不补零」:**
**`7:53:01` 少了一位,宽度立刻掉 14 像素。**
**结论:只要补零做到位,比例字体的时间水印也不会抖。**
**② 宽度会变,位置就会抖**
定位写法 宽度变化时怎么表现
---------------------------------------------
x=10 左边固定,右边伸缩,不抖
x=w-tw-10 右边固定,左边伸缩,不抖
x=(w-tw)/2 两边都动,肉眼可见地左右晃
**第三行是最容易踩的:居中定位配一张每秒都在变的文字,**
**水印会一直小幅左右跳——单看一帧没问题,播起来很扎眼。**
**③ 补零 + 等宽字体:让宽度彻底不动**
字体 四种时刻的宽度 差值
----------------------------------------
微软雅黑 96 ~ 96 0.0
Consolas 104 ~ 104 0.0
**两行的差值都是 0,但结论不能推广——微软雅黑的数字恰好也是等宽的,**
**换成数字宽度不一的字体(不少手写体、艺术体都这样),补零也救不回来。**
**Consolas 是「保证等宽」的选择,雅黑是「碰巧等宽」。**
**这就是为什么监控画面上的时间戳几乎都用等宽字体——不是为了好看,是为了不抖。**
**④ 命令行怎么写**
**`-vf "drawtext=text='%{localtime}':fontsize=24:fontcolor=white:x=10:y=10"`**
**`%{localtime}` 是每帧现取的系统时间,不是开播时取一次。**
**想要固定格式得写 `%{localtime\:%H\\:%M\\:%S}`——**
**里面的冒号还要再转义一层,这是滤镜参数套模板造成的双重转义。**
getlength 返回的是排版宽度,浮点数,比 textbbox 更适合量「会不会抖」。
textbbox 给的是包围盒,含上下伸部,做定位时更常用。
四舍五入到整数再看也不影响结论:差 0 就是差 0。 真要比较,建议把所有时刻都量一遍再取最大最小值,别只挑两个。
等宽字体不一定都好看。Consolas 的零带斜杠,糊在视频里反而更清楚—— 这也是监控行业偏爱它的一个附带原因。
30 秒实验
- 加日期:把格式从时分秒扩到年月日加时分秒,看宽度还稳不稳。
- 换字体:试
simhei.ttf,看它的数字是不是也等宽。 - 真跑对比:
x=10与x=(w-tw)/2各录 10 秒,肉眼比抖动。
常见误区
- 小时不补零。宽度直接少 14 像素,左右会晃。
- 居中定位配动态文字。每帧重算 tw,两边都在动,晃得最明显。
- 以为所有字体的数字都等宽。只有部分是,得实测。
自测三问(点开对答案)
1. 时间水印为什么会左右抖? —— 文字宽度随内容变化,居中或贴右定位时,位置就跟着变。 2. 怎么让宽度彻底不动? —— 补零 + 等宽字体。补零固定字符数,等宽字体固定每字符宽度。 3. `%{localtime}` 是什么时候取的? —— 每帧现取,不是开播时取一次。- ☐ (本节完,下一节 6.4 文字跑马灯案例实战)