@pooder/kit 5.3.1 → 6.0.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.js +475 -131
- package/.test-dist/src/extensions/dieline.js +283 -180
- package/.test-dist/src/extensions/dielineShape.js +66 -0
- package/.test-dist/src/extensions/feature.js +388 -303
- package/.test-dist/src/extensions/film.js +133 -74
- package/.test-dist/src/extensions/geometry.js +120 -56
- package/.test-dist/src/extensions/image.js +296 -212
- package/.test-dist/src/extensions/index.js +1 -3
- package/.test-dist/src/extensions/maskOps.js +75 -20
- package/.test-dist/src/extensions/ruler.js +312 -215
- package/.test-dist/src/extensions/sceneLayoutModel.js +9 -3
- package/.test-dist/src/extensions/sceneVisibility.js +3 -10
- package/.test-dist/src/extensions/tracer.js +229 -58
- package/.test-dist/src/extensions/white-ink.js +139 -129
- package/.test-dist/src/services/CanvasService.js +888 -126
- package/.test-dist/src/services/index.js +1 -0
- package/.test-dist/src/services/visibility.js +54 -0
- package/.test-dist/tests/run.js +58 -4
- package/CHANGELOG.md +12 -0
- package/dist/index.d.mts +377 -82
- package/dist/index.d.ts +377 -82
- package/dist/index.js +3920 -2178
- package/dist/index.mjs +3992 -2247
- package/package.json +1 -1
- package/src/extensions/background.ts +631 -145
- package/src/extensions/dieline.ts +280 -187
- package/src/extensions/dielineShape.ts +109 -0
- package/src/extensions/feature.ts +485 -366
- package/src/extensions/film.ts +152 -76
- package/src/extensions/geometry.ts +203 -104
- package/src/extensions/image.ts +319 -238
- package/src/extensions/index.ts +0 -1
- package/src/extensions/ruler.ts +481 -268
- package/src/extensions/sceneLayoutModel.ts +18 -6
- package/src/extensions/white-ink.ts +157 -171
- package/src/services/CanvasService.ts +1126 -140
- package/src/services/index.ts +1 -0
- package/src/services/renderSpec.ts +69 -4
- package/src/services/visibility.ts +78 -0
- package/tests/run.ts +139 -4
- package/.test-dist/src/CanvasService.js +0 -249
- package/.test-dist/src/ViewportSystem.js +0 -75
- package/.test-dist/src/background.js +0 -203
- package/.test-dist/src/bridgeSelection.js +0 -20
- package/.test-dist/src/constraints.js +0 -237
- package/.test-dist/src/dieline.js +0 -818
- package/.test-dist/src/edgeScale.js +0 -12
- package/.test-dist/src/feature.js +0 -826
- package/.test-dist/src/featureComplete.js +0 -32
- package/.test-dist/src/film.js +0 -167
- package/.test-dist/src/geometry.js +0 -506
- package/.test-dist/src/image.js +0 -1250
- package/.test-dist/src/maskOps.js +0 -270
- package/.test-dist/src/mirror.js +0 -104
- package/.test-dist/src/renderSpec.js +0 -2
- package/.test-dist/src/ruler.js +0 -343
- package/.test-dist/src/sceneLayout.js +0 -99
- package/.test-dist/src/sceneLayoutModel.js +0 -196
- package/.test-dist/src/sceneView.js +0 -40
- package/.test-dist/src/sceneVisibility.js +0 -42
- package/.test-dist/src/size.js +0 -332
- package/.test-dist/src/tracer.js +0 -544
- package/.test-dist/src/white-ink.js +0 -829
- package/.test-dist/src/wrappedOffsets.js +0 -33
- package/src/extensions/sceneVisibility.ts +0 -71
package/src/extensions/image.ts
CHANGED
|
@@ -14,8 +14,10 @@ import {
|
|
|
14
14
|
Pattern,
|
|
15
15
|
Point,
|
|
16
16
|
} from "fabric";
|
|
17
|
-
import { CanvasService, RenderObjectSpec } from "../services";
|
|
18
|
-
import {
|
|
17
|
+
import { CanvasService, RenderLayoutRect, RenderObjectSpec } from "../services";
|
|
18
|
+
import { isDielineShape, normalizeShapeStyle } from "./dielineShape";
|
|
19
|
+
import type { DielineShape, DielineShapeStyle } from "./dielineShape";
|
|
20
|
+
import { generateDielinePath, getPathBounds } from "./geometry";
|
|
19
21
|
import {
|
|
20
22
|
buildSceneGeometry,
|
|
21
23
|
computeSceneLayout,
|
|
@@ -64,11 +66,11 @@ interface FrameVisualConfig {
|
|
|
64
66
|
outerBackground: string;
|
|
65
67
|
}
|
|
66
68
|
|
|
67
|
-
type DielineShape = "rect" | "circle" | "ellipse" | "custom";
|
|
68
69
|
type ShapeOverlayShape = Exclude<DielineShape, "custom">;
|
|
69
70
|
|
|
70
71
|
interface SceneGeometryLike {
|
|
71
72
|
shape: DielineShape;
|
|
73
|
+
shapeStyle: DielineShapeStyle;
|
|
72
74
|
radius: number;
|
|
73
75
|
offset: number;
|
|
74
76
|
}
|
|
@@ -134,6 +136,10 @@ export class ImageTool implements Extension {
|
|
|
134
136
|
private dirtyTrackerDisposable?: { dispose(): void };
|
|
135
137
|
private cropShapeHatchPattern?: Pattern;
|
|
136
138
|
private cropShapeHatchPatternColor?: string;
|
|
139
|
+
private cropShapeHatchPatternKey?: string;
|
|
140
|
+
private imageSpecs: RenderObjectSpec[] = [];
|
|
141
|
+
private overlaySpecs: RenderObjectSpec[] = [];
|
|
142
|
+
private renderProducerDisposable?: { dispose: () => void };
|
|
137
143
|
|
|
138
144
|
activate(context: ExtensionContext) {
|
|
139
145
|
this.context = context;
|
|
@@ -142,6 +148,41 @@ export class ImageTool implements Extension {
|
|
|
142
148
|
console.warn("CanvasService not found for ImageTool");
|
|
143
149
|
return;
|
|
144
150
|
}
|
|
151
|
+
this.renderProducerDisposable?.dispose();
|
|
152
|
+
this.renderProducerDisposable = this.canvasService.registerRenderProducer(
|
|
153
|
+
this.id,
|
|
154
|
+
() => ({
|
|
155
|
+
passes: [
|
|
156
|
+
{
|
|
157
|
+
id: IMAGE_OBJECT_LAYER_ID,
|
|
158
|
+
stack: 500,
|
|
159
|
+
order: 0,
|
|
160
|
+
visibility: {
|
|
161
|
+
op: "not",
|
|
162
|
+
expr: {
|
|
163
|
+
op: "sessionActive",
|
|
164
|
+
toolId: "pooder.kit.white-ink",
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
objects: this.imageSpecs,
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
id: IMAGE_OVERLAY_LAYER_ID,
|
|
171
|
+
stack: 800,
|
|
172
|
+
order: 0,
|
|
173
|
+
visibility: {
|
|
174
|
+
op: "not",
|
|
175
|
+
expr: {
|
|
176
|
+
op: "sessionActive",
|
|
177
|
+
toolId: "pooder.kit.white-ink",
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
objects: this.overlaySpecs,
|
|
181
|
+
},
|
|
182
|
+
],
|
|
183
|
+
}),
|
|
184
|
+
{ priority: 300 },
|
|
185
|
+
);
|
|
145
186
|
|
|
146
187
|
context.eventBus.on("tool:activated", this.onToolActivated);
|
|
147
188
|
context.eventBus.on("object:modified", this.onObjectModified);
|
|
@@ -202,13 +243,15 @@ export class ImageTool implements Extension {
|
|
|
202
243
|
this.dirtyTrackerDisposable = undefined;
|
|
203
244
|
this.cropShapeHatchPattern = undefined;
|
|
204
245
|
this.cropShapeHatchPatternColor = undefined;
|
|
246
|
+
this.cropShapeHatchPatternKey = undefined;
|
|
247
|
+
this.imageSpecs = [];
|
|
248
|
+
this.overlaySpecs = [];
|
|
205
249
|
|
|
206
250
|
this.clearRenderedImages();
|
|
251
|
+
this.renderProducerDisposable?.dispose();
|
|
252
|
+
this.renderProducerDisposable = undefined;
|
|
207
253
|
if (this.canvasService) {
|
|
208
|
-
void this.canvasService.
|
|
209
|
-
IMAGE_OVERLAY_LAYER_ID,
|
|
210
|
-
[],
|
|
211
|
-
);
|
|
254
|
+
void this.canvasService.flushRenderFromProducers();
|
|
212
255
|
this.canvasService = undefined;
|
|
213
256
|
}
|
|
214
257
|
this.context = undefined;
|
|
@@ -766,47 +809,41 @@ export class ImageTool implements Extension {
|
|
|
766
809
|
return { left: 0, top: 0, width: 0, height: 0 };
|
|
767
810
|
}
|
|
768
811
|
|
|
769
|
-
return {
|
|
812
|
+
return this.canvasService.toSceneRect({
|
|
770
813
|
left: layout.cutRect.left,
|
|
771
814
|
top: layout.cutRect.top,
|
|
772
815
|
width: layout.cutRect.width,
|
|
773
816
|
height: layout.cutRect.height,
|
|
774
|
-
};
|
|
817
|
+
});
|
|
775
818
|
}
|
|
776
819
|
|
|
777
|
-
private
|
|
778
|
-
if (!this.
|
|
779
|
-
|
|
780
|
-
|
|
820
|
+
private getFrameRectScreen(frame?: FrameRect): FrameRect {
|
|
821
|
+
if (!this.canvasService) {
|
|
822
|
+
return { left: 0, top: 0, width: 0, height: 0 };
|
|
823
|
+
}
|
|
824
|
+
return this.canvasService.toScreenRect(frame || this.getFrameRect());
|
|
825
|
+
}
|
|
781
826
|
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
if (
|
|
793
|
-
!Number.isFinite(width) ||
|
|
794
|
-
!Number.isFinite(height) ||
|
|
795
|
-
!Number.isFinite(left) ||
|
|
796
|
-
!Number.isFinite(top)
|
|
797
|
-
) {
|
|
798
|
-
return null;
|
|
799
|
-
}
|
|
827
|
+
private toLayoutSceneRect(rect: FrameRect): RenderLayoutRect {
|
|
828
|
+
return {
|
|
829
|
+
left: rect.left,
|
|
830
|
+
top: rect.top,
|
|
831
|
+
width: rect.width,
|
|
832
|
+
height: rect.height,
|
|
833
|
+
space: "scene",
|
|
834
|
+
};
|
|
835
|
+
}
|
|
800
836
|
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
837
|
+
private async resolveDefaultFitArea(): Promise<DielineFitArea | null> {
|
|
838
|
+
if (!this.canvasService) return null;
|
|
839
|
+
const frame = this.getFrameRect();
|
|
840
|
+
if (frame.width <= 0 || frame.height <= 0) return null;
|
|
841
|
+
return {
|
|
842
|
+
width: Math.max(1, frame.width),
|
|
843
|
+
height: Math.max(1, frame.height),
|
|
844
|
+
left: frame.left + frame.width / 2,
|
|
845
|
+
top: frame.top + frame.height / 2,
|
|
846
|
+
};
|
|
810
847
|
}
|
|
811
848
|
|
|
812
849
|
private async fitImageToDefaultArea(id: string) {
|
|
@@ -818,13 +855,14 @@ export class ImageTool implements Extension {
|
|
|
818
855
|
return;
|
|
819
856
|
}
|
|
820
857
|
|
|
821
|
-
const
|
|
822
|
-
const
|
|
858
|
+
const viewport = this.canvasService.getSceneViewportRect();
|
|
859
|
+
const canvasW = Math.max(1, viewport.width || 0);
|
|
860
|
+
const canvasH = Math.max(1, viewport.height || 0);
|
|
823
861
|
await this.fitImageToArea(id, {
|
|
824
862
|
width: canvasW,
|
|
825
863
|
height: canvasH,
|
|
826
|
-
left: canvasW / 2,
|
|
827
|
-
top: canvasH / 2,
|
|
864
|
+
left: viewport.left + canvasW / 2,
|
|
865
|
+
top: viewport.top + canvasH / 2,
|
|
828
866
|
});
|
|
829
867
|
}
|
|
830
868
|
|
|
@@ -837,9 +875,7 @@ export class ImageTool implements Extension {
|
|
|
837
875
|
|
|
838
876
|
private getOverlayObjects(): any[] {
|
|
839
877
|
if (!this.canvasService) return [];
|
|
840
|
-
return this.canvasService.
|
|
841
|
-
IMAGE_OVERLAY_LAYER_ID,
|
|
842
|
-
) as any[];
|
|
878
|
+
return this.canvasService.getPassObjects(IMAGE_OVERLAY_LAYER_ID) as any[];
|
|
843
879
|
}
|
|
844
880
|
|
|
845
881
|
private getImageObject(id: string): any | undefined {
|
|
@@ -848,9 +884,9 @@ export class ImageTool implements Extension {
|
|
|
848
884
|
|
|
849
885
|
private clearRenderedImages() {
|
|
850
886
|
if (!this.canvasService) return;
|
|
851
|
-
|
|
852
|
-
this.
|
|
853
|
-
this.canvasService.
|
|
887
|
+
this.imageSpecs = [];
|
|
888
|
+
this.overlaySpecs = [];
|
|
889
|
+
this.canvasService.requestRenderFromProducers();
|
|
854
890
|
}
|
|
855
891
|
|
|
856
892
|
private purgeSourceSizeCacheForItem(item?: ImageItem) {
|
|
@@ -884,6 +920,32 @@ export class ImageTool implements Extension {
|
|
|
884
920
|
return { width: 1, height: 1 };
|
|
885
921
|
}
|
|
886
922
|
|
|
923
|
+
private async ensureSourceSize(src: string): Promise<SourceSize | null> {
|
|
924
|
+
if (!src) return null;
|
|
925
|
+
const cached = this.sourceSizeBySrc.get(src);
|
|
926
|
+
if (cached) return cached;
|
|
927
|
+
|
|
928
|
+
try {
|
|
929
|
+
const image = await FabricImage.fromURL(src, {
|
|
930
|
+
crossOrigin: "anonymous",
|
|
931
|
+
});
|
|
932
|
+
const width = Number(image?.width || 0);
|
|
933
|
+
const height = Number(image?.height || 0);
|
|
934
|
+
if (width > 0 && height > 0) {
|
|
935
|
+
const size = { width, height };
|
|
936
|
+
this.sourceSizeBySrc.set(src, size);
|
|
937
|
+
return size;
|
|
938
|
+
}
|
|
939
|
+
} catch (error) {
|
|
940
|
+
this.debug("image:size:load-failed", {
|
|
941
|
+
src,
|
|
942
|
+
error: error instanceof Error ? error.message : String(error),
|
|
943
|
+
});
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
return null;
|
|
947
|
+
}
|
|
948
|
+
|
|
887
949
|
private getCoverScale(frame: FrameRect, size: SourceSize): number {
|
|
888
950
|
const sw = Math.max(1, size.width);
|
|
889
951
|
const sh = Math.max(1, size.height);
|
|
@@ -929,19 +991,24 @@ export class ImageTool implements Extension {
|
|
|
929
991
|
|
|
930
992
|
private toSceneGeometryLike(raw: any): SceneGeometryLike | null {
|
|
931
993
|
const shape = raw?.shape;
|
|
932
|
-
if (
|
|
933
|
-
shape !== "rect" &&
|
|
934
|
-
shape !== "circle" &&
|
|
935
|
-
shape !== "ellipse" &&
|
|
936
|
-
shape !== "custom"
|
|
937
|
-
) {
|
|
994
|
+
if (!isDielineShape(shape)) {
|
|
938
995
|
return null;
|
|
939
996
|
}
|
|
940
997
|
|
|
941
|
-
const
|
|
942
|
-
const
|
|
998
|
+
const radiusRaw = Number(raw?.radius);
|
|
999
|
+
const offsetRaw = Number(raw?.offset);
|
|
1000
|
+
const unit = typeof raw?.unit === "string" ? raw.unit : "px";
|
|
1001
|
+
const radius =
|
|
1002
|
+
unit === "scene" || !this.canvasService
|
|
1003
|
+
? radiusRaw
|
|
1004
|
+
: this.canvasService.toSceneLength(radiusRaw);
|
|
1005
|
+
const offset =
|
|
1006
|
+
unit === "scene" || !this.canvasService
|
|
1007
|
+
? offsetRaw
|
|
1008
|
+
: this.canvasService.toSceneLength(offsetRaw);
|
|
943
1009
|
return {
|
|
944
1010
|
shape,
|
|
1011
|
+
shapeStyle: normalizeShapeStyle(raw?.shapeStyle),
|
|
945
1012
|
radius: Number.isFinite(radius) ? radius : 0,
|
|
946
1013
|
offset: Number.isFinite(offset) ? offset : 0,
|
|
947
1014
|
};
|
|
@@ -1008,9 +1075,12 @@ export class ImageTool implements Extension {
|
|
|
1008
1075
|
color = "rgba(255, 0, 0, 0.6)",
|
|
1009
1076
|
): Pattern | undefined {
|
|
1010
1077
|
if (typeof document === "undefined") return undefined;
|
|
1078
|
+
const sceneScale = this.canvasService?.getSceneScale() || 1;
|
|
1079
|
+
const cacheKey = `${color}::${sceneScale.toFixed(6)}`;
|
|
1011
1080
|
if (
|
|
1012
1081
|
this.cropShapeHatchPattern &&
|
|
1013
|
-
this.cropShapeHatchPatternColor === color
|
|
1082
|
+
this.cropShapeHatchPatternColor === color &&
|
|
1083
|
+
this.cropShapeHatchPatternKey === cacheKey
|
|
1014
1084
|
) {
|
|
1015
1085
|
return this.cropShapeHatchPattern;
|
|
1016
1086
|
}
|
|
@@ -1043,8 +1113,18 @@ export class ImageTool implements Extension {
|
|
|
1043
1113
|
// @ts-ignore: Fabric Pattern accepts canvas source here.
|
|
1044
1114
|
repetition: "repeat",
|
|
1045
1115
|
});
|
|
1116
|
+
// Scene specs are scaled to screen by CanvasService; keep hatch density in screen pixels.
|
|
1117
|
+
(pattern as any).patternTransform = [
|
|
1118
|
+
1 / sceneScale,
|
|
1119
|
+
0,
|
|
1120
|
+
0,
|
|
1121
|
+
1 / sceneScale,
|
|
1122
|
+
0,
|
|
1123
|
+
0,
|
|
1124
|
+
];
|
|
1046
1125
|
this.cropShapeHatchPattern = pattern;
|
|
1047
1126
|
this.cropShapeHatchPatternColor = color;
|
|
1127
|
+
this.cropShapeHatchPatternKey = cacheKey;
|
|
1048
1128
|
return pattern;
|
|
1049
1129
|
}
|
|
1050
1130
|
|
|
@@ -1062,6 +1142,7 @@ export class ImageTool implements Extension {
|
|
|
1062
1142
|
}
|
|
1063
1143
|
|
|
1064
1144
|
const shape = sceneGeometry.shape as ShapeOverlayShape;
|
|
1145
|
+
const shapeStyle = sceneGeometry.shapeStyle;
|
|
1065
1146
|
const inset = 0;
|
|
1066
1147
|
const shapeWidth = Math.max(1, frame.width);
|
|
1067
1148
|
const shapeHeight = Math.max(1, frame.height);
|
|
@@ -1072,6 +1153,7 @@ export class ImageTool implements Extension {
|
|
|
1072
1153
|
frameWidth: frame.width,
|
|
1073
1154
|
frameHeight: frame.height,
|
|
1074
1155
|
offset: sceneGeometry.offset,
|
|
1156
|
+
shapeStyle,
|
|
1075
1157
|
inset,
|
|
1076
1158
|
shapeWidth,
|
|
1077
1159
|
shapeHeight,
|
|
@@ -1097,6 +1179,7 @@ export class ImageTool implements Extension {
|
|
|
1097
1179
|
x: frame.width / 2,
|
|
1098
1180
|
y: frame.height / 2,
|
|
1099
1181
|
features: [],
|
|
1182
|
+
shapeStyle,
|
|
1100
1183
|
canvasWidth: frame.width,
|
|
1101
1184
|
canvasHeight: frame.height,
|
|
1102
1185
|
};
|
|
@@ -1116,6 +1199,9 @@ export class ImageTool implements Extension {
|
|
|
1116
1199
|
|
|
1117
1200
|
const patternFill = this.getCropShapeHatchPattern();
|
|
1118
1201
|
const hatchFill = patternFill || "rgba(255, 0, 0, 0.22)";
|
|
1202
|
+
const shapeBounds = getPathBounds(shapePathData);
|
|
1203
|
+
const hatchBounds = getPathBounds(hatchPathData);
|
|
1204
|
+
const frameRect = this.toLayoutSceneRect(frame);
|
|
1119
1205
|
const hatchPathLength = hatchPathData.length;
|
|
1120
1206
|
const shapePathLength = shapePathData.length;
|
|
1121
1207
|
const specs: RenderObjectSpec[] = [
|
|
@@ -1123,10 +1209,16 @@ export class ImageTool implements Extension {
|
|
|
1123
1209
|
id: "image.cropShapeHatch",
|
|
1124
1210
|
type: "path",
|
|
1125
1211
|
data: { id: "image.cropShapeHatch", zIndex: 5 },
|
|
1212
|
+
layout: {
|
|
1213
|
+
reference: "custom",
|
|
1214
|
+
referenceRect: frameRect,
|
|
1215
|
+
alignX: "start",
|
|
1216
|
+
alignY: "start",
|
|
1217
|
+
offsetX: hatchBounds.x,
|
|
1218
|
+
offsetY: hatchBounds.y,
|
|
1219
|
+
},
|
|
1126
1220
|
props: {
|
|
1127
1221
|
pathData: hatchPathData,
|
|
1128
|
-
left: frame.left,
|
|
1129
|
-
top: frame.top,
|
|
1130
1222
|
originX: "left",
|
|
1131
1223
|
originY: "top",
|
|
1132
1224
|
fill: hatchFill,
|
|
@@ -1143,15 +1235,21 @@ export class ImageTool implements Extension {
|
|
|
1143
1235
|
id: "image.cropShapePath",
|
|
1144
1236
|
type: "path",
|
|
1145
1237
|
data: { id: "image.cropShapePath", zIndex: 6 },
|
|
1238
|
+
layout: {
|
|
1239
|
+
reference: "custom",
|
|
1240
|
+
referenceRect: frameRect,
|
|
1241
|
+
alignX: "start",
|
|
1242
|
+
alignY: "start",
|
|
1243
|
+
offsetX: shapeBounds.x,
|
|
1244
|
+
offsetY: shapeBounds.y,
|
|
1245
|
+
},
|
|
1146
1246
|
props: {
|
|
1147
1247
|
pathData: shapePathData,
|
|
1148
|
-
left: frame.left,
|
|
1149
|
-
top: frame.top,
|
|
1150
1248
|
originX: "left",
|
|
1151
1249
|
originY: "top",
|
|
1152
1250
|
fill: "rgba(0,0,0,0)",
|
|
1153
1251
|
stroke: "rgba(255, 0, 0, 0.9)",
|
|
1154
|
-
strokeWidth: 1,
|
|
1252
|
+
strokeWidth: this.canvasService?.toSceneLength(1) ?? 1,
|
|
1155
1253
|
selectable: false,
|
|
1156
1254
|
evented: false,
|
|
1157
1255
|
excludeFromExport: true,
|
|
@@ -1168,6 +1266,8 @@ export class ImageTool implements Extension {
|
|
|
1168
1266
|
fillRule: "evenodd",
|
|
1169
1267
|
shapePathLength,
|
|
1170
1268
|
hatchPathLength,
|
|
1269
|
+
shapeBounds,
|
|
1270
|
+
hatchBounds,
|
|
1171
1271
|
hatchFillType:
|
|
1172
1272
|
hatchFill && typeof hatchFill === "object" ? "pattern" : "color",
|
|
1173
1273
|
ids: specs.map((spec) => spec.id),
|
|
@@ -1241,126 +1341,45 @@ export class ImageTool implements Extension {
|
|
|
1241
1341
|
};
|
|
1242
1342
|
}
|
|
1243
1343
|
|
|
1344
|
+
private toSceneObjectScale(value: number): number {
|
|
1345
|
+
if (!this.canvasService) return value;
|
|
1346
|
+
return value / this.canvasService.getSceneScale();
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1244
1349
|
private getCurrentSrc(obj: any): string | undefined {
|
|
1245
1350
|
if (!obj) return undefined;
|
|
1246
1351
|
if (typeof obj.getSrc === "function") return obj.getSrc();
|
|
1247
1352
|
return obj?._originalElement?.src;
|
|
1248
1353
|
}
|
|
1249
1354
|
|
|
1250
|
-
private
|
|
1251
|
-
|
|
1252
|
-
obj.setControlsVisibility({
|
|
1253
|
-
mt: false,
|
|
1254
|
-
mb: false,
|
|
1255
|
-
ml: false,
|
|
1256
|
-
mr: false,
|
|
1257
|
-
tl: true,
|
|
1258
|
-
tr: true,
|
|
1259
|
-
bl: true,
|
|
1260
|
-
br: true,
|
|
1261
|
-
mtr: true,
|
|
1262
|
-
});
|
|
1263
|
-
}
|
|
1264
|
-
|
|
1265
|
-
private async upsertImageObject(
|
|
1266
|
-
item: ImageItem,
|
|
1355
|
+
private async buildImageSpecs(
|
|
1356
|
+
items: ImageItem[],
|
|
1267
1357
|
frame: FrameRect,
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
if (!this.canvasService) return;
|
|
1271
|
-
const canvas = this.canvasService.canvas;
|
|
1272
|
-
const render = this.resolveRenderImageState(item);
|
|
1273
|
-
if (!render.src) return;
|
|
1274
|
-
|
|
1275
|
-
let obj = this.getImageObject(item.id);
|
|
1276
|
-
const currentSrc = this.getCurrentSrc(obj);
|
|
1358
|
+
): Promise<RenderObjectSpec[]> {
|
|
1359
|
+
const specs: RenderObjectSpec[] = [];
|
|
1277
1360
|
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
}
|
|
1361
|
+
for (const item of items) {
|
|
1362
|
+
const render = this.resolveRenderImageState(item);
|
|
1363
|
+
if (!render.src) continue;
|
|
1282
1364
|
|
|
1283
|
-
|
|
1284
|
-
const
|
|
1285
|
-
|
|
1286
|
-
});
|
|
1287
|
-
if (seq !== this.renderSeq) return;
|
|
1365
|
+
const ensured = await this.ensureSourceSize(render.src);
|
|
1366
|
+
const sourceSize = ensured || this.getSourceSize(render.src);
|
|
1367
|
+
const props = this.computeCanvasProps(render, sourceSize, frame);
|
|
1288
1368
|
|
|
1289
|
-
|
|
1369
|
+
specs.push({
|
|
1370
|
+
id: item.id,
|
|
1371
|
+
type: "image",
|
|
1372
|
+
src: render.src,
|
|
1290
1373
|
data: {
|
|
1291
1374
|
id: item.id,
|
|
1292
1375
|
layerId: IMAGE_OBJECT_LAYER_ID,
|
|
1293
1376
|
type: "image-item",
|
|
1294
1377
|
},
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
obj = created as any;
|
|
1298
|
-
}
|
|
1299
|
-
|
|
1300
|
-
this.rememberSourceSize(render.src, obj);
|
|
1301
|
-
const sourceSize = this.getSourceSize(render.src, obj);
|
|
1302
|
-
const props = this.computeCanvasProps(render, sourceSize, frame);
|
|
1303
|
-
|
|
1304
|
-
obj.set({
|
|
1305
|
-
...props,
|
|
1306
|
-
data: {
|
|
1307
|
-
...(obj.data || {}),
|
|
1308
|
-
id: item.id,
|
|
1309
|
-
layerId: IMAGE_OBJECT_LAYER_ID,
|
|
1310
|
-
type: "image-item",
|
|
1311
|
-
},
|
|
1312
|
-
});
|
|
1313
|
-
this.applyImageControlVisibility(obj);
|
|
1314
|
-
obj.setCoords();
|
|
1315
|
-
|
|
1316
|
-
const resolver = this.loadResolvers.get(item.id);
|
|
1317
|
-
if (resolver) {
|
|
1318
|
-
resolver();
|
|
1319
|
-
this.loadResolvers.delete(item.id);
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
|
|
1323
|
-
private syncImageZOrder(items: ImageItem[]) {
|
|
1324
|
-
if (!this.canvasService) return;
|
|
1325
|
-
const canvas = this.canvasService.canvas;
|
|
1326
|
-
|
|
1327
|
-
const objects = canvas.getObjects();
|
|
1328
|
-
let insertIndex = 0;
|
|
1329
|
-
|
|
1330
|
-
const backgroundLayer = this.canvasService.getLayer("background");
|
|
1331
|
-
if (backgroundLayer) {
|
|
1332
|
-
const bgIndex = objects.indexOf(backgroundLayer as any);
|
|
1333
|
-
if (bgIndex >= 0) insertIndex = bgIndex + 1;
|
|
1378
|
+
props,
|
|
1379
|
+
});
|
|
1334
1380
|
}
|
|
1335
1381
|
|
|
1336
|
-
|
|
1337
|
-
const obj = this.getImageObject(item.id);
|
|
1338
|
-
if (!obj) return;
|
|
1339
|
-
canvas.moveObjectTo(obj, insertIndex);
|
|
1340
|
-
insertIndex += 1;
|
|
1341
|
-
});
|
|
1342
|
-
|
|
1343
|
-
const overlayObjects = this.getOverlayObjects().sort((a: any, b: any) => {
|
|
1344
|
-
const az = Number(a?.data?.zIndex ?? 0);
|
|
1345
|
-
const bz = Number(b?.data?.zIndex ?? 0);
|
|
1346
|
-
return az - bz;
|
|
1347
|
-
});
|
|
1348
|
-
overlayObjects.forEach((obj) => {
|
|
1349
|
-
canvas.bringObjectToFront(obj);
|
|
1350
|
-
});
|
|
1351
|
-
|
|
1352
|
-
if (this.isDebugEnabled()) {
|
|
1353
|
-
const stack = canvas
|
|
1354
|
-
.getObjects()
|
|
1355
|
-
.map((obj: any, index: number) => ({
|
|
1356
|
-
index,
|
|
1357
|
-
id: obj?.data?.id,
|
|
1358
|
-
layerId: obj?.data?.layerId,
|
|
1359
|
-
zIndex: obj?.data?.zIndex,
|
|
1360
|
-
}))
|
|
1361
|
-
.filter((item) => item.layerId === IMAGE_OVERLAY_LAYER_ID);
|
|
1362
|
-
this.debug("overlay:stack", stack);
|
|
1363
|
-
}
|
|
1382
|
+
return specs;
|
|
1364
1383
|
}
|
|
1365
1384
|
|
|
1366
1385
|
private buildOverlaySpecs(
|
|
@@ -1384,26 +1403,52 @@ export class ImageTool implements Extension {
|
|
|
1384
1403
|
return [];
|
|
1385
1404
|
}
|
|
1386
1405
|
|
|
1387
|
-
const
|
|
1388
|
-
const
|
|
1406
|
+
const viewport = this.canvasService.getSceneViewportRect();
|
|
1407
|
+
const canvasW = viewport.width || 0;
|
|
1408
|
+
const canvasH = viewport.height || 0;
|
|
1409
|
+
const canvasLeft = viewport.left || 0;
|
|
1410
|
+
const canvasTop = viewport.top || 0;
|
|
1389
1411
|
const visual = this.getFrameVisualConfig();
|
|
1412
|
+
const strokeWidthScene = this.canvasService.toSceneLength(
|
|
1413
|
+
visual.strokeWidth,
|
|
1414
|
+
);
|
|
1415
|
+
const dashLengthScene = this.canvasService.toSceneLength(visual.dashLength);
|
|
1390
1416
|
|
|
1391
|
-
const frameLeft = Math.max(
|
|
1392
|
-
|
|
1417
|
+
const frameLeft = Math.max(
|
|
1418
|
+
canvasLeft,
|
|
1419
|
+
Math.min(canvasLeft + canvasW, frame.left),
|
|
1420
|
+
);
|
|
1421
|
+
const frameTop = Math.max(
|
|
1422
|
+
canvasTop,
|
|
1423
|
+
Math.min(canvasTop + canvasH, frame.top),
|
|
1424
|
+
);
|
|
1393
1425
|
const frameRight = Math.max(
|
|
1394
1426
|
frameLeft,
|
|
1395
|
-
Math.min(canvasW, frame.left + frame.width),
|
|
1427
|
+
Math.min(canvasLeft + canvasW, frame.left + frame.width),
|
|
1396
1428
|
);
|
|
1397
1429
|
const frameBottom = Math.max(
|
|
1398
1430
|
frameTop,
|
|
1399
|
-
Math.min(canvasH, frame.top + frame.height),
|
|
1431
|
+
Math.min(canvasTop + canvasH, frame.top + frame.height),
|
|
1400
1432
|
);
|
|
1401
1433
|
const visibleFrameH = Math.max(0, frameBottom - frameTop);
|
|
1402
1434
|
|
|
1403
|
-
const topH = frameTop;
|
|
1404
|
-
const bottomH = Math.max(0, canvasH - frameBottom);
|
|
1405
|
-
const leftW = frameLeft;
|
|
1406
|
-
const rightW = Math.max(0, canvasW - frameRight);
|
|
1435
|
+
const topH = Math.max(0, frameTop - canvasTop);
|
|
1436
|
+
const bottomH = Math.max(0, canvasTop + canvasH - frameBottom);
|
|
1437
|
+
const leftW = Math.max(0, frameLeft - canvasLeft);
|
|
1438
|
+
const rightW = Math.max(0, canvasLeft + canvasW - frameRight);
|
|
1439
|
+
const viewportRect = this.toLayoutSceneRect({
|
|
1440
|
+
left: canvasLeft,
|
|
1441
|
+
top: canvasTop,
|
|
1442
|
+
width: canvasW,
|
|
1443
|
+
height: canvasH,
|
|
1444
|
+
});
|
|
1445
|
+
const visibleFrameBandRect = this.toLayoutSceneRect({
|
|
1446
|
+
left: canvasLeft,
|
|
1447
|
+
top: frameTop,
|
|
1448
|
+
width: canvasW,
|
|
1449
|
+
height: visibleFrameH,
|
|
1450
|
+
});
|
|
1451
|
+
const frameRect = this.toLayoutSceneRect(frame);
|
|
1407
1452
|
const shapeOverlay = this.buildCropShapeOverlaySpecs(frame, sceneGeometry);
|
|
1408
1453
|
|
|
1409
1454
|
const mask: RenderObjectSpec[] = [
|
|
@@ -1411,13 +1456,17 @@ export class ImageTool implements Extension {
|
|
|
1411
1456
|
id: "image.cropMask.top",
|
|
1412
1457
|
type: "rect",
|
|
1413
1458
|
data: { id: "image.cropMask.top", zIndex: 1 },
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1459
|
+
layout: {
|
|
1460
|
+
reference: "custom",
|
|
1461
|
+
referenceRect: viewportRect,
|
|
1462
|
+
alignX: "start",
|
|
1463
|
+
alignY: "start",
|
|
1464
|
+
width: "100%",
|
|
1418
1465
|
height: topH,
|
|
1419
|
-
|
|
1420
|
-
|
|
1466
|
+
},
|
|
1467
|
+
props: {
|
|
1468
|
+
originX: "left",
|
|
1469
|
+
originY: "top",
|
|
1421
1470
|
fill: visual.outerBackground,
|
|
1422
1471
|
selectable: false,
|
|
1423
1472
|
evented: false,
|
|
@@ -1427,13 +1476,17 @@ export class ImageTool implements Extension {
|
|
|
1427
1476
|
id: "image.cropMask.bottom",
|
|
1428
1477
|
type: "rect",
|
|
1429
1478
|
data: { id: "image.cropMask.bottom", zIndex: 2 },
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1479
|
+
layout: {
|
|
1480
|
+
reference: "custom",
|
|
1481
|
+
referenceRect: viewportRect,
|
|
1482
|
+
alignX: "start",
|
|
1483
|
+
alignY: "end",
|
|
1484
|
+
width: "100%",
|
|
1434
1485
|
height: bottomH,
|
|
1435
|
-
|
|
1436
|
-
|
|
1486
|
+
},
|
|
1487
|
+
props: {
|
|
1488
|
+
originX: "left",
|
|
1489
|
+
originY: "top",
|
|
1437
1490
|
fill: visual.outerBackground,
|
|
1438
1491
|
selectable: false,
|
|
1439
1492
|
evented: false,
|
|
@@ -1443,13 +1496,17 @@ export class ImageTool implements Extension {
|
|
|
1443
1496
|
id: "image.cropMask.left",
|
|
1444
1497
|
type: "rect",
|
|
1445
1498
|
data: { id: "image.cropMask.left", zIndex: 3 },
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1499
|
+
layout: {
|
|
1500
|
+
reference: "custom",
|
|
1501
|
+
referenceRect: visibleFrameBandRect,
|
|
1502
|
+
alignX: "start",
|
|
1503
|
+
alignY: "start",
|
|
1449
1504
|
width: leftW,
|
|
1450
|
-
height:
|
|
1451
|
-
|
|
1452
|
-
|
|
1505
|
+
height: "100%",
|
|
1506
|
+
},
|
|
1507
|
+
props: {
|
|
1508
|
+
originX: "left",
|
|
1509
|
+
originY: "top",
|
|
1453
1510
|
fill: visual.outerBackground,
|
|
1454
1511
|
selectable: false,
|
|
1455
1512
|
evented: false,
|
|
@@ -1459,13 +1516,17 @@ export class ImageTool implements Extension {
|
|
|
1459
1516
|
id: "image.cropMask.right",
|
|
1460
1517
|
type: "rect",
|
|
1461
1518
|
data: { id: "image.cropMask.right", zIndex: 4 },
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1519
|
+
layout: {
|
|
1520
|
+
reference: "custom",
|
|
1521
|
+
referenceRect: visibleFrameBandRect,
|
|
1522
|
+
alignX: "end",
|
|
1523
|
+
alignY: "start",
|
|
1465
1524
|
width: rightW,
|
|
1466
|
-
height:
|
|
1467
|
-
|
|
1468
|
-
|
|
1525
|
+
height: "100%",
|
|
1526
|
+
},
|
|
1527
|
+
props: {
|
|
1528
|
+
originX: "left",
|
|
1529
|
+
originY: "top",
|
|
1469
1530
|
fill: visual.outerBackground,
|
|
1470
1531
|
selectable: false,
|
|
1471
1532
|
evented: false,
|
|
@@ -1477,29 +1538,36 @@ export class ImageTool implements Extension {
|
|
|
1477
1538
|
id: "image.cropFrame",
|
|
1478
1539
|
type: "rect",
|
|
1479
1540
|
data: { id: "image.cropFrame", zIndex: 7 },
|
|
1541
|
+
layout: {
|
|
1542
|
+
reference: "custom",
|
|
1543
|
+
referenceRect: frameRect,
|
|
1544
|
+
alignX: "start",
|
|
1545
|
+
alignY: "start",
|
|
1546
|
+
width: "100%",
|
|
1547
|
+
height: "100%",
|
|
1548
|
+
},
|
|
1480
1549
|
props: {
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
width: frame.width,
|
|
1484
|
-
height: frame.height,
|
|
1485
|
-
originX: "center",
|
|
1486
|
-
originY: "center",
|
|
1550
|
+
originX: "left",
|
|
1551
|
+
originY: "top",
|
|
1487
1552
|
fill: visual.innerBackground,
|
|
1488
1553
|
stroke:
|
|
1489
1554
|
visual.strokeStyle === "hidden"
|
|
1490
1555
|
? "rgba(0,0,0,0)"
|
|
1491
1556
|
: visual.strokeColor,
|
|
1492
|
-
strokeWidth: visual.strokeStyle === "hidden" ? 0 :
|
|
1557
|
+
strokeWidth: visual.strokeStyle === "hidden" ? 0 : strokeWidthScene,
|
|
1493
1558
|
strokeDashArray:
|
|
1494
1559
|
visual.strokeStyle === "dashed"
|
|
1495
|
-
? [
|
|
1560
|
+
? [dashLengthScene, dashLengthScene]
|
|
1496
1561
|
: undefined,
|
|
1497
1562
|
selectable: false,
|
|
1498
1563
|
evented: false,
|
|
1499
1564
|
},
|
|
1500
1565
|
};
|
|
1501
1566
|
|
|
1502
|
-
const specs =
|
|
1567
|
+
const specs =
|
|
1568
|
+
shapeOverlay.length > 0
|
|
1569
|
+
? [...mask, ...shapeOverlay]
|
|
1570
|
+
: [...mask, ...shapeOverlay, frameSpec];
|
|
1503
1571
|
this.debug("overlay:built", {
|
|
1504
1572
|
frame,
|
|
1505
1573
|
shape: sceneGeometry?.shape,
|
|
@@ -1530,35 +1598,38 @@ export class ImageTool implements Extension {
|
|
|
1530
1598
|
});
|
|
1531
1599
|
}
|
|
1532
1600
|
|
|
1533
|
-
this.
|
|
1534
|
-
const id = obj?.data?.id;
|
|
1535
|
-
if (typeof id === "string" && !desiredIds.has(id)) {
|
|
1536
|
-
this.canvasService?.canvas.remove(obj);
|
|
1537
|
-
}
|
|
1538
|
-
});
|
|
1539
|
-
|
|
1540
|
-
for (const item of renderItems) {
|
|
1541
|
-
if (seq !== this.renderSeq) return;
|
|
1542
|
-
await this.upsertImageObject(item, frame, seq);
|
|
1543
|
-
}
|
|
1601
|
+
const imageSpecs = await this.buildImageSpecs(renderItems, frame);
|
|
1544
1602
|
if (seq !== this.renderSeq) return;
|
|
1545
1603
|
|
|
1546
|
-
this.syncImageZOrder(renderItems);
|
|
1547
1604
|
const sceneGeometry = await this.resolveSceneGeometryForOverlay();
|
|
1548
1605
|
if (seq !== this.renderSeq) return;
|
|
1549
1606
|
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1607
|
+
this.imageSpecs = imageSpecs;
|
|
1608
|
+
this.overlaySpecs = this.buildOverlaySpecs(frame, sceneGeometry);
|
|
1609
|
+
await this.canvasService.flushRenderFromProducers();
|
|
1610
|
+
if (seq !== this.renderSeq) return;
|
|
1611
|
+
|
|
1612
|
+
renderItems.forEach((item) => {
|
|
1613
|
+
if (!this.getImageObject(item.id)) return;
|
|
1614
|
+
const resolver = this.loadResolvers.get(item.id);
|
|
1615
|
+
if (!resolver) return;
|
|
1616
|
+
resolver();
|
|
1617
|
+
this.loadResolvers.delete(item.id);
|
|
1618
|
+
});
|
|
1619
|
+
|
|
1620
|
+
if (this.focusedImageId && this.isToolActive) {
|
|
1621
|
+
this.setImageFocus(this.focusedImageId, {
|
|
1622
|
+
syncCanvasSelection: true,
|
|
1623
|
+
skipRender: true,
|
|
1624
|
+
});
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1556
1627
|
const overlayCanvasCount = this.getOverlayObjects().length;
|
|
1557
1628
|
|
|
1558
1629
|
this.debug("render:done", {
|
|
1559
1630
|
seq,
|
|
1560
1631
|
renderCount: renderItems.length,
|
|
1561
|
-
overlayCount: overlaySpecs.length,
|
|
1632
|
+
overlayCount: this.overlaySpecs.length,
|
|
1562
1633
|
overlayCanvasCount,
|
|
1563
1634
|
isToolActive: this.isToolActive,
|
|
1564
1635
|
isImageSelectionActive: this.isImageSelectionActive,
|
|
@@ -1584,8 +1655,12 @@ export class ImageTool implements Extension {
|
|
|
1584
1655
|
const center = target.getCenterPoint
|
|
1585
1656
|
? target.getCenterPoint()
|
|
1586
1657
|
: new Point(target.left ?? 0, target.top ?? 0);
|
|
1658
|
+
const centerScene = this.canvasService
|
|
1659
|
+
? this.canvasService.toScenePoint({ x: center.x, y: center.y })
|
|
1660
|
+
: { x: center.x, y: center.y };
|
|
1587
1661
|
|
|
1588
1662
|
const objectScale = Number.isFinite(target?.scaleX) ? target.scaleX : 1;
|
|
1663
|
+
const objectScaleScene = this.toSceneObjectScale(objectScale || 1);
|
|
1589
1664
|
|
|
1590
1665
|
const workingItem = this.workingItems.find((item) => item.id === id);
|
|
1591
1666
|
const sourceKey = workingItem?.sourceUrl || workingItem?.url || "";
|
|
@@ -1593,10 +1668,10 @@ export class ImageTool implements Extension {
|
|
|
1593
1668
|
const coverScale = this.getCoverScale(frame, sourceSize);
|
|
1594
1669
|
|
|
1595
1670
|
const updates: Partial<ImageItem> = {
|
|
1596
|
-
left: this.clampNormalized((
|
|
1597
|
-
top: this.clampNormalized((
|
|
1671
|
+
left: this.clampNormalized((centerScene.x - frame.left) / frame.width),
|
|
1672
|
+
top: this.clampNormalized((centerScene.y - frame.top) / frame.height),
|
|
1598
1673
|
angle: Number.isFinite(target.angle) ? target.angle : 0,
|
|
1599
|
-
scale: Math.max(0.05,
|
|
1674
|
+
scale: Math.max(0.05, objectScaleScene / coverScale),
|
|
1600
1675
|
};
|
|
1601
1676
|
|
|
1602
1677
|
this.focusedImageId = id;
|
|
@@ -1691,7 +1766,7 @@ export class ImageTool implements Extension {
|
|
|
1691
1766
|
const frame = this.getFrameRect();
|
|
1692
1767
|
const coverScale = this.getCoverScale(frame, source);
|
|
1693
1768
|
|
|
1694
|
-
const currentScale = obj.scaleX || 1;
|
|
1769
|
+
const currentScale = this.toSceneObjectScale(obj.scaleX || 1);
|
|
1695
1770
|
const zoom = Math.max(0.05, currentScale / coverScale);
|
|
1696
1771
|
|
|
1697
1772
|
const updated: Partial<ImageItem> = {
|
|
@@ -1739,16 +1814,21 @@ export class ImageTool implements Extension {
|
|
|
1739
1814
|
Math.max(1, area.height) / Math.max(1, source.height),
|
|
1740
1815
|
);
|
|
1741
1816
|
|
|
1742
|
-
const
|
|
1743
|
-
const
|
|
1817
|
+
const viewport = this.canvasService.getSceneViewportRect();
|
|
1818
|
+
const canvasW = viewport.width || 1;
|
|
1819
|
+
const canvasH = viewport.height || 1;
|
|
1744
1820
|
|
|
1745
1821
|
const areaLeftInput = area.left ?? 0.5;
|
|
1746
1822
|
const areaTopInput = area.top ?? 0.5;
|
|
1747
1823
|
|
|
1748
1824
|
const areaLeftPx =
|
|
1749
|
-
areaLeftInput <= 1.5
|
|
1825
|
+
areaLeftInput <= 1.5
|
|
1826
|
+
? viewport.left + areaLeftInput * canvasW
|
|
1827
|
+
: areaLeftInput;
|
|
1750
1828
|
const areaTopPx =
|
|
1751
|
-
areaTopInput <= 1.5
|
|
1829
|
+
areaTopInput <= 1.5
|
|
1830
|
+
? viewport.top + areaTopInput * canvasH
|
|
1831
|
+
: areaTopInput;
|
|
1752
1832
|
|
|
1753
1833
|
const updates: Partial<ImageItem> = {
|
|
1754
1834
|
scale: Math.max(0.05, desiredScale / baseCover),
|
|
@@ -1827,7 +1907,8 @@ export class ImageTool implements Extension {
|
|
|
1827
1907
|
throw new Error("image-ids-required");
|
|
1828
1908
|
}
|
|
1829
1909
|
|
|
1830
|
-
const
|
|
1910
|
+
const frameScene = this.getFrameRect();
|
|
1911
|
+
const frame = this.getFrameRectScreen(frameScene);
|
|
1831
1912
|
const multiplier = Math.max(1, options.multiplier ?? 2);
|
|
1832
1913
|
const format: "png" | "jpeg" = options.format === "jpeg" ? "jpeg" : "png";
|
|
1833
1914
|
|