@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
@@ -15,6 +15,8 @@ export { DataValidations } from "./modules/excel/data-validations.js";
15
15
  export { FormCheckbox } from "./modules/excel/form-control.js";
16
16
  export * from "./modules/excel/enums.js";
17
17
  export * from "./modules/excel/types.js";
18
+ export { createTextWatermarkImage } from "./modules/excel/utils/watermark-image.js";
19
+ export type { TextWatermarkImageOptions } from "./modules/excel/utils/watermark-image.js";
18
20
  export type { PivotTable, PivotTableModel, PivotTableValue, PivotTableSource, CacheField, SharedItemValue, DataField, PivotTableSubtotal, RecordValue, ParsedCacheDefinition, ParsedCacheRecords } from "./modules/excel/pivot-table.js";
19
21
  export type { FormCheckboxModel, FormCheckboxOptions, FormControlRange, FormControlAnchor } from "./modules/excel/form-control.js";
20
22
  export { WorkbookWriter } from "./modules/excel/stream/workbook-writer.browser.js";
@@ -25,6 +25,8 @@ export * from "./modules/excel/enums.js";
25
25
  // =============================================================================
26
26
  // Export all type definitions from types.ts
27
27
  export * from "./modules/excel/types.js";
28
+ // Watermark image generator utility
29
+ export { createTextWatermarkImage } from "./modules/excel/utils/watermark-image.js";
28
30
  // =============================================================================
29
31
  // Streaming Writer (Browser-compatible)
30
32
  // Uses cross-platform base implementation without Node.js fs
@@ -15,6 +15,8 @@ export { WorksheetWriter } from "./modules/excel/stream/worksheet-writer.js";
15
15
  export { WorksheetReader } from "./modules/excel/stream/worksheet-reader.js";
16
16
  export * from "./modules/excel/enums.js";
17
17
  export * from "./modules/excel/types.js";
18
+ export { createTextWatermarkImage } from "./modules/excel/utils/watermark-image.js";
19
+ export type { TextWatermarkImageOptions } from "./modules/excel/utils/watermark-image.js";
18
20
  export type { PivotTable, PivotTableModel, PivotTableValue, PivotTableSource, CacheField, SharedItemValue, DataField, PivotTableSubtotal, RecordValue, ParsedCacheDefinition, ParsedCacheRecords } from "./modules/excel/pivot-table.js";
19
21
  export type { FormCheckboxModel, FormCheckboxOptions, FormControlRange, FormControlAnchor } from "./modules/excel/form-control.js";
20
22
  export type { WorkbookReaderOptions, ParseEvent, SharedStringEvent, WorksheetReadyEvent, HyperlinksEvent } from "./modules/excel/stream/workbook-reader.js";
@@ -29,6 +29,8 @@ export * from "./modules/excel/enums.js";
29
29
  // =============================================================================
30
30
  // Export all type definitions from types.ts
31
31
  export * from "./modules/excel/types.js";
32
+ // Watermark image generator utility
33
+ export { createTextWatermarkImage } from "./modules/excel/utils/watermark-image.js";
32
34
  export { CsvParserStream, CsvFormatterStream, createCsvParserStream, createCsvFormatterStream } from "./modules/csv/stream/index.js";
33
35
  // =============================================================================
34
36
  // Additional Classes & Types
@@ -19,6 +19,19 @@ interface BackgroundModel {
19
19
  type: "background";
20
20
  imageId: string;
21
21
  }
