tilekit 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.
- tilekit-0.1.0/.idea/.gitignore +8 -0
- tilekit-0.1.0/.idea/inspectionProfiles/profiles_settings.xml +6 -0
- tilekit-0.1.0/.idea/misc.xml +7 -0
- tilekit-0.1.0/.idea/modules.xml +8 -0
- tilekit-0.1.0/.idea/tilekit.iml +11 -0
- tilekit-0.1.0/.idea/vcs.xml +6 -0
- tilekit-0.1.0/.idea/workspace.xml +94 -0
- tilekit-0.1.0/PKG-INFO +212 -0
- tilekit-0.1.0/README.md +197 -0
- tilekit-0.1.0/pyproject.toml +28 -0
- tilekit-0.1.0/src/tilekit/__init__.py +1 -0
- tilekit-0.1.0/src/tilekit/downloader.py +413 -0
- tilekit-0.1.0/src/tilekit/error_info.py +3 -0
- tilekit-0.1.0/tests/test_for_downloader.py +72 -0
- tilekit-0.1.0/uv.lock +435 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="Black">
|
|
4
|
+
<option name="sdkName" value="uv (tilekit)" />
|
|
5
|
+
</component>
|
|
6
|
+
<component name="ProjectRootManager" version="2" project-jdk-name="py13" project-jdk-type="Python SDK" />
|
|
7
|
+
</project>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<module type="PYTHON_MODULE" version="4">
|
|
3
|
+
<component name="NewModuleRootManager">
|
|
4
|
+
<content url="file://$MODULE_DIR$">
|
|
5
|
+
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
|
6
|
+
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
|
7
|
+
</content>
|
|
8
|
+
<orderEntry type="jdk" jdkName="uv (tilekit)" jdkType="Python SDK" />
|
|
9
|
+
<orderEntry type="sourceFolder" forTests="false" />
|
|
10
|
+
</component>
|
|
11
|
+
</module>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="AutoImportSettings">
|
|
4
|
+
<option name="autoReloadType" value="SELECTIVE" />
|
|
5
|
+
</component>
|
|
6
|
+
<component name="ChangeListManager">
|
|
7
|
+
<list default="true" id="7ecbaad1-0830-4879-b1c9-a862886743c8" name="更改" comment="">
|
|
8
|
+
<change afterPath="$PROJECT_DIR$/.idea/.gitignore" afterDir="false" />
|
|
9
|
+
<change afterPath="$PROJECT_DIR$/.idea/inspectionProfiles/profiles_settings.xml" afterDir="false" />
|
|
10
|
+
<change afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" />
|
|
11
|
+
<change afterPath="$PROJECT_DIR$/.idea/modules.xml" afterDir="false" />
|
|
12
|
+
<change afterPath="$PROJECT_DIR$/.idea/tilekit.iml" afterDir="false" />
|
|
13
|
+
<change afterPath="$PROJECT_DIR$/.idea/vcs.xml" afterDir="false" />
|
|
14
|
+
<change afterPath="$PROJECT_DIR$/pyproject.toml" afterDir="false" />
|
|
15
|
+
</list>
|
|
16
|
+
<option name="SHOW_DIALOG" value="false" />
|
|
17
|
+
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
18
|
+
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
19
|
+
<option name="LAST_RESOLUTION" value="IGNORE" />
|
|
20
|
+
</component>
|
|
21
|
+
<component name="FileTemplateManagerImpl">
|
|
22
|
+
<option name="RECENT_TEMPLATES">
|
|
23
|
+
<list>
|
|
24
|
+
<option value="Python Script" />
|
|
25
|
+
</list>
|
|
26
|
+
</option>
|
|
27
|
+
</component>
|
|
28
|
+
<component name="Git.Settings">
|
|
29
|
+
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
|
30
|
+
</component>
|
|
31
|
+
<component name="ProjectColorInfo">{
|
|
32
|
+
"associatedIndex": 8
|
|
33
|
+
}</component>
|
|
34
|
+
<component name="ProjectId" id="368YvrMt0ewdwPXScps4FAd05Jq" />
|
|
35
|
+
<component name="ProjectLevelVcsManager">
|
|
36
|
+
<ConfirmationsSetting value="1" id="Add" />
|
|
37
|
+
</component>
|
|
38
|
+
<component name="ProjectViewState">
|
|
39
|
+
<option name="hideEmptyMiddlePackages" value="true" />
|
|
40
|
+
<option name="showLibraryContents" value="true" />
|
|
41
|
+
</component>
|
|
42
|
+
<component name="PropertiesComponent">{
|
|
43
|
+
"keyToString": {
|
|
44
|
+
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
|
45
|
+
"RunOnceActivity.ShowReadmeOnStart": "true",
|
|
46
|
+
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager": "true",
|
|
47
|
+
"RunOnceActivity.git.unshallow": "true",
|
|
48
|
+
"git-widget-placeholder": "main",
|
|
49
|
+
"last_opened_file_path": "F:/zpz/Projects3/tilekit/src/tilekit",
|
|
50
|
+
"node.js.detected.package.eslint": "true",
|
|
51
|
+
"node.js.detected.package.tslint": "true",
|
|
52
|
+
"node.js.selected.package.eslint": "(autodetect)",
|
|
53
|
+
"node.js.selected.package.tslint": "(autodetect)",
|
|
54
|
+
"nodejs_package_manager_path": "npm",
|
|
55
|
+
"settings.editor.selected.configurable": "com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable",
|
|
56
|
+
"vue.rearranger.settings.migration": "true"
|
|
57
|
+
}
|
|
58
|
+
}</component>
|
|
59
|
+
<component name="RecentsManager">
|
|
60
|
+
<key name="CopyFile.RECENT_KEYS">
|
|
61
|
+
<recent name="F:\zpz\Projects3\tilekit\src\tilekit" />
|
|
62
|
+
<recent name="F:\zpz\Projects3\tilekit\tilekit" />
|
|
63
|
+
</key>
|
|
64
|
+
<key name="MoveFile.RECENT_KEYS">
|
|
65
|
+
<recent name="F:\zpz\Projects3\tilekit\test" />
|
|
66
|
+
</key>
|
|
67
|
+
</component>
|
|
68
|
+
<component name="SharedIndexes">
|
|
69
|
+
<attachedChunks>
|
|
70
|
+
<set>
|
|
71
|
+
<option value="bundled-js-predefined-d6986cc7102b-b26f3e71634d-JavaScript-PY-251.26094.141" />
|
|
72
|
+
<option value="bundled-python-sdk-9f8e2b94138c-36ea0e71a18c-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-251.26094.141" />
|
|
73
|
+
</set>
|
|
74
|
+
</attachedChunks>
|
|
75
|
+
</component>
|
|
76
|
+
<component name="TaskManager">
|
|
77
|
+
<task active="true" id="Default" summary="默认任务">
|
|
78
|
+
<changelist id="7ecbaad1-0830-4879-b1c9-a862886743c8" name="更改" comment="" />
|
|
79
|
+
<created>1764389899006</created>
|
|
80
|
+
<option name="number" value="Default" />
|
|
81
|
+
<option name="presentableId" value="Default" />
|
|
82
|
+
<updated>1764389899006</updated>
|
|
83
|
+
<workItem from="1764389900136" duration="637000" />
|
|
84
|
+
<workItem from="1764390545007" duration="171000" />
|
|
85
|
+
<workItem from="1764390726886" duration="1651000" />
|
|
86
|
+
<workItem from="1764392460821" duration="643000" />
|
|
87
|
+
<workItem from="1764393268748" duration="2106000" />
|
|
88
|
+
</task>
|
|
89
|
+
<servers />
|
|
90
|
+
</component>
|
|
91
|
+
<component name="TypeScriptGeneratedFilesManager">
|
|
92
|
+
<option name="version" value="3" />
|
|
93
|
+
</component>
|
|
94
|
+
</project>
|
tilekit-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tilekit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: tilekit
|
|
5
|
+
Author: ZPZ
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Requires-Dist: mercantile>=1.2.1
|
|
9
|
+
Requires-Dist: numpy>=2.3.5
|
|
10
|
+
Requires-Dist: pillow>=12.0.0
|
|
11
|
+
Requires-Dist: rasterio>=1.4.3
|
|
12
|
+
Requires-Dist: requests>=2.32.5
|
|
13
|
+
Requires-Dist: tqdm>=4.67.1
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# tilekit
|
|
17
|
+
|
|
18
|
+
A lightweight toolkit for downloading **JL1 (Jilin-1)** XYZ/TMS tiles and saving them as **georeferenced GeoTIFFs**.
|
|
19
|
+
|
|
20
|
+
`tilekit` wraps the low-level HTTP requests, TMS/XYZ conversion, logging, and raster writing into a simple, high-level API based on `mercantile`, `rasterio`, and `Pillow`.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Features
|
|
25
|
+
|
|
26
|
+
- 🗺 **Bounding box download**
|
|
27
|
+
Construct tile lists from a lon/lat bounding box and zoom level.
|
|
28
|
+
|
|
29
|
+
- 📐 **Shapefile-based download**
|
|
30
|
+
Use a polygon boundary (shapefile, EPSG:4326) to determine the tile coverage.
|
|
31
|
+
|
|
32
|
+
- 🔁 **XYZ → TMS conversion**
|
|
33
|
+
Handles the JL1 API’s TMS-style Y coordinate internally, while filenames remain in standard XYZ.
|
|
34
|
+
|
|
35
|
+
- ⏸ **Resume support / precheck**
|
|
36
|
+
Skips tiles that already exist on disk (`z/x/y.tif`) to avoid duplicate downloads.
|
|
37
|
+
|
|
38
|
+
- 🧍 **Human-like throttling**
|
|
39
|
+
Randomized delays between requests to mimic human behavior and reduce the risk of rate limiting.
|
|
40
|
+
|
|
41
|
+
- 🧾 **Structured logging**
|
|
42
|
+
Logs progress and errors both to console and to `download.log` in the output folder.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Installation
|
|
47
|
+
|
|
48
|
+
Once published on PyPI:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install tilekit
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
## Getting Started
|
|
57
|
+
|
|
58
|
+
### 1. Download tiles by lon/lat bounding box
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
from tilekit.downloader import TileDownloader
|
|
62
|
+
|
|
63
|
+
min_lon = 114.98
|
|
64
|
+
max_lon = 117.20
|
|
65
|
+
min_lat = 38.69
|
|
66
|
+
max_lat = 41.18
|
|
67
|
+
zoom = 18
|
|
68
|
+
|
|
69
|
+
# JL1 API keys (replace with your own)
|
|
70
|
+
mk = "your_mk_token_here"
|
|
71
|
+
tk = "your_tk_token_here"
|
|
72
|
+
|
|
73
|
+
downloader = TileDownloader.from_lon_lat(
|
|
74
|
+
min_lat=min_lat,
|
|
75
|
+
max_lat=max_lat,
|
|
76
|
+
min_lon=min_lon,
|
|
77
|
+
max_lon=max_lon,
|
|
78
|
+
zoom=zoom,
|
|
79
|
+
mk=mk,
|
|
80
|
+
tk=tk,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
print("Total tiles to download:", len(downloader.tile_list))
|
|
84
|
+
|
|
85
|
+
downloader.download_tiles(
|
|
86
|
+
output_folder=r"F:\xxx\JL1Tiles",
|
|
87
|
+
verbose_debug=False,
|
|
88
|
+
)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
This will:
|
|
92
|
+
|
|
93
|
+
- Compute all tiles covering the bounding box at zoom level 18
|
|
94
|
+
- Convert XYZ Y to JL1’s TMS convention internally
|
|
95
|
+
- Download each tile and save it as `z/x/y.tif` with proper georeferencing
|
|
96
|
+
|
|
97
|
+
------
|
|
98
|
+
|
|
99
|
+
### 2. Download tiles based on a shapefile boundary
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
from tilekit.downloader import TileDownloader
|
|
103
|
+
|
|
104
|
+
zoom = 18
|
|
105
|
+
mk = "your_mk_token_here"
|
|
106
|
+
tk = "your_tk_token_here"
|
|
107
|
+
|
|
108
|
+
# Shapefile should be in EPSG:4326 (lon/lat)
|
|
109
|
+
shp_path = r"beijing.shp"
|
|
110
|
+
|
|
111
|
+
downloader = TileDownloader.from_shp(
|
|
112
|
+
shp_path=shp_path,
|
|
113
|
+
zoom=zoom,
|
|
114
|
+
mk=mk,
|
|
115
|
+
tk=tk,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
print("Total tiles to download:", len(downloader.tile_list))
|
|
119
|
+
|
|
120
|
+
downloader.download_tiles(
|
|
121
|
+
output_folder=r"F:\xxx\JL1Tiles",
|
|
122
|
+
verbose_debug=False,
|
|
123
|
+
)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`from_shp` will:
|
|
127
|
+
|
|
128
|
+
- Read the shapefile using `geopandas`
|
|
129
|
+
- Reproject to EPSG:4326 if necessary
|
|
130
|
+
- Use the overall bounding box (`total_bounds`) to determine the tile range
|
|
131
|
+
|
|
132
|
+
> Note: `geopandas` is only required if you use `from_shp`.
|
|
133
|
+
> You can install it via `pip install geopandas`.
|
|
134
|
+
|
|
135
|
+
------
|
|
136
|
+
|
|
137
|
+
## API Overview
|
|
138
|
+
|
|
139
|
+
### `TileDownloader`
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
@dataclass
|
|
143
|
+
class TileDownloader:
|
|
144
|
+
tile_list: Sequence[mercantile.Tile]
|
|
145
|
+
mk: str = "..."
|
|
146
|
+
tk: str = "..."
|
|
147
|
+
zoom: Optional[int] = None
|
|
148
|
+
|
|
149
|
+
def download_tiles(
|
|
150
|
+
self,
|
|
151
|
+
output_folder: Union[str, Path],
|
|
152
|
+
tile_list: Optional[Sequence[Tile]] = None,
|
|
153
|
+
verbose_debug: bool = False,
|
|
154
|
+
) -> None:
|
|
155
|
+
...
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Key methods:**
|
|
159
|
+
|
|
160
|
+
- `TileDownloader.from_lon_lat(min_lat, max_lat, min_lon, max_lon, zoom, mk, tk)`
|
|
161
|
+
Build a downloader from a bounding box.
|
|
162
|
+
- `TileDownloader.from_shp(shp_path, zoom, mk, tk)`
|
|
163
|
+
Build a downloader from a shapefile boundary.
|
|
164
|
+
- `TileDownloader.from_XYZs(tiles, mk, tk)`
|
|
165
|
+
Build a downloader from an existing list of `mercantile.Tile` objects (all at the same zoom level).
|
|
166
|
+
- `TileDownloader.download_tiles(output_folder, tile_list=None, verbose_debug=False)`
|
|
167
|
+
Download all tiles and save as GeoTIFF files (`z/x/y.tif`), skipping files that already exist.
|
|
168
|
+
|
|
169
|
+
------
|
|
170
|
+
|
|
171
|
+
## Output Format
|
|
172
|
+
|
|
173
|
+
Each downloaded tile is saved as a **multi-band GeoTIFF**:
|
|
174
|
+
|
|
175
|
+
- Filename: `output_folder/z/x/y.tif`
|
|
176
|
+
- Coordinate reference system: `EPSG:4326`
|
|
177
|
+
- Transform: computed from the tile’s geographic bounds via `rasterio.transform.from_bounds`
|
|
178
|
+
- Compression: LZW (`Compression.lzw`)
|
|
179
|
+
- Bands: derived from the source image (e.g., RGB → 3 bands)
|
|
180
|
+
|
|
181
|
+
------
|
|
182
|
+
|
|
183
|
+
## Requirements
|
|
184
|
+
|
|
185
|
+
Core dependencies (installed automatically when you install `tilekit`):
|
|
186
|
+
|
|
187
|
+
- `mercantile`
|
|
188
|
+
- `rasterio`
|
|
189
|
+
- `numpy`
|
|
190
|
+
- `requests`
|
|
191
|
+
- `Pillow`
|
|
192
|
+
- `tqdm`
|
|
193
|
+
|
|
194
|
+
Optional (for shapefile-based workflows):
|
|
195
|
+
|
|
196
|
+
- `geopandas`
|
|
197
|
+
|
|
198
|
+
------
|
|
199
|
+
|
|
200
|
+
## Notes
|
|
201
|
+
|
|
202
|
+
- You must provide valid **JL1 API keys** (`mk`, `tk`) to access the tile service.
|
|
203
|
+
The examples in this README use placeholder values; please replace them with your own.
|
|
204
|
+
- The downloader includes:
|
|
205
|
+
- A precheck step that skips already downloaded tiles
|
|
206
|
+
- Randomized delays between requests via `human_delay` to reduce the risk of being rate-limited
|
|
207
|
+
|
|
208
|
+
------
|
|
209
|
+
|
|
210
|
+
## License
|
|
211
|
+
|
|
212
|
+
`tilekit` is released under the **Apache 2.0** License.
|
tilekit-0.1.0/README.md
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# tilekit
|
|
2
|
+
|
|
3
|
+
A lightweight toolkit for downloading **JL1 (Jilin-1)** XYZ/TMS tiles and saving them as **georeferenced GeoTIFFs**.
|
|
4
|
+
|
|
5
|
+
`tilekit` wraps the low-level HTTP requests, TMS/XYZ conversion, logging, and raster writing into a simple, high-level API based on `mercantile`, `rasterio`, and `Pillow`.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- 🗺 **Bounding box download**
|
|
12
|
+
Construct tile lists from a lon/lat bounding box and zoom level.
|
|
13
|
+
|
|
14
|
+
- 📐 **Shapefile-based download**
|
|
15
|
+
Use a polygon boundary (shapefile, EPSG:4326) to determine the tile coverage.
|
|
16
|
+
|
|
17
|
+
- 🔁 **XYZ → TMS conversion**
|
|
18
|
+
Handles the JL1 API’s TMS-style Y coordinate internally, while filenames remain in standard XYZ.
|
|
19
|
+
|
|
20
|
+
- ⏸ **Resume support / precheck**
|
|
21
|
+
Skips tiles that already exist on disk (`z/x/y.tif`) to avoid duplicate downloads.
|
|
22
|
+
|
|
23
|
+
- 🧍 **Human-like throttling**
|
|
24
|
+
Randomized delays between requests to mimic human behavior and reduce the risk of rate limiting.
|
|
25
|
+
|
|
26
|
+
- 🧾 **Structured logging**
|
|
27
|
+
Logs progress and errors both to console and to `download.log` in the output folder.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
Once published on PyPI:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install tilekit
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
## Getting Started
|
|
42
|
+
|
|
43
|
+
### 1. Download tiles by lon/lat bounding box
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
from tilekit.downloader import TileDownloader
|
|
47
|
+
|
|
48
|
+
min_lon = 114.98
|
|
49
|
+
max_lon = 117.20
|
|
50
|
+
min_lat = 38.69
|
|
51
|
+
max_lat = 41.18
|
|
52
|
+
zoom = 18
|
|
53
|
+
|
|
54
|
+
# JL1 API keys (replace with your own)
|
|
55
|
+
mk = "your_mk_token_here"
|
|
56
|
+
tk = "your_tk_token_here"
|
|
57
|
+
|
|
58
|
+
downloader = TileDownloader.from_lon_lat(
|
|
59
|
+
min_lat=min_lat,
|
|
60
|
+
max_lat=max_lat,
|
|
61
|
+
min_lon=min_lon,
|
|
62
|
+
max_lon=max_lon,
|
|
63
|
+
zoom=zoom,
|
|
64
|
+
mk=mk,
|
|
65
|
+
tk=tk,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
print("Total tiles to download:", len(downloader.tile_list))
|
|
69
|
+
|
|
70
|
+
downloader.download_tiles(
|
|
71
|
+
output_folder=r"F:\xxx\JL1Tiles",
|
|
72
|
+
verbose_debug=False,
|
|
73
|
+
)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
This will:
|
|
77
|
+
|
|
78
|
+
- Compute all tiles covering the bounding box at zoom level 18
|
|
79
|
+
- Convert XYZ Y to JL1’s TMS convention internally
|
|
80
|
+
- Download each tile and save it as `z/x/y.tif` with proper georeferencing
|
|
81
|
+
|
|
82
|
+
------
|
|
83
|
+
|
|
84
|
+
### 2. Download tiles based on a shapefile boundary
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
from tilekit.downloader import TileDownloader
|
|
88
|
+
|
|
89
|
+
zoom = 18
|
|
90
|
+
mk = "your_mk_token_here"
|
|
91
|
+
tk = "your_tk_token_here"
|
|
92
|
+
|
|
93
|
+
# Shapefile should be in EPSG:4326 (lon/lat)
|
|
94
|
+
shp_path = r"beijing.shp"
|
|
95
|
+
|
|
96
|
+
downloader = TileDownloader.from_shp(
|
|
97
|
+
shp_path=shp_path,
|
|
98
|
+
zoom=zoom,
|
|
99
|
+
mk=mk,
|
|
100
|
+
tk=tk,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
print("Total tiles to download:", len(downloader.tile_list))
|
|
104
|
+
|
|
105
|
+
downloader.download_tiles(
|
|
106
|
+
output_folder=r"F:\xxx\JL1Tiles",
|
|
107
|
+
verbose_debug=False,
|
|
108
|
+
)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`from_shp` will:
|
|
112
|
+
|
|
113
|
+
- Read the shapefile using `geopandas`
|
|
114
|
+
- Reproject to EPSG:4326 if necessary
|
|
115
|
+
- Use the overall bounding box (`total_bounds`) to determine the tile range
|
|
116
|
+
|
|
117
|
+
> Note: `geopandas` is only required if you use `from_shp`.
|
|
118
|
+
> You can install it via `pip install geopandas`.
|
|
119
|
+
|
|
120
|
+
------
|
|
121
|
+
|
|
122
|
+
## API Overview
|
|
123
|
+
|
|
124
|
+
### `TileDownloader`
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
@dataclass
|
|
128
|
+
class TileDownloader:
|
|
129
|
+
tile_list: Sequence[mercantile.Tile]
|
|
130
|
+
mk: str = "..."
|
|
131
|
+
tk: str = "..."
|
|
132
|
+
zoom: Optional[int] = None
|
|
133
|
+
|
|
134
|
+
def download_tiles(
|
|
135
|
+
self,
|
|
136
|
+
output_folder: Union[str, Path],
|
|
137
|
+
tile_list: Optional[Sequence[Tile]] = None,
|
|
138
|
+
verbose_debug: bool = False,
|
|
139
|
+
) -> None:
|
|
140
|
+
...
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Key methods:**
|
|
144
|
+
|
|
145
|
+
- `TileDownloader.from_lon_lat(min_lat, max_lat, min_lon, max_lon, zoom, mk, tk)`
|
|
146
|
+
Build a downloader from a bounding box.
|
|
147
|
+
- `TileDownloader.from_shp(shp_path, zoom, mk, tk)`
|
|
148
|
+
Build a downloader from a shapefile boundary.
|
|
149
|
+
- `TileDownloader.from_XYZs(tiles, mk, tk)`
|
|
150
|
+
Build a downloader from an existing list of `mercantile.Tile` objects (all at the same zoom level).
|
|
151
|
+
- `TileDownloader.download_tiles(output_folder, tile_list=None, verbose_debug=False)`
|
|
152
|
+
Download all tiles and save as GeoTIFF files (`z/x/y.tif`), skipping files that already exist.
|
|
153
|
+
|
|
154
|
+
------
|
|
155
|
+
|
|
156
|
+
## Output Format
|
|
157
|
+
|
|
158
|
+
Each downloaded tile is saved as a **multi-band GeoTIFF**:
|
|
159
|
+
|
|
160
|
+
- Filename: `output_folder/z/x/y.tif`
|
|
161
|
+
- Coordinate reference system: `EPSG:4326`
|
|
162
|
+
- Transform: computed from the tile’s geographic bounds via `rasterio.transform.from_bounds`
|
|
163
|
+
- Compression: LZW (`Compression.lzw`)
|
|
164
|
+
- Bands: derived from the source image (e.g., RGB → 3 bands)
|
|
165
|
+
|
|
166
|
+
------
|
|
167
|
+
|
|
168
|
+
## Requirements
|
|
169
|
+
|
|
170
|
+
Core dependencies (installed automatically when you install `tilekit`):
|
|
171
|
+
|
|
172
|
+
- `mercantile`
|
|
173
|
+
- `rasterio`
|
|
174
|
+
- `numpy`
|
|
175
|
+
- `requests`
|
|
176
|
+
- `Pillow`
|
|
177
|
+
- `tqdm`
|
|
178
|
+
|
|
179
|
+
Optional (for shapefile-based workflows):
|
|
180
|
+
|
|
181
|
+
- `geopandas`
|
|
182
|
+
|
|
183
|
+
------
|
|
184
|
+
|
|
185
|
+
## Notes
|
|
186
|
+
|
|
187
|
+
- You must provide valid **JL1 API keys** (`mk`, `tk`) to access the tile service.
|
|
188
|
+
The examples in this README use placeholder values; please replace them with your own.
|
|
189
|
+
- The downloader includes:
|
|
190
|
+
- A precheck step that skips already downloaded tiles
|
|
191
|
+
- Randomized delays between requests via `human_delay` to reduce the risk of being rate-limited
|
|
192
|
+
|
|
193
|
+
------
|
|
194
|
+
|
|
195
|
+
## License
|
|
196
|
+
|
|
197
|
+
`tilekit` is released under the **Apache 2.0** License.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "tilekit"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "tilekit"
|
|
5
|
+
license = { text = "Apache-2.0" }
|
|
6
|
+
readme = { file = "README.md", content-type = "text/markdown" }
|
|
7
|
+
requires-python = ">=3.11"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "ZPZ" }
|
|
10
|
+
]
|
|
11
|
+
dependencies = [
|
|
12
|
+
"mercantile>=1.2.1",
|
|
13
|
+
"numpy>=2.3.5",
|
|
14
|
+
"pillow>=12.0.0",
|
|
15
|
+
"rasterio>=1.4.3",
|
|
16
|
+
"requests>=2.32.5",
|
|
17
|
+
"tqdm>=4.67.1",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
[build-system]
|
|
21
|
+
requires = ["hatchling"]
|
|
22
|
+
build-backend = "hatchling.build"
|
|
23
|
+
|
|
24
|
+
# [tool.uv]
|
|
25
|
+
# package-dir = "src"
|
|
26
|
+
|
|
27
|
+
# [tool.hatch.build.targets.wheel]
|
|
28
|
+
# packages = ["src/foo"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .downloader import TileDownloader
|