Files
appRobotVideoControls/programs/screenShot.js
2026-05-15 07:20:09 +02:00

158 lines
6.7 KiB
JavaScript
Executable File

const fs = require('fs');
const path = require('path');
const { exec } = require('child_process');
const { logSnapshot } = require('./log');
function processPython(command, name0, name1, outDir, ws) {
const relUrl = `/snapshots/${name0}`;
const relUrlApp = `/snapshots/${name0.replace('.jpg','_two_cam_annotated.jpg')}`;
// The Python postprocessor writes an overlay named "_two_cam_overlay.png" and a CSV named "_two_cam.csv"
const relOverlay = `/snapshots/${name0.replace('.jpg','_two_cam_overlay.png')}`;
const relOverlayCSV = `/snapshots/${name0.replace('.jpg','_two_cam.csv')}`;
const annotatedPath = path.join(outDir, name0.replace('.jpg','_two_cam_annotated.jpg'));
const overlayPath = path.join(outDir, name0.replace('.jpg','_two_cam_overlay.png'));
const csvPath = path.join(outDir, name0.replace('.jpg','_two_cam.csv'));
// Run the Python post-processing and send the snapshot response only
// after the annotated files are present to avoid transient 404s in the browser.
exec(command, (error, stdout, stderr) => {
try {
if (error) {
console.error(`Error: ${error.message}`);
// Capture which generated files actually exist for debugging
const files = {
annotated: fs.existsSync(annotatedPath),
overlay: fs.existsSync(overlayPath),
csv: fs.existsSync(csvPath)
};
// Log full details server-side for diagnosis
const detailed = {
type: 'snapshot',
ok: false,
error: error.message,
stdout: String(stdout).slice(0, 4096),
stderr: String(stderr).slice(0, 4096),
files
};
logSnapshot(command, JSON.stringify(detailed));
// Send a short, user-friendly error to the client (no large stdout/stderr)
const shortError = String(stderr || error.message || '').includes('Corrupt JPEG')
? 'postprocessor failed: corrupt JPEG input'
: 'postprocessor failed';
try { ws.send(JSON.stringify({ type: 'snapshot', ok: false, error: shortError })); } catch (e) {}
return;
}
if (stderr) {
// Log stderr but don't fail outright; sometimes tools output warnings on stderr.
if (String(stderr).trim()) console.error(`Stderr: ${stderr}`);
}
console.log(`Output:\n${stdout}`);
// Wait up to ~1s (10 * 100ms) for the generated files to appear on disk.
const waitForFiles = (paths, attempts = 10, delayMs = 100) => new Promise((resolve) => {
let tries = 0;
(function poll() {
const ok = paths.every(p => fs.existsSync(p));
if (ok || tries >= attempts) return resolve(ok);
tries++;
setTimeout(poll, delayMs);
})();
});
waitForFiles([annotatedPath, overlayPath, csvPath]).then((found) => {
if (!found) {
const files = {
annotated: fs.existsSync(annotatedPath),
overlay: fs.existsSync(overlayPath),
csv: fs.existsSync(csvPath)
};
// Log details server-side
const detailed = {
type: 'snapshot',
ok: false,
url: relUrl,
urlApp: relUrlApp,
overlay: relOverlay,
overlayCSV: relOverlayCSV,
files
};
logSnapshot(command, JSON.stringify(detailed));
// Send a concise error to the client
try { ws.send(JSON.stringify({ type: 'snapshot', ok: false, error: 'postprocessor incomplete (missing outputs)' })); } catch (e) {}
return;
}
const response = JSON.stringify({
type: 'snapshot',
ok: found,
url: relUrl,
urlApp: relUrlApp,
overlay: relOverlay,
overlayCSV: relOverlayCSV
});
logSnapshot(command, response);
try { ws.send(response); } catch (e) {}
}).catch((waitErr) => {
console.error('waitForFiles failed:', waitErr);
const response = JSON.stringify({ type: 'snapshot', ok: false, error: String(waitErr) });
logSnapshot(command, response);
try { ws.send(response); } catch (e) {}
});
} catch (handlerErr) {
console.error('snapshot handler error:', handlerErr);
const response = JSON.stringify({ type: 'snapshot', ok: false, error: String(handlerErr) });
logSnapshot(command, response);
try { ws.send(response); } catch (e) {}
}
});
}
function snapshot(outDir, cam0, cam1, ws){
if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });
const picDate = Date.now();
var name0 = `snapshot_video0_${picDate}.jpg`;
var name1 = `snapshot_video1_${picDate}.jpg`;
console.log('Taking snapshot from cam0 async');
(async () => {
try {
const BASE_PATH = process.env.APP_BASE_PATH || '/usr/src/app';
console.log('Taking snapshot from cam1 a…');
await cam0.snapshotHighRes(path.join(outDir, name0));
await cam1.snapshotHighRes(path.join(outDir, name1));
console.log('Snapshot gespeichert:', name1);
strFile0 = path.join(outDir, name0);
strFile1 = path.join(outDir, name1);
//const command = `python3 /usr/src/app/programs/readTwoImages.py -i ${strFile0} -i ${strFile1} -npz /usr/src/app/data/settings/callibration_cam0.npz -npz /usr/src/app/data/settings/callibration_cam1.npz -settings /usr/src/app/data/settings/settings1m.json`;
const command = `python3 ${path.join(BASE_PATH, 'programs/readTwoImages.py')} \
-i ${strFile0} \
-i ${strFile1} \
-npz ${path.join(BASE_PATH, 'data/settings/callibration_cam0.npz')} \
-npz ${path.join(BASE_PATH, 'data/settings/callibration_cam1.npz')} \
-settings ${path.join(BASE_PATH, 'data/settings/settings1m.json')}`;
console.log("Executing Python " + command);
processPython(command, name0, name1, outDir, ws);
} catch (err) {
console.error('Snapshot fehlgeschlagen:', err);
}
})();
}
module.exports = { snapshot };