Coverage for src/cstlcore/maps/services.py: 94%
51 statements
« prev ^ index » next coverage.py v7.9.1, created at 2026-02-19 12:46 +0000
« prev ^ index » next coverage.py v7.9.1, created at 2026-02-19 12:46 +0000
1import math
2import os
3import shutil
4import tempfile
5import uuid
6from pathlib import Path
8from fastapi import UploadFile
9from PIL import Image
11from cstlcore.settings import settings
14def generate_leaflet_tiles(
15 image_path, output_dir, tile_size=256, min_zoom=0, max_zoom=4
16):
17 with Image.open(image_path) as image:
18 if image.mode not in ("RGBA", "RGB"):
19 image = image.convert("RGBA")
20 image_width, image_height = image.size
22 for zoom in range(min_zoom, max_zoom + 1):
23 scale = 2**zoom
24 scaled_width = tile_size * scale
25 scaled_height = int(image_height * (scaled_width / image_width))
27 zoom_image = image.resize(
28 (scaled_width, scaled_height), Image.Resampling.LANCZOS
29 )
31 pad_width = math.ceil(scaled_width / tile_size) * tile_size
32 pad_height = math.ceil(scaled_height / tile_size) * tile_size
34 padded_image = Image.new("RGBA", (pad_width, pad_height), (0, 0, 0, 0))
35 padded_image.paste(zoom_image, (0, 0))
37 x_tiles = pad_width // tile_size
38 y_tiles = pad_height // tile_size
40 for x in range(x_tiles):
41 for y in range(y_tiles):
42 left = x * tile_size
43 upper = y * tile_size
44 right = left + tile_size
45 lower = upper + tile_size
47 tile = padded_image.crop((left, upper, right, lower))
49 tile_dir = os.path.join(output_dir, str(zoom), str(x))
50 os.makedirs(tile_dir, exist_ok=True)
51 tile_path = os.path.join(tile_dir, f"{y}.png")
52 tile.save(tile_path)
55def verify_and_store_map(uploaded_file: UploadFile, map_id: uuid.UUID):
56 with tempfile.TemporaryDirectory() as tmpdir:
57 tmp_path = Path(tmpdir)
58 uploaded_file_path = tmp_path / f"{uploaded_file.filename}"
59 uploaded_file_path.parent.mkdir(parents=True, exist_ok=True)
60 with uploaded_file_path.open("wb") as f:
61 shutil.copyfileobj(uploaded_file.file, f)
63 # verify if the uploaded file is an image
64 try:
65 with Image.open(uploaded_file_path) as img:
66 img.verify() # Verify that it is an image
67 except (IOError, SyntaxError) as e:
68 raise ValueError(f"Uploaded file is not a valid image: {e}")
70 # Generate tiles
71 output_dir = settings.fs.map_directory / f"{map_id}"
72 output_dir.mkdir(parents=True, exist_ok=True)
73 generate_leaflet_tiles(
74 image_path=uploaded_file_path,
75 output_dir=output_dir,
76 tile_size=256,
77 min_zoom=0,
78 max_zoom=5,
79 )