@printine/designer 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/README.md +146 -0
  2. package/dist/DesignerRuntimeContext.d.ts +3 -0
  3. package/dist/PrintineDesigner.d.ts +9 -0
  4. package/dist/api/client.d.ts +8 -0
  5. package/dist/api/client.js +82 -0
  6. package/dist/api/common-endpoints.d.ts +12 -0
  7. package/dist/api/design-endpoints.d.ts +18 -0
  8. package/dist/api/endpoints.d.ts +33 -0
  9. package/dist/api/endpoints.js +46 -0
  10. package/dist/api/files-endpoints.d.ts +1 -0
  11. package/dist/assets/icons/aspect_ratio.d.ts +3 -0
  12. package/dist/assets/icons/delete.d.ts +3 -0
  13. package/dist/assets/icons/fit_screen.d.ts +3 -0
  14. package/dist/assets/icons/index.d.ts +11 -0
  15. package/dist/assets/icons/loading_1.d.ts +3 -0
  16. package/dist/assets/icons/loading_2.d.ts +3 -0
  17. package/dist/assets/icons/loading_3.d.ts +3 -0
  18. package/dist/assets/icons/pan.d.ts +3 -0
  19. package/dist/assets/icons/setting.d.ts +3 -0
  20. package/dist/assets/icons/text_color.d.ts +3 -0
  21. package/dist/assets/icons/text_h.d.ts +3 -0
  22. package/dist/assets/icons/text_v.d.ts +3 -0
  23. package/dist/bundled-assets.d.ts +4 -0
  24. package/dist/components/add-design.d.ts +8 -0
  25. package/dist/components/assets-dialog.d.ts +21 -0
  26. package/dist/components/canvas-context-menu.d.ts +6 -0
  27. package/dist/components/color-picker/index.d.ts +10 -0
  28. package/dist/components/context.d.ts +24 -0
  29. package/dist/components/design.d.ts +9 -0
  30. package/dist/components/fonts.d.ts +26 -0
  31. package/dist/components/image-crop.d.ts +4 -0
  32. package/dist/components/image-edit.d.ts +1 -0
  33. package/dist/components/layout/aside.d.ts +3 -0
  34. package/dist/components/layout/bottom-nav/element-menu-sheet.d.ts +11 -0
  35. package/dist/components/layout/bottom-nav/element-sheet.d.ts +11 -0
  36. package/dist/components/layout/bottom-nav/index.d.ts +1 -0
  37. package/dist/components/layout/header.d.ts +5 -0
  38. package/dist/components/loading.d.ts +3 -0
  39. package/dist/components/menus/ai.d.ts +5 -0
  40. package/dist/components/menus/background.d.ts +6 -0
  41. package/dist/components/menus/clipart.d.ts +6 -0
  42. package/dist/components/menus/files.d.ts +7 -0
  43. package/dist/components/menus/image.d.ts +8 -0
  44. package/dist/components/menus/index.d.ts +13 -0
  45. package/dist/components/menus/layer.d.ts +5 -0
  46. package/dist/components/menus/product.d.ts +3 -0
  47. package/dist/components/menus/sca.d.ts +5 -0
  48. package/dist/components/menus/shapes.d.ts +6 -0
  49. package/dist/components/menus/templates.d.ts +6 -0
  50. package/dist/components/menus/text-effects.d.ts +5 -0
  51. package/dist/components/menus/text.d.ts +6 -0
  52. package/dist/components/placement-tab.d.ts +7 -0
  53. package/dist/components/preview/3d.d.ts +7 -0
  54. package/dist/components/preview/graphic.d.ts +7 -0
  55. package/dist/components/preview/index.d.ts +18 -0
  56. package/dist/components/preview/open.d.ts +7 -0
  57. package/dist/components/preview/real-time/3d.d.ts +12 -0
  58. package/dist/components/preview/real-time/graphic.d.ts +18 -0
  59. package/dist/components/preview/real-time/index.d.ts +11 -0
  60. package/dist/components/scale-tools.d.ts +7 -0
  61. package/dist/components/semi-deisgn-config.d.ts +13 -0
  62. package/dist/components/semi-design-link.d.ts +9 -0
  63. package/dist/components/store.d.ts +1 -0
  64. package/dist/components/toolbar.d.ts +2 -0
  65. package/dist/config-D2qm60gf.js +16 -0
  66. package/dist/contracts/api-design.d.ts +176 -0
  67. package/dist/contracts/design.d.ts +86 -0
  68. package/dist/design-7zRpRtv9.js +20331 -0
  69. package/dist/engine/canvas-designer.d.ts +101 -0
  70. package/dist/engine/canvas-designer.js +313 -0
  71. package/dist/engine/constants.d.ts +27 -0
  72. package/dist/engine/constants.js +148 -0
  73. package/dist/engine/editor.d.ts +186 -0
  74. package/dist/engine/editor.js +734 -0
  75. package/dist/engine/events.d.ts +34 -0
  76. package/dist/engine/events.js +7 -0
  77. package/dist/engine/extensions/curved-text.d.ts +59 -0
  78. package/dist/engine/fabric.d.ts +4 -0
  79. package/dist/engine/fabric.js +187 -0
  80. package/dist/engine/history.d.ts +27 -0
  81. package/dist/engine/history.js +56 -0
  82. package/dist/engine/managers/event.d.ts +101 -0
  83. package/dist/engine/managers/event.js +410 -0
  84. package/dist/engine/managers/resize.d.ts +24 -0
  85. package/dist/engine/managers/resize.js +63 -0
  86. package/dist/engine/managers/snapline.d.ts +70 -0
  87. package/dist/engine/managers/snapline.js +124 -0
  88. package/dist/engine/managers/workspace.d.ts +26 -0
  89. package/dist/engine/managers/workspace.js +53 -0
  90. package/dist/engine/processors/image.d.ts +88 -0
  91. package/dist/engine/processors/image.js +473 -0
  92. package/dist/engine/processors/template.d.ts +45 -0
  93. package/dist/engine/processors/template.js +314 -0
  94. package/dist/engine/processors/text.d.ts +74 -0
  95. package/dist/engine/processors/text.js +215 -0
  96. package/dist/engine/semi-export-editor.d.ts +199 -0
  97. package/dist/engine/types.d.ts +28 -0
  98. package/dist/engine/utils/common.d.ts +25 -0
  99. package/dist/engine/utils/common.js +68 -0
  100. package/dist/engine/utils/dialog.d.ts +25 -0
  101. package/dist/engine/utils/font.d.ts +5 -0
  102. package/dist/engine/utils/font.js +39 -0
  103. package/dist/engine/utils/image.d.ts +8 -0
  104. package/dist/engine/utils/image.js +50 -0
  105. package/dist/engine/utils/loading.d.ts +17 -0
  106. package/dist/engine/utils/loading.js +71 -0
  107. package/dist/engine/utils/measure.d.ts +6 -0
  108. package/dist/engine/utils/measure.js +6 -0
  109. package/dist/engine/utils/mockup.d.ts +59 -0
  110. package/dist/engine/utils/setting.d.ts +4 -0
  111. package/dist/engine/utils/setting.js +73 -0
  112. package/dist/fabric-types.d.ts +59 -0
  113. package/dist/full-designer.js +14 -0
  114. package/dist/hooks/pagination.d.ts +19 -0
  115. package/dist/hooks/use-adobe-express.d.ts +50 -0
  116. package/dist/hooks/use-before-unload.d.ts +1 -0
  117. package/dist/hooks/use-image-drop.d.ts +18 -0
  118. package/dist/hooks/use-oss-upload.d.ts +34 -0
  119. package/dist/hooks/use-screen.d.ts +1 -0
  120. package/dist/i18n/index.d.ts +12 -0
  121. package/dist/images/design/asset_empty.png +0 -0
  122. package/dist/images/design/design/background.svg +3 -0
  123. package/dist/images/design/design/color-picker.svg +15 -0
  124. package/dist/images/design/design/computer.svg +1 -0
  125. package/dist/images/design/design/copy.svg +1 -0
  126. package/dist/images/design/design/image.svg +10 -0
  127. package/dist/images/design/design/line.svg +1 -0
  128. package/dist/images/design/design/text.svg +1 -0
  129. package/dist/images/design/design/title.svg +1 -0
  130. package/dist/images/design/empty.png +0 -0
  131. package/dist/images/design/layer_empty.png +0 -0
  132. package/dist/images/design/menu/ai.svg +1 -0
  133. package/dist/images/design/menu/back.svg +4 -0
  134. package/dist/images/design/menu/background.svg +6 -0
  135. package/dist/images/design/menu/clipart.svg +6 -0
  136. package/dist/images/design/menu/file.svg +4 -0
  137. package/dist/images/design/menu/fill.svg +1 -0
  138. package/dist/images/design/menu/image.svg +7 -0
  139. package/dist/images/design/menu/layer.svg +6 -0
  140. package/dist/images/design/menu/product.svg +3 -0
  141. package/dist/images/design/menu/sca.svg +5 -0
  142. package/dist/images/design/menu/shapes.svg +5 -0
  143. package/dist/images/design/menu/templates.svg +6 -0
  144. package/dist/images/design/menu/text.svg +6 -0
  145. package/dist/images/design/menu/uploads.svg +7 -0
  146. package/dist/images/design/spinner.svg +3 -0
  147. package/dist/images/design/spinners.svg +17 -0
  148. package/dist/images/design/transparent_pattern.svg +5 -0
  149. package/dist/index.d.ts +39 -0
  150. package/dist/index.js +127 -0
  151. package/dist/lib/analytics.d.ts +17 -0
  152. package/dist/lib/cn.d.ts +3 -0
  153. package/dist/lib/common.d.ts +16 -0
  154. package/dist/lib/config.d.ts +14 -0
  155. package/dist/lib/navigation.d.ts +2 -0
  156. package/dist/renderer/ThreeDPreview.d.ts +14 -0
  157. package/dist/renderer/sticker.js +1731 -0
  158. package/dist/renderer/three-d-preview.js +32 -0
  159. package/dist/state/designer-store.d.ts +43 -0
  160. package/dist/state/designer-store.js +85 -0
  161. package/dist/style.css +1 -0
  162. package/dist/types.d.ts +184 -0
  163. package/dist/ui/accordion.d.ts +7 -0
  164. package/dist/ui/button-group.d.ts +11 -0
  165. package/dist/ui/button.d.ts +10 -0
  166. package/dist/ui/checkbox.d.ts +4 -0
  167. package/dist/ui/command.d.ts +18 -0
  168. package/dist/ui/confirm-dialog.d.ts +15 -0
  169. package/dist/ui/context-menu.d.ts +25 -0
  170. package/dist/ui/dialog.d.ts +15 -0
  171. package/dist/ui/drawer.d.ts +15 -0
  172. package/dist/ui/editable-combobox.d.ts +10 -0
  173. package/dist/ui/hint.d.ts +8 -0
  174. package/dist/ui/image.d.ts +24 -0
  175. package/dist/ui/input-group.d.ts +16 -0
  176. package/dist/ui/input-with-addon.d.ts +17 -0
  177. package/dist/ui/input.d.ts +3 -0
  178. package/dist/ui/label.d.ts +4 -0
  179. package/dist/ui/loading-button.d.ts +15 -0
  180. package/dist/ui/popover.d.ts +9 -0
  181. package/dist/ui/scroll-area.d.ts +5 -0
  182. package/dist/ui/select.d.ts +22 -0
  183. package/dist/ui/separator.d.ts +4 -0
  184. package/dist/ui/shared-loading-button.d.ts +20 -0
  185. package/dist/ui/simple-dialog.d.ts +19 -0
  186. package/dist/ui/simple-popover.d.ts +13 -0
  187. package/dist/ui/simple-select.d.ts +20 -0
  188. package/dist/ui/skeleton.d.ts +2 -0
  189. package/dist/ui/slider.d.ts +4 -0
  190. package/dist/ui/spinner-box.d.ts +12 -0
  191. package/dist/ui/spinner.d.ts +2 -0
  192. package/dist/ui/switch.d.ts +6 -0
  193. package/dist/ui/tab/index.d.ts +15 -0
  194. package/dist/ui/textarea.d.ts +3 -0
  195. package/dist/ui/tooltip.d.ts +7 -0
  196. package/dist/workers/image-resize.worker.d.ts +1 -0
  197. package/dist/workers/mockup.worker.d.ts +5 -0
  198. package/dist/workers/render.worker.d.ts +1 -0
  199. package/package.json +201 -0
