複数のTTF(TrueTypeFont)が格納されているTTCファイルから単一のTTFに分割するスクリプトです。
元は https://github.com/yhchen/ttc2ttf となります。
使用方法は、
$ python ttc_split.py [TTF Filename]
ttc_split.py
import sys import argparse import struct import pathlib # original: https://github.com/yhchen/ttc2ttf def iter_ttf(buf: bytes, tpl_ttf_offset: tuple[int]): def bit_ceil(v: int, align: int) -> int: return (v + (align - 1)) & ~(align - 1) for i, table_header_offset in enumerate(tpl_ttf_offset): print("Extract TTF #{:d}".format(i + 1)) print("\tOffset {:d}".format(table_header_offset)) tpl_table_count = struct.unpack_from( "!H", buf, table_header_offset + 0x04, ) header_length = 0x0C + tpl_table_count[0] * 0x10 print("\tHeaderlänge: %s Byte" % header_length) table_length = 0 for j in range(tpl_table_count[0]): length = struct.unpack_from( "!L", buf, table_header_offset + 0x0C + 0x0C + j * 0x10 )[0] table_length += bit_ceil(length, 4) total_length = header_length + table_length new_buf = bytearray(total_length) header = struct.unpack_from( header_length * "c", buf, table_header_offset, ) struct.pack_into(header_length * "c", new_buf, 0, *header) current_offset = header_length for j in range(tpl_table_count[0]): offset = struct.unpack_from( "!L", buf, table_header_offset + 0x0C + 0x08 + j * 0x10 )[0] length = struct.unpack_from( "!L", buf, table_header_offset + 0x0C + 0x0C + j * 0x10 )[0] struct.pack_into( "!L", new_buf, 0x0C + 0x08 + j * 0x10, current_offset, ) current_table = struct.unpack_from(length * "c", buf, offset) struct.pack_into( length * "c", new_buf, current_offset, *current_table, ) current_offset += bit_ceil(length, 4) yield i, new_buf def split_ttc(ttc_file: pathlib.Path, buf: bytes): tpl_ttf_count = struct.unpack_from("!L", buf, 0x08) print("TrueType count = {:d}".format(tpl_ttf_count[0])) tpl_ttf_offset = struct.unpack_from( "!" + tpl_ttf_count[0] * "L", buf, 0x0C, ) for i, ttfdata in iter_ttf(buf, tpl_ttf_offset): ttf_path = pathlib.Path("{:s}_{:02d}.ttf".format(ttc_file.stem, i)) with ttf_path.open("wb") as wf: wf.write(ttfdata) print("\tSaved {:s} {:d} Bytes".format(ttf_path.name, len(ttfdata))) print() def main(): parser = argparse.ArgumentParser() parser.add_argument("ttc_filename") args = parser.parse_args() ttc_file = pathlib.Path(args.ttc_filename) if ttc_file.exists() is False: return -1 if ttc_file.suffix.lower() != ".ttc": return -1 with ttc_file.open("rb") as rf: buf = rf.read() rf.close() if buf[:4] != b"ttcf": return -1 split_ttc(ttc_file, buf) return 0 if __name__ == "__main__": sys.exit(main())