@mce/bigesj 0.11.0 → 0.11.2
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/dist/index.js +917 -516
- package/package.json +2 -6
package/dist/index.js
CHANGED
|
@@ -1,110 +1,132 @@
|
|
|
1
|
-
import { useEditor
|
|
2
|
-
import { assets
|
|
3
|
-
import { ref
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
for (let
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
import { useEditor, definePlugin } from "mce";
|
|
2
|
+
import { assets, Element2D } from "modern-canvas";
|
|
3
|
+
import { ref, onBeforeUnmount } from "vue";
|
|
4
|
+
import { createSharedComposable } from "@vueuse/core";
|
|
5
|
+
import { idGenerator, normalizeCRLF, isGradient } from "modern-idoc";
|
|
6
|
+
import { gunzipSync } from "fflate";
|
|
7
|
+
const bigeFonts = ref([]);
|
|
8
|
+
function levenshteinDistance(a, b) {
|
|
9
|
+
const matrix = [];
|
|
10
|
+
for (let i = 0; i <= b.length; i++) {
|
|
11
|
+
matrix[i] = [i];
|
|
12
|
+
}
|
|
13
|
+
for (let j = 0; j <= a.length; j++) {
|
|
14
|
+
matrix[0][j] = j;
|
|
15
|
+
}
|
|
16
|
+
for (let i = 1; i <= b.length; i++) {
|
|
17
|
+
for (let j = 1; j <= a.length; j++) {
|
|
18
|
+
const cost = a[j - 1] === b[i - 1] ? 0 : 1;
|
|
19
|
+
matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j - 1] + cost);
|
|
17
20
|
}
|
|
18
|
-
|
|
21
|
+
}
|
|
22
|
+
return matrix[b.length][a.length];
|
|
19
23
|
}
|
|
20
|
-
function
|
|
24
|
+
function useFonts() {
|
|
21
25
|
const {
|
|
22
|
-
loadFont:
|
|
23
|
-
} =
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
loadFont: baseLoadFont
|
|
27
|
+
} = useEditor();
|
|
28
|
+
const fontPromises = ref(/* @__PURE__ */ new Map());
|
|
29
|
+
async function loadBigeFonts(url) {
|
|
30
|
+
let result = bigeFonts.value;
|
|
31
|
+
if (!result.length) {
|
|
32
|
+
result = await fetch(url).then((rep) => rep.json()).then((res) => res.data.datalist);
|
|
33
|
+
bigeFonts.value = result;
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
27
36
|
}
|
|
28
|
-
function
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
function searchBigeFont(keyword, fonts = bigeFonts.value) {
|
|
38
|
+
const idIndexMap = new Map(fonts.map((item, index2) => [item.id, index2]));
|
|
39
|
+
const nameIndexMap = new Map(
|
|
40
|
+
fonts.flatMap((item, index2) => {
|
|
41
|
+
return [...item.en_name.split(","), ...item.name.split(",")].map((name) => {
|
|
42
|
+
return [name, index2];
|
|
43
|
+
});
|
|
44
|
+
})
|
|
45
|
+
);
|
|
46
|
+
const fontFamilies = keyword.replace(/"/g, "").split(",");
|
|
47
|
+
let index;
|
|
48
|
+
fontFamilies.forEach((fontFamily) => {
|
|
49
|
+
index ??= idIndexMap.get(fontFamily);
|
|
50
|
+
index ??= nameIndexMap.get(fontFamily);
|
|
51
|
+
});
|
|
52
|
+
if (index === void 0) {
|
|
53
|
+
let prevWeight;
|
|
54
|
+
fontFamilies.forEach((rawA) => {
|
|
55
|
+
let a = rawA;
|
|
56
|
+
if (a.endsWith(" R")) {
|
|
57
|
+
a = `${a.substring(0, a.length - 2)}常规`;
|
|
58
|
+
} else if (a.endsWith(" B")) {
|
|
59
|
+
a = `${a.substring(0, a.length - 2)}粗体`;
|
|
60
|
+
}
|
|
61
|
+
const aLen = a.length;
|
|
62
|
+
nameIndexMap.forEach((i, b) => {
|
|
63
|
+
const dist = levenshteinDistance(a, b);
|
|
64
|
+
if (aLen <= dist) {
|
|
44
65
|
return;
|
|
45
|
-
|
|
46
|
-
|
|
66
|
+
}
|
|
67
|
+
const weight = -(dist * 0.9 + (b.endsWith("常规") ? 0 : 1) * 0.1);
|
|
68
|
+
if (prevWeight === void 0 || weight > prevWeight) {
|
|
69
|
+
prevWeight = weight;
|
|
70
|
+
index = i;
|
|
71
|
+
}
|
|
47
72
|
});
|
|
48
73
|
});
|
|
49
74
|
}
|
|
50
|
-
return
|
|
75
|
+
return index !== void 0 ? fonts[index] : void 0;
|
|
51
76
|
}
|
|
52
|
-
async function
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
77
|
+
async function loadFont(name) {
|
|
78
|
+
const names = typeof name === "string" ? [name] : name;
|
|
79
|
+
const result = [];
|
|
80
|
+
for (const name2 of names) {
|
|
81
|
+
let promise = fontPromises.value.get(name2);
|
|
82
|
+
if (!promise) {
|
|
83
|
+
const font = searchBigeFont(name2);
|
|
84
|
+
if (font) {
|
|
85
|
+
promise = fontPromises.value.get(font.en_name);
|
|
86
|
+
if (!promise) {
|
|
87
|
+
const names2 = Array.from(
|
|
88
|
+
new Set(
|
|
89
|
+
[name2, font.en_name].filter(Boolean).map((v) => v.replace(/"/g, ""))
|
|
90
|
+
)
|
|
91
|
+
);
|
|
92
|
+
promise = baseLoadFont({
|
|
93
|
+
family: names2,
|
|
94
|
+
src: font.fonturl
|
|
95
|
+
});
|
|
96
|
+
names2.forEach((name3) => fontPromises.value.set(name3, promise));
|
|
97
|
+
fontPromises.value.set(String(name2), promise);
|
|
98
|
+
}
|
|
68
99
|
}
|
|
69
100
|
}
|
|
70
|
-
|
|
101
|
+
promise && result.push(promise);
|
|
71
102
|
}
|
|
72
|
-
return await Promise.all(
|
|
103
|
+
return await Promise.all(result);
|
|
73
104
|
}
|
|
74
105
|
return {
|
|
75
|
-
bigeFonts
|
|
76
|
-
searchBigeFont
|
|
77
|
-
loadBigeFonts
|
|
78
|
-
loadFont
|
|
106
|
+
bigeFonts,
|
|
107
|
+
searchBigeFont,
|
|
108
|
+
loadBigeFonts,
|
|
109
|
+
loadFont
|
|
79
110
|
};
|
|
80
111
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const s = () => {
|
|
91
|
-
r -= 1, t && r <= 0 && (t.stop(), o = void 0, t = void 0);
|
|
92
|
-
};
|
|
93
|
-
return ((...i) => (r += 1, t || (t = it(!0), o = t.run(() => e(...i))), ut(s), o));
|
|
94
|
-
}
|
|
95
|
-
const _ = /* @__PURE__ */ yt(() => {
|
|
96
|
-
const e = /* @__PURE__ */ new Map();
|
|
97
|
-
function r(t, s) {
|
|
98
|
-
let i = e.get(t);
|
|
99
|
-
return i || (i = fetch(t).then(s), e.set(t, i)), i;
|
|
112
|
+
const useSharedTextAssets = createSharedComposable(() => {
|
|
113
|
+
const requests = /* @__PURE__ */ new Map();
|
|
114
|
+
function baseFetch(url, handle) {
|
|
115
|
+
let rep = requests.get(url);
|
|
116
|
+
if (!rep) {
|
|
117
|
+
rep = fetch(url).then(handle);
|
|
118
|
+
requests.set(url, rep);
|
|
119
|
+
}
|
|
120
|
+
return rep;
|
|
100
121
|
}
|
|
101
|
-
async function
|
|
102
|
-
return
|
|
122
|
+
async function fetchToText(url) {
|
|
123
|
+
return baseFetch(url, (rep) => rep.text());
|
|
103
124
|
}
|
|
104
125
|
return {
|
|
105
|
-
fetchToText
|
|
126
|
+
fetchToText
|
|
106
127
|
};
|
|
107
|
-
})
|
|
128
|
+
});
|
|
129
|
+
const animations = {
|
|
108
130
|
easing: {
|
|
109
131
|
匀速: "linear",
|
|
110
132
|
加速: "cubic-bezier(0.55, 0, 1, 0.45)",
|
|
@@ -437,406 +459,699 @@ const _ = /* @__PURE__ */ yt(() => {
|
|
|
437
459
|
]
|
|
438
460
|
}
|
|
439
461
|
};
|
|
440
|
-
function
|
|
462
|
+
function convertAnimation(el, animation, type) {
|
|
441
463
|
const {
|
|
442
|
-
name
|
|
443
|
-
delay
|
|
444
|
-
duration
|
|
445
|
-
iterations
|
|
446
|
-
mode
|
|
447
|
-
easing
|
|
448
|
-
path
|
|
449
|
-
offsetRotate
|
|
450
|
-
...
|
|
451
|
-
} =
|
|
452
|
-
let
|
|
453
|
-
if (
|
|
454
|
-
let
|
|
455
|
-
|
|
456
|
-
const
|
|
457
|
-
|
|
464
|
+
name,
|
|
465
|
+
delay = 0,
|
|
466
|
+
duration,
|
|
467
|
+
iterations,
|
|
468
|
+
mode,
|
|
469
|
+
easing,
|
|
470
|
+
path,
|
|
471
|
+
offsetRotate,
|
|
472
|
+
...meta
|
|
473
|
+
} = animation;
|
|
474
|
+
let keyframes;
|
|
475
|
+
if (name === "自定义路径" && path) {
|
|
476
|
+
let d = `M ${el.style.width / 2} ${el.style.height / 2}`;
|
|
477
|
+
path.forEach((v) => {
|
|
478
|
+
const keys = Object.keys(v);
|
|
479
|
+
d += ` ${keys[0]}${v[keys[0]].join(" ")}`;
|
|
458
480
|
});
|
|
459
|
-
const
|
|
460
|
-
switch (
|
|
481
|
+
const offsetPath = `path("${d}")`;
|
|
482
|
+
switch (type) {
|
|
461
483
|
case "in":
|
|
462
|
-
|
|
463
|
-
{ opacity: 0, offsetDistance: "100%", offsetPath
|
|
464
|
-
{ offsetDistance: "0%", offsetPath
|
|
484
|
+
keyframes = [
|
|
485
|
+
{ opacity: 0, offsetDistance: "100%", offsetPath, offsetRotate },
|
|
486
|
+
{ offsetDistance: "0%", offsetPath, offsetRotate }
|
|
465
487
|
];
|
|
466
488
|
break;
|
|
467
489
|
case "stay":
|
|
468
|
-
|
|
469
|
-
{ offsetDistance: "0%", offsetPath
|
|
470
|
-
{ offsetDistance: "100%", offsetPath
|
|
490
|
+
keyframes = [
|
|
491
|
+
{ offsetDistance: "0%", offsetPath, offsetRotate },
|
|
492
|
+
{ offsetDistance: "100%", offsetPath, offsetRotate }
|
|
471
493
|
];
|
|
472
494
|
break;
|
|
473
495
|
case "out":
|
|
474
|
-
|
|
475
|
-
{ offsetDistance: "0%", offsetPath
|
|
476
|
-
{ opacity: 0, offsetDistance: "100%", offsetPath
|
|
496
|
+
keyframes = [
|
|
497
|
+
{ offsetDistance: "0%", offsetPath, offsetRotate },
|
|
498
|
+
{ opacity: 0, offsetDistance: "100%", offsetPath, offsetRotate }
|
|
477
499
|
];
|
|
478
500
|
break;
|
|
479
501
|
}
|
|
480
|
-
} else
|
|
481
|
-
switch (
|
|
502
|
+
} else {
|
|
503
|
+
switch (type) {
|
|
482
504
|
case "in":
|
|
483
|
-
|
|
505
|
+
keyframes = animations.textIn[name]?.[0] ?? animations.in[name];
|
|
484
506
|
break;
|
|
485
507
|
case "stay":
|
|
486
|
-
|
|
508
|
+
keyframes = animations.stay[name];
|
|
487
509
|
break;
|
|
488
510
|
case "out":
|
|
489
|
-
|
|
511
|
+
keyframes = animations.out[name];
|
|
490
512
|
break;
|
|
491
513
|
}
|
|
514
|
+
}
|
|
492
515
|
return {
|
|
493
|
-
id:
|
|
494
|
-
name:
|
|
495
|
-
delay
|
|
496
|
-
duration:
|
|
497
|
-
effectMode:
|
|
498
|
-
keyframes:
|
|
499
|
-
easing:
|
|
516
|
+
id: idGenerator(),
|
|
517
|
+
name: animation.name ?? animation.title ?? animation.id,
|
|
518
|
+
delay,
|
|
519
|
+
duration: name ? duration * (iterations || 1) : 0,
|
|
520
|
+
effectMode: mode === "逐字" || mode === "逐行" ? "sibling" : "parent",
|
|
521
|
+
keyframes: keyframes ?? [],
|
|
522
|
+
easing: animations.easing[easing],
|
|
500
523
|
meta: {
|
|
501
|
-
...
|
|
524
|
+
...meta,
|
|
502
525
|
inCanvasIs: "Animation",
|
|
503
526
|
inPptIs: "Animation",
|
|
504
527
|
inEditorIs: "Node"
|
|
505
528
|
}
|
|
506
529
|
};
|
|
507
530
|
}
|
|
508
|
-
function
|
|
509
|
-
if (!
|
|
531
|
+
function parseAnimations(el) {
|
|
532
|
+
if (!el.animations?.length) {
|
|
510
533
|
return {
|
|
511
534
|
delay: 0,
|
|
512
535
|
duration: 0,
|
|
513
536
|
animations: []
|
|
514
537
|
};
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
538
|
+
}
|
|
539
|
+
let _animIn;
|
|
540
|
+
let _animStay;
|
|
541
|
+
let _animOut;
|
|
542
|
+
if (el.animations[0].in) {
|
|
543
|
+
_animIn = el.animations[0].in;
|
|
544
|
+
_animStay = el.animations[0].stay;
|
|
545
|
+
_animOut = el.animations[0].out;
|
|
546
|
+
} else {
|
|
547
|
+
_animIn = el.animations?.find((v) => v.category === "in");
|
|
548
|
+
_animStay = el.animations?.find((v) => v.category === "stay");
|
|
549
|
+
_animOut = el.animations?.find((v) => v.category === "out");
|
|
550
|
+
}
|
|
551
|
+
const startTime = _animIn?.delay ?? 0;
|
|
552
|
+
const endTime = _animOut ? _animOut.delay - startTime + _animOut.duration : 0;
|
|
553
|
+
const animations2 = [];
|
|
554
|
+
if (_animIn) {
|
|
555
|
+
animations2.push(
|
|
556
|
+
convertAnimation(el, {
|
|
557
|
+
..._animIn,
|
|
558
|
+
delay: 0
|
|
559
|
+
}, "in")
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
if (_animStay) {
|
|
563
|
+
animations2.push(
|
|
564
|
+
convertAnimation(el, {
|
|
565
|
+
..._animStay,
|
|
566
|
+
delay: _animStay.delay - startTime
|
|
567
|
+
}, "stay")
|
|
568
|
+
);
|
|
569
|
+
}
|
|
570
|
+
if (_animOut) {
|
|
571
|
+
animations2.push(
|
|
572
|
+
convertAnimation(el, {
|
|
573
|
+
..._animOut,
|
|
574
|
+
delay: _animOut.delay - startTime
|
|
575
|
+
}, "out")
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
return {
|
|
579
|
+
delay: startTime,
|
|
580
|
+
duration: endTime - startTime,
|
|
581
|
+
animations: animations2.filter((v) => !!v?.keyframes)
|
|
537
582
|
};
|
|
538
583
|
}
|
|
539
|
-
async function
|
|
584
|
+
async function convertImageElementToUrl(el) {
|
|
585
|
+
const {
|
|
586
|
+
transform = {},
|
|
587
|
+
style = {},
|
|
588
|
+
maskUrl,
|
|
589
|
+
imageEffects = [],
|
|
590
|
+
imageEffectsRatio = 1
|
|
591
|
+
} = el;
|
|
592
|
+
const url = el.clipUrl || el.url;
|
|
593
|
+
const {
|
|
594
|
+
translateX = 0,
|
|
595
|
+
translateY = 0,
|
|
596
|
+
zoom = 1
|
|
597
|
+
} = transform ?? {};
|
|
598
|
+
const {
|
|
599
|
+
scaleX = 1,
|
|
600
|
+
scaleY = 1,
|
|
601
|
+
filter
|
|
602
|
+
} = style;
|
|
603
|
+
if (translateX === 0 && translateY === 0 && zoom === 1 && scaleX === 1 && scaleY === 1 && !maskUrl && !filter && !imageEffects.length) {
|
|
604
|
+
return url;
|
|
605
|
+
}
|
|
606
|
+
const img = await assets.fetchImageBitmap(url);
|
|
607
|
+
const {
|
|
608
|
+
originWidth = img.width,
|
|
609
|
+
originHeight = img.height,
|
|
610
|
+
imageWidth = originWidth,
|
|
611
|
+
imageHeight = originHeight
|
|
612
|
+
} = transform;
|
|
540
613
|
const {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
if (f === 0 && c === 0 && d === 1 && l === 1 && a === 1 && !t && !M && !s.length)
|
|
556
|
-
return n;
|
|
557
|
-
const L = await B.fetchImageBitmap(n), {
|
|
558
|
-
originWidth: w = L.width,
|
|
559
|
-
originHeight: h = L.height,
|
|
560
|
-
imageWidth: u = w,
|
|
561
|
-
imageHeight: C = h
|
|
562
|
-
} = r, {
|
|
563
|
-
width: m = w,
|
|
564
|
-
height: g = h
|
|
565
|
-
} = o, T = window.devicePixelRatio || 1, [j, y] = W(m, g, T);
|
|
566
|
-
if (M && (y.filter = M), y.scale(l, a), y.translate(l < 0 ? -m : 0, a < 0 ? -g : 0), t) {
|
|
567
|
-
const D = await B.fetchImageBitmap(t);
|
|
568
|
-
y.drawImage(D, 0, 0, D.width, D.height, 0, 0, m, g), D.close(), y.globalCompositeOperation = "source-in";
|
|
614
|
+
width = originWidth,
|
|
615
|
+
height = originHeight
|
|
616
|
+
} = style;
|
|
617
|
+
const dpr = window.devicePixelRatio || 1;
|
|
618
|
+
const [canvas, ctx] = createCanvas(width, height, dpr);
|
|
619
|
+
if (filter)
|
|
620
|
+
ctx.filter = filter;
|
|
621
|
+
ctx.scale(scaleX, scaleY);
|
|
622
|
+
ctx.translate(scaleX < 0 ? -width : 0, scaleY < 0 ? -height : 0);
|
|
623
|
+
if (maskUrl) {
|
|
624
|
+
const mask = await assets.fetchImageBitmap(maskUrl);
|
|
625
|
+
ctx.drawImage(mask, 0, 0, mask.width, mask.height, 0, 0, width, height);
|
|
626
|
+
mask.close();
|
|
627
|
+
ctx.globalCompositeOperation = "source-in";
|
|
569
628
|
}
|
|
570
|
-
const
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
629
|
+
const dw = imageWidth * zoom;
|
|
630
|
+
const dh = imageHeight * zoom;
|
|
631
|
+
const dx = -(dw / 2 - imageWidth / 2) + translateX;
|
|
632
|
+
const dy = -(dh / 2 - imageHeight / 2) + translateY;
|
|
633
|
+
ctx.drawImage(img, 0, 0, img.width, img.height, dx, dy, dw, dh);
|
|
634
|
+
img.close();
|
|
635
|
+
ctx.globalCompositeOperation = "source-over";
|
|
636
|
+
if (imageEffects.length > 0) {
|
|
637
|
+
const scale = 0.9;
|
|
638
|
+
const center = {
|
|
639
|
+
x: (width - width * scale) / 2,
|
|
640
|
+
y: (height - height * scale) / 2
|
|
641
|
+
};
|
|
642
|
+
const canvasBitmap = await createImageBitmap(canvas);
|
|
643
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
644
|
+
ctx.scale(scale, scale);
|
|
645
|
+
for (let i = imageEffects.length - 1; i >= 0; i--) {
|
|
646
|
+
const { filling, offset, stroke } = imageEffects[i];
|
|
647
|
+
let effectCanvas = canvasBitmap;
|
|
648
|
+
if (filling) {
|
|
649
|
+
const [canvas1, ctx1] = createCanvas(width, height, dpr);
|
|
650
|
+
ctx1.drawImage(effectCanvas, 0, 0, width, height);
|
|
651
|
+
ctx1.globalCompositeOperation = "source-in";
|
|
652
|
+
if (filling.color) {
|
|
653
|
+
const [canvas2, ctx2] = createCanvas(width, height, dpr);
|
|
654
|
+
ctx2.fillStyle = filling.color;
|
|
655
|
+
ctx2.fillRect(0, 0, width, height);
|
|
656
|
+
ctx1.drawImage(canvas2, 0, 0, width, height);
|
|
657
|
+
} else if (filling.imageContent?.image) {
|
|
658
|
+
const img2 = await assets.fetchImageBitmap(filling.imageContent.image);
|
|
659
|
+
ctx1.drawImage(img2, 0, 0, width, height);
|
|
660
|
+
img2.close();
|
|
588
661
|
}
|
|
589
|
-
|
|
662
|
+
effectCanvas = canvas1;
|
|
590
663
|
}
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
const [,
|
|
594
|
-
|
|
595
|
-
const
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
664
|
+
stroke?.forEach(({ width: width2, color }) => {
|
|
665
|
+
effectCanvas = new ImageStroke().use((ctx2, image, options) => {
|
|
666
|
+
const [, ctx1] = createCanvas(image.width, image.height);
|
|
667
|
+
ctx1.drawImage(image, 0, 0);
|
|
668
|
+
const paths = getContours(ctx1);
|
|
669
|
+
const x = options.thickness;
|
|
670
|
+
const y = options.thickness;
|
|
671
|
+
ctx2.strokeStyle = options.color;
|
|
672
|
+
ctx2.lineWidth = options.thickness * 2;
|
|
673
|
+
ctx2.lineJoin = "round";
|
|
674
|
+
paths.forEach((path) => {
|
|
675
|
+
ctx2.beginPath();
|
|
676
|
+
ctx2.moveTo(x + path[0].x, y + path[1].y);
|
|
677
|
+
for (let i2 = 1; i2 < path.length; i2++) {
|
|
678
|
+
ctx2.lineTo(x + path[i2].x, y + path[i2].y);
|
|
679
|
+
}
|
|
680
|
+
ctx2.closePath();
|
|
681
|
+
});
|
|
682
|
+
ctx2.stroke();
|
|
683
|
+
}).make(effectCanvas, {
|
|
684
|
+
color,
|
|
685
|
+
thickness: width2 / 50 * imageEffectsRatio
|
|
605
686
|
});
|
|
606
|
-
})
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
y
|
|
687
|
+
});
|
|
688
|
+
if (offset) {
|
|
689
|
+
let { x, y } = offset;
|
|
690
|
+
x = x / 50 * imageEffectsRatio * 200;
|
|
691
|
+
y = y / 50 * imageEffectsRatio * 200;
|
|
692
|
+
ctx.drawImage(effectCanvas, x + center.x, y + center.y, width, height);
|
|
693
|
+
} else {
|
|
694
|
+
ctx.drawImage(effectCanvas, center.x, center.y, width, height);
|
|
695
|
+
}
|
|
611
696
|
}
|
|
612
|
-
|
|
697
|
+
canvasBitmap.close();
|
|
613
698
|
}
|
|
614
|
-
return await new Promise((
|
|
615
|
-
|
|
699
|
+
return await new Promise((resolve) => {
|
|
700
|
+
canvas.toBlob((blob) => {
|
|
616
701
|
try {
|
|
617
|
-
|
|
618
|
-
} catch (
|
|
619
|
-
console.error(`Failed to URL.createObjectURL, url: ${
|
|
702
|
+
resolve(URL.createObjectURL(blob));
|
|
703
|
+
} catch (e) {
|
|
704
|
+
console.error(`Failed to URL.createObjectURL, url: ${url}`, e);
|
|
705
|
+
resolve(url);
|
|
620
706
|
}
|
|
621
707
|
});
|
|
622
708
|
});
|
|
623
709
|
}
|
|
624
|
-
function
|
|
625
|
-
const
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
710
|
+
function createCanvas(width, height, ratio = 1) {
|
|
711
|
+
const canvas = document.createElement("canvas");
|
|
712
|
+
canvas.width = width * ratio;
|
|
713
|
+
canvas.height = height * ratio;
|
|
714
|
+
canvas.style.width = `${width}px`;
|
|
715
|
+
canvas.style.height = `${height}px`;
|
|
716
|
+
const ctx = canvas.getContext("2d");
|
|
717
|
+
ctx.scale(ratio, ratio);
|
|
718
|
+
return [canvas, ctx];
|
|
629
719
|
}
|
|
630
|
-
class
|
|
720
|
+
class ImageStroke {
|
|
631
721
|
canvas = document.createElement("canvas");
|
|
632
722
|
method;
|
|
633
|
-
use(
|
|
634
|
-
|
|
723
|
+
use(method) {
|
|
724
|
+
this.method = method;
|
|
725
|
+
return this;
|
|
635
726
|
}
|
|
636
|
-
make(
|
|
637
|
-
const { canvas
|
|
638
|
-
|
|
727
|
+
make(image, options) {
|
|
728
|
+
const { canvas } = this;
|
|
729
|
+
const ctx = this.canvas.getContext("2d");
|
|
730
|
+
const strokeSize = options.thickness * 2;
|
|
731
|
+
const [resultWidth, resultHeight] = [image.width, image.height].map((val) => val + strokeSize);
|
|
732
|
+
if (resultWidth !== canvas.width || resultHeight !== canvas.height) {
|
|
733
|
+
canvas.width = resultWidth;
|
|
734
|
+
canvas.height = resultHeight;
|
|
735
|
+
}
|
|
736
|
+
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
|
737
|
+
this.method(ctx, image, options);
|
|
738
|
+
ctx.drawImage(image, options.thickness, options.thickness);
|
|
739
|
+
return canvas;
|
|
639
740
|
}
|
|
640
741
|
}
|
|
641
|
-
function
|
|
642
|
-
const
|
|
643
|
-
|
|
644
|
-
const
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
742
|
+
function getContours(ctx) {
|
|
743
|
+
const cx = 0;
|
|
744
|
+
const cy = 0;
|
|
745
|
+
const canvasWidth = ctx.canvas.width;
|
|
746
|
+
const canvasHeight = ctx.canvas.height;
|
|
747
|
+
const paths = [];
|
|
748
|
+
let lastPos = 3;
|
|
749
|
+
const alpha = 100;
|
|
750
|
+
const trace = () => {
|
|
751
|
+
const path = [];
|
|
752
|
+
const data = new Uint32Array(ctx.getImageData(cx, cy, canvasWidth, canvasHeight).data.buffer);
|
|
753
|
+
let x;
|
|
754
|
+
let y;
|
|
755
|
+
let startX;
|
|
756
|
+
let startY;
|
|
757
|
+
let startPos = -1;
|
|
758
|
+
let step;
|
|
759
|
+
let prevStep = 9;
|
|
760
|
+
const steps = [9, 0, 3, 3, 2, 0, 9, 3, 1, 9, 1, 1, 2, 0, 2, 9];
|
|
761
|
+
function getState(x2, y2) {
|
|
762
|
+
return x2 >= 0 && y2 >= 0 && x2 < canvasWidth && y2 < canvasHeight ? data[y2 * canvasWidth + x2] >>> 24 > alpha : false;
|
|
651
763
|
}
|
|
652
|
-
function
|
|
653
|
-
let
|
|
654
|
-
|
|
764
|
+
function getNextStep(x2, y2) {
|
|
765
|
+
let v = 0;
|
|
766
|
+
if (getState(x2 - 1, y2 - 1)) {
|
|
767
|
+
v += 1;
|
|
768
|
+
}
|
|
769
|
+
if (getState(x2, y2 - 1)) {
|
|
770
|
+
v += 2;
|
|
771
|
+
}
|
|
772
|
+
if (getState(x2 - 1, y2)) {
|
|
773
|
+
v += 4;
|
|
774
|
+
}
|
|
775
|
+
if (getState(x2, y2)) {
|
|
776
|
+
v += 8;
|
|
777
|
+
}
|
|
778
|
+
if (v === 6)
|
|
779
|
+
return prevStep === 0 ? 2 : 3;
|
|
780
|
+
else if (v === 9)
|
|
781
|
+
return prevStep === 3 ? 0 : 1;
|
|
782
|
+
else
|
|
783
|
+
return steps[v];
|
|
655
784
|
}
|
|
656
|
-
for (let
|
|
657
|
-
if (
|
|
658
|
-
|
|
785
|
+
for (let i = lastPos; i < data.length; i++) {
|
|
786
|
+
if (data[i] >>> 24 > alpha) {
|
|
787
|
+
startPos = lastPos = i;
|
|
659
788
|
break;
|
|
660
789
|
}
|
|
661
|
-
if (h >= 0) {
|
|
662
|
-
a = L = h % t, M = w = Math.floor(h / t);
|
|
663
|
-
do
|
|
664
|
-
u = T(a, M), u === 0 ? M-- : u === 1 ? M++ : u === 2 ? a-- : u === 3 && a++, u !== C && (d.push({ x: a + 0, y: M + 0 }), C = u);
|
|
665
|
-
while (a !== L || M !== w);
|
|
666
790
|
}
|
|
667
|
-
|
|
668
|
-
|
|
791
|
+
if (startPos >= 0) {
|
|
792
|
+
x = startX = startPos % canvasWidth;
|
|
793
|
+
y = startY = Math.floor(startPos / canvasWidth);
|
|
794
|
+
do {
|
|
795
|
+
step = getNextStep(x, y);
|
|
796
|
+
if (step === 0)
|
|
797
|
+
y--;
|
|
798
|
+
else if (step === 1)
|
|
799
|
+
y++;
|
|
800
|
+
else if (step === 2)
|
|
801
|
+
x--;
|
|
802
|
+
else if (step === 3)
|
|
803
|
+
x++;
|
|
804
|
+
if (step !== prevStep) {
|
|
805
|
+
path.push({ x: x + cx, y: y + cy });
|
|
806
|
+
prevStep = step;
|
|
807
|
+
}
|
|
808
|
+
} while (x !== startX || y !== startY);
|
|
809
|
+
}
|
|
810
|
+
paths.push(path);
|
|
811
|
+
return path;
|
|
812
|
+
};
|
|
813
|
+
trace();
|
|
814
|
+
return paths;
|
|
669
815
|
}
|
|
670
|
-
async function
|
|
816
|
+
async function convertSvgElementToUrl(el) {
|
|
671
817
|
const {
|
|
672
|
-
id
|
|
673
|
-
doc
|
|
674
|
-
url
|
|
675
|
-
style
|
|
676
|
-
background
|
|
677
|
-
} =
|
|
678
|
-
let
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
818
|
+
id,
|
|
819
|
+
doc,
|
|
820
|
+
url,
|
|
821
|
+
style = {},
|
|
822
|
+
background = {}
|
|
823
|
+
} = el;
|
|
824
|
+
let xml = doc;
|
|
825
|
+
if (!xml) {
|
|
826
|
+
xml = await fetch(url).then((rep) => rep.text());
|
|
827
|
+
}
|
|
828
|
+
const svg = new DOMParser().parseFromString(
|
|
829
|
+
xml.replace(new RegExp(`#el-${id} `, "gi"), "").replace(/data-colors\s/, " ").replace(/[a-z-]+="([^\s<]*<\S*)"/gi, ""),
|
|
682
830
|
"image/svg+xml"
|
|
683
831
|
).documentElement;
|
|
684
|
-
if (!(
|
|
685
|
-
throw new TypeError(`Failed to DOMParser, parse svg to DOM error: ${
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
832
|
+
if (!(svg instanceof SVGElement)) {
|
|
833
|
+
throw new TypeError(`Failed to DOMParser, parse svg to DOM error: ${xml}`);
|
|
834
|
+
}
|
|
835
|
+
if (background.src) {
|
|
836
|
+
const fillId = `#${id}-fill-blip`;
|
|
837
|
+
const fillPattern = svg.querySelector(fillId);
|
|
838
|
+
const fillImage = fillPattern?.querySelector("image");
|
|
839
|
+
if (fillPattern && fillImage) {
|
|
689
840
|
try {
|
|
690
|
-
const
|
|
691
|
-
const
|
|
692
|
-
|
|
841
|
+
const base64Url = await assets.fetchImageBitmap(background.src).then((bitmap) => {
|
|
842
|
+
const canvas = document.createElement("canvas");
|
|
843
|
+
canvas.width = bitmap.width;
|
|
844
|
+
canvas.height = bitmap.height;
|
|
845
|
+
canvas.getContext("2d")?.drawImage(bitmap, 0, 0);
|
|
846
|
+
bitmap.close();
|
|
847
|
+
return canvas.toDataURL("image/png");
|
|
693
848
|
});
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
849
|
+
fillImage?.setAttribute("href", base64Url);
|
|
850
|
+
fillPattern?.setAttribute("fill", fillId);
|
|
851
|
+
} catch (e) {
|
|
852
|
+
console.error(e);
|
|
697
853
|
}
|
|
854
|
+
}
|
|
698
855
|
}
|
|
699
|
-
|
|
700
|
-
|
|
856
|
+
if (style.width)
|
|
857
|
+
svg.setAttribute("width", String(style.width * 2));
|
|
858
|
+
if (style.height)
|
|
859
|
+
svg.setAttribute("height", String(style.height * 2));
|
|
860
|
+
return await convertImageElementToUrl({
|
|
861
|
+
...el,
|
|
701
862
|
transform: {
|
|
702
|
-
...
|
|
703
|
-
originWidth:
|
|
704
|
-
originHeight:
|
|
863
|
+
...el.transform,
|
|
864
|
+
originWidth: style.width,
|
|
865
|
+
originHeight: style.height
|
|
705
866
|
},
|
|
706
|
-
url: `data:image/svg+xml;charset=utf-8,${encodeURIComponent(
|
|
867
|
+
url: `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg.outerHTML)}`
|
|
707
868
|
});
|
|
708
869
|
}
|
|
709
|
-
const
|
|
710
|
-
async function
|
|
711
|
-
const { fetchToText
|
|
712
|
-
|
|
713
|
-
|
|
870
|
+
const highlightReferImage = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2ZXJzaW9uPSIxLjEiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgNzIgNzIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDcyIDcyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxnPgoJPHBhdGggZD0iTTE5LjMsMzguMWMwLjIsMC41LDAuNCwwLjksMC43LDEuNGMwLjIsMC4zLDAuNCwwLjQsMC44LDAuNGMwLjMsMCwwLjUtMC4xLDAuNi0wLjRjMC4xLTAuMywwLjEtMC42LDAuMi0wLjkgICBjMC0wLjIsMC4xLTAuNCwwLjMtMC41YzAuMi0wLjEsMC40LTAuMiwwLjYtMC4xYzAuMiwwLDAuNCwwLjEsMC41LDAuM2MwLjEsMC4yLDAuMiwwLjQsMC4xLDAuNmMtMC4xLDAuNi0wLjIsMS4yLTAuNCwxLjcgICBjLTAuMywwLjgtMC45LDEuMi0xLjcsMS4yYy0wLjksMC0xLjYtMC40LTIuMS0xLjJjLTAuMy0wLjQtMC41LTAuOC0wLjctMS4zYy0wLjQsMC4zLTEsMC42LTEuNywxYy0wLjUsMC4yLTAuOCwwLjEtMS4xLTAuMyAgIGMtMC4yLTAuNS0wLjEtMC45LDAuMy0xLjFjMC43LTAuNCwxLjQtMC44LDEuOS0xLjFjLTAuMi0wLjktMC40LTIuMS0wLjUtMy43TDE1LjksMzRjLTAuMiwwLTAuNCwwLTAuNi0wLjEgICBjLTAuMi0wLjEtMC4zLTAuMy0wLjMtMC41YzAtMC4yLDAtMC40LDAuMi0wLjZzMC4zLTAuMywwLjUtMC4zbDEuMi0wLjFjLTAuMS0wLjktMC4xLTEuOS0wLjEtMi45YzAtMC4yLDAuMS0wLjQsMC4yLTAuNiAgIGMwLjItMC4xLDAuMy0wLjIsMC42LTAuMmMwLjIsMCwwLjQsMC4xLDAuNiwwLjJjMC4yLDAuMSwwLjIsMC4zLDAuMywwLjZjMCwwLjEsMCwxLDAuMSwyLjdsMy4yLTAuNGMwLjIsMCwwLjQsMCwwLjUsMC4xICAgYzAuMiwwLjEsMC4zLDAuMywwLjMsMC41czAsMC40LTAuMSwwLjVjLTAuMSwwLjItMC4zLDAuMy0wLjUsMC4zbC0zLjMsMC40YzAuMSwxLjIsMC4yLDIuMSwwLjMsMi44YzAuNy0wLjYsMS40LTEuNCwyLTIuMiAgIGMwLjMtMC40LDAuNy0wLjQsMS4xLTAuMmMwLjQsMC4zLDAuNCwwLjcsMC4yLDFDMjEuMywzNi4zLDIwLjQsMzcuMywxOS4zLDM4LjF6IE0yMC42LDMxLjFjLTAuMy0wLjItMC43LTAuNS0xLjEtMC44ICAgYy0wLjMtMC4zLTAuMy0wLjYtMC4xLTAuOWMwLjMtMC4zLDAuNi0wLjQsMS0wLjJjMC40LDAuMiwwLjcsMC41LDEuMSwwLjdjMC40LDAuMywwLjQsMC42LDAuMiwxQzIxLjMsMzEuMywyMSwzMS4zLDIwLjYsMzEuMXogICAgTTIzLjMsMzAuOWMwLTAuMiwwLjEtMC40LDAuMi0wLjVjMC4xLTAuMSwwLjMtMC4yLDAuNi0wLjJzMC40LDAuMSwwLjYsMC4yYzAuMSwwLjEsMC4yLDAuMywwLjIsMC41djYuNWMwLDAuMi0wLjEsMC40LTAuMiwwLjUgICBjLTAuMSwwLjEtMC4zLDAuMi0wLjYsMC4ycy0wLjQtMC4xLTAuNi0wLjJjLTAuMS0wLjEtMC4yLTAuMy0wLjItMC41VjMwLjl6IE0yNC4zLDQxLjZjLTAuMiwwLTAuNC0wLjEtMC42LTAuMiAgIGMtMC4yLTAuMS0wLjItMC4zLTAuMi0wLjZjMC0wLjIsMC4xLTAuNCwwLjItMC42YzAuMi0wLjEsMC4zLTAuMiwwLjYtMC4yaDAuOWMwLjYsMCwxLTAuNCwxLTEuMXYtOS40YzAtMC4yLDAuMS0wLjQsMC4yLTAuNiAgIGMwLjItMC4xLDAuMy0wLjIsMC42LTAuMmMwLjIsMCwwLjQsMC4xLDAuNiwwLjJjMC4yLDAuMSwwLjIsMC4zLDAuMiwwLjZWMzljMCwwLjgtMC4yLDEuNS0wLjcsMS45cy0xLjEsMC43LTEuOCwwLjdIMjQuM3oiLz4KCTxwYXRoIGQ9Ik00MC42LDM3LjdoLTMuOHYwLjdoNC40YzAuMSwwLDAuMywwLjEsMC40LDAuMmMwLjEsMC4xLDAuMiwwLjIsMC4yLDAuNGMwLDAuMS0wLjEsMC4zLTAuMiwwLjRjLTAuMSwwLjEtMC4yLDAuMi0wLjQsMC4yICAgaC00LjR2MC43SDQyYzAuMiwwLDAuMywwLjEsMC40LDAuMmMwLjEsMC4xLDAuMiwwLjIsMC4yLDAuNHMtMC4xLDAuMy0wLjIsMC40Yy0wLjEsMC4xLTAuMiwwLjItMC40LDAuMkgzMGMtMC4yLDAtMC4zLTAuMS0wLjQtMC4yICAgYy0wLjEtMC4xLTAuMi0wLjItMC4yLTAuNHMwLjEtMC4zLDAuMi0wLjRjMC4xLTAuMSwwLjItMC4yLDAuNC0wLjJoNS4ydi0wLjdoLTQuNGMtMC4xLDAtMC4zLTAuMS0wLjQtMC4ycy0wLjItMC4yLTAuMi0wLjQgICBjMC0wLjEsMC4xLTAuMywwLjItMC40czAuMi0wLjIsMC40LTAuMmg0LjR2LTAuN2gtMy43aDBjLTAuMiwwLTAuNC0wLjEtMC42LTAuMnMtMC4yLTAuMy0wLjItMC42di0zLjFjMC0wLjIsMC4xLTAuNCwwLjItMC42ICAgYzAuMS0wLjEsMC4zLTAuMiwwLjYtMC4yaDMuOHYtMC44SDMwYy0wLjIsMC0wLjMtMC4xLTAuNC0wLjJjLTAuMS0wLjEtMC4yLTAuMi0wLjItMC40czAuMS0wLjMsMC4yLTAuNGMwLjEtMC4xLDAuMi0wLjIsMC40LTAuMiAgIGg1LjJ2LTAuOGMtMS40LDAtMi45LDAuMS00LjMsMC4xYy0wLjIsMC0wLjMsMC0wLjQtMC4xYy0wLjEtMC4xLTAuMi0wLjItMC4yLTAuNGMwLTAuMiwwLTAuMywwLjItMC40YzAuMS0wLjEsMC4zLTAuMiwwLjQtMC4yICAgYzMuMywwLDYuOC0wLjEsMTAuMi0wLjNjMC4yLDAsMC4zLDAsMC40LDAuMmMwLjEsMC4xLDAuMiwwLjMsMC4yLDAuNGMwLDAuMiwwLDAuMy0wLjEsMC40Yy0wLjEsMC4xLTAuMiwwLjItMC40LDAuMiAgIGMtMS4xLDAtMi41LDAuMS00LjMsMC4xdjAuOGg1LjFjMC4yLDAsMC4zLDAuMSwwLjQsMC4yYzAuMSwwLjEsMC4yLDAuMiwwLjIsMC40cy0wLjEsMC4zLTAuMiwwLjRjLTAuMSwwLjEtMC4yLDAuMi0wLjQsMC4yaC01LjEgICB2MC44aDMuOGMwLjIsMCwwLjQsMC4xLDAuNiwwLjJjMC4xLDAuMSwwLjIsMC4zLDAuMiwwLjZ2My4xYzAsMC4yLTAuMSwwLjQtMC4yLDAuNkM0MSwzNy43LDQwLjgsMzcuNyw0MC42LDM3Ljd6IE0zNS4xLDM0LjlWMzQgICBoLTIuOXYwLjlIMzUuMXogTTM1LjEsMzYuN3YtMC45aC0yLjl2MC45SDM1LjF6IE0zOS44LDM0LjlWMzRoLTIuOXYwLjlIMzkuOHogTTM5LjgsMzYuN3YtMC45aC0yLjl2MC45SDM5Ljh6Ii8+Cgk8cGF0aCBkPSJNNDUuNSw0MS4xYy0wLjMsMC40LTAuNywwLjUtMS4xLDAuM2MtMC40LTAuMy0wLjUtMC43LTAuMy0xLjFsMS0xLjdjMC4zLTAuNCwwLjctMC41LDEuMS0wLjNjMC40LDAuMywwLjUsMC43LDAuMywxLjEgICBMNDUuNSw0MS4xeiBNNTUsMzcuN2MtMC4xLDAtMC4xLDAtMC4yLDBoLTguOWMtMC4zLDAtMC41LTAuMS0wLjYtMC4yYy0wLjItMC4yLTAuMi0wLjQtMC4yLTAuNnYtMy40YzAtMC4yLDAuMS0wLjQsMC4yLTAuNiAgIGMwLjEtMC4xLDAuMy0wLjIsMC42LTAuMmgzLjN2LTMuMWMwLTAuMiwwLjEtMC40LDAuMi0wLjZjMC4yLTAuMiwwLjQtMC4yLDAuNi0wLjJzMC40LDAuMSwwLjYsMC4yYzAuMiwwLjIsMC4yLDAuNCwwLjIsMC42djAuM0g1NiAgIGMwLjIsMCwwLjQsMC4xLDAuNiwwLjJjMC4xLDAuMSwwLjIsMC4zLDAuMiwwLjZzLTAuMSwwLjQtMC4yLDAuNWMtMC4xLDAuMS0wLjMsMC4yLTAuNiwwLjJoLTUuMnYxLjNoNGMwLjIsMCwwLjQsMC4xLDAuNiwwLjIgICBjMC4xLDAuMSwwLjIsMC4zLDAuMiwwLjZ2My40QzU1LjYsMzcuMyw1NS40LDM3LjYsNTUsMzcuN3ogTTUzLjksMzYuMnYtMmgtNy4xdjJINTMuOXogTTQ5LjYsNDAuN2MwLDAuMy0wLjEsMC41LTAuMiwwLjYgICBjLTAuMiwwLjEtMC40LDAuMi0wLjYsMC4yYy0wLjIsMC0wLjQtMC4xLTAuNi0wLjJjLTAuMS0wLjItMC4yLTAuNC0wLjItMC42bDAtMS42YzAtMC4yLDAuMS0wLjQsMC4yLTAuNmMwLjItMC4yLDAuMy0wLjIsMC42LTAuMiAgIHMwLjQsMC4xLDAuNiwwLjJjMC4yLDAuMiwwLjIsMC40LDAuMiwwLjZWNDAuN3ogTTUyLjgsNDAuN2MwLDAuMi0wLjEsMC40LTAuMiwwLjZjLTAuMiwwLjEtMC40LDAuMi0wLjYsMC4yICAgYy0wLjIsMC0wLjQtMC4xLTAuNi0wLjJjLTAuMi0wLjEtMC4yLTAuMy0wLjItMC42bDAtMS42YzAtMC4yLDAuMS0wLjQsMC4yLTAuNmMwLjItMC4yLDAuMy0wLjIsMC42LTAuMmMwLjIsMCwwLjQsMC4xLDAuNiwwLjIgICBjMC4yLDAuMiwwLjIsMC40LDAuMiwwLjZWNDAuN3ogTTU2LjYsNDAuM2MwLjIsMC40LDAuMSwwLjgtMC4zLDEuMWMtMC41LDAuMy0wLjgsMC4yLTEuMS0wLjNsLTEtMS43Yy0wLjItMC41LTAuMS0wLjgsMC4zLTEuMSAgIGMwLjUtMC4yLDAuOS0wLjEsMS4xLDAuM0w1Ni42LDQwLjN6Ii8+CjwvZz4KPC9zdmc+";
|
|
871
|
+
async function convertTextStyle(el, isByWord = false) {
|
|
872
|
+
const { fetchToText } = useSharedTextAssets();
|
|
873
|
+
const style = {
|
|
874
|
+
...el.style,
|
|
875
|
+
highlightReferImage,
|
|
714
876
|
listStyleType: "none",
|
|
715
877
|
listStyleImage: "none"
|
|
716
878
|
};
|
|
717
|
-
|
|
879
|
+
if (el.style.fontSize) {
|
|
880
|
+
style.fontSize = Math.floor(el.style.fontSize);
|
|
881
|
+
}
|
|
882
|
+
if (el.listStyle?.colormap) {
|
|
883
|
+
style.listStyleColormap = el.listStyle?.colormap;
|
|
884
|
+
}
|
|
885
|
+
if (!isByWord) {
|
|
886
|
+
if (el.listMode) {
|
|
887
|
+
style.listStyleType = "disc";
|
|
888
|
+
} else if (el.listStyle) {
|
|
889
|
+
style.listStyleImage = await fetchToText(el.listStyle.image);
|
|
890
|
+
style.listStyleSize = `${el.listStyle.size * 100}%`;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
if (el.background?.enabled) {
|
|
894
|
+
style.backgroundImage = el.background.image;
|
|
895
|
+
style.backgroundSize = el.background.size;
|
|
896
|
+
style.backgroundColormap = el.background.colormap;
|
|
897
|
+
style.padding = el.background.padding;
|
|
898
|
+
} else {
|
|
899
|
+
style.padding = 0;
|
|
900
|
+
}
|
|
901
|
+
return style;
|
|
718
902
|
}
|
|
719
|
-
async function
|
|
720
|
-
const
|
|
721
|
-
if (
|
|
722
|
-
return
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
903
|
+
async function convertTextEffects(el) {
|
|
904
|
+
const effects = el.textEffects ?? [];
|
|
905
|
+
if (!effects.length) {
|
|
906
|
+
return void 0;
|
|
907
|
+
}
|
|
908
|
+
return await Promise.all(
|
|
909
|
+
[...effects].reverse().map(async (effect) => {
|
|
910
|
+
const result = {};
|
|
911
|
+
const { offset, skew, stroke, shadow, filling } = effect;
|
|
912
|
+
if (offset) {
|
|
913
|
+
result.translateX = offset.x;
|
|
914
|
+
result.translateY = offset.y;
|
|
915
|
+
}
|
|
916
|
+
if (skew) {
|
|
917
|
+
result.skewX = skew.x;
|
|
918
|
+
result.skewY = skew.y;
|
|
919
|
+
}
|
|
920
|
+
if (stroke?.color && stroke.width) {
|
|
921
|
+
result.textStrokeWidth = stroke.width;
|
|
922
|
+
result.textStrokeColor = stroke.color;
|
|
923
|
+
}
|
|
924
|
+
if (shadow) {
|
|
925
|
+
result.shadowOffsetX = shadow.offsetX;
|
|
926
|
+
result.shadowOffsetY = shadow.offsetY;
|
|
927
|
+
result.shadowBlur = shadow.blur;
|
|
928
|
+
result.shadowColor = shadow.color;
|
|
929
|
+
}
|
|
930
|
+
if (filling) {
|
|
931
|
+
const { color, imageContent, gradient } = filling;
|
|
932
|
+
if (imageContent?.image) ;
|
|
933
|
+
else if (gradient) {
|
|
934
|
+
result.color = `linear-gradient(${90 - gradient.angle}deg, ${gradient.stops.map((stop) => `${stop.color} ${stop.offset * 100}%`).join(",")})`;
|
|
935
|
+
} else if (color) {
|
|
936
|
+
result.color = color;
|
|
728
937
|
}
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
)
|
|
938
|
+
}
|
|
939
|
+
return result;
|
|
940
|
+
})
|
|
941
|
+
);
|
|
732
942
|
}
|
|
733
|
-
function
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
let
|
|
741
|
-
|
|
742
|
-
|
|
943
|
+
function getTextContents(el) {
|
|
944
|
+
if (el.version) {
|
|
945
|
+
return el.contents;
|
|
946
|
+
}
|
|
947
|
+
return el.contents.map((p) => {
|
|
948
|
+
let prevChar;
|
|
949
|
+
return p.map((f, fIndex) => {
|
|
950
|
+
let content = f.content;
|
|
951
|
+
content = content.replace(/ |\r\n|\n\r|[\n\r\t\v]/g, " ");
|
|
952
|
+
content = content.replace(/<br\/>/g, "\n");
|
|
953
|
+
let newContent = "";
|
|
954
|
+
let cIndex = 0;
|
|
955
|
+
for (const char of Array.from(content)) {
|
|
956
|
+
if (fIndex === 0 && cIndex === 0 && char === " ") ;
|
|
957
|
+
else if (prevChar === " " && char === " ") ;
|
|
958
|
+
else {
|
|
959
|
+
newContent += char;
|
|
960
|
+
}
|
|
961
|
+
prevChar = char;
|
|
962
|
+
cIndex++;
|
|
963
|
+
}
|
|
743
964
|
return {
|
|
744
|
-
...
|
|
745
|
-
content:
|
|
965
|
+
...f,
|
|
966
|
+
content: newContent
|
|
746
967
|
};
|
|
747
|
-
}).filter((
|
|
968
|
+
}).filter((f) => f.content);
|
|
748
969
|
});
|
|
749
970
|
}
|
|
750
|
-
async function
|
|
751
|
-
const { fetchToText
|
|
752
|
-
|
|
753
|
-
|
|
971
|
+
async function convertTextContent(el, isByWord = false) {
|
|
972
|
+
const { fetchToText } = useSharedTextAssets();
|
|
973
|
+
const bigeContents = getTextContents(el);
|
|
974
|
+
const paragraphs = [];
|
|
975
|
+
for (let i = 0, len = bigeContents.length; i < len; i++) {
|
|
976
|
+
const bigeParagraphs = bigeContents[i];
|
|
977
|
+
const paragraph = {
|
|
754
978
|
fragments: []
|
|
755
979
|
};
|
|
756
|
-
|
|
757
|
-
for (let
|
|
758
|
-
const
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
980
|
+
paragraphs.push(paragraph);
|
|
981
|
+
for (let i2 = 0, len2 = bigeParagraphs.length; i2 < len2; i2++) {
|
|
982
|
+
const fragment = {};
|
|
983
|
+
const raw = bigeParagraphs[i2];
|
|
984
|
+
for (const key in raw) {
|
|
985
|
+
if (key !== "id" && raw[key] !== "") {
|
|
986
|
+
fragment[key] = raw[key];
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
if (fragment.fontSize) {
|
|
990
|
+
fragment.fontSize = Math.floor(fragment.fontSize);
|
|
991
|
+
}
|
|
992
|
+
fragment.content = normalizeCRLF(fragment.content);
|
|
993
|
+
if (fragment.highlight) {
|
|
994
|
+
fragment.highlightImage = await fetchToText(fragment.highlight.image);
|
|
995
|
+
if (isByWord) {
|
|
996
|
+
fragment.highlightSize = "cover";
|
|
997
|
+
} else {
|
|
998
|
+
if (fragment.highlight.size) {
|
|
999
|
+
fragment.highlightSize = `${fragment.highlight.size}rem`;
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
if (fragment.highlight.colormap) {
|
|
1003
|
+
fragment.highlightColormap = fragment.highlight.colormap;
|
|
1004
|
+
}
|
|
1005
|
+
if (fragment.highlight.line) {
|
|
1006
|
+
fragment.highlightLine = fragment.highlight.line;
|
|
1007
|
+
}
|
|
1008
|
+
if (fragment.highlight.thickness) {
|
|
1009
|
+
fragment.highlightThickness = `${fragment.highlight.thickness}%`;
|
|
1010
|
+
}
|
|
1011
|
+
delete fragment.highlight;
|
|
1012
|
+
}
|
|
1013
|
+
if (!isByWord) {
|
|
1014
|
+
if (fragment.listMode) {
|
|
1015
|
+
paragraph.listStyleType = "disc";
|
|
1016
|
+
} else if (fragment.listStyle) {
|
|
1017
|
+
paragraph.listStyleImage = await fetchToText(fragment.listStyle.image);
|
|
1018
|
+
paragraph.listStyleSize = `${fragment.listStyle.size * 100}%`;
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
const prev = paragraph.fragments[paragraph.fragments.length - 1];
|
|
1022
|
+
if (prev && Object.keys(prev).length === 1 && prev.content && Object.keys(fragment).length === 1 && fragment.content) {
|
|
1023
|
+
prev.content += fragment.content;
|
|
1024
|
+
} else {
|
|
1025
|
+
paragraph.fragments.push(fragment);
|
|
1026
|
+
}
|
|
764
1027
|
}
|
|
765
1028
|
}
|
|
766
|
-
return
|
|
1029
|
+
return paragraphs;
|
|
767
1030
|
}
|
|
768
|
-
const
|
|
769
|
-
async function
|
|
770
|
-
const
|
|
771
|
-
delete
|
|
772
|
-
|
|
1031
|
+
const percentageToPx = (per) => (Number.parseFloat(per) || 0) / 100;
|
|
1032
|
+
async function convertElement(el, parent, context) {
|
|
1033
|
+
const style = { ...el.style ?? el };
|
|
1034
|
+
delete style.bottom;
|
|
1035
|
+
delete style.right;
|
|
1036
|
+
const meta = {
|
|
773
1037
|
inPptIs: "Shape",
|
|
774
1038
|
inEditorIs: "Element"
|
|
775
1039
|
};
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
1040
|
+
if (el.id) {
|
|
1041
|
+
meta.rawId = el.id;
|
|
1042
|
+
}
|
|
1043
|
+
if (el.name) {
|
|
1044
|
+
meta.rawName = el.name;
|
|
1045
|
+
}
|
|
1046
|
+
const element = {
|
|
1047
|
+
id: idGenerator(),
|
|
1048
|
+
name: el.name ?? el.title ?? el.id,
|
|
1049
|
+
style,
|
|
1050
|
+
meta,
|
|
782
1051
|
children: []
|
|
783
1052
|
};
|
|
784
|
-
if (
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
1053
|
+
if (style.borderRadius) {
|
|
1054
|
+
style.borderRadius = style.borderRadius * 0.01 * Math.max(style.height, style.width);
|
|
1055
|
+
}
|
|
1056
|
+
if (parent && el.groupStyle) {
|
|
1057
|
+
style.width = parent.style.width * percentageToPx(el.groupStyle.width);
|
|
1058
|
+
style.height = parent.style.height * percentageToPx(el.groupStyle.height);
|
|
1059
|
+
style.left = parent.style.width * percentageToPx(el.groupStyle.left);
|
|
1060
|
+
style.top = parent.style.height * percentageToPx(el.groupStyle.top);
|
|
1061
|
+
}
|
|
1062
|
+
if (el.editable === false) {
|
|
1063
|
+
style.visibility = "hidden";
|
|
792
1064
|
}
|
|
793
|
-
|
|
1065
|
+
if (el.lock === true) {
|
|
1066
|
+
meta.lock = true;
|
|
1067
|
+
}
|
|
1068
|
+
if (el.animations?.length) {
|
|
1069
|
+
const parsed = parseAnimations(el);
|
|
1070
|
+
element.delay = parsed.delay;
|
|
1071
|
+
element.duration = parsed.duration;
|
|
1072
|
+
element.children.push(...parsed.animations);
|
|
1073
|
+
if (context) {
|
|
1074
|
+
parsed.animations.forEach((animation) => {
|
|
1075
|
+
context.endTime = Math.max(
|
|
1076
|
+
context.endTime,
|
|
1077
|
+
parsed.delay + animation.delay + animation.duration
|
|
1078
|
+
);
|
|
1079
|
+
});
|
|
1080
|
+
context.endTime = Math.max(context.endTime, parsed.delay + parsed.duration);
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
switch (el.type) {
|
|
794
1084
|
case "image":
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
1085
|
+
meta.inPptIs = "Picture";
|
|
1086
|
+
element.foreground = {
|
|
1087
|
+
image: await convertImageElementToUrl(el),
|
|
1088
|
+
fillWithShape: true
|
|
1089
|
+
};
|
|
1090
|
+
if (el.clipUrl) {
|
|
1091
|
+
meta.rawForegroundImage = el.url;
|
|
1092
|
+
}
|
|
1093
|
+
if (el.cropping) {
|
|
1094
|
+
const width = el.style.width;
|
|
1095
|
+
const height = el.style.height;
|
|
1096
|
+
const {
|
|
1097
|
+
imageWidth,
|
|
1098
|
+
imageHeight,
|
|
1099
|
+
maskWidth = width,
|
|
1100
|
+
maskHeight = height,
|
|
1101
|
+
translateX,
|
|
1102
|
+
translateY,
|
|
1103
|
+
zoom = 1
|
|
1104
|
+
} = el.cropping;
|
|
1105
|
+
const cvsWidth = imageWidth * zoom;
|
|
1106
|
+
const cvsHeight = imageHeight * zoom;
|
|
1107
|
+
const distX = (cvsWidth - maskWidth) / 2 - translateX;
|
|
1108
|
+
const distY = (cvsHeight - maskHeight) / 2 - translateY;
|
|
1109
|
+
const originX = distX + maskWidth / 2;
|
|
1110
|
+
const originY = distY + maskHeight / 2;
|
|
1111
|
+
const left = -(width / 2 - originX);
|
|
1112
|
+
const top = -(height / 2 - originY);
|
|
1113
|
+
const right = cvsWidth - (left + width);
|
|
1114
|
+
const bottom = cvsHeight - (top + height);
|
|
1115
|
+
element.foreground.cropRect = {
|
|
1116
|
+
left: left / cvsWidth,
|
|
1117
|
+
top: top / cvsHeight,
|
|
1118
|
+
right: right / cvsWidth,
|
|
1119
|
+
bottom: bottom / cvsHeight
|
|
813
1120
|
};
|
|
814
1121
|
}
|
|
815
1122
|
break;
|
|
816
1123
|
case "svg": {
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
1124
|
+
meta.inPptIs = "Picture";
|
|
1125
|
+
element.foreground = {
|
|
1126
|
+
image: await convertSvgElementToUrl(el),
|
|
1127
|
+
fillWithShape: true
|
|
820
1128
|
};
|
|
821
1129
|
break;
|
|
822
1130
|
}
|
|
823
1131
|
case "text": {
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
style
|
|
827
|
-
|
|
1132
|
+
meta.inPptIs = "Shape";
|
|
1133
|
+
if (style.writingMode === "horizontal-tb") {
|
|
1134
|
+
style.width = Math.ceil(style.width + style.letterSpacing);
|
|
1135
|
+
} else {
|
|
1136
|
+
style.height = Math.ceil(style.height + style.letterSpacing);
|
|
1137
|
+
}
|
|
1138
|
+
element.text = {
|
|
1139
|
+
content: await convertTextContent(el),
|
|
1140
|
+
style: await convertTextStyle(el),
|
|
1141
|
+
effects: await convertTextEffects(el)
|
|
828
1142
|
// plugins: [deformation(el.deformation?.type?.endsWith("byWord") ? -1 : 999, () => el.deformation)],
|
|
829
1143
|
};
|
|
830
1144
|
break;
|
|
831
1145
|
}
|
|
832
1146
|
case "com":
|
|
833
|
-
|
|
834
|
-
|
|
1147
|
+
meta.inPptIs = "GroupShape";
|
|
1148
|
+
element.children = (await Promise.all(
|
|
1149
|
+
el.children.map(async (child) => {
|
|
835
1150
|
try {
|
|
836
|
-
return await
|
|
837
|
-
} catch (
|
|
838
|
-
console.warn(
|
|
839
|
-
return;
|
|
1151
|
+
return await convertElement(child, el, context);
|
|
1152
|
+
} catch (e) {
|
|
1153
|
+
console.warn(e);
|
|
1154
|
+
return void 0;
|
|
840
1155
|
}
|
|
841
1156
|
})
|
|
842
1157
|
)).filter(Boolean);
|
|
@@ -863,193 +1178,279 @@ async function q(e, r, o) {
|
|
|
863
1178
|
case "collage":
|
|
864
1179
|
case "imageWall":
|
|
865
1180
|
default:
|
|
866
|
-
console.warn(
|
|
1181
|
+
console.warn(el);
|
|
867
1182
|
break;
|
|
868
1183
|
}
|
|
869
|
-
return
|
|
1184
|
+
return element;
|
|
870
1185
|
}
|
|
871
|
-
async function
|
|
872
|
-
const
|
|
873
|
-
|
|
1186
|
+
async function convertLayout(layout, isFrame = true, context) {
|
|
1187
|
+
const id = idGenerator();
|
|
1188
|
+
const style = {
|
|
1189
|
+
...layout.style ?? layout
|
|
874
1190
|
};
|
|
875
|
-
delete
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
1191
|
+
delete style.right;
|
|
1192
|
+
delete style.bottom;
|
|
1193
|
+
if (isFrame) {
|
|
1194
|
+
style.overflow = "hidden";
|
|
1195
|
+
}
|
|
1196
|
+
const meta = {
|
|
1197
|
+
inPptIs: isFrame ? "Slide" : "GroupShape",
|
|
1198
|
+
inEditorIs: isFrame ? "Frame" : "Element"
|
|
879
1199
|
};
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
1200
|
+
if (layout.id) {
|
|
1201
|
+
meta.rawId = layout.id;
|
|
1202
|
+
}
|
|
1203
|
+
if (layout.name) {
|
|
1204
|
+
meta.rawName = layout.name;
|
|
1205
|
+
}
|
|
1206
|
+
let background;
|
|
1207
|
+
if (layout.background) {
|
|
1208
|
+
if (layout.background.color) {
|
|
1209
|
+
background ??= {};
|
|
1210
|
+
if (isGradient(layout.background.color ?? "")) {
|
|
1211
|
+
background.image = layout.background.color;
|
|
1212
|
+
} else {
|
|
1213
|
+
background.color = layout.background.color;
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
if (layout.background.image) {
|
|
1217
|
+
background ??= {};
|
|
1218
|
+
background.image = layout.background.image;
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
return {
|
|
1222
|
+
id,
|
|
1223
|
+
name: isFrame ? `Frame ${id}` : layout.name,
|
|
1224
|
+
style,
|
|
886
1225
|
// TODO 过滤掉部分属性
|
|
887
|
-
background
|
|
1226
|
+
background,
|
|
888
1227
|
children: (await Promise.all(
|
|
889
|
-
|
|
1228
|
+
layout.elements.map(async (element) => {
|
|
890
1229
|
try {
|
|
891
|
-
return await
|
|
892
|
-
} catch (
|
|
893
|
-
console.warn(
|
|
894
|
-
return;
|
|
1230
|
+
return await convertElement(element, void 0, context);
|
|
1231
|
+
} catch (e) {
|
|
1232
|
+
console.warn(e);
|
|
1233
|
+
return void 0;
|
|
895
1234
|
}
|
|
896
1235
|
})
|
|
897
1236
|
)).filter(Boolean),
|
|
898
|
-
meta
|
|
1237
|
+
meta
|
|
899
1238
|
};
|
|
900
1239
|
}
|
|
901
|
-
async function
|
|
1240
|
+
async function convertDoc(doc, gap = 0) {
|
|
902
1241
|
const {
|
|
903
|
-
layouts
|
|
904
|
-
metas
|
|
905
|
-
} =
|
|
1242
|
+
layouts,
|
|
1243
|
+
metas = {}
|
|
1244
|
+
} = doc;
|
|
1245
|
+
const context = {
|
|
906
1246
|
endTime: 0
|
|
907
1247
|
};
|
|
908
|
-
let
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
1248
|
+
let children = await Promise.all(
|
|
1249
|
+
layouts.map(async (layout, index) => {
|
|
1250
|
+
return {
|
|
1251
|
+
index,
|
|
1252
|
+
element: await convertLayout(layout, true, context)
|
|
1253
|
+
};
|
|
1254
|
+
})
|
|
1255
|
+
);
|
|
1256
|
+
let top = 0;
|
|
1257
|
+
children = children.sort((a, b) => a.index - b.index).map((v, index) => {
|
|
1258
|
+
const element = v.element;
|
|
1259
|
+
if (element.style) {
|
|
1260
|
+
element.style.top = top;
|
|
1261
|
+
top += Number(element.style.height) + gap;
|
|
1262
|
+
}
|
|
1263
|
+
element.name = `Frame ${index + 1}`;
|
|
1264
|
+
return element;
|
|
917
1265
|
});
|
|
918
|
-
const
|
|
919
|
-
const
|
|
1266
|
+
const minmax = children.reduce((child) => {
|
|
1267
|
+
const left = child.style?.left ?? 0;
|
|
1268
|
+
const top2 = child.style?.top ?? 0;
|
|
1269
|
+
const width = child.style?.width ?? 0;
|
|
1270
|
+
const height = child.style?.height ?? 0;
|
|
920
1271
|
return {
|
|
921
|
-
minX:
|
|
922
|
-
minY:
|
|
923
|
-
maxX:
|
|
924
|
-
maxY:
|
|
1272
|
+
minX: left,
|
|
1273
|
+
minY: top2,
|
|
1274
|
+
maxX: left + width,
|
|
1275
|
+
maxY: top2 + height
|
|
925
1276
|
};
|
|
926
1277
|
}, { minX: 0, minY: 0, maxX: 0, maxY: 0 });
|
|
927
1278
|
return {
|
|
928
|
-
id:
|
|
929
|
-
name:
|
|
1279
|
+
id: idGenerator(),
|
|
1280
|
+
name: metas.name || "doc",
|
|
930
1281
|
style: {
|
|
931
|
-
width:
|
|
932
|
-
height:
|
|
1282
|
+
width: metas?.width ?? minmax.maxX - minmax.minX,
|
|
1283
|
+
height: metas?.height ?? minmax.maxY - minmax.minY
|
|
933
1284
|
},
|
|
934
|
-
children
|
|
1285
|
+
children,
|
|
935
1286
|
meta: {
|
|
936
|
-
...
|
|
937
|
-
endTime:
|
|
1287
|
+
...metas,
|
|
1288
|
+
endTime: context.endTime,
|
|
938
1289
|
inEditorIs: "Doc"
|
|
939
1290
|
}
|
|
940
1291
|
};
|
|
941
1292
|
}
|
|
942
|
-
function
|
|
943
|
-
const { config
|
|
1293
|
+
function bidTidLoader(editor, api) {
|
|
1294
|
+
const { config } = editor;
|
|
944
1295
|
return {
|
|
945
1296
|
name: "bigesj:bidTid",
|
|
946
|
-
test: (
|
|
947
|
-
load: async (
|
|
948
|
-
const
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
1297
|
+
test: (source) => typeof source === "object" && source && !!(source.bid || source.tid),
|
|
1298
|
+
load: async (source) => {
|
|
1299
|
+
const text = source.bid ?? source.tid ?? "";
|
|
1300
|
+
const load = async (id) => {
|
|
1301
|
+
return await fetch(
|
|
1302
|
+
(source.bid ? api.bid : api.tid).replace("%d", id)
|
|
1303
|
+
).then((rep) => rep.json()).then((res) => res.data);
|
|
1304
|
+
};
|
|
1305
|
+
let maxTime = 0;
|
|
1306
|
+
const docs = await Promise.all(
|
|
1307
|
+
text.split("|").map(async (text1) => {
|
|
1308
|
+
let [id, text2] = text1.split("[");
|
|
1309
|
+
if (text2) {
|
|
1310
|
+
text2 = text2.substring(0, text2.length - 1);
|
|
1311
|
+
}
|
|
1312
|
+
const included = text2 ? text2.split(",").map((v) => Number(v)) : void 0;
|
|
1313
|
+
const bigeDoc = await load(id);
|
|
1314
|
+
const { content: _content, ...raw } = bigeDoc;
|
|
1315
|
+
const content = JSON.parse(_content);
|
|
1316
|
+
if (included !== void 0) {
|
|
1317
|
+
content.layouts = content.layouts.filter((_, index) => included.includes(index));
|
|
1318
|
+
}
|
|
1319
|
+
const doc2 = await convertDoc(content);
|
|
1320
|
+
doc2.meta.raw = raw;
|
|
1321
|
+
maxTime = Math.max(maxTime, doc2.meta?.maxTime ?? 0);
|
|
1322
|
+
return doc2;
|
|
960
1323
|
})
|
|
961
|
-
)
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1324
|
+
);
|
|
1325
|
+
const doc = { ...docs[0], id: text, children: [] };
|
|
1326
|
+
doc.meta ??= {};
|
|
1327
|
+
doc.meta.maxTime = maxTime;
|
|
1328
|
+
doc.meta.inEditorIs = "Doc";
|
|
1329
|
+
let left = 0;
|
|
1330
|
+
docs.forEach((_doc) => {
|
|
1331
|
+
let width = 0;
|
|
1332
|
+
_doc.children?.forEach((element) => {
|
|
1333
|
+
if (element.style) {
|
|
1334
|
+
element.style.left = left;
|
|
1335
|
+
width = Math.max(width, Number(element.style.width));
|
|
1336
|
+
doc.children.push(element);
|
|
1337
|
+
}
|
|
1338
|
+
});
|
|
1339
|
+
left += width + config.value.frameGap;
|
|
1340
|
+
});
|
|
1341
|
+
return doc;
|
|
970
1342
|
}
|
|
971
1343
|
};
|
|
972
1344
|
}
|
|
973
|
-
function
|
|
1345
|
+
function bigeLoader() {
|
|
974
1346
|
return {
|
|
975
1347
|
name: "bigesj:bige",
|
|
976
1348
|
accept: ".bige",
|
|
977
|
-
test: (
|
|
978
|
-
|
|
979
|
-
|
|
1349
|
+
test: (file) => {
|
|
1350
|
+
return file instanceof File && file.name.endsWith(".bige");
|
|
1351
|
+
},
|
|
1352
|
+
load: async (file) => {
|
|
1353
|
+
const bigeDoc = JSON.parse(
|
|
980
1354
|
new TextDecoder().decode(
|
|
981
|
-
|
|
1355
|
+
gunzipSync(new Uint8Array(await file.arrayBuffer()))
|
|
982
1356
|
)
|
|
983
|
-
)
|
|
984
|
-
|
|
1357
|
+
);
|
|
1358
|
+
const { content, ...raw } = bigeDoc;
|
|
1359
|
+
const doc = await convertDoc(content);
|
|
1360
|
+
doc.meta.raw = raw;
|
|
1361
|
+
return doc;
|
|
985
1362
|
}
|
|
986
1363
|
};
|
|
987
1364
|
}
|
|
988
|
-
function
|
|
1365
|
+
function plugin(options = {}) {
|
|
989
1366
|
const {
|
|
990
|
-
font
|
|
991
|
-
api
|
|
992
|
-
} =
|
|
1367
|
+
font,
|
|
1368
|
+
api
|
|
1369
|
+
} = options;
|
|
1370
|
+
const _api = {
|
|
993
1371
|
fonts: "/new/design/fonts",
|
|
994
1372
|
bid: "/new/udesign/info/%d",
|
|
995
1373
|
tid: "/new/design/info/%d",
|
|
996
|
-
...
|
|
1374
|
+
...api
|
|
997
1375
|
};
|
|
998
|
-
return
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1376
|
+
return definePlugin((editor) => {
|
|
1377
|
+
return {
|
|
1378
|
+
name: "bigesj",
|
|
1379
|
+
loaders: [
|
|
1380
|
+
bigeLoader(),
|
|
1381
|
+
bidTidLoader(editor, _api)
|
|
1382
|
+
],
|
|
1383
|
+
setup: async () => {
|
|
1384
|
+
if (font) {
|
|
1385
|
+
await setupFonts(editor, _api);
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
};
|
|
1389
|
+
});
|
|
1008
1390
|
}
|
|
1009
|
-
async function
|
|
1391
|
+
async function setupFonts(editor, api) {
|
|
1010
1392
|
const {
|
|
1011
|
-
on
|
|
1012
|
-
off
|
|
1013
|
-
root
|
|
1014
|
-
} =
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1393
|
+
on,
|
|
1394
|
+
off,
|
|
1395
|
+
root
|
|
1396
|
+
} = editor;
|
|
1397
|
+
const {
|
|
1398
|
+
loadBigeFonts,
|
|
1399
|
+
loadFont
|
|
1400
|
+
} = useFonts();
|
|
1401
|
+
function preloadNode(node) {
|
|
1402
|
+
if (node instanceof Element2D) {
|
|
1403
|
+
if (node.style.fontFamily) {
|
|
1404
|
+
loadFont(node.style.fontFamily).then(() => node.text.update());
|
|
1405
|
+
}
|
|
1406
|
+
node.text.content.forEach((p) => {
|
|
1407
|
+
p.fragments.forEach((f) => {
|
|
1408
|
+
if (f.fontFamily) {
|
|
1409
|
+
loadFont(f.fontFamily).then(() => node.text.update());
|
|
1410
|
+
}
|
|
1411
|
+
});
|
|
1412
|
+
if (p.fontFamily) {
|
|
1413
|
+
loadFont(p.fontFamily).then(() => node.text.update());
|
|
1414
|
+
}
|
|
1415
|
+
});
|
|
1416
|
+
}
|
|
1024
1417
|
}
|
|
1025
|
-
function
|
|
1026
|
-
|
|
1027
|
-
|
|
1418
|
+
function preloadNodes(node) {
|
|
1419
|
+
node.forEach((child) => {
|
|
1420
|
+
preloadNode(child);
|
|
1421
|
+
child.findOne((descendant) => {
|
|
1422
|
+
preloadNode(descendant);
|
|
1423
|
+
return false;
|
|
1424
|
+
});
|
|
1028
1425
|
});
|
|
1029
1426
|
}
|
|
1030
|
-
async function
|
|
1031
|
-
|
|
1427
|
+
async function preload() {
|
|
1428
|
+
root.value && preloadNodes([root.value]);
|
|
1032
1429
|
}
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1430
|
+
onBeforeUnmount(() => {
|
|
1431
|
+
off("setDoc", preload);
|
|
1432
|
+
off("addElement", preloadNodes);
|
|
1433
|
+
});
|
|
1434
|
+
on("setDoc", preload);
|
|
1435
|
+
on("addElement", preloadNodes);
|
|
1436
|
+
await loadBigeFonts(api.fonts);
|
|
1036
1437
|
}
|
|
1037
1438
|
export {
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1439
|
+
bidTidLoader,
|
|
1440
|
+
bigeLoader,
|
|
1441
|
+
convertAnimation,
|
|
1442
|
+
convertDoc,
|
|
1443
|
+
convertElement,
|
|
1444
|
+
convertImageElementToUrl,
|
|
1445
|
+
convertLayout,
|
|
1446
|
+
convertSvgElementToUrl,
|
|
1447
|
+
convertTextContent,
|
|
1448
|
+
convertTextEffects,
|
|
1449
|
+
convertTextStyle,
|
|
1450
|
+
plugin as default,
|
|
1451
|
+
getTextContents,
|
|
1452
|
+
parseAnimations,
|
|
1453
|
+
plugin,
|
|
1454
|
+
useFonts,
|
|
1455
|
+
useSharedTextAssets
|
|
1055
1456
|
};
|