@pooder/kit 6.0.1 → 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/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/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/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/SceneLayoutService.js +96 -0
- package/.test-dist/src/services/index.js +1 -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 +116 -0
- package/CHANGELOG.md +6 -0
- package/dist/index.d.mts +390 -367
- package/dist/index.d.ts +390 -367
- package/dist/index.js +5138 -4927
- package/dist/index.mjs +1149 -1977
- 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} +14 -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} +123 -402
- 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/SceneLayoutService.ts +139 -0
- package/src/services/index.ts +1 -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 +146 -0
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/extensions/background.ts
|
|
1
|
+
// src/extensions/background/BackgroundTool.ts
|
|
2
2
|
import {
|
|
3
3
|
ContributionPointIds
|
|
4
4
|
} from "@pooder/core";
|
|
@@ -157,7 +157,7 @@ function getHeartShapeParams(style) {
|
|
|
157
157
|
};
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
-
// src/
|
|
160
|
+
// src/shared/scene/sceneLayoutModel.ts
|
|
161
161
|
var DEFAULT_SIZE_STATE = {
|
|
162
162
|
unit: "mm",
|
|
163
163
|
actualWidthMm: 500,
|
|
@@ -392,8 +392,117 @@ function buildSceneGeometry(configService, layout) {
|
|
|
392
392
|
};
|
|
393
393
|
}
|
|
394
394
|
|
|
395
|
-
// src/
|
|
395
|
+
// src/shared/constants/layers.ts
|
|
396
396
|
var BACKGROUND_LAYER_ID = "background";
|
|
397
|
+
var IMAGE_OBJECT_LAYER_ID = "image.user";
|
|
398
|
+
var IMAGE_OVERLAY_LAYER_ID = "image-overlay";
|
|
399
|
+
var WHITE_INK_OBJECT_LAYER_ID = "white-ink.user";
|
|
400
|
+
var WHITE_INK_COVER_LAYER_ID = "white-ink.cover";
|
|
401
|
+
var WHITE_INK_OVERLAY_LAYER_ID = "white-ink.overlay";
|
|
402
|
+
var DIELINE_LAYER_ID = "dieline-overlay";
|
|
403
|
+
var FEATURE_OVERLAY_LAYER_ID = "feature-overlay";
|
|
404
|
+
var RULER_LAYER_ID = "ruler-overlay";
|
|
405
|
+
var FILM_LAYER_ID = "overlay";
|
|
406
|
+
|
|
407
|
+
// src/shared/imaging/sourceSizeCache.ts
|
|
408
|
+
function normalizeSourceSize(size) {
|
|
409
|
+
const width = Number(size.width || 0);
|
|
410
|
+
const height = Number(size.height || 0);
|
|
411
|
+
if (!Number.isFinite(width) || !Number.isFinite(height)) return null;
|
|
412
|
+
if (width <= 0 || height <= 0) return null;
|
|
413
|
+
return { width, height };
|
|
414
|
+
}
|
|
415
|
+
function getCoverScale(frame, source) {
|
|
416
|
+
const frameWidth = Math.max(1, Number(frame.width || 0));
|
|
417
|
+
const frameHeight = Math.max(1, Number(frame.height || 0));
|
|
418
|
+
const sourceWidth = Math.max(1, Number(source.width || 0));
|
|
419
|
+
const sourceHeight = Math.max(1, Number(source.height || 0));
|
|
420
|
+
return Math.max(frameWidth / sourceWidth, frameHeight / sourceHeight);
|
|
421
|
+
}
|
|
422
|
+
function createSourceSizeCache(loadSize) {
|
|
423
|
+
const sizesBySrc = /* @__PURE__ */ new Map();
|
|
424
|
+
const pendingBySrc = /* @__PURE__ */ new Map();
|
|
425
|
+
const rememberSourceSize = (src, size) => {
|
|
426
|
+
const normalized = normalizeSourceSize(size);
|
|
427
|
+
if (!src || !normalized) return null;
|
|
428
|
+
sizesBySrc.set(src, normalized);
|
|
429
|
+
return normalized;
|
|
430
|
+
};
|
|
431
|
+
const getSourceSize = (src) => {
|
|
432
|
+
if (!src) return null;
|
|
433
|
+
const cached = sizesBySrc.get(src);
|
|
434
|
+
if (!cached) return null;
|
|
435
|
+
return { width: cached.width, height: cached.height };
|
|
436
|
+
};
|
|
437
|
+
const ensureImageSize = async (src) => {
|
|
438
|
+
if (!src) return null;
|
|
439
|
+
const cached = sizesBySrc.get(src);
|
|
440
|
+
if (cached) return { width: cached.width, height: cached.height };
|
|
441
|
+
const pending = pendingBySrc.get(src);
|
|
442
|
+
if (pending) {
|
|
443
|
+
return pending;
|
|
444
|
+
}
|
|
445
|
+
const task = loadSize(src);
|
|
446
|
+
pendingBySrc.set(src, task);
|
|
447
|
+
try {
|
|
448
|
+
const size = await task;
|
|
449
|
+
if (size) {
|
|
450
|
+
rememberSourceSize(src, size);
|
|
451
|
+
}
|
|
452
|
+
return size;
|
|
453
|
+
} finally {
|
|
454
|
+
if (pendingBySrc.get(src) === task) {
|
|
455
|
+
pendingBySrc.delete(src);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
const deleteSourceSize = (src) => {
|
|
460
|
+
if (!src) return;
|
|
461
|
+
sizesBySrc.delete(src);
|
|
462
|
+
pendingBySrc.delete(src);
|
|
463
|
+
};
|
|
464
|
+
const clear = () => {
|
|
465
|
+
sizesBySrc.clear();
|
|
466
|
+
pendingBySrc.clear();
|
|
467
|
+
};
|
|
468
|
+
return {
|
|
469
|
+
ensureImageSize,
|
|
470
|
+
rememberSourceSize,
|
|
471
|
+
getSourceSize,
|
|
472
|
+
deleteSourceSize,
|
|
473
|
+
clear
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// src/shared/runtime/subscriptions.ts
|
|
478
|
+
var SubscriptionBag = class {
|
|
479
|
+
constructor() {
|
|
480
|
+
this.disposables = [];
|
|
481
|
+
}
|
|
482
|
+
add(disposable) {
|
|
483
|
+
if (disposable) {
|
|
484
|
+
this.disposables.push(disposable);
|
|
485
|
+
}
|
|
486
|
+
return disposable;
|
|
487
|
+
}
|
|
488
|
+
on(eventBus, event, handler) {
|
|
489
|
+
eventBus.on(event, handler);
|
|
490
|
+
this.disposables.push({
|
|
491
|
+
dispose: () => eventBus.off(event, handler)
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
onConfigChange(configService, handler) {
|
|
495
|
+
this.add(configService.onAnyChange(handler));
|
|
496
|
+
}
|
|
497
|
+
disposeAll() {
|
|
498
|
+
while (this.disposables.length > 0) {
|
|
499
|
+
const disposable = this.disposables.pop();
|
|
500
|
+
disposable == null ? void 0 : disposable.dispose();
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
// src/extensions/background/BackgroundTool.ts
|
|
397
506
|
var BACKGROUND_CONFIG_KEY = "background.config";
|
|
398
507
|
var DEFAULT_WIDTH = 800;
|
|
399
508
|
var DEFAULT_HEIGHT = 600;
|
|
@@ -409,7 +518,7 @@ var DEFAULT_BACKGROUND_CONFIG = {
|
|
|
409
518
|
order: 0,
|
|
410
519
|
enabled: true,
|
|
411
520
|
exportable: false,
|
|
412
|
-
color: "#
|
|
521
|
+
color: "#eee"
|
|
413
522
|
}
|
|
414
523
|
]
|
|
415
524
|
};
|
|
@@ -520,10 +629,12 @@ var BackgroundTool = class {
|
|
|
520
629
|
};
|
|
521
630
|
this.config = cloneConfig(DEFAULT_BACKGROUND_CONFIG);
|
|
522
631
|
this.specs = [];
|
|
632
|
+
this.subscriptions = new SubscriptionBag();
|
|
523
633
|
this.renderSeq = 0;
|
|
524
634
|
this.latestSceneLayout = null;
|
|
525
|
-
this.
|
|
526
|
-
|
|
635
|
+
this.sourceSizeCache = createSourceSizeCache(
|
|
636
|
+
(src) => this.loadImageSize(src)
|
|
637
|
+
);
|
|
527
638
|
this.onCanvasResized = () => {
|
|
528
639
|
this.latestSceneLayout = null;
|
|
529
640
|
this.updateBackground();
|
|
@@ -537,7 +648,8 @@ var BackgroundTool = class {
|
|
|
537
648
|
}
|
|
538
649
|
}
|
|
539
650
|
activate(context) {
|
|
540
|
-
var _a
|
|
651
|
+
var _a;
|
|
652
|
+
this.subscriptions.disposeAll();
|
|
541
653
|
this.canvasService = context.services.get("CanvasService");
|
|
542
654
|
if (!this.canvasService) {
|
|
543
655
|
console.warn("CanvasService not found for BackgroundTool");
|
|
@@ -553,8 +665,8 @@ var BackgroundTool = class {
|
|
|
553
665
|
DEFAULT_BACKGROUND_CONFIG
|
|
554
666
|
)
|
|
555
667
|
);
|
|
556
|
-
|
|
557
|
-
|
|
668
|
+
this.subscriptions.onConfigChange(
|
|
669
|
+
this.configService,
|
|
558
670
|
(e) => {
|
|
559
671
|
if (e.key === BACKGROUND_CONFIG_KEY) {
|
|
560
672
|
this.config = normalizeConfig(e.value);
|
|
@@ -568,7 +680,7 @@ var BackgroundTool = class {
|
|
|
568
680
|
}
|
|
569
681
|
);
|
|
570
682
|
}
|
|
571
|
-
(
|
|
683
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
572
684
|
this.renderProducerDisposable = this.canvasService.registerRenderProducer(
|
|
573
685
|
this.id,
|
|
574
686
|
() => ({
|
|
@@ -583,20 +695,26 @@ var BackgroundTool = class {
|
|
|
583
695
|
}),
|
|
584
696
|
{ priority: 0 }
|
|
585
697
|
);
|
|
586
|
-
|
|
587
|
-
|
|
698
|
+
this.subscriptions.on(
|
|
699
|
+
context.eventBus,
|
|
700
|
+
"canvas:resized",
|
|
701
|
+
this.onCanvasResized
|
|
702
|
+
);
|
|
703
|
+
this.subscriptions.on(
|
|
704
|
+
context.eventBus,
|
|
705
|
+
"scene:layout:change",
|
|
706
|
+
this.onSceneLayoutChanged
|
|
707
|
+
);
|
|
588
708
|
this.updateBackground();
|
|
589
709
|
}
|
|
590
710
|
deactivate(context) {
|
|
591
|
-
var _a
|
|
592
|
-
|
|
593
|
-
context.eventBus.off("scene:layout:change", this.onSceneLayoutChanged);
|
|
711
|
+
var _a;
|
|
712
|
+
this.subscriptions.disposeAll();
|
|
594
713
|
this.renderSeq += 1;
|
|
595
714
|
this.specs = [];
|
|
596
715
|
this.latestSceneLayout = null;
|
|
597
|
-
|
|
598
|
-
this.
|
|
599
|
-
(_b = this.renderProducerDisposable) == null ? void 0 : _b.dispose();
|
|
716
|
+
this.sourceSizeCache.clear();
|
|
717
|
+
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
600
718
|
this.renderProducerDisposable = void 0;
|
|
601
719
|
if (!this.canvasService) return;
|
|
602
720
|
void this.canvasService.flushRenderFromProducers();
|
|
@@ -804,7 +922,7 @@ var BackgroundTool = class {
|
|
|
804
922
|
buildImageLayerSpec(layer) {
|
|
805
923
|
const src = String(layer.src || "").trim();
|
|
806
924
|
if (!src) return [];
|
|
807
|
-
const sourceSize = this.
|
|
925
|
+
const sourceSize = this.sourceSizeCache.getSourceSize(src);
|
|
808
926
|
if (!sourceSize) return [];
|
|
809
927
|
const rect = this.resolveAnchorRect(layer.anchor);
|
|
810
928
|
const placement = this.resolveImagePlacement(rect, sourceSize, layer.fit);
|
|
@@ -863,24 +981,6 @@ var BackgroundTool = class {
|
|
|
863
981
|
});
|
|
864
982
|
return Array.from(urls);
|
|
865
983
|
}
|
|
866
|
-
async ensureImageSize(src) {
|
|
867
|
-
if (!src) return null;
|
|
868
|
-
const cached = this.sourceSizeBySrc.get(src);
|
|
869
|
-
if (cached) return cached;
|
|
870
|
-
const pending = this.pendingSizeBySrc.get(src);
|
|
871
|
-
if (pending) {
|
|
872
|
-
return pending;
|
|
873
|
-
}
|
|
874
|
-
const task = this.loadImageSize(src);
|
|
875
|
-
this.pendingSizeBySrc.set(src, task);
|
|
876
|
-
try {
|
|
877
|
-
return await task;
|
|
878
|
-
} finally {
|
|
879
|
-
if (this.pendingSizeBySrc.get(src) === task) {
|
|
880
|
-
this.pendingSizeBySrc.delete(src);
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
984
|
async loadImageSize(src) {
|
|
885
985
|
try {
|
|
886
986
|
const image = await FabricImage.fromURL(src, {
|
|
@@ -889,9 +989,7 @@ var BackgroundTool = class {
|
|
|
889
989
|
const width = Number((image == null ? void 0 : image.width) || 0);
|
|
890
990
|
const height = Number((image == null ? void 0 : image.height) || 0);
|
|
891
991
|
if (width > 0 && height > 0) {
|
|
892
|
-
|
|
893
|
-
this.sourceSizeBySrc.set(src, size);
|
|
894
|
-
return size;
|
|
992
|
+
return { width, height };
|
|
895
993
|
}
|
|
896
994
|
} catch (error) {
|
|
897
995
|
console.error("[BackgroundTool] Failed to load image", src, error);
|
|
@@ -907,7 +1005,9 @@ var BackgroundTool = class {
|
|
|
907
1005
|
const currentConfig = cloneConfig(this.config);
|
|
908
1006
|
const activeUrls = this.collectActiveImageUrls(currentConfig);
|
|
909
1007
|
if (activeUrls.length > 0) {
|
|
910
|
-
await Promise.all(
|
|
1008
|
+
await Promise.all(
|
|
1009
|
+
activeUrls.map((url) => this.sourceSizeCache.ensureImageSize(url))
|
|
1010
|
+
);
|
|
911
1011
|
if (seq !== this.renderSeq) return;
|
|
912
1012
|
}
|
|
913
1013
|
this.specs = this.buildBackgroundSpecs(currentConfig);
|
|
@@ -917,7 +1017,7 @@ var BackgroundTool = class {
|
|
|
917
1017
|
}
|
|
918
1018
|
};
|
|
919
1019
|
|
|
920
|
-
// src/extensions/image.ts
|
|
1020
|
+
// src/extensions/image/ImageTool.ts
|
|
921
1021
|
import {
|
|
922
1022
|
ContributionPointIds as ContributionPointIds2
|
|
923
1023
|
} from "@pooder/core";
|
|
@@ -1549,9 +1649,351 @@ function getPathBounds(pathData) {
|
|
|
1549
1649
|
};
|
|
1550
1650
|
}
|
|
1551
1651
|
|
|
1552
|
-
// src/
|
|
1553
|
-
|
|
1554
|
-
|
|
1652
|
+
// src/shared/scene/frame.ts
|
|
1653
|
+
function emptyFrameRect() {
|
|
1654
|
+
return { left: 0, top: 0, width: 0, height: 0 };
|
|
1655
|
+
}
|
|
1656
|
+
function resolveCutFrameRect(canvasService, configService) {
|
|
1657
|
+
if (!canvasService || !configService) {
|
|
1658
|
+
return emptyFrameRect();
|
|
1659
|
+
}
|
|
1660
|
+
const sizeState = readSizeState(configService);
|
|
1661
|
+
const layout = computeSceneLayout(canvasService, sizeState);
|
|
1662
|
+
if (!layout) {
|
|
1663
|
+
return emptyFrameRect();
|
|
1664
|
+
}
|
|
1665
|
+
return canvasService.toSceneRect({
|
|
1666
|
+
left: layout.cutRect.left,
|
|
1667
|
+
top: layout.cutRect.top,
|
|
1668
|
+
width: layout.cutRect.width,
|
|
1669
|
+
height: layout.cutRect.height
|
|
1670
|
+
});
|
|
1671
|
+
}
|
|
1672
|
+
function toLayoutSceneRect(rect) {
|
|
1673
|
+
return {
|
|
1674
|
+
left: rect.left,
|
|
1675
|
+
top: rect.top,
|
|
1676
|
+
width: rect.width,
|
|
1677
|
+
height: rect.height,
|
|
1678
|
+
space: "scene"
|
|
1679
|
+
};
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
// src/shared/runtime/sessionState.ts
|
|
1683
|
+
function cloneWithJson(value) {
|
|
1684
|
+
return JSON.parse(JSON.stringify(value));
|
|
1685
|
+
}
|
|
1686
|
+
function applyCommittedSnapshot(session, nextCommitted, options) {
|
|
1687
|
+
const clone = options.clone;
|
|
1688
|
+
session.committed = clone(nextCommitted);
|
|
1689
|
+
const shouldPreserveDirtyWorking = options.toolActive && options.preserveDirtyWorking !== false && session.hasWorkingChanges;
|
|
1690
|
+
if (!shouldPreserveDirtyWorking) {
|
|
1691
|
+
session.working = clone(session.committed);
|
|
1692
|
+
session.hasWorkingChanges = false;
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
function runDeferredConfigUpdate(state, action, cooldownMs = 0) {
|
|
1696
|
+
state.isUpdatingConfig = true;
|
|
1697
|
+
action();
|
|
1698
|
+
if (cooldownMs <= 0) {
|
|
1699
|
+
state.isUpdatingConfig = false;
|
|
1700
|
+
return;
|
|
1701
|
+
}
|
|
1702
|
+
setTimeout(() => {
|
|
1703
|
+
state.isUpdatingConfig = false;
|
|
1704
|
+
}, cooldownMs);
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
// src/extensions/image/commands.ts
|
|
1708
|
+
function createImageCommands(tool) {
|
|
1709
|
+
return [
|
|
1710
|
+
{
|
|
1711
|
+
command: "addImage",
|
|
1712
|
+
id: "addImage",
|
|
1713
|
+
title: "Add Image",
|
|
1714
|
+
handler: async (url, options) => {
|
|
1715
|
+
const result = await tool.upsertImageEntry(url, {
|
|
1716
|
+
mode: "add",
|
|
1717
|
+
addOptions: options
|
|
1718
|
+
});
|
|
1719
|
+
return result.id;
|
|
1720
|
+
}
|
|
1721
|
+
},
|
|
1722
|
+
{
|
|
1723
|
+
command: "upsertImage",
|
|
1724
|
+
id: "upsertImage",
|
|
1725
|
+
title: "Upsert Image",
|
|
1726
|
+
handler: async (url, options = {}) => {
|
|
1727
|
+
return await tool.upsertImageEntry(url, options);
|
|
1728
|
+
}
|
|
1729
|
+
},
|
|
1730
|
+
{
|
|
1731
|
+
command: "getWorkingImages",
|
|
1732
|
+
id: "getWorkingImages",
|
|
1733
|
+
title: "Get Working Images",
|
|
1734
|
+
handler: () => {
|
|
1735
|
+
return tool.cloneItems(tool.workingItems);
|
|
1736
|
+
}
|
|
1737
|
+
},
|
|
1738
|
+
{
|
|
1739
|
+
command: "setWorkingImage",
|
|
1740
|
+
id: "setWorkingImage",
|
|
1741
|
+
title: "Set Working Image",
|
|
1742
|
+
handler: (id, updates) => {
|
|
1743
|
+
tool.updateImageInWorking(id, updates);
|
|
1744
|
+
}
|
|
1745
|
+
},
|
|
1746
|
+
{
|
|
1747
|
+
command: "resetWorkingImages",
|
|
1748
|
+
id: "resetWorkingImages",
|
|
1749
|
+
title: "Reset Working Images",
|
|
1750
|
+
handler: () => {
|
|
1751
|
+
tool.workingItems = tool.cloneItems(tool.items);
|
|
1752
|
+
tool.hasWorkingChanges = false;
|
|
1753
|
+
tool.updateImages();
|
|
1754
|
+
tool.emitWorkingChange();
|
|
1755
|
+
}
|
|
1756
|
+
},
|
|
1757
|
+
{
|
|
1758
|
+
command: "completeImages",
|
|
1759
|
+
id: "completeImages",
|
|
1760
|
+
title: "Complete Images",
|
|
1761
|
+
handler: async () => {
|
|
1762
|
+
return await tool.commitWorkingImagesAsCropped();
|
|
1763
|
+
}
|
|
1764
|
+
},
|
|
1765
|
+
{
|
|
1766
|
+
command: "exportUserCroppedImage",
|
|
1767
|
+
id: "exportUserCroppedImage",
|
|
1768
|
+
title: "Export User Cropped Image",
|
|
1769
|
+
handler: async (options = {}) => {
|
|
1770
|
+
return await tool.exportUserCroppedImage(options);
|
|
1771
|
+
}
|
|
1772
|
+
},
|
|
1773
|
+
{
|
|
1774
|
+
command: "fitImageToArea",
|
|
1775
|
+
id: "fitImageToArea",
|
|
1776
|
+
title: "Fit Image to Area",
|
|
1777
|
+
handler: async (id, area) => {
|
|
1778
|
+
await tool.fitImageToArea(id, area);
|
|
1779
|
+
}
|
|
1780
|
+
},
|
|
1781
|
+
{
|
|
1782
|
+
command: "fitImageToDefaultArea",
|
|
1783
|
+
id: "fitImageToDefaultArea",
|
|
1784
|
+
title: "Fit Image to Default Area",
|
|
1785
|
+
handler: async (id) => {
|
|
1786
|
+
await tool.fitImageToDefaultArea(id);
|
|
1787
|
+
}
|
|
1788
|
+
},
|
|
1789
|
+
{
|
|
1790
|
+
command: "focusImage",
|
|
1791
|
+
id: "focusImage",
|
|
1792
|
+
title: "Focus Image",
|
|
1793
|
+
handler: (id, options = {}) => {
|
|
1794
|
+
return tool.setImageFocus(id, options);
|
|
1795
|
+
}
|
|
1796
|
+
},
|
|
1797
|
+
{
|
|
1798
|
+
command: "removeImage",
|
|
1799
|
+
id: "removeImage",
|
|
1800
|
+
title: "Remove Image",
|
|
1801
|
+
handler: (id) => {
|
|
1802
|
+
const removed = tool.items.find((item) => item.id === id);
|
|
1803
|
+
const next = tool.items.filter((item) => item.id !== id);
|
|
1804
|
+
if (next.length !== tool.items.length) {
|
|
1805
|
+
tool.purgeSourceSizeCacheForItem(removed);
|
|
1806
|
+
if (tool.focusedImageId === id) {
|
|
1807
|
+
tool.setImageFocus(null, {
|
|
1808
|
+
syncCanvasSelection: true,
|
|
1809
|
+
skipRender: true
|
|
1810
|
+
});
|
|
1811
|
+
}
|
|
1812
|
+
tool.updateConfig(next);
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
},
|
|
1816
|
+
{
|
|
1817
|
+
command: "updateImage",
|
|
1818
|
+
id: "updateImage",
|
|
1819
|
+
title: "Update Image",
|
|
1820
|
+
handler: async (id, updates, options = {}) => {
|
|
1821
|
+
await tool.updateImage(id, updates, options);
|
|
1822
|
+
}
|
|
1823
|
+
},
|
|
1824
|
+
{
|
|
1825
|
+
command: "clearImages",
|
|
1826
|
+
id: "clearImages",
|
|
1827
|
+
title: "Clear Images",
|
|
1828
|
+
handler: () => {
|
|
1829
|
+
tool.sourceSizeCache.clear();
|
|
1830
|
+
tool.setImageFocus(null, {
|
|
1831
|
+
syncCanvasSelection: true,
|
|
1832
|
+
skipRender: true
|
|
1833
|
+
});
|
|
1834
|
+
tool.updateConfig([]);
|
|
1835
|
+
}
|
|
1836
|
+
},
|
|
1837
|
+
{
|
|
1838
|
+
command: "bringToFront",
|
|
1839
|
+
id: "bringToFront",
|
|
1840
|
+
title: "Bring Image to Front",
|
|
1841
|
+
handler: (id) => {
|
|
1842
|
+
const index = tool.items.findIndex((item) => item.id === id);
|
|
1843
|
+
if (index !== -1 && index < tool.items.length - 1) {
|
|
1844
|
+
const next = [...tool.items];
|
|
1845
|
+
const [item] = next.splice(index, 1);
|
|
1846
|
+
next.push(item);
|
|
1847
|
+
tool.updateConfig(next);
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
},
|
|
1851
|
+
{
|
|
1852
|
+
command: "sendToBack",
|
|
1853
|
+
id: "sendToBack",
|
|
1854
|
+
title: "Send Image to Back",
|
|
1855
|
+
handler: (id) => {
|
|
1856
|
+
const index = tool.items.findIndex((item) => item.id === id);
|
|
1857
|
+
if (index > 0) {
|
|
1858
|
+
const next = [...tool.items];
|
|
1859
|
+
const [item] = next.splice(index, 1);
|
|
1860
|
+
next.unshift(item);
|
|
1861
|
+
tool.updateConfig(next);
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
];
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1868
|
+
// src/extensions/image/config.ts
|
|
1869
|
+
function createImageConfigurations() {
|
|
1870
|
+
return [
|
|
1871
|
+
{
|
|
1872
|
+
id: "image.items",
|
|
1873
|
+
type: "array",
|
|
1874
|
+
label: "Images",
|
|
1875
|
+
default: []
|
|
1876
|
+
},
|
|
1877
|
+
{
|
|
1878
|
+
id: "image.debug",
|
|
1879
|
+
type: "boolean",
|
|
1880
|
+
label: "Image Debug Log",
|
|
1881
|
+
default: false
|
|
1882
|
+
},
|
|
1883
|
+
{
|
|
1884
|
+
id: "image.control.cornerSize",
|
|
1885
|
+
type: "number",
|
|
1886
|
+
label: "Image Control Corner Size",
|
|
1887
|
+
min: 4,
|
|
1888
|
+
max: 64,
|
|
1889
|
+
step: 1,
|
|
1890
|
+
default: 14
|
|
1891
|
+
},
|
|
1892
|
+
{
|
|
1893
|
+
id: "image.control.touchCornerSize",
|
|
1894
|
+
type: "number",
|
|
1895
|
+
label: "Image Control Touch Corner Size",
|
|
1896
|
+
min: 8,
|
|
1897
|
+
max: 96,
|
|
1898
|
+
step: 1,
|
|
1899
|
+
default: 24
|
|
1900
|
+
},
|
|
1901
|
+
{
|
|
1902
|
+
id: "image.control.cornerStyle",
|
|
1903
|
+
type: "select",
|
|
1904
|
+
label: "Image Control Corner Style",
|
|
1905
|
+
options: ["circle", "rect"],
|
|
1906
|
+
default: "circle"
|
|
1907
|
+
},
|
|
1908
|
+
{
|
|
1909
|
+
id: "image.control.cornerColor",
|
|
1910
|
+
type: "color",
|
|
1911
|
+
label: "Image Control Corner Color",
|
|
1912
|
+
default: "#ffffff"
|
|
1913
|
+
},
|
|
1914
|
+
{
|
|
1915
|
+
id: "image.control.cornerStrokeColor",
|
|
1916
|
+
type: "color",
|
|
1917
|
+
label: "Image Control Corner Stroke Color",
|
|
1918
|
+
default: "#1677ff"
|
|
1919
|
+
},
|
|
1920
|
+
{
|
|
1921
|
+
id: "image.control.transparentCorners",
|
|
1922
|
+
type: "boolean",
|
|
1923
|
+
label: "Image Control Transparent Corners",
|
|
1924
|
+
default: false
|
|
1925
|
+
},
|
|
1926
|
+
{
|
|
1927
|
+
id: "image.control.borderColor",
|
|
1928
|
+
type: "color",
|
|
1929
|
+
label: "Image Control Border Color",
|
|
1930
|
+
default: "#1677ff"
|
|
1931
|
+
},
|
|
1932
|
+
{
|
|
1933
|
+
id: "image.control.borderScaleFactor",
|
|
1934
|
+
type: "number",
|
|
1935
|
+
label: "Image Control Border Width",
|
|
1936
|
+
min: 0.5,
|
|
1937
|
+
max: 8,
|
|
1938
|
+
step: 0.1,
|
|
1939
|
+
default: 1.5
|
|
1940
|
+
},
|
|
1941
|
+
{
|
|
1942
|
+
id: "image.control.padding",
|
|
1943
|
+
type: "number",
|
|
1944
|
+
label: "Image Control Padding",
|
|
1945
|
+
min: 0,
|
|
1946
|
+
max: 64,
|
|
1947
|
+
step: 1,
|
|
1948
|
+
default: 0
|
|
1949
|
+
},
|
|
1950
|
+
{
|
|
1951
|
+
id: "image.frame.strokeColor",
|
|
1952
|
+
type: "color",
|
|
1953
|
+
label: "Image Frame Stroke Color",
|
|
1954
|
+
default: "#808080"
|
|
1955
|
+
},
|
|
1956
|
+
{
|
|
1957
|
+
id: "image.frame.strokeWidth",
|
|
1958
|
+
type: "number",
|
|
1959
|
+
label: "Image Frame Stroke Width",
|
|
1960
|
+
min: 0,
|
|
1961
|
+
max: 20,
|
|
1962
|
+
step: 0.5,
|
|
1963
|
+
default: 2
|
|
1964
|
+
},
|
|
1965
|
+
{
|
|
1966
|
+
id: "image.frame.strokeStyle",
|
|
1967
|
+
type: "select",
|
|
1968
|
+
label: "Image Frame Stroke Style",
|
|
1969
|
+
options: ["solid", "dashed", "hidden"],
|
|
1970
|
+
default: "dashed"
|
|
1971
|
+
},
|
|
1972
|
+
{
|
|
1973
|
+
id: "image.frame.dashLength",
|
|
1974
|
+
type: "number",
|
|
1975
|
+
label: "Image Frame Dash Length",
|
|
1976
|
+
min: 1,
|
|
1977
|
+
max: 40,
|
|
1978
|
+
step: 1,
|
|
1979
|
+
default: 8
|
|
1980
|
+
},
|
|
1981
|
+
{
|
|
1982
|
+
id: "image.frame.innerBackground",
|
|
1983
|
+
type: "color",
|
|
1984
|
+
label: "Image Frame Inner Background",
|
|
1985
|
+
default: "rgba(0,0,0,0)"
|
|
1986
|
+
},
|
|
1987
|
+
{
|
|
1988
|
+
id: "image.frame.outerBackground",
|
|
1989
|
+
type: "color",
|
|
1990
|
+
label: "Image Frame Outer Background",
|
|
1991
|
+
default: "#f5f5f5"
|
|
1992
|
+
}
|
|
1993
|
+
];
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1996
|
+
// src/extensions/image/ImageTool.ts
|
|
1555
1997
|
var IMAGE_DEFAULT_CONTROL_CAPABILITIES = [
|
|
1556
1998
|
"rotate",
|
|
1557
1999
|
"scale"
|
|
@@ -1590,7 +2032,9 @@ var ImageTool = class {
|
|
|
1590
2032
|
this.workingItems = [];
|
|
1591
2033
|
this.hasWorkingChanges = false;
|
|
1592
2034
|
this.loadResolvers = /* @__PURE__ */ new Map();
|
|
1593
|
-
this.
|
|
2035
|
+
this.sourceSizeCache = createSourceSizeCache(
|
|
2036
|
+
(src) => this.loadImageSize(src)
|
|
2037
|
+
);
|
|
1594
2038
|
this.isUpdatingConfig = false;
|
|
1595
2039
|
this.isToolActive = false;
|
|
1596
2040
|
this.isImageSelectionActive = false;
|
|
@@ -1598,6 +2042,7 @@ var ImageTool = class {
|
|
|
1598
2042
|
this.renderSeq = 0;
|
|
1599
2043
|
this.imageSpecs = [];
|
|
1600
2044
|
this.overlaySpecs = [];
|
|
2045
|
+
this.subscriptions = new SubscriptionBag();
|
|
1601
2046
|
this.imageControlsByCapabilityKey = /* @__PURE__ */ new Map();
|
|
1602
2047
|
this.onToolActivated = (event) => {
|
|
1603
2048
|
const before = this.isToolActive;
|
|
@@ -1695,6 +2140,7 @@ var ImageTool = class {
|
|
|
1695
2140
|
}
|
|
1696
2141
|
activate(context) {
|
|
1697
2142
|
var _a;
|
|
2143
|
+
this.subscriptions.disposeAll();
|
|
1698
2144
|
this.context = context;
|
|
1699
2145
|
this.canvasService = context.services.get("CanvasService");
|
|
1700
2146
|
if (!this.canvasService) {
|
|
@@ -1736,40 +2182,55 @@ var ImageTool = class {
|
|
|
1736
2182
|
}),
|
|
1737
2183
|
{ priority: 300 }
|
|
1738
2184
|
);
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
2185
|
+
this.subscriptions.on(context.eventBus, "tool:activated", this.onToolActivated);
|
|
2186
|
+
this.subscriptions.on(context.eventBus, "object:modified", this.onObjectModified);
|
|
2187
|
+
this.subscriptions.on(
|
|
2188
|
+
context.eventBus,
|
|
2189
|
+
"selection:created",
|
|
2190
|
+
this.onSelectionChanged
|
|
2191
|
+
);
|
|
2192
|
+
this.subscriptions.on(
|
|
2193
|
+
context.eventBus,
|
|
2194
|
+
"selection:updated",
|
|
2195
|
+
this.onSelectionChanged
|
|
2196
|
+
);
|
|
2197
|
+
this.subscriptions.on(
|
|
2198
|
+
context.eventBus,
|
|
2199
|
+
"selection:cleared",
|
|
2200
|
+
this.onSelectionCleared
|
|
2201
|
+
);
|
|
2202
|
+
this.subscriptions.on(
|
|
2203
|
+
context.eventBus,
|
|
2204
|
+
"scene:layout:change",
|
|
2205
|
+
this.onSceneLayoutChanged
|
|
2206
|
+
);
|
|
2207
|
+
this.subscriptions.on(
|
|
2208
|
+
context.eventBus,
|
|
2209
|
+
"scene:geometry:change",
|
|
2210
|
+
this.onSceneGeometryChanged
|
|
2211
|
+
);
|
|
1746
2212
|
const configService = context.services.get(
|
|
1747
2213
|
"ConfigurationService"
|
|
1748
2214
|
);
|
|
1749
2215
|
if (configService) {
|
|
1750
|
-
this.items
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
if (!this.isToolActive || !this.hasWorkingChanges) {
|
|
1760
|
-
this.workingItems = this.cloneItems(this.items);
|
|
1761
|
-
this.hasWorkingChanges = false;
|
|
2216
|
+
this.applyCommittedItems(configService.get("image.items", []) || []);
|
|
2217
|
+
this.subscriptions.onConfigChange(
|
|
2218
|
+
configService,
|
|
2219
|
+
(e) => {
|
|
2220
|
+
if (this.isUpdatingConfig) return;
|
|
2221
|
+
if (e.key === "image.items") {
|
|
2222
|
+
this.applyCommittedItems(e.value || []);
|
|
2223
|
+
this.updateImages();
|
|
2224
|
+
return;
|
|
1762
2225
|
}
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
this.imageControlsByCapabilityKey.clear();
|
|
2226
|
+
if (e.key.startsWith("size.") || e.key.startsWith("image.frame.") || e.key.startsWith("image.control.")) {
|
|
2227
|
+
if (e.key.startsWith("image.control.")) {
|
|
2228
|
+
this.imageControlsByCapabilityKey.clear();
|
|
2229
|
+
}
|
|
2230
|
+
this.updateImages();
|
|
1769
2231
|
}
|
|
1770
|
-
this.updateImages();
|
|
1771
2232
|
}
|
|
1772
|
-
|
|
2233
|
+
);
|
|
1773
2234
|
}
|
|
1774
2235
|
const toolSessionService = context.services.get("ToolSessionService");
|
|
1775
2236
|
this.dirtyTrackerDisposable = toolSessionService == null ? void 0 : toolSessionService.registerDirtyTracker(
|
|
@@ -1780,18 +2241,13 @@ var ImageTool = class {
|
|
|
1780
2241
|
}
|
|
1781
2242
|
deactivate(context) {
|
|
1782
2243
|
var _a, _b;
|
|
1783
|
-
|
|
1784
|
-
context.eventBus.off("object:modified", this.onObjectModified);
|
|
1785
|
-
context.eventBus.off("selection:created", this.onSelectionChanged);
|
|
1786
|
-
context.eventBus.off("selection:updated", this.onSelectionChanged);
|
|
1787
|
-
context.eventBus.off("selection:cleared", this.onSelectionCleared);
|
|
1788
|
-
context.eventBus.off("scene:layout:change", this.onSceneLayoutChanged);
|
|
1789
|
-
context.eventBus.off("scene:geometry:change", this.onSceneGeometryChanged);
|
|
2244
|
+
this.subscriptions.disposeAll();
|
|
1790
2245
|
(_a = this.dirtyTrackerDisposable) == null ? void 0 : _a.dispose();
|
|
1791
2246
|
this.dirtyTrackerDisposable = void 0;
|
|
1792
2247
|
this.cropShapeHatchPattern = void 0;
|
|
1793
2248
|
this.cropShapeHatchPatternColor = void 0;
|
|
1794
2249
|
this.cropShapeHatchPatternKey = void 0;
|
|
2250
|
+
this.sourceSizeCache.clear();
|
|
1795
2251
|
this.imageSpecs = [];
|
|
1796
2252
|
this.overlaySpecs = [];
|
|
1797
2253
|
this.imageControlsByCapabilityKey.clear();
|
|
@@ -1930,272 +2386,8 @@ var ImageTool = class {
|
|
|
1930
2386
|
}
|
|
1931
2387
|
}
|
|
1932
2388
|
],
|
|
1933
|
-
[ContributionPointIds2.CONFIGURATIONS]:
|
|
1934
|
-
|
|
1935
|
-
id: "image.items",
|
|
1936
|
-
type: "array",
|
|
1937
|
-
label: "Images",
|
|
1938
|
-
default: []
|
|
1939
|
-
},
|
|
1940
|
-
{
|
|
1941
|
-
id: "image.debug",
|
|
1942
|
-
type: "boolean",
|
|
1943
|
-
label: "Image Debug Log",
|
|
1944
|
-
default: false
|
|
1945
|
-
},
|
|
1946
|
-
{
|
|
1947
|
-
id: "image.control.cornerSize",
|
|
1948
|
-
type: "number",
|
|
1949
|
-
label: "Image Control Corner Size",
|
|
1950
|
-
min: 4,
|
|
1951
|
-
max: 64,
|
|
1952
|
-
step: 1,
|
|
1953
|
-
default: 14
|
|
1954
|
-
},
|
|
1955
|
-
{
|
|
1956
|
-
id: "image.control.touchCornerSize",
|
|
1957
|
-
type: "number",
|
|
1958
|
-
label: "Image Control Touch Corner Size",
|
|
1959
|
-
min: 8,
|
|
1960
|
-
max: 96,
|
|
1961
|
-
step: 1,
|
|
1962
|
-
default: 24
|
|
1963
|
-
},
|
|
1964
|
-
{
|
|
1965
|
-
id: "image.control.cornerStyle",
|
|
1966
|
-
type: "select",
|
|
1967
|
-
label: "Image Control Corner Style",
|
|
1968
|
-
options: ["circle", "rect"],
|
|
1969
|
-
default: "circle"
|
|
1970
|
-
},
|
|
1971
|
-
{
|
|
1972
|
-
id: "image.control.cornerColor",
|
|
1973
|
-
type: "color",
|
|
1974
|
-
label: "Image Control Corner Color",
|
|
1975
|
-
default: "#ffffff"
|
|
1976
|
-
},
|
|
1977
|
-
{
|
|
1978
|
-
id: "image.control.cornerStrokeColor",
|
|
1979
|
-
type: "color",
|
|
1980
|
-
label: "Image Control Corner Stroke Color",
|
|
1981
|
-
default: "#1677ff"
|
|
1982
|
-
},
|
|
1983
|
-
{
|
|
1984
|
-
id: "image.control.transparentCorners",
|
|
1985
|
-
type: "boolean",
|
|
1986
|
-
label: "Image Control Transparent Corners",
|
|
1987
|
-
default: false
|
|
1988
|
-
},
|
|
1989
|
-
{
|
|
1990
|
-
id: "image.control.borderColor",
|
|
1991
|
-
type: "color",
|
|
1992
|
-
label: "Image Control Border Color",
|
|
1993
|
-
default: "#1677ff"
|
|
1994
|
-
},
|
|
1995
|
-
{
|
|
1996
|
-
id: "image.control.borderScaleFactor",
|
|
1997
|
-
type: "number",
|
|
1998
|
-
label: "Image Control Border Width",
|
|
1999
|
-
min: 0.5,
|
|
2000
|
-
max: 8,
|
|
2001
|
-
step: 0.1,
|
|
2002
|
-
default: 1.5
|
|
2003
|
-
},
|
|
2004
|
-
{
|
|
2005
|
-
id: "image.control.padding",
|
|
2006
|
-
type: "number",
|
|
2007
|
-
label: "Image Control Padding",
|
|
2008
|
-
min: 0,
|
|
2009
|
-
max: 64,
|
|
2010
|
-
step: 1,
|
|
2011
|
-
default: 0
|
|
2012
|
-
},
|
|
2013
|
-
{
|
|
2014
|
-
id: "image.frame.strokeColor",
|
|
2015
|
-
type: "color",
|
|
2016
|
-
label: "Image Frame Stroke Color",
|
|
2017
|
-
default: "#808080"
|
|
2018
|
-
},
|
|
2019
|
-
{
|
|
2020
|
-
id: "image.frame.strokeWidth",
|
|
2021
|
-
type: "number",
|
|
2022
|
-
label: "Image Frame Stroke Width",
|
|
2023
|
-
min: 0,
|
|
2024
|
-
max: 20,
|
|
2025
|
-
step: 0.5,
|
|
2026
|
-
default: 2
|
|
2027
|
-
},
|
|
2028
|
-
{
|
|
2029
|
-
id: "image.frame.strokeStyle",
|
|
2030
|
-
type: "select",
|
|
2031
|
-
label: "Image Frame Stroke Style",
|
|
2032
|
-
options: ["solid", "dashed", "hidden"],
|
|
2033
|
-
default: "dashed"
|
|
2034
|
-
},
|
|
2035
|
-
{
|
|
2036
|
-
id: "image.frame.dashLength",
|
|
2037
|
-
type: "number",
|
|
2038
|
-
label: "Image Frame Dash Length",
|
|
2039
|
-
min: 1,
|
|
2040
|
-
max: 40,
|
|
2041
|
-
step: 1,
|
|
2042
|
-
default: 8
|
|
2043
|
-
},
|
|
2044
|
-
{
|
|
2045
|
-
id: "image.frame.innerBackground",
|
|
2046
|
-
type: "color",
|
|
2047
|
-
label: "Image Frame Inner Background",
|
|
2048
|
-
default: "rgba(0,0,0,0)"
|
|
2049
|
-
},
|
|
2050
|
-
{
|
|
2051
|
-
id: "image.frame.outerBackground",
|
|
2052
|
-
type: "color",
|
|
2053
|
-
label: "Image Frame Outer Background",
|
|
2054
|
-
default: "#f5f5f5"
|
|
2055
|
-
}
|
|
2056
|
-
],
|
|
2057
|
-
[ContributionPointIds2.COMMANDS]: [
|
|
2058
|
-
{
|
|
2059
|
-
command: "addImage",
|
|
2060
|
-
title: "Add Image",
|
|
2061
|
-
handler: async (url, options) => {
|
|
2062
|
-
const result = await this.upsertImageEntry(url, {
|
|
2063
|
-
mode: "add",
|
|
2064
|
-
addOptions: options
|
|
2065
|
-
});
|
|
2066
|
-
return result.id;
|
|
2067
|
-
}
|
|
2068
|
-
},
|
|
2069
|
-
{
|
|
2070
|
-
command: "upsertImage",
|
|
2071
|
-
title: "Upsert Image",
|
|
2072
|
-
handler: async (url, options = {}) => {
|
|
2073
|
-
return await this.upsertImageEntry(url, options);
|
|
2074
|
-
}
|
|
2075
|
-
},
|
|
2076
|
-
{
|
|
2077
|
-
command: "getWorkingImages",
|
|
2078
|
-
title: "Get Working Images",
|
|
2079
|
-
handler: () => {
|
|
2080
|
-
return this.cloneItems(this.workingItems);
|
|
2081
|
-
}
|
|
2082
|
-
},
|
|
2083
|
-
{
|
|
2084
|
-
command: "setWorkingImage",
|
|
2085
|
-
title: "Set Working Image",
|
|
2086
|
-
handler: (id, updates) => {
|
|
2087
|
-
this.updateImageInWorking(id, updates);
|
|
2088
|
-
}
|
|
2089
|
-
},
|
|
2090
|
-
{
|
|
2091
|
-
command: "resetWorkingImages",
|
|
2092
|
-
title: "Reset Working Images",
|
|
2093
|
-
handler: () => {
|
|
2094
|
-
this.workingItems = this.cloneItems(this.items);
|
|
2095
|
-
this.hasWorkingChanges = false;
|
|
2096
|
-
this.updateImages();
|
|
2097
|
-
this.emitWorkingChange();
|
|
2098
|
-
}
|
|
2099
|
-
},
|
|
2100
|
-
{
|
|
2101
|
-
command: "completeImages",
|
|
2102
|
-
title: "Complete Images",
|
|
2103
|
-
handler: async () => {
|
|
2104
|
-
return await this.commitWorkingImagesAsCropped();
|
|
2105
|
-
}
|
|
2106
|
-
},
|
|
2107
|
-
{
|
|
2108
|
-
command: "exportUserCroppedImage",
|
|
2109
|
-
title: "Export User Cropped Image",
|
|
2110
|
-
handler: async (options = {}) => {
|
|
2111
|
-
return await this.exportUserCroppedImage(options);
|
|
2112
|
-
}
|
|
2113
|
-
},
|
|
2114
|
-
{
|
|
2115
|
-
command: "fitImageToArea",
|
|
2116
|
-
title: "Fit Image to Area",
|
|
2117
|
-
handler: async (id, area) => {
|
|
2118
|
-
await this.fitImageToArea(id, area);
|
|
2119
|
-
}
|
|
2120
|
-
},
|
|
2121
|
-
{
|
|
2122
|
-
command: "fitImageToDefaultArea",
|
|
2123
|
-
title: "Fit Image to Default Area",
|
|
2124
|
-
handler: async (id) => {
|
|
2125
|
-
await this.fitImageToDefaultArea(id);
|
|
2126
|
-
}
|
|
2127
|
-
},
|
|
2128
|
-
{
|
|
2129
|
-
command: "focusImage",
|
|
2130
|
-
title: "Focus Image",
|
|
2131
|
-
handler: (id, options = {}) => {
|
|
2132
|
-
return this.setImageFocus(id, options);
|
|
2133
|
-
}
|
|
2134
|
-
},
|
|
2135
|
-
{
|
|
2136
|
-
command: "removeImage",
|
|
2137
|
-
title: "Remove Image",
|
|
2138
|
-
handler: (id) => {
|
|
2139
|
-
const removed = this.items.find((item) => item.id === id);
|
|
2140
|
-
const next = this.items.filter((item) => item.id !== id);
|
|
2141
|
-
if (next.length !== this.items.length) {
|
|
2142
|
-
this.purgeSourceSizeCacheForItem(removed);
|
|
2143
|
-
if (this.focusedImageId === id) {
|
|
2144
|
-
this.setImageFocus(null, {
|
|
2145
|
-
syncCanvasSelection: true,
|
|
2146
|
-
skipRender: true
|
|
2147
|
-
});
|
|
2148
|
-
}
|
|
2149
|
-
this.updateConfig(next);
|
|
2150
|
-
}
|
|
2151
|
-
}
|
|
2152
|
-
},
|
|
2153
|
-
{
|
|
2154
|
-
command: "updateImage",
|
|
2155
|
-
title: "Update Image",
|
|
2156
|
-
handler: async (id, updates, options = {}) => {
|
|
2157
|
-
await this.updateImage(id, updates, options);
|
|
2158
|
-
}
|
|
2159
|
-
},
|
|
2160
|
-
{
|
|
2161
|
-
command: "clearImages",
|
|
2162
|
-
title: "Clear Images",
|
|
2163
|
-
handler: () => {
|
|
2164
|
-
this.sourceSizeBySrc.clear();
|
|
2165
|
-
this.setImageFocus(null, {
|
|
2166
|
-
syncCanvasSelection: true,
|
|
2167
|
-
skipRender: true
|
|
2168
|
-
});
|
|
2169
|
-
this.updateConfig([]);
|
|
2170
|
-
}
|
|
2171
|
-
},
|
|
2172
|
-
{
|
|
2173
|
-
command: "bringToFront",
|
|
2174
|
-
title: "Bring Image to Front",
|
|
2175
|
-
handler: (id) => {
|
|
2176
|
-
const index = this.items.findIndex((item) => item.id === id);
|
|
2177
|
-
if (index !== -1 && index < this.items.length - 1) {
|
|
2178
|
-
const next = [...this.items];
|
|
2179
|
-
const [item] = next.splice(index, 1);
|
|
2180
|
-
next.push(item);
|
|
2181
|
-
this.updateConfig(next);
|
|
2182
|
-
}
|
|
2183
|
-
}
|
|
2184
|
-
},
|
|
2185
|
-
{
|
|
2186
|
-
command: "sendToBack",
|
|
2187
|
-
title: "Send Image to Back",
|
|
2188
|
-
handler: (id) => {
|
|
2189
|
-
const index = this.items.findIndex((item) => item.id === id);
|
|
2190
|
-
if (index > 0) {
|
|
2191
|
-
const next = [...this.items];
|
|
2192
|
-
const [item] = next.splice(index, 1);
|
|
2193
|
-
next.unshift(item);
|
|
2194
|
-
this.updateConfig(next);
|
|
2195
|
-
}
|
|
2196
|
-
}
|
|
2197
|
-
}
|
|
2198
|
-
]
|
|
2389
|
+
[ContributionPointIds2.CONFIGURATIONS]: createImageConfigurations(),
|
|
2390
|
+
[ContributionPointIds2.COMMANDS]: createImageCommands(this)
|
|
2199
2391
|
};
|
|
2200
2392
|
}
|
|
2201
2393
|
normalizeItem(item) {
|
|
@@ -2321,47 +2513,45 @@ var ImageTool = class {
|
|
|
2321
2513
|
if (!configService) return fallback;
|
|
2322
2514
|
return (_a = configService.get(key, fallback)) != null ? _a : fallback;
|
|
2323
2515
|
}
|
|
2516
|
+
applyCommittedItems(nextItems) {
|
|
2517
|
+
const session = {
|
|
2518
|
+
committed: this.items,
|
|
2519
|
+
working: this.workingItems,
|
|
2520
|
+
hasWorkingChanges: this.hasWorkingChanges
|
|
2521
|
+
};
|
|
2522
|
+
applyCommittedSnapshot(session, this.normalizeItems(nextItems), {
|
|
2523
|
+
clone: (items) => this.cloneItems(items),
|
|
2524
|
+
toolActive: this.isToolActive,
|
|
2525
|
+
preserveDirtyWorking: true
|
|
2526
|
+
});
|
|
2527
|
+
this.items = session.committed;
|
|
2528
|
+
this.workingItems = session.working;
|
|
2529
|
+
this.hasWorkingChanges = session.hasWorkingChanges;
|
|
2530
|
+
}
|
|
2324
2531
|
updateConfig(newItems, skipCanvasUpdate = false) {
|
|
2325
2532
|
if (!this.context) return;
|
|
2326
|
-
this.
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2533
|
+
this.applyCommittedItems(newItems);
|
|
2534
|
+
runDeferredConfigUpdate(
|
|
2535
|
+
this,
|
|
2536
|
+
() => {
|
|
2537
|
+
var _a;
|
|
2538
|
+
const configService = (_a = this.context) == null ? void 0 : _a.services.get(
|
|
2539
|
+
"ConfigurationService"
|
|
2540
|
+
);
|
|
2541
|
+
configService == null ? void 0 : configService.update("image.items", this.items);
|
|
2542
|
+
if (!skipCanvasUpdate) {
|
|
2543
|
+
this.updateImages();
|
|
2544
|
+
}
|
|
2545
|
+
},
|
|
2546
|
+
50
|
|
2334
2547
|
);
|
|
2335
|
-
configService == null ? void 0 : configService.update("image.items", this.items);
|
|
2336
|
-
if (!skipCanvasUpdate) {
|
|
2337
|
-
this.updateImages();
|
|
2338
|
-
}
|
|
2339
|
-
setTimeout(() => {
|
|
2340
|
-
this.isUpdatingConfig = false;
|
|
2341
|
-
}, 50);
|
|
2342
2548
|
}
|
|
2343
2549
|
getFrameRect() {
|
|
2344
2550
|
var _a;
|
|
2345
|
-
if (!this.canvasService) {
|
|
2346
|
-
return { left: 0, top: 0, width: 0, height: 0 };
|
|
2347
|
-
}
|
|
2348
2551
|
const configService = (_a = this.context) == null ? void 0 : _a.services.get(
|
|
2349
2552
|
"ConfigurationService"
|
|
2350
2553
|
);
|
|
2351
|
-
|
|
2352
|
-
return { left: 0, top: 0, width: 0, height: 0 };
|
|
2353
|
-
}
|
|
2354
|
-
const sizeState = readSizeState(configService);
|
|
2355
|
-
const layout = computeSceneLayout(this.canvasService, sizeState);
|
|
2356
|
-
if (!layout) {
|
|
2357
|
-
return { left: 0, top: 0, width: 0, height: 0 };
|
|
2358
|
-
}
|
|
2359
|
-
return this.canvasService.toSceneRect({
|
|
2360
|
-
left: layout.cutRect.left,
|
|
2361
|
-
top: layout.cutRect.top,
|
|
2362
|
-
width: layout.cutRect.width,
|
|
2363
|
-
height: layout.cutRect.height
|
|
2364
|
-
});
|
|
2554
|
+
return resolveCutFrameRect(this.canvasService, configService);
|
|
2365
2555
|
}
|
|
2366
2556
|
getFrameRectScreen(frame) {
|
|
2367
2557
|
if (!this.canvasService) {
|
|
@@ -2370,13 +2560,7 @@ var ImageTool = class {
|
|
|
2370
2560
|
return this.canvasService.toScreenRect(frame || this.getFrameRect());
|
|
2371
2561
|
}
|
|
2372
2562
|
toLayoutSceneRect(rect) {
|
|
2373
|
-
return
|
|
2374
|
-
left: rect.left,
|
|
2375
|
-
top: rect.top,
|
|
2376
|
-
width: rect.width,
|
|
2377
|
-
height: rect.height,
|
|
2378
|
-
space: "scene"
|
|
2379
|
-
};
|
|
2563
|
+
return toLayoutSceneRect(rect);
|
|
2380
2564
|
}
|
|
2381
2565
|
async resolveDefaultFitArea() {
|
|
2382
2566
|
if (!this.canvasService) return null;
|
|
@@ -2434,31 +2618,31 @@ var ImageTool = class {
|
|
|
2434
2618
|
const sources = [item.url, item.sourceUrl, item.committedUrl].filter(
|
|
2435
2619
|
(value) => typeof value === "string" && value.length > 0
|
|
2436
2620
|
);
|
|
2437
|
-
sources.forEach((src) => this.
|
|
2621
|
+
sources.forEach((src) => this.sourceSizeCache.deleteSourceSize(src));
|
|
2438
2622
|
}
|
|
2439
2623
|
rememberSourceSize(src, obj) {
|
|
2440
2624
|
const width = Number((obj == null ? void 0 : obj.width) || 0);
|
|
2441
2625
|
const height = Number((obj == null ? void 0 : obj.height) || 0);
|
|
2442
2626
|
if (src && width > 0 && height > 0) {
|
|
2443
|
-
this.
|
|
2627
|
+
this.sourceSizeCache.rememberSourceSize(src, { width, height });
|
|
2444
2628
|
}
|
|
2445
2629
|
}
|
|
2446
2630
|
getSourceSize(src, obj) {
|
|
2447
|
-
const cached = src ? this.
|
|
2631
|
+
const cached = src ? this.sourceSizeCache.getSourceSize(src) : void 0;
|
|
2448
2632
|
if (cached) return cached;
|
|
2449
2633
|
const width = Number((obj == null ? void 0 : obj.width) || 0);
|
|
2450
2634
|
const height = Number((obj == null ? void 0 : obj.height) || 0);
|
|
2451
2635
|
if (src && width > 0 && height > 0) {
|
|
2452
2636
|
const size = { width, height };
|
|
2453
|
-
this.
|
|
2637
|
+
this.sourceSizeCache.rememberSourceSize(src, size);
|
|
2454
2638
|
return size;
|
|
2455
2639
|
}
|
|
2456
2640
|
return { width: 1, height: 1 };
|
|
2457
2641
|
}
|
|
2458
2642
|
async ensureSourceSize(src) {
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2643
|
+
return this.sourceSizeCache.ensureImageSize(src);
|
|
2644
|
+
}
|
|
2645
|
+
async loadImageSize(src) {
|
|
2462
2646
|
try {
|
|
2463
2647
|
const image = await FabricImage2.fromURL(src, {
|
|
2464
2648
|
crossOrigin: "anonymous"
|
|
@@ -2466,9 +2650,7 @@ var ImageTool = class {
|
|
|
2466
2650
|
const width = Number((image == null ? void 0 : image.width) || 0);
|
|
2467
2651
|
const height = Number((image == null ? void 0 : image.height) || 0);
|
|
2468
2652
|
if (width > 0 && height > 0) {
|
|
2469
|
-
|
|
2470
|
-
this.sourceSizeBySrc.set(src, size);
|
|
2471
|
-
return size;
|
|
2653
|
+
return { width, height };
|
|
2472
2654
|
}
|
|
2473
2655
|
} catch (error) {
|
|
2474
2656
|
this.debug("image:size:load-failed", {
|
|
@@ -2479,11 +2661,7 @@ var ImageTool = class {
|
|
|
2479
2661
|
return null;
|
|
2480
2662
|
}
|
|
2481
2663
|
getCoverScale(frame, size) {
|
|
2482
|
-
|
|
2483
|
-
const sh = Math.max(1, size.height);
|
|
2484
|
-
const fw = Math.max(1, frame.width);
|
|
2485
|
-
const fh = Math.max(1, frame.height);
|
|
2486
|
-
return Math.max(fw / sw, fh / sh);
|
|
2664
|
+
return getCoverScale(frame, size);
|
|
2487
2665
|
}
|
|
2488
2666
|
getFrameVisualConfig() {
|
|
2489
2667
|
var _a, _b;
|
|
@@ -3235,7 +3413,7 @@ var ImageTool = class {
|
|
|
3235
3413
|
})
|
|
3236
3414
|
);
|
|
3237
3415
|
if (previousCommitted && previousCommitted !== url) {
|
|
3238
|
-
this.
|
|
3416
|
+
this.sourceSizeCache.deleteSourceSize(previousCommitted);
|
|
3239
3417
|
}
|
|
3240
3418
|
}
|
|
3241
3419
|
this.hasWorkingChanges = false;
|
|
@@ -3331,7 +3509,7 @@ var ImageTool = class {
|
|
|
3331
3509
|
}
|
|
3332
3510
|
};
|
|
3333
3511
|
|
|
3334
|
-
// src/extensions/size.ts
|
|
3512
|
+
// src/extensions/size/SizeTool.ts
|
|
3335
3513
|
import {
|
|
3336
3514
|
ContributionPointIds as ContributionPointIds3
|
|
3337
3515
|
} from "@pooder/core";
|
|
@@ -3632,16 +3810,16 @@ var SizeTool = class {
|
|
|
3632
3810
|
if (!layout || layout.scale <= 0) return null;
|
|
3633
3811
|
const all = this.canvasService.canvas.getObjects();
|
|
3634
3812
|
const active = this.canvasService.canvas.getActiveObject();
|
|
3635
|
-
const activeId = ((_a = active == null ? void 0 : active.data) == null ? void 0 : _a.layerId) ===
|
|
3813
|
+
const activeId = ((_a = active == null ? void 0 : active.data) == null ? void 0 : _a.layerId) === IMAGE_OBJECT_LAYER_ID ? (_b = active == null ? void 0 : active.data) == null ? void 0 : _b.id : null;
|
|
3636
3814
|
const targetId = id || activeId;
|
|
3637
3815
|
const target = all.find(
|
|
3638
3816
|
(obj) => {
|
|
3639
3817
|
var _a2, _b2;
|
|
3640
|
-
return ((_a2 = obj == null ? void 0 : obj.data) == null ? void 0 : _a2.layerId) ===
|
|
3818
|
+
return ((_a2 = obj == null ? void 0 : obj.data) == null ? void 0 : _a2.layerId) === IMAGE_OBJECT_LAYER_ID && ((_b2 = obj == null ? void 0 : obj.data) == null ? void 0 : _b2.id) === targetId;
|
|
3641
3819
|
}
|
|
3642
3820
|
) || all.find((obj) => {
|
|
3643
3821
|
var _a2;
|
|
3644
|
-
return ((_a2 = obj == null ? void 0 : obj.data) == null ? void 0 : _a2.layerId) ===
|
|
3822
|
+
return ((_a2 = obj == null ? void 0 : obj.data) == null ? void 0 : _a2.layerId) === IMAGE_OBJECT_LAYER_ID;
|
|
3645
3823
|
});
|
|
3646
3824
|
if (!target) return null;
|
|
3647
3825
|
const objectWidthPx = Math.abs((target.width || 0) * (target.scaleX || 1));
|
|
@@ -3662,1029 +3840,213 @@ var SizeTool = class {
|
|
|
3662
3840
|
}
|
|
3663
3841
|
};
|
|
3664
3842
|
|
|
3665
|
-
// src/extensions/dieline.ts
|
|
3843
|
+
// src/extensions/dieline/DielineTool.ts
|
|
3666
3844
|
import {
|
|
3667
3845
|
ContributionPointIds as ContributionPointIds4
|
|
3668
3846
|
} from "@pooder/core";
|
|
3669
3847
|
import { Canvas as FabricCanvas2, Path, Pattern as Pattern2 } from "fabric";
|
|
3670
3848
|
|
|
3671
|
-
// src/extensions/
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
const srcIdx = (y * width + x) * 4;
|
|
3691
|
-
const r = data[srcIdx];
|
|
3692
|
-
const g = data[srcIdx + 1];
|
|
3693
|
-
const b = data[srcIdx + 2];
|
|
3694
|
-
const a = data[srcIdx + 3];
|
|
3695
|
-
const destIdx = (y + padding) * paddedWidth + (x + padding);
|
|
3696
|
-
if (resolvedMode === "alpha") {
|
|
3697
|
-
if (a > threshold) mask[destIdx] = 1;
|
|
3698
|
-
} else {
|
|
3699
|
-
if (a > threshold && !(r > whiteThreshold && g > whiteThreshold && b > whiteThreshold)) {
|
|
3700
|
-
mask[destIdx] = 1;
|
|
3701
|
-
}
|
|
3702
|
-
}
|
|
3703
|
-
}
|
|
3704
|
-
}
|
|
3705
|
-
return mask;
|
|
3706
|
-
}
|
|
3707
|
-
function inferMaskMode(imageData, alphaOpaqueCutoff) {
|
|
3708
|
-
const analysis = analyzeAlpha(imageData, alphaOpaqueCutoff);
|
|
3709
|
-
if (analysis.minAlpha === 255) return "whitebg";
|
|
3710
|
-
if (analysis.veryTransparentRatio >= 5e-4) return "alpha";
|
|
3711
|
-
if (analysis.belowOpaqueRatio >= 0.01) return "alpha";
|
|
3712
|
-
return "whitebg";
|
|
3713
|
-
}
|
|
3714
|
-
function analyzeAlpha(imageData, alphaOpaqueCutoff) {
|
|
3715
|
-
const { data } = imageData;
|
|
3716
|
-
const total = data.length / 4;
|
|
3717
|
-
let belowOpaque = 0;
|
|
3718
|
-
let veryTransparent = 0;
|
|
3719
|
-
let minAlpha = 255;
|
|
3720
|
-
for (let i = 3; i < data.length; i += 4) {
|
|
3721
|
-
const a = data[i];
|
|
3722
|
-
if (a < minAlpha) minAlpha = a;
|
|
3723
|
-
if (a < alphaOpaqueCutoff) belowOpaque++;
|
|
3724
|
-
if (a < 32) veryTransparent++;
|
|
3725
|
-
}
|
|
3726
|
-
return {
|
|
3727
|
-
total,
|
|
3728
|
-
minAlpha,
|
|
3729
|
-
belowOpaqueRatio: belowOpaque / total,
|
|
3730
|
-
veryTransparentRatio: veryTransparent / total
|
|
3731
|
-
};
|
|
3732
|
-
}
|
|
3733
|
-
function circularMorphology(mask, width, height, radius, op) {
|
|
3734
|
-
const r = Math.max(0, Math.floor(radius));
|
|
3735
|
-
if (r <= 0) {
|
|
3736
|
-
return mask.slice();
|
|
3737
|
-
}
|
|
3738
|
-
const dilateDisk = (m, radiusPx) => {
|
|
3739
|
-
const horizontalDist = new Int32Array(width * height);
|
|
3740
|
-
for (let y = 0; y < height; y++) {
|
|
3741
|
-
let lastSolid = -radiusPx * 2;
|
|
3742
|
-
for (let x = 0; x < width; x++) {
|
|
3743
|
-
if (m[y * width + x]) lastSolid = x;
|
|
3744
|
-
horizontalDist[y * width + x] = x - lastSolid;
|
|
3745
|
-
}
|
|
3746
|
-
lastSolid = width + radiusPx * 2;
|
|
3747
|
-
for (let x = width - 1; x >= 0; x--) {
|
|
3748
|
-
if (m[y * width + x]) lastSolid = x;
|
|
3749
|
-
horizontalDist[y * width + x] = Math.min(
|
|
3750
|
-
horizontalDist[y * width + x],
|
|
3751
|
-
lastSolid - x
|
|
3752
|
-
);
|
|
3753
|
-
}
|
|
3754
|
-
}
|
|
3755
|
-
const result = new Uint8Array(width * height);
|
|
3756
|
-
const r2 = radiusPx * radiusPx;
|
|
3757
|
-
for (let x = 0; x < width; x++) {
|
|
3758
|
-
for (let y = 0; y < height; y++) {
|
|
3759
|
-
let found = false;
|
|
3760
|
-
const minY = Math.max(0, y - radiusPx);
|
|
3761
|
-
const maxY = Math.min(height - 1, y + radiusPx);
|
|
3762
|
-
for (let dy = minY; dy <= maxY; dy++) {
|
|
3763
|
-
const dY = dy - y;
|
|
3764
|
-
const hDist = horizontalDist[dy * width + x];
|
|
3765
|
-
if (hDist * hDist + dY * dY <= r2) {
|
|
3766
|
-
found = true;
|
|
3767
|
-
break;
|
|
3768
|
-
}
|
|
3769
|
-
}
|
|
3770
|
-
if (found) result[y * width + x] = 1;
|
|
3771
|
-
}
|
|
3772
|
-
}
|
|
3773
|
-
return result;
|
|
3774
|
-
};
|
|
3775
|
-
const erodeDiamond = (m, radiusPx) => {
|
|
3776
|
-
if (radiusPx <= 0) return m.slice();
|
|
3777
|
-
let current = m;
|
|
3778
|
-
for (let step = 0; step < radiusPx; step++) {
|
|
3779
|
-
const next = new Uint8Array(width * height);
|
|
3780
|
-
for (let y = 1; y < height - 1; y++) {
|
|
3781
|
-
const row = y * width;
|
|
3782
|
-
for (let x = 1; x < width - 1; x++) {
|
|
3783
|
-
const idx = row + x;
|
|
3784
|
-
if (current[idx] && current[idx - 1] && current[idx + 1] && current[idx - width] && current[idx + width]) {
|
|
3785
|
-
next[idx] = 1;
|
|
3786
|
-
}
|
|
3787
|
-
}
|
|
3788
|
-
}
|
|
3789
|
-
current = next;
|
|
3790
|
-
}
|
|
3791
|
-
return current;
|
|
3792
|
-
};
|
|
3793
|
-
const restoreBridgePixels = (source, eroded) => {
|
|
3794
|
-
const restored = eroded.slice();
|
|
3795
|
-
for (let y = 1; y < height - 1; y++) {
|
|
3796
|
-
const row = y * width;
|
|
3797
|
-
for (let x = 1; x < width - 1; x++) {
|
|
3798
|
-
const idx = row + x;
|
|
3799
|
-
if (!source[idx] || restored[idx]) continue;
|
|
3800
|
-
const up = source[idx - width] === 1;
|
|
3801
|
-
const down = source[idx + width] === 1;
|
|
3802
|
-
const left = source[idx - 1] === 1;
|
|
3803
|
-
const right = source[idx + 1] === 1;
|
|
3804
|
-
const upLeft = source[idx - width - 1] === 1;
|
|
3805
|
-
const upRight = source[idx - width + 1] === 1;
|
|
3806
|
-
const downLeft = source[idx + width - 1] === 1;
|
|
3807
|
-
const downRight = source[idx + width + 1] === 1;
|
|
3808
|
-
const keepsBridge = left && right || up && down || upLeft && downRight || upRight && downLeft;
|
|
3809
|
-
if (keepsBridge) {
|
|
3810
|
-
restored[idx] = 1;
|
|
3811
|
-
}
|
|
3812
|
-
}
|
|
3813
|
-
}
|
|
3814
|
-
return restored;
|
|
3815
|
-
};
|
|
3816
|
-
const erodePreservingBridges = (m, radiusPx) => {
|
|
3817
|
-
const eroded = erodeDiamond(m, radiusPx);
|
|
3818
|
-
return restoreBridgePixels(m, eroded);
|
|
3819
|
-
};
|
|
3820
|
-
switch (op) {
|
|
3821
|
-
case "dilate":
|
|
3822
|
-
return dilateDisk(mask, r);
|
|
3823
|
-
case "erode":
|
|
3824
|
-
return erodePreservingBridges(mask, r);
|
|
3825
|
-
case "closing": {
|
|
3826
|
-
const erodeRadius = Math.max(1, Math.floor(r * 0.65));
|
|
3827
|
-
return erodePreservingBridges(dilateDisk(mask, r), erodeRadius);
|
|
3828
|
-
}
|
|
3829
|
-
case "opening":
|
|
3830
|
-
return dilateDisk(erodePreservingBridges(mask, r), r);
|
|
3831
|
-
default:
|
|
3832
|
-
return mask;
|
|
3833
|
-
}
|
|
3834
|
-
}
|
|
3835
|
-
function fillHoles(mask, width, height) {
|
|
3836
|
-
const background = new Uint8Array(width * height);
|
|
3837
|
-
const queue = [];
|
|
3838
|
-
for (let x = 0; x < width; x++) {
|
|
3839
|
-
if (mask[x] === 0) {
|
|
3840
|
-
background[x] = 1;
|
|
3841
|
-
queue.push(x);
|
|
3842
|
-
}
|
|
3843
|
-
const lastRowIdx = (height - 1) * width + x;
|
|
3844
|
-
if (mask[lastRowIdx] === 0) {
|
|
3845
|
-
background[lastRowIdx] = 1;
|
|
3846
|
-
queue.push(lastRowIdx);
|
|
3847
|
-
}
|
|
3848
|
-
}
|
|
3849
|
-
for (let y = 1; y < height - 1; y++) {
|
|
3850
|
-
const leftIdx = y * width;
|
|
3851
|
-
const rightIdx = y * width + (width - 1);
|
|
3852
|
-
if (mask[leftIdx] === 0) {
|
|
3853
|
-
background[leftIdx] = 1;
|
|
3854
|
-
queue.push(leftIdx);
|
|
3855
|
-
}
|
|
3856
|
-
if (mask[rightIdx] === 0) {
|
|
3857
|
-
background[rightIdx] = 1;
|
|
3858
|
-
queue.push(rightIdx);
|
|
3859
|
-
}
|
|
3860
|
-
}
|
|
3861
|
-
let head = 0;
|
|
3862
|
-
while (head < queue.length) {
|
|
3863
|
-
const idx = queue[head++];
|
|
3864
|
-
const x = idx % width;
|
|
3865
|
-
const y = (idx - x) / width;
|
|
3866
|
-
const up = y > 0 ? idx - width : -1;
|
|
3867
|
-
const down = y < height - 1 ? idx + width : -1;
|
|
3868
|
-
const left = x > 0 ? idx - 1 : -1;
|
|
3869
|
-
const right = x < width - 1 ? idx + 1 : -1;
|
|
3870
|
-
if (up >= 0 && mask[up] === 0 && background[up] === 0) {
|
|
3871
|
-
background[up] = 1;
|
|
3872
|
-
queue.push(up);
|
|
3873
|
-
}
|
|
3874
|
-
if (down >= 0 && mask[down] === 0 && background[down] === 0) {
|
|
3875
|
-
background[down] = 1;
|
|
3876
|
-
queue.push(down);
|
|
3877
|
-
}
|
|
3878
|
-
if (left >= 0 && mask[left] === 0 && background[left] === 0) {
|
|
3879
|
-
background[left] = 1;
|
|
3880
|
-
queue.push(left);
|
|
3881
|
-
}
|
|
3882
|
-
if (right >= 0 && mask[right] === 0 && background[right] === 0) {
|
|
3883
|
-
background[right] = 1;
|
|
3884
|
-
queue.push(right);
|
|
3885
|
-
}
|
|
3886
|
-
}
|
|
3887
|
-
const filledMask = new Uint8Array(width * height);
|
|
3888
|
-
for (let i = 0; i < width * height; i++) {
|
|
3889
|
-
filledMask[i] = background[i] === 0 ? 1 : 0;
|
|
3890
|
-
}
|
|
3891
|
-
return filledMask;
|
|
3892
|
-
}
|
|
3893
|
-
function polygonSignedArea(points) {
|
|
3894
|
-
if (points.length < 3) return 0;
|
|
3895
|
-
let sum = 0;
|
|
3896
|
-
for (let i = 0; i < points.length; i++) {
|
|
3897
|
-
const a = points[i];
|
|
3898
|
-
const b = points[(i + 1) % points.length];
|
|
3899
|
-
sum += a.x * b.y - b.x * a.y;
|
|
3900
|
-
}
|
|
3901
|
-
return sum / 2;
|
|
3902
|
-
}
|
|
3903
|
-
|
|
3904
|
-
// src/extensions/tracer.ts
|
|
3905
|
-
var ImageTracer = class {
|
|
3906
|
-
/**
|
|
3907
|
-
* Main entry point: Traces an image URL to an SVG path string.
|
|
3908
|
-
* @param imageUrl The URL or Base64 string of the image.
|
|
3909
|
-
* @param options Configuration options.
|
|
3910
|
-
*/
|
|
3911
|
-
static async trace(imageUrl, options = {}) {
|
|
3912
|
-
const { pathData } = await this.traceWithBounds(imageUrl, options);
|
|
3913
|
-
return pathData;
|
|
3914
|
-
}
|
|
3915
|
-
static async traceWithBounds(imageUrl, options = {}) {
|
|
3916
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
3917
|
-
const img = await this.loadImage(imageUrl);
|
|
3918
|
-
const width = img.width;
|
|
3919
|
-
const height = img.height;
|
|
3920
|
-
if (width <= 0 || height <= 0) {
|
|
3921
|
-
const w = (_a = options.scaleToWidth) != null ? _a : 0;
|
|
3922
|
-
const h = (_b = options.scaleToHeight) != null ? _b : 0;
|
|
3923
|
-
return {
|
|
3924
|
-
pathData: `M 0 0 L ${w} 0 L ${w} ${h} L 0 ${h} Z`,
|
|
3925
|
-
baseBounds: { x: 0, y: 0, width: w, height: h },
|
|
3926
|
-
bounds: { x: 0, y: 0, width: w, height: h }
|
|
3927
|
-
};
|
|
3928
|
-
}
|
|
3929
|
-
const debug = options.debug === true;
|
|
3930
|
-
const debugLog = (message, payload) => {
|
|
3931
|
-
if (!debug) return;
|
|
3932
|
-
if (payload) {
|
|
3933
|
-
console.info(`[ImageTracer] ${message}`, payload);
|
|
3934
|
-
return;
|
|
3935
|
-
}
|
|
3936
|
-
console.info(`[ImageTracer] ${message}`);
|
|
3937
|
-
};
|
|
3938
|
-
const canvas = document.createElement("canvas");
|
|
3939
|
-
canvas.width = width;
|
|
3940
|
-
canvas.height = height;
|
|
3941
|
-
const ctx = canvas.getContext("2d");
|
|
3942
|
-
if (!ctx) throw new Error("Could not get 2D context");
|
|
3943
|
-
ctx.drawImage(img, 0, 0);
|
|
3944
|
-
const imageData = ctx.getImageData(0, 0, width, height);
|
|
3945
|
-
const threshold = (_c = options.threshold) != null ? _c : 10;
|
|
3946
|
-
const expand = Math.max(0, Math.floor((_d = options.expand) != null ? _d : 0));
|
|
3947
|
-
const simplifyTolerance = (_e = options.simplifyTolerance) != null ? _e : 2.5;
|
|
3948
|
-
const useSmoothing = options.smoothing !== false;
|
|
3949
|
-
const componentMode = "all";
|
|
3950
|
-
const minComponentArea = 0;
|
|
3951
|
-
const maxDim = Math.max(width, height);
|
|
3952
|
-
const maskMode = "auto";
|
|
3953
|
-
const whiteThreshold = 240;
|
|
3954
|
-
const alphaOpaqueCutoff = 250;
|
|
3955
|
-
const preprocessDilateRadius = Math.max(
|
|
3956
|
-
2,
|
|
3957
|
-
Math.floor(Math.max(maxDim * 0.012, expand * 0.35))
|
|
3958
|
-
);
|
|
3959
|
-
const preprocessErodeRadius = Math.max(
|
|
3960
|
-
1,
|
|
3961
|
-
Math.floor(preprocessDilateRadius * 0.65)
|
|
3962
|
-
);
|
|
3963
|
-
const smoothDilateRadius = Math.max(
|
|
3964
|
-
1,
|
|
3965
|
-
Math.floor(preprocessDilateRadius * 0.25)
|
|
3966
|
-
);
|
|
3967
|
-
const smoothErodeRadius = Math.max(1, Math.floor(smoothDilateRadius * 0.8));
|
|
3968
|
-
const connectStartDilateRadius = Math.max(
|
|
3969
|
-
1,
|
|
3970
|
-
Math.floor(Math.max(maxDim * 6e-3, expand * 0.2))
|
|
3971
|
-
);
|
|
3972
|
-
const connectMaxDilateRadius = Math.max(
|
|
3973
|
-
connectStartDilateRadius,
|
|
3974
|
-
Math.floor(Math.max(maxDim * 0.2, expand * 2.5))
|
|
3975
|
-
);
|
|
3976
|
-
const connectErodeRatio = 0.65;
|
|
3977
|
-
debugLog("traceWithBounds:start", {
|
|
3978
|
-
width,
|
|
3979
|
-
height,
|
|
3980
|
-
threshold,
|
|
3981
|
-
expand,
|
|
3982
|
-
simplifyTolerance,
|
|
3983
|
-
smoothing: useSmoothing,
|
|
3984
|
-
strategy: {
|
|
3985
|
-
maskMode,
|
|
3986
|
-
whiteThreshold,
|
|
3987
|
-
alphaOpaqueCutoff,
|
|
3988
|
-
fillHoles: true,
|
|
3989
|
-
preprocessDilateRadius,
|
|
3990
|
-
preprocessErodeRadius,
|
|
3991
|
-
smoothDilateRadius,
|
|
3992
|
-
smoothErodeRadius,
|
|
3993
|
-
connectEnabled: true,
|
|
3994
|
-
connectStartDilateRadius,
|
|
3995
|
-
connectMaxDilateRadius,
|
|
3996
|
-
connectErodeRatio
|
|
3997
|
-
}
|
|
3998
|
-
});
|
|
3999
|
-
const padding = Math.max(
|
|
4000
|
-
preprocessDilateRadius,
|
|
4001
|
-
smoothDilateRadius,
|
|
4002
|
-
connectMaxDilateRadius,
|
|
4003
|
-
expand
|
|
4004
|
-
) + 2;
|
|
4005
|
-
const paddedWidth = width + padding * 2;
|
|
4006
|
-
const paddedHeight = height + padding * 2;
|
|
4007
|
-
const summarizeMaskContours = (m) => {
|
|
4008
|
-
const summary = this.summarizeAllContours(
|
|
4009
|
-
m,
|
|
4010
|
-
paddedWidth,
|
|
4011
|
-
paddedHeight,
|
|
4012
|
-
minComponentArea
|
|
4013
|
-
);
|
|
4014
|
-
return {
|
|
4015
|
-
rawContourCount: summary.rawCount,
|
|
4016
|
-
selectedContourCount: summary.selectedCount
|
|
4017
|
-
};
|
|
4018
|
-
};
|
|
4019
|
-
let mask = createMask(imageData, {
|
|
4020
|
-
threshold,
|
|
4021
|
-
padding,
|
|
4022
|
-
paddedWidth,
|
|
4023
|
-
paddedHeight,
|
|
4024
|
-
maskMode,
|
|
4025
|
-
whiteThreshold,
|
|
4026
|
-
alphaOpaqueCutoff
|
|
4027
|
-
});
|
|
4028
|
-
if (debug) {
|
|
4029
|
-
debugLog(
|
|
4030
|
-
"traceWithBounds:mask:after-create",
|
|
4031
|
-
summarizeMaskContours(mask)
|
|
4032
|
-
);
|
|
4033
|
-
}
|
|
4034
|
-
mask = circularMorphology(
|
|
4035
|
-
mask,
|
|
4036
|
-
paddedWidth,
|
|
4037
|
-
paddedHeight,
|
|
4038
|
-
preprocessDilateRadius,
|
|
4039
|
-
"dilate"
|
|
4040
|
-
);
|
|
4041
|
-
mask = fillHoles(mask, paddedWidth, paddedHeight);
|
|
4042
|
-
mask = circularMorphology(
|
|
4043
|
-
mask,
|
|
4044
|
-
paddedWidth,
|
|
4045
|
-
paddedHeight,
|
|
4046
|
-
preprocessErodeRadius,
|
|
4047
|
-
"erode"
|
|
4048
|
-
);
|
|
4049
|
-
mask = fillHoles(mask, paddedWidth, paddedHeight);
|
|
4050
|
-
if (debug) {
|
|
4051
|
-
debugLog("traceWithBounds:mask:after-preprocess", {
|
|
4052
|
-
dilateRadius: preprocessDilateRadius,
|
|
4053
|
-
erodeRadius: preprocessErodeRadius,
|
|
4054
|
-
...summarizeMaskContours(mask)
|
|
4055
|
-
});
|
|
4056
|
-
}
|
|
4057
|
-
mask = circularMorphology(
|
|
4058
|
-
mask,
|
|
4059
|
-
paddedWidth,
|
|
4060
|
-
paddedHeight,
|
|
4061
|
-
smoothDilateRadius,
|
|
4062
|
-
"dilate"
|
|
4063
|
-
);
|
|
4064
|
-
mask = fillHoles(mask, paddedWidth, paddedHeight);
|
|
4065
|
-
mask = circularMorphology(
|
|
4066
|
-
mask,
|
|
4067
|
-
paddedWidth,
|
|
4068
|
-
paddedHeight,
|
|
4069
|
-
smoothErodeRadius,
|
|
4070
|
-
"erode"
|
|
4071
|
-
);
|
|
4072
|
-
mask = fillHoles(mask, paddedWidth, paddedHeight);
|
|
4073
|
-
if (debug) {
|
|
4074
|
-
debugLog("traceWithBounds:mask:after-smooth", {
|
|
4075
|
-
dilateRadius: smoothDilateRadius,
|
|
4076
|
-
erodeRadius: smoothErodeRadius,
|
|
4077
|
-
...summarizeMaskContours(mask)
|
|
4078
|
-
});
|
|
4079
|
-
}
|
|
4080
|
-
const beforeConnectSummary = summarizeMaskContours(mask);
|
|
4081
|
-
if (beforeConnectSummary.selectedContourCount <= 1) {
|
|
4082
|
-
debugLog("traceWithBounds:mask:connect-skipped", {
|
|
4083
|
-
reason: "already-single-component",
|
|
4084
|
-
before: beforeConnectSummary
|
|
4085
|
-
});
|
|
4086
|
-
} else {
|
|
4087
|
-
const connectResult = this.findForceConnectResult(
|
|
4088
|
-
mask,
|
|
4089
|
-
paddedWidth,
|
|
4090
|
-
paddedHeight,
|
|
4091
|
-
minComponentArea,
|
|
4092
|
-
connectStartDilateRadius,
|
|
4093
|
-
connectMaxDilateRadius,
|
|
4094
|
-
connectErodeRatio
|
|
4095
|
-
);
|
|
4096
|
-
if (debug) {
|
|
4097
|
-
debugLog("traceWithBounds:mask:after-connect", {
|
|
4098
|
-
before: beforeConnectSummary,
|
|
4099
|
-
appliedDilateRadius: connectResult.appliedDilateRadius,
|
|
4100
|
-
appliedErodeRadius: connectResult.appliedErodeRadius,
|
|
4101
|
-
reachedSingleComponent: connectResult.reachedSingleComponent,
|
|
4102
|
-
after: {
|
|
4103
|
-
rawContourCount: connectResult.rawContourCount,
|
|
4104
|
-
selectedContourCount: connectResult.selectedContourCount
|
|
3849
|
+
// src/extensions/dieline/commands.ts
|
|
3850
|
+
function createDielineCommands(tool, state) {
|
|
3851
|
+
return [
|
|
3852
|
+
{
|
|
3853
|
+
command: "updateFeaturePosition",
|
|
3854
|
+
id: "updateFeaturePosition",
|
|
3855
|
+
title: "Update Feature Position",
|
|
3856
|
+
handler: (groupId, x, y) => {
|
|
3857
|
+
var _a;
|
|
3858
|
+
const configService = (_a = tool.context) == null ? void 0 : _a.services.get("ConfigurationService");
|
|
3859
|
+
if (!configService) return;
|
|
3860
|
+
const features = configService.get("dieline.features") || [];
|
|
3861
|
+
let changed = false;
|
|
3862
|
+
const newFeatures = features.map((f) => {
|
|
3863
|
+
if (f.groupId === groupId) {
|
|
3864
|
+
if (f.x !== x || f.y !== y) {
|
|
3865
|
+
changed = true;
|
|
3866
|
+
return { ...f, x, y };
|
|
3867
|
+
}
|
|
4105
3868
|
}
|
|
3869
|
+
return f;
|
|
4106
3870
|
});
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
}
|
|
4110
|
-
if (debug) {
|
|
4111
|
-
const afterConnectSummary = summarizeMaskContours(mask);
|
|
4112
|
-
if (afterConnectSummary.selectedContourCount > 1) {
|
|
4113
|
-
debugLog("traceWithBounds:mask:connect-warning", {
|
|
4114
|
-
reason: "still-multi-component-after-connect-search",
|
|
4115
|
-
summary: afterConnectSummary
|
|
4116
|
-
});
|
|
4117
|
-
}
|
|
4118
|
-
}
|
|
4119
|
-
const baseMask = mask;
|
|
4120
|
-
const baseContoursRaw = this.traceAllContours(
|
|
4121
|
-
baseMask,
|
|
4122
|
-
paddedWidth,
|
|
4123
|
-
paddedHeight
|
|
4124
|
-
);
|
|
4125
|
-
const baseContours = this.selectContours(
|
|
4126
|
-
baseContoursRaw,
|
|
4127
|
-
componentMode,
|
|
4128
|
-
minComponentArea
|
|
4129
|
-
);
|
|
4130
|
-
if (!baseContours.length) {
|
|
4131
|
-
const w = (_f = options.scaleToWidth) != null ? _f : width;
|
|
4132
|
-
const h = (_g = options.scaleToHeight) != null ? _g : height;
|
|
4133
|
-
debugLog("fallback:no-base-contour", { width: w, height: h });
|
|
4134
|
-
return {
|
|
4135
|
-
pathData: `M 0 0 L ${w} 0 L ${w} ${h} L 0 ${h} Z`,
|
|
4136
|
-
baseBounds: { x: 0, y: 0, width: w, height: h },
|
|
4137
|
-
bounds: { x: 0, y: 0, width: w, height: h }
|
|
4138
|
-
};
|
|
4139
|
-
}
|
|
4140
|
-
const baseUnpaddedContours = baseContours.map(
|
|
4141
|
-
(contour) => contour.map((p) => ({
|
|
4142
|
-
x: p.x - padding,
|
|
4143
|
-
y: p.y - padding
|
|
4144
|
-
}))
|
|
4145
|
-
).filter((contour) => contour.length > 2);
|
|
4146
|
-
if (!baseUnpaddedContours.length) {
|
|
4147
|
-
const w = (_h = options.scaleToWidth) != null ? _h : width;
|
|
4148
|
-
const h = (_i = options.scaleToHeight) != null ? _i : height;
|
|
4149
|
-
debugLog("fallback:empty-base-contours", { width: w, height: h });
|
|
4150
|
-
return {
|
|
4151
|
-
pathData: `M 0 0 L ${w} 0 L ${w} ${h} L 0 ${h} Z`,
|
|
4152
|
-
baseBounds: { x: 0, y: 0, width: w, height: h },
|
|
4153
|
-
bounds: { x: 0, y: 0, width: w, height: h }
|
|
4154
|
-
};
|
|
4155
|
-
}
|
|
4156
|
-
let baseBounds = this.boundsFromPoints(
|
|
4157
|
-
this.flattenContours(baseUnpaddedContours)
|
|
4158
|
-
);
|
|
4159
|
-
let maskExpanded = baseMask;
|
|
4160
|
-
if (expand > 0) {
|
|
4161
|
-
maskExpanded = circularMorphology(
|
|
4162
|
-
baseMask,
|
|
4163
|
-
paddedWidth,
|
|
4164
|
-
paddedHeight,
|
|
4165
|
-
expand,
|
|
4166
|
-
"dilate"
|
|
4167
|
-
);
|
|
4168
|
-
}
|
|
4169
|
-
const expandedContoursRaw = this.traceAllContours(
|
|
4170
|
-
maskExpanded,
|
|
4171
|
-
paddedWidth,
|
|
4172
|
-
paddedHeight
|
|
4173
|
-
);
|
|
4174
|
-
const expandedContours = this.selectContours(
|
|
4175
|
-
expandedContoursRaw,
|
|
4176
|
-
componentMode,
|
|
4177
|
-
minComponentArea
|
|
4178
|
-
);
|
|
4179
|
-
if (!expandedContours.length) {
|
|
4180
|
-
debugLog("fallback:no-expanded-contour", {
|
|
4181
|
-
baseBounds,
|
|
4182
|
-
width,
|
|
4183
|
-
height,
|
|
4184
|
-
expand
|
|
4185
|
-
});
|
|
4186
|
-
return {
|
|
4187
|
-
pathData: `M 0 0 L ${width} 0 L ${width} ${height} L 0 ${height} Z`,
|
|
4188
|
-
baseBounds,
|
|
4189
|
-
bounds: baseBounds
|
|
4190
|
-
};
|
|
4191
|
-
}
|
|
4192
|
-
const expandedUnpaddedContours = expandedContours.map(
|
|
4193
|
-
(contour) => contour.map((p) => ({
|
|
4194
|
-
x: p.x - padding,
|
|
4195
|
-
y: p.y - padding
|
|
4196
|
-
}))
|
|
4197
|
-
).filter((contour) => contour.length > 2);
|
|
4198
|
-
if (!expandedUnpaddedContours.length) {
|
|
4199
|
-
debugLog("fallback:empty-expanded-contours", {
|
|
4200
|
-
baseBounds,
|
|
4201
|
-
width,
|
|
4202
|
-
height,
|
|
4203
|
-
expand
|
|
4204
|
-
});
|
|
4205
|
-
return {
|
|
4206
|
-
pathData: `M 0 0 L ${width} 0 L ${width} ${height} L 0 ${height} Z`,
|
|
4207
|
-
baseBounds,
|
|
4208
|
-
bounds: baseBounds
|
|
4209
|
-
};
|
|
4210
|
-
}
|
|
4211
|
-
let globalBounds = this.boundsFromPoints(
|
|
4212
|
-
this.flattenContours(expandedUnpaddedContours)
|
|
4213
|
-
);
|
|
4214
|
-
let finalContours = expandedUnpaddedContours;
|
|
4215
|
-
if (options.scaleToWidth && options.scaleToHeight) {
|
|
4216
|
-
finalContours = this.scaleContours(
|
|
4217
|
-
expandedUnpaddedContours,
|
|
4218
|
-
options.scaleToWidth,
|
|
4219
|
-
options.scaleToHeight,
|
|
4220
|
-
globalBounds
|
|
4221
|
-
);
|
|
4222
|
-
globalBounds = this.boundsFromPoints(this.flattenContours(finalContours));
|
|
4223
|
-
const baseScaledContours = this.scaleContours(
|
|
4224
|
-
baseUnpaddedContours,
|
|
4225
|
-
options.scaleToWidth,
|
|
4226
|
-
options.scaleToHeight,
|
|
4227
|
-
baseBounds
|
|
4228
|
-
);
|
|
4229
|
-
baseBounds = this.boundsFromPoints(
|
|
4230
|
-
this.flattenContours(baseScaledContours)
|
|
4231
|
-
);
|
|
4232
|
-
}
|
|
4233
|
-
if (expand > 0) {
|
|
4234
|
-
const expectedExpandedBounds = {
|
|
4235
|
-
x: baseBounds.x - expand,
|
|
4236
|
-
y: baseBounds.y - expand,
|
|
4237
|
-
width: baseBounds.width + expand * 2,
|
|
4238
|
-
height: baseBounds.height + expand * 2
|
|
4239
|
-
};
|
|
4240
|
-
if (expectedExpandedBounds.width > 0 && expectedExpandedBounds.height > 0 && globalBounds.width > 0 && globalBounds.height > 0) {
|
|
4241
|
-
const shouldNormalizeExpandBounds = Math.abs(globalBounds.x - expectedExpandedBounds.x) > 1 || Math.abs(globalBounds.y - expectedExpandedBounds.y) > 1 || Math.abs(globalBounds.width - expectedExpandedBounds.width) > 1 || Math.abs(globalBounds.height - expectedExpandedBounds.height) > 1;
|
|
4242
|
-
if (shouldNormalizeExpandBounds) {
|
|
4243
|
-
const beforeNormalize = globalBounds;
|
|
4244
|
-
finalContours = this.translateContours(
|
|
4245
|
-
this.scaleContours(
|
|
4246
|
-
finalContours,
|
|
4247
|
-
expectedExpandedBounds.width,
|
|
4248
|
-
expectedExpandedBounds.height,
|
|
4249
|
-
globalBounds
|
|
4250
|
-
),
|
|
4251
|
-
expectedExpandedBounds.x,
|
|
4252
|
-
expectedExpandedBounds.y
|
|
4253
|
-
);
|
|
4254
|
-
globalBounds = this.boundsFromPoints(
|
|
4255
|
-
this.flattenContours(finalContours)
|
|
4256
|
-
);
|
|
4257
|
-
debugLog("traceWithBounds:expand-normalized", {
|
|
4258
|
-
expand,
|
|
4259
|
-
expectedExpandedBounds,
|
|
4260
|
-
beforeNormalize,
|
|
4261
|
-
afterNormalize: globalBounds
|
|
4262
|
-
});
|
|
3871
|
+
if (changed) {
|
|
3872
|
+
configService.update("dieline.features", newFeatures);
|
|
4263
3873
|
}
|
|
4264
3874
|
}
|
|
4265
|
-
}
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
expandedBounds: globalBounds,
|
|
4273
|
-
expandedDeltaX: globalBounds.width - baseBounds.width,
|
|
4274
|
-
expandedDeltaY: globalBounds.height - baseBounds.height,
|
|
4275
|
-
expandedMayOverflowImageBounds: expand > 0,
|
|
4276
|
-
useSmoothing,
|
|
4277
|
-
componentMode
|
|
4278
|
-
});
|
|
4279
|
-
if (useSmoothing) {
|
|
4280
|
-
return {
|
|
4281
|
-
pathData: this.contoursToSVGPaper(finalContours, simplifyTolerance),
|
|
4282
|
-
baseBounds,
|
|
4283
|
-
bounds: globalBounds
|
|
4284
|
-
};
|
|
4285
|
-
} else {
|
|
4286
|
-
const simplifiedContours = finalContours.map((points) => this.douglasPeucker(points, simplifyTolerance)).filter((points) => points.length > 2);
|
|
4287
|
-
const pathData = this.contoursToSVG(simplifiedContours) || this.contoursToSVG(finalContours);
|
|
4288
|
-
return {
|
|
4289
|
-
pathData,
|
|
4290
|
-
baseBounds,
|
|
4291
|
-
bounds: globalBounds
|
|
4292
|
-
};
|
|
4293
|
-
}
|
|
4294
|
-
}
|
|
4295
|
-
static pickPrimaryContour(contours) {
|
|
4296
|
-
if (contours.length === 0) return null;
|
|
4297
|
-
return contours.reduce((best, cur) => {
|
|
4298
|
-
if (!best) return cur;
|
|
4299
|
-
const bestArea = Math.abs(polygonSignedArea(best));
|
|
4300
|
-
const curArea = Math.abs(polygonSignedArea(cur));
|
|
4301
|
-
if (curArea !== bestArea) return curArea > bestArea ? cur : best;
|
|
4302
|
-
return cur.length > best.length ? cur : best;
|
|
4303
|
-
}, contours[0]);
|
|
4304
|
-
}
|
|
4305
|
-
static flattenContours(contours) {
|
|
4306
|
-
return contours.flatMap((contour) => contour);
|
|
4307
|
-
}
|
|
4308
|
-
static contourCentroid(points) {
|
|
4309
|
-
if (!points.length) return { x: 0, y: 0 };
|
|
4310
|
-
const sum = points.reduce(
|
|
4311
|
-
(acc, p) => ({ x: acc.x + p.x, y: acc.y + p.y }),
|
|
4312
|
-
{ x: 0, y: 0 }
|
|
4313
|
-
);
|
|
4314
|
-
return {
|
|
4315
|
-
x: sum.x / points.length,
|
|
4316
|
-
y: sum.y / points.length
|
|
4317
|
-
};
|
|
4318
|
-
}
|
|
4319
|
-
static pointInPolygon(point, polygon) {
|
|
4320
|
-
let inside = false;
|
|
4321
|
-
const { x, y } = point;
|
|
4322
|
-
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
|
|
4323
|
-
const xi = polygon[i].x;
|
|
4324
|
-
const yi = polygon[i].y;
|
|
4325
|
-
const xj = polygon[j].x;
|
|
4326
|
-
const yj = polygon[j].y;
|
|
4327
|
-
const intersects = yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi || Number.EPSILON) + xi;
|
|
4328
|
-
if (intersects) inside = !inside;
|
|
4329
|
-
}
|
|
4330
|
-
return inside;
|
|
4331
|
-
}
|
|
4332
|
-
static keepOutermostContours(contours) {
|
|
4333
|
-
if (contours.length <= 1) return contours;
|
|
4334
|
-
const sorted = [...contours].sort(
|
|
4335
|
-
(a, b) => Math.abs(polygonSignedArea(b)) - Math.abs(polygonSignedArea(a))
|
|
4336
|
-
);
|
|
4337
|
-
const selected = [];
|
|
4338
|
-
for (const contour of sorted) {
|
|
4339
|
-
const centroid = this.contourCentroid(contour);
|
|
4340
|
-
const isNested = selected.some(
|
|
4341
|
-
(outer) => this.pointInPolygon(centroid, outer)
|
|
4342
|
-
);
|
|
4343
|
-
if (!isNested) {
|
|
4344
|
-
selected.push(contour);
|
|
4345
|
-
}
|
|
4346
|
-
}
|
|
4347
|
-
return selected;
|
|
4348
|
-
}
|
|
4349
|
-
static summarizeAllContours(mask, width, height, minComponentArea) {
|
|
4350
|
-
const raw = this.traceAllContours(mask, width, height);
|
|
4351
|
-
const selected = this.selectContours(raw, "all", minComponentArea);
|
|
4352
|
-
return {
|
|
4353
|
-
rawCount: raw.length,
|
|
4354
|
-
selectedCount: selected.length
|
|
4355
|
-
};
|
|
4356
|
-
}
|
|
4357
|
-
static findForceConnectResult(sourceMask, width, height, minComponentArea, startDilateRadius, maxDilateRadius, erodeRatio) {
|
|
4358
|
-
const initial = this.summarizeAllContours(
|
|
4359
|
-
sourceMask,
|
|
4360
|
-
width,
|
|
4361
|
-
height,
|
|
4362
|
-
minComponentArea
|
|
4363
|
-
);
|
|
4364
|
-
if (initial.selectedCount <= 1) {
|
|
4365
|
-
return {
|
|
4366
|
-
mask: sourceMask,
|
|
4367
|
-
appliedDilateRadius: 0,
|
|
4368
|
-
appliedErodeRadius: 0,
|
|
4369
|
-
reachedSingleComponent: true,
|
|
4370
|
-
rawContourCount: initial.rawCount,
|
|
4371
|
-
selectedContourCount: initial.selectedCount
|
|
4372
|
-
};
|
|
4373
|
-
}
|
|
4374
|
-
const normalizedStart = Math.max(1, Math.floor(startDilateRadius));
|
|
4375
|
-
const normalizedMax = Math.max(
|
|
4376
|
-
normalizedStart,
|
|
4377
|
-
Math.floor(maxDilateRadius)
|
|
4378
|
-
);
|
|
4379
|
-
const normalizedErodeRatio = Math.max(0, erodeRatio);
|
|
4380
|
-
const evaluate = (dilateRadius) => {
|
|
4381
|
-
const erodeRadius = Math.max(
|
|
4382
|
-
1,
|
|
4383
|
-
Math.floor(dilateRadius * normalizedErodeRatio)
|
|
4384
|
-
);
|
|
4385
|
-
let mask = sourceMask;
|
|
4386
|
-
mask = circularMorphology(mask, width, height, dilateRadius, "dilate");
|
|
4387
|
-
mask = fillHoles(mask, width, height);
|
|
4388
|
-
mask = circularMorphology(mask, width, height, erodeRadius, "erode");
|
|
4389
|
-
mask = fillHoles(mask, width, height);
|
|
4390
|
-
const summary = this.summarizeAllContours(
|
|
4391
|
-
mask,
|
|
4392
|
-
width,
|
|
4393
|
-
height,
|
|
4394
|
-
minComponentArea
|
|
4395
|
-
);
|
|
4396
|
-
return {
|
|
4397
|
-
dilateRadius,
|
|
4398
|
-
erodeRadius,
|
|
4399
|
-
mask,
|
|
4400
|
-
rawCount: summary.rawCount,
|
|
4401
|
-
selectedCount: summary.selectedCount
|
|
4402
|
-
};
|
|
4403
|
-
};
|
|
4404
|
-
let low = normalizedStart - 1;
|
|
4405
|
-
let high = normalizedStart;
|
|
4406
|
-
let highResult = evaluate(high);
|
|
4407
|
-
while (high < normalizedMax && highResult.selectedCount > 1) {
|
|
4408
|
-
low = high;
|
|
4409
|
-
high = Math.min(
|
|
4410
|
-
normalizedMax,
|
|
4411
|
-
Math.max(high + 1, Math.floor(high * 1.6))
|
|
4412
|
-
);
|
|
4413
|
-
highResult = evaluate(high);
|
|
4414
|
-
}
|
|
4415
|
-
if (highResult.selectedCount > 1) {
|
|
4416
|
-
return {
|
|
4417
|
-
mask: highResult.mask,
|
|
4418
|
-
appliedDilateRadius: highResult.dilateRadius,
|
|
4419
|
-
appliedErodeRadius: highResult.erodeRadius,
|
|
4420
|
-
reachedSingleComponent: false,
|
|
4421
|
-
rawContourCount: highResult.rawCount,
|
|
4422
|
-
selectedContourCount: highResult.selectedCount
|
|
4423
|
-
};
|
|
4424
|
-
}
|
|
4425
|
-
let best = highResult;
|
|
4426
|
-
while (low + 1 < high) {
|
|
4427
|
-
const mid = Math.floor((low + high) / 2);
|
|
4428
|
-
const midResult = evaluate(mid);
|
|
4429
|
-
if (midResult.selectedCount <= 1) {
|
|
4430
|
-
best = midResult;
|
|
4431
|
-
high = mid;
|
|
4432
|
-
} else {
|
|
4433
|
-
low = mid;
|
|
3875
|
+
},
|
|
3876
|
+
{
|
|
3877
|
+
command: "exportCutImage",
|
|
3878
|
+
id: "exportCutImage",
|
|
3879
|
+
title: "Export Cut Image",
|
|
3880
|
+
handler: (options) => {
|
|
3881
|
+
return tool.exportCutImage(options);
|
|
4434
3882
|
}
|
|
4435
|
-
}
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
x: minX,
|
|
4480
|
-
y: minY,
|
|
4481
|
-
width: maxX - minX,
|
|
4482
|
-
height: maxY - minY
|
|
4483
|
-
};
|
|
4484
|
-
}
|
|
4485
|
-
/**
|
|
4486
|
-
* Traces all contours in the mask with optimized start-point detection
|
|
4487
|
-
*/
|
|
4488
|
-
static traceAllContours(mask, width, height) {
|
|
4489
|
-
const visited = new Uint8Array(width * height);
|
|
4490
|
-
const allContours = [];
|
|
4491
|
-
for (let y = 0; y < height; y++) {
|
|
4492
|
-
for (let x = 0; x < width; x++) {
|
|
4493
|
-
const idx = y * width + x;
|
|
4494
|
-
if (mask[idx] && !visited[idx]) {
|
|
4495
|
-
const isLeftEdge = x === 0 || mask[idx - 1] === 0;
|
|
4496
|
-
if (isLeftEdge) {
|
|
4497
|
-
const contour = this.marchingSquares(
|
|
4498
|
-
mask,
|
|
4499
|
-
visited,
|
|
4500
|
-
x,
|
|
4501
|
-
y,
|
|
4502
|
-
width,
|
|
4503
|
-
height
|
|
4504
|
-
);
|
|
4505
|
-
if (contour.length > 2) {
|
|
4506
|
-
allContours.push(contour);
|
|
4507
|
-
}
|
|
3883
|
+
},
|
|
3884
|
+
{
|
|
3885
|
+
command: "detectEdge",
|
|
3886
|
+
id: "detectEdge",
|
|
3887
|
+
title: "Detect Edge from Image",
|
|
3888
|
+
handler: async (imageUrl, options) => {
|
|
3889
|
+
var _a, _b, _c;
|
|
3890
|
+
try {
|
|
3891
|
+
const detectOptions = options || {};
|
|
3892
|
+
const debug = detectOptions.debug === true;
|
|
3893
|
+
const tracerOptions = {
|
|
3894
|
+
expand: (_a = detectOptions.expand) != null ? _a : 0,
|
|
3895
|
+
smoothing: (_b = detectOptions.smoothing) != null ? _b : true,
|
|
3896
|
+
simplifyTolerance: (_c = detectOptions.simplifyTolerance) != null ? _c : 2,
|
|
3897
|
+
threshold: detectOptions.threshold,
|
|
3898
|
+
debug
|
|
3899
|
+
};
|
|
3900
|
+
const loadImage = (url) => {
|
|
3901
|
+
return new Promise((resolve, reject) => {
|
|
3902
|
+
const img2 = new Image();
|
|
3903
|
+
img2.crossOrigin = "Anonymous";
|
|
3904
|
+
img2.onload = () => resolve(img2);
|
|
3905
|
+
img2.onerror = (e) => reject(e);
|
|
3906
|
+
img2.src = url;
|
|
3907
|
+
});
|
|
3908
|
+
};
|
|
3909
|
+
const [img, traced] = await Promise.all([
|
|
3910
|
+
loadImage(imageUrl),
|
|
3911
|
+
import("./tracer-PO7CRBYY.mjs").then(
|
|
3912
|
+
({ ImageTracer }) => ImageTracer.traceWithBounds(imageUrl, tracerOptions)
|
|
3913
|
+
)
|
|
3914
|
+
]);
|
|
3915
|
+
const { pathData, baseBounds, bounds } = traced;
|
|
3916
|
+
if (debug) {
|
|
3917
|
+
console.info("[DielineTool] detectEdge", {
|
|
3918
|
+
imageWidth: img.width,
|
|
3919
|
+
imageHeight: img.height,
|
|
3920
|
+
baseBounds,
|
|
3921
|
+
expandedBounds: bounds,
|
|
3922
|
+
currentDielineWidth: state.width,
|
|
3923
|
+
currentDielineHeight: state.height,
|
|
3924
|
+
options: tracerOptions,
|
|
3925
|
+
strategy: "single-connected-silhouette"
|
|
3926
|
+
});
|
|
4508
3927
|
}
|
|
3928
|
+
return {
|
|
3929
|
+
pathData,
|
|
3930
|
+
rawBounds: bounds,
|
|
3931
|
+
baseBounds,
|
|
3932
|
+
imageWidth: img.width,
|
|
3933
|
+
imageHeight: img.height
|
|
3934
|
+
};
|
|
3935
|
+
} catch (e) {
|
|
3936
|
+
console.error("Edge detection failed", e);
|
|
3937
|
+
throw e;
|
|
4509
3938
|
}
|
|
4510
3939
|
}
|
|
4511
3940
|
}
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
const scaleX = targetWidth / bounds.width;
|
|
4617
|
-
const scaleY = targetHeight / bounds.height;
|
|
4618
|
-
return points.map((p) => ({
|
|
4619
|
-
x: (p.x - bounds.x) * scaleX,
|
|
4620
|
-
y: (p.y - bounds.y) * scaleY
|
|
4621
|
-
}));
|
|
4622
|
-
}
|
|
4623
|
-
static scaleContours(contours, targetWidth, targetHeight, bounds) {
|
|
4624
|
-
return contours.map(
|
|
4625
|
-
(points) => this.scalePoints(points, targetWidth, targetHeight, bounds)
|
|
4626
|
-
);
|
|
4627
|
-
}
|
|
4628
|
-
static translateContours(contours, offsetX, offsetY) {
|
|
4629
|
-
return contours.map(
|
|
4630
|
-
(points) => points.map((p) => ({
|
|
4631
|
-
x: p.x + offsetX,
|
|
4632
|
-
y: p.y + offsetY
|
|
4633
|
-
}))
|
|
4634
|
-
);
|
|
4635
|
-
}
|
|
4636
|
-
static pointsToSVG(points) {
|
|
4637
|
-
if (points.length === 0) return "";
|
|
4638
|
-
const head = points[0];
|
|
4639
|
-
const tail = points.slice(1);
|
|
4640
|
-
return `M ${head.x} ${head.y} ` + tail.map((p) => `L ${p.x} ${p.y}`).join(" ") + " Z";
|
|
4641
|
-
}
|
|
4642
|
-
static contoursToSVG(contours) {
|
|
4643
|
-
return contours.filter((points) => points.length > 2).map((points) => this.pointsToSVG(points)).join(" ").trim();
|
|
4644
|
-
}
|
|
4645
|
-
static ensurePaper() {
|
|
4646
|
-
if (!paper2.project) {
|
|
4647
|
-
paper2.setup(new paper2.Size(100, 100));
|
|
4648
|
-
}
|
|
4649
|
-
}
|
|
4650
|
-
static pointsToSVGPaper(points, tolerance) {
|
|
4651
|
-
if (points.length < 3) return this.pointsToSVG(points);
|
|
4652
|
-
this.ensurePaper();
|
|
4653
|
-
const path = new paper2.Path({
|
|
4654
|
-
segments: points.map((p) => [p.x, p.y]),
|
|
4655
|
-
closed: true
|
|
4656
|
-
});
|
|
4657
|
-
path.simplify(tolerance);
|
|
4658
|
-
const data = path.pathData;
|
|
4659
|
-
path.remove();
|
|
4660
|
-
return data;
|
|
4661
|
-
}
|
|
4662
|
-
static contoursToSVGPaper(contours, tolerance) {
|
|
4663
|
-
const normalizedContours = contours.filter((points) => points.length > 2);
|
|
4664
|
-
if (!normalizedContours.length) return "";
|
|
4665
|
-
if (normalizedContours.length === 1) {
|
|
4666
|
-
return this.pointsToSVGPaper(normalizedContours[0], tolerance);
|
|
4667
|
-
}
|
|
4668
|
-
this.ensurePaper();
|
|
4669
|
-
const compound = new paper2.CompoundPath({ insert: false });
|
|
4670
|
-
for (const points of normalizedContours) {
|
|
4671
|
-
const child = new paper2.Path({
|
|
4672
|
-
segments: points.map((p) => [p.x, p.y]),
|
|
4673
|
-
closed: true,
|
|
4674
|
-
insert: false
|
|
4675
|
-
});
|
|
4676
|
-
child.simplify(tolerance);
|
|
4677
|
-
compound.addChild(child);
|
|
3941
|
+
];
|
|
3942
|
+
}
|
|
3943
|
+
|
|
3944
|
+
// src/extensions/dieline/config.ts
|
|
3945
|
+
function createDielineConfigurations(state) {
|
|
3946
|
+
return [
|
|
3947
|
+
{
|
|
3948
|
+
id: "dieline.shape",
|
|
3949
|
+
type: "select",
|
|
3950
|
+
label: "Shape",
|
|
3951
|
+
options: Array.from(DIELINE_SHAPES),
|
|
3952
|
+
default: state.shape
|
|
3953
|
+
},
|
|
3954
|
+
{
|
|
3955
|
+
id: "dieline.radius",
|
|
3956
|
+
type: "number",
|
|
3957
|
+
label: "Corner Radius (mm)",
|
|
3958
|
+
min: 0,
|
|
3959
|
+
max: 500,
|
|
3960
|
+
default: state.radius
|
|
3961
|
+
},
|
|
3962
|
+
{
|
|
3963
|
+
id: "dieline.shapeStyle",
|
|
3964
|
+
type: "json",
|
|
3965
|
+
label: "Shape Style",
|
|
3966
|
+
default: state.shapeStyle
|
|
3967
|
+
},
|
|
3968
|
+
{
|
|
3969
|
+
id: "dieline.showBleedLines",
|
|
3970
|
+
type: "boolean",
|
|
3971
|
+
label: "Show Bleed Lines",
|
|
3972
|
+
default: state.showBleedLines
|
|
3973
|
+
},
|
|
3974
|
+
{
|
|
3975
|
+
id: "dieline.strokeWidth",
|
|
3976
|
+
type: "number",
|
|
3977
|
+
label: "Line Width",
|
|
3978
|
+
min: 0.1,
|
|
3979
|
+
max: 10,
|
|
3980
|
+
step: 0.1,
|
|
3981
|
+
default: state.mainLine.width
|
|
3982
|
+
},
|
|
3983
|
+
{
|
|
3984
|
+
id: "dieline.strokeColor",
|
|
3985
|
+
type: "color",
|
|
3986
|
+
label: "Line Color",
|
|
3987
|
+
default: state.mainLine.color
|
|
3988
|
+
},
|
|
3989
|
+
{
|
|
3990
|
+
id: "dieline.dashLength",
|
|
3991
|
+
type: "number",
|
|
3992
|
+
label: "Dash Length",
|
|
3993
|
+
min: 1,
|
|
3994
|
+
max: 50,
|
|
3995
|
+
default: state.mainLine.dashLength
|
|
3996
|
+
},
|
|
3997
|
+
{
|
|
3998
|
+
id: "dieline.style",
|
|
3999
|
+
type: "select",
|
|
4000
|
+
label: "Line Style",
|
|
4001
|
+
options: ["solid", "dashed", "hidden"],
|
|
4002
|
+
default: state.mainLine.style
|
|
4003
|
+
},
|
|
4004
|
+
{
|
|
4005
|
+
id: "dieline.offsetStrokeWidth",
|
|
4006
|
+
type: "number",
|
|
4007
|
+
label: "Offset Line Width",
|
|
4008
|
+
min: 0.1,
|
|
4009
|
+
max: 10,
|
|
4010
|
+
step: 0.1,
|
|
4011
|
+
default: state.offsetLine.width
|
|
4012
|
+
},
|
|
4013
|
+
{
|
|
4014
|
+
id: "dieline.offsetStrokeColor",
|
|
4015
|
+
type: "color",
|
|
4016
|
+
label: "Offset Line Color",
|
|
4017
|
+
default: state.offsetLine.color
|
|
4018
|
+
},
|
|
4019
|
+
{
|
|
4020
|
+
id: "dieline.offsetDashLength",
|
|
4021
|
+
type: "number",
|
|
4022
|
+
label: "Offset Dash Length",
|
|
4023
|
+
min: 1,
|
|
4024
|
+
max: 50,
|
|
4025
|
+
default: state.offsetLine.dashLength
|
|
4026
|
+
},
|
|
4027
|
+
{
|
|
4028
|
+
id: "dieline.offsetStyle",
|
|
4029
|
+
type: "select",
|
|
4030
|
+
label: "Offset Line Style",
|
|
4031
|
+
options: ["solid", "dashed", "hidden"],
|
|
4032
|
+
default: state.offsetLine.style
|
|
4033
|
+
},
|
|
4034
|
+
{
|
|
4035
|
+
id: "dieline.insideColor",
|
|
4036
|
+
type: "color",
|
|
4037
|
+
label: "Inside Color",
|
|
4038
|
+
default: state.insideColor
|
|
4039
|
+
},
|
|
4040
|
+
{
|
|
4041
|
+
id: "dieline.features",
|
|
4042
|
+
type: "json",
|
|
4043
|
+
label: "Edge Features",
|
|
4044
|
+
default: state.features
|
|
4678
4045
|
}
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
return data;
|
|
4682
|
-
}
|
|
4683
|
-
};
|
|
4046
|
+
];
|
|
4047
|
+
}
|
|
4684
4048
|
|
|
4685
|
-
// src/extensions/dieline.ts
|
|
4686
|
-
var IMAGE_OBJECT_LAYER_ID2 = "image.user";
|
|
4687
|
-
var DIELINE_LAYER_ID = "dieline-overlay";
|
|
4049
|
+
// src/extensions/dieline/DielineTool.ts
|
|
4688
4050
|
var DielineTool = class {
|
|
4689
4051
|
constructor(options) {
|
|
4690
4052
|
this.id = "pooder.kit.dieline";
|
|
@@ -4925,208 +4287,20 @@ var DielineTool = class {
|
|
|
4925
4287
|
this.context = void 0;
|
|
4926
4288
|
}
|
|
4927
4289
|
contribute() {
|
|
4928
|
-
const s = this.state;
|
|
4929
4290
|
return {
|
|
4930
4291
|
[ContributionPointIds4.TOOLS]: [
|
|
4931
4292
|
{
|
|
4932
4293
|
id: this.id,
|
|
4933
4294
|
name: "Dieline",
|
|
4934
|
-
interaction: "session",
|
|
4935
|
-
session: {
|
|
4936
|
-
autoBegin: false,
|
|
4937
|
-
leavePolicy: "block"
|
|
4938
|
-
}
|
|
4939
|
-
}
|
|
4940
|
-
],
|
|
4941
|
-
[ContributionPointIds4.CONFIGURATIONS]: [
|
|
4942
|
-
{
|
|
4943
|
-
id: "dieline.shape",
|
|
4944
|
-
type: "select",
|
|
4945
|
-
label: "Shape",
|
|
4946
|
-
options: Array.from(DIELINE_SHAPES),
|
|
4947
|
-
default: s.shape
|
|
4948
|
-
},
|
|
4949
|
-
{
|
|
4950
|
-
id: "dieline.radius",
|
|
4951
|
-
type: "number",
|
|
4952
|
-
label: "Corner Radius (mm)",
|
|
4953
|
-
min: 0,
|
|
4954
|
-
max: 500,
|
|
4955
|
-
default: s.radius
|
|
4956
|
-
},
|
|
4957
|
-
{
|
|
4958
|
-
id: "dieline.shapeStyle",
|
|
4959
|
-
type: "json",
|
|
4960
|
-
label: "Shape Style",
|
|
4961
|
-
default: s.shapeStyle
|
|
4962
|
-
},
|
|
4963
|
-
{
|
|
4964
|
-
id: "dieline.showBleedLines",
|
|
4965
|
-
type: "boolean",
|
|
4966
|
-
label: "Show Bleed Lines",
|
|
4967
|
-
default: s.showBleedLines
|
|
4968
|
-
},
|
|
4969
|
-
{
|
|
4970
|
-
id: "dieline.strokeWidth",
|
|
4971
|
-
type: "number",
|
|
4972
|
-
label: "Line Width",
|
|
4973
|
-
min: 0.1,
|
|
4974
|
-
max: 10,
|
|
4975
|
-
step: 0.1,
|
|
4976
|
-
default: s.mainLine.width
|
|
4977
|
-
},
|
|
4978
|
-
{
|
|
4979
|
-
id: "dieline.strokeColor",
|
|
4980
|
-
type: "color",
|
|
4981
|
-
label: "Line Color",
|
|
4982
|
-
default: s.mainLine.color
|
|
4983
|
-
},
|
|
4984
|
-
{
|
|
4985
|
-
id: "dieline.dashLength",
|
|
4986
|
-
type: "number",
|
|
4987
|
-
label: "Dash Length",
|
|
4988
|
-
min: 1,
|
|
4989
|
-
max: 50,
|
|
4990
|
-
default: s.mainLine.dashLength
|
|
4991
|
-
},
|
|
4992
|
-
{
|
|
4993
|
-
id: "dieline.style",
|
|
4994
|
-
type: "select",
|
|
4995
|
-
label: "Line Style",
|
|
4996
|
-
options: ["solid", "dashed", "hidden"],
|
|
4997
|
-
default: s.mainLine.style
|
|
4998
|
-
},
|
|
4999
|
-
{
|
|
5000
|
-
id: "dieline.offsetStrokeWidth",
|
|
5001
|
-
type: "number",
|
|
5002
|
-
label: "Offset Line Width",
|
|
5003
|
-
min: 0.1,
|
|
5004
|
-
max: 10,
|
|
5005
|
-
step: 0.1,
|
|
5006
|
-
default: s.offsetLine.width
|
|
5007
|
-
},
|
|
5008
|
-
{
|
|
5009
|
-
id: "dieline.offsetStrokeColor",
|
|
5010
|
-
type: "color",
|
|
5011
|
-
label: "Offset Line Color",
|
|
5012
|
-
default: s.offsetLine.color
|
|
5013
|
-
},
|
|
5014
|
-
{
|
|
5015
|
-
id: "dieline.offsetDashLength",
|
|
5016
|
-
type: "number",
|
|
5017
|
-
label: "Offset Dash Length",
|
|
5018
|
-
min: 1,
|
|
5019
|
-
max: 50,
|
|
5020
|
-
default: s.offsetLine.dashLength
|
|
5021
|
-
},
|
|
5022
|
-
{
|
|
5023
|
-
id: "dieline.offsetStyle",
|
|
5024
|
-
type: "select",
|
|
5025
|
-
label: "Offset Line Style",
|
|
5026
|
-
options: ["solid", "dashed", "hidden"],
|
|
5027
|
-
default: s.offsetLine.style
|
|
5028
|
-
},
|
|
5029
|
-
{
|
|
5030
|
-
id: "dieline.insideColor",
|
|
5031
|
-
type: "color",
|
|
5032
|
-
label: "Inside Color",
|
|
5033
|
-
default: s.insideColor
|
|
5034
|
-
},
|
|
5035
|
-
{
|
|
5036
|
-
id: "dieline.features",
|
|
5037
|
-
type: "json",
|
|
5038
|
-
label: "Edge Features",
|
|
5039
|
-
default: s.features
|
|
5040
|
-
}
|
|
5041
|
-
],
|
|
5042
|
-
[ContributionPointIds4.COMMANDS]: [
|
|
5043
|
-
{
|
|
5044
|
-
command: "updateFeaturePosition",
|
|
5045
|
-
title: "Update Feature Position",
|
|
5046
|
-
handler: (groupId, x, y) => {
|
|
5047
|
-
var _a;
|
|
5048
|
-
const configService = (_a = this.context) == null ? void 0 : _a.services.get(
|
|
5049
|
-
"ConfigurationService"
|
|
5050
|
-
);
|
|
5051
|
-
if (!configService) return;
|
|
5052
|
-
const features = configService.get("dieline.features") || [];
|
|
5053
|
-
let changed = false;
|
|
5054
|
-
const newFeatures = features.map((f) => {
|
|
5055
|
-
if (f.groupId === groupId) {
|
|
5056
|
-
if (f.x !== x || f.y !== y) {
|
|
5057
|
-
changed = true;
|
|
5058
|
-
return { ...f, x, y };
|
|
5059
|
-
}
|
|
5060
|
-
}
|
|
5061
|
-
return f;
|
|
5062
|
-
});
|
|
5063
|
-
if (changed) {
|
|
5064
|
-
configService.update("dieline.features", newFeatures);
|
|
5065
|
-
}
|
|
5066
|
-
}
|
|
5067
|
-
},
|
|
5068
|
-
{
|
|
5069
|
-
command: "exportCutImage",
|
|
5070
|
-
title: "Export Cut Image",
|
|
5071
|
-
handler: (options) => {
|
|
5072
|
-
return this.exportCutImage(options);
|
|
5073
|
-
}
|
|
5074
|
-
},
|
|
5075
|
-
{
|
|
5076
|
-
command: "detectEdge",
|
|
5077
|
-
title: "Detect Edge from Image",
|
|
5078
|
-
handler: async (imageUrl, options) => {
|
|
5079
|
-
var _a, _b, _c;
|
|
5080
|
-
try {
|
|
5081
|
-
const detectOptions = options || {};
|
|
5082
|
-
const debug = detectOptions.debug === true;
|
|
5083
|
-
const tracerOptions = {
|
|
5084
|
-
expand: (_a = detectOptions.expand) != null ? _a : 0,
|
|
5085
|
-
smoothing: (_b = detectOptions.smoothing) != null ? _b : true,
|
|
5086
|
-
simplifyTolerance: (_c = detectOptions.simplifyTolerance) != null ? _c : 2,
|
|
5087
|
-
threshold: detectOptions.threshold,
|
|
5088
|
-
debug
|
|
5089
|
-
};
|
|
5090
|
-
const loadImage = (url) => {
|
|
5091
|
-
return new Promise((resolve, reject) => {
|
|
5092
|
-
const img2 = new Image();
|
|
5093
|
-
img2.crossOrigin = "Anonymous";
|
|
5094
|
-
img2.onload = () => resolve(img2);
|
|
5095
|
-
img2.onerror = (e) => reject(e);
|
|
5096
|
-
img2.src = url;
|
|
5097
|
-
});
|
|
5098
|
-
};
|
|
5099
|
-
const [img, traced] = await Promise.all([
|
|
5100
|
-
loadImage(imageUrl),
|
|
5101
|
-
ImageTracer.traceWithBounds(imageUrl, tracerOptions)
|
|
5102
|
-
]);
|
|
5103
|
-
const { pathData, baseBounds, bounds } = traced;
|
|
5104
|
-
if (debug) {
|
|
5105
|
-
console.info("[DielineTool] detectEdge", {
|
|
5106
|
-
imageWidth: img.width,
|
|
5107
|
-
imageHeight: img.height,
|
|
5108
|
-
baseBounds,
|
|
5109
|
-
expandedBounds: bounds,
|
|
5110
|
-
currentDielineWidth: s.width,
|
|
5111
|
-
currentDielineHeight: s.height,
|
|
5112
|
-
options: tracerOptions,
|
|
5113
|
-
strategy: "single-connected-silhouette"
|
|
5114
|
-
});
|
|
5115
|
-
}
|
|
5116
|
-
return {
|
|
5117
|
-
pathData,
|
|
5118
|
-
rawBounds: bounds,
|
|
5119
|
-
baseBounds,
|
|
5120
|
-
imageWidth: img.width,
|
|
5121
|
-
imageHeight: img.height
|
|
5122
|
-
};
|
|
5123
|
-
} catch (e) {
|
|
5124
|
-
console.error("Edge detection failed", e);
|
|
5125
|
-
throw e;
|
|
5126
|
-
}
|
|
4295
|
+
interaction: "session",
|
|
4296
|
+
session: {
|
|
4297
|
+
autoBegin: false,
|
|
4298
|
+
leavePolicy: "block"
|
|
5127
4299
|
}
|
|
5128
4300
|
}
|
|
5129
|
-
]
|
|
4301
|
+
],
|
|
4302
|
+
[ContributionPointIds4.CONFIGURATIONS]: createDielineConfigurations(this.state),
|
|
4303
|
+
[ContributionPointIds4.COMMANDS]: createDielineCommands(this, this.state)
|
|
5130
4304
|
};
|
|
5131
4305
|
}
|
|
5132
4306
|
createHatchPattern(color = "rgba(0, 0, 0, 0.3)") {
|
|
@@ -5404,7 +4578,7 @@ var DielineTool = class {
|
|
|
5404
4578
|
op: "not",
|
|
5405
4579
|
expr: { op: "anySessionActive" }
|
|
5406
4580
|
},
|
|
5407
|
-
targetPassIds: [
|
|
4581
|
+
targetPassIds: [IMAGE_OBJECT_LAYER_ID],
|
|
5408
4582
|
source: {
|
|
5409
4583
|
id: "dieline.effect.clip-path",
|
|
5410
4584
|
type: "path",
|
|
@@ -5569,7 +4743,7 @@ var DielineTool = class {
|
|
|
5569
4743
|
const exportBounds = pathBounds;
|
|
5570
4744
|
const sourceImages = this.canvasService.canvas.getObjects().filter((obj) => {
|
|
5571
4745
|
var _a2;
|
|
5572
|
-
return ((_a2 = obj == null ? void 0 : obj.data) == null ? void 0 : _a2.layerId) ===
|
|
4746
|
+
return ((_a2 = obj == null ? void 0 : obj.data) == null ? void 0 : _a2.layerId) === IMAGE_OBJECT_LAYER_ID;
|
|
5573
4747
|
});
|
|
5574
4748
|
if (!sourceImages.length) {
|
|
5575
4749
|
console.warn(
|
|
@@ -5641,7 +4815,7 @@ var DielineTool = class {
|
|
|
5641
4815
|
}
|
|
5642
4816
|
};
|
|
5643
4817
|
|
|
5644
|
-
// src/extensions/feature.ts
|
|
4818
|
+
// src/extensions/feature/FeatureTool.ts
|
|
5645
4819
|
import {
|
|
5646
4820
|
ContributionPointIds as ContributionPointIds5
|
|
5647
4821
|
} from "@pooder/core";
|
|
@@ -5843,8 +5017,7 @@ function completeFeaturesStrict(features, context, update) {
|
|
|
5843
5017
|
return { ok: true };
|
|
5844
5018
|
}
|
|
5845
5019
|
|
|
5846
|
-
// src/extensions/feature.ts
|
|
5847
|
-
var FEATURE_OVERLAY_LAYER_ID = "feature-overlay";
|
|
5020
|
+
// src/extensions/feature/FeatureTool.ts
|
|
5848
5021
|
var FEATURE_STROKE_WIDTH = 2;
|
|
5849
5022
|
var DEFAULT_RECT_SIZE = 10;
|
|
5850
5023
|
var DEFAULT_CIRCLE_RADIUS = 5;
|
|
@@ -5862,6 +5035,7 @@ var FeatureTool = class {
|
|
|
5862
5035
|
this.hasWorkingChanges = false;
|
|
5863
5036
|
this.specs = [];
|
|
5864
5037
|
this.renderSeq = 0;
|
|
5038
|
+
this.subscriptions = new SubscriptionBag();
|
|
5865
5039
|
this.handleMoving = null;
|
|
5866
5040
|
this.handleModified = null;
|
|
5867
5041
|
this.handleSceneGeometryChange = null;
|
|
@@ -5879,6 +5053,7 @@ var FeatureTool = class {
|
|
|
5879
5053
|
}
|
|
5880
5054
|
activate(context) {
|
|
5881
5055
|
var _a;
|
|
5056
|
+
this.subscriptions.disposeAll();
|
|
5882
5057
|
this.context = context;
|
|
5883
5058
|
this.canvasService = context.services.get("CanvasService");
|
|
5884
5059
|
if (!this.canvasService) {
|
|
@@ -5907,29 +5082,32 @@ var FeatureTool = class {
|
|
|
5907
5082
|
const features = configService.get("dieline.features", []) || [];
|
|
5908
5083
|
this.workingFeatures = this.cloneFeatures(features);
|
|
5909
5084
|
this.hasWorkingChanges = false;
|
|
5910
|
-
|
|
5911
|
-
|
|
5912
|
-
|
|
5913
|
-
if (this.
|
|
5914
|
-
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
|
|
5085
|
+
this.subscriptions.onConfigChange(
|
|
5086
|
+
configService,
|
|
5087
|
+
(e) => {
|
|
5088
|
+
if (this.isUpdatingConfig) return;
|
|
5089
|
+
if (e.key === "dieline.features") {
|
|
5090
|
+
if (this.isFeatureSessionActive) return;
|
|
5091
|
+
const next = e.value || [];
|
|
5092
|
+
this.workingFeatures = this.cloneFeatures(next);
|
|
5093
|
+
this.hasWorkingChanges = false;
|
|
5094
|
+
this.redraw();
|
|
5095
|
+
this.emitWorkingChange();
|
|
5096
|
+
}
|
|
5919
5097
|
}
|
|
5920
|
-
|
|
5098
|
+
);
|
|
5921
5099
|
}
|
|
5922
5100
|
const toolSessionService = context.services.get("ToolSessionService");
|
|
5923
5101
|
this.dirtyTrackerDisposable = toolSessionService == null ? void 0 : toolSessionService.registerDirtyTracker(
|
|
5924
5102
|
this.id,
|
|
5925
5103
|
() => this.hasWorkingChanges
|
|
5926
5104
|
);
|
|
5927
|
-
|
|
5105
|
+
this.subscriptions.on(context.eventBus, "tool:activated", this.onToolActivated);
|
|
5928
5106
|
this.setup();
|
|
5929
5107
|
}
|
|
5930
5108
|
deactivate(context) {
|
|
5931
5109
|
var _a;
|
|
5932
|
-
|
|
5110
|
+
this.subscriptions.disposeAll();
|
|
5933
5111
|
this.restoreSessionFeaturesToConfig();
|
|
5934
5112
|
(_a = this.dirtyTrackerDisposable) == null ? void 0 : _a.dispose();
|
|
5935
5113
|
this.dirtyTrackerDisposable = void 0;
|
|
@@ -6072,7 +5250,7 @@ var FeatureTool = class {
|
|
|
6072
5250
|
};
|
|
6073
5251
|
}
|
|
6074
5252
|
cloneFeatures(features) {
|
|
6075
|
-
return
|
|
5253
|
+
return cloneWithJson(features || []);
|
|
6076
5254
|
}
|
|
6077
5255
|
getConfigService() {
|
|
6078
5256
|
var _a;
|
|
@@ -6756,12 +5934,11 @@ var FeatureTool = class {
|
|
|
6756
5934
|
}
|
|
6757
5935
|
};
|
|
6758
5936
|
|
|
6759
|
-
// src/extensions/film.ts
|
|
5937
|
+
// src/extensions/film/FilmTool.ts
|
|
6760
5938
|
import {
|
|
6761
5939
|
ContributionPointIds as ContributionPointIds6
|
|
6762
5940
|
} from "@pooder/core";
|
|
6763
5941
|
import { FabricImage as FabricImage3 } from "fabric";
|
|
6764
|
-
var FILM_LAYER_ID = "overlay";
|
|
6765
5942
|
var FILM_IMAGE_ID = "film-image";
|
|
6766
5943
|
var DEFAULT_WIDTH2 = 800;
|
|
6767
5944
|
var DEFAULT_HEIGHT2 = 600;
|
|
@@ -6776,8 +5953,10 @@ var FilmTool = class {
|
|
|
6776
5953
|
this.specs = [];
|
|
6777
5954
|
this.renderSeq = 0;
|
|
6778
5955
|
this.renderImageUrl = "";
|
|
6779
|
-
this.
|
|
6780
|
-
|
|
5956
|
+
this.sourceSizeCache = createSourceSizeCache(
|
|
5957
|
+
(src) => this.loadImageSize(src)
|
|
5958
|
+
);
|
|
5959
|
+
this.subscriptions = new SubscriptionBag();
|
|
6781
5960
|
this.onCanvasResized = () => {
|
|
6782
5961
|
this.updateFilm();
|
|
6783
5962
|
};
|
|
@@ -6787,6 +5966,7 @@ var FilmTool = class {
|
|
|
6787
5966
|
}
|
|
6788
5967
|
activate(context) {
|
|
6789
5968
|
var _a;
|
|
5969
|
+
this.subscriptions.disposeAll();
|
|
6790
5970
|
this.canvasService = context.services.get("CanvasService");
|
|
6791
5971
|
if (!this.canvasService) {
|
|
6792
5972
|
console.warn("CanvasService not found for FilmTool");
|
|
@@ -6813,28 +5993,32 @@ var FilmTool = class {
|
|
|
6813
5993
|
if (configService) {
|
|
6814
5994
|
this.url = configService.get("film.url", this.url);
|
|
6815
5995
|
this.opacity = configService.get("film.opacity", this.opacity);
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
|
|
6823
|
-
|
|
6824
|
-
this
|
|
5996
|
+
this.subscriptions.onConfigChange(
|
|
5997
|
+
configService,
|
|
5998
|
+
(e) => {
|
|
5999
|
+
if (e.key.startsWith("film.")) {
|
|
6000
|
+
const prop = e.key.split(".")[1];
|
|
6001
|
+
console.log(
|
|
6002
|
+
`[FilmTool] Config change detected: ${e.key} -> ${e.value}`
|
|
6003
|
+
);
|
|
6004
|
+
if (prop && prop in this) {
|
|
6005
|
+
this[prop] = e.value;
|
|
6006
|
+
this.updateFilm();
|
|
6007
|
+
}
|
|
6825
6008
|
}
|
|
6826
6009
|
}
|
|
6827
|
-
|
|
6010
|
+
);
|
|
6828
6011
|
}
|
|
6829
|
-
|
|
6012
|
+
this.subscriptions.on(context.eventBus, "canvas:resized", this.onCanvasResized);
|
|
6830
6013
|
this.updateFilm();
|
|
6831
6014
|
}
|
|
6832
6015
|
deactivate(context) {
|
|
6833
6016
|
var _a;
|
|
6834
|
-
|
|
6017
|
+
this.subscriptions.disposeAll();
|
|
6835
6018
|
this.renderSeq += 1;
|
|
6836
6019
|
this.specs = [];
|
|
6837
6020
|
this.renderImageUrl = "";
|
|
6021
|
+
this.sourceSizeCache.clear();
|
|
6838
6022
|
(_a = this.renderProducerDisposable) == null ? void 0 : _a.dispose();
|
|
6839
6023
|
this.renderProducerDisposable = void 0;
|
|
6840
6024
|
if (!this.canvasService) return;
|
|
@@ -6893,10 +6077,13 @@ var FilmTool = class {
|
|
|
6893
6077
|
return [];
|
|
6894
6078
|
}
|
|
6895
6079
|
const { width, height } = this.getViewportSize();
|
|
6896
|
-
const sourceSize = this.
|
|
6080
|
+
const sourceSize = this.sourceSizeCache.getSourceSize(imageUrl);
|
|
6897
6081
|
const sourceWidth = Math.max(1, Number((sourceSize == null ? void 0 : sourceSize.width) || width));
|
|
6898
6082
|
const sourceHeight = Math.max(1, Number((sourceSize == null ? void 0 : sourceSize.height) || height));
|
|
6899
|
-
const coverScale =
|
|
6083
|
+
const coverScale = getCoverScale(
|
|
6084
|
+
{ width, height },
|
|
6085
|
+
{ width: sourceWidth, height: sourceHeight }
|
|
6086
|
+
);
|
|
6900
6087
|
return [
|
|
6901
6088
|
{
|
|
6902
6089
|
id: FILM_IMAGE_ID,
|
|
@@ -6923,24 +6110,6 @@ var FilmTool = class {
|
|
|
6923
6110
|
}
|
|
6924
6111
|
];
|
|
6925
6112
|
}
|
|
6926
|
-
async ensureImageSize(src) {
|
|
6927
|
-
if (!src) return null;
|
|
6928
|
-
const cached = this.sourceSizeBySrc.get(src);
|
|
6929
|
-
if (cached) return cached;
|
|
6930
|
-
const pending = this.pendingSizeBySrc.get(src);
|
|
6931
|
-
if (pending) {
|
|
6932
|
-
return pending;
|
|
6933
|
-
}
|
|
6934
|
-
const task = this.loadImageSize(src);
|
|
6935
|
-
this.pendingSizeBySrc.set(src, task);
|
|
6936
|
-
try {
|
|
6937
|
-
return await task;
|
|
6938
|
-
} finally {
|
|
6939
|
-
if (this.pendingSizeBySrc.get(src) === task) {
|
|
6940
|
-
this.pendingSizeBySrc.delete(src);
|
|
6941
|
-
}
|
|
6942
|
-
}
|
|
6943
|
-
}
|
|
6944
6113
|
async loadImageSize(src) {
|
|
6945
6114
|
try {
|
|
6946
6115
|
const image = await FabricImage3.fromURL(src, {
|
|
@@ -6949,9 +6118,7 @@ var FilmTool = class {
|
|
|
6949
6118
|
const width = Number((image == null ? void 0 : image.width) || 0);
|
|
6950
6119
|
const height = Number((image == null ? void 0 : image.height) || 0);
|
|
6951
6120
|
if (width > 0 && height > 0) {
|
|
6952
|
-
|
|
6953
|
-
this.sourceSizeBySrc.set(src, size);
|
|
6954
|
-
return size;
|
|
6121
|
+
return { width, height };
|
|
6955
6122
|
}
|
|
6956
6123
|
} catch (error) {
|
|
6957
6124
|
console.error("[FilmTool] Failed to load film image", src, error);
|
|
@@ -6968,7 +6135,7 @@ var FilmTool = class {
|
|
|
6968
6135
|
if (!nextUrl) {
|
|
6969
6136
|
this.renderImageUrl = "";
|
|
6970
6137
|
} else if (nextUrl !== this.renderImageUrl) {
|
|
6971
|
-
const loaded = await this.ensureImageSize(nextUrl);
|
|
6138
|
+
const loaded = await this.sourceSizeCache.ensureImageSize(nextUrl);
|
|
6972
6139
|
if (seq !== this.renderSeq) return;
|
|
6973
6140
|
if (loaded) {
|
|
6974
6141
|
this.renderImageUrl = nextUrl;
|
|
@@ -6981,7 +6148,7 @@ var FilmTool = class {
|
|
|
6981
6148
|
}
|
|
6982
6149
|
};
|
|
6983
6150
|
|
|
6984
|
-
// src/extensions/mirror.ts
|
|
6151
|
+
// src/extensions/mirror/MirrorTool.ts
|
|
6985
6152
|
import {
|
|
6986
6153
|
ContributionPointIds as ContributionPointIds7
|
|
6987
6154
|
} from "@pooder/core";
|
|
@@ -7073,11 +6240,10 @@ var MirrorTool = class {
|
|
|
7073
6240
|
}
|
|
7074
6241
|
};
|
|
7075
6242
|
|
|
7076
|
-
// src/extensions/ruler.ts
|
|
6243
|
+
// src/extensions/ruler/RulerTool.ts
|
|
7077
6244
|
import {
|
|
7078
6245
|
ContributionPointIds as ContributionPointIds8
|
|
7079
6246
|
} from "@pooder/core";
|
|
7080
|
-
var RULER_LAYER_ID = "ruler-overlay";
|
|
7081
6247
|
var EXTENSION_LINE_LENGTH = 5;
|
|
7082
6248
|
var MIN_ARROW_SIZE = 4;
|
|
7083
6249
|
var THICKNESS_TO_STROKE_WIDTH_RATIO = 20;
|
|
@@ -7639,17 +6805,197 @@ var RulerTool = class {
|
|
|
7639
6805
|
}
|
|
7640
6806
|
};
|
|
7641
6807
|
|
|
7642
|
-
// src/extensions/white-ink.ts
|
|
6808
|
+
// src/extensions/white-ink/WhiteInkTool.ts
|
|
7643
6809
|
import {
|
|
7644
6810
|
ContributionPointIds as ContributionPointIds9
|
|
7645
6811
|
} from "@pooder/core";
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
var WHITE_INK_OVERLAY_LAYER_ID = "white-ink.overlay";
|
|
7649
|
-
var IMAGE_OBJECT_LAYER_ID3 = "image.user";
|
|
7650
|
-
var WHITE_INK_DEBUG_KEY = "whiteInk.debug";
|
|
6812
|
+
|
|
6813
|
+
// src/extensions/white-ink/commands.ts
|
|
7651
6814
|
var WHITE_INK_PREVIEW_IMAGE_VISIBLE_KEY = "whiteInk.previewImageVisible";
|
|
7652
6815
|
var WHITE_INK_DEFAULT_OPACITY = 0.85;
|
|
6816
|
+
function createWhiteInkCommands(tool) {
|
|
6817
|
+
return [
|
|
6818
|
+
{
|
|
6819
|
+
command: "addWhiteInk",
|
|
6820
|
+
id: "addWhiteInk",
|
|
6821
|
+
title: "Add White Ink",
|
|
6822
|
+
handler: async (url, options) => {
|
|
6823
|
+
return await tool.addWhiteInkEntry(url, options);
|
|
6824
|
+
}
|
|
6825
|
+
},
|
|
6826
|
+
{
|
|
6827
|
+
command: "upsertWhiteInk",
|
|
6828
|
+
id: "upsertWhiteInk",
|
|
6829
|
+
title: "Upsert White Ink",
|
|
6830
|
+
handler: async (url, options = {}) => {
|
|
6831
|
+
return await tool.upsertWhiteInkEntry(url, options);
|
|
6832
|
+
}
|
|
6833
|
+
},
|
|
6834
|
+
{
|
|
6835
|
+
command: "getWhiteInks",
|
|
6836
|
+
id: "getWhiteInks",
|
|
6837
|
+
title: "Get White Inks",
|
|
6838
|
+
handler: () => tool.cloneItems(tool.items)
|
|
6839
|
+
},
|
|
6840
|
+
{
|
|
6841
|
+
command: "getWhiteInkSettings",
|
|
6842
|
+
id: "getWhiteInkSettings",
|
|
6843
|
+
title: "Get White Ink Settings",
|
|
6844
|
+
handler: () => {
|
|
6845
|
+
const first = tool.getEffectiveWhiteInkItem(tool.items);
|
|
6846
|
+
const primarySource = tool.getPrimaryImageSource();
|
|
6847
|
+
const sourceUrl = tool.resolveSourceUrl(first) || primarySource;
|
|
6848
|
+
return {
|
|
6849
|
+
id: (first == null ? void 0 : first.id) || null,
|
|
6850
|
+
url: sourceUrl,
|
|
6851
|
+
sourceUrl,
|
|
6852
|
+
opacity: WHITE_INK_DEFAULT_OPACITY,
|
|
6853
|
+
printWithWhiteInk: tool.printWithWhiteInk,
|
|
6854
|
+
previewImageVisible: tool.previewImageVisible
|
|
6855
|
+
};
|
|
6856
|
+
}
|
|
6857
|
+
},
|
|
6858
|
+
{
|
|
6859
|
+
command: "setWhiteInkPrintEnabled",
|
|
6860
|
+
id: "setWhiteInkPrintEnabled",
|
|
6861
|
+
title: "Set White Ink Preview Enabled",
|
|
6862
|
+
handler: (enabled) => {
|
|
6863
|
+
var _a;
|
|
6864
|
+
tool.printWithWhiteInk = !!enabled;
|
|
6865
|
+
const configService = (_a = tool.context) == null ? void 0 : _a.services.get("ConfigurationService");
|
|
6866
|
+
configService == null ? void 0 : configService.update("whiteInk.printWithWhiteInk", tool.printWithWhiteInk);
|
|
6867
|
+
tool.updateWhiteInks();
|
|
6868
|
+
return { ok: true };
|
|
6869
|
+
}
|
|
6870
|
+
},
|
|
6871
|
+
{
|
|
6872
|
+
command: "setWhiteInkPreviewImageVisible",
|
|
6873
|
+
id: "setWhiteInkPreviewImageVisible",
|
|
6874
|
+
title: "Set White Ink Cover Visible",
|
|
6875
|
+
handler: (visible) => {
|
|
6876
|
+
var _a;
|
|
6877
|
+
tool.previewImageVisible = !!visible;
|
|
6878
|
+
const configService = (_a = tool.context) == null ? void 0 : _a.services.get("ConfigurationService");
|
|
6879
|
+
configService == null ? void 0 : configService.update(
|
|
6880
|
+
WHITE_INK_PREVIEW_IMAGE_VISIBLE_KEY,
|
|
6881
|
+
tool.previewImageVisible
|
|
6882
|
+
);
|
|
6883
|
+
tool.updateWhiteInks();
|
|
6884
|
+
return { ok: true };
|
|
6885
|
+
}
|
|
6886
|
+
},
|
|
6887
|
+
{
|
|
6888
|
+
command: "getWorkingWhiteInks",
|
|
6889
|
+
id: "getWorkingWhiteInks",
|
|
6890
|
+
title: "Get Working White Inks",
|
|
6891
|
+
handler: () => tool.cloneItems(tool.workingItems)
|
|
6892
|
+
},
|
|
6893
|
+
{
|
|
6894
|
+
command: "setWorkingWhiteInk",
|
|
6895
|
+
id: "setWorkingWhiteInk",
|
|
6896
|
+
title: "Set Working White Ink",
|
|
6897
|
+
handler: (id, updates) => {
|
|
6898
|
+
tool.updateWhiteInkInWorking(id, updates);
|
|
6899
|
+
}
|
|
6900
|
+
},
|
|
6901
|
+
{
|
|
6902
|
+
command: "updateWhiteInk",
|
|
6903
|
+
id: "updateWhiteInk",
|
|
6904
|
+
title: "Update White Ink",
|
|
6905
|
+
handler: async (id, updates, options = {}) => {
|
|
6906
|
+
await tool.updateWhiteInkItem(id, updates, options);
|
|
6907
|
+
}
|
|
6908
|
+
},
|
|
6909
|
+
{
|
|
6910
|
+
command: "removeWhiteInk",
|
|
6911
|
+
id: "removeWhiteInk",
|
|
6912
|
+
title: "Remove White Ink",
|
|
6913
|
+
handler: (id) => {
|
|
6914
|
+
tool.removeWhiteInk(id);
|
|
6915
|
+
}
|
|
6916
|
+
},
|
|
6917
|
+
{
|
|
6918
|
+
command: "clearWhiteInks",
|
|
6919
|
+
id: "clearWhiteInks",
|
|
6920
|
+
title: "Clear White Inks",
|
|
6921
|
+
handler: () => {
|
|
6922
|
+
tool.clearWhiteInks();
|
|
6923
|
+
}
|
|
6924
|
+
},
|
|
6925
|
+
{
|
|
6926
|
+
command: "resetWorkingWhiteInks",
|
|
6927
|
+
id: "resetWorkingWhiteInks",
|
|
6928
|
+
title: "Reset Working White Inks",
|
|
6929
|
+
handler: () => {
|
|
6930
|
+
tool.workingItems = tool.cloneItems(tool.items);
|
|
6931
|
+
tool.hasWorkingChanges = false;
|
|
6932
|
+
tool.updateWhiteInks();
|
|
6933
|
+
}
|
|
6934
|
+
},
|
|
6935
|
+
{
|
|
6936
|
+
command: "completeWhiteInks",
|
|
6937
|
+
id: "completeWhiteInks",
|
|
6938
|
+
title: "Complete White Inks",
|
|
6939
|
+
handler: async () => {
|
|
6940
|
+
return await tool.completeWhiteInks();
|
|
6941
|
+
}
|
|
6942
|
+
},
|
|
6943
|
+
{
|
|
6944
|
+
command: "setWhiteInkImage",
|
|
6945
|
+
id: "setWhiteInkImage",
|
|
6946
|
+
title: "Set White Ink Image",
|
|
6947
|
+
handler: async (url) => {
|
|
6948
|
+
if (!url) {
|
|
6949
|
+
tool.clearWhiteInks();
|
|
6950
|
+
return { ok: true };
|
|
6951
|
+
}
|
|
6952
|
+
const targetId = tool.resolveReplaceTargetId(null);
|
|
6953
|
+
const upsertResult = await tool.upsertWhiteInkEntry(url, {
|
|
6954
|
+
id: targetId || void 0,
|
|
6955
|
+
mode: targetId ? "replace" : "add",
|
|
6956
|
+
createIfMissing: true,
|
|
6957
|
+
addOptions: {}
|
|
6958
|
+
});
|
|
6959
|
+
return { ok: true, id: upsertResult.id };
|
|
6960
|
+
}
|
|
6961
|
+
}
|
|
6962
|
+
];
|
|
6963
|
+
}
|
|
6964
|
+
|
|
6965
|
+
// src/extensions/white-ink/config.ts
|
|
6966
|
+
function createWhiteInkConfigurations() {
|
|
6967
|
+
return [
|
|
6968
|
+
{
|
|
6969
|
+
id: "whiteInk.items",
|
|
6970
|
+
type: "array",
|
|
6971
|
+
label: "White Ink Images",
|
|
6972
|
+
default: []
|
|
6973
|
+
},
|
|
6974
|
+
{
|
|
6975
|
+
id: "whiteInk.printWithWhiteInk",
|
|
6976
|
+
type: "boolean",
|
|
6977
|
+
label: "Preview White Ink",
|
|
6978
|
+
default: true
|
|
6979
|
+
},
|
|
6980
|
+
{
|
|
6981
|
+
id: "whiteInk.previewImageVisible",
|
|
6982
|
+
type: "boolean",
|
|
6983
|
+
label: "Show Cover During White Ink Preview",
|
|
6984
|
+
default: true
|
|
6985
|
+
},
|
|
6986
|
+
{
|
|
6987
|
+
id: "whiteInk.debug",
|
|
6988
|
+
type: "boolean",
|
|
6989
|
+
label: "White Ink Debug Log",
|
|
6990
|
+
default: false
|
|
6991
|
+
}
|
|
6992
|
+
];
|
|
6993
|
+
}
|
|
6994
|
+
|
|
6995
|
+
// src/extensions/white-ink/WhiteInkTool.ts
|
|
6996
|
+
var WHITE_INK_DEBUG_KEY = "whiteInk.debug";
|
|
6997
|
+
var WHITE_INK_PREVIEW_IMAGE_VISIBLE_KEY2 = "whiteInk.previewImageVisible";
|
|
6998
|
+
var WHITE_INK_DEFAULT_OPACITY2 = 0.85;
|
|
7653
6999
|
var WHITE_INK_AUTO_ITEM_ID = "white-ink-auto";
|
|
7654
7000
|
var WHITE_INK_COVER_OPACITY_FACTOR = 0.45;
|
|
7655
7001
|
var WHITE_INK_COVER_OPACITY_MIN = 0.15;
|
|
@@ -7665,7 +7011,9 @@ var WhiteInkTool = class {
|
|
|
7665
7011
|
this.items = [];
|
|
7666
7012
|
this.workingItems = [];
|
|
7667
7013
|
this.hasWorkingChanges = false;
|
|
7668
|
-
this.
|
|
7014
|
+
this.sourceSizeCache = createSourceSizeCache(
|
|
7015
|
+
(src) => this.loadImageSize(src)
|
|
7016
|
+
);
|
|
7669
7017
|
this.previewMaskBySource = /* @__PURE__ */ new Map();
|
|
7670
7018
|
this.pendingPreviewMaskBySource = /* @__PURE__ */ new Map();
|
|
7671
7019
|
this.isUpdatingConfig = false;
|
|
@@ -7676,6 +7024,7 @@ var WhiteInkTool = class {
|
|
|
7676
7024
|
this.whiteSpecs = [];
|
|
7677
7025
|
this.coverSpecs = [];
|
|
7678
7026
|
this.overlaySpecs = [];
|
|
7027
|
+
this.subscriptions = new SubscriptionBag();
|
|
7679
7028
|
this.onToolActivated = (event) => {
|
|
7680
7029
|
const before = this.isToolActive;
|
|
7681
7030
|
this.syncToolActiveFromWorkbench(event.id);
|
|
@@ -7693,19 +7042,19 @@ var WhiteInkTool = class {
|
|
|
7693
7042
|
this.onObjectAdded = (e) => {
|
|
7694
7043
|
var _a, _b;
|
|
7695
7044
|
const layerId = (_b = (_a = e == null ? void 0 : e.target) == null ? void 0 : _a.data) == null ? void 0 : _b.layerId;
|
|
7696
|
-
if (layerId !==
|
|
7045
|
+
if (layerId !== IMAGE_OBJECT_LAYER_ID) return;
|
|
7697
7046
|
this.updateWhiteInks();
|
|
7698
7047
|
};
|
|
7699
7048
|
this.onObjectModified = (e) => {
|
|
7700
7049
|
var _a, _b;
|
|
7701
7050
|
const layerId = (_b = (_a = e == null ? void 0 : e.target) == null ? void 0 : _a.data) == null ? void 0 : _b.layerId;
|
|
7702
|
-
if (layerId !==
|
|
7051
|
+
if (layerId !== IMAGE_OBJECT_LAYER_ID) return;
|
|
7703
7052
|
this.updateWhiteInks();
|
|
7704
7053
|
};
|
|
7705
7054
|
this.onObjectRemoved = (e) => {
|
|
7706
7055
|
var _a, _b;
|
|
7707
7056
|
const layerId = (_b = (_a = e == null ? void 0 : e.target) == null ? void 0 : _a.data) == null ? void 0 : _b.layerId;
|
|
7708
|
-
if (layerId !==
|
|
7057
|
+
if (layerId !== IMAGE_OBJECT_LAYER_ID) return;
|
|
7709
7058
|
this.updateWhiteInks();
|
|
7710
7059
|
};
|
|
7711
7060
|
this.onImageWorkingChanged = () => {
|
|
@@ -7714,6 +7063,7 @@ var WhiteInkTool = class {
|
|
|
7714
7063
|
}
|
|
7715
7064
|
activate(context) {
|
|
7716
7065
|
var _a;
|
|
7066
|
+
this.subscriptions.disposeAll();
|
|
7717
7067
|
this.context = context;
|
|
7718
7068
|
this.canvasService = context.services.get("CanvasService");
|
|
7719
7069
|
if (!this.canvasService) {
|
|
@@ -7747,62 +7097,73 @@ var WhiteInkTool = class {
|
|
|
7747
7097
|
}),
|
|
7748
7098
|
{ priority: 260 }
|
|
7749
7099
|
);
|
|
7750
|
-
|
|
7751
|
-
|
|
7752
|
-
|
|
7753
|
-
|
|
7754
|
-
|
|
7755
|
-
|
|
7100
|
+
this.subscriptions.on(context.eventBus, "tool:activated", this.onToolActivated);
|
|
7101
|
+
this.subscriptions.on(
|
|
7102
|
+
context.eventBus,
|
|
7103
|
+
"scene:layout:change",
|
|
7104
|
+
this.onSceneLayoutChanged
|
|
7105
|
+
);
|
|
7106
|
+
this.subscriptions.on(context.eventBus, "object:added", this.onObjectAdded);
|
|
7107
|
+
this.subscriptions.on(
|
|
7108
|
+
context.eventBus,
|
|
7109
|
+
"object:modified",
|
|
7110
|
+
this.onObjectModified
|
|
7111
|
+
);
|
|
7112
|
+
this.subscriptions.on(
|
|
7113
|
+
context.eventBus,
|
|
7114
|
+
"object:removed",
|
|
7115
|
+
this.onObjectRemoved
|
|
7116
|
+
);
|
|
7117
|
+
this.subscriptions.on(
|
|
7118
|
+
context.eventBus,
|
|
7119
|
+
"image:working:change",
|
|
7120
|
+
this.onImageWorkingChanged
|
|
7121
|
+
);
|
|
7756
7122
|
const configService = context.services.get(
|
|
7757
7123
|
"ConfigurationService"
|
|
7758
7124
|
);
|
|
7759
7125
|
if (configService) {
|
|
7760
|
-
this.items
|
|
7761
|
-
configService.get("whiteInk.items", []) || []
|
|
7762
|
-
);
|
|
7763
|
-
this.workingItems = this.cloneItems(this.items);
|
|
7764
|
-
this.hasWorkingChanges = false;
|
|
7126
|
+
this.applyCommittedItems(configService.get("whiteInk.items", []) || []);
|
|
7765
7127
|
this.printWithWhiteInk = !!configService.get(
|
|
7766
7128
|
"whiteInk.printWithWhiteInk",
|
|
7767
7129
|
true
|
|
7768
7130
|
);
|
|
7769
7131
|
this.previewImageVisible = !!configService.get(
|
|
7770
|
-
|
|
7132
|
+
WHITE_INK_PREVIEW_IMAGE_VISIBLE_KEY2,
|
|
7771
7133
|
true
|
|
7772
7134
|
);
|
|
7773
7135
|
this.migrateLegacyConfigIfNeeded(configService);
|
|
7774
|
-
|
|
7775
|
-
|
|
7776
|
-
|
|
7777
|
-
|
|
7778
|
-
if (
|
|
7779
|
-
this.
|
|
7780
|
-
this.
|
|
7136
|
+
this.subscriptions.onConfigChange(
|
|
7137
|
+
configService,
|
|
7138
|
+
(e) => {
|
|
7139
|
+
if (this.isUpdatingConfig) return;
|
|
7140
|
+
if (e.key === "whiteInk.items") {
|
|
7141
|
+
this.applyCommittedItems(e.value || []);
|
|
7142
|
+
this.updateWhiteInks();
|
|
7143
|
+
return;
|
|
7144
|
+
}
|
|
7145
|
+
if (e.key === "whiteInk.printWithWhiteInk") {
|
|
7146
|
+
this.printWithWhiteInk = !!e.value;
|
|
7147
|
+
this.updateWhiteInks();
|
|
7148
|
+
return;
|
|
7149
|
+
}
|
|
7150
|
+
if (e.key === WHITE_INK_PREVIEW_IMAGE_VISIBLE_KEY2) {
|
|
7151
|
+
this.previewImageVisible = !!e.value;
|
|
7152
|
+
this.updateWhiteInks();
|
|
7153
|
+
return;
|
|
7154
|
+
}
|
|
7155
|
+
if (e.key === "image.items") {
|
|
7156
|
+
this.updateWhiteInks();
|
|
7157
|
+
return;
|
|
7158
|
+
}
|
|
7159
|
+
if (e.key === WHITE_INK_DEBUG_KEY) {
|
|
7160
|
+
return;
|
|
7161
|
+
}
|
|
7162
|
+
if (e.key.startsWith("size.")) {
|
|
7163
|
+
this.updateWhiteInks();
|
|
7781
7164
|
}
|
|
7782
|
-
this.updateWhiteInks();
|
|
7783
|
-
return;
|
|
7784
|
-
}
|
|
7785
|
-
if (e.key === "whiteInk.printWithWhiteInk") {
|
|
7786
|
-
this.printWithWhiteInk = !!e.value;
|
|
7787
|
-
this.updateWhiteInks();
|
|
7788
|
-
return;
|
|
7789
|
-
}
|
|
7790
|
-
if (e.key === WHITE_INK_PREVIEW_IMAGE_VISIBLE_KEY) {
|
|
7791
|
-
this.previewImageVisible = !!e.value;
|
|
7792
|
-
this.updateWhiteInks();
|
|
7793
|
-
return;
|
|
7794
|
-
}
|
|
7795
|
-
if (e.key === "image.items") {
|
|
7796
|
-
this.updateWhiteInks();
|
|
7797
|
-
return;
|
|
7798
|
-
}
|
|
7799
|
-
if (e.key === WHITE_INK_DEBUG_KEY) {
|
|
7800
|
-
return;
|
|
7801
|
-
}
|
|
7802
|
-
if (e.key.startsWith("size.")) {
|
|
7803
|
-
this.updateWhiteInks();
|
|
7804
7165
|
}
|
|
7805
|
-
|
|
7166
|
+
);
|
|
7806
7167
|
}
|
|
7807
7168
|
const toolSessionService = context.services.get("ToolSessionService");
|
|
7808
7169
|
this.dirtyTrackerDisposable = toolSessionService == null ? void 0 : toolSessionService.registerDirtyTracker(
|
|
@@ -7813,14 +7174,10 @@ var WhiteInkTool = class {
|
|
|
7813
7174
|
}
|
|
7814
7175
|
deactivate(context) {
|
|
7815
7176
|
var _a, _b;
|
|
7816
|
-
|
|
7817
|
-
context.eventBus.off("scene:layout:change", this.onSceneLayoutChanged);
|
|
7818
|
-
context.eventBus.off("object:added", this.onObjectAdded);
|
|
7819
|
-
context.eventBus.off("object:modified", this.onObjectModified);
|
|
7820
|
-
context.eventBus.off("object:removed", this.onObjectRemoved);
|
|
7821
|
-
context.eventBus.off("image:working:change", this.onImageWorkingChanged);
|
|
7177
|
+
this.subscriptions.disposeAll();
|
|
7822
7178
|
(_a = this.dirtyTrackerDisposable) == null ? void 0 : _a.dispose();
|
|
7823
7179
|
this.dirtyTrackerDisposable = void 0;
|
|
7180
|
+
this.sourceSizeCache.clear();
|
|
7824
7181
|
this.clearRenderedWhiteInks();
|
|
7825
7182
|
(_b = this.renderProducerDisposable) == null ? void 0 : _b.dispose();
|
|
7826
7183
|
this.renderProducerDisposable = void 0;
|
|
@@ -7848,171 +7205,8 @@ var WhiteInkTool = class {
|
|
|
7848
7205
|
}
|
|
7849
7206
|
}
|
|
7850
7207
|
],
|
|
7851
|
-
[ContributionPointIds9.CONFIGURATIONS]:
|
|
7852
|
-
|
|
7853
|
-
id: "whiteInk.items",
|
|
7854
|
-
type: "array",
|
|
7855
|
-
label: "White Ink Images",
|
|
7856
|
-
default: []
|
|
7857
|
-
},
|
|
7858
|
-
{
|
|
7859
|
-
id: "whiteInk.printWithWhiteInk",
|
|
7860
|
-
type: "boolean",
|
|
7861
|
-
label: "Preview White Ink",
|
|
7862
|
-
default: true
|
|
7863
|
-
},
|
|
7864
|
-
{
|
|
7865
|
-
id: WHITE_INK_PREVIEW_IMAGE_VISIBLE_KEY,
|
|
7866
|
-
type: "boolean",
|
|
7867
|
-
label: "Show Cover During White Ink Preview",
|
|
7868
|
-
default: true
|
|
7869
|
-
},
|
|
7870
|
-
{
|
|
7871
|
-
id: WHITE_INK_DEBUG_KEY,
|
|
7872
|
-
type: "boolean",
|
|
7873
|
-
label: "White Ink Debug Log",
|
|
7874
|
-
default: false
|
|
7875
|
-
}
|
|
7876
|
-
],
|
|
7877
|
-
[ContributionPointIds9.COMMANDS]: [
|
|
7878
|
-
{
|
|
7879
|
-
command: "addWhiteInk",
|
|
7880
|
-
title: "Add White Ink",
|
|
7881
|
-
handler: async (url, options) => {
|
|
7882
|
-
return await this.addWhiteInkEntry(url, options);
|
|
7883
|
-
}
|
|
7884
|
-
},
|
|
7885
|
-
{
|
|
7886
|
-
command: "upsertWhiteInk",
|
|
7887
|
-
title: "Upsert White Ink",
|
|
7888
|
-
handler: async (url, options = {}) => {
|
|
7889
|
-
return await this.upsertWhiteInkEntry(url, options);
|
|
7890
|
-
}
|
|
7891
|
-
},
|
|
7892
|
-
{
|
|
7893
|
-
command: "getWhiteInks",
|
|
7894
|
-
title: "Get White Inks",
|
|
7895
|
-
handler: () => this.cloneItems(this.items)
|
|
7896
|
-
},
|
|
7897
|
-
{
|
|
7898
|
-
command: "getWhiteInkSettings",
|
|
7899
|
-
title: "Get White Ink Settings",
|
|
7900
|
-
handler: () => {
|
|
7901
|
-
const first = this.getEffectiveWhiteInkItem(this.items);
|
|
7902
|
-
const primarySource = this.getPrimaryImageSource();
|
|
7903
|
-
const sourceUrl = this.resolveSourceUrl(first) || primarySource;
|
|
7904
|
-
return {
|
|
7905
|
-
id: (first == null ? void 0 : first.id) || null,
|
|
7906
|
-
url: sourceUrl,
|
|
7907
|
-
sourceUrl,
|
|
7908
|
-
opacity: WHITE_INK_DEFAULT_OPACITY,
|
|
7909
|
-
printWithWhiteInk: this.printWithWhiteInk,
|
|
7910
|
-
previewImageVisible: this.previewImageVisible
|
|
7911
|
-
};
|
|
7912
|
-
}
|
|
7913
|
-
},
|
|
7914
|
-
{
|
|
7915
|
-
command: "setWhiteInkPrintEnabled",
|
|
7916
|
-
title: "Set White Ink Preview Enabled",
|
|
7917
|
-
handler: (enabled) => {
|
|
7918
|
-
var _a;
|
|
7919
|
-
this.printWithWhiteInk = !!enabled;
|
|
7920
|
-
const configService = (_a = this.context) == null ? void 0 : _a.services.get(
|
|
7921
|
-
"ConfigurationService"
|
|
7922
|
-
);
|
|
7923
|
-
configService == null ? void 0 : configService.update(
|
|
7924
|
-
"whiteInk.printWithWhiteInk",
|
|
7925
|
-
this.printWithWhiteInk
|
|
7926
|
-
);
|
|
7927
|
-
this.updateWhiteInks();
|
|
7928
|
-
return { ok: true };
|
|
7929
|
-
}
|
|
7930
|
-
},
|
|
7931
|
-
{
|
|
7932
|
-
command: "setWhiteInkPreviewImageVisible",
|
|
7933
|
-
title: "Set White Ink Cover Visible",
|
|
7934
|
-
handler: (visible) => {
|
|
7935
|
-
var _a;
|
|
7936
|
-
this.previewImageVisible = !!visible;
|
|
7937
|
-
const configService = (_a = this.context) == null ? void 0 : _a.services.get(
|
|
7938
|
-
"ConfigurationService"
|
|
7939
|
-
);
|
|
7940
|
-
configService == null ? void 0 : configService.update(
|
|
7941
|
-
WHITE_INK_PREVIEW_IMAGE_VISIBLE_KEY,
|
|
7942
|
-
this.previewImageVisible
|
|
7943
|
-
);
|
|
7944
|
-
this.updateWhiteInks();
|
|
7945
|
-
return { ok: true };
|
|
7946
|
-
}
|
|
7947
|
-
},
|
|
7948
|
-
{
|
|
7949
|
-
command: "getWorkingWhiteInks",
|
|
7950
|
-
title: "Get Working White Inks",
|
|
7951
|
-
handler: () => this.cloneItems(this.workingItems)
|
|
7952
|
-
},
|
|
7953
|
-
{
|
|
7954
|
-
command: "setWorkingWhiteInk",
|
|
7955
|
-
title: "Set Working White Ink",
|
|
7956
|
-
handler: (id, updates) => {
|
|
7957
|
-
this.updateWhiteInkInWorking(id, updates);
|
|
7958
|
-
}
|
|
7959
|
-
},
|
|
7960
|
-
{
|
|
7961
|
-
command: "updateWhiteInk",
|
|
7962
|
-
title: "Update White Ink",
|
|
7963
|
-
handler: async (id, updates, options = {}) => {
|
|
7964
|
-
await this.updateWhiteInkItem(id, updates, options);
|
|
7965
|
-
}
|
|
7966
|
-
},
|
|
7967
|
-
{
|
|
7968
|
-
command: "removeWhiteInk",
|
|
7969
|
-
title: "Remove White Ink",
|
|
7970
|
-
handler: (id) => {
|
|
7971
|
-
this.removeWhiteInk(id);
|
|
7972
|
-
}
|
|
7973
|
-
},
|
|
7974
|
-
{
|
|
7975
|
-
command: "clearWhiteInks",
|
|
7976
|
-
title: "Clear White Inks",
|
|
7977
|
-
handler: () => {
|
|
7978
|
-
this.clearWhiteInks();
|
|
7979
|
-
}
|
|
7980
|
-
},
|
|
7981
|
-
{
|
|
7982
|
-
command: "resetWorkingWhiteInks",
|
|
7983
|
-
title: "Reset Working White Inks",
|
|
7984
|
-
handler: () => {
|
|
7985
|
-
this.workingItems = this.cloneItems(this.items);
|
|
7986
|
-
this.hasWorkingChanges = false;
|
|
7987
|
-
this.updateWhiteInks();
|
|
7988
|
-
}
|
|
7989
|
-
},
|
|
7990
|
-
{
|
|
7991
|
-
command: "completeWhiteInks",
|
|
7992
|
-
title: "Complete White Inks",
|
|
7993
|
-
handler: async () => {
|
|
7994
|
-
return await this.completeWhiteInks();
|
|
7995
|
-
}
|
|
7996
|
-
},
|
|
7997
|
-
{
|
|
7998
|
-
command: "setWhiteInkImage",
|
|
7999
|
-
title: "Set White Ink Image",
|
|
8000
|
-
handler: async (url) => {
|
|
8001
|
-
if (!url) {
|
|
8002
|
-
this.clearWhiteInks();
|
|
8003
|
-
return { ok: true };
|
|
8004
|
-
}
|
|
8005
|
-
const targetId = this.resolveReplaceTargetId(null);
|
|
8006
|
-
const upsertResult = await this.upsertWhiteInkEntry(url, {
|
|
8007
|
-
id: targetId || void 0,
|
|
8008
|
-
mode: targetId ? "replace" : "add",
|
|
8009
|
-
createIfMissing: true,
|
|
8010
|
-
addOptions: {}
|
|
8011
|
-
});
|
|
8012
|
-
return { ok: true, id: upsertResult.id };
|
|
8013
|
-
}
|
|
8014
|
-
}
|
|
8015
|
-
]
|
|
7208
|
+
[ContributionPointIds9.CONFIGURATIONS]: createWhiteInkConfigurations(),
|
|
7209
|
+
[ContributionPointIds9.COMMANDS]: createWhiteInkCommands(this)
|
|
8016
7210
|
};
|
|
8017
7211
|
}
|
|
8018
7212
|
migrateLegacyConfigIfNeeded(configService) {
|
|
@@ -8022,15 +7216,12 @@ var WhiteInkTool = class {
|
|
|
8022
7216
|
const item = this.normalizeItem({
|
|
8023
7217
|
id: this.generateId(),
|
|
8024
7218
|
sourceUrl: legacyMask,
|
|
8025
|
-
opacity:
|
|
7219
|
+
opacity: WHITE_INK_DEFAULT_OPACITY2
|
|
7220
|
+
});
|
|
7221
|
+
this.applyCommittedItems([item]);
|
|
7222
|
+
runDeferredConfigUpdate(this, () => {
|
|
7223
|
+
configService.update("whiteInk.items", this.items);
|
|
8026
7224
|
});
|
|
8027
|
-
this.items = [item];
|
|
8028
|
-
this.workingItems = this.cloneItems(this.items);
|
|
8029
|
-
this.isUpdatingConfig = true;
|
|
8030
|
-
configService.update("whiteInk.items", this.items);
|
|
8031
|
-
setTimeout(() => {
|
|
8032
|
-
this.isUpdatingConfig = false;
|
|
8033
|
-
}, 0);
|
|
8034
7225
|
}
|
|
8035
7226
|
syncToolActiveFromWorkbench(fallbackId) {
|
|
8036
7227
|
var _a;
|
|
@@ -8072,7 +7263,7 @@ var WhiteInkTool = class {
|
|
|
8072
7263
|
id: String(item.id || this.generateId()),
|
|
8073
7264
|
sourceUrl,
|
|
8074
7265
|
url: sourceUrl,
|
|
8075
|
-
opacity:
|
|
7266
|
+
opacity: WHITE_INK_DEFAULT_OPACITY2
|
|
8076
7267
|
};
|
|
8077
7268
|
}
|
|
8078
7269
|
normalizeItems(items) {
|
|
@@ -8091,7 +7282,7 @@ var WhiteInkTool = class {
|
|
|
8091
7282
|
}
|
|
8092
7283
|
return {
|
|
8093
7284
|
id: WHITE_INK_AUTO_ITEM_ID,
|
|
8094
|
-
opacity:
|
|
7285
|
+
opacity: WHITE_INK_DEFAULT_OPACITY2
|
|
8095
7286
|
};
|
|
8096
7287
|
}
|
|
8097
7288
|
generateId() {
|
|
@@ -8114,31 +7305,45 @@ var WhiteInkTool = class {
|
|
|
8114
7305
|
}
|
|
8115
7306
|
return null;
|
|
8116
7307
|
}
|
|
7308
|
+
applyCommittedItems(nextItems) {
|
|
7309
|
+
const session = {
|
|
7310
|
+
committed: this.items,
|
|
7311
|
+
working: this.workingItems,
|
|
7312
|
+
hasWorkingChanges: this.hasWorkingChanges
|
|
7313
|
+
};
|
|
7314
|
+
applyCommittedSnapshot(session, this.normalizeItems(nextItems), {
|
|
7315
|
+
clone: (items) => this.cloneItems(items),
|
|
7316
|
+
toolActive: this.isToolActive,
|
|
7317
|
+
preserveDirtyWorking: true
|
|
7318
|
+
});
|
|
7319
|
+
this.items = session.committed;
|
|
7320
|
+
this.workingItems = session.working;
|
|
7321
|
+
this.hasWorkingChanges = session.hasWorkingChanges;
|
|
7322
|
+
}
|
|
8117
7323
|
updateConfig(newItems, skipCanvasUpdate = false) {
|
|
8118
7324
|
if (!this.context) return;
|
|
8119
|
-
this.
|
|
8120
|
-
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
|
|
8124
|
-
|
|
8125
|
-
|
|
8126
|
-
|
|
7325
|
+
this.applyCommittedItems(newItems);
|
|
7326
|
+
runDeferredConfigUpdate(
|
|
7327
|
+
this,
|
|
7328
|
+
() => {
|
|
7329
|
+
var _a;
|
|
7330
|
+
const configService = (_a = this.context) == null ? void 0 : _a.services.get(
|
|
7331
|
+
"ConfigurationService"
|
|
7332
|
+
);
|
|
7333
|
+
configService == null ? void 0 : configService.update("whiteInk.items", this.items);
|
|
7334
|
+
if (!skipCanvasUpdate) {
|
|
7335
|
+
this.updateWhiteInks();
|
|
7336
|
+
}
|
|
7337
|
+
},
|
|
7338
|
+
50
|
|
8127
7339
|
);
|
|
8128
|
-
configService == null ? void 0 : configService.update("whiteInk.items", this.items);
|
|
8129
|
-
if (!skipCanvasUpdate) {
|
|
8130
|
-
this.updateWhiteInks();
|
|
8131
|
-
}
|
|
8132
|
-
setTimeout(() => {
|
|
8133
|
-
this.isUpdatingConfig = false;
|
|
8134
|
-
}, 50);
|
|
8135
7340
|
}
|
|
8136
7341
|
async addWhiteInkEntry(url, options) {
|
|
8137
7342
|
const id = this.generateId();
|
|
8138
7343
|
const item = this.normalizeItem({
|
|
8139
7344
|
id,
|
|
8140
7345
|
sourceUrl: url,
|
|
8141
|
-
opacity:
|
|
7346
|
+
opacity: WHITE_INK_DEFAULT_OPACITY2,
|
|
8142
7347
|
...options
|
|
8143
7348
|
});
|
|
8144
7349
|
const sessionDirtyBeforeAdd = this.isToolActive && this.hasWorkingChanges;
|
|
@@ -8223,7 +7428,7 @@ var WhiteInkTool = class {
|
|
|
8223
7428
|
this.updateConfig(next);
|
|
8224
7429
|
}
|
|
8225
7430
|
clearWhiteInks() {
|
|
8226
|
-
this.
|
|
7431
|
+
this.sourceSizeCache.clear();
|
|
8227
7432
|
this.previewMaskBySource.clear();
|
|
8228
7433
|
this.pendingPreviewMaskBySource.clear();
|
|
8229
7434
|
this.updateConfig([]);
|
|
@@ -8235,41 +7440,19 @@ var WhiteInkTool = class {
|
|
|
8235
7440
|
}
|
|
8236
7441
|
getFrameRect() {
|
|
8237
7442
|
var _a;
|
|
8238
|
-
if (!this.canvasService) {
|
|
8239
|
-
return { left: 0, top: 0, width: 0, height: 0 };
|
|
8240
|
-
}
|
|
8241
7443
|
const configService = (_a = this.context) == null ? void 0 : _a.services.get(
|
|
8242
7444
|
"ConfigurationService"
|
|
8243
7445
|
);
|
|
8244
|
-
|
|
8245
|
-
return { left: 0, top: 0, width: 0, height: 0 };
|
|
8246
|
-
}
|
|
8247
|
-
const sizeState = readSizeState(configService);
|
|
8248
|
-
const layout = computeSceneLayout(this.canvasService, sizeState);
|
|
8249
|
-
if (!layout) {
|
|
8250
|
-
return { left: 0, top: 0, width: 0, height: 0 };
|
|
8251
|
-
}
|
|
8252
|
-
return this.canvasService.toSceneRect({
|
|
8253
|
-
left: layout.cutRect.left,
|
|
8254
|
-
top: layout.cutRect.top,
|
|
8255
|
-
width: layout.cutRect.width,
|
|
8256
|
-
height: layout.cutRect.height
|
|
8257
|
-
});
|
|
7446
|
+
return resolveCutFrameRect(this.canvasService, configService);
|
|
8258
7447
|
}
|
|
8259
7448
|
toLayoutSceneRect(rect) {
|
|
8260
|
-
return
|
|
8261
|
-
left: rect.left,
|
|
8262
|
-
top: rect.top,
|
|
8263
|
-
width: rect.width,
|
|
8264
|
-
height: rect.height,
|
|
8265
|
-
space: "scene"
|
|
8266
|
-
};
|
|
7449
|
+
return toLayoutSceneRect(rect);
|
|
8267
7450
|
}
|
|
8268
7451
|
getImageObjects() {
|
|
8269
7452
|
if (!this.canvasService) return [];
|
|
8270
7453
|
return this.canvasService.canvas.getObjects().filter((obj) => {
|
|
8271
7454
|
var _a;
|
|
8272
|
-
return ((_a = obj == null ? void 0 : obj.data) == null ? void 0 : _a.layerId) ===
|
|
7455
|
+
return ((_a = obj == null ? void 0 : obj.data) == null ? void 0 : _a.layerId) === IMAGE_OBJECT_LAYER_ID;
|
|
8273
7456
|
});
|
|
8274
7457
|
}
|
|
8275
7458
|
getPrimaryImageObject() {
|
|
@@ -8341,21 +7524,16 @@ var WhiteInkTool = class {
|
|
|
8341
7524
|
return snapshot.src === placement.committedUrl;
|
|
8342
7525
|
}
|
|
8343
7526
|
getCoverScale(frame, source) {
|
|
8344
|
-
|
|
8345
|
-
const frameH = Math.max(1, frame.height);
|
|
8346
|
-
const sourceW = Math.max(1, source.width);
|
|
8347
|
-
const sourceH = Math.max(1, source.height);
|
|
8348
|
-
return Math.max(frameW / sourceW, frameH / sourceH);
|
|
7527
|
+
return getCoverScale(frame, source);
|
|
8349
7528
|
}
|
|
8350
7529
|
async ensureSourceSize(sourceUrl) {
|
|
8351
|
-
|
|
8352
|
-
|
|
8353
|
-
|
|
7530
|
+
return this.sourceSizeCache.ensureImageSize(sourceUrl);
|
|
7531
|
+
}
|
|
7532
|
+
async loadImageSize(sourceUrl) {
|
|
8354
7533
|
try {
|
|
8355
7534
|
const image = await this.loadImageElement(sourceUrl);
|
|
8356
7535
|
const size = this.getElementSize(image);
|
|
8357
7536
|
if (!size) return null;
|
|
8358
|
-
this.rememberSourceSize(sourceUrl, size);
|
|
8359
7537
|
return {
|
|
8360
7538
|
width: size.width,
|
|
8361
7539
|
height: size.height
|
|
@@ -8400,22 +7578,10 @@ var WhiteInkTool = class {
|
|
|
8400
7578
|
return (obj == null ? void 0 : obj._element) || (obj == null ? void 0 : obj._originalElement) || null;
|
|
8401
7579
|
}
|
|
8402
7580
|
rememberSourceSize(src, size) {
|
|
8403
|
-
|
|
8404
|
-
if (!Number.isFinite(size.width) || !Number.isFinite(size.height)) return;
|
|
8405
|
-
if (size.width <= 0 || size.height <= 0) return;
|
|
8406
|
-
this.sourceSizeBySrc.set(src, {
|
|
8407
|
-
width: size.width,
|
|
8408
|
-
height: size.height
|
|
8409
|
-
});
|
|
7581
|
+
this.sourceSizeCache.rememberSourceSize(src, size);
|
|
8410
7582
|
}
|
|
8411
7583
|
getSourceSize(src) {
|
|
8412
|
-
|
|
8413
|
-
const cached = this.sourceSizeBySrc.get(src);
|
|
8414
|
-
if (!cached) return null;
|
|
8415
|
-
return {
|
|
8416
|
-
width: cached.width,
|
|
8417
|
-
height: cached.height
|
|
8418
|
-
};
|
|
7584
|
+
return this.sourceSizeCache.getSourceSize(src);
|
|
8419
7585
|
}
|
|
8420
7586
|
computeWhiteScaleAdjust(baseSource, whiteSource) {
|
|
8421
7587
|
if (!baseSource || !whiteSource || baseSource === whiteSource) {
|
|
@@ -8435,7 +7601,7 @@ var WhiteInkTool = class {
|
|
|
8435
7601
|
};
|
|
8436
7602
|
}
|
|
8437
7603
|
computeCoverOpacity() {
|
|
8438
|
-
const raw =
|
|
7604
|
+
const raw = WHITE_INK_DEFAULT_OPACITY2 * WHITE_INK_COVER_OPACITY_FACTOR;
|
|
8439
7605
|
return Math.max(
|
|
8440
7606
|
WHITE_INK_COVER_OPACITY_MIN,
|
|
8441
7607
|
Math.min(WHITE_INK_COVER_OPACITY_MAX, raw)
|
|
@@ -8699,7 +7865,7 @@ var WhiteInkTool = class {
|
|
|
8699
7865
|
purgeSourceCaches(item) {
|
|
8700
7866
|
const sourceUrl = this.resolveSourceUrl(item);
|
|
8701
7867
|
if (!sourceUrl) return;
|
|
8702
|
-
this.
|
|
7868
|
+
this.sourceSizeCache.deleteSourceSize(sourceUrl);
|
|
8703
7869
|
const prefix = `${sourceUrl}::`;
|
|
8704
7870
|
Array.from(this.previewMaskBySource.keys()).forEach((cacheKey) => {
|
|
8705
7871
|
if (cacheKey.startsWith(prefix)) {
|
|
@@ -8738,7 +7904,7 @@ var WhiteInkTool = class {
|
|
|
8738
7904
|
"white-ink.main",
|
|
8739
7905
|
snapshot,
|
|
8740
7906
|
sources.whiteSrc,
|
|
8741
|
-
|
|
7907
|
+
WHITE_INK_DEFAULT_OPACITY2,
|
|
8742
7908
|
WHITE_INK_OBJECT_LAYER_ID,
|
|
8743
7909
|
"white-ink",
|
|
8744
7910
|
sources.whiteScaleAdjustX,
|
|
@@ -8846,7 +8012,7 @@ var WhiteInkTool = class {
|
|
|
8846
8012
|
}
|
|
8847
8013
|
};
|
|
8848
8014
|
|
|
8849
|
-
// src/
|
|
8015
|
+
// src/services/SceneLayoutService.ts
|
|
8850
8016
|
import {
|
|
8851
8017
|
COMMAND_SERVICE,
|
|
8852
8018
|
CONFIGURATION_SERVICE
|
|
@@ -8859,6 +8025,7 @@ var SceneLayoutService = class {
|
|
|
8859
8025
|
constructor() {
|
|
8860
8026
|
this.lastLayout = null;
|
|
8861
8027
|
this.lastGeometry = null;
|
|
8028
|
+
this.subscriptions = new SubscriptionBag();
|
|
8862
8029
|
this.commandDisposables = [];
|
|
8863
8030
|
this.onCanvasResized = () => {
|
|
8864
8031
|
this.refresh();
|
|
@@ -8894,16 +8061,13 @@ var SceneLayoutService = class {
|
|
|
8894
8061
|
() => this.getGeometry()
|
|
8895
8062
|
)
|
|
8896
8063
|
);
|
|
8897
|
-
this.
|
|
8898
|
-
|
|
8064
|
+
this.subscriptions.disposeAll();
|
|
8065
|
+
this.subscriptions.onConfigChange(configService, this.onConfigChanged);
|
|
8066
|
+
this.subscriptions.on(context.eventBus, "canvas:resized", this.onCanvasResized);
|
|
8899
8067
|
this.refresh();
|
|
8900
8068
|
}
|
|
8901
8069
|
dispose(context) {
|
|
8902
|
-
|
|
8903
|
-
const activeContext = (_a = this.context) != null ? _a : context;
|
|
8904
|
-
activeContext.eventBus.off("canvas:resized", this.onCanvasResized);
|
|
8905
|
-
(_b = this.onConfigChange) == null ? void 0 : _b.dispose();
|
|
8906
|
-
this.onConfigChange = void 0;
|
|
8070
|
+
this.subscriptions.disposeAll();
|
|
8907
8071
|
this.commandDisposables.forEach((item) => item.dispose());
|
|
8908
8072
|
this.commandDisposables = [];
|
|
8909
8073
|
this.context = void 0;
|
|
@@ -10084,5 +9248,13 @@ export {
|
|
|
10084
9248
|
SizeTool,
|
|
10085
9249
|
ViewportSystem,
|
|
10086
9250
|
WhiteInkTool,
|
|
9251
|
+
getCoverScale as computeImageCoverScale,
|
|
9252
|
+
getCoverScale as computeWhiteInkCoverScale,
|
|
9253
|
+
createDielineCommands,
|
|
9254
|
+
createDielineConfigurations,
|
|
9255
|
+
createImageCommands,
|
|
9256
|
+
createImageConfigurations,
|
|
9257
|
+
createWhiteInkCommands,
|
|
9258
|
+
createWhiteInkConfigurations,
|
|
10087
9259
|
evaluateVisibilityExpr
|
|
10088
9260
|
};
|