-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathscale_font.py
175 lines (147 loc) · 5.42 KB
/
scale_font.py
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
import os
import time
from fontTools.ttLib import TTFont
from fontTools.pens.ttGlyphPen import TTGlyphPen
from fontTools.pens.transformPen import TransformPen
from fontTools.misc.transform import Identity
import multiprocessing as mp
from multiprocessing.managers import SyncManager
from functools import partial
def print_progress(current, total, width=50):
progress = current / total
filled = int(width * progress)
bar = f"\r处理进度: [{'=' * filled}{'>' if filled < width else ''}{' ' * (width - filled)}] "
bar += f"{current}/{total} ({progress:.1%})"
print(bar, end='', flush=True)
if current == total:
print()
def list_ttf_files(directory):
"""Return TTF files sorted by modification time (newest first)"""
# Get files with timestamps
ttf_files = []
for f in os.listdir(directory):
if f.lower().endswith('.ttf'):
path = os.path.join(directory, f)
mtime = os.path.getmtime(path)
ttf_files.append((mtime, f))
# Sort by timestamp descending
ttf_files.sort(reverse=True)
# Return only filenames
return [f for _, f in ttf_files]
def fix_gvar_table(font):
if "gvar" not in font:
return
broken = []
for glyph_name in list(font["gvar"].variations.keys()):
try:
_ = font["gvar"].variations[glyph_name]
except AssertionError:
broken.append(glyph_name)
for glyph_name in broken:
del font["gvar"].variations[glyph_name]
def process_glyph_chunk(chunk_data):
chunk, scale, glyf_table = chunk_data
results = {}
# show start of chunk work with thread id
print(f"开始处理字形块, {len(chunk)}个字形,线程ID: {mp.current_process().name}")
for glyph_name, glyph in chunk:
if glyph.isComposite():
continue
pen = TTGlyphPen(None)
transform = Identity.scale(scale)
transform_pen = TransformPen(pen, transform)
# Pass glyf_table to draw()
glyph.draw(transform_pen, glyf_table)
results[glyph_name] = pen.glyph()
return results
def adjust_weight(font, scale):
# Start timing for gvar fix
fix_start = time.time()
print("开始修复 gvar...")
fix_gvar_table(font)
fix_time = time.time() - fix_start
print(f"修复 gvar 耗时: {fix_time:.2f}s")
# Start timing for scaling
scale_start = time.time()
print("\n开始缩放处理...")
glyf_table = font['glyf']
glyphs = [(name, glyf_table[name]) for name in font.getGlyphOrder()]
total_glyphs = len(glyphs)
# Split work into chunks
cpu_count = mp.cpu_count()
chunk_size = max(1, total_glyphs // cpu_count)
chunks = [glyphs[i:i + chunk_size] for i in range(0, len(glyphs), chunk_size)]
chunks_with_data = [(chunk, scale, glyf_table) for chunk in chunks]
# Process in parallel
with mp.Pool(cpu_count) as pool:
results = pool.map(process_glyph_chunk, chunks_with_data)
# Merge results
processed = 0
for chunk_result in results:
for glyph_name, new_glyph in chunk_result.items():
glyf_table[glyph_name] = new_glyph
processed += 1
# Show progress every 10 glyphs
if processed % 1000 == 0 or processed == total_glyphs:
print_progress(processed, total_glyphs)
scale_time = time.time() - scale_start
print(f"\n缩放完成,耗时: {scale_time:.2f}s")
return fix_time, scale_time
def main():
overall_start = time.time()
current_directory = os.getcwd()
ttf_files = list_ttf_files(current_directory)
if not ttf_files:
print("当前目录未找到TTF。")
return
print("可用TTF:")
for i, f in enumerate(ttf_files, start=1):
print(f"{i}: {f}")
print("\n0: 退出")
print("\n读取输入中...")
step_start = time.time()
try:
choice = int(input("请输入TTF编号: "))
if choice == 0:
print("已退出。")
return
elif not 1 <= choice <= len(ttf_files):
print("选择无效。")
return
except ValueError:
print("输入无效。")
return
try:
scale_input = input("请输入缩放比例(如1.2或80%):")
if scale_input.endswith('%'):
scale = float(scale_input[:-1]) / 100
else:
scale = float(scale_input)
if scale <= 0:
print("缩放比例必须>0。")
return
except ValueError:
print("输入无效。")
return
input_time = time.time() - step_start
print(f"输入处理耗时: {input_time:.2f}s\n")
selected_file = ttf_files[choice-1]
print(f"加载字体中... ({selected_file})")
step_start = time.time()
font = TTFont(selected_file)
load_time = time.time() - step_start
print(f"字体加载耗时: {load_time:.2f}s\n")
fix_time, scale_time = adjust_weight(font, scale)
print("保存字体中...")
step_start = time.time()
scale_percentage = f"{int(scale * 100)}%"
new_file_name = f"{scale_percentage}_{os.path.basename(selected_file)}"
font.save(new_file_name)
save_time = time.time() - step_start
print(f"保存字体耗时: {save_time:.2f}s\n")
overall = time.time() - overall_start
print("全部步骤完成。")
print(f"总耗时: {overall:.2f}s")
print(f"已保存: {new_file_name}")
if __name__ == "__main__":
main()