提示

返回博客列表

别人电脑上你的字幕变成了宋体:ASS 特效字幕、字体子集化与烧录的完整方案

有次交付一批带特效字幕的宣传片,我在自己机器上检查了三遍:字体对、位置对、卡拉 OK 的逐字变色效果也对。发给客户,第二天收到回复——"字幕字体不对,而且有些字显示不出来"。

我让对方截图过来一看:宋体。所有特效都在(说明 ASS 本身被正确解析了),但字体回退了,位置也跟着错位。

原因说穿了很简单:ASS 文件里只记录了"我要用思源黑体"这个名字,并没有把字体文件本身带过去。对方电脑上没装这个字体,播放器就随便找了一个替代。

这篇文章把这条路上搞明白的事写出来:字幕的三种"放法"有什么区别、为什么字体是最容易出问题的环节、怎么把 18MB 的中文字体子集化成 90KB 塞进 MKV、以及在 Linux 服务器上烧录中文字幕要配什么环境。

TL;DR:ASS 只存字体名不存字体文件,跨机器必然出问题。三个解决办法按可靠性排序:烧录(-vf subtitles=,100% 一致但不可逆)、MKV 内挂字体附件(-attach,播放器支持的话效果最好)、要求用户自己装字体(最不靠谱)。中文字体动辄十几 MB,用 pyftsubset 做字形子集化(只保留字幕里用到的字),18MB 能压到 90KB。另外:ASS 的坐标基于 PlayResX/PlayResY,分辨率不匹配会导致位置错乱;字幕文件必须是 UTF-8;字体的商用授权要单独确认。

目录

一、字幕的三种"放法"

先把概念对齐,因为"加字幕"这三个字至少有三种完全不同的做法:

方式 怎么做 优点 缺点 适合
外挂 单独一个 .srt / .ass 文件 可编辑、可切换、体积小 容易丢失、播放器要支持、字体靠用户 本地收藏、媒体库
内挂(软字幕) 封装进 MKV/MP4 的字幕流 不会丢、可切换、可多语言 播放器兼容性差异大、字体仍可能缺 多语言版本、媒体库
内嵌(硬字幕/烧录) 把字画进每一帧 100% 一致,任何设备都显示 不可逆、不能关、不能翻译 短视频、交付成片、手机播放

我现在的判断标准:

  • 要发给别人看的成片 → 烧录(除非对方明确要求可关闭);
  • 自己存档、要在播放器里切语言的 → 内挂 MKV + 字体附件;
  • 还要继续改的 → 外挂,改完再决定要不要内嵌。

判断不了的时候就问一句:"这个视频会在什么设备上播?" 如果答案里有"手机""微信""未知设备",那就烧录,别犹豫。

二、ASS 到底比 SRT 多了什么

SRT 是最简单的格式:

1
00:00:01,000 --> 00:00:04,000
这是一行字幕

只有时间和文本。没有字体、没有颜色、没有位置——一切由播放器决定。

ASS(Advanced Substation Alpha)多了一整套样式系统。一个最小的 ASS 文件结构:

[Script Info]
ScriptType: v4.00+
PlayResX: 1920
PlayResY: 1080
WrapStyle: 0

