datapng-tiler 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. datapng_tiler-0.1.0/.github/dependabot.yml +10 -0
  2. datapng_tiler-0.1.0/.github/workflows/ci.yml +50 -0
  3. datapng_tiler-0.1.0/.github/workflows/release.yml +72 -0
  4. datapng_tiler-0.1.0/.gitignore +17 -0
  5. datapng_tiler-0.1.0/.python-version +1 -0
  6. datapng_tiler-0.1.0/BENCHMARKS.md +107 -0
  7. datapng_tiler-0.1.0/CHANGELOG.md +30 -0
  8. datapng_tiler-0.1.0/CONTRIBUTING.md +57 -0
  9. datapng_tiler-0.1.0/LICENSE +21 -0
  10. datapng_tiler-0.1.0/NOTICE +51 -0
  11. datapng_tiler-0.1.0/PKG-INFO +238 -0
  12. datapng_tiler-0.1.0/README.en.md +87 -0
  13. datapng_tiler-0.1.0/README.md +210 -0
  14. datapng_tiler-0.1.0/pyproject.toml +63 -0
  15. datapng_tiler-0.1.0/scripts/benchmark.py +148 -0
  16. datapng_tiler-0.1.0/scripts/check_schema_sync.py +50 -0
  17. datapng_tiler-0.1.0/src/datapng_tiler/__init__.py +12 -0
  18. datapng_tiler-0.1.0/src/datapng_tiler/__main__.py +8 -0
  19. datapng_tiler-0.1.0/src/datapng_tiler/cli.py +690 -0
  20. datapng_tiler-0.1.0/src/datapng_tiler/codec.py +299 -0
  21. datapng_tiler-0.1.0/src/datapng_tiler/convert.py +179 -0
  22. datapng_tiler-0.1.0/src/datapng_tiler/engine.py +403 -0
  23. datapng_tiler-0.1.0/src/datapng_tiler/fileio.py +78 -0
  24. datapng_tiler-0.1.0/src/datapng_tiler/geo.py +311 -0
  25. datapng_tiler-0.1.0/src/datapng_tiler/imageio.py +167 -0
  26. datapng_tiler-0.1.0/src/datapng_tiler/legend.py +198 -0
  27. datapng_tiler-0.1.0/src/datapng_tiler/modes/__init__.py +12 -0
  28. datapng_tiler-0.1.0/src/datapng_tiler/modes/base.py +207 -0
  29. datapng_tiler-0.1.0/src/datapng_tiler/modes/numerical.py +308 -0
  30. datapng_tiler-0.1.0/src/datapng_tiler/modes/palette.py +308 -0
  31. datapng_tiler-0.1.0/src/datapng_tiler/py.typed +0 -0
  32. datapng_tiler-0.1.0/src/datapng_tiler/schema/datapng-0.7.0.schema.json +201 -0
  33. datapng_tiler-0.1.0/src/datapng_tiler/tilejson.py +146 -0
  34. datapng_tiler-0.1.0/src/datapng_tiler/validate.py +266 -0
  35. datapng_tiler-0.1.0/src/datapng_tiler/viewer.py +365 -0
  36. datapng_tiler-0.1.0/tests/__init__.py +0 -0
  37. datapng_tiler-0.1.0/tests/conftest.py +160 -0
  38. datapng_tiler-0.1.0/tests/helpers.py +134 -0
  39. datapng_tiler-0.1.0/tests/modes/__init__.py +0 -0
  40. datapng_tiler-0.1.0/tests/modes/test_palette.py +186 -0
  41. datapng_tiler-0.1.0/tests/test_cli.py +553 -0
  42. datapng_tiler-0.1.0/tests/test_codec.py +297 -0
  43. datapng_tiler-0.1.0/tests/test_convert.py +149 -0
  44. datapng_tiler-0.1.0/tests/test_engine.py +314 -0
  45. datapng_tiler-0.1.0/tests/test_fileio.py +71 -0
  46. datapng_tiler-0.1.0/tests/test_geo.py +270 -0
  47. datapng_tiler-0.1.0/tests/test_imageio.py +169 -0
  48. datapng_tiler-0.1.0/tests/test_legend.py +147 -0
  49. datapng_tiler-0.1.0/tests/test_tilejson.py +295 -0
  50. datapng_tiler-0.1.0/tests/test_viewer.py +116 -0
  51. datapng_tiler-0.1.0/uv.lock +555 -0
