[スクラッチ上級者講座] 任意のフォントファイル(ttf)から個別のsvg画像に変換してコスチュームとして使う方法
※ 当ページには【広告/PR】を含む場合があります。
2020/11/19
スクラッチアプリを作っていて文字フォントをスプライトで自由に操作できたらなぁ、と思う場面が結構あると思います。
残念ながら現状のスクラッチで自由にフォント文字使う機能は用意されてありません。
よって、必要の際には自分で一から作成するしかありません。
しかも、その機能を実現するためには色々な課題を考慮する必要もあります。
今回は試作的なテーマとして、
はじめに
今回は個人利用OK・商用サイト利用OKの公開されているフォントで適当な物を教材的な目的でダウンロードして使わせていただきます。
まず、公開されているフォントは扱いは良く利用規約を確認すべきです。
今回使わせていただく無償フォントも、著作権の関係から再配布・販売・改造は禁止です。
今回も個人用のアプリやWEBサイトの利用に用途を限定するとして、ttfからsvgのようなWebフォント用にファイル変換までなら許可されているようです。
特にスクラッチのウェブページにアプリを上げる場合、ttfの創作物の改変・再配布とみなされないために、ウェブからフリーのフォントをダウンロードして使う際にはライセンス情報を十分に注意して使う必要があります。
弊社はスクラッチのサイトを回避して、独自のサーバーからスクラッチアプリを公開しているやり方をとっているため、ここら辺のややこしいライセンス衝突問題はクリアしております。
詳しくは
ttf -> svgへ変換
オンラインの無料で使えるファイルコンバータを利用して、ttf形式のフォントをsvg(フォント)に変換します。 例えば、今回は
ttfをsvgに変換する場合、
SVGフォント
SVGフォント?
SVGでは、Webフォントを定義するための要素
<font>
ただしFirefoxなどでは
woff
判例を上げると、以下のようになります。
<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フォントからさらに
glyph
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 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をインポートする際に、内部のプログラム処理で読み込んだ画像のサイズを
viewBox
width/height
上の例では、svg画像が
1024x879
対策は簡単で、
viewBox
width/height
<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
このフォルダ内で早速このスクリプトを実行すると、
fonts
spec_char
uni4
unif9a
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フォントを試す際、スクラッチのプロジェクトに読み込ませる前に、まず読み込ませる先のプロジェクトが非公開にされているか確認しましょう。
スクラッチのデスクトップ版を利用してオフラインのプライベートモードで利用しても良いと思います。
スクラッチプロジェクトを公開していまうと、誰にでもリミックスされたり、ソースコードの中身からリソースが再利用可能になるので、
フリーフォントを使ってスクラッチアプリを公開したい場合には、フォントの著作権元の許可が必要になりますのでご注意ください。
なお弊社では、
こちらはネットワークやクラウドインフラの知識が必要になってきますので、どちらかと言えばフロントエンド開発者向けの対応策です。
特殊文字の配置
まずは特殊文字から読み込みこんでみます。
手順としては、新しいスプライトを作成し、コスチュームをアップロード、ファイル選択ダイアログから
spec_char

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

...すでに漢字以外のフォントを全て読み込んだ時点で800文字に迫る勢いです。
今回のフォントも総文字数は8000文字弱はあります。
文字全てを一つのスプライトに設定して使うのは現実的でなく、スプライトを分散させて利用する必要が出てきます。
そのやり方はまたいつかブログの記事で紹介したいと思います。
フォント文字の使い方
今回は応用的なプログラムは作成しませんが、基本的な使い方をやってみます。
先程、文字を設定したスプライトに何か変数を追加しておきます。
ここでは
もじ_
もじ_を◯にする
ゑ
コスチュームを◯にする
◯の1番目の文字
このブロックを組み合わせると、以下のように動作します。

まとめ
今回は一般的なフォントからスクラッチのプログラムで扱う導入方法を検討してみました。
ここまで読んでいただけたなら、中々一筋縄にはいかないことが理解していただけるかと思いますが、技術的には不可能ではありません。
著作権のあるフォントの関係で、アプリの公開はすこし厳しいかも知れません。
自分専用のタイピングゲームなどを作成して楽しまれてたいかがかと思います。
またフォントを扱うプログラムは文字総数がかなり多く、このままでは動作が重くまだまだ実用性に乏しいので、次回以降は拡張機能を使った動作改善の方法を紹介してみようと思います。