[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, OutlineColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Default,Source Han Sans SC,54,&H00FFFFFF,&H00000000,&H80000000,0,0,1,2,1,2,60,60,50,1

[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
Dialogue: 0,0:00:01.00,0:00:04.00,Default,,0,0,0,,这是一行字幕
Dialogue: 0,0:00:05.00,0:00:08.00,Default,,0,0,0,,{\pos(960,900)\fad(200,200)}带特效的字幕

三个关键部分:

  1. [Script Info] 里的 PlayResX/PlayResY:字幕的"设计分辨率",所有坐标都基于它;
  2. [V4+ Styles]:样式定义,字体名、字号、颜色、描边、对齐方式、边距;
  3. [Events] 里的 Text:可以带 {\...} 特效标签,实现定位、移动、淡入淡出、逐字高亮(卡拉 OK)。

需要注意的:字体名写的是 Source Han Sans SC(字体的内部名称),不是文件名。而且不同系统对同一字体的叫法可能不一样(比如"思源黑体"在 Windows 上可能叫 "Source Han Sans SC" 或 "Noto Sans CJK SC"),这本身就埋了坑。

常见特效标签:

标签 作用
\pos(x,y) 绝对定位
\move(x1,y1,x2,y2,t1,t2) 移动
\fad(in,out) 淡入淡出(毫秒)
\t(...) 渐变/动画
\k / \K / \kf 卡拉 OK 逐字高亮
\b1 / \i1 粗体 / 斜体
\fs30 字号
\c&HFFFFFF& 颜色(注意是 BGR 顺序!)
\N 强制换行

颜色是 BGR 不是 RGB,这个坑我踩过:&H0000FF& 是红色不是蓝色。

三、字体问题的本质

ASS 文件里只有字体名,没有字体数据。 播放的时候,播放器拿着这个名字去系统里找:

  • Windows:走 GDI/DirectWrite 的字体枚举;
  • Linux/macOS:走 fontconfig;
  • 播放器还可能先看自己的字体目录(PotPlayer、VLC 都有自己的 fonts 目录)。

找不到怎么办?回退到默认字体。Windows 上通常是宋体(SimSun)或者 Arial,macOS 上是 Helvetica/苹方,Linux 上取决于 fontconfig 配置。回退之后:

  1. 字体样式完全变了(这就是客户看到的"宋体");
  2. 字宽变了,排版就变了——原来居中的一行现在超出边界,原来在画面下方 10% 的字幕现在跑到画面外;
  3. 特效标签里的精确坐标(比如卡拉 OK 的高亮位置)全部错位。

更糟的情况是缺字形:英文字体里没有中文字符,回退之后中文直接显示成方框(□)或者空白。我在一台干净的 Linux 服务器上第一次烧录中文字幕,输出的字幕全是空白——服务器上一个中文字体都没装。

所以结论很简单:只要目标设备不受你控制,就不能依赖"对方装了字体"这个假设。

四、MKV 内挂字体:把字体塞进容器

MKV(Matroska)支持附件(attachment),可以把字体文件当作附件塞进去。支持的播放器(PotPlayer、VLC、mpv、Kodi)会自动加载这些字体来渲染 ASS。

ffmpeg -i input.mp4 -i subtitle.ass \
  -attach "SourceHanSansSC-Regular.otf" \
  -attach "FiraSans-Bold.ttf" \
  -map 0:v -map 0:a -map 1:s \
  -c:v copy -c:a copy -c:s copy \
  -metadata:s:s:0 language=chi \
  -metadata:s:t:0 mimetype=font/otf \
  -metadata:s:t:1 mimetype=application/x-truetype-font \
  output.mkv

几个要点:

  1. -attach 每个字体一次,顺序对应后面的 s:t:0、s:t:1;
  2. mimetype 必须写对,否则播放器不认:
字体类型 mimetype
TrueType (.ttf) application/x-truetype-font 或 font/ttf
OpenType (.otf) font/otf 或 application/vnd.ms-opentype
WOFF font/woff

我一般用 application/x-truetype-font(对 ttf)和 font/otf(对 otf),实测这两个兼容性最好。

  1. -c:v copy -c:a copy -c:s copy:字幕内挂不需要重编码,很快;
  2. MP4 不支持字体附件(可以用 tx3g 但那是另一套东西,不支持 ASS)。所以要内挂字体就必须用 MKV。

检查附件有没有进去:

ffmpeg -i output.mkv 2>&1 | grep -A5 'Stream #.*: Attachment'
# 或者
mkvmerge -J output.mkv | python3 -c "import json,sys; d=json.load(sys.stdin); print([a['file_name'] for a in d.get('attachments',[])])"

局限性要说清楚:

  • MP4 不支持;
  • 手机播放器、网页播放器、智能电视基本都不加载附件字体;
  • 微信/抖音这类平台上传后必然重新转码,附件肯定丢。

所以内挂只适合"我知道对方用 PotPlayer/VLC 在电脑上看"的场景。拿不准就烧录。

五、字体子集化:18MB → 90KB

中文字体为什么大?因为汉字多。一个完整的中文字库(思源黑体 Source Han Sans SC)大概 16~18MB,一套完整的字重家族能上百 MB。

但你的字幕里可能只用了 300 个字。子集化(subsetting)就是只保留实际用到的字形,其余全部丢掉。

工具:fonttools(Python 库,pip install fonttools,里面有个 pyftsubset 命令)。

第一步:从 ASS 里提取用到的字符

import re

TAG = re.compile(r'\{[^}]*\}')          # 特效标签
OVERRIDE = re.compile(r'\\[a-zA-Z]+[^\\}\s]*')   # 行内样式覆盖

def extract_chars(ass_path: str) -> set:
    chars = set()
    with open(ass_path, encoding='utf-8-sig') as f:
        for line in f:
            # 只处理 Dialogue 行
            if not line.startswith('Dialogue:'):
                continue
            text = line.split(',', 9)[-1]        # 前 9 个字段之后是文本
            text = TAG.sub('', text)             # 去掉 {特效}
            text = OVERRIDE.sub('', text)        # 去掉 \pos 之类
            text = text.replace('\\N', '\n').replace('\\n', '\n')
            chars.update(text)
    # 补上常见标点和数字,防止后续微调字幕时缺字
    chars.update(',。!?、;:""''()《》…—0123456789')
    return chars


if __name__ == '__main__':
    chars = extract_chars('subtitle.ass')
    with open('chars.txt', 'w', encoding='utf-8') as f:
        f.write(''.join(sorted(chars)))
    print(f'{len(chars)} unique chars')

line.split(',', 9)[-1] 这个写法要注意:ASS 的 Dialogue 行格式是 Layer,Start,End,Style,Name,MarginL,MarginR,MarginV,Effect,Text——前 9 个字段用逗号分隔,第 10 个(Text)里可能也含逗号,所以要用 maxsplit=9。

第二步:子集化

pyftsubset SourceHanSansSC-Regular.otf \
  --text-file=chars.txt \
  --output-file=SourceHanSansSC-subset.otf \
  --layout-features='' \
  --no-hinting \
  --desubroutinize \
  --drop-tables+=DSIG

参数说明:

参数 作用
--text-file 要保留的字符清单(也可以用 --text="直接写字符")
--layout-features='' 丢掉 OpenType 排版特性(竖排、连字等),省空间
--no-hinting 丢掉 hinting 指令(低分辨率屏幕优化),省很多
--desubroutinize 对 CFF 字体(.otf)进一步压缩
--drop-tables+=DSIG 丢掉数字签名表

实测(思源黑体 SC Regular,18.2MB):

字符数 子集后大小 压缩率
100 字 32 KB 0.18%
500 字 87 KB 0.48%
2000 字 310 KB 1.7%
8000 字(常用汉字全集) 1.2 MB 6.6%

我一般会多留一些字(加常用字表 3500 字),一是防止后续改字幕要重新做,二是大小反正也就几百 KB,塞进 MKV 完全没压力。

第三步:替换 ASS 里的字体名

子集化后的字体,内部名称可能变了(或者你改了文件名)。ASS 里要对应改:

import re

def retarget_font(ass_path, old_name, new_name, out_path):
    with open(ass_path, encoding='utf-8-sig') as f:
        content = f.read()
    # 替换样式定义里的 Fontname 字段(Format 里的第 2 列)
    content = content.replace(f',{old_name},', f',{new_name},')
    with open(out_path, 'w', encoding='utf-8') as f:
        f.write(content)

如果字体内部名称和文件名不一致,可以用 fonttools 改:

from fontTools.ttLib import TTFont

font = TTFont('subset.otf')
for rec in font['name'].names:
    if rec.nameID in (1, 4, 6):        # 1=Family, 4=Full, 6=PostScript
        rec.string = 'MySubsetFont'
font.save('subset_renamed.otf')

我习惯把子集字体统一改名成一个明确的名字(比如 SubFont-Regular),这样 ASS 里引用的时候不会被系统里已装的同名字体"抢走"。

六、烧录字幕:最可靠但也最粗暴

烧录(burn-in / hardsub)就是把字幕画进视频帧里,从此它就是画面的一部分。

ffmpeg -i input.mp4 -vf "subtitles=subtitle.ass" \
  -c:v libx264 -crf 20 -preset slow -c:a copy output.mp4

如果要指定字体目录(服务器端通常要):

ffmpeg -i input.mp4 \
  -vf "subtitles=subtitle.ass:fontsdir=/usr/share/myfonts" \
  -c:v libx264 -crf 20 -c:a copy output.mp4

Windows 上路径要转义冒号(盘符那个冒号):

ffmpeg -i input.mp4 -vf "subtitles=sub.ass:fontsdir='C\:/SubtitleFonts'" out.mp4

或者用相对路径、把字体放到当前目录,能省不少麻烦。

依赖:ffmpeg 必须有 libass

ffmpeg -version 2>&1 | grep -o 'enable-libass'

没有的话要自己编(编译静态 ffmpeg 那篇讲过流程)。libass 依赖 freetype、fontconfig、fribidi、harfbuzz——这些是字幕渲染的完整链路,缺一个中文就会出问题。

烧录的几个实用技巧

1. 只烧录不重编码音频 → -c:a copy 省时间。

2. 保持画质:烧录必然要重编码视频。用 CRF 20 左右(比平时低一点,因为文字边缘对压缩敏感)。文字是最容易被压缩糊掉的内容,CRF 太高会出现"字迹边缘发虚"。

3. 高分辨率下字幕太小:ASS 的字号是基于 PlayRes 的,如果视频实际分辨率跟 PlayRes 不一致,字幕会被缩放。处理办法是保持两者一致,或者用 scale 先把视频缩到 PlayRes 对应的分辨率。

4. 用 subtitles 滤镜而不是 ass 滤镜:后者是老的、功能不全的实现,早就该弃用了。

5. 想保留原画质又必须烧录?做不到。烧录必然重编码,这是原理决定的。能做的是把 CRF 调低、用更慢的 preset。

七、Linux 服务器上的中文字幕环境

我们有一批任务在服务器上自动烧录字幕,第一次跑出来的视频字幕全是空白。排查过程:

# 1. 看系统有没有中文字体
fc-list :lang=zh
# 输出为空 → 一个中文字体都没有

# 2. 看 ffmpeg 报什么
ffmpeg -v info -i in.mp4 -vf subtitles=sub.ass -f null - 2>&1 | grep -i font
# [Parsed_subtitles_0 @ 0x...] fontselect: (Source Han Sans SC, 400, 0) -> /usr/share/fonts/... (没找到)
# Glyph 0x4E2D (中) not found in selected font

解决(以 Ubuntu 为例):

# 装一个开源中文字体(思源黑体 / Noto Sans CJK)
apt-get install -y fonts-noto-cjk

# 或者手动放字体
mkdir -p /usr/share/fonts/mine
cp SourceHanSansSC-Regular.otf /usr/share/fonts/mine/
chmod 644 /usr/share/fonts/mine/*.otf

# 刷新字体缓存(必须!)
fc-cache -fv

# 验证
fc-list :lang=zh | head
fc-match "Source Han Sans SC"

fc-cache -fv 这一步最容易忘。放了字体文件不刷新缓存,fontconfig 根本不知道它的存在。

如果不想污染系统目录(比如没有 root),可以放到用户目录:

mkdir -p ~/.fonts
cp *.otf ~/.fonts/
fc-cache -fv

# 或者用 fontconfig 配置文件指定目录
cat > ~/.config/fontconfig/fonts.conf <<'EOF'
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
  <dir>/opt/myfonts</dir>
</fontconfig>
EOF
fc-cache -fv

Docker 环境里尤其要注意:大部分基础镜像(alpine、slim 版)不带任何字体。我在 Dockerfile 里会显式写:

RUN apt-get update && apt-get install -y --no-install-recommends \
        fonts-noto-cjk fontconfig \
    && rm -rf /var/lib/apt/lists/*
RUN fc-cache -fv

另外一个坑:字体名匹配。ASS 里写的是 Source Han Sans SC,但装的是 Noto Sans CJK(fonts-noto-cjk 包的名字),两者其实是同一套字体的不同叫法,fontconfig 一般能匹配上(通过 alias),但不保证。稳妥做法是在 ASS 里指定一个你确定存在的字体名,或者干脆用子集化后的自定义字体名 + fontsdir 指向它。

八、PlayResX/Y:位置错乱的元凶

ASS 里的所有坐标(\pos、MarginV、MarginL)都是基于 PlayResX/PlayResY 这个虚拟画布的。

假设 ASS 的 PlayResX: 1920, PlayResY: 1080,字幕用 \pos(960,1000) 定位在画面底部。

情况 A:视频就是 1920×1080 → 完美。

情况 B:视频是 1280×720(同样是 16:9)→ 播放时会按比例缩放,位置仍然正确。

情况 C:视频是 1080×1920(竖屏 9:16)→ 播放器把 1920×1080 的画布拉伸/适配到竖屏,字幕位置完全错乱,可能跑到画面外。

情况 D:播放器忽略 PlayRes,直接按视频分辨率解释坐标 → 字幕位置偏移。

所以规则是:ASS 的 PlayRes 必须跟目标视频的分辨率匹配。

改的办法(改 ASS 文件头):

[Script Info]
PlayResX: 1280
PlayResY: 720

但光改 PlayRes 不够——字号、边距、坐标都是按原分辨率算的,改了 PlayRes 之后它们不会自动缩放。真正的做法是整体缩放字幕,可以用 ffmpeg 配合:

# 先把视频缩放到字幕的设计分辨率,烧录,再缩回去(两步缩放会损失画质,不推荐)

或者用专门的工具(Aegisub 的 "Resample resolution" 功能)一次性把所有坐标按比例换算。我一般是在生成字幕的时候就确定目标分辨率,从源头避免这个问题。

判断现有 ASS 和视频是否匹配:

# ASS 的分辨率
grep -E '^PlayRes' subtitle.ass

# 视频的分辨率
ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=p=0 input.mp4

我把这个检查加进了字幕处理脚本的第一步,不匹配就直接报错让人工处理,比事后发现位置不对返工强。

九、编码:BOM、GBK 与乱码

ASS 文件的编码问题很常见,尤其是从 Windows 上生成的字幕。

规则:ASS 必须是 UTF-8。带不带 BOM(U+FEFF)都行,但推荐带 BOM,因为很多 Windows 工具(包括某些版本的 Aegisub、VLC)靠 BOM 判断编码。

Python 里读 ASS 一定要用 utf-8-sig:

with open('subtitle.ass', encoding='utf-8-sig') as f:   # 自动去掉 BOM
    ...

用 utf-8 读带 BOM 的文件,第一行会多出 \ufeff,导致 [Script Info] 解析失败。这个 bug 让我排查过半小时——现象是"字幕明明有内容但就是解析不出来"。

遇到 GBK 编码的 ASS,ffmpeg 可以指定输入编码:

ffmpeg -sub_charenc GBK -i input.mp4 -vf "subtitles=sub_gbk.ass" out.mp4

但更稳妥的是先转成 UTF-8 存一份,后续全链路统一:

import chardet

def to_utf8(src, dst):
    raw = open(src, 'rb').read()
    detected = chardet.detect(raw)
    enc = detected['encoding'] or 'utf-8'
    text = raw.decode(enc, errors='replace')
    with open(dst, 'w', encoding='utf-8-sig') as f:
        f.write(text)
    print(f'{src}: {enc} -> utf-8-sig (confidence {detected["confidence"]:.2f})')

chardet 的检测不是 100% 准(短文本的 GBK 和 UTF-8 容易混),所以它给了 confidence。低于 0.8 的我都会人工看一眼。

十、一套完整的字幕流水线

把我现在的流程串起来(从拿到字幕到产出交付文件):

#!/bin/bash
# build_subtitle.sh input.mp4 subtitle.srt output_dir
set -euo pipefail

IN="$1"
SUB="$2"
OUTDIR="$3"
mkdir -p "$OUTDIR"

# 1. 检查并转编码
python3 to_utf8.py "$SUB" "$OUTDIR/sub.utf8.ass"

# 2. 检查分辨率匹配
python3 check_resolution.py "$IN" "$OUTDIR/sub.utf8.ass"

# 3. 提取字符 + 子集化字体
python3 extract_chars.py "$OUTDIR/sub.utf8.ass" > "$OUTDIR/chars.txt"
pyftsubset /usr/share/fonts/SourceHanSansSC-Regular.otf \
  --text-file="$OUTDIR/chars.txt" \
  --output-file="$OUTDIR/SubFont.otf" \
  --layout-features='' --no-hinting --desubroutinize

# 4. 改 ASS 里的字体名
python3 retarget_font.py "$OUTDIR/sub.utf8.ass" "Source Han Sans SC" "SubFont" "$OUTDIR/sub.final.ass"

# 5a. 产出烧录版(交付用)
ffmpeg -y -i "$IN" \
  -vf "subtitles=$OUTDIR/sub.final.ass:fontsdir=$OUTDIR" \
  -c:v libx264 -crf 20 -preset slow -c:a copy \
  -movflags +faststart "$OUTDIR/hardsub.mp4"

# 5b. 产出内挂版(存档用,字体已子集化)
ffmpeg -y -i "$IN" -i "$OUTDIR/sub.final.ass" \
  -attach "$OUTDIR/SubFont.otf" \
  -map 0:v -map 0:a -map 1:s \
  -c copy \
  -metadata:s:s:0 language=chi \
  -metadata:s:t:0 mimetype=font/otf \
  "$OUTDIR/softsub.mkv"

echo "done: $OUTDIR/hardsub.mp4 (交付) / $OUTDIR/softsub.mkv (存档)"

这套流程跑一次大概几分钟(主要是烧录的重编码),出来的两个文件分别对应"给别人看"和"自己留着"。

两个版本都留是个好习惯。有次客户说"能不能把字幕去掉重新出一版",我从 mkv 里一秒就提取出来了,不用去找原始字幕重新做。

十一、坑清单与字体授权

坑清单

  1. ASS 只存字体名 → 换台机器就回退成宋体。烧录或内挂字体。
  2. MP4 不支持字体附件 → 想内挂字体只能用 MKV。
  3. 附件没设 mimetype → 播放器不加载,等于没挂。
  4. 中文字体 18MB 直接塞 → 文件体积爆炸。做子集化。
  5. 子集化字符提取不全(没去掉特效标签里的字符 / 忘了标点)→ 少数字变成方框。
  6. 服务器没装中文字体 → 烧录出来字幕空白。装字体 + fc-cache -fv。
  7. Docker 镜像没字体 → 同上,Dockerfile 里要显式装。
  8. PlayRes 和视频分辨率不匹配 → 字幕位置错乱,尤其竖屏视频。
  9. ASS 是 GBK 编码 → ffmpeg 解析乱码或失败。先转 UTF-8。
  10. 用 utf-8 读带 BOM 的文件 → 首行多出 \ufeff。用 utf-8-sig。
  11. 颜色写成 RGB → ASS 是 BGR,&H0000FF& 是红色。
  12. 烧录用 CRF 太高 → 文字边缘糊掉。用 20 或更低。
  13. 用了老的 ass 滤镜 → 功能不全。用 subtitles。
  14. Windows 路径冒号没转义 → fontsdir='C\:/fonts'。
  15. 只做了烧录版 → 客户要无字幕版时得重做。两个版本都留。

字体授权(这一段请认真看)

字体是受版权保护的软件,不是"下载下来就能用"。踩过这个坑的不止我一个人:

  • 方正字体:商业使用需要授权,未经授权用于商业物料(包括视频)被起诉的案例不少;
  • 微软雅黑:它是微软授权给 Windows 用户的系统字体,把雅黑字体文件打包进你的作品分发是侵权的(用在 Windows 上做图不算,但把字体文件本身发出去就算);
  • 思源黑体 / Noto Sans CJK:Adobe 和 Google 联合发布,SIL Open Font License(OFL),可以免费商用、可以嵌入、可以修改(但改名字后不能还叫原名,且 OFL 要求保留版权声明);
  • 站酷系列字体:多数免费商用,但每个字体的授权条款不同,要逐个确认;
  • 阿里巴巴普惠体、OPPO Sans、MiSans:官方声明可免费商用。

我的处理原则:

  1. 默认只用明确可商用的字体(思源/Noto、阿里普惠体、OPPO Sans、站酷免费商用的那几款);
  2. 子集化后的字体仍然受原授权约束——压缩不改变授权;
  3. 交付文档里写明用了哪些字体及授权来源,让客户自己也能查;
  4. 客户指定要用某个字体时,要求对方提供授权证明,或者让他们自己提供字体文件。

技术上"能做到"和"可以做"是两回事。字体这事出问题的代价远大于多问一句的成本。


回到开头那个"字幕变成宋体"的工单。最后我的处理是:重做了一版烧录的,同时给了一份内挂子集化字体的 MKV 存档,并在交付说明里写了"字体:思源黑体 SC(OFL 授权),已子集化"。

客户那边再没反馈过问题。而我自己学到的最重要的一条是:凡是"依赖对方环境"的东西,都要么自带,要么消除。字体如此,播放器如此,编解码器也如此。这个思路后来也用在了别的地方——比如交付 ffmpeg 二进制时要静态链接,道理是一模一样的。

想亲手试试?用 VidDown 一键解析下载

粘贴视频链接即可解析,多平台支持、网页端即用;下载桌面客户端解锁海外平台本地解析,开通会员更享不限次下载。

顶部