#!/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_metadata(mbtiles): """Legge metadata e tile info 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("SELECT name, value FROM metadata;") metadata = dict(cur.fetchall()) conn.close() return tile_count, minzoom, maxzoom, metadata def main(): if len(sys.argv) != 3: print("Uso: python3 verify_mbtiles_metadata.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 metadata MBTiles ==") # 1) Bounds dal TIFF minlon, minlat, maxlon, maxlat = read_gdal_bounds(raster) print(f"Bounds TIFF: {minlon},{minlat},{maxlon},{maxlat}") # 2) Lettura MBTiles tile_count, minzoom, maxzoom, metadata = read_mbtiles_metadata(mbtiles) print(f"Tile count: {tile_count}") print(f"Zoom effettivi: {minzoom}..{maxzoom}") # 3) Confronto bounds mb_bounds = metadata.get("bounds", None) if mb_bounds: mb_minlon, mb_minlat, mb_maxlon, mb_maxlat = map(float, mb_bounds.split(",")) print(f"Bounds MBTiles: {mb_bounds}") if abs(mb_minlon - minlon) < 1e-4 and \ abs(mb_minlat - minlat) < 1e-4 and \ abs(mb_maxlon - maxlon) < 1e-4 and \ abs(mb_maxlat - maxlat) < 1e-4: print("✔ Bounds OK") else: print("✘ Bounds NON corrispondono al TIFF") else: print("✘ Metadata 'bounds' mancante") # 4) Confronto minzoom/maxzoom if "minzoom" in metadata and "maxzoom" in metadata: mz = int(metadata["minzoom"]) xz = int(metadata["maxzoom"]) if mz == minzoom and xz == maxzoom: print("✔ minzoom/maxzoom OK") else: print(f"✘ minzoom/maxzoom NON coerenti: metadata={mz}..{xz}, reali={minzoom}..{maxzoom}") else: print("✘ Metadata minzoom/maxzoom mancanti") # 5) Center if "center" in metadata: print(f"Center: {metadata['center']}") else: print("✘ Metadata 'center' mancante") print("\n== Verifica completata ==") if __name__ == "__main__": main()