[スクラッチ上級者講座] 任意のフォントファイル(ttf)から個別のsvg画像に変換してコスチュームとして使う方法


2020/11/19

スクラッチアプリを作っていて文字フォントをスプライトで自由に操作できたらなぁ、と思う場面が結構あると思います。

残念ながら現状のスクラッチで自由にフォント文字使う機能は用意されてありませんので、必要の際には自分で一から作成するしかありません。しかも、その機能を実現するためには色々な課題を考慮する必要もあります。

今回は試作的なテーマとして、一般的なttfファイルから初めてスクラッチプロジェクトに導入する方法を検討してみたいと思います。

はじめに

今回は個人利用OK・商用サイト利用OKの公開されているフォントで適当な物を教材的な目的でダウンロードして使わせていただきます。

手書きフォント「あんずもじ」, リンク先: http://www8.plala.or.jp/p_dolce

まず、公開されているフォントは扱いは良く利用規約を確認すべきです。今回使わせていただく無償フォントも、著作権の関係から再配布・販売・改造は禁止です。

今回も個人用のアプリやWEBサイトの利用に用途を限定するとして、ttfからsvgのようなWebフォント用にファイル変換までなら許可されているようです。

特にスクラッチのウェブページにアプリを上げる場合、ttfの創作物の改変・再配布とみなされないために、ウェブからフリーのフォントをダウンロードして使う際にはライセンス情報を十分に注意して使う必要があります。

弊社はスクラッチのサイトを回避して、独自のサーバーからスクラッチアプリを公開しているやり方をとっているため、ここら辺のややこしいライセンス衝突問題はクリアしております。詳しくは
Scratch-guiのデフォルトプロジェクトのアセット置き場を変える方法の記事をご参照ください。

ttf -> svgへ変換

オンラインの無料で使えるファイルコンバータを利用して、ttf形式のフォントをsvg(フォント)に変換します。例えば、今回は
Convertioで変換しました。

ttfをsvgに変換する場合、
SVGフォント形式に変換されます。まずはこれがどういうものかをさっとおさらいします。

SVGフォント?

SVG Fonts - MDN Doc

SVGでは、Webフォントを定義するための要素
<font>がサポートされています。

ただしFirefoxなどでは
woffなどの新しいフォントレンダリング技術の開発に集中する理由で、SVGフォントの実装は現在無期限停止になっている扱いをされている状況ですので、現在はあまり主流には使われていないWebフォント形式となっています。

判例を上げると、以下のようになります。

            <font id="Font1" horiz-adv-x="1000">
    <font-face font-family="Super Sans" font-weight="bold" font-style="normal"
        units-per-em="1000" cap-height="600" x-height="400"
        ascent="700" descent="300"
        alphabetic="0" mathematical="350" ideographic="400" hanging="500">
        <font-face-src>
            <font-face-name name="Super Sans Bold"/>
        </font-face-src>
    </font-face>
    <missing-glyph><path d="M0,0h200v200h-200z"/></missing-glyph>
    <glyph unicode="!" horiz-adv-x="300"><!-- !の外形を定義 --></glyph>
    <glyph unicode="@"><!-- @の外形を定義 --></glyph>
    <!-- 他のglyphsは略 -->
</font>
        
svgフォントは以下のような階層構造をもつ要素です。

            font:
    フォントの宣言をするコンテナ要素
font-face:
    フォントに関わる様々な設定情報を記述.
    フォント名称や太さ・基底線・描画グリッドなど
missing-glyph:
    対応していない文字に対する形状を定義
glyph:
    文字の形状とマッピングテーブルの定義
v-kern, h-kern:
    文字のカーニング情報を定義
        
より詳しいSVGフォントの説明はそちらのサイトをご参照ください。

ここでの結論では、スクラッチのコスチューム画像での登録は一つのコスチュームにつき、静的なsvg画像を一つ割り当てるようにしないと行けないので、スクラッチアプリでこのsvgフォントをそのまま直接使うことは出来ません。

ということで、このSVGフォントからさらに
glyph要素を抽出し、文字を一つ一つ個別のsvgファイルとして取り出す必要があります。

SVGフォントを分割・抽出するシェルスクリプト

たとえば先程のttfからsvgフォントに変換したファイルの中で重要なポイントだけ選り抜いて見てみると、

            <!-- 中略 -->
