@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/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 points = this.marchingSquares(imageData, (_a = options.threshold) != null ? _a : 10);
230
- let finalPoints = points;
231
- if (options.scaleToWidth && options.scaleToHeight && points.length > 0) {
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
- points,
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
- (_b = options.simplifyTolerance) != null ? _b : 0.5
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(imageData, alphaThreshold) {
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
- const index = (y * width + x) * 4;
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
- let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
371
- for (const p of points) {
372
- if (p.x < minX) minX = p.x;
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("ConfigurationService");
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: this.generateId(),
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 newItem.id;
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("ConfigurationService");
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 { layoutScale, layoutOffsetX, layoutOffsetY, visualWidth, visualHeight } = layout;
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) updates.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.width !== void 0 && obj.width) {
2414
- const targetScaleX = item.width * layoutScale / obj.width;
2415
- if (Math.abs(obj.scaleX - targetScaleX) > 1e-3) updates.scaleX = targetScaleX;
2416
- }
2417
- if (item.height !== void 0 && obj.height) {
2418
- const targetScaleY = item.height * layoutScale / obj.height;
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 { width, height, left, top } = item;
2447
- const { layoutScale, layoutOffsetX, layoutOffsetY, visualWidth, visualHeight, dielinePhysicalWidth, dielinePhysicalHeight, bleedOffset } = layout;
2448
- if (width === void 0 && height === void 0) {
2449
- const targetWidth = dielinePhysicalWidth + 2 * bleedOffset;
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.width !== width || item.height !== height || item.left !== left || item.top !== top) {
2474
- this.updateImageInConfig(item.id, { width, height, left, top });
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 { layoutScale, layoutOffsetX, layoutOffsetY, visualWidth, visualHeight } = layout;
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
- if (image.width) {
2490
- const pixelWidth = image.width * image.scaleX;
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, true);
2647
+ this.updateConfig(newItems, skipCanvasUpdate);
2505
2648
  }
2506
2649
  }
2507
2650
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pooder/kit",
3
- "version": "3.3.0",
3
+ "version": "3.4.0",
4
4
  "description": "Standard plugins for Pooder editor",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",