@pooder/kit 6.0.0 → 6.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/.test-dist/src/extensions/background/BackgroundTool.js +524 -0
- package/.test-dist/src/extensions/background/index.js +17 -0
- package/.test-dist/src/extensions/background.js +1 -1
- package/.test-dist/src/extensions/dieline/DielineTool.js +748 -0
- package/.test-dist/src/extensions/dieline/commands.js +127 -0
- package/.test-dist/src/extensions/dieline/config.js +107 -0
- package/.test-dist/src/extensions/dieline/index.js +21 -0
- package/.test-dist/src/extensions/dieline/model.js +2 -0
- package/.test-dist/src/extensions/dieline/renderer.js +2 -0
- package/.test-dist/src/extensions/dieline.js +4 -0
- package/.test-dist/src/extensions/feature/FeatureTool.js +914 -0
- package/.test-dist/src/extensions/feature/index.js +17 -0
- package/.test-dist/src/extensions/film/FilmTool.js +207 -0
- package/.test-dist/src/extensions/film/index.js +17 -0
- package/.test-dist/src/extensions/image/ImageTool.js +1499 -0
- package/.test-dist/src/extensions/image/commands.js +162 -0
- package/.test-dist/src/extensions/image/config.js +129 -0
- package/.test-dist/src/extensions/image/index.js +21 -0
- package/.test-dist/src/extensions/image/model.js +2 -0
- package/.test-dist/src/extensions/image/renderer.js +5 -0
- package/.test-dist/src/extensions/image.js +182 -7
- package/.test-dist/src/extensions/mirror/MirrorTool.js +104 -0
- package/.test-dist/src/extensions/mirror/index.js +17 -0
- package/.test-dist/src/extensions/ruler/RulerTool.js +442 -0
- package/.test-dist/src/extensions/ruler/index.js +17 -0
- package/.test-dist/src/extensions/sceneLayout.js +2 -93
- package/.test-dist/src/extensions/sceneLayoutModel.js +15 -200
- package/.test-dist/src/extensions/size/SizeTool.js +332 -0
- package/.test-dist/src/extensions/size/index.js +17 -0
- package/.test-dist/src/extensions/white-ink/WhiteInkTool.js +1003 -0
- package/.test-dist/src/extensions/white-ink/commands.js +148 -0
- package/.test-dist/src/extensions/white-ink/config.js +31 -0
- package/.test-dist/src/extensions/white-ink/index.js +21 -0
- package/.test-dist/src/extensions/white-ink/model.js +2 -0
- package/.test-dist/src/extensions/white-ink/renderer.js +5 -0
- package/.test-dist/src/services/CanvasService.js +34 -13
- package/.test-dist/src/services/SceneLayoutService.js +96 -0
- package/.test-dist/src/services/index.js +1 -0
- package/.test-dist/src/services/visibility.js +3 -0
- package/.test-dist/src/shared/constants/layers.js +25 -0
- package/.test-dist/src/shared/imaging/sourceSizeCache.js +82 -0
- package/.test-dist/src/shared/index.js +22 -0
- package/.test-dist/src/shared/runtime/sessionState.js +74 -0
- package/.test-dist/src/shared/runtime/subscriptions.js +30 -0
- package/.test-dist/src/shared/scene/frame.js +34 -0
- package/.test-dist/src/shared/scene/sceneLayoutModel.js +202 -0
- package/.test-dist/tests/run.js +118 -0
- package/CHANGELOG.md +12 -0
- package/dist/index.d.mts +403 -366
- package/dist/index.d.ts +403 -366
- package/dist/index.js +5172 -4752
- package/dist/index.mjs +1410 -2027
- package/dist/tracer-PO7CRBYY.mjs +1016 -0
- package/package.json +1 -1
- package/src/extensions/{background.ts → background/BackgroundTool.ts} +33 -50
- package/src/extensions/background/index.ts +1 -0
- package/src/extensions/{dieline.ts → dieline/DielineTool.ts} +18 -218
- package/src/extensions/dieline/commands.ts +109 -0
- package/src/extensions/dieline/config.ts +106 -0
- package/src/extensions/dieline/index.ts +5 -0
- package/src/extensions/dieline/model.ts +1 -0
- package/src/extensions/dieline/renderer.ts +1 -0
- package/src/extensions/{feature.ts → feature/FeatureTool.ts} +27 -21
- package/src/extensions/feature/index.ts +1 -0
- package/src/extensions/{film.ts → film/FilmTool.ts} +36 -48
- package/src/extensions/film/index.ts +1 -0
- package/src/extensions/{image.ts → image/ImageTool.ts} +289 -335
- package/src/extensions/image/commands.ts +176 -0
- package/src/extensions/image/config.ts +128 -0
- package/src/extensions/image/index.ts +5 -0
- package/src/extensions/image/model.ts +1 -0
- package/src/extensions/image/renderer.ts +1 -0
- package/src/extensions/{mirror.ts → mirror/MirrorTool.ts} +1 -1
- package/src/extensions/mirror/index.ts +1 -0
- package/src/extensions/{ruler.ts → ruler/RulerTool.ts} +4 -5
- package/src/extensions/ruler/index.ts +1 -0
- package/src/extensions/sceneLayout.ts +1 -140
- package/src/extensions/sceneLayoutModel.ts +1 -364
- package/src/extensions/{size.ts → size/SizeTool.ts} +7 -6
- package/src/extensions/size/index.ts +1 -0
- package/src/extensions/{white-ink.ts → white-ink/WhiteInkTool.ts} +130 -317
- package/src/extensions/white-ink/commands.ts +157 -0
- package/src/extensions/white-ink/config.ts +30 -0
- package/src/extensions/white-ink/index.ts +5 -0
- package/src/extensions/white-ink/model.ts +1 -0
- package/src/extensions/white-ink/renderer.ts +1 -0
- package/src/services/CanvasService.ts +43 -12
- package/src/services/SceneLayoutService.ts +139 -0
- package/src/services/index.ts +1 -0
- package/src/services/renderSpec.ts +2 -0
- package/src/services/visibility.ts +5 -0
- package/src/shared/constants/layers.ts +23 -0
- package/src/shared/imaging/sourceSizeCache.ts +103 -0
- package/src/shared/index.ts +6 -0
- package/src/shared/runtime/sessionState.ts +105 -0
- package/src/shared/runtime/subscriptions.ts +45 -0
- package/src/shared/scene/frame.ts +46 -0
- package/src/shared/scene/sceneLayoutModel.ts +367 -0
- package/tests/run.ts +151 -0
package/package.json
CHANGED
|
@@ -7,17 +7,18 @@ import {
|
|
|
7
7
|
ConfigurationService,
|
|
8
8
|
} from "@pooder/core";
|
|
9
9
|
import { FabricImage } from "fabric";
|
|
10
|
-
import { CanvasService, RenderObjectSpec } from "
|
|
10
|
+
import { CanvasService, RenderObjectSpec } from "../../services";
|
|
11
11
|
import {
|
|
12
12
|
computeSceneLayout,
|
|
13
13
|
readSizeState,
|
|
14
14
|
type SceneLayoutSnapshot,
|
|
15
|
-
} from "
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
15
|
+
} from "../../shared/scene/sceneLayoutModel";
|
|
16
|
+
import { BACKGROUND_LAYER_ID } from "../../shared/constants/layers";
|
|
17
|
+
import {
|
|
18
|
+
createSourceSizeCache,
|
|
19
|
+
type SourceSize,
|
|
20
|
+
} from "../../shared/imaging/sourceSizeCache";
|
|
21
|
+
import { SubscriptionBag } from "../../shared/runtime/subscriptions";
|
|
21
22
|
|
|
22
23
|
interface Rect {
|
|
23
24
|
left: number;
|
|
@@ -47,7 +48,6 @@ export interface BackgroundConfig {
|
|
|
47
48
|
layers: BackgroundLayer[];
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
const BACKGROUND_LAYER_ID = "background";
|
|
51
51
|
const BACKGROUND_CONFIG_KEY = "background.config";
|
|
52
52
|
|
|
53
53
|
const DEFAULT_WIDTH = 800;
|
|
@@ -65,7 +65,7 @@ const DEFAULT_BACKGROUND_CONFIG: BackgroundConfig = {
|
|
|
65
65
|
order: 0,
|
|
66
66
|
enabled: true,
|
|
67
67
|
exportable: false,
|
|
68
|
-
color: "#
|
|
68
|
+
color: "#eee",
|
|
69
69
|
},
|
|
70
70
|
],
|
|
71
71
|
};
|
|
@@ -245,13 +245,13 @@ export class BackgroundTool implements Extension {
|
|
|
245
245
|
|
|
246
246
|
private specs: RenderObjectSpec[] = [];
|
|
247
247
|
private renderProducerDisposable?: { dispose: () => void };
|
|
248
|
-
private
|
|
248
|
+
private readonly subscriptions = new SubscriptionBag();
|
|
249
249
|
|
|
250
250
|
private renderSeq = 0;
|
|
251
251
|
private latestSceneLayout: SceneLayoutSnapshot | null = null;
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
252
|
+
private sourceSizeCache = createSourceSizeCache((src) =>
|
|
253
|
+
this.loadImageSize(src),
|
|
254
|
+
);
|
|
255
255
|
|
|
256
256
|
private onCanvasResized = () => {
|
|
257
257
|
this.latestSceneLayout = null;
|
|
@@ -270,6 +270,7 @@ export class BackgroundTool implements Extension {
|
|
|
270
270
|
}
|
|
271
271
|
|
|
272
272
|
activate(context: ExtensionContext) {
|
|
273
|
+
this.subscriptions.disposeAll();
|
|
273
274
|
this.canvasService = context.services.get<CanvasService>("CanvasService");
|
|
274
275
|
if (!this.canvasService) {
|
|
275
276
|
console.warn("CanvasService not found for BackgroundTool");
|
|
@@ -286,8 +287,8 @@ export class BackgroundTool implements Extension {
|
|
|
286
287
|
DEFAULT_BACKGROUND_CONFIG,
|
|
287
288
|
),
|
|
288
289
|
);
|
|
289
|
-
this.
|
|
290
|
-
|
|
290
|
+
this.subscriptions.onConfigChange(
|
|
291
|
+
this.configService,
|
|
291
292
|
(e: { key: string; value: any }) => {
|
|
292
293
|
if (e.key === BACKGROUND_CONFIG_KEY) {
|
|
293
294
|
this.config = normalizeConfig(e.value);
|
|
@@ -319,21 +320,26 @@ export class BackgroundTool implements Extension {
|
|
|
319
320
|
{ priority: 0 },
|
|
320
321
|
);
|
|
321
322
|
|
|
322
|
-
|
|
323
|
-
|
|
323
|
+
this.subscriptions.on(
|
|
324
|
+
context.eventBus,
|
|
325
|
+
"canvas:resized",
|
|
326
|
+
this.onCanvasResized,
|
|
327
|
+
);
|
|
328
|
+
this.subscriptions.on(
|
|
329
|
+
context.eventBus,
|
|
330
|
+
"scene:layout:change",
|
|
331
|
+
this.onSceneLayoutChanged,
|
|
332
|
+
);
|
|
324
333
|
this.updateBackground();
|
|
325
334
|
}
|
|
326
335
|
|
|
327
336
|
deactivate(context: ExtensionContext) {
|
|
328
|
-
|
|
329
|
-
context.eventBus.off("scene:layout:change", this.onSceneLayoutChanged);
|
|
337
|
+
this.subscriptions.disposeAll();
|
|
330
338
|
|
|
331
339
|
this.renderSeq += 1;
|
|
332
340
|
this.specs = [];
|
|
333
341
|
this.latestSceneLayout = null;
|
|
334
|
-
|
|
335
|
-
this.configChangeDisposable?.dispose();
|
|
336
|
-
this.configChangeDisposable = undefined;
|
|
342
|
+
this.sourceSizeCache.clear();
|
|
337
343
|
|
|
338
344
|
this.renderProducerDisposable?.dispose();
|
|
339
345
|
this.renderProducerDisposable = undefined;
|
|
@@ -576,7 +582,7 @@ export class BackgroundTool implements Extension {
|
|
|
576
582
|
const src = String(layer.src || "").trim();
|
|
577
583
|
if (!src) return [];
|
|
578
584
|
|
|
579
|
-
const sourceSize = this.
|
|
585
|
+
const sourceSize = this.sourceSizeCache.getSourceSize(src);
|
|
580
586
|
if (!sourceSize) return [];
|
|
581
587
|
|
|
582
588
|
const rect = this.resolveAnchorRect(layer.anchor);
|
|
@@ -648,29 +654,6 @@ export class BackgroundTool implements Extension {
|
|
|
648
654
|
return Array.from(urls);
|
|
649
655
|
}
|
|
650
656
|
|
|
651
|
-
private async ensureImageSize(src: string): Promise<SourceSize | null> {
|
|
652
|
-
if (!src) return null;
|
|
653
|
-
|
|
654
|
-
const cached = this.sourceSizeBySrc.get(src);
|
|
655
|
-
if (cached) return cached;
|
|
656
|
-
|
|
657
|
-
const pending = this.pendingSizeBySrc.get(src);
|
|
658
|
-
if (pending) {
|
|
659
|
-
return pending;
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
const task = this.loadImageSize(src);
|
|
663
|
-
this.pendingSizeBySrc.set(src, task);
|
|
664
|
-
|
|
665
|
-
try {
|
|
666
|
-
return await task;
|
|
667
|
-
} finally {
|
|
668
|
-
if (this.pendingSizeBySrc.get(src) === task) {
|
|
669
|
-
this.pendingSizeBySrc.delete(src);
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
|
|
674
657
|
private async loadImageSize(src: string): Promise<SourceSize | null> {
|
|
675
658
|
try {
|
|
676
659
|
const image = await FabricImage.fromURL(src, {
|
|
@@ -679,9 +662,7 @@ export class BackgroundTool implements Extension {
|
|
|
679
662
|
const width = Number(image?.width || 0);
|
|
680
663
|
const height = Number(image?.height || 0);
|
|
681
664
|
if (width > 0 && height > 0) {
|
|
682
|
-
|
|
683
|
-
this.sourceSizeBySrc.set(src, size);
|
|
684
|
-
return size;
|
|
665
|
+
return { width, height };
|
|
685
666
|
}
|
|
686
667
|
} catch (error) {
|
|
687
668
|
console.error("[BackgroundTool] Failed to load image", src, error);
|
|
@@ -702,7 +683,9 @@ export class BackgroundTool implements Extension {
|
|
|
702
683
|
const activeUrls = this.collectActiveImageUrls(currentConfig);
|
|
703
684
|
|
|
704
685
|
if (activeUrls.length > 0) {
|
|
705
|
-
await Promise.all(
|
|
686
|
+
await Promise.all(
|
|
687
|
+
activeUrls.map((url) => this.sourceSizeCache.ensureImageSize(url)),
|
|
688
|
+
);
|
|
706
689
|
if (seq !== this.renderSeq) return;
|
|
707
690
|
}
|
|
708
691
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./BackgroundTool";
|
|
@@ -2,32 +2,34 @@ import {
|
|
|
2
2
|
Extension,
|
|
3
3
|
ExtensionContext,
|
|
4
4
|
ContributionPointIds,
|
|
5
|
-
CommandContribution,
|
|
6
|
-
ConfigurationContribution,
|
|
7
5
|
ConfigurationService,
|
|
8
6
|
} from "@pooder/core";
|
|
9
7
|
import { Canvas as FabricCanvas, Path, Pattern } from "fabric";
|
|
10
|
-
import { CanvasService, RenderEffectSpec, RenderObjectSpec } from "
|
|
11
|
-
import {
|
|
12
|
-
import { parseLengthToMm } from "../units";
|
|
8
|
+
import { CanvasService, RenderEffectSpec, RenderObjectSpec } from "../../services";
|
|
9
|
+
import { parseLengthToMm } from "../../units";
|
|
13
10
|
import {
|
|
14
11
|
DEFAULT_DIELINE_SHAPE,
|
|
15
12
|
DEFAULT_DIELINE_SHAPE_STYLE,
|
|
16
|
-
DIELINE_SHAPES,
|
|
17
13
|
normalizeShapeStyle,
|
|
18
14
|
normalizeDielineShape,
|
|
19
|
-
} from "
|
|
20
|
-
import type { DielineShape, DielineShapeStyle } from "
|
|
15
|
+
} from "../dielineShape";
|
|
16
|
+
import type { DielineShape, DielineShapeStyle } from "../dielineShape";
|
|
21
17
|
import {
|
|
22
18
|
generateDielinePath,
|
|
23
19
|
generateBleedZonePath,
|
|
24
20
|
DielineFeature,
|
|
25
|
-
} from "
|
|
21
|
+
} from "../geometry";
|
|
26
22
|
import {
|
|
27
23
|
buildSceneGeometry,
|
|
28
24
|
computeSceneLayout,
|
|
29
25
|
readSizeState,
|
|
30
|
-
} from "
|
|
26
|
+
} from "../../shared/scene/sceneLayoutModel";
|
|
27
|
+
import {
|
|
28
|
+
DIELINE_LAYER_ID,
|
|
29
|
+
IMAGE_OBJECT_LAYER_ID,
|
|
30
|
+
} from "../../shared/constants/layers";
|
|
31
|
+
import { createDielineCommands } from "./commands";
|
|
32
|
+
import { createDielineConfigurations } from "./config";
|
|
31
33
|
|
|
32
34
|
export interface DielineGeometry {
|
|
33
35
|
shape: DielineShape;
|
|
@@ -72,9 +74,6 @@ export interface DielineState {
|
|
|
72
74
|
customSourceHeightPx?: number;
|
|
73
75
|
}
|
|
74
76
|
|
|
75
|
-
const IMAGE_OBJECT_LAYER_ID = "image.user";
|
|
76
|
-
const DIELINE_LAYER_ID = "dieline-overlay";
|
|
77
|
-
|
|
78
77
|
export class DielineTool implements Extension {
|
|
79
78
|
id = "pooder.kit.dieline";
|
|
80
79
|
public metadata = {
|
|
@@ -359,7 +358,6 @@ export class DielineTool implements Extension {
|
|
|
359
358
|
}
|
|
360
359
|
|
|
361
360
|
contribute() {
|
|
362
|
-
const s = this.state;
|
|
363
361
|
return {
|
|
364
362
|
[ContributionPointIds.TOOLS]: [
|
|
365
363
|
{
|
|
@@ -372,210 +370,8 @@ export class DielineTool implements Extension {
|
|
|
372
370
|
},
|
|
373
371
|
},
|
|
374
372
|
],
|
|
375
|
-
[ContributionPointIds.CONFIGURATIONS]:
|
|
376
|
-
|
|
377
|
-
id: "dieline.shape",
|
|
378
|
-
type: "select",
|
|
379
|
-
label: "Shape",
|
|
380
|
-
options: Array.from(DIELINE_SHAPES),
|
|
381
|
-
default: s.shape,
|
|
382
|
-
},
|
|
383
|
-
{
|
|
384
|
-
id: "dieline.radius",
|
|
385
|
-
type: "number",
|
|
386
|
-
label: "Corner Radius (mm)",
|
|
387
|
-
min: 0,
|
|
388
|
-
max: 500,
|
|
389
|
-
default: s.radius,
|
|
390
|
-
},
|
|
391
|
-
{
|
|
392
|
-
id: "dieline.shapeStyle",
|
|
393
|
-
type: "json",
|
|
394
|
-
label: "Shape Style",
|
|
395
|
-
default: s.shapeStyle,
|
|
396
|
-
},
|
|
397
|
-
{
|
|
398
|
-
id: "dieline.showBleedLines",
|
|
399
|
-
type: "boolean",
|
|
400
|
-
label: "Show Bleed Lines",
|
|
401
|
-
default: s.showBleedLines,
|
|
402
|
-
},
|
|
403
|
-
{
|
|
404
|
-
id: "dieline.strokeWidth",
|
|
405
|
-
type: "number",
|
|
406
|
-
label: "Line Width",
|
|
407
|
-
min: 0.1,
|
|
408
|
-
max: 10,
|
|
409
|
-
step: 0.1,
|
|
410
|
-
default: s.mainLine.width,
|
|
411
|
-
},
|
|
412
|
-
{
|
|
413
|
-
id: "dieline.strokeColor",
|
|
414
|
-
type: "color",
|
|
415
|
-
label: "Line Color",
|
|
416
|
-
default: s.mainLine.color,
|
|
417
|
-
},
|
|
418
|
-
{
|
|
419
|
-
id: "dieline.dashLength",
|
|
420
|
-
type: "number",
|
|
421
|
-
label: "Dash Length",
|
|
422
|
-
min: 1,
|
|
423
|
-
max: 50,
|
|
424
|
-
default: s.mainLine.dashLength,
|
|
425
|
-
},
|
|
426
|
-
{
|
|
427
|
-
id: "dieline.style",
|
|
428
|
-
type: "select",
|
|
429
|
-
label: "Line Style",
|
|
430
|
-
options: ["solid", "dashed", "hidden"],
|
|
431
|
-
default: s.mainLine.style,
|
|
432
|
-
},
|
|
433
|
-
{
|
|
434
|
-
id: "dieline.offsetStrokeWidth",
|
|
435
|
-
type: "number",
|
|
436
|
-
label: "Offset Line Width",
|
|
437
|
-
min: 0.1,
|
|
438
|
-
max: 10,
|
|
439
|
-
step: 0.1,
|
|
440
|
-
default: s.offsetLine.width,
|
|
441
|
-
},
|
|
442
|
-
{
|
|
443
|
-
id: "dieline.offsetStrokeColor",
|
|
444
|
-
type: "color",
|
|
445
|
-
label: "Offset Line Color",
|
|
446
|
-
default: s.offsetLine.color,
|
|
447
|
-
},
|
|
448
|
-
{
|
|
449
|
-
id: "dieline.offsetDashLength",
|
|
450
|
-
type: "number",
|
|
451
|
-
label: "Offset Dash Length",
|
|
452
|
-
min: 1,
|
|
453
|
-
max: 50,
|
|
454
|
-
default: s.offsetLine.dashLength,
|
|
455
|
-
},
|
|
456
|
-
{
|
|
457
|
-
id: "dieline.offsetStyle",
|
|
458
|
-
type: "select",
|
|
459
|
-
label: "Offset Line Style",
|
|
460
|
-
options: ["solid", "dashed", "hidden"],
|
|
461
|
-
default: s.offsetLine.style,
|
|
462
|
-
},
|
|
463
|
-
{
|
|
464
|
-
id: "dieline.insideColor",
|
|
465
|
-
type: "color",
|
|
466
|
-
label: "Inside Color",
|
|
467
|
-
default: s.insideColor,
|
|
468
|
-
},
|
|
469
|
-
{
|
|
470
|
-
id: "dieline.features",
|
|
471
|
-
type: "json",
|
|
472
|
-
label: "Edge Features",
|
|
473
|
-
default: s.features,
|
|
474
|
-
},
|
|
475
|
-
] as ConfigurationContribution[],
|
|
476
|
-
[ContributionPointIds.COMMANDS]: [
|
|
477
|
-
{
|
|
478
|
-
command: "updateFeaturePosition",
|
|
479
|
-
title: "Update Feature Position",
|
|
480
|
-
handler: (groupId: string, x: number, y: number) => {
|
|
481
|
-
const configService = this.context?.services.get<any>(
|
|
482
|
-
"ConfigurationService",
|
|
483
|
-
);
|
|
484
|
-
if (!configService) return;
|
|
485
|
-
|
|
486
|
-
const features = configService.get("dieline.features") || [];
|
|
487
|
-
|
|
488
|
-
let changed = false;
|
|
489
|
-
const newFeatures = features.map((f: any) => {
|
|
490
|
-
if (f.groupId === groupId) {
|
|
491
|
-
if (f.x !== x || f.y !== y) {
|
|
492
|
-
changed = true;
|
|
493
|
-
return { ...f, x, y };
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
return f;
|
|
497
|
-
});
|
|
498
|
-
|
|
499
|
-
if (changed) {
|
|
500
|
-
configService.update("dieline.features", newFeatures);
|
|
501
|
-
}
|
|
502
|
-
},
|
|
503
|
-
},
|
|
504
|
-
{
|
|
505
|
-
command: "exportCutImage",
|
|
506
|
-
title: "Export Cut Image",
|
|
507
|
-
handler: (options?: { debug?: boolean }) => {
|
|
508
|
-
return this.exportCutImage(options);
|
|
509
|
-
},
|
|
510
|
-
},
|
|
511
|
-
{
|
|
512
|
-
command: "detectEdge",
|
|
513
|
-
title: "Detect Edge from Image",
|
|
514
|
-
handler: async (
|
|
515
|
-
imageUrl: string,
|
|
516
|
-
options?: {
|
|
517
|
-
expand?: number;
|
|
518
|
-
smoothing?: boolean;
|
|
519
|
-
simplifyTolerance?: number;
|
|
520
|
-
threshold?: number;
|
|
521
|
-
debug?: boolean;
|
|
522
|
-
},
|
|
523
|
-
) => {
|
|
524
|
-
try {
|
|
525
|
-
const detectOptions = options || {};
|
|
526
|
-
const debug = detectOptions.debug === true;
|
|
527
|
-
const tracerOptions = {
|
|
528
|
-
expand: detectOptions.expand ?? 0,
|
|
529
|
-
smoothing: detectOptions.smoothing ?? true,
|
|
530
|
-
simplifyTolerance: detectOptions.simplifyTolerance ?? 2,
|
|
531
|
-
threshold: detectOptions.threshold,
|
|
532
|
-
debug,
|
|
533
|
-
};
|
|
534
|
-
|
|
535
|
-
// Helper to get image dimensions
|
|
536
|
-
const loadImage = (url: string): Promise<HTMLImageElement> => {
|
|
537
|
-
return new Promise((resolve, reject) => {
|
|
538
|
-
const img = new Image();
|
|
539
|
-
img.crossOrigin = "Anonymous";
|
|
540
|
-
img.onload = () => resolve(img);
|
|
541
|
-
img.onerror = (e) => reject(e);
|
|
542
|
-
img.src = url;
|
|
543
|
-
});
|
|
544
|
-
};
|
|
545
|
-
|
|
546
|
-
const [img, traced] = await Promise.all([
|
|
547
|
-
loadImage(imageUrl),
|
|
548
|
-
ImageTracer.traceWithBounds(imageUrl, tracerOptions),
|
|
549
|
-
]);
|
|
550
|
-
const { pathData, baseBounds, bounds } = traced;
|
|
551
|
-
|
|
552
|
-
if (debug) {
|
|
553
|
-
console.info("[DielineTool] detectEdge", {
|
|
554
|
-
imageWidth: img.width,
|
|
555
|
-
imageHeight: img.height,
|
|
556
|
-
baseBounds,
|
|
557
|
-
expandedBounds: bounds,
|
|
558
|
-
currentDielineWidth: s.width,
|
|
559
|
-
currentDielineHeight: s.height,
|
|
560
|
-
options: tracerOptions,
|
|
561
|
-
strategy: "single-connected-silhouette",
|
|
562
|
-
});
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
return {
|
|
566
|
-
pathData,
|
|
567
|
-
rawBounds: bounds,
|
|
568
|
-
baseBounds,
|
|
569
|
-
imageWidth: img.width,
|
|
570
|
-
imageHeight: img.height,
|
|
571
|
-
};
|
|
572
|
-
} catch (e) {
|
|
573
|
-
console.error("Edge detection failed", e);
|
|
574
|
-
throw e;
|
|
575
|
-
}
|
|
576
|
-
},
|
|
577
|
-
},
|
|
578
|
-
] as CommandContribution[],
|
|
373
|
+
[ContributionPointIds.CONFIGURATIONS]: createDielineConfigurations(this.state),
|
|
374
|
+
[ContributionPointIds.COMMANDS]: createDielineCommands(this, this.state),
|
|
579
375
|
};
|
|
580
376
|
}
|
|
581
377
|
|
|
@@ -900,6 +696,10 @@ export class DielineTool implements Extension {
|
|
|
900
696
|
{
|
|
901
697
|
type: "clipPath",
|
|
902
698
|
id: "dieline.clip.image",
|
|
699
|
+
visibility: {
|
|
700
|
+
op: "not",
|
|
701
|
+
expr: { op: "anySessionActive" },
|
|
702
|
+
},
|
|
903
703
|
targetPassIds: [IMAGE_OBJECT_LAYER_ID],
|
|
904
704
|
source: {
|
|
905
705
|
id: "dieline.effect.clip-path",
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { CommandContribution } from "@pooder/core";
|
|
2
|
+
|
|
3
|
+
export function createDielineCommands(tool: any, state: any): CommandContribution[] {
|
|
4
|
+
return [
|
|
5
|
+
{
|
|
6
|
+
command: "updateFeaturePosition",
|
|
7
|
+
id: "updateFeaturePosition",
|
|
8
|
+
title: "Update Feature Position",
|
|
9
|
+
handler: (groupId: string, x: number, y: number) => {
|
|
10
|
+
const configService = tool.context?.services.get("ConfigurationService");
|
|
11
|
+
if (!configService) return;
|
|
12
|
+
|
|
13
|
+
const features = configService.get("dieline.features") || [];
|
|
14
|
+
|
|
15
|
+
let changed = false;
|
|
16
|
+
const newFeatures = features.map((f: any) => {
|
|
17
|
+
if (f.groupId === groupId) {
|
|
18
|
+
if (f.x !== x || f.y !== y) {
|
|
19
|
+
changed = true;
|
|
20
|
+
return { ...f, x, y };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return f;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
if (changed) {
|
|
27
|
+
configService.update("dieline.features", newFeatures);
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
command: "exportCutImage",
|
|
33
|
+
id: "exportCutImage",
|
|
34
|
+
title: "Export Cut Image",
|
|
35
|
+
handler: (options?: { debug?: boolean }) => {
|
|
36
|
+
return tool.exportCutImage(options);
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
command: "detectEdge",
|
|
41
|
+
id: "detectEdge",
|
|
42
|
+
title: "Detect Edge from Image",
|
|
43
|
+
handler: async (
|
|
44
|
+
imageUrl: string,
|
|
45
|
+
options?: {
|
|
46
|
+
expand?: number;
|
|
47
|
+
smoothing?: boolean;
|
|
48
|
+
simplifyTolerance?: number;
|
|
49
|
+
threshold?: number;
|
|
50
|
+
debug?: boolean;
|
|
51
|
+
},
|
|
52
|
+
) => {
|
|
53
|
+
try {
|
|
54
|
+
const detectOptions = options || {};
|
|
55
|
+
const debug = detectOptions.debug === true;
|
|
56
|
+
const tracerOptions = {
|
|
57
|
+
expand: detectOptions.expand ?? 0,
|
|
58
|
+
smoothing: detectOptions.smoothing ?? true,
|
|
59
|
+
simplifyTolerance: detectOptions.simplifyTolerance ?? 2,
|
|
60
|
+
threshold: detectOptions.threshold,
|
|
61
|
+
debug,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const loadImage = (url: string): Promise<HTMLImageElement> => {
|
|
65
|
+
return new Promise((resolve, reject) => {
|
|
66
|
+
const img = new Image();
|
|
67
|
+
img.crossOrigin = "Anonymous";
|
|
68
|
+
img.onload = () => resolve(img);
|
|
69
|
+
img.onerror = (e) => reject(e);
|
|
70
|
+
img.src = url;
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const [img, traced] = await Promise.all([
|
|
75
|
+
loadImage(imageUrl),
|
|
76
|
+
import("../tracer").then(({ ImageTracer }) =>
|
|
77
|
+
ImageTracer.traceWithBounds(imageUrl, tracerOptions),
|
|
78
|
+
),
|
|
79
|
+
]);
|
|
80
|
+
const { pathData, baseBounds, bounds } = traced;
|
|
81
|
+
|
|
82
|
+
if (debug) {
|
|
83
|
+
console.info("[DielineTool] detectEdge", {
|
|
84
|
+
imageWidth: img.width,
|
|
85
|
+
imageHeight: img.height,
|
|
86
|
+
baseBounds,
|
|
87
|
+
expandedBounds: bounds,
|
|
88
|
+
currentDielineWidth: state.width,
|
|
89
|
+
currentDielineHeight: state.height,
|
|
90
|
+
options: tracerOptions,
|
|
91
|
+
strategy: "single-connected-silhouette",
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
pathData,
|
|
97
|
+
rawBounds: bounds,
|
|
98
|
+
baseBounds,
|
|
99
|
+
imageWidth: img.width,
|
|
100
|
+
imageHeight: img.height,
|
|
101
|
+
};
|
|
102
|
+
} catch (e) {
|
|
103
|
+
console.error("Edge detection failed", e);
|
|
104
|
+
throw e;
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
];
|
|
109
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { ConfigurationContribution } from "@pooder/core";
|
|
2
|
+
import { DIELINE_SHAPES } from "../dielineShape";
|
|
3
|
+
|
|
4
|
+
export function createDielineConfigurations(state: any): ConfigurationContribution[] {
|
|
5
|
+
return [
|
|
6
|
+
{
|
|
7
|
+
id: "dieline.shape",
|
|
8
|
+
type: "select",
|
|
9
|
+
label: "Shape",
|
|
10
|
+
options: Array.from(DIELINE_SHAPES),
|
|
11
|
+
default: state.shape,
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
id: "dieline.radius",
|
|
15
|
+
type: "number",
|
|
16
|
+
label: "Corner Radius (mm)",
|
|
17
|
+
min: 0,
|
|
18
|
+
max: 500,
|
|
19
|
+
default: state.radius,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: "dieline.shapeStyle",
|
|
23
|
+
type: "json",
|
|
24
|
+
label: "Shape Style",
|
|
25
|
+
default: state.shapeStyle,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: "dieline.showBleedLines",
|
|
29
|
+
type: "boolean",
|
|
30
|
+
label: "Show Bleed Lines",
|
|
31
|
+
default: state.showBleedLines,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: "dieline.strokeWidth",
|
|
35
|
+
type: "number",
|
|
36
|
+
label: "Line Width",
|
|
37
|
+
min: 0.1,
|
|
38
|
+
max: 10,
|
|
39
|
+
step: 0.1,
|
|
40
|
+
default: state.mainLine.width,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: "dieline.strokeColor",
|
|
44
|
+
type: "color",
|
|
45
|
+
label: "Line Color",
|
|
46
|
+
default: state.mainLine.color,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: "dieline.dashLength",
|
|
50
|
+
type: "number",
|
|
51
|
+
label: "Dash Length",
|
|
52
|
+
min: 1,
|
|
53
|
+
max: 50,
|
|
54
|
+
default: state.mainLine.dashLength,
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: "dieline.style",
|
|
58
|
+
type: "select",
|
|
59
|
+
label: "Line Style",
|
|
60
|
+
options: ["solid", "dashed", "hidden"],
|
|
61
|
+
default: state.mainLine.style,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: "dieline.offsetStrokeWidth",
|
|
65
|
+
type: "number",
|
|
66
|
+
label: "Offset Line Width",
|
|
67
|
+
min: 0.1,
|
|
68
|
+
max: 10,
|
|
69
|
+
step: 0.1,
|
|
70
|
+
default: state.offsetLine.width,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
id: "dieline.offsetStrokeColor",
|
|
74
|
+
type: "color",
|
|
75
|
+
label: "Offset Line Color",
|
|
76
|
+
default: state.offsetLine.color,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: "dieline.offsetDashLength",
|
|
80
|
+
type: "number",
|
|
81
|
+
label: "Offset Dash Length",
|
|
82
|
+
min: 1,
|
|
83
|
+
max: 50,
|
|
84
|
+
default: state.offsetLine.dashLength,
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
id: "dieline.offsetStyle",
|
|
88
|
+
type: "select",
|
|
89
|
+
label: "Offset Line Style",
|
|
90
|
+
options: ["solid", "dashed", "hidden"],
|
|
91
|
+
default: state.offsetLine.style,
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: "dieline.insideColor",
|
|
95
|
+
type: "color",
|
|
96
|
+
label: "Inside Color",
|
|
97
|
+
default: state.insideColor,
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
id: "dieline.features",
|
|
101
|
+
type: "json",
|
|
102
|
+
label: "Edge Features",
|
|
103
|
+
default: state.features,
|
|
104
|
+
},
|
|
105
|
+
];
|
|
106
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type { DielineGeometry, DielineState, LineStyle } from "./DielineTool";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type { RenderEffectSpec, RenderObjectSpec } from "../../services";
|