Desktop MP4 export renders frames from a hidden BrowserWindow via capturePage, pipes PNGs to a bundled ffmpeg (libx264/yuv420p/+faststart), and writes the file through an atomic temp-file swap. It shares scene validation (shared/renderValidation.cjs) and the render.html renderer with the standalone Puppeteer server, which is hardened in parallel. Render worker & main (electron/): - abortable render loop with an inactivity watchdog and cancel plumbing - atomic temp-file + rename so a cancel/failure never truncates a pre-existing target (#7); stdin EPIPE / early-exit / backpressure-hang handled (#8) - HiDPI frames normalized to canvas size (#10); odd dimensions padded to even (#13, also server); backgroundThrottling disabled (#12) - reject canvases larger than the display (#11); single-render guard; isolated render session that blocks network requests (#5) Tests: - Electron harnesses (scripts/verify-*.cjs) for capture, export, cancel, timeout, assets, background, capture-fidelity, resolution, odd-dims, aggregated by verify-desktop-render.cjs - server smoke + e2e and shared validation unit tests - headless hook (src/devtools/headless.ts) to run the in-app suite under browser/electron hosts; pixel-diff util + capture fixtures (test/) - dev_docs plans: integration, fixes (#7-#13), and the e2e/capture strategy Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
42 lines
1.2 KiB
JavaScript
42 lines
1.2 KiB
JavaScript
function diffBgra(a, b, options = {}) {
|
|
if (!a || !b || a.length !== b.length) {
|
|
throw new Error(`bitmap size mismatch: ${a?.length || 0} != ${b?.length || 0}`)
|
|
}
|
|
const perChannelTolerance = Number.isFinite(options.perChannelTolerance)
|
|
? options.perChannelTolerance
|
|
: 2
|
|
const maxMismatchedRatio = Number.isFinite(options.maxMismatchedRatio)
|
|
? options.maxMismatchedRatio
|
|
: 0.001
|
|
|
|
let mismatchedPixels = 0
|
|
let maxDelta = 0
|
|
let totalDelta = 0
|
|
const pixels = a.length / 4
|
|
|
|
for (let i = 0; i < a.length; i += 4) {
|
|
let pixelMismatch = false
|
|
for (let c = 0; c < 4; c += 1) {
|
|
const delta = Math.abs(a[i + c] - b[i + c])
|
|
maxDelta = Math.max(maxDelta, delta)
|
|
totalDelta += delta
|
|
if (delta > perChannelTolerance) pixelMismatch = true
|
|
}
|
|
if (pixelMismatch) mismatchedPixels += 1
|
|
}
|
|
|
|
const mismatchedRatio = pixels ? mismatchedPixels / pixels : 0
|
|
return {
|
|
ok: mismatchedRatio <= maxMismatchedRatio,
|
|
pixels,
|
|
mismatchedPixels,
|
|
mismatchedRatio,
|
|
maxDelta,
|
|
meanDelta: pixels ? totalDelta / (pixels * 4) : 0,
|
|
perChannelTolerance,
|
|
maxMismatchedRatio,
|
|
}
|
|
}
|
|
|
|
module.exports = { diffBgra }
|