Files
ubuntu-based-kiosk/kiosk-app/pdf-render.mjs
T
Claude fb4ee6fa62 Slideshow folders can include PDFs
PDFs in a slideshow folder now play alongside images and Word documents:
a one-page PDF is shown whole, a longer one fits the width and scrolls
through its pages during docInterval (first 30 pages - rendering a huge
PDF for a few seconds on screen isn't worth the time and memory).

- kiosk-app/pdf-render.mjs renders pages to canvases with pdf.js
  (pdfjs-dist ^6.3.289, new kiosk-app dependency): no viewer toolbar, and
  the slideshow's existing auto-scroll works on it. pdf.js >= 4.2.67 is
  required (CVE-2024-4367: older versions could run script embedded in a
  crafted PDF); isEvalSupported:false too. It's a module because pdf.js
  only ships as one - confirmed to load (with its worker) from file:// in
  Electron 44.
- Hands pdf.js a copy of the bytes: it transfers the buffer it's given,
  which would break the cached copy the next time round.
- slideshow.js lists .pdf as a document type; the title-request handler
  serves any listed non-image item (still only from that folder).
- provision_install_app now copies kiosk-app/*.mjs as well - without it
  pdf-render.mjs would never reach an installed kiosk.

Tested with the real main.js on Electron 44.5.1 under Xvfb + Openbox,
app files copied with provision_install_app's own glob: a photo, a
one-page PDF, a three-page PDF and a .docx played in order, twice round;
the one-page PDF shown whole, the three-page one scrolled through all
pages. Offline bundle rebuilt with pdfjs-dist (437 MB total, +22 MB).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cjz8a58eB5P9sUweqd3NHm
2026-10-03 15:43:05 +00:00

72 lines
3.2 KiB
JavaScript

// Browser-side PDF rendering for slideshow.html, via pdf.js (pdfjs-dist,
// an npm dependency of this app). A module because pdf.js only ships as
// one; it sets window.KioskPdf for slideshow.html's classic script.
//
// Pages are drawn to canvases (no viewer toolbar, and the slideshow can
// scroll them like a Word document). pdf.js >= 4.2.67 is required - older
// versions could run JavaScript embedded in a crafted PDF (CVE-2024-4367);
// isEvalSupported:false is set as well, belt and braces.
import * as pdfjs from './node_modules/pdfjs-dist/build/pdf.min.mjs';
const base = new URL('./node_modules/pdfjs-dist/', import.meta.url).href;
pdfjs.GlobalWorkerOptions.workerSrc = base + 'build/pdf.worker.min.mjs';
// Rendering every page of a huge PDF would take a long time and a lot of
// memory for something shown for seconds - stop after this many.
const MAX_PAGES = 30;
window.KioskPdf = {
// Render `bytes` into `container` (emptied first), sized for a screen of
// width x height: a one-page PDF fits entirely (like an image); a longer
// one fits the width, pages stacked, for the slideshow to scroll.
async render(bytes, container, width, height) {
container.innerHTML = '';
const task = pdfjs.getDocument({
// A copy: pdf.js transfers (empties) the buffer it's given, and the
// slideshow caches these bytes to show the PDF again next round.
data: bytes.slice(),
isEvalSupported: false,
cMapUrl: base + 'cmaps/',
cMapPacked: true,
standardFontDataUrl: base + 'standard_fonts/',
});
try {
const doc = await task.promise;
const count = Math.min(doc.numPages, MAX_PAGES);
const single = doc.numPages === 1;
const gap = 16;
container.style.display = 'flex';
container.style.flexDirection = 'column';
container.style.alignItems = 'center';
container.style.gap = gap + 'px';
container.style.padding = (single ? 0 : gap) + 'px 0';
container.style.minHeight = single ? '100%' : '';
container.style.justifyContent = single ? 'center' : '';
const dpr = window.devicePixelRatio || 1;
for (let n = 1; n <= count; n++) {
const page = await doc.getPage(n);
const natural = page.getViewport({ scale: 1 });
const scale = single
? Math.min(width / natural.width, height / natural.height)
: Math.min((width - 2 * gap) / natural.width, 1.6 * (96 / 72));
const vp = page.getViewport({ scale: scale * dpr });
const canvas = document.createElement('canvas');
canvas.width = Math.floor(vp.width);
canvas.height = Math.floor(vp.height);
canvas.style.width = Math.floor(vp.width / dpr) + 'px';
canvas.style.height = Math.floor(vp.height / dpr) + 'px';
canvas.style.background = '#fff';
canvas.style.boxShadow = single ? '' : '0 2px 8px rgba(0,0,0,.4)';
container.appendChild(canvas);
await page.render({ canvasContext: canvas.getContext('2d'), viewport: vp }).promise;
page.cleanup();
}
return { pages: doc.numPages, rendered: count };
} finally {
// Frees the document and its worker-side data (pdf.js 6 has this on
// the loading task, not the document).
task.destroy();
}
},
};