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
@@ -32,7 +32,6 @@ __export(src_exports, {
32
32
  MaskType: () => MaskType,
33
33
  PaintMaskOutline: () => PaintMaskOutline,
34
34
  PixelAccumulator: () => PixelAccumulator,
35
- PixelEngineConfig: () => PixelEngineConfig,
36
35
  PixelWriter: () => PixelWriter,
37
36
  TilePool: () => TilePool,
38
37
  TileType: () => TileType,
@@ -59,6 +58,7 @@ __export(src_exports, {
59
58
  blendPixelDataPaintBuffer: () => blendPixelDataPaintBuffer,
60
59
  clearPixelDataFast: () => clearPixelDataFast,
61
60
  color32ToCssRGBA: () => color32ToCssRGBA,
61
+ color32ToCssRGBAString: () => color32ToCssRGBAString,
62
62
  color32ToHex: () => color32ToHex,
63
63
  colorBurnFast: () => colorBurnFast,
64
64
  colorBurnPerfect: () => colorBurnPerfect,
@@ -71,6 +71,8 @@ __export(src_exports, {
71
71
  copyImageDataLike: () => copyImageDataLike,
72
72
  copyMask: () => copyMask,
73
73
  copyPixelData: () => copyPixelData,
74
+ cropPixelData: () => cropPixelData,
75
+ cssRGBAToColor32: () => cssRGBAToColor32,
74
76
  darkenFast: () => darkenFast,
75
77
  darkenPerfect: () => darkenPerfect,
76
78
  darkerFast: () => darkerFast,
@@ -109,6 +111,7 @@ __export(src_exports, {
109
111
  getImageDataFromClipboard: () => getImageDataFromClipboard,
110
112
  getIndexedImageColor: () => getIndexedImageColor,
111
113
  getIndexedImageColorCounts: () => getIndexedImageColorCounts,
114
+ getPixelDataTransparentTrimmedBounds: () => getPixelDataTransparentTrimmedBounds,
112
115
  getRectsBounds: () => getRectsBounds,
113
116
  getSupportedPixelFormats: () => getSupportedPixelFormats,
114
117
  hardLightFast: () => hardLightFast,
@@ -182,6 +185,8 @@ __export(src_exports, {
182
185
  makeReusableImageData: () => makeReusableImageData,
183
186
  makeReusableOffscreenCanvas: () => makeReusableOffscreenCanvas,
184
187
  makeReusablePixelData: () => makeReusablePixelData,
188
+ makeTileTargetConfig: () => makeTileTargetConfig,
189
+ makeTileTargetMeta: () => makeTileTargetMeta,
185
190
  merge2BinaryMaskRects: () => merge2BinaryMaskRects,
186
191
  mergeAlphaMasks: () => mergeAlphaMasks,
187
192
  mergeBinaryMaskRects: () => mergeBinaryMaskRects,
@@ -204,7 +209,6 @@ __export(src_exports, {
204
209
  mutatorClear: () => mutatorClear,
205
210
  mutatorFill: () => mutatorFill,
206
211
  mutatorFillBinaryMask: () => mutatorFillBinaryMask,
207
- mutatorFillRect: () => mutatorFillRect,
208
212
  mutatorInvert: () => mutatorInvert,
209
213
  overlayFast: () => overlayFast,
210
214
  overlayPerfect: () => overlayPerfect,
@@ -248,6 +252,8 @@ __export(src_exports, {
248
252
  toBlendModeIndexAndName: () => toBlendModeIndexAndName,
249
253
  trimMaskRectBounds: () => trimMaskRectBounds,
250
254
  trimRectBounds: () => trimRectBounds,
255
+ trimTransparentPixelData: () => trimTransparentPixelData,
256
+ trimTransparentPixelDataInPlace: () => trimTransparentPixelDataInPlace,
251
257
  uInt32ArrayToImageData: () => uInt32ArrayToImageData,
252
258
  uInt32ArrayToImageDataLike: () => uInt32ArrayToImageDataLike,
253
259
  uInt32ArrayToPixelData: () => uInt32ArrayToPixelData,
@@ -280,43 +286,7 @@ __export(errors_exports, {
280
286
  var OFFSCREEN_CANVAS_CTX_FAILED = "Failed to create OffscreenCanvas context";
281
287
  var CANVAS_CTX_FAILED = "Failed to create Canvas context";
282
288
 
283
- // src/color.ts
284
- function packColor(r, g, b, a) {
285
- return (a << 24 | b << 16 | g << 8 | r) >>> 0;
286
- }
287
- function packRGBA({
288
- r,
289
- g,
290
- b,
291
- a
292
- }) {
293
- return (a << 24 | b << 16 | g << 8 | r) >>> 0;
294
- }
295
- var unpackRed = (packed) => packed >>> 0 & 255;
296
- var unpackGreen = (packed) => packed >>> 8 & 255;
297
- var unpackBlue = (packed) => packed >>> 16 & 255;
298
- var unpackAlpha = (packed) => packed >>> 24 & 255;
299
- function unpackColor(packed) {
300
- return {
301
- r: packed >>> 0 & 255,
302
- g: packed >>> 8 & 255,
303
- b: packed >>> 16 & 255,
304
- a: packed >>> 24 & 255
305
- };
306
- }
307
- var SCRATCH_RGBA = {
308
- r: 0,
309
- g: 0,
310
- b: 0,
311
- a: 0
312
- };
313
- function unpackColorTo(packed, scratch = SCRATCH_RGBA) {
314
- scratch.r = packed >>> 0 & 255;
315
- scratch.g = packed >>> 8 & 255;
316
- scratch.b = packed >>> 16 & 255;
317
- scratch.a = packed >>> 24 & 255;
318
- return scratch;
319
- }
289
+ // src/Color/colorDistance.ts
320
290
  function colorDistance(a, b) {
321
291
  const dr = (a & 255) - (b & 255);
322
292
  const dg = (a >>> 8 & 255) - (b >>> 8 & 255);
@@ -324,34 +294,6 @@ function colorDistance(a, b) {
324
294
  const da = (a >>> 24 & 255) - (b >>> 24 & 255);
325
295
  return dr * dr + dg * dg + db * db + da * da;
326
296
  }
327
- function lerpColor32(a, b, t) {
328
- const r = (a & 255) + t * ((b & 255) - (a & 255));
329
- const g = (a >>> 8 & 255) + t * ((b >>> 8 & 255) - (a >>> 8 & 255));
330
- const b_ = (a >>> 16 & 255) + t * ((b >>> 16 & 255) - (a >>> 16 & 255));
331
- const a_ = (a >>> 24 & 255) + t * ((b >>> 24 & 255) - (a >>> 24 & 255));
332
- return (a_ << 24 | b_ << 16 | g << 8 | r) >>> 0;
333
- }
334
- function lerpColor32Fast(src, dst, w) {
335
- const invA = 255 - w;
336
- const rb = (src & 16711935) * w + (dst & 16711935) * invA >>> 8 & 16711935;
337
- const ga = (src >>> 8 & 16711935) * w + (dst >>> 8 & 16711935) * invA >>> 8 & 16711935;
338
- return (rb | ga << 8) >>> 0;
339
- }
340
- function color32ToHex(color) {
341
- const r = (color & 255).toString(16).padStart(2, "0");
342
- const g = (color >>> 8 & 255).toString(16).padStart(2, "0");
343
- const b = (color >>> 16 & 255).toString(16).padStart(2, "0");
344
- const a = (color >>> 24 & 255).toString(16).padStart(2, "0");
345
- return `#${r}${g}${b}${a}`;
346
- }
347
- function color32ToCssRGBA(color) {
348
- const r = color & 255;
349
- const g = color >>> 8 & 255;
350
- const b = color >>> 16 & 255;
351
- const a = color >>> 24 & 255;
352
- const alpha = Number((a / 255).toFixed(3));
353
- return `rgba(${r},${g},${b},${alpha})`;
354
- }
355
297
 
356
298
  // src/ImageData/extractImageDataBuffer.ts
357
299
  function extractImageDataBuffer(imageData, _x, _y, _w, _h) {
@@ -2112,9 +2054,6 @@ function makeReusableCanvasMeta(factory) {
2112
2054
  canvas.width = width;
2113
2055
  canvas.height = height;
2114
2056
  ctx.imageSmoothingEnabled = false;
2115
- } else {
2116
- ctx.setTransform(1, 0, 0, 1, 0, 0);
2117
- ctx.clearRect(0, 0, width, height);
2118
2057
  }
2119
2058
  return result;
2120
2059
  }
@@ -2235,6 +2174,96 @@ async function writeImageDataToClipboard(imageData) {
2235
2174
  return writeImgBlobToClipboard(blob);
2236
2175
  }
2237
2176
 
2177
+ // src/Color/lerpColor32.ts
2178
+ function lerpColor32(a, b, t) {
2179
+ const r = (a & 255) + t * ((b & 255) - (a & 255));
2180
+ const g = (a >>> 8 & 255) + t * ((b >>> 8 & 255) - (a >>> 8 & 255));
2181
+ const b_ = (a >>> 16 & 255) + t * ((b >>> 16 & 255) - (a >>> 16 & 255));
2182
+ const a_ = (a >>> 24 & 255) + t * ((b >>> 24 & 255) - (a >>> 24 & 255));
2183
+ return (a_ << 24 | b_ << 16 | g << 8 | r) >>> 0;
2184
+ }
2185
+ function lerpColor32Fast(src, dst, w) {
2186
+ const invA = 255 - w;
2187
+ const rb = (src & 16711935) * w + (dst & 16711935) * invA >>> 8 & 16711935;
2188
+ const ga = (src >>> 8 & 16711935) * w + (dst >>> 8 & 16711935) * invA >>> 8 & 16711935;
2189
+ return (rb | ga << 8) >>> 0;
2190
+ }
2191
+
2192
+ // src/Color/convert-color.ts
2193
+ function color32ToHex(color) {
2194
+ const r = (color & 255).toString(16).padStart(2, "0");
2195
+ const g = (color >>> 8 & 255).toString(16).padStart(2, "0");
2196
+ const b = (color >>> 16 & 255).toString(16).padStart(2, "0");
2197
+ const a = (color >>> 24 & 255).toString(16).padStart(2, "0");
2198
+ return `#${r}${g}${b}${a}`;
2199
+ }
2200
+ function color32ToCssRGBAString(color) {
2201
+ const r = color & 255;
2202
+ const g = color >>> 8 & 255;
2203
+ const b = color >>> 16 & 255;
2204
+ const a = color >>> 24 & 255;
2205
+ const alpha = Number((a / 255).toFixed(3));
2206
+ return `rgba(${r},${g},${b},${alpha})`;
2207
+ }
2208
+ function color32ToCssRGBA(color) {
2209
+ const r = color & 255;
2210
+ const g = color >>> 8 & 255;
2211
+ const b = color >>> 16 & 255;
2212
+ const a = color >>> 24 & 255;
2213
+ return {
2214
+ r,
2215
+ g,
2216
+ b,
2217
+ a: a / 255
2218
+ };
2219
+ }
2220
+ function cssRGBAToColor32({
2221
+ r,
2222
+ g,
2223
+ b,
2224
+ a
2225
+ }) {
2226
+ return (a * 255 << 24 | b << 16 | g << 8 | r) >>> 0;
2227
+ }
2228
+
2229
+ // src/Color/pack-color.ts
2230
+ function packColor(r, g, b, a) {
2231
+ return (a << 24 | b << 16 | g << 8 | r) >>> 0;
2232
+ }
2233
+ function packRGBA({
2234
+ r,
2235
+ g,
2236
+ b,
2237
+ a
2238
+ }) {
2239
+ return (a << 24 | b << 16 | g << 8 | r) >>> 0;
2240
+ }
2241
+ var unpackRed = (packed) => packed >>> 0 & 255;
2242
+ var unpackGreen = (packed) => packed >>> 8 & 255;
2243
+ var unpackBlue = (packed) => packed >>> 16 & 255;
2244
+ var unpackAlpha = (packed) => packed >>> 24 & 255;
2245
+ function unpackColor(packed) {
2246
+ return {
2247
+ r: packed >>> 0 & 255,
2248
+ g: packed >>> 8 & 255,
2249
+ b: packed >>> 16 & 255,
2250
+ a: packed >>> 24 & 255
2251
+ };
2252
+ }
2253
+ var SCRATCH_RGBA = {
2254
+ r: 0,
2255
+ g: 0,
2256
+ b: 0,
2257
+ a: 0
2258
+ };
2259
+ function unpackColorTo(packed, scratch = SCRATCH_RGBA) {
2260
+ scratch.r = packed >>> 0 & 255;
2261
+ scratch.g = packed >>> 8 & 255;
2262
+ scratch.b = packed >>> 16 & 255;
2263
+ scratch.a = packed >>> 24 & 255;
2264
+ return scratch;
2265
+ }
2266
+
2238
2267
  // src/Control/BatchedQueue.ts
2239
2268
  function makeBatchedQueue(processor, queue) {
2240
2269
  let activeSet = /* @__PURE__ */ new Set();
@@ -2414,10 +2443,14 @@ var PixelAccumulator = class {
2414
2443
  * @param y pixel y coordinate
2415
2444
  */
2416
2445
  storePixelBeforeState(x, y) {
2417
- const shift = this.config.tileShift;
2418
2446
  const columns = this.config.targetColumns;
2419
- const tx = x >> shift;
2420
- const ty = y >> shift;
2447
+ const targetWidth = this.config.targetWidth;
2448
+ const targetHeight = this.config.targetHeight;
2449
+ if (x < 0 || x >= targetWidth || y < 0 || y >= targetHeight) {
2450
+ return null;
2451
+ }
2452
+ const tx = x * this.config.invTileSize | 0;
2453
+ const ty = y * this.config.invTileSize | 0;
2421
2454
  const id = ty * columns + tx;
2422
2455
  let tile = this.lookup[id];
2423
2456
  let added = false;
@@ -2444,12 +2477,21 @@ var PixelAccumulator = class {
2444
2477
  * @param h pixel height
2445
2478
  */
2446
2479
  storeRegionBeforeState(x, y, w, h) {
2447
- const shift = this.config.tileShift;
2448
2480
  const columns = this.config.targetColumns;
2449
- const startX = x >> shift;
2450
- const startY = y >> shift;
2451
- const endX = x + w - 1 >> shift;
2452
- const endY = y + h - 1 >> shift;
2481
+ const targetWidth = this.config.targetWidth;
2482
+ const targetHeight = this.config.targetHeight;
2483
+ const invTileSize = this.config.invTileSize;
2484
+ const clipX1 = Math.max(0, x);
2485
+ const clipY1 = Math.max(0, y);
2486
+ const clipX2 = Math.min(targetWidth - 1, x + w - 1);
2487
+ const clipY2 = Math.min(targetHeight - 1, y + h - 1);
2488
+ if (clipX2 < clipX1 || clipY2 < clipY1) {
2489
+ return null;
2490
+ }
2491
+ const startX = clipX1 * invTileSize | 0;
2492
+ const startY = clipY1 * invTileSize | 0;
2493
+ const endX = clipX2 * invTileSize | 0;
2494
+ const endY = clipY2 * invTileSize | 0;
2453
2495
  const startIndex = this.beforeTiles.length;
2454
2496
  for (let ty = startY; ty <= endY; ty++) {
2455
2497
  for (let tx = startX; tx <= endX; tx++) {
@@ -2566,31 +2608,6 @@ var PixelAccumulator = class {
2566
2608
  }
2567
2609
  };
2568
2610
 
2569
- // src/History/PixelEngineConfig.ts
2570
- var PixelEngineConfig = class {
2571
- tileSize;
2572
- // pixelX = tileX << tileShift
2573
- // pixelY = tileY << tileShift
2574
- tileShift;
2575
- tileMask;
2576
- tileArea;
2577
- target;
2578
- targetColumns = 0;
2579
- targetRows = 0;
2580
- constructor(tileSize, target) {
2581
- if ((tileSize & tileSize - 1) !== 0) {
2582
- throw new Error("tileSize must be a power of 2");
2583
- }
2584
- this.tileSize = tileSize;
2585
- this.tileShift = 31 - Math.clz32(tileSize);
2586
- this.tileMask = tileSize - 1;
2587
- this.tileArea = tileSize * tileSize;
2588
- this.target = target;
2589
- this.targetColumns = target.w + this.tileMask >> this.tileShift;
2590
- this.targetRows = target.h + this.tileMask >> this.tileShift;
2591
- }
2592
- };
2593
-
2594
2611
  // src/PixelData/applyAlphaMaskToPixelData.ts
2595
2612
  function applyAlphaMaskToPixelData(target, mask, opts) {
2596
2613
  const targetX = opts?.x ?? 0;
@@ -2784,6 +2801,8 @@ function makePixelTile(id, tx, ty, tileSize, tileArea) {
2784
2801
  id,
2785
2802
  tx,
2786
2803
  ty,
2804
+ x: tx * tileSize,
2805
+ y: ty * tileSize,
2787
2806
  w: tileSize,
2788
2807
  h: tileSize,
2789
2808
  data: data32,
@@ -2793,25 +2812,28 @@ function makePixelTile(id, tx, ty, tileSize, tileArea) {
2793
2812
 
2794
2813
  // src/Tile/TilePool.ts
2795
2814
  var TilePool = class {
2796
- constructor(config, tileFactory) {
2815
+ constructor(tileSize, tileFactory) {
2816
+ this.tileSize = tileSize;
2797
2817
  this.tileFactory = tileFactory;
2798
2818
  this.pool = [];
2799
- this.tileSize = config.tileSize;
2800
- this.tileArea = config.tileArea;
2819
+ this.tileSize = tileSize;
2820
+ this.tileArea = tileSize * tileSize;
2801
2821
  }
2802
2822
  pool;
2803
- tileSize;
2804
2823
  tileArea;
2805
2824
  getTile(id, tx, ty) {
2806
2825
  let tile = this.pool.pop();
2826
+ const tileSize = this.tileSize;
2807
2827
  if (tile) {
2808
2828
  tile.id = id;
2809
2829
  tile.tx = tx;
2810
2830
  tile.ty = ty;
2831
+ tile.x = tx * tileSize;
2832
+ tile.y = ty * tileSize;
2811
2833
  tile.data.fill(0);
2812
2834
  return tile;
2813
2835
  }
2814
- return this.tileFactory(id, tx, ty, this.tileSize, this.tileArea);
2836
+ return this.tileFactory(id, tx, ty, tileSize, this.tileArea);
2815
2837
  }
2816
2838
  releaseTile(tile) {
2817
2839
  this.pool.push(tile);
@@ -2828,6 +2850,25 @@ var TilePool = class {
2828
2850
  }
2829
2851
  };
2830
2852
 
2853
+ // src/Tile/TileTargetConfig.ts
2854
+ function makeTileTargetConfig(tileSize, target) {
2855
+ return {
2856
+ target,
2857
+ ...makeTileTargetMeta(tileSize, target)
2858
+ };
2859
+ }
2860
+ function makeTileTargetMeta(tileSize, target) {
2861
+ return {
2862
+ targetWidth: target.w,
2863
+ targetHeight: target.h,
2864
+ tileSize,
2865
+ invTileSize: 1 / tileSize,
2866
+ tileArea: tileSize * tileSize,
2867
+ targetColumns: Math.ceil(target.w / tileSize),
2868
+ targetRows: Math.ceil(target.h / tileSize)
2869
+ };
2870
+ }
2871
+
2831
2872
  // src/History/PixelWriter.ts
2832
2873
  var PixelWriter = class {
2833
2874
  historyManager;
@@ -2840,10 +2881,10 @@ var PixelWriter = class {
2840
2881
  constructor(target, mutatorFactory, options) {
2841
2882
  const tileSize = options?.tileSize ?? 256;
2842
2883
  const maxHistorySteps = options?.maxHistorySteps ?? 50;
2843
- this.config = new PixelEngineConfig(tileSize, target);
2884
+ this.config = makeTileTargetConfig(tileSize, target);
2844
2885
  this.historyManager = options?.historyManager ?? new HistoryManager(maxHistorySteps);
2845
2886
  this.historyActionFactory = options?.historyActionFactory ?? makeHistoryAction;
2846
- this.pixelTilePool = options?.pixelTilePool ?? new TilePool(this.config, makePixelTile);
2887
+ this.pixelTilePool = options?.pixelTilePool ?? new TilePool(this.config.tileSize, makePixelTile);
2847
2888
  this.accumulator = options?.accumulator ?? new PixelAccumulator(this.config, this.pixelTilePool);
2848
2889
  this.mutator = mutatorFactory(this);
2849
2890
  }
@@ -2920,6 +2961,7 @@ var mutatorApplyAlphaMask = ((writer, deps = defaults) => {
2920
2961
  const w = opts?.w ?? target.w;
2921
2962
  const h = opts?.h ?? target.h;
2922
2963
  const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
2964
+ if (!didChange) return false;
2923
2965
  return didChange(applyAlphaMaskToPixelData2(target, mask, opts));
2924
2966
  }
2925
2967
  };
@@ -3022,7 +3064,12 @@ var mutatorApplyBinaryMask = ((writer, deps = defaults2) => {
3022
3064
  const w = opts?.w ?? target.w;
3023
3065
  const h = opts?.h ?? target.h;
3024
3066
  const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
3025
- return didChange(applyBinaryMaskToPixelData2(target, mask, opts));
3067
+ if (!didChange) return false;
3068
+ const b = applyBinaryMaskToPixelData2(target, mask, opts);
3069
+ console.log({
3070
+ b
3071
+ });
3072
+ return didChange(b);
3026
3073
  }
3027
3074
  };
3028
3075
  });
@@ -3045,6 +3092,7 @@ var mutatorApplyMask = ((writer, deps = defaults3) => {
3045
3092
  const w = opts?.w ?? target.w;
3046
3093
  const h = opts?.h ?? target.h;
3047
3094
  const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
3095
+ if (!didChange) return false;
3048
3096
  if (mask.type === 1 /* BINARY */) {
3049
3097
  return didChange(applyBinaryMaskToPixelData2(target, mask, opts));
3050
3098
  } else {
@@ -3189,6 +3237,7 @@ var mutatorBlendAlphaMask = ((writer, deps = defaults4) => {
3189
3237
  const w = opts?.w ?? src.w;
3190
3238
  const h = opts?.h ?? src.h;
3191
3239
  const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
3240
+ if (!didChange) return false;
3192
3241
  return didChange(blendPixelDataAlphaMask2(writer.config.target, src, mask, opts));
3193
3242
  }
3194
3243
  };
@@ -3316,6 +3365,7 @@ var mutatorBlendBinaryMask = ((writer, deps = defaults5) => {
3316
3365
  const w = opts?.w ?? src.w;
3317
3366
  const h = opts?.h ?? src.h;
3318
3367
  const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
3368
+ if (!didChange) return false;
3319
3369
  return didChange(blendPixelDataBinaryMask2(writer.config.target, src, mask, opts));
3320
3370
  }
3321
3371
  };
@@ -3390,6 +3440,7 @@ var mutatorBlendColor = ((writer, deps = defaults6) => {
3390
3440
  const w = opts?.w ?? target.w;
3391
3441
  const h = opts?.h ?? target.h;
3392
3442
  const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
3443
+ if (!didChange) return false;
3393
3444
  return didChange(blendColorPixelData2(target, color, opts));
3394
3445
  }
3395
3446
  };
@@ -3502,6 +3553,7 @@ var mutatorBlendColorPaintAlphaMask = ((writer, deps = defaults7) => {
3502
3553
  const tx = x + mask.centerOffsetX;
3503
3554
  const ty = y + mask.centerOffsetY;
3504
3555
  const didChange = writer.accumulator.storeRegionBeforeState(tx, ty, mask.w, mask.h);
3556
+ if (!didChange) return false;
3505
3557
  OPTS.x = tx;
3506
3558
  OPTS.y = ty;
3507
3559
  OPTS.alpha = alpha;
@@ -3598,6 +3650,7 @@ var mutatorBlendColorPaintBinaryMask = ((writer, deps = defaults8) => {
3598
3650
  const tx = x + mask.centerOffsetX;
3599
3651
  const ty = y + mask.centerOffsetY;
3600
3652
  const didChange = writer.accumulator.storeRegionBeforeState(tx, ty, mask.w, mask.h);
3653
+ if (!didChange) return false;
3601
3654
  OPTS.x = tx;
3602
3655
  OPTS.y = ty;
3603
3656
  OPTS.alpha = alpha;
@@ -3610,33 +3663,44 @@ var mutatorBlendColorPaintBinaryMask = ((writer, deps = defaults8) => {
3610
3663
  // src/History/PixelMutator/mutatorBlendColorPaintMask.ts
3611
3664
  var defaults9 = {
3612
3665
  blendColorPixelDataAlphaMask,
3613
- blendColorPixelDataBinaryMask
3666
+ blendColorPixelDataBinaryMask,
3667
+ blendColorPixelData
3614
3668
  };
3615
3669
  var mutatorBlendColorPaintMask = ((writer, deps = defaults9) => {
3616
3670
  const {
3617
3671
  blendColorPixelDataBinaryMask: blendColorPixelDataBinaryMask2 = defaults9.blendColorPixelDataBinaryMask,
3618
- blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults9.blendColorPixelDataAlphaMask
3672
+ blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults9.blendColorPixelDataAlphaMask,
3673
+ blendColorPixelData: blendColorPixelData2 = defaults9.blendColorPixelData
3619
3674
  } = deps;
3620
3675
  const OPTS = {
3621
3676
  x: 0,
3622
3677
  y: 0,
3623
3678
  blendFn: sourceOverPerfect,
3624
- alpha: 255
3679
+ alpha: 255,
3680
+ w: void 0,
3681
+ h: void 0
3625
3682
  };
3626
3683
  return {
3627
3684
  blendColorPaintMask(color, mask, x, y, alpha = 255, blendFn = sourceOverPerfect) {
3628
3685
  const tx = x + mask.centerOffsetX;
3629
3686
  const ty = y + mask.centerOffsetY;
3630
3687
  const didChange = writer.accumulator.storeRegionBeforeState(tx, ty, mask.w, mask.h);
3688
+ if (!didChange) return false;
3631
3689
  OPTS.x = tx;
3632
3690
  OPTS.y = ty;
3633
3691
  OPTS.alpha = alpha;
3634
3692
  OPTS.blendFn = blendFn;
3635
- if (mask.type === 1 /* BINARY */) {
3636
- return didChange(blendColorPixelDataBinaryMask2(writer.config.target, color, mask, OPTS));
3637
- } else {
3693
+ OPTS.w = void 0;
3694
+ OPTS.h = void 0;
3695
+ if (mask.data) {
3696
+ if (mask.type === 1 /* BINARY */) {
3697
+ return didChange(blendColorPixelDataBinaryMask2(writer.config.target, color, mask, OPTS));
3698
+ }
3638
3699
  return didChange(blendColorPixelDataAlphaMask2(writer.config.target, color, mask, OPTS));
3639
3700
  }
3701
+ OPTS.w = mask.w;
3702
+ OPTS.h = mask.h;
3703
+ return didChange(blendColorPixelData2(writer.config.target, color, OPTS));
3640
3704
  }
3641
3705
  };
3642
3706
  });
@@ -3669,6 +3733,7 @@ var mutatorBlendColorPaintRect = ((writer, deps = defaults10) => {
3669
3733
  OPTS.blendFn = blendFn;
3670
3734
  OPTS.alpha = alpha;
3671
3735
  const didChange = writer.accumulator.storeRegionBeforeState(topLeftX, topLeftY, brushWidth, brushHeight);
3736
+ if (!didChange) return false;
3672
3737
  return didChange(blendColorPixelData2(target, color, OPTS));
3673
3738
  }
3674
3739
  };
@@ -3691,6 +3756,7 @@ var mutatorBlendMask = ((writer, deps = defaults11) => {
3691
3756
  const w = opts?.w ?? src.w;
3692
3757
  const h = opts?.h ?? src.h;
3693
3758
  const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
3759
+ if (!didChange) return false;
3694
3760
  if (mask.type === 1 /* BINARY */) {
3695
3761
  return didChange(blendPixelDataBinaryMask2(writer.config.target, src, mask, opts));
3696
3762
  } else {
@@ -3737,6 +3803,7 @@ var mutatorBlendPixel = ((writer, deps = defaults12) => {
3737
3803
  return {
3738
3804
  blendPixel(x, y, color, alpha, blendFn) {
3739
3805
  const didChange = writer.accumulator.storePixelBeforeState(x, y);
3806
+ if (!didChange) return false;
3740
3807
  return didChange(blendPixel2(writer.config.target, x, y, color, alpha, blendFn));
3741
3808
  }
3742
3809
  };
@@ -3844,6 +3911,7 @@ var mutatorBlendPixelData = ((writer, deps = defaults13) => {
3844
3911
  const w = opts?.w ?? src.w;
3845
3912
  const h = opts?.h ?? src.h;
3846
3913
  const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
3914
+ if (!didChange) return false;
3847
3915
  return didChange(blendPixelData2(writer.config.target, src, opts));
3848
3916
  }
3849
3917
  };
@@ -3857,16 +3925,16 @@ function fillPixelData(dst, color, _x, _y, _w, _h) {
3857
3925
  let y;
3858
3926
  let w;
3859
3927
  let h;
3860
- if (typeof _x === "object") {
3861
- x = _x.x ?? 0;
3862
- y = _x.y ?? 0;
3863
- w = _x.w ?? dstW;
3864
- h = _x.h ?? dstH;
3865
- } else if (typeof _x === "number") {
3928
+ if (typeof _x === "number") {
3866
3929
  x = _x;
3867
3930
  y = _y;
3868
3931
  w = _w;
3869
3932
  h = _h;
3933
+ } else if (typeof _x === "object") {
3934
+ x = _x.x ?? 0;
3935
+ y = _x.y ?? 0;
3936
+ w = _x.w ?? dstW;
3937
+ h = _x.h ?? dstH;
3870
3938
  } else {
3871
3939
  x = 0;
3872
3940
  y = 0;
@@ -3931,6 +3999,7 @@ var mutatorClear = ((writer, deps = defaults14) => {
3931
3999
  const w = rect?.w ?? target.w;
3932
4000
  const h = rect?.h ?? target.h;
3933
4001
  const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
4002
+ if (!didChange) return false;
3934
4003
  return didChange(fillPixelData2(target, 0, x, y, w, h));
3935
4004
  }
3936
4005
  };
@@ -3944,24 +4013,37 @@ var mutatorFill = ((writer, deps = defaults15) => {
3944
4013
  const {
3945
4014
  fillPixelData: fillPixelData2 = defaults15.fillPixelData
3946
4015
  } = deps;
3947
- return {
3948
- fill(color, x = 0, y = 0, w = writer.config.target.w, h = writer.config.target.h) {
3949
- const target = writer.config.target;
3950
- const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
3951
- return didChange(fillPixelData2(target, color, x, y, w, h));
4016
+ const config = writer.config;
4017
+ function fill(color, _x, _y, _w, _h) {
4018
+ const target = config.target;
4019
+ const dstW = target.w;
4020
+ const dstH = target.h;
4021
+ let x;
4022
+ let y;
4023
+ let w;
4024
+ let h;
4025
+ if (typeof _x === "number") {
4026
+ x = _x;
4027
+ y = _y;
4028
+ w = _w;
4029
+ h = _h;
4030
+ } else if (typeof _x === "object") {
4031
+ x = _x.x ?? 0;
4032
+ y = _x.y ?? 0;
4033
+ w = _x.w ?? dstW;
4034
+ h = _x.h ?? dstH;
4035
+ } else {
4036
+ x = 0;
4037
+ y = 0;
4038
+ w = dstW;
4039
+ h = dstH;
3952
4040
  }
3953
- };
3954
- });
3955
- var mutatorFillRect = ((writer, deps = defaults15) => {
3956
- const {
3957
- fillPixelData: fillPixelData2 = defaults15.fillPixelData
3958
- } = deps;
4041
+ const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
4042
+ if (!didChange) return false;
4043
+ return didChange(fillPixelData2(target, color, x, y, w, h));
4044
+ }
3959
4045
  return {
3960
- fillRect(color, rect) {
3961
- const target = writer.config.target;
3962
- const didChange = writer.accumulator.storeRegionBeforeState(rect.x, rect.y, rect.w, rect.h);
3963
- return didChange(fillPixelData2(target, color, rect.x, rect.y, rect.w, rect.h));
3964
- }
4046
+ fill
3965
4047
  };
3966
4048
  });
3967
4049
 
@@ -4023,6 +4105,7 @@ var mutatorFillBinaryMask = ((writer, deps = defaults16) => {
4023
4105
  return {
4024
4106
  fillBinaryMask(color, mask, x = 0, y = 0) {
4025
4107
  const didChange = writer.accumulator.storeRegionBeforeState(x, y, mask.w, mask.h);
4108
+ if (!didChange) return false;
4026
4109
  return didChange(fillPixelDataBinaryMask2(writer.config.target, color, mask, x, y));
4027
4110
  }
4028
4111
  };
@@ -4107,7 +4190,8 @@ var mutatorInvert = ((writer, deps = defaults17) => {
4107
4190
  const w = opts?.w ?? target.w;
4108
4191
  const h = opts?.h ?? target.h;
4109
4192
  const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
4110
- return didChange(invertPixelData2(target, opts));
4193
+ if (!didChange) return false;
4194
+ return didChange?.(invertPixelData2(target, opts));
4111
4195
  }
4112
4196
  };
4113
4197
  });
@@ -4132,7 +4216,6 @@ function makeFullPixelMutator(writer) {
4132
4216
  ...mutatorClear(writer),
4133
4217
  ...mutatorFill(writer),
4134
4218
  ...mutatorFillBinaryMask(writer),
4135
- ...mutatorFillRect(writer),
4136
4219
  ...mutatorInvert(writer)
4137
4220
  };
4138
4221
  }
@@ -5306,26 +5389,55 @@ function trimRectBounds(x, y, w, h, targetWidth, targetHeight, out) {
5306
5389
  return res;
5307
5390
  }
5308
5391
 
5392
+ // src/Tile/MaskTile.ts
5393
+ var makeAlphaMaskTile = (id, tx, ty, tileSize, tileArea) => {
5394
+ return {
5395
+ tileType: 1 /* MASK */,
5396
+ type: 0 /* ALPHA */,
5397
+ data: new Uint8Array(tileArea),
5398
+ w: tileSize,
5399
+ h: tileSize,
5400
+ x: tx * tileSize,
5401
+ y: ty * tileSize,
5402
+ id,
5403
+ tx,
5404
+ ty
5405
+ };
5406
+ };
5407
+ var makeBinaryMaskTile = (id, tx, ty, tileSize, tileArea) => {
5408
+ return {
5409
+ tileType: 1 /* MASK */,
5410
+ type: 1 /* BINARY */,
5411
+ data: new Uint8Array(tileArea),
5412
+ w: tileSize,
5413
+ h: tileSize,
5414
+ x: tx * tileSize,
5415
+ y: ty * tileSize,
5416
+ id,
5417
+ tx,
5418
+ ty
5419
+ };
5420
+ };
5421
+
5309
5422
  // src/Paint/eachTileInBounds.ts
5310
5423
  function eachTileInBounds(config, lookup, tilePool, bounds, callback) {
5311
5424
  const {
5312
- tileShift,
5313
- targetColumns,
5314
5425
  targetRows,
5426
+ targetColumns,
5315
5427
  tileSize
5316
5428
  } = config;
5317
- const x1 = Math.max(0, bounds.x >> tileShift);
5318
- const y1 = Math.max(0, bounds.y >> tileShift);
5319
- const x2 = Math.min(targetColumns - 1, bounds.x + bounds.w - 1 >> tileShift);
5320
- const y2 = Math.min(targetRows - 1, bounds.y + bounds.h - 1 >> tileShift);
5429
+ const x1 = Math.max(0, Math.floor(bounds.x / tileSize));
5430
+ const y1 = Math.max(0, Math.floor(bounds.y / tileSize));
5431
+ const x2 = Math.min(targetColumns - 1, Math.floor((bounds.x + bounds.w - 1) / tileSize));
5432
+ const y2 = Math.min(targetRows - 1, Math.floor((bounds.y + bounds.h - 1) / tileSize));
5321
5433
  if (x1 > x2 || y1 > y2) return;
5322
5434
  for (let ty = y1; ty <= y2; ty++) {
5323
5435
  const rowOffset = ty * targetColumns;
5324
- const tileTop = ty << tileShift;
5436
+ const tileTop = ty * tileSize;
5325
5437
  for (let tx = x1; tx <= x2; tx++) {
5326
5438
  const id = rowOffset + tx;
5327
5439
  const tile = lookup[id] ?? (lookup[id] = tilePool.getTile(id, tx, ty));
5328
- const tileLeft = tx << tileShift;
5440
+ const tileLeft = tx * tileSize;
5329
5441
  const startX = bounds.x > tileLeft ? bounds.x : tileLeft;
5330
5442
  const startY = bounds.y > tileTop ? bounds.y : tileTop;
5331
5443
  const maskEndX = bounds.x + bounds.w;
@@ -5341,7 +5453,7 @@ function eachTileInBounds(config, lookup, tilePool, bounds, callback) {
5341
5453
 
5342
5454
  // src/Paint/AlphaMaskPaintBuffer.ts
5343
5455
  var AlphaMaskPaintBuffer = class {
5344
- constructor(config, tilePool) {
5456
+ constructor(config, tilePool = new TilePool(config.tileSize, makeAlphaMaskTile)) {
5345
5457
  this.config = config;
5346
5458
  this.tilePool = tilePool;
5347
5459
  this.lookup = [];
@@ -5361,9 +5473,9 @@ var AlphaMaskPaintBuffer = class {
5361
5473
  const lookup = this.lookup;
5362
5474
  const tilePool = this.tilePool;
5363
5475
  const config = this.config;
5364
- const tileShift = config.tileShift;
5365
- const tileMask = config.tileMask;
5366
- const target = config.target;
5476
+ const targetW = config.targetWidth;
5477
+ const targetH = config.targetHeight;
5478
+ const tileSize = config.tileSize;
5367
5479
  const {
5368
5480
  w: bW,
5369
5481
  h: bH,
@@ -5377,7 +5489,7 @@ var AlphaMaskPaintBuffer = class {
5377
5489
  this.forEachLinePointFn(x0, y0, x1, y1, (px, py) => {
5378
5490
  const topLeftX = Math.floor(px + centerOffsetX);
5379
5491
  const topLeftY = Math.floor(py + centerOffsetY);
5380
- trimRectBoundsFn(topLeftX, topLeftY, bW, bH, target.w, target.h, scratch);
5492
+ trimRectBoundsFn(topLeftX, topLeftY, bW, bH, targetW, targetH, scratch);
5381
5493
  if (scratch.w <= 0 || scratch.h <= 0) return;
5382
5494
  eachTileInBoundsFn(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
5383
5495
  const data = tile.data;
@@ -5385,8 +5497,8 @@ var AlphaMaskPaintBuffer = class {
5385
5497
  for (let i = 0; i < bH_t; i++) {
5386
5498
  const canvasY = bY + i;
5387
5499
  const bOff = (canvasY - topLeftY) * bW;
5388
- const tOff = (canvasY & tileMask) << tileShift;
5389
- const dS = tOff + (bX & tileMask);
5500
+ const tOff = (canvasY - tile.y) * tileSize;
5501
+ const dS = tOff + (bX - tile.x);
5390
5502
  for (let j = 0; j < bW_t; j++) {
5391
5503
  const canvasX = bX + j;
5392
5504
  const brushA = bD[bOff + (canvasX - topLeftX)];
@@ -5409,9 +5521,9 @@ var AlphaMaskPaintBuffer = class {
5409
5521
  const lookup = this.lookup;
5410
5522
  const tilePool = this.tilePool;
5411
5523
  const config = this.config;
5412
- const tileShift = config.tileShift;
5413
- const tileMask = config.tileMask;
5414
- const target = config.target;
5524
+ const targetW = config.targetWidth;
5525
+ const targetH = config.targetHeight;
5526
+ const tileSize = config.tileSize;
5415
5527
  const {
5416
5528
  w: bW,
5417
5529
  h: bH,
@@ -5425,7 +5537,7 @@ var AlphaMaskPaintBuffer = class {
5425
5537
  this.forEachLinePointFn(x0, y0, x1, y1, (px, py) => {
5426
5538
  const topLeftX = Math.floor(px + centerOffsetX);
5427
5539
  const topLeftY = Math.floor(py + centerOffsetY);
5428
- trimRectBoundsFn(topLeftX, topLeftY, bW, bH, target.w, target.h, scratch);
5540
+ trimRectBoundsFn(topLeftX, topLeftY, bW, bH, targetW, targetH, scratch);
5429
5541
  if (scratch.w <= 0 || scratch.h <= 0) return;
5430
5542
  eachTileInBoundsFn(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
5431
5543
  const data = tile.data;
@@ -5433,8 +5545,8 @@ var AlphaMaskPaintBuffer = class {
5433
5545
  for (let i = 0; i < bH_t; i++) {
5434
5546
  const canvasY = bY + i;
5435
5547
  const bOff = (canvasY - topLeftY) * bW;
5436
- const tOff = (canvasY & tileMask) << tileShift;
5437
- const dS = tOff + (bX & tileMask);
5548
+ const tOff = (canvasY - tile.y) * tileSize;
5549
+ const dS = tOff + (bX - tile.x);
5438
5550
  for (let j = 0; j < bW_t; j++) {
5439
5551
  const canvasX = bX + j;
5440
5552
  if (bD[bOff + (canvasX - topLeftX)]) {
@@ -5456,9 +5568,9 @@ var AlphaMaskPaintBuffer = class {
5456
5568
  const lookup = this.lookup;
5457
5569
  const tilePool = this.tilePool;
5458
5570
  const config = this.config;
5459
- const tileShift = config.tileShift;
5460
- const tileMask = config.tileMask;
5461
- const target = config.target;
5571
+ const targetW = config.targetWidth;
5572
+ const targetH = config.targetHeight;
5573
+ const tileSize = config.tileSize;
5462
5574
  const brushWidth = brush.w;
5463
5575
  const brushHeight = brush.h;
5464
5576
  const centerOffsetX = brush.centerOffsetX;
@@ -5469,15 +5581,15 @@ var AlphaMaskPaintBuffer = class {
5469
5581
  this.forEachLinePointFn(x0, y0, x1, y1, (px, py) => {
5470
5582
  const topLeftX = Math.floor(px + centerOffsetX);
5471
5583
  const topLeftY = Math.floor(py + centerOffsetY);
5472
- trimRectBoundsFn(topLeftX, topLeftY, brushWidth, brushHeight, target.w, target.h, scratch);
5584
+ trimRectBoundsFn(topLeftX, topLeftY, brushWidth, brushHeight, targetW, targetH, scratch);
5473
5585
  if (scratch.w <= 0 || scratch.h <= 0) return;
5474
5586
  eachTileInBoundsFn(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
5475
5587
  const data = tile.data;
5476
5588
  let tileChanged = false;
5477
5589
  for (let i = 0; i < bH_t; i++) {
5478
5590
  const canvasY = bY + i;
5479
- const tOff = (canvasY & tileMask) << tileShift;
5480
- const dS = tOff + (bX & tileMask);
5591
+ const tOff = (canvasY - tile.y) * tileSize;
5592
+ const dS = tOff + (bX - tile.x);
5481
5593
  for (let j = 0; j < bW_t; j++) {
5482
5594
  const idx = dS + j;
5483
5595
  if (alpha > data[idx]) {
@@ -5500,7 +5612,7 @@ var AlphaMaskPaintBuffer = class {
5500
5612
 
5501
5613
  // src/Paint/BinaryMaskPaintBuffer.ts
5502
5614
  var BinaryMaskPaintBuffer = class {
5503
- constructor(config, tilePool) {
5615
+ constructor(config, tilePool = new TilePool(config.tileSize, makeBinaryMaskTile)) {
5504
5616
  this.config = config;
5505
5617
  this.tilePool = tilePool;
5506
5618
  this.lookup = [];
@@ -5520,9 +5632,9 @@ var BinaryMaskPaintBuffer = class {
5520
5632
  const lookup = this.lookup;
5521
5633
  const tilePool = this.tilePool;
5522
5634
  const config = this.config;
5523
- const tileShift = config.tileShift;
5524
- const tileMask = config.tileMask;
5525
- const target = config.target;
5635
+ const targetW = config.targetWidth;
5636
+ const targetH = config.targetHeight;
5637
+ const tileSize = config.tileSize;
5526
5638
  const {
5527
5639
  w: bW,
5528
5640
  h: bH,
@@ -5536,7 +5648,7 @@ var BinaryMaskPaintBuffer = class {
5536
5648
  this.forEachLinePointFn(x0, y0, x1, y1, (px, py) => {
5537
5649
  const topLeftX = Math.floor(px + centerOffsetX);
5538
5650
  const topLeftY = Math.floor(py + centerOffsetY);
5539
- trimRectBoundsFn(topLeftX, topLeftY, bW, bH, target.w, target.h, scratch);
5651
+ trimRectBoundsFn(topLeftX, topLeftY, bW, bH, targetW, targetH, scratch);
5540
5652
  if (scratch.w <= 0 || scratch.h <= 0) return;
5541
5653
  eachTileInBoundsFn(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
5542
5654
  const data = tile.data;
@@ -5544,8 +5656,8 @@ var BinaryMaskPaintBuffer = class {
5544
5656
  for (let i = 0; i < bH_t; i++) {
5545
5657
  const canvasY = bY + i;
5546
5658
  const bOff = (canvasY - topLeftY) * bW;
5547
- const tOff = (canvasY & tileMask) << tileShift;
5548
- const dS = tOff + (bX & tileMask);
5659
+ const tOff = (canvasY - tile.y) * tileSize;
5660
+ const dS = tOff + (bX - tile.x);
5549
5661
  for (let j = 0; j < bW_t; j++) {
5550
5662
  const canvasX = bX + j;
5551
5663
  if (bD[bOff + (canvasX - topLeftX)]) {
@@ -5567,9 +5679,9 @@ var BinaryMaskPaintBuffer = class {
5567
5679
  const lookup = this.lookup;
5568
5680
  const tilePool = this.tilePool;
5569
5681
  const config = this.config;
5570
- const tileShift = config.tileShift;
5571
- const tileMask = config.tileMask;
5572
- const target = config.target;
5682
+ const targetW = config.targetWidth;
5683
+ const targetH = config.targetHeight;
5684
+ const tileSize = config.tileSize;
5573
5685
  const brushWidth = brush.w;
5574
5686
  const brushHeight = brush.h;
5575
5687
  const centerOffsetX = brush.centerOffsetX;
@@ -5580,15 +5692,15 @@ var BinaryMaskPaintBuffer = class {
5580
5692
  this.forEachLinePointFn(x0, y0, x1, y1, (px, py) => {
5581
5693
  const topLeftX = Math.floor(px + centerOffsetX);
5582
5694
  const topLeftY = Math.floor(py + centerOffsetY);
5583
- trimRectBoundsFn(topLeftX, topLeftY, brushWidth, brushHeight, target.w, target.h, scratch);
5695
+ trimRectBoundsFn(topLeftX, topLeftY, brushWidth, brushHeight, targetW, targetH, scratch);
5584
5696
  if (scratch.w <= 0 || scratch.h <= 0) return;
5585
5697
  eachTileInBoundsFn(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
5586
5698
  const data = tile.data;
5587
5699
  let tileChanged = false;
5588
5700
  for (let i = 0; i < bH_t; i++) {
5589
5701
  const canvasY = bY + i;
5590
- const tOff = (canvasY & tileMask) << tileShift;
5591
- const dS = tOff + (bX & tileMask);
5702
+ const tOff = (canvasY - tile.y) * tileSize;
5703
+ const dS = tOff + (bX - tile.x);
5592
5704
  for (let j = 0; j < bW_t; j++) {
5593
5705
  const idx = dS + j;
5594
5706
  if (data[idx] === 0) {
@@ -5630,9 +5742,9 @@ var ColorPaintBuffer = class {
5630
5742
  const lookup = this.lookup;
5631
5743
  const tilePool = this.tilePool;
5632
5744
  const config = this.config;
5633
- const tileShift = config.tileShift;
5634
- const tileMask = config.tileMask;
5635
- const target = config.target;
5745
+ const tileSize = config.tileSize;
5746
+ const targetW = config.targetWidth;
5747
+ const targetH = config.targetHeight;
5636
5748
  const {
5637
5749
  w: bW,
5638
5750
  h: bH,
@@ -5645,7 +5757,7 @@ var ColorPaintBuffer = class {
5645
5757
  forEachLinePoint(x0, y0, x1, y1, (px, py) => {
5646
5758
  const topLeftX = Math.floor(px + centerOffsetX);
5647
5759
  const topLeftY = Math.floor(py + centerOffsetY);
5648
- trimRectBounds(topLeftX, topLeftY, bW, bH, target.w, target.h, scratch);
5760
+ trimRectBounds(topLeftX, topLeftY, bW, bH, targetW, targetH, scratch);
5649
5761
  if (scratch.w <= 0 || scratch.h <= 0) return;
5650
5762
  eachTileInBounds(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
5651
5763
  const d32 = tile.data;
@@ -5653,8 +5765,8 @@ var ColorPaintBuffer = class {
5653
5765
  for (let i = 0; i < bH_t; i++) {
5654
5766
  const canvasY = bY + i;
5655
5767
  const bOff = (canvasY - topLeftY) * bW;
5656
- const tOff = (canvasY & tileMask) << tileShift;
5657
- const dS = tOff + (bX & tileMask);
5768
+ const tOff = (canvasY - tile.y) * tileSize;
5769
+ const dS = tOff + (bX - tile.x);
5658
5770
  for (let j = 0; j < bW_t; j++) {
5659
5771
  const canvasX = bX + j;
5660
5772
  const brushA = bD[bOff + (canvasX - topLeftX)];
@@ -5684,9 +5796,9 @@ var ColorPaintBuffer = class {
5684
5796
  const lookup = this.lookup;
5685
5797
  const tilePool = this.tilePool;
5686
5798
  const config = this.config;
5687
- const tileShift = config.tileShift;
5688
- const tileMask = config.tileMask;
5689
- const target = config.target;
5799
+ const tileSize = config.tileSize;
5800
+ const targetW = config.targetWidth;
5801
+ const targetH = config.targetHeight;
5690
5802
  const {
5691
5803
  w: bW,
5692
5804
  h: bH,
@@ -5698,7 +5810,7 @@ var ColorPaintBuffer = class {
5698
5810
  forEachLinePoint(x0, y0, x1, y1, (px, py) => {
5699
5811
  const topLeftX = Math.floor(px + centerOffsetX);
5700
5812
  const topLeftY = Math.floor(py + centerOffsetY);
5701
- trimRectBounds(topLeftX, topLeftY, bW, bH, target.w, target.h, scratch);
5813
+ trimRectBounds(topLeftX, topLeftY, bW, bH, targetW, targetH, scratch);
5702
5814
  if (scratch.w <= 0 || scratch.h <= 0) return;
5703
5815
  eachTileInBounds(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
5704
5816
  const d32 = tile.data;
@@ -5706,8 +5818,8 @@ var ColorPaintBuffer = class {
5706
5818
  for (let i = 0; i < bH_t; i++) {
5707
5819
  const canvasY = bY + i;
5708
5820
  const bOff = (canvasY - topLeftY) * bW;
5709
- const tOff = (canvasY & tileMask) << tileShift;
5710
- const dS = tOff + (bX & tileMask);
5821
+ const tOff = (canvasY - tile.y) * tileSize;
5822
+ const dS = tOff + (bX - tile.x);
5711
5823
  for (let j = 0; j < bW_t; j++) {
5712
5824
  const canvasX = bX + j;
5713
5825
  if (bD[bOff + (canvasX - topLeftX)]) {
@@ -5731,9 +5843,9 @@ var ColorPaintBuffer = class {
5731
5843
  const lookup = this.lookup;
5732
5844
  const tilePool = this.tilePool;
5733
5845
  const config = this.config;
5734
- const tileShift = config.tileShift;
5735
- const tileMask = config.tileMask;
5736
- const target = config.target;
5846
+ const targetW = config.targetWidth;
5847
+ const targetH = config.targetHeight;
5848
+ const tileSize = config.tileSize;
5737
5849
  const brushWidth = brush.w;
5738
5850
  const brushHeight = brush.h;
5739
5851
  const centerOffsetX = brush.centerOffsetX;
@@ -5742,15 +5854,15 @@ var ColorPaintBuffer = class {
5742
5854
  forEachLinePoint(x0, y0, x1, y1, (px, py) => {
5743
5855
  const topLeftX = Math.floor(px + centerOffsetX);
5744
5856
  const topLeftY = Math.floor(py + centerOffsetY);
5745
- trimRectBounds(topLeftX, topLeftY, brushWidth, brushHeight, target.w, target.h, scratch);
5857
+ trimRectBounds(topLeftX, topLeftY, brushWidth, brushHeight, targetW, targetH, scratch);
5746
5858
  if (scratch.w <= 0 || scratch.h <= 0) return;
5747
5859
  eachTileInBounds(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
5748
5860
  const d32 = tile.data;
5749
5861
  let tileChanged = false;
5750
5862
  for (let i = 0; i < bH_t; i++) {
5751
5863
  const canvasY = bY + i;
5752
- const tOff = (canvasY & tileMask) << tileShift;
5753
- const dS = tOff + (bX & tileMask);
5864
+ const tOff = (canvasY - tile.y) * tileSize;
5865
+ const dS = tOff + (bX - tile.x);
5754
5866
  for (let j = 0; j < bW_t; j++) {
5755
5867
  const idx = dS + j;
5756
5868
  if (d32[idx] !== color) {
@@ -5782,7 +5894,6 @@ var SCRATCH_OPTS = {
5782
5894
  };
5783
5895
  function commitMaskPaintBuffer(accumulator, paintBuffer, color, alpha = 255, blendFn = sourceOverPerfect, blendColorPixelDataMaskFn) {
5784
5896
  const config = accumulator.config;
5785
- const tileShift = config.tileShift;
5786
5897
  const lookup = paintBuffer.lookup;
5787
5898
  SCRATCH_OPTS.alpha = alpha;
5788
5899
  SCRATCH_OPTS.blendFn = blendFn;
@@ -5790,10 +5901,8 @@ function commitMaskPaintBuffer(accumulator, paintBuffer, color, alpha = 255, ble
5790
5901
  const tile = lookup[i];
5791
5902
  if (tile) {
5792
5903
  const didChange = accumulator.storeTileBeforeState(tile.id, tile.tx, tile.ty);
5793
- const dx = tile.tx << tileShift;
5794
- const dy = tile.ty << tileShift;
5795
- SCRATCH_OPTS.x = dx;
5796
- SCRATCH_OPTS.y = dy;
5904
+ SCRATCH_OPTS.x = tile.x;
5905
+ SCRATCH_OPTS.y = tile.y;
5797
5906
  SCRATCH_OPTS.w = tile.w;
5798
5907
  SCRATCH_OPTS.h = tile.h;
5799
5908
  didChange(blendColorPixelDataMaskFn(config.target, color, tile, SCRATCH_OPTS));
@@ -5809,49 +5918,51 @@ function makeAlphaMaskPaintBufferCommitter(accumulator, paintBuffer) {
5809
5918
  };
5810
5919
  }
5811
5920
 
5812
- // src/Internal/_constants.ts
5813
- var DEFAULT_CANVAS_FACTORY = (w, h) => new OffscreenCanvas(w, h);
5814
-
5815
- // src/Tile/MaskTile.ts
5816
- var makeAlphaMaskTile = (id, tx, ty, tileSize, tileArea) => {
5817
- return {
5818
- tileType: 1 /* MASK */,
5819
- type: 0 /* ALPHA */,
5820
- data: new Uint8Array(tileArea),
5821
- w: tileSize,
5822
- h: tileSize,
5823
- id,
5824
- tx,
5825
- ty
5921
+ // src/PixelData/ReusablePixelData.ts
5922
+ function makeReusablePixelData() {
5923
+ const pixelData = {
5924
+ w: 0,
5925
+ h: 0,
5926
+ data: null,
5927
+ imageData: null
5826
5928
  };
5827
- };
5828
- var makeBinaryMaskTile = (id, tx, ty, tileSize, tileArea) => {
5829
- return {
5830
- tileType: 1 /* MASK */,
5831
- type: 1 /* BINARY */,
5832
- data: new Uint8Array(tileArea),
5833
- w: tileSize,
5834
- h: tileSize,
5835
- id,
5836
- tx,
5837
- ty
5929
+ return function getReusablePixelData(width, height) {
5930
+ if (pixelData.w !== width || pixelData.h !== height) {
5931
+ setPixelData(pixelData, new ImageData(width, height));
5932
+ } else {
5933
+ pixelData.data.fill(0);
5934
+ }
5935
+ return pixelData;
5838
5936
  };
5839
- };
5937
+ }
5840
5938
 
5841
5939
  // src/Paint/Render/AlphaMaskPaintBufferCanvasRenderer.ts
5842
- function makeAlphaMaskPaintBufferCanvasRenderer(paintBuffer, canvasFactory = DEFAULT_CANVAS_FACTORY) {
5843
- const config = paintBuffer.config;
5844
- const tileSize = config.tileSize;
5845
- const tileShift = config.tileShift;
5846
- const tileArea = config.tileArea;
5847
- const lookup = paintBuffer.lookup;
5848
- const canvas = canvasFactory(tileSize, tileSize);
5849
- const ctx = canvas.getContext("2d");
5850
- if (!ctx) throw new Error(CANVAS_CTX_FAILED);
5851
- ctx.imageSmoothingEnabled = false;
5852
- const bridge = makePixelData(new ImageData(tileSize, tileSize));
5853
- const view32 = bridge.data;
5854
- return function drawPaintBuffer(targetCtx, color, alpha = 255, compOperation = "source-over") {
5940
+ function makeAlphaMaskPaintBufferCanvasRenderer(paintBuffer, reusableCanvasFactory) {
5941
+ const factory = reusableCanvasFactory ?? makeReusableOffscreenCanvas;
5942
+ const getBuffer = factory();
5943
+ const getBridge = makeReusablePixelData();
5944
+ let config;
5945
+ let tileSize;
5946
+ let tileArea;
5947
+ let lookup;
5948
+ let view32;
5949
+ let bridge;
5950
+ let canvas;
5951
+ let ctx;
5952
+ setBuffer(paintBuffer);
5953
+ function setBuffer(value) {
5954
+ paintBuffer = value;
5955
+ config = paintBuffer.config;
5956
+ tileSize = config.tileSize;
5957
+ tileArea = config.tileArea;
5958
+ lookup = paintBuffer.lookup;
5959
+ bridge = getBridge(tileSize, tileSize);
5960
+ view32 = bridge.data;
5961
+ const buff = getBuffer(tileSize, tileSize);
5962
+ canvas = buff.canvas;
5963
+ ctx = buff.ctx;
5964
+ }
5965
+ function draw(targetCtx, color, alpha = 255, compOperation = "source-over") {
5855
5966
  if (alpha === 0) return;
5856
5967
  const baseSrcAlpha = color >>> 24;
5857
5968
  const colorRGB = color & 16777215;
@@ -5874,29 +5985,31 @@ function makeAlphaMaskPaintBufferCanvasRenderer(paintBuffer, canvasFactory = DEF
5874
5985
  view32[p] = (colorRGB | finalA << 24) >>> 0;
5875
5986
  }
5876
5987
  }
5877
- const dx = tile.tx << tileShift;
5878
- const dy = tile.ty << tileShift;
5879
5988
  ctx.putImageData(bridge.imageData, 0, 0);
5880
- targetCtx.drawImage(canvas, dx, dy);
5989
+ targetCtx.drawImage(canvas, tile.x, tile.y);
5881
5990
  }
5882
5991
  }
5883
5992
  targetCtx.globalAlpha = 1;
5884
5993
  targetCtx.globalCompositeOperation = "source-over";
5994
+ }
5995
+ return {
5996
+ draw,
5997
+ setBuffer
5885
5998
  };
5886
5999
  }
5887
6000
 
5888
6001
  // src/Paint/Commit/AlphaMaskPaintBufferManager.ts
5889
- function makeAlphaMaskPaintBufferManager(writer, canvasFactory = DEFAULT_CANVAS_FACTORY) {
5890
- const pool = new TilePool(writer.config, makeAlphaMaskTile);
6002
+ function makeAlphaMaskPaintBufferManager(writer, reusableCanvasFactory) {
6003
+ const pool = new TilePool(writer.config.tileSize, makeAlphaMaskTile);
5891
6004
  const buffer = new AlphaMaskPaintBuffer(writer.config, pool);
5892
- const draw = makeAlphaMaskPaintBufferCanvasRenderer(buffer, canvasFactory);
6005
+ const renderer = makeAlphaMaskPaintBufferCanvasRenderer(buffer, reusableCanvasFactory);
5893
6006
  return {
5894
6007
  clear: buffer.clear.bind(buffer),
5895
6008
  paintRect: buffer.paintRect.bind(buffer),
5896
6009
  paintAlphaMask: buffer.paintAlphaMask.bind(buffer),
5897
6010
  paintBinaryMask: buffer.paintBinaryMask.bind(buffer),
5898
6011
  commit: makeAlphaMaskPaintBufferCommitter(writer.accumulator, buffer),
5899
- draw
6012
+ renderer
5900
6013
  };
5901
6014
  }
5902
6015
 
@@ -5908,19 +6021,32 @@ function makeBinaryMaskPaintBufferCommitter(accumulator, paintBuffer) {
5908
6021
  }
5909
6022
 
5910
6023
  // src/Paint/Render/BinaryMaskPaintBufferCanvasRenderer.ts
5911
- function makeBinaryMaskPaintBufferCanvasRenderer(paintBuffer, canvasFactory = DEFAULT_CANVAS_FACTORY) {
5912
- const config = paintBuffer.config;
5913
- const tileSize = config.tileSize;
5914
- const tileShift = config.tileShift;
5915
- const tileArea = config.tileArea;
5916
- const lookup = paintBuffer.lookup;
5917
- const canvas = canvasFactory(tileSize, tileSize);
5918
- const ctx = canvas.getContext("2d");
5919
- if (!ctx) throw new Error(CANVAS_CTX_FAILED);
5920
- ctx.imageSmoothingEnabled = false;
5921
- const bridge = makePixelData(new ImageData(tileSize, tileSize));
5922
- const view32 = bridge.data;
5923
- return function drawPaintBuffer(targetCtx, color, alpha = 255, compOperation = "source-over") {
6024
+ function makeBinaryMaskPaintBufferCanvasRenderer(paintBuffer, reusableCanvasFactory) {
6025
+ const factory = reusableCanvasFactory ?? makeReusableOffscreenCanvas;
6026
+ const getBuffer = factory();
6027
+ const getBridge = makeReusablePixelData();
6028
+ let config;
6029
+ let tileSize;
6030
+ let tileArea;
6031
+ let lookup;
6032
+ let view32;
6033
+ let bridge;
6034
+ let canvas;
6035
+ let ctx;
6036
+ setBuffer(paintBuffer);
6037
+ function setBuffer(value) {
6038
+ paintBuffer = value;
6039
+ config = paintBuffer.config;
6040
+ tileSize = config.tileSize;
6041
+ tileArea = config.tileArea;
6042
+ lookup = paintBuffer.lookup;
6043
+ bridge = getBridge(tileSize, tileSize);
6044
+ view32 = bridge.data;
6045
+ const buff = getBuffer(tileSize, tileSize);
6046
+ canvas = buff.canvas;
6047
+ ctx = buff.ctx;
6048
+ }
6049
+ function draw(targetCtx, color, alpha = 255, compOperation = "source-over") {
5924
6050
  if (alpha === 0) return;
5925
6051
  const baseSrcAlpha = color >>> 24;
5926
6052
  if (baseSrcAlpha === 0) return;
@@ -5936,28 +6062,30 @@ function makeBinaryMaskPaintBufferCanvasRenderer(paintBuffer, canvasFactory = DE
5936
6062
  view32[p] = color;
5937
6063
  }
5938
6064
  }
5939
- const dx = tile.tx << tileShift;
5940
- const dy = tile.ty << tileShift;
5941
6065
  ctx.putImageData(bridge.imageData, 0, 0);
5942
- targetCtx.drawImage(canvas, dx, dy);
6066
+ targetCtx.drawImage(canvas, tile.x, tile.y);
5943
6067
  }
5944
6068
  }
5945
6069
  targetCtx.globalAlpha = 1;
5946
6070
  targetCtx.globalCompositeOperation = "source-over";
6071
+ }
6072
+ return {
6073
+ draw,
6074
+ setBuffer
5947
6075
  };
5948
6076
  }
5949
6077
 
5950
6078
  // src/Paint/Commit/BinaryMaskPaintBufferManager.ts
5951
- function makeBinaryMaskPaintBufferManager(writer, canvasFactory = DEFAULT_CANVAS_FACTORY) {
5952
- const pool = new TilePool(writer.config, makeBinaryMaskTile);
6079
+ function makeBinaryMaskPaintBufferManager(writer, reusableCanvasFactory) {
6080
+ const pool = new TilePool(writer.config.tileSize, makeBinaryMaskTile);
5953
6081
  const buffer = new BinaryMaskPaintBuffer(writer.config, pool);
5954
- const draw = makeBinaryMaskPaintBufferCanvasRenderer(buffer, canvasFactory);
6082
+ const renderer = makeBinaryMaskPaintBufferCanvasRenderer(buffer, reusableCanvasFactory);
5955
6083
  return {
5956
6084
  clear: buffer.clear.bind(buffer),
5957
6085
  paintRect: buffer.paintRect.bind(buffer),
5958
6086
  paintBinaryMask: buffer.paintBinaryMask.bind(buffer),
5959
6087
  commit: makeBinaryMaskPaintBufferCommitter(writer.accumulator, buffer),
5960
- draw
6088
+ renderer
5961
6089
  };
5962
6090
  }
5963
6091
 
@@ -5972,7 +6100,6 @@ var SCRATCH_OPTS2 = {
5972
6100
  };
5973
6101
  function commitColorPaintBuffer(accumulator, paintBuffer, alpha = 255, blendFn = sourceOverPerfect, blendPixelDataFn = blendPixelData) {
5974
6102
  const config = accumulator.config;
5975
- const tileShift = config.tileShift;
5976
6103
  const lookup = paintBuffer.lookup;
5977
6104
  SCRATCH_OPTS2.alpha = alpha;
5978
6105
  SCRATCH_OPTS2.blendFn = blendFn;
@@ -5980,10 +6107,8 @@ function commitColorPaintBuffer(accumulator, paintBuffer, alpha = 255, blendFn =
5980
6107
  const tile = lookup[i];
5981
6108
  if (tile) {
5982
6109
  const didChange = accumulator.storeTileBeforeState(tile.id, tile.tx, tile.ty);
5983
- const dx = tile.tx << tileShift;
5984
- const dy = tile.ty << tileShift;
5985
- SCRATCH_OPTS2.x = dx;
5986
- SCRATCH_OPTS2.y = dy;
6110
+ SCRATCH_OPTS2.x = tile.x;
6111
+ SCRATCH_OPTS2.y = tile.y;
5987
6112
  SCRATCH_OPTS2.w = tile.w;
5988
6113
  SCRATCH_OPTS2.h = tile.h;
5989
6114
  didChange(blendPixelDataFn(config.target, tile, SCRATCH_OPTS2));
@@ -6000,44 +6125,47 @@ function makeColorPaintBufferCommitter(accumulator, paintBuffer) {
6000
6125
  }
6001
6126
 
6002
6127
  // src/Paint/Render/ColorPaintBufferCanvasRenderer.ts
6003
- function makeColorPaintBufferCanvasRenderer(paintBuffer, canvasFactory = DEFAULT_CANVAS_FACTORY) {
6004
- const config = paintBuffer.config;
6005
- const tileSize = config.tileSize;
6006
- const tileShift = config.tileShift;
6007
- const lookup = paintBuffer.lookup;
6008
- const canvas = canvasFactory(tileSize, tileSize);
6009
- const ctx = canvas.getContext("2d");
6010
- if (!ctx) throw new Error(CANVAS_CTX_FAILED);
6011
- ctx.imageSmoothingEnabled = false;
6012
- return function drawPaintBuffer(targetCtx, alpha = 255, compOperation = "source-over") {
6128
+ function makeColorPaintBufferCanvasRenderer(paintBuffer, reusableCanvasFactory) {
6129
+ const factory = reusableCanvasFactory ?? makeReusableOffscreenCanvas;
6130
+ const getBuffer = factory();
6131
+ function draw(targetCtx, alpha = 255, compOperation = "source-over") {
6132
+ const buff = getBuffer(paintBuffer.config.tileSize, paintBuffer.config.tileSize);
6133
+ const lookup = paintBuffer.lookup;
6134
+ const length = lookup.length;
6135
+ const ctx = buff.ctx;
6136
+ const canvas = buff.canvas;
6013
6137
  targetCtx.globalAlpha = alpha / 255;
6014
6138
  targetCtx.globalCompositeOperation = compOperation;
6015
- for (let i = 0; i < lookup.length; i++) {
6139
+ for (let i = 0; i < length; i++) {
6016
6140
  const tile = lookup[i];
6017
6141
  if (tile) {
6018
- const dx = tile.tx << tileShift;
6019
- const dy = tile.ty << tileShift;
6020
6142
  ctx.putImageData(tile.imageData, 0, 0);
6021
- targetCtx.drawImage(canvas, dx, dy);
6143
+ targetCtx.drawImage(canvas, tile.x, tile.y);
6022
6144
  }
6023
6145
  }
6024
6146
  targetCtx.globalAlpha = 1;
6025
6147
  targetCtx.globalCompositeOperation = "source-over";
6148
+ }
6149
+ return {
6150
+ draw,
6151
+ setBuffer(value) {
6152
+ paintBuffer = value;
6153
+ }
6026
6154
  };
6027
6155
  }
6028
6156
 
6029
6157
  // src/Paint/Commit/ColorPaintBufferManager.ts
6030
- function makeColorPaintBufferManager(writer, canvasFactory = DEFAULT_CANVAS_FACTORY) {
6031
- const pool = new TilePool(writer.config, makePixelTile);
6158
+ function makeColorPaintBufferManager(writer, reusableCanvasFactory) {
6159
+ const pool = new TilePool(writer.config.tileSize, makePixelTile);
6032
6160
  const buffer = new ColorPaintBuffer(writer.config, pool);
6033
- const draw = makeColorPaintBufferCanvasRenderer(buffer, canvasFactory);
6161
+ const renderer = makeColorPaintBufferCanvasRenderer(buffer, reusableCanvasFactory);
6034
6162
  return {
6035
6163
  clear: buffer.clear.bind(buffer),
6036
6164
  paintRect: buffer.paintRect.bind(buffer),
6037
6165
  paintAlphaMask: buffer.paintAlphaMask.bind(buffer),
6038
6166
  paintBinaryMask: buffer.paintBinaryMask.bind(buffer),
6039
6167
  commit: makeColorPaintBufferCommitter(writer.accumulator, buffer),
6040
- draw
6168
+ renderer
6041
6169
  };
6042
6170
  }
6043
6171
 
@@ -6173,24 +6301,6 @@ function makePaintRect(w, h) {
6173
6301
  };
6174
6302
  }
6175
6303
 
6176
- // src/PixelData/ReusablePixelData.ts
6177
- function makeReusablePixelData() {
6178
- const pixelData = {
6179
- w: 0,
6180
- h: 0,
6181
- data: null,
6182
- imageData: null
6183
- };
6184
- return function getReusablePixelData(width, height) {
6185
- if (pixelData.w !== width || pixelData.h !== height) {
6186
- setPixelData(pixelData, new ImageData(width, height));
6187
- } else {
6188
- pixelData.data.fill(0);
6189
- }
6190
- return pixelData;
6191
- };
6192
- }
6193
-
6194
6304
  // src/Paint/Render/PaintCursorRenderer.ts
6195
6305
  function makePaintCursorRenderer(reusableCanvasFactory) {
6196
6306
  const factory = reusableCanvasFactory ?? makeReusableOffscreenCanvas;
@@ -6266,6 +6376,9 @@ function makePaintCursorRenderer(reusableCanvasFactory) {
6266
6376
  const dy = centerY * _scale + currentBrush.centerOffsetY * _scale - 1;
6267
6377
  drawCtx.drawImage(canvas, Math.floor(dx), Math.floor(dy));
6268
6378
  }
6379
+ function drawRaw(drawCtx, x, y) {
6380
+ drawCtx.drawImage(canvas, Math.floor(x * _scale), Math.floor(y * _scale));
6381
+ }
6269
6382
  function getSettings() {
6270
6383
  return {
6271
6384
  color: _color,
@@ -6278,6 +6391,7 @@ function makePaintCursorRenderer(reusableCanvasFactory) {
6278
6391
  getBounds,
6279
6392
  getBoundsScaled: getOutlineBoundsScaled,
6280
6393
  draw,
6394
+ drawRaw,
6281
6395
  getSettings
6282
6396
  };
6283
6397
  }
@@ -6339,20 +6453,29 @@ var SCRATCH_OPTS5 = {
6339
6453
  x: 0,
6340
6454
  y: 0,
6341
6455
  alpha: 255,
6342
- blendFn: sourceOverPerfect
6456
+ blendFn: sourceOverPerfect,
6457
+ w: void 0,
6458
+ h: void 0
6343
6459
  };
6344
- function blendColorPixelDataPaintMask(dst, color, mask, x, y, alpha = 255, blendFn = sourceOverPerfect) {
6460
+ function blendColorPixelDataPaintMask(target, color, mask, x, y, alpha = 255, blendFn = sourceOverPerfect) {
6345
6461
  const tx = x + mask.centerOffsetX;
6346
6462
  const ty = y + mask.centerOffsetY;
6347
6463
  SCRATCH_OPTS5.x = tx;
6348
6464
  SCRATCH_OPTS5.y = ty;
6349
6465
  SCRATCH_OPTS5.alpha = alpha;
6350
6466
  SCRATCH_OPTS5.blendFn = blendFn;
6351
- if (mask.type === 1 /* BINARY */) {
6352
- return blendColorPixelDataBinaryMask(dst, color, mask, SCRATCH_OPTS5);
6353
- } else {
6354
- return blendColorPixelDataAlphaMask(dst, color, mask, SCRATCH_OPTS5);
6467
+ SCRATCH_OPTS5.w = void 0;
6468
+ SCRATCH_OPTS5.h = void 0;
6469
+ if (mask.data) {
6470
+ if (mask.type === 1 /* BINARY */) {
6471
+ return blendColorPixelDataBinaryMask(target, color, mask, SCRATCH_OPTS5);
6472
+ } else {
6473
+ return blendColorPixelDataAlphaMask(target, color, mask, SCRATCH_OPTS5);
6474
+ }
6355
6475
  }
6476
+ SCRATCH_OPTS5.w = mask.w;
6477
+ SCRATCH_OPTS5.h = mask.h;
6478
+ return blendColorPixelData(target, color, SCRATCH_OPTS5);
6356
6479
  }
6357
6480
 
6358
6481
  // src/PixelData/blendPixelDataMask.ts
@@ -6372,13 +6495,12 @@ var SCRATCH_OPTS6 = {
6372
6495
  blendFn: void 0
6373
6496
  };
6374
6497
  function blendPixelDataPaintBuffer(target, paintBuffer, alpha = 255, blendFn, blendPixelDataFn = blendPixelData) {
6375
- const tileShift = paintBuffer.config.tileShift;
6376
6498
  const lookup = paintBuffer.lookup;
6377
6499
  for (let i = 0; i < lookup.length; i++) {
6378
6500
  const tile = lookup[i];
6379
6501
  if (tile) {
6380
- const x = tile.tx << tileShift;
6381
- const y = tile.ty << tileShift;
6502
+ const x = tile.x;
6503
+ const y = tile.y;
6382
6504
  SCRATCH_OPTS6.x = x;
6383
6505
  SCRATCH_OPTS6.y = y;
6384
6506
  SCRATCH_OPTS6.alpha = alpha;
@@ -6452,6 +6574,36 @@ function copyPixelData(target) {
6452
6574
  return makePixelData(new ImageData(buffer, target.w, target.h));
6453
6575
  }
6454
6576
 
6577
+ // src/PixelData/cropPixelData.ts
6578
+ function cropPixelData(src, x, y, w, h, out) {
6579
+ const cx = Math.max(x, 0);
6580
+ const cy = Math.max(y, 0);
6581
+ const cw = Math.min(x + w, src.w) - cx;
6582
+ const ch = Math.min(y + h, src.h) - cy;
6583
+ if (cw <= 0 || ch <= 0) {
6584
+ throw new Error(`Crop [${x},${y} ${w}x${h}] does not overlap PixelData [${src.w}x${src.h}]`);
6585
+ }
6586
+ const cropped = new ImageData(cw, ch);
6587
+ let dst32;
6588
+ if (out) {
6589
+ setPixelData(out, cropped);
6590
+ dst32 = out.data;
6591
+ } else {
6592
+ dst32 = new Uint32Array(cropped.data.buffer);
6593
+ }
6594
+ for (let row = 0; row < ch; row++) {
6595
+ const srcOffset = (cy + row) * src.w + cx;
6596
+ const dstOffset = row * cw;
6597
+ dst32.set(src.data.subarray(srcOffset, srcOffset + cw), dstOffset);
6598
+ }
6599
+ return out ?? {
6600
+ data: dst32,
6601
+ imageData: cropped,
6602
+ w: cw,
6603
+ h: ch
6604
+ };
6605
+ }
6606
+
6455
6607
  // src/PixelData/extractPixelDataBuffer.ts
6456
6608
  function extractPixelDataBuffer(source, _x, _y, _w, _h) {
6457
6609
  let x;
@@ -6667,6 +6819,46 @@ function rotateSquareInPlace(pixelData) {
6667
6819
  }
6668
6820
  }
6669
6821
 
6822
+ // src/PixelData/trimPixelData.ts
6823
+ function getPixelDataTransparentTrimmedBounds(target) {
6824
+ let minX = target.w;
6825
+ let minY = target.h;
6826
+ let maxX = -1;
6827
+ let maxY = -1;
6828
+ for (let y = 0; y < target.h; y++) {
6829
+ for (let x = 0; x < target.w; x++) {
6830
+ const alpha = target.data[y * target.w + x] >>> 24;
6831
+ if (alpha !== 0) {
6832
+ if (x < minX) minX = x;
6833
+ if (x > maxX) maxX = x;
6834
+ if (y < minY) minY = y;
6835
+ if (y > maxY) maxY = y;
6836
+ }
6837
+ }
6838
+ }
6839
+ if (maxX === -1) return null;
6840
+ return {
6841
+ x: minX,
6842
+ y: minY,
6843
+ w: maxX - minX + 1,
6844
+ h: maxY - minY + 1
6845
+ };
6846
+ }
6847
+ function trimTransparentPixelData(target) {
6848
+ const r = getPixelDataTransparentTrimmedBounds(target);
6849
+ if (!r) {
6850
+ throw new Error("PixelData is fully transparent \u2014 no crop bounds found");
6851
+ }
6852
+ return cropPixelData(target, r.x, r.y, r.w, r.h);
6853
+ }
6854
+ function trimTransparentPixelDataInPlace(target) {
6855
+ const r = getPixelDataTransparentTrimmedBounds(target);
6856
+ if (!r) {
6857
+ throw new Error("PixelData is fully transparent \u2014 no crop bounds found");
6858
+ }
6859
+ cropPixelData(target, r.x, r.y, r.w, r.h, target);
6860
+ }
6861
+
6670
6862
  // src/PixelData/uInt32ArrayToPixelData.ts
6671
6863
  function uInt32ArrayToPixelData(data, width, height) {
6672
6864
  const buffer = data.buffer;
@@ -6727,14 +6919,11 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
6727
6919
 
6728
6920
  // src/PixelData/writePaintBufferToPixelData.ts
6729
6921
  function writePaintBufferToPixelData(target, paintBuffer, writePixelDataBufferFn = writePixelDataBuffer) {
6730
- const tileShift = paintBuffer.config.tileShift;
6731
6922
  const lookup = paintBuffer.lookup;
6732
6923
  for (let i = 0; i < lookup.length; i++) {
6733
6924
  const tile = lookup[i];
6734
6925
  if (tile) {
6735
- const dx = tile.tx << tileShift;
6736
- const dy = tile.ty << tileShift;
6737
- writePixelDataBufferFn(target, tile.data, dx, dy, tile.w, tile.h);
6926
+ writePixelDataBufferFn(target, tile.data, tile.x, tile.y, tile.w, tile.h);
6738
6927
  }
6739
6928
  }
6740
6929
  }
@@ -6787,7 +6976,6 @@ function writePixelData(target, source, x = 0, y = 0) {
6787
6976
  MaskType,
6788
6977
  PaintMaskOutline,
6789
6978
  PixelAccumulator,
6790
- PixelEngineConfig,
6791
6979
  PixelWriter,
6792
6980
  TilePool,
6793
6981
  TileType,
@@ -6814,6 +7002,7 @@ function writePixelData(target, source, x = 0, y = 0) {
6814
7002
  blendPixelDataPaintBuffer,
6815
7003
  clearPixelDataFast,
6816
7004
  color32ToCssRGBA,
7005
+ color32ToCssRGBAString,
6817
7006
  color32ToHex,
6818
7007
  colorBurnFast,
6819
7008
  colorBurnPerfect,
@@ -6826,6 +7015,8 @@ function writePixelData(target, source, x = 0, y = 0) {
6826
7015
  copyImageDataLike,
6827
7016
  copyMask,
6828
7017
  copyPixelData,
7018
+ cropPixelData,
7019
+ cssRGBAToColor32,
6829
7020
  darkenFast,
6830
7021
  darkenPerfect,
6831
7022
  darkerFast,
@@ -6864,6 +7055,7 @@ function writePixelData(target, source, x = 0, y = 0) {
6864
7055
  getImageDataFromClipboard,
6865
7056
  getIndexedImageColor,
6866
7057
  getIndexedImageColorCounts,
7058
+ getPixelDataTransparentTrimmedBounds,
6867
7059
  getRectsBounds,
6868
7060
  getSupportedPixelFormats,
6869
7061
  hardLightFast,
@@ -6937,6 +7129,8 @@ function writePixelData(target, source, x = 0, y = 0) {
6937
7129
  makeReusableImageData,
6938
7130
  makeReusableOffscreenCanvas,
6939
7131
  makeReusablePixelData,
7132
+ makeTileTargetConfig,
7133
+ makeTileTargetMeta,
6940
7134
  merge2BinaryMaskRects,
6941
7135
  mergeAlphaMasks,
6942
7136
  mergeBinaryMaskRects,
@@ -6959,7 +7153,6 @@ function writePixelData(target, source, x = 0, y = 0) {
6959
7153
  mutatorClear,
6960
7154
  mutatorFill,
6961
7155
  mutatorFillBinaryMask,
6962
- mutatorFillRect,
6963
7156
  mutatorInvert,
6964
7157
  overlayFast,
6965
7158
  overlayPerfect,
@@ -7003,6 +7196,8 @@ function writePixelData(target, source, x = 0, y = 0) {
7003
7196
  toBlendModeIndexAndName,
7004
7197
  trimMaskRectBounds,
7005
7198
  trimRectBounds,
7199
+ trimTransparentPixelData,
7200
+ trimTransparentPixelDataInPlace,
7006
7201
  uInt32ArrayToImageData,
7007
7202
  uInt32ArrayToImageDataLike,
7008
7203
  uInt32ArrayToPixelData,