@cj-tech-master/excelts 9.0.0 → 9.1.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 (96) hide show
  1. package/dist/browser/index.browser.d.ts +2 -0
  2. package/dist/browser/index.browser.js +2 -0
  3. package/dist/browser/index.d.ts +2 -0
  4. package/dist/browser/index.js +2 -0
  5. package/dist/browser/modules/excel/image.d.ts +27 -2
  6. package/dist/browser/modules/excel/image.js +23 -1
  7. package/dist/browser/modules/excel/stream/worksheet-writer.d.ts +16 -1
  8. package/dist/browser/modules/excel/stream/worksheet-writer.js +68 -0
  9. package/dist/browser/modules/excel/types.d.ts +72 -0
  10. package/dist/browser/modules/excel/utils/drawing-utils.d.ts +4 -0
  11. package/dist/browser/modules/excel/utils/drawing-utils.js +5 -0
  12. package/dist/browser/modules/excel/utils/ooxml-paths.d.ts +4 -0
  13. package/dist/browser/modules/excel/utils/ooxml-paths.js +15 -0
  14. package/dist/browser/modules/excel/utils/watermark-image.d.ts +67 -0
  15. package/dist/browser/modules/excel/utils/watermark-image.js +383 -0
  16. package/dist/browser/modules/excel/worksheet.d.ts +39 -1
  17. package/dist/browser/modules/excel/worksheet.js +99 -0
  18. package/dist/browser/modules/excel/xlsx/xform/core/content-types-xform.js +3 -2
  19. package/dist/browser/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +6 -1
  20. package/dist/browser/modules/excel/xlsx/xform/drawing/blip-fill-xform.d.ts +2 -1
  21. package/dist/browser/modules/excel/xlsx/xform/drawing/blip-fill-xform.js +0 -1
  22. package/dist/browser/modules/excel/xlsx/xform/drawing/blip-xform.d.ts +3 -1
  23. package/dist/browser/modules/excel/xlsx/xform/drawing/blip-xform.js +22 -6
  24. package/dist/browser/modules/excel/xlsx/xform/drawing/pic-xform.d.ts +3 -0
  25. package/dist/browser/modules/excel/xlsx/xform/drawing/pic-xform.js +5 -1
  26. package/dist/browser/modules/excel/xlsx/xform/drawing/vml-drawing-xform.d.ts +19 -0
  27. package/dist/browser/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +103 -4
  28. package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +135 -8
  29. package/dist/browser/modules/excel/xlsx/xlsx.browser.d.ts +1 -0
  30. package/dist/browser/modules/excel/xlsx/xlsx.browser.js +53 -1
  31. package/dist/browser/modules/pdf/core/pdf-writer.d.ts +1 -1
  32. package/dist/browser/modules/pdf/core/pdf-writer.js +2 -1
  33. package/dist/browser/modules/pdf/index.d.ts +1 -1
  34. package/dist/browser/modules/pdf/render/page-renderer.d.ts +29 -1
  35. package/dist/browser/modules/pdf/render/page-renderer.js +394 -25
  36. package/dist/browser/modules/pdf/render/pdf-exporter.js +84 -47
  37. package/dist/browser/modules/pdf/types.d.ts +235 -0
  38. package/dist/cjs/index.js +5 -2
  39. package/dist/cjs/modules/excel/image.js +23 -1
  40. package/dist/cjs/modules/excel/stream/worksheet-writer.js +68 -0
  41. package/dist/cjs/modules/excel/utils/drawing-utils.js +5 -0
  42. package/dist/cjs/modules/excel/utils/ooxml-paths.js +19 -0
  43. package/dist/cjs/modules/excel/utils/watermark-image.js +386 -0
  44. package/dist/cjs/modules/excel/worksheet.js +99 -0
  45. package/dist/cjs/modules/excel/xlsx/xform/core/content-types-xform.js +3 -2
  46. package/dist/cjs/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +6 -1
  47. package/dist/cjs/modules/excel/xlsx/xform/drawing/blip-fill-xform.js +0 -1
  48. package/dist/cjs/modules/excel/xlsx/xform/drawing/blip-xform.js +22 -6
  49. package/dist/cjs/modules/excel/xlsx/xform/drawing/pic-xform.js +5 -1
  50. package/dist/cjs/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +103 -4
  51. package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +134 -7
  52. package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +52 -0
  53. package/dist/cjs/modules/pdf/core/pdf-writer.js +2 -1
  54. package/dist/cjs/modules/pdf/render/page-renderer.js +396 -25
  55. package/dist/cjs/modules/pdf/render/pdf-exporter.js +83 -46
  56. package/dist/esm/index.browser.js +2 -0
  57. package/dist/esm/index.js +2 -0
  58. package/dist/esm/modules/excel/image.js +23 -1
  59. package/dist/esm/modules/excel/stream/worksheet-writer.js +68 -0
  60. package/dist/esm/modules/excel/utils/drawing-utils.js +5 -0
  61. package/dist/esm/modules/excel/utils/ooxml-paths.js +15 -0
  62. package/dist/esm/modules/excel/utils/watermark-image.js +383 -0
  63. package/dist/esm/modules/excel/worksheet.js +99 -0
  64. package/dist/esm/modules/excel/xlsx/xform/core/content-types-xform.js +3 -2
  65. package/dist/esm/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +6 -1
  66. package/dist/esm/modules/excel/xlsx/xform/drawing/blip-fill-xform.js +0 -1
  67. package/dist/esm/modules/excel/xlsx/xform/drawing/blip-xform.js +22 -6
  68. package/dist/esm/modules/excel/xlsx/xform/drawing/pic-xform.js +5 -1
  69. package/dist/esm/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +103 -4
  70. package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +135 -8
  71. package/dist/esm/modules/excel/xlsx/xlsx.browser.js +53 -1
  72. package/dist/esm/modules/pdf/core/pdf-writer.js +2 -1
  73. package/dist/esm/modules/pdf/render/page-renderer.js +394 -25
  74. package/dist/esm/modules/pdf/render/pdf-exporter.js +84 -47
  75. package/dist/iife/excelts.iife.js +2390 -469
  76. package/dist/iife/excelts.iife.js.map +1 -1
  77. package/dist/iife/excelts.iife.min.js +47 -47
  78. package/dist/types/index.browser.d.ts +2 -0
  79. package/dist/types/index.d.ts +2 -0
  80. package/dist/types/modules/excel/image.d.ts +27 -2
  81. package/dist/types/modules/excel/stream/worksheet-writer.d.ts +16 -1
  82. package/dist/types/modules/excel/types.d.ts +72 -0
  83. package/dist/types/modules/excel/utils/drawing-utils.d.ts +4 -0
  84. package/dist/types/modules/excel/utils/ooxml-paths.d.ts +4 -0
  85. package/dist/types/modules/excel/utils/watermark-image.d.ts +67 -0
  86. package/dist/types/modules/excel/worksheet.d.ts +39 -1
  87. package/dist/types/modules/excel/xlsx/xform/drawing/blip-fill-xform.d.ts +2 -1
  88. package/dist/types/modules/excel/xlsx/xform/drawing/blip-xform.d.ts +3 -1
  89. package/dist/types/modules/excel/xlsx/xform/drawing/pic-xform.d.ts +3 -0
  90. package/dist/types/modules/excel/xlsx/xform/drawing/vml-drawing-xform.d.ts +19 -0
  91. package/dist/types/modules/excel/xlsx/xlsx.browser.d.ts +1 -0
  92. package/dist/types/modules/pdf/core/pdf-writer.d.ts +1 -1
  93. package/dist/types/modules/pdf/index.d.ts +1 -1
  94. package/dist/types/modules/pdf/render/page-renderer.d.ts +29 -1
  95. package/dist/types/modules/pdf/types.d.ts +235 -0
  96. package/package.json +1 -1
