@cj-tech-master/excelts 6.2.0 → 7.0.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.
Files changed (56) hide show
  1. package/README.md +45 -17
  2. package/README_zh.md +43 -15
  3. package/dist/browser/index.browser.d.ts +1 -1
  4. package/dist/browser/index.browser.js +1 -1
  5. package/dist/browser/index.d.ts +2 -2
  6. package/dist/browser/index.js +1 -1
  7. package/dist/browser/modules/excel/stream/workbook-writer.browser.d.ts +0 -2
  8. package/dist/browser/modules/excel/stream/workbook-writer.d.ts +2 -2
  9. package/dist/browser/modules/excel/types.d.ts +0 -2
  10. package/dist/browser/modules/pdf/excel-bridge.d.ts +29 -0
  11. package/dist/browser/modules/pdf/excel-bridge.js +423 -0
  12. package/dist/browser/modules/pdf/index.d.ts +22 -24
  13. package/dist/browser/modules/pdf/index.js +22 -25
  14. package/dist/browser/modules/pdf/pdf.d.ts +121 -0
  15. package/dist/browser/modules/pdf/pdf.js +255 -0
  16. package/dist/browser/modules/pdf/render/layout-engine.d.ts +10 -8
  17. package/dist/browser/modules/pdf/render/layout-engine.js +115 -209
  18. package/dist/browser/modules/pdf/render/pdf-exporter.d.ts +9 -62
  19. package/dist/browser/modules/pdf/render/pdf-exporter.js +38 -78
  20. package/dist/browser/modules/pdf/render/style-converter.d.ts +20 -18
  21. package/dist/browser/modules/pdf/render/style-converter.js +24 -23
  22. package/dist/browser/modules/pdf/types.d.ts +193 -11
  23. package/dist/browser/modules/pdf/types.js +22 -1
  24. package/dist/cjs/index.js +3 -3
  25. package/dist/cjs/modules/pdf/excel-bridge.js +426 -0
  26. package/dist/cjs/modules/pdf/index.js +25 -28
  27. package/dist/cjs/modules/pdf/pdf.js +258 -0
  28. package/dist/cjs/modules/pdf/render/layout-engine.js +116 -210
  29. package/dist/cjs/modules/pdf/render/pdf-exporter.js +37 -79
  30. package/dist/cjs/modules/pdf/render/style-converter.js +24 -23
  31. package/dist/cjs/modules/pdf/types.js +23 -2
  32. package/dist/esm/index.browser.js +1 -1
  33. package/dist/esm/index.js +1 -1
  34. package/dist/esm/modules/pdf/excel-bridge.js +423 -0
  35. package/dist/esm/modules/pdf/index.js +22 -25
  36. package/dist/esm/modules/pdf/pdf.js +255 -0
  37. package/dist/esm/modules/pdf/render/layout-engine.js +115 -209
  38. package/dist/esm/modules/pdf/render/pdf-exporter.js +38 -78
  39. package/dist/esm/modules/pdf/render/style-converter.js +24 -23
  40. package/dist/esm/modules/pdf/types.js +22 -1
  41. package/dist/iife/excelts.iife.js +728 -251
  42. package/dist/iife/excelts.iife.js.map +1 -1
  43. package/dist/iife/excelts.iife.min.js +34 -34
  44. package/dist/types/index.browser.d.ts +1 -1
  45. package/dist/types/index.d.ts +2 -2
  46. package/dist/types/modules/excel/stream/workbook-writer.browser.d.ts +0 -2
  47. package/dist/types/modules/excel/stream/workbook-writer.d.ts +2 -2
  48. package/dist/types/modules/excel/types.d.ts +0 -2
  49. package/dist/types/modules/pdf/excel-bridge.d.ts +29 -0
  50. package/dist/types/modules/pdf/index.d.ts +22 -24
  51. package/dist/types/modules/pdf/pdf.d.ts +121 -0
  52. package/dist/types/modules/pdf/render/layout-engine.d.ts +10 -8
  53. package/dist/types/modules/pdf/render/pdf-exporter.d.ts +9 -62
  54. package/dist/types/modules/pdf/render/style-converter.d.ts +20 -18
  55. package/dist/types/modules/pdf/types.d.ts +193 -11
  56. package/package.json +1 -1
