HEX
Server: LiteSpeed
System: Linux houston.panomity.com 6.8.0-100-generic #100-Ubuntu SMP PREEMPT_DYNAMIC Tue Jan 13 16:40:06 UTC 2026 x86_64
User: nudepix (1011)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
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']);

?>