@pdfme/schemas 6.2.3-dev.6 → 6.2.3-dev.8

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.
@@ -1,5 +1,398 @@
1
1
  import { A as getBoxVerticalInset, D as getBoxContentArea, E as createBoxDimension, F as ALIGN_LEFT, I as ALIGN_RIGHT, N as ALIGN_CENTER, O as getBoxDimensionPropPanelSchema, V as DEFAULT_FONT_COLOR, b as splitTextToSize, g as getFontKitFont, it as VERTICAL_ALIGN_MIDDLE, l as getTableBodyRange, o as createTableBodySplitRange, rt as VERTICAL_ALIGN_BOTTOM, x as widthOfTextAtSize, z as DEFAULT_ALIGNMENT } from "./splitRange-B6311Noc.js";
2
2
  import { cloneDeep, getDefaultFont, getFallbackFontName, isBlankPdf, mm2pt, pt2mm } from "@pdfme/common";
3
+ import { Buffer } from "buffer";
4
+ import jpegJsModule from "jpeg-js";
5
+ import UPNGModule from "@pdf-lib/upng";
6
+ //#region src/graphics/imagehelper.ts
7
+ var decoder = new TextDecoder();
8
+ var toUTF8String = (input, start = 0, end = input.length) => decoder.decode(input.slice(start, end));
9
+ var toHexString = (input, start = 0, end = input.length) => input.slice(start, end).reduce((memo, i) => memo + ("0" + i.toString(16)).slice(-2), "");
10
+ var readUInt16BE = (input, offset = 0) => input[offset] * 256 + input[offset + 1];
11
+ var readUInt32BE = (input, offset = 0) => input[offset] * 2 ** 24 + input[offset + 1] * 2 ** 16 + input[offset + 2] * 256 + input[offset + 3];
12
+ var extractSize = (input, index) => {
13
+ return {
14
+ height: readUInt16BE(input, index),
15
+ width: readUInt16BE(input, index + 2)
16
+ };
17
+ };
18
+ var validateInput = (input, index) => {
19
+ if (index > input.length) throw new TypeError("Corrupt JPG, exceeded buffer limits");
20
+ if (input[index] !== 255) throw new TypeError("Invalid JPG, marker table corrupted");
21
+ };
22
+ var JPG = {
23
+ validate: (input) => toHexString(input, 0, 2) === "ffd8",
24
+ calculate(input) {
25
+ input = input.slice(4);
26
+ let next;
27
+ while (input.length) {
28
+ const i = readUInt16BE(input, 0);
29
+ validateInput(input, i);
30
+ next = input[i + 1];
31
+ if (next === 192 || next === 193 || next === 194) return extractSize(input, i + 5);
32
+ input = input.slice(i + 2);
33
+ }
34
+ throw new TypeError("Invalid JPG, no size found");
35
+ }
36
+ };
37
+ var pngSignature = "PNG\r\n\n";
38
+ var pngImageHeaderChunkName = "IHDR";
39
+ var pngFriedChunkName = "CgBI";
40
+ var typeHandlers = {
41
+ jpg: JPG,
42
+ png: {
43
+ validate(input) {
44
+ if (pngSignature === toUTF8String(input, 1, 8)) {
45
+ let chunkName = toUTF8String(input, 12, 16);
46
+ if (chunkName === pngFriedChunkName) chunkName = toUTF8String(input, 28, 32);
47
+ if (chunkName !== pngImageHeaderChunkName) throw new TypeError("Invalid PNG");
48
+ return true;
49
+ }
50
+ return false;
51
+ },
52
+ calculate(input) {
53
+ if (toUTF8String(input, 12, 16) === pngFriedChunkName) return {
54
+ height: readUInt32BE(input, 36),
55
+ width: readUInt32BE(input, 32)
56
+ };
57
+ return {
58
+ height: readUInt32BE(input, 20),
59
+ width: readUInt32BE(input, 16)
60
+ };
61
+ }
62
+ }
63
+ };
64
+ function detector(input) {
65
+ const firstBytes = {
66
+ 137: "png",
67
+ 255: "jpg"
68
+ };
69
+ const byte = input[0];
70
+ if (byte in firstBytes) {
71
+ const type = firstBytes[byte];
72
+ if (type && typeHandlers[type].validate(input)) return type;
73
+ }
74
+ return Object.keys(typeHandlers).find((key) => typeHandlers[key].validate(input));
75
+ }
76
+ /**
77
+ * FNV-1a 32-bit fingerprint of an image data URL.
78
+ * Image embed cache keys are `${type}:${length}:${hash}` and must keep this hash.
79
+ */
80
+ var hashImageDataUrl = (value) => {
81
+ let hash = 2166136261;
82
+ for (let i = 0; i < value.length; i++) {
83
+ hash ^= value.charCodeAt(i);
84
+ hash = Math.imul(hash, 16777619);
85
+ }
86
+ return (hash >>> 0).toString(16).padStart(8, "0");
87
+ };
88
+ var getImageDimension = (value) => {
89
+ if (typeof value !== "string") return imageSize(Buffer.from(value));
90
+ const idx = value.indexOf(";base64,");
91
+ const imgBase64 = value.substring(idx + 8, value.length);
92
+ return imageSize(Buffer.from(imgBase64, "base64"));
93
+ };
94
+ var imageSize = (imgBuffer) => {
95
+ const type = detector(imgBuffer);
96
+ if (typeof type !== "undefined" && type in typeHandlers) {
97
+ const size = typeHandlers[type].calculate(imgBuffer);
98
+ if (size !== void 0) return size;
99
+ }
100
+ throw new TypeError("[@pdfme/schemas/images] Unsupported file type: " + (type === void 0 ? "undefined" : type));
101
+ };
102
+ //#endregion
103
+ //#region src/graphics/orientation.ts
104
+ var isJpegJsApi = (value) => !!value && typeof value === "object" && typeof value.decode === "function" && typeof value.encode === "function";
105
+ var isUPNGApi = (value) => !!value && typeof value === "object" && typeof value.decode === "function" && typeof value.toRGBA8 === "function" && typeof value.encode === "function";
106
+ var resolveExport = (value, guard, label) => {
107
+ let current = value;
108
+ while (current && typeof current === "object") {
109
+ if (guard(current)) return current;
110
+ current = current.default;
111
+ }
112
+ throw new TypeError(`Failed to resolve ${label} exports`);
113
+ };
114
+ var jpegJs = resolveExport(jpegJsModule, isJpegJsApi, "jpeg-js");
115
+ var UPNG = resolveExport(UPNGModule, isUPNGApi, "@pdf-lib/upng");
116
+ var JPEG_ENCODE_QUALITY = 90;
117
+ var JPEG_MAX_MEMORY_MB = 512;
118
+ var JPEG_SOI_0 = 255;
119
+ var JPEG_SOI_1 = 216;
120
+ var PNG_SIGNATURE = new Uint8Array([
121
+ 137,
122
+ 80,
123
+ 78,
124
+ 71,
125
+ 13,
126
+ 10,
127
+ 26,
128
+ 10
129
+ ]);
130
+ var toArrayBuffer = (bytes) => {
131
+ const copy = new Uint8Array(bytes.byteLength);
132
+ copy.set(bytes);
133
+ return copy.buffer;
134
+ };
135
+ var isPngSignature = (bytes) => {
136
+ if (bytes.length < PNG_SIGNATURE.length) return false;
137
+ for (let i = 0; i < PNG_SIGNATURE.length; i++) if (bytes[i] !== PNG_SIGNATURE[i]) return false;
138
+ return true;
139
+ };
140
+ var detectImageFormat = (bytes) => {
141
+ if (bytes.length >= 2 && bytes[0] === JPEG_SOI_0 && bytes[1] === JPEG_SOI_1) return "jpeg";
142
+ if (isPngSignature(bytes)) return "png";
143
+ return "other";
144
+ };
145
+ /** TIFF/IFD0: returns 1..8 or undefined. Never throws. */
146
+ var parseTiffOrientation = (tiff) => {
147
+ try {
148
+ if (tiff.length < 8) return void 0;
149
+ const le = tiff[0] === 73 && tiff[1] === 73;
150
+ if (!le && !(tiff[0] === 77 && tiff[1] === 77)) return void 0;
151
+ const view = new DataView(tiff.buffer, tiff.byteOffset, tiff.byteLength);
152
+ if (view.getUint16(2, le) !== 42) return void 0;
153
+ const ifd = view.getUint32(4, le);
154
+ if (ifd + 2 > tiff.length) return void 0;
155
+ const n = view.getUint16(ifd, le);
156
+ for (let i = 0; i < n; i++) {
157
+ const entry = ifd + 2 + i * 12;
158
+ if (entry + 12 > tiff.length) return void 0;
159
+ if (view.getUint16(entry, le) !== 274) continue;
160
+ if (view.getUint16(entry + 2, le) !== 3) return void 0;
161
+ if (view.getUint32(entry + 4, le) !== 1) return void 0;
162
+ const val = view.getUint16(entry + 8, le);
163
+ return val >= 1 && val <= 8 ? val : void 0;
164
+ }
165
+ return;
166
+ } catch {
167
+ return;
168
+ }
169
+ };
170
+ var isExifApp1Payload = (segment) => segment.length >= 6 && segment[0] === 69 && segment[1] === 120 && segment[2] === 105 && segment[3] === 102 && segment[4] === 0 && segment[5] === 0;
171
+ /** Standalone JPEG markers have no length field (TEM, RST0–7, SOI). */
172
+ var isStandaloneJpegMarker = (marker) => marker === 1 || marker >= 208 && marker <= 216;
173
+ /**
174
+ * JPEG: scan APP1 'Exif\0\0' segments; stop at SOS/EOI.
175
+ * Skips 0xFF fill/padding and standalone markers. If an Exif APP1 has no
176
+ * valid Orientation, keep scanning for a later one.
177
+ */
178
+ var getJpegOrientation = (bytes) => {
179
+ if (bytes.length < 2 || bytes[0] !== JPEG_SOI_0 || bytes[1] !== JPEG_SOI_1) return void 0;
180
+ let pos = 2;
181
+ while (pos < bytes.length) {
182
+ if (bytes[pos] !== 255) return void 0;
183
+ while (pos < bytes.length && bytes[pos] === 255) pos++;
184
+ if (pos >= bytes.length) return void 0;
185
+ const marker = bytes[pos++];
186
+ if (isStandaloneJpegMarker(marker)) continue;
187
+ if (marker === 218 || marker === 217) return void 0;
188
+ if (pos + 2 > bytes.length) return void 0;
189
+ const size = bytes[pos] << 8 | bytes[pos + 1];
190
+ if (size < 2 || pos + size > bytes.length) return void 0;
191
+ if (marker === 225 && size >= 8) {
192
+ const segment = bytes.subarray(pos + 2, pos + size);
193
+ if (isExifApp1Payload(segment)) {
194
+ const orientation = parseTiffOrientation(segment.subarray(6));
195
+ if (orientation !== void 0) return orientation;
196
+ }
197
+ }
198
+ pos += size;
199
+ }
200
+ };
201
+ /**
202
+ * PNG: scan chunks for eXIf (raw TIFF payload). Skip IDAT and other
203
+ * ancillary chunks; eXIf may appear after image data. Stop at IEND.
204
+ */
205
+ var getPngOrientation = (bytes) => {
206
+ if (!isPngSignature(bytes)) return void 0;
207
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
208
+ let pos = 8;
209
+ while (pos + 12 <= bytes.length) {
210
+ const length = view.getUint32(pos);
211
+ if (pos + 12 + length > bytes.length) return void 0;
212
+ const type = String.fromCharCode(bytes[pos + 4], bytes[pos + 5], bytes[pos + 6], bytes[pos + 7]);
213
+ if (type === "eXIf") return parseTiffOrientation(bytes.subarray(pos + 8, pos + 8 + length));
214
+ if (type === "IEND") return void 0;
215
+ pos += 12 + length;
216
+ }
217
+ };
218
+ var orientationSwapsDimensions = (orientation) => orientation >= 5;
219
+ /**
220
+ * Map source (x, y) into destination (dx, dy) for EXIF orientations 2–8.
221
+ * Orientations 5–8 swap width and height.
222
+ */
223
+ var transformRgba = (src, width, height, orientation) => {
224
+ const swap = orientationSwapsDimensions(orientation);
225
+ const destWidth = swap ? height : width;
226
+ const destHeight = swap ? width : height;
227
+ const dest = new Uint8Array(destWidth * destHeight * 4);
228
+ for (let y = 0; y < height; y++) for (let x = 0; x < width; x++) {
229
+ let dx = x;
230
+ let dy = y;
231
+ switch (orientation) {
232
+ case 2:
233
+ dx = width - 1 - x;
234
+ dy = y;
235
+ break;
236
+ case 3:
237
+ dx = width - 1 - x;
238
+ dy = height - 1 - y;
239
+ break;
240
+ case 4:
241
+ dx = x;
242
+ dy = height - 1 - y;
243
+ break;
244
+ case 5:
245
+ dx = y;
246
+ dy = x;
247
+ break;
248
+ case 6:
249
+ dx = height - 1 - y;
250
+ dy = x;
251
+ break;
252
+ case 7:
253
+ dx = height - 1 - y;
254
+ dy = width - 1 - x;
255
+ break;
256
+ case 8:
257
+ dx = y;
258
+ dy = width - 1 - x;
259
+ }
260
+ const srcIndex = (y * width + x) * 4;
261
+ const destIndex = (dy * destWidth + dx) * 4;
262
+ dest[destIndex] = src[srcIndex];
263
+ dest[destIndex + 1] = src[srcIndex + 1];
264
+ dest[destIndex + 2] = src[srcIndex + 2];
265
+ dest[destIndex + 3] = src[srcIndex + 3];
266
+ }
267
+ return {
268
+ data: dest,
269
+ width: destWidth,
270
+ height: destHeight
271
+ };
272
+ };
273
+ var bakeJpegOrientation = (bytes) => {
274
+ const orientation = getJpegOrientation(bytes);
275
+ if (!orientation || orientation === 1) return bytes;
276
+ const raw = jpegJs.decode(bytes, {
277
+ useTArray: true,
278
+ formatAsRGBA: true,
279
+ maxMemoryUsageInMB: JPEG_MAX_MEMORY_MB
280
+ });
281
+ const transformed = transformRgba(raw.data, raw.width, raw.height, orientation);
282
+ return new Uint8Array(jpegJs.encode({
283
+ data: transformed.data,
284
+ width: transformed.width,
285
+ height: transformed.height
286
+ }, JPEG_ENCODE_QUALITY).data);
287
+ };
288
+ var bakePngOrientation = (bytes) => {
289
+ const orientation = getPngOrientation(bytes);
290
+ if (!orientation || orientation === 1) return bytes;
291
+ const img = UPNG.decode(toArrayBuffer(bytes));
292
+ const transformed = transformRgba(new Uint8Array(UPNG.toRGBA8(img)[0]), img.width, img.height, orientation);
293
+ return new Uint8Array(UPNG.encode([toArrayBuffer(transformed.data)], transformed.width, transformed.height, 0));
294
+ };
295
+ /**
296
+ * One normalize path for JPEG and PNG. Tag absent/1 is a byte-identical
297
+ * passthrough. Tag 2–8 decodes, transforms pixels, and re-encodes without
298
+ * an orientation tag. May throw on decode/encode failure — callers fall back.
299
+ */
300
+ var normalizeImageOrientation = (bytes) => {
301
+ const kind = detectImageFormat(bytes);
302
+ if (kind === "jpeg") return bakeJpegOrientation(bytes);
303
+ if (kind === "png") return bakePngOrientation(bytes);
304
+ return bytes;
305
+ };
306
+ //#endregion
307
+ //#region src/tables/constants.ts
308
+ var DEFAULT_TABLE_IMAGE_HEIGHT_MODE = "fixed";
309
+ var TABLE_IMAGE_DATA_URL_PATTERN = /^data:image\/(png|jpe?g);base64,/i;
310
+ //#endregion
311
+ //#region src/tables/types.ts
312
+ var TABLE_CELL_TYPES = ["text", "image"];
313
+ var TABLE_IMAGE_HEIGHT_MODES = ["fixed", "auto"];
314
+ //#endregion
315
+ //#region src/tables/imageCell.ts
316
+ var DIMENSION_CACHE_PREFIX = "tableImageDim:";
317
+ var WARN_CACHE_PREFIX = "tableImageWarned:";
318
+ var FAILED_DIMENSION = null;
319
+ var isTableCellType = (value) => typeof value === "string" && TABLE_CELL_TYPES.some((cellType) => cellType === value);
320
+ var isDimension = (value) => {
321
+ if (!value || typeof value !== "object") return false;
322
+ const record = value;
323
+ return typeof record.width === "number" && typeof record.height === "number";
324
+ };
325
+ var dataUrlToBytes = (value) => {
326
+ const index = value.indexOf(";base64,");
327
+ const base64 = index >= 0 ? value.slice(index + 8) : value;
328
+ return new Uint8Array(Buffer.from(base64, "base64"));
329
+ };
330
+ var applyOrientation = (dimension, bytes) => {
331
+ const format = detectImageFormat(bytes);
332
+ const orientation = format === "jpeg" ? getJpegOrientation(bytes) : format === "png" ? getPngOrientation(bytes) : void 0;
333
+ if (orientation !== void 0 && orientationSwapsDimensions(orientation)) return {
334
+ width: dimension.height,
335
+ height: dimension.width
336
+ };
337
+ return dimension;
338
+ };
339
+ var isTableImageDataUrl = (value) => TABLE_IMAGE_DATA_URL_PATTERN.test(value);
340
+ var imageCacheSuffix = (value) => `${value.length}:${hashImageDataUrl(value)}`;
341
+ var resolveImageDimension = (value, cache) => {
342
+ if (!isTableImageDataUrl(value)) return void 0;
343
+ const key = `${DIMENSION_CACHE_PREFIX}${imageCacheSuffix(value)}`;
344
+ const cached = cache.get(key);
345
+ if (cached === FAILED_DIMENSION) return void 0;
346
+ if (isDimension(cached)) return cached;
347
+ try {
348
+ const bytes = dataUrlToBytes(value);
349
+ const dimension = applyOrientation(getImageDimension(bytes), bytes);
350
+ cache.set(key, dimension);
351
+ return dimension;
352
+ } catch {
353
+ cache.set(key, FAILED_DIMENSION);
354
+ return;
355
+ }
356
+ };
357
+ var warnInvalidTableImageOnce = (value, columnIndex, cache) => {
358
+ if (value == null || value === "") return;
359
+ const key = `${WARN_CACHE_PREFIX}${imageCacheSuffix(value)}`;
360
+ if (cache.has(key)) return;
361
+ cache.set(key, true);
362
+ console.warn(`[@pdfme/schemas/table] unsupported image in column ${columnIndex}; only PNG/JPEG data URL is supported`);
363
+ };
364
+ var normalizeTableCellType = (value, columnIndex, cache) => {
365
+ if (value == null) return void 0;
366
+ if (isTableCellType(value)) return value;
367
+ const warnKey = `tableCellTypeWarned:${String(value)}`;
368
+ if (!cache.has(warnKey)) {
369
+ cache.set(warnKey, true);
370
+ console.warn(`[@pdfme/schemas/table] unsupported cell type "${String(value)}" in column ${columnIndex}; treating as text`);
371
+ }
372
+ return "text";
373
+ };
374
+ var normalizeTableImageHeightMode = (value) => value === "fixed" || value === "auto" ? value : void 0;
375
+ var normalizeTableImageHeight = (value) => typeof value === "number" && Number.isFinite(value) ? value : void 0;
376
+ var getTableImageObjectPosition = (alignment, verticalAlignment) => {
377
+ return `${alignment === "center" || alignment === "right" ? alignment : "left"} ${verticalAlignment === "top" ? "top" : verticalAlignment === "bottom" ? "bottom" : "center"}`;
378
+ };
379
+ var resolveFixedTableImageHeight = (imageHeight) => typeof imageHeight === "number" && Number.isFinite(imageHeight) && imageHeight > 0 ? imageHeight : 20;
380
+ /**
381
+ * Fixed height is kept for empty and invalid values so rows in the column stay aligned.
382
+ * Auto height is 0 unless a PNG/JPEG data URL resolves.
383
+ */
384
+ var resolveTableImageContentHeight = (arg) => {
385
+ const mode = arg.mode ?? "fixed";
386
+ if (!arg.value) return mode === "auto" ? 0 : resolveFixedTableImageHeight(arg.imageHeight);
387
+ const dimension = resolveImageDimension(arg.value, arg.cache);
388
+ if (!dimension || dimension.width <= 0) {
389
+ warnInvalidTableImageOnce(arg.value, arg.columnIndex, arg.cache);
390
+ return mode === "auto" ? 0 : resolveFixedTableImageHeight(arg.imageHeight);
391
+ }
392
+ if (mode === "auto") return arg.contentWidth * dimension.height / dimension.width;
393
+ return resolveFixedTableImageHeight(arg.imageHeight);
394
+ };
395
+ //#endregion
3
396
  //#region \0@oxc-project+runtime@0.151.0/helpers/esm/typeof.js