@@ -8,12 +8,13 @@
8
8
  * It is used internally by the public `pdf()` and `excelToPdf()` APIs.
9
9
  */
10
10
  import { PdfWriter } from "../core/pdf-writer.js";
11
+ import { PdfContentStream } from "../core/pdf-stream.js";
11
12
  import { PdfDict, pdfRef, pdfNumber, pdfString as pdfStr } from "../core/pdf-object.js";
12
13
  import { FontManager, resolvePdfFontName } from "../font/font-manager.js";
13
14
  import { parseTtf } from "../font/ttf-parser.js";
14
15
  import { initEncryption } from "../core/encryption.js";
15
16
  import { layoutSheet } from "./layout-engine.js";
16
- import { renderPage, alphaGsName } from "./page-renderer.js";
17
+ import { renderPage, alphaGsName, renderWatermark, parseImageDimensions } from "./page-renderer.js";
17
18
  import { decodePng } from "./png-decoder.js";
18
19
  import { PdfError, PdfRenderError } from "../errors.js";
19
20
  import { PageSizes } from "../types.js";
@@ -83,8 +84,21 @@ async function finishExport(ctx, workbook, options) {
83
84
  ensureAtLeastOnePage(allPages, documentOptions, sheets);
84
85
  fixPageNumbers(allPages);
85
86
  trackFontsForHeaders(allPages, fontManager);
87
+ // Track watermark fonts
88
+ const watermark = documentOptions.watermark;
89
+ if (watermark && watermark.type === "text") {
90
+ const wmFontFamily = watermark.fontFamily ?? "Helvetica";
91
+ const wmBold = watermark.bold ?? false;
92
+ const wmItalic = watermark.italic ?? false;
93
+ if (fontManager.hasEmbeddedFont()) {
94
+ fontManager.trackText(watermark.text);
95
+ }
96
+ else {
97
+ fontManager.ensureFont(resolvePdfFontName(wmFontFamily, wmBold, wmItalic));
98
+ }
99
+ }
86
100
  const fontObjectMap = fontManager.writeFontResources(writer);
87
- const { pageObjNums, sheetFirstPage, pagesTreeObjNum } = await renderAllPages(allPages, fontManager, writer, fontObjectMap);
101
+ const { pageObjNums, sheetFirstPage, pagesTreeObjNum } = await renderAllPages(allPages, fontManager, writer, fontObjectMap, watermark);
88
102
  return buildFinalPdf(writer, pageObjNums, pagesTreeObjNum, sheetFirstPage, documentOptions, workbook, options);
89
103
  }
