@pooder/kit 5.3.0 → 5.3.1

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.
Files changed (60) hide show
  1. package/.test-dist/src/CanvasService.js +249 -249
  2. package/.test-dist/src/ViewportSystem.js +75 -75
  3. package/.test-dist/src/background.js +203 -203
  4. package/.test-dist/src/bridgeSelection.js +20 -20
  5. package/.test-dist/src/constraints.js +237 -237
  6. package/.test-dist/src/dieline.js +818 -818
  7. package/.test-dist/src/edgeScale.js +12 -12
  8. package/.test-dist/src/feature.js +826 -826
  9. package/.test-dist/src/featureComplete.js +32 -32
  10. package/.test-dist/src/film.js +167 -167
  11. package/.test-dist/src/geometry.js +506 -506
  12. package/.test-dist/src/image.js +1250 -1250
  13. package/.test-dist/src/maskOps.js +270 -270
  14. package/.test-dist/src/mirror.js +104 -104
  15. package/.test-dist/src/renderSpec.js +2 -2
  16. package/.test-dist/src/ruler.js +343 -343
  17. package/.test-dist/src/sceneLayout.js +99 -99
  18. package/.test-dist/src/sceneLayoutModel.js +196 -196
  19. package/.test-dist/src/sceneView.js +40 -40
  20. package/.test-dist/src/sceneVisibility.js +42 -42
  21. package/.test-dist/src/size.js +332 -332
  22. package/.test-dist/src/tracer.js +544 -544
  23. package/.test-dist/src/white-ink.js +829 -829
  24. package/.test-dist/src/wrappedOffsets.js +33 -33
  25. package/CHANGELOG.md +6 -0
  26. package/dist/index.d.mts +6 -0
  27. package/dist/index.d.ts +6 -0
  28. package/dist/index.js +108 -20
  29. package/dist/index.mjs +108 -20
  30. package/package.json +1 -1
  31. package/src/coordinate.ts +106 -106
  32. package/src/extensions/background.ts +230 -230
  33. package/src/extensions/bridgeSelection.ts +17 -17
  34. package/src/extensions/constraints.ts +322 -322
  35. package/src/extensions/dieline.ts +46 -0
  36. package/src/extensions/edgeScale.ts +19 -19
  37. package/src/extensions/feature.ts +1021 -1021
  38. package/src/extensions/featureComplete.ts +46 -46
  39. package/src/extensions/film.ts +194 -194
  40. package/src/extensions/geometry.ts +752 -719
  41. package/src/extensions/image.ts +1926 -1924
  42. package/src/extensions/index.ts +11 -11
  43. package/src/extensions/maskOps.ts +283 -283
  44. package/src/extensions/mirror.ts +128 -128
  45. package/src/extensions/ruler.ts +451 -451
  46. package/src/extensions/sceneLayout.ts +140 -140
  47. package/src/extensions/sceneLayoutModel.ts +352 -342
  48. package/src/extensions/sceneVisibility.ts +71 -71
  49. package/src/extensions/size.ts +389 -389
  50. package/src/extensions/tracer.ts +58 -19
  51. package/src/extensions/white-ink.ts +1400 -1400
  52. package/src/extensions/wrappedOffsets.ts +33 -33
  53. package/src/index.ts +2 -2
  54. package/src/services/CanvasService.ts +300 -300
  55. package/src/services/ViewportSystem.ts +95 -95
  56. package/src/services/index.ts +3 -3
  57. package/src/services/renderSpec.ts +18 -18
  58. package/src/units.ts +27 -27
  59. package/tests/run.ts +118 -118
  60. package/tsconfig.test.json +15 -15