<font id="apricotJapanesefont" horiz-adv-x="1024" vert-adv-y="1024" >
  <font-face
    font-family="apricotJapanesefont"
    font-weight="400"
    font-stretch="normal"
    units-per-em="1024"
    panose-1="2 0 6 0 0 0 0 0 0 0"
    ascent="880"
    descent="-144"
    x-height="429"
    cap-height="678"
    bbox="-0.133333 -143.133 1023.13 878.8"
    underline-thickness="48"
    underline-position="-120"
    unicode-range="U+0020-FFEE"
  />
<!-- 中略 -->
<!-- 下は文字'3'の外形定義 -->
<glyph glyph-name="three" unicode="3" horiz-adv-x="512"
d="M213 70q-29 9 -52.5 28.5t-47.5 38.5q-5 8 -7 17.5t0 19.5l12 19q8 6 18 8t22 -1l21 -14l2 -6l10 -4l-1 -4q12 -6 22.5 -14.5t24.5 -9.5q15 4 26 11t18 18q11 20 13 44l4 48q-3 24 -12 45.5t-28 41.5q-14 6 -28.5 8.5t-26.5 13.5q-6 11 -8.5 20t0.5 19l12 20q20 6 41 15
t38 23q22 20 31.5 46t7.5 56l-13 22q-12 9 -27 11.5t-34 2.5q-17 -4 -30.5 -14t-32.5 -7l-20 11q-6 9 -7.5 18.5t0.5 19.5l11 19q28 23 61.5 29.5t73.5 -0.5q15 -5 29.5 -11t28.5 -17l14 -17q21 -27 22.5 -62t-3.5 -70q-8 -28 -24.5 -51t-33.5 -46l-15 -13l8 -6
q30 -45 37.5 -94t-0.5 -103q-5 -24 -14 -45t-23 -40l-21 -20q-22 -12 -46 -19.5t-53 -4.5z" />
<!-- ...以下略 -->
        
細かい要素ごとの属性の役割はここでは説明しませんが、こちらのサイトの解説が詳しいので気になったらそちらで確認してください。

まず
font-face要素のなかで着目すると、今回はbbox属性があります。この属性は全てのグリフ(文字)を欠けること無く描画可能な最小の矩形範囲だそうですので、個別に文字を描画する際のviewBoxに設定するのにちょうど良さそうです。

次に文字の形状定義を表す
glyph要素の中身は、グリフの名称・glyph-name、文字のユニコード・unicode、パス形状・dは文字を抽出するのに重要な情報を与えてくれます。

では以上の情報から、文字
3をsvg表示してみます。svgの描画を試す場合、軽量なオンラインSVG viewer/editorを利用してみます。

            <svg xmlns="http://www.w3.org/2000/svg" viewBox="-0.133333 -143.133 1023.13 878.8" width="102.3" height="87.9" version="1.1">
   <path d="M213 70q-29 9 -52.5 28.5t-47.5 38.5q-5 8 -7 17.5t0 19.5l12 19q8 6 18 8t22 -1l21 -14l2 -6l10 -4l-1 -4q12 -6 22.5 -14.5t24.5 -9.5q15 4 26 11t18 18q11 20 13 44l4 48q-3 24 -12 45.5t-28 41.5q-14 6 -28.5 8.5t-26.5 13.5q-6 11 -8.5 20t0.5 19l12 20q20 6 41 15
t38 23q22 20 31.5 46t7.5 56l-13 22q-12 9 -27 11.5t-34 2.5q-17 -4 -30.5 -14t-32.5 -7l-20 11q-6 9 -7.5 18.5t0.5 19.5l11 19q28 23 61.5 29.5t73.5 -0.5q15 -5 29.5 -11t28.5 -17l14 -17q21 -27 22.5 -62t-3.5 -70q-8 -28 -24.5 -51t-33.5 -46l-15 -13l8 -6
q30 -45 37.5 -94t-0.5 -103q-5 -24 -14 -45t-23 -40l-21 -20q-22 -12 -46 -19.5t-53 -4.5z" />
</svg>
        
このsvgコードを試すと、

で文字が確かに表示されています。

