tilekit 0.1.0
tilekit
License: Apache-2.0
Requires Python: >=3.11

# tilekit

A lightweight toolkit for downloading **JL1 (Jilin-1)** XYZ/TMS tiles and saving them as **georeferenced GeoTIFFs**.

`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`.

---

## Features

- 🗺 **Bounding box download**  
  Construct tile lists from a lon/lat bounding box and zoom level.

- 📐 **Shapefile-based download**  
  Use a polygon boundary (shapefile, EPSG:4326) to determine the tile coverage.

- 🔁 **XYZ → TMS conversion**  
  Handles the JL1 API’s TMS-style Y coordinate internally, while filenames remain in standard XYZ.

- ⏸ **Resume support / precheck**  
  Skips tiles that already exist on disk (`z/x/y.tif`) to avoid duplicate downloads.

- 🧍 **Human-like throttling**  
  Randomized delays between requests to mimic human behavior and reduce the risk of rate limiting.

- 🧾 **Structured logging**  
  Logs progress and errors both to console and to `download.log` in the output folder.

---

## Installation

Once published on PyPI:

```bash
pip install tilekit
```



## Getting Started

### 1. Download tiles by lon/lat bounding box

```
from tilekit.downloader import TileDownloader

min_lon = 114.98
max_lon = 117.20
min_lat = 38.69
max_lat = 41.18
zoom = 18

# JL1 API keys (replace with your own)
mk = "your_mk_token_here"
tk = "your_tk_token_here"

downloader = TileDownloader.from_lon_lat(
    min_lat=min_lat,
    max_lat=max_lat,
    min_lon=min_lon,
    max_lon=max_lon,
    zoom=zoom,
    mk=mk,
    tk=tk,
)

print("Total tiles to download:", len(downloader.tile_list))

downloader.download_tiles(
    output_folder=r"F:\xxx\JL1Tiles",
    verbose_debug=False,
)
```

This will:

- Compute all tiles covering the bounding box at zoom level 18
- Convert XYZ Y to JL1’s TMS convention internally
- Download each tile and save it as `z/x/y.tif` with proper georeferencing

------

### 2. Download tiles based on a shapefile boundary

```
from tilekit.downloader import TileDownloader

zoom = 18
mk = "your_mk_token_here"
tk = "your_tk_token_here"

# Shapefile should be in EPSG:4326 (lon/lat)
shp_path = r"beijing.shp"

downloader = TileDownloader.from_shp(
    shp_path=shp_path,
    zoom=zoom,
    mk=mk,
    tk=tk,
)

print("Total tiles to download:", len(downloader.tile_list))

downloader.download_tiles(
    output_folder=r"F:\xxx\JL1Tiles",
    verbose_debug=False,
)
```

`from_shp` will:

- Read the shapefile using `geopandas`
- Reproject to EPSG:4326 if necessary
- Use the overall bounding box (`total_bounds`) to determine the tile range

> Note: `geopandas` is only required if you use `from_shp`.
>  You can install it via `pip install geopandas`.

------

## API Overview

### `TileDownloader`

```
@dataclass
class TileDownloader:
    tile_list: Sequence[mercantile.Tile]
    mk: str = "..."
    tk: str = "..."
    zoom: Optional[int] = None

    def download_tiles(
        self,
        output_folder: Union[str, Path],
        tile_list: Optional[Sequence[Tile]] = None,
        verbose_debug: bool = False,
    ) -> None:
        ...
```

**Key methods:**

- `TileDownloader.from_lon_lat(min_lat, max_lat, min_lon, max_lon, zoom, mk, tk)`
   Build a downloader from a bounding box.
- `TileDownloader.from_shp(shp_path, zoom, mk, tk)`
   Build a downloader from a shapefile boundary.
- `TileDownloader.from_XYZs(tiles, mk, tk)`
   Build a downloader from an existing list of `mercantile.Tile` objects (all at the same zoom level).
- `TileDownloader.download_tiles(output_folder, tile_list=None, verbose_debug=False)`
   Download all tiles and save as GeoTIFF files (`z/x/y.tif`), skipping files that already exist.

------

## Output Format

Each downloaded tile is saved as a **multi-band GeoTIFF**:

- Filename: `output_folder/z/x/y.tif`
- Coordinate reference system: `EPSG:4326`
- Transform: computed from the tile’s geographic bounds via `rasterio.transform.from_bounds`
- Compression: LZW (`Compression.lzw`)
- Bands: derived from the source image (e.g., RGB → 3 bands)

------

## Requirements

Core dependencies (installed automatically when you install `tilekit`):

- `mercantile`
- `rasterio`
- `numpy`
- `requests`
- `Pillow`
- `tqdm`

Optional (for shapefile-based workflows):

- `geopandas`

------

## Notes

- You must provide valid **JL1 API keys** (`mk`, `tk`) to access the tile service.
   The examples in this README use placeholder values; please replace them with your own.
- The downloader includes:
  - A precheck step that skips already downloaded tiles
  - Randomized delays between requests via `human_delay` to reduce the risk of being rate-limited

------

## License

`tilekit` is released under the **Apache 2.0** License.