ste-canvas-poster 1.0.0 → 1.0.1
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/CHANGELOG.md +6 -0
- package/README.md +1 -34
- package/package.json +5 -5
- package/src/posterAdapter.js +9 -67
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -134,7 +134,7 @@ computed: {
|
|
|
134
134
|
|
|
135
135
|
### renderPoster(options)
|
|
136
136
|
|
|
137
|
-
|
|
137
|
+
渲染海报,自动处理rpx 转换和平台差异。
|
|
138
138
|
|
|
139
139
|
```typescript
|
|
140
140
|
function renderPoster(options: RenderPosterOptions): Promise<PosterEngine>;
|
|
@@ -232,16 +232,6 @@ function measureText(text: string, fontSize: number, bold?: boolean): number;
|
|
|
232
232
|
|
|
233
233
|
**返回值**:文本宽度(rpx),向上取整
|
|
234
234
|
|
|
235
|
-
典型用途 — 配合 Flex 布局计算容器宽度:
|
|
236
|
-
|
|
237
|
-
```javascript
|
|
238
|
-
import { measureText } from 'ste-canvas-poster';
|
|
239
|
-
|
|
240
|
-
const textWidth = Math.min(measureText(nickname, 24), 300);
|
|
241
|
-
// 在 schema 中使用
|
|
242
|
-
{ type: 'text', text: '{{nickname}}', css: { width: textWidth, height: 24, fontSize: 24 } }
|
|
243
|
-
```
|
|
244
|
-
|
|
245
235
|
---
|
|
246
236
|
|
|
247
237
|
## Schema 规范
|
|
@@ -498,29 +488,6 @@ Canvas 内部尺寸小于元素坐标范围。确保 `canvas.width/height` 不
|
|
|
498
488
|
|
|
499
489
|
`fontSize` 单位为 rpx,确保 `useRpx: true`(默认值)。
|
|
500
490
|
|
|
501
|
-
### 图片加载失败
|
|
502
|
-
|
|
503
|
-
数据中的图片路径字段名需以 `Image`/`Img`/`Url`/`Src`/`Photo`/`Pic` 结尾,或完整匹配 `background`/`qrcode`/`cover`/`avatar`,引擎才会自动解析路径。
|
|
504
|
-
|
|
505
|
-
### Flex 布局中 text 子元素位置不正确
|
|
506
|
-
|
|
507
|
-
Canvas 无法在绘制前测量文本尺寸,Flex 布局依赖子元素显式声明的 `width`/`height` 来计算位置。text 子元素若未设置,会被视为尺寸 0。
|
|
508
|
-
|
|
509
|
-
**解决**:为 text 子元素显式设置 `width` 和 `height`,配合 `measureText` 动态计算宽度:
|
|
510
|
-
|
|
511
|
-
```javascript
|
|
512
|
-
import { measureText } from 'ste-canvas-poster';
|
|
513
|
-
|
|
514
|
-
const textWidth = Math.min(measureText(nickname, 24), 300);
|
|
515
|
-
{ type: 'text', text: '{{nickname}}', css: { width: textWidth, height: 24 } }
|
|
516
|
-
```
|
|
517
|
-
|
|
518
|
-
若不方便预计算宽度,可改用绝对定位(`left`/`top`)替代 Flex 布局。
|
|
519
|
-
|
|
520
|
-
### 导出图片圆角看起来不生效
|
|
521
|
-
|
|
522
|
-
画布默认背景是透明的,圆角外区域也是透明。如果查看器/聊天窗口是白底,透明区域和白底融为一体看起来像没有圆角。设置 `background: '#FFFFFF'` 即可明显看到圆角效果。
|
|
523
|
-
|
|
524
491
|
---
|
|
525
492
|
|
|
526
493
|
## 文件结构
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "ste-canvas-poster",
|
|
3
3
|
"displayName": "ste-canvas-poster",
|
|
4
4
|
"name": "ste-canvas-poster",
|
|
5
|
-
"version": "1.0.
|
|
5
|
+
"version": "1.0.1",
|
|
6
6
|
"description": "基于 Canvas 2D API 的声明式海报绘制引擎,支持微信小程序与 APP 双端",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"main": "index.js",
|
|
@@ -61,9 +61,9 @@
|
|
|
61
61
|
"encrypt": [],
|
|
62
62
|
"platforms": {
|
|
63
63
|
"cloud": {
|
|
64
|
-
"tcb": "
|
|
65
|
-
"aliyun": "
|
|
66
|
-
"alipay": "
|
|
64
|
+
"tcb": "x",
|
|
65
|
+
"aliyun": "x",
|
|
66
|
+
"alipay": "x"
|
|
67
67
|
},
|
|
68
68
|
"client": {
|
|
69
69
|
"uni-app": {
|
|
@@ -140,4 +140,4 @@
|
|
|
140
140
|
"publishConfig": {
|
|
141
141
|
"access": "public"
|
|
142
142
|
}
|
|
143
|
-
}
|
|
143
|
+
}
|
package/src/posterAdapter.js
CHANGED
|
@@ -15,67 +15,6 @@
|
|
|
15
15
|
|
|
16
16
|
import { PosterEngine } from "./posterEngine.js";
|
|
17
17
|
|
|
18
|
-
// ─────────────────────────────────────────────
|
|
19
|
-
// 工具函数
|
|
20
|
-
// ─────────────────────────────────────────────
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* 判断是否为完整 URL
|
|
24
|
-
* @param {string} src
|
|
25
|
-
* @returns {boolean}
|
|
26
|
-
*/
|
|
27
|
-
function isFullUrl(src) {
|
|
28
|
-
if (!src) return false;
|
|
29
|
-
return (
|
|
30
|
-
/^https?:\/\//i.test(src) ||
|
|
31
|
-
/^data:image/i.test(src) ||
|
|
32
|
-
/^wxfile:/i.test(src)
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* 解析图片路径(相对路径 → 完整 URL)
|
|
38
|
-
* @param {string} src
|
|
39
|
-
* @returns {string}
|
|
40
|
-
*/
|
|
41
|
-
function resolveImagePath(src) {
|
|
42
|
-
if (!src) return "";
|
|
43
|
-
if (isFullUrl(src)) return src;
|
|
44
|
-
// #ifdef APP-PLUS
|
|
45
|
-
if (/^(file:|\/var\/|\/storage\/)/i.test(src)) return src;
|
|
46
|
-
// #endif
|
|
47
|
-
return src;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* 深度解析数据对象中的所有图片路径
|
|
52
|
-
* @param {Object} data
|
|
53
|
-
* @returns {Object}
|
|
54
|
-
*/
|
|
55
|
-
const IMAGE_KEY_SUFFIX_RE = /(Image|Img|Url|Src|Photo|Pic)$/i;
|
|
56
|
-
const IMAGE_KEY_EXACT_RE = /^(background|qrcode|cover|avatar)$/i;
|
|
57
|
-
|
|
58
|
-
function resolveDataImages(data) {
|
|
59
|
-
if (!data || typeof data !== "object") return data;
|
|
60
|
-
|
|
61
|
-
let resolved = null;
|
|
62
|
-
for (const [key, value] of Object.entries(data)) {
|
|
63
|
-
if (
|
|
64
|
-
typeof value === "string" &&
|
|
65
|
-
(IMAGE_KEY_SUFFIX_RE.test(key) || IMAGE_KEY_EXACT_RE.test(key))
|
|
66
|
-
) {
|
|
67
|
-
const newPath = resolveImagePath(value);
|
|
68
|
-
if (newPath !== value) {
|
|
69
|
-
if (!resolved) {
|
|
70
|
-
resolved = { ...data };
|
|
71
|
-
}
|
|
72
|
-
resolved[key] = newPath;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
return resolved || data;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
18
|
// ─────────────────────────────────────────────
|
|
80
19
|
// 辅助:rpx → px 转换
|
|
81
20
|
// ─────────────────────────────────────────────
|
|
@@ -151,7 +90,10 @@ function transformSchemaRpx(schema) {
|
|
|
151
90
|
if (value && typeof value === "object") {
|
|
152
91
|
traverseInPlace(value);
|
|
153
92
|
} else if (shouldTransform(value)) {
|
|
154
|
-
if (
|
|
93
|
+
if (
|
|
94
|
+
NON_DIMENSION_KEYS.has(key) ||
|
|
95
|
+
(key === "fontWeight" && typeof value === "number")
|
|
96
|
+
) {
|
|
155
97
|
continue;
|
|
156
98
|
}
|
|
157
99
|
obj[key] = transformValue(value, scale);
|
|
@@ -260,7 +202,7 @@ async function preloadSchemaImages(schema, data = {}) {
|
|
|
260
202
|
// 下载失败保留原值
|
|
261
203
|
}),
|
|
262
204
|
);
|
|
263
|
-
}
|
|
205
|
+
}
|
|
264
206
|
}
|
|
265
207
|
|
|
266
208
|
await Promise.all(promises);
|
|
@@ -378,11 +320,11 @@ export async function renderPoster({
|
|
|
378
320
|
const schemaCopy = JSON.parse(JSON.stringify(schema));
|
|
379
321
|
|
|
380
322
|
// 自动将 schema 中的 rpx 转换为 px(业务层可以直接使用设计稿的 rpx 值)
|
|
381
|
-
const transformedSchema = useRpx
|
|
323
|
+
const transformedSchema = useRpx
|
|
324
|
+
? transformSchemaRpx(schemaCopy)
|
|
325
|
+
: schemaCopy;
|
|
382
326
|
|
|
383
|
-
|
|
384
|
-
const resolvedData = resolveDataImages(data);
|
|
385
|
-
let preloadedData = resolvedData;
|
|
327
|
+
let preloadedData = data;
|
|
386
328
|
|
|
387
329
|
// #ifdef APP-PLUS
|
|
388
330
|
preloadedData = await preloadSchemaImages(transformedSchema, resolvedData);
|