ext-apps/examples
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Olivier Chafik 61fe39b4db
feat(pdf-server): rasterize imported annotations + form/save consistency follow-ups (#593)
* feat(pdf-server): rasterize imported annotations via annotationCanvasMap

Adds an 'imported' annotation type for anything in a loaded PDF that we
either don't model (Ink, Polygon, Caret, FileAttachment, ...) or can't
faithfully re-render (Stamp with an appearance stream, e.g. an image
signature). These now:
- Appear in the annotation panel as '<Subtype> (from PDF)'
- Render in our layer as a positioned div whose body is the per-
  annotation canvas pdf.js produced via page.render({annotationCanvasMap})
  - if pdf.js didn't divert it (no hasOwnCanvas), the box is transparent
    over the main-canvas pixel and just captures clicks
- Are selectable and draggable (resize/rotate disabled - bitmap would
  just stretch)
- Are skipped by addAnnotationDicts; getAnnotatedPdfBytes already
  filters baseline ids, so save leaves the original in the PDF.
  Move/delete are UI-only for now (documented).

Link (2) and Popup (16) are excluded - navigational/auxiliary, not
markup.

importPdfjsAnnotation tests added for unsupported-type and
appearance-stamp paths; computeDiff round-trip for 'imported'.

* fix(pdf-server): isEditing on page.render so stamps always divert to annotationCanvasMap

StampAnnotation.hasOwnCanvas defaults to noRotate; stamps without that
flag composited onto the main canvas, so deleting the 'imported' overlay
left an unclickable pixel. isEditing forces hasOwnCanvas=true for stamps
(via mustBeViewedWhenEditing) so the appearance lands in the per-id
canvas and our DOM element is the only render.

* fix(pdf-server): refresh annotation panel after save rebases baseline

setDirty(false) updated the title and save button but the panel kept
showing pending-change badges because it diffs against
pdfBaselineAnnotations/FormValues and was never re-rendered.

* fix(pdf-server): imported stamp canvases cropped/2x on retina

renderPage applied devicePixelRatio via ctx.scale(dpr,dpr) instead of
page.render's transform parameter. pdf.js sizes annotationCanvasMap
backing buffers as rectW * outputScaleX * viewport.scale, and
outputScaleX is read from transform[0] (defaults 1). So on retina the
per-annotation canvas got a 1x backing while its internal setTransform
(from the SVD of the already-dpr-scaled ctx) was 2x - the appearance
rendered at 2x into a half-sized buffer, showing only the top-left
quarter.

Pass dpr via transform: [dpr,0,0,dpr,0,0] so outputScaleX matches.
Also filter AnnotationLayer.render() to Widget annotations only so it
stops creating empty pointer-events:auto sections for stamps in
#form-layer that could steal clicks from our overlays.

* feat(pdf-server): strip deleted baseline annotations from /Annots on save

buildAnnotatedPdfBytes takes a removedRefs list and walks each page's
/Annots array (backwards) removing matching PDFRef entries.
getAnnotatedPdfBytes computes that list from baseline annotations no
longer in annotationMap, parsing the ref back from our id via
parseAnnotationRef (handles both pdf-<num>-<gen> and pdf-<num>R).

Panel: removed baseline annotations now stay listed as crossed-out cards
with a revert button (mirrors cleared form fields), so the user can see
and undo the pending deletion before save commits it.

* fix(pdf-server): re-render after seeding storage from AcroForm tree

buildFieldNameMap runs AFTER the first renderPage (perf: don't block the
canvas on an O(numPages) scan). When it detects a widget/field-tree
mismatch and pushes the field-tree value into annotationStorage, the
form layer has already rendered the stale widget value. Re-render once
when that happens so the input shows the AcroForm truth.

* fix(pdf-server): reload PDF after successful save instead of rebasing in place

Rebasing baselines while keeping the old pdfDocument drifts: subsequent
renders rasterize annotations that were just stripped from disk, and the
field/widget split pdf-lib's save can create isn't visible until reload.
Reload makes 'viewer == disk' an invariant. localStorage cleared first;
file_changed echo suppressed by lastSavedMtime as before.
2026-04-02 10:03:35 +01:00
..
basic-host chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
basic-server-preact chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
basic-server-react chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
basic-server-solid chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
basic-server-svelte chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
basic-server-vanillajs chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
basic-server-vue chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
budget-allocator-server chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
cohort-heatmap-server chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
customer-segmentation-server chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
debug-server chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
integration-server chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
map-server chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
pdf-server feat(pdf-server): rasterize imported annotations + form/save consistency follow-ups (#593) 2026-04-02 10:03:35 +01:00
qr-server chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
quickstart chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
say-server chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
scenario-modeler-server chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
shadertoy-server chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
sheet-music-server chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
system-monitor-server chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
threejs-server chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
transcript-server chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
video-resource-server chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
wiki-explorer-server chore: bump ext-apps to 1.4.0 (#582) 2026-04-02 04:33:13 +01:00
run-all.ts add EXAMPLE=folder-name support for tests & basic-host (#292) 2026-01-19 20:16:37 +00:00