File: /home/panomity.de/vr.panomity.com/api/depth-generate.php
<?php
/**
* DepthAnything V2 Proxy – erzeugt Depthmap über den Depth-Server (plano)
* Erwartet POST { pano_id: int, encoder?: 'vitl'|'vitb'|'vits', grayscale?: 1|0 }
* Speichert dmap.png in panos/p{ID}.tiles und setzt depthmap_visible=1.
*/
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
header('Content-Type: application/json');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); echo json_encode(['error' => 'Method not allowed']); exit; }
$dbPath = __DIR__ . '/../admin/data/vrm.db';
if (!file_exists($dbPath)) { http_response_code(500); echo json_encode(['error' => 'Database not found']); exit; }
$db = new SQLite3($dbPath);
$db->busyTimeout(5000);
$input = file_get_contents('php://input');
$data = json_decode($input, true);
$panoId = isset($data['pano_id']) ? (int)$data['pano_id'] : 0;
$encoder = isset($data['encoder']) ? $data['encoder'] : 'vitl';
$grayscale = isset($data['grayscale']) ? (int)$data['grayscale'] : 0;
$inputSize = isset($data['input_size']) ? (int)$data['input_size'] : 1024;
if ($panoId <= 0) { http_response_code(400); echo json_encode(['error' => 'Invalid pano_id']); exit; }
// Bild-URL ermitteln (öffentlich erreichbar)
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
$host = $_SERVER['HTTP_HOST'] ?? 'localhost';
$base = $scheme . '://' . $host;
$imageCandidates = [
// Bevorzugt bereits rekonstruierte Equirect
$base . '/panos/p' . $panoId . '.tiles/equirect.jpg',
// Versuche zuerst potentielles Original (falls beibehalten)
$base . '/p' . $panoId . '.jpg',
$base . '/p' . $panoId . '.jpeg',
$base . '/p' . $panoId . '.png',
$base . '/p' . $panoId . '.tif',
$base . '/p' . $panoId . '.tiff',
$base . '/p' . $panoId . '.psb',
// Größere Previews
$base . '/panos/p' . $panoId . '.tiles/preview.jpg',
// Fallback Thumbnails
$base . '/panos/p' . $panoId . '.tiles/thumb.jpg',
$base . '/panos/p' . $panoId . '.tiles/fb_thumb.jpg',
];
$imageUrl = null;
// Versuche per HTTP die beste erreichbare URL zu finden (200 OK)
foreach ($imageCandidates as $u) {
$chh = curl_init($u);
curl_setopt_array($chh, [
CURLOPT_NOBODY => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_RETURNTRANSFER => true,
]);
curl_exec($chh);
$codeH = curl_getinfo($chh, CURLINFO_HTTP_CODE);
curl_close($chh);
if ((int)$codeH === 200) { $imageUrl = $u; break; }
}
// Falls keine URL mit 200, verwende den ersten Kandidaten als Hinweis
if ($imageUrl === null) { $imageUrl = $imageCandidates[0]; }
// Zusätzlich: lokaler Dateipfad -> Base64, falls der Depth-Server das Bild nicht per URL abrufen kann
$fsBase = __DIR__ . '/../';
$localCandidates = [
// ZUERST das rekonstruierte Equirect prüfen
$fsBase . 'panos/p' . $panoId . '.tiles/equirect.jpg',
// Dann Originale
$fsBase . 'p' . $panoId . '.jpg',
$fsBase . 'p' . $panoId . '.jpeg',
$fsBase . 'p' . $panoId . '.png',
$fsBase . 'p' . $panoId . '.tif',
$fsBase . 'p' . $panoId . '.tiff',
$fsBase . 'p' . $panoId . '.psb',
// Dann Previews/Thumbnails
$fsBase . 'panos/p' . $panoId . '.tiles/preview.jpg',
$fsBase . 'panos/p' . $panoId . '.tiles/thumb.jpg',
$fsBase . 'panos/p' . $panoId . '.tiles/fb_thumb.jpg',
];
$imageBase64 = null;
$imagePath = null;
foreach ($localCandidates as $path) {
if (file_exists($path)) { $bin = @file_get_contents($path); if ($bin !== false) { $imageBase64 = base64_encode($bin); $imagePath = $path; break; } }
}
// Wenn keine lokale Datei gefunden wurde, versuche die gefundene URL herunterzuladen
if ($imageBase64 === null && $imageUrl) {
$chg = curl_init($imageUrl);
curl_setopt_array($chg, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_TIMEOUT => 20,
]);
$bin = curl_exec($chg);
$codeG = curl_getinfo($chg, CURLINFO_HTTP_CODE);
curl_close($chg);
if ((int)$codeG === 200 && $bin !== false) { $imageBase64 = base64_encode($bin); }
}
// Bildgröße ermitteln und Input-Size entsprechend anpassen
if ($imagePath && function_exists('getimagesize')) {
$imageInfo = @getimagesize($imagePath);
if ($imageInfo !== false) {
$imageWidth = $imageInfo[0];
$imageHeight = $imageInfo[1];
$longestEdge = max($imageWidth, $imageHeight);
// Verwende die längste Kante als Input-Size, aber maximal 4096 (typisches Maximum für DepthAnything)
// Stelle sicher, dass wir mindestens die Standardgröße verwenden
$calculatedSize = min($longestEdge, 4096);
if ($calculatedSize > $inputSize) {
$inputSize = $calculatedSize;
}
}
} elseif ($imageBase64 && function_exists('imagecreatefromstring')) {
// Falls Bild von URL geladen wurde, versuche Größe aus Base64 zu ermitteln
$imageData = @base64_decode($imageBase64);
if ($imageData !== false) {
$imageResource = @imagecreatefromstring($imageData);
if ($imageResource !== false) {
$imageWidth = imagesx($imageResource);
$imageHeight = imagesy($imageResource);
imagedestroy($imageResource);
$longestEdge = max($imageWidth, $imageHeight);
$calculatedSize = min($longestEdge, 4096);
if ($calculatedSize > $inputSize) {
$inputSize = $calculatedSize;
}
}
}
}
// Depth-Server anfragen
$payload = [
'image_url' => $imageUrl,
'image_base64' => $imageBase64, // Server darf eine der beiden Quellen nutzen
'encoder' => $encoder,
'grayscale' => (bool)$grayscale,
'input_size' => $inputSize
];
$ch = curl_init('http://plano.panomity.com:5005/depth');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 300,
]);
$resp = curl_exec($ch);
$err = curl_error($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
curl_close($ch);
// Fallback bei Fehlern: Encoder herunterschalten
if ($code !== 200 || !empty($err)) {
$fallbacks = [
['encoder' => 'vitl', 'input_size' => min($inputSize, 2048)], // Versuche mit reduzierter Größe
['encoder' => 'vitb', 'input_size' => min($inputSize, 2048)],
['encoder' => 'vitb', 'input_size' => 1024],
['encoder' => 'vitb', 'input_size' => 518],
['encoder' => 'vits', 'input_size' => 518],
['encoder' => 'vits', 'input_size' => 384],
];
foreach ($fallbacks as $fb) {
if ($fb['encoder'] === $encoder && $fb['input_size'] === $inputSize) continue;
$payload['encoder'] = $fb['encoder'];
$payload['input_size'] = $fb['input_size'];
$ch2 = curl_init('http://plano.panomity.com:5005/depth');
curl_setopt_array($ch2, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 300,
]);
$resp2 = curl_exec($ch2);
$err2 = curl_error($ch2);
$code2 = curl_getinfo($ch2, CURLINFO_HTTP_CODE);
$contentType = curl_getinfo($ch2, CURLINFO_CONTENT_TYPE);
curl_close($ch2);
if ($code2 === 200 && empty($err2)) { $resp = $resp2; $err = ''; $code = 200; break; }
}
}
if ($code !== 200 || !empty($err)) {
http_response_code(500);
echo json_encode(['error' => 'Depth server error', 'http_code' => $code, 'details' => $err, 'body' => substr((string)$resp, 0, 300)]);
exit;
}
// PNG-Binary erwarten
$isJson = (strpos((string)$contentType, 'application/json') !== false);
if ($isJson) {
$jr = json_decode($resp, true);
if (!isset($jr['png_base64'])) { http_response_code(500); echo json_encode(['error' => 'Invalid depth response']); exit; }
$pngData = base64_decode($jr['png_base64']);
} else {
$pngData = $resp; // binary
}
if (!$pngData) { http_response_code(500); echo json_encode(['error' => 'Empty PNG data']); exit; }
// Datei speichern
$panoDir = __DIR__ . '/../panos/p' . $panoId . '.tiles/';
if (!is_dir($panoDir)) { @mkdir($panoDir, 0777, true); }
$depthFile = $panoDir . 'dmap.png';
$ok = @file_put_contents($depthFile, $pngData);
if ($ok === false) { http_response_code(500); echo json_encode(['error' => 'Failed to save depth file']); exit; }
// Sichtbarkeit setzen
$db->exec("UPDATE panos SET depthmap_visible = 1 WHERE id = " . (int)$panoId);
$db->close();
echo json_encode(['success' => true, 'file' => 'panos/p' . $panoId . '.tiles/dmap.png']);
?>