ChordPro Windows 中文 PDF 字体乱码修复报告
Q7nl1s admin

ChordPro Windows 中文 PDF 字体乱码修复报告

1. 问题摘要

在 Windows 平台上使用 ChordPro 生成包含中文字符的 PDF 时,会出现字体乱码(无法显示中文)的问题。控制台会提示 Unknown font propertyFont text has no size 等错误。

2. 根本原因

  • 字体获取机制缺失: ChordPro 的 Text::Layout 模块在 Windows 上没有实现自动获取系统字体的逻辑(仅支持 Linux 的 fc-match)。
  • 文件格式不支持: Windows 默认的中文字体(如微软雅黑 Microsoft YaHei)通常是 .ttc (TrueType Collection) 格式,而原代码只支持 .ttf.otf
  • 路径解析问题: 原代码不支持带有盘符(如 C:/)的绝对路径。
  • 配置问题: 默认配置未针对中文环境设置合适的字体,且字体名称解析器对带空格的字体名支持不佳。

3. 修复方案

我们修改了 lib/Text/Layout/FontConfig.pmlib/ChordPro/Config.pm 两个文件。

3.1 修改 lib/Text/Layout/FontConfig.pm

此文件负责字体的发现和注册。我们添加了 Windows 注册表查询功能,并修复了对 TTC 格式和空格文件名的支持。

修改 1: 在 _fallback 中添加 Windows 支持

定位到 sub _fallback,添加 _fallback_win32 调用:

1
2
3
4
5
6
7
8
9
sub _fallback {
unless ( defined $fallback ) {
$fallback = '';
if ( $^O =~ /MSWin32/ ) {
$fallback = \&_fallback_win32; # 添加此行
}
else {
foreach ( split( /:/, $ENV{PATH} ) ) {
# ...

修改 2: 实现 _fallback_win32 函数

在文件末尾添加以下函数,通过 reg query 获取 Windows 安装的字体:

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
sub _fallback_win32 {
my ( $family, $style, $weight ) = @_;
state $fonts;
unless ( $fonts ) {
$fonts = {};
my $cmd = 'reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts"';
if ( open( my $fh, '-|', $cmd ) ) {
while ( <$fh> ) {
chomp;
if ( /^\s*(.*?)\s+REG_SZ\s+(.*)$/ ) {
my ( $n, $f ) = ( $1, $2 );
$n =~ s/\s+\(TrueType\)$//;
$f =~ s/^\s+//; $f =~ s/\s+$//;
$fonts->{lc($n)} = $f;
}
}
close($fh);
}
warn "Loaded " . scalar(keys %$fonts) . " fonts from Registry via reg.exe.\n";
}
my $f = $fonts->{lc($family)};
unless ( $f ) {
my $target = lc($family);
$target =~ s/^"//; $target =~ s/"$//;
foreach my $k ( keys %$fonts ) {
if ( index($k, $target) == 0 ) {
$f = $fonts->{$k};
last;
}
}
}
return unless $f;
return $f if $f =~ /^[A-Z]:/i; # Absolute
return $ENV{SystemRoot} . "/Fonts/" . $f;
}

修改 3: 支持 .ttc 和 Windows 路径

sub register_font 中:

1
2
3
4
   if ( $font =~ /\.(?:[ot]tf|ttc)$/i ) { # 修改正则支持 .ttc
if ( $font =~ m;^(?:/|[A-Z]:);i ) { # 修改正则支持 C: 盘符
$ff = $font if -r -s $font;
}

修改 4: 大小写不敏感的字体查找

sub find_font 中:

1
2
3
4
5
   my $try = sub {
my $fam = lc($family); # 强制转换为小写查找
if ( $fonts{$fam}
&& $fonts{$fam}->{$style}
&& $fonts{$fam}->{$style}->{$weight} ) {

修改 5: 屏蔽解析警告

sub parse 中,注释掉 carp

1
2
3
4
else {
# carp("Unknown font property: $t"); # 注释掉以支持带空格的字体名
$family .= " " . $_;
}

3.2 修改 lib/ChordPro/Config.pm

此文件负责加载配置。我们添加了自动检测中文环境并切换字体的逻辑。

修改 configurator 函数

if ( $^O =~ /MSWin32/ ) 代码块中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
   if ( $^O =~ /MSWin32/ ) {
eval {
my $acp = Win32::GetACP();
if ( $acp == 936 || $acp == 950 ) { # Chinese Simpl/Trad
for my $tag ( qw( text chord title subtitle footer toc grid tab comment comment_box comment_italic chordfingers diagram diagram_base) ) {
my $current = $cfg->{pdf}->{fonts}->{$tag};
my $size = 10; # fallback
if ( $current && $current =~ /\b(\d+(?:\.\d+)?)\b/ ) {
$size = $1;
}
$cfg->{pdf}->{fonts}->{$tag} = {
description => "Microsoft YaHei $size",
size => $size, # 显式设置 size,修复 PDF 模块报错
color => "foreground",
background => "background"
};
}
push( @{ $cfg->{pdf}->{fontdir} }, "C:/Windows/Fonts" );
}
};
}

4. 验证

image-20260117181330561

修复后,ChordPro 能够:

  1. 正确检测中文 Windows 环境 (Code Page 936/950)。
  2. 自动从注册表找到并加载 Microsoft YaHei (微软雅黑, msyh.ttc)。
  3. 生成完美显示的中文 PDF,无乱码,无报错。
 Comments
Comment plugin failed to load
Loading comment plugin