jspdf-utils 0.1.24 → 0.1.26

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/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # jsPDF Utils
2
2
 
3
- HTML to PDF utilities for jsPDF with support for Arabic text, tables, and automatic page breaking.
3
+ Utilities for rendering HTML into paginated PDF output with `jsPDF` and
4
+ `html2canvas`.
4
5
 
5
6
  ## Installation
6
7
 
@@ -8,79 +9,129 @@ HTML to PDF utilities for jsPDF with support for Arabic text, tables, and automa
8
9
  npm install jspdf-utils jspdf html2canvas
9
10
  ```
10
11
 
11
- ## Usage
12
+ ## Exported API
12
13
 
13
- ```javascript
14
+ - `generatePDF(doc, source, opts)`
15
+ - `generateImagePDF(source, opts)`
16
+ - `generateImages(source, opts)`
17
+ - `previewImages(source, container, opts)`
18
+ - `PAGE_SIZES`
19
+ - `PAGE_MARGINS`
20
+ - Types: `PageOptions`, `PageOptionsInput`, `ImagePDFOptions`
21
+
22
+ Type import example:
23
+
24
+ ```ts
25
+ import type { PageOptionsInput } from "jspdf-utils";
26
+ ```
27
+
28
+ ## Quick Start
29
+
30
+ ### 1) HTML -> vector/text PDF (`doc.html`)
31
+
32
+ ```ts
14
33
  import jsPDF from "jspdf";
15
- import { renderHTML } from "jspdf-utils";
34
+ import { generatePDF } from "jspdf-utils";
35
+
36
+ const target = document.getElementById("print-section");
37
+ if (!target) throw new Error("Missing #print-section");
16
38
 
17
39
  const doc = new jsPDF({ unit: "mm", format: "a4" });
18
40
 
19
- // Add fonts if needed for Arabic/RTL text
20
- doc.addFont("path/to/arial.ttf", "arial", "normal", "normal");
21
- doc.addFont("path/to/arial-bold.ttf", "arial", "normal", "bold");
41
+ // Optional for Arabic/RTL text:
42
+ // doc.addFont("/fonts/arial.ttf", "arial", "normal");
43
+ // doc.addFont("/fonts/arial-bold.ttf", "arial", "bold");
22
44
 
23
- // Render HTML element to PDF
24
- const element = document.getElementById("content");
25
- await renderHTML(doc, element);
45
+ await generatePDF(doc, target, {
46
+ margin: { top: 20, right: 20, bottom: 20, left: 20 },
47
+ forcedPageCount: 1,
48
+ });
26
49
 
27
50
  doc.save("output.pdf");
28
51
  ```
29
52
 
30
- ## Features
53
+ ### 2) HTML -> image-based PDF (raster pages)
31
54
 
32
- - **Automatic page breaking**: Prevents tables and text from being split awkwardly
33
- - **Table splitting**: Large tables are split across pages with repeated headers
34
- - **Text wrapping**: Long text blocks are intelligently broken at word boundaries
35
- - **RTL/Arabic support**: Works with right-to-left languages when proper fonts are loaded
55
+ ```ts
56
+ import { generateImagePDF } from "jspdf-utils";
36
57
 
37
- ## Development
58
+ const target = document.getElementById("print-section");
59
+ if (!target) throw new Error("Missing #print-section");
38
60
 
39
- ### Running the Example
61
+ const imagePDF = await generateImagePDF(target, {
62
+ format: "a5",
63
+ imageFormat: "PNG",
64
+ forcedPageCount: 1,
65
+ });
40
66
 
41
- ```bash
42
- npm install
43
- npm run dev
44
- # Open http://localhost:5173
67
+ imagePDF.save("output-image.pdf");
45
68
  ```
46
69
 
47
- ### Project Structure
70
+ ### 3) Preview pages as images in a container
48
71
 
72
+ ```ts
73
+ import { previewImages } from "jspdf-utils";
74
+
75
+ const target = document.getElementById("print-section");
76
+ const preview = document.getElementById("preview-container");
77
+ if (!target || !preview) throw new Error("Missing preview elements");
78
+
79
+ await previewImages(target, preview, {
80
+ format: "a5",
81
+ forcedPageCount: 1,
82
+ });
49
83
  ```
50
- ├── src/
51
- │ └── html-to-pdf.js # Main utility functions
52
- ├── index.html # Example/demo page
53
- └── package.json
54
- ```
55
84
 
56
- ## API
85
+ ## Options
86
+
87
+ ### `PageOptionsInput`
88
+
89
+ - `unit?: string` (default: `"mm"`)
90
+ - `format?: "a0" | "a1" | "a2" | "a3" | "a4" | "a5" | "a6" | "letter" | "legal" | "tabloid"` (default: `"a4"`)
91
+ - `pageWidth?: number` (default comes from `format`)
92
+ - `pageHeight?: number` (default comes from `format`)
93
+ - `margin?: number | { top?: number; right?: number; bottom?: number; left?: number }`
94
+
95
+ ### `ImagePDFOptions`
96
+
97
+ - `imageFormat?: "JPEG" | "PNG"`
98
+ - `imageQuality?: number`
99
+ - `scale?: number`
100
+ - `marginContent?: MarginContentInput`
101
+ - `forcedPageCount?: number`
57
102
 
58
- ### `renderHTML(doc, source, opts)`
103
+ `forcedPageCount` behavior:
59
104
 
60
- Renders an HTML element to PDF.
105
+ - Forces output to the first `N` pages only.
106
+ - `generatePDF`: trims extra pages after `doc.html` rendering.
107
+ - `generateImagePDF`: only rasterizes and writes first `N` pages.
108
+ - `generateImages` and `previewImages`: only returns/displays first `N` pages.
109
+ - Invalid values (`<= 0`, `NaN`, `Infinity`) are ignored.
61
110
 
62
- - **doc**: jsPDF instance
63
- - **source**: HTML element to render
64
- - **opts**: Optional configuration (overrides defaults)
111
+ ## Margin Content and Borders
65
112
 
