LoginSignup
18
12

More than 5 years have passed since last update.

TTFの全グリフをPNGにしてみる

Last updated at Posted at 2018-12-24

以前、別記事にてアスキーアート関連の論文をまとめました
アスキーアート関連の論文を探してみた

その中で「アスキーアート分類手法の比較検討」にて「文字単位で画像特徴量(HOG)を抽出し...」というのをやってみたくて色々模索した記事です。この記事ではttfファイルをpngで出力するところまでやります。最終的な目標は機械学習によるAAの分類です。

本記事で紹介する方法は以下の手順を踏んでttfをpngに変換します。

  1. fonttoolsを使ってttfファイルのグリフ一覧を読み込み
  2. SVGPathPenを使って全グリフをSVGに変換する
  3. cairosvgを使ってSVGをPNGに変換する
  4. PNGをリサイズして縮小する※必要ないかも...

興味ある方は以下、手順を記載するので読み進めてください。なお、1〜2の内容は以下のブログを参考にさせていただいています。めちゃくちゃ詳しく書いてあるのでfonttools知らない方は是非とも読んでみてください。
fontTools のペンを使ってグリフのアウトラインを取得する

※以下の手順はjupyter notebookを利用することを想定しています。

1. fonttoolsを使ってttfファイルのグリフ一覧を読み込み

まず、Pythonでttfファイルを扱うためにfonttoolsを使用します。インストール方法はpipから

pip install fonttools

fonttoolsでフォントを読み込んでグリフを取得するために以下の処理を行います。

from fontTools.ttLib import TTFont
font = TTFont('/Users/eskey/workspace/aahub/ml/Saitamaar.ttf')
glyph_set = font.getGlyphSet() 
cmap = font.getBestCmap() 

glyph_setがグリフオブジェクト、cmapがUnicodeとグリフの対応テーブルになります。

2. SVGPathPenを使って全グリフをSVGに変換する

グリフ情報の準備が済んだのでSVGに変換します。まずは、ファイル出力用にディレクトリを作成します。

import os
os.mkdir("output_svg")
os.mkdir("output_png")
os.mkdir("output_resize")

次に、全グリフをSVGに変換する関数を記述します。

from textwrap import dedent
from fontTools.pens.svgPathPen import SVGPathPen

# GlyphをSVGに変換
def save_all_glyph_as_svg(font):    
    glyph_set = font.getGlyphSet()
    cmap = font.getBestCmap()

    output_path = "output_svg/"
    for c in cmap:
        glyph_name = cmap[c]
        glyph = glyph_set[glyph_name]
        svg_path_pen = SVGPathPen(glyph_set)
        glyph.draw(svg_path_pen)

        ascender = font['OS/2'].sTypoAscender
        descender = font['OS/2'].sTypoDescender
        width = glyph.width
        height = ascender - descender

        content = dedent(f'''\
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 {-ascender} {width} {height}">
                <g transform="scale(1, -1)">
                    <path d="{svg_path_pen.getCommands()}"/>
                </g>
            </svg>
        ''')
        with open(output_path + str(c) + ".svg", 'w') as f:
            f.write(content) 

上記関数はcmapテーブルをループで回して全てのグリフをSVGとして保存する関数です。

save_all_glyph_as_svg(font)

実行するとoutput_svgフォルダにSVGが保存されます。
Screen Shot 2018-12-31 at 20.42.31.png

3. cairosvgを使ってSVGをPNGに変換する

全グリフをSVGで保存できたら次はPNGに変換します。cariosvgもpipでインストールできます。

pip install cairosvg

さて、cariosvgにはSVGをPNGに変換するsvg2pngという関数が用意されています。

svg2png(url="SVGのパス", write_to="出力先のパス")

先ほどのoutput_svgの全SVGをPNGに変換する関数を作成します。

from cairosvg import svg2png
import os


# SVGをPNGに変換する
def convert_all_svg_to_png():
    path = "output_svg"
    files = os.listdir(path)
    files_file = [f for f in files if os.path.isfile(os.path.join(path, f))]
    for fname in files_file:
        bname, ext =  os.path.splitext(fname)

        try:
            svg2png(url='output_svg/' + bname + '.svg', write_to='output_png/' + bname + '.png')
        except:
            print(fname)
    return 

上記処理ではtry〜 exceptでsvg2pngの例外処理を行っています。これはsvg2pngがゼロ幅スペースのユニコードで異常終了するからです。以下がsvg2pngで落ちると思われるコードになります。
uni200B
uniE9D7
uniE9D6
uniE9D5
uni035F
uni035D
uni035E
uni0009

では、関数を実行します。

convert_all_svg_to_png()

見事、SVGがPNGに変換されました。
Screen Shot 2018-12-31 at 20.42.40.png

  1. PNGをリサイズして縮小する 上記までの処理でttfをpngに変換する目的は達成していますが、この状態だと非常にサイズがでかいです。

状況に応じて画像をリサイズする必要があるかもしれませんので以下処理を書き残しておきます。以下の関数はoutput_pngフォルダの全画像ファイルのサイズを20/1のサイズに変更します。

import os
import glob
from PIL import Image


# PNGをリサイズする
path = "output_png"
files = os.listdir(path)
files_file = [f for f in files if os.path.isfile(os.path.join(path, f))]
for fname in files_file:
    bname, ext =  os.path.splitext(fname)
    if ext != ".png":
        continue
    img = Image.open("./output_png/" + bname + ext)
    img_resize = img.resize((int(img.width/20), int(img.height/20)))
    img_resize.save("./output_resize/" + bname + "_herf" + ext)

これで、20分の1のサイズで文字ファイルを全部画像にすることができました。このあと、HOGを抽出してクラスタリングしたり、AAからうまいことHOGで表せるようにしたいと思います。
それでは。

18
12
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
18
12