90
104
  function ensureAtLeastOnePage(allPages, documentOptions, sheets) {
@@ -133,20 +147,20 @@ function trackFontsForHeaders(allPages, fontManager) {
133
147
  }
134
148
  }
135
149
  }
136
- async function renderAllPages(allPages, fontManager, writer, fontObjectMap) {
150
+ async function renderAllPages(allPages, fontManager, writer, fontObjectMap, watermark) {
137
151
  const pageObjNums = [];
138
152
  const pagesTreeObjNum = writer.allocObject();
139
153
  const sheetFirstPage = new Map();
140
154
  const totalPages = allPages.length;
141
155
  for (let i = 0; i < allPages.length; i++) {
142
- renderSinglePage(allPages[i], fontManager, writer, fontObjectMap, totalPages, pageObjNums, pagesTreeObjNum, sheetFirstPage);
156
+ renderSinglePage(allPages[i], fontManager, writer, fontObjectMap, totalPages, pageObjNums, pagesTreeObjNum, sheetFirstPage, watermark);
143
157
  if (i < allPages.length - 1) {
144
158
  await yieldToEventLoop();
145
159
  }
146
160
  }
147
161
  return { pageObjNums, sheetFirstPage, pagesTreeObjNum };
148
162
  }
149
- function renderSinglePage(page, fontManager, writer, fontObjectMap, totalPages, pageObjNums, pagesTreeObjNum, sheetFirstPage) {
163
+ function renderSinglePage(page, fontManager, writer, fontObjectMap, totalPages, pageObjNums, pagesTreeObjNum, sheetFirstPage, watermark) {
150
164
  try {
151
165
  const { stream: contentStream, alphaValues } = renderPage(page, page.options, fontManager, totalPages);
152
166
  // Handle images: create XObject Image entries and draw them
@@ -160,10 +174,46 @@ function renderSinglePage(page, fontManager, writer, fontObjectMap, totalPages,
160
174
  contentStream.drawImage(imgName, img.rect.x, img.rect.y, img.rect.width, img.rect.height);
161
175
  }
162
176
  }
163
- // Add content stream object
177
+ // --- Render watermark into a separate content stream ---
178
+ // PDF supports Contents as an array of stream references. The watermark stream
179
+ // is placed BEFORE the main content stream so it renders behind everything.
180
+ let watermarkContentObjNum;
181
+ const shouldApplyWatermark = watermark && isWatermarkApplicable(watermark, page);
182
+ if (shouldApplyWatermark) {
183
+ const wmContentStream = new PdfContentStream();
184
+ const wmResult = renderWatermark(wmContentStream, page, watermark, fontManager);
185
+ // Register watermark alpha values in the shared set
186
+ for (const alpha of wmResult.alphaValues) {
187
+ alphaValues.add(alpha);
188
+ }
189
+ // Register watermark image XObjects
190
+ for (const wmImg of wmResult.imageXObjects) {
191
+ const imgObjNum = writeImageXObject(writer, wmImg.data, wmImg.format);
192
+ imageXObjects.set(wmImg.name, imgObjNum);
193
+ }
194
+ // Write watermark content stream object
195
+ watermarkContentObjNum = writer.allocObject();
196
+ writer.addStreamObject(watermarkContentObjNum, new PdfDict(), wmContentStream);
197
+ }
198
+ // Add main content stream object
164
199
  const contentObjNum = writer.allocObject();
165
- const contentDict = new PdfDict();
166
- writer.addStreamObject(contentObjNum, contentDict, contentStream);
200
+ writer.addStreamObject(contentObjNum, new PdfDict(), contentStream);
201
+ // Build Contents reference — array if watermark exists, single ref otherwise.
202
+ // placement "under" (default): watermark stream first, then content
203
+ // placement "over": content first, then watermark stream on top
204
+ let contentsRef;
205
+ if (watermarkContentObjNum) {
206
+ const placement = watermark?.placement ?? "under";
207
+ if (placement === "over") {
208
+ contentsRef = `[${pdfRef(contentObjNum)} ${pdfRef(watermarkContentObjNum)}]`;
209
+ }
210
+ else {
211
+ contentsRef = `[${pdfRef(watermarkContentObjNum)} ${pdfRef(contentObjNum)}]`;
212
+ }
213
+ }
214
+ else {
215
+ contentsRef = pdfRef(contentObjNum);
216
+ }
167
217
  // Add resources dictionary object
168
218
  const resourcesObjNum = writer.allocObject();
169
219
  const fontDictStr = fontManager.buildFontDictString(fontObjectMap);
@@ -212,7 +262,7 @@ function renderSinglePage(page, fontManager, writer, fontObjectMap, totalPages,
212
262
  parentRef: pagesTreeObjNum,
213
263
  width: page.width,
214
264
  height: page.height,
215
- contentsRef: contentObjNum,
265
+ contentsRef: contentsRef,
216
266
  resourcesRef: resourcesObjNum,
217
267
  annotRefs: annotRefs.length > 0 ? annotRefs : undefined
218
268
  });
@@ -337,7 +387,8 @@ function resolveOptions(options, sheet) {
337
387
  title: options?.title ?? "",
338
388
  author: options?.author ?? "",
339
389
  subject: options?.subject ?? "",
340
- creator: options?.creator ?? "excelts"
390
+ creator: options?.creator ?? "excelts",
391
+ watermark: options?.watermark
341
392
  };
342
393
  }
343
394
  /** Map PaperSize enum values to PDF page sizes. */
@@ -428,6 +479,28 @@ function buildOutlines(writer, sheetFirstPage, pageObjNums) {
428
479
  return outlinesObjNum;
429
480
  }
430
481
  // =============================================================================
482
+ // Watermark Filtering
483
+ // =============================================================================
484
+ /**
485
+ * Check if a watermark should be applied to a specific page based on
486
+ * optional page number and sheet name filters.
487
+ */
488
+ function isWatermarkApplicable(watermark, page) {
489
+ if (watermark.pages && watermark.pages.length > 0) {
490
+ if (!watermark.pages.includes(page.pageNumber)) {
491
+ return false;
492
+ }
493
+ }
494
+ if (watermark.sheets && watermark.sheets.length > 0) {
495
+ // Case-insensitive sheet name matching, consistent with the rest of the API
496
+ const sheetLower = page.sheetName.toLowerCase();
497
+ if (!watermark.sheets.some(s => s.toLowerCase() === sheetLower)) {
498
+ return false;
499
+ }
500
+ }
501
+ return true;
502
+ }
503
+ // =============================================================================
431
504
  // Image XObject
432
505
  // =============================================================================
433
506
  /**
@@ -444,7 +517,7 @@ function writeImageXObject(writer, data, format) {
444
517
  */
445
518
  function writeJpegImageXObject(writer, data) {
446
519
  const objNum = writer.allocObject();
447
- const dims = getJpegDimensions(data);
520
+ const dims = parseImageDimensions(data, "jpeg");
448
521
  const dict = new PdfDict()
449
522
  .set("Type", "/XObject")
450
523
  .set("Subtype", "/Image")
@@ -486,39 +559,3 @@ function writePngImageXObject(writer, data) {
486
559
  writer.addStreamObject(objNum, dict, png.pixels);
487
560
  return objNum;
488
561
  }
489
- /**
490
- * Extract width and height from a JPEG file header.
491
- * Scans for SOF markers (SOF0-SOF3, SOF5-SOF7, SOF9-SOF11, SOF13-SOF15)
492
- * which all share the same frame header layout.
493
- * Handles 0xFF padding bytes per JPEG spec.
494
- */
495
- function getJpegDimensions(data) {
496
- let offset = 2; // skip SOI marker (0xFFD8)
497
- while (offset < data.length - 1) {
498
- // Skip any 0xFF fill bytes
499
- while (offset < data.length && data[offset] === 0xff && data[offset + 1] === 0xff) {
500
- offset++;
501
- }
502
- if (offset >= data.length - 1 || data[offset] !== 0xff) {
503
- break;
504
- }
505
- const marker = data[offset + 1];
506
- // SOF markers: C0-C3, C5-C7, C9-CB, CD-CF (excluding C4=DHT, C8=JPG, CC=DAC)
507
- const isSof = marker >= 0xc0 && marker <= 0xcf && marker !== 0xc4 && marker !== 0xc8 && marker !== 0xcc;
508
- if (isSof) {
509
- if (offset + 8 < data.length) {
510
- const height = (data[offset + 5] << 8) | data[offset + 6];
511
- const width = (data[offset + 7] << 8) | data[offset + 8];
512
- return { width, height };
513
- }
514
- break;
515
- }
516
- // Skip segment: 2 byte marker + segment length (includes the 2 length bytes)
517
- if (offset + 3 >= data.length) {
518
- break;
519
- }
520
- const segLen = (data[offset + 2] << 8) | data[offset + 3];
521
- offset += 2 + segLen;
522
- }
523
- return { width: 1, height: 1 };
524
- }