@@ -0,0 +1,426 @@
1
+ "use strict";
2
+ /**
3
+ * Excel-to-PDF Bridge
4
+ *
5
+ * Converts Excel Workbook data into the PDF module's independent data model.
6
+ * This is the ONLY file in the PDF module that imports from @excel.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { Workbook } from "excelts";
11
+ * import { excelToPdf } from "excelts/pdf";
12
+ *
13
+ * const workbook = new Workbook();
14
+ * // ... build workbook ...
15
+ * const pdf = excelToPdf(workbook);
16
+ * ```
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.excelToPdf = excelToPdf;
20
+ const enums_1 = require("../excel/enums.js");
21
+ const cell_format_1 = require("../excel/utils/cell-format.js");
22
+ const utils_base_1 = require("../../utils/utils.base.js");
23
+ const pdf_exporter_1 = require("./render/pdf-exporter");
24
+ const types_1 = require("./types");
25
+ // =============================================================================
26
+ // Public API
27
+ // =============================================================================
28
+ /**
29
+ * Export an Excel Workbook directly to PDF.
30
+ *
31
+ * This is a convenience function that converts the Workbook to the PDF module's
32
+ * data model and then generates the PDF.
33
+ *
34
+ * @param workbook - An Excel Workbook instance
35
+ * @param options - PDF export options
36
+ * @returns PDF file as a Uint8Array
37
+ */
38
+ function excelToPdf(workbook, options) {
39
+ const pdfWorkbook = excelWorkbookToPdf(workbook);
40
+ return (0, pdf_exporter_1.exportPdf)(pdfWorkbook, options);
41
+ }
42
+ /**
43
+ * Convert an Excel Workbook to the internal PdfWorkbook data structure.
44
+ */
45
+ function excelWorkbookToPdf(workbook) {
46
+ return {
47
+ title: workbook.title || undefined,
48
+ creator: workbook.creator || undefined,
49
+ subject: workbook.subject || undefined,
50
+ sheets: workbook.worksheets.map(ws => convertSheet(ws, workbook))
51
+ };
52
+ }
53
+ // =============================================================================
54
+ // Sheet Conversion
55
+ // =============================================================================
56
+ function convertSheet(ws, workbook) {
57
+ const dimensions = ws.dimensions;
58
+ const hasData = dimensions && dimensions.model.top > 0 && dimensions.model.left > 0;
59
+ const bounds = hasData
60
+ ? {
61
+ top: dimensions.model.top,
62
+ left: dimensions.model.left,
63
+ bottom: dimensions.model.bottom,
64
+ right: dimensions.model.right
65
+ }
66
+ : { top: 0, left: 0, bottom: 0, right: 0 };
67
+ // Convert columns
68
+ const columns = new Map();
69
+ if (hasData) {
70
+ for (let c = bounds.left; c <= bounds.right; c++) {
71
+ const col = ws.getColumn(c);
72
+ columns.set(c, {
73
+ hidden: col.hidden || undefined,
74
+ width: col.width ?? undefined
75
+ });
76
+ }
77
+ }
78
+ // Convert rows
79
+ const rows = new Map();
80
+ if (hasData) {
81
+ for (let r = bounds.top; r <= bounds.bottom; r++) {
82
+ const row = ws.findRow(r);
83
+ if (!row) {
84
+ continue;
85
+ }
86
+ const cells = new Map();
87
+ row.eachCell({ includeEmpty: false }, cell => {
88
+ cells.set(cell.col, convertCell(cell));
89
+ });
90
+ rows.set(r, {
91
+ hidden: row.hidden || undefined,
92
+ height: row.height ?? undefined,
93
+ cells
94
+ });
95
+ }
96
+ }
97
+ // Convert merges
98
+ const merges = ws.hasMerges && ws.model.mergeCells ? [...ws.model.mergeCells] : undefined;
99
+ // Convert pageSetup
100
+ const ps = ws.pageSetup;
101
+ const pageSetup = ps
102
+ ? {
103
+ orientation: ps.orientation,
104
+ paperSize: ps.paperSize,
105
+ margins: ps.margins
106
+ ? {
107
+ left: ps.margins.left,
108
+ right: ps.margins.right,
109
+ top: ps.margins.top,
110
+ bottom: ps.margins.bottom
111
+ }
112
+ : undefined,
113
+ scale: ps.scale,
114
+ printTitlesRow: ps.printTitlesRow,
115
+ showGridLines: ps.showGridLines,
116
+ printArea: ps.printArea
117
+ }
118
+ : undefined;
119
+ // Convert row/col breaks
120
+ const rowBreaks = ws.rowBreaks?.map((b) => b.id);
121
+ const colBreaks = ws.colBreaks?.map((b) => b.id);
122
+ // Convert images
123
+ const images = collectImages(ws, workbook);
124
+ // Extend bounds to cover image anchors (so layout engine includes them)
125
+ if (images) {
126
+ for (const img of images) {
127
+ const tl = img.range.tl;
128
+ const tlCol = (tl.nativeCol ?? tl.col ?? 0) + 1; // 0-indexed → 1-indexed
129
+ const tlRow = (tl.nativeRow ?? tl.row ?? 0) + 1;
130
+ if (bounds.top === 0 && bounds.left === 0) {
131
+ bounds.top = 1;
132
+ bounds.left = 1;
133
+ }
134
+ if (tlCol > bounds.right) {
135
+ bounds.right = tlCol;
136
+ }
137
+ if (tlRow > bounds.bottom) {
138
+ bounds.bottom = tlRow;
139
+ }
140
+ // Also extend to bottom-right anchor if present
141
+ if (img.range.br) {
142
+ const br = img.range.br;
143
+ const brCol = (br.nativeCol ?? br.col ?? 0) + 1;
144
+ const brRow = (br.nativeRow ?? br.row ?? 0) + 1;
145
+ if (brCol > bounds.right) {
146
+ bounds.right = brCol;
147
+ }
148
+ if (brRow > bounds.bottom) {
149
+ bounds.bottom = brRow;
150
+ }
151
+ }
152
+ }
153
+ // Ensure columns/rows exist for extended bounds
154
+ for (let c = bounds.left; c <= bounds.right; c++) {
155
+ if (!columns.has(c)) {
156
+ const col = ws.getColumn(c);
157
+ columns.set(c, {
158
+ hidden: col.hidden || undefined,
159
+ width: col.width ?? undefined
160
+ });
161
+ }
162
+ }
163
+ for (let r = bounds.top; r <= bounds.bottom; r++) {
164
+ if (!rows.has(r)) {
165
+ rows.set(r, { cells: new Map() });
166
+ }
167
+ }
168
+ }
169
+ return {
170
+ name: ws.name,
171
+ state: ws.state ?? "visible",
172
+ bounds,
173
+ columns,
174
+ rows,
175
+ merges,
176
+ pageSetup,
177
+ rowBreaks,
178
+ colBreaks,
179
+ images
180
+ };
181
+ }
182
+ // =============================================================================
183
+ // Cell Conversion
184
+ // =============================================================================
185
+ // Use any-typed cell to avoid importing the Cell class directly
186
+ // (Worksheet.eachCell provides it)
187
+ function convertCell(cell) {
188
+ const type = mapValueType(cell.type);
189
+ const text = getCellDisplayText(cell);
190
+ const style = convertCellStyle(cell.style);
191
+ return {
192
+ type,
193
+ value: convertCellValue(cell),
194
+ text,
195
+ style,
196
+ hyperlink: cell.hyperlink || undefined,
197
+ result: cell.result ?? undefined,
198
+ col: cell.col
199
+ };
200
+ }
201
+ function mapValueType(vt) {
202
+ switch (vt) {
203
+ case enums_1.ValueType.Null:
204
+ return types_1.PdfCellType.Empty;
205
+ case enums_1.ValueType.Merge:
206
+ return types_1.PdfCellType.Merge;
207
+ case enums_1.ValueType.Number:
208
+ return types_1.PdfCellType.Number;
209
+ case enums_1.ValueType.String:
210
+ case enums_1.ValueType.SharedString:
211
+ return types_1.PdfCellType.String;
212
+ case enums_1.ValueType.Date:
213
+ return types_1.PdfCellType.Date;
214
+ case enums_1.ValueType.Hyperlink:
215
+ return types_1.PdfCellType.Hyperlink;
216
+ case enums_1.ValueType.Formula:
217
+ return types_1.PdfCellType.Formula;
218
+ case enums_1.ValueType.RichText:
219
+ return types_1.PdfCellType.RichText;
220
+ case enums_1.ValueType.Boolean:
221
+ return types_1.PdfCellType.Boolean;
222
+ case enums_1.ValueType.Error:
223
+ return types_1.PdfCellType.Error;
224
+ default:
225
+ return types_1.PdfCellType.String;
226
+ }
227
+ }
228
+ /**
229
+ * Get display text for a cell, applying numFmt formatting.
230
+ */
231
+ function getCellDisplayText(cell) {
232
+ if (!cell) {
233
+ return "";
234
+ }
235
+ switch (cell.type) {
236
+ case enums_1.ValueType.Null:
237
+ case enums_1.ValueType.Merge:
238
+ return "";
239
+ case enums_1.ValueType.RichText:
240
+ case enums_1.ValueType.Hyperlink:
241
+ return cell.text ?? "";
242
+ case enums_1.ValueType.Error: {
243
+ const errValue = cell.value;
244
+ return errValue?.error ?? cell.text ?? "";
245
+ }
246
+ case enums_1.ValueType.Formula: {
247
+ const result = cell.result;
248
+ if (result !== undefined && result !== null) {
249
+ if (typeof result === "object" && "error" in result) {
250
+ return result.error;
251
+ }
252
+ return formatCellValueSafe(result, cell.style?.numFmt);
253
+ }
254
+ return cell.text ?? "";
255
+ }
256
+ default: {
257
+ const value = cell.value;
258
+ if (value === null || value === undefined) {
259
+ return "";
260
+ }
261
+ return formatCellValueSafe(value, cell.style?.numFmt);
262
+ }
263
+ }
264
+ }
265
+ function formatCellValueSafe(value, numFmt) {
266
+ const fmt = typeof numFmt === "string" ? numFmt : numFmt?.formatCode;
267
+ if (fmt && (typeof value === "number" || value instanceof Date || typeof value === "boolean")) {
268
+ try {
269
+ return (0, cell_format_1.formatCellValue)(value, fmt);
270
+ }
271
+ catch {
272
+ // Fall through to default
273
+ }
274
+ }
275
+ if (value instanceof Date) {
276
+ return value.toLocaleDateString();
277
+ }
278
+ return String(value);
279
+ }
280
+ function convertCellValue(cell) {
281
+ if (cell.type === enums_1.ValueType.RichText) {
282
+ // Preserve richText structure for the PDF engine
283
+ const rtValue = cell.value;
284
+ if (rtValue?.richText) {
285
+ return {
286
+ richText: rtValue.richText.map((run) => ({
287
+ text: run.text,
288
+ font: run.font ? convertFontStyle(run.font) : undefined
289
+ }))
290
+ };
291
+ }
292
+ }
293
+ return cell.value;
294
+ }
295
+ // =============================================================================
296
+ // Style Conversion
297
+ // =============================================================================
298
+ function convertCellStyle(style) {
299
+ if (!style) {
300
+ return undefined;
301
+ }
302
+ return {
303
+ font: style.font ? convertFontStyle(style.font) : undefined,
304
+ numFmt: style.numFmt,
305
+ fill: style.fill ? convertFill(style.fill) : undefined,
306
+ border: style.border ? convertBorders(style.border) : undefined,
307
+ alignment: style.alignment ? convertAlignment(style.alignment) : undefined
308
+ };
309
+ }
310
+ function convertFontStyle(font) {
311
+ return {
312
+ name: font.name,
313
+ size: font.size,
314
+ bold: font.bold,
315
+ italic: font.italic,
316
+ strike: font.strike,
317
+ underline: font.underline,
318
+ color: font.color ? convertColor(font.color) : undefined
319
+ };
320
+ }
321
+ function convertColor(color) {
322
+ return {
323
+ argb: color.argb,
324
+ theme: color.theme,
325
+ tint: color.tint
326
+ };
327
+ }
328
+ function convertFill(fill) {
329
+ const result = {
330
+ type: fill.type ?? "pattern",
331
+ pattern: fill.pattern,
332
+ fgColor: fill.fgColor ? convertColor(fill.fgColor) : undefined
333
+ };
334
+ if (fill.stops) {
335
+ result.stops = fill.stops.map((s) => ({
336
+ color: convertColor(s.color)
337
+ }));
338
+ }
339
+ return result;
340
+ }
341
+ function convertBorderSide(border) {
342
+ return {
343
+ style: border.style,
344
+ color: border.color ? convertColor(border.color) : undefined
345
+ };
346
+ }
347
+ function convertBorders(borders) {
348
+ return {
349
+ top: borders.top ? convertBorderSide(borders.top) : undefined,
350
+ right: borders.right ? convertBorderSide(borders.right) : undefined,
351
+ bottom: borders.bottom ? convertBorderSide(borders.bottom) : undefined,
352
+ left: borders.left ? convertBorderSide(borders.left) : undefined
353
+ };
354
+ }
355
+ function convertAlignment(alignment) {
356
+ return {
357
+ horizontal: alignment.horizontal,
358
+ vertical: alignment.vertical,
359
+ wrapText: alignment.wrapText,
360
+ indent: alignment.indent,
361
+ textRotation: alignment.textRotation
362
+ };
363
+ }
364
+ // =============================================================================
365
+ // Image Collection
366
+ // =============================================================================
367
+ function collectImages(ws, workbook) {
368
+ const wsImages = ws.getImages?.();
369
+ if (!wsImages || !Array.isArray(wsImages) || wsImages.length === 0) {
370
+ return undefined;
371
+ }
372
+ const images = [];
373
+ for (const wsImage of wsImages) {
374
+ if (!wsImage.range?.tl) {
375
+ continue;
376
+ }
377
+ const imageId = wsImage.imageId;
378
+ const mediaItem = workbook.getImage?.(Number(imageId));
379
+ if (!mediaItem) {
380
+ continue;
381
+ }
382
+ // Get image data
383
+ let data;
384
+ if (mediaItem.buffer instanceof Uint8Array) {
385
+ data = mediaItem.buffer;
386
+ }
387
+ else if (mediaItem.base64) {
388
+ data = (0, utils_base_1.base64ToUint8Array)(mediaItem.base64);
389
+ }
390
+ if (!data || data.length === 0) {
391
+ continue;
392
+ }
393
+ const format = mediaItem.extension;
394
+ if (format !== "jpeg" && format !== "png") {
395
+ continue;
396
+ }
397
+ images.push({
398
+ data,
399
+ format: format,
400
+ range: {
401
+ tl: {
402
+ col: wsImage.range.tl.col ?? 0,
403
+ row: wsImage.range.tl.row ?? 0,
404
+ nativeCol: wsImage.range.tl.nativeCol,
405
+ nativeRow: wsImage.range.tl.nativeRow,
406
+ nativeColOff: wsImage.range.tl.nativeColOff,
407
+ nativeRowOff: wsImage.range.tl.nativeRowOff
408
+ },
409
+ br: wsImage.range.br
410
+ ? {
411
+ col: wsImage.range.br.col ?? 0,
412
+ row: wsImage.range.br.row ?? 0,
413
+ nativeCol: wsImage.range.br.nativeCol,
414
+ nativeRow: wsImage.range.br.nativeRow,
415
+ nativeColOff: wsImage.range.br.nativeColOff,
416
+ nativeRowOff: wsImage.range.br.nativeRowOff
417
+ }
418
+ : undefined,
419
+ ext: wsImage.range.ext
420
+ ? { width: wsImage.range.ext.width, height: wsImage.range.ext.height }
421
+ : undefined
422
+ }
423
+ });
424
+ }
425
+ return images.length > 0 ? images : undefined;
426
+ }
@@ -2,46 +2,43 @@
2
2
  /**
3
3
  * PDF module for excelts.
4
4
  *
5
- * Provides Excel-to-PDF conversion with zero external dependencies.
6
- * Supports cell values, fonts, colors, borders, fills, alignment,
7
- * merged cells, pagination, and customizable page layout.
5
+ * A full-featured, zero-dependency PDF engine.
8
6
  *
9
- * @example
7
+ * @example Standalone:
10
8
  * ```typescript
11
- * import { Workbook, PdfExporter } from "excelts";
9
+ * import { pdf } from "excelts/pdf";
12
10
  *
13
- * const workbook = new Workbook();
14
- * const sheet = workbook.addWorksheet("Sales");
15
- * sheet.columns = [
16
- * { header: "Product", key: "product", width: 20 },
17
- * { header: "Revenue", key: "revenue", width: 15 }
18
- * ];
19
- * sheet.addRow({ product: "Widget", revenue: 1000 });
11
+ * const bytes = pdf([
12
+ * ["Product", "Revenue"],
13
+ * ["Widget", 1000],
14
+ * ["Gadget", 2500]
15
+ * ]);
16
+ * ```
20
17
  *
21
- * const exporter = new PdfExporter(workbook);
22
- * const pdfBuffer = exporter.export({
23
- * pageSize: "A4",
24
- * orientation: "portrait",
25
- * fitToPage: true,
26
- * showGridLines: true,
27
- * showPageNumbers: true
28
- * });
18
+ * @example From Excel Workbook:
19
+ * ```typescript
20
+ * import { Workbook } from "excelts";
21
+ * import { excelToPdf } from "excelts/pdf";
29
22
  *
30
- * // Write to file (Node.js)
31
- * import { writeFileSync } from "fs";
32
- * writeFileSync("output.pdf", pdfBuffer);
23
+ * const workbook = new Workbook();
24
+ * const sheet = workbook.addWorksheet("Sales");
25
+ * sheet.addRow(["Product", "Revenue"]);
26
+ * const bytes = excelToPdf(workbook);
33
27
  * ```
34
28
  *
35
29
  * @module pdf
36
30
  */
