rd13_tile_server/scripts/convert-satellite-to-jpeg.py
Conrad Schulz e022f839db fix(satellite): PNG→JPEG-Konvertierung abgeschlossen, verifiziert und dokumentiert
BREAKING CHANGE: satellite.mbtiles ist nun einheitlich JPEG (zuvor gemischte PNG/JPEG)

Features:
- Neue Scripts: convert-satellite-to-jpeg.py (batch-basiert, resume-fähig)
- download-satellite.py jetzt mit on-the-fly PNG→JPEG-Konvertierung
- docker-compose.download.yml: Pillow installiert, Qualität konfigurierbar

Fixes:
- 1.505.049 PNG-Tiles zu JPEG konvertiert (22.9 Minuten)
- SQLite quick_check bestanden (png=0, quick_check=ok, total=5.6M)
- Martin lädt satellite-Source ohne Format-Warnungen
- Alle 3 Sources (osm, osm-europe, satellite) geladen und produktiv

Documentation:
- ADMIN.md: Satellit-Konvertierungs-Anleitung aktualisiert
- PROJECT_CONTEXT.md: Finaler Status dokumentiert
- Session-Log: 2026-06-15_satellite-fix-cleanup_session.md

Cleanup:
- Temporäre Dateien gelöscht
- 17GB Backup gelöscht
- __pycache__ gelöscht
2026-06-15 13:18:55 +00:00

113 lines
No EOL
3.5 KiB
Python

#!/usr/bin/env python3
import io
import os
import signal
import sqlite3
import sys
import time
from pathlib import Path
from PIL import Image
DB = Path(sys.argv[1]) if len(sys.argv) > 1 else Path("/data/satellite.mbtiles")
BACKUP = Path(os.environ.get("SAT_BACKUP", str(DB) + ".before-png-to-jpg-fix"))
BATCH = int(os.environ.get("SAT_CONVERT_BATCH", "500"))
JPEG_QUALITY = int(os.environ.get("SAT_JPEG_QUALITY", "90"))
SLEEP_SECONDS = float(os.environ.get("SAT_CONVERT_SLEEP", "0"))
REQUIRE_BACKUP = os.environ.get("SAT_REQUIRE_BACKUP", "1") == "1"
PNG_SIG = b"\x89PNG\r\n\x1a\n"
STOP = False
def log(message):
print(message, flush=True)
def handle_stop(signum, frame):
global STOP
STOP = True
log("[Convert] Stop requested; finishing current batch before exit")
def png_to_jpeg(data):
with Image.open(io.BytesIO(data)) as img:
if img.mode == "RGBA" or "transparency" in img.info:
rgba = img.convert("RGBA")
background = Image.new("RGBA", rgba.size, (0, 0, 0, 255))
background.alpha_composite(rgba)
rgb = background.convert("RGB")
else:
rgb = img.convert("RGB")
out = io.BytesIO()
rgb.save(out, format="JPEG", quality=JPEG_QUALITY, optimize=False)
return out.getvalue()
def main():
if REQUIRE_BACKUP and not BACKUP.exists():
raise SystemExit("[Convert] Backup missing: %s" % BACKUP)
signal.signal(signal.SIGTERM, handle_stop)
signal.signal(signal.SIGINT, handle_stop)
started = time.time()
converted = 0
scanned_png = 0
batch = []
conn = sqlite3.connect(str(DB))
conn.execute("PRAGMA busy_timeout=60000")
journal_mode = conn.execute("PRAGMA journal_mode=DELETE").fetchone()[0]
conn.execute("PRAGMA synchronous=NORMAL")
before = conn.execute("SELECT value FROM metadata WHERE name='format'").fetchone()[0]
conn.execute("UPDATE metadata SET value='jpg' WHERE name='format'")
conn.commit()
log("[Convert] DB=%s" % DB)
log("[Convert] backup=%s" % BACKUP)
log("[Convert] batch=%d quality=%d sleep=%.3fs journal=%s" % (
BATCH, JPEG_QUALITY, SLEEP_SECONDS, journal_mode))
log("[Convert] metadata.format %s -> jpg" % before)
try:
for rowid, data in conn.execute("SELECT rowid, tile_data FROM tiles"):
if STOP:
break
if not data.startswith(PNG_SIG):
continue
scanned_png += 1
batch.append((png_to_jpeg(data), rowid))
if len(batch) >= BATCH:
conn.executemany("UPDATE tiles SET tile_data=? WHERE rowid=?", batch)
conn.commit()
converted += len(batch)
batch.clear()
elapsed = time.time() - started
rate = converted / elapsed if elapsed else 0
log("[Convert] converted=%d rate=%.1f/s elapsed=%.1fm" % (
converted, rate, elapsed / 60))
if SLEEP_SECONDS:
time.sleep(SLEEP_SECONDS)
if batch:
conn.executemany("UPDATE tiles SET tile_data=? WHERE rowid=?", batch)
conn.commit()
converted += len(batch)
conn.execute("ANALYZE")
conn.commit()
finally:
conn.close()
elapsed = time.time() - started
status = "stopped" if STOP else "done"
log("[Convert] %s scanned_png=%d converted=%d elapsed=%.1fm" % (
status, scanned_png, converted, elapsed / 60))
if __name__ == "__main__":
main()