@segnavia/render 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/deck-pdf.js CHANGED
@@ -4,8 +4,9 @@ import { pdfPixelBox } from "./pdf-geometry.js";
4
4
  import { composeImposedPdf, drawClippedPage, embedOnePage } from "./pdf-compose.js";
5
5
  import { Imposition, fitPage, impose, pagePlacementLayout } from "@segnavia/format";
6
6
  import { newNonce } from "@segnavia/frame/bridge";
7
- import { htmlSlideDocument, notesLayoutGeometry, printableDeck } from "@segnavia/frame/print-document";
7
+ import { htmlSlideDocument, notesLayoutGeometry, paginateNotes, printableDeck } from "@segnavia/frame/print-document";
8
8
  import { PDFDocument } from "pdf-lib";
9
+ import { fitImage, imageLayerStyles } from "@segnavia/frame/image-fit";
9
10
  //#region src/deck-pdf.ts
10
11
  function nameSlideError(error, id) {
11
12
  if (error instanceof Error) {
@@ -14,6 +15,47 @@ function nameSlideError(error, id) {
14
15
  }
15
16
  throw new Error(`Slide "${id}" could not be rendered: ${String(error)}`);
16
17
  }
18
+ function firstNotesPages(pageOwners, slideCount) {
19
+ return Array.from({ length: slideCount }, (_, slide) => pageOwners.indexOf(slide));
20
+ }
21
+ async function placeRenderedImages(tab) {
22
+ const layers = tab.locator("[data-segnavia-image-layer]");
23
+ const styles = (await layers.evaluateAll((elements) => elements.map((element) => {
24
+ const layer = element;
25
+ const image = layer.querySelector("img");
26
+ return {
27
+ slide: {
28
+ width: Number(layer.dataset.slideWidth),
29
+ height: Number(layer.dataset.slideHeight)
30
+ },
31
+ image: {
32
+ width: image?.naturalWidth ?? 0,
33
+ height: image?.naturalHeight ?? 0
34
+ },
35
+ fit: layer.dataset.fit,
36
+ frame: layer.dataset.frame === "true"
37
+ };
38
+ }))).map((fact) => {
39
+ if (fact.image.width <= 0 || fact.image.height <= 0) return null;
40
+ const placement = fitImage(fact.slide, fact.image, fact.fit, void 0, fact.frame);
41
+ return imageLayerStyles(fact.image, placement, fact.slide);
42
+ });
43
+ await layers.evaluateAll((elements, values) => {
44
+ elements.forEach((element, index) => {
45
+ const styles = values[index];
46
+ if (!styles) return;
47
+ const layer = element;
48
+ const image = layer.querySelector("img");
49
+ if (!image) return;
50
+ Object.assign(layer.style, styles.layer);
51
+ Object.assign(image.style, styles.image);
52
+ });
53
+ }, styles);
54
+ }
55
+ async function paginateRenderedNotes(tab, maxSheets) {
56
+ if (maxSheets === void 0) return tab.evaluate(paginateNotes, null);
57
+ return tab.evaluate(`(${paginateNotes.toString()})(null,${JSON.stringify(maxSheets)})`);
58
+ }
17
59
  async function regularDeckPdf(deck, opts, services) {
18
60
  const htmlSlides = deck.slides.flatMap((slide, index) => slide.content.kind === "html" ? [{
19
61
  index,
@@ -23,19 +65,27 @@ async function regularDeckPdf(deck, opts, services) {
23
65
  const css = `${services.fontFaces(opts)}${opts.css ?? ""}`;
24
66
  const slideCss = containFixedPageOverflow(css);
25
67
  const notesGeometry = opts.layout === "notes" ? notesLayoutGeometry(deck.size, opts.notesPaper) : void 0;
68
+ let pageOwners = [];
26
69
  const [printable, rendered] = await Promise.all([services.renderPdf({
27
70
  viewport: notesGeometry ? {
28
71
  width: Math.round(notesGeometry.sheet.width),
29
72
  height: Math.round(notesGeometry.sheet.height)
30
73
  } : deck.size,
31
- scripts: deck.scripts === "sandboxed",
74
+ scripts: true,
32
75
  html: printableDeck(deck, {
33
76
  ...opts,
34
77
  css,
35
78
  omitHtmlSlideFrames: true
36
79
  }),
37
80
  boundMs: opts.boundMs,
38
- beforeOutput: opts.beforeOutput
81
+ beforeOutput: async (tab) => {
82
+ await placeRenderedImages(tab);
83
+ if (notesGeometry) {
84
+ if ((await paginateRenderedNotes(tab, opts.limits?.maxSheets)).exceeded) throw new RenderRefusedError(`The PDF needs more than ${opts.limits?.maxSheets} sheets; the limit is ${opts.limits?.maxSheets}.`);
85
+ pageOwners = await tab.locator(".sheet").evaluateAll((sheets) => sheets.map((sheet) => Number(sheet.dataset.slideIndex)));
86
+ }
87
+ await opts.beforeOutput?.(tab);
88
+ }
39
89
  }, {
40
90
  preferCSSPageSize: true,
41
91
  printBackground: true
@@ -77,8 +127,10 @@ async function regularDeckPdf(deck, opts, services) {
77
127
  height: deck.size.height
78
128
  };
79
129
  const geometry = pdfPixelBox(slideBox, notesGeometry?.sheet.height ?? deck.size.height);
130
+ const firstPages = notesGeometry ? firstNotesPages(pageOwners, deck.slides.length) : [];
80
131
  for (const item of rendered) {
81
- const sheet = pages[item.index];
132
+ const pageIndex = notesGeometry ? firstPages[item.index] ?? -1 : item.index;
133
+ const sheet = pages[pageIndex < 0 ? item.index : pageIndex];
82
134
  if (!sheet) throw new Error(`The print document has no sheet for slide "${deck.slides[item.index]?.id ?? item.index}".`);
83
135
  const embedded = await embedOnePage(output, item.bytes, `The rendered slide "${deck.slides[item.index]?.id ?? item.index}"`);
84
136
  drawClippedPage(sheet, embedded, geometry, geometry);
@@ -107,9 +159,10 @@ async function imposedDeckPdf(deck, imposition, opts, services) {
107
159
  index,
108
160
  bytes: await services.renderPdf({
109
161
  viewport: deck.size,
110
- scripts: deck.scripts === "sandboxed",
162
+ scripts: slide.content.kind === "html" ? deck.scripts === "sandboxed" : true,
111
163
  html,
112
- boundMs: opts.boundMs
164
+ boundMs: opts.boundMs,
165
+ beforeOutput: slide.content.kind === "image" ? placeRenderedImages : void 0
113
166
  }, {
114
167
  width: `${deck.size.width}px`,
115
168
  height: `${deck.size.height}px`,
@@ -151,4 +204,4 @@ async function renderDeckPdf(deck, opts, services) {
151
204
  return imposedDeckPdf(deck, Imposition.parse(opts.imposition), opts, services);
152
205
  }
153
206
  //#endregion
154
- export { renderDeckPdf };
207
+ export { firstNotesPages, renderDeckPdf };
package/dist/index.js CHANGED
@@ -358,7 +358,7 @@ async function openRenderer(options) {
358
358
  });
359
359
  return withTab({
360
360
  viewport: deck.size,
361
- scripts: deck.scripts === "sandboxed",
361
+ scripts: true,
362
362
  scale: opts.scale,
363
363
  html,
364
364
  waitForReady: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@segnavia/render",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -26,9 +26,9 @@
26
26
  }
27
27
  },
28
28
  "dependencies": {
29
- "@segnavia/format": "0.7.0",
30
- "@segnavia/frame": "0.7.0",
31
- "@segnavia/html": "0.7.0",
29
+ "@segnavia/format": "0.9.0",
30
+ "@segnavia/frame": "0.9.0",
31
+ "@segnavia/html": "0.9.0",
32
32
  "playwright-core": "1.55.1",
33
33
  "pdf-lib": "^1.17.1"
34
34
  }