pixel-data-js 0.25.2 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.prod.cjs +1696 -1526
- package/dist/index.prod.cjs.map +1 -1
- package/dist/index.prod.d.ts +414 -311
- package/dist/index.prod.js +1676 -1519
- package/dist/index.prod.js.map +1 -1
- package/package.json +8 -9
- package/src/Algorithm/floodFillSelection.ts +49 -80
- package/src/Canvas/PixelCanvas.ts +1 -1
- package/src/Canvas/ReusableCanvas.ts +1 -1
- package/src/History/HistoryAction.ts +6 -5
- package/src/History/PixelMutator/mutatorApplyAlphaMask.ts +8 -10
- package/src/History/PixelMutator/mutatorApplyBinaryMask.ts +8 -10
- package/src/History/PixelMutator/mutatorApplyMask.ts +39 -0
- package/src/History/PixelMutator/{mutatorBlendPixelDataAlphaMask.ts → mutatorBlendAlphaMask.ts} +9 -9
- package/src/History/PixelMutator/{mutatorBlendPixelDataBinaryMask.ts → mutatorBlendBinaryMask.ts} +9 -9
- package/src/History/PixelMutator/mutatorBlendColor.ts +8 -9
- package/src/History/PixelMutator/mutatorBlendColorPaintAlphaMask.ts +51 -0
- package/src/History/PixelMutator/mutatorBlendColorPaintBinaryMask.ts +51 -0
- package/src/History/PixelMutator/{mutatorBlendPaintMask.ts → mutatorBlendColorPaintMask.ts} +3 -3
- package/src/History/PixelMutator/mutatorBlendMask.ts +43 -0
- package/src/History/PixelMutator/mutatorBlendPaintRect.ts +55 -0
- package/src/History/PixelMutator/mutatorBlendPixel.ts +2 -2
- package/src/History/PixelMutator/mutatorBlendPixelData.ts +8 -9
- package/src/History/PixelMutator/mutatorClear.ts +13 -11
- package/src/History/PixelMutator/mutatorFill.ts +2 -2
- package/src/History/PixelMutator/mutatorFillBinaryMask.ts +3 -4
- package/src/History/PixelMutator/mutatorInvert.ts +8 -9
- package/src/History/PixelMutator.ts +20 -4
- package/src/History/PixelWriter.ts +11 -13
- package/src/Input/fileToImageData.ts +1 -1
- package/src/Internal/helpers.ts +4 -1
- package/src/Mask/applyBinaryMaskToAlphaMask.ts +8 -10
- package/src/Paint/PaintBuffer.ts +3 -3
- package/src/Paint/PaintBufferCanvasRenderer.ts +1 -1
- package/src/Paint/makePaintMask.ts +5 -5
- package/src/Paint/makeRectFalloffPaintAlphaMask.ts +3 -3
- package/src/PixelData/applyAlphaMaskToPixelData.ts +14 -16
- package/src/PixelData/applyBinaryMaskToPixelData.ts +14 -16
- package/src/PixelData/applyMaskToPixelData.ts +22 -0
- package/src/PixelData/blendColorPixelData.ts +12 -15
- package/src/PixelData/blendColorPixelDataAlphaMask.ts +16 -16
- package/src/PixelData/blendColorPixelDataBinaryMask.ts +16 -16
- package/src/PixelData/blendColorPixelDataMask.ts +16 -0
- package/src/PixelData/blendColorPixelDataPaintAlphaMask.ts +30 -0
- package/src/PixelData/blendColorPixelDataPaintBinaryMask.ts +30 -0
- package/src/PixelData/blendColorPixelDataPaintMask.ts +35 -0
- package/src/PixelData/blendPixelData.ts +14 -16
- package/src/PixelData/blendPixelDataAlphaMask.ts +17 -19
- package/src/PixelData/blendPixelDataBinaryMask.ts +17 -19
- package/src/PixelData/blendPixelDataMask.ts +16 -0
- package/src/PixelData/blendPixelDataPaintBuffer.ts +1 -1
- package/src/PixelData/{clearPixelData.ts → clearPixelDataFast.ts} +2 -2
- package/src/PixelData/fillPixelDataBinaryMask.ts +8 -22
- package/src/PixelData/fillPixelDataFast.ts +2 -2
- package/src/PixelData/invertPixelData.ts +13 -16
- package/src/_types.ts +8 -7
- package/src/index.ts +41 -31
- package/dist/index.dev.cjs +0 -5419
- package/dist/index.dev.cjs.map +0 -1
- package/dist/index.dev.js +0 -5208
- package/dist/index.dev.js.map +0 -1
- package/src/Canvas/_constants.ts +0 -2
- package/src/PixelData/PixelBuffer32.ts +0 -28
package/dist/index.prod.js
CHANGED
|
@@ -297,37 +297,22 @@ function trimMaskRectBounds(target, bounds) {
|
|
|
297
297
|
}
|
|
298
298
|
|
|
299
299
|
// src/Algorithm/floodFillSelection.ts
|
|
300
|
-
function floodFillSelection(
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
imageData = img;
|
|
313
|
-
}
|
|
314
|
-
const {
|
|
315
|
-
width,
|
|
316
|
-
height
|
|
317
|
-
} = img;
|
|
318
|
-
const limit = bounds || {
|
|
319
|
-
x: 0,
|
|
320
|
-
y: 0,
|
|
321
|
-
w: width,
|
|
322
|
-
h: height
|
|
323
|
-
};
|
|
324
|
-
const xMin = Math.max(0, limit.x);
|
|
325
|
-
const xMax = Math.min(width - 1, limit.x + limit.w - 1);
|
|
326
|
-
const yMin = Math.max(0, limit.y);
|
|
327
|
-
const yMax = Math.min(height - 1, limit.y + limit.h - 1);
|
|
300
|
+
function floodFillSelection(target, startX, startY, contiguous = true, tolerance = 0, bounds, out) {
|
|
301
|
+
const data32 = target.data32;
|
|
302
|
+
const width = target.width;
|
|
303
|
+
const height = target.height;
|
|
304
|
+
const lx = bounds?.x ?? 0;
|
|
305
|
+
const ly = bounds?.y ?? 0;
|
|
306
|
+
const lw = bounds?.w ?? width;
|
|
307
|
+
const lh = bounds?.h ?? height;
|
|
308
|
+
const xMin = Math.max(0, lx);
|
|
309
|
+
const xMax = Math.min(width - 1, lx + lw - 1);
|
|
310
|
+
const yMin = Math.max(0, ly);
|
|
311
|
+
const yMax = Math.min(height - 1, ly + lh - 1);
|
|
328
312
|
if (startX < xMin || startX > xMax || startY < yMin || startY > yMax) {
|
|
329
313
|
return null;
|
|
330
314
|
}
|
|
315
|
+
out = out ?? {};
|
|
331
316
|
const baseColor = data32[startY * width + startX];
|
|
332
317
|
let matchCount = 0;
|
|
333
318
|
const matchX = new Uint16Array(width * height);
|
|
@@ -398,42 +383,33 @@ function floodFillSelection(img, startX, startY, {
|
|
|
398
383
|
}
|
|
399
384
|
}
|
|
400
385
|
}
|
|
401
|
-
if (matchCount === 0)
|
|
402
|
-
return null;
|
|
403
|
-
}
|
|
386
|
+
if (matchCount === 0) return null;
|
|
404
387
|
const w = maxX - minX + 1;
|
|
405
388
|
const h = maxY - minY + 1;
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
const
|
|
415
|
-
const sh = selectionRect.h;
|
|
416
|
-
const finalMask = selectionRect.data;
|
|
389
|
+
out.startX = startX;
|
|
390
|
+
out.startY = startY;
|
|
391
|
+
out.x = minX;
|
|
392
|
+
out.y = minY;
|
|
393
|
+
out.w = w;
|
|
394
|
+
out.h = h;
|
|
395
|
+
out.data = new Uint8Array(w * h);
|
|
396
|
+
out.type = 1 /* BINARY */;
|
|
397
|
+
const finalMask = out.data;
|
|
417
398
|
for (let i = 0; i < matchCount; i++) {
|
|
418
|
-
const mx = matchX[i] -
|
|
419
|
-
const my = matchY[i] -
|
|
420
|
-
if (mx >= 0 && mx <
|
|
421
|
-
finalMask[my *
|
|
399
|
+
const mx = matchX[i] - minX;
|
|
400
|
+
const my = matchY[i] - minY;
|
|
401
|
+
if (mx >= 0 && mx < w && my >= 0 && my < h) {
|
|
402
|
+
finalMask[my * w + mx] = 1;
|
|
422
403
|
}
|
|
423
404
|
}
|
|
424
|
-
trimMaskRectBounds(
|
|
405
|
+
trimMaskRectBounds(out, {
|
|
425
406
|
x: 0,
|
|
426
407
|
y: 0,
|
|
427
408
|
w: width,
|
|
428
409
|
h: height
|
|
429
410
|
});
|
|
430
|
-
|
|
431
|
-
return
|
|
432
|
-
startX,
|
|
433
|
-
startY,
|
|
434
|
-
selectionRect,
|
|
435
|
-
pixels: extracted
|
|
436
|
-
};
|
|
411
|
+
out.pixels = extractImageDataBuffer(target.imageData, out.x, out.y, out.w, out.h);
|
|
412
|
+
return out;
|
|
437
413
|
}
|
|
438
414
|
|
|
439
415
|
// src/Algorithm/forEachLinePoint.ts
|
|
@@ -456,35 +432,6 @@ function forEachLinePoint(x0, y0, x1, y1, callback) {
|
|
|
456
432
|
}
|
|
457
433
|
}
|
|
458
434
|
|
|
459
|
-
// src/BlendModes/blend-modes.ts
|
|
460
|
-
var BaseBlendMode = {
|
|
461
|
-
overwrite: 0,
|
|
462
|
-
sourceOver: 1,
|
|
463
|
-
darken: 2,
|
|
464
|
-
multiply: 3,
|
|
465
|
-
colorBurn: 4,
|
|
466
|
-
linearBurn: 5,
|
|
467
|
-
darkerColor: 6,
|
|
468
|
-
lighten: 7,
|
|
469
|
-
screen: 8,
|
|
470
|
-
colorDodge: 9,
|
|
471
|
-
linearDodge: 10,
|
|
472
|
-
lighterColor: 11,
|
|
473
|
-
overlay: 12,
|
|
474
|
-
softLight: 13,
|
|
475
|
-
hardLight: 14,
|
|
476
|
-
vividLight: 15,
|
|
477
|
-
linearLight: 16,
|
|
478
|
-
pinLight: 17,
|
|
479
|
-
hardMix: 18,
|
|
480
|
-
difference: 19,
|
|
481
|
-
exclusion: 20,
|
|
482
|
-
subtract: 21,
|
|
483
|
-
divide: 22
|
|
484
|
-
};
|
|
485
|
-
var overwriteBase = (src, _dst) => src;
|
|
486
|
-
overwriteBase.isOverwrite = true;
|
|
487
|
-
|
|
488
435
|
// src/BlendModes/BlendModeRegistry.ts
|
|
489
436
|
function makeBlendModeRegistry(blendModes, initialEntries, registryName = "anonymous") {
|
|
490
437
|
const blendToName = /* @__PURE__ */ new Map();
|
|
@@ -524,6 +471,35 @@ function makeBlendModeRegistry(blendModes, initialEntries, registryName = "anony
|
|
|
524
471
|
};
|
|
525
472
|
}
|
|
526
473
|
|
|
474
|
+
// src/BlendModes/blend-modes.ts
|
|
475
|
+
var BaseBlendMode = {
|
|
476
|
+
overwrite: 0,
|
|
477
|
+
sourceOver: 1,
|
|
478
|
+
darken: 2,
|
|
479
|
+
multiply: 3,
|
|
480
|
+
colorBurn: 4,
|
|
481
|
+
linearBurn: 5,
|
|
482
|
+
darkerColor: 6,
|
|
483
|
+
lighten: 7,
|
|
484
|
+
screen: 8,
|
|
485
|
+
colorDodge: 9,
|
|
486
|
+
linearDodge: 10,
|
|
487
|
+
lighterColor: 11,
|
|
488
|
+
overlay: 12,
|
|
489
|
+
softLight: 13,
|
|
490
|
+
hardLight: 14,
|
|
491
|
+
vividLight: 15,
|
|
492
|
+
linearLight: 16,
|
|
493
|
+
pinLight: 17,
|
|
494
|
+
hardMix: 18,
|
|
495
|
+
difference: 19,
|
|
496
|
+
exclusion: 20,
|
|
497
|
+
subtract: 21,
|
|
498
|
+
divide: 22
|
|
499
|
+
};
|
|
500
|
+
var overwriteBase = (src, _dst) => src;
|
|
501
|
+
overwriteBase.isOverwrite = true;
|
|
502
|
+
|
|
527
503
|
// src/BlendModes/blend-modes-fast.ts
|
|
528
504
|
var overwriteFast = overwriteBase;
|
|
529
505
|
var sourceOverFast = (src, dst) => {
|
|
@@ -1529,28 +1505,10 @@ var getKeyByValue = (obj, value) => {
|
|
|
1529
1505
|
}
|
|
1530
1506
|
};
|
|
1531
1507
|
|
|
1532
|
-
//
|
|
1508
|
+
// support/error-strings.ts
|
|
1533
1509
|
var OFFSCREEN_CANVAS_CTX_FAILED = "Failed to create OffscreenCanvas context";
|
|
1534
1510
|
var CANVAS_CTX_FAILED = "Failed to create Canvas context";
|
|
1535
1511
|
|
|
1536
|
-
// src/Canvas/canvas-blend-modes.ts
|
|
1537
|
-
var CANVAS_COMPOSITE_MAP = {
|
|
1538
|
-
[BaseBlendMode.overwrite]: "copy",
|
|
1539
|
-
[BaseBlendMode.sourceOver]: "source-over",
|
|
1540
|
-
[BaseBlendMode.darken]: "darken",
|
|
1541
|
-
[BaseBlendMode.multiply]: "multiply",
|
|
1542
|
-
[BaseBlendMode.colorBurn]: "color-burn",
|
|
1543
|
-
[BaseBlendMode.lighten]: "lighten",
|
|
1544
|
-
[BaseBlendMode.screen]: "screen",
|
|
1545
|
-
[BaseBlendMode.colorDodge]: "color-dodge",
|
|
1546
|
-
[BaseBlendMode.linearDodge]: "lighter",
|
|
1547
|
-
[BaseBlendMode.overlay]: "overlay",
|
|
1548
|
-
[BaseBlendMode.softLight]: "soft-light",
|
|
1549
|
-
[BaseBlendMode.hardLight]: "hard-light",
|
|
1550
|
-
[BaseBlendMode.difference]: "difference",
|
|
1551
|
-
[BaseBlendMode.exclusion]: "exclusion"
|
|
1552
|
-
};
|
|
1553
|
-
|
|
1554
1512
|
// src/Canvas/ReusableCanvas.ts
|
|
1555
1513
|
function makeReusableCanvas() {
|
|
1556
1514
|
return makeReusableCanvasMeta((w, h) => {
|
|
@@ -1649,6 +1607,24 @@ function makePixelCanvas(canvas) {
|
|
|
1649
1607
|
};
|
|
1650
1608
|
}
|
|
1651
1609
|
|
|
1610
|
+
// src/Canvas/canvas-blend-modes.ts
|
|
1611
|
+
var CANVAS_COMPOSITE_MAP = {
|
|
1612
|
+
[BaseBlendMode.overwrite]: "copy",
|
|
1613
|
+
[BaseBlendMode.sourceOver]: "source-over",
|
|
1614
|
+
[BaseBlendMode.darken]: "darken",
|
|
1615
|
+
[BaseBlendMode.multiply]: "multiply",
|
|
1616
|
+
[BaseBlendMode.colorBurn]: "color-burn",
|
|
1617
|
+
[BaseBlendMode.lighten]: "lighten",
|
|
1618
|
+
[BaseBlendMode.screen]: "screen",
|
|
1619
|
+
[BaseBlendMode.colorDodge]: "color-dodge",
|
|
1620
|
+
[BaseBlendMode.linearDodge]: "lighter",
|
|
1621
|
+
[BaseBlendMode.overlay]: "overlay",
|
|
1622
|
+
[BaseBlendMode.softLight]: "soft-light",
|
|
1623
|
+
[BaseBlendMode.hardLight]: "hard-light",
|
|
1624
|
+
[BaseBlendMode.difference]: "difference",
|
|
1625
|
+
[BaseBlendMode.exclusion]: "exclusion"
|
|
1626
|
+
};
|
|
1627
|
+
|
|
1652
1628
|
// src/ImageData/imgBlobToImageData.ts
|
|
1653
1629
|
async function imgBlobToImageData(blob) {
|
|
1654
1630
|
let bitmap = null;
|
|
@@ -1733,10 +1709,9 @@ function applyPatchTiles(target, tiles, tileSize) {
|
|
|
1733
1709
|
}
|
|
1734
1710
|
|
|
1735
1711
|
// src/History/HistoryAction.ts
|
|
1736
|
-
function makeHistoryAction(
|
|
1737
|
-
const target =
|
|
1738
|
-
const tileSize =
|
|
1739
|
-
const accumulator = writer.accumulator;
|
|
1712
|
+
function makeHistoryAction(config, accumulator, patch, after, afterUndo, afterRedo, applyPatchTilesFn = applyPatchTiles) {
|
|
1713
|
+
const target = config.target;
|
|
1714
|
+
const tileSize = config.tileSize;
|
|
1740
1715
|
return {
|
|
1741
1716
|
undo: () => {
|
|
1742
1717
|
applyPatchTilesFn(target, patch.beforeTiles, tileSize);
|
|
@@ -2006,20 +1981,17 @@ var PixelEngineConfig = class {
|
|
|
2006
1981
|
}
|
|
2007
1982
|
};
|
|
2008
1983
|
|
|
2009
|
-
// src/PixelData/
|
|
2010
|
-
function
|
|
2011
|
-
const
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
1984
|
+
// src/PixelData/applyAlphaMaskToPixelData.ts
|
|
1985
|
+
function applyAlphaMaskToPixelData(target, mask, opts) {
|
|
1986
|
+
const targetX = opts?.x ?? 0;
|
|
1987
|
+
const targetY = opts?.y ?? 0;
|
|
1988
|
+
const width = opts?.w ?? target.width;
|
|
1989
|
+
const height = opts?.h ?? target.height;
|
|
1990
|
+
const globalAlpha = opts?.alpha ?? 255;
|
|
1991
|
+
const mx = opts?.mx ?? 0;
|
|
1992
|
+
const my = opts?.my ?? 0;
|
|
1993
|
+
const invertMask = opts?.invertMask ?? false;
|
|
2019
1994
|
if (globalAlpha === 0) return false;
|
|
2020
|
-
const baseSrcAlpha = color >>> 24;
|
|
2021
|
-
const isOverwrite = blendFn.isOverwrite || false;
|
|
2022
|
-
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
2023
1995
|
let x = targetX;
|
|
2024
1996
|
let y = targetY;
|
|
2025
1997
|
let w = width;
|
|
@@ -2032,112 +2004,318 @@ function blendColorPixelData(dst, color, opts = {}) {
|
|
|
2032
2004
|
h += y;
|
|
2033
2005
|
y = 0;
|
|
2034
2006
|
}
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
if (
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
const
|
|
2045
|
-
const
|
|
2046
|
-
|
|
2047
|
-
const
|
|
2007
|
+
w = Math.min(w, target.width - x);
|
|
2008
|
+
h = Math.min(h, target.height - y);
|
|
2009
|
+
if (w <= 0) return false;
|
|
2010
|
+
if (h <= 0) return false;
|
|
2011
|
+
const mPitch = mask.w;
|
|
2012
|
+
if (mPitch <= 0) return false;
|
|
2013
|
+
const startX = mx + (x - targetX);
|
|
2014
|
+
const startY = my + (y - targetY);
|
|
2015
|
+
const sX0 = Math.max(0, startX);
|
|
2016
|
+
const sY0 = Math.max(0, startY);
|
|
2017
|
+
const sX1 = Math.min(mPitch, startX + w);
|
|
2018
|
+
const sY1 = Math.min(mask.h, startY + h);
|
|
2019
|
+
const finalW = sX1 - sX0;
|
|
2020
|
+
const finalH = sY1 - sY0;
|
|
2021
|
+
if (finalW <= 0) return false;
|
|
2022
|
+
if (finalH <= 0) return false;
|
|
2023
|
+
const xShift = sX0 - startX;
|
|
2024
|
+
const yShift = sY0 - startY;
|
|
2025
|
+
const dst32 = target.data32;
|
|
2026
|
+
const dw = target.width;
|
|
2027
|
+
const dStride = dw - finalW;
|
|
2028
|
+
const mStride = mPitch - finalW;
|
|
2029
|
+
const maskData = mask.data;
|
|
2030
|
+
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
2031
|
+
let mIdx = sY0 * mPitch + sX0;
|
|
2048
2032
|
let didChange = false;
|
|
2049
|
-
for (let iy = 0; iy <
|
|
2050
|
-
for (let ix = 0; ix <
|
|
2051
|
-
const
|
|
2052
|
-
const
|
|
2053
|
-
|
|
2054
|
-
|
|
2033
|
+
for (let iy = 0; iy < h; iy++) {
|
|
2034
|
+
for (let ix = 0; ix < w; ix++) {
|
|
2035
|
+
const mVal = maskData[mIdx];
|
|
2036
|
+
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
2037
|
+
let weight = 0;
|
|
2038
|
+
if (effectiveM === 0) {
|
|
2039
|
+
weight = 0;
|
|
2040
|
+
} else if (effectiveM === 255) {
|
|
2041
|
+
weight = globalAlpha;
|
|
2042
|
+
} else if (globalAlpha === 255) {
|
|
2043
|
+
weight = effectiveM;
|
|
2044
|
+
} else {
|
|
2045
|
+
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
2046
|
+
}
|
|
2047
|
+
if (weight === 0) {
|
|
2048
|
+
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
2055
2049
|
didChange = true;
|
|
2050
|
+
} else if (weight !== 255) {
|
|
2051
|
+
const d = dst32[dIdx];
|
|
2052
|
+
const da = d >>> 24;
|
|
2053
|
+
if (da !== 0) {
|
|
2054
|
+
const finalAlpha = da === 255 ? weight : da * weight + 128 >> 8;
|
|
2055
|
+
const current = dst32[dIdx];
|
|
2056
|
+
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
2057
|
+
if (current !== next) {
|
|
2058
|
+
dst32[dIdx] = next;
|
|
2059
|
+
didChange = true;
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2056
2062
|
}
|
|
2057
2063
|
dIdx++;
|
|
2064
|
+
mIdx++;
|
|
2058
2065
|
}
|
|
2059
2066
|
dIdx += dStride;
|
|
2067
|
+
mIdx += mStride;
|
|
2060
2068
|
}
|
|
2061
2069
|
return didChange;
|
|
2062
2070
|
}
|
|
2063
2071
|
|
|
2064
|
-
// src/
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
};
|
|
2068
|
-
var mutatorBlendColor = ((writer, deps = defaults2) => {
|
|
2072
|
+
// src/ImageData/resizeImageData.ts
|
|
2073
|
+
function resizeImageData(target, newWidth, newHeight, offsetX = 0, offsetY = 0) {
|
|
2074
|
+
const result = new ImageData(newWidth, newHeight);
|
|
2069
2075
|
const {
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2082
|
-
return didChange(blendColorPixelData2(target, color, opts));
|
|
2083
|
-
}
|
|
2084
|
-
};
|
|
2085
|
-
});
|
|
2086
|
-
|
|
2087
|
-
// src/PixelData/blendPixel.ts
|
|
2088
|
-
function blendPixel(target, x, y, color, alpha = 255, blendFn = sourceOverPerfect) {
|
|
2089
|
-
if (alpha === 0) return false;
|
|
2090
|
-
let width = target.width;
|
|
2091
|
-
let height = target.height;
|
|
2092
|
-
if (x < 0 || x >= width || y < 0 || y >= height) return false;
|
|
2093
|
-
let srcAlpha = color >>> 24;
|
|
2094
|
-
let isOverwrite = blendFn.isOverwrite;
|
|
2095
|
-
if (srcAlpha === 0 && !isOverwrite) return false;
|
|
2096
|
-
let dst32 = target.data32;
|
|
2097
|
-
let index = y * width + x;
|
|
2098
|
-
let finalColor = color;
|
|
2099
|
-
if (alpha !== 255) {
|
|
2100
|
-
let finalAlpha = srcAlpha * alpha + 128 >> 8;
|
|
2101
|
-
if (finalAlpha === 0 && !isOverwrite) return false;
|
|
2102
|
-
finalColor = (color & 16777215 | finalAlpha << 24) >>> 0;
|
|
2076
|
+
width: oldW,
|
|
2077
|
+
height: oldH,
|
|
2078
|
+
data: oldData
|
|
2079
|
+
} = target;
|
|
2080
|
+
const newData = result.data;
|
|
2081
|
+
const x0 = Math.max(0, offsetX);
|
|
2082
|
+
const y0 = Math.max(0, offsetY);
|
|
2083
|
+
const x1 = Math.min(newWidth, offsetX + oldW);
|
|
2084
|
+
const y1 = Math.min(newHeight, offsetY + oldH);
|
|
2085
|
+
if (x1 <= x0 || y1 <= y0) {
|
|
2086
|
+
return result;
|
|
2103
2087
|
}
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2088
|
+
const rowCount = y1 - y0;
|
|
2089
|
+
const rowLen = (x1 - x0) * 4;
|
|
2090
|
+
for (let row = 0; row < rowCount; row++) {
|
|
2091
|
+
const dstY = y0 + row;
|
|
2092
|
+
const srcY = dstY - offsetY;
|
|
2093
|
+
const srcX = x0 - offsetX;
|
|
2094
|
+
const dstStart = (dstY * newWidth + x0) * 4;
|
|
2095
|
+
const srcStart = (srcY * oldW + srcX) * 4;
|
|
2096
|
+
newData.set(oldData.subarray(srcStart, srcStart + rowLen), dstStart);
|
|
2109
2097
|
}
|
|
2110
|
-
return
|
|
2098
|
+
return result;
|
|
2111
2099
|
}
|
|
2112
2100
|
|
|
2113
|
-
// src/
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
} = deps;
|
|
2121
|
-
return {
|
|
2122
|
-
blendPixel(x, y, color, alpha, blendFn) {
|
|
2123
|
-
const didChange = writer.accumulator.storePixelBeforeState(x, y);
|
|
2124
|
-
return didChange(blendPixel2(writer.config.target, x, y, color, alpha, blendFn));
|
|
2125
|
-
}
|
|
2101
|
+
// src/Rect/trimRectBounds.ts
|
|
2102
|
+
function trimRectBounds(x, y, w, h, targetWidth, targetHeight, out) {
|
|
2103
|
+
const res = out ?? {
|
|
2104
|
+
x: 0,
|
|
2105
|
+
y: 0,
|
|
2106
|
+
w: 0,
|
|
2107
|
+
h: 0
|
|
2126
2108
|
};
|
|
2127
|
-
|
|
2109
|
+
const left = Math.max(0, x);
|
|
2110
|
+
const top = Math.max(0, y);
|
|
2111
|
+
const right = Math.min(targetWidth, x + w);
|
|
2112
|
+
const bottom = Math.min(targetHeight, y + h);
|
|
2113
|
+
res.x = left;
|
|
2114
|
+
res.y = top;
|
|
2115
|
+
res.w = Math.max(0, right - left);
|
|
2116
|
+
res.h = Math.max(0, bottom - top);
|
|
2117
|
+
return res;
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
// src/Paint/PaintBuffer.ts
|
|
2121
|
+
var PaintBuffer = class {
|
|
2122
|
+
constructor(config, tilePool) {
|
|
2123
|
+
this.config = config;
|
|
2124
|
+
this.tilePool = tilePool;
|
|
2125
|
+
this.lookup = [];
|
|
2126
|
+
}
|
|
2127
|
+
lookup;
|
|
2128
|
+
scratchBounds = {
|
|
2129
|
+
x: 0,
|
|
2130
|
+
y: 0,
|
|
2131
|
+
w: 0,
|
|
2132
|
+
h: 0
|
|
2133
|
+
};
|
|
2134
|
+
eachTileInBounds(bounds, callback) {
|
|
2135
|
+
const {
|
|
2136
|
+
tileShift,
|
|
2137
|
+
targetColumns,
|
|
2138
|
+
targetRows,
|
|
2139
|
+
tileSize
|
|
2140
|
+
} = this.config;
|
|
2141
|
+
const x1 = Math.max(0, bounds.x >> tileShift);
|
|
2142
|
+
const y1 = Math.max(0, bounds.y >> tileShift);
|
|
2143
|
+
const x2 = Math.min(targetColumns - 1, bounds.x + bounds.w - 1 >> tileShift);
|
|
2144
|
+
const y2 = Math.min(targetRows - 1, bounds.y + bounds.h - 1 >> tileShift);
|
|
2145
|
+
if (x1 > x2 || y1 > y2) return;
|
|
2146
|
+
const lookup = this.lookup;
|
|
2147
|
+
const tilePool = this.tilePool;
|
|
2148
|
+
for (let ty = y1; ty <= y2; ty++) {
|
|
2149
|
+
const rowOffset = ty * targetColumns;
|
|
2150
|
+
const tileTop = ty << tileShift;
|
|
2151
|
+
for (let tx = x1; tx <= x2; tx++) {
|
|
2152
|
+
const id = rowOffset + tx;
|
|
2153
|
+
const tile = lookup[id] ?? (lookup[id] = tilePool.getTile(id, tx, ty));
|
|
2154
|
+
const tileLeft = tx << tileShift;
|
|
2155
|
+
const startX = bounds.x > tileLeft ? bounds.x : tileLeft;
|
|
2156
|
+
const startY = bounds.y > tileTop ? bounds.y : tileTop;
|
|
2157
|
+
const maskEndX = bounds.x + bounds.w;
|
|
2158
|
+
const tileEndX = tileLeft + tileSize;
|
|
2159
|
+
const endX = maskEndX < tileEndX ? maskEndX : tileEndX;
|
|
2160
|
+
const maskEndY = bounds.y + bounds.h;
|
|
2161
|
+
const tileEndY = tileTop + tileSize;
|
|
2162
|
+
const endY = maskEndY < tileEndY ? maskEndY : tileEndY;
|
|
2163
|
+
callback(tile, startX, startY, endX - startX, endY - startY);
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
writePaintAlphaMaskStroke(color, brush, x0, y0, x1, y1) {
|
|
2168
|
+
const cA = color >>> 24;
|
|
2169
|
+
if (cA === 0) return false;
|
|
2170
|
+
const {
|
|
2171
|
+
tileShift,
|
|
2172
|
+
tileMask,
|
|
2173
|
+
target
|
|
2174
|
+
} = this.config;
|
|
2175
|
+
const {
|
|
2176
|
+
w: bW,
|
|
2177
|
+
h: bH,
|
|
2178
|
+
data: bD,
|
|
2179
|
+
centerOffsetX,
|
|
2180
|
+
centerOffsetY
|
|
2181
|
+
} = brush;
|
|
2182
|
+
const cRGB = color & 16777215;
|
|
2183
|
+
const scratch = this.scratchBounds;
|
|
2184
|
+
let changed = false;
|
|
2185
|
+
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
2186
|
+
const topLeftX = Math.floor(px + centerOffsetX);
|
|
2187
|
+
const topLeftY = Math.floor(py + centerOffsetY);
|
|
2188
|
+
trimRectBounds(topLeftX, topLeftY, bW, bH, target.width, target.height, scratch);
|
|
2189
|
+
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
2190
|
+
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
2191
|
+
const d32 = tile.data32;
|
|
2192
|
+
let tileChanged = false;
|
|
2193
|
+
for (let i = 0; i < bH_t; i++) {
|
|
2194
|
+
const canvasY = bY + i;
|
|
2195
|
+
const bOff = (canvasY - topLeftY) * bW;
|
|
2196
|
+
const tOff = (canvasY & tileMask) << tileShift;
|
|
2197
|
+
const dS = tOff + (bX & tileMask);
|
|
2198
|
+
for (let j = 0; j < bW_t; j++) {
|
|
2199
|
+
const canvasX = bX + j;
|
|
2200
|
+
const brushA = bD[bOff + (canvasX - topLeftX)];
|
|
2201
|
+
if (brushA === 0) continue;
|
|
2202
|
+
const t = cA * brushA + 128;
|
|
2203
|
+
const blendedA = t + (t >> 8) >> 8;
|
|
2204
|
+
const idx = dS + j;
|
|
2205
|
+
const cur = d32[idx];
|
|
2206
|
+
if (brushA > cur >>> 24) {
|
|
2207
|
+
const next = (cRGB | blendedA << 24) >>> 0;
|
|
2208
|
+
if (cur !== next) {
|
|
2209
|
+
d32[idx] = next;
|
|
2210
|
+
tileChanged = true;
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2215
|
+
if (tileChanged) changed = true;
|
|
2216
|
+
});
|
|
2217
|
+
});
|
|
2218
|
+
return changed;
|
|
2219
|
+
}
|
|
2220
|
+
writePaintBinaryMaskStroke(color, brush, x0, y0, x1, y1) {
|
|
2221
|
+
const alphaIsZero = color >>> 24 === 0;
|
|
2222
|
+
if (alphaIsZero) return false;
|
|
2223
|
+
const {
|
|
2224
|
+
tileShift,
|
|
2225
|
+
tileMask,
|
|
2226
|
+
target
|
|
2227
|
+
} = this.config;
|
|
2228
|
+
const {
|
|
2229
|
+
w: bW,
|
|
2230
|
+
h: bH,
|
|
2231
|
+
data: bD,
|
|
2232
|
+
centerOffsetX,
|
|
2233
|
+
centerOffsetY
|
|
2234
|
+
} = brush;
|
|
2235
|
+
const scratch = this.scratchBounds;
|
|
2236
|
+
let changed = false;
|
|
2237
|
+
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
2238
|
+
const topLeftX = Math.floor(px + centerOffsetX);
|
|
2239
|
+
const topLeftY = Math.floor(py + centerOffsetY);
|
|
2240
|
+
trimRectBounds(topLeftX, topLeftY, bW, bH, target.width, target.height, scratch);
|
|
2241
|
+
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
2242
|
+
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
2243
|
+
const d32 = tile.data32;
|
|
2244
|
+
let tileChanged = false;
|
|
2245
|
+
for (let i = 0; i < bH_t; i++) {
|
|
2246
|
+
const canvasY = bY + i;
|
|
2247
|
+
const bOff = (canvasY - topLeftY) * bW;
|
|
2248
|
+
const tOff = (canvasY & tileMask) << tileShift;
|
|
2249
|
+
const dS = tOff + (bX & tileMask);
|
|
2250
|
+
for (let j = 0; j < bW_t; j++) {
|
|
2251
|
+
const canvasX = bX + j;
|
|
2252
|
+
if (bD[bOff + (canvasX - topLeftX)]) {
|
|
2253
|
+
const idx = dS + j;
|
|
2254
|
+
if (d32[idx] !== color) {
|
|
2255
|
+
d32[idx] = color;
|
|
2256
|
+
tileChanged = true;
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
if (tileChanged) changed = true;
|
|
2262
|
+
});
|
|
2263
|
+
});
|
|
2264
|
+
return changed;
|
|
2265
|
+
}
|
|
2266
|
+
writeRectStroke(color, brushWidth, brushHeight, x0, y0, x1, y1) {
|
|
2267
|
+
const alphaIsZero = color >>> 24 === 0;
|
|
2268
|
+
if (alphaIsZero) return false;
|
|
2269
|
+
const config = this.config;
|
|
2270
|
+
const tileShift = config.tileShift;
|
|
2271
|
+
const tileMask = config.tileMask;
|
|
2272
|
+
const target = config.target;
|
|
2273
|
+
const scratch = this.scratchBounds;
|
|
2274
|
+
const centerOffsetX = -(brushWidth - 1 >> 1);
|
|
2275
|
+
const centerOffsetY = -(brushHeight - 1 >> 1);
|
|
2276
|
+
let changed = false;
|
|
2277
|
+
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
2278
|
+
const topLeftX = Math.floor(px + centerOffsetX);
|
|
2279
|
+
const topLeftY = Math.floor(py + centerOffsetY);
|
|
2280
|
+
trimRectBounds(topLeftX, topLeftY, brushWidth, brushHeight, target.width, target.height, scratch);
|
|
2281
|
+
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
2282
|
+
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
2283
|
+
const d32 = tile.data32;
|
|
2284
|
+
let tileChanged = false;
|
|
2285
|
+
for (let i = 0; i < bH_t; i++) {
|
|
2286
|
+
const canvasY = bY + i;
|
|
2287
|
+
const tOff = (canvasY & tileMask) << tileShift;
|
|
2288
|
+
const dS = tOff + (bX & tileMask);
|
|
2289
|
+
for (let j = 0; j < bW_t; j++) {
|
|
2290
|
+
const idx = dS + j;
|
|
2291
|
+
if (d32[idx] !== color) {
|
|
2292
|
+
d32[idx] = color;
|
|
2293
|
+
tileChanged = true;
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2296
|
+
}
|
|
2297
|
+
if (tileChanged) {
|
|
2298
|
+
changed = true;
|
|
2299
|
+
}
|
|
2300
|
+
});
|
|
2301
|
+
});
|
|
2302
|
+
return changed;
|
|
2303
|
+
}
|
|
2304
|
+
clear() {
|
|
2305
|
+
this.tilePool.releaseTiles(this.lookup);
|
|
2306
|
+
}
|
|
2307
|
+
};
|
|
2128
2308
|
|
|
2129
2309
|
// src/PixelData/blendPixelData.ts
|
|
2130
|
-
function blendPixelData(
|
|
2131
|
-
const
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
blendFn = sourceOverPerfect
|
|
2140
|
-
} = opts;
|
|
2310
|
+
function blendPixelData(target, src, opts) {
|
|
2311
|
+
const targetX = opts?.x ?? 0;
|
|
2312
|
+
const targetY = opts?.y ?? 0;
|
|
2313
|
+
const sourceX = opts?.sx ?? 0;
|
|
2314
|
+
const sourceY = opts?.sy ?? 0;
|
|
2315
|
+
const width = opts?.w ?? src.width;
|
|
2316
|
+
const height = opts?.h ?? src.height;
|
|
2317
|
+
const globalAlpha = opts?.alpha ?? 255;
|
|
2318
|
+
const blendFn = opts?.blendFn ?? sourceOverPerfect;
|
|
2141
2319
|
if (globalAlpha === 0) return false;
|
|
2142
2320
|
let x = targetX;
|
|
2143
2321
|
let y = targetY;
|
|
@@ -2167,12 +2345,12 @@ function blendPixelData(dst, src, opts = {}) {
|
|
|
2167
2345
|
h += y;
|
|
2168
2346
|
y = 0;
|
|
2169
2347
|
}
|
|
2170
|
-
const actualW = Math.min(w,
|
|
2171
|
-
const actualH = Math.min(h,
|
|
2348
|
+
const actualW = Math.min(w, target.width - x);
|
|
2349
|
+
const actualH = Math.min(h, target.height - y);
|
|
2172
2350
|
if (actualW <= 0 || actualH <= 0) return false;
|
|
2173
|
-
const dst32 =
|
|
2351
|
+
const dst32 = target.data32;
|
|
2174
2352
|
const src32 = src.data32;
|
|
2175
|
-
const dw =
|
|
2353
|
+
const dw = target.width;
|
|
2176
2354
|
const sw = src.width;
|
|
2177
2355
|
let dIdx = y * dw + x | 0;
|
|
2178
2356
|
let sIdx = sy * sw + sx | 0;
|
|
@@ -2215,44 +2393,334 @@ function blendPixelData(dst, src, opts = {}) {
|
|
|
2215
2393
|
return didChange;
|
|
2216
2394
|
}
|
|
2217
2395
|
|
|
2218
|
-
// src/
|
|
2219
|
-
var
|
|
2220
|
-
|
|
2396
|
+
// src/PixelTile/PixelTile.ts
|
|
2397
|
+
var PixelTile = class {
|
|
2398
|
+
constructor(id, tx, ty, tileSize, tileArea) {
|
|
2399
|
+
this.id = id;
|
|
2400
|
+
this.tx = tx;
|
|
2401
|
+
this.ty = ty;
|
|
2402
|
+
this.width = this.height = tileSize;
|
|
2403
|
+
this.data32 = new Uint32Array(tileArea);
|
|
2404
|
+
const data8 = new Uint8ClampedArray(this.data32.buffer);
|
|
2405
|
+
this.imageData = new ImageData(data8, tileSize, tileSize);
|
|
2406
|
+
}
|
|
2407
|
+
data32;
|
|
2408
|
+
width;
|
|
2409
|
+
height;
|
|
2410
|
+
imageData;
|
|
2221
2411
|
};
|
|
2222
|
-
var mutatorBlendPixelData = ((writer, deps = defaults4) => {
|
|
2223
|
-
const {
|
|
2224
|
-
blendPixelData: blendPixelData2 = defaults4.blendPixelData
|
|
2225
|
-
} = deps;
|
|
2226
|
-
return {
|
|
2227
|
-
blendPixelData(src, opts = {}) {
|
|
2228
|
-
const {
|
|
2229
|
-
x = 0,
|
|
2230
|
-
y = 0,
|
|
2231
|
-
w = src.width,
|
|
2232
|
-
h = src.height
|
|
2233
|
-
} = opts;
|
|
2234
|
-
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2235
|
-
return didChange(blendPixelData2(writer.config.target, src, opts));
|
|
2236
|
-
}
|
|
2237
|
-
};
|
|
2238
|
-
});
|
|
2239
2412
|
|
|
2240
|
-
// src/
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2413
|
+
// src/PixelTile/PixelTilePool.ts
|
|
2414
|
+
var PixelTilePool = class {
|
|
2415
|
+
pool;
|
|
2416
|
+
tileSize;
|
|
2417
|
+
tileArea;
|
|
2418
|
+
constructor(config) {
|
|
2419
|
+
this.pool = [];
|
|
2420
|
+
this.tileSize = config.tileSize;
|
|
2421
|
+
this.tileArea = config.tileArea;
|
|
2422
|
+
}
|
|
2423
|
+
getTile(id, tx, ty) {
|
|
2424
|
+
let tile = this.pool.pop();
|
|
2425
|
+
if (tile) {
|
|
2426
|
+
tile.id = id;
|
|
2427
|
+
tile.tx = tx;
|
|
2428
|
+
tile.ty = ty;
|
|
2429
|
+
tile.data32.fill(0);
|
|
2430
|
+
return tile;
|
|
2431
|
+
}
|
|
2432
|
+
return new PixelTile(id, tx, ty, this.tileSize, this.tileArea);
|
|
2433
|
+
}
|
|
2434
|
+
releaseTile(tile) {
|
|
2435
|
+
this.pool.push(tile);
|
|
2436
|
+
}
|
|
2437
|
+
releaseTiles(tiles) {
|
|
2438
|
+
let length = tiles.length;
|
|
2439
|
+
for (let i = 0; i < length; i++) {
|
|
2440
|
+
let tile = tiles[i];
|
|
2441
|
+
if (tile) {
|
|
2442
|
+
this.pool.push(tile);
|
|
2443
|
+
}
|
|
2444
|
+
}
|
|
2445
|
+
tiles.length = 0;
|
|
2446
|
+
}
|
|
2447
|
+
};
|
|
2448
|
+
|
|
2449
|
+
// src/History/PixelWriter.ts
|
|
2450
|
+
var PixelWriter = class {
|
|
2451
|
+
historyManager;
|
|
2452
|
+
accumulator;
|
|
2453
|
+
historyActionFactory;
|
|
2454
|
+
config;
|
|
2455
|
+
pixelTilePool;
|
|
2456
|
+
paintBuffer;
|
|
2457
|
+
mutator;
|
|
2458
|
+
blendPixelDataOpts = {
|
|
2459
|
+
alpha: 255,
|
|
2460
|
+
blendFn: sourceOverPerfect,
|
|
2461
|
+
x: 0,
|
|
2462
|
+
y: 0,
|
|
2463
|
+
w: 0,
|
|
2464
|
+
h: 0
|
|
2465
|
+
};
|
|
2466
|
+
_inProgress = false;
|
|
2467
|
+
constructor(target, mutatorFactory, options) {
|
|
2468
|
+
const tileSize = options?.tileSize ?? 256;
|
|
2469
|
+
const maxHistorySteps = options?.maxHistorySteps ?? 50;
|
|
2470
|
+
this.config = new PixelEngineConfig(tileSize, target);
|
|
2471
|
+
this.historyManager = options?.historyManager ?? new HistoryManager(maxHistorySteps);
|
|
2472
|
+
this.historyActionFactory = options?.historyActionFactory ?? makeHistoryAction;
|
|
2473
|
+
this.pixelTilePool = options?.pixelTilePool ?? new PixelTilePool(this.config);
|
|
2474
|
+
this.accumulator = options?.accumulator ?? new PixelAccumulator(this.config, this.pixelTilePool);
|
|
2475
|
+
this.mutator = mutatorFactory(this);
|
|
2476
|
+
this.paintBuffer = new PaintBuffer(this.config, this.pixelTilePool);
|
|
2477
|
+
}
|
|
2478
|
+
/**
|
|
2479
|
+
* Executes `transaction` and commits the resulting pixel changes as a single
|
|
2480
|
+
* undoable history action.
|
|
2481
|
+
*
|
|
2482
|
+
* - If `transaction` throws, all accumulated changes are rolled back and the error
|
|
2483
|
+
* is re-thrown. No action is committed.
|
|
2484
|
+
* - If `transaction` completes without modifying any pixels, no action is committed.
|
|
2485
|
+
* - `withHistory` is not re-entrant. Calling it again from inside `transaction` will
|
|
2486
|
+
* throw immediately to prevent silent data loss from a nested extractPatch.
|
|
2487
|
+
*
|
|
2488
|
+
* @param transaction Callback to be executed inside the transaction.
|
|
2489
|
+
* @param after Called after both undo and redo — use for generic change notifications.
|
|
2490
|
+
* @param afterUndo Called after undo only — use for dimension or state changes specific to undo.
|
|
2491
|
+
* @param afterRedo Called after redo only.
|
|
2492
|
+
*/
|
|
2493
|
+
withHistory(transaction, after, afterUndo, afterRedo) {
|
|
2494
|
+
if (this._inProgress) {
|
|
2495
|
+
throw new Error("withHistory is not re-entrant \u2014 commit or rollback the current operation first");
|
|
2496
|
+
}
|
|
2497
|
+
this._inProgress = true;
|
|
2498
|
+
try {
|
|
2499
|
+
transaction(this.mutator);
|
|
2500
|
+
} catch (e) {
|
|
2501
|
+
this.accumulator.rollbackAfterError();
|
|
2502
|
+
throw e;
|
|
2503
|
+
} finally {
|
|
2504
|
+
this._inProgress = false;
|
|
2505
|
+
}
|
|
2506
|
+
if (this.accumulator.beforeTiles.length === 0) return;
|
|
2507
|
+
const patch = this.accumulator.extractPatch();
|
|
2508
|
+
const action = this.historyActionFactory(this.config, this.accumulator, patch, after, afterUndo, afterRedo);
|
|
2509
|
+
this.historyManager.commit(action);
|
|
2510
|
+
}
|
|
2511
|
+
resize(newWidth, newHeight, offsetX = 0, offsetY = 0, after, afterUndo, afterRedo, resizeImageDataFn = resizeImageData) {
|
|
2512
|
+
if (this._inProgress) {
|
|
2513
|
+
throw new Error("Cannot resize inside a withHistory callback");
|
|
2514
|
+
}
|
|
2515
|
+
if (this.accumulator.beforeTiles.length > 0) {
|
|
2516
|
+
throw new Error("Cannot resize with an open accumulator \u2014 commit or rollback first");
|
|
2517
|
+
}
|
|
2518
|
+
const config = this.config;
|
|
2519
|
+
const target = config.target;
|
|
2520
|
+
const beforeImageData = target.imageData;
|
|
2521
|
+
const afterImageData = resizeImageDataFn(beforeImageData, newWidth, newHeight, offsetX, offsetY);
|
|
2522
|
+
target.set(afterImageData);
|
|
2523
|
+
this.historyManager.commit({
|
|
2524
|
+
undo: () => {
|
|
2525
|
+
target.set(beforeImageData);
|
|
2526
|
+
afterUndo?.(beforeImageData);
|
|
2527
|
+
after?.(beforeImageData);
|
|
2528
|
+
},
|
|
2529
|
+
redo: () => {
|
|
2530
|
+
target.set(afterImageData);
|
|
2531
|
+
afterRedo?.(afterImageData);
|
|
2532
|
+
after?.(afterImageData);
|
|
2533
|
+
}
|
|
2534
|
+
});
|
|
2535
|
+
}
|
|
2536
|
+
commitPaintBuffer(alpha = 255, blendFn = sourceOverPerfect, blendPixelDataFn = blendPixelData) {
|
|
2537
|
+
const paintBuffer = this.paintBuffer;
|
|
2538
|
+
const tileShift = paintBuffer.config.tileShift;
|
|
2539
|
+
const lookup = paintBuffer.lookup;
|
|
2540
|
+
const opts = this.blendPixelDataOpts;
|
|
2541
|
+
opts.alpha = alpha;
|
|
2542
|
+
opts.blendFn = blendFn;
|
|
2543
|
+
for (let i = 0; i < lookup.length; i++) {
|
|
2544
|
+
const tile = lookup[i];
|
|
2545
|
+
if (tile) {
|
|
2546
|
+
const didChange = this.accumulator.storeTileBeforeState(tile.id, tile.tx, tile.ty);
|
|
2547
|
+
const dx = tile.tx << tileShift;
|
|
2548
|
+
const dy = tile.ty << tileShift;
|
|
2549
|
+
opts.x = dx;
|
|
2550
|
+
opts.y = dy;
|
|
2551
|
+
opts.w = tile.width;
|
|
2552
|
+
opts.h = tile.height;
|
|
2553
|
+
didChange(blendPixelDataFn(this.config.target, tile, opts));
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
paintBuffer.clear();
|
|
2557
|
+
}
|
|
2558
|
+
};
|
|
2559
|
+
|
|
2560
|
+
// src/History/PixelMutator/mutatorApplyAlphaMask.ts
|
|
2561
|
+
var defaults2 = {
|
|
2562
|
+
applyAlphaMaskToPixelData
|
|
2563
|
+
};
|
|
2564
|
+
var mutatorApplyAlphaMask = ((writer, deps = defaults2) => {
|
|
2565
|
+
const {
|
|
2566
|
+
applyAlphaMaskToPixelData: applyAlphaMaskToPixelData2 = defaults2.applyAlphaMaskToPixelData
|
|
2567
|
+
} = deps;
|
|
2568
|
+
return {
|
|
2569
|
+
applyAlphaMask(mask, opts) {
|
|
2570
|
+
const target = writer.config.target;
|
|
2571
|
+
const x = opts?.x ?? 0;
|
|
2572
|
+
const y = opts?.y ?? 0;
|
|
2573
|
+
const w = opts?.w ?? target.width;
|
|
2574
|
+
const h = opts?.h ?? target.height;
|
|
2575
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2576
|
+
return didChange(applyAlphaMaskToPixelData2(target, mask, opts));
|
|
2577
|
+
}
|
|
2578
|
+
};
|
|
2579
|
+
});
|
|
2580
|
+
|
|
2581
|
+
// src/PixelData/applyBinaryMaskToPixelData.ts
|
|
2582
|
+
function applyBinaryMaskToPixelData(target, mask, opts) {
|
|
2583
|
+
const targetX = opts?.x ?? 0;
|
|
2584
|
+
const targetY = opts?.y ?? 0;
|
|
2585
|
+
const width = opts?.w ?? target.width;
|
|
2586
|
+
const height = opts?.h ?? target.height;
|
|
2587
|
+
const globalAlpha = opts?.alpha ?? 255;
|
|
2588
|
+
const mx = opts?.mx ?? 0;
|
|
2589
|
+
const my = opts?.my ?? 0;
|
|
2590
|
+
const invertMask = opts?.invertMask ?? false;
|
|
2591
|
+
if (globalAlpha === 0) return false;
|
|
2592
|
+
let x = targetX;
|
|
2593
|
+
let y = targetY;
|
|
2594
|
+
let w = width;
|
|
2595
|
+
let h = height;
|
|
2596
|
+
if (x < 0) {
|
|
2597
|
+
w += x;
|
|
2598
|
+
x = 0;
|
|
2599
|
+
}
|
|
2600
|
+
if (y < 0) {
|
|
2601
|
+
h += y;
|
|
2602
|
+
y = 0;
|
|
2603
|
+
}
|
|
2604
|
+
w = Math.min(w, target.width - x);
|
|
2605
|
+
h = Math.min(h, target.height - y);
|
|
2606
|
+
if (w <= 0 || h <= 0) return false;
|
|
2607
|
+
const mPitch = mask.w;
|
|
2608
|
+
if (mPitch <= 0) return false;
|
|
2609
|
+
const startX = mx + (x - targetX);
|
|
2610
|
+
const startY = my + (y - targetY);
|
|
2611
|
+
const sX0 = Math.max(0, startX);
|
|
2612
|
+
const sY0 = Math.max(0, startY);
|
|
2613
|
+
const sX1 = Math.min(mPitch, startX + w);
|
|
2614
|
+
const sY1 = Math.min(mask.h, startY + h);
|
|
2615
|
+
const finalW = sX1 - sX0;
|
|
2616
|
+
const finalH = sY1 - sY0;
|
|
2617
|
+
if (finalW <= 0 || finalH <= 0) {
|
|
2618
|
+
return false;
|
|
2619
|
+
}
|
|
2620
|
+
const xShift = sX0 - startX;
|
|
2621
|
+
const yShift = sY0 - startY;
|
|
2622
|
+
const dst32 = target.data32;
|
|
2623
|
+
const dw = target.width;
|
|
2624
|
+
const dStride = dw - finalW;
|
|
2625
|
+
const mStride = mPitch - finalW;
|
|
2626
|
+
const maskData = mask.data;
|
|
2627
|
+
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
2628
|
+
let mIdx = sY0 * mPitch + sX0;
|
|
2629
|
+
let didChange = false;
|
|
2630
|
+
for (let iy = 0; iy < finalH; iy++) {
|
|
2631
|
+
for (let ix = 0; ix < finalW; ix++) {
|
|
2632
|
+
const mVal = maskData[mIdx];
|
|
2633
|
+
const isMaskedOut = invertMask ? mVal !== 0 : mVal === 0;
|
|
2634
|
+
if (isMaskedOut) {
|
|
2635
|
+
const current = dst32[dIdx];
|
|
2636
|
+
const next = (current & 16777215) >>> 0;
|
|
2637
|
+
if (current !== next) {
|
|
2638
|
+
dst32[dIdx] = next;
|
|
2639
|
+
didChange = true;
|
|
2640
|
+
}
|
|
2641
|
+
} else if (globalAlpha !== 255) {
|
|
2642
|
+
const d = dst32[dIdx];
|
|
2643
|
+
const da = d >>> 24;
|
|
2644
|
+
if (da !== 0) {
|
|
2645
|
+
const finalAlpha = da === 255 ? globalAlpha : da * globalAlpha + 128 >> 8;
|
|
2646
|
+
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
2647
|
+
if (d !== next) {
|
|
2648
|
+
dst32[dIdx] = next;
|
|
2649
|
+
didChange = true;
|
|
2650
|
+
}
|
|
2651
|
+
}
|
|
2652
|
+
}
|
|
2653
|
+
dIdx++;
|
|
2654
|
+
mIdx++;
|
|
2655
|
+
}
|
|
2656
|
+
dIdx += dStride;
|
|
2657
|
+
mIdx += mStride;
|
|
2658
|
+
}
|
|
2659
|
+
return didChange;
|
|
2660
|
+
}
|
|
2661
|
+
|
|
2662
|
+
// src/History/PixelMutator/mutatorApplyBinaryMask.ts
|
|
2663
|
+
var defaults3 = {
|
|
2664
|
+
applyBinaryMaskToPixelData
|
|
2665
|
+
};
|
|
2666
|
+
var mutatorApplyBinaryMask = ((writer, deps = defaults3) => {
|
|
2667
|
+
const {
|
|
2668
|
+
applyBinaryMaskToPixelData: applyBinaryMaskToPixelData2 = defaults3.applyBinaryMaskToPixelData
|
|
2669
|
+
} = deps;
|
|
2670
|
+
return {
|
|
2671
|
+
applyBinaryMask(mask, opts) {
|
|
2672
|
+
const target = writer.config.target;
|
|
2673
|
+
const x = opts?.x ?? 0;
|
|
2674
|
+
const y = opts?.y ?? 0;
|
|
2675
|
+
const w = opts?.w ?? target.width;
|
|
2676
|
+
const h = opts?.h ?? target.height;
|
|
2677
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2678
|
+
return didChange(applyBinaryMaskToPixelData2(target, mask, opts));
|
|
2679
|
+
}
|
|
2680
|
+
};
|
|
2681
|
+
});
|
|
2682
|
+
|
|
2683
|
+
// src/History/PixelMutator/mutatorApplyMask.ts
|
|
2684
|
+
var defaults4 = {
|
|
2685
|
+
applyBinaryMaskToPixelData,
|
|
2686
|
+
applyAlphaMaskToPixelData
|
|
2687
|
+
};
|
|
2688
|
+
var mutatorApplyMask = ((writer, deps = defaults4) => {
|
|
2689
|
+
const {
|
|
2690
|
+
applyBinaryMaskToPixelData: applyBinaryMaskToPixelData2 = defaults4.applyBinaryMaskToPixelData,
|
|
2691
|
+
applyAlphaMaskToPixelData: applyAlphaMaskToPixelData2 = defaults4.applyAlphaMaskToPixelData
|
|
2692
|
+
} = deps;
|
|
2693
|
+
return {
|
|
2694
|
+
applyMask(mask, opts) {
|
|
2695
|
+
const target = writer.config.target;
|
|
2696
|
+
const x = opts?.x ?? 0;
|
|
2697
|
+
const y = opts?.y ?? 0;
|
|
2698
|
+
const w = opts?.w ?? target.width;
|
|
2699
|
+
const h = opts?.h ?? target.height;
|
|
2700
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2701
|
+
if (mask.type === 1 /* BINARY */) {
|
|
2702
|
+
return didChange(applyBinaryMaskToPixelData2(target, mask, opts));
|
|
2703
|
+
} else {
|
|
2704
|
+
return didChange(applyAlphaMaskToPixelData2(target, mask, opts));
|
|
2705
|
+
}
|
|
2706
|
+
}
|
|
2707
|
+
};
|
|
2708
|
+
});
|
|
2709
|
+
|
|
2710
|
+
// src/PixelData/blendPixelDataAlphaMask.ts
|
|
2711
|
+
function blendPixelDataAlphaMask(target, src, alphaMask, opts) {
|
|
2712
|
+
const targetX = opts?.x ?? 0;
|
|
2713
|
+
const targetY = opts?.y ?? 0;
|
|
2714
|
+
const sourceX = opts?.sx ?? 0;
|
|
2715
|
+
const sourceY = opts?.sy ?? 0;
|
|
2716
|
+
const width = opts?.w ?? src.width;
|
|
2717
|
+
const height = opts?.h ?? src.height;
|
|
2718
|
+
const globalAlpha = opts?.alpha ?? 255;
|
|
2719
|
+
const blendFn = opts?.blendFn ?? sourceOverPerfect;
|
|
2720
|
+
const mx = opts?.mx ?? 0;
|
|
2721
|
+
const my = opts?.my ?? 0;
|
|
2722
|
+
const invertMask = opts?.invertMask ?? false;
|
|
2723
|
+
if (globalAlpha === 0) return false;
|
|
2256
2724
|
let x = targetX;
|
|
2257
2725
|
let y = targetY;
|
|
2258
2726
|
let sx = sourceX;
|
|
@@ -2281,16 +2749,16 @@ function blendPixelDataAlphaMask(dst, src, alphaMask, opts = {}) {
|
|
|
2281
2749
|
h += y;
|
|
2282
2750
|
y = 0;
|
|
2283
2751
|
}
|
|
2284
|
-
const actualW = Math.min(w,
|
|
2285
|
-
const actualH = Math.min(h,
|
|
2752
|
+
const actualW = Math.min(w, target.width - x);
|
|
2753
|
+
const actualH = Math.min(h, target.height - y);
|
|
2286
2754
|
if (actualW <= 0 || actualH <= 0) return false;
|
|
2287
|
-
const dw =
|
|
2755
|
+
const dw = target.width;
|
|
2288
2756
|
const sw = src.width;
|
|
2289
2757
|
const mPitch = alphaMask.w;
|
|
2290
2758
|
const maskData = alphaMask.data;
|
|
2291
2759
|
const dx = x - targetX | 0;
|
|
2292
2760
|
const dy = y - targetY | 0;
|
|
2293
|
-
const dst32 =
|
|
2761
|
+
const dst32 = target.data32;
|
|
2294
2762
|
const src32 = src.data32;
|
|
2295
2763
|
let dIdx = y * dw + x | 0;
|
|
2296
2764
|
let sIdx = sy * sw + sx | 0;
|
|
@@ -2359,20 +2827,20 @@ function blendPixelDataAlphaMask(dst, src, alphaMask, opts = {}) {
|
|
|
2359
2827
|
return didChange;
|
|
2360
2828
|
}
|
|
2361
2829
|
|
|
2362
|
-
// src/History/PixelMutator/
|
|
2830
|
+
// src/History/PixelMutator/mutatorBlendAlphaMask.ts
|
|
2363
2831
|
var defaults5 = {
|
|
2364
2832
|
blendPixelDataAlphaMask
|
|
2365
2833
|
};
|
|
2366
|
-
var
|
|
2834
|
+
var mutatorBlendAlphaMask = ((writer, deps = defaults5) => {
|
|
2367
2835
|
const {
|
|
2368
2836
|
blendPixelDataAlphaMask: blendPixelDataAlphaMask2 = defaults5.blendPixelDataAlphaMask
|
|
2369
2837
|
} = deps;
|
|
2370
2838
|
return {
|
|
2371
|
-
|
|
2372
|
-
const x = opts
|
|
2373
|
-
const y = opts
|
|
2374
|
-
const w = opts
|
|
2375
|
-
const h = opts
|
|
2839
|
+
blendAlphaMask(src, mask, opts) {
|
|
2840
|
+
const x = opts?.x ?? 0;
|
|
2841
|
+
const y = opts?.y ?? 0;
|
|
2842
|
+
const w = opts?.w ?? src.width;
|
|
2843
|
+
const h = opts?.h ?? src.height;
|
|
2376
2844
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2377
2845
|
return didChange(blendPixelDataAlphaMask2(writer.config.target, src, mask, opts));
|
|
2378
2846
|
}
|
|
@@ -2380,20 +2848,18 @@ var mutatorBlendPixelDataAlphaMask = ((writer, deps = defaults5) => {
|
|
|
2380
2848
|
});
|
|
2381
2849
|
|
|
2382
2850
|
// src/PixelData/blendPixelDataBinaryMask.ts
|
|
2383
|
-
function blendPixelDataBinaryMask(
|
|
2384
|
-
const
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
invertMask = false
|
|
2396
|
-
} = opts;
|
|
2851
|
+
function blendPixelDataBinaryMask(target, src, binaryMask, opts) {
|
|
2852
|
+
const targetX = opts?.x ?? 0;
|
|
2853
|
+
const targetY = opts?.y ?? 0;
|
|
2854
|
+
const sourceX = opts?.sx ?? 0;
|
|
2855
|
+
const sourceY = opts?.sy ?? 0;
|
|
2856
|
+
const width = opts?.w ?? src.width;
|
|
2857
|
+
const height = opts?.h ?? src.height;
|
|
2858
|
+
const globalAlpha = opts?.alpha ?? 255;
|
|
2859
|
+
const blendFn = opts?.blendFn ?? sourceOverPerfect;
|
|
2860
|
+
const mx = opts?.mx ?? 0;
|
|
2861
|
+
const my = opts?.my ?? 0;
|
|
2862
|
+
const invertMask = opts?.invertMask ?? false;
|
|
2397
2863
|
if (globalAlpha === 0) return false;
|
|
2398
2864
|
let x = targetX;
|
|
2399
2865
|
let y = targetY;
|
|
@@ -2423,14 +2889,14 @@ function blendPixelDataBinaryMask(dst, src, binaryMask, opts = {}) {
|
|
|
2423
2889
|
h += y;
|
|
2424
2890
|
y = 0;
|
|
2425
2891
|
}
|
|
2426
|
-
const actualW = Math.min(w,
|
|
2427
|
-
const actualH = Math.min(h,
|
|
2892
|
+
const actualW = Math.min(w, target.width - x);
|
|
2893
|
+
const actualH = Math.min(h, target.height - y);
|
|
2428
2894
|
if (actualW <= 0 || actualH <= 0) return false;
|
|
2429
2895
|
const dx = x - targetX | 0;
|
|
2430
2896
|
const dy = y - targetY | 0;
|
|
2431
|
-
const dst32 =
|
|
2897
|
+
const dst32 = target.data32;
|
|
2432
2898
|
const src32 = src.data32;
|
|
2433
|
-
const dw =
|
|
2899
|
+
const dw = target.width;
|
|
2434
2900
|
const sw = src.width;
|
|
2435
2901
|
const mPitch = binaryMask.w;
|
|
2436
2902
|
const maskData = binaryMask.data;
|
|
@@ -2488,1146 +2954,744 @@ function blendPixelDataBinaryMask(dst, src, binaryMask, opts = {}) {
|
|
|
2488
2954
|
return didChange;
|
|
2489
2955
|
}
|
|
2490
2956
|
|
|
2491
|
-
// src/History/PixelMutator/
|
|
2957
|
+
// src/History/PixelMutator/mutatorBlendBinaryMask.ts
|
|
2492
2958
|
var defaults6 = {
|
|
2493
2959
|
blendPixelDataBinaryMask
|
|
2494
2960
|
};
|
|
2495
|
-
var
|
|
2961
|
+
var mutatorBlendBinaryMask = ((writer, deps = defaults6) => {
|
|
2496
2962
|
const {
|
|
2497
2963
|
blendPixelDataBinaryMask: blendPixelDataBinaryMask2 = defaults6.blendPixelDataBinaryMask
|
|
2498
2964
|
} = deps;
|
|
2499
2965
|
return {
|
|
2500
|
-
|
|
2501
|
-
const x = opts
|
|
2502
|
-
const y = opts
|
|
2503
|
-
const w = opts
|
|
2504
|
-
const h = opts
|
|
2966
|
+
blendBinaryMask(src, mask, opts) {
|
|
2967
|
+
const x = opts?.x ?? 0;
|
|
2968
|
+
const y = opts?.y ?? 0;
|
|
2969
|
+
const w = opts?.w ?? src.width;
|
|
2970
|
+
const h = opts?.h ?? src.height;
|
|
2505
2971
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2506
2972
|
return didChange(blendPixelDataBinaryMask2(writer.config.target, src, mask, opts));
|
|
2507
2973
|
}
|
|
2508
2974
|
};
|
|
2509
2975
|
});
|
|
2510
2976
|
|
|
2511
|
-
// src/PixelData/
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2977
|
+
// src/PixelData/blendColorPixelData.ts
|
|
2978
|
+
function blendColorPixelData(target, color, opts) {
|
|
2979
|
+
const targetX = opts?.x ?? 0;
|
|
2980
|
+
const targetY = opts?.y ?? 0;
|
|
2981
|
+
const width = opts?.w ?? target.width;
|
|
2982
|
+
const height = opts?.h ?? target.height;
|
|
2983
|
+
const globalAlpha = opts?.alpha ?? 255;
|
|
2984
|
+
const blendFn = opts?.blendFn ?? sourceOverPerfect;
|
|
2985
|
+
if (globalAlpha === 0) return false;
|
|
2986
|
+
const baseSrcAlpha = color >>> 24;
|
|
2987
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
2988
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
2989
|
+
let x = targetX;
|
|
2990
|
+
let y = targetY;
|
|
2991
|
+
let w = width;
|
|
2992
|
+
let h = height;
|
|
2993
|
+
if (x < 0) {
|
|
2994
|
+
w += x;
|
|
2529
2995
|
x = 0;
|
|
2996
|
+
}
|
|
2997
|
+
if (y < 0) {
|
|
2998
|
+
h += y;
|
|
2530
2999
|
y = 0;
|
|
2531
|
-
w = dst.width;
|
|
2532
|
-
h = dst.height;
|
|
2533
3000
|
}
|
|
2534
|
-
const
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
const dst32 = dst.data32;
|
|
2543
|
-
const dw = dst.width;
|
|
2544
|
-
if (actualW === dw && actualH === dst.height && finalX === 0 && finalY === 0) {
|
|
2545
|
-
dst32.fill(color);
|
|
2546
|
-
return;
|
|
3001
|
+
const actualW = Math.min(w, target.width - x);
|
|
3002
|
+
const actualH = Math.min(h, target.height - y);
|
|
3003
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
3004
|
+
let finalSrcColor = color;
|
|
3005
|
+
if (globalAlpha < 255) {
|
|
3006
|
+
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
3007
|
+
if (a === 0 && !isOverwrite) return false;
|
|
3008
|
+
finalSrcColor = (color & 16777215 | a << 24) >>> 0;
|
|
2547
3009
|
}
|
|
3010
|
+
const dst32 = target.data32;
|
|
3011
|
+
const dw = target.width;
|
|
3012
|
+
let dIdx = y * dw + x | 0;
|
|
3013
|
+
const dStride = dw - actualW | 0;
|
|
3014
|
+
let didChange = false;
|
|
2548
3015
|
for (let iy = 0; iy < actualH; iy++) {
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
3016
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
3017
|
+
const current = dst32[dIdx];
|
|
3018
|
+
const next = blendFn(finalSrcColor, current);
|
|
3019
|
+
if (current !== next) {
|
|
3020
|
+
dst32[dIdx] = next;
|
|
3021
|
+
didChange = true;
|
|
3022
|
+
}
|
|
3023
|
+
dIdx++;
|
|
3024
|
+
}
|
|
3025
|
+
dIdx += dStride;
|
|
2552
3026
|
}
|
|
3027
|
+
return didChange;
|
|
2553
3028
|
}
|
|
2554
3029
|
|
|
2555
|
-
// src/History/PixelMutator/
|
|
3030
|
+
// src/History/PixelMutator/mutatorBlendColor.ts
|
|
2556
3031
|
var defaults7 = {
|
|
2557
|
-
|
|
3032
|
+
blendColorPixelData
|
|
2558
3033
|
};
|
|
2559
|
-
var
|
|
3034
|
+
var mutatorBlendColor = ((writer, deps = defaults7) => {
|
|
2560
3035
|
const {
|
|
2561
|
-
|
|
3036
|
+
blendColorPixelData: blendColorPixelData2 = defaults7.blendColorPixelData
|
|
2562
3037
|
} = deps;
|
|
2563
3038
|
return {
|
|
2564
|
-
|
|
3039
|
+
blendColor(color, opts) {
|
|
2565
3040
|
const target = writer.config.target;
|
|
2566
|
-
const x =
|
|
2567
|
-
const y =
|
|
2568
|
-
const w =
|
|
2569
|
-
const h =
|
|
2570
|
-
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2571
|
-
|
|
3041
|
+
const x = opts?.x ?? 0;
|
|
3042
|
+
const y = opts?.y ?? 0;
|
|
3043
|
+
const w = opts?.w ?? target.width;
|
|
3044
|
+
const h = opts?.h ?? target.height;
|
|
3045
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3046
|
+
return didChange(blendColorPixelData2(target, color, opts));
|
|
2572
3047
|
}
|
|
2573
3048
|
};
|
|
2574
3049
|
});
|
|
2575
3050
|
|
|
2576
|
-
// src/PixelData/
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
3051
|
+
// src/PixelData/blendColorPixelDataAlphaMask.ts
|
|
3052
|
+
function blendColorPixelDataAlphaMask(target, color, mask, opts) {
|
|
3053
|
+
const targetX = opts?.x ?? 0;
|
|
3054
|
+
const targetY = opts?.y ?? 0;
|
|
3055
|
+
const w = opts?.w ?? mask.w;
|
|
3056
|
+
const h = opts?.h ?? mask.h;
|
|
3057
|
+
const globalAlpha = opts?.alpha ?? 255;
|
|
3058
|
+
const blendFn = opts?.blendFn ?? sourceOverPerfect;
|
|
3059
|
+
const mx = opts?.mx ?? 0;
|
|
3060
|
+
const my = opts?.my ?? 0;
|
|
3061
|
+
const invertMask = opts?.invertMask ?? false;
|
|
3062
|
+
if (globalAlpha === 0) return false;
|
|
3063
|
+
const baseSrcAlpha = color >>> 24;
|
|
3064
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
3065
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
3066
|
+
let x = targetX;
|
|
3067
|
+
let y = targetY;
|
|
3068
|
+
let actualW = w;
|
|
3069
|
+
let actualH = h;
|
|
3070
|
+
if (x < 0) {
|
|
3071
|
+
actualW += x;
|
|
2594
3072
|
x = 0;
|
|
3073
|
+
}
|
|
3074
|
+
if (y < 0) {
|
|
3075
|
+
actualH += y;
|
|
2595
3076
|
y = 0;
|
|
2596
|
-
w = dst.width;
|
|
2597
|
-
h = dst.height;
|
|
2598
3077
|
}
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
const
|
|
2608
|
-
|
|
2609
|
-
let
|
|
3078
|
+
actualW = Math.min(actualW, target.width - x);
|
|
3079
|
+
actualH = Math.min(actualH, target.height - y);
|
|
3080
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
3081
|
+
const dx = x - targetX | 0;
|
|
3082
|
+
const dy = y - targetY | 0;
|
|
3083
|
+
const dst32 = target.data32;
|
|
3084
|
+
const dw = target.width;
|
|
3085
|
+
const mPitch = mask.w;
|
|
3086
|
+
const maskData = mask.data;
|
|
3087
|
+
let dIdx = y * dw + x | 0;
|
|
3088
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
3089
|
+
const dStride = dw - actualW | 0;
|
|
3090
|
+
const mStride = mPitch - actualW | 0;
|
|
3091
|
+
const isOpaque = globalAlpha === 255;
|
|
3092
|
+
const colorRGB = color & 16777215;
|
|
3093
|
+
let didChange = false;
|
|
2610
3094
|
for (let iy = 0; iy < actualH; iy++) {
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
3095
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
3096
|
+
const mVal = maskData[mIdx];
|
|
3097
|
+
const effM = invertMask ? 255 - mVal : mVal;
|
|
3098
|
+
if (effM === 0) {
|
|
3099
|
+
dIdx++;
|
|
3100
|
+
mIdx++;
|
|
3101
|
+
continue;
|
|
3102
|
+
}
|
|
3103
|
+
let weight = globalAlpha;
|
|
3104
|
+
if (isOpaque) {
|
|
3105
|
+
weight = effM;
|
|
3106
|
+
} else if (effM !== 255) {
|
|
3107
|
+
weight = effM * globalAlpha + 128 >> 8;
|
|
2618
3108
|
}
|
|
3109
|
+
if (weight === 0) {
|
|
3110
|
+
dIdx++;
|
|
3111
|
+
mIdx++;
|
|
3112
|
+
continue;
|
|
3113
|
+
}
|
|
3114
|
+
let finalCol = color;
|
|
3115
|
+
if (weight < 255) {
|
|
3116
|
+
const a = baseSrcAlpha * weight + 128 >> 8;
|
|
3117
|
+
if (a === 0 && !isOverwrite) {
|
|
3118
|
+
dIdx++;
|
|
3119
|
+
mIdx++;
|
|
3120
|
+
continue;
|
|
3121
|
+
}
|
|
3122
|
+
finalCol = (colorRGB | a << 24) >>> 0;
|
|
3123
|
+
}
|
|
3124
|
+
const current = dst32[dIdx];
|
|
3125
|
+
const next = blendFn(finalCol, current);
|
|
3126
|
+
if (current !== next) {
|
|
3127
|
+
dst32[dIdx] = next;
|
|
3128
|
+
didChange = true;
|
|
3129
|
+
}
|
|
3130
|
+
dIdx++;
|
|
3131
|
+
mIdx++;
|
|
2619
3132
|
}
|
|
3133
|
+
dIdx += dStride;
|
|
3134
|
+
mIdx += mStride;
|
|
2620
3135
|
}
|
|
2621
|
-
return
|
|
3136
|
+
return didChange;
|
|
2622
3137
|
}
|
|
2623
3138
|
|
|
2624
|
-
// src/History/PixelMutator/
|
|
3139
|
+
// src/History/PixelMutator/mutatorBlendColorPaintAlphaMask.ts
|
|
2625
3140
|
var defaults8 = {
|
|
2626
|
-
|
|
3141
|
+
blendColorPixelDataAlphaMask
|
|
2627
3142
|
};
|
|
2628
|
-
var
|
|
3143
|
+
var mutatorBlendColorPaintAlphaMask = ((writer, deps = defaults8) => {
|
|
2629
3144
|
const {
|
|
2630
|
-
|
|
3145
|
+
blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults8.blendColorPixelDataAlphaMask
|
|
2631
3146
|
} = deps;
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
}
|
|
3147
|
+
const OPTS = {
|
|
3148
|
+
x: 0,
|
|
3149
|
+
y: 0,
|
|
3150
|
+
blendFn: sourceOverPerfect,
|
|
3151
|
+
alpha: 255
|
|
2638
3152
|
};
|
|
2639
|
-
});
|
|
2640
|
-
var mutatorFillRect = ((writer, deps = defaults8) => {
|
|
2641
|
-
const {
|
|
2642
|
-
fillPixelData: fillPixelData2 = defaults8.fillPixelData
|
|
2643
|
-
} = deps;
|
|
2644
3153
|
return {
|
|
2645
|
-
|
|
2646
|
-
const
|
|
2647
|
-
const
|
|
2648
|
-
|
|
3154
|
+
blendColorPaintAlphaMask(color, mask, x, y, alpha = 255, blendFn = sourceOverPerfect) {
|
|
3155
|
+
const tx = x + mask.centerOffsetX;
|
|
3156
|
+
const ty = y + mask.centerOffsetY;
|
|
3157
|
+
const didChange = writer.accumulator.storeRegionBeforeState(tx, ty, mask.w, mask.h);
|
|
3158
|
+
OPTS.x = tx;
|
|
3159
|
+
OPTS.y = ty;
|
|
3160
|
+
OPTS.alpha = alpha;
|
|
3161
|
+
OPTS.blendFn = blendFn;
|
|
3162
|
+
return didChange(blendColorPixelDataAlphaMask2(writer.config.target, color, mask, OPTS));
|
|
2649
3163
|
}
|
|
2650
3164
|
};
|
|
2651
3165
|
});
|
|
2652
3166
|
|
|
2653
|
-
// src/PixelData/
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
const
|
|
2660
|
-
|
|
2661
|
-
const
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
const colorRGB = color & 16777215;
|
|
2674
|
-
const a = baseSrcAlpha * alpha + 128 >> 8;
|
|
2675
|
-
finalCol = (colorRGB | a << 24) >>> 0;
|
|
2676
|
-
}
|
|
2677
|
-
let hasChanged = false;
|
|
2678
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
2679
|
-
const currentY = finalY + iy;
|
|
2680
|
-
const maskY = currentY - y;
|
|
2681
|
-
const maskOffset = maskY * maskW;
|
|
2682
|
-
const dstRowOffset = currentY * dw;
|
|
2683
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
2684
|
-
const currentX = finalX + ix;
|
|
2685
|
-
const maskX = currentX - x;
|
|
2686
|
-
const maskIndex = maskOffset + maskX;
|
|
2687
|
-
if (maskData[maskIndex]) {
|
|
2688
|
-
const current = dst32[dstRowOffset + currentX];
|
|
2689
|
-
if (current !== finalCol) {
|
|
2690
|
-
dst32[dstRowOffset + currentX] = finalCol;
|
|
2691
|
-
hasChanged = true;
|
|
2692
|
-
}
|
|
2693
|
-
}
|
|
2694
|
-
}
|
|
3167
|
+
// src/PixelData/blendColorPixelDataBinaryMask.ts
|
|
3168
|
+
function blendColorPixelDataBinaryMask(target, color, mask, opts) {
|
|
3169
|
+
const targetX = opts?.x ?? 0;
|
|
3170
|
+
const targetY = opts?.y ?? 0;
|
|
3171
|
+
let w = opts?.w ?? mask.w;
|
|
3172
|
+
let h = opts?.h ?? mask.h;
|
|
3173
|
+
const globalAlpha = opts?.alpha ?? 255;
|
|
3174
|
+
const blendFn = opts?.blendFn ?? sourceOverPerfect;
|
|
3175
|
+
const mx = opts?.mx ?? 0;
|
|
3176
|
+
const my = opts?.my ?? 0;
|
|
3177
|
+
const invertMask = opts?.invertMask ?? false;
|
|
3178
|
+
if (globalAlpha === 0) return false;
|
|
3179
|
+
const baseSrcAlpha = color >>> 24;
|
|
3180
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
3181
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
3182
|
+
let x = targetX;
|
|
3183
|
+
let y = targetY;
|
|
3184
|
+
if (x < 0) {
|
|
3185
|
+
w += x;
|
|
3186
|
+
x = 0;
|
|
2695
3187
|
}
|
|
2696
|
-
|
|
3188
|
+
if (y < 0) {
|
|
3189
|
+
h += y;
|
|
3190
|
+
y = 0;
|
|
3191
|
+
}
|
|
3192
|
+
const actualW = Math.min(w, target.width - x);
|
|
3193
|
+
const actualH = Math.min(h, target.height - y);
|
|
3194
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
3195
|
+
let baseColorWithGlobalAlpha = color;
|
|
3196
|
+
if (globalAlpha < 255) {
|
|
3197
|
+
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
3198
|
+
if (a === 0 && !isOverwrite) return false;
|
|
3199
|
+
baseColorWithGlobalAlpha = (color & 16777215 | a << 24) >>> 0;
|
|
3200
|
+
}
|
|
3201
|
+
const dx = x - targetX | 0;
|
|
3202
|
+
const dy = y - targetY | 0;
|
|
3203
|
+
const dst32 = target.data32;
|
|
3204
|
+
const dw = target.width;
|
|
3205
|
+
const mPitch = mask.w;
|
|
3206
|
+
const maskData = mask.data;
|
|
3207
|
+
let dIdx = y * dw + x | 0;
|
|
3208
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
3209
|
+
const dStride = dw - actualW | 0;
|
|
3210
|
+
const mStride = mPitch - actualW | 0;
|
|
3211
|
+
const skipVal = invertMask ? 1 : 0;
|
|
3212
|
+
let didChange = false;
|
|
3213
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
3214
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
3215
|
+
if (maskData[mIdx] === skipVal) {
|
|
3216
|
+
dIdx++;
|
|
3217
|
+
mIdx++;
|
|
3218
|
+
continue;
|
|
3219
|
+
}
|
|
3220
|
+
const current = dst32[dIdx];
|
|
3221
|
+
const next = blendFn(baseColorWithGlobalAlpha, current);
|
|
3222
|
+
if (current !== next) {
|
|
3223
|
+
dst32[dIdx] = next;
|
|
3224
|
+
didChange = true;
|
|
3225
|
+
}
|
|
3226
|
+
dIdx++;
|
|
3227
|
+
mIdx++;
|
|
3228
|
+
}
|
|
3229
|
+
dIdx += dStride;
|
|
3230
|
+
mIdx += mStride;
|
|
3231
|
+
}
|
|
3232
|
+
return didChange;
|
|
2697
3233
|
}
|
|
2698
3234
|
|
|
2699
|
-
// src/History/PixelMutator/
|
|
3235
|
+
// src/History/PixelMutator/mutatorBlendColorPaintBinaryMask.ts
|
|
2700
3236
|
var defaults9 = {
|
|
2701
|
-
|
|
3237
|
+
blendColorPixelDataBinaryMask
|
|
2702
3238
|
};
|
|
2703
|
-
var
|
|
3239
|
+
var mutatorBlendColorPaintBinaryMask = ((writer, deps = defaults9) => {
|
|
2704
3240
|
const {
|
|
2705
|
-
|
|
3241
|
+
blendColorPixelDataBinaryMask: blendColorPixelDataBinaryMask2 = defaults9.blendColorPixelDataBinaryMask
|
|
2706
3242
|
} = deps;
|
|
3243
|
+
const OPTS = {
|
|
3244
|
+
x: 0,
|
|
3245
|
+
y: 0,
|
|
3246
|
+
blendFn: sourceOverPerfect,
|
|
3247
|
+
alpha: 255
|
|
3248
|
+
};
|
|
2707
3249
|
return {
|
|
2708
|
-
|
|
2709
|
-
const
|
|
2710
|
-
|
|
3250
|
+
blendColorPaintBinaryMask(color, mask, x, y, alpha = 255, blendFn = sourceOverPerfect) {
|
|
3251
|
+
const tx = x + mask.centerOffsetX;
|
|
3252
|
+
const ty = y + mask.centerOffsetY;
|
|
3253
|
+
const didChange = writer.accumulator.storeRegionBeforeState(tx, ty, mask.w, mask.h);
|
|
3254
|
+
OPTS.x = tx;
|
|
3255
|
+
OPTS.y = ty;
|
|
3256
|
+
OPTS.alpha = alpha;
|
|
3257
|
+
OPTS.blendFn = blendFn;
|
|
3258
|
+
return didChange(blendColorPixelDataBinaryMask2(writer.config.target, color, mask, OPTS));
|
|
2711
3259
|
}
|
|
2712
3260
|
};
|
|
2713
3261
|
});
|
|
2714
3262
|
|
|
2715
|
-
// src/
|
|
2716
|
-
var
|
|
2717
|
-
|
|
2718
|
-
|
|
3263
|
+
// src/History/PixelMutator/mutatorBlendColorPaintMask.ts
|
|
3264
|
+
var defaults10 = {
|
|
3265
|
+
blendColorPixelDataAlphaMask,
|
|
3266
|
+
blendColorPixelDataBinaryMask
|
|
3267
|
+
};
|
|
3268
|
+
var mutatorBlendColorPaintMask = ((writer, deps = defaults10) => {
|
|
2719
3269
|
const {
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
}
|
|
2729
|
-
|
|
3270
|
+
blendColorPixelDataBinaryMask: blendColorPixelDataBinaryMask2 = defaults10.blendColorPixelDataBinaryMask,
|
|
3271
|
+
blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults10.blendColorPixelDataAlphaMask
|
|
3272
|
+
} = deps;
|
|
3273
|
+
const OPTS = {
|
|
3274
|
+
x: 0,
|
|
3275
|
+
y: 0,
|
|
3276
|
+
blendFn: sourceOverPerfect,
|
|
3277
|
+
alpha: 255
|
|
3278
|
+
};
|
|
3279
|
+
return {
|
|
3280
|
+
blendColorPaintMask(color, mask, x, y, alpha = 255, blendFn = sourceOverPerfect) {
|
|
3281
|
+
const tx = x + mask.centerOffsetX;
|
|
3282
|
+
const ty = y + mask.centerOffsetY;
|
|
3283
|
+
const didChange = writer.accumulator.storeRegionBeforeState(tx, ty, mask.w, mask.h);
|
|
3284
|
+
OPTS.x = tx;
|
|
3285
|
+
OPTS.y = ty;
|
|
3286
|
+
OPTS.alpha = alpha;
|
|
3287
|
+
OPTS.blendFn = blendFn;
|
|
3288
|
+
if (mask.type === 1 /* BINARY */) {
|
|
3289
|
+
return didChange(blendColorPixelDataBinaryMask2(writer.config.target, color, mask, OPTS));
|
|
3290
|
+
} else {
|
|
3291
|
+
return didChange(blendColorPixelDataAlphaMask2(writer.config.target, color, mask, OPTS));
|
|
3292
|
+
}
|
|
3293
|
+
}
|
|
3294
|
+
};
|
|
3295
|
+
});
|
|
3296
|
+
|
|
3297
|
+
// src/History/PixelMutator/mutatorBlendMask.ts
|
|
3298
|
+
var defaults11 = {
|
|
3299
|
+
blendPixelDataAlphaMask,
|
|
3300
|
+
blendPixelDataBinaryMask
|
|
3301
|
+
};
|
|
3302
|
+
var mutatorBlendMask = ((writer, deps = defaults11) => {
|
|
3303
|
+
const {
|
|
3304
|
+
blendPixelDataAlphaMask: blendPixelDataAlphaMask2 = defaults11.blendPixelDataAlphaMask,
|
|
3305
|
+
blendPixelDataBinaryMask: blendPixelDataBinaryMask2 = defaults11.blendPixelDataBinaryMask
|
|
3306
|
+
} = deps;
|
|
3307
|
+
return {
|
|
3308
|
+
blendMask(src, mask, opts) {
|
|
3309
|
+
const x = opts?.x ?? 0;
|
|
3310
|
+
const y = opts?.y ?? 0;
|
|
3311
|
+
const w = opts?.w ?? src.width;
|
|
3312
|
+
const h = opts?.h ?? src.height;
|
|
3313
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3314
|
+
if (mask.type === 1 /* BINARY */) {
|
|
3315
|
+
return didChange(blendPixelDataBinaryMask2(writer.config.target, src, mask, opts));
|
|
3316
|
+
} else {
|
|
3317
|
+
return didChange(blendPixelDataAlphaMask2(writer.config.target, src, mask, opts));
|
|
3318
|
+
}
|
|
3319
|
+
}
|
|
3320
|
+
};
|
|
3321
|
+
});
|
|
3322
|
+
|
|
3323
|
+
// src/History/PixelMutator/mutatorBlendPaintRect.ts
|
|
3324
|
+
var defaults12 = {
|
|
3325
|
+
blendColorPixelData
|
|
3326
|
+
};
|
|
3327
|
+
var mutatorBlendPaintRect = ((writer, deps = defaults12) => {
|
|
3328
|
+
const {
|
|
3329
|
+
blendColorPixelData: blendColorPixelData2 = defaults12.blendColorPixelData
|
|
3330
|
+
} = deps;
|
|
3331
|
+
const OPTS = {
|
|
3332
|
+
x: 0,
|
|
3333
|
+
y: 0,
|
|
3334
|
+
w: 0,
|
|
3335
|
+
h: 0,
|
|
3336
|
+
blendFn: sourceOverPerfect,
|
|
3337
|
+
alpha: 255
|
|
3338
|
+
};
|
|
3339
|
+
return {
|
|
3340
|
+
blendPaintRect(color, centerX, centerY, brushWidth, brushHeight, alpha = 255, blendFn = sourceOverPerfect) {
|
|
3341
|
+
const target = writer.config.target;
|
|
3342
|
+
const topLeftX = centerX + -(brushWidth - 1 >> 1);
|
|
3343
|
+
const topLeftY = centerY + -(brushHeight - 1 >> 1);
|
|
3344
|
+
OPTS.x = topLeftX;
|
|
3345
|
+
OPTS.y = topLeftY;
|
|
3346
|
+
OPTS.w = brushWidth;
|
|
3347
|
+
OPTS.h = brushHeight;
|
|
3348
|
+
OPTS.blendFn = blendFn;
|
|
3349
|
+
OPTS.alpha = alpha;
|
|
3350
|
+
const didChange = writer.accumulator.storeRegionBeforeState(topLeftX, topLeftY, brushWidth, brushHeight);
|
|
3351
|
+
return didChange(blendColorPixelData2(target, color, OPTS));
|
|
3352
|
+
}
|
|
3353
|
+
};
|
|
3354
|
+
});
|
|
3355
|
+
|
|
3356
|
+
// src/PixelData/blendPixel.ts
|
|
3357
|
+
function blendPixel(target, x, y, color, alpha = 255, blendFn = sourceOverPerfect) {
|
|
3358
|
+
if (alpha === 0) return false;
|
|
3359
|
+
let width = target.width;
|
|
3360
|
+
let height = target.height;
|
|
3361
|
+
if (x < 0 || x >= width || y < 0 || y >= height) return false;
|
|
3362
|
+
let srcAlpha = color >>> 24;
|
|
3363
|
+
let isOverwrite = blendFn.isOverwrite;
|
|
3364
|
+
if (srcAlpha === 0 && !isOverwrite) return false;
|
|
3365
|
+
let dst32 = target.data32;
|
|
3366
|
+
let index = y * width + x;
|
|
3367
|
+
let finalColor = color;
|
|
3368
|
+
if (alpha !== 255) {
|
|
3369
|
+
let finalAlpha = srcAlpha * alpha + 128 >> 8;
|
|
3370
|
+
if (finalAlpha === 0 && !isOverwrite) return false;
|
|
3371
|
+
finalColor = (color & 16777215 | finalAlpha << 24) >>> 0;
|
|
3372
|
+
}
|
|
3373
|
+
let current = dst32[index];
|
|
3374
|
+
let next = blendFn(finalColor, current);
|
|
3375
|
+
if (current !== next) {
|
|
3376
|
+
dst32[index] = next;
|
|
3377
|
+
return true;
|
|
3378
|
+
}
|
|
3379
|
+
return false;
|
|
3380
|
+
}
|
|
3381
|
+
|
|
3382
|
+
// src/History/PixelMutator/mutatorBlendPixel.ts
|
|
3383
|
+
var defaults13 = {
|
|
3384
|
+
blendPixel
|
|
3385
|
+
};
|
|
3386
|
+
var mutatorBlendPixel = ((writer, deps = defaults13) => {
|
|
3387
|
+
const {
|
|
3388
|
+
blendPixel: blendPixel2 = defaults13.blendPixel
|
|
3389
|
+
} = deps;
|
|
3390
|
+
return {
|
|
3391
|
+
blendPixel(x, y, color, alpha, blendFn) {
|
|
3392
|
+
const didChange = writer.accumulator.storePixelBeforeState(x, y);
|
|
3393
|
+
return didChange(blendPixel2(writer.config.target, x, y, color, alpha, blendFn));
|
|
3394
|
+
}
|
|
3395
|
+
};
|
|
3396
|
+
});
|
|
3397
|
+
|
|
3398
|
+
// src/History/PixelMutator/mutatorBlendPixelData.ts
|
|
3399
|
+
var defaults14 = {
|
|
3400
|
+
blendPixelData
|
|
3401
|
+
};
|
|
3402
|
+
var mutatorBlendPixelData = ((writer, deps = defaults14) => {
|
|
3403
|
+
const {
|
|
3404
|
+
blendPixelData: blendPixelData2 = defaults14.blendPixelData
|
|
3405
|
+
} = deps;
|
|
3406
|
+
return {
|
|
3407
|
+
blendPixelData(src, opts) {
|
|
3408
|
+
const x = opts?.x ?? 0;
|
|
3409
|
+
const y = opts?.y ?? 0;
|
|
3410
|
+
const w = opts?.w ?? src.width;
|
|
3411
|
+
const h = opts?.h ?? src.height;
|
|
3412
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3413
|
+
return didChange(blendPixelData2(writer.config.target, src, opts));
|
|
3414
|
+
}
|
|
3415
|
+
};
|
|
3416
|
+
});
|
|
3417
|
+
|
|
3418
|
+
// src/PixelData/fillPixelData.ts
|
|
3419
|
+
var SCRATCH_RECT = makeClippedRect();
|
|
3420
|
+
function fillPixelData(dst, color, _x, _y, _w, _h) {
|
|
3421
|
+
let x;
|
|
3422
|
+
let y;
|
|
3423
|
+
let w;
|
|
3424
|
+
let h;
|
|
3425
|
+
if (typeof _x === "object") {
|
|
3426
|
+
x = _x.x ?? 0;
|
|
3427
|
+
y = _x.y ?? 0;
|
|
3428
|
+
w = _x.w ?? dst.width;
|
|
3429
|
+
h = _x.h ?? dst.height;
|
|
3430
|
+
} else if (typeof _x === "number") {
|
|
3431
|
+
x = _x;
|
|
3432
|
+
y = _y;
|
|
3433
|
+
w = _w;
|
|
3434
|
+
h = _h;
|
|
3435
|
+
} else {
|
|
3436
|
+
x = 0;
|
|
3437
|
+
y = 0;
|
|
3438
|
+
w = dst.width;
|
|
3439
|
+
h = dst.height;
|
|
3440
|
+
}
|
|
3441
|
+
const clip = resolveRectClipping(x, y, w, h, dst.width, dst.height, SCRATCH_RECT);
|
|
2730
3442
|
if (!clip.inBounds) return false;
|
|
2731
3443
|
const {
|
|
2732
|
-
x,
|
|
2733
|
-
y,
|
|
3444
|
+
x: finalX,
|
|
3445
|
+
y: finalY,
|
|
2734
3446
|
w: actualW,
|
|
2735
3447
|
h: actualH
|
|
2736
3448
|
} = clip;
|
|
2737
3449
|
const dst32 = dst.data32;
|
|
2738
3450
|
const dw = dst.width;
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
2749
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
2750
|
-
const mVal = maskData[mIdx];
|
|
2751
|
-
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
2752
|
-
if (isHit) {
|
|
2753
|
-
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
2754
|
-
}
|
|
2755
|
-
dIdx++;
|
|
2756
|
-
mIdx++;
|
|
2757
|
-
}
|
|
2758
|
-
dIdx += dStride;
|
|
2759
|
-
mIdx += mStride;
|
|
2760
|
-
}
|
|
2761
|
-
} else {
|
|
2762
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
2763
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
2764
|
-
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
2765
|
-
dIdx++;
|
|
3451
|
+
let hasChanged = false;
|
|
3452
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
3453
|
+
const rowOffset = (finalY + iy) * dw;
|
|
3454
|
+
const start = rowOffset + finalX;
|
|
3455
|
+
const end = start + actualW;
|
|
3456
|
+
for (let i = start; i < end; i++) {
|
|
3457
|
+
if (dst32[i] !== color) {
|
|
3458
|
+
dst32[i] = color;
|
|
3459
|
+
hasChanged = true;
|
|
2766
3460
|
}
|
|
2767
|
-
dIdx += dStride;
|
|
2768
3461
|
}
|
|
2769
3462
|
}
|
|
2770
|
-
return
|
|
3463
|
+
return hasChanged;
|
|
2771
3464
|
}
|
|
2772
3465
|
|
|
2773
|
-
// src/History/PixelMutator/
|
|
2774
|
-
var
|
|
2775
|
-
|
|
3466
|
+
// src/History/PixelMutator/mutatorClear.ts
|
|
3467
|
+
var defaults15 = {
|
|
3468
|
+
fillPixelData
|
|
2776
3469
|
};
|
|
2777
|
-
var
|
|
3470
|
+
var mutatorClear = ((writer, deps = defaults15) => {
|
|
2778
3471
|
const {
|
|
2779
|
-
|
|
3472
|
+
fillPixelData: fillPixelData2 = defaults15.fillPixelData
|
|
2780
3473
|
} = deps;
|
|
2781
3474
|
return {
|
|
2782
|
-
|
|
3475
|
+
clear(rect) {
|
|
2783
3476
|
const target = writer.config.target;
|
|
2784
|
-
const
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
h = target.height
|
|
2789
|
-
} = opts;
|
|
3477
|
+
const x = rect?.x ?? 0;
|
|
3478
|
+
const y = rect?.y ?? 0;
|
|
3479
|
+
const w = rect?.w ?? target.width;
|
|
3480
|
+
const h = rect?.h ?? target.height;
|
|
2790
3481
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2791
|
-
return didChange(
|
|
3482
|
+
return didChange(fillPixelData2(target, 0, x, y, w, h));
|
|
2792
3483
|
}
|
|
2793
3484
|
};
|
|
2794
3485
|
});
|
|
2795
3486
|
|
|
2796
|
-
// src/History/PixelMutator.ts
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
// @sort
|
|
2800
|
-
...mutatorBlendColor(writer),
|
|
2801
|
-
...mutatorBlendPixel(writer),
|
|
2802
|
-
...mutatorBlendPixelData(writer),
|
|
2803
|
-
...mutatorBlendPixelDataAlphaMask(writer),
|
|
2804
|
-
...mutatorBlendPixelDataBinaryMask(writer),
|
|
2805
|
-
...mutatorClear(writer),
|
|
2806
|
-
...mutatorFill(writer),
|
|
2807
|
-
...mutatorFillBinaryMask(writer),
|
|
2808
|
-
...mutatorFillRect(writer),
|
|
2809
|
-
...mutatorInvert(writer)
|
|
2810
|
-
};
|
|
2811
|
-
}
|
|
2812
|
-
|
|
2813
|
-
// src/ImageData/resizeImageData.ts
|
|
2814
|
-
function resizeImageData(target, newWidth, newHeight, offsetX = 0, offsetY = 0) {
|
|
2815
|
-
const result = new ImageData(newWidth, newHeight);
|
|
2816
|
-
const {
|
|
2817
|
-
width: oldW,
|
|
2818
|
-
height: oldH,
|
|
2819
|
-
data: oldData
|
|
2820
|
-
} = target;
|
|
2821
|
-
const newData = result.data;
|
|
2822
|
-
const x0 = Math.max(0, offsetX);
|
|
2823
|
-
const y0 = Math.max(0, offsetY);
|
|
2824
|
-
const x1 = Math.min(newWidth, offsetX + oldW);
|
|
2825
|
-
const y1 = Math.min(newHeight, offsetY + oldH);
|
|
2826
|
-
if (x1 <= x0 || y1 <= y0) {
|
|
2827
|
-
return result;
|
|
2828
|
-
}
|
|
2829
|
-
const rowCount = y1 - y0;
|
|
2830
|
-
const rowLen = (x1 - x0) * 4;
|
|
2831
|
-
for (let row = 0; row < rowCount; row++) {
|
|
2832
|
-
const dstY = y0 + row;
|
|
2833
|
-
const srcY = dstY - offsetY;
|
|
2834
|
-
const srcX = x0 - offsetX;
|
|
2835
|
-
const dstStart = (dstY * newWidth + x0) * 4;
|
|
2836
|
-
const srcStart = (srcY * oldW + srcX) * 4;
|
|
2837
|
-
newData.set(oldData.subarray(srcStart, srcStart + rowLen), dstStart);
|
|
2838
|
-
}
|
|
2839
|
-
return result;
|
|
2840
|
-
}
|
|
2841
|
-
|
|
2842
|
-
// src/Internal/helpers.ts
|
|
2843
|
-
var macro_halfAndFloor = (value) => value >> 1;
|
|
2844
|
-
|
|
2845
|
-
// src/Rect/trimRectBounds.ts
|
|
2846
|
-
function trimRectBounds(x, y, w, h, targetWidth, targetHeight, out) {
|
|
2847
|
-
const res = out ?? {
|
|
2848
|
-
x: 0,
|
|
2849
|
-
y: 0,
|
|
2850
|
-
w: 0,
|
|
2851
|
-
h: 0
|
|
2852
|
-
};
|
|
2853
|
-
const left = Math.max(0, x);
|
|
2854
|
-
const top = Math.max(0, y);
|
|
2855
|
-
const right = Math.min(targetWidth, x + w);
|
|
2856
|
-
const bottom = Math.min(targetHeight, y + h);
|
|
2857
|
-
res.x = left;
|
|
2858
|
-
res.y = top;
|
|
2859
|
-
res.w = Math.max(0, right - left);
|
|
2860
|
-
res.h = Math.max(0, bottom - top);
|
|
2861
|
-
return res;
|
|
2862
|
-
}
|
|
2863
|
-
|
|
2864
|
-
// src/Paint/PaintBuffer.ts
|
|
2865
|
-
var PaintBuffer = class {
|
|
2866
|
-
constructor(config, tilePool) {
|
|
2867
|
-
this.config = config;
|
|
2868
|
-
this.tilePool = tilePool;
|
|
2869
|
-
this.lookup = [];
|
|
2870
|
-
}
|
|
2871
|
-
lookup;
|
|
2872
|
-
scratchBounds = {
|
|
2873
|
-
x: 0,
|
|
2874
|
-
y: 0,
|
|
2875
|
-
w: 0,
|
|
2876
|
-
h: 0
|
|
2877
|
-
};
|
|
2878
|
-
eachTileInBounds(bounds, callback) {
|
|
2879
|
-
const {
|
|
2880
|
-
tileShift,
|
|
2881
|
-
targetColumns,
|
|
2882
|
-
targetRows,
|
|
2883
|
-
tileSize
|
|
2884
|
-
} = this.config;
|
|
2885
|
-
const x1 = Math.max(0, bounds.x >> tileShift);
|
|
2886
|
-
const y1 = Math.max(0, bounds.y >> tileShift);
|
|
2887
|
-
const x2 = Math.min(targetColumns - 1, bounds.x + bounds.w - 1 >> tileShift);
|
|
2888
|
-
const y2 = Math.min(targetRows - 1, bounds.y + bounds.h - 1 >> tileShift);
|
|
2889
|
-
if (x1 > x2 || y1 > y2) return;
|
|
2890
|
-
const lookup = this.lookup;
|
|
2891
|
-
const tilePool = this.tilePool;
|
|
2892
|
-
for (let ty = y1; ty <= y2; ty++) {
|
|
2893
|
-
const rowOffset = ty * targetColumns;
|
|
2894
|
-
const tileTop = ty << tileShift;
|
|
2895
|
-
for (let tx = x1; tx <= x2; tx++) {
|
|
2896
|
-
const id = rowOffset + tx;
|
|
2897
|
-
const tile = lookup[id] ?? (lookup[id] = tilePool.getTile(id, tx, ty));
|
|
2898
|
-
const tileLeft = tx << tileShift;
|
|
2899
|
-
const startX = bounds.x > tileLeft ? bounds.x : tileLeft;
|
|
2900
|
-
const startY = bounds.y > tileTop ? bounds.y : tileTop;
|
|
2901
|
-
const maskEndX = bounds.x + bounds.w;
|
|
2902
|
-
const tileEndX = tileLeft + tileSize;
|
|
2903
|
-
const endX = maskEndX < tileEndX ? maskEndX : tileEndX;
|
|
2904
|
-
const maskEndY = bounds.y + bounds.h;
|
|
2905
|
-
const tileEndY = tileTop + tileSize;
|
|
2906
|
-
const endY = maskEndY < tileEndY ? maskEndY : tileEndY;
|
|
2907
|
-
callback(tile, startX, startY, endX - startX, endY - startY);
|
|
2908
|
-
}
|
|
2909
|
-
}
|
|
2910
|
-
}
|
|
2911
|
-
writePaintAlphaMaskStroke(color, brush, x0, y0, x1, y1) {
|
|
2912
|
-
const cA = color >>> 24;
|
|
2913
|
-
if (cA === 0) return false;
|
|
2914
|
-
const {
|
|
2915
|
-
tileShift,
|
|
2916
|
-
tileMask,
|
|
2917
|
-
target
|
|
2918
|
-
} = this.config;
|
|
2919
|
-
const {
|
|
2920
|
-
w: bW,
|
|
2921
|
-
h: bH,
|
|
2922
|
-
data: bD,
|
|
2923
|
-
centerOffsetX,
|
|
2924
|
-
centerOffsetY
|
|
2925
|
-
} = brush;
|
|
2926
|
-
const cRGB = color & 16777215;
|
|
2927
|
-
const scratch = this.scratchBounds;
|
|
2928
|
-
let changed = false;
|
|
2929
|
-
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
2930
|
-
const topLeftX = Math.floor(px + centerOffsetX);
|
|
2931
|
-
const topLeftY = Math.floor(py + centerOffsetY);
|
|
2932
|
-
trimRectBounds(topLeftX, topLeftY, bW, bH, target.width, target.height, scratch);
|
|
2933
|
-
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
2934
|
-
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
2935
|
-
const d32 = tile.data32;
|
|
2936
|
-
let tileChanged = false;
|
|
2937
|
-
for (let i = 0; i < bH_t; i++) {
|
|
2938
|
-
const canvasY = bY + i;
|
|
2939
|
-
const bOff = (canvasY - topLeftY) * bW;
|
|
2940
|
-
const tOff = (canvasY & tileMask) << tileShift;
|
|
2941
|
-
const dS = tOff + (bX & tileMask);
|
|
2942
|
-
for (let j = 0; j < bW_t; j++) {
|
|
2943
|
-
const canvasX = bX + j;
|
|
2944
|
-
const brushA = bD[bOff + (canvasX - topLeftX)];
|
|
2945
|
-
if (brushA === 0) continue;
|
|
2946
|
-
const t = cA * brushA + 128;
|
|
2947
|
-
const blendedA = t + (t >> 8) >> 8;
|
|
2948
|
-
const idx = dS + j;
|
|
2949
|
-
const cur = d32[idx];
|
|
2950
|
-
if (brushA > cur >>> 24) {
|
|
2951
|
-
const next = (cRGB | blendedA << 24) >>> 0;
|
|
2952
|
-
if (cur !== next) {
|
|
2953
|
-
d32[idx] = next;
|
|
2954
|
-
tileChanged = true;
|
|
2955
|
-
}
|
|
2956
|
-
}
|
|
2957
|
-
}
|
|
2958
|
-
}
|
|
2959
|
-
if (tileChanged) changed = true;
|
|
2960
|
-
});
|
|
2961
|
-
});
|
|
2962
|
-
return changed;
|
|
2963
|
-
}
|
|
2964
|
-
writePaintBinaryMaskStroke(color, brush, x0, y0, x1, y1) {
|
|
2965
|
-
const alphaIsZero = color >>> 24 === 0;
|
|
2966
|
-
if (alphaIsZero) return false;
|
|
2967
|
-
const {
|
|
2968
|
-
tileShift,
|
|
2969
|
-
tileMask,
|
|
2970
|
-
target
|
|
2971
|
-
} = this.config;
|
|
2972
|
-
const {
|
|
2973
|
-
w: bW,
|
|
2974
|
-
h: bH,
|
|
2975
|
-
data: bD,
|
|
2976
|
-
centerOffsetX,
|
|
2977
|
-
centerOffsetY
|
|
2978
|
-
} = brush;
|
|
2979
|
-
const scratch = this.scratchBounds;
|
|
2980
|
-
let changed = false;
|
|
2981
|
-
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
2982
|
-
const topLeftX = Math.floor(px + centerOffsetX);
|
|
2983
|
-
const topLeftY = Math.floor(py + centerOffsetY);
|
|
2984
|
-
trimRectBounds(topLeftX, topLeftY, bW, bH, target.width, target.height, scratch);
|
|
2985
|
-
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
2986
|
-
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
2987
|
-
const d32 = tile.data32;
|
|
2988
|
-
let tileChanged = false;
|
|
2989
|
-
for (let i = 0; i < bH_t; i++) {
|
|
2990
|
-
const canvasY = bY + i;
|
|
2991
|
-
const bOff = (canvasY - topLeftY) * bW;
|
|
2992
|
-
const tOff = (canvasY & tileMask) << tileShift;
|
|
2993
|
-
const dS = tOff + (bX & tileMask);
|
|
2994
|
-
for (let j = 0; j < bW_t; j++) {
|
|
2995
|
-
const canvasX = bX + j;
|
|
2996
|
-
if (bD[bOff + (canvasX - topLeftX)]) {
|
|
2997
|
-
const idx = dS + j;
|
|
2998
|
-
if (d32[idx] !== color) {
|
|
2999
|
-
d32[idx] = color;
|
|
3000
|
-
tileChanged = true;
|
|
3001
|
-
}
|
|
3002
|
-
}
|
|
3003
|
-
}
|
|
3004
|
-
}
|
|
3005
|
-
if (tileChanged) changed = true;
|
|
3006
|
-
});
|
|
3007
|
-
});
|
|
3008
|
-
return changed;
|
|
3009
|
-
}
|
|
3010
|
-
writeRectStroke(color, brushWidth, brushHeight, x0, y0, x1, y1) {
|
|
3011
|
-
const alphaIsZero = color >>> 24 === 0;
|
|
3012
|
-
if (alphaIsZero) return false;
|
|
3013
|
-
const config = this.config;
|
|
3014
|
-
const tileShift = config.tileShift;
|
|
3015
|
-
const tileMask = config.tileMask;
|
|
3016
|
-
const target = config.target;
|
|
3017
|
-
const scratch = this.scratchBounds;
|
|
3018
|
-
const centerOffsetX = macro_halfAndFloor(brushWidth - 1);
|
|
3019
|
-
const centerOffsetY = macro_halfAndFloor(brushHeight - 1);
|
|
3020
|
-
let changed = false;
|
|
3021
|
-
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
3022
|
-
const topLeftX = Math.floor(px + centerOffsetX);
|
|
3023
|
-
const topLeftY = Math.floor(py + centerOffsetY);
|
|
3024
|
-
trimRectBounds(topLeftX, topLeftY, brushWidth, brushHeight, target.width, target.height, scratch);
|
|
3025
|
-
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
3026
|
-
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
3027
|
-
const d32 = tile.data32;
|
|
3028
|
-
let tileChanged = false;
|
|
3029
|
-
for (let i = 0; i < bH_t; i++) {
|
|
3030
|
-
const canvasY = bY + i;
|
|
3031
|
-
const tOff = (canvasY & tileMask) << tileShift;
|
|
3032
|
-
const dS = tOff + (bX & tileMask);
|
|
3033
|
-
for (let j = 0; j < bW_t; j++) {
|
|
3034
|
-
const idx = dS + j;
|
|
3035
|
-
if (d32[idx] !== color) {
|
|
3036
|
-
d32[idx] = color;
|
|
3037
|
-
tileChanged = true;
|
|
3038
|
-
}
|
|
3039
|
-
}
|
|
3040
|
-
}
|
|
3041
|
-
if (tileChanged) {
|
|
3042
|
-
changed = true;
|
|
3043
|
-
}
|
|
3044
|
-
});
|
|
3045
|
-
});
|
|
3046
|
-
return changed;
|
|
3047
|
-
}
|
|
3048
|
-
clear() {
|
|
3049
|
-
this.tilePool.releaseTiles(this.lookup);
|
|
3050
|
-
}
|
|
3051
|
-
};
|
|
3052
|
-
|
|
3053
|
-
// src/PixelTile/PixelTile.ts
|
|
3054
|
-
var PixelTile = class {
|
|
3055
|
-
constructor(id, tx, ty, tileSize, tileArea) {
|
|
3056
|
-
this.id = id;
|
|
3057
|
-
this.tx = tx;
|
|
3058
|
-
this.ty = ty;
|
|
3059
|
-
this.width = this.height = tileSize;
|
|
3060
|
-
this.data32 = new Uint32Array(tileArea);
|
|
3061
|
-
const data8 = new Uint8ClampedArray(this.data32.buffer);
|
|
3062
|
-
this.imageData = new ImageData(data8, tileSize, tileSize);
|
|
3063
|
-
}
|
|
3064
|
-
data32;
|
|
3065
|
-
width;
|
|
3066
|
-
height;
|
|
3067
|
-
imageData;
|
|
3068
|
-
};
|
|
3069
|
-
|
|
3070
|
-
// src/PixelTile/PixelTilePool.ts
|
|
3071
|
-
var PixelTilePool = class {
|
|
3072
|
-
pool;
|
|
3073
|
-
tileSize;
|
|
3074
|
-
tileArea;
|
|
3075
|
-
constructor(config) {
|
|
3076
|
-
this.pool = [];
|
|
3077
|
-
this.tileSize = config.tileSize;
|
|
3078
|
-
this.tileArea = config.tileArea;
|
|
3079
|
-
}
|
|
3080
|
-
getTile(id, tx, ty) {
|
|
3081
|
-
let tile = this.pool.pop();
|
|
3082
|
-
if (tile) {
|
|
3083
|
-
tile.id = id;
|
|
3084
|
-
tile.tx = tx;
|
|
3085
|
-
tile.ty = ty;
|
|
3086
|
-
tile.data32.fill(0);
|
|
3087
|
-
return tile;
|
|
3088
|
-
}
|
|
3089
|
-
return new PixelTile(id, tx, ty, this.tileSize, this.tileArea);
|
|
3090
|
-
}
|
|
3091
|
-
releaseTile(tile) {
|
|
3092
|
-
this.pool.push(tile);
|
|
3093
|
-
}
|
|
3094
|
-
releaseTiles(tiles) {
|
|
3095
|
-
let length = tiles.length;
|
|
3096
|
-
for (let i = 0; i < length; i++) {
|
|
3097
|
-
let tile = tiles[i];
|
|
3098
|
-
if (tile) {
|
|
3099
|
-
this.pool.push(tile);
|
|
3100
|
-
}
|
|
3101
|
-
}
|
|
3102
|
-
tiles.length = 0;
|
|
3103
|
-
}
|
|
3104
|
-
};
|
|
3105
|
-
|
|
3106
|
-
// src/History/PixelWriter.ts
|
|
3107
|
-
var PixelWriter = class {
|
|
3108
|
-
historyManager;
|
|
3109
|
-
accumulator;
|
|
3110
|
-
historyActionFactory;
|
|
3111
|
-
config;
|
|
3112
|
-
pixelTilePool;
|
|
3113
|
-
paintBuffer;
|
|
3114
|
-
mutator;
|
|
3115
|
-
blendPixelDataOpts = {
|
|
3116
|
-
alpha: 255,
|
|
3117
|
-
blendFn: sourceOverPerfect,
|
|
3118
|
-
x: 0,
|
|
3119
|
-
y: 0,
|
|
3120
|
-
w: 0,
|
|
3121
|
-
h: 0
|
|
3122
|
-
};
|
|
3123
|
-
_inProgress = false;
|
|
3124
|
-
constructor(target, mutatorFactory, {
|
|
3125
|
-
tileSize = 256,
|
|
3126
|
-
maxHistorySteps = 50,
|
|
3127
|
-
historyManager = new HistoryManager(maxHistorySteps),
|
|
3128
|
-
historyActionFactory = makeHistoryAction,
|
|
3129
|
-
pixelTilePool,
|
|
3130
|
-
accumulator
|
|
3131
|
-
} = {}) {
|
|
3132
|
-
this.config = new PixelEngineConfig(tileSize, target);
|
|
3133
|
-
this.historyManager = historyManager;
|
|
3134
|
-
this.pixelTilePool = pixelTilePool ?? new PixelTilePool(this.config);
|
|
3135
|
-
this.accumulator = accumulator ?? new PixelAccumulator(this.config, this.pixelTilePool);
|
|
3136
|
-
this.historyActionFactory = historyActionFactory;
|
|
3137
|
-
this.mutator = mutatorFactory(this);
|
|
3138
|
-
this.paintBuffer = new PaintBuffer(this.config, this.pixelTilePool);
|
|
3139
|
-
}
|
|
3140
|
-
/**
|
|
3141
|
-
* Executes `transaction` and commits the resulting pixel changes as a single
|
|
3142
|
-
* undoable history action.
|
|
3143
|
-
*
|
|
3144
|
-
* - If `transaction` throws, all accumulated changes are rolled back and the error
|
|
3145
|
-
* is re-thrown. No action is committed.
|
|
3146
|
-
* - If `transaction` completes without modifying any pixels, no action is committed.
|
|
3147
|
-
* - `withHistory` is not re-entrant. Calling it again from inside `transaction` will
|
|
3148
|
-
* throw immediately to prevent silent data loss from a nested extractPatch.
|
|
3149
|
-
*
|
|
3150
|
-
* @param transaction Callback to be executed inside the transaction.
|
|
3151
|
-
* @param after Called after both undo and redo — use for generic change notifications.
|
|
3152
|
-
* @param afterUndo Called after undo only — use for dimension or state changes specific to undo.
|
|
3153
|
-
* @param afterRedo Called after redo only.
|
|
3154
|
-
*/
|
|
3155
|
-
withHistory(transaction, after, afterUndo, afterRedo) {
|
|
3156
|
-
if (this._inProgress) {
|
|
3157
|
-
throw new Error("withHistory is not re-entrant \u2014 commit or rollback the current operation first");
|
|
3158
|
-
}
|
|
3159
|
-
this._inProgress = true;
|
|
3160
|
-
try {
|
|
3161
|
-
transaction(this.mutator);
|
|
3162
|
-
} catch (e) {
|
|
3163
|
-
this.accumulator.rollbackAfterError();
|
|
3164
|
-
throw e;
|
|
3165
|
-
} finally {
|
|
3166
|
-
this._inProgress = false;
|
|
3167
|
-
}
|
|
3168
|
-
if (this.accumulator.beforeTiles.length === 0) return;
|
|
3169
|
-
const patch = this.accumulator.extractPatch();
|
|
3170
|
-
const action = this.historyActionFactory(this, patch, after, afterUndo, afterRedo);
|
|
3171
|
-
this.historyManager.commit(action);
|
|
3172
|
-
}
|
|
3173
|
-
resize(newWidth, newHeight, offsetX = 0, offsetY = 0, after, afterUndo, afterRedo, resizeImageDataFn = resizeImageData) {
|
|
3174
|
-
if (this._inProgress) {
|
|
3175
|
-
throw new Error("Cannot resize inside a withHistory callback");
|
|
3176
|
-
}
|
|
3177
|
-
if (this.accumulator.beforeTiles.length > 0) {
|
|
3178
|
-
throw new Error("Cannot resize with an open accumulator \u2014 commit or rollback first");
|
|
3179
|
-
}
|
|
3180
|
-
const config = this.config;
|
|
3181
|
-
const target = config.target;
|
|
3182
|
-
const beforeImageData = target.imageData;
|
|
3183
|
-
const afterImageData = resizeImageDataFn(beforeImageData, newWidth, newHeight, offsetX, offsetY);
|
|
3184
|
-
target.set(afterImageData);
|
|
3185
|
-
this.historyManager.commit({
|
|
3186
|
-
undo: () => {
|
|
3187
|
-
target.set(beforeImageData);
|
|
3188
|
-
afterUndo?.(beforeImageData);
|
|
3189
|
-
after?.(beforeImageData);
|
|
3190
|
-
},
|
|
3191
|
-
redo: () => {
|
|
3192
|
-
target.set(afterImageData);
|
|
3193
|
-
afterRedo?.(afterImageData);
|
|
3194
|
-
after?.(afterImageData);
|
|
3195
|
-
}
|
|
3196
|
-
});
|
|
3197
|
-
}
|
|
3198
|
-
commitPaintBuffer(alpha = 255, blendFn = sourceOverPerfect, blendPixelDataFn = blendPixelData) {
|
|
3199
|
-
const paintBuffer = this.paintBuffer;
|
|
3200
|
-
const tileShift = paintBuffer.config.tileShift;
|
|
3201
|
-
const lookup = paintBuffer.lookup;
|
|
3202
|
-
const opts = this.blendPixelDataOpts;
|
|
3203
|
-
opts.alpha = alpha;
|
|
3204
|
-
opts.blendFn = blendFn;
|
|
3205
|
-
for (let i = 0; i < lookup.length; i++) {
|
|
3206
|
-
const tile = lookup[i];
|
|
3207
|
-
if (tile) {
|
|
3208
|
-
const didChange = this.accumulator.storeTileBeforeState(tile.id, tile.tx, tile.ty);
|
|
3209
|
-
const dx = tile.tx << tileShift;
|
|
3210
|
-
const dy = tile.ty << tileShift;
|
|
3211
|
-
opts.x = dx;
|
|
3212
|
-
opts.y = dy;
|
|
3213
|
-
opts.w = tile.width;
|
|
3214
|
-
opts.h = tile.height;
|
|
3215
|
-
didChange(blendPixelDataFn(this.config.target, tile, opts));
|
|
3216
|
-
}
|
|
3217
|
-
}
|
|
3218
|
-
paintBuffer.clear();
|
|
3219
|
-
}
|
|
3487
|
+
// src/History/PixelMutator/mutatorFill.ts
|
|
3488
|
+
var defaults16 = {
|
|
3489
|
+
fillPixelData
|
|
3220
3490
|
};
|
|
3221
|
-
|
|
3222
|
-
// src/PixelData/applyAlphaMaskToPixelData.ts
|
|
3223
|
-
function applyAlphaMaskToPixelData(dst, mask, opts = {}) {
|
|
3491
|
+
var mutatorFill = ((writer, deps = defaults16) => {
|
|
3224
3492
|
const {
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
invertMask = false
|
|
3233
|
-
} = opts;
|
|
3234
|
-
if (globalAlpha === 0) return false;
|
|
3235
|
-
let x = targetX;
|
|
3236
|
-
let y = targetY;
|
|
3237
|
-
let w = width;
|
|
3238
|
-
let h = height;
|
|
3239
|
-
if (x < 0) {
|
|
3240
|
-
w += x;
|
|
3241
|
-
x = 0;
|
|
3242
|
-
}
|
|
3243
|
-
if (y < 0) {
|
|
3244
|
-
h += y;
|
|
3245
|
-
y = 0;
|
|
3246
|
-
}
|
|
3247
|
-
w = Math.min(w, dst.width - x);
|
|
3248
|
-
h = Math.min(h, dst.height - y);
|
|
3249
|
-
if (w <= 0) return false;
|
|
3250
|
-
if (h <= 0) return false;
|
|
3251
|
-
const mPitch = mask.w;
|
|
3252
|
-
if (mPitch <= 0) return false;
|
|
3253
|
-
const startX = mx + (x - targetX);
|
|
3254
|
-
const startY = my + (y - targetY);
|
|
3255
|
-
const sX0 = Math.max(0, startX);
|
|
3256
|
-
const sY0 = Math.max(0, startY);
|
|
3257
|
-
const sX1 = Math.min(mPitch, startX + w);
|
|
3258
|
-
const sY1 = Math.min(mask.h, startY + h);
|
|
3259
|
-
const finalW = sX1 - sX0;
|
|
3260
|
-
const finalH = sY1 - sY0;
|
|
3261
|
-
if (finalW <= 0) return false;
|
|
3262
|
-
if (finalH <= 0) return false;
|
|
3263
|
-
const xShift = sX0 - startX;
|
|
3264
|
-
const yShift = sY0 - startY;
|
|
3265
|
-
const dst32 = dst.data32;
|
|
3266
|
-
const dw = dst.width;
|
|
3267
|
-
const dStride = dw - finalW;
|
|
3268
|
-
const mStride = mPitch - finalW;
|
|
3269
|
-
const maskData = mask.data;
|
|
3270
|
-
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
3271
|
-
let mIdx = sY0 * mPitch + sX0;
|
|
3272
|
-
let didChange = false;
|
|
3273
|
-
for (let iy = 0; iy < h; iy++) {
|
|
3274
|
-
for (let ix = 0; ix < w; ix++) {
|
|
3275
|
-
const mVal = maskData[mIdx];
|
|
3276
|
-
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
3277
|
-
let weight = 0;
|
|
3278
|
-
if (effectiveM === 0) {
|
|
3279
|
-
weight = 0;
|
|
3280
|
-
} else if (effectiveM === 255) {
|
|
3281
|
-
weight = globalAlpha;
|
|
3282
|
-
} else if (globalAlpha === 255) {
|
|
3283
|
-
weight = effectiveM;
|
|
3284
|
-
} else {
|
|
3285
|
-
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
3286
|
-
}
|
|
3287
|
-
if (weight === 0) {
|
|
3288
|
-
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
3289
|
-
didChange = true;
|
|
3290
|
-
} else if (weight !== 255) {
|
|
3291
|
-
const d = dst32[dIdx];
|
|
3292
|
-
const da = d >>> 24;
|
|
3293
|
-
if (da !== 0) {
|
|
3294
|
-
const finalAlpha = da === 255 ? weight : da * weight + 128 >> 8;
|
|
3295
|
-
const current = dst32[dIdx];
|
|
3296
|
-
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
3297
|
-
if (current !== next) {
|
|
3298
|
-
dst32[dIdx] = next;
|
|
3299
|
-
didChange = true;
|
|
3300
|
-
}
|
|
3301
|
-
}
|
|
3302
|
-
}
|
|
3303
|
-
dIdx++;
|
|
3304
|
-
mIdx++;
|
|
3493
|
+
fillPixelData: fillPixelData2 = defaults16.fillPixelData
|
|
3494
|
+
} = deps;
|
|
3495
|
+
return {
|
|
3496
|
+
fill(color, x = 0, y = 0, w = writer.config.target.width, h = writer.config.target.height) {
|
|
3497
|
+
const target = writer.config.target;
|
|
3498
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3499
|
+
return didChange(fillPixelData2(target, color, x, y, w, h));
|
|
3305
3500
|
}
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
return didChange;
|
|
3310
|
-
}
|
|
3311
|
-
|
|
3312
|
-
// src/History/PixelMutator/mutatorApplyAlphaMask.ts
|
|
3313
|
-
var defaults11 = {
|
|
3314
|
-
applyAlphaMaskToPixelData
|
|
3315
|
-
};
|
|
3316
|
-
var mutatorApplyAlphaMask = ((writer, deps = defaults11) => {
|
|
3501
|
+
};
|
|
3502
|
+
});
|
|
3503
|
+
var mutatorFillRect = ((writer, deps = defaults16) => {
|
|
3317
3504
|
const {
|
|
3318
|
-
|
|
3505
|
+
fillPixelData: fillPixelData2 = defaults16.fillPixelData
|
|
3319
3506
|
} = deps;
|
|
3320
3507
|
return {
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
const
|
|
3324
|
-
|
|
3325
|
-
y = 0,
|
|
3326
|
-
w = target.width,
|
|
3327
|
-
h = target.height
|
|
3328
|
-
} = opts;
|
|
3329
|
-
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3330
|
-
return didChange(applyAlphaMaskToPixelData2(target, mask, opts));
|
|
3508
|
+
fillRect(color, rect) {
|
|
3509
|
+
const target = writer.config.target;
|
|
3510
|
+
const didChange = writer.accumulator.storeRegionBeforeState(rect.x, rect.y, rect.w, rect.h);
|
|
3511
|
+
return didChange(fillPixelData2(target, color, rect.x, rect.y, rect.w, rect.h));
|
|
3331
3512
|
}
|
|
3332
3513
|
};
|
|
3333
3514
|
});
|
|
3334
3515
|
|
|
3335
|
-
// src/PixelData/
|
|
3336
|
-
|
|
3516
|
+
// src/PixelData/fillPixelDataBinaryMask.ts
|
|
3517
|
+
var SCRATCH_RECT2 = makeClippedRect();
|
|
3518
|
+
function fillPixelDataBinaryMask(target, color, mask, x = 0, y = 0) {
|
|
3519
|
+
const maskW = mask.w;
|
|
3520
|
+
const maskH = mask.h;
|
|
3521
|
+
const clip = resolveRectClipping(x, y, maskW, maskH, target.width, target.height, SCRATCH_RECT2);
|
|
3522
|
+
if (!clip.inBounds) return false;
|
|
3337
3523
|
const {
|
|
3338
|
-
x:
|
|
3339
|
-
y:
|
|
3340
|
-
w:
|
|
3341
|
-
h:
|
|
3342
|
-
|
|
3343
|
-
mx = 0,
|
|
3344
|
-
my = 0,
|
|
3345
|
-
invertMask = false
|
|
3346
|
-
} = opts;
|
|
3347
|
-
if (globalAlpha === 0) return false;
|
|
3348
|
-
let x = targetX;
|
|
3349
|
-
let y = targetY;
|
|
3350
|
-
let w = width;
|
|
3351
|
-
let h = height;
|
|
3352
|
-
if (x < 0) {
|
|
3353
|
-
w += x;
|
|
3354
|
-
x = 0;
|
|
3355
|
-
}
|
|
3356
|
-
if (y < 0) {
|
|
3357
|
-
h += y;
|
|
3358
|
-
y = 0;
|
|
3359
|
-
}
|
|
3360
|
-
w = Math.min(w, dst.width - x);
|
|
3361
|
-
h = Math.min(h, dst.height - y);
|
|
3362
|
-
if (w <= 0 || h <= 0) return false;
|
|
3363
|
-
const mPitch = mask.w;
|
|
3364
|
-
if (mPitch <= 0) return false;
|
|
3365
|
-
const startX = mx + (x - targetX);
|
|
3366
|
-
const startY = my + (y - targetY);
|
|
3367
|
-
const sX0 = Math.max(0, startX);
|
|
3368
|
-
const sY0 = Math.max(0, startY);
|
|
3369
|
-
const sX1 = Math.min(mPitch, startX + w);
|
|
3370
|
-
const sY1 = Math.min(mask.h, startY + h);
|
|
3371
|
-
const finalW = sX1 - sX0;
|
|
3372
|
-
const finalH = sY1 - sY0;
|
|
3373
|
-
if (finalW <= 0 || finalH <= 0) {
|
|
3374
|
-
return false;
|
|
3375
|
-
}
|
|
3376
|
-
const xShift = sX0 - startX;
|
|
3377
|
-
const yShift = sY0 - startY;
|
|
3378
|
-
const dst32 = dst.data32;
|
|
3379
|
-
const dw = dst.width;
|
|
3380
|
-
const dStride = dw - finalW;
|
|
3381
|
-
const mStride = mPitch - finalW;
|
|
3524
|
+
x: finalX,
|
|
3525
|
+
y: finalY,
|
|
3526
|
+
w: actualW,
|
|
3527
|
+
h: actualH
|
|
3528
|
+
} = clip;
|
|
3382
3529
|
const maskData = mask.data;
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
let
|
|
3386
|
-
for (let iy = 0; iy <
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
if (da !== 0) {
|
|
3401
|
-
const finalAlpha = da === 255 ? globalAlpha : da * globalAlpha + 128 >> 8;
|
|
3402
|
-
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
3403
|
-
if (d !== next) {
|
|
3404
|
-
dst32[dIdx] = next;
|
|
3405
|
-
didChange = true;
|
|
3406
|
-
}
|
|
3530
|
+
const dst32 = target.data32;
|
|
3531
|
+
const dw = target.width;
|
|
3532
|
+
let hasChanged = false;
|
|
3533
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
3534
|
+
const currentY = finalY + iy;
|
|
3535
|
+
const maskY = currentY - y;
|
|
3536
|
+
const maskOffset = maskY * maskW;
|
|
3537
|
+
const dstRowOffset = currentY * dw;
|
|
3538
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
3539
|
+
const currentX = finalX + ix;
|
|
3540
|
+
const maskX = currentX - x;
|
|
3541
|
+
const maskIndex = maskOffset + maskX;
|
|
3542
|
+
if (maskData[maskIndex]) {
|
|
3543
|
+
const current = dst32[dstRowOffset + currentX];
|
|
3544
|
+
if (current !== color) {
|
|
3545
|
+
dst32[dstRowOffset + currentX] = color;
|
|
3546
|
+
hasChanged = true;
|
|
3407
3547
|
}
|
|
3408
3548
|
}
|
|
3409
|
-
dIdx++;
|
|
3410
|
-
mIdx++;
|
|
3411
3549
|
}
|
|
3412
|
-
dIdx += dStride;
|
|
3413
|
-
mIdx += mStride;
|
|
3414
3550
|
}
|
|
3415
|
-
return
|
|
3551
|
+
return hasChanged;
|
|
3416
3552
|
}
|
|
3417
3553
|
|
|
3418
|
-
// src/History/PixelMutator/
|
|
3419
|
-
var
|
|
3420
|
-
|
|
3554
|
+
// src/History/PixelMutator/mutatorFillBinaryMask.ts
|
|
3555
|
+
var defaults17 = {
|
|
3556
|
+
fillPixelDataBinaryMask
|
|
3421
3557
|
};
|
|
3422
|
-
var
|
|
3558
|
+
var mutatorFillBinaryMask = ((writer, deps = defaults17) => {
|
|
3423
3559
|
const {
|
|
3424
|
-
|
|
3560
|
+
fillPixelDataBinaryMask: fillPixelDataBinaryMask2 = defaults17.fillPixelDataBinaryMask
|
|
3425
3561
|
} = deps;
|
|
3426
3562
|
return {
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
x = 0,
|
|
3431
|
-
y = 0,
|
|
3432
|
-
w = target.width,
|
|
3433
|
-
h = target.height
|
|
3434
|
-
} = opts;
|
|
3435
|
-
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3436
|
-
return didChange(applyBinaryMaskToPixelData2(target, mask, opts));
|
|
3563
|
+
fillBinaryMask(color, mask, x = 0, y = 0) {
|
|
3564
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, mask.w, mask.h);
|
|
3565
|
+
return didChange(fillPixelDataBinaryMask2(writer.config.target, color, mask, x, y));
|
|
3437
3566
|
}
|
|
3438
3567
|
};
|
|
3439
3568
|
});
|
|
3440
3569
|
|
|
3441
|
-
// src/PixelData/
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
const
|
|
3445
|
-
const
|
|
3446
|
-
const
|
|
3447
|
-
const
|
|
3448
|
-
const
|
|
3449
|
-
const
|
|
3450
|
-
const
|
|
3451
|
-
const invertMask = opts
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
const
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
let dIdx = y * dw + x | 0;
|
|
3478
|
-
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
3479
|
-
const dStride = dw - actualW | 0;
|
|
3480
|
-
const mStride = mPitch - actualW | 0;
|
|
3481
|
-
const isOpaque = globalAlpha === 255;
|
|
3482
|
-
const colorRGB = color & 16777215;
|
|
3483
|
-
let didChange = false;
|
|
3484
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
3485
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
3486
|
-
const mVal = maskData[mIdx];
|
|
3487
|
-
const effM = invertMask ? 255 - mVal : mVal;
|
|
3488
|
-
if (effM === 0) {
|
|
3489
|
-
dIdx++;
|
|
3490
|
-
mIdx++;
|
|
3491
|
-
continue;
|
|
3492
|
-
}
|
|
3493
|
-
let weight = globalAlpha;
|
|
3494
|
-
if (isOpaque) {
|
|
3495
|
-
weight = effM;
|
|
3496
|
-
} else if (effM !== 255) {
|
|
3497
|
-
weight = effM * globalAlpha + 128 >> 8;
|
|
3498
|
-
}
|
|
3499
|
-
if (weight === 0) {
|
|
3500
|
-
dIdx++;
|
|
3501
|
-
mIdx++;
|
|
3502
|
-
continue;
|
|
3503
|
-
}
|
|
3504
|
-
let finalCol = color;
|
|
3505
|
-
if (weight < 255) {
|
|
3506
|
-
const a = baseSrcAlpha * weight + 128 >> 8;
|
|
3507
|
-
if (a === 0 && !isOverwrite) {
|
|
3508
|
-
dIdx++;
|
|
3509
|
-
mIdx++;
|
|
3510
|
-
continue;
|
|
3570
|
+
// src/PixelData/invertPixelData.ts
|
|
3571
|
+
var SCRATCH_RECT3 = makeClippedRect();
|
|
3572
|
+
function invertPixelData(target, opts) {
|
|
3573
|
+
const mask = opts?.mask;
|
|
3574
|
+
const targetX = opts?.x ?? 0;
|
|
3575
|
+
const targetY = opts?.y ?? 0;
|
|
3576
|
+
const mx = opts?.mx ?? 0;
|
|
3577
|
+
const my = opts?.my ?? 0;
|
|
3578
|
+
const width = opts?.w ?? target.width;
|
|
3579
|
+
const height = opts?.h ?? target.height;
|
|
3580
|
+
const invertMask = opts?.invertMask ?? false;
|
|
3581
|
+
const clip = resolveRectClipping(targetX, targetY, width, height, target.width, target.height, SCRATCH_RECT3);
|
|
3582
|
+
if (!clip.inBounds) return false;
|
|
3583
|
+
const {
|
|
3584
|
+
x,
|
|
3585
|
+
y,
|
|
3586
|
+
w: actualW,
|
|
3587
|
+
h: actualH
|
|
3588
|
+
} = clip;
|
|
3589
|
+
const dst32 = target.data32;
|
|
3590
|
+
const dw = target.width;
|
|
3591
|
+
const mPitch = mask?.w ?? width;
|
|
3592
|
+
const dx = x - targetX;
|
|
3593
|
+
const dy = y - targetY;
|
|
3594
|
+
let dIdx = y * dw + x;
|
|
3595
|
+
let mIdx = (my + dy) * mPitch + (mx + dx);
|
|
3596
|
+
const dStride = dw - actualW;
|
|
3597
|
+
const mStride = mPitch - actualW;
|
|
3598
|
+
if (mask) {
|
|
3599
|
+
const maskData = mask.data;
|
|
3600
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
3601
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
3602
|
+
const mVal = maskData[mIdx];
|
|
3603
|
+
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
3604
|
+
if (isHit) {
|
|
3605
|
+
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
3511
3606
|
}
|
|
3512
|
-
finalCol = (colorRGB | a << 24) >>> 0;
|
|
3513
|
-
}
|
|
3514
|
-
const current = dst32[dIdx];
|
|
3515
|
-
const next = blendFn(finalCol, current);
|
|
3516
|
-
if (current !== next) {
|
|
3517
|
-
dst32[dIdx] = next;
|
|
3518
|
-
didChange = true;
|
|
3519
|
-
}
|
|
3520
|
-
dIdx++;
|
|
3521
|
-
mIdx++;
|
|
3522
|
-
}
|
|
3523
|
-
dIdx += dStride;
|
|
3524
|
-
mIdx += mStride;
|
|
3525
|
-
}
|
|
3526
|
-
return didChange;
|
|
3527
|
-
}
|
|
3528
|
-
|
|
3529
|
-
// src/PixelData/blendColorPixelDataBinaryMask.ts
|
|
3530
|
-
function blendColorPixelDataBinaryMask(dst, color, mask, opts = {}) {
|
|
3531
|
-
const targetX = opts.x ?? 0;
|
|
3532
|
-
const targetY = opts.y ?? 0;
|
|
3533
|
-
let w = opts.w ?? mask.w;
|
|
3534
|
-
let h = opts.h ?? mask.h;
|
|
3535
|
-
const globalAlpha = opts.alpha ?? 255;
|
|
3536
|
-
const blendFn = opts.blendFn ?? sourceOverPerfect;
|
|
3537
|
-
const mx = opts.mx ?? 0;
|
|
3538
|
-
const my = opts.my ?? 0;
|
|
3539
|
-
const invertMask = opts.invertMask ?? false;
|
|
3540
|
-
if (globalAlpha === 0) return false;
|
|
3541
|
-
const baseSrcAlpha = color >>> 24;
|
|
3542
|
-
const isOverwrite = blendFn.isOverwrite || false;
|
|
3543
|
-
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
3544
|
-
let x = targetX;
|
|
3545
|
-
let y = targetY;
|
|
3546
|
-
if (x < 0) {
|
|
3547
|
-
w += x;
|
|
3548
|
-
x = 0;
|
|
3549
|
-
}
|
|
3550
|
-
if (y < 0) {
|
|
3551
|
-
h += y;
|
|
3552
|
-
y = 0;
|
|
3553
|
-
}
|
|
3554
|
-
const actualW = Math.min(w, dst.width - x);
|
|
3555
|
-
const actualH = Math.min(h, dst.height - y);
|
|
3556
|
-
if (actualW <= 0 || actualH <= 0) return false;
|
|
3557
|
-
let baseColorWithGlobalAlpha = color;
|
|
3558
|
-
if (globalAlpha < 255) {
|
|
3559
|
-
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
3560
|
-
if (a === 0 && !isOverwrite) return false;
|
|
3561
|
-
baseColorWithGlobalAlpha = (color & 16777215 | a << 24) >>> 0;
|
|
3562
|
-
}
|
|
3563
|
-
const dx = x - targetX | 0;
|
|
3564
|
-
const dy = y - targetY | 0;
|
|
3565
|
-
const dst32 = dst.data32;
|
|
3566
|
-
const dw = dst.width;
|
|
3567
|
-
const mPitch = mask.w;
|
|
3568
|
-
const maskData = mask.data;
|
|
3569
|
-
let dIdx = y * dw + x | 0;
|
|
3570
|
-
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
3571
|
-
const dStride = dw - actualW | 0;
|
|
3572
|
-
const mStride = mPitch - actualW | 0;
|
|
3573
|
-
const skipVal = invertMask ? 1 : 0;
|
|
3574
|
-
let didChange = false;
|
|
3575
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
3576
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
3577
|
-
if (maskData[mIdx] === skipVal) {
|
|
3578
3607
|
dIdx++;
|
|
3579
3608
|
mIdx++;
|
|
3580
|
-
continue;
|
|
3581
3609
|
}
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3610
|
+
dIdx += dStride;
|
|
3611
|
+
mIdx += mStride;
|
|
3612
|
+
}
|
|
3613
|
+
} else {
|
|
3614
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
3615
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
3616
|
+
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
3617
|
+
dIdx++;
|
|
3587
3618
|
}
|
|
3588
|
-
dIdx
|
|
3589
|
-
mIdx++;
|
|
3619
|
+
dIdx += dStride;
|
|
3590
3620
|
}
|
|
3591
|
-
dIdx += dStride;
|
|
3592
|
-
mIdx += mStride;
|
|
3593
3621
|
}
|
|
3594
|
-
return
|
|
3622
|
+
return true;
|
|
3595
3623
|
}
|
|
3596
3624
|
|
|
3597
|
-
// src/History/PixelMutator/
|
|
3598
|
-
var
|
|
3599
|
-
|
|
3600
|
-
blendColorPixelDataBinaryMask
|
|
3625
|
+
// src/History/PixelMutator/mutatorInvert.ts
|
|
3626
|
+
var defaults18 = {
|
|
3627
|
+
invertPixelData
|
|
3601
3628
|
};
|
|
3602
|
-
var
|
|
3629
|
+
var mutatorInvert = ((writer, deps = defaults18) => {
|
|
3603
3630
|
const {
|
|
3604
|
-
|
|
3605
|
-
blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults13.blendColorPixelDataAlphaMask
|
|
3631
|
+
invertPixelData: invertPixelData2 = defaults18.invertPixelData
|
|
3606
3632
|
} = deps;
|
|
3607
|
-
const OPTS = {
|
|
3608
|
-
x: 0,
|
|
3609
|
-
y: 0,
|
|
3610
|
-
blendFn: sourceOverPerfect,
|
|
3611
|
-
alpha: 255
|
|
3612
|
-
};
|
|
3613
3633
|
return {
|
|
3614
|
-
|
|
3615
|
-
const
|
|
3616
|
-
const
|
|
3617
|
-
const
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
if (mask.type === 1 /* BINARY */) {
|
|
3623
|
-
return didChange(blendColorPixelDataBinaryMask2(writer.config.target, color, mask, OPTS));
|
|
3624
|
-
} else {
|
|
3625
|
-
return didChange(blendColorPixelDataAlphaMask2(writer.config.target, color, mask, OPTS));
|
|
3626
|
-
}
|
|
3634
|
+
invert(opts) {
|
|
3635
|
+
const target = writer.config.target;
|
|
3636
|
+
const x = opts?.x ?? 0;
|
|
3637
|
+
const y = opts?.y ?? 0;
|
|
3638
|
+
const w = opts?.w ?? target.width;
|
|
3639
|
+
const h = opts?.h ?? target.height;
|
|
3640
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3641
|
+
return didChange(invertPixelData2(target, opts));
|
|
3627
3642
|
}
|
|
3628
3643
|
};
|
|
3629
3644
|
});
|
|
3630
3645
|
|
|
3646
|
+
// src/History/PixelMutator.ts
|
|
3647
|
+
function makeFullPixelMutator(writer) {
|
|
3648
|
+
return {
|
|
3649
|
+
// @sort
|
|
3650
|
+
...mutatorApplyAlphaMask(writer),
|
|
3651
|
+
...mutatorApplyBinaryMask(writer),
|
|
3652
|
+
...mutatorApplyMask(writer),
|
|
3653
|
+
...mutatorBlendAlphaMask(writer),
|
|
3654
|
+
...mutatorBlendBinaryMask(writer),
|
|
3655
|
+
...mutatorBlendColor(writer),
|
|
3656
|
+
...mutatorBlendColorPaintAlphaMask(writer),
|
|
3657
|
+
...mutatorBlendColorPaintBinaryMask(writer),
|
|
3658
|
+
...mutatorBlendColorPaintMask(writer),
|
|
3659
|
+
...mutatorBlendMask(writer),
|
|
3660
|
+
...mutatorBlendPaintRect(writer),
|
|
3661
|
+
...mutatorBlendPixel(writer),
|
|
3662
|
+
...mutatorBlendPixelData(writer),
|
|
3663
|
+
...mutatorClear(writer),
|
|
3664
|
+
...mutatorFill(writer),
|
|
3665
|
+
...mutatorFillBinaryMask(writer),
|
|
3666
|
+
...mutatorFillRect(writer),
|
|
3667
|
+
...mutatorInvert(writer)
|
|
3668
|
+
};
|
|
3669
|
+
}
|
|
3670
|
+
|
|
3671
|
+
// src/ImageData/ImageDataLike.ts
|
|
3672
|
+
function makeImageDataLike(width, height, data) {
|
|
3673
|
+
const size = width * height * 4;
|
|
3674
|
+
const buffer = data ? new Uint8ClampedArray(data.buffer, data.byteOffset, size) : new Uint8ClampedArray(size);
|
|
3675
|
+
return {
|
|
3676
|
+
width,
|
|
3677
|
+
height,
|
|
3678
|
+
data: buffer
|
|
3679
|
+
};
|
|
3680
|
+
}
|
|
3681
|
+
|
|
3682
|
+
// src/ImageData/ReusableImageData.ts
|
|
3683
|
+
function makeReusableImageData() {
|
|
3684
|
+
let imageData = null;
|
|
3685
|
+
return function getReusableImageData(width, height) {
|
|
3686
|
+
if (imageData === null || imageData.width !== width || imageData.height !== height) {
|
|
3687
|
+
imageData = new ImageData(width, height);
|
|
3688
|
+
} else {
|
|
3689
|
+
imageData.data.fill(0);
|
|
3690
|
+
}
|
|
3691
|
+
return imageData;
|
|
3692
|
+
};
|
|
3693
|
+
}
|
|
3694
|
+
|
|
3631
3695
|
// src/ImageData/copyImageData.ts
|
|
3632
3696
|
function copyImageData({
|
|
3633
3697
|
data,
|
|
@@ -3648,17 +3712,6 @@ function copyImageDataLike({
|
|
|
3648
3712
|
};
|
|
3649
3713
|
}
|
|
3650
3714
|
|
|
3651
|
-
// src/ImageData/ImageDataLike.ts
|
|
3652
|
-
function makeImageDataLike(width, height, data) {
|
|
3653
|
-
const size = width * height * 4;
|
|
3654
|
-
const buffer = data ? new Uint8ClampedArray(data.buffer, data.byteOffset, size) : new Uint8ClampedArray(size);
|
|
3655
|
-
return {
|
|
3656
|
-
width,
|
|
3657
|
-
height,
|
|
3658
|
-
data: buffer
|
|
3659
|
-
};
|
|
3660
|
-
}
|
|
3661
|
-
|
|
3662
3715
|
// src/ImageData/imageDataToAlphaMaskBuffer.ts
|
|
3663
3716
|
function imageDataToAlphaMaskBuffer(imageData) {
|
|
3664
3717
|
const {
|
|
@@ -3749,19 +3802,6 @@ function resampleImageData(source, factor) {
|
|
|
3749
3802
|
return new ImageData(uint8ClampedArray, width, height);
|
|
3750
3803
|
}
|
|
3751
3804
|
|
|
3752
|
-
// src/ImageData/ReusableImageData.ts
|
|
3753
|
-
function makeReusableImageData() {
|
|
3754
|
-
let imageData = null;
|
|
3755
|
-
return function getReusableImageData(width, height) {
|
|
3756
|
-
if (imageData === null || imageData.width !== width || imageData.height !== height) {
|
|
3757
|
-
imageData = new ImageData(width, height);
|
|
3758
|
-
} else {
|
|
3759
|
-
imageData.data.fill(0);
|
|
3760
|
-
}
|
|
3761
|
-
return imageData;
|
|
3762
|
-
};
|
|
3763
|
-
}
|
|
3764
|
-
|
|
3765
3805
|
// src/ImageData/serialization.ts
|
|
3766
3806
|
function base64EncodeArrayBuffer(buffer) {
|
|
3767
3807
|
const uint8 = new Uint8Array(buffer);
|
|
@@ -3916,18 +3956,6 @@ function writeImageDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
3916
3956
|
}
|
|
3917
3957
|
}
|
|
3918
3958
|
|
|
3919
|
-
// src/IndexedImage/getIndexedImageColorCounts.ts
|
|
3920
|
-
function getIndexedImageColorCounts(indexedImage) {
|
|
3921
|
-
const data = indexedImage.data;
|
|
3922
|
-
const palette = indexedImage.palette;
|
|
3923
|
-
const frequencies = new Int32Array(palette.length);
|
|
3924
|
-
for (let i = 0; i < data.length; i++) {
|
|
3925
|
-
const colorIndex = data[i];
|
|
3926
|
-
frequencies[colorIndex]++;
|
|
3927
|
-
}
|
|
3928
|
-
return frequencies;
|
|
3929
|
-
}
|
|
3930
|
-
|
|
3931
3959
|
// src/IndexedImage/IndexedImage.ts
|
|
3932
3960
|
var IndexedImage = class _IndexedImage {
|
|
3933
3961
|
/** The width of the image in pixels. */
|
|
@@ -4006,6 +4034,18 @@ var IndexedImage = class _IndexedImage {
|
|
|
4006
4034
|
}
|
|
4007
4035
|
};
|
|
4008
4036
|
|
|
4037
|
+
// src/IndexedImage/getIndexedImageColorCounts.ts
|
|
4038
|
+
function getIndexedImageColorCounts(indexedImage) {
|
|
4039
|
+
const data = indexedImage.data;
|
|
4040
|
+
const palette = indexedImage.palette;
|
|
4041
|
+
const frequencies = new Int32Array(palette.length);
|
|
4042
|
+
for (let i = 0; i < data.length; i++) {
|
|
4043
|
+
const colorIndex = data[i];
|
|
4044
|
+
frequencies[colorIndex]++;
|
|
4045
|
+
}
|
|
4046
|
+
return frequencies;
|
|
4047
|
+
}
|
|
4048
|
+
|
|
4009
4049
|
// src/IndexedImage/indexedImageToAverageColor.ts
|
|
4010
4050
|
function indexedImageToAverageColor(indexedImage, includeTransparent = false) {
|
|
4011
4051
|
const {
|
|
@@ -4164,16 +4204,14 @@ function makeBinaryMask(w, h, data) {
|
|
|
4164
4204
|
}
|
|
4165
4205
|
|
|
4166
4206
|
// src/Mask/applyBinaryMaskToAlphaMask.ts
|
|
4167
|
-
function applyBinaryMaskToAlphaMask(alphaMaskDst, binaryMaskSrc, opts
|
|
4168
|
-
const
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
invertMask = false
|
|
4176
|
-
} = opts;
|
|
4207
|
+
function applyBinaryMaskToAlphaMask(alphaMaskDst, binaryMaskSrc, opts) {
|
|
4208
|
+
const targetX = opts?.x ?? 0;
|
|
4209
|
+
const targetY = opts?.y ?? 0;
|
|
4210
|
+
const reqWidth = opts?.w ?? 0;
|
|
4211
|
+
const reqHeight = opts?.h ?? 0;
|
|
4212
|
+
const mx = opts?.mx ?? 0;
|
|
4213
|
+
const my = opts?.my ?? 0;
|
|
4214
|
+
const invertMask = opts?.invertMask ?? false;
|
|
4177
4215
|
const dstWidth = alphaMaskDst.w;
|
|
4178
4216
|
if (dstWidth <= 0) return;
|
|
4179
4217
|
if (binaryMaskSrc.data.length === 0) return;
|
|
@@ -4586,14 +4624,156 @@ function pushPiece(dest, r, x, y, w, h) {
|
|
|
4586
4624
|
for (let row = 0; row < h; row++) {
|
|
4587
4625
|
data.set(r.data.subarray((ly + row) * r.w + lx, (ly + row) * r.w + lx + w), row * w);
|
|
4588
4626
|
}
|
|
4589
|
-
dest.push({
|
|
4590
|
-
x,
|
|
4591
|
-
y,
|
|
4592
|
-
w,
|
|
4593
|
-
h,
|
|
4627
|
+
dest.push({
|
|
4628
|
+
x,
|
|
4629
|
+
y,
|
|
4630
|
+
w,
|
|
4631
|
+
h,
|
|
4632
|
+
data,
|
|
4633
|
+
type: 1 /* BINARY */
|
|
4634
|
+
});
|
|
4635
|
+
}
|
|
4636
|
+
|
|
4637
|
+
// src/Paint/PaintBufferCanvasRenderer.ts
|
|
4638
|
+
function makePaintBufferCanvasRenderer(paintBuffer, offscreenCanvasClass = OffscreenCanvas) {
|
|
4639
|
+
const config = paintBuffer.config;
|
|
4640
|
+
const tileSize = config.tileSize;
|
|
4641
|
+
const tileShift = config.tileShift;
|
|
4642
|
+
const lookup = paintBuffer.lookup;
|
|
4643
|
+
const canvas = new offscreenCanvasClass(tileSize, tileSize);
|
|
4644
|
+
const ctx = canvas.getContext("2d");
|
|
4645
|
+
if (!ctx) throw new Error(CANVAS_CTX_FAILED);
|
|
4646
|
+
ctx.imageSmoothingEnabled = false;
|
|
4647
|
+
return function drawPaintBuffer(targetCtx, alpha = 255, compOperation = "source-over") {
|
|
4648
|
+
targetCtx.globalAlpha = alpha / 255;
|
|
4649
|
+
targetCtx.globalCompositeOperation = compOperation;
|
|
4650
|
+
for (let i = 0; i < lookup.length; i++) {
|
|
4651
|
+
const tile = lookup[i];
|
|
4652
|
+
if (tile) {
|
|
4653
|
+
const dx = tile.tx << tileShift;
|
|
4654
|
+
const dy = tile.ty << tileShift;
|
|
4655
|
+
ctx.putImageData(tile.imageData, 0, 0);
|
|
4656
|
+
targetCtx.drawImage(canvas, dx, dy);
|
|
4657
|
+
}
|
|
4658
|
+
}
|
|
4659
|
+
targetCtx.globalAlpha = 1;
|
|
4660
|
+
targetCtx.globalCompositeOperation = "source-over";
|
|
4661
|
+
};
|
|
4662
|
+
}
|
|
4663
|
+
|
|
4664
|
+
// src/Paint/makeCirclePaintAlphaMask.ts
|
|
4665
|
+
function makeCirclePaintAlphaMask(size, fallOff = (d) => d) {
|
|
4666
|
+
const area = size * size;
|
|
4667
|
+
const data = new Uint8Array(area);
|
|
4668
|
+
const radius = size / 2;
|
|
4669
|
+
const invR = 1 / radius;
|
|
4670
|
+
const centerOffset = -Math.ceil(radius - 0.5);
|
|
4671
|
+
for (let y = 0; y < size; y++) {
|
|
4672
|
+
const rowOffset = y * size;
|
|
4673
|
+
const dy = y - radius + 0.5;
|
|
4674
|
+
const dy2 = dy * dy;
|
|
4675
|
+
for (let x = 0; x < size; x++) {
|
|
4676
|
+
const dx = x - radius + 0.5;
|
|
4677
|
+
const distSqr = dx * dx + dy2;
|
|
4678
|
+
if (distSqr <= radius * radius) {
|
|
4679
|
+
const dist = Math.sqrt(distSqr) * invR;
|
|
4680
|
+
const strength = fallOff(1 - dist);
|
|
4681
|
+
if (strength > 0) {
|
|
4682
|
+
const intensity = strength * 255 | 0;
|
|
4683
|
+
data[rowOffset + x] = Math.max(0, Math.min(255, intensity));
|
|
4684
|
+
}
|
|
4685
|
+
}
|
|
4686
|
+
}
|
|
4687
|
+
}
|
|
4688
|
+
return {
|
|
4689
|
+
type: 0 /* ALPHA */,
|
|
4690
|
+
data,
|
|
4691
|
+
w: size,
|
|
4692
|
+
h: size,
|
|
4693
|
+
centerOffsetX: centerOffset,
|
|
4694
|
+
centerOffsetY: centerOffset
|
|
4695
|
+
};
|
|
4696
|
+
}
|
|
4697
|
+
|
|
4698
|
+
// src/Paint/makeCirclePaintBinaryMask.ts
|
|
4699
|
+
function makeCirclePaintBinaryMask(size) {
|
|
4700
|
+
const area = size * size;
|
|
4701
|
+
const data = new Uint8Array(area);
|
|
4702
|
+
const radius = size / 2;
|
|
4703
|
+
const centerOffset = -Math.ceil(radius - 0.5);
|
|
4704
|
+
for (let y = 0; y < size; y++) {
|
|
4705
|
+
for (let x = 0; x < size; x++) {
|
|
4706
|
+
const dx = x - radius + 0.5;
|
|
4707
|
+
const dy = y - radius + 0.5;
|
|
4708
|
+
const distSqr = dx * dx + dy * dy;
|
|
4709
|
+
if (distSqr <= radius * radius) {
|
|
4710
|
+
data[y * size + x] = 1;
|
|
4711
|
+
}
|
|
4712
|
+
}
|
|
4713
|
+
}
|
|
4714
|
+
return {
|
|
4715
|
+
type: 1 /* BINARY */,
|
|
4716
|
+
data,
|
|
4717
|
+
w: size,
|
|
4718
|
+
h: size,
|
|
4719
|
+
centerOffsetX: centerOffset,
|
|
4720
|
+
centerOffsetY: centerOffset
|
|
4721
|
+
};
|
|
4722
|
+
}
|
|
4723
|
+
|
|
4724
|
+
// src/Paint/makePaintMask.ts
|
|
4725
|
+
function makePaintBinaryMask(mask) {
|
|
4726
|
+
return {
|
|
4727
|
+
type: 1 /* BINARY */,
|
|
4728
|
+
data: mask.data,
|
|
4729
|
+
w: mask.w,
|
|
4730
|
+
h: mask.h,
|
|
4731
|
+
centerOffsetX: -(mask.w >> 1),
|
|
4732
|
+
centerOffsetY: -(mask.h >> 1)
|
|
4733
|
+
};
|
|
4734
|
+
}
|
|
4735
|
+
function makePaintAlphaMask(mask) {
|
|
4736
|
+
return {
|
|
4737
|
+
type: 0 /* ALPHA */,
|
|
4738
|
+
data: mask.data,
|
|
4739
|
+
w: mask.w,
|
|
4740
|
+
h: mask.h,
|
|
4741
|
+
centerOffsetX: -(mask.w >> 1),
|
|
4742
|
+
centerOffsetY: -(mask.h >> 1)
|
|
4743
|
+
};
|
|
4744
|
+
}
|
|
4745
|
+
|
|
4746
|
+
// src/Paint/makeRectFalloffPaintAlphaMask.ts
|
|
4747
|
+
function makeRectFalloffPaintAlphaMask(width, height, fallOff = (d) => d) {
|
|
4748
|
+
const fPx = Math.floor(width / 2);
|
|
4749
|
+
const fPy = Math.floor(height / 2);
|
|
4750
|
+
const invHalfW = 2 / width;
|
|
4751
|
+
const invHalfH = 2 / height;
|
|
4752
|
+
const offX = width % 2 === 0 ? 0.5 : 0;
|
|
4753
|
+
const offY = height % 2 === 0 ? 0.5 : 0;
|
|
4754
|
+
const area = width * height;
|
|
4755
|
+
const data = new Uint8Array(area);
|
|
4756
|
+
for (let y = 0; y < height; y++) {
|
|
4757
|
+
const dy = Math.abs(y - fPy + offY) * invHalfH;
|
|
4758
|
+
const rowOffset = y * width;
|
|
4759
|
+
for (let x = 0; x < width; x++) {
|
|
4760
|
+
const dx = Math.abs(x - fPx + offX) * invHalfW;
|
|
4761
|
+
const dist = dx > dy ? dx : dy;
|
|
4762
|
+
const strength = fallOff(1 - dist);
|
|
4763
|
+
if (strength > 0) {
|
|
4764
|
+
const intensity = strength * 255 | 0;
|
|
4765
|
+
data[rowOffset + x] = Math.max(0, Math.min(255, intensity));
|
|
4766
|
+
}
|
|
4767
|
+
}
|
|
4768
|
+
}
|
|
4769
|
+
return {
|
|
4770
|
+
type: 0 /* ALPHA */,
|
|
4594
4771
|
data,
|
|
4595
|
-
|
|
4596
|
-
|
|
4772
|
+
w: width,
|
|
4773
|
+
h: height,
|
|
4774
|
+
centerOffsetX: -(width >> 1),
|
|
4775
|
+
centerOffsetY: -(height >> 1)
|
|
4776
|
+
};
|
|
4597
4777
|
}
|
|
4598
4778
|
|
|
4599
4779
|
// src/PixelData/PixelData.ts
|
|
@@ -4617,14 +4797,96 @@ var PixelData = class {
|
|
|
4617
4797
|
}
|
|
4618
4798
|
};
|
|
4619
4799
|
|
|
4620
|
-
// src/PixelData/
|
|
4800
|
+
// src/PixelData/applyMaskToPixelData.ts
|
|
4801
|
+
function applyMaskToPixelData(dst, mask, opts) {
|
|
4802
|
+
if (mask.type === 1 /* BINARY */) {
|
|
4803
|
+
return applyBinaryMaskToPixelData(dst, mask, opts);
|
|
4804
|
+
} else {
|
|
4805
|
+
return applyAlphaMaskToPixelData(dst, mask, opts);
|
|
4806
|
+
}
|
|
4807
|
+
}
|
|
4808
|
+
|
|
4809
|
+
// src/PixelData/blendColorPixelDataMask.ts
|
|
4810
|
+
function blendColorPixelDataMask(dst, color, mask, opts) {
|
|
4811
|
+
if (mask.type === 1 /* BINARY */) {
|
|
4812
|
+
return blendColorPixelDataBinaryMask(dst, color, mask, opts);
|
|
4813
|
+
} else {
|
|
4814
|
+
return blendColorPixelDataAlphaMask(dst, color, mask, opts);
|
|
4815
|
+
}
|
|
4816
|
+
}
|
|
4817
|
+
|
|
4818
|
+
// src/PixelData/blendColorPixelDataPaintAlphaMask.ts
|
|
4621
4819
|
var SCRATCH_OPTS = {
|
|
4820
|
+
x: 0,
|
|
4821
|
+
y: 0,
|
|
4822
|
+
alpha: 255,
|
|
4823
|
+
blendFn: sourceOverPerfect
|
|
4824
|
+
};
|
|
4825
|
+
function blendColorPixelDataPaintAlphaMask(dst, color, mask, x, y, alpha = 255, blendFn = sourceOverPerfect) {
|
|
4826
|
+
const tx = x + mask.centerOffsetX;
|
|
4827
|
+
const ty = y + mask.centerOffsetY;
|
|
4828
|
+
SCRATCH_OPTS.x = tx;
|
|
4829
|
+
SCRATCH_OPTS.y = ty;
|
|
4830
|
+
SCRATCH_OPTS.alpha = alpha;
|
|
4831
|
+
SCRATCH_OPTS.blendFn = blendFn;
|
|
4832
|
+
return blendColorPixelDataAlphaMask(dst, color, mask, SCRATCH_OPTS);
|
|
4833
|
+
}
|
|
4834
|
+
|
|
4835
|
+
// src/PixelData/blendColorPixelDataPaintBinaryMask.ts
|
|
4836
|
+
var SCRATCH_OPTS2 = {
|
|
4837
|
+
x: 0,
|
|
4838
|
+
y: 0,
|
|
4839
|
+
alpha: 255,
|
|
4840
|
+
blendFn: sourceOverPerfect
|
|
4841
|
+
};
|
|
4842
|
+
function blendColorPixelDataPaintBinaryMask(dst, color, mask, x, y, alpha = 255, blendFn = sourceOverPerfect) {
|
|
4843
|
+
const tx = x + mask.centerOffsetX;
|
|
4844
|
+
const ty = y + mask.centerOffsetY;
|
|
4845
|
+
SCRATCH_OPTS2.x = tx;
|
|
4846
|
+
SCRATCH_OPTS2.y = ty;
|
|
4847
|
+
SCRATCH_OPTS2.alpha = alpha;
|
|
4848
|
+
SCRATCH_OPTS2.blendFn = blendFn;
|
|
4849
|
+
return blendColorPixelDataBinaryMask(dst, color, mask, SCRATCH_OPTS2);
|
|
4850
|
+
}
|
|
4851
|
+
|
|
4852
|
+
// src/PixelData/blendColorPixelDataPaintMask.ts
|
|
4853
|
+
var SCRATCH_OPTS3 = {
|
|
4854
|
+
x: 0,
|
|
4855
|
+
y: 0,
|
|
4856
|
+
alpha: 255,
|
|
4857
|
+
blendFn: sourceOverPerfect
|
|
4858
|
+
};
|
|
4859
|
+
function blendColorPixelDataPaintMask(dst, color, mask, x, y, alpha = 255, blendFn = sourceOverPerfect) {
|
|
4860
|
+
const tx = x + mask.centerOffsetX;
|
|
4861
|
+
const ty = y + mask.centerOffsetY;
|
|
4862
|
+
SCRATCH_OPTS3.x = tx;
|
|
4863
|
+
SCRATCH_OPTS3.y = ty;
|
|
4864
|
+
SCRATCH_OPTS3.alpha = alpha;
|
|
4865
|
+
SCRATCH_OPTS3.blendFn = blendFn;
|
|
4866
|
+
if (mask.type === 1 /* BINARY */) {
|
|
4867
|
+
return blendColorPixelDataBinaryMask(dst, color, mask, SCRATCH_OPTS3);
|
|
4868
|
+
} else {
|
|
4869
|
+
return blendColorPixelDataAlphaMask(dst, color, mask, SCRATCH_OPTS3);
|
|
4870
|
+
}
|
|
4871
|
+
}
|
|
4872
|
+
|
|
4873
|
+
// src/PixelData/blendPixelDataMask.ts
|
|
4874
|
+
function blendPixelDataMask(target, src, mask, opts) {
|
|
4875
|
+
if (mask.type === 1 /* BINARY */) {
|
|
4876
|
+
return blendPixelDataBinaryMask(target, src, mask, opts);
|
|
4877
|
+
} else {
|
|
4878
|
+
return blendPixelDataAlphaMask(target, src, mask, opts);
|
|
4879
|
+
}
|
|
4880
|
+
}
|
|
4881
|
+
|
|
4882
|
+
// src/PixelData/blendPixelDataPaintBuffer.ts
|
|
4883
|
+
var SCRATCH_OPTS4 = {
|
|
4622
4884
|
x: 0,
|
|
4623
4885
|
y: 0,
|
|
4624
4886
|
alpha: 255,
|
|
4625
4887
|
blendFn: void 0
|
|
4626
4888
|
};
|
|
4627
|
-
function blendPixelDataPaintBuffer(
|
|
4889
|
+
function blendPixelDataPaintBuffer(target, paintBuffer, alpha = 255, blendFn, blendPixelDataFn = blendPixelData) {
|
|
4628
4890
|
const tileShift = paintBuffer.config.tileShift;
|
|
4629
4891
|
const lookup = paintBuffer.lookup;
|
|
4630
4892
|
for (let i = 0; i < lookup.length; i++) {
|
|
@@ -4632,17 +4894,61 @@ function blendPixelDataPaintBuffer(paintBuffer, target, alpha = 255, blendFn, bl
|
|
|
4632
4894
|
if (tile) {
|
|
4633
4895
|
const x = tile.tx << tileShift;
|
|
4634
4896
|
const y = tile.ty << tileShift;
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
blendPixelDataFn(target, tile,
|
|
4897
|
+
SCRATCH_OPTS4.x = x;
|
|
4898
|
+
SCRATCH_OPTS4.y = y;
|
|
4899
|
+
SCRATCH_OPTS4.alpha = alpha;
|
|
4900
|
+
SCRATCH_OPTS4.blendFn = blendFn;
|
|
4901
|
+
blendPixelDataFn(target, tile, SCRATCH_OPTS4);
|
|
4640
4902
|
}
|
|
4641
4903
|
}
|
|
4642
4904
|
}
|
|
4643
4905
|
|
|
4644
|
-
// src/PixelData/
|
|
4645
|
-
|
|
4906
|
+
// src/PixelData/fillPixelDataFast.ts
|
|
4907
|
+
var SCRATCH_RECT4 = makeClippedRect();
|
|
4908
|
+
function fillPixelDataFast(dst, color, _x, _y, _w, _h) {
|
|
4909
|
+
let x;
|
|
4910
|
+
let y;
|
|
4911
|
+
let w;
|
|
4912
|
+
let h;
|
|
4913
|
+
if (typeof _x === "object") {
|
|
4914
|
+
x = _x.x ?? 0;
|
|
4915
|
+
y = _x.y ?? 0;
|
|
4916
|
+
w = _x.w ?? dst.width;
|
|
4917
|
+
h = _x.h ?? dst.height;
|
|
4918
|
+
} else if (typeof _x === "number") {
|
|
4919
|
+
x = _x;
|
|
4920
|
+
y = _y;
|
|
4921
|
+
w = _w;
|
|
4922
|
+
h = _h;
|
|
4923
|
+
} else {
|
|
4924
|
+
x = 0;
|
|
4925
|
+
y = 0;
|
|
4926
|
+
w = dst.width;
|
|
4927
|
+
h = dst.height;
|
|
4928
|
+
}
|
|
4929
|
+
const clip = resolveRectClipping(x, y, w, h, dst.width, dst.height, SCRATCH_RECT4);
|
|
4930
|
+
if (!clip.inBounds) return;
|
|
4931
|
+
const {
|
|
4932
|
+
x: finalX,
|
|
4933
|
+
y: finalY,
|
|
4934
|
+
w: actualW,
|
|
4935
|
+
h: actualH
|
|
4936
|
+
} = clip;
|
|
4937
|
+
const dst32 = dst.data32;
|
|
4938
|
+
const dw = dst.width;
|
|
4939
|
+
if (actualW === dw && actualH === dst.height && finalX === 0 && finalY === 0) {
|
|
4940
|
+
dst32.fill(color);
|
|
4941
|
+
return;
|
|
4942
|
+
}
|
|
4943
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
4944
|
+
const start = (finalY + iy) * dw + finalX;
|
|
4945
|
+
const end = start + actualW;
|
|
4946
|
+
dst32.fill(color, start, end);
|
|
4947
|
+
}
|
|
4948
|
+
}
|
|
4949
|
+
|
|
4950
|
+
// src/PixelData/clearPixelDataFast.ts
|
|
4951
|
+
function clearPixelDataFast(dst, rect) {
|
|
4646
4952
|
fillPixelDataFast(dst, 0, rect);
|
|
4647
4953
|
}
|
|
4648
4954
|
|
|
@@ -4705,26 +5011,6 @@ function extractPixelData(source, _x, _y, _w, _h) {
|
|
|
4705
5011
|
return result;
|
|
4706
5012
|
}
|
|
4707
5013
|
|
|
4708
|
-
// src/PixelData/PixelBuffer32.ts
|
|
4709
|
-
var PixelBuffer32 = class _PixelBuffer32 {
|
|
4710
|
-
constructor(width, height, data32) {
|
|
4711
|
-
this.width = width;
|
|
4712
|
-
this.height = height;
|
|
4713
|
-
this.data32 = data32 ?? new Uint32Array(width * height);
|
|
4714
|
-
}
|
|
4715
|
-
data32;
|
|
4716
|
-
set(width, height, data32) {
|
|
4717
|
-
;
|
|
4718
|
-
this.data32 = data32 ?? new Uint32Array(width * height);
|
|
4719
|
-
this.width = width;
|
|
4720
|
-
this.height = height;
|
|
4721
|
-
}
|
|
4722
|
-
copy() {
|
|
4723
|
-
const newData32 = new Uint32Array(this.data32);
|
|
4724
|
-
return new _PixelBuffer32(this.width, this.height, newData32);
|
|
4725
|
-
}
|
|
4726
|
-
};
|
|
4727
|
-
|
|
4728
5014
|
// src/PixelData/pixelDataToAlphaMask.ts
|
|
4729
5015
|
function pixelDataToAlphaMask(pixelData) {
|
|
4730
5016
|
const {
|
|
@@ -4876,161 +5162,16 @@ function writePaintBufferToPixelData(target, paintBuffer, writePixelDataBufferFn
|
|
|
4876
5162
|
}
|
|
4877
5163
|
}
|
|
4878
5164
|
}
|
|
4879
|
-
|
|
4880
|
-
// src/Paint/makeCirclePaintAlphaMask.ts
|
|
4881
|
-
function makeCirclePaintAlphaMask(size, fallOff = (d) => d) {
|
|
4882
|
-
const area = size * size;
|
|
4883
|
-
const data = new Uint8Array(area);
|
|
4884
|
-
const radius = size / 2;
|
|
4885
|
-
const invR = 1 / radius;
|
|
4886
|
-
const centerOffset = -Math.ceil(radius - 0.5);
|
|
4887
|
-
for (let y = 0; y < size; y++) {
|
|
4888
|
-
const rowOffset = y * size;
|
|
4889
|
-
const dy = y - radius + 0.5;
|
|
4890
|
-
const dy2 = dy * dy;
|
|
4891
|
-
for (let x = 0; x < size; x++) {
|
|
4892
|
-
const dx = x - radius + 0.5;
|
|
4893
|
-
const distSqr = dx * dx + dy2;
|
|
4894
|
-
if (distSqr <= radius * radius) {
|
|
4895
|
-
const dist = Math.sqrt(distSqr) * invR;
|
|
4896
|
-
const strength = fallOff(1 - dist);
|
|
4897
|
-
if (strength > 0) {
|
|
4898
|
-
const intensity = strength * 255 | 0;
|
|
4899
|
-
data[rowOffset + x] = Math.max(0, Math.min(255, intensity));
|
|
4900
|
-
}
|
|
4901
|
-
}
|
|
4902
|
-
}
|
|
4903
|
-
}
|
|
4904
|
-
return {
|
|
4905
|
-
type: 0 /* ALPHA */,
|
|
4906
|
-
data,
|
|
4907
|
-
w: size,
|
|
4908
|
-
h: size,
|
|
4909
|
-
centerOffsetX: centerOffset,
|
|
4910
|
-
centerOffsetY: centerOffset
|
|
4911
|
-
};
|
|
4912
|
-
}
|
|
4913
|
-
|
|
4914
|
-
// src/Paint/makeCirclePaintBinaryMask.ts
|
|
4915
|
-
function makeCirclePaintBinaryMask(size) {
|
|
4916
|
-
const area = size * size;
|
|
4917
|
-
const data = new Uint8Array(area);
|
|
4918
|
-
const radius = size / 2;
|
|
4919
|
-
const centerOffset = -Math.ceil(radius - 0.5);
|
|
4920
|
-
for (let y = 0; y < size; y++) {
|
|
4921
|
-
for (let x = 0; x < size; x++) {
|
|
4922
|
-
const dx = x - radius + 0.5;
|
|
4923
|
-
const dy = y - radius + 0.5;
|
|
4924
|
-
const distSqr = dx * dx + dy * dy;
|
|
4925
|
-
if (distSqr <= radius * radius) {
|
|
4926
|
-
data[y * size + x] = 1;
|
|
4927
|
-
}
|
|
4928
|
-
}
|
|
4929
|
-
}
|
|
4930
|
-
return {
|
|
4931
|
-
type: 1 /* BINARY */,
|
|
4932
|
-
data,
|
|
4933
|
-
w: size,
|
|
4934
|
-
h: size,
|
|
4935
|
-
centerOffsetX: centerOffset,
|
|
4936
|
-
centerOffsetY: centerOffset
|
|
4937
|
-
};
|
|
4938
|
-
}
|
|
4939
|
-
|
|
4940
|
-
// src/Paint/makePaintMask.ts
|
|
4941
|
-
function makePaintBinaryMask(mask) {
|
|
4942
|
-
return {
|
|
4943
|
-
type: 1 /* BINARY */,
|
|
4944
|
-
data: mask.data,
|
|
4945
|
-
w: mask.w,
|
|
4946
|
-
h: mask.h,
|
|
4947
|
-
centerOffsetX: -(mask.w >> 1),
|
|
4948
|
-
centerOffsetY: -(mask.h >> 1)
|
|
4949
|
-
};
|
|
4950
|
-
}
|
|
4951
|
-
function makePaintAlphaMask(mask) {
|
|
4952
|
-
return {
|
|
4953
|
-
type: 0 /* ALPHA */,
|
|
4954
|
-
data: mask.data,
|
|
4955
|
-
w: mask.w,
|
|
4956
|
-
h: mask.h,
|
|
4957
|
-
centerOffsetX: -(mask.w >> 1),
|
|
4958
|
-
centerOffsetY: -(mask.h >> 1)
|
|
4959
|
-
};
|
|
4960
|
-
}
|
|
4961
|
-
|
|
4962
|
-
// src/Paint/makeRectFalloffPaintAlphaMask.ts
|
|
4963
|
-
function makeRectFalloffPaintAlphaMask(width, height, fallOff = (d) => d) {
|
|
4964
|
-
const fPx = Math.floor(width / 2);
|
|
4965
|
-
const fPy = Math.floor(height / 2);
|
|
4966
|
-
const invHalfW = 2 / width;
|
|
4967
|
-
const invHalfH = 2 / height;
|
|
4968
|
-
const offX = width % 2 === 0 ? 0.5 : 0;
|
|
4969
|
-
const offY = height % 2 === 0 ? 0.5 : 0;
|
|
4970
|
-
const area = width * height;
|
|
4971
|
-
const data = new Uint8Array(area);
|
|
4972
|
-
for (let y = 0; y < height; y++) {
|
|
4973
|
-
const dy = Math.abs(y - fPy + offY) * invHalfH;
|
|
4974
|
-
const rowOffset = y * width;
|
|
4975
|
-
for (let x = 0; x < width; x++) {
|
|
4976
|
-
const dx = Math.abs(x - fPx + offX) * invHalfW;
|
|
4977
|
-
const dist = dx > dy ? dx : dy;
|
|
4978
|
-
const strength = fallOff(1 - dist);
|
|
4979
|
-
if (strength > 0) {
|
|
4980
|
-
const intensity = strength * 255 | 0;
|
|
4981
|
-
data[rowOffset + x] = Math.max(0, Math.min(255, intensity));
|
|
4982
|
-
}
|
|
4983
|
-
}
|
|
4984
|
-
}
|
|
4985
|
-
return {
|
|
4986
|
-
type: 0 /* ALPHA */,
|
|
4987
|
-
data,
|
|
4988
|
-
w: width,
|
|
4989
|
-
h: height,
|
|
4990
|
-
centerOffsetX: -macro_halfAndFloor(width),
|
|
4991
|
-
centerOffsetY: -macro_halfAndFloor(height)
|
|
4992
|
-
};
|
|
4993
|
-
}
|
|
4994
|
-
|
|
4995
|
-
// src/Paint/PaintBufferCanvasRenderer.ts
|
|
4996
|
-
function makePaintBufferCanvasRenderer(paintBuffer, offscreenCanvasClass = OffscreenCanvas) {
|
|
4997
|
-
const config = paintBuffer.config;
|
|
4998
|
-
const tileSize = config.tileSize;
|
|
4999
|
-
const tileShift = config.tileShift;
|
|
5000
|
-
const lookup = paintBuffer.lookup;
|
|
5001
|
-
const canvas = new offscreenCanvasClass(tileSize, tileSize);
|
|
5002
|
-
const ctx = canvas.getContext("2d");
|
|
5003
|
-
if (!ctx) throw new Error(CANVAS_CTX_FAILED);
|
|
5004
|
-
ctx.imageSmoothingEnabled = false;
|
|
5005
|
-
return function drawPaintBuffer(targetCtx, alpha = 255, compOperation = "source-over") {
|
|
5006
|
-
targetCtx.globalAlpha = alpha / 255;
|
|
5007
|
-
targetCtx.globalCompositeOperation = compOperation;
|
|
5008
|
-
for (let i = 0; i < lookup.length; i++) {
|
|
5009
|
-
const tile = lookup[i];
|
|
5010
|
-
if (tile) {
|
|
5011
|
-
const dx = tile.tx << tileShift;
|
|
5012
|
-
const dy = tile.ty << tileShift;
|
|
5013
|
-
ctx.putImageData(tile.imageData, 0, 0);
|
|
5014
|
-
targetCtx.drawImage(canvas, dx, dy);
|
|
5015
|
-
}
|
|
5016
|
-
}
|
|
5017
|
-
targetCtx.globalAlpha = 1;
|
|
5018
|
-
targetCtx.globalCompositeOperation = "source-over";
|
|
5019
|
-
};
|
|
5020
|
-
}
|
|
5021
5165
|
export {
|
|
5022
5166
|
BASE_FAST_BLEND_MODE_FUNCTIONS,
|
|
5023
5167
|
BASE_PERFECT_BLEND_MODE_FUNCTIONS,
|
|
5024
5168
|
BaseBlendMode,
|
|
5025
5169
|
CANVAS_COMPOSITE_MAP,
|
|
5026
|
-
CANVAS_CTX_FAILED,
|
|
5027
5170
|
HistoryManager,
|
|
5028
5171
|
IndexedImage,
|
|
5029
5172
|
MaskType,
|
|
5030
|
-
OFFSCREEN_CANVAS_CTX_FAILED,
|
|
5031
5173
|
PaintBuffer,
|
|
5032
5174
|
PixelAccumulator,
|
|
5033
|
-
PixelBuffer32,
|
|
5034
5175
|
PixelData,
|
|
5035
5176
|
PixelEngineConfig,
|
|
5036
5177
|
PixelTile,
|
|
@@ -5040,18 +5181,24 @@ export {
|
|
|
5040
5181
|
applyAlphaMaskToPixelData,
|
|
5041
5182
|
applyBinaryMaskToAlphaMask,
|
|
5042
5183
|
applyBinaryMaskToPixelData,
|
|
5184
|
+
applyMaskToPixelData,
|
|
5043
5185
|
applyPatchTiles,
|
|
5044
5186
|
base64DecodeArrayBuffer,
|
|
5045
5187
|
base64EncodeArrayBuffer,
|
|
5046
5188
|
blendColorPixelData,
|
|
5047
5189
|
blendColorPixelDataAlphaMask,
|
|
5048
5190
|
blendColorPixelDataBinaryMask,
|
|
5191
|
+
blendColorPixelDataMask,
|
|
5192
|
+
blendColorPixelDataPaintAlphaMask,
|
|
5193
|
+
blendColorPixelDataPaintBinaryMask,
|
|
5194
|
+
blendColorPixelDataPaintMask,
|
|
5049
5195
|
blendPixel,
|
|
5050
5196
|
blendPixelData,
|
|
5051
5197
|
blendPixelDataAlphaMask,
|
|
5052
5198
|
blendPixelDataBinaryMask,
|
|
5199
|
+
blendPixelDataMask,
|
|
5053
5200
|
blendPixelDataPaintBuffer,
|
|
5054
|
-
|
|
5201
|
+
clearPixelDataFast,
|
|
5055
5202
|
color32ToCssRGBA,
|
|
5056
5203
|
color32ToHex,
|
|
5057
5204
|
colorBurnFast,
|
|
@@ -5124,6 +5271,8 @@ export {
|
|
|
5124
5271
|
makeCanvasFrameRenderer,
|
|
5125
5272
|
makeCirclePaintAlphaMask,
|
|
5126
5273
|
makeCirclePaintBinaryMask,
|
|
5274
|
+
makeClippedBlit,
|
|
5275
|
+
makeClippedRect,
|
|
5127
5276
|
makeFastBlendModeRegistry,
|
|
5128
5277
|
makeFullPixelMutator,
|
|
5129
5278
|
makeHistoryAction,
|
|
@@ -5145,12 +5294,17 @@ export {
|
|
|
5145
5294
|
multiplyPerfect,
|
|
5146
5295
|
mutatorApplyAlphaMask,
|
|
5147
5296
|
mutatorApplyBinaryMask,
|
|
5297
|
+
mutatorApplyMask,
|
|
5298
|
+
mutatorBlendAlphaMask,
|
|
5299
|
+
mutatorBlendBinaryMask,
|
|
5148
5300
|
mutatorBlendColor,
|
|
5149
|
-
|
|
5301
|
+
mutatorBlendColorPaintAlphaMask,
|
|
5302
|
+
mutatorBlendColorPaintBinaryMask,
|
|
5303
|
+
mutatorBlendColorPaintMask,
|
|
5304
|
+
mutatorBlendMask,
|
|
5305
|
+
mutatorBlendPaintRect,
|
|
5150
5306
|
mutatorBlendPixel,
|
|
5151
5307
|
mutatorBlendPixelData,
|
|
5152
|
-
mutatorBlendPixelDataAlphaMask,
|
|
5153
|
-
mutatorBlendPixelDataBinaryMask,
|
|
5154
5308
|
mutatorClear,
|
|
5155
5309
|
mutatorFill,
|
|
5156
5310
|
mutatorFillBinaryMask,
|
|
@@ -5168,10 +5322,13 @@ export {
|
|
|
5168
5322
|
pixelDataToAlphaMask,
|
|
5169
5323
|
reflectPixelDataHorizontal,
|
|
5170
5324
|
reflectPixelDataVertical,
|
|
5325
|
+
resample32,
|
|
5171
5326
|
resampleImageData,
|
|
5172
5327
|
resampleIndexedImage,
|
|
5173
5328
|
resamplePixelData,
|
|
5174
5329
|
resizeImageData,
|
|
5330
|
+
resolveBlitClipping,
|
|
5331
|
+
resolveRectClipping,
|
|
5175
5332
|
rotatePixelData,
|
|
5176
5333
|
screenFast,
|
|
5177
5334
|
screenPerfect,
|