@pooder/kit 3.3.0 → 3.4.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/CHANGELOG.md +6 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +287 -144
- package/dist/index.mjs +287 -144
- package/package.json +1 -1
- package/src/image.ts +113 -138
- package/src/tracer.ts +278 -164
package/dist/index.mjs
CHANGED
|
@@ -215,7 +215,7 @@ var ImageTracer = class {
|
|
|
215
215
|
* @param options Configuration options.
|
|
216
216
|
*/
|
|
217
217
|
static async trace(imageUrl, options = {}) {
|
|
218
|
-
var _a, _b;
|
|
218
|
+
var _a, _b, _c, _d, _e;
|
|
219
219
|
const img = await this.loadImage(imageUrl);
|
|
220
220
|
const width = img.width;
|
|
221
221
|
const height = img.height;
|
|
@@ -226,21 +226,213 @@ var ImageTracer = class {
|
|
|
226
226
|
if (!ctx) throw new Error("Could not get 2D context");
|
|
227
227
|
ctx.drawImage(img, 0, 0);
|
|
228
228
|
const imageData = ctx.getImageData(0, 0, width, height);
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
229
|
+
const threshold = (_a = options.threshold) != null ? _a : 10;
|
|
230
|
+
const adaptiveRadius = Math.max(
|
|
231
|
+
5,
|
|
232
|
+
Math.floor(Math.max(width, height) * 0.02)
|
|
233
|
+
);
|
|
234
|
+
const radius = (_b = options.morphologyRadius) != null ? _b : adaptiveRadius;
|
|
235
|
+
let mask = this.createMask(imageData, threshold);
|
|
236
|
+
if (radius > 0) {
|
|
237
|
+
mask = this.dilate(mask, width, height, radius);
|
|
238
|
+
mask = this.erode(mask, width, height, radius);
|
|
239
|
+
mask = this.fillHoles(mask, width, height);
|
|
240
|
+
}
|
|
241
|
+
const allContourPoints = this.traceAllContours(mask, width, height);
|
|
242
|
+
if (allContourPoints.length === 0) {
|
|
243
|
+
const w = (_c = options.scaleToWidth) != null ? _c : width;
|
|
244
|
+
const h = (_d = options.scaleToHeight) != null ? _d : height;
|
|
245
|
+
return `M 0 0 L ${w} 0 L ${w} ${h} L 0 ${h} Z`;
|
|
246
|
+
}
|
|
247
|
+
const primaryContour = allContourPoints.sort(
|
|
248
|
+
(a, b) => b.length - a.length
|
|
249
|
+
)[0];
|
|
250
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
251
|
+
for (const p of primaryContour) {
|
|
252
|
+
if (p.x < minX) minX = p.x;
|
|
253
|
+
if (p.y < minY) minY = p.y;
|
|
254
|
+
if (p.x > maxX) maxX = p.x;
|
|
255
|
+
if (p.y > maxY) maxY = p.y;
|
|
256
|
+
}
|
|
257
|
+
const globalBounds = {
|
|
258
|
+
minX,
|
|
259
|
+
minY,
|
|
260
|
+
width: maxX - minX,
|
|
261
|
+
height: maxY - minY
|
|
262
|
+
};
|
|
263
|
+
let finalPoints = primaryContour;
|
|
264
|
+
if (options.scaleToWidth && options.scaleToHeight) {
|
|
232
265
|
finalPoints = this.scalePoints(
|
|
233
|
-
|
|
266
|
+
primaryContour,
|
|
234
267
|
options.scaleToWidth,
|
|
235
|
-
options.scaleToHeight
|
|
268
|
+
options.scaleToHeight,
|
|
269
|
+
globalBounds
|
|
236
270
|
);
|
|
237
271
|
}
|
|
238
272
|
const simplifiedPoints = this.douglasPeucker(
|
|
239
273
|
finalPoints,
|
|
240
|
-
(
|
|
274
|
+
(_e = options.simplifyTolerance) != null ? _e : 2
|
|
241
275
|
);
|
|
242
276
|
return this.pointsToSVG(simplifiedPoints);
|
|
243
277
|
}
|
|
278
|
+
static createMask(imageData, threshold) {
|
|
279
|
+
const { width, height, data } = imageData;
|
|
280
|
+
const mask = new Uint8Array(width * height);
|
|
281
|
+
for (let i = 0; i < width * height; i++) {
|
|
282
|
+
const idx = i * 4;
|
|
283
|
+
const r = data[idx];
|
|
284
|
+
const g = data[idx + 1];
|
|
285
|
+
const b = data[idx + 2];
|
|
286
|
+
const a = data[idx + 3];
|
|
287
|
+
if (a > threshold && !(r > 240 && g > 240 && b > 240)) {
|
|
288
|
+
mask[i] = 1;
|
|
289
|
+
} else {
|
|
290
|
+
mask[i] = 0;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return mask;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Fast 1D-separable Dilation
|
|
297
|
+
*/
|
|
298
|
+
static dilate(mask, width, height, radius) {
|
|
299
|
+
const horizontal = new Uint8Array(width * height);
|
|
300
|
+
for (let y = 0; y < height; y++) {
|
|
301
|
+
let count = 0;
|
|
302
|
+
for (let x = -radius; x < width; x++) {
|
|
303
|
+
if (x + radius < width && mask[y * width + x + radius]) count++;
|
|
304
|
+
if (x - radius - 1 >= 0 && mask[y * width + x - radius - 1]) count--;
|
|
305
|
+
if (x >= 0) horizontal[y * width + x] = count > 0 ? 1 : 0;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
const vertical = new Uint8Array(width * height);
|
|
309
|
+
for (let x = 0; x < width; x++) {
|
|
310
|
+
let count = 0;
|
|
311
|
+
for (let y = -radius; y < height; y++) {
|
|
312
|
+
if (y + radius < height && horizontal[(y + radius) * width + x])
|
|
313
|
+
count++;
|
|
314
|
+
if (y - radius - 1 >= 0 && horizontal[(y - radius - 1) * width + x])
|
|
315
|
+
count--;
|
|
316
|
+
if (y >= 0) vertical[y * width + x] = count > 0 ? 1 : 0;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return vertical;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Fast 1D-separable Erosion
|
|
323
|
+
*/
|
|
324
|
+
static erode(mask, width, height, radius) {
|
|
325
|
+
const horizontal = new Uint8Array(width * height);
|
|
326
|
+
for (let y = 0; y < height; y++) {
|
|
327
|
+
let count = 0;
|
|
328
|
+
for (let x = -radius; x < width; x++) {
|
|
329
|
+
if (x + radius < width && mask[y * width + x + radius]) count++;
|
|
330
|
+
if (x - radius - 1 >= 0 && mask[y * width + x - radius - 1]) count--;
|
|
331
|
+
if (x >= 0) {
|
|
332
|
+
const winWidth = Math.min(x + radius, width - 1) - Math.max(x - radius, 0) + 1;
|
|
333
|
+
horizontal[y * width + x] = count === winWidth ? 1 : 0;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
const vertical = new Uint8Array(width * height);
|
|
338
|
+
for (let x = 0; x < width; x++) {
|
|
339
|
+
let count = 0;
|
|
340
|
+
for (let y = -radius; y < height; y++) {
|
|
341
|
+
if (y + radius < height && horizontal[(y + radius) * width + x])
|
|
342
|
+
count++;
|
|
343
|
+
if (y - radius - 1 >= 0 && horizontal[(y - radius - 1) * width + x])
|
|
344
|
+
count--;
|
|
345
|
+
if (y >= 0) {
|
|
346
|
+
const winHeight = Math.min(y + radius, height - 1) - Math.max(y - radius, 0) + 1;
|
|
347
|
+
vertical[y * width + x] = count === winHeight ? 1 : 0;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return vertical;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Fills internal holes in the binary mask using flood fill from edges.
|
|
355
|
+
*/
|
|
356
|
+
static fillHoles(mask, width, height) {
|
|
357
|
+
const background = new Uint8Array(width * height);
|
|
358
|
+
const queue = [];
|
|
359
|
+
for (let x = 0; x < width; x++) {
|
|
360
|
+
if (mask[x] === 0) {
|
|
361
|
+
background[x] = 1;
|
|
362
|
+
queue.push([x, 0]);
|
|
363
|
+
}
|
|
364
|
+
const lastRow = (height - 1) * width + x;
|
|
365
|
+
if (mask[lastRow] === 0) {
|
|
366
|
+
background[lastRow] = 1;
|
|
367
|
+
queue.push([x, height - 1]);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
for (let y = 1; y < height - 1; y++) {
|
|
371
|
+
if (mask[y * width] === 0) {
|
|
372
|
+
background[y * width] = 1;
|
|
373
|
+
queue.push([0, y]);
|
|
374
|
+
}
|
|
375
|
+
if (mask[y * width + width - 1] === 0) {
|
|
376
|
+
background[y * width + width - 1] = 1;
|
|
377
|
+
queue.push([width - 1, y]);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
const dirs = [
|
|
381
|
+
[0, 1],
|
|
382
|
+
[0, -1],
|
|
383
|
+
[1, 0],
|
|
384
|
+
[-1, 0]
|
|
385
|
+
];
|
|
386
|
+
let head = 0;
|
|
387
|
+
while (head < queue.length) {
|
|
388
|
+
const [cx, cy] = queue[head++];
|
|
389
|
+
for (const [dx, dy] of dirs) {
|
|
390
|
+
const nx = cx + dx;
|
|
391
|
+
const ny = cy + dy;
|
|
392
|
+
if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
|
|
393
|
+
const nidx = ny * width + nx;
|
|
394
|
+
if (mask[nidx] === 0 && background[nidx] === 0) {
|
|
395
|
+
background[nidx] = 1;
|
|
396
|
+
queue.push([nx, ny]);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
const filledMask = new Uint8Array(width * height);
|
|
402
|
+
for (let i = 0; i < width * height; i++) {
|
|
403
|
+
filledMask[i] = background[i] === 0 ? 1 : 0;
|
|
404
|
+
}
|
|
405
|
+
return filledMask;
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Traces all contours in the mask with optimized start-point detection
|
|
409
|
+
*/
|
|
410
|
+
static traceAllContours(mask, width, height) {
|
|
411
|
+
const visited = new Uint8Array(width * height);
|
|
412
|
+
const allContours = [];
|
|
413
|
+
for (let y = 0; y < height; y++) {
|
|
414
|
+
for (let x = 0; x < width; x++) {
|
|
415
|
+
const idx = y * width + x;
|
|
416
|
+
if (mask[idx] && !visited[idx]) {
|
|
417
|
+
const isLeftEdge = x === 0 || mask[idx - 1] === 0;
|
|
418
|
+
if (isLeftEdge) {
|
|
419
|
+
const contour = this.marchingSquares(
|
|
420
|
+
mask,
|
|
421
|
+
visited,
|
|
422
|
+
x,
|
|
423
|
+
y,
|
|
424
|
+
width,
|
|
425
|
+
height
|
|
426
|
+
);
|
|
427
|
+
if (contour.length > 2) {
|
|
428
|
+
allContours.push(contour);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
return allContours;
|
|
435
|
+
}
|
|
244
436
|
static loadImage(url) {
|
|
245
437
|
return new Promise((resolve, reject) => {
|
|
246
438
|
const img = new Image();
|
|
@@ -254,33 +446,11 @@ var ImageTracer = class {
|
|
|
254
446
|
* Moore-Neighbor Tracing Algorithm
|
|
255
447
|
* More robust for irregular shapes than simple Marching Squares walker.
|
|
256
448
|
*/
|
|
257
|
-
static marchingSquares(
|
|
258
|
-
const width = imageData.width;
|
|
259
|
-
const height = imageData.height;
|
|
260
|
-
const data = imageData.data;
|
|
449
|
+
static marchingSquares(mask, visited, startX, startY, width, height) {
|
|
261
450
|
const isSolid = (x, y) => {
|
|
262
451
|
if (x < 0 || x >= width || y < 0 || y >= height) return false;
|
|
263
|
-
|
|
264
|
-
const r = data[index];
|
|
265
|
-
const g = data[index + 1];
|
|
266
|
-
const b = data[index + 2];
|
|
267
|
-
const a = data[index + 3];
|
|
268
|
-
if (a <= alphaThreshold) return false;
|
|
269
|
-
if (r > 240 && g > 240 && b > 240) return false;
|
|
270
|
-
return true;
|
|
452
|
+
return mask[y * width + x] === 1;
|
|
271
453
|
};
|
|
272
|
-
let startX = -1;
|
|
273
|
-
let startY = -1;
|
|
274
|
-
searchLoop: for (let y = 0; y < height; y++) {
|
|
275
|
-
for (let x = 0; x < width; x++) {
|
|
276
|
-
if (isSolid(x, y)) {
|
|
277
|
-
startX = x;
|
|
278
|
-
startY = y;
|
|
279
|
-
break searchLoop;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
if (startX === -1) return [];
|
|
284
454
|
const points = [];
|
|
285
455
|
let cx = startX;
|
|
286
456
|
let cy = startY;
|
|
@@ -299,6 +469,7 @@ var ImageTracer = class {
|
|
|
299
469
|
let steps = 0;
|
|
300
470
|
do {
|
|
301
471
|
points.push({ x: cx, y: cy });
|
|
472
|
+
visited[cy * width + cx] = 1;
|
|
302
473
|
let found = false;
|
|
303
474
|
for (let i = 0; i < 8; i++) {
|
|
304
475
|
const idx = (backtrack + 1 + i) % 8;
|
|
@@ -307,16 +478,12 @@ var ImageTracer = class {
|
|
|
307
478
|
if (isSolid(nx, ny)) {
|
|
308
479
|
cx = nx;
|
|
309
480
|
cy = ny;
|
|
310
|
-
backtrack = (idx + 4) % 8;
|
|
311
|
-
backtrack = (idx + 4 + 1) % 8;
|
|
312
481
|
backtrack = (idx + 4 + 1) % 8;
|
|
313
482
|
found = true;
|
|
314
483
|
break;
|
|
315
484
|
}
|
|
316
485
|
}
|
|
317
|
-
if (!found)
|
|
318
|
-
break;
|
|
319
|
-
}
|
|
486
|
+
if (!found) break;
|
|
320
487
|
steps++;
|
|
321
488
|
} while ((cx !== startX || cy !== startY) && steps < maxSteps);
|
|
322
489
|
return points;
|
|
@@ -365,23 +532,14 @@ var ImageTracer = class {
|
|
|
365
532
|
dy = p.y - y;
|
|
366
533
|
return dx * dx + dy * dy;
|
|
367
534
|
}
|
|
368
|
-
static scalePoints(points, targetWidth, targetHeight) {
|
|
535
|
+
static scalePoints(points, targetWidth, targetHeight, bounds) {
|
|
369
536
|
if (points.length === 0) return points;
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
if (p.y < minY) minY = p.y;
|
|
374
|
-
if (p.x > maxX) maxX = p.x;
|
|
375
|
-
if (p.y > maxY) maxY = p.y;
|
|
376
|
-
}
|
|
377
|
-
const srcW = maxX - minX;
|
|
378
|
-
const srcH = maxY - minY;
|
|
379
|
-
if (srcW === 0 || srcH === 0) return points;
|
|
380
|
-
const scaleX = targetWidth / srcW;
|
|
381
|
-
const scaleY = targetHeight / srcH;
|
|
537
|
+
if (bounds.width === 0 || bounds.height === 0) return points;
|
|
538
|
+
const scaleX = targetWidth / bounds.width;
|
|
539
|
+
const scaleY = targetHeight / bounds.height;
|
|
382
540
|
return points.map((p) => ({
|
|
383
|
-
x: (p.x - minX) * scaleX,
|
|
384
|
-
y: (p.y - minY) * scaleY
|
|
541
|
+
x: (p.x - bounds.minX) * scaleX,
|
|
542
|
+
y: (p.y - bounds.minY) * scaleY
|
|
385
543
|
}));
|
|
386
544
|
}
|
|
387
545
|
static pointsToSVG(points) {
|
|
@@ -2141,6 +2299,7 @@ var ImageTool = class {
|
|
|
2141
2299
|
};
|
|
2142
2300
|
this.items = [];
|
|
2143
2301
|
this.objectMap = /* @__PURE__ */ new Map();
|
|
2302
|
+
this.loadResolvers = /* @__PURE__ */ new Map();
|
|
2144
2303
|
this.isUpdatingConfig = false;
|
|
2145
2304
|
}
|
|
2146
2305
|
activate(context) {
|
|
@@ -2150,19 +2309,15 @@ var ImageTool = class {
|
|
|
2150
2309
|
console.warn("CanvasService not found for ImageTool");
|
|
2151
2310
|
return;
|
|
2152
2311
|
}
|
|
2153
|
-
const configService = context.services.get(
|
|
2312
|
+
const configService = context.services.get(
|
|
2313
|
+
"ConfigurationService"
|
|
2314
|
+
);
|
|
2154
2315
|
if (configService) {
|
|
2155
2316
|
this.items = configService.get("image.items", []) || [];
|
|
2156
2317
|
configService.onAnyChange((e) => {
|
|
2157
2318
|
if (this.isUpdatingConfig) return;
|
|
2158
|
-
let shouldUpdate = false;
|
|
2159
2319
|
if (e.key === "image.items") {
|
|
2160
2320
|
this.items = e.value || [];
|
|
2161
|
-
shouldUpdate = true;
|
|
2162
|
-
} else if (e.key.startsWith("dieline.") && e.key !== "dieline.holes") {
|
|
2163
|
-
shouldUpdate = true;
|
|
2164
|
-
}
|
|
2165
|
-
if (shouldUpdate) {
|
|
2166
2321
|
this.updateImages();
|
|
2167
2322
|
}
|
|
2168
2323
|
});
|
|
@@ -2198,15 +2353,39 @@ var ImageTool = class {
|
|
|
2198
2353
|
{
|
|
2199
2354
|
command: "addImage",
|
|
2200
2355
|
title: "Add Image",
|
|
2201
|
-
handler: (url, options) => {
|
|
2356
|
+
handler: async (url, options) => {
|
|
2357
|
+
const id = this.generateId();
|
|
2202
2358
|
const newItem = {
|
|
2203
|
-
id
|
|
2359
|
+
id,
|
|
2204
2360
|
url,
|
|
2205
2361
|
opacity: 1,
|
|
2206
2362
|
...options
|
|
2207
2363
|
};
|
|
2364
|
+
const promise = new Promise((resolve) => {
|
|
2365
|
+
this.loadResolvers.set(id, () => resolve(id));
|
|
2366
|
+
});
|
|
2208
2367
|
this.updateConfig([...this.items, newItem]);
|
|
2209
|
-
return
|
|
2368
|
+
return promise;
|
|
2369
|
+
}
|
|
2370
|
+
},
|
|
2371
|
+
{
|
|
2372
|
+
command: "fitImageToArea",
|
|
2373
|
+
title: "Fit Image to Area",
|
|
2374
|
+
handler: (id, area) => {
|
|
2375
|
+
var _a, _b;
|
|
2376
|
+
const item = this.items.find((i) => i.id === id);
|
|
2377
|
+
const obj = this.objectMap.get(id);
|
|
2378
|
+
if (item && obj && obj.width && obj.height) {
|
|
2379
|
+
const scale = Math.max(
|
|
2380
|
+
area.width / obj.width,
|
|
2381
|
+
area.height / obj.height
|
|
2382
|
+
);
|
|
2383
|
+
this.updateImageInConfig(id, {
|
|
2384
|
+
scale,
|
|
2385
|
+
left: (_a = area.left) != null ? _a : 0.5,
|
|
2386
|
+
top: (_b = area.top) != null ? _b : 0.5
|
|
2387
|
+
});
|
|
2388
|
+
}
|
|
2210
2389
|
}
|
|
2211
2390
|
},
|
|
2212
2391
|
{
|
|
@@ -2274,7 +2453,9 @@ var ImageTool = class {
|
|
|
2274
2453
|
if (!this.context) return;
|
|
2275
2454
|
this.isUpdatingConfig = true;
|
|
2276
2455
|
this.items = newItems;
|
|
2277
|
-
const configService = this.context.services.get(
|
|
2456
|
+
const configService = this.context.services.get(
|
|
2457
|
+
"ConfigurationService"
|
|
2458
|
+
);
|
|
2278
2459
|
if (configService) {
|
|
2279
2460
|
configService.update("image.items", newItems);
|
|
2280
2461
|
}
|
|
@@ -2320,53 +2501,12 @@ var ImageTool = class {
|
|
|
2320
2501
|
var _a, _b;
|
|
2321
2502
|
const canvasW = ((_a = this.canvasService) == null ? void 0 : _a.canvas.width) || 800;
|
|
2322
2503
|
const canvasH = ((_b = this.canvasService) == null ? void 0 : _b.canvas.height) || 600;
|
|
2323
|
-
let layoutScale = 1;
|
|
2324
|
-
let layoutOffsetX = 0;
|
|
2325
|
-
let layoutOffsetY = 0;
|
|
2326
|
-
let visualWidth = canvasW;
|
|
2327
|
-
let visualHeight = canvasH;
|
|
2328
|
-
let dielinePhysicalWidth = 500;
|
|
2329
|
-
let dielinePhysicalHeight = 500;
|
|
2330
|
-
let bleedOffset = 0;
|
|
2331
|
-
if (this.context) {
|
|
2332
|
-
const configService = this.context.services.get("ConfigurationService");
|
|
2333
|
-
if (configService) {
|
|
2334
|
-
dielinePhysicalWidth = configService.get("dieline.width") || 500;
|
|
2335
|
-
dielinePhysicalHeight = configService.get("dieline.height") || 500;
|
|
2336
|
-
bleedOffset = configService.get("dieline.offset") || 0;
|
|
2337
|
-
const paddingValue = configService.get("dieline.padding") || 40;
|
|
2338
|
-
let padding = 0;
|
|
2339
|
-
if (typeof paddingValue === "number") {
|
|
2340
|
-
padding = paddingValue;
|
|
2341
|
-
} else if (typeof paddingValue === "string") {
|
|
2342
|
-
if (paddingValue.endsWith("%")) {
|
|
2343
|
-
const percent = parseFloat(paddingValue) / 100;
|
|
2344
|
-
padding = Math.min(canvasW, canvasH) * percent;
|
|
2345
|
-
} else {
|
|
2346
|
-
padding = parseFloat(paddingValue) || 0;
|
|
2347
|
-
}
|
|
2348
|
-
}
|
|
2349
|
-
const layout = Coordinate.calculateLayout(
|
|
2350
|
-
{ width: canvasW, height: canvasH },
|
|
2351
|
-
{ width: dielinePhysicalWidth, height: dielinePhysicalHeight },
|
|
2352
|
-
padding
|
|
2353
|
-
);
|
|
2354
|
-
layoutScale = layout.scale;
|
|
2355
|
-
layoutOffsetX = layout.offsetX;
|
|
2356
|
-
layoutOffsetY = layout.offsetY;
|
|
2357
|
-
visualWidth = layout.width;
|
|
2358
|
-
visualHeight = layout.height;
|
|
2359
|
-
}
|
|
2360
|
-
}
|
|
2361
2504
|
return {
|
|
2362
|
-
layoutScale,
|
|
2363
|
-
layoutOffsetX,
|
|
2364
|
-
layoutOffsetY,
|
|
2365
|
-
visualWidth,
|
|
2366
|
-
visualHeight
|
|
2367
|
-
dielinePhysicalWidth,
|
|
2368
|
-
dielinePhysicalHeight,
|
|
2369
|
-
bleedOffset
|
|
2505
|
+
layoutScale: 1,
|
|
2506
|
+
layoutOffsetX: 0,
|
|
2507
|
+
layoutOffsetY: 0,
|
|
2508
|
+
visualWidth: canvasW,
|
|
2509
|
+
visualHeight: canvasH
|
|
2370
2510
|
};
|
|
2371
2511
|
}
|
|
2372
2512
|
updateImages() {
|
|
@@ -2389,8 +2529,8 @@ var ImageTool = class {
|
|
|
2389
2529
|
if (!obj) {
|
|
2390
2530
|
this.loadImage(item, layer, layout);
|
|
2391
2531
|
} else {
|
|
2392
|
-
this.updateObjectProperties(obj, item, layout);
|
|
2393
2532
|
layer.remove(obj);
|
|
2533
|
+
this.updateObjectProperties(obj, item, layout);
|
|
2394
2534
|
layer.add(obj);
|
|
2395
2535
|
}
|
|
2396
2536
|
});
|
|
@@ -2398,10 +2538,17 @@ var ImageTool = class {
|
|
|
2398
2538
|
this.canvasService.requestRenderAll();
|
|
2399
2539
|
}
|
|
2400
2540
|
updateObjectProperties(obj, item, layout) {
|
|
2401
|
-
const {
|
|
2541
|
+
const {
|
|
2542
|
+
layoutScale,
|
|
2543
|
+
layoutOffsetX,
|
|
2544
|
+
layoutOffsetY,
|
|
2545
|
+
visualWidth,
|
|
2546
|
+
visualHeight
|
|
2547
|
+
} = layout;
|
|
2402
2548
|
const updates = {};
|
|
2403
2549
|
if (obj.opacity !== item.opacity) updates.opacity = item.opacity;
|
|
2404
|
-
if (item.angle !== void 0 && obj.angle !== item.angle)
|
|
2550
|
+
if (item.angle !== void 0 && obj.angle !== item.angle)
|
|
2551
|
+
updates.angle = item.angle;
|
|
2405
2552
|
if (item.left !== void 0) {
|
|
2406
2553
|
const globalLeft = layoutOffsetX + item.left * visualWidth;
|
|
2407
2554
|
if (Math.abs(obj.left - globalLeft) > 1) updates.left = globalLeft;
|
|
@@ -2410,13 +2557,12 @@ var ImageTool = class {
|
|
|
2410
2557
|
const globalTop = layoutOffsetY + item.top * visualHeight;
|
|
2411
2558
|
if (Math.abs(obj.top - globalTop) > 1) updates.top = globalTop;
|
|
2412
2559
|
}
|
|
2413
|
-
if (item.
|
|
2414
|
-
const
|
|
2415
|
-
if (Math.abs(obj.scaleX -
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
if (Math.abs(obj.scaleY - targetScaleY) > 1e-3) updates.scaleY = targetScaleY;
|
|
2560
|
+
if (item.scale !== void 0) {
|
|
2561
|
+
const targetScale = item.scale * layoutScale;
|
|
2562
|
+
if (Math.abs(obj.scaleX - targetScale) > 1e-3) {
|
|
2563
|
+
updates.scaleX = targetScale;
|
|
2564
|
+
updates.scaleY = targetScale;
|
|
2565
|
+
}
|
|
2420
2566
|
}
|
|
2421
2567
|
if (obj.originX !== "center") {
|
|
2422
2568
|
updates.originX = "center";
|
|
@@ -2424,6 +2570,7 @@ var ImageTool = class {
|
|
|
2424
2570
|
}
|
|
2425
2571
|
if (Object.keys(updates).length > 0) {
|
|
2426
2572
|
obj.set(updates);
|
|
2573
|
+
obj.setCoords();
|
|
2427
2574
|
}
|
|
2428
2575
|
}
|
|
2429
2576
|
loadImage(item, layer, layout) {
|
|
@@ -2443,18 +2590,10 @@ var ImageTool = class {
|
|
|
2443
2590
|
ml: false,
|
|
2444
2591
|
mr: false
|
|
2445
2592
|
});
|
|
2446
|
-
let {
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
const targetHeight = dielinePhysicalHeight + 2 * bleedOffset;
|
|
2451
|
-
const targetMax = Math.max(targetWidth, targetHeight);
|
|
2452
|
-
const imageMax = Math.max(image.width || 1, image.height || 1);
|
|
2453
|
-
const scale = targetMax / imageMax;
|
|
2454
|
-
width = (image.width || 1) * scale;
|
|
2455
|
-
height = (image.height || 1) * scale;
|
|
2456
|
-
item.width = width;
|
|
2457
|
-
item.height = height;
|
|
2593
|
+
let { scale, left, top } = item;
|
|
2594
|
+
if (scale === void 0) {
|
|
2595
|
+
scale = 1;
|
|
2596
|
+
item.scale = scale;
|
|
2458
2597
|
}
|
|
2459
2598
|
if (left === void 0 && top === void 0) {
|
|
2460
2599
|
left = 0.5;
|
|
@@ -2465,13 +2604,18 @@ var ImageTool = class {
|
|
|
2465
2604
|
this.updateObjectProperties(image, item, layout);
|
|
2466
2605
|
layer.add(image);
|
|
2467
2606
|
this.objectMap.set(item.id, image);
|
|
2607
|
+
const resolver = this.loadResolvers.get(item.id);
|
|
2608
|
+
if (resolver) {
|
|
2609
|
+
resolver();
|
|
2610
|
+
this.loadResolvers.delete(item.id);
|
|
2611
|
+
}
|
|
2468
2612
|
image.on("modified", (e) => {
|
|
2469
2613
|
this.handleObjectModified(item.id, image);
|
|
2470
2614
|
});
|
|
2471
2615
|
layer.dirty = true;
|
|
2472
2616
|
(_a = this.canvasService) == null ? void 0 : _a.requestRenderAll();
|
|
2473
|
-
if (item.
|
|
2474
|
-
this.updateImageInConfig(item.id, {
|
|
2617
|
+
if (item.scale !== scale || item.left !== left || item.top !== top) {
|
|
2618
|
+
this.updateImageInConfig(item.id, { scale, left, top }, true);
|
|
2475
2619
|
}
|
|
2476
2620
|
}).catch((err) => {
|
|
2477
2621
|
console.error("Failed to load image", item.url, err);
|
|
@@ -2479,29 +2623,28 @@ var ImageTool = class {
|
|
|
2479
2623
|
}
|
|
2480
2624
|
handleObjectModified(id, image) {
|
|
2481
2625
|
const layout = this.getLayoutInfo();
|
|
2482
|
-
const {
|
|
2626
|
+
const {
|
|
2627
|
+
layoutScale,
|
|
2628
|
+
layoutOffsetX,
|
|
2629
|
+
layoutOffsetY,
|
|
2630
|
+
visualWidth,
|
|
2631
|
+
visualHeight
|
|
2632
|
+
} = layout;
|
|
2483
2633
|
const matrix = image.calcTransformMatrix();
|
|
2484
2634
|
const globalPoint = util.transformPoint(new Point2(0, 0), matrix);
|
|
2485
2635
|
const updates = {};
|
|
2486
2636
|
updates.left = (globalPoint.x - layoutOffsetX) / visualWidth;
|
|
2487
2637
|
updates.top = (globalPoint.y - layoutOffsetY) / visualHeight;
|
|
2488
2638
|
updates.angle = image.angle;
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
updates.width = pixelWidth / layoutScale;
|
|
2492
|
-
}
|
|
2493
|
-
if (image.height) {
|
|
2494
|
-
const pixelHeight = image.height * image.scaleY;
|
|
2495
|
-
updates.height = pixelHeight / layoutScale;
|
|
2496
|
-
}
|
|
2497
|
-
this.updateImageInConfig(id, updates);
|
|
2639
|
+
updates.scale = image.scaleX / layoutScale;
|
|
2640
|
+
this.updateImageInConfig(id, updates, true);
|
|
2498
2641
|
}
|
|
2499
|
-
updateImageInConfig(id, updates) {
|
|
2642
|
+
updateImageInConfig(id, updates, skipCanvasUpdate = false) {
|
|
2500
2643
|
const index = this.items.findIndex((i) => i.id === id);
|
|
2501
2644
|
if (index !== -1) {
|
|
2502
2645
|
const newItems = [...this.items];
|
|
2503
2646
|
newItems[index] = { ...newItems[index], ...updates };
|
|
2504
|
-
this.updateConfig(newItems,
|
|
2647
|
+
this.updateConfig(newItems, skipCanvasUpdate);
|
|
2505
2648
|
}
|
|
2506
2649
|
}
|
|
2507
2650
|
};
|