字号改的是面积,不是边长:16 到 32 边长翻倍,像素数涨到 3.14 倍。 颜色只改值不改形状,四个颜色的非透明像素数完全一样。
上一节把文字水印贴上了,但只知道它「在那儿」。 这一节管两件事:它多大、什么颜色,以及它相对画面到底占几成。
一、字号:像素数按面积涨
同一句「水印」,四档字号各画一遍:
fontsize 字形宽 字形高 非透明像素 相对 16
12 24 11 154 0.65× 16 32 15 236 1.00× 24 48 23 481 2.04× 32 64 31 741 3.14×
从 16 到 32,宽高都翻了一倍,像素数却只涨到 3.14 倍。 不到 4 倍,是因为小字号时笔画相对更粗,抗锯齿也占了更大比例。
但趋势仍然是按面积走:字号调大一档,观感上的存在感是翻着上去的。 所以「稍微大一点」这个念头要克制,很容易一下就大到盖住画面。
二、颜色:只改值,不改形状
四个颜色,同一档字号:
颜色 R G B 非透明像素
白 255 255 255 481 红 255 0 0 481 黄 255 255 0 481 半透明白 255 255 255 481
四行的非透明像素数一模一样——颜色只改值,不改形状。 最后一行的通道均值还是满的 255,因为 alpha 是单独一个通道。
这就解释了为什么透明必须靠 alpha,而不是「把颜色调暗一点」。 调暗得到的是灰色字,压在亮背景上仍然是一块实心,透不出底下的画面。
三、字号相对画面到底占几成
同一句 fontsize=24,放到三种画面高度里看:
画面高度 占几成 观感
90 27% 太大,几乎盖住画面 720 3.3% 偏小,勉强能看 1080 2.2% 更小,得放大字号
水印字号通常取画面高度的 3% 到 5%。按这个标准,24 号连 720p 都不够。
所以字号不能照抄。实战里常写 fontsize=h/30 这种比例式,
让同一行命令在 720p 与 1080p 上都合适。
注意 fontsize 本身不认表达式,这个比例得在外面算好再拼进去——
只有 x、y 是每帧重算的表达式。
四、命令行的写法
-vf "drawtext=text='水印':fontsize=24:[email protected]:x=10:y=10"
fontcolor 后面加 @0.5 就是半透明,取值范围 0 到 1。
它比单独的 alpha 参数直观,也不影响字形的其他属性。
想要描边再加 borderw=2:bordercolor=black,
白色文字配黑色描边,压在亮背景上也能看清——这是加在复杂画面上的常用组合。
五、动手 Demo:四档字号、四个颜色
先按 12、16、24、32 四档字号画同一句话,量字形尺寸与非透明像素。 再固定字号换四种颜色,看像素数变不变。
import numpy as np
from PIL import Image, ImageDraw, ImageFont
FONT = u"C:/Windows/Fonts/msyh.ttc"
def draw(text, size, color=(255, 255, 255, 255)):
f = ImageFont.truetype(FONT, size)
bb = ImageDraw.Draw(Image.new(u"RGBA", (8, 8))).textbbox(
(0, 0), text, font=f)
im = Image.new(u"RGBA", (bb[2] - bb[0] + 8, bb[3] - bb[1] + 8),
(0, 0, 0, 0))
ImageDraw.Draw(im).text((4 - bb[0], 4 - bb[1]), text, font=f,
fill=color)
return im, bb
rows = []
for size in (12, 16, 24, 32):
im, bb = draw(u"水印", size)
rows.append((size, bb[2] - bb[0], bb[3] - bb[1],
int((np.array(im)[:, :, 3] > 0).sum())))
base = [r[3] for r in rows if r[0] == 16][0]
for size, w_, h_, n in rows:
print(u"fontsize %-3d 字形 %dx%d 非透明 %4d 相对 16 %.2f 倍"
% (size, w_, h_, n, n / float(base)))
for tag, col in ((u"白", (255, 255, 255, 255)), (u"红", (255, 0, 0, 255)),
(u"黄", (255, 255, 0, 255)),
(u"半透明白", (255, 255, 255, 128))):
im, bb = draw(u"水印", 24, col)
a = np.array(im)
m = a[:, :, 3] > 0
print(u"%-6s R %d G %d B %d 非透明 %d"
% (tag, a[:, :, 0][m].mean(), a[:, :, 1][m].mean(),
a[:, :, 2][m].mean(), int(m.sum())))
实跑输出:
--------------------------------------------------------------------
6.3.2 drawtext 控制文字颜色及大小
--------------------------------------------------------------------
**① 字号:像素数按面积涨,不是按边长涨**
fontsize 字形宽 字形高 非透明像素 相对 16
-------------------------------------------------------------
12 24 11 154 0.65×
16 32 15 236 1.00×
24 48 23 481 2.04×
32 64 31 741 3.14×
**从 16 到 32,字形宽高都翻了一倍,非透明像素却只涨到 3.14 倍。**
**不到 4 倍的原因是:小字号时笔画相对更粗,抗锯齿也占了更大的比例。**
**但整体趋势仍然按面积走——字号调大一档,观感上的存在感是翻着上去的,**
**不是线性上去的。**
**② 颜色:只改值,不改形状**
颜色 R G B 非透明像素
---------------------------------------------------
白 255 255 255 481
红 255 0 0 481
黄 255 255 0 481
半透明白 255 255 255 481
**四行的非透明像素数完全一样——颜色只改值,不改形状。**
**但最后一行的通道均值还是满的 255,因为 alpha 是单独一个通道:**
**画出来是「白」,贴上去才「半透」——这就是为什么透明必须靠 alpha 通道,**
**而不是「把颜色调暗一点」。**
**③ 命令行怎么写**
**`-vf "drawtext=text='水印':fontsize=24:[email protected]:x=10:y=10"`**
**`fontcolor` 后面加 `@0.5` 就是半透明,取值范围 0 到 1。**
**它比 `alpha` 参数直观,也不影响字形的其他属性。**
**④ 字号与画面的比例**
画面高度 字号 24 占几成 观感
------------------------------------------------------
90 27% 太大,几乎盖住画面
720 3.3% 偏小,勉强能看
1080 2.2% 更小,得放大字号
**同一句 `fontsize=24`,在 160×90 上占了四分之一高,在 1080p 上只占 2%。**
**水印字号通常取画面高度的 3% 到 5%,按这个标准,24 号连 720p 都不够。**
**所以字号不能照抄,得按画面高度换算——**
**实战里常用 `fontsize=h/30` 这种写法,让它随分辨率自动缩放。**
先把四行都算出来存进 rows,找到 16 那一档的像素数当基准,再统一打印。
这样就不会出现「拿自己当基准」的 1.00 倍假象。
a[:, :, 0][m] 是「取红色通道,再按 alpha 掩码筛出字形像素」,
算均值时只算字形,背景的透明像素不参与,否则均值会被稀释。
半透明那一行通道均值仍是 255,因为它测的是颜色值不是透明度。 想量透明度得看 alpha 通道的均值。
30 秒实验
- 改字号:把 24 换成 48,看像素数是几倍,与你猜的一样吗。
- 加描边:用
ImageDraw.text(..., stroke_width=2)模拟borderw,看像素涨多少。 - 真跑对比:有 drawtext 的机器上,同一句命令换
fontsize看tw的变化。
常见误区
- 以为字号翻倍像素也翻倍。是按面积涨,接近 4 倍。
- 把颜色调暗当透明用。那不是透明,是灰色,透不出底下画面。
- 在
fontsize里写h/30。它只接受数字,表达式只有 x、y 支持。
自测三问(点开对答案)
1. 字号从 16 到 32,非透明像素涨几倍? —— 3.14 倍,不是 4 倍:小字号笔画相对更粗,抗锯齿占比更大。 2. 为什么四个颜色的非透明像素数一样? —— 颜色只改像素值,不改哪些像素被画到,形状由字形决定。 3. 水印字号一般取画面高度的多少? —— 3% 到 5%。`fontsize=24` 在 1080p 上只有 2.2%。- ☐ (本节完,下一节 6.3.3 查看 drawtext 的参数)