66
- ### `prepare(source, opts)`
113
+ `marginContent` supports:
67
114
 
68
- Prepares an HTML element for rendering (used internally by renderHTML).
115
+ - `top`, `right`, `bottom`, `left` as:
116
+ - `HTMLElement`, or
117
+ - `(page: number, totalPages: number) => HTMLElement`
118
+ - `contentBorder` (vector rectangle)
119
+ - `textBorder` (repeated text around page edges)
69
120
 
70
- Returns: `{ clone, layout, options, cleanup }`
121
+ Rendering order:
71
122
 
72
- ### Default Options
123
+ - Margin content and borders are rendered beneath page content.
124
+ - Main document content stays visually above borders/text borders.
73
125
 
74
- ```javascript
75
- {
76
- unit: 'mm',
77
- format: 'a4',
78
- pageWidth: 210,
79
- pageHeight: 297,
80
- margin: { top: 20, right: 20, bottom: 20, left: 20 }
81
- }
126
+ ## Development
127
+
128
+ ```bash
129
+ npm install
130
+ npm run dev
82
131
  ```
83
132
 
133
+ Open [http://localhost:5173](http://localhost:5173).
134
+
84
135
  ## License
85
136
 
86
137
  MIT
@@ -48,7 +48,7 @@ export interface PrepareResult {
48
48
  /**
49
49
  * Render an HTML element to PDF using doc.html().
50
50
  */
51
- declare function generatePDF(doc: jsPDF, source: HTMLElement, opts?: PageOptionsInput & Pick<ImagePDFOptions, "marginContent">): Promise<jsPDF>;
51
+ declare function generatePDF(doc: jsPDF, source: HTMLElement, opts?: PageOptionsInput & Pick<ImagePDFOptions, "marginContent" | "forcedPageCount">): Promise<jsPDF>;
52
52
  type MarginFactory = (page: number, totalPages: number) => HTMLElement;
53
53
  export interface ContentBorder {
54
54
  /** Stroke color (default: "#000000") */
@@ -99,6 +99,11 @@ export interface ImagePDFOptions {
99
99
  imageQuality?: number;
100
100
  scale?: number;
101
101
  marginContent?: MarginContentInput;
102
+ /**
103
+ * Force output to the first N pages only.
104
+ * Example: 1 means only page 1 is generated/exported.
105
+ */
106
+ forcedPageCount?: number;
102
107
  }
103
108
  /**
104
109
  * Render an HTML element as an image-based PDF. Each page is a rasterized
@@ -1,5 +1,5 @@
1
- import S from "html2canvas";
2
- const J = {
1
+ import P from "html2canvas";
2
+ const K = {
3
3
  a0: [841, 1189],
4
4
  a1: [594, 841],
5
5
  a2: [420, 594],
@@ -10,7 +10,7 @@ const J = {
10
10
  letter: [215.9, 279.4],
11
11
  legal: [215.9, 355.6],
12
12
  tabloid: [279.4, 431.8]
13
- }, Q = {
13
+ }, V = {
14
14
  a0: 40,
15
15
  a1: 35,
16
16
  a2: 30,
@@ -25,8 +25,8 @@ const J = {
25
25
  function M(t) {
26
26
  return { top: t, right: t, bottom: t, left: t };
27
27
  }
28
- function Z(t, e) {
29
- const a = M(Q[e]);
28
+ function Y(t, e) {
29
+ const a = M(V[e]);
30
30
  return t == null ? a : typeof t == "number" ? M(t) : {
31
31
  top: t.top ?? a.top,
32
32
  right: t.right ?? a.right,
@@ -34,21 +34,21 @@ function Z(t, e) {
34
34
  left: t.left ?? a.left
35
35
  };
36
36
  }
37
- function x(t = {}) {
38
- const e = t.format ?? "a4", [a, n] = J[e];
37
+ function v(t = {}) {
38
+ const e = t.format ?? "a4", [a, n] = K[e];
39
39
  return {
40
40
  unit: t.unit ?? "mm",
41
41
  format: e,
42
42
  pageWidth: t.pageWidth ?? a,
43
43
  pageHeight: t.pageHeight ?? n,
44
- margin: Z(t.margin, e)
44
+ margin: Y(t.margin, e)
45
45
  };
46
46
  }
47
- function E(t, e) {
47
+ function N(t, e) {
48
48
  const a = t.offsetWidth, n = e.pageWidth - e.margin.left - e.margin.right, o = n / a, r = (e.pageHeight - e.margin.top - e.margin.bottom) / o;
49
49
  return { renderedWidth: a, scale: o, contentWidthMm: n, pageContentPx: r };
50
50
  }
51
- function N(t, e = 210) {
51
+ function F(t, e = 210) {
52
52
  const a = t.cloneNode(!0);
53
53
  return Object.assign(a.style, {
54
54
  position: "fixed",
@@ -60,7 +60,7 @@ function N(t, e = 210) {
60
60
  pointerEvents: "none"
61
61
  }), document.body.appendChild(a), a;
62
62
  }
63
- async function F(t) {
63
+ async function O(t) {
64
64
  const e = Array.from(t.querySelectorAll("img"));
65
65
  await Promise.all(
66
66
  e.map((a) => {
@@ -71,8 +71,8 @@ async function F(t) {
71
71
  })
72
72
  );
73
73
  }
74
- async function K(t) {
75
- await F(t);
74
+ async function X(t) {
75
+ await O(t);
76
76
  const e = t.getBoundingClientRect();
77
77
  let a = e.bottom;
78
78
  for (const o of Array.from(t.querySelectorAll("*"))) {
@@ -82,27 +82,27 @@ async function K(t) {
82
82
  const n = a - e.top;
83
83
  n > t.offsetHeight && (t.style.minHeight = n + "px");
84
84
  }
85
- async function V(t) {
85
+ async function tt(t) {
86
86
  const e = Array.from(t.querySelectorAll("img"));
87
87
  if (e.length === 0) return;
88
- await F(t);
88
+ await O(t);
89
89
  const a = 2;
90
90
  for (const n of e) {
91
91
  if (!n.naturalWidth || !n.naturalHeight || n.src.startsWith("data:image/svg")) continue;
92
- const o = n.offsetWidth || n.naturalWidth, i = n.offsetHeight || n.naturalHeight, r = Math.min(o * a, n.naturalWidth), h = Math.min(i * a, n.naturalHeight);
93
- if (n.naturalWidth <= r && n.naturalHeight <= h && n.src.startsWith("data:"))
92
+ const o = n.offsetWidth || n.naturalWidth, i = n.offsetHeight || n.naturalHeight, r = Math.min(o * a, n.naturalWidth), l = Math.min(i * a, n.naturalHeight);
93
+ if (n.naturalWidth <= r && n.naturalHeight <= l && n.src.startsWith("data:"))
94
94
  continue;
95
95
  const s = document.createElement("canvas");
96
- s.width = r, s.height = h;
97
- const l = s.getContext("2d");
98
- if (l)
96
+ s.width = r, s.height = l;
97
+ const g = s.getContext("2d");
98
+ if (g)
99
99
  try {
100
- l.drawImage(n, 0, 0, r, h), n.style.width = o + "px", n.style.height = i + "px", n.src = s.toDataURL("image/png");
100
+ g.drawImage(n, 0, 0, r, l), n.style.width = o + "px", n.style.height = i + "px", n.src = s.toDataURL("image/png");
101
101
  } catch {
102
102
  }
103
103
  }
104
104
  }
105
- function P() {
105
+ function S() {
106
106
  const t = document.createElement("style");
107
107
  return t.setAttribute("data-jspdf-utils", ""), t.textContent = "img { display: inline !important; }", document.head.appendChild(t), () => t.remove();
108
108
  }
@@ -121,20 +121,20 @@ function I(t, e) {
121
121
  t.querySelectorAll(":scope > table")
122
122
  )) {
123
123
  if (a.offsetHeight <= e) continue;
124
- const n = D(a);
124
+ const n = k(a);
125
125
  if (!n) continue;
126
- const { headerRow: o, bodyRows: i, headerHeight: r } = n, h = e - r - 2, s = [];
127
- let l = [], c = 0;
126
+ const { headerRow: o, bodyRows: i, headerHeight: r } = n, l = e - r - 2, s = [];
127
+ let g = [], c = 0;
128
128
  for (const d of i) {
129
- const g = d.offsetHeight;
130
- c + g > h && l.length > 0 && (s.push(l), l = [], c = 0), l.push(d), c += g;
129
+ const h = d.offsetHeight;
130
+ c + h > l && g.length > 0 && (s.push(g), g = [], c = 0), g.push(d), c += h;
131
131
  }
132
- l.length > 0 && s.push(l);
132
+ g.length > 0 && s.push(g);
133
133
  for (const d of s) {
134
- const g = a.cloneNode(!1);
135
- o && g.appendChild(o.cloneNode(!0));
136
- for (const u of d) g.appendChild(u.cloneNode(!0));
137
- a.parentNode.insertBefore(g, a);
134
+ const h = a.cloneNode(!1);
135
+ o && h.appendChild(o.cloneNode(!0));
136
+ for (const f of d) h.appendChild(f.cloneNode(!0));
137
+ a.parentNode.insertBefore(h, a);
138
138
  }
139
139
  a.remove();
140
140
  }
@@ -147,7 +147,7 @@ function L(t, e, a, n) {
147
147
  width: a
148
148
  }), n.appendChild(o), o;
149
149
  }
150
- function O(t, e, a, n) {
150
+ function D(t, e, a, n) {
151
151
  let o = n + 1, i = e.length;
152
152
  for (; o < i; ) {
153
153
  const r = Math.ceil((o + i) / 2);
@@ -155,80 +155,80 @@ function O(t, e, a, n) {
155
155
  }
156
156
  return o;
157
157
  }
158
- function D(t) {
158
+ function k(t) {
159
159
  const e = Array.from(t.rows);
160
160
  if (e.length === 0) return null;
161
161
  const a = e[0].querySelector("th") !== null, n = a ? e[0] : null, o = a ? e.slice(1) : e, i = n ? n.offsetHeight : 0;
162
162
  return { rows: e, hasHeader: a, headerRow: n, bodyRows: o, headerHeight: i };
163
163
  }
164
- function k(t, e) {
164
+ function j(t, e) {
165
165
  for (const a of Array.from(t.querySelectorAll(":scope > *"))) {
166
166
  const n = a;
167
167
  if (n.offsetHeight <= e || n.tagName === "TABLE")
168
168
  continue;
169
- const o = n.tagName, i = n.getAttribute("style") || "", r = getComputedStyle(n).width, h = (n.textContent || "").split(/\s+/).filter(Boolean), s = L(o, i, r, t), l = [];
169
+ const o = n.tagName, i = n.getAttribute("style") || "", r = getComputedStyle(n).width, l = (n.textContent || "").split(/\s+/).filter(Boolean), s = L(o, i, r, t), g = [];
170
170
  let c = 0;
171
- for (; c < h.length; ) {
172
- const d = O(s, h, e, c), g = document.createElement(o);
173
- g.setAttribute("style", i), g.textContent = h.slice(c, d).join(" "), l.push(g), c = d;
171
+ for (; c < l.length; ) {
172
+ const d = D(s, l, e, c), h = document.createElement(o);
173
+ h.setAttribute("style", i), h.textContent = l.slice(c, d).join(" "), g.push(h), c = d;
174
174
  }
175
175
  s.remove();
176
- for (const d of l)
176
+ for (const d of g)
177
177
  n.parentNode.insertBefore(d, n);
178
178
  n.remove();
179
179
  }
180
180
  }
181
- function Y(t, e, a) {
182
- const n = D(t);
181
+ function et(t, e, a) {
182
+ const n = k(t);
183
183
  if (!n) return !1;
184
184
  const { headerRow: o, bodyRows: i, headerHeight: r } = n;
185
185
  if (i.length < 2) return !1;
186
- const h = a - r - 2;
187
- if (h <= 0) return !1;
188
- let s = 0, l = 0;
189
- for (const g of i) {
190
- if (l + g.offsetHeight > h) break;
191
- l += g.offsetHeight, s++;
186
+ const l = a - r - 2;
187
+ if (l <= 0) return !1;
188
+ let s = 0, g = 0;
189
+ for (const h of i) {
190
+ if (g + h.offsetHeight > l) break;
191
+ g += h.offsetHeight, s++;
192
192
  }
193
193
  if (s === 0 || s === i.length) return !1;
194
194
  const c = t.cloneNode(!1);
195
195
  o && c.appendChild(o.cloneNode(!0));
196
- for (let g = 0; g < s; g++)
197
- c.appendChild(i[g].cloneNode(!0));
196
+ for (let h = 0; h < s; h++)
197
+ c.appendChild(i[h].cloneNode(!0));
198
198
  const d = t.cloneNode(!1);
199
199
  o && d.appendChild(o.cloneNode(!0));
200
- for (let g = s; g < i.length; g++)
201
- d.appendChild(i[g].cloneNode(!0));
200
+ for (let h = s; h < i.length; h++)
201
+ d.appendChild(i[h].cloneNode(!0));
202
202
  return e.insertBefore(c, t), e.insertBefore(d, t), t.remove(), !0;
203
203
  }
204
- function X(t, e, a) {
204
+ function nt(t, e, a) {
205
205
  if (t.tagName === "TABLE" || t.tagName === "IMG") return !1;
206
206
  const n = (t.textContent || "").split(/\s+/).filter(Boolean);
207
207
  if (n.length < 2) return !1;
208
- const o = t.tagName, i = t.getAttribute("style") || "", r = getComputedStyle(t).width, h = L(o, i, r, e);
209
- if (h.textContent = n[0], h.offsetHeight > a)
210
- return h.remove(), !1;
211
- const s = O(h, n, a, 0);
212
- if (h.remove(), s >= n.length) return !1;
213
- const l = document.createElement(o);
214
- l.setAttribute("style", i), l.textContent = n.slice(0, s).join(" ");
208
+ const o = t.tagName, i = t.getAttribute("style") || "", r = getComputedStyle(t).width, l = L(o, i, r, e);
209
+ if (l.textContent = n[0], l.offsetHeight > a)
210
+ return l.remove(), !1;
211
+ const s = D(l, n, a, 0);
212
+ if (l.remove(), s >= n.length) return !1;
213
+ const g = document.createElement(o);
214
+ g.setAttribute("style", i), g.textContent = n.slice(0, s).join(" ");
215
215
  const c = document.createElement(o);
216
- return c.setAttribute("style", i), c.textContent = n.slice(s).join(" "), e.insertBefore(l, t), e.insertBefore(c, t), t.remove(), !0;
216
+ return c.setAttribute("style", i), c.textContent = n.slice(s).join(" "), e.insertBefore(g, t), e.insertBefore(c, t), t.remove(), !0;
217
217
  }
218
- function j(t, e) {
218
+ function z(t, e) {
219
219
  let a = 0;
220
220
  for (; a < t.children.length; ) {
221
221
  const n = t.children[a], o = n.offsetTop, i = o + n.offsetHeight, r = (Math.floor(o / e) + 1) * e;
222
222
  if (i > r) {
223
- const h = r - o;
223
+ const l = r - o;
224
224
  if (n.tagName === "TABLE") {
225
- if (Y(
225
+ if (et(
226
226
  n,
227
227
  t,
228
- h
228
+ l
229
229
  ))
230
230
  continue;
231
- } else if (X(n, t, h))
231
+ } else if (nt(n, t, l))
232
232
  continue;
233
233
  if (n.offsetHeight <= e) {
234
234
  const s = document.createElement("div");
@@ -238,11 +238,11 @@ function j(t, e) {
238
238
  a++;
239
239
  }
240
240
  }
241
- function tt(t, e = {}) {
242
- const a = x(e), n = P(), o = N(t, a.pageWidth);
241
+ function ot(t, e = {}) {
242
+ const a = v(e), n = S(), o = F(t, a.pageWidth);
243
243
  T(o);
244
- const i = E(o, a);
245
- return I(o, i.pageContentPx), k(o, i.pageContentPx), j(o, i.pageContentPx), {
244
+ const i = N(o, a);
245
+ return I(o, i.pageContentPx), j(o, i.pageContentPx), z(o, i.pageContentPx), {
246
246
  clone: o,
247
247
  layout: i,
248
248
  options: a,
@@ -251,12 +251,12 @@ function tt(t, e = {}) {
251
251
  }
252
252
  };
253
253
  }
254
- async function rt(t, e, a = {}) {
255
- const { clone: n, layout: o, options: i, cleanup: r } = tt(e, a);
254
+ async function dt(t, e, a = {}) {
255
+ const { clone: n, layout: o, options: i, cleanup: r } = ot(e, a);
256
256
  try {
257
- await V(n), await new Promise((h) => {
257
+ await tt(n), await new Promise((l) => {
258
258
  t.html(n, {
259
- callback: () => h(),
259
+ callback: () => l(),
260
260
  width: o.contentWidthMm,
261
261
  windowWidth: o.renderedWidth,
262
262
  margin: [
@@ -270,7 +270,28 @@ async function rt(t, e, a = {}) {
270
270
  } finally {
271
271
  r();
272
272
  }
273
- return a.marginContent && await _(t, a.marginContent, a), t;
273
+ if (a.forcedPageCount && at(t, a.forcedPageCount), a.marginContent) {
274
+ const l = it(t);
275
+ await gt(t, a.marginContent, a), rt(t, l);
276
+ }
277
+ return t;
278
+ }
279
+ function G(t) {
280
+ if (t == null || !Number.isFinite(t)) return;
281
+ const e = Math.floor(t);
282
+ if (!(e < 1))
283
+ return e;
284
+ }
285
+ function U(t, e) {
286
+ const a = G(e);
287
+ return a ? Math.min(t, a) : t;
288
+ }
289
+ function at(t, e) {
290
+ const a = G(e);
291
+ if (!a) return;
292
+ const n = t.getNumberOfPages();
293
+ for (let o = n; o > a; o--)
294
+ t.deletePage(o);
274
295
  }
275
296
  function A(t, e) {
276
297
  switch (t) {
@@ -305,7 +326,7 @@ async function B(t, e, a, n) {
305
326
  overflow: "hidden"
306
327
  }), o.appendChild(t), document.body.appendChild(o);
307
328
  try {
308
- return await S(o, {
329
+ return await P(o, {
309
330
  scale: n,
310
331
  backgroundColor: null
311
332
  });
@@ -313,10 +334,35 @@ async function B(t, e, a, n) {
313
334
  o.remove();
314
335
  }
315
336
  }
316
- const v = ["top", "right", "bottom", "left"];
317
- async function G(t, e, a) {
337
+ const H = ["top", "right", "bottom", "left"];
338
+ function it(t) {
339
+ var o;
340
+ const e = (o = t.internal) == null ? void 0 : o.pages;
341
+ if (!Array.isArray(e)) return [];
342
+ const a = t.getNumberOfPages(), n = [];
343
+ for (let i = 1; i <= a; i++) {
344
+ const r = e[i];
345
+ n.push(Array.isArray(r) ? r.length : 0);
346
+ }
347
+ return n;
348
+ }
349
+ function rt(t, e) {
350
+ var o;
351
+ const a = (o = t.internal) == null ? void 0 : o.pages;
352
+ if (!Array.isArray(a)) return;
353
+ const n = Math.min(t.getNumberOfPages(), e.length);
354
+ for (let i = 1; i <= n; i++) {
355
+ const r = a[i];
356
+ if (!Array.isArray(r)) continue;
357
+ const l = e[i - 1] ?? r.length;
358
+ if (l < 0 || l >= r.length) continue;
359
+ const s = r.slice(0, l), g = r.slice(l);
360
+ a[i] = [...g, ...s];
361
+ }
362
+ }
363
+ async function R(t, e, a) {
318
364
  const n = {};
319
- for (const o of v) {
365
+ for (const o of H) {
320
366
  const i = t[o];
321
367
  if (i && typeof i != "function") {
322
368
  const r = A(o, e);
@@ -330,7 +376,7 @@ async function G(t, e, a) {
330
376
  }
331
377
  return n;
332
378
  }
333
- function et(t, e) {
379
+ function st(t, e) {
334
380
  return t == null ? e.margin : typeof t == "number" ? M(t) : {
335
381
  top: t.top ?? e.margin.top,
336
382
  right: t.right ?? e.margin.right,
@@ -338,10 +384,10 @@ function et(t, e) {
338
384
  left: t.left ?? e.margin.left
339
385
  };
340
386
  }
341
- const nt = /[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF\u0590-\u05FF]/;
342
- async function R(t, e, a, n, o, i, r, h, s = !1) {
343
- const l = document.createElement("div");
344
- Object.assign(l.style, {
387
+ const ct = /[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF\u0590-\u05FF]/;
388
+ async function E(t, e, a, n, o, i, r, l, s = !1) {
389
+ const g = document.createElement("div");
390
+ Object.assign(g.style, {
345
391
  position: "fixed",
346
392
  left: "-99999px",
347
393
  top: "0",
@@ -355,7 +401,7 @@ async function R(t, e, a, n, o, i, r, h, s = !1) {
355
401
  color: r,
356
402
  display: "flex",
357
403
  alignItems: "center",
358
- gap: `${h}px`,
404
+ gap: `${l}px`,
359
405
  direction: s ? "rtl" : "ltr"
360
406
  });
361
407
  const c = document.createElement("span");
@@ -369,110 +415,110 @@ async function R(t, e, a, n, o, i, r, h, s = !1) {
369
415
  }), document.body.appendChild(c);
370
416
  const d = c.offsetWidth;
371
417
  c.remove();
372
- const g = Math.ceil(e / (d + h)) + 2;
373
- for (let u = 0; u < g; u++) {
374
- const f = document.createElement("span");
375
- f.textContent = t, f.style.flexShrink = "0", l.appendChild(f);
418
+ const h = Math.ceil(e / (d + l)) + 2;
419
+ for (let f = 0; f < h; f++) {
420
+ const m = document.createElement("span");
421
+ m.textContent = t, m.style.flexShrink = "0", g.appendChild(m);
376
422
  }
377
- document.body.appendChild(l);
423
+ document.body.appendChild(g);
378
424
  try {
379
- return await S(l, {
425
+ return await P(g, {
380
426
  scale: 3,
381
427
  backgroundColor: null,
382
428
  width: Math.ceil(e),
383
429
  height: Math.ceil(a)
384
430
  });
385
431
  } finally {
386
- l.remove();
432
+ g.remove();
387
433
  }
388
434
  }
389
- async function U(t, e, a, n, o, i, r) {
435
+ async function q(t, e, a, n, o, i, r) {
390
436
  const {
391
- text: h,
437
+ text: l,
392
438
  color: s = "#000000",
393
- fontSize: l = 2.5,
439
+ fontSize: g = 2.5,
394
440
  fontFamily: c = "Arial, sans-serif",
395
441
  fontWeight: d = "normal"
396
- } = e, g = l * a, u = (e.gap ?? l * 0.5) * a, f = g * 0.5, m = Math.ceil(g * 2.5), p = nt.test(h), y = Math.round(i - f * 2), b = Math.round(r - f * 2), [w, C] = await Promise.all([
397
- R(
398
- h,
442
+ } = e, h = g * a, f = (e.gap ?? g * 0.5) * a, m = h * 0.5, u = Math.ceil(h * 2.5), p = ct.test(l), y = Math.round(i - m * 2), w = Math.round(r - m * 2), [b, C] = await Promise.all([
443
+ E(
444
+ l,
399
445
  y,
400
- m,
401
- g,
446
+ u,
447
+ h,
402
448
  c,
403
449
  d,
404
450
  s,
405
- u,
451
+ f,
406
452
  p
407
453
  ),
408
- R(
454
+ E(
455
+ l,
456
+ w,
457
+ u,
409
458
  h,
410
- b,
411
- m,
412
- g,
413
459
  c,
414
460
  d,
415
461
  s,
416
- u,
462
+ f,
417
463
  p
418
464
  )
419
- ]), H = Math.round(m / 2);
465
+ ]), x = Math.round(u / 2);
420
466
  t.drawImage(
421
- w,
467
+ b,
422
468
  0,
423
469
  0,
424
- w.width,
425
- w.height,
426
- n + f,
427
- o - H,
470
+ b.width,
471
+ b.height,
472
+ n + m,
473
+ o - x,
428
474
  y,
429
- m
475
+ u
430
476
  ), t.drawImage(
431
- w,
477
+ b,
432
478
  0,
433
479
  0,
434
- w.width,
435
- w.height,
436
- n + f,
437
- o + r - H,
480
+ b.width,
481
+ b.height,
482
+ n + m,
483
+ o + r - x,
438
484
  y,
439
- m
440
- ), t.save(), t.translate(n, o + r - f), t.rotate(-Math.PI / 2), t.drawImage(
485
+ u
486
+ ), t.save(), t.translate(n, o + r - m), t.rotate(-Math.PI / 2), t.drawImage(
441
487
  C,
442
488
  0,
443
489
  0,
444
490
  C.width,
445
491
  C.height,
446
492
  0,
447
- -H,
448
- b,
449
- m
450
- ), t.restore(), t.save(), t.translate(n + i, o + f), t.rotate(Math.PI / 2), t.drawImage(
493
+ -x,
494
+ w,
495
+ u
496
+ ), t.restore(), t.save(), t.translate(n + i, o + m), t.rotate(Math.PI / 2), t.drawImage(
451
497
  C,
452
498
  0,
453
499
  0,
454
500
  C.width,
455
501
  C.height,
456
502
  0,
457
- -H,
458
- b,
459
- m
503
+ -x,
504
+ w,
505
+ u
460
506
  ), t.restore();
461
507
  }
462
508
  function W(t, e) {
463
- return et(t.margin, e);
509
+ return st(t.margin, e);
464
510
  }
465
- async function ot(t, e, a, n, o, i, r, h) {
466
- for (const s of v) {
467
- const l = e[s];
468
- if (!l) continue;
511
+ async function $(t, e, a, n, o, i, r, l) {
512
+ for (const s of H) {
513
+ const g = e[s];
514
+ if (!g) continue;
469
515
  const c = A(s, n);
470
516
  let d;
471
- typeof l == "function" ? d = await B(
472
- l(i, r),
517
+ typeof g == "function" ? d = await B(
518
+ g(i, r),
473
519
  c.width,
474
520
  c.height,
475
- h
521
+ l
476
522
  ) : d = a[s], t.drawImage(
477
523
  d,
478
524
  0,
@@ -486,8 +532,8 @@ async function ot(t, e, a, n, o, i, r, h) {
486
532
  );
487
533
  }
488
534
  if (e.contentBorder) {
489
- const { color: s = "#000000", width: l = 0.3 } = e.contentBorder, c = W(e.contentBorder, n);
490
- t.strokeStyle = s, t.lineWidth = l * o, t.strokeRect(
535
+ const { color: s = "#000000", width: g = 0.3 } = e.contentBorder, c = W(e.contentBorder, n);
536
+ t.strokeStyle = s, t.lineWidth = g * o, t.strokeRect(
491
537
  Math.round(c.left * o),
492
538
  Math.round(c.top * o),
493
539
  Math.round((n.pageWidth - c.left - c.right) * o),
@@ -496,7 +542,7 @@ async function ot(t, e, a, n, o, i, r, h) {
496
542
  }
497
543
  if (e.textBorder) {
498
544
  const s = W(e.textBorder, n);
499
- await U(
545
+ await q(
500
546
  t,
501
547
  e.textBorder,
502
548
  o,
@@ -507,7 +553,7 @@ async function ot(t, e, a, n, o, i, r, h) {
507
553
  );
508
554
  }
509
555
  }
510
- function q(t, e) {
556
+ function _(t, e) {
511
557
  const a = e.pageWidth - e.margin.left - e.margin.right, n = e.pageHeight - e.margin.top - e.margin.bottom, o = t.width, i = n / a * o, r = o / a;
512
558
  return {
513
559
  contentWidthMm: a,
@@ -521,7 +567,7 @@ function q(t, e) {
521
567
  marginLeftPx: Math.round(e.margin.left * r)
522
568
  };
523
569
  }
524
- function $(t, e, a) {
570
+ function J(t, e, a) {
525
571
  const n = Math.min(
526
572
  a.contentHeightPx,
527
573
  t.height - e * a.contentHeightPx
@@ -529,23 +575,26 @@ function $(t, e, a) {
529
575
  o.width = a.pageWidthPx, o.height = a.pageHeightPx;
530
576
  const i = o.getContext("2d");
531
577
  if (!i) throw new Error("Could not get canvas context");
532
- return i.fillStyle = "#ffffff", i.fillRect(0, 0, a.pageWidthPx, a.pageHeightPx), i.drawImage(
533
- t,
578
+ return i.fillStyle = "#ffffff", i.fillRect(0, 0, a.pageWidthPx, a.pageHeightPx), { canvas: o, ctx: i, sliceHeight: n };
579
+ }
580
+ function Q(t, e, a, n, o) {
581
+ t.drawImage(
582
+ e,
534
583
  0,
535
- e * a.contentHeightPx,
536
- a.contentWidthPx,
537
- n,
538
- a.marginLeftPx,
539
- a.marginTopPx,
540
- a.contentWidthPx,
541
- n
542
- ), { canvas: o, ctx: i };
543
- }
544
- async function z(t, e) {
545
- const a = P(), n = N(t, e.pageWidth);
584
+ a * n.contentHeightPx,
585
+ n.contentWidthPx,
586
+ o,
587
+ n.marginLeftPx,
588
+ n.marginTopPx,
589
+ n.contentWidthPx,
590
+ o
591
+ );
592
+ }
593
+ async function Z(t, e) {
594
+ const a = S(), n = F(t, e.pageWidth);
546
595
  n.style.opacity = "1", n.style.left = "-99999px", T(n);
547
- const o = E(n, e);
548
- return I(n, o.pageContentPx), k(n, o.pageContentPx), j(n, o.pageContentPx), await K(n), {
596
+ const o = N(n, e);
597
+ return I(n, o.pageContentPx), j(n, o.pageContentPx), z(n, o.pageContentPx), await X(n), {
549
598
  clone: n,
550
599
  layout: o,
551
600
  cleanup: () => {
@@ -553,28 +602,42 @@ async function z(t, e) {
553
602
  }
554
603
  };
555
604
  }
556
- async function st(t, e = {}) {
557
- const { imageFormat: a = "JPEG", imageQuality: n = 0.7, scale: o = 3 } = e, i = x(e), { clone: r, cleanup: h } = await z(t, i);
605
+ async function ft(t, e = {}) {
606
+ const { imageFormat: a = "JPEG", imageQuality: n = 0.7, scale: o = 3 } = e, i = v(e), { clone: r, cleanup: l } = await Z(t, i);
558
607
  try {
559
- const s = await S(r, {
608
+ const s = await P(r, {
560
609
  scale: o,
561
- backgroundColor: "#ffffff"
562
- }), { jsPDF: l } = await import("jspdf"), c = q(s, i), d = Math.ceil(s.height / c.contentHeightPx), g = i.pageWidth > i.pageHeight ? "l" : "p", u = new l({
563
- orientation: g,
610
+ backgroundColor: null
611
+ }), { jsPDF: g } = await import("jspdf"), c = _(s, i), d = Math.ceil(s.height / c.contentHeightPx), h = U(
612
+ d,
613
+ e.forcedPageCount
614
+ ), f = i.pageWidth > i.pageHeight ? "l" : "p", { marginContent: m } = e, u = m ? await R(m, i, o) : {}, p = new g({
615
+ orientation: f,
564
616
  unit: "mm",
565
617
  format: [i.pageWidth, i.pageHeight]
566
618
  });
567
- for (let f = 0; f < d; f++) {
568
- const { canvas: m, ctx: p } = $(
569
- s,
570
- f,
571
- c
572
- ), y = m.toDataURL(
619
+ for (let y = 0; y < h; y++) {
620
+ const {
621
+ canvas: w,
622
+ ctx: b,
623
+ sliceHeight: C
624
+ } = J(s, y, c);
625
+ m && await $(
626
+ b,
627
+ m,
628
+ u,
629
+ i,
630
+ c.pxPerMm,
631
+ y + 1,
632
+ h,
633
+ o
634
+ ), Q(b, s, y, c, C);
635
+ const x = w.toDataURL(
573
636
  `image/${a.toLowerCase()}`,
574
637
  n
575
638
  );
576
- f > 0 && u.addPage([i.pageWidth, i.pageHeight], g), u.addImage(
577
- y,
639
+ y > 0 && p.addPage([i.pageWidth, i.pageHeight], f), p.addImage(
640
+ x,
578
641
  a,
579
642
  0,
580
643
  0,
@@ -584,48 +647,53 @@ async function st(t, e = {}) {
584
647
  "SLOW"
585
648
  );
586
649
  }
587
- return e.marginContent && await _(u, e.marginContent, e), u;
650
+ return p;
588
651
  } finally {
589
- h();
652
+ l();
590
653
  }
591
654
  }
592
- async function at(t, e = {}) {
593
- const { imageFormat: a = "PNG", imageQuality: n = 0.75, scale: o = 2 } = e, i = x(e), { clone: r, cleanup: h } = await z(t, i);
655
+ async function lt(t, e = {}) {
656
+ const { imageFormat: a = "PNG", imageQuality: n = 0.75, scale: o = 2 } = e, i = v(e), { clone: r, cleanup: l } = await Z(t, i);
594
657
  try {
595
- const s = await S(r, {
658
+ const s = await P(r, {
596
659
  scale: o,
597
- backgroundColor: "#ffffff"
598
- }), l = q(s, i), c = Math.ceil(s.height / l.contentHeightPx), d = [], { marginContent: g } = e, u = g ? await G(g, i, o) : {};
599
- for (let f = 0; f < c; f++) {
600
- const { canvas: m, ctx: p } = $(
601
- s,
660
+ backgroundColor: null
661
+ }), g = _(s, i), c = Math.ceil(s.height / g.contentHeightPx), d = U(
662
+ c,
663
+ e.forcedPageCount
664
+ ), h = [], { marginContent: f } = e, m = f ? await R(f, i, o) : {};
665
+ for (let u = 0; u < d; u++) {
666
+ const {
667
+ canvas: p,
668
+ ctx: y,
669
+ sliceHeight: w
670
+ } = J(s, u, g);
671
+ f && await $(
672
+ y,
602
673
  f,
603
- l
604
- );
605
- g && await ot(
606
- p,
607
- g,
608
- u,
674
+ m,
609
675
  i,
610
- l.pxPerMm,
611
- f + 1,
612
- c,
676
+ g.pxPerMm,
677
+ u + 1,
678
+ d,
613
679
  o
614
- ), d.push(
615
- m.toDataURL(
680
+ ), Q(y, s, u, g, w), h.push(
681
+ p.toDataURL(
616
682
  `image/${a.toLowerCase()}`,
617
683
  n
618
684
  )
619
685
  );
620
686
  }
621
- return d;
687
+ return h;
622
688
  } finally {
623
- h();
689
+ l();
624
690
  }
625
691
  }
626
- async function ct(t, e, a = {}) {
627
- const n = x(a), o = await at(t, a);
692
+ async function ut(t, e, a = {}) {
693
+ const n = v(a), o = await lt(t, a);
628
694
  e.innerHTML = "", Object.assign(e.style, {
695
+ display: "flex",
696
+ flexDirection: "column",
629
697
  direction: "ltr",
630
698
  width: "fit-content",
631
699
  height: n.pageHeight + "mm",
@@ -646,62 +714,62 @@ async function ct(t, e, a = {}) {
646
714
  }), r.style.setProperty("display", "inline", "important"), e.appendChild(r);
647
715
  }
648
716
  }
649
- async function _(t, e, a = {}) {
650
- const n = x(a), o = t.getNumberOfPages(), i = 4, r = i * (96 / 25.4), h = P(), s = Math.round(n.pageWidth * r), l = Math.round(n.pageHeight * r), c = await G(e, n, i), d = {};
651
- for (const u of v)
652
- c[u] && (d[u] = c[u].toDataURL("image/png"));
653
- let g;
717
+ async function gt(t, e, a = {}) {
718
+ const n = v(a), o = t.getNumberOfPages(), i = 4, r = i * (96 / 25.4), l = S(), s = Math.round(n.pageWidth * r), g = Math.round(n.pageHeight * r), c = await R(e, n, i), d = {};
719
+ for (const f of H)
720
+ c[f] && (d[f] = c[f].toDataURL("image/png"));
721
+ let h;
654
722
  if (e.textBorder) {
655
- const u = document.createElement("canvas");
656
- u.width = s, u.height = l;
657
- const f = u.getContext("2d");
658
- if (f) {
659
- const m = W(e.textBorder, n);
660
- await U(
661
- f,
723
+ const f = document.createElement("canvas");
724
+ f.width = s, f.height = g;
725
+ const m = f.getContext("2d");
726
+ if (m) {
727
+ const u = W(e.textBorder, n);
728
+ await q(
729
+ m,
662
730
  e.textBorder,
663
731
  r,
664
- Math.round(m.left * r),
665
- Math.round(m.top * r),
666
- Math.round((n.pageWidth - m.left - m.right) * r),
667
- Math.round((n.pageHeight - m.top - m.bottom) * r)
668
- ), g = u.toDataURL("image/png");
732
+ Math.round(u.left * r),
733
+ Math.round(u.top * r),
734
+ Math.round((n.pageWidth - u.left - u.right) * r),
735
+ Math.round((n.pageHeight - u.top - u.bottom) * r)
736
+ ), h = f.toDataURL("image/png");
669
737
  }
670
738
  }
671
- for (let u = 1; u <= o; u++) {
672
- t.setPage(u);
673
- for (const f of v) {
674
- const m = e[f];
675
- if (!m) continue;
676
- const p = A(f, n);
677
- let y, b;
678
- typeof m == "function" ? y = (await B(
679
- m(u, o),
739
+ for (let f = 1; f <= o; f++) {
740
+ t.setPage(f);
741
+ for (const m of H) {
742
+ const u = e[m];
743
+ if (!u) continue;
744
+ const p = A(m, n);
745
+ let y, w;
746
+ typeof u == "function" ? y = (await B(
747
+ u(f, o),
680
748
  p.width,
681
749
  p.height,
682
750
  i
683
- )).toDataURL("image/png") : (y = d[f], b = `margin-${f}`), t.addImage(
751
+ )).toDataURL("image/png") : (y = d[m], w = `margin-${m}`), t.addImage(
684
752
  y,
685
753
  "PNG",
686
754
  p.x,
687
755
  p.y,
688
756
  p.width,
689
757
  p.height,
690
- b,
758
+ w,
691
759
  "SLOW"
692
760
  );
693
761
  }
694
762
  if (e.contentBorder) {
695
- const { color: f = "#000000", width: m = 0.3 } = e.contentBorder, p = W(e.contentBorder, n);
696
- t.setDrawColor(f), t.setLineWidth(m), t.rect(
763
+ const { color: m = "#000000", width: u = 0.3 } = e.contentBorder, p = W(e.contentBorder, n);
764
+ t.setDrawColor(m), t.setLineWidth(u), t.rect(
697
765
  p.left,
698
766
  p.top,
699
767
  n.pageWidth - p.left - p.right,
700
768
  n.pageHeight - p.top - p.bottom
701
769
  );
702
770
  }
703
- g && t.addImage(
704
- g,
771
+ h && t.addImage(
772
+ h,
705
773
  "PNG",
706
774
  0,
707
775
  0,
@@ -711,13 +779,13 @@ async function _(t, e, a = {}) {
711
779
  "SLOW"
712
780
  );
713
781
  }
714
- return h(), t;
782
+ return l(), t;
715
783
  }
716
784
  export {
717
- Q as PAGE_MARGINS,
718
- J as PAGE_SIZES,
719
- st as generateImagePDF,
720
- at as generateImages,
721
- rt as generatePDF,
722
- ct as previewImages
785
+ V as PAGE_MARGINS,
786
+ K as PAGE_SIZES,
787
+ ft as generateImagePDF,
788
+ lt as generateImages,
789
+ dt as generatePDF,
790
+ ut as previewImages
723
791
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jspdf-utils",
3
- "version": "0.1.24",
3
+ "version": "0.1.26",
4
4
  "description": "Utility helpers for jsPDF's doc.html() renderer with automatic page breaking, table splitting, and RTL support",
5
5
  "type": "module",
6
6
  "main": "dist/html-to-pdf.js",