@@ -1,33 +1,33 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.wrappedDistance = wrappedDistance;
4
- exports.sampleWrappedOffsets = sampleWrappedOffsets;
5
- function wrappedDistance(total, start, end) {
6
- if (!Number.isFinite(total) || total <= 0)
7
- return 0;
8
- if (!Number.isFinite(start) || !Number.isFinite(end))
9
- return 0;
10
- const s = ((start % total) + total) % total;
11
- const e = ((end % total) + total) % total;
12
- return e >= s ? e - s : total - s + e;
13
- }
14
- function sampleWrappedOffsets(total, start, end, count) {
15
- if (!Number.isFinite(total) || total <= 0)
16
- return [];
17
- if (!Number.isFinite(start) || !Number.isFinite(end))
18
- return [];
19
- const n = Math.max(0, Math.floor(count));
20
- if (n <= 0)
21
- return [];
22
- const dist = wrappedDistance(total, start, end);
23
- if (n === 1)
24
- return [((start % total) + total) % total];
25
- const step = dist / (n - 1);
26
- const offsets = [];
27
- for (let i = 0; i < n; i++) {
28
- const raw = start + step * i;
29
- const wrapped = ((raw % total) + total) % total;
30
- offsets.push(wrapped);
31
- }
32
- return offsets;
33
- }
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.wrappedDistance = wrappedDistance;
4
+ exports.sampleWrappedOffsets = sampleWrappedOffsets;
5
+ function wrappedDistance(total, start, end) {
6
+ if (!Number.isFinite(total) || total <= 0)
7
+ return 0;
8
+ if (!Number.isFinite(start) || !Number.isFinite(end))
9
+ return 0;
10
+ const s = ((start % total) + total) % total;
11
+ const e = ((end % total) + total) % total;
12
+ return e >= s ? e - s : total - s + e;
13
+ }
14
+ function sampleWrappedOffsets(total, start, end, count) {
15
+ if (!Number.isFinite(total) || total <= 0)
16
+ return [];
17
+ if (!Number.isFinite(start) || !Number.isFinite(end))
18
+ return [];
19
+ const n = Math.max(0, Math.floor(count));
20
+ if (n <= 0)
21
+ return [];
22
+ const dist = wrappedDistance(total, start, end);
23
+ if (n === 1)
24
+ return [((start % total) + total) % total];
25
+ const step = dist / (n - 1);
26
+ const offsets = [];
27
+ for (let i = 0; i < n; i++) {
28
+ const raw = start + step * i;
29
+ const wrapped = ((raw % total) + total) % total;
30
+ offsets.push(wrapped);
31
+ }
32
+ return offsets;
33
+ }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @pooder/kit
2
2
 
3
+ ## 5.3.1
4
+
5
+ ### Patch Changes
6
+
7
+ - fix edge detection and expand
8
+
3
9
  ## 5.3.0
4
10
 
5
11
  ### Minor Changes
package/dist/index.d.mts CHANGED
@@ -216,6 +216,8 @@ interface DielineGeometry {
216
216
  scale?: number;
217
217
  strokeWidth?: number;
218
218
  pathData?: string;
219
+ customSourceWidthPx?: number;
220
+ customSourceHeightPx?: number;
219
221
  }