4
397
  function _typeof(o) {
5
398
  "@babel/helpers - typeof";
@@ -50,6 +443,7 @@ var Cell = class {
50
443
  _defineProperty(this, "wrappedWidth", 0);
51
444
  _defineProperty(this, "minReadableWidth", 0);
52
445
  _defineProperty(this, "minWidth", 0);
446
+ _defineProperty(this, "imageContentHeight", 0);
53
447
  _defineProperty(this, "width", 0);
54
448
  _defineProperty(this, "height", 0);
55
449
  _defineProperty(this, "x", 0);
@@ -60,8 +454,13 @@ var Cell = class {
60
454
  const splitRegex = /\r\n|\r|\n/g;
61
455
  this.text = raw.split(splitRegex);
62
456
  }
457
+ isImage() {
458
+ return this.section !== "head" && this.styles.cellType === "image";
459
+ }
63
460
  getContentHeight() {
64
- const height = (Array.isArray(this.text) ? this.text.length : 1) * (pt2mm(this.styles.fontSize) * this.styles.lineHeight) + getBoxVerticalInset(getCellBoxStyle(this));
461
+ const verticalInset = getBoxVerticalInset(getCellBoxStyle(this));
462
+ if (this.isImage()) return Math.max(this.imageContentHeight + verticalInset, this.styles.minCellHeight);
463
+ const height = (Array.isArray(this.text) ? this.text.length : 1) * (pt2mm(this.styles.fontSize) * this.styles.lineHeight) + verticalInset;
65
464
  return Math.max(height, this.styles.minCellHeight);
66
465
  }
67
466
  padding(name) {
@@ -128,11 +527,12 @@ var Table = class Table {
128
527
  this.body = content.body;
129
528
  }
130
529
  static async create(arg) {
131
- const { input, content, font, _cache } = arg;
530
+ const { input, content, font, basePdf, _cache } = arg;
132
531
  const table = new Table(input, content);
133
532
  await calculateWidths({
134
533
  table,
135
534
  font,
535
+ basePdf,
136
536
  _cache
137
537
  });
138
538
  return table;
@@ -154,7 +554,7 @@ var Table = class Table {
154
554
  }
155
555
  };
156
556
  async function calculateWidths(arg) {
157
- const { table, font, _cache } = arg;
557
+ const { table, font, basePdf, _cache } = arg;
158
558
  const getFontKitFontByFontName = (fontName) => getFontKitFont(fontName, font, _cache);
159
559
  await calculate(table, getFontKitFontByFontName);
160
560
  const resizableColumns = [];
@@ -173,7 +573,7 @@ async function calculateWidths(arg) {
173
573
  if (resizeWidth) resizeWidth = resizeColumns(resizableColumns, resizeWidth, (column) => column.minWidth);
174
574
  resizeWidth = Math.abs(resizeWidth);
175
575
  applyColSpans(table);
176
- await fitContent(table, getFontKitFontByFontName);
576
+ await fitContent(table, getFontKitFontByFontName, basePdf, _cache);
177
577
  applyRowSpans(table);
178
578
  }
179
579
  function applyRowSpans(table) {
@@ -229,7 +629,15 @@ function applyColSpans(table) {
229
629
  }
230
630
  }
231
631
  }
232
- async function fitContent(table, getFontKitFontByFontName) {
632
+ var autoImageHeightLimit = (table, cell, basePdf) => {
633
+ if (!isBlankPdf(basePdf)) return void 0;
634
+ const [paddingTop, , paddingBottom] = basePdf.padding;
635
+ const pageContentHeight = basePdf.height - paddingTop - paddingBottom;
636
+ const headHeight = table.settings.templateShowHead ? table.head.reduce((sum, row) => sum + row.height, 0) : 0;
637
+ const verticalInset = getBoxVerticalInset(getCellBoxStyle(cell));
638
+ return pageContentHeight - headHeight - verticalInset - 1;
639
+ };
640
+ async function fitContent(table, getFontKitFontByFontName, basePdf, cache) {
233
641
  const rowSpanHeight = {
234
642
  count: 0,
235
643
  height: 0
@@ -238,7 +646,6 @@ async function fitContent(table, getFontKitFontByFontName) {
238
646
  for (const column of table.columns) {
239
647
  const cell = row.cells[column.index];
240
648
  if (!cell) continue;
241
- const fontKitFont = await getFontKitFontByFontName(cell.styles.fontName);
242
649
  const contentArea = getBoxContentArea({
243
650
  position: {
244
651
  x: 0,
@@ -248,13 +655,31 @@ async function fitContent(table, getFontKitFontByFontName) {
248
655
  height: cell.height,
249
656
  ...getCellBoxStyle(cell)
250
657
  });
251
- cell.text = splitTextToSize({
252
- value: cell.raw,
253
- characterSpacing: cell.styles.characterSpacing,
254
- boxWidthInPt: mm2pt(contentArea.width),
255
- fontSize: cell.styles.fontSize,
256
- fontKitFont
257
- });
658
+ if (cell.isImage()) {
659
+ cell.text = [];
660
+ let imageContentHeight = resolveTableImageContentHeight({
661
+ value: cell.raw,
662
+ mode: cell.styles.imageHeightMode,
663
+ imageHeight: cell.styles.imageHeight,
664
+ contentWidth: contentArea.width,
665
+ columnIndex: column.index,
666
+ cache
667
+ });
668
+ if ((cell.styles.imageHeightMode ?? "fixed") === "auto") {
669
+ const limit = autoImageHeightLimit(table, cell, basePdf);
670
+ if (limit !== void 0) imageContentHeight = Math.min(imageContentHeight, Math.max(0, limit));
671
+ }
672
+ cell.imageContentHeight = imageContentHeight;
673
+ } else {
674
+ const fontKitFont = await getFontKitFontByFontName(cell.styles.fontName);
675
+ cell.text = splitTextToSize({
676
+ value: cell.raw,
677
+ characterSpacing: cell.styles.characterSpacing,
678
+ boxWidthInPt: mm2pt(contentArea.width),
679
+ fontSize: cell.styles.fontSize,
680
+ fontKitFont
681
+ });
682
+ }
258
683
  cell.contentHeight = cell.getContentHeight();
259
684
  let realContentHeight = cell.contentHeight;
260
685
  if (rowSpanHeight && rowSpanHeight.count > 0) {
@@ -291,6 +716,13 @@ async function calculate(table, getFontKitFontByFontName) {
291
716
  const cell = row.cells[column.index];
292
717
  if (!cell) continue;
293
718
  const hPadding = cell.padding("right") + cell.padding("left");
719
+ if (cell.isImage()) {
720
+ cell.contentWidth = hPadding;
721
+ cell.minReadableWidth = hPadding;
722
+ cell.minWidth = cell.styles.cellWidth;
723
+ cell.wrappedWidth = cell.styles.cellWidth;
724
+ continue;
725
+ }
294
726
  const fontKitFont = await getFontKitFontByFontName(cell.styles.fontName);
295
727
  cell.contentWidth = getStringWidth(cell, fontKitFont) + hPadding;
296
728
  cell.minReadableWidth = getStringWidth(Object.assign(cell, { text: cell.text.join(" ").split(/\s+/) }), fontKitFont) + hPadding;
@@ -404,24 +836,51 @@ function mapCellStyle(style) {
404
836
  };
405
837
  return Object.fromEntries(Object.entries(mapping).filter(([, value]) => value !== void 0));
406
838
  }
407
- function getTableOptions(schema, body) {
839
+ function getTableOptions(schema, body, cache) {
408
840
  const columnStylesWidth = schema.headWidthPercentages.reduce((acc, cur, i) => ({
409
841
  ...acc,
410
842
  [i]: { cellWidth: schema.width * (cur / 100) }
411
843
  }), {});
412
- const columnStylesAlignment = Object.entries(schema.columnStyles.alignment || {}).reduce((acc, [key, value]) => ({
844
+ const alignmentMap = schema.columnStyles.alignment || {};
845
+ const verticalAlignmentMap = schema.columnStyles.verticalAlignment || {};
846
+ const cellTypeMap = schema.columnStyles.cellType || {};
847
+ const imageHeightModeMap = schema.columnStyles.imageHeightMode || {};
848
+ const imageHeightMap = schema.columnStyles.imageHeight || {};
849
+ const columnStylesAlignment = Object.entries(alignmentMap).reduce((acc, [key, value]) => ({
413
850
  ...acc,
414
851
  [key]: { alignment: value }
415
852
  }), {});
416
- const allKeys = /* @__PURE__ */ new Set([...Object.keys(columnStylesWidth).map(Number), ...Object.keys(columnStylesAlignment).map(Number)]);
853
+ const columnStylesVerticalAlignment = Object.entries(verticalAlignmentMap).reduce((acc, [key, value]) => ({
854
+ ...acc,
855
+ [key]: { verticalAlignment: value }
856
+ }), {});
857
+ const allKeys = /* @__PURE__ */ new Set([
858
+ ...Object.keys(columnStylesWidth).map(Number),
859
+ ...Object.keys(columnStylesAlignment).map(Number),
860
+ ...Object.keys(columnStylesVerticalAlignment).map(Number),
861
+ ...Object.keys(cellTypeMap).map(Number),
862
+ ...Object.keys(imageHeightModeMap).map(Number),
863
+ ...Object.keys(imageHeightMap).map(Number)
864
+ ]);
417
865
  const columnStyles = Array.from(allKeys).reduce((acc, key) => {
418
866
  const widthStyle = columnStylesWidth[key] || {};
419
867
  const alignmentStyle = columnStylesAlignment[key] || {};
868
+ const verticalAlignmentStyle = columnStylesVerticalAlignment[key] || {};
869
+ const cellType = normalizeTableCellType(cellTypeMap[key], key, cache);
870
+ const imageHeightMode = normalizeTableImageHeightMode(imageHeightModeMap[key]);
871
+ const imageHeight = normalizeTableImageHeight(imageHeightMap[key]);
872
+ const imageStyle = {
873
+ ...cellType ? { cellType } : {},
874
+ ...imageHeightMode ? { imageHeightMode } : {},
875
+ ...imageHeight !== void 0 ? { imageHeight } : {}
876
+ };
420
877
  return {
421
878
  ...acc,
422
879
  [key]: {
423
880
  ...widthStyle,
424
- ...alignmentStyle
881
+ ...alignmentStyle,
882
+ ...verticalAlignmentStyle,
883
+ ...imageStyle
425
884
  }
426
885
  };
427
886
  }, {});
@@ -471,14 +930,15 @@ function parseContent4Input(options) {
471
930
  body
472
931
  };
473
932
  }
474
- function parseInput(schema, body) {
475
- const options = getTableOptions(schema, body);
933
+ function parseInput(schema, body, cache, templateShowHead) {
934
+ const options = getTableOptions(schema, body, cache);
476
935
  const styles = parseStyles(options);
477
936
  const settings = {
478
937
  startY: options.startY,
479
938
  margin: options.margin,
480
939
  tableWidth: options.tableWidth,
481
940
  showHead: options.showHead,
941
+ templateShowHead,
482
942
  tableLineWidth: options.tableLineWidth ?? 0,
483
943
  tableLineColor: options.tableLineColor ?? ""
484
944
  };
@@ -498,14 +958,16 @@ function createSingleTable(body, args) {
498
958
  schema.bodyStyles.alternateBackgroundColor = schema.bodyStyles.backgroundColor;
499
959
  schema.bodyStyles.backgroundColor = alternateBackgroundColor;
500
960
  }
961
+ const templateShowHead = schema.showHead !== false;
501
962
  schema.showHead = schema.showHead === false ? false : !schema.__isSplit || schema.repeatHead === true;
502
- const input = parseInput(schema, body);
963
+ const input = parseInput(schema, body, _cache, templateShowHead);
503
964
  const font = options.font || getDefaultFont();
504
965
  const content = parseContent4Table(input, getFallbackFontName(font));
505
966
  return Table.create({
506
967
  input,
507
968
  content,
508
969
  font,
970
+ basePdf,
509
971
  _cache
510
972
  });
511
973
  }
@@ -667,31 +1129,6 @@ var getCellPropPanelSchema = (arg) => {
667
1129
  }
668
1130
  };
669
1131
  };
670
- var getColumnStylesPropPanelSchema = ({ head, i18n }) => ({ alignment: {
671
- type: "object",
672
- widget: "lineTitle",
673
- title: i18n("schemas.text.textAlign"),
674
- column: 3,
675
- properties: head.reduce((acc, cur, i) => Object.assign(acc, { [i]: {
676
- title: cur || "Column " + String(i + 1),
677
- type: "string",
678
- widget: "select",
679
- props: { options: [
680
- {
681
- label: i18n("schemas.left"),
682
- value: ALIGN_LEFT
683
- },
684
- {
685
- label: i18n("schemas.center"),
686
- value: ALIGN_CENTER
687
- },
688
- {
689
- label: i18n("schemas.right"),
690
- value: ALIGN_RIGHT
691
- }
692
- ] }
693
- } }), {})
694
- } });
695
1132
  var getBody = (value) => {
696
1133
  if (typeof value === "string") return JSON.parse(value || "[]");
697
1134
  return value || [];
@@ -750,9 +1187,11 @@ var getDynamicHeightsForTable = async (value, args) => {
750
1187
  const initialPageIndex = Math.max(0, Math.floor((schema.position.y - paddingTop) / pageContentHeight));
751
1188
  const headRowCount = schema.showHead ? table.head.length : 0;
752
1189
  const SAFETY_MARGIN = .5;
1190
+ const EPSILON = .01;
753
1191
  let currentPageIndex = initialPageIndex;
754
1192
  let currentPageY = schema.position.y;
755
1193
  let rowsOnCurrentPage = 0;
1194
+ let headerTravelsWithBody = false;
756
1195
  const result = [];
757
1196
  for (let i = 0; i < baseHeights.length; i++) {
758
1197
  const isBodyRow = i >= headRowCount;
@@ -760,26 +1199,37 @@ var getDynamicHeightsForTable = async (value, args) => {
760
1199
  while (true) {
761
1200
  const currentPageStartY = getPageStartY(currentPageIndex);
762
1201
  const remainingHeight = currentPageStartY + pageContentHeight - currentPageY;
763
- const totalRowHeight = rowHeight + (isBodyRow && rowsOnCurrentPage === 0 && currentPageIndex > initialPageIndex ? headerHeight : 0);
764
- if (totalRowHeight > remainingHeight - SAFETY_MARGIN) {
1202
+ const totalRowHeight = rowHeight + (isBodyRow && rowsOnCurrentPage === 0 && currentPageIndex > initialPageIndex && !headerTravelsWithBody ? headerHeight : 0);
1203
+ if (totalRowHeight > remainingHeight - SAFETY_MARGIN + EPSILON) {
765
1204
  if (rowsOnCurrentPage === 0 && Math.abs(currentPageY - currentPageStartY) < SAFETY_MARGIN) {
766
1205
  result.push(totalRowHeight);
767
1206
  currentPageY += totalRowHeight;
768
1207
  rowsOnCurrentPage++;
1208
+ headerTravelsWithBody = false;
769
1209
  break;
770
1210
  }
1211
+ const headerWouldBeAlone = !headerTravelsWithBody && currentPageIndex === initialPageIndex && isBodyRow && headRowCount > 0 && result.length === headRowCount && rowsOnCurrentPage === headRowCount;
771
1212
  currentPageIndex++;
772
- currentPageY = getPageStartY(currentPageIndex);
773
- rowsOnCurrentPage = 0;
1213
+ if (headerWouldBeAlone) {
1214
+ headerTravelsWithBody = true;
1215
+ currentPageY = getPageStartY(currentPageIndex) + headerHeight;
1216
+ rowsOnCurrentPage = headRowCount;
1217
+ } else {
1218
+ headerTravelsWithBody = false;
1219
+ currentPageY = getPageStartY(currentPageIndex);
1220
+ rowsOnCurrentPage = 0;
1221
+ }
774
1222
  continue;
775
1223
  }
776
1224
  result.push(totalRowHeight);
777
1225
  currentPageY += totalRowHeight;
778
1226
  rowsOnCurrentPage++;
1227
+ if (isBodyRow) headerTravelsWithBody = false;
779
1228
  if (currentPageY >= currentPageStartY + pageContentHeight - SAFETY_MARGIN) {
780
1229
  currentPageIndex++;
781
1230
  currentPageY = getPageStartY(currentPageIndex);
782
1231
  rowsOnCurrentPage = 0;
1232
+ headerTravelsWithBody = false;
783
1233
  }
784
1234
  break;
785
1235
  }
@@ -803,6 +1253,6 @@ var getDynamicLayoutForTable = async (value, args) => {
803
1253
  };
804
1254
  };
805
1255
  //#endregion
806
- export { getCellPropPanelSchema as a, remapColumnStylesOnRemove as c, createSingleTable as d, getBodyWithSchemaRange as i, HEX_COLOR_PATTERN as l, getDynamicLayoutForTable as n, getColumnStylesPropPanelSchema as o, getBody as r, getDefaultCellStyles as s, getDynamicHeightsForTable as t, OPAQUE_HEX_COLOR_PATTERN as u };
1256
+ export { hashImageDataUrl as C, normalizeImageOrientation as S, TABLE_CELL_TYPES as _, getCellPropPanelSchema as a, TABLE_IMAGE_DATA_URL_PATTERN as b, HEX_COLOR_PATTERN as c, getTableImageObjectPosition as d, normalizeTableCellType as f, warnInvalidTableImageOnce as g, resolveImageDimension as h, getBodyWithSchemaRange as i, OPAQUE_HEX_COLOR_PATTERN as l, resolveFixedTableImageHeight as m, getDynamicLayoutForTable as n, getDefaultCellStyles as o, normalizeTableImageHeightMode as p, getBody as r, remapColumnStylesOnRemove as s, getDynamicHeightsForTable as t, createSingleTable as u, TABLE_IMAGE_HEIGHT_MODES as v, detectImageFormat as x, DEFAULT_TABLE_IMAGE_HEIGHT_MODE as y };
807
1257
 
808
- //# sourceMappingURL=dynamicTemplate-Zqt6kNsE.js.map
1258
+ //# sourceMappingURL=dynamicTemplate-Bnu4jVaz.js.map