pixel-data-js 0.35.0 → 0.37.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.
Files changed (84) hide show
  1. package/dist/index.prod.cjs +521 -326
  2. package/dist/index.prod.cjs.map +1 -1
  3. package/dist/index.prod.d.ts +132 -78
  4. package/dist/index.prod.js +513 -324
  5. package/dist/index.prod.js.map +1 -1
  6. package/package.json +2 -2
  7. package/src/Algorithm/floodFillSelection.ts +3 -2
  8. package/src/BlendModes/blend-modes-fast.ts +2 -1
  9. package/src/BlendModes/blend-modes-perfect.ts +2 -1
  10. package/src/Canvas/ReusableCanvas.ts +0 -5
  11. package/src/Color/_color-types.ts +8 -0
  12. package/src/Color/colorDistance.ts +9 -0
  13. package/src/Color/convert-color.ts +43 -0
  14. package/src/Color/lerpColor32.ts +44 -0
  15. package/src/Color/pack-color.ts +38 -0
  16. package/src/History/HistoryAction.ts +2 -2
  17. package/src/History/PixelAccumulator.ts +32 -13
  18. package/src/History/PixelMutator/mutatorApplyAlphaMask.ts +2 -0
  19. package/src/History/PixelMutator/mutatorApplyBinaryMask.ts +5 -1
  20. package/src/History/PixelMutator/mutatorApplyMask.ts +1 -0
  21. package/src/History/PixelMutator/mutatorBlendAlphaMask.ts +1 -0
  22. package/src/History/PixelMutator/mutatorBlendBinaryMask.ts +1 -0
  23. package/src/History/PixelMutator/mutatorBlendColor.ts +4 -1
  24. package/src/History/PixelMutator/mutatorBlendColorPaintAlphaMask.ts +2 -1
  25. package/src/History/PixelMutator/mutatorBlendColorPaintBinaryMask.ts +2 -1
  26. package/src/History/PixelMutator/mutatorBlendColorPaintMask.ts +24 -8
  27. package/src/History/PixelMutator/mutatorBlendColorPaintRect.ts +4 -1
  28. package/src/History/PixelMutator/mutatorBlendMask.ts +1 -0
  29. package/src/History/PixelMutator/mutatorBlendPixel.ts +3 -1
  30. package/src/History/PixelMutator/mutatorBlendPixelData.ts +1 -0
  31. package/src/History/PixelMutator/mutatorClear.ts +3 -2
  32. package/src/History/PixelMutator/mutatorFill.ts +54 -38
  33. package/src/History/PixelMutator/mutatorFillBinaryMask.ts +3 -2
  34. package/src/History/PixelMutator/mutatorInvert.ts +3 -2
  35. package/src/History/PixelMutator.ts +1 -2
  36. package/src/History/PixelWriter.ts +5 -5
  37. package/src/IndexedImage/IndexedImage.ts +1 -1
  38. package/src/IndexedImage/indexedImageToAverageColor.ts +3 -2
  39. package/src/Mask/_mask-types.ts +9 -0
  40. package/src/Paint/AlphaMaskPaintBuffer.ts +26 -26
  41. package/src/Paint/BinaryMaskPaintBuffer.ts +19 -19
  42. package/src/Paint/ColorPaintBuffer.ts +40 -42
  43. package/src/Paint/Commit/AlphaMaskPaintBufferCommitter.ts +1 -1
  44. package/src/Paint/Commit/AlphaMaskPaintBufferManager.ts +6 -7
  45. package/src/Paint/Commit/BinaryMaskPaintBufferCommitter.ts +1 -1
  46. package/src/Paint/Commit/BinaryMaskPaintBufferManager.ts +6 -7
  47. package/src/Paint/Commit/ColorPaintBufferManager.ts +6 -7
  48. package/src/Paint/Commit/commitColorPaintBuffer.ts +2 -6
  49. package/src/Paint/Commit/commitMaskPaintBuffer.ts +3 -7
  50. package/src/Paint/Render/AlphaMaskPaintBufferCanvasRenderer.ts +42 -25
  51. package/src/Paint/Render/BinaryMaskPaintBufferCanvasRenderer.ts +40 -24
  52. package/src/Paint/Render/ColorPaintBufferCanvasRenderer.ts +21 -21
  53. package/src/Paint/Render/PaintCursorRenderer.ts +12 -2
  54. package/src/Paint/eachTileInBounds.ts +9 -10
  55. package/src/PixelData/_pixelData-types.ts +7 -0
  56. package/src/PixelData/blendColorPixelData.ts +2 -1
  57. package/src/PixelData/blendColorPixelDataAlphaMask.ts +2 -1
  58. package/src/PixelData/blendColorPixelDataBinaryMask.ts +2 -1
  59. package/src/PixelData/blendColorPixelDataMask.ts +2 -1
  60. package/src/PixelData/blendColorPixelDataPaintAlphaMask.ts +1 -1
  61. package/src/PixelData/blendColorPixelDataPaintBinaryMask.ts +1 -1
  62. package/src/PixelData/blendColorPixelDataPaintMask.ts +19 -8
  63. package/src/PixelData/blendPixel.ts +2 -1
  64. package/src/PixelData/blendPixelData.ts +2 -1
  65. package/src/PixelData/blendPixelDataAlphaMask.ts +2 -1
  66. package/src/PixelData/blendPixelDataBinaryMask.ts +2 -1
  67. package/src/PixelData/blendPixelDataPaintBuffer.ts +2 -3
  68. package/src/PixelData/clearPixelDataFast.ts +1 -1
  69. package/src/PixelData/cropPixelData.ts +36 -0
  70. package/src/PixelData/fillPixelData.ts +7 -7
  71. package/src/PixelData/fillPixelDataBinaryMask.ts +1 -1
  72. package/src/PixelData/fillPixelDataFast.ts +1 -1
  73. package/src/PixelData/trimPixelData.ts +49 -0
  74. package/src/PixelData/writePaintBufferToPixelData.ts +1 -5
  75. package/src/Tile/MaskTile.ts +4 -0
  76. package/src/Tile/PixelTile.ts +2 -0
  77. package/src/Tile/TilePool.ts +9 -8
  78. package/src/Tile/TileTargetConfig.ts +27 -0
  79. package/src/Tile/_tile-types.ts +16 -0
  80. package/src/_types.ts +1 -6
  81. package/src/index.ts +9 -3
  82. package/src/History/PixelEngineConfig.ts +0 -28
  83. package/src/Internal/_constants.ts +0 -3
  84. package/src/color.ts +0 -112