@@ -0,0 +1,473 @@
1
+ import "../fabric.js";
2
+ import { getImageControls as F } from "../utils/setting.js";
3
+ import { loadImage as b, loadSvgImage as $ } from "../utils/image.js";
4
+ import { isSvg as D } from "../utils/measure.js";
5
+ import { HistoryManager as O } from "../history.js";
6
+ import { fabric as C } from "fabric";
7
+ class tt {
8
+ constructor(t) {
9
+ this.cropRect = null, this.overlay = null, this.editor = t;
10
+ }
11
+ /**
12
+ * 给图片添加 svg 形状图片蒙层
13
+ */
14
+ async addShapeImage(t, e, o = {}) {
15
+ const { width: g, height: i } = e.getBoundingRect(), n = Math.max(g, i), s = Math.min(t.width, t.height), a = s < n ? 1 : n / s, r = e.getCenterPoint(), h = r.x - t.width * a / 2, d = r.y - t.height * a / 2, l = this.editor.createLoading({
16
+ left: h,
17
+ top: d,
18
+ width: t.width,
19
+ height: t.height,
20
+ scaleX: a,
21
+ scaleY: a
22
+ });
23
+ try {
24
+ l.addLoadingGroup();
25
+ const c = t.file && !o.fullSizeSrc ? URL.createObjectURL(t.file) : "", m = await b(c || t.uri);
26
+ e.set({
27
+ absolutePositioned: !0
28
+ }), l.removeLoadingGroup(), m.set({
29
+ name: t.name,
30
+ scaleX: a,
31
+ scaleY: a,
32
+ originSrc: t.uri,
33
+ strokeWidth: 0,
34
+ left: h,
35
+ top: d,
36
+ clipPath: e,
37
+ ...o
38
+ }), this.editor.addObject(m), this.editor.canvas.requestRenderAll();
39
+ } catch {
40
+ l.removeLoadingGroup();
41
+ }
42
+ }
43
+ /**
44
+ * 添加图片(本地图片)
45
+ */
46
+ async addImage(t, e = {}) {
47
+ const o = this.editor.workspaceManager.printAreaSize, { center: g } = this.editor.workspaceManager.dimension, i = this.editor.workspaceManager.scale, n = o.width / t.width, s = o.height / t.height;
48
+ let a = Math.min(n, s);
49
+ t.width * 2 <= o.width && t.height * 2 <= o.height && (a = Math.min(a * 2, 2));
50
+ const r = a * i, h = g.x - t.width * r / 2, d = g.y - t.height * r / 2, l = this.editor.createLoading({
51
+ left: h,
52
+ top: d,
53
+ width: t.width,
54
+ height: t.height,
55
+ scaleX: r,
56
+ scaleY: r
57
+ });
58
+ try {
59
+ l.addLoadingGroup();
60
+ const c = t.file && !e.fullSizeSrc ? URL.createObjectURL(t.file) : "", m = await b(c || t.uri);
61
+ l.removeLoadingGroup(), m.set({
62
+ name: t.name,
63
+ scaleX: r,
64
+ scaleY: r,
65
+ originSrc: t.uri,
66
+ strokeWidth: 0,
67
+ left: h,
68
+ top: d,
69
+ ...e
70
+ }), this.editor.registerImageCache(t.uri, m, c || void 0), this.editor.addObject(m);
71
+ } catch {
72
+ l.removeLoadingGroup();
73
+ }
74
+ }
75
+ /** 添加图片(远程图片),自动区分位图和 SVG */
76
+ async addImageFromUrl(t, e = {}) {
77
+ D(t) ? await this.addSvgImage(t, e) : await this.addBitmapImage(t, e);
78
+ }
79
+ /**
80
+ * 添加图片(远程图片),只支持位图
81
+ */
82
+ async addBitmapImage(t, e = {}) {
83
+ const { center: o } = this.editor.workspaceManager.dimension, g = this.editor.workspaceManager.scale, i = this.editor.workspaceManager.printAreaSize, n = this.editor.createLoading({
84
+ left: o.x - 30,
85
+ top: o.y - 30,
86
+ width: 60,
87
+ height: 60,
88
+ scaleX: 1,
89
+ scaleY: 1
90
+ });
91
+ try {
92
+ n.addLoadingGroup();
93
+ const s = await b(t), { width: a = 0, height: r = 0 } = s, h = i.width / a, d = i.height / r;
94
+ let l = Math.min(h, d);
95
+ a * 2 <= i.width && r * 2 <= i.height && (l = Math.min(l * 2, 2));
96
+ const c = l * g, m = o.x - a * c / 2, w = o.y - r * c / 2;
97
+ n.removeLoadingGroup(), s.set({
98
+ scaleX: c,
99
+ scaleY: c,
100
+ originSrc: t,
101
+ strokeWidth: 0,
102
+ left: m,
103
+ top: w,
104
+ ...e
105
+ }), this.editor.registerImageCache(t, s), this.editor.addObject(s);
106
+ } catch {
107
+ n.removeLoadingGroup();
108
+ }
109
+ }
110
+ /**
111
+ * 从模板中添加图片
112
+ */
113
+ async addImageFromTemplate(t, e) {
114
+ const o = e.left + t.position.left * e.s, g = e.top + t.position.top * e.s, i = t.position.width * e.s, n = t.position.height * e.s, s = this.editor.createLoading({
115
+ left: o,
116
+ top: g,
117
+ width: t.image.width,
118
+ height: t.image.height,
119
+ scaleX: i / t.image.width,
120
+ scaleY: n / t.image.height
121
+ });
122
+ try {
123
+ s.addLoadingGroup();
124
+ const a = t.type === "image" ? await b(t.image.url) : await $(t.image.url), r = i / (a.width || 1), h = n / (a.height || 1);
125
+ let d;
126
+ return t.image.mask && (d = await new Promise((l) => {
127
+ C.util.enlivenObjects(
128
+ [t.image.mask],
129
+ ([c]) => {
130
+ c.set({ originX: "left", originY: "top" }), c.absolutePositioned ? c.set({
131
+ left: e.left + (c.left || 0) * e.s,
132
+ top: e.top + (c.top || 0) * e.s,
133
+ scaleX: (c.scaleX || 1) * e.s,
134
+ scaleY: (c.scaleY || 1) * e.s,
135
+ evented: !1,
136
+ selectable: !1
137
+ }) : c.set({
138
+ evented: !1,
139
+ selectable: !1
140
+ }), c.setCoords(), l(c);
141
+ },
142
+ ""
143
+ );
144
+ })), s.removeLoadingGroup(), a instanceof C.Image ? (a.set({
145
+ scaleX: r,
146
+ scaleY: h,
147
+ originSrc: t.image.url,
148
+ strokeWidth: 0,
149
+ left: o,
150
+ top: g,
151
+ angle: t.position.rotation || 0,
152
+ flipX: t.image?.flipX || !1,
153
+ flipY: t.image?.flipY || !1,
154
+ clipPath: d
155
+ }), this.editor.registerImageCache(t.image.url, a)) : a.set({
156
+ scaleX: r,
157
+ scaleY: h,
158
+ originSrc: t.image.url,
159
+ left: o,
160
+ top: g,
161
+ angle: t.position.rotation || 0,
162
+ flipX: t.image?.flipX || !1,
163
+ flipY: t.image?.flipY || !1,
164
+ fill: t.image?.fill
165
+ }), this.editor.addObject(a, !1), this.editor.canvas.moveTo(a, e.zIndex), a;
166
+ } catch {
167
+ return s.removeLoadingGroup(), null;
168
+ }
169
+ }
170
+ /**
171
+ * 添加 svg 图片
172
+ */
173
+ async addSvgImage(t, e = {}) {
174
+ const { width: o, height: g, center: i } = this.editor.workspaceManager.dimension, n = this.editor.createLoading({
175
+ left: i.x - 30,
176
+ top: i.y - 30,
177
+ width: 60,
178
+ height: 60,
179
+ scaleX: 1,
180
+ scaleY: 1
181
+ });
182
+ try {
183
+ n.addLoadingGroup();
184
+ const s = await $(t), a = Math.min(o, g), r = Math.max(s.width, s.height), h = r >= a ? a / r : s.scaleX ?? 1, d = i.x - s.width * h / 2, l = i.y - s.height * h / 2;
185
+ s.set({
186
+ originSrc: t,
187
+ scaleX: h,
188
+ scaleY: h,
189
+ left: d,
190
+ top: l,
191
+ sourceType: "svg",
192
+ ...e
193
+ }), n.removeLoadingGroup(), this.editor.addObject(s);
194
+ } catch {
195
+ n.removeLoadingGroup();
196
+ }
197
+ }
198
+ /**
199
+ * 替换图片对象
200
+ */
201
+ async replaceImage(t, e, o = {}) {
202
+ t.visible = !1, this.editor.canvas.requestRenderAll();
203
+ const g = this.editor.createLoading({
204
+ left: t.left ?? 0,
205
+ top: t.top ?? 0,
206
+ width: e.width,
207
+ height: e.height,
208
+ scaleX: t.scaleX ?? 1,
209
+ scaleY: t.scaleY ?? 1
210
+ });
211
+ try {
212
+ g.addLoadingGroup();
213
+ const i = e.file ? URL.createObjectURL(e.file) : "", n = await b(i || e.uri);
214
+ t.setSrc(e.uri, () => {
215
+ g.removeLoadingGroup(), t.set({
216
+ name: n.name,
217
+ originSrc: e.uri,
218
+ visible: !0,
219
+ ...o
220
+ }), this.editor.registerImageCache(e.uri, n, i || void 0), this.editor.canvas.renderAll(), this.editor.canvas.fire("object:modified", {
221
+ target: t
222
+ });
223
+ });
224
+ } catch {
225
+ g.removeLoadingGroup();
226
+ }
227
+ }
228
+ /**
229
+ * 修改图片对象配置
230
+ */
231
+ updateImageConfig(t) {
232
+ const e = this.editor.activeObject;
233
+ e && (e.set(t), this.editor.canvas.requestRenderAll(), this.editor.canvas.fire("object:modified", { target: e }));
234
+ }
235
+ /**
236
+ * 修改 svg 对象填充色
237
+ */
238
+ updateSvgColor(t) {
239
+ const e = this.editor.activeObject;
240
+ e && (e.stroke ? e.set({
241
+ stroke: t
242
+ }) : e.fill && e.set({
243
+ fill: t
244
+ }), e.type === "group" && e._objects.forEach((o) => {
245
+ o.stroke ? o.set({
246
+ stroke: t
247
+ }) : o.fill && o.set({
248
+ fill: t
249
+ });
250
+ }), this.editor.canvas.requestRenderAll(), this.editor.canvas.fire("object:modified", { target: e }));
251
+ }
252
+ /**
253
+ * 图片在可编辑区域内的适配
254
+ */
255
+ fitToEditableArea(t) {
256
+ const e = this.editor.activeObject, { width: o, height: g, center: i } = this.editor.workspaceManager.dimension;
257
+ if (!e || !o || !g || !i) return;
258
+ const n = e.width || 0, s = e.height || 0;
259
+ if (!n || !s) return;
260
+ const a = C.util.degreesToRadians(e.angle || 0), r = Math.abs(Math.cos(a)), h = Math.abs(Math.sin(a)), d = n * r + s * h, l = n * h + s * r;
261
+ if (!d || !l) return;
262
+ const c = Math.min(o / d, g / l), m = Math.max(o / d, g / l), w = e.scaleX || 1, p = e.scaleY || 1, f = w >= 0 ? 1 : -1, X = p >= 0 ? 1 : -1;
263
+ let u = w;
264
+ t === "fit" ? u = c : t === "fill" && (u = m), e.set({
265
+ scaleX: u * f,
266
+ scaleY: u * X
267
+ }), e.setPositionByOrigin(new C.Point(i.x, i.y), "center", "center"), e.setCoords(), this.editor.canvas.requestRenderAll(), this.editor.canvas.fire("object:modified", { target: e });
268
+ }
269
+ /**
270
+ * 图片镜像
271
+ */
272
+ flip(t) {
273
+ const e = this.editor.canvas.getActiveObject();
274
+ e && (t === "horizontal" ? e.set({
275
+ scaleX: e.scaleX * -1
276
+ }) : e.set({
277
+ scaleY: e.scaleY * -1
278
+ }), this.editor.canvas.requestRenderAll(), this.editor.canvas.fire("object:modified", { target: e }));
279
+ }
280
+ /**
281
+ * 图片复制
282
+ */
283
+ copy() {
284
+ const t = this.editor.canvas.getActiveObjects();
285
+ if (t.length === 0) return;
286
+ this.editor.canvas.discardActiveObject();
287
+ const e = t.map((o) => new Promise((g) => {
288
+ o.clone((i) => {
289
+ g(i);
290
+ }, O.DEFAULT_SAVE_PROPERTIES);
291
+ }));
292
+ Promise.all(e).then((o) => {
293
+ o.forEach((g) => {
294
+ this.editor.addObject(g);
295
+ });
296
+ });
297
+ }
298
+ /**
299
+ * 监听裁剪框的 scaling、moving、deselected 事件
300
+ */
301
+ _startCropListener(t) {
302
+ const e = (i, n) => {
303
+ const s = i.width * Math.abs(i.scaleX), a = i.height * Math.abs(i.scaleY), r = s / 2, h = a / 2, d = i.getCenterPoint(), l = d.x, c = d.y, w = (n.angle || 0) * Math.PI / 180, p = Math.cos(-w), f = Math.sin(-w), X = l - n.centerX, u = c - n.centerY, Y = X * p - u * f, y = X * f + u * p, M = n.originalWidth / 2, x = n.originalHeight / 2, R = Y - r, P = Y + r, v = y - h, S = y + h;
304
+ return R >= -M && P <= M && v >= -x && S <= x;
305
+ }, o = () => {
306
+ const i = this.cropRect, n = 20;
307
+ let s = i.width * Math.abs(i.scaleX), a = i.height * Math.abs(i.scaleY);
308
+ s < n && (i.set({ scaleX: n / i.width * (i.scaleX > 0 ? 1 : -1) }), s = n), a < n && (i.set({ scaleY: n / i.height * (i.scaleY > 0 ? 1 : -1) }), a = n);
309
+ const r = t.originalWidth, h = t.originalHeight;
310
+ if (s > r && (i.set({ scaleX: r / i.width * (i.scaleX > 0 ? 1 : -1) }), s = r), a > h && (i.set({ scaleY: h / i.height * (i.scaleY > 0 ? 1 : -1) }), a = h), !e(i, t)) {
311
+ s = i.width * Math.abs(i.scaleX), a = i.height * Math.abs(i.scaleY);
312
+ const d = s / 2, l = a / 2, c = i.getCenterPoint(), m = c.x, w = c.y, f = (t.angle || 0) * Math.PI / 180, X = Math.cos(-f), u = Math.sin(-f), Y = m - t.centerX, y = w - t.centerY, M = Y * X - y * u, x = Y * u + y * X, R = r / 2, P = h / 2, v = R - d, S = P - l, H = Math.max(-v, Math.min(v, M)), I = Math.max(-S, Math.min(S, x)), A = t.centerX + (H * Math.cos(f) - I * Math.sin(f)), k = t.centerY + (H * Math.sin(f) + I * Math.cos(f));
313
+ i.setPositionByOrigin(new C.Point(A, k), "center", "center");
314
+ }
315
+ i.setCoords(), this._updateOverlayClipPath(t);
316
+ }, g = () => {
317
+ const i = this.cropRect;
318
+ if (!e(i, t)) {
319
+ const s = (t.angle || 0) * Math.PI / 180, a = Math.cos(-s), r = Math.sin(-s), h = i.width * Math.abs(i.scaleX), d = i.height * Math.abs(i.scaleY), l = h / 2, c = d / 2, m = i.getCenterPoint(), w = m.x, p = m.y, f = w - t.centerX, X = p - t.centerY, u = f * a - X * r, Y = f * r + X * a, y = t.originalWidth / 2 - l, M = t.originalHeight / 2 - c, x = Math.max(-y, Math.min(y, u)), R = Math.max(-M, Math.min(M, Y)), P = t.centerX + (x * Math.cos(s) - R * Math.sin(s)), v = t.centerY + (x * Math.sin(s) + R * Math.cos(s));
320
+ i.setPositionByOrigin(new C.Point(P, v), "center", "center"), i.setCoords();
321
+ }
322
+ this._updateOverlayClipPath(t);
323
+ };
324
+ this.cropRect.on("scaling", o), this.cropRect.on("moving", g), this.cropRect.on("deselected", () => this.editor.events.emit("design:hideCrop"));
325
+ }
326
+ /**
327
+ * 清除裁剪框
328
+ */
329
+ clearCropRect(t) {
330
+ this.cropRect && (this.editor.canvas.remove(this.cropRect), this.editor.canvas.remove(this.overlay), this.cropRect = null, this.overlay = null, this.editor.canvas.requestRenderAll(), t.set({ selectable: !0, evented: !0 }));
331
+ }
332
+ /**
333
+ * 显示裁剪框
334
+ */
335
+ async showCropRect() {
336
+ const t = this.editor.activeObject;
337
+ if (!t) return;
338
+ t.set({ selectable: !1, evented: !1 });
339
+ const e = F(), o = t.angle || 0, g = o * Math.PI / 180, i = t.width * Math.abs(t.scaleX), n = t.height * Math.abs(t.scaleY), s = t.getCenterPoint(), a = s.x, r = s.y, h = Math.cos(g), d = Math.sin(g), l = i / 2, c = n / 2, m = [
340
+ { x: -l, y: -c },
341
+ { x: l, y: -c },
342
+ { x: l, y: c },
343
+ { x: -l, y: c }
344
+ ].map((M) => ({
345
+ x: a + M.x * h - M.y * d,
346
+ y: r + M.x * d + M.y * h
347
+ })), w = m.map((M) => M.x), p = m.map((M) => M.y), f = Math.min(...w), X = Math.min(...p), u = Math.max(...w), Y = Math.max(...p), y = {
348
+ scaleX: t.scaleX,
349
+ scaleY: t.scaleY,
350
+ left: f,
351
+ top: X,
352
+ right: u,
353
+ bottom: Y,
354
+ width: u - f,
355
+ height: Y - X,
356
+ angle: o,
357
+ // 保存原始图片信息(用于计算)
358
+ centerX: a,
359
+ centerY: r,
360
+ originalWidth: i,
361
+ originalHeight: n
362
+ };
363
+ this.cropRect = new C.Rect({
364
+ angle: t.angle,
365
+ id: "cropRect",
366
+ left: t.left,
367
+ top: t.top,
368
+ width: t.width,
369
+ height: t.height,
370
+ scaleX: t.scaleX,
371
+ scaleY: t.scaleY,
372
+ fill: "transparent",
373
+ strokeWidth: 0,
374
+ excludeHistory: !0,
375
+ lockRotation: !0,
376
+ controls: e,
377
+ originX: "left",
378
+ originY: "top"
379
+ }), this.overlay = new C.Rect({
380
+ id: "cropOverlay",
381
+ left: y.left,
382
+ top: y.top,
383
+ width: y.width,
384
+ height: y.height,
385
+ strokeWidth: 0,
386
+ fill: "#fff",
387
+ opacity: 0.8,
388
+ selectable: !1,
389
+ evented: !1,
390
+ excludeHistory: !0,
391
+ originX: "left",
392
+ originY: "top"
393
+ }), this._startCropListener(y), this._updateOverlayClipPath(y), this.editor.canvas.add(this.overlay), this.editor.canvas.add(this.cropRect), this.editor.canvas.bringToFront(this.overlay), this.editor.canvas.bringToFront(this.cropRect), this.editor.canvas.setActiveObject(this.cropRect), this.editor.canvas.requestRenderAll();
394
+ }
395
+ /** 对图片进行裁剪 */
396
+ async onCrop(t) {
397
+ if (!this.cropRect) return;
398
+ const e = this.cropRect, o = t.getElement(), g = t.width * Math.abs(t.scaleX), i = t.height * Math.abs(t.scaleY), n = t.angle || 0, s = n * Math.PI / 180, a = t.getCenterPoint(), r = a.x, h = a.y, d = e.width * Math.abs(e.scaleX), l = e.height * Math.abs(e.scaleY), c = e.getCenterPoint(), m = c.x, w = c.y;
399
+ try {
400
+ let p, f;
401
+ o && o.naturalWidth ? (p = o.naturalWidth, f = o.naturalHeight) : o && o.width ? (p = o.width, f = o.height) : (p = t.width, f = t.height);
402
+ const X = g / p, u = i / f, Y = m - r, y = w - h, M = Math.cos(-s), x = Math.sin(-s), R = Y * M - y * x, P = Y * x + y * M, v = {
403
+ x: p / 2,
404
+ y: f / 2
405
+ }, S = {
406
+ x: v.x + R / X,
407
+ y: v.y + P / u
408
+ }, H = d / X, I = l / u, A = S.x - H / 2, k = S.y - I / 2, E = t.getSrc ? t.getSrc() : t.getElement() ? t.getElement().src : t.originSrc || "", U = await b(E), W = document.createElement("canvas");
409
+ W.width = Math.round(H), W.height = Math.round(I), W.getContext("2d").drawImage(
410
+ U.getElement(),
411
+ Math.round(A),
412
+ Math.round(k),
413
+ Math.round(H),
414
+ Math.round(I),
415
+ 0,
416
+ 0,
417
+ Math.round(H),
418
+ Math.round(I)
419
+ );
420
+ const _ = await new Promise((z, q) => {
421
+ W.toBlob((T) => T ? z(T) : q(new Error("toBlob failed")), "image/png", 1);
422
+ }), G = URL.createObjectURL(_), L = await b(G);
423
+ L.set({
424
+ scaleX: t.scaleX,
425
+ scaleY: t.scaleY,
426
+ angle: n,
427
+ name: t.name,
428
+ id: t.id,
429
+ originX: "left",
430
+ originY: "top"
431
+ }), this.editor.registerImageCache(G, L, G), L.cropBlob = _, L.isCropped = !0, L.setPositionByOrigin(new C.Point(m, w), "center", "center"), this.editor.canvas.remove(t), this.editor.canvas.add(L), this.editor.canvas.setActiveObject(L), this.editor.canvas.requestRenderAll(), this.editor.canvas.fire("object:added", { target: L });
432
+ } catch (p) {
433
+ console.error("裁剪过程发生错误:", p);
434
+ }
435
+ }
436
+ _calcOuterClipPath(t) {
437
+ const e = this.cropRect, o = e.width * Math.abs(e.scaleX), g = e.height * Math.abs(e.scaleY), n = (e.angle || 0) * Math.PI / 180, s = e.getCenterPoint(), a = s.x, r = s.y, h = o / 2, d = g / 2, l = Math.cos(n), c = Math.sin(n), m = [
438
+ { x: -h, y: -d },
439
+ { x: -h, y: d },
440
+ { x: h, y: d },
441
+ { x: h, y: -d }
442
+ ].map((p) => ({
443
+ x: a + p.x * l - p.y * c,
444
+ y: r + p.x * c + p.y * l
445
+ }));
446
+ return [
447
+ `M ${t.left} ${t.top}`,
448
+ `L ${t.right} ${t.top}`,
449
+ `L ${t.right} ${t.bottom}`,
450
+ `L ${t.left} ${t.bottom}`,
451
+ "Z",
452
+ `M ${m[0].x} ${m[0].y}`,
453
+ `L ${m[1].x} ${m[1].y}`,
454
+ `L ${m[2].x} ${m[2].y}`,
455
+ `L ${m[3].x} ${m[3].y}`,
456
+ "Z"
457
+ ].join(" ");
458
+ }
459
+ _updateOverlayClipPath(t) {
460
+ if (!this.cropRect || !this.overlay) return;
461
+ const e = this._calcOuterClipPath(t), o = new C.Path(e);
462
+ o.set({
463
+ fill: "white",
464
+ absolutePositioned: !0
465
+ }), this.overlay.set({
466
+ clipPath: o
467
+ }), this.editor.canvas.requestRenderAll();
468
+ }
469
+ }
470
+ export {
471
+ tt as ImageProcessor,
472
+ tt as default
473
+ };
@@ -0,0 +1,45 @@
1
+ import fabric from '../fabric';
2
+ import '../../fabric-types';
3
+ import type { RenderableBox } from '../types';
4
+ import type { TemplateBaseInfo, TemplateData } from '../../contracts/api-design';
5
+ import type { Editor } from '../editor';
6
+ /**
7
+ * 模板处理
8
+ *
9
+ * Produces and consumes the same template payload the existing Printine
10
+ * `user-templates` and `template-categories` endpoints already exchange.
11
+ */
12
+ export declare class TemplateProcessor {
13
+ private editor;
14
+ constructor(editor: Editor);
15
+ /**
16
+ * 获取当前选中的对象,将其组合转为临时模板
17
+ */
18
+ saveAsTemplate(): Promise<TemplateData | null>;
19
+ /**
20
+ * 计算选中对象的总边界框
21
+ */
22
+ _getSelectionBoundingBox(objects: fabric.Object[]): RenderableBox | null;
23
+ /**
24
+ * 计算对象相对于边界框的位置
25
+ */
26
+ _calculateRelativePosition(obj: fabric.Object, boundingBox: RenderableBox): {
27
+ left: number;
28
+ top: number;
29
+ };
30
+ /**
31
+ * 生成预览图片
32
+ */
33
+ _generatePreviewImage(objects: fabric.Object[], boundingBox: RenderableBox): Promise<string | null>;
34
+ /**
35
+ * 将带裁剪的图片对象栅格化为裁剪后的位图
36
+ * 离屏画布尺寸按裁剪外接框(非整图),避免透明区域“占位置”
37
+ * 返回的数据中的 left/top 为模板局部坐标(相对 boundingBox 左上角)
38
+ */
39
+ private _rasterizeClippedImage;
40
+ /**
41
+ * 将模板添加到画布中
42
+ */
43
+ addTemplate(template: TemplateBaseInfo): Promise<void>;
44
+ }
45
+ export default TemplateProcessor;