地図タイルサーバを立てたい話 (その1.5):まともな地名が表示されるようにする

まとめ: 日本の OpenStreetMap 生データを MBTiles にビルドして TileServer GL でサービングするときに地名を表示したい場合、name_intname:latin は大字や丁目がピンイン表記になっているので参照せずに name の日本語表記を参照する。このとき日本語フォントを glyphs というファイル群に変換した上で与える必要があるが、これは TTF ファイルを Font Maker にアップロードすると変換できる。

data/
 ├ output.mbtiles
 ├ config.json
 ├ fonts/font-name/xxxxx-xxxxx.pbf # 好きな日本語フォントを glyphs にして配置
 └ styles/style-name/style.json # name:latin でなく name を参照し日本語フォントを指定
前回のあらすじ
前回、日本の OpenStreetMap 生データを Planetiler のデフォルトのプロファイルで MBTiles にビルドし、TileServer GL でサービングしてラスタタイルとして取得しました。ただ、スタイルを指定しないと (デフォルトスタイルだと) 地名が表示されなかったので、TileServer GL の READMEtest_data.zip からスタイル及びフォントを拝借するとアルファベットで地名が表示されました。が、大字や丁目レベルの地名はしばしばピンイン表記になっていました。例えば下図左の右上は「藤倉二丁目」がピンイン表記になっています。この記事ではこれを下図右のように直します。

修正前後のタイル /styles/maptiler-basic/512/14/14537/6440.png (地図画像出典: OpenStreetMap)
タイルに含まれる情報の確認
そもそもまともな地名がタイルに含まれていないのか調べるために、レンダリング元のベクタタイルの方を取得してデシリアライズします。すると name_intname:latinピンイン表記になっていますが、namename:nonlatin はまともな日本語表記になっているので、こちらを表示させたいです。

import requests
import mapbox_vector_tile

url = "http://{タイルサーバの IP アドレス}:{ポート}/data/openmaptiles/14/14537/6440.pbf"
pbf = requests.get(url).content
tile = mapbox_vector_tile.decode(pbf)
place_features = tile["place"]["features"]
for feat in place_features:
    if feat["properties"]["name"] == "藤倉二丁目":
        for k, v in feat["properties"].items():
            print(k, "=", v)
name_int = téng cāng èr dīng mù
name:nonlatin = 藤倉二丁目
name_de = 藤倉二丁目
name = 藤倉二丁目
rank = 34
class = neighbourhood
name:latin = téng cāng èr dīng mù
name_en = 藤倉二丁目

style.json の変更
なので、以下にある style.json 内の name:latin を撲滅します (何箇所かありますがすべて撲滅します)。

vi data/styles/maptiler-basic/style.json
-        "text-field": "{name:latin}\n{name:nonlatin}",
+        "text-field": "{name}",

反映させるには、タイルサーバを再起動する必要があります。

docker stop tileserver
docker start tileserver

これで「藤倉二丁目」になるかと思いましたが、ラスタタイルからは地名が消えました (なおベクタタイルをクライアント側で描画する分には意図通り日本語地名になっていました)。この挙動から推察するに、タイルサーバでのラスタタイルレンダリング時に利用できる日本語フォントがなさそうです。思えばスタイル拝借元の test_data.zipチューリッヒの地図だったので日本語フォントが同梱されていないのは残念でもないし当然かもしれません。

フォントの glyphs 化
タイルサーバが日本語フォントを利用できなければなりませんが、タイルサーバのあるマシンにフォントをインストールすればよいのではなく、フォントを glyphs というファイル群 font-name/xxxxx-xxxxx.pbf にして TileServer GL 起動時に渡す必要があります [1]。[1] によると glyphs は MapLibre 系地図描画エンジン向けのフォーマットで、TileServer GL も MapLibre GL でラスタタイルをレンダリングするのでこのフォーマットが要求されるのだと思います。

[1] からたどると Font Maker [4] に TTF をアップロードして glyphs に変換するのが MapLibre チームの推奨する方法のようです。手元の端末で Font Maker に TTF をアップロードするとブラウザで変換が実行されました。端末がぶおーんといって 5-10 分くらいで変換されました (ちゃんと測っていません)。

なお、私は最初変換ツール [4] の存在に気付かず、[2] を参考に [3] を利用して変換しました。

▼クリックして展開以下のコマンドで変換しました。私の手元ではインストール前に警告のエラー扱いを抑制しないとインストールに失敗しました。変換は一瞬でした。しかし、現在はツール [4] での変換が推奨されているかもしれません。

sudo apt install npm
git clone https://github.com/mapbox/node-fontnik
cd node-fontnik
vi binding.gyp  # 5 行目を 'error_on_warnings%':'false', に変更する
npm install
../
mkdir ume-hgo4/  # フォルダ名がスタイルで指定するフォント名になるが適当でよい
 ./node-fontnik/bin/build-glyphs ume-hgo4.ttf ume-hgo4/


何にせよ、変換された ume-hgo4/xxxxx-xxxxx.pbf を丸ごと data/fonts/ 以下に移動します。

style.json の変更 (再)
そして、再度 style.json を変更します。"Open Sans Regular(Bold)" が参照されている箇所すべてに "ume-hgo4", を割り込ませておきます (あと、フォントが小さいと思ったのでこの箇所の少し下の方にあるフォントサイズも適当に大きくしました)。

vi data/styles/maptiler-basic/style.json
        "text-font": [
+          "ume-hgo4",
          "Open Sans Regular"
        ],

これで再度タイルサーバを再起動させると、記事冒頭の右側の画像のようにまともな地名が表示されました。