@@ -13,43 +13,7 @@ __export(errors_exports, {
13
13
  var OFFSCREEN_CANVAS_CTX_FAILED = "Failed to create OffscreenCanvas context";
14
14
  var CANVAS_CTX_FAILED = "Failed to create Canvas context";
15
15
 
16
- // src/color.ts
17
- function packColor(r, g, b, a) {
18
- return (a << 24 | b << 16 | g << 8 | r) >>> 0;
19
- }
20
- function packRGBA({
21
- r,
22
- g,
23
- b,
24
- a
25
- }) {
26
- return (a << 24 | b << 16 | g << 8 | r) >>> 0;
27
- }
28
- var unpackRed = (packed) => packed >>> 0 & 255;
29
- var unpackGreen = (packed) => packed >>> 8 & 255;
30
- var unpackBlue = (packed) => packed >>> 16 & 255;
31
- var unpackAlpha = (packed) => packed >>> 24 & 255;
32
- function unpackColor(packed) {
33
- return {
34
- r: packed >>> 0 & 255,
35
- g: packed >>> 8 & 255,
36
- b: packed >>> 16 & 255,
37
- a: packed >>> 24 & 255
38
- };
39
- }
40
- var SCRATCH_RGBA = {
41
- r: 0,
42
- g: 0,
43
- b: 0,
44
- a: 0
45
- };
46
- function unpackColorTo(packed, scratch = SCRATCH_RGBA) {
47
- scratch.r = packed >>> 0 & 255;
48
- scratch.g = packed >>> 8 & 255;
49
- scratch.b = packed >>> 16 & 255;
50
- scratch.a = packed >>> 24 & 255;
51
- return scratch;
52
- }
16
+ // src/Color/colorDistance.ts
53
17
  function colorDistance(a, b) {
54
18
  const dr = (a & 255) - (b & 255);
55
19
  const dg = (a >>> 8 & 255) - (b >>> 8 & 255);
@@ -57,34 +21,6 @@ function colorDistance(a, b) {
57
21
  const da = (a >>> 24 & 255) - (b >>> 24 & 255);
58
22
  return dr * dr + dg * dg + db * db + da * da;
59
23
  }
60
- function lerpColor32(a, b, t) {
61
- const r = (a & 255) + t * ((b & 255) - (a & 255));
62
- const g = (a >>> 8 & 255) + t * ((b >>> 8 & 255) - (a >>> 8 & 255));
63
- const b_ = (a >>> 16 & 255) + t * ((b >>> 16 & 255) - (a >>> 16 & 255));
64
- const a_ = (a >>> 24 & 255) + t * ((b >>> 24 & 255) - (a >>> 24 & 255));
65
- return (a_ << 24 | b_ << 16 | g << 8 | r) >>> 0;
66
- }
67
- function lerpColor32Fast(src, dst, w) {
68
- const invA = 255 - w;
69
- const rb = (src & 16711935) * w + (dst & 16711935) * invA >>> 8 & 16711935;
70
- const ga = (src >>> 8 & 16711935) * w + (dst >>> 8 & 16711935) * invA >>> 8 & 16711935;
71
- return (rb | ga << 8) >>> 0;
72
- }
73
- function color32ToHex(color) {
74
- const r = (color & 255).toString(16).padStart(2, "0");
75
- const g = (color >>> 8 & 255).toString(16).padStart(2, "0");
76
- const b = (color >>> 16 & 255).toString(16).padStart(2, "0");
77
- const a = (color >>> 24 & 255).toString(16).padStart(2, "0");
78
- return `#${r}${g}${b}${a}`;
79
- }
80
- function color32ToCssRGBA(color) {
81
- const r = color & 255;
82
- const g = color >>> 8 & 255;
83
- const b = color >>> 16 & 255;
84
- const a = color >>> 24 & 255;
85
- const alpha = Number((a / 255).toFixed(3));
86
- return `rgba(${r},${g},${b},${alpha})`;
87
- }
88
24
 
89
25
  // src/ImageData/extractImageDataBuffer.ts
90
26
  function extractImageDataBuffer(imageData, _x, _y, _w, _h) {
@@ -1845,9 +1781,6 @@ function makeReusableCanvasMeta(factory) {
1845
1781
  canvas.width = width;
1846
1782
  canvas.height = height;
1847
1783
  ctx.imageSmoothingEnabled = false;
1848
- } else {
1849
- ctx.setTransform(1, 0, 0, 1, 0, 0);
1850
- ctx.clearRect(0, 0, width, height);
1851
1784
  }
1852
1785
  return result;
1853
1786
  }
@@ -1968,6 +1901,96 @@ async function writeImageDataToClipboard(imageData) {
1968
1901
  return writeImgBlobToClipboard(blob);
1969
1902
  }
1970
1903
 
1904
+ // src/Color/lerpColor32.ts
1905
+ function lerpColor32(a, b, t) {
1906
+ const r = (a & 255) + t * ((b & 255) - (a & 255));
1907
+ const g = (a >>> 8 & 255) + t * ((b >>> 8 & 255) - (a >>> 8 & 255));
1908
+ const b_ = (a >>> 16 & 255) + t * ((b >>> 16 & 255) - (a >>> 16 & 255));
1909
+ const a_ = (a >>> 24 & 255) + t * ((b >>> 24 & 255) - (a >>> 24 & 255));
1910
+ return (a_ << 24 | b_ << 16 | g << 8 | r) >>> 0;
1911
+ }
1912
+ function lerpColor32Fast(src, dst, w) {
1913
+ const invA = 255 - w;
1914
+ const rb = (src & 16711935) * w + (dst & 16711935) * invA >>> 8 & 16711935;
1915
+ const ga = (src >>> 8 & 16711935) * w + (dst >>> 8 & 16711935) * invA >>> 8 & 16711935;
1916
+ return (rb | ga << 8) >>> 0;
1917
+ }
1918
+
1919
+ // src/Color/convert-color.ts
1920
+ function color32ToHex(color) {
1921
+ const r = (color & 255).toString(16).padStart(2, "0");
1922
+ const g = (color >>> 8 & 255).toString(16).padStart(2, "0");
1923
+ const b = (color >>> 16 & 255).toString(16).padStart(2, "0");
1924
+ const a = (color >>> 24 & 255).toString(16).padStart(2, "0");
1925
+ return `#${r}${g}${b}${a}`;
1926
+ }
1927
+ function color32ToCssRGBAString(color) {
1928
+ const r = color & 255;
1929
+ const g = color >>> 8 & 255;
1930
+ const b = color >>> 16 & 255;
1931
+ const a = color >>> 24 & 255;
1932
+ const alpha = Number((a / 255).toFixed(3));
1933
+ return `rgba(${r},${g},${b},${alpha})`;
1934
+ }
1935
+ function color32ToCssRGBA(color) {
1936
+ const r = color & 255;
1937
+ const g = color >>> 8 & 255;
1938
+ const b = color >>> 16 & 255;
1939
+ const a = color >>> 24 & 255;
1940
+ return {
1941
+ r,
1942
+ g,
1943
+ b,
1944
+ a: a / 255
1945
+ };
1946
+ }
1947
+ function cssRGBAToColor32({
1948
+ r,
1949
+ g,
1950
+ b,
1951
+ a
1952
+ }) {
1953
+ return (a * 255 << 24 | b << 16 | g << 8 | r) >>> 0;
1954
+ }
1955
+
1956
+ // src/Color/pack-color.ts
1957
+ function packColor(r, g, b, a) {
1958
+ return (a << 24 | b << 16 | g << 8 | r) >>> 0;
1959
+ }
1960
+ function packRGBA({
1961
+ r,
1962
+ g,
1963
+ b,
1964
+ a
1965
+ }) {
1966
+ return (a << 24 | b << 16 | g << 8 | r) >>> 0;
1967
+ }
1968
+ var unpackRed = (packed) => packed >>> 0 & 255;
1969
+ var unpackGreen = (packed) => packed >>> 8 & 255;
1970
+ var unpackBlue = (packed) => packed >>> 16 & 255;
1971
+ var unpackAlpha = (packed) => packed >>> 24 & 255;
1972
+ function unpackColor(packed) {
1973
+ return {
1974
+ r: packed >>> 0 & 255,
1975
+ g: packed >>> 8 & 255,
1976
+ b: packed >>> 16 & 255,
1977
+ a: packed >>> 24 & 255
1978
+ };
1979
+ }
1980
+ var SCRATCH_RGBA = {
1981
+ r: 0,
1982
+ g: 0,
1983
+ b: 0,
1984
+ a: 0
1985
+ };
1986
+ function unpackColorTo(packed, scratch = SCRATCH_RGBA) {
1987
+ scratch.r = packed >>> 0 & 255;
1988
+ scratch.g = packed >>> 8 & 255;
1989
+ scratch.b = packed >>> 16 & 255;
1990
+ scratch.a = packed >>> 24 & 255;
1991
+ return scratch;
1992
+ }
1993
+
1971
1994
  // src/Control/BatchedQueue.ts
1972
1995
  function makeBatchedQueue(processor, queue) {
1973
1996
  let activeSet = /* @__PURE__ */ new Set();
@@ -2147,10 +2170,14 @@ var PixelAccumulator = class {
2147
2170
  * @param y pixel y coordinate
2148
2171
  */
2149
2172
  storePixelBeforeState(x, y) {
2150
- const shift = this.config.tileShift;
2151
2173
  const columns = this.config.targetColumns;
2152
- const tx = x >> shift;
2153
- const ty = y >> shift;
2174
+ const targetWidth = this.config.targetWidth;
2175
+ const targetHeight = this.config.targetHeight;
2176
+ if (x < 0 || x >= targetWidth || y < 0 || y >= targetHeight) {
2177
+ return null;
2178
+ }
2179
+ const tx = x * this.config.invTileSize | 0;
2180
+ const ty = y * this.config.invTileSize | 0;
2154
2181
  const id = ty * columns + tx;
2155
2182
  let tile = this.lookup[id];
2156
2183
  let added = false;
@@ -2177,12 +2204,21 @@ var PixelAccumulator = class {
2177
2204
  * @param h pixel height
2178
2205
  */
2179
2206
  storeRegionBeforeState(x, y, w, h) {
2180
- const shift = this.config.tileShift;
2181
2207
  const columns = this.config.targetColumns;
2182
- const startX = x >> shift;
2183
- const startY = y >> shift;
2184
- const endX = x + w - 1 >> shift;
2185
- const endY = y + h - 1 >> shift;
2208
+ const targetWidth = this.config.targetWidth;
2209
+ const targetHeight = this.config.targetHeight;
2210
+ const invTileSize = this.config.invTileSize;
2211
+ const clipX1 = Math.max(0, x);
2212
+ const clipY1 = Math.max(0, y);
2213
+ const clipX2 = Math.min(targetWidth - 1, x + w - 1);
2214
+ const clipY2 = Math.min(targetHeight - 1, y + h - 1);
2215
+ if (clipX2 < clipX1 || clipY2 < clipY1) {
2216
+ return null;
2217
+ }
2218
+ const startX = clipX1 * invTileSize | 0;
2219
+ const startY = clipY1 * invTileSize | 0;
2220
+ const endX = clipX2 * invTileSize | 0;
2221
+ const endY = clipY2 * invTileSize | 0;
2186
2222
  const startIndex = this.beforeTiles.length;
2187
2223
  for (let ty = startY; ty <= endY; ty++) {
2188
2224
  for (let tx = startX; tx <= endX; tx++) {
@@ -2299,31 +2335,6 @@ var PixelAccumulator = class {
2299
2335
  }
2300
2336
  };
2301
2337
 
2302
- // src/History/PixelEngineConfig.ts
2303
- var PixelEngineConfig = class {
2304
- tileSize;
2305
- // pixelX = tileX << tileShift
2306
- // pixelY = tileY << tileShift
2307
- tileShift;
2308
- tileMask;
2309
- tileArea;
2310
- target;
2311
- targetColumns = 0;
2312
- targetRows = 0;
2313
- constructor(tileSize, target) {
2314
- if ((tileSize & tileSize - 1) !== 0) {
2315
- throw new Error("tileSize must be a power of 2");
2316
- }
2317
- this.tileSize = tileSize;
2318
- this.tileShift = 31 - Math.clz32(tileSize);
2319
- this.tileMask = tileSize - 1;
2320
- this.tileArea = tileSize * tileSize;
2321
- this.target = target;
2322
- this.targetColumns = target.w + this.tileMask >> this.tileShift;
2323
- this.targetRows = target.h + this.tileMask >> this.tileShift;
2324
- }
2325
- };
2326
-
2327
2338
  // src/PixelData/applyAlphaMaskToPixelData.ts
2328
2339
  function applyAlphaMaskToPixelData(target, mask, opts) {
2329
2340
  const targetX = opts?.x ?? 0;
@@ -2517,6 +2528,8 @@ function makePixelTile(id, tx, ty, tileSize, tileArea) {
2517
2528
  id,
2518
2529
  tx,
2519
2530
  ty,
2531
+ x: tx * tileSize,
2532
+ y: ty * tileSize,
2520
2533
  w: tileSize,
2521
2534
  h: tileSize,
2522
2535
  data: data32,
@@ -2526,25 +2539,28 @@ function makePixelTile(id, tx, ty, tileSize, tileArea) {
2526
2539
 
2527
2540
  // src/Tile/TilePool.ts
2528
2541
  var TilePool = class {
2529
- constructor(config, tileFactory) {
2542
+ constructor(tileSize, tileFactory) {
2543
+ this.tileSize = tileSize;
2530
2544
  this.tileFactory = tileFactory;
2531
2545
  this.pool = [];
2532
- this.tileSize = config.tileSize;
2533
- this.tileArea = config.tileArea;
2546
+ this.tileSize = tileSize;
2547
+ this.tileArea = tileSize * tileSize;
2534
2548
  }
2535
2549
  pool;
2536
- tileSize;
2537
2550
  tileArea;
2538
2551
  getTile(id, tx, ty) {
2539
2552
  let tile = this.pool.pop();
2553
+ const tileSize = this.tileSize;
2540
2554
  if (tile) {
2541
2555
  tile.id = id;
2542
2556
  tile.tx = tx;
2543
2557
  tile.ty = ty;
2558
+ tile.x = tx * tileSize;
2559
+ tile.y = ty * tileSize;
2544
2560
  tile.data.fill(0);
2545
2561
  return tile;
2546
2562
  }
2547
- return this.tileFactory(id, tx, ty, this.tileSize, this.tileArea);
2563
+ return this.tileFactory(id, tx, ty, tileSize, this.tileArea);
2548
2564
  }
2549
2565
  releaseTile(tile) {
2550
2566
  this.pool.push(tile);
@@ -2561,6 +2577,25 @@ var TilePool = class {
2561
2577
  }
2562
2578
  };
2563
2579
 
2580
+ // src/Tile/TileTargetConfig.ts
2581
+ function makeTileTargetConfig(tileSize, target) {
2582
+ return {
2583
+ target,
2584
+ ...makeTileTargetMeta(tileSize, target)
2585
+ };
2586
+ }
2587
+ function makeTileTargetMeta(tileSize, target) {
2588
+ return {
2589
+ targetWidth: target.w,
2590
+ targetHeight: target.h,
2591
+ tileSize,
2592
+ invTileSize: 1 / tileSize,
2593
+ tileArea: tileSize * tileSize,
2594
+ targetColumns: Math.ceil(target.w / tileSize),
2595
+ targetRows: Math.ceil(target.h / tileSize)
2596
+ };
2597
+ }
2598
+
2564
2599
  // src/History/PixelWriter.ts
2565
2600
  var PixelWriter = class {
2566
2601
  historyManager;
@@ -2573,10 +2608,10 @@ var PixelWriter = class {
2573
2608
  constructor(target, mutatorFactory, options) {
2574
2609
  const tileSize = options?.tileSize ?? 256;
2575
2610
  const maxHistorySteps = options?.maxHistorySteps ?? 50;
2576
- this.config = new PixelEngineConfig(tileSize, target);
2611
+ this.config = makeTileTargetConfig(tileSize, target);
2577
2612
  this.historyManager = options?.historyManager ?? new HistoryManager(maxHistorySteps);
2578
2613
  this.historyActionFactory = options?.historyActionFactory ?? makeHistoryAction;
2579
- this.pixelTilePool = options?.pixelTilePool ?? new TilePool(this.config, makePixelTile);
2614
+ this.pixelTilePool = options?.pixelTilePool ?? new TilePool(this.config.tileSize, makePixelTile);
2580
2615
  this.accumulator = options?.accumulator ?? new PixelAccumulator(this.config, this.pixelTilePool);
2581
2616
  this.mutator = mutatorFactory(this);
2582
2617
  }
@@ -2653,6 +2688,7 @@ var mutatorApplyAlphaMask = ((writer, deps = defaults) => {
2653
2688
  const w = opts?.w ?? target.w;
2654
2689
  const h = opts?.h ?? target.h;
2655
2690
  const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
2691
+ if (!didChange) return false;
2656
2692
  return didChange(applyAlphaMaskToPixelData2(target, mask, opts));
2657
2693
  }
2658
2694
  };
@@ -2755,7 +2791,12 @@ var mutatorApplyBinaryMask = ((writer, deps = defaults2) => {
2755
2791
  const w = opts?.w ?? target.w;
2756
2792
  const h = opts?.h ?? target.h;
2757
2793
  const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
2758
- return didChange(applyBinaryMaskToPixelData2(target, mask, opts));
2794
+ if (!didChange) return false;
2795
+ const b = applyBinaryMaskToPixelData2(target, mask, opts);
2796
+ console.log({
2797
+ b
2798
+ });
2799
+ return didChange(b);
2759
2800
  }
2760
2801
  };
2761
2802
  });
@@ -2778,6 +2819,7 @@ var mutatorApplyMask = ((writer, deps = defaults3) => {
2778
2819
  const w = opts?.w ?? target.w;
2779
2820
  const h = opts?.h ?? target.h;
2780
2821
  const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
2822
+ if (!didChange) return false;
2781
2823
  if (mask.type === 1 /* BINARY */) {
2782
2824
  return didChange(applyBinaryMaskToPixelData2(target, mask, opts));
2783
2825
  } else {
@@ -2922,6 +2964,7 @@ var mutatorBlendAlphaMask = ((writer, deps = defaults4) => {
2922
2964
  const w = opts?.w ?? src.w;
2923
2965
  const h = opts?.h ?? src.h;
2924
2966
  const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
2967
+ if (!didChange) return false;
2925
2968
  return didChange(blendPixelDataAlphaMask2(writer.config.target, src, mask, opts));
2926
2969
  }
2927
2970
  };
@@ -3049,6 +3092,7 @@ var mutatorBlendBinaryMask = ((writer, deps = defaults5) => {
3049
3092
  const w = opts?.w ?? src.w;
3050
3093
  const h = opts?.h ?? src.h;
3051
3094
  const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
3095
+ if (!didChange) return false;
3052
3096
  return didChange(blendPixelDataBinaryMask2(writer.config.target, src, mask, opts));
3053
3097
  }
3054
3098
  };
@@ -3123,6 +3167,7 @@ var mutatorBlendColor = ((writer, deps = defaults6) => {
3123
3167
  const w = opts?.w ?? target.w;
3124
3168
  const h = opts?.h ?? target.h;
3125
3169
  const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
3170
+ if (!didChange) return false;
3126
3171
  return didChange(blendColorPixelData2(target, color, opts));
3127
3172
  }
3128
3173
  };
@@ -3235,6 +3280,7 @@ var mutatorBlendColorPaintAlphaMask = ((writer, deps = defaults7) => {
3235
3280
  const tx = x + mask.centerOffsetX;
3236
3281
  const ty = y + mask.centerOffsetY;
3237
3282
  const didChange = writer.accumulator.storeRegionBeforeState(tx, ty, mask.w, mask.h);
3283
+ if (!didChange) return false;
3238
3284
  OPTS.x = tx;
3239
3285
  OPTS.y = ty;
3240
3286
  OPTS.alpha = alpha;
@@ -3331,6 +3377,7 @@ var mutatorBlendColorPaintBinaryMask = ((writer, deps = defaults8) => {
3331
3377
  const tx = x + mask.centerOffsetX;
3332
3378
  const ty = y + mask.centerOffsetY;
3333
3379
  const didChange = writer.accumulator.storeRegionBeforeState(tx, ty, mask.w, mask.h);
3380
+ if (!didChange) return false;
3334
3381
  OPTS.x = tx;
3335
3382
  OPTS.y = ty;
3336
3383
  OPTS.alpha = alpha;
@@ -3343,33 +3390,44 @@ var mutatorBlendColorPaintBinaryMask = ((writer, deps = defaults8) => {
3343
3390
  // src/History/PixelMutator/mutatorBlendColorPaintMask.ts
3344
3391
  var defaults9 = {
3345
3392
  blendColorPixelDataAlphaMask,
3346
- blendColorPixelDataBinaryMask
3393
+ blendColorPixelDataBinaryMask,
3394
+ blendColorPixelData
3347
3395
  };
3348
3396
  var mutatorBlendColorPaintMask = ((writer, deps = defaults9) => {
3349
3397
  const {
3350
3398
  blendColorPixelDataBinaryMask: blendColorPixelDataBinaryMask2 = defaults9.blendColorPixelDataBinaryMask,
3351
- blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults9.blendColorPixelDataAlphaMask
3399
+ blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults9.blendColorPixelDataAlphaMask,
3400
+ blendColorPixelData: blendColorPixelData2 = defaults9.blendColorPixelData
3352
3401
  } = deps;
3353
3402
  const OPTS = {
3354
3403
  x: 0,
3355
3404
  y: 0,
3356
3405
  blendFn: sourceOverPerfect,
3357
- alpha: 255
3406
+ alpha: 255,
3407
+ w: void 0,
3408
+ h: void 0
3358
3409
  };
3359
3410
  return {
3360
3411
  blendColorPaintMask(color, mask, x, y, alpha = 255, blendFn = sourceOverPerfect) {
3361
3412
  const tx = x + mask.centerOffsetX;
3362
3413
  const ty = y + mask.centerOffsetY;
3363
3414
  const didChange = writer.accumulator.storeRegionBeforeState(tx, ty, mask.w, mask.h);
3415
+ if (!didChange) return false;
3364
3416
  OPTS.x = tx;
3365
3417
  OPTS.y = ty;
3366
3418
  OPTS.alpha = alpha;
3367
3419
  OPTS.blendFn = blendFn;
3368
- if (mask.type === 1 /* BINARY */) {
3369
- return didChange(blendColorPixelDataBinaryMask2(writer.config.target, color, mask, OPTS));
3370
- } else {
3420
+ OPTS.w = void 0;
3421
+ OPTS.h = void 0;
3422
+ if (mask.data) {
3423
+ if (mask.type === 1 /* BINARY */) {
3424
+ return didChange(blendColorPixelDataBinaryMask2(writer.config.target, color, mask, OPTS));
3425
+ }
3371
3426
  return didChange(blendColorPixelDataAlphaMask2(writer.config.target, color, mask, OPTS));
3372
3427
  }
3428
+ OPTS.w = mask.w;
3429
+ OPTS.h = mask.h;
3430
+ return didChange(blendColorPixelData2(writer.config.target, color, OPTS));
3373
3431
  }
3374
3432
  };
3375
3433
  });
@@ -3402,6 +3460,7 @@ var mutatorBlendColorPaintRect = ((writer, deps = defaults10) => {
3402
3460
  OPTS.blendFn = blendFn;
3403
3461
  OPTS.alpha = alpha;
3404
3462
  const didChange = writer.accumulator.storeRegionBeforeState(topLeftX, topLeftY, brushWidth, brushHeight);
3463
+ if (!didChange) return false;
3405
3464
  return didChange(blendColorPixelData2(target, color, OPTS));
3406
3465
  }
3407
3466
  };
@@ -3424,6 +3483,7 @@ var mutatorBlendMask = ((writer, deps = defaults11) => {
3424
3483
  const w = opts?.w ?? src.w;
3425
3484
  const h = opts?.h ?? src.h;
3426
3485
  const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
3486
+ if (!didChange) return false;
3427
3487
  if (mask.type === 1 /* BINARY */) {
3428
3488
  return didChange(blendPixelDataBinaryMask2(writer.config.target, src, mask, opts));
3429
3489
  } else {
@@ -3470,6 +3530,7 @@ var mutatorBlendPixel = ((writer, deps = defaults12) => {
3470
3530
  return {
3471
3531
  blendPixel(x, y, color, alpha, blendFn) {
3472
3532
  const didChange = writer.accumulator.storePixelBeforeState(x, y);
3533
+ if (!didChange) return false;
3473
3534
  return didChange(blendPixel2(writer.config.target, x, y, color, alpha, blendFn));
3474
3535
  }
3475
3536
  };
@@ -3577,6 +3638,7 @@ var mutatorBlendPixelData = ((writer, deps = defaults13) => {
3577
3638
  const w = opts?.w ?? src.w;
3578
3639
  const h = opts?.h ?? src.h;
3579
3640
  const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
3641
+ if (!didChange) return false;
3580
3642
  return didChange(blendPixelData2(writer.config.target, src, opts));
3581
3643
  }
3582
3644
  };
@@ -3590,16 +3652,16 @@ function fillPixelData(dst, color, _x, _y, _w, _h) {
3590
3652
  let y;
3591
3653
  let w;
3592
3654
  let h;
3593
- if (typeof _x === "object") {
3594
- x = _x.x ?? 0;
3595
- y = _x.y ?? 0;
3596
- w = _x.w ?? dstW;
3597
- h = _x.h ?? dstH;
3598
- } else if (typeof _x === "number") {
3655
+ if (typeof _x === "number") {
3599
3656
  x = _x;
3600
3657
  y = _y;
3601
3658
  w = _w;
3602
3659
  h = _h;
3660
+ } else if (typeof _x === "object") {
3661
+ x = _x.x ?? 0;
3662
+ y = _x.y ?? 0;
3663
+ w = _x.w ?? dstW;
3664
+ h = _x.h ?? dstH;
3603
3665
  } else {
3604
3666
  x = 0;
3605
3667
  y = 0;
@@ -3664,6 +3726,7 @@ var mutatorClear = ((writer, deps = defaults14) => {
3664
3726
  const w = rect?.w ?? target.w;
3665
3727
  const h = rect?.h ?? target.h;
3666
3728
  const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
3729
+ if (!didChange) return false;
3667
3730
  return didChange(fillPixelData2(target, 0, x, y, w, h));
3668
3731
  }
3669
3732
  };
@@ -3677,24 +3740,37 @@ var mutatorFill = ((writer, deps = defaults15) => {
3677
3740
  const {
3678
3741
  fillPixelData: fillPixelData2 = defaults15.fillPixelData
3679
3742
  } = deps;
3680
- return {
3681
- fill(color, x = 0, y = 0, w = writer.config.target.w, h = writer.config.target.h) {
3682
- const target = writer.config.target;
3683
- const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
3684
- return didChange(fillPixelData2(target, color, x, y, w, h));
3743
+ const config = writer.config;
3744
+ function fill(color, _x, _y, _w, _h) {
3745
+ const target = config.target;
3746
+ const dstW = target.w;
3747
+ const dstH = target.h;
3748
+ let x;
3749
+ let y;
3750
+ let w;
3751
+ let h;
3752
+ if (typeof _x === "number") {
3753
+ x = _x;
3754
+ y = _y;
3755
+ w = _w;
3756
+ h = _h;
3757
+ } else if (typeof _x === "object") {
3758
+ x = _x.x ?? 0;
3759
+ y = _x.y ?? 0;
3760
+ w = _x.w ?? dstW;
3761
+ h = _x.h ?? dstH;
3762
+ } else {
3763
+ x = 0;
3764
+ y = 0;
3765
+ w = dstW;
3766
+ h = dstH;
3685
3767
  }
3686
- };
3687
- });
3688
- var mutatorFillRect = ((writer, deps = defaults15) => {
3689
- const {
3690
- fillPixelData: fillPixelData2 = defaults15.fillPixelData
3691
- } = deps;
3768
+ const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
3769
+ if (!didChange) return false;
3770
+ return didChange(fillPixelData2(target, color, x, y, w, h));
3771
+ }
3692
3772
  return {
3693
- fillRect(color, rect) {
3694
- const target = writer.config.target;
3695
- const didChange = writer.accumulator.storeRegionBeforeState(rect.x, rect.y, rect.w, rect.h);
3696
- return didChange(fillPixelData2(target, color, rect.x, rect.y, rect.w, rect.h));
3697
- }
3773
+ fill
3698
3774
  };
3699
3775
  });
3700
3776
 
@@ -3756,6 +3832,7 @@ var mutatorFillBinaryMask = ((writer, deps = defaults16) => {
3756
3832
  return {
3757
3833
  fillBinaryMask(color, mask, x = 0, y = 0) {
3758
3834
  const didChange = writer.accumulator.storeRegionBeforeState(x, y, mask.w, mask.h);
3835
+ if (!didChange) return false;
3759
3836
  return didChange(fillPixelDataBinaryMask2(writer.config.target, color, mask, x, y));
3760
3837
  }
3761
3838
  };
@@ -3840,7 +3917,8 @@ var mutatorInvert = ((writer, deps = defaults17) => {
3840
3917
  const w = opts?.w ?? target.w;
3841
3918
  const h = opts?.h ?? target.h;
3842
3919
  const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
3843
- return didChange(invertPixelData2(target, opts));
3920
+ if (!didChange) return false;
3921
+ return didChange?.(invertPixelData2(target, opts));
3844
3922
  }
3845
3923
  };
3846
3924
  });
@@ -3865,7 +3943,6 @@ function makeFullPixelMutator(writer) {
3865
3943
  ...mutatorClear(writer),
3866
3944
  ...mutatorFill(writer),
3867
3945
  ...mutatorFillBinaryMask(writer),
3868
- ...mutatorFillRect(writer),
3869
3946
  ...mutatorInvert(writer)
3870
3947
  };
3871
3948
  }
@@ -5039,26 +5116,55 @@ function trimRectBounds(x, y, w, h, targetWidth, targetHeight, out) {
5039
5116
  return res;
5040
5117
  }
5041
5118
 
5119
+ // src/Tile/MaskTile.ts
5120
+ var makeAlphaMaskTile = (id, tx, ty, tileSize, tileArea) => {
5121
+ return {
5122
+ tileType: 1 /* MASK */,
5123
+ type: 0 /* ALPHA */,
5124
+ data: new Uint8Array(tileArea),
5125
+ w: tileSize,
5126
+ h: tileSize,
5127
+ x: tx * tileSize,
5128
+ y: ty * tileSize,
5129
+ id,
5130
+ tx,
5131
+ ty
5132
+ };
5133
+ };
5134
+ var makeBinaryMaskTile = (id, tx, ty, tileSize, tileArea) => {
5135
+ return {
5136
+ tileType: 1 /* MASK */,
5137
+ type: 1 /* BINARY */,
5138
+ data: new Uint8Array(tileArea),
5139
+ w: tileSize,
5140
+ h: tileSize,
5141
+ x: tx * tileSize,
5142
+ y: ty * tileSize,
5143
+ id,
5144
+ tx,
5145
+ ty
5146
+ };
5147
+ };
5148
+
5042
5149
  // src/Paint/eachTileInBounds.ts
5043
5150
  function eachTileInBounds(config, lookup, tilePool, bounds, callback) {
5044
5151
  const {
5045
- tileShift,
5046
- targetColumns,
5047
5152
  targetRows,
5153
+ targetColumns,
5048
5154
  tileSize
5049
5155
  } = config;
5050
- const x1 = Math.max(0, bounds.x >> tileShift);
5051
- const y1 = Math.max(0, bounds.y >> tileShift);
5052
- const x2 = Math.min(targetColumns - 1, bounds.x + bounds.w - 1 >> tileShift);
5053
- const y2 = Math.min(targetRows - 1, bounds.y + bounds.h - 1 >> tileShift);
5156
+ const x1 = Math.max(0, Math.floor(bounds.x / tileSize));
5157
+ const y1 = Math.max(0, Math.floor(bounds.y / tileSize));
5158
+ const x2 = Math.min(targetColumns - 1, Math.floor((bounds.x + bounds.w - 1) / tileSize));
5159
+ const y2 = Math.min(targetRows - 1, Math.floor((bounds.y + bounds.h - 1) / tileSize));
5054
5160
  if (x1 > x2 || y1 > y2) return;
5055
5161
  for (let ty = y1; ty <= y2; ty++) {
5056
5162
  const rowOffset = ty * targetColumns;
5057
- const tileTop = ty << tileShift;
5163
+ const tileTop = ty * tileSize;
5058
5164
  for (let tx = x1; tx <= x2; tx++) {
5059
5165
  const id = rowOffset + tx;
5060
5166
  const tile = lookup[id] ?? (lookup[id] = tilePool.getTile(id, tx, ty));
5061
- const tileLeft = tx << tileShift;
5167
+ const tileLeft = tx * tileSize;
5062
5168
  const startX = bounds.x > tileLeft ? bounds.x : tileLeft;
5063
5169
  const startY = bounds.y > tileTop ? bounds.y : tileTop;
5064
5170
  const maskEndX = bounds.x + bounds.w;
@@ -5074,7 +5180,7 @@ function eachTileInBounds(config, lookup, tilePool, bounds, callback) {
5074
5180
 
5075
5181
  // src/Paint/AlphaMaskPaintBuffer.ts
5076
5182
  var AlphaMaskPaintBuffer = class {
5077
- constructor(config, tilePool) {
5183
+ constructor(config, tilePool = new TilePool(config.tileSize, makeAlphaMaskTile)) {
5078
5184
  this.config = config;
5079
5185
  this.tilePool = tilePool;
5080
5186
  this.lookup = [];
@@ -5094,9 +5200,9 @@ var AlphaMaskPaintBuffer = class {
5094
5200
  const lookup = this.lookup;
5095
5201
  const tilePool = this.tilePool;
5096
5202
  const config = this.config;
5097
- const tileShift = config.tileShift;
5098
- const tileMask = config.tileMask;
5099
- const target = config.target;
5203
+ const targetW = config.targetWidth;
5204
+ const targetH = config.targetHeight;
5205
+ const tileSize = config.tileSize;
5100
5206
  const {
5101
5207
  w: bW,
5102
5208
  h: bH,
@@ -5110,7 +5216,7 @@ var AlphaMaskPaintBuffer = class {
5110
5216
  this.forEachLinePointFn(x0, y0, x1, y1, (px, py) => {
5111
5217
  const topLeftX = Math.floor(px + centerOffsetX);
5112
5218
  const topLeftY = Math.floor(py + centerOffsetY);
5113
- trimRectBoundsFn(topLeftX, topLeftY, bW, bH, target.w, target.h, scratch);
5219
+ trimRectBoundsFn(topLeftX, topLeftY, bW, bH, targetW, targetH, scratch);
5114
5220
  if (scratch.w <= 0 || scratch.h <= 0) return;
5115
5221
  eachTileInBoundsFn(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
5116
5222
  const data = tile.data;
@@ -5118,8 +5224,8 @@ var AlphaMaskPaintBuffer = class {
5118
5224
  for (let i = 0; i < bH_t; i++) {
5119
5225
  const canvasY = bY + i;
5120
5226
  const bOff = (canvasY - topLeftY) * bW;
5121
- const tOff = (canvasY & tileMask) << tileShift;
5122
- const dS = tOff + (bX & tileMask);
5227
+ const tOff = (canvasY - tile.y) * tileSize;
5228
+ const dS = tOff + (bX - tile.x);
5123
5229
  for (let j = 0; j < bW_t; j++) {
5124
5230
  const canvasX = bX + j;
5125
5231
  const brushA = bD[bOff + (canvasX - topLeftX)];
@@ -5142,9 +5248,9 @@ var AlphaMaskPaintBuffer = class {
5142
5248
  const lookup = this.lookup;
5143
5249
  const tilePool = this.tilePool;
5144
5250
  const config = this.config;
5145
- const tileShift = config.tileShift;
5146
- const tileMask = config.tileMask;
5147
- const target = config.target;
5251
+ const targetW = config.targetWidth;
5252
+ const targetH = config.targetHeight;
5253
+ const tileSize = config.tileSize;
5148
5254
  const {
5149
5255
  w: bW,
5150
5256
  h: bH,
@@ -5158,7 +5264,7 @@ var AlphaMaskPaintBuffer = class {
5158
5264
  this.forEachLinePointFn(x0, y0, x1, y1, (px, py) => {
5159
5265
  const topLeftX = Math.floor(px + centerOffsetX);
5160
5266
  const topLeftY = Math.floor(py + centerOffsetY);
5161
- trimRectBoundsFn(topLeftX, topLeftY, bW, bH, target.w, target.h, scratch);
5267
+ trimRectBoundsFn(topLeftX, topLeftY, bW, bH, targetW, targetH, scratch);
5162
5268
  if (scratch.w <= 0 || scratch.h <= 0) return;
5163
5269
  eachTileInBoundsFn(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
5164
5270
  const data = tile.data;
@@ -5166,8 +5272,8 @@ var AlphaMaskPaintBuffer = class {
5166
5272
  for (let i = 0; i < bH_t; i++) {
5167
5273
  const canvasY = bY + i;
5168
5274
  const bOff = (canvasY - topLeftY) * bW;
5169
- const tOff = (canvasY & tileMask) << tileShift;
5170
- const dS = tOff + (bX & tileMask);
5275
+ const tOff = (canvasY - tile.y) * tileSize;
5276
+ const dS = tOff + (bX - tile.x);
5171
5277
  for (let j = 0; j < bW_t; j++) {
5172
5278
  const canvasX = bX + j;
5173
5279
  if (bD[bOff + (canvasX - topLeftX)]) {
@@ -5189,9 +5295,9 @@ var AlphaMaskPaintBuffer = class {
5189
5295
  const lookup = this.lookup;
5190
5296
  const tilePool = this.tilePool;
5191
5297
  const config = this.config;
5192
- const tileShift = config.tileShift;
5193
- const tileMask = config.tileMask;
5194
- const target = config.target;
5298
+ const targetW = config.targetWidth;
5299
+ const targetH = config.targetHeight;
5300
+ const tileSize = config.tileSize;
5195
5301
  const brushWidth = brush.w;
5196
5302
  const brushHeight = brush.h;
5197
5303
  const centerOffsetX = brush.centerOffsetX;
@@ -5202,15 +5308,15 @@ var AlphaMaskPaintBuffer = class {
5202
5308
  this.forEachLinePointFn(x0, y0, x1, y1, (px, py) => {
5203
5309
  const topLeftX = Math.floor(px + centerOffsetX);
5204
5310
  const topLeftY = Math.floor(py + centerOffsetY);
5205
- trimRectBoundsFn(topLeftX, topLeftY, brushWidth, brushHeight, target.w, target.h, scratch);
5311
+ trimRectBoundsFn(topLeftX, topLeftY, brushWidth, brushHeight, targetW, targetH, scratch);
5206
5312
  if (scratch.w <= 0 || scratch.h <= 0) return;
5207
5313
  eachTileInBoundsFn(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
5208
5314
  const data = tile.data;
5209
5315
  let tileChanged = false;
5210
5316
  for (let i = 0; i < bH_t; i++) {
5211
5317
  const canvasY = bY + i;
5212
- const tOff = (canvasY & tileMask) << tileShift;
5213
- const dS = tOff + (bX & tileMask);
5318
+ const tOff = (canvasY - tile.y) * tileSize;
5319
+ const dS = tOff + (bX - tile.x);
5214
5320
  for (let j = 0; j < bW_t; j++) {
5215
5321
  const idx = dS + j;
5216
5322
  if (alpha > data[idx]) {
@@ -5233,7 +5339,7 @@ var AlphaMaskPaintBuffer = class {
5233
5339
 
5234
5340
  // src/Paint/BinaryMaskPaintBuffer.ts
5235
5341
  var BinaryMaskPaintBuffer = class {
5236
- constructor(config, tilePool) {
5342
+ constructor(config, tilePool = new TilePool(config.tileSize, makeBinaryMaskTile)) {
5237
5343
  this.config = config;
5238
5344
  this.tilePool = tilePool;
5239
5345
  this.lookup = [];
@@ -5253,9 +5359,9 @@ var BinaryMaskPaintBuffer = class {
5253
5359
  const lookup = this.lookup;
5254
5360
  const tilePool = this.tilePool;
5255
5361
  const config = this.config;
5256
- const tileShift = config.tileShift;
5257
- const tileMask = config.tileMask;
5258
- const target = config.target;
5362
+ const targetW = config.targetWidth;
5363
+ const targetH = config.targetHeight;
5364
+ const tileSize = config.tileSize;
5259
5365
  const {
5260
5366
  w: bW,
5261
5367
  h: bH,
@@ -5269,7 +5375,7 @@ var BinaryMaskPaintBuffer = class {
5269
5375
  this.forEachLinePointFn(x0, y0, x1, y1, (px, py) => {
5270
5376
  const topLeftX = Math.floor(px + centerOffsetX);
5271
5377
  const topLeftY = Math.floor(py + centerOffsetY);
5272
- trimRectBoundsFn(topLeftX, topLeftY, bW, bH, target.w, target.h, scratch);
5378
+ trimRectBoundsFn(topLeftX, topLeftY, bW, bH, targetW, targetH, scratch);
5273
5379
  if (scratch.w <= 0 || scratch.h <= 0) return;
5274
5380
  eachTileInBoundsFn(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
5275
5381
  const data = tile.data;
@@ -5277,8 +5383,8 @@ var BinaryMaskPaintBuffer = class {
5277
5383
  for (let i = 0; i < bH_t; i++) {
5278
5384
  const canvasY = bY + i;
5279
5385
  const bOff = (canvasY - topLeftY) * bW;
5280
- const tOff = (canvasY & tileMask) << tileShift;
5281
- const dS = tOff + (bX & tileMask);
5386
+ const tOff = (canvasY - tile.y) * tileSize;
5387
+ const dS = tOff + (bX - tile.x);
5282
5388
  for (let j = 0; j < bW_t; j++) {
5283
5389
  const canvasX = bX + j;
5284
5390
  if (bD[bOff + (canvasX - topLeftX)]) {
@@ -5300,9 +5406,9 @@ var BinaryMaskPaintBuffer = class {
5300
5406
  const lookup = this.lookup;
5301
5407
  const tilePool = this.tilePool;
5302
5408
  const config = this.config;
5303
- const tileShift = config.tileShift;
5304
- const tileMask = config.tileMask;
5305
- const target = config.target;
5409
+ const targetW = config.targetWidth;
5410
+ const targetH = config.targetHeight;
5411
+ const tileSize = config.tileSize;
5306
5412
  const brushWidth = brush.w;
5307
5413
  const brushHeight = brush.h;
5308
5414
  const centerOffsetX = brush.centerOffsetX;
@@ -5313,15 +5419,15 @@ var BinaryMaskPaintBuffer = class {
5313
5419
  this.forEachLinePointFn(x0, y0, x1, y1, (px, py) => {
5314
5420
  const topLeftX = Math.floor(px + centerOffsetX);
5315
5421
  const topLeftY = Math.floor(py + centerOffsetY);
5316
- trimRectBoundsFn(topLeftX, topLeftY, brushWidth, brushHeight, target.w, target.h, scratch);
5422
+ trimRectBoundsFn(topLeftX, topLeftY, brushWidth, brushHeight, targetW, targetH, scratch);
5317
5423
  if (scratch.w <= 0 || scratch.h <= 0) return;
5318
5424
  eachTileInBoundsFn(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
5319
5425
  const data = tile.data;
5320
5426
  let tileChanged = false;
5321
5427
  for (let i = 0; i < bH_t; i++) {
5322
5428
  const canvasY = bY + i;
5323
- const tOff = (canvasY & tileMask) << tileShift;
5324
- const dS = tOff + (bX & tileMask);
5429
+ const tOff = (canvasY - tile.y) * tileSize;
5430
+ const dS = tOff + (bX - tile.x);
5325
5431
  for (let j = 0; j < bW_t; j++) {
5326
5432
  const idx = dS + j;
5327
5433
  if (data[idx] === 0) {
@@ -5363,9 +5469,9 @@ var ColorPaintBuffer = class {
5363
5469
  const lookup = this.lookup;
5364
5470
  const tilePool = this.tilePool;
5365
5471
  const config = this.config;
5366
- const tileShift = config.tileShift;
5367
- const tileMask = config.tileMask;
5368
- const target = config.target;
5472
+ const tileSize = config.tileSize;
5473
+ const targetW = config.targetWidth;
5474
+ const targetH = config.targetHeight;
5369
5475
  const {
5370
5476
  w: bW,
5371
5477
  h: bH,
@@ -5378,7 +5484,7 @@ var ColorPaintBuffer = class {
5378
5484
  forEachLinePoint(x0, y0, x1, y1, (px, py) => {
5379
5485
  const topLeftX = Math.floor(px + centerOffsetX);
5380
5486
  const topLeftY = Math.floor(py + centerOffsetY);
5381
- trimRectBounds(topLeftX, topLeftY, bW, bH, target.w, target.h, scratch);
5487
+ trimRectBounds(topLeftX, topLeftY, bW, bH, targetW, targetH, scratch);
5382
5488
  if (scratch.w <= 0 || scratch.h <= 0) return;
5383
5489
  eachTileInBounds(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
5384
5490
  const d32 = tile.data;
@@ -5386,8 +5492,8 @@ var ColorPaintBuffer = class {
5386
5492
  for (let i = 0; i < bH_t; i++) {
5387
5493
  const canvasY = bY + i;
5388
5494
  const bOff = (canvasY - topLeftY) * bW;
5389
- const tOff = (canvasY & tileMask) << tileShift;
5390
- const dS = tOff + (bX & tileMask);
5495
+ const tOff = (canvasY - tile.y) * tileSize;
5496
+ const dS = tOff + (bX - tile.x);
5391
5497
  for (let j = 0; j < bW_t; j++) {
5392
5498
  const canvasX = bX + j;
5393
5499
  const brushA = bD[bOff + (canvasX - topLeftX)];
@@ -5417,9 +5523,9 @@ var ColorPaintBuffer = class {
5417
5523
  const lookup = this.lookup;
5418
5524
  const tilePool = this.tilePool;
5419
5525
  const config = this.config;
5420
- const tileShift = config.tileShift;
5421
- const tileMask = config.tileMask;
5422
- const target = config.target;
5526
+ const tileSize = config.tileSize;
5527
+ const targetW = config.targetWidth;
5528
+ const targetH = config.targetHeight;
5423
5529
  const {
5424
5530
  w: bW,
5425
5531
  h: bH,
@@ -5431,7 +5537,7 @@ var ColorPaintBuffer = class {
5431
5537
  forEachLinePoint(x0, y0, x1, y1, (px, py) => {
5432
5538
  const topLeftX = Math.floor(px + centerOffsetX);
5433
5539
  const topLeftY = Math.floor(py + centerOffsetY);
5434
- trimRectBounds(topLeftX, topLeftY, bW, bH, target.w, target.h, scratch);
5540
+ trimRectBounds(topLeftX, topLeftY, bW, bH, targetW, targetH, scratch);
5435
5541
  if (scratch.w <= 0 || scratch.h <= 0) return;
5436
5542
  eachTileInBounds(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
5437
5543
  const d32 = tile.data;
@@ -5439,8 +5545,8 @@ var ColorPaintBuffer = class {
5439
5545
  for (let i = 0; i < bH_t; i++) {
5440
5546
  const canvasY = bY + i;
5441
5547
  const bOff = (canvasY - topLeftY) * bW;
5442
- const tOff = (canvasY & tileMask) << tileShift;
5443
- const dS = tOff + (bX & tileMask);
5548
+ const tOff = (canvasY - tile.y) * tileSize;
5549
+ const dS = tOff + (bX - tile.x);
5444
5550
  for (let j = 0; j < bW_t; j++) {
5445
5551
  const canvasX = bX + j;
5446
5552
  if (bD[bOff + (canvasX - topLeftX)]) {
@@ -5464,9 +5570,9 @@ var ColorPaintBuffer = class {
5464
5570
  const lookup = this.lookup;
5465
5571
  const tilePool = this.tilePool;
5466
5572
  const config = this.config;
5467
- const tileShift = config.tileShift;
5468
- const tileMask = config.tileMask;
5469
- const target = config.target;
5573
+ const targetW = config.targetWidth;
5574
+ const targetH = config.targetHeight;
5575
+ const tileSize = config.tileSize;
5470
5576
  const brushWidth = brush.w;
5471
5577
  const brushHeight = brush.h;
5472
5578
  const centerOffsetX = brush.centerOffsetX;
@@ -5475,15 +5581,15 @@ var ColorPaintBuffer = class {
5475
5581
  forEachLinePoint(x0, y0, x1, y1, (px, py) => {
5476
5582
  const topLeftX = Math.floor(px + centerOffsetX);
5477
5583
  const topLeftY = Math.floor(py + centerOffsetY);
5478
- trimRectBounds(topLeftX, topLeftY, brushWidth, brushHeight, target.w, target.h, scratch);
5584
+ trimRectBounds(topLeftX, topLeftY, brushWidth, brushHeight, targetW, targetH, scratch);
5479
5585
  if (scratch.w <= 0 || scratch.h <= 0) return;
5480
5586
  eachTileInBounds(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
5481
5587
  const d32 = tile.data;
5482
5588
  let tileChanged = false;
5483
5589
  for (let i = 0; i < bH_t; i++) {
5484
5590
  const canvasY = bY + i;
5485
- const tOff = (canvasY & tileMask) << tileShift;
5486
- const dS = tOff + (bX & tileMask);
5591
+ const tOff = (canvasY - tile.y) * tileSize;
5592
+ const dS = tOff + (bX - tile.x);
5487
5593
  for (let j = 0; j < bW_t; j++) {
5488
5594
  const idx = dS + j;
5489
5595
  if (d32[idx] !== color) {
@@ -5515,7 +5621,6 @@ var SCRATCH_OPTS = {
5515
5621
  };
5516
5622
  function commitMaskPaintBuffer(accumulator, paintBuffer, color, alpha = 255, blendFn = sourceOverPerfect, blendColorPixelDataMaskFn) {
5517
5623
  const config = accumulator.config;
5518
- const tileShift = config.tileShift;
5519
5624
  const lookup = paintBuffer.lookup;
5520
5625
  SCRATCH_OPTS.alpha = alpha;
5521
5626
  SCRATCH_OPTS.blendFn = blendFn;
@@ -5523,10 +5628,8 @@ function commitMaskPaintBuffer(accumulator, paintBuffer, color, alpha = 255, ble
5523
5628
  const tile = lookup[i];
5524
5629
  if (tile) {
5525
5630
  const didChange = accumulator.storeTileBeforeState(tile.id, tile.tx, tile.ty);
5526
- const dx = tile.tx << tileShift;
5527
- const dy = tile.ty << tileShift;
5528
- SCRATCH_OPTS.x = dx;
5529
- SCRATCH_OPTS.y = dy;
5631
+ SCRATCH_OPTS.x = tile.x;
5632
+ SCRATCH_OPTS.y = tile.y;
5530
5633
  SCRATCH_OPTS.w = tile.w;
5531
5634
  SCRATCH_OPTS.h = tile.h;
5532
5635
  didChange(blendColorPixelDataMaskFn(config.target, color, tile, SCRATCH_OPTS));
@@ -5542,49 +5645,51 @@ function makeAlphaMaskPaintBufferCommitter(accumulator, paintBuffer) {
5542
5645
  };
5543
5646
  }
5544
5647
 
5545
- // src/Internal/_constants.ts
5546
- var DEFAULT_CANVAS_FACTORY = (w, h) => new OffscreenCanvas(w, h);
5547
-
5548
- // src/Tile/MaskTile.ts
5549
- var makeAlphaMaskTile = (id, tx, ty, tileSize, tileArea) => {
5550
- return {
5551
- tileType: 1 /* MASK */,
5552
- type: 0 /* ALPHA */,
5553
- data: new Uint8Array(tileArea),
5554
- w: tileSize,
5555
- h: tileSize,
5556
- id,
5557
- tx,
5558
- ty
5648
+ // src/PixelData/ReusablePixelData.ts
5649
+ function makeReusablePixelData() {
5650
+ const pixelData = {
5651
+ w: 0,
5652
+ h: 0,
5653
+ data: null,
5654
+ imageData: null
5559
5655
  };
5560
- };
5561
- var makeBinaryMaskTile = (id, tx, ty, tileSize, tileArea) => {
5562
- return {
5563
- tileType: 1 /* MASK */,
5564
- type: 1 /* BINARY */,
5565
- data: new Uint8Array(tileArea),
5566
- w: tileSize,
5567
- h: tileSize,
5568
- id,
5569
- tx,
5570
- ty
5656
+ return function getReusablePixelData(width, height) {
5657
+ if (pixelData.w !== width || pixelData.h !== height) {
5658
+ setPixelData(pixelData, new ImageData(width, height));
5659
+ } else {
5660
+ pixelData.data.fill(0);
5661
+ }
5662
+ return pixelData;
5571
5663
  };
5572
- };
5664
+ }
5573
5665
 
5574
5666
  // src/Paint/Render/AlphaMaskPaintBufferCanvasRenderer.ts
5575
- function makeAlphaMaskPaintBufferCanvasRenderer(paintBuffer, canvasFactory = DEFAULT_CANVAS_FACTORY) {
5576
- const config = paintBuffer.config;
5577
- const tileSize = config.tileSize;
5578
- const tileShift = config.tileShift;
5579
- const tileArea = config.tileArea;
5580
- const lookup = paintBuffer.lookup;
5581
- const canvas = canvasFactory(tileSize, tileSize);
5582
- const ctx = canvas.getContext("2d");
5583
- if (!ctx) throw new Error(CANVAS_CTX_FAILED);
5584
- ctx.imageSmoothingEnabled = false;
5585
- const bridge = makePixelData(new ImageData(tileSize, tileSize));
5586
- const view32 = bridge.data;
5587
- return function drawPaintBuffer(targetCtx, color, alpha = 255, compOperation = "source-over") {
5667
+ function makeAlphaMaskPaintBufferCanvasRenderer(paintBuffer, reusableCanvasFactory) {
5668
+ const factory = reusableCanvasFactory ?? makeReusableOffscreenCanvas;
5669
+ const getBuffer = factory();
5670
+ const getBridge = makeReusablePixelData();
5671
+ let config;
5672
+ let tileSize;
5673
+ let tileArea;
5674
+ let lookup;
5675
+ let view32;
5676
+ let bridge;
5677
+ let canvas;
5678
+ let ctx;
5679
+ setBuffer(paintBuffer);
5680
+ function setBuffer(value) {
5681
+ paintBuffer = value;
5682
+ config = paintBuffer.config;
5683
+ tileSize = config.tileSize;
5684
+ tileArea = config.tileArea;
5685
+ lookup = paintBuffer.lookup;
5686
+ bridge = getBridge(tileSize, tileSize);
5687
+ view32 = bridge.data;
5688
+ const buff = getBuffer(tileSize, tileSize);
5689
+ canvas = buff.canvas;
5690
+ ctx = buff.ctx;
5691
+ }
5692
+ function draw(targetCtx, color, alpha = 255, compOperation = "source-over") {
5588
5693
  if (alpha === 0) return;
5589
5694
  const baseSrcAlpha = color >>> 24;
5590
5695
  const colorRGB = color & 16777215;
@@ -5607,29 +5712,31 @@ function makeAlphaMaskPaintBufferCanvasRenderer(paintBuffer, canvasFactory = DEF
5607
5712
  view32[p] = (colorRGB | finalA << 24) >>> 0;
5608
5713
  }
5609
5714
  }
5610
- const dx = tile.tx << tileShift;
5611
- const dy = tile.ty << tileShift;
5612
5715
  ctx.putImageData(bridge.imageData, 0, 0);
5613
- targetCtx.drawImage(canvas, dx, dy);
5716
+ targetCtx.drawImage(canvas, tile.x, tile.y);
5614
5717
  }
5615
5718
  }
5616
5719
  targetCtx.globalAlpha = 1;
5617
5720
  targetCtx.globalCompositeOperation = "source-over";
5721
+ }
5722
+ return {
5723
+ draw,
5724
+ setBuffer
5618
5725
  };
5619
5726
  }
5620
5727
 
5621
5728
  // src/Paint/Commit/AlphaMaskPaintBufferManager.ts
5622
- function makeAlphaMaskPaintBufferManager(writer, canvasFactory = DEFAULT_CANVAS_FACTORY) {
5623
- const pool = new TilePool(writer.config, makeAlphaMaskTile);
5729
+ function makeAlphaMaskPaintBufferManager(writer, reusableCanvasFactory) {
5730
+ const pool = new TilePool(writer.config.tileSize, makeAlphaMaskTile);
5624
5731
  const buffer = new AlphaMaskPaintBuffer(writer.config, pool);
5625
- const draw = makeAlphaMaskPaintBufferCanvasRenderer(buffer, canvasFactory);
5732
+ const renderer = makeAlphaMaskPaintBufferCanvasRenderer(buffer, reusableCanvasFactory);
5626
5733
  return {
5627
5734
  clear: buffer.clear.bind(buffer),
5628
5735
  paintRect: buffer.paintRect.bind(buffer),
5629
5736
  paintAlphaMask: buffer.paintAlphaMask.bind(buffer),
5630
5737
  paintBinaryMask: buffer.paintBinaryMask.bind(buffer),
5631
5738
  commit: makeAlphaMaskPaintBufferCommitter(writer.accumulator, buffer),
5632
- draw
5739
+ renderer
5633
5740
  };
5634
5741
  }
5635
5742
 
@@ -5641,19 +5748,32 @@ function makeBinaryMaskPaintBufferCommitter(accumulator, paintBuffer) {
5641
5748
  }
5642
5749
 
5643
5750
  // src/Paint/Render/BinaryMaskPaintBufferCanvasRenderer.ts
5644
- function makeBinaryMaskPaintBufferCanvasRenderer(paintBuffer, canvasFactory = DEFAULT_CANVAS_FACTORY) {
5645
- const config = paintBuffer.config;
5646
- const tileSize = config.tileSize;
5647
- const tileShift = config.tileShift;
5648
- const tileArea = config.tileArea;
5649
- const lookup = paintBuffer.lookup;
5650
- const canvas = canvasFactory(tileSize, tileSize);
5651
- const ctx = canvas.getContext("2d");
5652
- if (!ctx) throw new Error(CANVAS_CTX_FAILED);
5653
- ctx.imageSmoothingEnabled = false;
5654
- const bridge = makePixelData(new ImageData(tileSize, tileSize));
5655
- const view32 = bridge.data;
5656
- return function drawPaintBuffer(targetCtx, color, alpha = 255, compOperation = "source-over") {
5751
+ function makeBinaryMaskPaintBufferCanvasRenderer(paintBuffer, reusableCanvasFactory) {
5752
+ const factory = reusableCanvasFactory ?? makeReusableOffscreenCanvas;
5753
+ const getBuffer = factory();
5754
+ const getBridge = makeReusablePixelData();
5755
+ let config;
5756
+ let tileSize;
5757
+ let tileArea;
5758
+ let lookup;
5759
+ let view32;
5760
+ let bridge;
5761
+ let canvas;
5762
+ let ctx;
5763
+ setBuffer(paintBuffer);
5764
+ function setBuffer(value) {
5765
+ paintBuffer = value;
5766
+ config = paintBuffer.config;
5767
+ tileSize = config.tileSize;
5768
+ tileArea = config.tileArea;
5769
+ lookup = paintBuffer.lookup;
5770
+ bridge = getBridge(tileSize, tileSize);
5771
+ view32 = bridge.data;
5772
+ const buff = getBuffer(tileSize, tileSize);
5773
+ canvas = buff.canvas;
5774
+ ctx = buff.ctx;
5775
+ }
5776
+ function draw(targetCtx, color, alpha = 255, compOperation = "source-over") {
5657
5777
  if (alpha === 0) return;
5658
5778
  const baseSrcAlpha = color >>> 24;
5659
5779
  if (baseSrcAlpha === 0) return;
@@ -5669,28 +5789,30 @@ function makeBinaryMaskPaintBufferCanvasRenderer(paintBuffer, canvasFactory = DE
5669
5789
  view32[p] = color;
5670
5790
  }
5671
5791
  }
5672
- const dx = tile.tx << tileShift;
5673
- const dy = tile.ty << tileShift;
5674
5792
  ctx.putImageData(bridge.imageData, 0, 0);
5675
- targetCtx.drawImage(canvas, dx, dy);
5793
+ targetCtx.drawImage(canvas, tile.x, tile.y);
5676
5794
  }
5677
5795
  }
5678
5796
  targetCtx.globalAlpha = 1;
5679
5797
  targetCtx.globalCompositeOperation = "source-over";
5798
+ }
5799
+ return {
5800
+ draw,
5801
+ setBuffer
5680
5802
  };
5681
5803
  }
5682
5804
 
5683
5805
  // src/Paint/Commit/BinaryMaskPaintBufferManager.ts
5684
- function makeBinaryMaskPaintBufferManager(writer, canvasFactory = DEFAULT_CANVAS_FACTORY) {
5685
- const pool = new TilePool(writer.config, makeBinaryMaskTile);
5806
+ function makeBinaryMaskPaintBufferManager(writer, reusableCanvasFactory) {
5807
+ const pool = new TilePool(writer.config.tileSize, makeBinaryMaskTile);
5686
5808
  const buffer = new BinaryMaskPaintBuffer(writer.config, pool);
5687
- const draw = makeBinaryMaskPaintBufferCanvasRenderer(buffer, canvasFactory);
5809
+ const renderer = makeBinaryMaskPaintBufferCanvasRenderer(buffer, reusableCanvasFactory);
5688
5810
  return {
5689
5811
  clear: buffer.clear.bind(buffer),
5690
5812
  paintRect: buffer.paintRect.bind(buffer),
5691
5813
  paintBinaryMask: buffer.paintBinaryMask.bind(buffer),
5692
5814
  commit: makeBinaryMaskPaintBufferCommitter(writer.accumulator, buffer),
5693
- draw
5815
+ renderer
5694
5816
  };
5695
5817
  }
5696
5818
 
@@ -5705,7 +5827,6 @@ var SCRATCH_OPTS2 = {
5705
5827
  };
5706
5828
  function commitColorPaintBuffer(accumulator, paintBuffer, alpha = 255, blendFn = sourceOverPerfect, blendPixelDataFn = blendPixelData) {
5707
5829
  const config = accumulator.config;
5708
- const tileShift = config.tileShift;
5709
5830
  const lookup = paintBuffer.lookup;
5710
5831
  SCRATCH_OPTS2.alpha = alpha;
5711
5832
  SCRATCH_OPTS2.blendFn = blendFn;
@@ -5713,10 +5834,8 @@ function commitColorPaintBuffer(accumulator, paintBuffer, alpha = 255, blendFn =
5713
5834
  const tile = lookup[i];
5714
5835
  if (tile) {
5715
5836
  const didChange = accumulator.storeTileBeforeState(tile.id, tile.tx, tile.ty);
5716
- const dx = tile.tx << tileShift;
5717
- const dy = tile.ty << tileShift;
5718
- SCRATCH_OPTS2.x = dx;
5719
- SCRATCH_OPTS2.y = dy;
5837
+ SCRATCH_OPTS2.x = tile.x;
5838
+ SCRATCH_OPTS2.y = tile.y;
5720
5839
  SCRATCH_OPTS2.w = tile.w;
5721
5840
  SCRATCH_OPTS2.h = tile.h;
5722
5841
  didChange(blendPixelDataFn(config.target, tile, SCRATCH_OPTS2));
@@ -5733,44 +5852,47 @@ function makeColorPaintBufferCommitter(accumulator, paintBuffer) {
5733
5852
  }
5734
5853
 
5735
5854
  // src/Paint/Render/ColorPaintBufferCanvasRenderer.ts
5736
- function makeColorPaintBufferCanvasRenderer(paintBuffer, canvasFactory = DEFAULT_CANVAS_FACTORY) {
5737
- const config = paintBuffer.config;
5738
- const tileSize = config.tileSize;
5739
- const tileShift = config.tileShift;
5740
- const lookup = paintBuffer.lookup;
5741
- const canvas = canvasFactory(tileSize, tileSize);
5742
- const ctx = canvas.getContext("2d");
5743
- if (!ctx) throw new Error(CANVAS_CTX_FAILED);
5744
- ctx.imageSmoothingEnabled = false;
5745
- return function drawPaintBuffer(targetCtx, alpha = 255, compOperation = "source-over") {
5855
+ function makeColorPaintBufferCanvasRenderer(paintBuffer, reusableCanvasFactory) {
5856
+ const factory = reusableCanvasFactory ?? makeReusableOffscreenCanvas;
5857
+ const getBuffer = factory();
5858
+ function draw(targetCtx, alpha = 255, compOperation = "source-over") {
5859
+ const buff = getBuffer(paintBuffer.config.tileSize, paintBuffer.config.tileSize);
5860
+ const lookup = paintBuffer.lookup;
5861
+ const length = lookup.length;
5862
+ const ctx = buff.ctx;
5863
+ const canvas = buff.canvas;
5746
5864
  targetCtx.globalAlpha = alpha / 255;
5747
5865
  targetCtx.globalCompositeOperation = compOperation;
5748
- for (let i = 0; i < lookup.length; i++) {
5866
+ for (let i = 0; i < length; i++) {
5749
5867
  const tile = lookup[i];
5750
5868
  if (tile) {
5751
- const dx = tile.tx << tileShift;
5752
- const dy = tile.ty << tileShift;
5753
5869
  ctx.putImageData(tile.imageData, 0, 0);
5754
- targetCtx.drawImage(canvas, dx, dy);
5870
+ targetCtx.drawImage(canvas, tile.x, tile.y);
5755
5871
  }
5756
5872
  }
5757
5873
  targetCtx.globalAlpha = 1;
5758
5874
  targetCtx.globalCompositeOperation = "source-over";
5875
+ }
5876
+ return {
5877
+ draw,
5878
+ setBuffer(value) {
5879
+ paintBuffer = value;
5880
+ }
5759
5881
  };
5760
5882
  }
5761
5883
 
5762
5884
  // src/Paint/Commit/ColorPaintBufferManager.ts
5763
- function makeColorPaintBufferManager(writer, canvasFactory = DEFAULT_CANVAS_FACTORY) {
5764
- const pool = new TilePool(writer.config, makePixelTile);
5885
+ function makeColorPaintBufferManager(writer, reusableCanvasFactory) {
5886
+ const pool = new TilePool(writer.config.tileSize, makePixelTile);
5765
5887
  const buffer = new ColorPaintBuffer(writer.config, pool);
5766
- const draw = makeColorPaintBufferCanvasRenderer(buffer, canvasFactory);
5888
+ const renderer = makeColorPaintBufferCanvasRenderer(buffer, reusableCanvasFactory);
5767
5889
  return {
5768
5890
  clear: buffer.clear.bind(buffer),
5769
5891
  paintRect: buffer.paintRect.bind(buffer),
5770
5892
  paintAlphaMask: buffer.paintAlphaMask.bind(buffer),
5771
5893
  paintBinaryMask: buffer.paintBinaryMask.bind(buffer),
5772
5894
  commit: makeColorPaintBufferCommitter(writer.accumulator, buffer),
5773
- draw
5895
+ renderer
5774
5896
  };
5775
5897
  }
5776
5898
 
@@ -5906,24 +6028,6 @@ function makePaintRect(w, h) {
5906
6028
  };
5907
6029
  }
5908
6030
 
5909
- // src/PixelData/ReusablePixelData.ts
5910
- function makeReusablePixelData() {
5911
- const pixelData = {
5912
- w: 0,
5913
- h: 0,
5914
- data: null,
5915
- imageData: null
5916
- };
5917
- return function getReusablePixelData(width, height) {
5918
- if (pixelData.w !== width || pixelData.h !== height) {
5919
- setPixelData(pixelData, new ImageData(width, height));
5920
- } else {
5921
- pixelData.data.fill(0);
5922
- }
5923
- return pixelData;
5924
- };
5925
- }
5926
-
5927
6031
  // src/Paint/Render/PaintCursorRenderer.ts
5928
6032
  function makePaintCursorRenderer(reusableCanvasFactory) {
5929
6033
  const factory = reusableCanvasFactory ?? makeReusableOffscreenCanvas;
@@ -5999,6 +6103,9 @@ function makePaintCursorRenderer(reusableCanvasFactory) {
5999
6103
  const dy = centerY * _scale + currentBrush.centerOffsetY * _scale - 1;
6000
6104
  drawCtx.drawImage(canvas, Math.floor(dx), Math.floor(dy));
6001
6105
  }
6106
+ function drawRaw(drawCtx, x, y) {
6107
+ drawCtx.drawImage(canvas, Math.floor(x * _scale), Math.floor(y * _scale));
6108
+ }
6002
6109
  function getSettings() {
6003
6110
  return {
6004
6111
  color: _color,
@@ -6011,6 +6118,7 @@ function makePaintCursorRenderer(reusableCanvasFactory) {
6011
6118
  getBounds,
6012
6119
  getBoundsScaled: getOutlineBoundsScaled,
6013
6120
  draw,
6121
+ drawRaw,
6014
6122
  getSettings
6015
6123
  };
6016
6124
  }
@@ -6072,20 +6180,29 @@ var SCRATCH_OPTS5 = {
6072
6180
  x: 0,
6073
6181
  y: 0,
6074
6182
  alpha: 255,
6075
- blendFn: sourceOverPerfect
6183
+ blendFn: sourceOverPerfect,
6184
+ w: void 0,
6185
+ h: void 0
6076
6186
  };
6077
- function blendColorPixelDataPaintMask(dst, color, mask, x, y, alpha = 255, blendFn = sourceOverPerfect) {
6187
+ function blendColorPixelDataPaintMask(target, color, mask, x, y, alpha = 255, blendFn = sourceOverPerfect) {
6078
6188
  const tx = x + mask.centerOffsetX;
6079
6189
  const ty = y + mask.centerOffsetY;
6080
6190
  SCRATCH_OPTS5.x = tx;
6081
6191
  SCRATCH_OPTS5.y = ty;
6082
6192
  SCRATCH_OPTS5.alpha = alpha;
6083
6193
  SCRATCH_OPTS5.blendFn = blendFn;
6084
- if (mask.type === 1 /* BINARY */) {
6085
- return blendColorPixelDataBinaryMask(dst, color, mask, SCRATCH_OPTS5);
6086
- } else {
6087
- return blendColorPixelDataAlphaMask(dst, color, mask, SCRATCH_OPTS5);
6194
+ SCRATCH_OPTS5.w = void 0;
6195
+ SCRATCH_OPTS5.h = void 0;
6196
+ if (mask.data) {
6197
+ if (mask.type === 1 /* BINARY */) {
6198
+ return blendColorPixelDataBinaryMask(target, color, mask, SCRATCH_OPTS5);
6199
+ } else {
6200
+ return blendColorPixelDataAlphaMask(target, color, mask, SCRATCH_OPTS5);
6201
+ }
6088
6202
  }
6203
+ SCRATCH_OPTS5.w = mask.w;
6204
+ SCRATCH_OPTS5.h = mask.h;
6205
+ return blendColorPixelData(target, color, SCRATCH_OPTS5);
6089
6206
  }
6090
6207
 
6091
6208
  // src/PixelData/blendPixelDataMask.ts
@@ -6105,13 +6222,12 @@ var SCRATCH_OPTS6 = {
6105
6222
  blendFn: void 0
6106
6223
  };
6107
6224
  function blendPixelDataPaintBuffer(target, paintBuffer, alpha = 255, blendFn, blendPixelDataFn = blendPixelData) {
6108
- const tileShift = paintBuffer.config.tileShift;
6109
6225
  const lookup = paintBuffer.lookup;
6110
6226
  for (let i = 0; i < lookup.length; i++) {
6111
6227
  const tile = lookup[i];
6112
6228
  if (tile) {
6113
- const x = tile.tx << tileShift;
6114
- const y = tile.ty << tileShift;
6229
+ const x = tile.x;
6230
+ const y = tile.y;
6115
6231
  SCRATCH_OPTS6.x = x;
6116
6232
  SCRATCH_OPTS6.y = y;
6117
6233
  SCRATCH_OPTS6.alpha = alpha;
@@ -6185,6 +6301,36 @@ function copyPixelData(target) {
6185
6301
  return makePixelData(new ImageData(buffer, target.w, target.h));
6186
6302
  }
6187
6303
 
6304
+ // src/PixelData/cropPixelData.ts
6305
+ function cropPixelData(src, x, y, w, h, out) {
6306
+ const cx = Math.max(x, 0);
6307
+ const cy = Math.max(y, 0);
6308
+ const cw = Math.min(x + w, src.w) - cx;
6309
+ const ch = Math.min(y + h, src.h) - cy;
6310
+ if (cw <= 0 || ch <= 0) {
6311
+ throw new Error(`Crop [${x},${y} ${w}x${h}] does not overlap PixelData [${src.w}x${src.h}]`);
6312
+ }
6313
+ const cropped = new ImageData(cw, ch);
6314
+ let dst32;
6315
+ if (out) {
6316
+ setPixelData(out, cropped);
6317
+ dst32 = out.data;
6318
+ } else {
6319
+ dst32 = new Uint32Array(cropped.data.buffer);
6320
+ }
6321
+ for (let row = 0; row < ch; row++) {
6322
+ const srcOffset = (cy + row) * src.w + cx;
6323
+ const dstOffset = row * cw;
6324
+ dst32.set(src.data.subarray(srcOffset, srcOffset + cw), dstOffset);
6325
+ }
6326
+ return out ?? {
6327
+ data: dst32,
6328
+ imageData: cropped,
6329
+ w: cw,
6330
+ h: ch
6331
+ };
6332
+ }
6333
+
6188
6334
  // src/PixelData/extractPixelDataBuffer.ts
6189
6335
  function extractPixelDataBuffer(source, _x, _y, _w, _h) {
6190
6336
  let x;
@@ -6400,6 +6546,46 @@ function rotateSquareInPlace(pixelData) {
6400
6546
  }
6401
6547
  }
6402
6548
 
6549
+ // src/PixelData/trimPixelData.ts
6550
+ function getPixelDataTransparentTrimmedBounds(target) {
6551
+ let minX = target.w;
6552
+ let minY = target.h;
6553
+ let maxX = -1;
6554
+ let maxY = -1;
6555
+ for (let y = 0; y < target.h; y++) {
6556
+ for (let x = 0; x < target.w; x++) {
6557
+ const alpha = target.data[y * target.w + x] >>> 24;
6558
+ if (alpha !== 0) {
6559
+ if (x < minX) minX = x;
6560
+ if (x > maxX) maxX = x;
6561
+ if (y < minY) minY = y;
6562
+ if (y > maxY) maxY = y;
6563
+ }
6564
+ }
6565
+ }
6566
+ if (maxX === -1) return null;
6567
+ return {
6568
+ x: minX,
6569
+ y: minY,
6570
+ w: maxX - minX + 1,
6571
+ h: maxY - minY + 1
6572
+ };
6573
+ }
6574
+ function trimTransparentPixelData(target) {
6575
+ const r = getPixelDataTransparentTrimmedBounds(target);
6576
+ if (!r) {
6577
+ throw new Error("PixelData is fully transparent \u2014 no crop bounds found");
6578
+ }
6579
+ return cropPixelData(target, r.x, r.y, r.w, r.h);
6580
+ }
6581
+ function trimTransparentPixelDataInPlace(target) {
6582
+ const r = getPixelDataTransparentTrimmedBounds(target);
6583
+ if (!r) {
6584
+ throw new Error("PixelData is fully transparent \u2014 no crop bounds found");
6585
+ }
6586
+ cropPixelData(target, r.x, r.y, r.w, r.h, target);
6587
+ }
6588
+
6403
6589
  // src/PixelData/uInt32ArrayToPixelData.ts
6404
6590
  function uInt32ArrayToPixelData(data, width, height) {
6405
6591
  const buffer = data.buffer;
@@ -6460,14 +6646,11 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
6460
6646
 
6461
6647
  // src/PixelData/writePaintBufferToPixelData.ts
6462
6648
  function writePaintBufferToPixelData(target, paintBuffer, writePixelDataBufferFn = writePixelDataBuffer) {
6463
- const tileShift = paintBuffer.config.tileShift;
6464
6649
  const lookup = paintBuffer.lookup;
6465
6650
  for (let i = 0; i < lookup.length; i++) {
6466
6651
  const tile = lookup[i];
6467
6652
  if (tile) {
6468
- const dx = tile.tx << tileShift;
6469
- const dy = tile.ty << tileShift;
6470
- writePixelDataBufferFn(target, tile.data, dx, dy, tile.w, tile.h);
6653
+ writePixelDataBufferFn(target, tile.data, tile.x, tile.y, tile.w, tile.h);
6471
6654
  }
6472
6655
  }
6473
6656
  }
@@ -6519,7 +6702,6 @@ export {
6519
6702
  MaskType,
6520
6703
  PaintMaskOutline,
6521
6704
  PixelAccumulator,
6522
- PixelEngineConfig,
6523
6705
  PixelWriter,
6524
6706
  TilePool,
6525
6707
  TileType,
@@ -6546,6 +6728,7 @@ export {
6546
6728
  blendPixelDataPaintBuffer,
6547
6729
  clearPixelDataFast,
6548
6730
  color32ToCssRGBA,
6731
+ color32ToCssRGBAString,
6549
6732
  color32ToHex,
6550
6733
  colorBurnFast,
6551
6734
  colorBurnPerfect,
@@ -6558,6 +6741,8 @@ export {
6558
6741
  copyImageDataLike,
6559
6742
  copyMask,
6560
6743
  copyPixelData,
6744
+ cropPixelData,
6745
+ cssRGBAToColor32,
6561
6746
  darkenFast,
6562
6747
  darkenPerfect,
6563
6748
  darkerFast,
@@ -6596,6 +6781,7 @@ export {
6596
6781
  getImageDataFromClipboard,
6597
6782
  getIndexedImageColor,
6598
6783
  getIndexedImageColorCounts,
6784
+ getPixelDataTransparentTrimmedBounds,
6599
6785
  getRectsBounds,
6600
6786
  getSupportedPixelFormats,
6601
6787
  hardLightFast,
@@ -6669,6 +6855,8 @@ export {
6669
6855
  makeReusableImageData,
6670
6856
  makeReusableOffscreenCanvas,
6671
6857
  makeReusablePixelData,
6858
+ makeTileTargetConfig,
6859
+ makeTileTargetMeta,
6672
6860
  merge2BinaryMaskRects,
6673
6861
  mergeAlphaMasks,
6674
6862
  mergeBinaryMaskRects,
@@ -6691,7 +6879,6 @@ export {
6691
6879
  mutatorClear,
6692
6880
  mutatorFill,
6693
6881
  mutatorFillBinaryMask,
6694
- mutatorFillRect,
6695
6882
  mutatorInvert,
6696
6883
  overlayFast,
6697
6884
  overlayPerfect,
@@ -6735,6 +6922,8 @@ export {
6735
6922
  toBlendModeIndexAndName,
6736
6923
  trimMaskRectBounds,
6737
6924
  trimRectBounds,
6925
+ trimTransparentPixelData,
6926
+ trimTransparentPixelDataInPlace,
6738
6927
  uInt32ArrayToImageData,
6739
6928
  uInt32ArrayToImageDataLike,
6740
6929
  uInt32ArrayToPixelData,