37
31
  Object.defineProperty(exports, "__esModule", { value: true });
38
- exports.isPdfError = exports.PdfStructureError = exports.PdfFontError = exports.PdfRenderError = exports.PdfError = exports.PageSizes = exports.exportPdf = exports.PdfExporter = void 0;
32
+ exports.isPdfError = exports.PdfStructureError = exports.PdfFontError = exports.PdfRenderError = exports.PdfError = exports.PageSizes = exports.excelToPdf = exports.pdf = void 0;
39
33
  // =============================================================================
40
- // Core Export
34
+ // Public API
41
35
  // =============================================================================
42
- var pdf_exporter_1 = require("./render/pdf-exporter");
43
- Object.defineProperty(exports, "PdfExporter", { enumerable: true, get: function () { return pdf_exporter_1.PdfExporter; } });
44
- Object.defineProperty(exports, "exportPdf", { enumerable: true, get: function () { return pdf_exporter_1.exportPdf; } });
36
+ /** Standalone PDF generation — accepts plain arrays, sheet objects, or workbooks. */
37
+ var pdf_1 = require("./pdf");
38
+ Object.defineProperty(exports, "pdf", { enumerable: true, get: function () { return pdf_1.pdf; } });
39
+ /** Excel-to-PDF conversion — accepts an Excel Workbook instance. */
40
+ var excel_bridge_1 = require("./excel-bridge");
41
+ Object.defineProperty(exports, "excelToPdf", { enumerable: true, get: function () { return excel_bridge_1.excelToPdf; } });
45
42
  var types_1 = require("./types");
46
43
  Object.defineProperty(exports, "PageSizes", { enumerable: true, get: function () { return types_1.PageSizes; } });
47
44
  // =============================================================================