ちょっと例で使った文字が
3であったので分かりづらいかも知れませんが、svgフォントの形式では、ttfでの文字定義と上下の軸方向の正負の取り扱いが逆であるので、ちょうど上下が反転して表示されていまいます。

要はいい感じに文字を反転するように、
transform属性からtranslateメソッドやscaleメソッド使って調整を入れます。

            <svg xmlns="http://www.w3.org/2000/svg" viewBox="-0.133333 -143.133 1023.13 878.8" width="102.3" height="87.9" transform="translate(0,50) scale(1,-1)" version="1.1">
   <path d="M213 70q-29 9 -52.5 28.5t-47.5 38.5q-5 8 -7 17.5t0 19.5l12 19q8 6 18 8t22 -1l21 -14l2 -6l10 -4l-1 -4q12 -6 22.5 -14.5t24.5 -9.5q15 4 26 11t18 18q11 20 13 44l4 48q-3 24 -12 45.5t-28 41.5q-14 6 -28.5 8.5t-26.5 13.5q-6 11 -8.5 20t0.5 19l12 20q20 6 41 15
t38 23q22 20 31.5 46t7.5 56l-13 22q-12 9 -27 11.5t-34 2.5q-17 -4 -30.5 -14t-32.5 -7l-20 11q-6 9 -7.5 18.5t0.5 19.5l11 19q28 23 61.5 29.5t73.5 -0.5q15 -5 29.5 -11t28.5 -17l14 -17q21 -27 22.5 -62t-3.5 -70q-8 -28 -24.5 -51t-33.5 -46l-15 -13l8 -6
q30 -45 37.5 -94t-0.5 -103q-5 -24 -14 -45t-23 -40l-21 -20q-22 -12 -46 -19.5t-53 -4.5z" />
</svg>
        

ということで、文字も上下裏返ったのですが、実はこれだとまだスクラッチで読み込ませた時に不十分です。

スクラッチがsvgをインポートする際に、内部のプログラム処理で読み込んだ画像のサイズを
viewBoxwidth/height属性から優先的に取得するのでかなり大きい画像のように扱われることがあります。

上の例では、svg画像が
1024x879のサイズの画像として扱われるのでコスチューム画像の表示枠外になってしまい表示されません。

対策は簡単で、
viewBoxwidth/height属性はスクラッチをインポートする際には使わないでおくと、スクラッチの内部処理で、svg画像サイズが自動で判別されるようになります。

            <svg xmlns="http://www.w3.org/2000/svg" transform="translate(0,50) scale(1,-1)" version="1.1">
   <path d="M213 70q-29 9 -52.5 28.5t-47.5 38.5q-5 8 -7 17.5t0 19.5l12 19q8 6 18 8t22 -1l21 -14l2 -6l10 -4l-1 -4q12 -6 22.5 -14.5t24.5 -9.5q15 4 26 11t18 18q11 20 13 44l4 48q-3 24 -12 45.5t-28 41.5q-14 6 -28.5 8.5t-26.5 13.5q-6 11 -8.5 20t0.5 19l12 20q20 6 41 15
t38 23q22 20 31.5 46t7.5 56l-13 22q-12 9 -27 11.5t-34 2.5q-17 -4 -30.5 -14t-32.5 -7l-20 11q-6 9 -7.5 18.5t0.5 19.5l11 19q28 23 61.5 29.5t73.5 -0.5q15 -5 29.5 -11t28.5 -17l14 -17q21 -27 22.5 -62t-3.5 -70q-8 -28 -24.5 -51t-33.5 -46l-15 -13l8 -6
q30 -45 37.5 -94t-0.5 -103q-5 -24 -14 -45t-23 -40l-21 -20q-22 -12 -46 -19.5t-53 -4.5z" />
</svg>
        
以上がスクラッチで読み込ませるsvgフォントの最低限必要な形式なのですが、いかんせんプログラムの自動判別で文字の描画配置が設定されるので、表示位置が気に入らない場合には手で個別のコスチュームの位置を移動させる必要も出てくるかも知れません。

抽出するシェルスクリプト

ここではシェルスクリプトの骨子だけを解説します。

            #!/bin/bash

FILE_NAME=$1

cat "${FILE_NAME}" | sed -e 's/<glyph/~/g' -e 's/unicode="~"/unicode=""/' \
    | tr -d "\n" | tr "~" "\n" | sed -e 's/unicode=""/unicode="~"/' \
    | grep 'd="' > tmp.svg

