pixel-data-js 0.25.0 → 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 +1832 -1606
- package/dist/index.prod.cjs.map +1 -1
- package/dist/index.prod.d.ts +458 -324
- package/dist/index.prod.js +1811 -1600
- 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/mutatorBlendColorPaintMask.ts +60 -0
- 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 -29
- package/dist/index.dev.cjs +0 -5363
- package/dist/index.dev.cjs.map +0 -1
- package/dist/index.dev.js +0 -5154
- 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,7 +1505,7 @@ 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
|
|
|
@@ -1631,6 +1607,24 @@ function makePixelCanvas(canvas) {
|
|
|
1631
1607
|
};
|
|
1632
1608
|
}
|
|
1633
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
|
+
|
|
1634
1628
|
// src/ImageData/imgBlobToImageData.ts
|
|
1635
1629
|
async function imgBlobToImageData(blob) {
|
|
1636
1630
|
let bitmap = null;
|
|
@@ -1715,10 +1709,9 @@ function applyPatchTiles(target, tiles, tileSize) {
|
|
|
1715
1709
|
}
|
|
1716
1710
|
|
|
1717
1711
|
// src/History/HistoryAction.ts
|
|
1718
|
-
function makeHistoryAction(
|
|
1719
|
-
const target =
|
|
1720
|
-
const tileSize =
|
|
1721
|
-
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;
|
|
1722
1715
|
return {
|
|
1723
1716
|
undo: () => {
|
|
1724
1717
|
applyPatchTilesFn(target, patch.beforeTiles, tileSize);
|
|
@@ -1988,20 +1981,17 @@ var PixelEngineConfig = class {
|
|
|
1988
1981
|
}
|
|
1989
1982
|
};
|
|
1990
1983
|
|
|
1991
|
-
// src/PixelData/
|
|
1992
|
-
function
|
|
1993
|
-
const
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
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;
|
|
2001
1994
|
if (globalAlpha === 0) return false;
|
|
2002
|
-
const baseSrcAlpha = color >>> 24;
|
|
2003
|
-
const isOverwrite = blendFn.isOverwrite || false;
|
|
2004
|
-
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
2005
1995
|
let x = targetX;
|
|
2006
1996
|
let y = targetY;
|
|
2007
1997
|
let w = width;
|
|
@@ -2014,114 +2004,320 @@ function blendColorPixelData(dst, color, opts = {}) {
|
|
|
2014
2004
|
h += y;
|
|
2015
2005
|
y = 0;
|
|
2016
2006
|
}
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
if (
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
const
|
|
2027
|
-
const
|
|
2028
|
-
|
|
2029
|
-
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;
|
|
2030
2032
|
let didChange = false;
|
|
2031
|
-
for (let iy = 0; iy <
|
|
2032
|
-
for (let ix = 0; ix <
|
|
2033
|
-
const
|
|
2034
|
-
const
|
|
2035
|
-
|
|
2036
|
-
|
|
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;
|
|
2037
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
|
+
}
|
|
2038
2062
|
}
|
|
2039
2063
|
dIdx++;
|
|
2064
|
+
mIdx++;
|
|
2040
2065
|
}
|
|
2041
2066
|
dIdx += dStride;
|
|
2067
|
+
mIdx += mStride;
|
|
2042
2068
|
}
|
|
2043
2069
|
return didChange;
|
|
2044
2070
|
}
|
|
2045
2071
|
|
|
2046
|
-
// src/
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
};
|
|
2050
|
-
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);
|
|
2051
2075
|
const {
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2064
|
-
return didChange(blendColorPixelData2(target, color, opts));
|
|
2065
|
-
}
|
|
2066
|
-
};
|
|
2067
|
-
});
|
|
2068
|
-
|
|
2069
|
-
// src/PixelData/blendPixel.ts
|
|
2070
|
-
function blendPixel(target, x, y, color, alpha = 255, blendFn = sourceOverPerfect) {
|
|
2071
|
-
if (alpha === 0) return false;
|
|
2072
|
-
let width = target.width;
|
|
2073
|
-
let height = target.height;
|
|
2074
|
-
if (x < 0 || x >= width || y < 0 || y >= height) return false;
|
|
2075
|
-
let srcAlpha = color >>> 24;
|
|
2076
|
-
let isOverwrite = blendFn.isOverwrite;
|
|
2077
|
-
if (srcAlpha === 0 && !isOverwrite) return false;
|
|
2078
|
-
let dst32 = target.data32;
|
|
2079
|
-
let index = y * width + x;
|
|
2080
|
-
let finalColor = color;
|
|
2081
|
-
if (alpha !== 255) {
|
|
2082
|
-
let finalAlpha = srcAlpha * alpha + 128 >> 8;
|
|
2083
|
-
if (finalAlpha === 0 && !isOverwrite) return false;
|
|
2084
|
-
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;
|
|
2085
2087
|
}
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
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);
|
|
2091
2097
|
}
|
|
2092
|
-
return
|
|
2098
|
+
return result;
|
|
2093
2099
|
}
|
|
2094
2100
|
|
|
2095
|
-
// src/
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
} = deps;
|
|
2103
|
-
return {
|
|
2104
|
-
blendPixel(x, y, color, alpha, blendFn) {
|
|
2105
|
-
const didChange = writer.accumulator.storePixelBeforeState(x, y);
|
|
2106
|
-
return didChange(blendPixel2(writer.config.target, x, y, color, alpha, blendFn));
|
|
2107
|
-
}
|
|
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
|
|
2108
2108
|
};
|
|
2109
|
-
|
|
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
|
+
}
|
|
2110
2119
|
|
|
2111
|
-
// src/
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
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
|
+
};
|
|
2308
|
+
|
|
2309
|
+
// src/PixelData/blendPixelData.ts
|
|
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;
|
|
2319
|
+
if (globalAlpha === 0) return false;
|
|
2320
|
+
let x = targetX;
|
|
2125
2321
|
let y = targetY;
|
|
2126
2322
|
let sx = sourceX;
|
|
2127
2323
|
let sy = sourceY;
|
|
@@ -2149,12 +2345,12 @@ function blendPixelData(dst, src, opts = {}) {
|
|
|
2149
2345
|
h += y;
|
|
2150
2346
|
y = 0;
|
|
2151
2347
|
}
|
|
2152
|
-
const actualW = Math.min(w,
|
|
2153
|
-
const actualH = Math.min(h,
|
|
2348
|
+
const actualW = Math.min(w, target.width - x);
|
|
2349
|
+
const actualH = Math.min(h, target.height - y);
|
|
2154
2350
|
if (actualW <= 0 || actualH <= 0) return false;
|
|
2155
|
-
const dst32 =
|
|
2351
|
+
const dst32 = target.data32;
|
|
2156
2352
|
const src32 = src.data32;
|
|
2157
|
-
const dw =
|
|
2353
|
+
const dw = target.width;
|
|
2158
2354
|
const sw = src.width;
|
|
2159
2355
|
let dIdx = y * dw + x | 0;
|
|
2160
2356
|
let sIdx = sy * sw + sx | 0;
|
|
@@ -2197,240 +2393,528 @@ function blendPixelData(dst, src, opts = {}) {
|
|
|
2197
2393
|
return didChange;
|
|
2198
2394
|
}
|
|
2199
2395
|
|
|
2200
|
-
// src/
|
|
2201
|
-
var
|
|
2202
|
-
|
|
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;
|
|
2203
2411
|
};
|
|
2204
|
-
var mutatorBlendPixelData = ((writer, deps = defaults4) => {
|
|
2205
|
-
const {
|
|
2206
|
-
blendPixelData: blendPixelData2 = defaults4.blendPixelData
|
|
2207
|
-
} = deps;
|
|
2208
|
-
return {
|
|
2209
|
-
blendPixelData(src, opts = {}) {
|
|
2210
|
-
const {
|
|
2211
|
-
x = 0,
|
|
2212
|
-
y = 0,
|
|
2213
|
-
w = src.width,
|
|
2214
|
-
h = src.height
|
|
2215
|
-
} = opts;
|
|
2216
|
-
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2217
|
-
return didChange(blendPixelData2(writer.config.target, src, opts));
|
|
2218
|
-
}
|
|
2219
|
-
};
|
|
2220
|
-
});
|
|
2221
2412
|
|
|
2222
|
-
// src/
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
alpha: globalAlpha = 255,
|
|
2232
|
-
blendFn = sourceOverPerfect,
|
|
2233
|
-
mx = 0,
|
|
2234
|
-
my = 0,
|
|
2235
|
-
invertMask = false
|
|
2236
|
-
} = opts;
|
|
2237
|
-
if (globalAlpha === 0) return false;
|
|
2238
|
-
let x = targetX;
|
|
2239
|
-
let y = targetY;
|
|
2240
|
-
let sx = sourceX;
|
|
2241
|
-
let sy = sourceY;
|
|
2242
|
-
let w = width;
|
|
2243
|
-
let h = height;
|
|
2244
|
-
if (sx < 0) {
|
|
2245
|
-
x -= sx;
|
|
2246
|
-
w += sx;
|
|
2247
|
-
sx = 0;
|
|
2248
|
-
}
|
|
2249
|
-
if (sy < 0) {
|
|
2250
|
-
y -= sy;
|
|
2251
|
-
h += sy;
|
|
2252
|
-
sy = 0;
|
|
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;
|
|
2253
2422
|
}
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
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);
|
|
2260
2433
|
}
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
h += y;
|
|
2264
|
-
y = 0;
|
|
2434
|
+
releaseTile(tile) {
|
|
2435
|
+
this.pool.push(tile);
|
|
2265
2436
|
}
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
const maskData = alphaMask.data;
|
|
2273
|
-
const dx = x - targetX | 0;
|
|
2274
|
-
const dy = y - targetY | 0;
|
|
2275
|
-
const dst32 = dst.data32;
|
|
2276
|
-
const src32 = src.data32;
|
|
2277
|
-
let dIdx = y * dw + x | 0;
|
|
2278
|
-
let sIdx = sy * sw + sx | 0;
|
|
2279
|
-
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
2280
|
-
const dStride = dw - actualW | 0;
|
|
2281
|
-
const sStride = sw - actualW | 0;
|
|
2282
|
-
const mStride = mPitch - actualW | 0;
|
|
2283
|
-
const isOpaque = globalAlpha === 255;
|
|
2284
|
-
const isOverwrite = blendFn.isOverwrite || false;
|
|
2285
|
-
let didChange = false;
|
|
2286
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
2287
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
2288
|
-
const mVal = maskData[mIdx];
|
|
2289
|
-
const effM = invertMask ? 255 - mVal : mVal;
|
|
2290
|
-
if (effM === 0) {
|
|
2291
|
-
dIdx++;
|
|
2292
|
-
sIdx++;
|
|
2293
|
-
mIdx++;
|
|
2294
|
-
continue;
|
|
2295
|
-
}
|
|
2296
|
-
const srcCol = src32[sIdx];
|
|
2297
|
-
const srcAlpha = srcCol >>> 24;
|
|
2298
|
-
if (srcAlpha === 0 && !isOverwrite) {
|
|
2299
|
-
dIdx++;
|
|
2300
|
-
sIdx++;
|
|
2301
|
-
mIdx++;
|
|
2302
|
-
continue;
|
|
2303
|
-
}
|
|
2304
|
-
let weight = globalAlpha;
|
|
2305
|
-
if (isOpaque) {
|
|
2306
|
-
weight = effM;
|
|
2307
|
-
} else if (effM !== 255) {
|
|
2308
|
-
weight = effM * globalAlpha + 128 >> 8;
|
|
2309
|
-
}
|
|
2310
|
-
if (weight === 0) {
|
|
2311
|
-
dIdx++;
|
|
2312
|
-
sIdx++;
|
|
2313
|
-
mIdx++;
|
|
2314
|
-
continue;
|
|
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);
|
|
2315
2443
|
}
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
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);
|
|
2326
2533
|
}
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
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));
|
|
2332
2554
|
}
|
|
2333
|
-
dIdx++;
|
|
2334
|
-
sIdx++;
|
|
2335
|
-
mIdx++;
|
|
2336
2555
|
}
|
|
2337
|
-
|
|
2338
|
-
sIdx += sStride;
|
|
2339
|
-
mIdx += mStride;
|
|
2556
|
+
paintBuffer.clear();
|
|
2340
2557
|
}
|
|
2341
|
-
|
|
2342
|
-
}
|
|
2558
|
+
};
|
|
2343
2559
|
|
|
2344
|
-
// src/History/PixelMutator/
|
|
2345
|
-
var
|
|
2346
|
-
|
|
2560
|
+
// src/History/PixelMutator/mutatorApplyAlphaMask.ts
|
|
2561
|
+
var defaults2 = {
|
|
2562
|
+
applyAlphaMaskToPixelData
|
|
2347
2563
|
};
|
|
2348
|
-
var
|
|
2564
|
+
var mutatorApplyAlphaMask = ((writer, deps = defaults2) => {
|
|
2349
2565
|
const {
|
|
2350
|
-
|
|
2566
|
+
applyAlphaMaskToPixelData: applyAlphaMaskToPixelData2 = defaults2.applyAlphaMaskToPixelData
|
|
2351
2567
|
} = deps;
|
|
2352
2568
|
return {
|
|
2353
|
-
|
|
2354
|
-
const
|
|
2355
|
-
const
|
|
2356
|
-
const
|
|
2357
|
-
const
|
|
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;
|
|
2358
2575
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2359
|
-
return didChange(
|
|
2576
|
+
return didChange(applyAlphaMaskToPixelData2(target, mask, opts));
|
|
2360
2577
|
}
|
|
2361
2578
|
};
|
|
2362
2579
|
});
|
|
2363
2580
|
|
|
2364
|
-
// src/PixelData/
|
|
2365
|
-
function
|
|
2366
|
-
const
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
blendFn = sourceOverPerfect,
|
|
2375
|
-
mx = 0,
|
|
2376
|
-
my = 0,
|
|
2377
|
-
invertMask = false
|
|
2378
|
-
} = opts;
|
|
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;
|
|
2379
2591
|
if (globalAlpha === 0) return false;
|
|
2380
2592
|
let x = targetX;
|
|
2381
2593
|
let y = targetY;
|
|
2382
|
-
let sx = sourceX;
|
|
2383
|
-
let sy = sourceY;
|
|
2384
2594
|
let w = width;
|
|
2385
2595
|
let h = height;
|
|
2386
|
-
if (sx < 0) {
|
|
2387
|
-
x -= sx;
|
|
2388
|
-
w += sx;
|
|
2389
|
-
sx = 0;
|
|
2390
|
-
}
|
|
2391
|
-
if (sy < 0) {
|
|
2392
|
-
y -= sy;
|
|
2393
|
-
h += sy;
|
|
2394
|
-
sy = 0;
|
|
2395
|
-
}
|
|
2396
|
-
w = Math.min(w, src.width - sx);
|
|
2397
|
-
h = Math.min(h, src.height - sy);
|
|
2398
2596
|
if (x < 0) {
|
|
2399
|
-
sx -= x;
|
|
2400
2597
|
w += x;
|
|
2401
2598
|
x = 0;
|
|
2402
2599
|
}
|
|
2403
2600
|
if (y < 0) {
|
|
2404
|
-
sy -= y;
|
|
2405
2601
|
h += y;
|
|
2406
2602
|
y = 0;
|
|
2407
2603
|
}
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
if (
|
|
2411
|
-
const
|
|
2412
|
-
|
|
2413
|
-
const
|
|
2414
|
-
const
|
|
2415
|
-
const
|
|
2416
|
-
const
|
|
2417
|
-
const
|
|
2418
|
-
const
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
const
|
|
2425
|
-
const
|
|
2426
|
-
const
|
|
2427
|
-
const
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
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;
|
|
2724
|
+
let x = targetX;
|
|
2725
|
+
let y = targetY;
|
|
2726
|
+
let sx = sourceX;
|
|
2727
|
+
let sy = sourceY;
|
|
2728
|
+
let w = width;
|
|
2729
|
+
let h = height;
|
|
2730
|
+
if (sx < 0) {
|
|
2731
|
+
x -= sx;
|
|
2732
|
+
w += sx;
|
|
2733
|
+
sx = 0;
|
|
2734
|
+
}
|
|
2735
|
+
if (sy < 0) {
|
|
2736
|
+
y -= sy;
|
|
2737
|
+
h += sy;
|
|
2738
|
+
sy = 0;
|
|
2739
|
+
}
|
|
2740
|
+
w = Math.min(w, src.width - sx);
|
|
2741
|
+
h = Math.min(h, src.height - sy);
|
|
2742
|
+
if (x < 0) {
|
|
2743
|
+
sx -= x;
|
|
2744
|
+
w += x;
|
|
2745
|
+
x = 0;
|
|
2746
|
+
}
|
|
2747
|
+
if (y < 0) {
|
|
2748
|
+
sy -= y;
|
|
2749
|
+
h += y;
|
|
2750
|
+
y = 0;
|
|
2751
|
+
}
|
|
2752
|
+
const actualW = Math.min(w, target.width - x);
|
|
2753
|
+
const actualH = Math.min(h, target.height - y);
|
|
2754
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
2755
|
+
const dw = target.width;
|
|
2756
|
+
const sw = src.width;
|
|
2757
|
+
const mPitch = alphaMask.w;
|
|
2758
|
+
const maskData = alphaMask.data;
|
|
2759
|
+
const dx = x - targetX | 0;
|
|
2760
|
+
const dy = y - targetY | 0;
|
|
2761
|
+
const dst32 = target.data32;
|
|
2762
|
+
const src32 = src.data32;
|
|
2763
|
+
let dIdx = y * dw + x | 0;
|
|
2764
|
+
let sIdx = sy * sw + sx | 0;
|
|
2765
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
2766
|
+
const dStride = dw - actualW | 0;
|
|
2767
|
+
const sStride = sw - actualW | 0;
|
|
2768
|
+
const mStride = mPitch - actualW | 0;
|
|
2769
|
+
const isOpaque = globalAlpha === 255;
|
|
2770
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
2771
|
+
let didChange = false;
|
|
2772
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2773
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2774
|
+
const mVal = maskData[mIdx];
|
|
2775
|
+
const effM = invertMask ? 255 - mVal : mVal;
|
|
2776
|
+
if (effM === 0) {
|
|
2777
|
+
dIdx++;
|
|
2778
|
+
sIdx++;
|
|
2779
|
+
mIdx++;
|
|
2780
|
+
continue;
|
|
2781
|
+
}
|
|
2782
|
+
const srcCol = src32[sIdx];
|
|
2783
|
+
const srcAlpha = srcCol >>> 24;
|
|
2784
|
+
if (srcAlpha === 0 && !isOverwrite) {
|
|
2785
|
+
dIdx++;
|
|
2786
|
+
sIdx++;
|
|
2787
|
+
mIdx++;
|
|
2788
|
+
continue;
|
|
2789
|
+
}
|
|
2790
|
+
let weight = globalAlpha;
|
|
2791
|
+
if (isOpaque) {
|
|
2792
|
+
weight = effM;
|
|
2793
|
+
} else if (effM !== 255) {
|
|
2794
|
+
weight = effM * globalAlpha + 128 >> 8;
|
|
2795
|
+
}
|
|
2796
|
+
if (weight === 0) {
|
|
2797
|
+
dIdx++;
|
|
2798
|
+
sIdx++;
|
|
2799
|
+
mIdx++;
|
|
2800
|
+
continue;
|
|
2801
|
+
}
|
|
2802
|
+
let finalCol = srcCol;
|
|
2803
|
+
if (weight < 255) {
|
|
2804
|
+
const a = srcAlpha * weight + 128 >> 8;
|
|
2805
|
+
if (a === 0 && !isOverwrite) {
|
|
2806
|
+
dIdx++;
|
|
2807
|
+
sIdx++;
|
|
2808
|
+
mIdx++;
|
|
2809
|
+
continue;
|
|
2810
|
+
}
|
|
2811
|
+
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
2812
|
+
}
|
|
2813
|
+
const current = dst32[dIdx];
|
|
2814
|
+
const next = blendFn(finalCol, dst32[dIdx]);
|
|
2815
|
+
if (current !== next) {
|
|
2816
|
+
dst32[dIdx] = next;
|
|
2817
|
+
didChange = true;
|
|
2818
|
+
}
|
|
2819
|
+
dIdx++;
|
|
2820
|
+
sIdx++;
|
|
2821
|
+
mIdx++;
|
|
2822
|
+
}
|
|
2823
|
+
dIdx += dStride;
|
|
2824
|
+
sIdx += sStride;
|
|
2825
|
+
mIdx += mStride;
|
|
2826
|
+
}
|
|
2827
|
+
return didChange;
|
|
2828
|
+
}
|
|
2829
|
+
|
|
2830
|
+
// src/History/PixelMutator/mutatorBlendAlphaMask.ts
|
|
2831
|
+
var defaults5 = {
|
|
2832
|
+
blendPixelDataAlphaMask
|
|
2833
|
+
};
|
|
2834
|
+
var mutatorBlendAlphaMask = ((writer, deps = defaults5) => {
|
|
2835
|
+
const {
|
|
2836
|
+
blendPixelDataAlphaMask: blendPixelDataAlphaMask2 = defaults5.blendPixelDataAlphaMask
|
|
2837
|
+
} = deps;
|
|
2838
|
+
return {
|
|
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;
|
|
2844
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2845
|
+
return didChange(blendPixelDataAlphaMask2(writer.config.target, src, mask, opts));
|
|
2846
|
+
}
|
|
2847
|
+
};
|
|
2848
|
+
});
|
|
2849
|
+
|
|
2850
|
+
// src/PixelData/blendPixelDataBinaryMask.ts
|
|
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;
|
|
2863
|
+
if (globalAlpha === 0) return false;
|
|
2864
|
+
let x = targetX;
|
|
2865
|
+
let y = targetY;
|
|
2866
|
+
let sx = sourceX;
|
|
2867
|
+
let sy = sourceY;
|
|
2868
|
+
let w = width;
|
|
2869
|
+
let h = height;
|
|
2870
|
+
if (sx < 0) {
|
|
2871
|
+
x -= sx;
|
|
2872
|
+
w += sx;
|
|
2873
|
+
sx = 0;
|
|
2874
|
+
}
|
|
2875
|
+
if (sy < 0) {
|
|
2876
|
+
y -= sy;
|
|
2877
|
+
h += sy;
|
|
2878
|
+
sy = 0;
|
|
2879
|
+
}
|
|
2880
|
+
w = Math.min(w, src.width - sx);
|
|
2881
|
+
h = Math.min(h, src.height - sy);
|
|
2882
|
+
if (x < 0) {
|
|
2883
|
+
sx -= x;
|
|
2884
|
+
w += x;
|
|
2885
|
+
x = 0;
|
|
2886
|
+
}
|
|
2887
|
+
if (y < 0) {
|
|
2888
|
+
sy -= y;
|
|
2889
|
+
h += y;
|
|
2890
|
+
y = 0;
|
|
2891
|
+
}
|
|
2892
|
+
const actualW = Math.min(w, target.width - x);
|
|
2893
|
+
const actualH = Math.min(h, target.height - y);
|
|
2894
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
2895
|
+
const dx = x - targetX | 0;
|
|
2896
|
+
const dy = y - targetY | 0;
|
|
2897
|
+
const dst32 = target.data32;
|
|
2898
|
+
const src32 = src.data32;
|
|
2899
|
+
const dw = target.width;
|
|
2900
|
+
const sw = src.width;
|
|
2901
|
+
const mPitch = binaryMask.w;
|
|
2902
|
+
const maskData = binaryMask.data;
|
|
2903
|
+
let dIdx = y * dw + x | 0;
|
|
2904
|
+
let sIdx = sy * sw + sx | 0;
|
|
2905
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
2906
|
+
const dStride = dw - actualW | 0;
|
|
2907
|
+
const sStride = sw - actualW | 0;
|
|
2908
|
+
const mStride = mPitch - actualW | 0;
|
|
2909
|
+
const skipVal = invertMask ? 1 : 0;
|
|
2910
|
+
const isOpaque = globalAlpha === 255;
|
|
2911
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
2912
|
+
let didChange = false;
|
|
2913
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2914
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2915
|
+
if (maskData[mIdx] === skipVal) {
|
|
2916
|
+
dIdx++;
|
|
2917
|
+
sIdx++;
|
|
2434
2918
|
mIdx++;
|
|
2435
2919
|
continue;
|
|
2436
2920
|
}
|
|
@@ -2470,956 +2954,744 @@ function blendPixelDataBinaryMask(dst, src, binaryMask, opts = {}) {
|
|
|
2470
2954
|
return didChange;
|
|
2471
2955
|
}
|
|
2472
2956
|
|
|
2473
|
-
// src/History/PixelMutator/
|
|
2957
|
+
// src/History/PixelMutator/mutatorBlendBinaryMask.ts
|
|
2474
2958
|
var defaults6 = {
|
|
2475
2959
|
blendPixelDataBinaryMask
|
|
2476
2960
|
};
|
|
2477
|
-
var
|
|
2961
|
+
var mutatorBlendBinaryMask = ((writer, deps = defaults6) => {
|
|
2478
2962
|
const {
|
|
2479
2963
|
blendPixelDataBinaryMask: blendPixelDataBinaryMask2 = defaults6.blendPixelDataBinaryMask
|
|
2480
2964
|
} = deps;
|
|
2481
2965
|
return {
|
|
2482
|
-
|
|
2483
|
-
const x = opts
|
|
2484
|
-
const y = opts
|
|
2485
|
-
const w = opts
|
|
2486
|
-
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;
|
|
2487
2971
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2488
2972
|
return didChange(blendPixelDataBinaryMask2(writer.config.target, src, mask, opts));
|
|
2489
2973
|
}
|
|
2490
2974
|
};
|
|
2491
2975
|
});
|
|
2492
2976
|
|
|
2493
|
-
// src/PixelData/
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
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;
|
|
2511
2995
|
x = 0;
|
|
2996
|
+
}
|
|
2997
|
+
if (y < 0) {
|
|
2998
|
+
h += y;
|
|
2512
2999
|
y = 0;
|
|
2513
|
-
w = dst.width;
|
|
2514
|
-
h = dst.height;
|
|
2515
3000
|
}
|
|
2516
|
-
const
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
const dst32 = dst.data32;
|
|
2525
|
-
const dw = dst.width;
|
|
2526
|
-
if (actualW === dw && actualH === dst.height && finalX === 0 && finalY === 0) {
|
|
2527
|
-
dst32.fill(color);
|
|
2528
|
-
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;
|
|
2529
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;
|
|
2530
3015
|
for (let iy = 0; iy < actualH; iy++) {
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
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;
|
|
2534
3026
|
}
|
|
3027
|
+
return didChange;
|
|
2535
3028
|
}
|
|
2536
3029
|
|
|
2537
|
-
// src/History/PixelMutator/
|
|
3030
|
+
// src/History/PixelMutator/mutatorBlendColor.ts
|
|
2538
3031
|
var defaults7 = {
|
|
2539
|
-
|
|
3032
|
+
blendColorPixelData
|
|
2540
3033
|
};
|
|
2541
|
-
var
|
|
3034
|
+
var mutatorBlendColor = ((writer, deps = defaults7) => {
|
|
2542
3035
|
const {
|
|
2543
|
-
|
|
3036
|
+
blendColorPixelData: blendColorPixelData2 = defaults7.blendColorPixelData
|
|
2544
3037
|
} = deps;
|
|
2545
3038
|
return {
|
|
2546
|
-
|
|
3039
|
+
blendColor(color, opts) {
|
|
2547
3040
|
const target = writer.config.target;
|
|
2548
|
-
const x =
|
|
2549
|
-
const y =
|
|
2550
|
-
const w =
|
|
2551
|
-
const h =
|
|
2552
|
-
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2553
|
-
|
|
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));
|
|
2554
3047
|
}
|
|
2555
3048
|
};
|
|
2556
3049
|
});
|
|
2557
3050
|
|
|
2558
|
-
// src/PixelData/
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
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;
|
|
2576
3072
|
x = 0;
|
|
3073
|
+
}
|
|
3074
|
+
if (y < 0) {
|
|
3075
|
+
actualH += y;
|
|
2577
3076
|
y = 0;
|
|
2578
|
-
w = dst.width;
|
|
2579
|
-
h = dst.height;
|
|
2580
3077
|
}
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
const
|
|
2590
|
-
|
|
2591
|
-
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;
|
|
2592
3094
|
for (let iy = 0; iy < actualH; iy++) {
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
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;
|
|
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;
|
|
2600
3129
|
}
|
|
3130
|
+
dIdx++;
|
|
3131
|
+
mIdx++;
|
|
2601
3132
|
}
|
|
3133
|
+
dIdx += dStride;
|
|
3134
|
+
mIdx += mStride;
|
|
2602
3135
|
}
|
|
2603
|
-
return
|
|
3136
|
+
return didChange;
|
|
2604
3137
|
}
|
|
2605
3138
|
|
|
2606
|
-
// src/History/PixelMutator/
|
|
3139
|
+
// src/History/PixelMutator/mutatorBlendColorPaintAlphaMask.ts
|
|
2607
3140
|
var defaults8 = {
|
|
2608
|
-
|
|
3141
|
+
blendColorPixelDataAlphaMask
|
|
2609
3142
|
};
|
|
2610
|
-
var
|
|
3143
|
+
var mutatorBlendColorPaintAlphaMask = ((writer, deps = defaults8) => {
|
|
2611
3144
|
const {
|
|
2612
|
-
|
|
3145
|
+
blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults8.blendColorPixelDataAlphaMask
|
|
2613
3146
|
} = deps;
|
|
3147
|
+
const OPTS = {
|
|
3148
|
+
x: 0,
|
|
3149
|
+
y: 0,
|
|
3150
|
+
blendFn: sourceOverPerfect,
|
|
3151
|
+
alpha: 255
|
|
3152
|
+
};
|
|
2614
3153
|
return {
|
|
2615
|
-
|
|
2616
|
-
const
|
|
2617
|
-
const
|
|
2618
|
-
|
|
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));
|
|
2619
3163
|
}
|
|
2620
3164
|
};
|
|
2621
3165
|
});
|
|
2622
|
-
|
|
3166
|
+
|
|
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;
|
|
3187
|
+
}
|
|
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;
|
|
3233
|
+
}
|
|
3234
|
+
|
|
3235
|
+
// src/History/PixelMutator/mutatorBlendColorPaintBinaryMask.ts
|
|
3236
|
+
var defaults9 = {
|
|
3237
|
+
blendColorPixelDataBinaryMask
|
|
3238
|
+
};
|
|
3239
|
+
var mutatorBlendColorPaintBinaryMask = ((writer, deps = defaults9) => {
|
|
2623
3240
|
const {
|
|
2624
|
-
|
|
3241
|
+
blendColorPixelDataBinaryMask: blendColorPixelDataBinaryMask2 = defaults9.blendColorPixelDataBinaryMask
|
|
2625
3242
|
} = deps;
|
|
3243
|
+
const OPTS = {
|
|
3244
|
+
x: 0,
|
|
3245
|
+
y: 0,
|
|
3246
|
+
blendFn: sourceOverPerfect,
|
|
3247
|
+
alpha: 255
|
|
3248
|
+
};
|
|
2626
3249
|
return {
|
|
2627
|
-
|
|
2628
|
-
const
|
|
2629
|
-
const
|
|
2630
|
-
|
|
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));
|
|
2631
3259
|
}
|
|
2632
3260
|
};
|
|
2633
3261
|
});
|
|
2634
3262
|
|
|
2635
|
-
// src/
|
|
2636
|
-
var
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
const maskW = mask.w;
|
|
2640
|
-
const maskH = mask.h;
|
|
2641
|
-
const clip = resolveRectClipping(x, y, maskW, maskH, dst.width, dst.height, SCRATCH_RECT3);
|
|
2642
|
-
if (!clip.inBounds) return false;
|
|
2643
|
-
const {
|
|
2644
|
-
x: finalX,
|
|
2645
|
-
y: finalY,
|
|
2646
|
-
w: actualW,
|
|
2647
|
-
h: actualH
|
|
2648
|
-
} = clip;
|
|
2649
|
-
const maskData = mask.data;
|
|
2650
|
-
const dst32 = dst.data32;
|
|
2651
|
-
const dw = dst.width;
|
|
2652
|
-
let finalCol = color;
|
|
2653
|
-
if (alpha < 255) {
|
|
2654
|
-
const baseSrcAlpha = color >>> 24;
|
|
2655
|
-
const colorRGB = color & 16777215;
|
|
2656
|
-
const a = baseSrcAlpha * alpha + 128 >> 8;
|
|
2657
|
-
finalCol = (colorRGB | a << 24) >>> 0;
|
|
2658
|
-
}
|
|
2659
|
-
let hasChanged = false;
|
|
2660
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
2661
|
-
const currentY = finalY + iy;
|
|
2662
|
-
const maskY = currentY - y;
|
|
2663
|
-
const maskOffset = maskY * maskW;
|
|
2664
|
-
const dstRowOffset = currentY * dw;
|
|
2665
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
2666
|
-
const currentX = finalX + ix;
|
|
2667
|
-
const maskX = currentX - x;
|
|
2668
|
-
const maskIndex = maskOffset + maskX;
|
|
2669
|
-
if (maskData[maskIndex]) {
|
|
2670
|
-
const current = dst32[dstRowOffset + currentX];
|
|
2671
|
-
if (current !== finalCol) {
|
|
2672
|
-
dst32[dstRowOffset + currentX] = finalCol;
|
|
2673
|
-
hasChanged = true;
|
|
2674
|
-
}
|
|
2675
|
-
}
|
|
2676
|
-
}
|
|
2677
|
-
}
|
|
2678
|
-
return hasChanged;
|
|
2679
|
-
}
|
|
2680
|
-
|
|
2681
|
-
// src/History/PixelMutator/mutatorFillBinaryMask.ts
|
|
2682
|
-
var defaults9 = {
|
|
2683
|
-
fillPixelDataBinaryMask
|
|
3263
|
+
// src/History/PixelMutator/mutatorBlendColorPaintMask.ts
|
|
3264
|
+
var defaults10 = {
|
|
3265
|
+
blendColorPixelDataAlphaMask,
|
|
3266
|
+
blendColorPixelDataBinaryMask
|
|
2684
3267
|
};
|
|
2685
|
-
var
|
|
3268
|
+
var mutatorBlendColorPaintMask = ((writer, deps = defaults10) => {
|
|
2686
3269
|
const {
|
|
2687
|
-
|
|
3270
|
+
blendColorPixelDataBinaryMask: blendColorPixelDataBinaryMask2 = defaults10.blendColorPixelDataBinaryMask,
|
|
3271
|
+
blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults10.blendColorPixelDataAlphaMask
|
|
2688
3272
|
} = deps;
|
|
3273
|
+
const OPTS = {
|
|
3274
|
+
x: 0,
|
|
3275
|
+
y: 0,
|
|
3276
|
+
blendFn: sourceOverPerfect,
|
|
3277
|
+
alpha: 255
|
|
3278
|
+
};
|
|
2689
3279
|
return {
|
|
2690
|
-
|
|
2691
|
-
const
|
|
2692
|
-
|
|
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
|
+
}
|
|
2693
3293
|
}
|
|
2694
3294
|
};
|
|
2695
3295
|
});
|
|
2696
3296
|
|
|
2697
|
-
// src/
|
|
2698
|
-
var
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
y: targetY = 0,
|
|
2704
|
-
w: width = pixelData.width,
|
|
2705
|
-
h: height = pixelData.height,
|
|
2706
|
-
mask,
|
|
2707
|
-
mx = 0,
|
|
2708
|
-
my = 0,
|
|
2709
|
-
invertMask = false
|
|
2710
|
-
} = opts;
|
|
2711
|
-
const clip = resolveRectClipping(targetX, targetY, width, height, dst.width, dst.height, SCRATCH_RECT4);
|
|
2712
|
-
if (!clip.inBounds) return false;
|
|
3297
|
+
// src/History/PixelMutator/mutatorBlendMask.ts
|
|
3298
|
+
var defaults11 = {
|
|
3299
|
+
blendPixelDataAlphaMask,
|
|
3300
|
+
blendPixelDataBinaryMask
|
|
3301
|
+
};
|
|
3302
|
+
var mutatorBlendMask = ((writer, deps = defaults11) => {
|
|
2713
3303
|
const {
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
if (mask) {
|
|
2729
|
-
const maskData = mask.data;
|
|
2730
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
2731
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
2732
|
-
const mVal = maskData[mIdx];
|
|
2733
|
-
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
2734
|
-
if (isHit) {
|
|
2735
|
-
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
2736
|
-
}
|
|
2737
|
-
dIdx++;
|
|
2738
|
-
mIdx++;
|
|
2739
|
-
}
|
|
2740
|
-
dIdx += dStride;
|
|
2741
|
-
mIdx += mStride;
|
|
2742
|
-
}
|
|
2743
|
-
} else {
|
|
2744
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
2745
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
2746
|
-
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
2747
|
-
dIdx++;
|
|
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));
|
|
2748
3318
|
}
|
|
2749
|
-
dIdx += dStride;
|
|
2750
3319
|
}
|
|
2751
|
-
}
|
|
2752
|
-
|
|
2753
|
-
}
|
|
3320
|
+
};
|
|
3321
|
+
});
|
|
2754
3322
|
|
|
2755
|
-
// src/History/PixelMutator/
|
|
2756
|
-
var
|
|
2757
|
-
|
|
3323
|
+
// src/History/PixelMutator/mutatorBlendPaintRect.ts
|
|
3324
|
+
var defaults12 = {
|
|
3325
|
+
blendColorPixelData
|
|
2758
3326
|
};
|
|
2759
|
-
var
|
|
3327
|
+
var mutatorBlendPaintRect = ((writer, deps = defaults12) => {
|
|
2760
3328
|
const {
|
|
2761
|
-
|
|
3329
|
+
blendColorPixelData: blendColorPixelData2 = defaults12.blendColorPixelData
|
|
2762
3330
|
} = deps;
|
|
3331
|
+
const OPTS = {
|
|
3332
|
+
x: 0,
|
|
3333
|
+
y: 0,
|
|
3334
|
+
w: 0,
|
|
3335
|
+
h: 0,
|
|
3336
|
+
blendFn: sourceOverPerfect,
|
|
3337
|
+
alpha: 255
|
|
3338
|
+
};
|
|
2763
3339
|
return {
|
|
2764
|
-
|
|
3340
|
+
blendPaintRect(color, centerX, centerY, brushWidth, brushHeight, alpha = 255, blendFn = sourceOverPerfect) {
|
|
2765
3341
|
const target = writer.config.target;
|
|
2766
|
-
const
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
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));
|
|
2774
3352
|
}
|
|
2775
3353
|
};
|
|
2776
3354
|
});
|
|
2777
3355
|
|
|
2778
|
-
// src/
|
|
2779
|
-
function
|
|
2780
|
-
return
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
// src/ImageData/resizeImageData.ts
|
|
2796
|
-
function resizeImageData(target, newWidth, newHeight, offsetX = 0, offsetY = 0) {
|
|
2797
|
-
const result = new ImageData(newWidth, newHeight);
|
|
2798
|
-
const {
|
|
2799
|
-
width: oldW,
|
|
2800
|
-
height: oldH,
|
|
2801
|
-
data: oldData
|
|
2802
|
-
} = target;
|
|
2803
|
-
const newData = result.data;
|
|
2804
|
-
const x0 = Math.max(0, offsetX);
|
|
2805
|
-
const y0 = Math.max(0, offsetY);
|
|
2806
|
-
const x1 = Math.min(newWidth, offsetX + oldW);
|
|
2807
|
-
const y1 = Math.min(newHeight, offsetY + oldH);
|
|
2808
|
-
if (x1 <= x0 || y1 <= y0) {
|
|
2809
|
-
return result;
|
|
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;
|
|
2810
3372
|
}
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
const srcX = x0 - offsetX;
|
|
2817
|
-
const dstStart = (dstY * newWidth + x0) * 4;
|
|
2818
|
-
const srcStart = (srcY * oldW + srcX) * 4;
|
|
2819
|
-
newData.set(oldData.subarray(srcStart, srcStart + rowLen), dstStart);
|
|
3373
|
+
let current = dst32[index];
|
|
3374
|
+
let next = blendFn(finalColor, current);
|
|
3375
|
+
if (current !== next) {
|
|
3376
|
+
dst32[index] = next;
|
|
3377
|
+
return true;
|
|
2820
3378
|
}
|
|
2821
|
-
return
|
|
3379
|
+
return false;
|
|
2822
3380
|
}
|
|
2823
3381
|
|
|
2824
|
-
// src/
|
|
2825
|
-
var
|
|
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
|
+
});
|
|
2826
3397
|
|
|
2827
|
-
// src/
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
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
|
+
}
|
|
2834
3415
|
};
|
|
2835
|
-
|
|
2836
|
-
const top = Math.max(0, y);
|
|
2837
|
-
const right = Math.min(targetWidth, x + w);
|
|
2838
|
-
const bottom = Math.min(targetHeight, y + h);
|
|
2839
|
-
res.x = left;
|
|
2840
|
-
res.y = top;
|
|
2841
|
-
res.w = Math.max(0, right - left);
|
|
2842
|
-
res.h = Math.max(0, bottom - top);
|
|
2843
|
-
return res;
|
|
2844
|
-
}
|
|
3416
|
+
});
|
|
2845
3417
|
|
|
2846
|
-
// src/
|
|
2847
|
-
var
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
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;
|
|
2852
3440
|
}
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
x: 0,
|
|
2856
|
-
y: 0,
|
|
2857
|
-
w: 0,
|
|
2858
|
-
h: 0
|
|
2859
|
-
};
|
|
2860
|
-
eachTileInBounds(bounds, callback) {
|
|
2861
|
-
const {
|
|
2862
|
-
tileShift,
|
|
2863
|
-
targetColumns,
|
|
2864
|
-
targetRows,
|
|
2865
|
-
tileSize
|
|
2866
|
-
} = this.config;
|
|
2867
|
-
const x1 = Math.max(0, bounds.x >> tileShift);
|
|
2868
|
-
const y1 = Math.max(0, bounds.y >> tileShift);
|
|
2869
|
-
const x2 = Math.min(targetColumns - 1, bounds.x + bounds.w - 1 >> tileShift);
|
|
2870
|
-
const y2 = Math.min(targetRows - 1, bounds.y + bounds.h - 1 >> tileShift);
|
|
2871
|
-
if (x1 > x2 || y1 > y2) return;
|
|
2872
|
-
const lookup = this.lookup;
|
|
2873
|
-
const tilePool = this.tilePool;
|
|
2874
|
-
for (let ty = y1; ty <= y2; ty++) {
|
|
2875
|
-
const rowOffset = ty * targetColumns;
|
|
2876
|
-
const tileTop = ty << tileShift;
|
|
2877
|
-
for (let tx = x1; tx <= x2; tx++) {
|
|
2878
|
-
const id = rowOffset + tx;
|
|
2879
|
-
const tile = lookup[id] ?? (lookup[id] = tilePool.getTile(id, tx, ty));
|
|
2880
|
-
const tileLeft = tx << tileShift;
|
|
2881
|
-
const startX = bounds.x > tileLeft ? bounds.x : tileLeft;
|
|
2882
|
-
const startY = bounds.y > tileTop ? bounds.y : tileTop;
|
|
2883
|
-
const maskEndX = bounds.x + bounds.w;
|
|
2884
|
-
const tileEndX = tileLeft + tileSize;
|
|
2885
|
-
const endX = maskEndX < tileEndX ? maskEndX : tileEndX;
|
|
2886
|
-
const maskEndY = bounds.y + bounds.h;
|
|
2887
|
-
const tileEndY = tileTop + tileSize;
|
|
2888
|
-
const endY = maskEndY < tileEndY ? maskEndY : tileEndY;
|
|
2889
|
-
callback(tile, startX, startY, endX - startX, endY - startY);
|
|
2890
|
-
}
|
|
2891
|
-
}
|
|
2892
|
-
}
|
|
2893
|
-
writePaintAlphaMaskStroke(color, brush, x0, y0, x1, y1) {
|
|
2894
|
-
const cA = color >>> 24;
|
|
2895
|
-
if (cA === 0) return false;
|
|
2896
|
-
const {
|
|
2897
|
-
tileShift,
|
|
2898
|
-
tileMask,
|
|
2899
|
-
target
|
|
2900
|
-
} = this.config;
|
|
2901
|
-
const {
|
|
2902
|
-
w: bW,
|
|
2903
|
-
h: bH,
|
|
2904
|
-
data: bD,
|
|
2905
|
-
centerOffsetX,
|
|
2906
|
-
centerOffsetY
|
|
2907
|
-
} = brush;
|
|
2908
|
-
const cRGB = color & 16777215;
|
|
2909
|
-
const scratch = this.scratchBounds;
|
|
2910
|
-
let changed = false;
|
|
2911
|
-
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
2912
|
-
const topLeftX = Math.floor(px + centerOffsetX);
|
|
2913
|
-
const topLeftY = Math.floor(py + centerOffsetY);
|
|
2914
|
-
trimRectBounds(topLeftX, topLeftY, bW, bH, target.width, target.height, scratch);
|
|
2915
|
-
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
2916
|
-
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
2917
|
-
const d32 = tile.data32;
|
|
2918
|
-
let tileChanged = false;
|
|
2919
|
-
for (let i = 0; i < bH_t; i++) {
|
|
2920
|
-
const canvasY = bY + i;
|
|
2921
|
-
const bOff = (canvasY - topLeftY) * bW;
|
|
2922
|
-
const tOff = (canvasY & tileMask) << tileShift;
|
|
2923
|
-
const dS = tOff + (bX & tileMask);
|
|
2924
|
-
for (let j = 0; j < bW_t; j++) {
|
|
2925
|
-
const canvasX = bX + j;
|
|
2926
|
-
const brushA = bD[bOff + (canvasX - topLeftX)];
|
|
2927
|
-
if (brushA === 0) continue;
|
|
2928
|
-
const t = cA * brushA + 128;
|
|
2929
|
-
const blendedA = t + (t >> 8) >> 8;
|
|
2930
|
-
const idx = dS + j;
|
|
2931
|
-
const cur = d32[idx];
|
|
2932
|
-
if (brushA > cur >>> 24) {
|
|
2933
|
-
const next = (cRGB | blendedA << 24) >>> 0;
|
|
2934
|
-
if (cur !== next) {
|
|
2935
|
-
d32[idx] = next;
|
|
2936
|
-
tileChanged = true;
|
|
2937
|
-
}
|
|
2938
|
-
}
|
|
2939
|
-
}
|
|
2940
|
-
}
|
|
2941
|
-
if (tileChanged) changed = true;
|
|
2942
|
-
});
|
|
2943
|
-
});
|
|
2944
|
-
return changed;
|
|
2945
|
-
}
|
|
2946
|
-
writePaintBinaryMaskStroke(color, brush, x0, y0, x1, y1) {
|
|
2947
|
-
const alphaIsZero = color >>> 24 === 0;
|
|
2948
|
-
if (alphaIsZero) return false;
|
|
2949
|
-
const {
|
|
2950
|
-
tileShift,
|
|
2951
|
-
tileMask,
|
|
2952
|
-
target
|
|
2953
|
-
} = this.config;
|
|
2954
|
-
const {
|
|
2955
|
-
w: bW,
|
|
2956
|
-
h: bH,
|
|
2957
|
-
data: bD,
|
|
2958
|
-
centerOffsetX,
|
|
2959
|
-
centerOffsetY
|
|
2960
|
-
} = brush;
|
|
2961
|
-
const scratch = this.scratchBounds;
|
|
2962
|
-
let changed = false;
|
|
2963
|
-
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
2964
|
-
const topLeftX = Math.floor(px + centerOffsetX);
|
|
2965
|
-
const topLeftY = Math.floor(py + centerOffsetY);
|
|
2966
|
-
trimRectBounds(topLeftX, topLeftY, bW, bH, target.width, target.height, scratch);
|
|
2967
|
-
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
2968
|
-
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
2969
|
-
const d32 = tile.data32;
|
|
2970
|
-
let tileChanged = false;
|
|
2971
|
-
for (let i = 0; i < bH_t; i++) {
|
|
2972
|
-
const canvasY = bY + i;
|
|
2973
|
-
const bOff = (canvasY - topLeftY) * bW;
|
|
2974
|
-
const tOff = (canvasY & tileMask) << tileShift;
|
|
2975
|
-
const dS = tOff + (bX & tileMask);
|
|
2976
|
-
for (let j = 0; j < bW_t; j++) {
|
|
2977
|
-
const canvasX = bX + j;
|
|
2978
|
-
if (bD[bOff + (canvasX - topLeftX)]) {
|
|
2979
|
-
const idx = dS + j;
|
|
2980
|
-
if (d32[idx] !== color) {
|
|
2981
|
-
d32[idx] = color;
|
|
2982
|
-
tileChanged = true;
|
|
2983
|
-
}
|
|
2984
|
-
}
|
|
2985
|
-
}
|
|
2986
|
-
}
|
|
2987
|
-
if (tileChanged) changed = true;
|
|
2988
|
-
});
|
|
2989
|
-
});
|
|
2990
|
-
return changed;
|
|
2991
|
-
}
|
|
2992
|
-
writeRectStroke(color, brushWidth, brushHeight, x0, y0, x1, y1) {
|
|
2993
|
-
const alphaIsZero = color >>> 24 === 0;
|
|
2994
|
-
if (alphaIsZero) return false;
|
|
2995
|
-
const config = this.config;
|
|
2996
|
-
const tileShift = config.tileShift;
|
|
2997
|
-
const tileMask = config.tileMask;
|
|
2998
|
-
const target = config.target;
|
|
2999
|
-
const scratch = this.scratchBounds;
|
|
3000
|
-
const centerOffsetX = macro_halfAndFloor(brushWidth - 1);
|
|
3001
|
-
const centerOffsetY = macro_halfAndFloor(brushHeight - 1);
|
|
3002
|
-
let changed = false;
|
|
3003
|
-
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
3004
|
-
const topLeftX = Math.floor(px + centerOffsetX);
|
|
3005
|
-
const topLeftY = Math.floor(py + centerOffsetY);
|
|
3006
|
-
trimRectBounds(topLeftX, topLeftY, brushWidth, brushHeight, target.width, target.height, scratch);
|
|
3007
|
-
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
3008
|
-
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
3009
|
-
const d32 = tile.data32;
|
|
3010
|
-
let tileChanged = false;
|
|
3011
|
-
for (let i = 0; i < bH_t; i++) {
|
|
3012
|
-
const canvasY = bY + i;
|
|
3013
|
-
const tOff = (canvasY & tileMask) << tileShift;
|
|
3014
|
-
const dS = tOff + (bX & tileMask);
|
|
3015
|
-
for (let j = 0; j < bW_t; j++) {
|
|
3016
|
-
const idx = dS + j;
|
|
3017
|
-
if (d32[idx] !== color) {
|
|
3018
|
-
d32[idx] = color;
|
|
3019
|
-
tileChanged = true;
|
|
3020
|
-
}
|
|
3021
|
-
}
|
|
3022
|
-
}
|
|
3023
|
-
if (tileChanged) {
|
|
3024
|
-
changed = true;
|
|
3025
|
-
}
|
|
3026
|
-
});
|
|
3027
|
-
});
|
|
3028
|
-
return changed;
|
|
3029
|
-
}
|
|
3030
|
-
clear() {
|
|
3031
|
-
this.tilePool.releaseTiles(this.lookup);
|
|
3032
|
-
}
|
|
3033
|
-
};
|
|
3034
|
-
|
|
3035
|
-
// src/PixelTile/PixelTile.ts
|
|
3036
|
-
var PixelTile = class {
|
|
3037
|
-
constructor(id, tx, ty, tileSize, tileArea) {
|
|
3038
|
-
this.id = id;
|
|
3039
|
-
this.tx = tx;
|
|
3040
|
-
this.ty = ty;
|
|
3041
|
-
this.width = this.height = tileSize;
|
|
3042
|
-
this.data32 = new Uint32Array(tileArea);
|
|
3043
|
-
const data8 = new Uint8ClampedArray(this.data32.buffer);
|
|
3044
|
-
this.imageData = new ImageData(data8, tileSize, tileSize);
|
|
3045
|
-
}
|
|
3046
|
-
data32;
|
|
3047
|
-
width;
|
|
3048
|
-
height;
|
|
3049
|
-
imageData;
|
|
3050
|
-
};
|
|
3051
|
-
|
|
3052
|
-
// src/PixelTile/PixelTilePool.ts
|
|
3053
|
-
var PixelTilePool = class {
|
|
3054
|
-
pool;
|
|
3055
|
-
tileSize;
|
|
3056
|
-
tileArea;
|
|
3057
|
-
constructor(config) {
|
|
3058
|
-
this.pool = [];
|
|
3059
|
-
this.tileSize = config.tileSize;
|
|
3060
|
-
this.tileArea = config.tileArea;
|
|
3061
|
-
}
|
|
3062
|
-
getTile(id, tx, ty) {
|
|
3063
|
-
let tile = this.pool.pop();
|
|
3064
|
-
if (tile) {
|
|
3065
|
-
tile.id = id;
|
|
3066
|
-
tile.tx = tx;
|
|
3067
|
-
tile.ty = ty;
|
|
3068
|
-
tile.data32.fill(0);
|
|
3069
|
-
return tile;
|
|
3070
|
-
}
|
|
3071
|
-
return new PixelTile(id, tx, ty, this.tileSize, this.tileArea);
|
|
3072
|
-
}
|
|
3073
|
-
releaseTile(tile) {
|
|
3074
|
-
this.pool.push(tile);
|
|
3075
|
-
}
|
|
3076
|
-
releaseTiles(tiles) {
|
|
3077
|
-
let length = tiles.length;
|
|
3078
|
-
for (let i = 0; i < length; i++) {
|
|
3079
|
-
let tile = tiles[i];
|
|
3080
|
-
if (tile) {
|
|
3081
|
-
this.pool.push(tile);
|
|
3082
|
-
}
|
|
3083
|
-
}
|
|
3084
|
-
tiles.length = 0;
|
|
3085
|
-
}
|
|
3086
|
-
};
|
|
3087
|
-
|
|
3088
|
-
// src/History/PixelWriter.ts
|
|
3089
|
-
var PixelWriter = class {
|
|
3090
|
-
historyManager;
|
|
3091
|
-
accumulator;
|
|
3092
|
-
historyActionFactory;
|
|
3093
|
-
config;
|
|
3094
|
-
pixelTilePool;
|
|
3095
|
-
paintBuffer;
|
|
3096
|
-
mutator;
|
|
3097
|
-
blendPixelDataOpts = {
|
|
3098
|
-
alpha: 255,
|
|
3099
|
-
blendFn: sourceOverPerfect,
|
|
3100
|
-
x: 0,
|
|
3101
|
-
y: 0,
|
|
3102
|
-
w: 0,
|
|
3103
|
-
h: 0
|
|
3104
|
-
};
|
|
3105
|
-
_inProgress = false;
|
|
3106
|
-
constructor(target, mutatorFactory, {
|
|
3107
|
-
tileSize = 256,
|
|
3108
|
-
maxHistorySteps = 50,
|
|
3109
|
-
historyManager = new HistoryManager(maxHistorySteps),
|
|
3110
|
-
historyActionFactory = makeHistoryAction,
|
|
3111
|
-
pixelTilePool,
|
|
3112
|
-
accumulator
|
|
3113
|
-
} = {}) {
|
|
3114
|
-
this.config = new PixelEngineConfig(tileSize, target);
|
|
3115
|
-
this.historyManager = historyManager;
|
|
3116
|
-
this.pixelTilePool = pixelTilePool ?? new PixelTilePool(this.config);
|
|
3117
|
-
this.accumulator = accumulator ?? new PixelAccumulator(this.config, this.pixelTilePool);
|
|
3118
|
-
this.historyActionFactory = historyActionFactory;
|
|
3119
|
-
this.mutator = mutatorFactory(this);
|
|
3120
|
-
this.paintBuffer = new PaintBuffer(this.config, this.pixelTilePool);
|
|
3121
|
-
}
|
|
3122
|
-
/**
|
|
3123
|
-
* Executes `transaction` and commits the resulting pixel changes as a single
|
|
3124
|
-
* undoable history action.
|
|
3125
|
-
*
|
|
3126
|
-
* - If `transaction` throws, all accumulated changes are rolled back and the error
|
|
3127
|
-
* is re-thrown. No action is committed.
|
|
3128
|
-
* - If `transaction` completes without modifying any pixels, no action is committed.
|
|
3129
|
-
* - `withHistory` is not re-entrant. Calling it again from inside `transaction` will
|
|
3130
|
-
* throw immediately to prevent silent data loss from a nested extractPatch.
|
|
3131
|
-
*
|
|
3132
|
-
* @param transaction Callback to be executed inside the transaction.
|
|
3133
|
-
* @param after Called after both undo and redo — use for generic change notifications.
|
|
3134
|
-
* @param afterUndo Called after undo only — use for dimension or state changes specific to undo.
|
|
3135
|
-
* @param afterRedo Called after redo only.
|
|
3136
|
-
*/
|
|
3137
|
-
withHistory(transaction, after, afterUndo, afterRedo) {
|
|
3138
|
-
if (this._inProgress) {
|
|
3139
|
-
throw new Error("withHistory is not re-entrant \u2014 commit or rollback the current operation first");
|
|
3140
|
-
}
|
|
3141
|
-
this._inProgress = true;
|
|
3142
|
-
try {
|
|
3143
|
-
transaction(this.mutator);
|
|
3144
|
-
} catch (e) {
|
|
3145
|
-
this.accumulator.rollbackAfterError();
|
|
3146
|
-
throw e;
|
|
3147
|
-
} finally {
|
|
3148
|
-
this._inProgress = false;
|
|
3149
|
-
}
|
|
3150
|
-
if (this.accumulator.beforeTiles.length === 0) return;
|
|
3151
|
-
const patch = this.accumulator.extractPatch();
|
|
3152
|
-
const action = this.historyActionFactory(this, patch, after, afterUndo, afterRedo);
|
|
3153
|
-
this.historyManager.commit(action);
|
|
3154
|
-
}
|
|
3155
|
-
resize(newWidth, newHeight, offsetX = 0, offsetY = 0, after, afterUndo, afterRedo, resizeImageDataFn = resizeImageData) {
|
|
3156
|
-
if (this._inProgress) {
|
|
3157
|
-
throw new Error("Cannot resize inside a withHistory callback");
|
|
3158
|
-
}
|
|
3159
|
-
if (this.accumulator.beforeTiles.length > 0) {
|
|
3160
|
-
throw new Error("Cannot resize with an open accumulator \u2014 commit or rollback first");
|
|
3161
|
-
}
|
|
3162
|
-
const config = this.config;
|
|
3163
|
-
const target = config.target;
|
|
3164
|
-
const beforeImageData = target.imageData;
|
|
3165
|
-
const afterImageData = resizeImageDataFn(beforeImageData, newWidth, newHeight, offsetX, offsetY);
|
|
3166
|
-
target.set(afterImageData);
|
|
3167
|
-
this.historyManager.commit({
|
|
3168
|
-
undo: () => {
|
|
3169
|
-
target.set(beforeImageData);
|
|
3170
|
-
afterUndo?.(beforeImageData);
|
|
3171
|
-
after?.(beforeImageData);
|
|
3172
|
-
},
|
|
3173
|
-
redo: () => {
|
|
3174
|
-
target.set(afterImageData);
|
|
3175
|
-
afterRedo?.(afterImageData);
|
|
3176
|
-
after?.(afterImageData);
|
|
3177
|
-
}
|
|
3178
|
-
});
|
|
3179
|
-
}
|
|
3180
|
-
commitPaintBuffer(alpha = 255, blendFn = sourceOverPerfect, blendPixelDataFn = blendPixelData) {
|
|
3181
|
-
const paintBuffer = this.paintBuffer;
|
|
3182
|
-
const tileShift = paintBuffer.config.tileShift;
|
|
3183
|
-
const lookup = paintBuffer.lookup;
|
|
3184
|
-
const opts = this.blendPixelDataOpts;
|
|
3185
|
-
opts.alpha = alpha;
|
|
3186
|
-
opts.blendFn = blendFn;
|
|
3187
|
-
for (let i = 0; i < lookup.length; i++) {
|
|
3188
|
-
const tile = lookup[i];
|
|
3189
|
-
if (tile) {
|
|
3190
|
-
const didChange = this.accumulator.storeTileBeforeState(tile.id, tile.tx, tile.ty);
|
|
3191
|
-
const dx = tile.tx << tileShift;
|
|
3192
|
-
const dy = tile.ty << tileShift;
|
|
3193
|
-
opts.x = dx;
|
|
3194
|
-
opts.y = dy;
|
|
3195
|
-
opts.w = tile.width;
|
|
3196
|
-
opts.h = tile.height;
|
|
3197
|
-
didChange(blendPixelDataFn(this.config.target, tile, opts));
|
|
3198
|
-
}
|
|
3199
|
-
}
|
|
3200
|
-
paintBuffer.clear();
|
|
3201
|
-
}
|
|
3202
|
-
};
|
|
3203
|
-
|
|
3204
|
-
// src/PixelData/applyAlphaMaskToPixelData.ts
|
|
3205
|
-
function applyAlphaMaskToPixelData(dst, mask, opts = {}) {
|
|
3441
|
+
const clip = resolveRectClipping(x, y, w, h, dst.width, dst.height, SCRATCH_RECT);
|
|
3442
|
+
if (!clip.inBounds) return false;
|
|
3206
3443
|
const {
|
|
3207
|
-
x:
|
|
3208
|
-
y:
|
|
3209
|
-
w:
|
|
3210
|
-
h:
|
|
3211
|
-
|
|
3212
|
-
mx = 0,
|
|
3213
|
-
my = 0,
|
|
3214
|
-
invertMask = false
|
|
3215
|
-
} = opts;
|
|
3216
|
-
if (globalAlpha === 0) return false;
|
|
3217
|
-
let x = targetX;
|
|
3218
|
-
let y = targetY;
|
|
3219
|
-
let w = width;
|
|
3220
|
-
let h = height;
|
|
3221
|
-
if (x < 0) {
|
|
3222
|
-
w += x;
|
|
3223
|
-
x = 0;
|
|
3224
|
-
}
|
|
3225
|
-
if (y < 0) {
|
|
3226
|
-
h += y;
|
|
3227
|
-
y = 0;
|
|
3228
|
-
}
|
|
3229
|
-
w = Math.min(w, dst.width - x);
|
|
3230
|
-
h = Math.min(h, dst.height - y);
|
|
3231
|
-
if (w <= 0) return false;
|
|
3232
|
-
if (h <= 0) return false;
|
|
3233
|
-
const mPitch = mask.w;
|
|
3234
|
-
if (mPitch <= 0) return false;
|
|
3235
|
-
const startX = mx + (x - targetX);
|
|
3236
|
-
const startY = my + (y - targetY);
|
|
3237
|
-
const sX0 = Math.max(0, startX);
|
|
3238
|
-
const sY0 = Math.max(0, startY);
|
|
3239
|
-
const sX1 = Math.min(mPitch, startX + w);
|
|
3240
|
-
const sY1 = Math.min(mask.h, startY + h);
|
|
3241
|
-
const finalW = sX1 - sX0;
|
|
3242
|
-
const finalH = sY1 - sY0;
|
|
3243
|
-
if (finalW <= 0) return false;
|
|
3244
|
-
if (finalH <= 0) return false;
|
|
3245
|
-
const xShift = sX0 - startX;
|
|
3246
|
-
const yShift = sY0 - startY;
|
|
3444
|
+
x: finalX,
|
|
3445
|
+
y: finalY,
|
|
3446
|
+
w: actualW,
|
|
3447
|
+
h: actualH
|
|
3448
|
+
} = clip;
|
|
3247
3449
|
const dst32 = dst.data32;
|
|
3248
3450
|
const dw = dst.width;
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
3259
|
-
let weight = 0;
|
|
3260
|
-
if (effectiveM === 0) {
|
|
3261
|
-
weight = 0;
|
|
3262
|
-
} else if (effectiveM === 255) {
|
|
3263
|
-
weight = globalAlpha;
|
|
3264
|
-
} else if (globalAlpha === 255) {
|
|
3265
|
-
weight = effectiveM;
|
|
3266
|
-
} else {
|
|
3267
|
-
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
3268
|
-
}
|
|
3269
|
-
if (weight === 0) {
|
|
3270
|
-
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
3271
|
-
didChange = true;
|
|
3272
|
-
} else if (weight !== 255) {
|
|
3273
|
-
const d = dst32[dIdx];
|
|
3274
|
-
const da = d >>> 24;
|
|
3275
|
-
if (da !== 0) {
|
|
3276
|
-
const finalAlpha = da === 255 ? weight : da * weight + 128 >> 8;
|
|
3277
|
-
const current = dst32[dIdx];
|
|
3278
|
-
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
3279
|
-
if (current !== next) {
|
|
3280
|
-
dst32[dIdx] = next;
|
|
3281
|
-
didChange = true;
|
|
3282
|
-
}
|
|
3283
|
-
}
|
|
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;
|
|
3284
3460
|
}
|
|
3285
|
-
dIdx++;
|
|
3286
|
-
mIdx++;
|
|
3287
3461
|
}
|
|
3288
|
-
dIdx += dStride;
|
|
3289
|
-
mIdx += mStride;
|
|
3290
3462
|
}
|
|
3291
|
-
return
|
|
3463
|
+
return hasChanged;
|
|
3292
3464
|
}
|
|
3293
3465
|
|
|
3294
|
-
// src/History/PixelMutator/
|
|
3295
|
-
var
|
|
3296
|
-
|
|
3466
|
+
// src/History/PixelMutator/mutatorClear.ts
|
|
3467
|
+
var defaults15 = {
|
|
3468
|
+
fillPixelData
|
|
3297
3469
|
};
|
|
3298
|
-
var
|
|
3470
|
+
var mutatorClear = ((writer, deps = defaults15) => {
|
|
3299
3471
|
const {
|
|
3300
|
-
|
|
3472
|
+
fillPixelData: fillPixelData2 = defaults15.fillPixelData
|
|
3301
3473
|
} = deps;
|
|
3302
3474
|
return {
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
const
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
h = target.height
|
|
3310
|
-
} = opts;
|
|
3475
|
+
clear(rect) {
|
|
3476
|
+
const target = writer.config.target;
|
|
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;
|
|
3311
3481
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3312
|
-
return didChange(
|
|
3482
|
+
return didChange(fillPixelData2(target, 0, x, y, w, h));
|
|
3313
3483
|
}
|
|
3314
3484
|
};
|
|
3315
3485
|
});
|
|
3316
3486
|
|
|
3317
|
-
// src/
|
|
3318
|
-
|
|
3487
|
+
// src/History/PixelMutator/mutatorFill.ts
|
|
3488
|
+
var defaults16 = {
|
|
3489
|
+
fillPixelData
|
|
3490
|
+
};
|
|
3491
|
+
var mutatorFill = ((writer, deps = defaults16) => {
|
|
3319
3492
|
const {
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
}
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
const
|
|
3348
|
-
const
|
|
3349
|
-
|
|
3350
|
-
const
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
return false;
|
|
3357
|
-
}
|
|
3358
|
-
const xShift = sX0 - startX;
|
|
3359
|
-
const yShift = sY0 - startY;
|
|
3360
|
-
const dst32 = dst.data32;
|
|
3361
|
-
const dw = dst.width;
|
|
3362
|
-
const dStride = dw - finalW;
|
|
3363
|
-
const mStride = mPitch - finalW;
|
|
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));
|
|
3500
|
+
}
|
|
3501
|
+
};
|
|
3502
|
+
});
|
|
3503
|
+
var mutatorFillRect = ((writer, deps = defaults16) => {
|
|
3504
|
+
const {
|
|
3505
|
+
fillPixelData: fillPixelData2 = defaults16.fillPixelData
|
|
3506
|
+
} = deps;
|
|
3507
|
+
return {
|
|
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));
|
|
3512
|
+
}
|
|
3513
|
+
};
|
|
3514
|
+
});
|
|
3515
|
+
|
|
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;
|
|
3523
|
+
const {
|
|
3524
|
+
x: finalX,
|
|
3525
|
+
y: finalY,
|
|
3526
|
+
w: actualW,
|
|
3527
|
+
h: actualH
|
|
3528
|
+
} = clip;
|
|
3364
3529
|
const maskData = mask.data;
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
let
|
|
3368
|
-
for (let iy = 0; iy <
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
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;
|
|
3378
3547
|
}
|
|
3379
|
-
}
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3548
|
+
}
|
|
3549
|
+
}
|
|
3550
|
+
}
|
|
3551
|
+
return hasChanged;
|
|
3552
|
+
}
|
|
3553
|
+
|
|
3554
|
+
// src/History/PixelMutator/mutatorFillBinaryMask.ts
|
|
3555
|
+
var defaults17 = {
|
|
3556
|
+
fillPixelDataBinaryMask
|
|
3557
|
+
};
|
|
3558
|
+
var mutatorFillBinaryMask = ((writer, deps = defaults17) => {
|
|
3559
|
+
const {
|
|
3560
|
+
fillPixelDataBinaryMask: fillPixelDataBinaryMask2 = defaults17.fillPixelDataBinaryMask
|
|
3561
|
+
} = deps;
|
|
3562
|
+
return {
|
|
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));
|
|
3566
|
+
}
|
|
3567
|
+
};
|
|
3568
|
+
});
|
|
3569
|
+
|
|
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;
|
|
3389
3606
|
}
|
|
3607
|
+
dIdx++;
|
|
3608
|
+
mIdx++;
|
|
3390
3609
|
}
|
|
3391
|
-
dIdx
|
|
3392
|
-
mIdx
|
|
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++;
|
|
3618
|
+
}
|
|
3619
|
+
dIdx += dStride;
|
|
3393
3620
|
}
|
|
3394
|
-
dIdx += dStride;
|
|
3395
|
-
mIdx += mStride;
|
|
3396
3621
|
}
|
|
3397
|
-
return
|
|
3622
|
+
return true;
|
|
3398
3623
|
}
|
|
3399
3624
|
|
|
3400
|
-
// src/History/PixelMutator/
|
|
3401
|
-
var
|
|
3402
|
-
|
|
3625
|
+
// src/History/PixelMutator/mutatorInvert.ts
|
|
3626
|
+
var defaults18 = {
|
|
3627
|
+
invertPixelData
|
|
3403
3628
|
};
|
|
3404
|
-
var
|
|
3629
|
+
var mutatorInvert = ((writer, deps = defaults18) => {
|
|
3405
3630
|
const {
|
|
3406
|
-
|
|
3631
|
+
invertPixelData: invertPixelData2 = defaults18.invertPixelData
|
|
3407
3632
|
} = deps;
|
|
3408
3633
|
return {
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
const
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
h = target.height
|
|
3416
|
-
} = opts;
|
|
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;
|
|
3417
3640
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3418
|
-
return didChange(
|
|
3641
|
+
return didChange(invertPixelData2(target, opts));
|
|
3419
3642
|
}
|
|
3420
3643
|
};
|
|
3421
3644
|
});
|
|
3422
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
|
+
|
|
3423
3695
|
// src/ImageData/copyImageData.ts
|
|
3424
3696
|
function copyImageData({
|
|
3425
3697
|
data,
|
|
@@ -3440,17 +3712,6 @@ function copyImageDataLike({
|
|
|
3440
3712
|
};
|
|
3441
3713
|
}
|
|
3442
3714
|
|
|
3443
|
-
// src/ImageData/ImageDataLike.ts
|
|
3444
|
-
function makeImageDataLike(width, height, data) {
|
|
3445
|
-
const size = width * height * 4;
|
|
3446
|
-
const buffer = data ? new Uint8ClampedArray(data.buffer, data.byteOffset, size) : new Uint8ClampedArray(size);
|
|
3447
|
-
return {
|
|
3448
|
-
width,
|
|
3449
|
-
height,
|
|
3450
|
-
data: buffer
|
|
3451
|
-
};
|
|
3452
|
-
}
|
|
3453
|
-
|
|
3454
3715
|
// src/ImageData/imageDataToAlphaMaskBuffer.ts
|
|
3455
3716
|
function imageDataToAlphaMaskBuffer(imageData) {
|
|
3456
3717
|
const {
|
|
@@ -3538,20 +3799,7 @@ function resampleImageData(source, factor) {
|
|
|
3538
3799
|
height
|
|
3539
3800
|
} = resample32(src32, source.width, source.height, factor);
|
|
3540
3801
|
const uint8ClampedArray = new Uint8ClampedArray(data.buffer);
|
|
3541
|
-
return new ImageData(uint8ClampedArray, width, height);
|
|
3542
|
-
}
|
|
3543
|
-
|
|
3544
|
-
// src/ImageData/ReusableImageData.ts
|
|
3545
|
-
function makeReusableImageData() {
|
|
3546
|
-
let imageData = null;
|
|
3547
|
-
return function getReusableImageData(width, height) {
|
|
3548
|
-
if (imageData === null || imageData.width !== width || imageData.height !== height) {
|
|
3549
|
-
imageData = new ImageData(width, height);
|
|
3550
|
-
} else {
|
|
3551
|
-
imageData.data.fill(0);
|
|
3552
|
-
}
|
|
3553
|
-
return imageData;
|
|
3554
|
-
};
|
|
3802
|
+
return new ImageData(uint8ClampedArray, width, height);
|
|
3555
3803
|
}
|
|
3556
3804
|
|
|
3557
3805
|
// src/ImageData/serialization.ts
|
|
@@ -3708,18 +3956,6 @@ function writeImageDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
3708
3956
|
}
|
|
3709
3957
|
}
|
|
3710
3958
|
|
|
3711
|
-
// src/IndexedImage/getIndexedImageColorCounts.ts
|
|
3712
|
-
function getIndexedImageColorCounts(indexedImage) {
|
|
3713
|
-
const data = indexedImage.data;
|
|
3714
|
-
const palette = indexedImage.palette;
|
|
3715
|
-
const frequencies = new Int32Array(palette.length);
|
|
3716
|
-
for (let i = 0; i < data.length; i++) {
|
|
3717
|
-
const colorIndex = data[i];
|
|
3718
|
-
frequencies[colorIndex]++;
|
|
3719
|
-
}
|
|
3720
|
-
return frequencies;
|
|
3721
|
-
}
|
|
3722
|
-
|
|
3723
3959
|
// src/IndexedImage/IndexedImage.ts
|
|
3724
3960
|
var IndexedImage = class _IndexedImage {
|
|
3725
3961
|
/** The width of the image in pixels. */
|
|
@@ -3798,6 +4034,18 @@ var IndexedImage = class _IndexedImage {
|
|
|
3798
4034
|
}
|
|
3799
4035
|
};
|
|
3800
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
|
+
|
|
3801
4049
|
// src/IndexedImage/indexedImageToAverageColor.ts
|
|
3802
4050
|
function indexedImageToAverageColor(indexedImage, includeTransparent = false) {
|
|
3803
4051
|
const {
|
|
@@ -3956,16 +4204,14 @@ function makeBinaryMask(w, h, data) {
|
|
|
3956
4204
|
}
|
|
3957
4205
|
|
|
3958
4206
|
// src/Mask/applyBinaryMaskToAlphaMask.ts
|
|
3959
|
-
function applyBinaryMaskToAlphaMask(alphaMaskDst, binaryMaskSrc, opts
|
|
3960
|
-
const
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
invertMask = false
|
|
3968
|
-
} = 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;
|
|
3969
4215
|
const dstWidth = alphaMaskDst.w;
|
|
3970
4216
|
if (dstWidth <= 0) return;
|
|
3971
4217
|
if (binaryMaskSrc.data.length === 0) return;
|
|
@@ -4388,6 +4634,148 @@ function pushPiece(dest, r, x, y, w, h) {
|
|
|
4388
4634
|
});
|
|
4389
4635
|
}
|
|
4390
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 */,
|
|
4771
|
+
data,
|
|
4772
|
+
w: width,
|
|
4773
|
+
h: height,
|
|
4774
|
+
centerOffsetX: -(width >> 1),
|
|
4775
|
+
centerOffsetY: -(height >> 1)
|
|
4776
|
+
};
|
|
4777
|
+
}
|
|
4778
|
+
|
|
4391
4779
|
// src/PixelData/PixelData.ts
|
|
4392
4780
|
var PixelData = class {
|
|
4393
4781
|
data32;
|
|
@@ -4409,170 +4797,96 @@ var PixelData = class {
|
|
|
4409
4797
|
}
|
|
4410
4798
|
};
|
|
4411
4799
|
|
|
4412
|
-
// src/PixelData/
|
|
4413
|
-
function
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
const globalAlpha = opts.alpha ?? 255;
|
|
4419
|
-
const blendFn = opts.blendFn ?? sourceOverPerfect;
|
|
4420
|
-
const mx = opts.mx ?? 0;
|
|
4421
|
-
const my = opts.my ?? 0;
|
|
4422
|
-
const invertMask = opts.invertMask ?? false;
|
|
4423
|
-
if (globalAlpha === 0) return false;
|
|
4424
|
-
const baseSrcAlpha = color >>> 24;
|
|
4425
|
-
const isOverwrite = blendFn.isOverwrite || false;
|
|
4426
|
-
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
4427
|
-
let x = targetX;
|
|
4428
|
-
let y = targetY;
|
|
4429
|
-
let actualW = w;
|
|
4430
|
-
let actualH = h;
|
|
4431
|
-
if (x < 0) {
|
|
4432
|
-
actualW += x;
|
|
4433
|
-
x = 0;
|
|
4434
|
-
}
|
|
4435
|
-
if (y < 0) {
|
|
4436
|
-
actualH += y;
|
|
4437
|
-
y = 0;
|
|
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);
|
|
4438
4806
|
}
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
const maskData = mask.data;
|
|
4448
|
-
let dIdx = y * dw + x | 0;
|
|
4449
|
-
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
4450
|
-
const dStride = dw - actualW | 0;
|
|
4451
|
-
const mStride = mPitch - actualW | 0;
|
|
4452
|
-
const isOpaque = globalAlpha === 255;
|
|
4453
|
-
const colorRGB = color & 16777215;
|
|
4454
|
-
let didChange = false;
|
|
4455
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
4456
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
4457
|
-
const mVal = maskData[mIdx];
|
|
4458
|
-
const effM = invertMask ? 255 - mVal : mVal;
|
|
4459
|
-
if (effM === 0) {
|
|
4460
|
-
dIdx++;
|
|
4461
|
-
mIdx++;
|
|
4462
|
-
continue;
|
|
4463
|
-
}
|
|
4464
|
-
let weight = globalAlpha;
|
|
4465
|
-
if (isOpaque) {
|
|
4466
|
-
weight = effM;
|
|
4467
|
-
} else if (effM !== 255) {
|
|
4468
|
-
weight = effM * globalAlpha + 128 >> 8;
|
|
4469
|
-
}
|
|
4470
|
-
if (weight === 0) {
|
|
4471
|
-
dIdx++;
|
|
4472
|
-
mIdx++;
|
|
4473
|
-
continue;
|
|
4474
|
-
}
|
|
4475
|
-
let finalCol = color;
|
|
4476
|
-
if (weight < 255) {
|
|
4477
|
-
const a = baseSrcAlpha * weight + 128 >> 8;
|
|
4478
|
-
if (a === 0 && !isOverwrite) {
|
|
4479
|
-
dIdx++;
|
|
4480
|
-
mIdx++;
|
|
4481
|
-
continue;
|
|
4482
|
-
}
|
|
4483
|
-
finalCol = (colorRGB | a << 24) >>> 0;
|
|
4484
|
-
}
|
|
4485
|
-
const current = dst32[dIdx];
|
|
4486
|
-
const next = blendFn(finalCol, current);
|
|
4487
|
-
if (current !== next) {
|
|
4488
|
-
dst32[dIdx] = next;
|
|
4489
|
-
didChange = true;
|
|
4490
|
-
}
|
|
4491
|
-
dIdx++;
|
|
4492
|
-
mIdx++;
|
|
4493
|
-
}
|
|
4494
|
-
dIdx += dStride;
|
|
4495
|
-
mIdx += mStride;
|
|
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);
|
|
4496
4815
|
}
|
|
4497
|
-
return didChange;
|
|
4498
4816
|
}
|
|
4499
4817
|
|
|
4500
|
-
// src/PixelData/
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
const
|
|
4509
|
-
const
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
const
|
|
4526
|
-
const
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4818
|
+
// src/PixelData/blendColorPixelDataPaintAlphaMask.ts
|
|
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);
|
|
4533
4870
|
}
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
const dStride = dw - actualW | 0;
|
|
4543
|
-
const mStride = mPitch - actualW | 0;
|
|
4544
|
-
const skipVal = invertMask ? 1 : 0;
|
|
4545
|
-
let didChange = false;
|
|
4546
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
4547
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
4548
|
-
if (maskData[mIdx] === skipVal) {
|
|
4549
|
-
dIdx++;
|
|
4550
|
-
mIdx++;
|
|
4551
|
-
continue;
|
|
4552
|
-
}
|
|
4553
|
-
const current = dst32[dIdx];
|
|
4554
|
-
const next = blendFn(baseColorWithGlobalAlpha, current);
|
|
4555
|
-
if (current !== next) {
|
|
4556
|
-
dst32[dIdx] = next;
|
|
4557
|
-
didChange = true;
|
|
4558
|
-
}
|
|
4559
|
-
dIdx++;
|
|
4560
|
-
mIdx++;
|
|
4561
|
-
}
|
|
4562
|
-
dIdx += dStride;
|
|
4563
|
-
mIdx += mStride;
|
|
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);
|
|
4564
4879
|
}
|
|
4565
|
-
return didChange;
|
|
4566
4880
|
}
|
|
4567
4881
|
|
|
4568
4882
|
// src/PixelData/blendPixelDataPaintBuffer.ts
|
|
4569
|
-
var
|
|
4883
|
+
var SCRATCH_OPTS4 = {
|
|
4570
4884
|
x: 0,
|
|
4571
4885
|
y: 0,
|
|
4572
4886
|
alpha: 255,
|
|
4573
4887
|
blendFn: void 0
|
|
4574
4888
|
};
|
|
4575
|
-
function blendPixelDataPaintBuffer(
|
|
4889
|
+
function blendPixelDataPaintBuffer(target, paintBuffer, alpha = 255, blendFn, blendPixelDataFn = blendPixelData) {
|
|
4576
4890
|
const tileShift = paintBuffer.config.tileShift;
|
|
4577
4891
|
const lookup = paintBuffer.lookup;
|
|
4578
4892
|
for (let i = 0; i < lookup.length; i++) {
|
|
@@ -4580,17 +4894,61 @@ function blendPixelDataPaintBuffer(paintBuffer, target, alpha = 255, blendFn, bl
|
|
|
4580
4894
|
if (tile) {
|
|
4581
4895
|
const x = tile.tx << tileShift;
|
|
4582
4896
|
const y = tile.ty << tileShift;
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
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);
|
|
4588
4902
|
}
|
|
4589
4903
|
}
|
|
4590
4904
|
}
|
|
4591
4905
|
|
|
4592
|
-
// src/PixelData/
|
|
4593
|
-
|
|
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) {
|
|
4594
4952
|
fillPixelDataFast(dst, 0, rect);
|
|
4595
4953
|
}
|
|
4596
4954
|
|
|
@@ -4653,26 +5011,6 @@ function extractPixelData(source, _x, _y, _w, _h) {
|
|
|
4653
5011
|
return result;
|
|
4654
5012
|
}
|
|
4655
5013
|
|
|
4656
|
-
// src/PixelData/PixelBuffer32.ts
|
|
4657
|
-
var PixelBuffer32 = class _PixelBuffer32 {
|
|
4658
|
-
constructor(width, height, data32) {
|
|
4659
|
-
this.width = width;
|
|
4660
|
-
this.height = height;
|
|
4661
|
-
this.data32 = data32 ?? new Uint32Array(width * height);
|
|
4662
|
-
}
|
|
4663
|
-
data32;
|
|
4664
|
-
set(width, height, data32) {
|
|
4665
|
-
;
|
|
4666
|
-
this.data32 = data32 ?? new Uint32Array(width * height);
|
|
4667
|
-
this.width = width;
|
|
4668
|
-
this.height = height;
|
|
4669
|
-
}
|
|
4670
|
-
copy() {
|
|
4671
|
-
const newData32 = new Uint32Array(this.data32);
|
|
4672
|
-
return new _PixelBuffer32(this.width, this.height, newData32);
|
|
4673
|
-
}
|
|
4674
|
-
};
|
|
4675
|
-
|
|
4676
5014
|
// src/PixelData/pixelDataToAlphaMask.ts
|
|
4677
5015
|
function pixelDataToAlphaMask(pixelData) {
|
|
4678
5016
|
const {
|
|
@@ -4824,160 +5162,16 @@ function writePaintBufferToPixelData(target, paintBuffer, writePixelDataBufferFn
|
|
|
4824
5162
|
}
|
|
4825
5163
|
}
|
|
4826
5164
|
}
|
|
4827
|
-
|
|
4828
|
-
// src/Paint/makeCirclePaintAlphaMask.ts
|
|
4829
|
-
function makeCirclePaintAlphaMask(size, fallOff = (d) => d) {
|
|
4830
|
-
const area = size * size;
|
|
4831
|
-
const data = new Uint8Array(area);
|
|
4832
|
-
const radius = size / 2;
|
|
4833
|
-
const invR = 1 / radius;
|
|
4834
|
-
const centerOffset = -Math.ceil(radius - 0.5);
|
|
4835
|
-
for (let y = 0; y < size; y++) {
|
|
4836
|
-
const rowOffset = y * size;
|
|
4837
|
-
const dy = y - radius + 0.5;
|
|
4838
|
-
const dy2 = dy * dy;
|
|
4839
|
-
for (let x = 0; x < size; x++) {
|
|
4840
|
-
const dx = x - radius + 0.5;
|
|
4841
|
-
const distSqr = dx * dx + dy2;
|
|
4842
|
-
if (distSqr <= radius * radius) {
|
|
4843
|
-
const dist = Math.sqrt(distSqr) * invR;
|
|
4844
|
-
const strength = fallOff(1 - dist);
|
|
4845
|
-
if (strength > 0) {
|
|
4846
|
-
const intensity = strength * 255 | 0;
|
|
4847
|
-
data[rowOffset + x] = Math.max(0, Math.min(255, intensity));
|
|
4848
|
-
}
|
|
4849
|
-
}
|
|
4850
|
-
}
|
|
4851
|
-
}
|
|
4852
|
-
return {
|
|
4853
|
-
type: 0 /* ALPHA */,
|
|
4854
|
-
data,
|
|
4855
|
-
w: size,
|
|
4856
|
-
h: size,
|
|
4857
|
-
centerOffsetX: centerOffset,
|
|
4858
|
-
centerOffsetY: centerOffset
|
|
4859
|
-
};
|
|
4860
|
-
}
|
|
4861
|
-
|
|
4862
|
-
// src/Paint/makeCirclePaintBinaryMask.ts
|
|
4863
|
-
function makeCirclePaintBinaryMask(size) {
|
|
4864
|
-
const area = size * size;
|
|
4865
|
-
const data = new Uint8Array(area);
|
|
4866
|
-
const radius = size / 2;
|
|
4867
|
-
const centerOffset = -Math.ceil(radius - 0.5);
|
|
4868
|
-
for (let y = 0; y < size; y++) {
|
|
4869
|
-
for (let x = 0; x < size; x++) {
|
|
4870
|
-
const dx = x - radius + 0.5;
|
|
4871
|
-
const dy = y - radius + 0.5;
|
|
4872
|
-
const distSqr = dx * dx + dy * dy;
|
|
4873
|
-
if (distSqr <= radius * radius) {
|
|
4874
|
-
data[y * size + x] = 1;
|
|
4875
|
-
}
|
|
4876
|
-
}
|
|
4877
|
-
}
|
|
4878
|
-
return {
|
|
4879
|
-
type: 1 /* BINARY */,
|
|
4880
|
-
data,
|
|
4881
|
-
w: size,
|
|
4882
|
-
h: size,
|
|
4883
|
-
centerOffsetX: centerOffset,
|
|
4884
|
-
centerOffsetY: centerOffset
|
|
4885
|
-
};
|
|
4886
|
-
}
|
|
4887
|
-
|
|
4888
|
-
// src/Paint/makePaintMask.ts
|
|
4889
|
-
function makePaintBinaryMask(mask) {
|
|
4890
|
-
return {
|
|
4891
|
-
type: 1 /* BINARY */,
|
|
4892
|
-
data: mask.data,
|
|
4893
|
-
w: mask.w,
|
|
4894
|
-
h: mask.h,
|
|
4895
|
-
centerOffsetX: -macro_halfAndFloor(mask.w),
|
|
4896
|
-
centerOffsetY: -macro_halfAndFloor(mask.h)
|
|
4897
|
-
};
|
|
4898
|
-
}
|
|
4899
|
-
function makePaintAlphaMask(mask) {
|
|
4900
|
-
return {
|
|
4901
|
-
type: 0 /* ALPHA */,
|
|
4902
|
-
data: mask.data,
|
|
4903
|
-
w: mask.w,
|
|
4904
|
-
h: mask.h,
|
|
4905
|
-
centerOffsetX: -macro_halfAndFloor(mask.w),
|
|
4906
|
-
centerOffsetY: -macro_halfAndFloor(mask.h)
|
|
4907
|
-
};
|
|
4908
|
-
}
|
|
4909
|
-
|
|
4910
|
-
// src/Paint/makeRectFalloffPaintAlphaMask.ts
|
|
4911
|
-
function makeRectFalloffPaintAlphaMask(width, height, fallOff = (d) => d) {
|
|
4912
|
-
const fPx = Math.floor(width / 2);
|
|
4913
|
-
const fPy = Math.floor(height / 2);
|
|
4914
|
-
const invHalfW = 2 / width;
|
|
4915
|
-
const invHalfH = 2 / height;
|
|
4916
|
-
const offX = width % 2 === 0 ? 0.5 : 0;
|
|
4917
|
-
const offY = height % 2 === 0 ? 0.5 : 0;
|
|
4918
|
-
const area = width * height;
|
|
4919
|
-
const data = new Uint8Array(area);
|
|
4920
|
-
for (let y = 0; y < height; y++) {
|
|
4921
|
-
const dy = Math.abs(y - fPy + offY) * invHalfH;
|
|
4922
|
-
const rowOffset = y * width;
|
|
4923
|
-
for (let x = 0; x < width; x++) {
|
|
4924
|
-
const dx = Math.abs(x - fPx + offX) * invHalfW;
|
|
4925
|
-
const dist = dx > dy ? dx : dy;
|
|
4926
|
-
const strength = fallOff(1 - dist);
|
|
4927
|
-
if (strength > 0) {
|
|
4928
|
-
const intensity = strength * 255 | 0;
|
|
4929
|
-
data[rowOffset + x] = Math.max(0, Math.min(255, intensity));
|
|
4930
|
-
}
|
|
4931
|
-
}
|
|
4932
|
-
}
|
|
4933
|
-
return {
|
|
4934
|
-
type: 0 /* ALPHA */,
|
|
4935
|
-
data,
|
|
4936
|
-
w: width,
|
|
4937
|
-
h: height,
|
|
4938
|
-
centerOffsetX: -(width >> 1),
|
|
4939
|
-
centerOffsetY: -(height >> 1)
|
|
4940
|
-
};
|
|
4941
|
-
}
|
|
4942
|
-
|
|
4943
|
-
// src/Paint/PaintBufferCanvasRenderer.ts
|
|
4944
|
-
function makePaintBufferCanvasRenderer(paintBuffer, offscreenCanvasClass = OffscreenCanvas) {
|
|
4945
|
-
const config = paintBuffer.config;
|
|
4946
|
-
const tileSize = config.tileSize;
|
|
4947
|
-
const tileShift = config.tileShift;
|
|
4948
|
-
const lookup = paintBuffer.lookup;
|
|
4949
|
-
const canvas = new offscreenCanvasClass(tileSize, tileSize);
|
|
4950
|
-
const ctx = canvas.getContext("2d");
|
|
4951
|
-
if (!ctx) throw new Error(CANVAS_CTX_FAILED);
|
|
4952
|
-
ctx.imageSmoothingEnabled = false;
|
|
4953
|
-
return function drawPaintBuffer(targetCtx, alpha = 255, compOperation = "source-over") {
|
|
4954
|
-
targetCtx.globalAlpha = alpha / 255;
|
|
4955
|
-
targetCtx.globalCompositeOperation = compOperation;
|
|
4956
|
-
for (let i = 0; i < lookup.length; i++) {
|
|
4957
|
-
const tile = lookup[i];
|
|
4958
|
-
if (tile) {
|
|
4959
|
-
const dx = tile.tx << tileShift;
|
|
4960
|
-
const dy = tile.ty << tileShift;
|
|
4961
|
-
ctx.putImageData(tile.imageData, 0, 0);
|
|
4962
|
-
targetCtx.drawImage(canvas, dx, dy);
|
|
4963
|
-
}
|
|
4964
|
-
}
|
|
4965
|
-
targetCtx.globalAlpha = 1;
|
|
4966
|
-
targetCtx.globalCompositeOperation = "source-over";
|
|
4967
|
-
};
|
|
4968
|
-
}
|
|
4969
5165
|
export {
|
|
4970
5166
|
BASE_FAST_BLEND_MODE_FUNCTIONS,
|
|
4971
5167
|
BASE_PERFECT_BLEND_MODE_FUNCTIONS,
|
|
4972
5168
|
BaseBlendMode,
|
|
4973
|
-
|
|
5169
|
+
CANVAS_COMPOSITE_MAP,
|
|
4974
5170
|
HistoryManager,
|
|
4975
5171
|
IndexedImage,
|
|
4976
5172
|
MaskType,
|
|
4977
|
-
OFFSCREEN_CANVAS_CTX_FAILED,
|
|
4978
5173
|
PaintBuffer,
|
|
4979
5174
|
PixelAccumulator,
|
|
4980
|
-
PixelBuffer32,
|
|
4981
5175
|
PixelData,
|
|
4982
5176
|
PixelEngineConfig,
|
|
4983
5177
|
PixelTile,
|
|
@@ -4987,18 +5181,24 @@ export {
|
|
|
4987
5181
|
applyAlphaMaskToPixelData,
|
|
4988
5182
|
applyBinaryMaskToAlphaMask,
|
|
4989
5183
|
applyBinaryMaskToPixelData,
|
|
5184
|
+
applyMaskToPixelData,
|
|
4990
5185
|
applyPatchTiles,
|
|
4991
5186
|
base64DecodeArrayBuffer,
|
|
4992
5187
|
base64EncodeArrayBuffer,
|
|
4993
5188
|
blendColorPixelData,
|
|
4994
5189
|
blendColorPixelDataAlphaMask,
|
|
4995
5190
|
blendColorPixelDataBinaryMask,
|
|
5191
|
+
blendColorPixelDataMask,
|
|
5192
|
+
blendColorPixelDataPaintAlphaMask,
|
|
5193
|
+
blendColorPixelDataPaintBinaryMask,
|
|
5194
|
+
blendColorPixelDataPaintMask,
|
|
4996
5195
|
blendPixel,
|
|
4997
5196
|
blendPixelData,
|
|
4998
5197
|
blendPixelDataAlphaMask,
|
|
4999
5198
|
blendPixelDataBinaryMask,
|
|
5199
|
+
blendPixelDataMask,
|
|
5000
5200
|
blendPixelDataPaintBuffer,
|
|
5001
|
-
|
|
5201
|
+
clearPixelDataFast,
|
|
5002
5202
|
color32ToCssRGBA,
|
|
5003
5203
|
color32ToHex,
|
|
5004
5204
|
colorBurnFast,
|
|
@@ -5071,6 +5271,8 @@ export {
|
|
|
5071
5271
|
makeCanvasFrameRenderer,
|
|
5072
5272
|
makeCirclePaintAlphaMask,
|
|
5073
5273
|
makeCirclePaintBinaryMask,
|
|
5274
|
+
makeClippedBlit,
|
|
5275
|
+
makeClippedRect,
|
|
5074
5276
|
makeFastBlendModeRegistry,
|
|
5075
5277
|
makeFullPixelMutator,
|
|
5076
5278
|
makeHistoryAction,
|
|
@@ -5092,11 +5294,17 @@ export {
|
|
|
5092
5294
|
multiplyPerfect,
|
|
5093
5295
|
mutatorApplyAlphaMask,
|
|
5094
5296
|
mutatorApplyBinaryMask,
|
|
5297
|
+
mutatorApplyMask,
|
|
5298
|
+
mutatorBlendAlphaMask,
|
|
5299
|
+
mutatorBlendBinaryMask,
|
|
5095
5300
|
mutatorBlendColor,
|
|
5301
|
+
mutatorBlendColorPaintAlphaMask,
|
|
5302
|
+
mutatorBlendColorPaintBinaryMask,
|
|
5303
|
+
mutatorBlendColorPaintMask,
|
|
5304
|
+
mutatorBlendMask,
|
|
5305
|
+
mutatorBlendPaintRect,
|
|
5096
5306
|
mutatorBlendPixel,
|
|
5097
5307
|
mutatorBlendPixelData,
|
|
5098
|
-
mutatorBlendPixelDataAlphaMask,
|
|
5099
|
-
mutatorBlendPixelDataBinaryMask,
|
|
5100
5308
|
mutatorClear,
|
|
5101
5309
|
mutatorFill,
|
|
5102
5310
|
mutatorFillBinaryMask,
|
|
@@ -5114,10 +5322,13 @@ export {
|
|
|
5114
5322
|
pixelDataToAlphaMask,
|
|
5115
5323
|
reflectPixelDataHorizontal,
|
|
5116
5324
|
reflectPixelDataVertical,
|
|
5325
|
+
resample32,
|
|
5117
5326
|
resampleImageData,
|
|
5118
5327
|
resampleIndexedImage,
|
|
5119
5328
|
resamplePixelData,
|
|
5120
5329
|
resizeImageData,
|
|
5330
|
+
resolveBlitClipping,
|
|
5331
|
+
resolveRectClipping,
|
|
5121
5332
|
rotatePixelData,
|
|
5122
5333
|
screenFast,
|
|
5123
5334
|
screenPerfect,
|