@@ -0,0 +1,10 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "github-actions"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "monthly"
7
+ - package-ecosystem: "uv"
8
+ directory: "/"
9
+ schedule:
10
+ interval: "monthly"
@@ -0,0 +1,50 @@
1
+ name: ci
2
+
3
+ # PR と main への push で lint / テストを走らせる。
4
+ # 一般公開ツールのため 3 OS で回す。特にプロセス並列は Linux が fork、macOS/Windows が
5
+ # spawn と既定が異なり、ワーカへ状態を渡す経路の壊れ方が OS で変わる(tests/test_engine.py)。
6
+ on:
7
+ pull_request:
8
+ push:
9
+ branches:
10
+ - main
11
+
12
+ # fork からの PR でもブランチ側のコードを実行するため、既定より絞る。
13
+ permissions:
14
+ contents: read
15
+
16
+ jobs:
17
+ lint:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: astral-sh/setup-uv@v5
22
+ - name: ruff check
23
+ run: uv run --locked ruff check .
24
+ - name: ruff format --check
25
+ run: uv run --locked ruff format --check .
26
+
27
+ test:
28
+ strategy:
29
+ fail-fast: false
30
+ matrix:
31
+ os: [ubuntu-latest, macos-latest, windows-latest]
32
+ python-version: ["3.12", "3.13"]
33
+ runs-on: ${{ matrix.os }}
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+ - uses: astral-sh/setup-uv@v5
37
+ with:
38
+ python-version: ${{ matrix.python-version }}
39
+ - name: pytest
40
+ run: uv run --locked pytest
41
+
42
+ spec-schema:
43
+ # 同梱している JSON Schema が仕様リポジトリの配布物と一致しているかを確認する
44
+ # (仕様が更新されたのに実装側のスキーマが古いまま、を防ぐ)。
45
+ runs-on: ubuntu-latest
46
+ steps:
47
+ - uses: actions/checkout@v4
48
+ - uses: astral-sh/setup-uv@v5
49
+ - name: 仕様リポジトリのスキーマと突合
50
+ run: uv run --locked python scripts/check_schema_sync.py
@@ -0,0 +1,72 @@
1
+ name: release
2
+
3
+ # v* タグの push でビルドし、PyPI へ公開して GitHub Release を作成する。
4
+ # リリース手順:
5
+ # 1. src/datapng_tiler/__init__.py の __version__ と CHANGELOG.md を更新して main にマージ
6
+ # 2. git tag vX.Y.Z && git push origin vX.Y.Z
7
+ #
8
+ # PyPI への公開は Trusted Publishing(OIDC)で行うため API トークンを secrets に置かない。
9
+ # 初回のみ PyPI 側で pending publisher の登録が必要(README「リリース」を参照)。
10
+ on:
11
+ push:
12
+ tags:
13
+ - "v*"
14
+
15
+ permissions:
16
+ contents: read
17
+
18
+ jobs:
19
+ build:
20
+ runs-on: ubuntu-latest
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+
24
+ - name: タグとパッケージバージョンの整合チェック
25
+ run: |
26
+ pkg=$(grep -oP '__version__ = "\K[^"]+' src/datapng_tiler/__init__.py)
27
+ if [ "v$pkg" != "$GITHUB_REF_NAME" ]; then
28
+ echo "タグ $GITHUB_REF_NAME と __version__ v$pkg が不一致"
29
+ exit 1
30
+ fi
31
+
32
+ - uses: astral-sh/setup-uv@v5
33
+
34
+ - name: テスト
35
+ run: uv run --locked pytest
36
+
37
+ - name: ビルド(sdist + wheel)
38
+ run: uv build
39
+
40
+ - uses: actions/upload-artifact@v4
41
+ with:
42
+ name: dist
43
+ path: dist/
44
+
45
+ pypi:
46
+ needs: build
47
+ runs-on: ubuntu-latest
48
+ environment: pypi
49
+ permissions:
50
+ id-token: write # Trusted Publishing(OIDC)に必要
51
+ steps:
52
+ - uses: actions/download-artifact@v4
53
+ with:
54
+ name: dist
55
+ path: dist/
56
+ - uses: pypa/gh-action-pypi-publish@release/v1
57
+
58
+ github-release:
59
+ needs: pypi
60
+ runs-on: ubuntu-latest
61
+ permissions:
62
+ contents: write
63
+ steps:
64
+ - uses: actions/checkout@v4
65
+ - uses: actions/download-artifact@v4
66
+ with:
67
+ name: dist
68
+ path: dist/
69
+ - name: GitHub Release 作成
70
+ env:
71
+ GITHUB_TOKEN: ${{ github.token }}
72
+ run: gh release create "$GITHUB_REF_NAME" dist/* --title "$GITHUB_REF_NAME" --notes "詳細は CHANGELOG.md を参照。"
@@ -0,0 +1,17 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .venv/
6
+ dist/
7
+ build/
8
+
9
+ # ツール
10
+ .pytest_cache/
11
+ .ruff_cache/
12
+ .coverage
13
+ htmlcov/
14
+
15
+ # 作業用
16
+ /tmp/
17
+ *.tmp
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,107 @@
1
+ # 実測
2
+
3
+ 設定を選ぶための相対比較の記録です。**絶対値には意味がありません**(環境とデータで変わります)。
4
+ 再現するには次を実行してください。
5
+
6
+ ```sh
7
+ uv run python scripts/benchmark.py --size 4096 --max-zoom 13 --min-zoom 8 --jobs 8
8
+ ```
9
+
10
+ ## 測定条件
11
+
12
+ | 項目 | 値 |
13
+ |------|-----|
14
+ | データ | 合成 DEM 4096×4096 float32(地形らしい空間相関を持たせたもの。縁は無効値) |
15
+ | 出力 | z8–13、タイル 906 枚、512px |
16
+ | 符号化 | `factor=0.01` |
17
+ | 環境 | WSL2 / 16 論理コア / Python 3.12 / rasterio 1.5.1 / Pillow 12 |
18
+
19
+ 合成データは実際の地形より高周波成分が多く、**容量は実データより大きく出ます**。設定どうしの
20
+ 比較には使えますが、配信容量の見積もりには使わないでください。
21
+
22
+ ## 形式と圧縮設定
23
+
24
+ | 設定 | 時間 [s] | 合計 [MB] |
25
+ |------|---------:|----------:|
26
+ | WebP lossless method=0 | 35.3 | 229.0 |
27
+ | **WebP lossless method=1(既定)** | **42.8** | **172.0** |
28
+ | WebP lossless method=4 | 58.1 | 171.8 |
29
+ | WebP lossless method=6 | 127.9 | 171.7 |
30
+ | PNG compress_level=1 | 14.7 | 289.6 |
31
+ | **PNG compress_level=6(既定)** | **27.2** | **244.7** |
32
+ | PNG compress_level=9 | 71.9 | 240.6 |
33
+
34
+ **WebP の `method` 既定を 1 にした理由**: method 0 → 1 で容量が 25% 減るのに対し、1 → 6 では
35
+ 0.2% しか減らず、時間は 3 倍になります。容量がほぼ頭打ちになる最初の点が 1 です。
36
+
37
+ **PNG の `compress_level` 既定を 6 にした理由**: Pillow の既定と同じで、9 に上げても 1.7% しか
38
+ 減らないのに 2.6 倍の時間がかかります。速度が要るなら 1 が選べます(容量 +18%)。
39
+
40
+ **形式の選択**: WebP は PNG より **30% 小さく**、時間は 1.6 倍かかります。可逆圧縮なので値は
41
+ どちらも劣化しません。配信容量が効く用途では WebP(既定)、PNG しか受け付けないクライアントに
42
+ 合わせる必要がある場合だけ PNG を選んでください。
43
+
44
+ ## 並列数
45
+
46
+ | `-j` | 時間 [s] | 逐次比 |
47
+ |-----:|---------:|-------:|
48
+ | 1 | 217.9 | 1.0× |
49
+ | 2 | 124.4 | 1.8× |
50
+ | 4 | 70.8 | 3.1× |
51
+ | 8 | 43.4 | 5.0× |
52
+ | 16 | 34.1 | 6.4× |
53
+
54
+ 既定は CPU 数です。16 コアで 6.4 倍にとどまるのは、ズーム間に依存があるオーバービュー生成が
55
+ 逐次に近づくためです(同一ズーム内は並列)。
56
+
57
+ ## 時間の内訳
58
+
59
+ ベースタイル 60 枚を 1 プロセスで生成して `cProfile` で測った内訳です。
60
+
61
+ | 処理 | 割合 |
62
+ |------|-----:|
63
+ | WebP エンコード(Pillow → libwebp) | 75% |
64
+ | 再投影とウィンドウ読み取り(GDAL) | 14% |
65
+ | 符号化・画像の組み立て(本ツール) | 8% |
66
+
67
+ **支配項は画像エンコードで、自前の配列処理ではありません。** 高速化したいときは、まず
68
+ `--webp-method` や `--format` を見直すのが効きます。
69
+
70
+ ## qchizu-tools との比較
71
+
72
+ 設計の下敷きにした [qchizu-tools](https://github.com/qchizu-project/qchizu-tools)(非公開)の
73
+ `tile --mode numeric` と、同じ入力・同じ設定で比べました。同一マシンで連続して 2 回ずつ。
74
+
75
+ | 実装 | 1 回目 [s] | 2 回目 [s] | 合計 [MB] |
76
+ |------|----------:|----------:|----------:|
77
+ | qchizu-tools | 61.3 | 58.4 | 172.0 |
78
+ | datapng-tiler | 46.8 | 44.6 | 172.0 |
79
+
80
+ 容量は同一(同じ WebP 設定・同じ符号化)で、時間は約 24% 短くなりました。
81
+
82
+ **出力の突き合わせ**(有効画素 58,270,353 について復号値を比較):
83
+
84
+ - **99.51% が完全一致**
85
+ - 残り 0.49% は raw で 1(= 0.01 m)だけ違う
86
+ - 1 量子化ステップを超える差は 0 件
87
+
88
+ 差の原因は量子化を行う浮動小数の精度です。qchizu-tools は float32 の配列をそのまま
89
+ `values / factor` にかけるため、NumPy の弱い型付けにより float32 のまま計算されます。
90
+ 本ツールは float64 を明示しています(`codec.NumericalEncoding._to_scaled`)。原典を独立に
91
+ bilinear 補間して突き合わせると、本ツールの値は量子化の半幅(0.005 m)以内に収まります。
92
+
93
+ ## 値の正確性の実測
94
+
95
+ 合成 DEM(円錐 + 高周波成分、512×512、`factor=0.01`)を z13 までタイル化し、**配信物
96
+ (TileJSON + タイル)だけを見て復号**した値を、原典ラスタを独立に bilinear 補間した値と
97
+ 突き合わせました。
98
+
99
+ | 項目 | 値 |
100
+ |------|-----|
101
+ | 検査画素 | 8,615 |
102
+ | 最大差 | 0.00510 m |
103
+ | 中央値 | 0.00254 m |
104
+ | 量子化の半幅 | 0.005 m |
105
+
106
+ 最大差が量子化の半幅とほぼ一致しており、**量子化以外の誤差(幾何のずれ・補間の食い違い)は
107
+ 検出されませんでした**。
@@ -0,0 +1,30 @@
1
+ # 変更履歴
2
+
3
+ このファイルの書式は [Keep a Changelog](https://keepachangelog.com/ja/1.1.0/) に従い、
4
+ バージョニングは [Semantic Versioning](https://semver.org/lang/ja/) に従います。
5
+
6
+ ## [Unreleased]
7
+
8
+ ## [0.1.0] - 2026-08-29
9
+
10
+ 初版。[TileJSON DataPNG Extension](https://github.com/qchizu-project/tilejson-datapng-extension)
11
+ v0.7.0 に準拠します。
12
+
13
+ ### Added
14
+
15
+ - `tile`: ラスタから数値型・パレット型のタイル木と TileJSON を生成する
16
+ - 出力形式は WebP(可逆圧縮・既定)と PNG。形式はタイル URL の拡張子が示す
17
+ - `factor` / `offset` による量子化、`specialEncoding`(mapbox / terrarium)互換出力
18
+ - `support`(point / block)に応じた再投影アライメントとオーバービュー方式
19
+ - パレット型は凡例定義(YAML / JSON)から色を引き、PNG ではインデックスカラーで書く
20
+ - `--auto-data-range` で `dataRange` を生成タイルから実測
21
+ - プロセス並列・レジューム・アトミック書き込み
22
+ - `convert`: 既存タイル木の再エンコード(Terrain-RGB / Terrarium → 正式エンコード、形式変換)
23
+ - `tilejson`: 既存タイル木から TileJSON を生成する(範囲・ズームは走査して実測)
24
+ - `validate`: JSON Schema による仕様適合検証と、宣言と実タイルの突合
25
+ (タイル URL の拡張子と中身の食い違いも検出する)
26
+ - `inspect`: タイル 1 枚を復号して統計・特定画素の値を表示する
27
+ - プレビュー HTML(カーソル位置の値を仕様どおりに復号して表示。背景地図は既定で無し)
28
+
29
+ [Unreleased]: https://github.com/qchizu-project/datapng-tiler/compare/v0.1.0...HEAD
30
+ [0.1.0]: https://github.com/qchizu-project/datapng-tiler/releases/tag/v0.1.0
@@ -0,0 +1,57 @@
1
+ # コントリビューションについて
2
+
3
+ Issue・Pull Request を歓迎します。日本語でも英語でも構いません。
4
+
5
+ ## どこに出すか
6
+
7
+ このリポジトリは**仕様の実装**です。指摘の内容によって、出し先が変わります。
8
+
9
+ | 内容 | 出し先 |
10
+ |------|--------|
11
+ | このツールの不具合・機能追加 | このリポジトリの [Issues](https://github.com/qchizu-project/datapng-tiler/issues) |
12
+ | 仕様そのものへの疑問・提案 | [tilejson-datapng-extension](https://github.com/qchizu-project/tilejson-datapng-extension/issues) |
13
+
14
+ 「仕様ではこう読めるのに実装がそうなっていない」という指摘は、どちらでも構いません(こちらで振り分けます)。仕様の解釈が曖昧だった、という結論になることもあります。
15
+
16
+ ## 開発
17
+
18
+ ```sh
19
+ uv sync
20
+ uv run pytest -v
21
+ uv run ruff check . && uv run ruff format .
22
+ ```
23
+
24
+ CI は Ubuntu / macOS / Windows × Python 3.12 / 3.13 で回ります。プロセス並列の既定が
25
+ Linux は fork、macOS と Windows は spawn と異なるため、**ワーカへ渡す状態はすべて
26
+ `initargs` で明示的に渡してください**(グローバル変数は spawn では引き継がれません)。
27
+
28
+ ## テストの方針
29
+
30
+ - **仕様適合は独立デコーダで確かめます。** `tests/test_codec.py` には仕様書の変換式を
31
+ 文字どおり写したデコーダがあります。実装のデコーダで往復させても「実装が自分の仕様に
32
+ 従っている」ことしか言えないためです。新しいエンコードを足すときも、まず仕様の式を
33
+ ここへ写してください。
34
+ - **タイルの値は解析的に検証します。** 値が座標の 1 次関数になる合成ラスタを使い、
35
+ タイル画素が代表する座標での真値と突き合わせます(`tests/helpers.py`)。
36
+ 「絵として正しそう」では幾何の半画素ずれを検出できません。
37
+ - **外部データ・ネットワークに依存しません。** 必要なラスタはその場で合成します。
38
+ - 決定性(同じ入力から同じバイト列)と、並列・逐次の一致もテストで固定しています。
39
+
40
+ ## 設計上、動かしにくいところ
41
+
42
+ 次の 2 つは、片方だけ変えられない形に閉じてあります。壊さないでください。
43
+
44
+ - **`support` の宣言と生成方式**(`modes/base.py`)。TileJSON に書く `support` と、
45
+ 実際の再投影アライメント・オーバービュー方式は必ず一致します。
46
+ - **無効値の表し方**(`modes/numerical.py`)。アルファか `invalidColor` のどちらか一方で、
47
+ 併用はできません(仕様 §3.2.2 MUST NOT)。
48
+
49
+ ## コミットメッセージ
50
+
51
+ [Conventional Commits](https://www.conventionalcommits.org/ja/) の形式(`feat:` / `fix:` /
52
+ `docs:` / `refactor:` / `test:` / `chore:`)を使います。本文には**なぜそうしたか**を書いて
53
+ ください——何をしたかは diff を見れば分かります。
54
+
55
+ ## ライセンス
56
+
57
+ 貢献いただいたコードは MIT License で配布されます。
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 qchizu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,51 @@
1
+ datapng-tiler
2
+ Copyright (c) 2026 qchizu
3
+
4
+ 本ソフトウェアは MIT License で配布されます(LICENSE を参照)。
5
+
6
+
7
+ ## 準拠する仕様
8
+
9
+ 本ソフトウェアは以下の仕様に準拠して実装されています。いずれも本ソフトウェアの
10
+ 著作物ではありません。
11
+
12
+ - TileJSON DataPNG Extension(qchizu-project, CC0 1.0 Universal)
13
+ https://github.com/qchizu-project/tilejson-datapng-extension
14
+
15
+ `src/datapng_tiler/schema/datapng-0.7.0.schema.json` は、上記仕様が公開する
16
+ JSON Schema をそのまま同梱したものです。CC0 1.0 Universal(パブリックドメイン
17
+ 献呈)で公開されているため、再配布にクレジット表示は不要ですが、出典を明示する
18
+ ために記載します。
19
+
20
+ - TileJSON 3.0.0(Mapbox, CC-BY 3.0)
21
+ https://github.com/mapbox/tilejson-spec/tree/master/3.0.0
22
+
23
+ - データPNG/グリッドPNGタイル仕様 v0.1(産業技術総合研究所 地質調査総合センター)
24
+ https://gsj-seamless.jp/labs/datapng/
25
+
26
+ - Mapbox Terrain-RGB / Mapzen Terrarium(`specialEncoding` の互換復号式)
27
+ いずれも公開されている復号式のみを実装しており、コードの流用はありません。
28
+
29
+
30
+ ## 設計上の参照
31
+
32
+ タイル生成の設計(EPSG:3857 への再投影パラメータ算出、ベースタイル → オーバー
33
+ ビューの構成、プロセス並列とレジューム、数値の 24 ビット整数エンコード)は、
34
+ 同一著作権者が開発した非公開ツール `qchizu-tools` の運用知見を踏まえています。
35
+ コードは本リポジトリのために書き下ろしたものです。
36
+
37
+
38
+ ## 依存ライブラリ
39
+
40
+ 実行時の依存はいずれも寛容型ライセンスであり、MIT License と両立します。
41
+
42
+ | パッケージ | ライセンス |
43
+ |-----------|-----------|
44
+ | rasterio | BSD-3-Clause(同梱される GDAL は MIT/X 系、PROJ は MIT) |
45
+ | numpy | BSD-3-Clause |
46
+ | Pillow | MIT-CMU (HPND) |
47
+ | jsonschema | MIT |
48
+ | PyYAML | MIT |
49
+
50
+ プレビュー HTML は Leaflet(BSD-2-Clause)を CDN から読み込みます。Leaflet の
51
+ コードは本リポジトリに同梱していません。
@@ -0,0 +1,238 @@
1
+ Metadata-Version: 2.5
2
+ Name: datapng-tiler
3
+ Version: 0.1.0
4
+ Summary: Generate data tiles (numerical / palette) and TileJSON conforming to the TileJSON DataPNG Extension
5
+ Project-URL: Homepage, https://github.com/qchizu-project/datapng-tiler
6
+ Project-URL: Repository, https://github.com/qchizu-project/datapng-tiler
7
+ Project-URL: Issues, https://github.com/qchizu-project/datapng-tiler/issues
8
+ Project-URL: Changelog, https://github.com/qchizu-project/datapng-tiler/blob/main/CHANGELOG.md
9
+ Project-URL: Specification, https://github.com/qchizu-project/tilejson-datapng-extension
10
+ Author: qchizu
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ License-File: NOTICE
14
+ Keywords: dem,gis,png,raster,tilejson,tiles,webp,xyz
15
+ Classifier: Development Status :: 3 - Alpha
16
+ Classifier: Intended Audience :: Science/Research
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Scientific/Engineering :: GIS
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.12
22
+ Requires-Dist: jsonschema>=4.20
23
+ Requires-Dist: numpy>=1.26
24
+ Requires-Dist: pillow>=10.0
25
+ Requires-Dist: pyyaml>=6.0
26
+ Requires-Dist: rasterio>=1.3
27
+ Description-Content-Type: text/markdown
28
+
29
+ # datapng-tiler
30
+
31
+ ラスタデータから **データPNG タイル**(数値型・パレット型)と **TileJSON** を生成する CLI / Python ライブラリです。
32
+
33
+ [TileJSON DataPNG Extension](https://github.com/qchizu-project/tilejson-datapng-extension) v0.7.0 に準拠します。
34
+
35
+ > **Language**: [English README](./README.en.md)
36
+
37
+ ## これは何か
38
+
39
+ 標高・水深・気温のような**連続値**や、土地利用・浸水深階級のような**区分**を、地図タイルとして配信するときに使います。値を RGB に可逆に埋め込んだタイルと、それを復号するために必要なメタデータ(係数・単位・無効値・凡例など)を記述した TileJSON を、まとめて生成します。
40
+
41
+ | | 数値型(numerical) | パレット型(palette) |
42
+ |---|---|---|
43
+ | 入力 | 連続値のラスタ | クラス値ラスタ、または RGB ラスタ + 凡例定義 |
44
+ | 格納 | 値を 24 ビット符号付き整数に量子化して RGB へ | 凡例の色をそのまま |
45
+ | 用途 | 標高・水深・気温・濃度 | 土地利用・災害リスク区分 |
46
+
47
+ タイル画像は **WebP(可逆圧縮)が既定**で、PNG も選べます。どちらも可逆なので値は劣化しません。
48
+
49
+ ## インストール
50
+
51
+ ```sh
52
+ uvx datapng-tiler --help # 実行するだけなら(インストール不要)
53
+ pipx install datapng-tiler # コマンドとして常設する
54
+ pip install datapng-tiler # ライブラリとしても使う
55
+ ```
56
+
57
+ Python 3.12 以上が必要です。GDAL は rasterio の wheel に同梱されているので、別途インストールする必要はありません。
58
+
59
+ ## 使い方
60
+
61
+ ### 数値型タイル(標高など)
62
+
63
+ ```sh
64
+ datapng-tiler tile dem.tif -o tiles/ --factor 0.01 --unit m \
65
+ --description "標高は東京湾平均海面(T.P.)基準。"
66
+ ```
67
+
68
+ `tiles/` に以下が生成されます。
69
+
70
+ ```
71
+ tiles/
72
+ ├── {z}/{x}/{y}.webp タイル
73
+ ├── tiles.json TileJSON(datapng 拡張つき)
74
+ └── index.html プレビュー(ブラウザで開くと値を読める)
75
+ ```
76
+
77
+ `--factor 0.01` は「0.01 単位で量子化する」という意味です。標高なら 1cm 刻み。値が 24 ビット整数(±8,388,607)に収まらない場合は**エラーで止まります**——黙って折り返した誤った値を出力しないためです。エラーメッセージが適切な `--factor` を提示します。
78
+
79
+ ### パレット型タイル(区分など)
80
+
81
+ 凡例定義(YAML または JSON)を用意します。
82
+
83
+ ```yaml
84
+ # legend.yaml
85
+ title: 洪水浸水想定区域(想定最大規模)浸水深
86
+ items:
87
+ - value: 1 # クラス値ラスタを入力にするときの対応値
88
+ r: 245
89
+ g: 245
90
+ b: 50
91
+ title: 0.5m未満
92
+ description: 床下浸水相当。避難行動は徒歩で可能。
93
+ - value: 2
94
+ r: 255
95
+ g: 216
96
+ b: 0
97
+ title: 0.5〜3.0m
98
+ ```
99
+
100
+ ```sh
101
+ datapng-tiler tile flood.tif -o tiles/ --type palette --legend legend.yaml
102
+ ```
103
+
104
+ RGB ラスタ(すでに色が塗られたデータ)も入力にできます。その場合 `value` は不要です。**凡例に無い色が見つかるとエラーで止まります**(`--on-unknown-color nodata` で無効値として扱えます)。
105
+
106
+ ### 既存タイルの移行
107
+
108
+ Mapbox Terrain-RGB や Mapzen/Terrarium で配信されている既存のタイル資産を、正式なデータPNG エンコードへ移せます。タイルはすでに目的の格子に載っているので再投影せず、値を読み替えるだけです。
109
+
110
+ ```sh
111
+ datapng-tiler convert ./terrain-rgb/ -o tiles/ --from mapbox --factor 0.01 --unit m
112
+ ```
113
+
114
+ 逆に、既存のラスタから Terrain-RGB 互換のタイルを作ることもできます。
115
+
116
+ ```sh
117
+ datapng-tiler tile dem.tif -o tiles/ --encoding mapbox
118
+ ```
119
+
120
+ ### 検証
121
+
122
+ 生成物が仕様に適合しているかを確かめます。CI に組み込めます。
123
+
124
+ ```sh
125
+ datapng-tiler validate tiles/tiles.json --tiles tiles/
126
+ ```
127
+
128
+ 2 段階で見ます。
129
+
130
+ 1. `datapng` を仕様の JSON Schema にかける
131
+ 2. **宣言と実タイルを突き合わせる** — ズーム範囲・形式・無効値の表し方・凡例の色
132
+
133
+ とくに「アルファチャンネルを持つタイルに `invalidColor` を宣言してはならない」(仕様 §3.2.2 MUST NOT)は TileJSON だけを見ても分からず、実タイルを開いて初めて検出できます。
134
+
135
+ ### 1 枚を確認する
136
+
137
+ ```sh
138
+ datapng-tiler inspect tiles/14/14552/6451.webp --tilejson tiles/tiles.json --pixel 100 200
139
+ ```
140
+
141
+ ## 正確性について
142
+
143
+ このツールが特に気をつけていることを挙げます。
144
+
145
+ **無効値の判定に閾値を使いません。** 「nodata に近い値を無効とみなす」実装は、nodata が 0 や正の値であるデータで有効値を消してしまいます。GDAL のマスクを正とし、nodata の宣言が無いソースではワープの被覆マスク(`add_alpha`)でソース範囲外を無効にします。
146
+
147
+ **24 ビットに収まらない値を黙って通しません。** 既定でエラーにし、`--on-overflow clamp|nodata` で明示的に選べます。
148
+
149
+ **`support` の宣言と生成方式が必ず一致します。** `--support point`(既定)なら左上法で再投影し、オーバービューも左上の値を運びます。`--support block` なら中心整列で、オーバービューは整数領域での平均になります。TileJSON にはそのとおりの `support` が出ます。片方だけ変えられる API にはしていません。
150
+
151
+ **再投影は厳密寄りのトランスフォーマで行います。** GDAL 既定の近似トランスフォーマは近似誤差が出力解像度(=生成ズーム)によって変わるため、同じ地点を狙っても標本位置がサブピクセルでにじみ、「ズームによって値が違う」現象を生みます。
152
+
153
+ **オーバービューは raw 整数のまま合成します。** 値は raw 整数のアフィン関数なので、整数領域の平均と値領域の平均は一致し、ズームを重ねても量子化誤差が積み上がりません。
154
+
155
+ **出力は決定的です。** 同じ入力・同じ設定なら、`--jobs` を変えても生成されるタイルはバイト単位で一致します。
156
+
157
+ ## 無効値の表し方
158
+
159
+ 無効値はアルファ 0 か、指定した色のどちらか一方で表します。
160
+
161
+ | | 無効値 | `invalidColor` |
162
+ |---|---|---|
163
+ | 既定 | アルファ 0 | 宣言しない |
164
+ | `--no-alpha --invalid-color R G B` | 指定した色 | 宣言する |
165
+
166
+ 仕様 §3.2.2 の `invalidColor` は**完全に透明な画素を指せません**(WebP の可逆圧縮が透明画素の RGB を保存しないため)。既定の出力では無効画素が完全に透明になるので、色を宣言しても判定に使われません。CLI は `--invalid-color` の単独指定を拒否します。
167
+
168
+ なお、無効画素が 1 つも無いタイルはアルファチャンネルを持たない形で書かれます(容量が減ります)。
169
+
170
+ ## 主なオプション
171
+
172
+ ```
173
+ --format webp|png タイル画像形式(既定: webp)
174
+ --tile-size N タイル一辺の画素数(既定: 512)
175
+ --support point|block 画素値が代表する領域(既定: point = 左上節点)
176
+ --resampling nearest|bilinear|cubic|lanczos 再投影カーネル(既定: bilinear)
177
+ --factor F --offset O v = F × rawValue + O
178
+ --encoding mapbox|terrarium 互換エンコードで出力する
179
+ --on-overflow error|clamp|nodata 範囲外の値の扱い(既定: error)
180
+ --data-range MIN MAX TileJSON に載せる期待範囲
181
+ --auto-data-range 期待範囲を生成タイルから実測する
182
+ -z / --min-zoom ズーム範囲(既定: ソース解像度から自動)
183
+ --bounds W S E N 生成範囲(既定: ソース範囲)
184
+ -j / --jobs N 並列プロセス数(既定: CPU 数)
185
+ --overwrite 既存タイルも作り直す(入力を更新したときに必要)
186
+ --basemap none|gsi|osm プレビューの背景地図(既定: none)
187
+ ```
188
+
189
+ `datapng-tiler <サブコマンド> --help` で全オプションを確認できます。
190
+
191
+ 中断した実行は、同じコマンドをもう一度走らせれば続きから再開します(既存タイルはスキップされます)。**入力データを更新したときは `--overwrite` が必要です**——既定では既存タイルを作り直さないため、1 枚も更新されません。
192
+
193
+ ## プレビューについて
194
+
195
+ `index.html` はタイル木のルートに置かれ、ブラウザで開くとカーソル位置の値を表示します。画像として並べるだけでなく **TileJSON の宣言どおりに復号して見せる**ので、「絵としては出ているが値が違う」を見つけられます。
196
+
197
+ - 値の読み取りにはタイルが HTML と同一オリジンにある必要があります(`python -m http.server -d tiles/` などで開いてください)。別オリジンのタイルは表示はできますが値を読めません。
198
+ - **背景地図は既定で無しです。** 地理院タイルや OpenStreetMap を既定にすると、このツールを使うすべての人に第三者サービスの利用規約を負わせることになるためです。`--basemap gsi|osm` で明示的に選べます(選ぶと規約の所在を表示します)。
199
+
200
+ ## ライブラリとして使う
201
+
202
+ ```python
203
+ from datapng_tiler.codec import NumericalEncoding
204
+ from datapng_tiler.engine import tile_raster
205
+ from datapng_tiler.modes import NumericalMode
206
+ from datapng_tiler.tilejson import from_tree, write_tilejson
207
+
208
+ mode = NumericalMode(encoding=NumericalEncoding(factor=0.01), unit="m")
209
+ result = tile_raster("dem.tif", "tiles/", mode, processes=8)
210
+ write_tilejson(from_tree("tiles/", mode, name="標高"), "tiles/tiles.json")
211
+ ```
212
+
213
+ `datapng_tiler.codec` は純粋関数だけなので、符号化・復号だけを使うこともできます。
214
+
215
+ ## 開発
216
+
217
+ ```sh
218
+ uv sync
219
+ uv run pytest -v
220
+ uv run ruff check . && uv run ruff format .
221
+ ```
222
+
223
+ テストは外部データやネットワークに依存しません。仕様適合の検証には、**仕様書の変換式を文字どおり写した独立デコーダ**を使っています(実装同士の往復では「実装が自分の仕様に従っている」ことしか言えないため)。
224
+
225
+ 性能の実測は [BENCHMARKS.md](./BENCHMARKS.md) を参照してください。
226
+
227
+ ## リリース
228
+
229
+ 1. `src/datapng_tiler/__init__.py` の `__version__` と `CHANGELOG.md` を更新して main にマージ
230
+ 2. `git tag vX.Y.Z && git push origin vX.Y.Z`
231
+
232
+ タグの push で GitHub Actions が PyPI(Trusted Publishing)と GitHub Release へ公開します。初回のみ PyPI 側で pending publisher の登録が必要です。
233
+
234
+ ## ライセンス
235
+
236
+ MIT License([LICENSE](./LICENSE))。準拠仕様と依存ライブラリの帰属は [NOTICE](./NOTICE) を参照してください。
237
+
238
+ 準拠する仕様 [TileJSON DataPNG Extension](https://github.com/qchizu-project/tilejson-datapng-extension) は CC0 1.0 で公開されています。