#👇今回は利用しないが後でviewBox属性に設定できるかもしれないのでキープ
bbbox=$(head -n 1 tmp.svg | sed -e "s/.*bbox=\"\([^\"]*\)\".*/\1/")

rm -rf fonts
mkdir fonts
#👇漢字フォントは種類が多いのでUNICODE4* ~ uniFAまでを大まかにフォルダ仕訳する
mkdir fonts/uni4 fonts/uni5 fonts/uni6 fonts/uni7 \
      fonts/uni8 fonts/uni9 fonts/unif9a \
      fonts/spec_char
touch fonts/unicode_table.csv

makeSvgImg() {
svgfilename=$(echo -e "$2")
#👇特殊文字はファイル名に使えないので除外して、spec_charフォルダ内に仕訳する
if [[ "${svgfilename}" =~ [\!\#\\\/\%\'\?\*\(\)\"\<\>\.\;\,\|\-] ]] || [[ $1 =~ backslash ]]; then
    svgfilename="spec_char/$1"
fi
cat << EOF > fonts/${svgfilename}.svg
<svg xmlns="http://www.w3.org/2000/svg" transform="translate(0,50) scale(0.1,-0.1)" version="1.1">
   <path d="$3" />
</svg>
EOF
}

makeSvgImgUniX() {
svgfilename=$(echo -e "$2")
cat << EOF > fonts/$3/${svgfilename}.svg
<svg xmlns="http://www.w3.org/2000/svg" transform="translate(0,50) scale(0.1,-0.1)" version="1.1">
   <path d="$4" />
</svg>
EOF
}

cat tmp.svg | grep -e 'glyph-name' | grep -e 'unicode' | while read line; do
    glyph_name=$(echo "${line}" | sed -e "s/.*glyph-name=\"\([^\"]*\)\".*/\1/")
    unicode=$(echo "${line}" | sed -e "s/.*unicode=\"\([^\"]*\)\".*/\1/" | sed -e 's/&#x\([^;]*\);/\\u\1/')
    d_shape=$(echo "${line}" | sed -e "s/.*d=\"\([^\"]*\)\".*/\1/")

    if [[ $glyph_name =~ ^uni4 ]] ; then
        makeSvgImgUniX "$glyph_name" "$unicode" 'uni4' "$d_shape"
    elif [[ $glyph_name =~ ^uni5 ]] ; then
        makeSvgImgUniX "$glyph_name" "$unicode" 'uni5' "$d_shape"
    elif [[ $glyph_name =~ ^uni6 ]] ; then
        makeSvgImgUniX "$glyph_name" "$unicode" 'uni6' "$d_shape"
    elif [[ $glyph_name =~ ^uni7 ]] ; then
        makeSvgImgUniX "$glyph_name" "$unicode" 'uni7' "$d_shape"
    elif [[ $glyph_name =~ ^uni8 ]] ; then
        makeSvgImgUniX "$glyph_name" "$unicode" 'uni8' "$d_shape"
    elif [[ $glyph_name =~ ^uni9 ]] ; then
        makeSvgImgUniX "$glyph_name" "$unicode" 'uni9' "$d_shape"
    elif [[ $glyph_name =~ ^uniF(9|A) ]] ; then
        makeSvgImgUniX "$glyph_name" "$unicode" 'unif9a' "$d_shape"
    else
        makeSvgImg "$glyph_name" "$unicode" "$d_shape"
    fi

    if [[ $glyph_name =~ backslash ]] ; then
        #👇バックラッシュ文字は特殊文字の中でも特殊なので特別扱い
        echo -e "$glyph_name" '\' >> fonts/unicode_table.csv
    else
        echo -e "$glyph_name" "$unicode" >> fonts/unicode_table.csv
    fi
done

rm -rf tmp.svg
        
これをsvgfont_convert.shという名前で保存し、SVGフォントと同じフォルダにこのスクリプトを配置して置きます。※このスクリプトはgnu sedを含みますので、MacosxなどのBSD sed標準の環境では、少し修正が必要です。

このフォルダ内で早速このスクリプトを実行すると、
fontsフォルダ以下に個別のsvgフォントと特殊文字を仕分けしたフォルダspec_char、漢字フォントセットuni4からunif9a、今回出力したsvgファイルとユニコード文字の変換対応表unicode_table.csvが出力されていれば成功です。

            $ chmod +x svgfont_convert.sh
#👇下は利用例、svgfont_convert.sh <SVGフォントのファイル名>
$ ./svgfont_convert.sh AP.svg
#...数分の処理待ち
$ tree
.
├── AP.svg
└── fonts
    ├── unicode_table.csv
    ├── spec_char
    ├── uni4
    ├── uni5
    ├── uni6
    ├── uni7
    ├── uni8
    ├── uni9
    ├── unif9a
    #👇以降は特殊文字&漢字以外の標準フォント
    ├── ァ.svg
    ├── ィ.svg
    #...中略
    └── №.svg
        

スクラッチでの作業

早速先程の個別に抽出したsvgフォントをスクラッチプロジェクトで読み込んでみます。

免責事項

前節でも触れましたが、フリーフォントで頂いたものは利用規約を良く読んでからスクラッチプロジェクトで使いましょう。

svgフォントを試す際、スクラッチのプロジェクトに読み込ませる前に、まず読み込ませる先のプロジェクトが非公開にされているか確認しましょう。スクラッチのデスクトップ版を利用してオフラインのプライベートモードで利用しても良いと思います。

スクラッチプロジェクトを公開していまうと、誰にでもリミックスされたり、ソースコードの中身からリソースが再利用可能になるので、これが明らかに
再配布行為に当たります。

フリーフォントを使ってスクラッチアプリを公開したい場合には、フォントの著作権元の許可が必要になりますのでご注意ください。

なお弊社では、
こちらの記事に記載したように、ライセンス付きのリソースを個別にアクセス管理して、CORS制限を施すなどの対策で保護しながら対策しております。こちらはネットワークやクラウドインフラの知識が必要になってきますので、どちらかと言えばフロントエンド開発者向けの対応策です。

特殊文字の配置

まずは特殊文字から読み込みこんでみます。

手順としては、新しいスプライトを作成し、コスチュームをアップロード、ファイル選択ダイアログから
spec_charフォルダ内のsvgを全て開き、読み込んだコスチューム名を、それぞれの特殊文字へ手動で換えていきます。(以下の図参照。)

次に同じ手順で漢字以外の標準のフォントも読み込んでみます。

...すでに漢字以外のフォントを全て読み込んだ時点で800文字に迫る勢いです。

1つのコスチュームに設定して負荷なく動作する上限はせいぜい200~300個程度だと思うのですが、800近くになるとこの時点でスクラッチアプリの動作はかなり重いです。

今回のフォントも総文字数は8000文字弱はありますので、文字全てを一つのスプライトに設定して使うのは現実的でなく、スプライトを分散させて利用する必要が出てきます。

そのやり方はまたいつかブログの記事で紹介したいと思います。

フォント文字の使い方

今回は応用的なプログラムは作成しませんが、基本的な使い方をやってみます。

先程、文字を設定したスプライトに何か変数を追加しておきます。

ここでは
もじ_という変数を追加し、もじ_を◯にするブロックで旧ひらがなを設定してみます。

コスチュームを◯にするブロックに、◯の1番目の文字ブロックを組み合わせることで、変数に設定されている最初の文字を取得できるようになることを利用しています。

このブロックを組み合わせると、以下のように動作します。

まとめ

今回は一般的なフォントからスクラッチのプログラムで扱う導入方法を検討してみました。

ここまで読んでいただけたなら、中々一筋縄にはいかないことが理解していただけるかと思いますが、技術的には不可能ではありません。

著作権のあるフォントの関係で、アプリの公開はすこし厳しいかも知れませんが、自分専用のタイピングゲームなどを作成して楽しまれてたいかがかと思います。

またフォントを扱うプログラムは文字総数がかなり多く、このままでは動作が重くまだまだ実用性に乏しいので、次回以降は拡張機能を使った動作改善の方法を紹介してみようと思います。
記事を書いた人

記事の担当:taconocat

ナンデモ系エンジニア

これからの"地方格差"なきプログラミング教育とは何かを考えながら、 地方密着型プログラミング学習関連テーマの記事を不定期で独自にブログ発信しています。