leafer-x-watermark 3.1.0 → 4.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.
package/README.md CHANGED
@@ -1,219 +1,141 @@
1
- # leafer-x-watermark
2
-
3
- [![npm version][npm-version-src]][npm-version-href]
4
- [![npm downloads][npm-downloads-src]][npm-downloads-href]
5
- [![bundle][bundle-src]][bundle-href]
6
- [![License][license-src]][license-href]
7
-
8
- Leafer UI 水印插件,支持任意 LeaferJS 元素平铺水印
9
-
10
- > ⚠️ **重要提示**:如果需要使用 `tileStagger`(错位排列)功能,必须在 `new App()` 后立即调用 `installStaggerPattern()` 进行补丁安装(此为临时方案,待官方支持后将移除)。
11
-
12
- ## 特性
13
-
14
- - 🎨 **任意图形** - 支持任意 LeaferJS 元素作为水印内容
15
- - 🔄 **平铺模式** - 支持平铺(repeat)和拉伸(stretch)两种模式
16
- - 📐 **灵活缩放** - 支持自定义水印尺寸比例
17
- - 🔲 **间距控制** - 支持自定义水印间距
18
- - 🎯 **错位排列** - 支持水印错位(stagger)效果
19
- - 🔃 **旋转支持** - 支持水印旋转角度设置
20
- - ⚡ **性能优化** - 智能缓存,仅在必要时重新生成图片
21
- - 🚀 **多版本支持** - 提供同步、异步及 URL 三种版本,适配不同场景需求
22
-
23
- ## 📦 安装
24
-
25
- ```bash
26
- # pnpm
27
- pnpm add leafer-x-watermark
28
-
29
- # npm
30
- npm install leafer-x-watermark
31
-
32
- # yarn
33
- yarn add leafer-x-watermark
34
- ```
35
-
36
- ## 🚀 快速开始
37
-
38
- ### 版本选择
39
-
40
- 根据水印内容选择合适的版本:
41
-
42
- - **WatermarkSync(同步版本)** - 适用于纯文本、矩形等基础图形,性能更好
43
- - **WatermarkAsync(异步版本)** - 适用于包含图片URL、自定义字体等需要加载的异步资源
44
- - **WatermarkURL(URL版本)** - 直接通过图片URL创建水印,更加便捷
45
-
46
- ```typescript
47
- import { WatermarkSync } from 'leafer-x-watermark' // 同步版本
48
- import { WatermarkAsync } from 'leafer-x-watermark' // 异步版本
49
- import { WatermarkURL } from 'leafer-x-watermark' // URL版本
50
- ```
51
-
52
- ### 基础使用(同步版本)
53
-
54
- ```typescript
55
- import { App } from 'leafer-ui'
56
- import { WatermarkSync, installStaggerPattern } from 'leafer-x-watermark'
57
-
58
- const app = new App({ view: 'app' })
59
- installStaggerPattern() // 全局安装一次即可
60
-
61
- const watermark = new WatermarkSync({
62
- tileContent: JSON.stringify({
63
- tag: 'Text',
64
- text: '水印文字',
65
- fill: 'rgba(0, 0, 0, 0.1)',
66
- fontSize: 16,
67
- }),
68
- width: 800,
69
- height: 600,
70
- })
71
-
72
- app.tree.add(watermark)
73
- ```
74
-
75
- ### URL版本使用
76
-
77
- 可以直接使用图片 URL 作为水印内容:
78
-
79
- ```typescript
80
- import { App } from 'leafer-ui'
81
- import { WatermarkURL, installStaggerPattern } from 'leafer-x-watermark'
82
-
83
- const app = new App({ view: 'app' })
84
- installStaggerPattern()
85
-
86
- const watermark = new WatermarkURL({
87
- tileURL: 'https://example.com/logo.png',
88
- tileMode: true,
89
- tileSize: 50,
90
- width: 800,
91
- height: 600,
92
- })
93
-
94
- app.tree.add(watermark)
95
- ```
96
-
97
- ### 异步版本使用
98
-
99
- 当水印内容包含图片资源时,使用异步版本:
100
-
101
- ```typescript
102
- import { App } from 'leafer-ui'
103
- import { WatermarkAsync, installStaggerPattern } from 'leafer-x-watermark'
104
-
105
- const app = new App({ view: 'app' })
106
- installStaggerPattern()
107
-
108
- const watermark = new WatermarkAsync({
109
- tileContent: JSON.stringify({
110
- tag: 'Image',
111
- url: 'https://example.com/logo.png',
112
- width: 100,
113
- height: 100,
114
- }),
115
- tileMode: true,
116
- width: 800,
117
- height: 600,
118
- })
119
-
120
- app.tree.add(watermark)
121
- ```
122
-
123
- ## 📖 API 文档
124
-
125
- ### WatermarkSync / WatermarkAsync / WatermarkURL
126
-
127
- 三个版本的 API 基本相同,主要区别:
128
- - **WatermarkSync**: 同步生成,适用于纯图形。
129
- - **WatermarkAsync**: 异步生成,适用于包含外部资源的图形。
130
- - **WatermarkURL**: 直接使用 `tileURL` 属性设置图片 URL。
131
-
132
- 继承自 Leafer UI 的 [Rect](https://www.leaferjs.com/ui/reference/display/Rect.html) 组件,拥有所有 Rect 属性,并额外支持:
133
-
134
- | 属性 | 类型 | 默认值 | 说明 |
135
- |------|------|--------|------|
136
- | `tileContent` | string | - | 水印内容,LeaferJS 元素的 JSON 字符串(URL版本不支持) |
137
- | `tileURL` | string | - | 直接设置图片 URL 作为水印(仅限 URL版本) |
138
- | `tileMode` | boolean | `true` | 平铺模式:`true` 平铺,`false` 拉伸 |
139
- | `tileSize` | number | `100` | 显示比例(%),100 为原始大小 |
140
- | `tileGap` | `number \| { x?: number, y?: number }` | `0` | 间距比例(%),支持统一数值或分别设置 x/y 间距 |
141
- | `tileStagger` | `number \| { type?: 'x' \| 'y', offset: number }` | `0` | 错位偏移,支持数值(0-100)或详细配置 |
142
- | `tileRotation` | number | `0` | 水印旋转角度(度) |
143
-
144
- ### 属性说明
145
-
146
- #### tileContent / tileURL
147
-
148
- 水印内容支持 LeaferJS 元素的 JSON 字符串(Sync/Async版本)或直接图片 URL(URL版本):
149
-
150
- ```typescript
151
- // Sync / Async 版本使用 tileContent
152
- JSON.stringify({ tag: 'Text', text: '水印', fill: '#000', fontSize: 16 })
153
-
154
- // URL 版本使用 tileURL
155
- const tileURL = 'https://example.com/logo.png'
156
- ```
157
-
158
- #### tileSize
159
-
160
- 控制水印显示大小的比例:
161
- - `100` = 原始大小
162
- - `50` = 缩小 50%
163
- - `200` = 放大 200%
164
- - `0` 或负数 = 不显示水印
165
-
166
- #### tileGap
167
-
168
- 间距基于显示尺寸的百分比计算:
169
- - `tileGap: 10` 表示间距为水印宽/高的 10%
170
- - 支持分别设置:`{ x: 20, y: 10 }`
171
-
172
- #### tileStagger
173
-
174
- 错位排列效果,支持数值 (0-100) 或对象配置:
175
- - `tileStagger: 50` = 水平方向(x)相邻行偏移 50%
176
- - `{ type: 'y', offset: 50 }` = 垂直方向(y)相邻列偏移 50%
177
- - `0` = 无错位
178
- - `100` = 完全错位(等于一个完整水印尺寸)
179
-
180
- ⚠️ **注意**:使用 `tileStagger` 功能前必须先调用 `installStaggerPattern()`
181
-
182
- ## 💡 使用场景
183
-
184
- - 📄 文档版权保护
185
- - 🖼️ 图片水印
186
- - 🔒 机密文件标识
187
- - 🏢 企业 Logo 背景
188
- - 📑 证书防伪
189
-
190
- ## 🔗 相关链接
191
-
192
- - [在线演示](https://leafer-x-watermark.vercel.app/)
193
- - [Leafer UI 文档](https://www.leaferjs.com/ui/guide/)
194
-
195
- ## 🤝 贡献
196
-
197
- 欢迎提交 Issue 和 Pull Request!
198
-
199
- ## License
200
-
201
- [MIT](./LICENSE) License © 2024-PRESENT [XiaDeYu](https://github.com/Xdy1579883916)
202
-
203
- <!-- Badges -->
204
-
205
- [npm-version-src]: https://img.shields.io/npm/v/leafer-x-watermark?style=flat&colorA=080f12&colorB=1fa669
206
-
207
- [npm-version-href]: https://npmjs.com/package/leafer-x-watermark
208
-
209
- [npm-downloads-src]: https://img.shields.io/npm/dm/leafer-x-watermark?style=flat&colorA=080f12&colorB=1fa669
210
-
211
- [npm-downloads-href]: https://npmjs.com/package/leafer-x-watermark
212
-
213
- [bundle-src]: https://img.shields.io/bundlephobia/minzip/leafer-x-watermark?style=flat&colorA=080f12&colorB=1fa669&label=minzip
214
-
215
- [bundle-href]: https://bundlephobia.com/result?p=leafer-x-watermark
216
-
217
- [license-src]: https://img.shields.io/github/license/Xdy1579883916/leafer-x-watermark.svg?style=flat&colorA=080f12&colorB=1fa669
218
-
219
- [license-href]: https://github.com/Xdy1579883916/leafer-x-watermark/blob/master/LICENSE
1
+ # leafer-x-watermark
2
+
3
+ [![npm version][npm-version-src]][npm-version-href]
4
+ [![npm downloads][npm-downloads-src]][npm-downloads-href]
5
+ [![bundle][bundle-src]][bundle-href]
6
+ [![License][license-src]][license-href]
7
+
8
+ Leafer UI 水印插件,基于 Leafer 2.0.0 构建,使用更加简单高效。
9
+
10
+ ## 特性
11
+
12
+ - 🖼️ **图片水印** - 直接使用图片 URL 创建水印
13
+ - 🔄 **平铺模式** - 支持平铺(repeat)和拉伸(stretch)两种模式
14
+ - 📐 **灵活缩放** - 支持自定义水印尺寸比例
15
+ - 🔲 **间距控制** - 支持自定义水印间距
16
+ - 🎯 **错位排列** - 支持水印错位效果:基于 Leafer 2.0.0版本(interlace)支持
17
+ - 🔃 **旋转支持** - 支持水印旋转角度设置
18
+
19
+ ## 📦 安装
20
+
21
+ ```bash
22
+ # pnpm
23
+ pnpm add leafer-x-watermark
24
+
25
+ # npm
26
+ npm install leafer-x-watermark
27
+
28
+ # yarn
29
+ yarn add leafer-x-watermark
30
+ ```
31
+
32
+ ## 🚀 快速开始
33
+
34
+ ```typescript
35
+ import { App } from 'leafer-ui'
36
+ import { WatermarkURL } from 'leafer-x-watermark'
37
+
38
+ const app = new App({ view: 'app' })
39
+
40
+ const watermark = new WatermarkURL({
41
+ tileURL: 'https://leaferjs.com/image/logo.svg',
42
+ tileMode: true,
43
+ tileSize: 50, // 缩放 50%
44
+ tileGap: 20, // 间距 20%
45
+ tileStagger: 50, // 错位 50%
46
+ width: 800,
47
+ height: 600,
48
+ })
49
+
50
+ app.tree.add(watermark)
51
+ ```
52
+
53
+ ## 📖 API 文档
54
+
55
+ ### WatermarkURL
56
+
57
+ 继承自 Leafer UI 的 [Rect](https://www.leaferjs.com/ui/reference/display/Rect.html) 组件,拥有所有 Rect 属性。
58
+
59
+ | 属性 | 类型 | 默认值 | 说明 |
60
+ |------|------|--------|------|
61
+ | `tileURL` | string | - | 水印图片的 URL 地址 |
62
+ | `tileMode` | boolean | `true` | 平铺模式:`true` 平铺,`false` 拉伸 |
63
+ | `tileSize` | number | `100` | 显示比例(%),100 为原始大小 |
64
+ | `tileGap` | `number \| { x?: number, y?: number }` | `0` | 间距比例(%),支持统一数值或分别设置 x/y 间距 |
65
+ | `tileStagger` | `number \| { type?: 'x' \| 'y', offset: number }` | `0` | 错位偏移,支持数值(0-100)或详细配置 |
66
+ | `tileRotation` | number | `0` | 水印旋转角度(度) |
67
+
68
+ ### 属性说明
69
+
70
+ #### tileURL
71
+
72
+ 设置水印图片的地址,支持网络图片 URL 或 Base64 字符串。
73
+
74
+ ```typescript
75
+ // 使用网络图片
76
+ watermark.tileURL = 'https://example.com/logo.png'
77
+ ```
78
+
79
+ #### tileSize
80
+
81
+ 控制水印显示大小的比例:
82
+ - `100` = 原始大小
83
+ - `50` = 缩小 50%
84
+ - `200` = 放大 200%
85
+ - `0` = 不显示
86
+
87
+ #### tileGap
88
+
89
+ 间距基于显示尺寸的百分比计算:
90
+ - `tileGap: 10` 表示间距为水印宽/高的 10%
91
+ - 支持分别设置:`{ x: 20, y: 10 }`
92
+
93
+ #### tileStagger
94
+
95
+ 错位排列效果(Interlace),支持数值 (0-100) 或对象配置:
96
+ - `tileStagger: 50` = 水平方向(x)相邻行偏移 50%
97
+ - `{ type: 'y', offset: 50 }` = 垂直方向(y)相邻列偏移 50%
98
+ - `0` = 无错位
99
+
100
+ #### tileMode
101
+
102
+ - `true`: 启用平铺模式(Repeat),支持间距、错位等效果。
103
+ - `false`: 启用拉伸模式(Stretch),图片将填满整个区域。
104
+
105
+ ## 💡 使用场景
106
+
107
+ - 📄 文档版权保护
108
+ - 🖼️ 图片水印
109
+ - 🔒 机密文件标识
110
+ - 🏢 企业 Logo 背景
111
+
112
+ ## 🔗 相关链接
113
+
114
+ - [在线演示](https://leafer-x-watermark.vercel.app/)
115
+ - [Leafer UI 文档](https://www.leaferjs.com/ui/guide/)
116
+
117
+ ## 🤝 贡献
118
+
119
+ 欢迎提交 Issue 和 Pull Request!
120
+
121
+ ## License
122
+
123
+ [MIT](./LICENSE) License © 2024-PRESENT [XiaDeYu](https://github.com/Xdy1579883916)
124
+
125
+ <!-- Badges -->
126
+
127
+ [npm-version-src]: https://img.shields.io/npm/v/leafer-x-watermark?style=flat&colorA=080f12&colorB=1fa669
128
+
129
+ [npm-version-href]: https://npmjs.com/package/leafer-x-watermark
130
+
131
+ [npm-downloads-src]: https://img.shields.io/npm/dm/leafer-x-watermark?style=flat&colorA=080f12&colorB=1fa669
132
+
133
+ [npm-downloads-href]: https://npmjs.com/package/leafer-x-watermark
134
+
135
+ [bundle-src]: https://img.shields.io/bundlephobia/minzip/leafer-x-watermark?style=flat&colorA=080f12&colorB=1fa669&label=minzip
136
+
137
+ [bundle-href]: https://bundlephobia.com/result?p=leafer-x-watermark
138
+
139
+ [license-src]: https://img.shields.io/github/license/Xdy1579883916/leafer-x-watermark.svg?style=flat&colorA=080f12&colorB=1fa669
140
+
141
+ [license-href]: https://github.com/Xdy1579883916/leafer-x-watermark/blob/master/LICENSE
package/dist/index.d.mts CHANGED
@@ -7,16 +7,13 @@ interface IStaggerData {
7
7
  offset: number;
8
8
  }
9
9
  type IStagger = number | IStaggerData;
10
- interface INormalizedStagger {
11
- type: IStaggerType;
12
- offset: number;
13
- }
14
10
  declare module '@leafer-ui/interface' {
15
11
  interface IImagePaint {
16
12
  stagger?: IStagger;
17
13
  }
18
14
  }
19
15
 
16
+ type ITileContentParser = (content: string) => object | null;
20
17
  interface ITileGap {
21
18
  x?: number;
22
19
  y?: number;
@@ -31,7 +28,6 @@ interface IWatermarkAttrData {
31
28
  tileRotation?: number;
32
29
  }
33
30
  interface IProcessDataType extends IRectData {
34
- _tileContent?: string;
35
31
  _tileURL?: string;
36
32
  _tileMode?: boolean;
37
33
  _tileSize?: number;
@@ -48,6 +44,7 @@ interface IProcessDataType extends IRectData {
48
44
  }
49
45
  interface IWatermark extends IWatermarkAttrData, IUI {
50
46
  __: IProcessDataType;
47
+ tileContentParser?: ITileContentParser;
51
48
  }
52
49
  interface IWatermarkInputData extends IWatermarkAttrData, IRectInputData {
53
50
  }
@@ -59,15 +56,13 @@ declare abstract class ProcessorDataBase extends RectData implements IProcessDat
59
56
  width: number;
60
57
  height: number;
61
58
  };
62
- _tileContent?: string;
63
59
  _tileURL?: string;
64
60
  _tileMode?: boolean;
65
61
  _tileSize?: number;
66
62
  _tileGap?: number | ITileGap;
67
- _tileStagger?: number;
63
+ _tileStagger?: IStagger;
68
64
  _tileRotation?: number;
69
65
  abstract regenerateImage(): void | Promise<void>;
70
- setTileContent(value: string): void;
71
66
  setTileURL(value: string): void;
72
67
  setTileMode(value: boolean): void;
73
68
  setTileSize(value: number): void;
@@ -77,59 +72,20 @@ declare abstract class ProcessorDataBase extends RectData implements IProcessDat
77
72
  updateFill(): void;
78
73
  __getData(): IObject;
79
74
  __getInputData(names?: string[] | IObject, options?: IJSONOptions): IObject;
80
- protected createTileItem(itemData: object): IUI;
81
- protected parseAndValidateTileContent(): object | null;
82
75
  protected updateLeafDimensions(bounds: {
83
76
  width: number;
84
77
  height: number;
85
78
  }): void;
86
- protected finalizeCachedData(url: string, bounds: {
87
- width: number;
88
- height: number;
89
- }): void;
90
79
  }
91
80
 
92
81
  declare abstract class WatermarkBase<TConstructorData = IWatermarkInputData> extends Rect<TConstructorData> implements IWatermark {
93
82
  __: ProcessorDataBase;
83
+ tileContentParser?: ITileContentParser;
94
84
  constructor(data?: TConstructorData);
95
85
  syncParentSize(e?: PropertyEvent): void;
96
86
  destroy(): void;
97
87
  }
98
88
 
99
- declare class ProcessorDataAsync extends ProcessorDataBase {
100
- __leaf: WatermarkAsync;
101
- setTileContent(value: string): Promise<void>;
102
- regenerateImage(): Promise<void>;
103
- }
104
- declare class WatermarkAsync<TConstructorData = IWatermarkInputData> extends WatermarkBase<TConstructorData> {
105
- get __tag(): string;
106
- __: ProcessorDataAsync;
107
- tileContent?: string;
108
- tileMode: boolean;
109
- tileSize: number;
110
- tileGap: number | ITileGap;
111
- tileStagger: IStagger;
112
- tileRotation: number;
113
- get tileURL(): string;
114
- }
115
-
116
- declare class ProcessorData$1 extends ProcessorDataBase {
117
- __leaf: WatermarkSync;
118
- regenerateImage(): void;
119
- private _simpleExport;
120
- }
121
- declare class WatermarkSync<TConstructorData = IWatermarkInputData> extends WatermarkBase<TConstructorData> {
122
- get __tag(): string;
123
- __: ProcessorData$1;
124
- tileContent?: string;
125
- tileMode: boolean;
126
- tileSize: number;
127
- tileGap: number | ITileGap;
128
- tileStagger: IStagger;
129
- tileRotation: number;
130
- get tileURL(): string;
131
- }
132
-
133
89
  declare class ProcessorData extends ProcessorDataBase {
134
90
  __leaf: WatermarkURL;
135
91
  regenerateImage(): void;
@@ -145,9 +101,5 @@ declare class WatermarkURL<TConstructorData = IWatermarkInputData> extends Water
145
101
  tileRotation: number;
146
102
  }
147
103
 
148
- declare function normalizeStagger(stagger: IStagger): INormalizedStagger;
149
- declare function installStaggerPattern(): void;
150
- declare function processStaggerData(paint: any): INormalizedStagger | null;
151
-
152
- export { WatermarkAsync, WatermarkSync, WatermarkURL, installStaggerPattern, normalizeStagger, processStaggerData };
153
- export type { INormalizedStagger, IProcessDataType, IStagger, IStaggerData, IStaggerType, ITileGap, IWatermark, IWatermarkAttrData, IWatermarkInputData };
104
+ export { WatermarkURL };
105
+ export type { IProcessDataType, ITileContentParser, ITileGap, IWatermark, IWatermarkAttrData, IWatermarkInputData };
package/dist/index.mjs CHANGED
@@ -1,20 +1,20 @@
1
- import { Debug, RectData, isObject, UICreator, Rect, PropertyEvent, dataProcessor, boundsType, registerUI, Plugin, Creator, MatrixHelper, MathHelper, PaintImage, Platform } from '@leafer-ui/core';
1
+ import { RectData, isObject, Rect, PropertyEvent, dataProcessor, boundsType, registerUI, Creator } from '@leafer-ui/core';
2
2
 
3
- const console = Debug.get("leafer-x-watermark");
3
+ function normalizeStagger(stagger) {
4
+ if (typeof stagger === "number") {
5
+ return { type: "x", offset: stagger };
6
+ }
7
+ return { type: stagger.type || "x", offset: stagger.offset || 0 };
8
+ }
4
9
  class ProcessorDataBase extends RectData {
5
10
  _cachedUrl;
6
11
  _cachedBounds;
7
- _tileContent = "";
8
12
  _tileURL = "";
9
13
  _tileMode = true;
10
14
  _tileSize = 100;
11
15
  _tileGap = 0;
12
16
  _tileStagger = 0;
13
17
  _tileRotation = 0;
14
- setTileContent(value) {
15
- this._tileContent = value;
16
- this.regenerateImage();
17
- }
18
18
  setTileURL(value) {
19
19
  this._tileURL = value;
20
20
  this.regenerateImage();
@@ -22,7 +22,7 @@ class ProcessorDataBase extends RectData {
22
22
  setTileMode(value) {
23
23
  this._tileMode = value;
24
24
  this.updateFill();
25
- if (value && this.__leaf.syncParentSize)
25
+ if (this.__leaf.syncParentSize)
26
26
  this.__leaf.syncParentSize();
27
27
  }
28
28
  setTileSize(value) {
@@ -68,13 +68,21 @@ class ProcessorDataBase extends RectData {
68
68
  }
69
69
  const gapX = xGap / 100 * sizeWidth;
70
70
  const gapY = yGap / 100 * sizeHeight;
71
+ const interlace = normalizeStagger(_tileStagger);
71
72
  leaf.fill = {
72
73
  type: "image",
73
74
  url: this._cachedUrl,
74
75
  mode: "repeat",
75
76
  gap: { x: gapX, y: gapY },
76
77
  size: { width: sizeWidth, height: sizeHeight },
77
- stagger: _tileStagger,
78
+ interlace: {
79
+ type: interlace.type || "x",
80
+ offset: {
81
+ type: "percent",
82
+ // 为 0 时有bug,不渲染了,待修复。先手动改为1。
83
+ value: (interlace.offset || 1) / 100
84
+ }
85
+ },
78
86
  rotation: _tileRotation,
79
87
  align: "center"
80
88
  };
@@ -90,27 +98,6 @@ class ProcessorDataBase extends RectData {
90
98
  delete data.fill;
91
99
  return data;
92
100
  }
93
- createTileItem(itemData) {
94
- return UICreator.get("Group", {
95
- children: [itemData],
96
- around: "center"
97
- });
98
- }
99
- parseAndValidateTileContent() {
100
- const { _tileContent } = this;
101
- if (!_tileContent) {
102
- this._cachedUrl = void 0;
103
- this._cachedBounds = void 0;
104
- this.__leaf.fill = void 0;
105
- return null;
106
- }
107
- try {
108
- return JSON.parse(_tileContent);
109
- } catch (e) {
110
- console.error("Invalid tileContent JSON:", e);
111
- return null;
112
- }
113
- }
114
101
  updateLeafDimensions(bounds) {
115
102
  const leaf = this.__leaf;
116
103
  const { width, height } = leaf;
@@ -119,14 +106,10 @@ class ProcessorDataBase extends RectData {
119
106
  leaf.height = bounds.height;
120
107
  }
121
108
  }
122
- finalizeCachedData(url, bounds) {
123
- this._cachedUrl = url;
124
- this._cachedBounds = bounds;
125
- this.updateFill();
126
- }
127
109
  }
128
110
 
129
111
  class WatermarkBase extends Rect {
112
+ tileContentParser;
130
113
  constructor(data) {
131
114
  super(data);
132
115
  this.syncParentSize = this.syncParentSize.bind(this);
@@ -136,13 +119,17 @@ class WatermarkBase extends Rect {
136
119
  });
137
120
  }
138
121
  syncParentSize(e) {
139
- if (e && !["width", "height"].includes(e.attrName)) {
122
+ if (e && !["width", "height", "x", "y"].includes(e.attrName)) {
140
123
  return;
141
124
  }
142
125
  if (this.__._tileMode && this.parent) {
143
126
  this.width = this.parent.width;
144
127
  this.height = this.parent.height;
145
- this.y = this.x = 0;
128
+ this.y = this.x = this.rotation = 0;
129
+ this.scaleX = this.scaleY = 1;
130
+ } else {
131
+ this.width = this.__._cachedBounds?.width;
132
+ this.height = this.__._cachedBounds?.height;
146
133
  }
147
134
  }
148
135
  destroy() {
@@ -153,144 +140,6 @@ class WatermarkBase extends Rect {
153
140
  }
154
141
  }
155
142
 
156
- var __defProp$2 = Object.defineProperty;
157
- var __getOwnPropDesc$2 = Object.getOwnPropertyDescriptor;
158
- var __decorateClass$2 = (decorators, target, key, kind) => {
159
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$2(target, key) : target;
160
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
161
- if (decorator = decorators[i])
162
- result = (kind ? decorator(target, key, result) : decorator(result)) || result;
163
- if (kind && result) __defProp$2(target, key, result);
164
- return result;
165
- };
166
- class ProcessorDataAsync extends ProcessorDataBase {
167
- // 异步版本需要覆盖,以便正确 await
168
- async setTileContent(value) {
169
- this._tileContent = value;
170
- await this.regenerateImage();
171
- }
172
- async regenerateImage() {
173
- const itemData = this.parseAndValidateTileContent();
174
- if (!itemData)
175
- return;
176
- const tempItem = this.createTileItem(itemData);
177
- const bounds = tempItem.getBounds("box", "local");
178
- this.updateLeafDimensions(bounds);
179
- const exportWidth = 1e3;
180
- const { data: url } = await tempItem.export("png", {
181
- blob: false,
182
- size: { width: exportWidth }
183
- });
184
- tempItem.destroy();
185
- this.finalizeCachedData(url, bounds);
186
- }
187
- }
188
- let WatermarkAsync = class extends WatermarkBase {
189
- get __tag() {
190
- return "WatermarkAsync";
191
- }
192
- get tileURL() {
193
- return this.__._cachedUrl;
194
- }
195
- };
196
- __decorateClass$2([
197
- dataProcessor(ProcessorDataAsync)
198
- ], WatermarkAsync.prototype, "__", 2);
199
- __decorateClass$2([
200
- boundsType()
201
- ], WatermarkAsync.prototype, "tileContent", 2);
202
- __decorateClass$2([
203
- boundsType(true)
204
- ], WatermarkAsync.prototype, "tileMode", 2);
205
- __decorateClass$2([
206
- boundsType(100)
207
- ], WatermarkAsync.prototype, "tileSize", 2);
208
- __decorateClass$2([
209
- boundsType(0)
210
- ], WatermarkAsync.prototype, "tileGap", 2);
211
- __decorateClass$2([
212
- boundsType(0)
213
- ], WatermarkAsync.prototype, "tileStagger", 2);
214
- __decorateClass$2([
215
- boundsType(0)
216
- ], WatermarkAsync.prototype, "tileRotation", 2);
217
- WatermarkAsync = __decorateClass$2([
218
- registerUI()
219
- ], WatermarkAsync);
220
-
221
- var __defProp$1 = Object.defineProperty;
222
- var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
223
- var __decorateClass$1 = (decorators, target, key, kind) => {
224
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1(target, key) : target;
225
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
226
- if (decorator = decorators[i])
227
- result = (kind ? decorator(target, key, result) : decorator(result)) || result;
228
- if (kind && result) __defProp$1(target, key, result);
229
- return result;
230
- };
231
- let ProcessorData$1 = class ProcessorData extends ProcessorDataBase {
232
- regenerateImage() {
233
- const itemData = this.parseAndValidateTileContent();
234
- if (!itemData)
235
- return;
236
- const tempItem = this.createTileItem(itemData);
237
- const { url, bounds } = this._simpleExport(tempItem);
238
- this.updateLeafDimensions(bounds);
239
- tempItem.destroy();
240
- this.finalizeCachedData(url, bounds);
241
- }
242
- _simpleExport(ui) {
243
- const exportWidth = 1e3;
244
- const bounds = ui.getBounds("render", "local");
245
- const scaleRatio = exportWidth / bounds.width;
246
- const scaledWidth = Math.floor(bounds.width * scaleRatio);
247
- const scaledHeight = Math.floor(bounds.height * scaleRatio);
248
- const canvas = UICreator.get("Canvas", {
249
- x: 0,
250
- y: 0,
251
- width: scaledWidth,
252
- height: scaledHeight
253
- });
254
- canvas.draw(ui, void 0, scaleRatio);
255
- const url = canvas.canvas.toDataURL("image/png");
256
- canvas.destroy();
257
- return { url, bounds };
258
- }
259
- };
260
- let WatermarkSync = class extends WatermarkBase {
261
- get __tag() {
262
- return "WatermarkSync";
263
- }
264
- get tileURL() {
265
- return this.__._cachedUrl;
266
- }
267
- };
268
- __decorateClass$1([
269
- dataProcessor(ProcessorData$1)
270
- ], WatermarkSync.prototype, "__", 2);
271
- __decorateClass$1([
272
- boundsType()
273
- ], WatermarkSync.prototype, "tileContent", 2);
274
- __decorateClass$1([
275
- boundsType(true)
276
- ], WatermarkSync.prototype, "tileMode", 2);
277
- __decorateClass$1([
278
- boundsType(100)
279
- ], WatermarkSync.prototype, "tileSize", 2);
280
- __decorateClass$1([
281
- boundsType(0)
282
- ], WatermarkSync.prototype, "tileGap", 2);
283
- __decorateClass$1([
284
- boundsType(0)
285
- ], WatermarkSync.prototype, "tileStagger", 2);
286
- __decorateClass$1([
287
- boundsType(0)
288
- ], WatermarkSync.prototype, "tileRotation", 2);
289
- WatermarkSync = __decorateClass$1([
290
- registerUI()
291
- ], WatermarkSync);
292
- Plugin.add("leafer-x-watermark");
293
-
294
143
  var __defProp = Object.defineProperty;
295
144
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
296
145
  var __decorateClass = (decorators, target, key, kind) => {
@@ -301,17 +150,12 @@ var __decorateClass = (decorators, target, key, kind) => {
301
150
  if (kind && result) __defProp(target, key, result);
302
151
  return result;
303
152
  };
304
- async function toBase64(url) {
153
+ async function getBounds(url) {
305
154
  return new Promise((resolve) => {
306
155
  const leaferImage = Creator.image({ url });
307
156
  leaferImage.load((image) => {
308
157
  const { width, height } = image;
309
- const canvas = Creator.hitCanvas({ width, height, pixelRatio: 1 });
310
- canvas.drawImage(image.view, 0, 0);
311
- const data = canvas.toDataURL();
312
- canvas.destroy();
313
- leaferImage.destroy();
314
- resolve({ data, bounds: { width, height } });
158
+ resolve({ data: url, bounds: { width, height } });
315
159
  });
316
160
  });
317
161
  }
@@ -324,7 +168,7 @@ class ProcessorData extends ProcessorDataBase {
324
168
  this.__leaf.fill = void 0;
325
169
  return;
326
170
  }
327
- toBase64(url).then(({ data, bounds }) => {
171
+ getBounds(url).then(({ data, bounds }) => {
328
172
  this._cachedUrl = data;
329
173
  this._cachedBounds = bounds;
330
174
  this.updateLeafDimensions(bounds);
@@ -362,161 +206,4 @@ WatermarkURL = __decorateClass([
362
206
  registerUI()
363
207
  ], WatermarkURL);
364
208
 
365
- const { get, scale, copy } = MatrixHelper;
366
- const { getFloorScale } = MathHelper;
367
- const { abs } = Math;
368
- const ORIGINAL_CREATE_PATTERN = Symbol.for("leafer-x-watermark:PaintImage.createPattern.original");
369
- const STAGGER_PATTERN_ID = Symbol.for("leafer-x-watermark:paint.staggerPatternId");
370
- function ensureOriginalCreatePattern() {
371
- const anyPaintImage = PaintImage;
372
- if (!anyPaintImage[ORIGINAL_CREATE_PATTERN]) {
373
- anyPaintImage[ORIGINAL_CREATE_PATTERN] = PaintImage.createPattern.bind(PaintImage);
374
- }
375
- return anyPaintImage[ORIGINAL_CREATE_PATTERN];
376
- }
377
- const staggerCanvasCache = /* @__PURE__ */ new WeakMap();
378
- function normalizeStagger(stagger) {
379
- if (typeof stagger === "number") {
380
- return { type: "x", offset: stagger };
381
- }
382
- return { type: stagger.type || "x", offset: stagger.offset || 0 };
383
- }
384
- function isSameStaggerParams(a, b) {
385
- return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7];
386
- }
387
- function getStaggerCanvas(image, width, height, xGap, yGap, stagger, opacity, smooth) {
388
- const cached = staggerCanvasCache.get(image);
389
- if (cached) {
390
- const nextParams = [
391
- width,
392
- height,
393
- xGap,
394
- yGap,
395
- stagger.type,
396
- stagger.offset,
397
- opacity,
398
- smooth
399
- ];
400
- if (isSameStaggerParams(cached.params, nextParams))
401
- return cached.canvas;
402
- }
403
- const canvas = createStaggerCanvas(image, width, height, xGap, yGap, stagger, opacity, smooth);
404
- staggerCanvasCache.set(image, {
405
- params: [width, height, xGap, yGap, stagger.type, stagger.offset, opacity, smooth],
406
- canvas
407
- });
408
- return canvas;
409
- }
410
- function createStaggerCanvas(image, imgWidth, imgHeight, xGap, yGap, stagger, opacity, smooth) {
411
- const unitWidth = imgWidth + xGap;
412
- const unitHeight = imgHeight + yGap;
413
- const isXStagger = stagger.type === "x";
414
- const patternWidth = isXStagger ? unitWidth : unitWidth * 2;
415
- const patternHeight = isXStagger ? unitHeight * 2 : unitHeight;
416
- const canvas = Platform.origin.createCanvas(
417
- Math.max(Math.floor(patternWidth), 1),
418
- Math.max(Math.floor(patternHeight), 1)
419
- );
420
- const ctx = canvas.getContext("2d");
421
- if (opacity && opacity < 1)
422
- ctx.globalAlpha = opacity;
423
- ctx.imageSmoothingEnabled = smooth !== false;
424
- const imgView = image.view;
425
- const drawImg = (x, y) => {
426
- ctx.drawImage(imgView, 0, 0, image.width, image.height, x, y, imgWidth, imgHeight);
427
- };
428
- const offset = stagger.offset / 100 * (isXStagger ? unitWidth : unitHeight);
429
- if (isXStagger) {
430
- drawImg(0, 0);
431
- drawImg(offset, unitHeight);
432
- if (offset + imgWidth > unitWidth) {
433
- drawImg(offset - unitWidth, unitHeight);
434
- }
435
- } else {
436
- drawImg(0, 0);
437
- drawImg(unitWidth, offset);
438
- if (offset + imgHeight > unitHeight) {
439
- drawImg(unitWidth, offset - unitHeight);
440
- }
441
- }
442
- return canvas;
443
- }
444
- function createPatternWithStagger(paint, ui, canvas, renderOptions) {
445
- const originalCreatePattern = ensureOriginalCreatePattern();
446
- const rawStagger = paint.data?.stagger ?? paint.originPaint?.stagger;
447
- if (rawStagger === void 0 || rawStagger === 0) {
448
- originalCreatePattern(paint, ui, canvas, renderOptions);
449
- return;
450
- }
451
- const stagger = normalizeStagger(rawStagger);
452
- if (stagger.offset === 0) {
453
- originalCreatePattern(paint, ui, canvas, renderOptions);
454
- return;
455
- }
456
- let { scaleX, scaleY } = PaintImage.getImageRenderScaleData(paint, ui, canvas, renderOptions);
457
- const baseId = `${scaleX}-${scaleY}`;
458
- const staggerId = `${baseId}-stagger-${stagger.type}-${stagger.offset}`;
459
- const anyPaint = paint;
460
- if (ui.destroyed)
461
- return;
462
- if (paint.patternId === baseId && anyPaint[STAGGER_PATTERN_ID] === staggerId)
463
- return;
464
- if (Platform.image.isLarge(paint.image, scaleX, scaleY) && !paint.data.repeat)
465
- return;
466
- const { image, data } = paint;
467
- const { transform, gap } = data;
468
- const fixScale = PaintImage.getPatternFixScale(paint, scaleX, scaleY);
469
- if (fixScale) {
470
- scaleX *= fixScale;
471
- scaleY *= fixScale;
472
- }
473
- let imageMatrix;
474
- let xGap = 0;
475
- let yGap = 0;
476
- let { width, height } = image;
477
- width *= scaleX;
478
- height *= scaleY;
479
- if (gap) {
480
- xGap = gap.x * scaleX / abs(data.scaleX || 1);
481
- yGap = gap.y * scaleY / abs(data.scaleY || 1);
482
- }
483
- if (transform || scaleX !== 1 || scaleY !== 1) {
484
- scaleX *= getFloorScale(width + (xGap || 0));
485
- scaleY *= getFloorScale(height + (yGap || 0));
486
- imageMatrix = get();
487
- if (transform)
488
- copy(imageMatrix, transform);
489
- scale(imageMatrix, 1 / scaleX, 1 / scaleY);
490
- }
491
- const imageCanvas = getStaggerCanvas(
492
- image,
493
- width,
494
- height,
495
- xGap,
496
- yGap,
497
- stagger,
498
- data.opacity,
499
- ui.leafer?.config.smooth
500
- );
501
- const pattern = image.getPattern(
502
- imageCanvas,
503
- data.repeat || (Platform.origin.noRepeat || "no-repeat"),
504
- imageMatrix,
505
- paint
506
- );
507
- paint.style = pattern;
508
- paint.patternId = baseId;
509
- anyPaint[STAGGER_PATTERN_ID] = staggerId;
510
- }
511
- function installStaggerPattern() {
512
- ensureOriginalCreatePattern();
513
- PaintImage.createPattern = createPatternWithStagger;
514
- }
515
- function processStaggerData(paint) {
516
- if (paint.stagger !== void 0) {
517
- return normalizeStagger(paint.stagger);
518
- }
519
- return null;
520
- }
521
-
522
- export { WatermarkAsync, WatermarkSync, WatermarkURL, installStaggerPattern, normalizeStagger, processStaggerData };
209
+ export { WatermarkURL };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "leafer-x-watermark",
3
3
  "type": "module",
4
- "version": "3.1.0",
4
+ "version": "4.1.0",
5
5
  "packageManager": "pnpm@10.14.0",
6
6
  "description": "Leafer 水印插件",
7
7
  "author": "XiaDeYu <1579883916@qq.com>",