#!/usr/bin/env python3 import sqlite3 import json import subprocess import sys from pathlib import Path def read_gdal_bounds(raster): """Legge i bounds WGS84 dal TIFF usando gdalinfo -json.""" info = subprocess.check_output(["gdalinfo", "-json", raster]) info = json.loads(info) if "wgs84Extent" in info: coords = info["wgs84Extent"]["coordinates"][0] minlon, minlat = coords[0] maxlon, maxlat = coords[2] else: cc = info["cornerCoordinates"] minlon, minlat = cc["lowerLeft"] maxlon, maxlat = cc["upperRight"] # Normalizzazione latitudine if minlat > maxlat: minlat, maxlat = maxlat, minlat return (minlon, minlat, maxlon, maxlat) def read_mbtiles(mbtiles): """Legge tile info e metadata da un MBTiles.""" conn = sqlite3.connect(mbtiles) cur = conn.cursor() # Verifica tabella tiles cur.execute("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='tiles';") if cur.fetchone()[0] == 0: raise RuntimeError("La tabella 'tiles' non esiste nell'MBTiles.") # Conta tile cur.execute("SELECT COUNT(*) FROM tiles;") tile_count = cur.fetchone()[0] if tile_count == 0: raise RuntimeError("La tabella 'tiles' è vuota.") # Zoom min/max cur.execute("SELECT MIN(zoom_level), MAX(zoom_level) FROM tiles;") minzoom, maxzoom = cur.fetchone() # Metadata cur.execute("CREATE TABLE IF NOT EXISTS metadata (name TEXT PRIMARY KEY, value TEXT);") cur.execute("SELECT name, value FROM metadata;") metadata = dict(cur.fetchall()) return conn, cur, tile_count, minzoom, maxzoom, metadata def write_metadata(cur, name, value): cur.execute("REPLACE INTO metadata (name, value) VALUES (?, ?)", (name, value)) def main(): if len(sys.argv) != 3: print("Uso: python3 verify_and_fix_mbtiles.py ") sys.exit(1) raster = Path(sys.argv[1]) mbtiles = Path(sys.argv[2]) if not raster.exists(): print(f"Raster non trovato: {raster}") sys.exit(1) if not mbtiles.exists(): print(f"MBTiles non trovato: {mbtiles}") sys.exit(1) print("== Verifica e correzione metadata MBTiles ==") # 1) Bounds dal TIFF minlon, minlat, maxlon, maxlat = read_gdal_bounds(raster) expected_bounds = f"{minlon:.6f},{minlat:.6f},{maxlon:.6f},{maxlat:.6f}" print(f"Bounds TIFF: {expected_bounds}") # 2) Lettura MBTiles conn, cur, tile_count, minzoom, maxzoom, metadata = read_mbtiles(mbtiles) print(f"Tile count: {tile_count}") print(f"Zoom effettivi: {minzoom}..{maxzoom}") # 3) Verifica/correzione bounds mb_bounds = metadata.get("bounds") if mb_bounds != expected_bounds: print(f"✘ Bounds NON corretti → FIX") write_metadata(cur, "bounds", expected_bounds) else: print("✔ Bounds OK") # 4) Verifica/correzione minzoom/maxzoom mz = int(metadata.get("minzoom", -1)) xz = int(metadata.get("maxzoom", -1)) if mz != minzoom or xz != maxzoom: print(f"✘ minzoom/maxzoom NON coerenti → FIX") write_metadata(cur, "minzoom", str(minzoom)) write_metadata(cur, "maxzoom", str(maxzoom)) else: print("✔ minzoom/maxzoom OK") # 5) Verifica/correzione center ctr_lon = (minlon + maxlon) / 2 ctr_lat = (minlat + maxlat) / 2 ctr_zoom = (minzoom + maxzoom) // 2 expected_center = f"{ctr_lon:.6f},{ctr_lat:.6f},{ctr_zoom}" if metadata.get("center") != expected_center: print(f"✘ Center NON corretto → FIX") write_metadata(cur, "center", expected_center) else: print("✔ Center OK") # 6) Verifica/correzione format if metadata.get("format") != "png": print("✘ Format NON corretto → FIX") write_metadata(cur, "format", "png") else: print("✔ Format OK") # 7) Verifica/correzione scheme if metadata.get("scheme") != "xyz": print("✘ Scheme NON corretto → FIX") write_metadata(cur, "scheme", "xyz") else: print("✔ Scheme OK") # 8) Commit conn.commit() conn.close() print("\n== Correzione completata ==") print("MBTiles ora ha metadata coerenti e validi.") if __name__ == "__main__": main()