220
222
  interface LineStyle {
221
223
  width: number;
@@ -238,6 +240,8 @@ interface DielineState {
238
240
  showBleedLines: boolean;
239
241
  features: DielineFeature[];
240
242
  pathData?: string;
243
+ customSourceWidthPx?: number;
244
+ customSourceHeightPx?: number;
241
245
  }
242
246
  declare class DielineTool implements Extension {
243
247
  id: string;
@@ -640,6 +644,8 @@ interface SceneGeometrySnapshot {
640
644
  offset: number;
641
645
  scale: number;
642
646
  pathData?: string;
647
+ customSourceWidthPx?: number;
648
+ customSourceHeightPx?: number;
643
649
  }
644
650
 
645
651
  declare class SceneLayoutService implements Service {
package/dist/index.d.ts CHANGED
@@ -216,6 +216,8 @@ interface DielineGeometry {
216
216
  scale?: number;
217
217
  strokeWidth?: number;
218
218
  pathData?: string;
219
+ customSourceWidthPx?: number;
220
+ customSourceHeightPx?: number;
219
221
  }
220
222
  interface LineStyle {
221
223
  width: number;
@@ -238,6 +240,8 @@ interface DielineState {
238
240
  showBleedLines: boolean;
239
241
  features: DielineFeature[];
240
242
  pathData?: string;
243
+ customSourceWidthPx?: number;
244
+ customSourceHeightPx?: number;
241
245
  }
242
246
  declare class DielineTool implements Extension {
243
247
  id: string;
@@ -640,6 +644,8 @@ interface SceneGeometrySnapshot {
640
644
  offset: number;
641
645
  scale: number;
642
646
  pathData?: string;
647
+ customSourceWidthPx?: number;
648
+ customSourceHeightPx?: number;
643
649
  }
644
650
 
645
651
  declare class SceneLayoutService implements Service {
package/dist/index.js CHANGED
@@ -395,7 +395,17 @@ function selectOuterChain(args) {
395
395
  }
396
396
  function createBaseShape(options) {
397
397
  var _a;
398
- const { shape, width, height, radius, x, y, pathData } = options;
398
+ const {
399
+ shape,
400
+ width,
401
+ height,
402
+ radius,
403
+ x,
404
+ y,
405
+ pathData,
406
+ customSourceWidthPx,
407
+ customSourceHeightPx
408
+ } = options;
399
409
  const center = new import_paper.default.Point(x, y);
400
410
  if (shape === "rect") {
401
411
  return new import_paper.default.Path.Rectangle({
@@ -421,10 +431,21 @@ function createBaseShape(options) {
421
431
  single.pathData = pathData;
422
432
  return single;
423
433
  })();
424
- path.position = center;
434
+ const sourceWidth = Number(customSourceWidthPx != null ? customSourceWidthPx : 0);
435
+ const sourceHeight = Number(customSourceHeightPx != null ? customSourceHeightPx : 0);
436
+ if (Number.isFinite(sourceWidth) && Number.isFinite(sourceHeight) && sourceWidth > 0 && sourceHeight > 0 && width > 0 && height > 0) {
437
+ const targetLeft = x - width / 2;
438
+ const targetTop = y - height / 2;
439
+ path.scale(width / sourceWidth, height / sourceHeight, new import_paper.default.Point(0, 0));
440
+ path.translate(new import_paper.default.Point(targetLeft, targetTop));
441
+ return path;
442
+ }
425
443
  if (width > 0 && height > 0 && path.bounds.width > 0 && path.bounds.height > 0) {
444
+ path.position = center;
426
445
  path.scale(width / path.bounds.width, height / path.bounds.height);
446
+ return path;
427
447
  }
448
+ path.position = center;
428
449
  return path;
429
450
  } else {
430
451
  return new import_paper.default.Path.Rectangle({
@@ -1059,6 +1080,10 @@ function buildSceneGeometry(configService, layout) {
1059
1080
  "mm"
1060
1081
  );
1061
1082
  const offset = (layout.cutRect.width - layout.trimRect.width) / 2;
1083
+ const sourceWidth = Number(configService.get("dieline.customSourceWidthPx", 0));
1084
+ const sourceHeight = Number(
1085
+ configService.get("dieline.customSourceHeightPx", 0)
1086
+ );
1062
1087
  return {
1063
1088
  shape: configService.get("dieline.shape", "rect"),
1064
1089
  unit: "mm",
@@ -1070,7 +1095,9 @@ function buildSceneGeometry(configService, layout) {
1070
1095
  radius: radiusMm * layout.scale,
1071
1096
  offset,
1072
1097
  scale: layout.scale,
1073
- pathData: configService.get("dieline.pathData")
1098
+ pathData: configService.get("dieline.pathData"),
1099
+ customSourceWidthPx: Number.isFinite(sourceWidth) && sourceWidth > 0 ? sourceWidth : void 0,
1100
+ customSourceHeightPx: Number.isFinite(sourceHeight) && sourceHeight > 0 ? sourceHeight : void 0
1074
1101
  };
1075
1102
  }
1076
1103
 
@@ -2497,6 +2524,8 @@ var ImageTool = class {
2497
2524
  this.normalizeItem({
2498
2525
  ...item,
2499
2526
  url,
2527
+ // Keep original source for next image-tool session editing,
2528
+ // and use committedUrl as non-image-tools render source.
2500
2529
  sourceUrl,
2501
2530
  committedUrl: url
2502
2531
  })
@@ -3400,14 +3429,10 @@ var ImageTracer = class {
3400
3429
  };
3401
3430
  }
3402
3431
  const baseUnpaddedContours = baseContours.map(
3403
- (contour) => this.clampPointsToImageBounds(
3404
- contour.map((p) => ({
3405
- x: p.x - padding,
3406
- y: p.y - padding
3407
- })),
3408
- width,
3409
- height
3410
- )
3432
+ (contour) => contour.map((p) => ({
3433
+ x: p.x - padding,
3434
+ y: p.y - padding
3435
+ }))
3411
3436
  ).filter((contour) => contour.length > 2);
3412
3437
  if (!baseUnpaddedContours.length) {
3413
3438
  const w = (_h = options.scaleToWidth) != null ? _h : width;
@@ -3496,6 +3521,39 @@ var ImageTracer = class {
3496
3521
  this.flattenContours(baseScaledContours)
3497
3522
  );
3498
3523
  }
3524
+ if (expand > 0) {
3525
+ const expectedExpandedBounds = {
3526
+ x: baseBounds.x - expand,
3527
+ y: baseBounds.y - expand,
3528
+ width: baseBounds.width + expand * 2,
3529
+ height: baseBounds.height + expand * 2
3530
+ };
3531
+ if (expectedExpandedBounds.width > 0 && expectedExpandedBounds.height > 0 && globalBounds.width > 0 && globalBounds.height > 0) {
3532
+ 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;
3533
+ if (shouldNormalizeExpandBounds) {
3534
+ const beforeNormalize = globalBounds;
3535
+ finalContours = this.translateContours(
3536
+ this.scaleContours(
3537
+ finalContours,
3538
+ expectedExpandedBounds.width,
3539
+ expectedExpandedBounds.height,
3540
+ globalBounds
3541
+ ),
3542
+ expectedExpandedBounds.x,
3543
+ expectedExpandedBounds.y
3544
+ );
3545
+ globalBounds = this.boundsFromPoints(
3546
+ this.flattenContours(finalContours)
3547
+ );
3548
+ debugLog("traceWithBounds:expand-normalized", {
3549
+ expand,
3550
+ expectedExpandedBounds,
3551
+ beforeNormalize,
3552
+ afterNormalize: globalBounds
3553
+ });
3554
+ }
3555
+ }
3556
+ }
3499
3557
  debugLog("traceWithBounds:contours", {
3500
3558
  baseContourCount: baseContoursRaw.length,
3501
3559
  baseSelectedCount: baseContours.length,
@@ -3858,13 +3916,13 @@ var ImageTracer = class {
3858
3916
  (points) => this.scalePoints(points, targetWidth, targetHeight, bounds)
3859
3917
  );
3860
3918
  }
3861
- static clampPointsToImageBounds(points, width, height) {
3862
- const maxX = Math.max(0, width);
3863
- const maxY = Math.max(0, height);
3864
- return points.map((p) => ({
3865
- x: Math.max(0, Math.min(maxX, p.x)),
3866
- y: Math.max(0, Math.min(maxY, p.y))
3867
- }));
3919
+ static translateContours(contours, offsetX, offsetY) {
3920
+ return contours.map(
3921
+ (points) => points.map((p) => ({
3922
+ x: p.x + offsetX,
3923
+ y: p.y + offsetY
3924
+ }))
3925
+ );
3868
3926
  }
3869
3927
  static pointsToSVG(points) {
3870
3928
  if (points.length === 0) return "";
@@ -4026,6 +4084,14 @@ var DielineTool = class {
4026
4084
  );
4027
4085
  s.features = configService.get("dieline.features", s.features);
4028
4086
  s.pathData = configService.get("dieline.pathData", s.pathData);
4087
+ const sourceWidth = Number(
4088
+ configService.get("dieline.customSourceWidthPx", 0)
4089
+ );
4090
+ const sourceHeight = Number(
4091
+ configService.get("dieline.customSourceHeightPx", 0)
4092
+ );
4093
+ s.customSourceWidthPx = Number.isFinite(sourceWidth) && sourceWidth > 0 ? sourceWidth : void 0;
4094
+ s.customSourceHeightPx = Number.isFinite(sourceHeight) && sourceHeight > 0 ? sourceHeight : void 0;
4029
4095
  configService.onAnyChange((e) => {
4030
4096
  if (e.key.startsWith("size.")) {
4031
4097
  const nextSize = readSizeState(configService);
@@ -4084,6 +4150,12 @@ var DielineTool = class {
4084
4150
  case "dieline.pathData":
4085
4151
  s.pathData = e.value;
4086
4152
  break;
4153
+ case "dieline.customSourceWidthPx":
4154
+ s.customSourceWidthPx = Number.isFinite(Number(e.value)) && Number(e.value) > 0 ? Number(e.value) : void 0;
4155
+ break;
4156
+ case "dieline.customSourceHeightPx":
4157
+ s.customSourceHeightPx = Number.isFinite(Number(e.value)) && Number(e.value) > 0 ? Number(e.value) : void 0;
4158
+ break;
4087
4159
  }
4088
4160
  this.updateDieline();
4089
4161
  }
@@ -4428,7 +4500,9 @@ var DielineTool = class {
4428
4500
  x: cx,
4429
4501
  y: cy,
4430
4502
  features: cutFeatures,
4431
- pathData: this.state.pathData
4503
+ pathData: this.state.pathData,
4504
+ customSourceWidthPx: this.state.customSourceWidthPx,
4505
+ customSourceHeightPx: this.state.customSourceHeightPx
4432
4506
  });
4433
4507
  const mask = new import_fabric3.Path(maskPathData, {
4434
4508
  fill: outsideColor,
@@ -4451,6 +4525,8 @@ var DielineTool = class {
4451
4525
  y: cy,
4452
4526
  features: cutFeatures,
4453
4527
  pathData: this.state.pathData,
4528
+ customSourceWidthPx: this.state.customSourceWidthPx,
4529
+ customSourceHeightPx: this.state.customSourceHeightPx,
4454
4530
  canvasWidth: canvasW,
4455
4531
  canvasHeight: canvasH
4456
4532
  });
@@ -4475,6 +4551,8 @@ var DielineTool = class {
4475
4551
  y: cy,
4476
4552
  features: cutFeatures,
4477
4553
  pathData: this.state.pathData,
4554
+ customSourceWidthPx: this.state.customSourceWidthPx,
4555
+ customSourceHeightPx: this.state.customSourceHeightPx,
4478
4556
  canvasWidth: canvasW,
4479
4557
  canvasHeight: canvasH
4480
4558
  },
@@ -4487,6 +4565,8 @@ var DielineTool = class {
4487
4565
  y: cy,
4488
4566
  features: cutFeatures,
4489
4567
  pathData: this.state.pathData,
4568
+ customSourceWidthPx: this.state.customSourceWidthPx,
4569
+ customSourceHeightPx: this.state.customSourceHeightPx,
4490
4570
  canvasWidth: canvasW,
4491
4571
  canvasHeight: canvasH
4492
4572
  },
@@ -4516,6 +4596,8 @@ var DielineTool = class {
4516
4596
  y: cy,
4517
4597
  features: cutFeatures,
4518
4598
  pathData: this.state.pathData,
4599
+ customSourceWidthPx: this.state.customSourceWidthPx,
4600
+ customSourceHeightPx: this.state.customSourceHeightPx,
4519
4601
  canvasWidth: canvasW,
4520
4602
  canvasHeight: canvasH
4521
4603
  });
@@ -4540,6 +4622,8 @@ var DielineTool = class {
4540
4622
  y: cy,
4541
4623
  features: absoluteFeatures,
4542
4624
  pathData: this.state.pathData,
4625
+ customSourceWidthPx: this.state.customSourceWidthPx,
4626
+ customSourceHeightPx: this.state.customSourceHeightPx,
4543
4627
  canvasWidth: canvasW,
4544
4628
  canvasHeight: canvasH
4545
4629
  });
@@ -4585,7 +4669,9 @@ var DielineTool = class {
4585
4669
  return {
4586
4670
  ...sceneGeometry,
4587
4671
  strokeWidth: this.state.mainLine.width,
4588
- pathData: this.state.pathData
4672
+ pathData: this.state.pathData,
4673
+ customSourceWidthPx: this.state.customSourceWidthPx,
4674
+ customSourceHeightPx: this.state.customSourceHeightPx
4589
4675
  };
4590
4676
  }
4591
4677
  async exportCutImage(options) {
@@ -4644,6 +4730,8 @@ var DielineTool = class {
4644
4730
  y: cy,
4645
4731
  features: cutFeatures,
4646
4732
  pathData,
4733
+ customSourceWidthPx: this.state.customSourceWidthPx,
4734
+ customSourceHeightPx: this.state.customSourceHeightPx,
4647
4735
  canvasWidth: canvasW,
4648
4736
  canvasHeight: canvasH
4649
4737
  });
package/dist/index.mjs CHANGED
@@ -356,7 +356,17 @@ function selectOuterChain(args) {
356
356
  }
357
357
  function createBaseShape(options) {
358
358
  var _a;
359
- const { shape, width, height, radius, x, y, pathData } = options;
359
+ const {
360
+ shape,
361
+ width,
362
+ height,
363
+ radius,
364
+ x,
365
+ y,
366
+ pathData,
367
+ customSourceWidthPx,
368
+ customSourceHeightPx
369
+ } = options;
360
370
  const center = new paper.Point(x, y);
361
371
  if (shape === "rect") {
362
372
  return new paper.Path.Rectangle({
@@ -382,10 +392,21 @@ function createBaseShape(options) {
382
392
  single.pathData = pathData;
383
393
  return single;
384
394
  })();
385
- path.position = center;
395
+ const sourceWidth = Number(customSourceWidthPx != null ? customSourceWidthPx : 0);
396
+ const sourceHeight = Number(customSourceHeightPx != null ? customSourceHeightPx : 0);
397
+ if (Number.isFinite(sourceWidth) && Number.isFinite(sourceHeight) && sourceWidth > 0 && sourceHeight > 0 && width > 0 && height > 0) {
398
+ const targetLeft = x - width / 2;
399
+ const targetTop = y - height / 2;
400
+ path.scale(width / sourceWidth, height / sourceHeight, new paper.Point(0, 0));
401
+ path.translate(new paper.Point(targetLeft, targetTop));
402
+ return path;
403
+ }
386
404
  if (width > 0 && height > 0 && path.bounds.width > 0 && path.bounds.height > 0) {
405
+ path.position = center;
387
406
  path.scale(width / path.bounds.width, height / path.bounds.height);
407
+ return path;
388
408
  }
409
+ path.position = center;
389
410
  return path;
390
411
  } else {
391
412
  return new paper.Path.Rectangle({
@@ -1020,6 +1041,10 @@ function buildSceneGeometry(configService, layout) {
1020
1041
  "mm"
1021
1042
  );
1022
1043
  const offset = (layout.cutRect.width - layout.trimRect.width) / 2;
1044
+ const sourceWidth = Number(configService.get("dieline.customSourceWidthPx", 0));
1045
+ const sourceHeight = Number(
1046
+ configService.get("dieline.customSourceHeightPx", 0)
1047
+ );
1023
1048
  return {
1024
1049
  shape: configService.get("dieline.shape", "rect"),
1025
1050
  unit: "mm",
@@ -1031,7 +1056,9 @@ function buildSceneGeometry(configService, layout) {
1031
1056
  radius: radiusMm * layout.scale,
1032
1057
  offset,
1033
1058
  scale: layout.scale,
1034
- pathData: configService.get("dieline.pathData")
1059
+ pathData: configService.get("dieline.pathData"),
1060
+ customSourceWidthPx: Number.isFinite(sourceWidth) && sourceWidth > 0 ? sourceWidth : void 0,
1061
+ customSourceHeightPx: Number.isFinite(sourceHeight) && sourceHeight > 0 ? sourceHeight : void 0
1035
1062
  };
1036
1063
  }
1037
1064
 
@@ -2458,6 +2485,8 @@ var ImageTool = class {
2458
2485
  this.normalizeItem({
2459
2486
  ...item,
2460
2487
  url,
2488
+ // Keep original source for next image-tool session editing,
2489
+ // and use committedUrl as non-image-tools render source.
2461
2490
  sourceUrl,
2462
2491
  committedUrl: url
2463
2492
  })
@@ -3365,14 +3394,10 @@ var ImageTracer = class {
3365
3394
  };
3366
3395
  }
3367
3396
  const baseUnpaddedContours = baseContours.map(
3368
- (contour) => this.clampPointsToImageBounds(
3369
- contour.map((p) => ({
3370
- x: p.x - padding,
3371
- y: p.y - padding
3372
- })),
3373
- width,
3374
- height
3375
- )
3397
+ (contour) => contour.map((p) => ({
3398
+ x: p.x - padding,
3399
+ y: p.y - padding
3400
+ }))
3376
3401
  ).filter((contour) => contour.length > 2);
3377
3402
  if (!baseUnpaddedContours.length) {
3378
3403
  const w = (_h = options.scaleToWidth) != null ? _h : width;
@@ -3461,6 +3486,39 @@ var ImageTracer = class {
3461
3486
  this.flattenContours(baseScaledContours)
3462
3487
  );
3463
3488
  }
3489
+ if (expand > 0) {
3490
+ const expectedExpandedBounds = {
3491
+ x: baseBounds.x - expand,
3492
+ y: baseBounds.y - expand,
3493
+ width: baseBounds.width + expand * 2,
3494
+ height: baseBounds.height + expand * 2
3495
+ };
3496
+ if (expectedExpandedBounds.width > 0 && expectedExpandedBounds.height > 0 && globalBounds.width > 0 && globalBounds.height > 0) {
3497
+ 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;
3498
+ if (shouldNormalizeExpandBounds) {
3499
+ const beforeNormalize = globalBounds;
3500
+ finalContours = this.translateContours(
3501
+ this.scaleContours(
3502
+ finalContours,
3503
+ expectedExpandedBounds.width,
3504
+ expectedExpandedBounds.height,
3505
+ globalBounds
3506
+ ),
3507
+ expectedExpandedBounds.x,
3508
+ expectedExpandedBounds.y
3509
+ );
3510
+ globalBounds = this.boundsFromPoints(
3511
+ this.flattenContours(finalContours)
3512
+ );
3513
+ debugLog("traceWithBounds:expand-normalized", {
3514
+ expand,
3515
+ expectedExpandedBounds,
3516
+ beforeNormalize,
3517
+ afterNormalize: globalBounds
3518
+ });
3519
+ }
3520
+ }
3521
+ }
3464
3522
  debugLog("traceWithBounds:contours", {
3465
3523
  baseContourCount: baseContoursRaw.length,
3466
3524
  baseSelectedCount: baseContours.length,
@@ -3823,13 +3881,13 @@ var ImageTracer = class {
3823
3881
  (points) => this.scalePoints(points, targetWidth, targetHeight, bounds)
3824
3882
  );
3825
3883
  }
3826
- static clampPointsToImageBounds(points, width, height) {
3827
- const maxX = Math.max(0, width);
3828
- const maxY = Math.max(0, height);
3829
- return points.map((p) => ({
3830
- x: Math.max(0, Math.min(maxX, p.x)),
3831
- y: Math.max(0, Math.min(maxY, p.y))
3832
- }));
3884
+ static translateContours(contours, offsetX, offsetY) {
3885
+ return contours.map(
3886
+ (points) => points.map((p) => ({
3887
+ x: p.x + offsetX,
3888
+ y: p.y + offsetY
3889
+ }))
3890
+ );
3833
3891
  }
3834
3892
  static pointsToSVG(points) {
3835
3893
  if (points.length === 0) return "";
@@ -3991,6 +4049,14 @@ var DielineTool = class {
3991
4049
  );
3992
4050
  s.features = configService.get("dieline.features", s.features);
3993
4051
  s.pathData = configService.get("dieline.pathData", s.pathData);
4052
+ const sourceWidth = Number(
4053
+ configService.get("dieline.customSourceWidthPx", 0)
4054
+ );
4055
+ const sourceHeight = Number(
4056
+ configService.get("dieline.customSourceHeightPx", 0)
4057
+ );
4058
+ s.customSourceWidthPx = Number.isFinite(sourceWidth) && sourceWidth > 0 ? sourceWidth : void 0;
4059
+ s.customSourceHeightPx = Number.isFinite(sourceHeight) && sourceHeight > 0 ? sourceHeight : void 0;
3994
4060
  configService.onAnyChange((e) => {
3995
4061
  if (e.key.startsWith("size.")) {
3996
4062
  const nextSize = readSizeState(configService);
@@ -4049,6 +4115,12 @@ var DielineTool = class {
4049
4115
  case "dieline.pathData":
4050
4116
  s.pathData = e.value;
4051
4117
  break;
4118
+ case "dieline.customSourceWidthPx":
4119
+ s.customSourceWidthPx = Number.isFinite(Number(e.value)) && Number(e.value) > 0 ? Number(e.value) : void 0;
4120
+ break;
4121
+ case "dieline.customSourceHeightPx":
4122
+ s.customSourceHeightPx = Number.isFinite(Number(e.value)) && Number(e.value) > 0 ? Number(e.value) : void 0;
4123
+ break;
4052
4124
  }
4053
4125
  this.updateDieline();
4054
4126
  }
@@ -4393,7 +4465,9 @@ var DielineTool = class {
4393
4465
  x: cx,
4394
4466
  y: cy,
4395
4467
  features: cutFeatures,
4396
- pathData: this.state.pathData
4468
+ pathData: this.state.pathData,
4469
+ customSourceWidthPx: this.state.customSourceWidthPx,
4470
+ customSourceHeightPx: this.state.customSourceHeightPx
4397
4471
  });
4398
4472
  const mask = new Path(maskPathData, {
4399
4473
  fill: outsideColor,
@@ -4416,6 +4490,8 @@ var DielineTool = class {
4416
4490
  y: cy,
4417
4491
  features: cutFeatures,
4418
4492
  pathData: this.state.pathData,
4493
+ customSourceWidthPx: this.state.customSourceWidthPx,
4494
+ customSourceHeightPx: this.state.customSourceHeightPx,
4419
4495
  canvasWidth: canvasW,
4420
4496
  canvasHeight: canvasH
4421
4497
  });
@@ -4440,6 +4516,8 @@ var DielineTool = class {
4440
4516
  y: cy,
4441
4517
  features: cutFeatures,
4442
4518
  pathData: this.state.pathData,
4519
+ customSourceWidthPx: this.state.customSourceWidthPx,
4520
+ customSourceHeightPx: this.state.customSourceHeightPx,
4443
4521
  canvasWidth: canvasW,
4444
4522
  canvasHeight: canvasH
4445
4523
  },
@@ -4452,6 +4530,8 @@ var DielineTool = class {
4452
4530
  y: cy,
4453
4531
  features: cutFeatures,
4454
4532
  pathData: this.state.pathData,
4533
+ customSourceWidthPx: this.state.customSourceWidthPx,
4534
+ customSourceHeightPx: this.state.customSourceHeightPx,
4455
4535
  canvasWidth: canvasW,
4456
4536
  canvasHeight: canvasH
4457
4537
  },
@@ -4481,6 +4561,8 @@ var DielineTool = class {
4481
4561
  y: cy,
4482
4562
  features: cutFeatures,
4483
4563
  pathData: this.state.pathData,
4564
+ customSourceWidthPx: this.state.customSourceWidthPx,
4565
+ customSourceHeightPx: this.state.customSourceHeightPx,
4484
4566
  canvasWidth: canvasW,
4485
4567
  canvasHeight: canvasH
4486
4568
  });
@@ -4505,6 +4587,8 @@ var DielineTool = class {
4505
4587
  y: cy,
4506
4588
  features: absoluteFeatures,
4507
4589
  pathData: this.state.pathData,
4590
+ customSourceWidthPx: this.state.customSourceWidthPx,
4591
+ customSourceHeightPx: this.state.customSourceHeightPx,
4508
4592
  canvasWidth: canvasW,
4509
4593
  canvasHeight: canvasH
4510
4594
  });
@@ -4550,7 +4634,9 @@ var DielineTool = class {
4550
4634
  return {
4551
4635
  ...sceneGeometry,
4552
4636
  strokeWidth: this.state.mainLine.width,
4553
- pathData: this.state.pathData
4637
+ pathData: this.state.pathData,
4638
+ customSourceWidthPx: this.state.customSourceWidthPx,
4639
+ customSourceHeightPx: this.state.customSourceHeightPx
4554
4640
  };
4555
4641
  }
4556
4642
  async exportCutImage(options) {
@@ -4609,6 +4695,8 @@ var DielineTool = class {
4609
4695
  y: cy,
4610
4696
  features: cutFeatures,
4611
4697
  pathData,
4698
+ customSourceWidthPx: this.state.customSourceWidthPx,
4699
+ customSourceHeightPx: this.state.customSourceHeightPx,
4612
4700
  canvasWidth: canvasW,
4613
4701
  canvasHeight: canvasH
4614
4702
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pooder/kit",
3
- "version": "5.3.0",
3
+ "version": "5.3.1",
4
4
  "description": "Standard plugins for Pooder editor",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",