3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Pythonでフォントを編集する

Posted at

はじめに

PythonでM+FONTSをベースにM+A1というフォントを作成しました。
(https://microraptor.booth.pm/items/2347968)
備忘録と布教の意味を込めて、プログラムでフォントを読み込み、書き出す手順を説明していきます。

  • 筆者の環境
  • anaconda + Python3
  • 標準以外のライブラリ
  • defcon
  • ufo2ft
  • 元となるフォント
  • OpenType形式で改変が許可されているフォント
  • TrueTypeでも専用のソフトでOpenTypeに変換すればOKです

やりたいこと

いきなりOTF(OpenType)を読み込むことはできないので、UFO(Unified Font Object)形式に書き出してから、そのファイルを読み込んでOTFを作ります。

UFOって何? となるでしょうが、難しいことはありません。単なるxmlファイルです。
フォントデータを構成しているベジェ曲線の制御点がxmlとして書き出されます。

OTF -> UFO

defconでFontオブジェクトを生成し、extractUFOでOTF->UFOへ書き出します。


import defcon
import extractor

IMPORT_FILE = r'C:\example\abc.otf'
EXPORT_FILE = r'C:\example\abc_ufo'
font = defcon.Font()
extractor.extractUFO(IMPORT_FILE, font)
font.save(EXPORT_FILE)

欧文なら数秒、日本語書体なら数分でエクスポートが行われます。

出力結果

  • glyph
  • 文字ごとのパス情報がXML形式で書かれています。(形式は.gilf)
  • contents.plist
  • 収録している文字のパスファイル(.gilf)のリスト
  • fontinfo.plist
  • フォント全体の情報(フォント名、アセンダ・ディセンダ等数値、などなど)
  • kerning.plist
  • カーニング情報
  • layercontents.plist
  • よくわからん
  • lib.plist
  • 収録している文字のパスファイル(.gilf)のリスト
  • metainfo.plist
  • フォーマット、作者等

lib.plistとcontents.plistは似ているファイルなので、どちらを見ても参照してもよいです
(lib.plistはフォント名とフォントファイルの紐付けがないが、各.gilf内にもフォント名が書かれている。contents.plistは大量の.gilf内に存在するので探すのが手間。たいていはどちらでも構わないと思われる。)

UFO -> OTF

import os
import defcon
import ufo2ft
from xml.etree import ElementTree as ET

# Const
UFO_FILE = r'C:\example\abc_ufo'
GLIF_PATH = os.path.join(UFO_FILE, 'glyphs')

font = defcon.Font()

# 編集する文字を選択
glif_root = ET.parse(os.path.join(GLIF_PATH, 'a.glif'))
glyph = font.newGlyph('a')
glyph.unicode = int(glif_root.find('.//unicode').attrib['hex'], 16)
contour_list = glif_root.findall('.//contour')

# glifファイルから<contour>配下の<point>タグを順次読み込み
for tag_contour in contour_list:
    contour = defcon.Contour()
    point_list = tag_contour.findall('./point')

    for k, v in enumerate(point_list):
        # <point>にtypeが定義されていないならNone
        _type = v.attrib['type'] if 'type' in v.attrib else None
        # ポイントを設定
        contour.appendPoint(
            defcon.Point(
                (int(v.attrib['x']), int(v.attrib['y'])),
                segmentType=_type,
            )
        )
    # 1周分の輪郭を設定
    glyph.appendContour(contour)

# OTFに書き出し
otf = ufo2ft.compileOTF(font)
otf.save('new_font.otf')

これで、"a"のみが設定されたフォントファイルが出力されました。
パスを操作してから書き込めば、オリジナルのフォントが作れます。

リファレンス・参考資料

UFO公式 : https://unifiedfontobject.org/
DEFCON : https://defcon.robotools.dev/en/latest/
https://qiita.com/irori/items/5518c242e0244838783b
https://blog.hgrs.me/20190806022544
https://irori.github.io/wapuro-mincho/

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?