22
+ interface WatermarkModel {
23
+ type: "watermark";
24
+ imageId: string;
25
+ /** Opacity 0-1 for overlay mode */
26
+ opacity?: number;
27
+ }
28
+ interface HeaderImageModel {
29
+ type: "headerImage";
30
+ imageId: string;
31
+ headerWidth?: number;
32
+ headerHeight?: number;
33
+ applyTo?: "all" | "odd" | "even" | "first";
34
+ }
22
35
  interface ImageRangeModel {
23
36
  tl: AnchorModel;
24
37
  br?: AnchorModel;
@@ -31,7 +44,7 @@ interface ImageModel {
31
44
  hyperlinks?: ImageHyperlinks;
32
45
  range: ImageRangeModel;
33
46
  }
34
- type Model = BackgroundModel | ImageModel;
47
+ type Model = BackgroundModel | ImageModel | WatermarkModel | HeaderImageModel;
35
48
  type ImageModelInput = ModelInput;
36
49
  interface RangeInput {
37
50
  tl?: AnchorModel | {
@@ -51,15 +64,27 @@ interface ModelInput {
51
64
  imageId: string;
52
65
  range?: string | RangeInput | ImageRangeModel;
53
66
  hyperlinks?: ImageHyperlinks;
67
+ opacity?: number;
68
+ headerWidth?: number;
69
+ headerHeight?: number;
70
+ applyTo?: "all" | "odd" | "even" | "first";
54
71
  }
55
72
  declare class Image {
56
73
  readonly worksheet: Worksheet;
57
74
  type?: string;
58
75
  imageId?: string;
59
76
  range?: ImageRange;
77
+ /** Opacity for watermark overlay mode (0-1). */
78
+ opacity?: number;
79
+ /** Header image width in points. */
80
+ headerWidth?: number;
81
+ /** Header image height in points. */
82
+ headerHeight?: number;
83
+ /** Header watermark applyTo setting. */
84
+ applyTo?: "all" | "odd" | "even" | "first";
60
85
  constructor(worksheet: Worksheet, model?: ModelInput);
61
86
  get model(): Model;
62
- set model({ type, imageId, range, hyperlinks }: ModelInput);
87
+ set model({ type, imageId, range, hyperlinks, opacity, headerWidth, headerHeight, applyTo }: ModelInput);
63
88
  clone(worksheet?: Worksheet): Image;
64
89
  }
65
90
  export { Image, type Model as ImageModel, type ImageModelInput };
@@ -15,6 +15,20 @@ class Image {
15
15
  type: this.type,
16
16
  imageId: this.imageId ?? ""
17
17
  };
18
+ case "watermark":
19
+ return {
20
+ type: this.type,
21
+ imageId: this.imageId ?? "",
22
+ opacity: this.opacity
23
+ };
24
+ case "headerImage":
25
+ return {
26
+ type: this.type,
27
+ imageId: this.imageId ?? "",
28
+ headerWidth: this.headerWidth,
29
+ headerHeight: this.headerHeight,
30
+ applyTo: this.applyTo
31
+ };
18
32
  case "image": {
19
33
  const range = this.range;
20
34
  if (!range) {
@@ -36,9 +50,13 @@ class Image {
36
50
  throw new ImageError("Invalid Image Type");
37
51
  }
38
52
  }
39
- set model({ type, imageId, range, hyperlinks }) {
53
+ set model({ type, imageId, range, hyperlinks, opacity, headerWidth, headerHeight, applyTo }) {
40
54
  this.type = type;
41
55
  this.imageId = imageId;
56
+ this.opacity = opacity;
57
+ this.headerWidth = headerWidth;
58
+ this.headerHeight = headerHeight;
59
+ this.applyTo = applyTo;
42
60
  if (type === "image") {
43
61
  if (typeof range === "string") {
44
62
  const decoded = colCache.decode(range);
@@ -67,6 +85,10 @@ class Image {
67
85
  const cloned = new Image(target);
68
86
  cloned.type = this.type;
69
87
  cloned.imageId = this.imageId;
88
+ cloned.opacity = this.opacity;
89
+ cloned.headerWidth = this.headerWidth;
90
+ cloned.headerHeight = this.headerHeight;
91
+ cloned.applyTo = this.applyTo;
70
92
  if (this.range) {
71
93
  cloned.range = {
72
94
  tl: this.range.tl.clone(target),
@@ -3,7 +3,7 @@ import { Row } from "../row.js";
3
3
  import type { Cell } from "../cell.js";
4
4
  import { Column } from "../column.js";
5
5
  import { DataValidations } from "../data-validations.js";
6
- import type { RowBreak, ColBreak, PageSetup, HeaderFooter, WorksheetProperties, WorksheetView, WorksheetState, AutoFilter, WorksheetProtection, ConditionalFormattingOptions, AddImageRange } from "../types.js";
6
+ import type { RowBreak, ColBreak, PageSetup, HeaderFooter, WorksheetProperties, WorksheetView, WorksheetState, AutoFilter, WorksheetProtection, ConditionalFormattingOptions, AddImageRange, WatermarkOptions } from "../types.js";
7
7
  interface WorksheetWriterOptions {
8
8
  id: number;
9
9
  name?: string;
@@ -97,6 +97,8 @@ declare class WorksheetWriter {
97
97
  startedData: boolean;
98
98
  private _background?;
99
99
  private _headerRowCount?;
100
+ /** Watermark configuration */
101
+ private _watermark;
100
102
  /** Drawing model — populated during commit if images were added */
101
103
  private _drawing?;
102
104
  /** Relationship Id - assigned by WorkbookWriter */
@@ -141,6 +143,19 @@ declare class WorksheetWriter {
141
143
  * Each entry contains imageId and the normalised range (with native anchors).
142
144
  */
143
145
  getImages(): ReadonlyArray<WriterImageModel>;
146
+ /**
147
+ * Add a watermark to the worksheet using an image from `WorkbookWriter.addImage()`.
148
+ * Supports overlay mode (DrawingML with transparency) and header mode (VML behind content).
149
+ */
150
+ addWatermark(options: WatermarkOptions): void;
151
+ /**
152
+ * Get the current watermark configuration.
153
+ */
154
+ getWatermark(): WatermarkOptions | null;
155
+ /**
156
+ * Remove the watermark from the worksheet.
157
+ */
158
+ removeWatermark(): void;
144
159
  /**
145
160
  * Parse the user-supplied range into a normalised internal model
146
161
  * mirroring what the regular Worksheet / Image class does.
@@ -151,6 +151,8 @@ class WorksheetWriter {
151
151
  // auto filter
152
152
  this.autoFilter = options.autoFilter ?? null;
153
153
  this._media = [];
154
+ // watermark
155
+ this._watermark = null;
154
156
  // worksheet protection
155
157
  this.sheetProtection = null;
156
158
  // start writing to stream now
@@ -448,6 +450,57 @@ class WorksheetWriter {
448
450
  getImages() {
449
451
  return this._media;
450
452
  }
453
+ // =========================================================================
454
+ // Watermark
455
+ /**
456
+ * Add a watermark to the worksheet using an image from `WorkbookWriter.addImage()`.
457
+ * Supports overlay mode (DrawingML with transparency) and header mode (VML behind content).
458
+ */
459
+ addWatermark(options) {
460
+ // Remove existing watermark entries (both stored type tags)
461
+ this._media = this._media.filter(m => m._watermarkTag !== true);
462
+ const opacity = options.opacity !== undefined ? Math.max(0, Math.min(1, options.opacity)) : 0.15;
463
+ this._watermark = {
464
+ imageId: String(options.imageId),
465
+ mode: options.mode ?? "overlay",
466
+ opacity,
467
+ headerWidth: options.headerWidth,
468
+ headerHeight: options.headerHeight,
469
+ applyTo: options.applyTo
470
+ };
471
+ if (this._watermark.mode === "overlay") {
472
+ // Coverage range is computed lazily during commit() via _resolveWatermarkRange()
473
+ const entry = {
474
+ type: "image",
475
+ imageId: String(options.imageId),
476
+ range: {
477
+ tl: { nativeCol: 0, nativeColOff: 0, nativeRow: 0, nativeRowOff: 0 },
478
+ br: { nativeCol: 100, nativeColOff: 0, nativeRow: 200, nativeRowOff: 0 },
479
+ editAs: "absolute"
480
+ },
481
+ // Internal tag for dedup — not part of the WriterImageModel type
482
+ _watermarkTag: true,
483
+ opacity
484
+ };
485
+ this._media.push(entry);
486
+ }
487
+ // Note: header mode for streaming writer is limited — the VML file generation
488
+ // happens in WorkbookWriter.addWorksheets(), which handles worksheet.headerImage.
489
+ // We store the config in _watermark and it's picked up by the commit path.
490
+ }
491
+ /**
492
+ * Get the current watermark configuration.
493
+ */
494
+ getWatermark() {
495
+ return this._watermark;
496
+ }
497
+ /**
498
+ * Remove the watermark from the worksheet.
499
+ */
500
+ removeWatermark() {
501
+ this._watermark = null;
502
+ this._media = this._media.filter(m => m._watermarkTag !== true);
503
+ }
451
504
  /**
452
505
  * Parse the user-supplied range into a normalised internal model
453
506
  * mirroring what the regular Worksheet / Image class does.
@@ -626,6 +679,21 @@ class WorksheetWriter {
626
679
  if (this._media.length === 0) {
627
680
  return;
628
681
  }
682
+ // Resolve watermark coverage range from actual worksheet dimensions
683
+ // (at commit time, all rows have been flushed so _dimensions is accurate)
684
+ for (const entry of this._media) {
685
+ if (entry._watermarkTag) {
686
+ const dims = this._dimensions.model;
687
+ const maxCol = dims ? Math.max(dims.right ?? 100, 100) : 100;
688
+ const maxRow = dims ? Math.max(dims.bottom ?? 200, 200) : 200;
689
+ entry.range.br = {
690
+ nativeCol: maxCol,
691
+ nativeColOff: 0,
692
+ nativeRow: maxRow,
693
+ nativeRowOff: 0
694
+ };
695
+ }
696
+ }
629
697
  // Build the drawing model from the stored images.
630
698
  // The drawing XML will be generated later by WorkbookWriterBase.addDrawings().
631
699
  const drawingName = `drawing${this.id}`;
@@ -368,6 +368,78 @@ export interface ImageHyperlinkValue {
368
368
  hyperlink: string;
369
369
  tooltip?: string;
370
370
  }
371
+ /**
372
+ * Watermark placement mode in the Excel worksheet.
373
+ *
374
+ * - `"overlay"` — Places the watermark image as a DrawingML picture on top of cells.
375
+ * Visible on screen AND when printed. Supports transparency via `<a:alphaModFix>`.
376
+ * Users can move/delete the watermark unless the sheet is protected.
377
+ *
378
+ * - `"header"` — Places the watermark image in the page header using VML.
379
+ * Renders behind cell content. Visible in Page Layout view and Print Preview.
380
+ * Cannot be accidentally moved/deleted. The standard "true watermark" approach.
381
+ */
382
+ export type WatermarkMode = "overlay" | "header";
383
+ /**
384
+ * Options for adding a watermark to a worksheet.
385
+ *
386
+ * @example Overlay watermark (visible on screen + prints):
387
+ * ```typescript
388
+ * const imgId = workbook.addImage({ buffer: pngData, extension: "png" });
389
+ * worksheet.addWatermark({
390
+ * imageId: imgId,
391
+ * mode: "overlay",
392
+ * opacity: 0.15
393
+ * });
394
+ * ```
395
+ *
396
+ * @example Header watermark (behind content, prints correctly):
397
+ * ```typescript
398
+ * const imgId = workbook.addImage({ buffer: pngData, extension: "png" });
399
+ * worksheet.addWatermark({
400
+ * imageId: imgId,
401
+ * mode: "header"
402
+ * });
403
+ * ```
404
+ */
405
+ export interface WatermarkOptions {
406
+ /** Image ID obtained from `workbook.addImage()`. */
407
+ imageId: string | number;
408
+ /**
409
+ * Watermark placement mode.
410
+ * @default "overlay"
411
+ */
412
+ mode?: WatermarkMode;
413
+ /**
414
+ * Opacity for overlay mode (0 = fully transparent, 1 = fully opaque).
415
+ * Expressed as a percentage in OOXML (e.g. 0.15 = 15000 out of 100000).
416
+ * Only applies to `"overlay"` mode. In `"header"` mode, transparency
417
+ * must be baked into the image itself (use a PNG with alpha channel).
418
+ * @default 0.15
419
+ */
420
+ opacity?: number;
421
+ /**
422
+ * Image width in points (for "header" mode VML rendering).
423
+ * @default 467.25
424
+ */
425
+ headerWidth?: number;
426
+ /**
427
+ * Image height in points (for "header" mode VML rendering).
428
+ * @default 311.25
429
+ */
430
+ headerHeight?: number;
431
+ /**
432
+ * Which header sections to apply the watermark to (only for "header" mode).
433
+ *
434
+ * - `"all"` — applies to oddHeader, evenHeader, and firstHeader
435
+ * - `"odd"` — applies only to oddHeader (standard pages)
436
+ * - `"even"` — applies only to evenHeader
437
+ * - `"first"` — applies only to firstHeader
438
+ *
439
+ * @default "all"
440
+ */
441
+ applyTo?: "all" | "odd" | "even" | "first";
442
+ }
371
443
  export type Location = {
372
444
  top: number;
373
445
  left: number;
@@ -12,6 +12,8 @@ interface DrawingAnchor {
12
12
  tooltip?: string;
13
13
  rId: string;
14
14
  };
15
+ /** Alpha modulation for transparency (OOXML percentage, e.g. 15000 = 15%). */
16
+ alphaModFix?: number;
15
17
  };
16
18
  range: any;
17
19
  }
@@ -32,6 +34,8 @@ interface ImageMedium {
32
34
  hyperlink?: string;
33
35
  tooltip?: string;
34
36
  };
37
+ /** Opacity 0-1 for watermark overlay mode. */
38
+ opacity?: number;
35
39
  }
36
40
  /**
37
41
  * Resolves a media filename into the drawing-level relative target path.
@@ -64,6 +64,11 @@ export function buildDrawingAnchorsAndRels(media, existingRels, options) {
64
64
  },
65
65
  range: medium.range
66
66
  };
67
+ // Pass through watermark opacity as alphaModFix
68
+ if (medium.opacity !== undefined) {
69
+ const clamped = Math.max(0, Math.min(1, medium.opacity));
70
+ anchor.picture.alphaModFix = Math.round(clamped * 100000);
71
+ }
67
72
  // Handle image hyperlinks
68
73
  if (medium.hyperlinks && medium.hyperlinks.hyperlink) {
69
74
  const rIdHyperlink = options.nextRId(rels);
@@ -21,6 +21,7 @@ export declare function isBinaryEntryPath(path: string): boolean;
21
21
  export declare function getDrawingNameFromPath(path: string): string | undefined;
22
22
  export declare function getDrawingNameFromRelsPath(path: string): string | undefined;
23
23
  export declare function getVmlDrawingNameFromPath(path: string): string | undefined;
24
+ export declare function getVmlDrawingHFNameFromPath(path: string): string | undefined;
24
25
  export declare function getCommentsIndexFromPath(path: string): string | undefined;
25
26
  export declare function getTableNameFromPath(path: string): string | undefined;
26
27
  export declare function getPivotTableNameFromPath(path: string): string | undefined;
@@ -37,6 +38,8 @@ export declare function worksheetRelTarget(sheetId: number | string): string;
37
38
  export declare function commentsPath(sheetId: number | string): string;
38
39
  export declare function commentsPathFromName(commentName: string): string;
39
40
  export declare function vmlDrawingPath(sheetId: number | string): string;
41
+ export declare function vmlDrawingHFPath(sheetId: number | string): string;
42
+ export declare function vmlDrawingHFRelsPath(sheetId: number | string): string;
40
43
  export declare function tablePath(target: string): string;
41
44
  export declare function drawingPath(drawingName: string): string;
42
45
  export declare function drawingRelsPath(drawingName: string): string;
@@ -56,6 +59,7 @@ export declare const OOXML_REL_TARGETS: {
56
59
  export declare function pivotCacheDefinitionRelTargetFromWorkbook(n: number | string): string;
57
60
  export declare function commentsRelTargetFromWorksheet(sheetId: number | string): string;
58
61
  export declare function vmlDrawingRelTargetFromWorksheet(sheetId: number | string): string;
62
+ export declare function vmlDrawingHFRelTargetFromWorksheet(sheetId: number | string): string;
59
63
  export declare function drawingRelTargetFromWorksheet(drawingName: string): string;
60
64
  export declare function vmlDrawingRelTargetFromWorksheetName(vmlName: string): string;
61
65
  export declare function commentsRelTargetFromWorksheetName(commentName: string): string;
@@ -17,6 +17,7 @@ const mediaFilenameRegex = /^xl\/media\/([a-zA-Z0-9]+[.][a-zA-Z0-9]{3,4})$/;
17
17
  const drawingXmlRegex = /^xl\/drawings\/(drawing\d+)[.]xml$/;
18
18
  const drawingRelsXmlRegex = /^xl\/drawings\/_rels\/(drawing\d+)[.]xml[.]rels$/;
19
19
  const vmlDrawingRegex = /^xl\/drawings\/(vmlDrawing\d+)[.]vml$/;
20
+ const vmlDrawingHFRegex = /^xl\/drawings\/(vmlDrawingHF\d+)[.]vml$/;
20
21
  const commentsXmlRegex = /^xl\/comments(\d+)[.]xml$/;
21
22
  const tableXmlRegex = /^xl\/tables\/(table\d+)[.]xml$/;
22
23
  const pivotTableXmlRegex = /^xl\/pivotTables\/(pivotTable\d+)[.]xml$/;
@@ -72,6 +73,10 @@ export function getVmlDrawingNameFromPath(path) {
72
73
  const match = vmlDrawingRegex.exec(path);
73
74
  return match ? match[1] : undefined;
74
75
  }
76
+ export function getVmlDrawingHFNameFromPath(path) {
77
+ const match = vmlDrawingHFRegex.exec(path);
78
+ return match ? match[1] : undefined;
79
+ }
75
80
  export function getCommentsIndexFromPath(path) {
76
81
  const match = commentsXmlRegex.exec(path);
77
82
  return match ? match[1] : undefined;
@@ -129,6 +134,12 @@ export function commentsPathFromName(commentName) {
129
134
  export function vmlDrawingPath(sheetId) {
130
135
  return `xl/drawings/vmlDrawing${sheetId}.vml`;
131
136
  }
137
+ export function vmlDrawingHFPath(sheetId) {
138
+ return `xl/drawings/vmlDrawingHF${sheetId}.vml`;
139
+ }
140
+ export function vmlDrawingHFRelsPath(sheetId) {
141
+ return `xl/drawings/_rels/vmlDrawingHF${sheetId}.vml.rels`;
142
+ }
132
143
  export function tablePath(target) {
133
144
  return `xl/tables/${target}`;
134
145
  }
@@ -178,6 +189,10 @@ export function vmlDrawingRelTargetFromWorksheet(sheetId) {
178
189
  // Target inside xl/worksheets/_rels/sheetN.xml.rels (base: xl/worksheets/)
179
190
  return `../drawings/vmlDrawing${sheetId}.vml`;
180
191
  }
192
+ export function vmlDrawingHFRelTargetFromWorksheet(sheetId) {
193
+ // Target inside xl/worksheets/_rels/sheetN.xml.rels (base: xl/worksheets/)
194
+ return `../drawings/vmlDrawingHF${sheetId}.vml`;
195
+ }
181
196
  export function drawingRelTargetFromWorksheet(drawingName) {
182
197
  // Target inside xl/worksheets/_rels/sheetN.xml.rels (base: xl/worksheets/)
183
198
  return `../drawings/${drawingName}.xml`;
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Zero-dependency text-to-PNG watermark image generator.
3
+ *
4
+ * Renders text into a semi-transparent PNG suitable for use as an Excel watermark.
5
+ * Uses a built-in bitmap font for ASCII characters — no Canvas or external fonts required.
6
+ * PNG data is deflate-compressed using the archive module's built-in compressor.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * const png = createTextWatermarkImage("CONFIDENTIAL", {
11
+ * fontSize: 48,
12
+ * color: { r: 128, g: 128, b: 128 },
13
+ * opacity: 40,
14
+ * rotation: -45
15
+ * });
16
+ * const imgId = workbook.addImage({ buffer: png, extension: "png" });
17
+ * worksheet.addWatermark({ imageId: imgId });
18
+ * ```
19
+ */
20
+ /**
21
+ * Options for text watermark image generation.
22
+ */
23
+ export interface TextWatermarkImageOptions {
24
+ /**
25
+ * Approximate font size in pixels (glyph height).
26
+ * The built-in bitmap font is 8px tall; values larger than 8 are achieved by
27
+ * integer scaling. e.g. fontSize 48 → 6x scale.
28
+ * @default 48
29
+ */
30
+ fontSize?: number;
31
+ /**
32
+ * Text color as RGB (0-255 each).
33
+ * @default { r: 128, g: 128, b: 128 }
34
+ */
35
+ color?: {
36
+ r: number;
37
+ g: number;
38
+ b: number;
39
+ };
40
+ /**
41
+ * Opacity as a percentage (0 = fully transparent, 100 = fully opaque).
42
+ *
43
+ * Note: this is a **0–100 percentage** used when rendering the PNG image pixels.
44
+ * It is different from `WatermarkOptions.opacity` (which is 0–1) used by
45
+ * `worksheet.addWatermark()` for DrawingML `alphaModFix`.
46
+ *
47
+ * @default 40
48
+ */
49
+ opacity?: number;
50
+ /**
51
+ * Rotation in degrees (positive = counter-clockwise).
52
+ * @default -45
53
+ */
54
+ rotation?: number;
55
+ /**
56
+ * Padding in pixels around the text (before rotation).
57
+ * @default 20
58
+ */
59
+ padding?: number;
60
+ }
61
+ /**
62
+ * Generate a PNG image containing watermark text.
63
+ *
64
+ * The image has an alpha channel so the watermark is semi-transparent.
65
+ * Works in both Node.js and browsers with zero dependencies.
66
+ */
67
+ export declare function createTextWatermarkImage(text: string, options?: TextWatermarkImageOptions): Uint8Array;