pixel-data-js 0.24.0 → 0.25.2
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.dev.cjs +1476 -1834
- package/dist/index.dev.cjs.map +1 -1
- package/dist/index.dev.js +1465 -1816
- package/dist/index.dev.js.map +1 -1
- package/dist/index.prod.cjs +1475 -1833
- package/dist/index.prod.cjs.map +1 -1
- package/dist/index.prod.d.ts +233 -310
- package/dist/index.prod.js +1465 -1816
- package/dist/index.prod.js.map +1 -1
- package/package.json +1 -1
- package/src/Algorithm/floodFillSelection.ts +2 -2
- package/src/Canvas/canvas-blend-modes.ts +28 -0
- package/src/History/PixelAccumulator.ts +52 -29
- package/src/History/PixelEngineConfig.ts +7 -9
- package/src/History/PixelMutator/mutatorBlendPaintMask.ts +60 -0
- package/src/History/PixelMutator/mutatorBlendPixelData.ts +2 -2
- package/src/History/PixelMutator/mutatorBlendPixelDataAlphaMask.ts +2 -2
- package/src/History/PixelMutator/mutatorBlendPixelDataBinaryMask.ts +2 -2
- package/src/History/PixelMutator.ts +0 -20
- package/src/History/PixelPatchTiles.ts +2 -2
- package/src/History/PixelWriter.ts +132 -9
- package/src/Internal/helpers.ts +2 -0
- package/src/Paint/PaintBuffer.ts +269 -0
- package/src/{PixelTile/PaintBufferRenderer.ts → Paint/PaintBufferCanvasRenderer.ts} +13 -5
- package/src/Paint/makeCirclePaintAlphaMask.ts +41 -0
- package/src/{Mask/CircleBinaryMask.ts → Paint/makeCirclePaintBinaryMask.ts} +5 -6
- package/src/Paint/makePaintMask.ts +28 -0
- package/src/Paint/makeRectFalloffPaintAlphaMask.ts +47 -0
- package/src/PixelData/PixelBuffer32.ts +2 -2
- package/src/PixelData/PixelData.ts +1 -1
- package/src/PixelData/applyAlphaMaskToPixelData.ts +2 -2
- package/src/PixelData/applyBinaryMaskToPixelData.ts +2 -2
- package/src/PixelData/blendColorPixelData.ts +2 -2
- package/src/PixelData/blendColorPixelDataAlphaMask.ts +3 -3
- package/src/PixelData/blendColorPixelDataBinaryMask.ts +3 -3
- package/src/PixelData/blendPixel.ts +2 -2
- package/src/PixelData/blendPixelData.ts +3 -3
- package/src/PixelData/blendPixelDataAlphaMask.ts +3 -3
- package/src/PixelData/blendPixelDataBinaryMask.ts +3 -3
- package/src/PixelData/blendPixelDataPaintBuffer.ts +3 -3
- package/src/PixelData/clearPixelData.ts +2 -2
- package/src/PixelData/extractPixelData.ts +4 -4
- package/src/PixelData/extractPixelDataBuffer.ts +4 -4
- package/src/PixelData/fillPixelData.ts +5 -5
- package/src/PixelData/fillPixelDataBinaryMask.ts +3 -3
- package/src/PixelData/fillPixelDataFast.ts +5 -5
- package/src/PixelData/invertPixelData.ts +2 -2
- package/src/PixelData/pixelDataToAlphaMask.ts +2 -2
- package/src/PixelData/reflectPixelData.ts +3 -3
- package/src/PixelData/resamplePixelData.ts +2 -2
- package/src/PixelData/writePaintBufferToPixelData.ts +26 -0
- package/src/PixelData/writePixelDataBuffer.ts +5 -5
- package/src/Rect/trimMaskRectBounds.ts +121 -0
- package/src/Rect/trimRectBounds.ts +25 -116
- package/src/_types.ts +16 -15
- package/src/index.ts +11 -24
- package/src/History/PixelMutator/mutatorApplyCircleBrushStroke.ts +0 -182
- package/src/History/PixelMutator/mutatorApplyCirclePencil.ts +0 -59
- package/src/History/PixelMutator/mutatorApplyCirclePencilStroke.ts +0 -172
- package/src/History/PixelMutator/mutatorApplyRectBrush.ts +0 -64
- package/src/History/PixelMutator/mutatorApplyRectBrushStroke.ts +0 -184
- package/src/History/PixelMutator/mutatorApplyRectPencil.ts +0 -65
- package/src/History/PixelMutator/mutatorApplyRectPencilStroke.ts +0 -166
- package/src/History/PixelMutator/mutatorBlendColorCircleMask.ts +0 -71
- package/src/Mask/CircleAlphaMask.ts +0 -32
- package/src/PixelData/applyRectBrushToPixelData.ts +0 -98
- package/src/PixelData/blendColorPixelDataCircleMask.ts +0 -92
- package/src/PixelTile/PaintBuffer.ts +0 -122
- package/src/Rect/getCircleBrushOrPencilBounds.ts +0 -43
- package/src/Rect/getCircleBrushOrPencilStrokeBounds.ts +0 -24
- package/src/Rect/getRectBrushOrPencilBounds.ts +0 -38
- package/src/Rect/getRectBrushOrPencilStrokeBounds.ts +0 -26
package/dist/index.dev.js
CHANGED
|
@@ -232,8 +232,8 @@ function extractMaskBuffer(maskBuffer, maskWidth, xOrRect, y, w, h) {
|
|
|
232
232
|
return out;
|
|
233
233
|
}
|
|
234
234
|
|
|
235
|
-
// src/Rect/
|
|
236
|
-
function
|
|
235
|
+
// src/Rect/trimMaskRectBounds.ts
|
|
236
|
+
function trimMaskRectBounds(target, bounds) {
|
|
237
237
|
const originalX = target.x;
|
|
238
238
|
const originalY = target.y;
|
|
239
239
|
const originalW = target.w;
|
|
@@ -421,7 +421,7 @@ function floodFillSelection(img, startX, startY, {
|
|
|
421
421
|
finalMask[my * sw + mx] = 1;
|
|
422
422
|
}
|
|
423
423
|
}
|
|
424
|
-
|
|
424
|
+
trimMaskRectBounds(selectionRect, {
|
|
425
425
|
x: 0,
|
|
426
426
|
y: 0,
|
|
427
427
|
w: width,
|
|
@@ -1533,6 +1533,24 @@ var getKeyByValue = (obj, value) => {
|
|
|
1533
1533
|
var OFFSCREEN_CANVAS_CTX_FAILED = "Failed to create OffscreenCanvas context";
|
|
1534
1534
|
var CANVAS_CTX_FAILED = "Failed to create Canvas context";
|
|
1535
1535
|
|
|
1536
|
+
// src/Canvas/canvas-blend-modes.ts
|
|
1537
|
+
var CANVAS_COMPOSITE_MAP = {
|
|
1538
|
+
[BaseBlendMode.overwrite]: "copy",
|
|
1539
|
+
[BaseBlendMode.sourceOver]: "source-over",
|
|
1540
|
+
[BaseBlendMode.darken]: "darken",
|
|
1541
|
+
[BaseBlendMode.multiply]: "multiply",
|
|
1542
|
+
[BaseBlendMode.colorBurn]: "color-burn",
|
|
1543
|
+
[BaseBlendMode.lighten]: "lighten",
|
|
1544
|
+
[BaseBlendMode.screen]: "screen",
|
|
1545
|
+
[BaseBlendMode.colorDodge]: "color-dodge",
|
|
1546
|
+
[BaseBlendMode.linearDodge]: "lighter",
|
|
1547
|
+
[BaseBlendMode.overlay]: "overlay",
|
|
1548
|
+
[BaseBlendMode.softLight]: "soft-light",
|
|
1549
|
+
[BaseBlendMode.hardLight]: "hard-light",
|
|
1550
|
+
[BaseBlendMode.difference]: "difference",
|
|
1551
|
+
[BaseBlendMode.exclusion]: "exclusion"
|
|
1552
|
+
};
|
|
1553
|
+
|
|
1536
1554
|
// src/Canvas/ReusableCanvas.ts
|
|
1537
1555
|
function makeReusableCanvas() {
|
|
1538
1556
|
return makeReusableCanvasMeta((w, h) => {
|
|
@@ -1811,11 +1829,11 @@ var PixelAccumulator = class {
|
|
|
1811
1829
|
* @param y pixel y coordinate
|
|
1812
1830
|
*/
|
|
1813
1831
|
storePixelBeforeState(x, y) {
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1832
|
+
const shift = this.config.tileShift;
|
|
1833
|
+
const columns = this.config.targetColumns;
|
|
1834
|
+
const tx = x >> shift;
|
|
1835
|
+
const ty = y >> shift;
|
|
1836
|
+
const id = ty * columns + tx;
|
|
1819
1837
|
let tile = this.lookup[id];
|
|
1820
1838
|
let added = false;
|
|
1821
1839
|
if (!tile) {
|
|
@@ -1841,16 +1859,16 @@ var PixelAccumulator = class {
|
|
|
1841
1859
|
* @param h pixel height
|
|
1842
1860
|
*/
|
|
1843
1861
|
storeRegionBeforeState(x, y, w, h) {
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1862
|
+
const shift = this.config.tileShift;
|
|
1863
|
+
const columns = this.config.targetColumns;
|
|
1864
|
+
const startX = x >> shift;
|
|
1865
|
+
const startY = y >> shift;
|
|
1866
|
+
const endX = x + w - 1 >> shift;
|
|
1867
|
+
const endY = y + h - 1 >> shift;
|
|
1868
|
+
const startIndex = this.beforeTiles.length;
|
|
1851
1869
|
for (let ty = startY; ty <= endY; ty++) {
|
|
1852
1870
|
for (let tx = startX; tx <= endX; tx++) {
|
|
1853
|
-
|
|
1871
|
+
const id = ty * columns + tx;
|
|
1854
1872
|
let tile = this.lookup[id];
|
|
1855
1873
|
if (!tile) {
|
|
1856
1874
|
tile = this.tilePool.getTile(id, tx, ty);
|
|
@@ -1862,7 +1880,7 @@ var PixelAccumulator = class {
|
|
|
1862
1880
|
}
|
|
1863
1881
|
return (didChange) => {
|
|
1864
1882
|
if (!didChange) {
|
|
1865
|
-
|
|
1883
|
+
const length = this.beforeTiles.length;
|
|
1866
1884
|
for (let i = startIndex; i < length; i++) {
|
|
1867
1885
|
let t = this.beforeTiles[i];
|
|
1868
1886
|
if (t) {
|
|
@@ -1875,15 +1893,34 @@ var PixelAccumulator = class {
|
|
|
1875
1893
|
return didChange;
|
|
1876
1894
|
};
|
|
1877
1895
|
}
|
|
1896
|
+
storeTileBeforeState(id, tx, ty) {
|
|
1897
|
+
let tile = this.lookup[id];
|
|
1898
|
+
let added = false;
|
|
1899
|
+
if (!tile) {
|
|
1900
|
+
tile = this.tilePool.getTile(id, tx, ty);
|
|
1901
|
+
this.extractState(tile);
|
|
1902
|
+
this.lookup[id] = tile;
|
|
1903
|
+
this.beforeTiles.push(tile);
|
|
1904
|
+
added = true;
|
|
1905
|
+
}
|
|
1906
|
+
return (didChange) => {
|
|
1907
|
+
if (!didChange && added) {
|
|
1908
|
+
this.beforeTiles.pop();
|
|
1909
|
+
this.lookup[id] = void 0;
|
|
1910
|
+
this.tilePool.releaseTile(tile);
|
|
1911
|
+
}
|
|
1912
|
+
return didChange;
|
|
1913
|
+
};
|
|
1914
|
+
}
|
|
1878
1915
|
extractState(tile) {
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1916
|
+
const target = this.config.target;
|
|
1917
|
+
const TILE_SIZE = this.config.tileSize;
|
|
1918
|
+
const dst = tile.data32;
|
|
1919
|
+
const src = target.data32;
|
|
1920
|
+
const startX = tile.tx * TILE_SIZE;
|
|
1921
|
+
const startY = tile.ty * TILE_SIZE;
|
|
1922
|
+
const targetWidth = target.width;
|
|
1923
|
+
const targetHeight = target.height;
|
|
1887
1924
|
if (startX >= targetWidth || startX + TILE_SIZE <= 0 || startY >= targetHeight || startY + TILE_SIZE <= 0) {
|
|
1888
1925
|
dst.fill(0);
|
|
1889
1926
|
return;
|
|
@@ -1909,8 +1946,8 @@ var PixelAccumulator = class {
|
|
|
1909
1946
|
}
|
|
1910
1947
|
}
|
|
1911
1948
|
extractPatch() {
|
|
1912
|
-
|
|
1913
|
-
|
|
1949
|
+
const afterTiles = [];
|
|
1950
|
+
const length = this.beforeTiles.length;
|
|
1914
1951
|
for (let i = 0; i < length; i++) {
|
|
1915
1952
|
let beforeTile = this.beforeTiles[i];
|
|
1916
1953
|
if (beforeTile) {
|
|
@@ -1919,7 +1956,7 @@ var PixelAccumulator = class {
|
|
|
1919
1956
|
afterTiles.push(afterTile);
|
|
1920
1957
|
}
|
|
1921
1958
|
}
|
|
1922
|
-
|
|
1959
|
+
const beforeTiles = this.beforeTiles;
|
|
1923
1960
|
this.beforeTiles = [];
|
|
1924
1961
|
this.lookup.length = 0;
|
|
1925
1962
|
return {
|
|
@@ -1927,10 +1964,10 @@ var PixelAccumulator = class {
|
|
|
1927
1964
|
afterTiles
|
|
1928
1965
|
};
|
|
1929
1966
|
}
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1967
|
+
rollbackAfterError() {
|
|
1968
|
+
const target = this.config.target;
|
|
1969
|
+
const tileSize = this.config.tileSize;
|
|
1970
|
+
const length = this.beforeTiles.length;
|
|
1934
1971
|
applyPatchTiles(target, this.beforeTiles, tileSize);
|
|
1935
1972
|
for (let i = 0; i < length; i++) {
|
|
1936
1973
|
let tile = this.beforeTiles[i];
|
|
@@ -1954,6 +1991,7 @@ var PixelEngineConfig = class {
|
|
|
1954
1991
|
tileArea;
|
|
1955
1992
|
target;
|
|
1956
1993
|
targetColumns = 0;
|
|
1994
|
+
targetRows = 0;
|
|
1957
1995
|
constructor(tileSize, target) {
|
|
1958
1996
|
if ((tileSize & tileSize - 1) !== 0) {
|
|
1959
1997
|
throw new Error("tileSize must be a power of 2");
|
|
@@ -1962,28 +2000,26 @@ var PixelEngineConfig = class {
|
|
|
1962
2000
|
this.tileShift = 31 - Math.clz32(tileSize);
|
|
1963
2001
|
this.tileMask = tileSize - 1;
|
|
1964
2002
|
this.tileArea = tileSize * tileSize;
|
|
1965
|
-
this.setTarget(target);
|
|
1966
|
-
}
|
|
1967
|
-
setTarget(target) {
|
|
1968
|
-
;
|
|
1969
2003
|
this.target = target;
|
|
1970
2004
|
this.targetColumns = target.width + this.tileMask >> this.tileShift;
|
|
2005
|
+
this.targetRows = target.height + this.tileMask >> this.tileShift;
|
|
1971
2006
|
}
|
|
1972
2007
|
};
|
|
1973
2008
|
|
|
1974
|
-
// src/PixelData/
|
|
1975
|
-
function
|
|
2009
|
+
// src/PixelData/blendColorPixelData.ts
|
|
2010
|
+
function blendColorPixelData(dst, color, opts = {}) {
|
|
1976
2011
|
const {
|
|
1977
2012
|
x: targetX = 0,
|
|
1978
2013
|
y: targetY = 0,
|
|
1979
2014
|
w: width = dst.width,
|
|
1980
2015
|
h: height = dst.height,
|
|
1981
2016
|
alpha: globalAlpha = 255,
|
|
1982
|
-
|
|
1983
|
-
my = 0,
|
|
1984
|
-
invertMask = false
|
|
2017
|
+
blendFn = sourceOverPerfect
|
|
1985
2018
|
} = opts;
|
|
1986
2019
|
if (globalAlpha === 0) return false;
|
|
2020
|
+
const baseSrcAlpha = color >>> 24;
|
|
2021
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
2022
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
1987
2023
|
let x = targetX;
|
|
1988
2024
|
let y = targetY;
|
|
1989
2025
|
let w = width;
|
|
@@ -1996,82 +2032,46 @@ function applyAlphaMaskToPixelData(dst, mask, opts = {}) {
|
|
|
1996
2032
|
h += y;
|
|
1997
2033
|
y = 0;
|
|
1998
2034
|
}
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
if (
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
const sY0 = Math.max(0, startY);
|
|
2009
|
-
const sX1 = Math.min(mPitch, startX + w);
|
|
2010
|
-
const sY1 = Math.min(mask.h, startY + h);
|
|
2011
|
-
const finalW = sX1 - sX0;
|
|
2012
|
-
const finalH = sY1 - sY0;
|
|
2013
|
-
if (finalW <= 0) return false;
|
|
2014
|
-
if (finalH <= 0) return false;
|
|
2015
|
-
const xShift = sX0 - startX;
|
|
2016
|
-
const yShift = sY0 - startY;
|
|
2035
|
+
const actualW = Math.min(w, dst.width - x);
|
|
2036
|
+
const actualH = Math.min(h, dst.height - y);
|
|
2037
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
2038
|
+
let finalSrcColor = color;
|
|
2039
|
+
if (globalAlpha < 255) {
|
|
2040
|
+
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
2041
|
+
if (a === 0 && !isOverwrite) return false;
|
|
2042
|
+
finalSrcColor = (color & 16777215 | a << 24) >>> 0;
|
|
2043
|
+
}
|
|
2017
2044
|
const dst32 = dst.data32;
|
|
2018
2045
|
const dw = dst.width;
|
|
2019
|
-
|
|
2020
|
-
const
|
|
2021
|
-
const maskData = mask.data;
|
|
2022
|
-
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
2023
|
-
let mIdx = sY0 * mPitch + sX0;
|
|
2046
|
+
let dIdx = y * dw + x | 0;
|
|
2047
|
+
const dStride = dw - actualW | 0;
|
|
2024
2048
|
let didChange = false;
|
|
2025
|
-
for (let iy = 0; iy <
|
|
2026
|
-
for (let ix = 0; ix <
|
|
2027
|
-
const
|
|
2028
|
-
const
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
weight = 0;
|
|
2032
|
-
} else if (effectiveM === 255) {
|
|
2033
|
-
weight = globalAlpha;
|
|
2034
|
-
} else if (globalAlpha === 255) {
|
|
2035
|
-
weight = effectiveM;
|
|
2036
|
-
} else {
|
|
2037
|
-
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
2038
|
-
}
|
|
2039
|
-
if (weight === 0) {
|
|
2040
|
-
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
2049
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2050
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2051
|
+
const current = dst32[dIdx];
|
|
2052
|
+
const next = blendFn(finalSrcColor, current);
|
|
2053
|
+
if (current !== next) {
|
|
2054
|
+
dst32[dIdx] = next;
|
|
2041
2055
|
didChange = true;
|
|
2042
|
-
} else if (weight !== 255) {
|
|
2043
|
-
const d = dst32[dIdx];
|
|
2044
|
-
const da = d >>> 24;
|
|
2045
|
-
if (da !== 0) {
|
|
2046
|
-
const finalAlpha = da === 255 ? weight : da * weight + 128 >> 8;
|
|
2047
|
-
const current = dst32[dIdx];
|
|
2048
|
-
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
2049
|
-
if (current !== next) {
|
|
2050
|
-
dst32[dIdx] = next;
|
|
2051
|
-
didChange = true;
|
|
2052
|
-
}
|
|
2053
|
-
}
|
|
2054
2056
|
}
|
|
2055
2057
|
dIdx++;
|
|
2056
|
-
mIdx++;
|
|
2057
2058
|
}
|
|
2058
2059
|
dIdx += dStride;
|
|
2059
|
-
mIdx += mStride;
|
|
2060
2060
|
}
|
|
2061
2061
|
return didChange;
|
|
2062
2062
|
}
|
|
2063
2063
|
|
|
2064
|
-
// src/History/PixelMutator/
|
|
2064
|
+
// src/History/PixelMutator/mutatorBlendColor.ts
|
|
2065
2065
|
var defaults2 = {
|
|
2066
|
-
|
|
2066
|
+
blendColorPixelData
|
|
2067
2067
|
};
|
|
2068
|
-
var
|
|
2068
|
+
var mutatorBlendColor = ((writer, deps = defaults2) => {
|
|
2069
2069
|
const {
|
|
2070
|
-
|
|
2070
|
+
blendColorPixelData: blendColorPixelData2 = defaults2.blendColorPixelData
|
|
2071
2071
|
} = deps;
|
|
2072
2072
|
return {
|
|
2073
|
-
|
|
2074
|
-
|
|
2073
|
+
blendColor(color, opts = {}) {
|
|
2074
|
+
const target = writer.config.target;
|
|
2075
2075
|
const {
|
|
2076
2076
|
x = 0,
|
|
2077
2077
|
y = 0,
|
|
@@ -2079,159 +2079,227 @@ var mutatorApplyAlphaMask = ((writer, deps = defaults2) => {
|
|
|
2079
2079
|
h = target.height
|
|
2080
2080
|
} = opts;
|
|
2081
2081
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2082
|
-
return didChange(
|
|
2082
|
+
return didChange(blendColorPixelData2(target, color, opts));
|
|
2083
2083
|
}
|
|
2084
2084
|
};
|
|
2085
2085
|
});
|
|
2086
2086
|
|
|
2087
|
-
// src/PixelData/
|
|
2088
|
-
function
|
|
2087
|
+
// src/PixelData/blendPixel.ts
|
|
2088
|
+
function blendPixel(target, x, y, color, alpha = 255, blendFn = sourceOverPerfect) {
|
|
2089
|
+
if (alpha === 0) return false;
|
|
2090
|
+
let width = target.width;
|
|
2091
|
+
let height = target.height;
|
|
2092
|
+
if (x < 0 || x >= width || y < 0 || y >= height) return false;
|
|
2093
|
+
let srcAlpha = color >>> 24;
|
|
2094
|
+
let isOverwrite = blendFn.isOverwrite;
|
|
2095
|
+
if (srcAlpha === 0 && !isOverwrite) return false;
|
|
2096
|
+
let dst32 = target.data32;
|
|
2097
|
+
let index = y * width + x;
|
|
2098
|
+
let finalColor = color;
|
|
2099
|
+
if (alpha !== 255) {
|
|
2100
|
+
let finalAlpha = srcAlpha * alpha + 128 >> 8;
|
|
2101
|
+
if (finalAlpha === 0 && !isOverwrite) return false;
|
|
2102
|
+
finalColor = (color & 16777215 | finalAlpha << 24) >>> 0;
|
|
2103
|
+
}
|
|
2104
|
+
let current = dst32[index];
|
|
2105
|
+
let next = blendFn(finalColor, current);
|
|
2106
|
+
if (current !== next) {
|
|
2107
|
+
dst32[index] = next;
|
|
2108
|
+
return true;
|
|
2109
|
+
}
|
|
2110
|
+
return false;
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
// src/History/PixelMutator/mutatorBlendPixel.ts
|
|
2114
|
+
var defaults3 = {
|
|
2115
|
+
blendPixel
|
|
2116
|
+
};
|
|
2117
|
+
var mutatorBlendPixel = ((writer, deps = defaults3) => {
|
|
2118
|
+
const {
|
|
2119
|
+
blendPixel: blendPixel2 = defaults3.blendPixel
|
|
2120
|
+
} = deps;
|
|
2121
|
+
return {
|
|
2122
|
+
blendPixel(x, y, color, alpha, blendFn) {
|
|
2123
|
+
const didChange = writer.accumulator.storePixelBeforeState(x, y);
|
|
2124
|
+
return didChange(blendPixel2(writer.config.target, x, y, color, alpha, blendFn));
|
|
2125
|
+
}
|
|
2126
|
+
};
|
|
2127
|
+
});
|
|
2128
|
+
|
|
2129
|
+
// src/PixelData/blendPixelData.ts
|
|
2130
|
+
function blendPixelData(dst, src, opts = {}) {
|
|
2089
2131
|
const {
|
|
2090
2132
|
x: targetX = 0,
|
|
2091
2133
|
y: targetY = 0,
|
|
2092
|
-
|
|
2093
|
-
|
|
2134
|
+
sx: sourceX = 0,
|
|
2135
|
+
sy: sourceY = 0,
|
|
2136
|
+
w: width = src.width,
|
|
2137
|
+
h: height = src.height,
|
|
2094
2138
|
alpha: globalAlpha = 255,
|
|
2095
|
-
|
|
2096
|
-
my = 0,
|
|
2097
|
-
invertMask = false
|
|
2139
|
+
blendFn = sourceOverPerfect
|
|
2098
2140
|
} = opts;
|
|
2099
2141
|
if (globalAlpha === 0) return false;
|
|
2100
2142
|
let x = targetX;
|
|
2101
2143
|
let y = targetY;
|
|
2144
|
+
let sx = sourceX;
|
|
2145
|
+
let sy = sourceY;
|
|
2102
2146
|
let w = width;
|
|
2103
2147
|
let h = height;
|
|
2148
|
+
if (sx < 0) {
|
|
2149
|
+
x -= sx;
|
|
2150
|
+
w += sx;
|
|
2151
|
+
sx = 0;
|
|
2152
|
+
}
|
|
2153
|
+
if (sy < 0) {
|
|
2154
|
+
y -= sy;
|
|
2155
|
+
h += sy;
|
|
2156
|
+
sy = 0;
|
|
2157
|
+
}
|
|
2158
|
+
w = Math.min(w, src.width - sx);
|
|
2159
|
+
h = Math.min(h, src.height - sy);
|
|
2104
2160
|
if (x < 0) {
|
|
2161
|
+
sx -= x;
|
|
2105
2162
|
w += x;
|
|
2106
2163
|
x = 0;
|
|
2107
2164
|
}
|
|
2108
2165
|
if (y < 0) {
|
|
2166
|
+
sy -= y;
|
|
2109
2167
|
h += y;
|
|
2110
2168
|
y = 0;
|
|
2111
2169
|
}
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
if (
|
|
2115
|
-
const mPitch = mask.w;
|
|
2116
|
-
if (mPitch <= 0) return false;
|
|
2117
|
-
const startX = mx + (x - targetX);
|
|
2118
|
-
const startY = my + (y - targetY);
|
|
2119
|
-
const sX0 = Math.max(0, startX);
|
|
2120
|
-
const sY0 = Math.max(0, startY);
|
|
2121
|
-
const sX1 = Math.min(mPitch, startX + w);
|
|
2122
|
-
const sY1 = Math.min(mask.h, startY + h);
|
|
2123
|
-
const finalW = sX1 - sX0;
|
|
2124
|
-
const finalH = sY1 - sY0;
|
|
2125
|
-
if (finalW <= 0 || finalH <= 0) {
|
|
2126
|
-
return false;
|
|
2127
|
-
}
|
|
2128
|
-
const xShift = sX0 - startX;
|
|
2129
|
-
const yShift = sY0 - startY;
|
|
2170
|
+
const actualW = Math.min(w, dst.width - x);
|
|
2171
|
+
const actualH = Math.min(h, dst.height - y);
|
|
2172
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
2130
2173
|
const dst32 = dst.data32;
|
|
2174
|
+
const src32 = src.data32;
|
|
2131
2175
|
const dw = dst.width;
|
|
2132
|
-
const
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2176
|
+
const sw = src.width;
|
|
2177
|
+
let dIdx = y * dw + x | 0;
|
|
2178
|
+
let sIdx = sy * sw + sx | 0;
|
|
2179
|
+
const dStride = dw - actualW | 0;
|
|
2180
|
+
const sStride = sw - actualW | 0;
|
|
2181
|
+
const isOpaque = globalAlpha === 255;
|
|
2182
|
+
const isOverwrite = blendFn.isOverwrite;
|
|
2137
2183
|
let didChange = false;
|
|
2138
|
-
for (let iy = 0; iy <
|
|
2139
|
-
for (let ix = 0; ix <
|
|
2140
|
-
const
|
|
2141
|
-
const
|
|
2142
|
-
if (
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
2155
|
-
if (d !== next) {
|
|
2156
|
-
dst32[dIdx] = next;
|
|
2157
|
-
didChange = true;
|
|
2158
|
-
}
|
|
2184
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2185
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2186
|
+
const srcCol = src32[sIdx];
|
|
2187
|
+
const srcAlpha = srcCol >>> 24;
|
|
2188
|
+
if (srcAlpha === 0 && !isOverwrite) {
|
|
2189
|
+
dIdx++;
|
|
2190
|
+
sIdx++;
|
|
2191
|
+
continue;
|
|
2192
|
+
}
|
|
2193
|
+
let finalCol = srcCol;
|
|
2194
|
+
if (!isOpaque) {
|
|
2195
|
+
const a = srcAlpha * globalAlpha + 128 >> 8;
|
|
2196
|
+
if (a === 0 && !isOverwrite) {
|
|
2197
|
+
dIdx++;
|
|
2198
|
+
sIdx++;
|
|
2199
|
+
continue;
|
|
2159
2200
|
}
|
|
2201
|
+
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
2202
|
+
}
|
|
2203
|
+
const current = dst32[dIdx];
|
|
2204
|
+
const next = blendFn(finalCol, dst32[dIdx]);
|
|
2205
|
+
if (current !== next) {
|
|
2206
|
+
dst32[dIdx] = next;
|
|
2207
|
+
didChange = true;
|
|
2160
2208
|
}
|
|
2161
2209
|
dIdx++;
|
|
2162
|
-
|
|
2210
|
+
sIdx++;
|
|
2163
2211
|
}
|
|
2164
2212
|
dIdx += dStride;
|
|
2165
|
-
|
|
2213
|
+
sIdx += sStride;
|
|
2166
2214
|
}
|
|
2167
2215
|
return didChange;
|
|
2168
2216
|
}
|
|
2169
2217
|
|
|
2170
|
-
// src/History/PixelMutator/
|
|
2171
|
-
var
|
|
2172
|
-
|
|
2218
|
+
// src/History/PixelMutator/mutatorBlendPixelData.ts
|
|
2219
|
+
var defaults4 = {
|
|
2220
|
+
blendPixelData
|
|
2173
2221
|
};
|
|
2174
|
-
var
|
|
2222
|
+
var mutatorBlendPixelData = ((writer, deps = defaults4) => {
|
|
2175
2223
|
const {
|
|
2176
|
-
|
|
2224
|
+
blendPixelData: blendPixelData2 = defaults4.blendPixelData
|
|
2177
2225
|
} = deps;
|
|
2178
2226
|
return {
|
|
2179
|
-
|
|
2180
|
-
let target = writer.config.target;
|
|
2227
|
+
blendPixelData(src, opts = {}) {
|
|
2181
2228
|
const {
|
|
2182
2229
|
x = 0,
|
|
2183
2230
|
y = 0,
|
|
2184
|
-
w =
|
|
2185
|
-
h =
|
|
2231
|
+
w = src.width,
|
|
2232
|
+
h = src.height
|
|
2186
2233
|
} = opts;
|
|
2187
2234
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2188
|
-
return didChange(
|
|
2235
|
+
return didChange(blendPixelData2(writer.config.target, src, opts));
|
|
2189
2236
|
}
|
|
2190
2237
|
};
|
|
2191
2238
|
});
|
|
2192
2239
|
|
|
2193
|
-
// src/PixelData/
|
|
2194
|
-
function
|
|
2195
|
-
const
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2240
|
+
// src/PixelData/blendPixelDataAlphaMask.ts
|
|
2241
|
+
function blendPixelDataAlphaMask(dst, src, alphaMask, opts = {}) {
|
|
2242
|
+
const {
|
|
2243
|
+
x: targetX = 0,
|
|
2244
|
+
y: targetY = 0,
|
|
2245
|
+
sx: sourceX = 0,
|
|
2246
|
+
sy: sourceY = 0,
|
|
2247
|
+
w: width = src.width,
|
|
2248
|
+
h: height = src.height,
|
|
2249
|
+
alpha: globalAlpha = 255,
|
|
2250
|
+
blendFn = sourceOverPerfect,
|
|
2251
|
+
mx = 0,
|
|
2252
|
+
my = 0,
|
|
2253
|
+
invertMask = false
|
|
2254
|
+
} = opts;
|
|
2204
2255
|
if (globalAlpha === 0) return false;
|
|
2205
|
-
const baseSrcAlpha = color >>> 24;
|
|
2206
|
-
const isOverwrite = blendFn.isOverwrite || false;
|
|
2207
|
-
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
2208
2256
|
let x = targetX;
|
|
2209
2257
|
let y = targetY;
|
|
2210
|
-
let
|
|
2211
|
-
let
|
|
2258
|
+
let sx = sourceX;
|
|
2259
|
+
let sy = sourceY;
|
|
2260
|
+
let w = width;
|
|
2261
|
+
let h = height;
|
|
2262
|
+
if (sx < 0) {
|
|
2263
|
+
x -= sx;
|
|
2264
|
+
w += sx;
|
|
2265
|
+
sx = 0;
|
|
2266
|
+
}
|
|
2267
|
+
if (sy < 0) {
|
|
2268
|
+
y -= sy;
|
|
2269
|
+
h += sy;
|
|
2270
|
+
sy = 0;
|
|
2271
|
+
}
|
|
2272
|
+
w = Math.min(w, src.width - sx);
|
|
2273
|
+
h = Math.min(h, src.height - sy);
|
|
2212
2274
|
if (x < 0) {
|
|
2213
|
-
|
|
2275
|
+
sx -= x;
|
|
2276
|
+
w += x;
|
|
2214
2277
|
x = 0;
|
|
2215
2278
|
}
|
|
2216
2279
|
if (y < 0) {
|
|
2217
|
-
|
|
2280
|
+
sy -= y;
|
|
2281
|
+
h += y;
|
|
2218
2282
|
y = 0;
|
|
2219
2283
|
}
|
|
2220
|
-
actualW = Math.min(
|
|
2221
|
-
actualH = Math.min(
|
|
2284
|
+
const actualW = Math.min(w, dst.width - x);
|
|
2285
|
+
const actualH = Math.min(h, dst.height - y);
|
|
2222
2286
|
if (actualW <= 0 || actualH <= 0) return false;
|
|
2287
|
+
const dw = dst.width;
|
|
2288
|
+
const sw = src.width;
|
|
2289
|
+
const mPitch = alphaMask.w;
|
|
2290
|
+
const maskData = alphaMask.data;
|
|
2223
2291
|
const dx = x - targetX | 0;
|
|
2224
2292
|
const dy = y - targetY | 0;
|
|
2225
2293
|
const dst32 = dst.data32;
|
|
2226
|
-
const
|
|
2227
|
-
const mPitch = mask.w;
|
|
2228
|
-
const maskData = mask.data;
|
|
2294
|
+
const src32 = src.data32;
|
|
2229
2295
|
let dIdx = y * dw + x | 0;
|
|
2296
|
+
let sIdx = sy * sw + sx | 0;
|
|
2230
2297
|
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
2231
2298
|
const dStride = dw - actualW | 0;
|
|
2299
|
+
const sStride = sw - actualW | 0;
|
|
2232
2300
|
const mStride = mPitch - actualW | 0;
|
|
2233
2301
|
const isOpaque = globalAlpha === 255;
|
|
2234
|
-
const
|
|
2302
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
2235
2303
|
let didChange = false;
|
|
2236
2304
|
for (let iy = 0; iy < actualH; iy++) {
|
|
2237
2305
|
for (let ix = 0; ix < actualW; ix++) {
|
|
@@ -2239,6 +2307,15 @@ function blendColorPixelDataAlphaMask(dst, color, mask, opts = {}) {
|
|
|
2239
2307
|
const effM = invertMask ? 255 - mVal : mVal;
|
|
2240
2308
|
if (effM === 0) {
|
|
2241
2309
|
dIdx++;
|
|
2310
|
+
sIdx++;
|
|
2311
|
+
mIdx++;
|
|
2312
|
+
continue;
|
|
2313
|
+
}
|
|
2314
|
+
const srcCol = src32[sIdx];
|
|
2315
|
+
const srcAlpha = srcCol >>> 24;
|
|
2316
|
+
if (srcAlpha === 0 && !isOverwrite) {
|
|
2317
|
+
dIdx++;
|
|
2318
|
+
sIdx++;
|
|
2242
2319
|
mIdx++;
|
|
2243
2320
|
continue;
|
|
2244
2321
|
}
|
|
@@ -2250,844 +2327,459 @@ function blendColorPixelDataAlphaMask(dst, color, mask, opts = {}) {
|
|
|
2250
2327
|
}
|
|
2251
2328
|
if (weight === 0) {
|
|
2252
2329
|
dIdx++;
|
|
2330
|
+
sIdx++;
|
|
2253
2331
|
mIdx++;
|
|
2254
2332
|
continue;
|
|
2255
2333
|
}
|
|
2256
|
-
let finalCol =
|
|
2334
|
+
let finalCol = srcCol;
|
|
2257
2335
|
if (weight < 255) {
|
|
2258
|
-
const a =
|
|
2336
|
+
const a = srcAlpha * weight + 128 >> 8;
|
|
2259
2337
|
if (a === 0 && !isOverwrite) {
|
|
2260
2338
|
dIdx++;
|
|
2339
|
+
sIdx++;
|
|
2261
2340
|
mIdx++;
|
|
2262
2341
|
continue;
|
|
2263
2342
|
}
|
|
2264
|
-
finalCol = (
|
|
2343
|
+
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
2265
2344
|
}
|
|
2266
2345
|
const current = dst32[dIdx];
|
|
2267
|
-
const next = blendFn(finalCol,
|
|
2346
|
+
const next = blendFn(finalCol, dst32[dIdx]);
|
|
2268
2347
|
if (current !== next) {
|
|
2269
2348
|
dst32[dIdx] = next;
|
|
2270
2349
|
didChange = true;
|
|
2271
2350
|
}
|
|
2272
2351
|
dIdx++;
|
|
2352
|
+
sIdx++;
|
|
2273
2353
|
mIdx++;
|
|
2274
2354
|
}
|
|
2275
2355
|
dIdx += dStride;
|
|
2356
|
+
sIdx += sStride;
|
|
2276
2357
|
mIdx += mStride;
|
|
2277
2358
|
}
|
|
2278
2359
|
return didChange;
|
|
2279
2360
|
}
|
|
2280
2361
|
|
|
2281
|
-
// src/
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
const minOffset = -Math.ceil(r - 0.5);
|
|
2285
|
-
const maxOffset = Math.floor(r - 0.5);
|
|
2286
|
-
const startX = Math.floor(centerX + minOffset);
|
|
2287
|
-
const startY = Math.floor(centerY + minOffset);
|
|
2288
|
-
const endX = Math.floor(centerX + maxOffset) + 1;
|
|
2289
|
-
const endY = Math.floor(centerY + maxOffset) + 1;
|
|
2290
|
-
const res = out ?? {
|
|
2291
|
-
x: 0,
|
|
2292
|
-
y: 0,
|
|
2293
|
-
w: 0,
|
|
2294
|
-
h: 0
|
|
2295
|
-
};
|
|
2296
|
-
const cStartX = Math.max(0, startX);
|
|
2297
|
-
const cStartY = Math.max(0, startY);
|
|
2298
|
-
const cEndX = Math.min(targetWidth, endX);
|
|
2299
|
-
const cEndY = Math.min(targetHeight, endY);
|
|
2300
|
-
const w = cEndX - cStartX;
|
|
2301
|
-
const h = cEndY - cStartY;
|
|
2302
|
-
res.x = cStartX;
|
|
2303
|
-
res.y = cStartY;
|
|
2304
|
-
res.w = w < 0 ? 0 : w;
|
|
2305
|
-
res.h = h < 0 ? 0 : h;
|
|
2306
|
-
return res;
|
|
2307
|
-
}
|
|
2308
|
-
|
|
2309
|
-
// src/Rect/getCircleBrushOrPencilStrokeBounds.ts
|
|
2310
|
-
function getCircleBrushOrPencilStrokeBounds(x0, y0, x1, y1, brushSize, result) {
|
|
2311
|
-
const r = Math.ceil(brushSize / 2);
|
|
2312
|
-
const minX = Math.min(x0, x1) - r;
|
|
2313
|
-
const minY = Math.min(y0, y1) - r;
|
|
2314
|
-
const maxX = Math.max(x0, x1) + r;
|
|
2315
|
-
const maxY = Math.max(x0, y1) + r;
|
|
2316
|
-
result.x = Math.floor(minX);
|
|
2317
|
-
result.y = Math.floor(minY);
|
|
2318
|
-
result.w = Math.ceil(maxX - minX);
|
|
2319
|
-
result.h = Math.ceil(maxY - minY);
|
|
2320
|
-
return result;
|
|
2321
|
-
}
|
|
2322
|
-
|
|
2323
|
-
// src/History/PixelMutator/mutatorApplyCircleBrushStroke.ts
|
|
2324
|
-
var defaults4 = {
|
|
2325
|
-
forEachLinePoint,
|
|
2326
|
-
blendColorPixelDataAlphaMask,
|
|
2327
|
-
getCircleBrushOrPencilBounds,
|
|
2328
|
-
getCircleBrushOrPencilStrokeBounds
|
|
2362
|
+
// src/History/PixelMutator/mutatorBlendPixelDataAlphaMask.ts
|
|
2363
|
+
var defaults5 = {
|
|
2364
|
+
blendPixelDataAlphaMask
|
|
2329
2365
|
};
|
|
2330
|
-
var
|
|
2366
|
+
var mutatorBlendPixelDataAlphaMask = ((writer, deps = defaults5) => {
|
|
2331
2367
|
const {
|
|
2332
|
-
|
|
2333
|
-
blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults4.blendColorPixelDataAlphaMask,
|
|
2334
|
-
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults4.getCircleBrushOrPencilBounds,
|
|
2335
|
-
getCircleBrushOrPencilStrokeBounds: getCircleBrushOrPencilStrokeBounds2 = defaults4.getCircleBrushOrPencilStrokeBounds
|
|
2368
|
+
blendPixelDataAlphaMask: blendPixelDataAlphaMask2 = defaults5.blendPixelDataAlphaMask
|
|
2336
2369
|
} = deps;
|
|
2337
|
-
const strokeBoundsOut = {
|
|
2338
|
-
x: 0,
|
|
2339
|
-
y: 0,
|
|
2340
|
-
w: 0,
|
|
2341
|
-
h: 0
|
|
2342
|
-
};
|
|
2343
|
-
const circleBrushBounds = {
|
|
2344
|
-
x: 0,
|
|
2345
|
-
y: 0,
|
|
2346
|
-
w: 0,
|
|
2347
|
-
h: 0
|
|
2348
|
-
};
|
|
2349
|
-
const blendColorPixelOptions = {
|
|
2350
|
-
alpha: 255,
|
|
2351
|
-
blendFn: sourceOverPerfect,
|
|
2352
|
-
x: 0,
|
|
2353
|
-
y: 0,
|
|
2354
|
-
w: 0,
|
|
2355
|
-
h: 0
|
|
2356
|
-
};
|
|
2357
|
-
const mask = {
|
|
2358
|
-
type: 0 /* ALPHA */,
|
|
2359
|
-
data: null,
|
|
2360
|
-
w: 0,
|
|
2361
|
-
h: 0
|
|
2362
|
-
};
|
|
2363
2370
|
return {
|
|
2364
|
-
|
|
2365
|
-
const
|
|
2366
|
-
const
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
} = getCircleBrushOrPencilStrokeBounds2(x0, y0, x1, y1, brushSize, strokeBoundsOut);
|
|
2372
|
-
if (bw <= 0 || bh <= 0) return;
|
|
2373
|
-
mask.data = new Uint8Array(bw * bh);
|
|
2374
|
-
mask.w = bw;
|
|
2375
|
-
mask.h = bh;
|
|
2376
|
-
const maskData = mask.data;
|
|
2377
|
-
const brushData = brush.data;
|
|
2378
|
-
const minOffset = brush.minOffset;
|
|
2379
|
-
const target = writer.config.target;
|
|
2380
|
-
const targetWidth = target.width;
|
|
2381
|
-
const targetHeight = target.height;
|
|
2382
|
-
forEachLinePoint2(x0, y0, x1, y1, (px, py) => {
|
|
2383
|
-
const {
|
|
2384
|
-
x: cbx,
|
|
2385
|
-
y: cby,
|
|
2386
|
-
w: cbw,
|
|
2387
|
-
h: cbh
|
|
2388
|
-
} = getCircleBrushOrPencilBounds2(px, py, brushSize, targetWidth, targetHeight, circleBrushBounds);
|
|
2389
|
-
writer.accumulator.storeRegionBeforeState(cbx, cby, cbw, cbh);
|
|
2390
|
-
const startX = Math.max(bx, cbx);
|
|
2391
|
-
const startY = Math.max(by, cby);
|
|
2392
|
-
const endX = Math.min(bx + bw, cbx + cbw);
|
|
2393
|
-
const endY = Math.min(by + bh, cby + cbh);
|
|
2394
|
-
const unclippedStartX = Math.floor(px + minOffset);
|
|
2395
|
-
const unclippedStartY = Math.floor(py + minOffset);
|
|
2396
|
-
for (let my = startY; my < endY; my++) {
|
|
2397
|
-
const strokeMaskY = my - by;
|
|
2398
|
-
const strokeMaskRowOffset = strokeMaskY * bw;
|
|
2399
|
-
const brushY = my - unclippedStartY;
|
|
2400
|
-
const brushRowOffset = brushY * brushSize;
|
|
2401
|
-
for (let mx = startX; mx < endX; mx++) {
|
|
2402
|
-
const brushX = mx - unclippedStartX;
|
|
2403
|
-
const brushVal = brushData[brushRowOffset + brushX];
|
|
2404
|
-
if (brushVal > 0) {
|
|
2405
|
-
const strokeMaskIdx = strokeMaskRowOffset + (mx - bx);
|
|
2406
|
-
if (brushVal > maskData[strokeMaskIdx]) {
|
|
2407
|
-
maskData[strokeMaskIdx] = brushVal;
|
|
2408
|
-
}
|
|
2409
|
-
}
|
|
2410
|
-
}
|
|
2411
|
-
}
|
|
2412
|
-
});
|
|
2413
|
-
blendColorPixelOptions.blendFn = blendFn;
|
|
2414
|
-
blendColorPixelOptions.alpha = alpha;
|
|
2415
|
-
blendColorPixelOptions.x = bx;
|
|
2416
|
-
blendColorPixelOptions.y = by;
|
|
2417
|
-
blendColorPixelOptions.w = bw;
|
|
2418
|
-
blendColorPixelOptions.h = bh;
|
|
2419
|
-
blendColorPixelDataAlphaMask2(target, color, mask, blendColorPixelOptions);
|
|
2371
|
+
blendPixelDataAlphaMask(src, mask, opts = {}) {
|
|
2372
|
+
const x = opts.x ?? 0;
|
|
2373
|
+
const y = opts.y ?? 0;
|
|
2374
|
+
const w = opts.w ?? src.width;
|
|
2375
|
+
const h = opts.h ?? src.height;
|
|
2376
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2377
|
+
return didChange(blendPixelDataAlphaMask2(writer.config.target, src, mask, opts));
|
|
2420
2378
|
}
|
|
2421
2379
|
};
|
|
2422
2380
|
});
|
|
2423
2381
|
|
|
2424
|
-
// src/PixelData/
|
|
2425
|
-
function
|
|
2426
|
-
const
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2382
|
+
// src/PixelData/blendPixelDataBinaryMask.ts
|
|
2383
|
+
function blendPixelDataBinaryMask(dst, src, binaryMask, opts = {}) {
|
|
2384
|
+
const {
|
|
2385
|
+
x: targetX = 0,
|
|
2386
|
+
y: targetY = 0,
|
|
2387
|
+
sx: sourceX = 0,
|
|
2388
|
+
sy: sourceY = 0,
|
|
2389
|
+
w: width = src.width,
|
|
2390
|
+
h: height = src.height,
|
|
2391
|
+
alpha: globalAlpha = 255,
|
|
2392
|
+
blendFn = sourceOverPerfect,
|
|
2393
|
+
mx = 0,
|
|
2394
|
+
my = 0,
|
|
2395
|
+
invertMask = false
|
|
2396
|
+
} = opts;
|
|
2435
2397
|
if (globalAlpha === 0) return false;
|
|
2436
|
-
const baseSrcAlpha = color >>> 24;
|
|
2437
|
-
const isOverwrite = blendFn.isOverwrite || false;
|
|
2438
|
-
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
2439
2398
|
let x = targetX;
|
|
2440
2399
|
let y = targetY;
|
|
2400
|
+
let sx = sourceX;
|
|
2401
|
+
let sy = sourceY;
|
|
2402
|
+
let w = width;
|
|
2403
|
+
let h = height;
|
|
2404
|
+
if (sx < 0) {
|
|
2405
|
+
x -= sx;
|
|
2406
|
+
w += sx;
|
|
2407
|
+
sx = 0;
|
|
2408
|
+
}
|
|
2409
|
+
if (sy < 0) {
|
|
2410
|
+
y -= sy;
|
|
2411
|
+
h += sy;
|
|
2412
|
+
sy = 0;
|
|
2413
|
+
}
|
|
2414
|
+
w = Math.min(w, src.width - sx);
|
|
2415
|
+
h = Math.min(h, src.height - sy);
|
|
2441
2416
|
if (x < 0) {
|
|
2417
|
+
sx -= x;
|
|
2442
2418
|
w += x;
|
|
2443
2419
|
x = 0;
|
|
2444
2420
|
}
|
|
2445
2421
|
if (y < 0) {
|
|
2422
|
+
sy -= y;
|
|
2446
2423
|
h += y;
|
|
2447
2424
|
y = 0;
|
|
2448
2425
|
}
|
|
2449
2426
|
const actualW = Math.min(w, dst.width - x);
|
|
2450
2427
|
const actualH = Math.min(h, dst.height - y);
|
|
2451
2428
|
if (actualW <= 0 || actualH <= 0) return false;
|
|
2452
|
-
let baseColorWithGlobalAlpha = color;
|
|
2453
|
-
if (globalAlpha < 255) {
|
|
2454
|
-
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
2455
|
-
if (a === 0 && !isOverwrite) return false;
|
|
2456
|
-
baseColorWithGlobalAlpha = (color & 16777215 | a << 24) >>> 0;
|
|
2457
|
-
}
|
|
2458
2429
|
const dx = x - targetX | 0;
|
|
2459
2430
|
const dy = y - targetY | 0;
|
|
2460
2431
|
const dst32 = dst.data32;
|
|
2432
|
+
const src32 = src.data32;
|
|
2461
2433
|
const dw = dst.width;
|
|
2462
|
-
const
|
|
2463
|
-
const
|
|
2434
|
+
const sw = src.width;
|
|
2435
|
+
const mPitch = binaryMask.w;
|
|
2436
|
+
const maskData = binaryMask.data;
|
|
2464
2437
|
let dIdx = y * dw + x | 0;
|
|
2438
|
+
let sIdx = sy * sw + sx | 0;
|
|
2465
2439
|
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
2466
2440
|
const dStride = dw - actualW | 0;
|
|
2441
|
+
const sStride = sw - actualW | 0;
|
|
2467
2442
|
const mStride = mPitch - actualW | 0;
|
|
2468
2443
|
const skipVal = invertMask ? 1 : 0;
|
|
2444
|
+
const isOpaque = globalAlpha === 255;
|
|
2445
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
2469
2446
|
let didChange = false;
|
|
2470
2447
|
for (let iy = 0; iy < actualH; iy++) {
|
|
2471
2448
|
for (let ix = 0; ix < actualW; ix++) {
|
|
2472
2449
|
if (maskData[mIdx] === skipVal) {
|
|
2473
2450
|
dIdx++;
|
|
2451
|
+
sIdx++;
|
|
2452
|
+
mIdx++;
|
|
2453
|
+
continue;
|
|
2454
|
+
}
|
|
2455
|
+
const srcCol = src32[sIdx];
|
|
2456
|
+
const srcAlpha = srcCol >>> 24;
|
|
2457
|
+
if (srcAlpha === 0 && !isOverwrite) {
|
|
2458
|
+
dIdx++;
|
|
2459
|
+
sIdx++;
|
|
2474
2460
|
mIdx++;
|
|
2475
2461
|
continue;
|
|
2476
2462
|
}
|
|
2463
|
+
let finalCol = srcCol;
|
|
2464
|
+
if (!isOpaque) {
|
|
2465
|
+
const a = srcAlpha * globalAlpha + 128 >> 8;
|
|
2466
|
+
if (a === 0 && !isOverwrite) {
|
|
2467
|
+
dIdx++;
|
|
2468
|
+
sIdx++;
|
|
2469
|
+
mIdx++;
|
|
2470
|
+
continue;
|
|
2471
|
+
}
|
|
2472
|
+
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
2473
|
+
}
|
|
2477
2474
|
const current = dst32[dIdx];
|
|
2478
|
-
const next = blendFn(
|
|
2475
|
+
const next = blendFn(finalCol, dst32[dIdx]);
|
|
2479
2476
|
if (current !== next) {
|
|
2480
2477
|
dst32[dIdx] = next;
|
|
2481
2478
|
didChange = true;
|
|
2482
2479
|
}
|
|
2483
2480
|
dIdx++;
|
|
2481
|
+
sIdx++;
|
|
2484
2482
|
mIdx++;
|
|
2485
2483
|
}
|
|
2486
2484
|
dIdx += dStride;
|
|
2485
|
+
sIdx += sStride;
|
|
2487
2486
|
mIdx += mStride;
|
|
2488
2487
|
}
|
|
2489
2488
|
return didChange;
|
|
2490
2489
|
}
|
|
2491
2490
|
|
|
2492
|
-
// src/
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
if (b.w <= 0 || b.h <= 0) return false;
|
|
2496
|
-
const unclippedStartX = Math.floor(centerX + brush.minOffset);
|
|
2497
|
-
const unclippedStartY = Math.floor(centerY + brush.minOffset);
|
|
2498
|
-
const ix = Math.max(unclippedStartX, b.x);
|
|
2499
|
-
const iy = Math.max(unclippedStartY, b.y);
|
|
2500
|
-
const ir = Math.min(unclippedStartX + brush.w, b.x + b.w);
|
|
2501
|
-
const ib = Math.min(unclippedStartY + brush.h, b.y + b.h);
|
|
2502
|
-
const iw = ir - ix;
|
|
2503
|
-
const ih = ib - iy;
|
|
2504
|
-
if (iw <= 0 || ih <= 0) return false;
|
|
2505
|
-
scratchOptions.x = ix;
|
|
2506
|
-
scratchOptions.y = iy;
|
|
2507
|
-
scratchOptions.w = iw;
|
|
2508
|
-
scratchOptions.h = ih;
|
|
2509
|
-
scratchOptions.mx = ix - unclippedStartX;
|
|
2510
|
-
scratchOptions.my = iy - unclippedStartY;
|
|
2511
|
-
scratchOptions.alpha = alpha;
|
|
2512
|
-
scratchOptions.blendFn = blendFn;
|
|
2513
|
-
if (brush.type === 0 /* ALPHA */) {
|
|
2514
|
-
return blendColorPixelDataAlphaMask(target, color, brush, scratchOptions);
|
|
2515
|
-
}
|
|
2516
|
-
if (brush.type === 1 /* BINARY */) {
|
|
2517
|
-
return blendColorPixelDataBinaryMask(target, color, brush, scratchOptions);
|
|
2518
|
-
}
|
|
2519
|
-
return false;
|
|
2520
|
-
}
|
|
2521
|
-
|
|
2522
|
-
// src/History/PixelMutator/mutatorBlendColorCircleMask.ts
|
|
2523
|
-
var defaults5 = {
|
|
2524
|
-
blendColorPixelDataCircleMask,
|
|
2525
|
-
getCircleBrushOrPencilBounds
|
|
2491
|
+
// src/History/PixelMutator/mutatorBlendPixelDataBinaryMask.ts
|
|
2492
|
+
var defaults6 = {
|
|
2493
|
+
blendPixelDataBinaryMask
|
|
2526
2494
|
};
|
|
2527
|
-
var
|
|
2495
|
+
var mutatorBlendPixelDataBinaryMask = ((writer, deps = defaults6) => {
|
|
2528
2496
|
const {
|
|
2529
|
-
|
|
2530
|
-
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults5.getCircleBrushOrPencilBounds
|
|
2497
|
+
blendPixelDataBinaryMask: blendPixelDataBinaryMask2 = defaults6.blendPixelDataBinaryMask
|
|
2531
2498
|
} = deps;
|
|
2532
|
-
const boundsOut = {
|
|
2533
|
-
x: 0,
|
|
2534
|
-
y: 0,
|
|
2535
|
-
w: 0,
|
|
2536
|
-
h: 0
|
|
2537
|
-
};
|
|
2538
|
-
const blendColorPixelOptions = {
|
|
2539
|
-
alpha: 255,
|
|
2540
|
-
blendFn: sourceOverPerfect,
|
|
2541
|
-
x: 0,
|
|
2542
|
-
y: 0,
|
|
2543
|
-
w: 0,
|
|
2544
|
-
h: 0
|
|
2545
|
-
};
|
|
2546
2499
|
return {
|
|
2547
|
-
|
|
2548
|
-
const
|
|
2549
|
-
const
|
|
2550
|
-
const
|
|
2551
|
-
|
|
2500
|
+
blendPixelDataBinaryMask(src, mask, opts = {}) {
|
|
2501
|
+
const x = opts.x ?? 0;
|
|
2502
|
+
const y = opts.y ?? 0;
|
|
2503
|
+
const w = opts.w ?? src.width;
|
|
2504
|
+
const h = opts.h ?? src.height;
|
|
2505
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2506
|
+
return didChange(blendPixelDataBinaryMask2(writer.config.target, src, mask, opts));
|
|
2552
2507
|
}
|
|
2553
2508
|
};
|
|
2554
2509
|
});
|
|
2555
2510
|
|
|
2556
|
-
// src/
|
|
2557
|
-
var
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2511
|
+
// src/PixelData/fillPixelDataFast.ts
|
|
2512
|
+
var SCRATCH_RECT = makeClippedRect();
|
|
2513
|
+
function fillPixelDataFast(dst, color, _x, _y, _w, _h) {
|
|
2514
|
+
let x;
|
|
2515
|
+
let y;
|
|
2516
|
+
let w;
|
|
2517
|
+
let h;
|
|
2518
|
+
if (typeof _x === "object") {
|
|
2519
|
+
x = _x.x ?? 0;
|
|
2520
|
+
y = _x.y ?? 0;
|
|
2521
|
+
w = _x.w ?? dst.width;
|
|
2522
|
+
h = _x.h ?? dst.height;
|
|
2523
|
+
} else if (typeof _x === "number") {
|
|
2524
|
+
x = _x;
|
|
2525
|
+
y = _y;
|
|
2526
|
+
w = _w;
|
|
2527
|
+
h = _h;
|
|
2528
|
+
} else {
|
|
2529
|
+
x = 0;
|
|
2530
|
+
y = 0;
|
|
2531
|
+
w = dst.width;
|
|
2532
|
+
h = dst.height;
|
|
2533
|
+
}
|
|
2534
|
+
const clip = resolveRectClipping(x, y, w, h, dst.width, dst.height, SCRATCH_RECT);
|
|
2535
|
+
if (!clip.inBounds) return;
|
|
2562
2536
|
const {
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
});
|
|
2537
|
+
x: finalX,
|
|
2538
|
+
y: finalY,
|
|
2539
|
+
w: actualW,
|
|
2540
|
+
h: actualH
|
|
2541
|
+
} = clip;
|
|
2542
|
+
const dst32 = dst.data32;
|
|
2543
|
+
const dw = dst.width;
|
|
2544
|
+
if (actualW === dw && actualH === dst.height && finalX === 0 && finalY === 0) {
|
|
2545
|
+
dst32.fill(color);
|
|
2546
|
+
return;
|
|
2547
|
+
}
|
|
2548
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2549
|
+
const start = (finalY + iy) * dw + finalX;
|
|
2550
|
+
const end = start + actualW;
|
|
2551
|
+
dst32.fill(color, start, end);
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2581
2554
|
|
|
2582
|
-
// src/History/PixelMutator/
|
|
2555
|
+
// src/History/PixelMutator/mutatorClear.ts
|
|
2583
2556
|
var defaults7 = {
|
|
2584
|
-
|
|
2585
|
-
blendColorPixelDataBinaryMask,
|
|
2586
|
-
getCircleBrushOrPencilBounds,
|
|
2587
|
-
getCircleBrushOrPencilStrokeBounds
|
|
2557
|
+
fillPixelData: fillPixelDataFast
|
|
2588
2558
|
};
|
|
2589
|
-
var
|
|
2559
|
+
var mutatorClear = ((writer, deps = defaults7) => {
|
|
2590
2560
|
const {
|
|
2591
|
-
|
|
2592
|
-
blendColorPixelDataBinaryMask: blendColorPixelDataBinaryMask2 = defaults7.blendColorPixelDataBinaryMask,
|
|
2593
|
-
getCircleBrushOrPencilStrokeBounds: getCircleBrushOrPencilStrokeBounds2 = defaults7.getCircleBrushOrPencilStrokeBounds,
|
|
2594
|
-
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults7.getCircleBrushOrPencilBounds
|
|
2561
|
+
fillPixelData: fillPixelData2 = defaults7.fillPixelData
|
|
2595
2562
|
} = deps;
|
|
2596
|
-
const strokeBoundsOut = {
|
|
2597
|
-
x: 0,
|
|
2598
|
-
y: 0,
|
|
2599
|
-
w: 0,
|
|
2600
|
-
h: 0
|
|
2601
|
-
};
|
|
2602
|
-
const circlePencilBounds = {
|
|
2603
|
-
x: 0,
|
|
2604
|
-
y: 0,
|
|
2605
|
-
w: 0,
|
|
2606
|
-
h: 0
|
|
2607
|
-
};
|
|
2608
|
-
const blendColorPixelOptions = {
|
|
2609
|
-
alpha: 255,
|
|
2610
|
-
blendFn: sourceOverPerfect,
|
|
2611
|
-
x: 0,
|
|
2612
|
-
y: 0,
|
|
2613
|
-
w: 0,
|
|
2614
|
-
h: 0
|
|
2615
|
-
};
|
|
2616
|
-
const mask = {
|
|
2617
|
-
type: 1 /* BINARY */,
|
|
2618
|
-
data: null,
|
|
2619
|
-
w: 0,
|
|
2620
|
-
h: 0
|
|
2621
|
-
};
|
|
2622
2563
|
return {
|
|
2623
|
-
|
|
2624
|
-
const {
|
|
2625
|
-
x: bx,
|
|
2626
|
-
y: by,
|
|
2627
|
-
w: bw,
|
|
2628
|
-
h: bh
|
|
2629
|
-
} = getCircleBrushOrPencilStrokeBounds2(x0, y0, x1, y1, brush.size, strokeBoundsOut);
|
|
2630
|
-
if (bw <= 0 || bh <= 0) return;
|
|
2631
|
-
mask.data = new Uint8Array(bw * bh);
|
|
2632
|
-
mask.w = bw;
|
|
2633
|
-
mask.h = bh;
|
|
2634
|
-
const maskData = mask.data;
|
|
2564
|
+
clear(rect = {}) {
|
|
2635
2565
|
const target = writer.config.target;
|
|
2636
|
-
const
|
|
2637
|
-
const
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
w: cbw,
|
|
2643
|
-
h: cbh
|
|
2644
|
-
} = getCircleBrushOrPencilBounds2(px, py, brush.size, targetWidth, targetHeight, circlePencilBounds);
|
|
2645
|
-
writer.accumulator.storeRegionBeforeState(cbx, cby, cbw, cbh);
|
|
2646
|
-
const unclippedStartX = Math.floor(px + brush.minOffset);
|
|
2647
|
-
const unclippedStartY = Math.floor(py + brush.minOffset);
|
|
2648
|
-
const startX = Math.max(bx, unclippedStartX);
|
|
2649
|
-
const startY = Math.max(by, unclippedStartY);
|
|
2650
|
-
const endX = Math.min(bx + bw, unclippedStartX + brush.w);
|
|
2651
|
-
const endY = Math.min(by + bh, unclippedStartY + brush.h);
|
|
2652
|
-
for (let my = startY; my < endY; my++) {
|
|
2653
|
-
const brushY = my - unclippedStartY;
|
|
2654
|
-
const maskRowOffset = (my - by) * bw;
|
|
2655
|
-
const brushRowOffset = brushY * brush.w;
|
|
2656
|
-
for (let mx = startX; mx < endX; mx++) {
|
|
2657
|
-
const brushX = mx - unclippedStartX;
|
|
2658
|
-
const brushAlpha = brush.data[brushRowOffset + brushX];
|
|
2659
|
-
if (brushAlpha > 0) {
|
|
2660
|
-
const maskIdx = maskRowOffset + (mx - bx);
|
|
2661
|
-
maskData[maskIdx] = brushAlpha;
|
|
2662
|
-
}
|
|
2663
|
-
}
|
|
2664
|
-
}
|
|
2665
|
-
});
|
|
2666
|
-
blendColorPixelOptions.blendFn = blendFn;
|
|
2667
|
-
blendColorPixelOptions.alpha = alpha;
|
|
2668
|
-
blendColorPixelOptions.x = bx;
|
|
2669
|
-
blendColorPixelOptions.y = by;
|
|
2670
|
-
blendColorPixelOptions.w = bw;
|
|
2671
|
-
blendColorPixelOptions.h = bh;
|
|
2672
|
-
blendColorPixelDataBinaryMask2(target, color, mask, blendColorPixelOptions);
|
|
2566
|
+
const x = rect.x ?? 0;
|
|
2567
|
+
const y = rect.y ?? 0;
|
|
2568
|
+
const w = rect.w ?? target.width;
|
|
2569
|
+
const h = rect.h ?? target.height;
|
|
2570
|
+
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2571
|
+
fillPixelData2(target, 0, x, y, w, h);
|
|
2673
2572
|
}
|
|
2674
2573
|
};
|
|
2675
2574
|
});
|
|
2676
2575
|
|
|
2677
|
-
// src/
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
return res;
|
|
2700
|
-
}
|
|
2701
|
-
|
|
2702
|
-
// src/PixelData/applyRectBrushToPixelData.ts
|
|
2703
|
-
function applyRectBrushToPixelData(target, color, centerX, centerY, brushWidth, brushHeight, alpha = 255, fallOff, blendFn = sourceOverPerfect, bounds) {
|
|
2704
|
-
const targetWidth = target.width;
|
|
2705
|
-
const targetHeight = target.height;
|
|
2706
|
-
const b = bounds ?? getRectBrushOrPencilBounds(centerX, centerY, brushWidth, brushHeight, targetWidth, targetHeight);
|
|
2707
|
-
if (b.w <= 0 || b.h <= 0) {
|
|
2708
|
-
return false;
|
|
2576
|
+
// src/PixelData/fillPixelData.ts
|
|
2577
|
+
var SCRATCH_RECT2 = makeClippedRect();
|
|
2578
|
+
function fillPixelData(dst, color, _x, _y, _w, _h) {
|
|
2579
|
+
let x;
|
|
2580
|
+
let y;
|
|
2581
|
+
let w;
|
|
2582
|
+
let h;
|
|
2583
|
+
if (typeof _x === "object") {
|
|
2584
|
+
x = _x.x ?? 0;
|
|
2585
|
+
y = _x.y ?? 0;
|
|
2586
|
+
w = _x.w ?? dst.width;
|
|
2587
|
+
h = _x.h ?? dst.height;
|
|
2588
|
+
} else if (typeof _x === "number") {
|
|
2589
|
+
x = _x;
|
|
2590
|
+
y = _y;
|
|
2591
|
+
w = _w;
|
|
2592
|
+
h = _h;
|
|
2593
|
+
} else {
|
|
2594
|
+
x = 0;
|
|
2595
|
+
y = 0;
|
|
2596
|
+
w = dst.width;
|
|
2597
|
+
h = dst.height;
|
|
2709
2598
|
}
|
|
2710
|
-
const
|
|
2711
|
-
|
|
2712
|
-
const
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
const
|
|
2719
|
-
const
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
const dx = Math.abs(px - fCenterX + centerOffsetX) * invHalfW;
|
|
2730
|
-
const dist = dx > dy ? dx : dy;
|
|
2731
|
-
const strength = fallOff(dist);
|
|
2732
|
-
const maskVal = strength * 255 | 0;
|
|
2733
|
-
if (maskVal <= 0) continue;
|
|
2734
|
-
let weight = alpha;
|
|
2735
|
-
if (isOpaque) {
|
|
2736
|
-
weight = maskVal;
|
|
2737
|
-
} else if (maskVal !== 255) {
|
|
2738
|
-
weight = maskVal * alpha + 128 >> 8;
|
|
2739
|
-
}
|
|
2740
|
-
let finalCol = color;
|
|
2741
|
-
if (weight < 255) {
|
|
2742
|
-
const a = baseSrcAlpha * weight + 128 >> 8;
|
|
2743
|
-
if (a === 0 && !isOverwrite) continue;
|
|
2744
|
-
finalCol = (a << 24 | baseColor) >>> 0;
|
|
2745
|
-
}
|
|
2746
|
-
const current = data32[idx];
|
|
2747
|
-
const next = blendFn(finalCol, current);
|
|
2748
|
-
if (current !== next) {
|
|
2749
|
-
data32[idx] = next;
|
|
2750
|
-
didChange = true;
|
|
2599
|
+
const clip = resolveRectClipping(x, y, w, h, dst.width, dst.height, SCRATCH_RECT2);
|
|
2600
|
+
if (!clip.inBounds) return false;
|
|
2601
|
+
const {
|
|
2602
|
+
x: finalX,
|
|
2603
|
+
y: finalY,
|
|
2604
|
+
w: actualW,
|
|
2605
|
+
h: actualH
|
|
2606
|
+
} = clip;
|
|
2607
|
+
const dst32 = dst.data32;
|
|
2608
|
+
const dw = dst.width;
|
|
2609
|
+
let hasChanged = false;
|
|
2610
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2611
|
+
const rowOffset = (finalY + iy) * dw;
|
|
2612
|
+
const start = rowOffset + finalX;
|
|
2613
|
+
const end = start + actualW;
|
|
2614
|
+
for (let i = start; i < end; i++) {
|
|
2615
|
+
if (dst32[i] !== color) {
|
|
2616
|
+
dst32[i] = color;
|
|
2617
|
+
hasChanged = true;
|
|
2751
2618
|
}
|
|
2752
2619
|
}
|
|
2753
2620
|
}
|
|
2754
|
-
return
|
|
2621
|
+
return hasChanged;
|
|
2755
2622
|
}
|
|
2756
2623
|
|
|
2757
|
-
// src/History/PixelMutator/
|
|
2624
|
+
// src/History/PixelMutator/mutatorFill.ts
|
|
2758
2625
|
var defaults8 = {
|
|
2759
|
-
|
|
2760
|
-
getRectBrushOrPencilBounds
|
|
2626
|
+
fillPixelData
|
|
2761
2627
|
};
|
|
2762
|
-
var
|
|
2628
|
+
var mutatorFill = ((writer, deps = defaults8) => {
|
|
2763
2629
|
const {
|
|
2764
|
-
|
|
2765
|
-
getRectBrushOrPencilBounds: getRectBrushOrPencilBounds2 = defaults8.getRectBrushOrPencilBounds
|
|
2630
|
+
fillPixelData: fillPixelData2 = defaults8.fillPixelData
|
|
2766
2631
|
} = deps;
|
|
2767
|
-
const boundsOut = {
|
|
2768
|
-
x: 0,
|
|
2769
|
-
y: 0,
|
|
2770
|
-
w: 0,
|
|
2771
|
-
h: 0
|
|
2772
|
-
};
|
|
2773
2632
|
return {
|
|
2774
|
-
|
|
2633
|
+
fill(color, x = 0, y = 0, w = writer.config.target.width, h = writer.config.target.height) {
|
|
2775
2634
|
const target = writer.config.target;
|
|
2776
|
-
const
|
|
2777
|
-
|
|
2778
|
-
return didChange(applyRectBrushToPixelData2(target, color, centerX, centerY, brushWidth, brushHeight, alpha, fallOff, blendFn, b));
|
|
2635
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2636
|
+
return didChange(fillPixelData2(target, color, x, y, w, h));
|
|
2779
2637
|
}
|
|
2780
2638
|
};
|
|
2781
2639
|
});
|
|
2782
|
-
|
|
2783
|
-
// src/Rect/getRectBrushOrPencilStrokeBounds.ts
|
|
2784
|
-
function getRectBrushOrPencilStrokeBounds(x0, y0, x1, y1, brushWidth, brushHeight, result) {
|
|
2785
|
-
const halfW = brushWidth / 2;
|
|
2786
|
-
const halfH = brushHeight / 2;
|
|
2787
|
-
const minX = Math.min(x0, x1) - halfW;
|
|
2788
|
-
const minY = Math.min(y0, y1) - halfH;
|
|
2789
|
-
const maxX = Math.max(x0, x1) + halfW;
|
|
2790
|
-
const maxY = Math.max(y0, y1) + halfH;
|
|
2791
|
-
result.x = Math.floor(minX);
|
|
2792
|
-
result.y = Math.floor(minY);
|
|
2793
|
-
result.w = Math.ceil(maxX - minX);
|
|
2794
|
-
result.h = Math.ceil(maxY - minY);
|
|
2795
|
-
return result;
|
|
2796
|
-
}
|
|
2797
|
-
|
|
2798
|
-
// src/History/PixelMutator/mutatorApplyRectBrushStroke.ts
|
|
2799
|
-
var defaults9 = {
|
|
2800
|
-
forEachLinePoint,
|
|
2801
|
-
blendColorPixelDataAlphaMask,
|
|
2802
|
-
getRectBrushOrPencilBounds,
|
|
2803
|
-
getRectBrushOrPencilStrokeBounds
|
|
2804
|
-
};
|
|
2805
|
-
var mutatorApplyRectBrushStroke = ((writer, deps = defaults9) => {
|
|
2640
|
+
var mutatorFillRect = ((writer, deps = defaults8) => {
|
|
2806
2641
|
const {
|
|
2807
|
-
|
|
2808
|
-
blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults9.blendColorPixelDataAlphaMask,
|
|
2809
|
-
getRectBrushOrPencilBounds: getRectBrushOrPencilBounds2 = defaults9.getRectBrushOrPencilBounds,
|
|
2810
|
-
getRectBrushOrPencilStrokeBounds: getRectBrushOrPencilStrokeBounds2 = defaults9.getRectBrushOrPencilStrokeBounds
|
|
2642
|
+
fillPixelData: fillPixelData2 = defaults8.fillPixelData
|
|
2811
2643
|
} = deps;
|
|
2812
|
-
const strokeBoundsOut = {
|
|
2813
|
-
x: 0,
|
|
2814
|
-
y: 0,
|
|
2815
|
-
w: 0,
|
|
2816
|
-
h: 0
|
|
2817
|
-
};
|
|
2818
|
-
const rectBrushBounds = {
|
|
2819
|
-
x: 0,
|
|
2820
|
-
y: 0,
|
|
2821
|
-
w: 0,
|
|
2822
|
-
h: 0
|
|
2823
|
-
};
|
|
2824
|
-
const blendColorPixelOptions = {
|
|
2825
|
-
alpha: 255,
|
|
2826
|
-
blendFn: sourceOverPerfect,
|
|
2827
|
-
x: 0,
|
|
2828
|
-
y: 0,
|
|
2829
|
-
w: 0,
|
|
2830
|
-
h: 0
|
|
2831
|
-
};
|
|
2832
|
-
const mask = {
|
|
2833
|
-
type: 0 /* ALPHA */,
|
|
2834
|
-
data: null,
|
|
2835
|
-
w: 0,
|
|
2836
|
-
h: 0
|
|
2837
|
-
};
|
|
2838
2644
|
return {
|
|
2839
|
-
|
|
2840
|
-
const {
|
|
2841
|
-
x: bx,
|
|
2842
|
-
y: by,
|
|
2843
|
-
w: bw,
|
|
2844
|
-
h: bh
|
|
2845
|
-
} = getRectBrushOrPencilStrokeBounds2(x0, y0, x1, y1, brushWidth, brushHeight, strokeBoundsOut);
|
|
2846
|
-
if (bw <= 0 || bh <= 0) return;
|
|
2847
|
-
mask.data = new Uint8Array(bw * bh);
|
|
2848
|
-
mask.w = bw;
|
|
2849
|
-
mask.h = bh;
|
|
2850
|
-
const maskData = mask.data;
|
|
2851
|
-
const halfW = brushWidth / 2;
|
|
2852
|
-
const halfH = brushHeight / 2;
|
|
2853
|
-
const invHalfW = 1 / halfW;
|
|
2854
|
-
const invHalfH = 1 / halfH;
|
|
2855
|
-
const centerOffsetX = brushWidth % 2 === 0 ? 0.5 : 0;
|
|
2856
|
-
const centerOffsetY = brushHeight % 2 === 0 ? 0.5 : 0;
|
|
2645
|
+
fillRect(color, rect) {
|
|
2857
2646
|
const target = writer.config.target;
|
|
2858
|
-
const
|
|
2859
|
-
|
|
2860
|
-
forEachLinePoint2(x0, y0, x1, y1, (px, py) => {
|
|
2861
|
-
const {
|
|
2862
|
-
x: rbx,
|
|
2863
|
-
y: rby,
|
|
2864
|
-
w: rbw,
|
|
2865
|
-
h: rbh
|
|
2866
|
-
} = getRectBrushOrPencilBounds2(px, py, brushWidth, brushHeight, targetWidth, targetHeight, rectBrushBounds);
|
|
2867
|
-
writer.accumulator.storeRegionBeforeState(rbx, rby, rbw, rbh);
|
|
2868
|
-
const startX = Math.max(bx, rbx);
|
|
2869
|
-
const startY = Math.max(by, rby);
|
|
2870
|
-
const endX = Math.min(bx + bw, rbx + rbw);
|
|
2871
|
-
const endY = Math.min(by + bh, rby + rbh);
|
|
2872
|
-
const fPx = Math.floor(px);
|
|
2873
|
-
const fPy = Math.floor(py);
|
|
2874
|
-
for (let my = startY; my < endY; my++) {
|
|
2875
|
-
const dy = Math.abs(my - fPy + centerOffsetY) * invHalfH;
|
|
2876
|
-
const maskRowOffset = (my - by) * bw;
|
|
2877
|
-
for (let mx = startX; mx < endX; mx++) {
|
|
2878
|
-
const dx = Math.abs(mx - fPx + centerOffsetX) * invHalfW;
|
|
2879
|
-
const maskIdx = maskRowOffset + (mx - bx);
|
|
2880
|
-
const dist = dx > dy ? dx : dy;
|
|
2881
|
-
const strength = fallOff(dist);
|
|
2882
|
-
if (strength > 0) {
|
|
2883
|
-
const intensity = strength * 255 | 0;
|
|
2884
|
-
if (intensity > maskData[maskIdx]) {
|
|
2885
|
-
maskData[maskIdx] = intensity;
|
|
2886
|
-
}
|
|
2887
|
-
}
|
|
2888
|
-
}
|
|
2889
|
-
}
|
|
2890
|
-
});
|
|
2891
|
-
blendColorPixelOptions.blendFn = blendFn;
|
|
2892
|
-
blendColorPixelOptions.alpha = alpha;
|
|
2893
|
-
blendColorPixelOptions.x = bx;
|
|
2894
|
-
blendColorPixelOptions.y = by;
|
|
2895
|
-
blendColorPixelOptions.w = bw;
|
|
2896
|
-
blendColorPixelOptions.h = bh;
|
|
2897
|
-
blendColorPixelDataAlphaMask2(target, color, mask, blendColorPixelOptions);
|
|
2647
|
+
const didChange = writer.accumulator.storeRegionBeforeState(rect.x, rect.y, rect.w, rect.h);
|
|
2648
|
+
return didChange(fillPixelData2(target, color, rect.x, rect.y, rect.w, rect.h));
|
|
2898
2649
|
}
|
|
2899
2650
|
};
|
|
2900
2651
|
});
|
|
2901
2652
|
|
|
2902
|
-
// src/
|
|
2903
|
-
var
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2653
|
+
// src/PixelData/fillPixelDataBinaryMask.ts
|
|
2654
|
+
var SCRATCH_RECT3 = makeClippedRect();
|
|
2655
|
+
function fillPixelDataBinaryMask(dst, color, mask, alpha = 255, x = 0, y = 0) {
|
|
2656
|
+
if (alpha === 0) return false;
|
|
2657
|
+
const maskW = mask.w;
|
|
2658
|
+
const maskH = mask.h;
|
|
2659
|
+
const clip = resolveRectClipping(x, y, maskW, maskH, dst.width, dst.height, SCRATCH_RECT3);
|
|
2660
|
+
if (!clip.inBounds) return false;
|
|
2909
2661
|
const {
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2662
|
+
x: finalX,
|
|
2663
|
+
y: finalY,
|
|
2664
|
+
w: actualW,
|
|
2665
|
+
h: actualH
|
|
2666
|
+
} = clip;
|
|
2667
|
+
const maskData = mask.data;
|
|
2668
|
+
const dst32 = dst.data32;
|
|
2669
|
+
const dw = dst.width;
|
|
2670
|
+
let finalCol = color;
|
|
2671
|
+
if (alpha < 255) {
|
|
2672
|
+
const baseSrcAlpha = color >>> 24;
|
|
2673
|
+
const colorRGB = color & 16777215;
|
|
2674
|
+
const a = baseSrcAlpha * alpha + 128 >> 8;
|
|
2675
|
+
finalCol = (colorRGB | a << 24) >>> 0;
|
|
2676
|
+
}
|
|
2677
|
+
let hasChanged = false;
|
|
2678
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2679
|
+
const currentY = finalY + iy;
|
|
2680
|
+
const maskY = currentY - y;
|
|
2681
|
+
const maskOffset = maskY * maskW;
|
|
2682
|
+
const dstRowOffset = currentY * dw;
|
|
2683
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2684
|
+
const currentX = finalX + ix;
|
|
2685
|
+
const maskX = currentX - x;
|
|
2686
|
+
const maskIndex = maskOffset + maskX;
|
|
2687
|
+
if (maskData[maskIndex]) {
|
|
2688
|
+
const current = dst32[dstRowOffset + currentX];
|
|
2689
|
+
if (current !== finalCol) {
|
|
2690
|
+
dst32[dstRowOffset + currentX] = finalCol;
|
|
2691
|
+
hasChanged = true;
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
}
|
|
2695
|
+
}
|
|
2696
|
+
return hasChanged;
|
|
2697
|
+
}
|
|
2698
|
+
|
|
2699
|
+
// src/History/PixelMutator/mutatorFillBinaryMask.ts
|
|
2700
|
+
var defaults9 = {
|
|
2701
|
+
fillPixelDataBinaryMask
|
|
2936
2702
|
};
|
|
2937
|
-
var
|
|
2703
|
+
var mutatorFillBinaryMask = ((writer, deps = defaults9) => {
|
|
2938
2704
|
const {
|
|
2939
|
-
|
|
2940
|
-
blendColorPixelDataBinaryMask: blendColorPixelDataBinaryMask2 = defaults11.blendColorPixelDataBinaryMask,
|
|
2941
|
-
getRectBrushOrPencilBounds: getRectBrushOrPencilBounds2 = defaults11.getRectBrushOrPencilBounds,
|
|
2942
|
-
getRectBrushOrPencilStrokeBounds: getRectBrushOrPencilStrokeBounds2 = defaults11.getRectBrushOrPencilStrokeBounds
|
|
2705
|
+
fillPixelDataBinaryMask: fillPixelDataBinaryMask2 = defaults9.fillPixelDataBinaryMask
|
|
2943
2706
|
} = deps;
|
|
2944
|
-
const strokeBoundsOut = {
|
|
2945
|
-
x: 0,
|
|
2946
|
-
y: 0,
|
|
2947
|
-
w: 0,
|
|
2948
|
-
h: 0
|
|
2949
|
-
};
|
|
2950
|
-
const rectPencilBounds = {
|
|
2951
|
-
x: 0,
|
|
2952
|
-
y: 0,
|
|
2953
|
-
w: 0,
|
|
2954
|
-
h: 0
|
|
2955
|
-
};
|
|
2956
|
-
const blendColorPixelOptions = {
|
|
2957
|
-
alpha: 255,
|
|
2958
|
-
blendFn: sourceOverPerfect,
|
|
2959
|
-
x: 0,
|
|
2960
|
-
y: 0,
|
|
2961
|
-
w: 0,
|
|
2962
|
-
h: 0
|
|
2963
|
-
};
|
|
2964
|
-
const mask = {
|
|
2965
|
-
type: 1 /* BINARY */,
|
|
2966
|
-
data: null,
|
|
2967
|
-
w: 0,
|
|
2968
|
-
h: 0
|
|
2969
|
-
};
|
|
2970
2707
|
return {
|
|
2971
|
-
|
|
2972
|
-
const
|
|
2973
|
-
|
|
2974
|
-
y: by,
|
|
2975
|
-
w: bw,
|
|
2976
|
-
h: bh
|
|
2977
|
-
} = getRectBrushOrPencilStrokeBounds2(x0, y0, x1, y1, brushWidth, brushHeight, strokeBoundsOut);
|
|
2978
|
-
if (bw <= 0 || bh <= 0) return;
|
|
2979
|
-
mask.data = new Uint8Array(bw * bh);
|
|
2980
|
-
mask.w = bw;
|
|
2981
|
-
mask.h = bh;
|
|
2982
|
-
const maskData = mask.data;
|
|
2983
|
-
const halfW = brushWidth / 2;
|
|
2984
|
-
const halfH = brushHeight / 2;
|
|
2985
|
-
const centerOffset = brushWidth % 2 === 0 ? 0.5 : 0;
|
|
2986
|
-
const target = writer.config.target;
|
|
2987
|
-
const targetWidth = target.width;
|
|
2988
|
-
const targetHeight = target.height;
|
|
2989
|
-
forEachLinePoint2(x0, y0, x1, y1, (px, py) => {
|
|
2990
|
-
const {
|
|
2991
|
-
x: rbx,
|
|
2992
|
-
y: rby,
|
|
2993
|
-
w: rbw,
|
|
2994
|
-
h: rbh
|
|
2995
|
-
} = getRectBrushOrPencilBounds2(px, py, brushWidth, brushHeight, targetWidth, targetHeight, rectPencilBounds);
|
|
2996
|
-
writer.accumulator.storeRegionBeforeState(rbx, rby, rbw, rbh);
|
|
2997
|
-
const startX = Math.max(bx, rbx);
|
|
2998
|
-
const startY = Math.max(by, rby);
|
|
2999
|
-
const endX = Math.min(bx + bw, rbx + rbw);
|
|
3000
|
-
const endY = Math.min(by + bh, rby + rbh);
|
|
3001
|
-
const fPx = Math.floor(px);
|
|
3002
|
-
const fPy = Math.floor(py);
|
|
3003
|
-
for (let my = startY; my < endY; my++) {
|
|
3004
|
-
const dy = Math.abs(my - fPy + centerOffset);
|
|
3005
|
-
const maskRowOffset = (my - by) * bw;
|
|
3006
|
-
for (let mx = startX; mx < endX; mx++) {
|
|
3007
|
-
const dx = Math.abs(mx - fPx + centerOffset);
|
|
3008
|
-
const maskIdx = maskRowOffset + (mx - bx);
|
|
3009
|
-
if (dx <= halfW && dy <= halfH) {
|
|
3010
|
-
maskData[maskIdx] = 1;
|
|
3011
|
-
}
|
|
3012
|
-
}
|
|
3013
|
-
}
|
|
3014
|
-
});
|
|
3015
|
-
blendColorPixelOptions.blendFn = blendFn;
|
|
3016
|
-
blendColorPixelOptions.alpha = alpha;
|
|
3017
|
-
blendColorPixelOptions.x = bx;
|
|
3018
|
-
blendColorPixelOptions.y = by;
|
|
3019
|
-
blendColorPixelOptions.w = bw;
|
|
3020
|
-
blendColorPixelOptions.h = bh;
|
|
3021
|
-
blendColorPixelDataBinaryMask2(target, color, mask, blendColorPixelOptions);
|
|
2708
|
+
fillBinaryMask(color, mask, alpha = 255, x = 0, y = 0) {
|
|
2709
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, mask.w, mask.h);
|
|
2710
|
+
return didChange(fillPixelDataBinaryMask2(writer.config.target, color, mask, alpha, x, y));
|
|
3022
2711
|
}
|
|
3023
2712
|
};
|
|
3024
2713
|
});
|
|
3025
2714
|
|
|
3026
|
-
// src/PixelData/
|
|
3027
|
-
|
|
2715
|
+
// src/PixelData/invertPixelData.ts
|
|
2716
|
+
var SCRATCH_RECT4 = makeClippedRect();
|
|
2717
|
+
function invertPixelData(pixelData, opts = {}) {
|
|
2718
|
+
const dst = pixelData;
|
|
3028
2719
|
const {
|
|
3029
2720
|
x: targetX = 0,
|
|
3030
2721
|
y: targetY = 0,
|
|
3031
|
-
w: width =
|
|
3032
|
-
h: height =
|
|
3033
|
-
|
|
3034
|
-
|
|
2722
|
+
w: width = pixelData.width,
|
|
2723
|
+
h: height = pixelData.height,
|
|
2724
|
+
mask,
|
|
2725
|
+
mx = 0,
|
|
2726
|
+
my = 0,
|
|
2727
|
+
invertMask = false
|
|
3035
2728
|
} = opts;
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
const
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
if (x < 0) {
|
|
3045
|
-
w += x;
|
|
3046
|
-
x = 0;
|
|
3047
|
-
}
|
|
3048
|
-
if (y < 0) {
|
|
3049
|
-
h += y;
|
|
3050
|
-
y = 0;
|
|
3051
|
-
}
|
|
3052
|
-
const actualW = Math.min(w, dst.width - x);
|
|
3053
|
-
const actualH = Math.min(h, dst.height - y);
|
|
3054
|
-
if (actualW <= 0 || actualH <= 0) return false;
|
|
3055
|
-
let finalSrcColor = color;
|
|
3056
|
-
if (globalAlpha < 255) {
|
|
3057
|
-
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
3058
|
-
if (a === 0 && !isOverwrite) return false;
|
|
3059
|
-
finalSrcColor = (color & 16777215 | a << 24) >>> 0;
|
|
3060
|
-
}
|
|
2729
|
+
const clip = resolveRectClipping(targetX, targetY, width, height, dst.width, dst.height, SCRATCH_RECT4);
|
|
2730
|
+
if (!clip.inBounds) return false;
|
|
2731
|
+
const {
|
|
2732
|
+
x,
|
|
2733
|
+
y,
|
|
2734
|
+
w: actualW,
|
|
2735
|
+
h: actualH
|
|
2736
|
+
} = clip;
|
|
3061
2737
|
const dst32 = dst.data32;
|
|
3062
2738
|
const dw = dst.width;
|
|
3063
|
-
|
|
3064
|
-
const
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
2739
|
+
const mPitch = mask?.w ?? width;
|
|
2740
|
+
const dx = x - targetX;
|
|
2741
|
+
const dy = y - targetY;
|
|
2742
|
+
let dIdx = y * dw + x;
|
|
2743
|
+
let mIdx = (my + dy) * mPitch + (mx + dx);
|
|
2744
|
+
const dStride = dw - actualW;
|
|
2745
|
+
const mStride = mPitch - actualW;
|
|
2746
|
+
if (mask) {
|
|
2747
|
+
const maskData = mask.data;
|
|
2748
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2749
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2750
|
+
const mVal = maskData[mIdx];
|
|
2751
|
+
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
2752
|
+
if (isHit) {
|
|
2753
|
+
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
2754
|
+
}
|
|
2755
|
+
dIdx++;
|
|
2756
|
+
mIdx++;
|
|
3073
2757
|
}
|
|
3074
|
-
dIdx
|
|
2758
|
+
dIdx += dStride;
|
|
2759
|
+
mIdx += mStride;
|
|
2760
|
+
}
|
|
2761
|
+
} else {
|
|
2762
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2763
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2764
|
+
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
2765
|
+
dIdx++;
|
|
2766
|
+
}
|
|
2767
|
+
dIdx += dStride;
|
|
3075
2768
|
}
|
|
3076
|
-
dIdx += dStride;
|
|
3077
2769
|
}
|
|
3078
|
-
return
|
|
2770
|
+
return true;
|
|
3079
2771
|
}
|
|
3080
2772
|
|
|
3081
|
-
// src/History/PixelMutator/
|
|
3082
|
-
var
|
|
3083
|
-
|
|
2773
|
+
// src/History/PixelMutator/mutatorInvert.ts
|
|
2774
|
+
var defaults10 = {
|
|
2775
|
+
invertPixelData
|
|
3084
2776
|
};
|
|
3085
|
-
var
|
|
2777
|
+
var mutatorInvert = ((writer, deps = defaults10) => {
|
|
3086
2778
|
const {
|
|
3087
|
-
|
|
2779
|
+
invertPixelData: invertPixelData2 = defaults10.invertPixelData
|
|
3088
2780
|
} = deps;
|
|
3089
2781
|
return {
|
|
3090
|
-
|
|
2782
|
+
invert(opts = {}) {
|
|
3091
2783
|
const target = writer.config.target;
|
|
3092
2784
|
const {
|
|
3093
2785
|
x = 0,
|
|
@@ -3096,708 +2788,644 @@ var mutatorBlendColor = ((writer, deps = defaults12) => {
|
|
|
3096
2788
|
h = target.height
|
|
3097
2789
|
} = opts;
|
|
3098
2790
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3099
|
-
return didChange(
|
|
2791
|
+
return didChange(invertPixelData2(target, opts));
|
|
3100
2792
|
}
|
|
3101
2793
|
};
|
|
3102
2794
|
});
|
|
3103
2795
|
|
|
3104
|
-
// src/
|
|
3105
|
-
function
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
2796
|
+
// src/History/PixelMutator.ts
|
|
2797
|
+
function makeFullPixelMutator(writer) {
|
|
2798
|
+
return {
|
|
2799
|
+
// @sort
|
|
2800
|
+
...mutatorBlendColor(writer),
|
|
2801
|
+
...mutatorBlendPixel(writer),
|
|
2802
|
+
...mutatorBlendPixelData(writer),
|
|
2803
|
+
...mutatorBlendPixelDataAlphaMask(writer),
|
|
2804
|
+
...mutatorBlendPixelDataBinaryMask(writer),
|
|
2805
|
+
...mutatorClear(writer),
|
|
2806
|
+
...mutatorFill(writer),
|
|
2807
|
+
...mutatorFillBinaryMask(writer),
|
|
2808
|
+
...mutatorFillRect(writer),
|
|
2809
|
+
...mutatorInvert(writer)
|
|
2810
|
+
};
|
|
2811
|
+
}
|
|
2812
|
+
|
|
2813
|
+
// src/ImageData/resizeImageData.ts
|
|
2814
|
+
function resizeImageData(target, newWidth, newHeight, offsetX = 0, offsetY = 0) {
|
|
2815
|
+
const result = new ImageData(newWidth, newHeight);
|
|
2816
|
+
const {
|
|
2817
|
+
width: oldW,
|
|
2818
|
+
height: oldH,
|
|
2819
|
+
data: oldData
|
|
2820
|
+
} = target;
|
|
2821
|
+
const newData = result.data;
|
|
2822
|
+
const x0 = Math.max(0, offsetX);
|
|
2823
|
+
const y0 = Math.max(0, offsetY);
|
|
2824
|
+
const x1 = Math.min(newWidth, offsetX + oldW);
|
|
2825
|
+
const y1 = Math.min(newHeight, offsetY + oldH);
|
|
2826
|
+
if (x1 <= x0 || y1 <= y0) {
|
|
2827
|
+
return result;
|
|
3120
2828
|
}
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
2829
|
+
const rowCount = y1 - y0;
|
|
2830
|
+
const rowLen = (x1 - x0) * 4;
|
|
2831
|
+
for (let row = 0; row < rowCount; row++) {
|
|
2832
|
+
const dstY = y0 + row;
|
|
2833
|
+
const srcY = dstY - offsetY;
|
|
2834
|
+
const srcX = x0 - offsetX;
|
|
2835
|
+
const dstStart = (dstY * newWidth + x0) * 4;
|
|
2836
|
+
const srcStart = (srcY * oldW + srcX) * 4;
|
|
2837
|
+
newData.set(oldData.subarray(srcStart, srcStart + rowLen), dstStart);
|
|
3126
2838
|
}
|
|
3127
|
-
return
|
|
2839
|
+
return result;
|
|
3128
2840
|
}
|
|
3129
2841
|
|
|
3130
|
-
// src/
|
|
3131
|
-
var
|
|
3132
|
-
blendPixel
|
|
3133
|
-
};
|
|
3134
|
-
var mutatorBlendPixel = ((writer, deps = defaults13) => {
|
|
3135
|
-
const {
|
|
3136
|
-
blendPixel: blendPixel2 = defaults13.blendPixel
|
|
3137
|
-
} = deps;
|
|
3138
|
-
return {
|
|
3139
|
-
blendPixel(x, y, color, alpha, blendFn) {
|
|
3140
|
-
const didChange = writer.accumulator.storePixelBeforeState(x, y);
|
|
3141
|
-
return didChange(blendPixel2(writer.config.target, x, y, color, alpha, blendFn));
|
|
3142
|
-
}
|
|
3143
|
-
};
|
|
3144
|
-
});
|
|
2842
|
+
// src/Internal/helpers.ts
|
|
2843
|
+
var macro_halfAndFloor = (value) => value >> 1;
|
|
3145
2844
|
|
|
3146
|
-
// src/
|
|
3147
|
-
function
|
|
3148
|
-
const {
|
|
3149
|
-
x:
|
|
3150
|
-
y:
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
w: width = src.width,
|
|
3154
|
-
h: height = src.height,
|
|
3155
|
-
alpha: globalAlpha = 255,
|
|
3156
|
-
blendFn = sourceOverPerfect
|
|
3157
|
-
} = opts;
|
|
3158
|
-
if (globalAlpha === 0) return false;
|
|
3159
|
-
let x = targetX;
|
|
3160
|
-
let y = targetY;
|
|
3161
|
-
let sx = sourceX;
|
|
3162
|
-
let sy = sourceY;
|
|
3163
|
-
let w = width;
|
|
3164
|
-
let h = height;
|
|
3165
|
-
if (sx < 0) {
|
|
3166
|
-
x -= sx;
|
|
3167
|
-
w += sx;
|
|
3168
|
-
sx = 0;
|
|
3169
|
-
}
|
|
3170
|
-
if (sy < 0) {
|
|
3171
|
-
y -= sy;
|
|
3172
|
-
h += sy;
|
|
3173
|
-
sy = 0;
|
|
3174
|
-
}
|
|
3175
|
-
w = Math.min(w, src.width - sx);
|
|
3176
|
-
h = Math.min(h, src.height - sy);
|
|
3177
|
-
if (x < 0) {
|
|
3178
|
-
sx -= x;
|
|
3179
|
-
w += x;
|
|
3180
|
-
x = 0;
|
|
3181
|
-
}
|
|
3182
|
-
if (y < 0) {
|
|
3183
|
-
sy -= y;
|
|
3184
|
-
h += y;
|
|
3185
|
-
y = 0;
|
|
3186
|
-
}
|
|
3187
|
-
const actualW = Math.min(w, dst.width - x);
|
|
3188
|
-
const actualH = Math.min(h, dst.height - y);
|
|
3189
|
-
if (actualW <= 0 || actualH <= 0) return false;
|
|
3190
|
-
const dst32 = dst.data32;
|
|
3191
|
-
const src32 = src.data32;
|
|
3192
|
-
const dw = dst.width;
|
|
3193
|
-
const sw = src.width;
|
|
3194
|
-
let dIdx = y * dw + x | 0;
|
|
3195
|
-
let sIdx = sy * sw + sx | 0;
|
|
3196
|
-
const dStride = dw - actualW | 0;
|
|
3197
|
-
const sStride = sw - actualW | 0;
|
|
3198
|
-
const isOpaque = globalAlpha === 255;
|
|
3199
|
-
const isOverwrite = blendFn.isOverwrite;
|
|
3200
|
-
let didChange = false;
|
|
3201
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
3202
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
3203
|
-
const srcCol = src32[sIdx];
|
|
3204
|
-
const srcAlpha = srcCol >>> 24;
|
|
3205
|
-
if (srcAlpha === 0 && !isOverwrite) {
|
|
3206
|
-
dIdx++;
|
|
3207
|
-
sIdx++;
|
|
3208
|
-
continue;
|
|
3209
|
-
}
|
|
3210
|
-
let finalCol = srcCol;
|
|
3211
|
-
if (!isOpaque) {
|
|
3212
|
-
const a = srcAlpha * globalAlpha + 128 >> 8;
|
|
3213
|
-
if (a === 0 && !isOverwrite) {
|
|
3214
|
-
dIdx++;
|
|
3215
|
-
sIdx++;
|
|
3216
|
-
continue;
|
|
3217
|
-
}
|
|
3218
|
-
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
3219
|
-
}
|
|
3220
|
-
const current = dst32[dIdx];
|
|
3221
|
-
const next = blendFn(finalCol, dst32[dIdx]);
|
|
3222
|
-
if (current !== next) {
|
|
3223
|
-
dst32[dIdx] = next;
|
|
3224
|
-
didChange = true;
|
|
3225
|
-
}
|
|
3226
|
-
dIdx++;
|
|
3227
|
-
sIdx++;
|
|
3228
|
-
}
|
|
3229
|
-
dIdx += dStride;
|
|
3230
|
-
sIdx += sStride;
|
|
3231
|
-
}
|
|
3232
|
-
return didChange;
|
|
3233
|
-
}
|
|
3234
|
-
|
|
3235
|
-
// src/History/PixelMutator/mutatorBlendPixelData.ts
|
|
3236
|
-
var defaults14 = {
|
|
3237
|
-
blendPixelData
|
|
3238
|
-
};
|
|
3239
|
-
var mutatorBlendPixelData = ((writer, deps = defaults14) => {
|
|
3240
|
-
const {
|
|
3241
|
-
blendPixelData: blendPixelData2 = defaults14.blendPixelData
|
|
3242
|
-
} = deps;
|
|
3243
|
-
return {
|
|
3244
|
-
blendPixelData(src, opts = {}) {
|
|
3245
|
-
const {
|
|
3246
|
-
x = 0,
|
|
3247
|
-
y = 0,
|
|
3248
|
-
w = src.width,
|
|
3249
|
-
h = src.height
|
|
3250
|
-
} = opts;
|
|
3251
|
-
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3252
|
-
return didChange(blendPixelData2(writer.config.target, src, opts));
|
|
3253
|
-
}
|
|
3254
|
-
};
|
|
3255
|
-
});
|
|
3256
|
-
|
|
3257
|
-
// src/PixelData/blendPixelDataAlphaMask.ts
|
|
3258
|
-
function blendPixelDataAlphaMask(dst, src, alphaMask, opts = {}) {
|
|
3259
|
-
const {
|
|
3260
|
-
x: targetX = 0,
|
|
3261
|
-
y: targetY = 0,
|
|
3262
|
-
sx: sourceX = 0,
|
|
3263
|
-
sy: sourceY = 0,
|
|
3264
|
-
w: width = src.width,
|
|
3265
|
-
h: height = src.height,
|
|
3266
|
-
alpha: globalAlpha = 255,
|
|
3267
|
-
blendFn = sourceOverPerfect,
|
|
3268
|
-
mx = 0,
|
|
3269
|
-
my = 0,
|
|
3270
|
-
invertMask = false
|
|
3271
|
-
} = opts;
|
|
3272
|
-
if (globalAlpha === 0) return false;
|
|
3273
|
-
let x = targetX;
|
|
3274
|
-
let y = targetY;
|
|
3275
|
-
let sx = sourceX;
|
|
3276
|
-
let sy = sourceY;
|
|
3277
|
-
let w = width;
|
|
3278
|
-
let h = height;
|
|
3279
|
-
if (sx < 0) {
|
|
3280
|
-
x -= sx;
|
|
3281
|
-
w += sx;
|
|
3282
|
-
sx = 0;
|
|
3283
|
-
}
|
|
3284
|
-
if (sy < 0) {
|
|
3285
|
-
y -= sy;
|
|
3286
|
-
h += sy;
|
|
3287
|
-
sy = 0;
|
|
3288
|
-
}
|
|
3289
|
-
w = Math.min(w, src.width - sx);
|
|
3290
|
-
h = Math.min(h, src.height - sy);
|
|
3291
|
-
if (x < 0) {
|
|
3292
|
-
sx -= x;
|
|
3293
|
-
w += x;
|
|
3294
|
-
x = 0;
|
|
3295
|
-
}
|
|
3296
|
-
if (y < 0) {
|
|
3297
|
-
sy -= y;
|
|
3298
|
-
h += y;
|
|
3299
|
-
y = 0;
|
|
3300
|
-
}
|
|
3301
|
-
const actualW = Math.min(w, dst.width - x);
|
|
3302
|
-
const actualH = Math.min(h, dst.height - y);
|
|
3303
|
-
if (actualW <= 0 || actualH <= 0) return false;
|
|
3304
|
-
const dw = dst.width;
|
|
3305
|
-
const sw = src.width;
|
|
3306
|
-
const mPitch = alphaMask.w;
|
|
3307
|
-
const maskData = alphaMask.data;
|
|
3308
|
-
const dx = x - targetX | 0;
|
|
3309
|
-
const dy = y - targetY | 0;
|
|
3310
|
-
const dst32 = dst.data32;
|
|
3311
|
-
const src32 = src.data32;
|
|
3312
|
-
let dIdx = y * dw + x | 0;
|
|
3313
|
-
let sIdx = sy * sw + sx | 0;
|
|
3314
|
-
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
3315
|
-
const dStride = dw - actualW | 0;
|
|
3316
|
-
const sStride = sw - actualW | 0;
|
|
3317
|
-
const mStride = mPitch - actualW | 0;
|
|
3318
|
-
const isOpaque = globalAlpha === 255;
|
|
3319
|
-
const isOverwrite = blendFn.isOverwrite || false;
|
|
3320
|
-
let didChange = false;
|
|
3321
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
3322
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
3323
|
-
const mVal = maskData[mIdx];
|
|
3324
|
-
const effM = invertMask ? 255 - mVal : mVal;
|
|
3325
|
-
if (effM === 0) {
|
|
3326
|
-
dIdx++;
|
|
3327
|
-
sIdx++;
|
|
3328
|
-
mIdx++;
|
|
3329
|
-
continue;
|
|
3330
|
-
}
|
|
3331
|
-
const srcCol = src32[sIdx];
|
|
3332
|
-
const srcAlpha = srcCol >>> 24;
|
|
3333
|
-
if (srcAlpha === 0 && !isOverwrite) {
|
|
3334
|
-
dIdx++;
|
|
3335
|
-
sIdx++;
|
|
3336
|
-
mIdx++;
|
|
3337
|
-
continue;
|
|
3338
|
-
}
|
|
3339
|
-
let weight = globalAlpha;
|
|
3340
|
-
if (isOpaque) {
|
|
3341
|
-
weight = effM;
|
|
3342
|
-
} else if (effM !== 255) {
|
|
3343
|
-
weight = effM * globalAlpha + 128 >> 8;
|
|
3344
|
-
}
|
|
3345
|
-
if (weight === 0) {
|
|
3346
|
-
dIdx++;
|
|
3347
|
-
sIdx++;
|
|
3348
|
-
mIdx++;
|
|
3349
|
-
continue;
|
|
3350
|
-
}
|
|
3351
|
-
let finalCol = srcCol;
|
|
3352
|
-
if (weight < 255) {
|
|
3353
|
-
const a = srcAlpha * weight + 128 >> 8;
|
|
3354
|
-
if (a === 0 && !isOverwrite) {
|
|
3355
|
-
dIdx++;
|
|
3356
|
-
sIdx++;
|
|
3357
|
-
mIdx++;
|
|
3358
|
-
continue;
|
|
3359
|
-
}
|
|
3360
|
-
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
3361
|
-
}
|
|
3362
|
-
const current = dst32[dIdx];
|
|
3363
|
-
const next = blendFn(finalCol, dst32[dIdx]);
|
|
3364
|
-
if (current !== next) {
|
|
3365
|
-
dst32[dIdx] = next;
|
|
3366
|
-
didChange = true;
|
|
3367
|
-
}
|
|
3368
|
-
dIdx++;
|
|
3369
|
-
sIdx++;
|
|
3370
|
-
mIdx++;
|
|
3371
|
-
}
|
|
3372
|
-
dIdx += dStride;
|
|
3373
|
-
sIdx += sStride;
|
|
3374
|
-
mIdx += mStride;
|
|
3375
|
-
}
|
|
3376
|
-
return didChange;
|
|
3377
|
-
}
|
|
3378
|
-
|
|
3379
|
-
// src/History/PixelMutator/mutatorBlendPixelDataAlphaMask.ts
|
|
3380
|
-
var defaults15 = {
|
|
3381
|
-
blendPixelDataAlphaMask
|
|
3382
|
-
};
|
|
3383
|
-
var mutatorBlendPixelDataAlphaMask = ((writer, deps = defaults15) => {
|
|
3384
|
-
const {
|
|
3385
|
-
blendPixelDataAlphaMask: blendPixelDataAlphaMask2 = defaults15.blendPixelDataAlphaMask
|
|
3386
|
-
} = deps;
|
|
3387
|
-
return {
|
|
3388
|
-
blendPixelDataAlphaMask(src, mask, opts = {}) {
|
|
3389
|
-
const x = opts.x ?? 0;
|
|
3390
|
-
const y = opts.y ?? 0;
|
|
3391
|
-
const w = opts.w ?? src.width;
|
|
3392
|
-
const h = opts.h ?? src.height;
|
|
3393
|
-
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3394
|
-
return didChange(blendPixelDataAlphaMask2(writer.config.target, src, mask, opts));
|
|
3395
|
-
}
|
|
2845
|
+
// src/Rect/trimRectBounds.ts
|
|
2846
|
+
function trimRectBounds(x, y, w, h, targetWidth, targetHeight, out) {
|
|
2847
|
+
const res = out ?? {
|
|
2848
|
+
x: 0,
|
|
2849
|
+
y: 0,
|
|
2850
|
+
w: 0,
|
|
2851
|
+
h: 0
|
|
3396
2852
|
};
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
if (globalAlpha === 0) return false;
|
|
3415
|
-
let x = targetX;
|
|
3416
|
-
let y = targetY;
|
|
3417
|
-
let sx = sourceX;
|
|
3418
|
-
let sy = sourceY;
|
|
3419
|
-
let w = width;
|
|
3420
|
-
let h = height;
|
|
3421
|
-
if (sx < 0) {
|
|
3422
|
-
x -= sx;
|
|
3423
|
-
w += sx;
|
|
3424
|
-
sx = 0;
|
|
3425
|
-
}
|
|
3426
|
-
if (sy < 0) {
|
|
3427
|
-
y -= sy;
|
|
3428
|
-
h += sy;
|
|
3429
|
-
sy = 0;
|
|
3430
|
-
}
|
|
3431
|
-
w = Math.min(w, src.width - sx);
|
|
3432
|
-
h = Math.min(h, src.height - sy);
|
|
3433
|
-
if (x < 0) {
|
|
3434
|
-
sx -= x;
|
|
3435
|
-
w += x;
|
|
3436
|
-
x = 0;
|
|
3437
|
-
}
|
|
3438
|
-
if (y < 0) {
|
|
3439
|
-
sy -= y;
|
|
3440
|
-
h += y;
|
|
3441
|
-
y = 0;
|
|
2853
|
+
const left = Math.max(0, x);
|
|
2854
|
+
const top = Math.max(0, y);
|
|
2855
|
+
const right = Math.min(targetWidth, x + w);
|
|
2856
|
+
const bottom = Math.min(targetHeight, y + h);
|
|
2857
|
+
res.x = left;
|
|
2858
|
+
res.y = top;
|
|
2859
|
+
res.w = Math.max(0, right - left);
|
|
2860
|
+
res.h = Math.max(0, bottom - top);
|
|
2861
|
+
return res;
|
|
2862
|
+
}
|
|
2863
|
+
|
|
2864
|
+
// src/Paint/PaintBuffer.ts
|
|
2865
|
+
var PaintBuffer = class {
|
|
2866
|
+
constructor(config, tilePool) {
|
|
2867
|
+
this.config = config;
|
|
2868
|
+
this.tilePool = tilePool;
|
|
2869
|
+
this.lookup = [];
|
|
3442
2870
|
}
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
let finalCol = srcCol;
|
|
3481
|
-
if (!isOpaque) {
|
|
3482
|
-
const a = srcAlpha * globalAlpha + 128 >> 8;
|
|
3483
|
-
if (a === 0 && !isOverwrite) {
|
|
3484
|
-
dIdx++;
|
|
3485
|
-
sIdx++;
|
|
3486
|
-
mIdx++;
|
|
3487
|
-
continue;
|
|
3488
|
-
}
|
|
3489
|
-
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
3490
|
-
}
|
|
3491
|
-
const current = dst32[dIdx];
|
|
3492
|
-
const next = blendFn(finalCol, dst32[dIdx]);
|
|
3493
|
-
if (current !== next) {
|
|
3494
|
-
dst32[dIdx] = next;
|
|
3495
|
-
didChange = true;
|
|
2871
|
+
lookup;
|
|
2872
|
+
scratchBounds = {
|
|
2873
|
+
x: 0,
|
|
2874
|
+
y: 0,
|
|
2875
|
+
w: 0,
|
|
2876
|
+
h: 0
|
|
2877
|
+
};
|
|
2878
|
+
eachTileInBounds(bounds, callback) {
|
|
2879
|
+
const {
|
|
2880
|
+
tileShift,
|
|
2881
|
+
targetColumns,
|
|
2882
|
+
targetRows,
|
|
2883
|
+
tileSize
|
|
2884
|
+
} = this.config;
|
|
2885
|
+
const x1 = Math.max(0, bounds.x >> tileShift);
|
|
2886
|
+
const y1 = Math.max(0, bounds.y >> tileShift);
|
|
2887
|
+
const x2 = Math.min(targetColumns - 1, bounds.x + bounds.w - 1 >> tileShift);
|
|
2888
|
+
const y2 = Math.min(targetRows - 1, bounds.y + bounds.h - 1 >> tileShift);
|
|
2889
|
+
if (x1 > x2 || y1 > y2) return;
|
|
2890
|
+
const lookup = this.lookup;
|
|
2891
|
+
const tilePool = this.tilePool;
|
|
2892
|
+
for (let ty = y1; ty <= y2; ty++) {
|
|
2893
|
+
const rowOffset = ty * targetColumns;
|
|
2894
|
+
const tileTop = ty << tileShift;
|
|
2895
|
+
for (let tx = x1; tx <= x2; tx++) {
|
|
2896
|
+
const id = rowOffset + tx;
|
|
2897
|
+
const tile = lookup[id] ?? (lookup[id] = tilePool.getTile(id, tx, ty));
|
|
2898
|
+
const tileLeft = tx << tileShift;
|
|
2899
|
+
const startX = bounds.x > tileLeft ? bounds.x : tileLeft;
|
|
2900
|
+
const startY = bounds.y > tileTop ? bounds.y : tileTop;
|
|
2901
|
+
const maskEndX = bounds.x + bounds.w;
|
|
2902
|
+
const tileEndX = tileLeft + tileSize;
|
|
2903
|
+
const endX = maskEndX < tileEndX ? maskEndX : tileEndX;
|
|
2904
|
+
const maskEndY = bounds.y + bounds.h;
|
|
2905
|
+
const tileEndY = tileTop + tileSize;
|
|
2906
|
+
const endY = maskEndY < tileEndY ? maskEndY : tileEndY;
|
|
2907
|
+
callback(tile, startX, startY, endX - startX, endY - startY);
|
|
3496
2908
|
}
|
|
3497
|
-
dIdx++;
|
|
3498
|
-
sIdx++;
|
|
3499
|
-
mIdx++;
|
|
3500
2909
|
}
|
|
3501
|
-
dIdx += dStride;
|
|
3502
|
-
sIdx += sStride;
|
|
3503
|
-
mIdx += mStride;
|
|
3504
2910
|
}
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
2911
|
+
writePaintAlphaMaskStroke(color, brush, x0, y0, x1, y1) {
|
|
2912
|
+
const cA = color >>> 24;
|
|
2913
|
+
if (cA === 0) return false;
|
|
2914
|
+
const {
|
|
2915
|
+
tileShift,
|
|
2916
|
+
tileMask,
|
|
2917
|
+
target
|
|
2918
|
+
} = this.config;
|
|
2919
|
+
const {
|
|
2920
|
+
w: bW,
|
|
2921
|
+
h: bH,
|
|
2922
|
+
data: bD,
|
|
2923
|
+
centerOffsetX,
|
|
2924
|
+
centerOffsetY
|
|
2925
|
+
} = brush;
|
|
2926
|
+
const cRGB = color & 16777215;
|
|
2927
|
+
const scratch = this.scratchBounds;
|
|
2928
|
+
let changed = false;
|
|
2929
|
+
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
2930
|
+
const topLeftX = Math.floor(px + centerOffsetX);
|
|
2931
|
+
const topLeftY = Math.floor(py + centerOffsetY);
|
|
2932
|
+
trimRectBounds(topLeftX, topLeftY, bW, bH, target.width, target.height, scratch);
|
|
2933
|
+
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
2934
|
+
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
2935
|
+
const d32 = tile.data32;
|
|
2936
|
+
let tileChanged = false;
|
|
2937
|
+
for (let i = 0; i < bH_t; i++) {
|
|
2938
|
+
const canvasY = bY + i;
|
|
2939
|
+
const bOff = (canvasY - topLeftY) * bW;
|
|
2940
|
+
const tOff = (canvasY & tileMask) << tileShift;
|
|
2941
|
+
const dS = tOff + (bX & tileMask);
|
|
2942
|
+
for (let j = 0; j < bW_t; j++) {
|
|
2943
|
+
const canvasX = bX + j;
|
|
2944
|
+
const brushA = bD[bOff + (canvasX - topLeftX)];
|
|
2945
|
+
if (brushA === 0) continue;
|
|
2946
|
+
const t = cA * brushA + 128;
|
|
2947
|
+
const blendedA = t + (t >> 8) >> 8;
|
|
2948
|
+
const idx = dS + j;
|
|
2949
|
+
const cur = d32[idx];
|
|
2950
|
+
if (brushA > cur >>> 24) {
|
|
2951
|
+
const next = (cRGB | blendedA << 24) >>> 0;
|
|
2952
|
+
if (cur !== next) {
|
|
2953
|
+
d32[idx] = next;
|
|
2954
|
+
tileChanged = true;
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
}
|
|
2958
|
+
}
|
|
2959
|
+
if (tileChanged) changed = true;
|
|
2960
|
+
});
|
|
2961
|
+
});
|
|
2962
|
+
return changed;
|
|
3550
2963
|
}
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
2964
|
+
writePaintBinaryMaskStroke(color, brush, x0, y0, x1, y1) {
|
|
2965
|
+
const alphaIsZero = color >>> 24 === 0;
|
|
2966
|
+
if (alphaIsZero) return false;
|
|
2967
|
+
const {
|
|
2968
|
+
tileShift,
|
|
2969
|
+
tileMask,
|
|
2970
|
+
target
|
|
2971
|
+
} = this.config;
|
|
2972
|
+
const {
|
|
2973
|
+
w: bW,
|
|
2974
|
+
h: bH,
|
|
2975
|
+
data: bD,
|
|
2976
|
+
centerOffsetX,
|
|
2977
|
+
centerOffsetY
|
|
2978
|
+
} = brush;
|
|
2979
|
+
const scratch = this.scratchBounds;
|
|
2980
|
+
let changed = false;
|
|
2981
|
+
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
2982
|
+
const topLeftX = Math.floor(px + centerOffsetX);
|
|
2983
|
+
const topLeftY = Math.floor(py + centerOffsetY);
|
|
2984
|
+
trimRectBounds(topLeftX, topLeftY, bW, bH, target.width, target.height, scratch);
|
|
2985
|
+
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
2986
|
+
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
2987
|
+
const d32 = tile.data32;
|
|
2988
|
+
let tileChanged = false;
|
|
2989
|
+
for (let i = 0; i < bH_t; i++) {
|
|
2990
|
+
const canvasY = bY + i;
|
|
2991
|
+
const bOff = (canvasY - topLeftY) * bW;
|
|
2992
|
+
const tOff = (canvasY & tileMask) << tileShift;
|
|
2993
|
+
const dS = tOff + (bX & tileMask);
|
|
2994
|
+
for (let j = 0; j < bW_t; j++) {
|
|
2995
|
+
const canvasX = bX + j;
|
|
2996
|
+
if (bD[bOff + (canvasX - topLeftX)]) {
|
|
2997
|
+
const idx = dS + j;
|
|
2998
|
+
if (d32[idx] !== color) {
|
|
2999
|
+
d32[idx] = color;
|
|
3000
|
+
tileChanged = true;
|
|
3001
|
+
}
|
|
3002
|
+
}
|
|
3003
|
+
}
|
|
3004
|
+
}
|
|
3005
|
+
if (tileChanged) changed = true;
|
|
3006
|
+
});
|
|
3007
|
+
});
|
|
3008
|
+
return changed;
|
|
3009
|
+
}
|
|
3010
|
+
writeRectStroke(color, brushWidth, brushHeight, x0, y0, x1, y1) {
|
|
3011
|
+
const alphaIsZero = color >>> 24 === 0;
|
|
3012
|
+
if (alphaIsZero) return false;
|
|
3013
|
+
const config = this.config;
|
|
3014
|
+
const tileShift = config.tileShift;
|
|
3015
|
+
const tileMask = config.tileMask;
|
|
3016
|
+
const target = config.target;
|
|
3017
|
+
const scratch = this.scratchBounds;
|
|
3018
|
+
const centerOffsetX = macro_halfAndFloor(brushWidth - 1);
|
|
3019
|
+
const centerOffsetY = macro_halfAndFloor(brushHeight - 1);
|
|
3020
|
+
let changed = false;
|
|
3021
|
+
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
3022
|
+
const topLeftX = Math.floor(px + centerOffsetX);
|
|
3023
|
+
const topLeftY = Math.floor(py + centerOffsetY);
|
|
3024
|
+
trimRectBounds(topLeftX, topLeftY, brushWidth, brushHeight, target.width, target.height, scratch);
|
|
3025
|
+
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
3026
|
+
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
3027
|
+
const d32 = tile.data32;
|
|
3028
|
+
let tileChanged = false;
|
|
3029
|
+
for (let i = 0; i < bH_t; i++) {
|
|
3030
|
+
const canvasY = bY + i;
|
|
3031
|
+
const tOff = (canvasY & tileMask) << tileShift;
|
|
3032
|
+
const dS = tOff + (bX & tileMask);
|
|
3033
|
+
for (let j = 0; j < bW_t; j++) {
|
|
3034
|
+
const idx = dS + j;
|
|
3035
|
+
if (d32[idx] !== color) {
|
|
3036
|
+
d32[idx] = color;
|
|
3037
|
+
tileChanged = true;
|
|
3038
|
+
}
|
|
3039
|
+
}
|
|
3040
|
+
}
|
|
3041
|
+
if (tileChanged) {
|
|
3042
|
+
changed = true;
|
|
3043
|
+
}
|
|
3044
|
+
});
|
|
3045
|
+
});
|
|
3046
|
+
return changed;
|
|
3564
3047
|
}
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
const end = start + actualW;
|
|
3568
|
-
dst32.fill(color, start, end);
|
|
3048
|
+
clear() {
|
|
3049
|
+
this.tilePool.releaseTiles(this.lookup);
|
|
3569
3050
|
}
|
|
3570
|
-
}
|
|
3051
|
+
};
|
|
3571
3052
|
|
|
3572
|
-
// src/
|
|
3573
|
-
var
|
|
3574
|
-
|
|
3053
|
+
// src/PixelTile/PixelTile.ts
|
|
3054
|
+
var PixelTile = class {
|
|
3055
|
+
constructor(id, tx, ty, tileSize, tileArea) {
|
|
3056
|
+
this.id = id;
|
|
3057
|
+
this.tx = tx;
|
|
3058
|
+
this.ty = ty;
|
|
3059
|
+
this.width = this.height = tileSize;
|
|
3060
|
+
this.data32 = new Uint32Array(tileArea);
|
|
3061
|
+
const data8 = new Uint8ClampedArray(this.data32.buffer);
|
|
3062
|
+
this.imageData = new ImageData(data8, tileSize, tileSize);
|
|
3063
|
+
}
|
|
3064
|
+
data32;
|
|
3065
|
+
width;
|
|
3066
|
+
height;
|
|
3067
|
+
imageData;
|
|
3575
3068
|
};
|
|
3576
|
-
var mutatorClear = ((writer, deps = defaults17) => {
|
|
3577
|
-
const {
|
|
3578
|
-
fillPixelData: fillPixelData2 = defaults17.fillPixelData
|
|
3579
|
-
} = deps;
|
|
3580
|
-
return {
|
|
3581
|
-
clear(rect = {}) {
|
|
3582
|
-
const target = writer.config.target;
|
|
3583
|
-
const x = rect.x ?? 0;
|
|
3584
|
-
const y = rect.y ?? 0;
|
|
3585
|
-
const w = rect.w ?? target.width;
|
|
3586
|
-
const h = rect.h ?? target.height;
|
|
3587
|
-
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3588
|
-
fillPixelData2(target, 0, x, y, w, h);
|
|
3589
|
-
}
|
|
3590
|
-
};
|
|
3591
|
-
});
|
|
3592
3069
|
|
|
3593
|
-
// src/
|
|
3594
|
-
var
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
y = _x.y ?? 0;
|
|
3603
|
-
w = _x.w ?? dst.width;
|
|
3604
|
-
h = _x.h ?? dst.height;
|
|
3605
|
-
} else if (typeof _x === "number") {
|
|
3606
|
-
x = _x;
|
|
3607
|
-
y = _y;
|
|
3608
|
-
w = _w;
|
|
3609
|
-
h = _h;
|
|
3610
|
-
} else {
|
|
3611
|
-
x = 0;
|
|
3612
|
-
y = 0;
|
|
3613
|
-
w = dst.width;
|
|
3614
|
-
h = dst.height;
|
|
3070
|
+
// src/PixelTile/PixelTilePool.ts
|
|
3071
|
+
var PixelTilePool = class {
|
|
3072
|
+
pool;
|
|
3073
|
+
tileSize;
|
|
3074
|
+
tileArea;
|
|
3075
|
+
constructor(config) {
|
|
3076
|
+
this.pool = [];
|
|
3077
|
+
this.tileSize = config.tileSize;
|
|
3078
|
+
this.tileArea = config.tileArea;
|
|
3615
3079
|
}
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3080
|
+
getTile(id, tx, ty) {
|
|
3081
|
+
let tile = this.pool.pop();
|
|
3082
|
+
if (tile) {
|
|
3083
|
+
tile.id = id;
|
|
3084
|
+
tile.tx = tx;
|
|
3085
|
+
tile.ty = ty;
|
|
3086
|
+
tile.data32.fill(0);
|
|
3087
|
+
return tile;
|
|
3088
|
+
}
|
|
3089
|
+
return new PixelTile(id, tx, ty, this.tileSize, this.tileArea);
|
|
3090
|
+
}
|
|
3091
|
+
releaseTile(tile) {
|
|
3092
|
+
this.pool.push(tile);
|
|
3093
|
+
}
|
|
3094
|
+
releaseTiles(tiles) {
|
|
3095
|
+
let length = tiles.length;
|
|
3096
|
+
for (let i = 0; i < length; i++) {
|
|
3097
|
+
let tile = tiles[i];
|
|
3098
|
+
if (tile) {
|
|
3099
|
+
this.pool.push(tile);
|
|
3635
3100
|
}
|
|
3636
3101
|
}
|
|
3102
|
+
tiles.length = 0;
|
|
3637
3103
|
}
|
|
3638
|
-
return hasChanged;
|
|
3639
|
-
}
|
|
3640
|
-
|
|
3641
|
-
// src/History/PixelMutator/mutatorFill.ts
|
|
3642
|
-
var defaults18 = {
|
|
3643
|
-
fillPixelData
|
|
3644
3104
|
};
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3105
|
+
|
|
3106
|
+
// src/History/PixelWriter.ts
|
|
3107
|
+
var PixelWriter = class {
|
|
3108
|
+
historyManager;
|
|
3109
|
+
accumulator;
|
|
3110
|
+
historyActionFactory;
|
|
3111
|
+
config;
|
|
3112
|
+
pixelTilePool;
|
|
3113
|
+
paintBuffer;
|
|
3114
|
+
mutator;
|
|
3115
|
+
blendPixelDataOpts = {
|
|
3116
|
+
alpha: 255,
|
|
3117
|
+
blendFn: sourceOverPerfect,
|
|
3118
|
+
x: 0,
|
|
3119
|
+
y: 0,
|
|
3120
|
+
w: 0,
|
|
3121
|
+
h: 0
|
|
3655
3122
|
};
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3123
|
+
_inProgress = false;
|
|
3124
|
+
constructor(target, mutatorFactory, {
|
|
3125
|
+
tileSize = 256,
|
|
3126
|
+
maxHistorySteps = 50,
|
|
3127
|
+
historyManager = new HistoryManager(maxHistorySteps),
|
|
3128
|
+
historyActionFactory = makeHistoryAction,
|
|
3129
|
+
pixelTilePool,
|
|
3130
|
+
accumulator
|
|
3131
|
+
} = {}) {
|
|
3132
|
+
this.config = new PixelEngineConfig(tileSize, target);
|
|
3133
|
+
this.historyManager = historyManager;
|
|
3134
|
+
this.pixelTilePool = pixelTilePool ?? new PixelTilePool(this.config);
|
|
3135
|
+
this.accumulator = accumulator ?? new PixelAccumulator(this.config, this.pixelTilePool);
|
|
3136
|
+
this.historyActionFactory = historyActionFactory;
|
|
3137
|
+
this.mutator = mutatorFactory(this);
|
|
3138
|
+
this.paintBuffer = new PaintBuffer(this.config, this.pixelTilePool);
|
|
3139
|
+
}
|
|
3140
|
+
/**
|
|
3141
|
+
* Executes `transaction` and commits the resulting pixel changes as a single
|
|
3142
|
+
* undoable history action.
|
|
3143
|
+
*
|
|
3144
|
+
* - If `transaction` throws, all accumulated changes are rolled back and the error
|
|
3145
|
+
* is re-thrown. No action is committed.
|
|
3146
|
+
* - If `transaction` completes without modifying any pixels, no action is committed.
|
|
3147
|
+
* - `withHistory` is not re-entrant. Calling it again from inside `transaction` will
|
|
3148
|
+
* throw immediately to prevent silent data loss from a nested extractPatch.
|
|
3149
|
+
*
|
|
3150
|
+
* @param transaction Callback to be executed inside the transaction.
|
|
3151
|
+
* @param after Called after both undo and redo — use for generic change notifications.
|
|
3152
|
+
* @param afterUndo Called after undo only — use for dimension or state changes specific to undo.
|
|
3153
|
+
* @param afterRedo Called after redo only.
|
|
3154
|
+
*/
|
|
3155
|
+
withHistory(transaction, after, afterUndo, afterRedo) {
|
|
3156
|
+
if (this._inProgress) {
|
|
3157
|
+
throw new Error("withHistory is not re-entrant \u2014 commit or rollback the current operation first");
|
|
3666
3158
|
}
|
|
3667
|
-
|
|
3668
|
-
|
|
3159
|
+
this._inProgress = true;
|
|
3160
|
+
try {
|
|
3161
|
+
transaction(this.mutator);
|
|
3162
|
+
} catch (e) {
|
|
3163
|
+
this.accumulator.rollbackAfterError();
|
|
3164
|
+
throw e;
|
|
3165
|
+
} finally {
|
|
3166
|
+
this._inProgress = false;
|
|
3167
|
+
}
|
|
3168
|
+
if (this.accumulator.beforeTiles.length === 0) return;
|
|
3169
|
+
const patch = this.accumulator.extractPatch();
|
|
3170
|
+
const action = this.historyActionFactory(this, patch, after, afterUndo, afterRedo);
|
|
3171
|
+
this.historyManager.commit(action);
|
|
3172
|
+
}
|
|
3173
|
+
resize(newWidth, newHeight, offsetX = 0, offsetY = 0, after, afterUndo, afterRedo, resizeImageDataFn = resizeImageData) {
|
|
3174
|
+
if (this._inProgress) {
|
|
3175
|
+
throw new Error("Cannot resize inside a withHistory callback");
|
|
3176
|
+
}
|
|
3177
|
+
if (this.accumulator.beforeTiles.length > 0) {
|
|
3178
|
+
throw new Error("Cannot resize with an open accumulator \u2014 commit or rollback first");
|
|
3179
|
+
}
|
|
3180
|
+
const config = this.config;
|
|
3181
|
+
const target = config.target;
|
|
3182
|
+
const beforeImageData = target.imageData;
|
|
3183
|
+
const afterImageData = resizeImageDataFn(beforeImageData, newWidth, newHeight, offsetX, offsetY);
|
|
3184
|
+
target.set(afterImageData);
|
|
3185
|
+
this.historyManager.commit({
|
|
3186
|
+
undo: () => {
|
|
3187
|
+
target.set(beforeImageData);
|
|
3188
|
+
afterUndo?.(beforeImageData);
|
|
3189
|
+
after?.(beforeImageData);
|
|
3190
|
+
},
|
|
3191
|
+
redo: () => {
|
|
3192
|
+
target.set(afterImageData);
|
|
3193
|
+
afterRedo?.(afterImageData);
|
|
3194
|
+
after?.(afterImageData);
|
|
3195
|
+
}
|
|
3196
|
+
});
|
|
3197
|
+
}
|
|
3198
|
+
commitPaintBuffer(alpha = 255, blendFn = sourceOverPerfect, blendPixelDataFn = blendPixelData) {
|
|
3199
|
+
const paintBuffer = this.paintBuffer;
|
|
3200
|
+
const tileShift = paintBuffer.config.tileShift;
|
|
3201
|
+
const lookup = paintBuffer.lookup;
|
|
3202
|
+
const opts = this.blendPixelDataOpts;
|
|
3203
|
+
opts.alpha = alpha;
|
|
3204
|
+
opts.blendFn = blendFn;
|
|
3205
|
+
for (let i = 0; i < lookup.length; i++) {
|
|
3206
|
+
const tile = lookup[i];
|
|
3207
|
+
if (tile) {
|
|
3208
|
+
const didChange = this.accumulator.storeTileBeforeState(tile.id, tile.tx, tile.ty);
|
|
3209
|
+
const dx = tile.tx << tileShift;
|
|
3210
|
+
const dy = tile.ty << tileShift;
|
|
3211
|
+
opts.x = dx;
|
|
3212
|
+
opts.y = dy;
|
|
3213
|
+
opts.w = tile.width;
|
|
3214
|
+
opts.h = tile.height;
|
|
3215
|
+
didChange(blendPixelDataFn(this.config.target, tile, opts));
|
|
3216
|
+
}
|
|
3217
|
+
}
|
|
3218
|
+
paintBuffer.clear();
|
|
3219
|
+
}
|
|
3220
|
+
};
|
|
3669
3221
|
|
|
3670
|
-
// src/PixelData/
|
|
3671
|
-
|
|
3672
|
-
function fillPixelDataBinaryMask(dst, color, mask, alpha = 255, x = 0, y = 0) {
|
|
3673
|
-
if (alpha === 0) return false;
|
|
3674
|
-
const maskW = mask.w;
|
|
3675
|
-
const maskH = mask.h;
|
|
3676
|
-
const clip = resolveRectClipping(x, y, maskW, maskH, dst.width, dst.height, SCRATCH_RECT3);
|
|
3677
|
-
if (!clip.inBounds) return false;
|
|
3222
|
+
// src/PixelData/applyAlphaMaskToPixelData.ts
|
|
3223
|
+
function applyAlphaMaskToPixelData(dst, mask, opts = {}) {
|
|
3678
3224
|
const {
|
|
3679
|
-
x:
|
|
3680
|
-
y:
|
|
3681
|
-
w:
|
|
3682
|
-
h:
|
|
3683
|
-
|
|
3684
|
-
|
|
3225
|
+
x: targetX = 0,
|
|
3226
|
+
y: targetY = 0,
|
|
3227
|
+
w: width = dst.width,
|
|
3228
|
+
h: height = dst.height,
|
|
3229
|
+
alpha: globalAlpha = 255,
|
|
3230
|
+
mx = 0,
|
|
3231
|
+
my = 0,
|
|
3232
|
+
invertMask = false
|
|
3233
|
+
} = opts;
|
|
3234
|
+
if (globalAlpha === 0) return false;
|
|
3235
|
+
let x = targetX;
|
|
3236
|
+
let y = targetY;
|
|
3237
|
+
let w = width;
|
|
3238
|
+
let h = height;
|
|
3239
|
+
if (x < 0) {
|
|
3240
|
+
w += x;
|
|
3241
|
+
x = 0;
|
|
3242
|
+
}
|
|
3243
|
+
if (y < 0) {
|
|
3244
|
+
h += y;
|
|
3245
|
+
y = 0;
|
|
3246
|
+
}
|
|
3247
|
+
w = Math.min(w, dst.width - x);
|
|
3248
|
+
h = Math.min(h, dst.height - y);
|
|
3249
|
+
if (w <= 0) return false;
|
|
3250
|
+
if (h <= 0) return false;
|
|
3251
|
+
const mPitch = mask.w;
|
|
3252
|
+
if (mPitch <= 0) return false;
|
|
3253
|
+
const startX = mx + (x - targetX);
|
|
3254
|
+
const startY = my + (y - targetY);
|
|
3255
|
+
const sX0 = Math.max(0, startX);
|
|
3256
|
+
const sY0 = Math.max(0, startY);
|
|
3257
|
+
const sX1 = Math.min(mPitch, startX + w);
|
|
3258
|
+
const sY1 = Math.min(mask.h, startY + h);
|
|
3259
|
+
const finalW = sX1 - sX0;
|
|
3260
|
+
const finalH = sY1 - sY0;
|
|
3261
|
+
if (finalW <= 0) return false;
|
|
3262
|
+
if (finalH <= 0) return false;
|
|
3263
|
+
const xShift = sX0 - startX;
|
|
3264
|
+
const yShift = sY0 - startY;
|
|
3685
3265
|
const dst32 = dst.data32;
|
|
3686
3266
|
const dw = dst.width;
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3267
|
+
const dStride = dw - finalW;
|
|
3268
|
+
const mStride = mPitch - finalW;
|
|
3269
|
+
const maskData = mask.data;
|
|
3270
|
+
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
3271
|
+
let mIdx = sY0 * mPitch + sX0;
|
|
3272
|
+
let didChange = false;
|
|
3273
|
+
for (let iy = 0; iy < h; iy++) {
|
|
3274
|
+
for (let ix = 0; ix < w; ix++) {
|
|
3275
|
+
const mVal = maskData[mIdx];
|
|
3276
|
+
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
3277
|
+
let weight = 0;
|
|
3278
|
+
if (effectiveM === 0) {
|
|
3279
|
+
weight = 0;
|
|
3280
|
+
} else if (effectiveM === 255) {
|
|
3281
|
+
weight = globalAlpha;
|
|
3282
|
+
} else if (globalAlpha === 255) {
|
|
3283
|
+
weight = effectiveM;
|
|
3284
|
+
} else {
|
|
3285
|
+
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
3286
|
+
}
|
|
3287
|
+
if (weight === 0) {
|
|
3288
|
+
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
3289
|
+
didChange = true;
|
|
3290
|
+
} else if (weight !== 255) {
|
|
3291
|
+
const d = dst32[dIdx];
|
|
3292
|
+
const da = d >>> 24;
|
|
3293
|
+
if (da !== 0) {
|
|
3294
|
+
const finalAlpha = da === 255 ? weight : da * weight + 128 >> 8;
|
|
3295
|
+
const current = dst32[dIdx];
|
|
3296
|
+
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
3297
|
+
if (current !== next) {
|
|
3298
|
+
dst32[dIdx] = next;
|
|
3299
|
+
didChange = true;
|
|
3300
|
+
}
|
|
3709
3301
|
}
|
|
3710
3302
|
}
|
|
3303
|
+
dIdx++;
|
|
3304
|
+
mIdx++;
|
|
3711
3305
|
}
|
|
3306
|
+
dIdx += dStride;
|
|
3307
|
+
mIdx += mStride;
|
|
3712
3308
|
}
|
|
3713
|
-
return
|
|
3309
|
+
return didChange;
|
|
3714
3310
|
}
|
|
3715
3311
|
|
|
3716
|
-
// src/History/PixelMutator/
|
|
3717
|
-
var
|
|
3718
|
-
|
|
3312
|
+
// src/History/PixelMutator/mutatorApplyAlphaMask.ts
|
|
3313
|
+
var defaults11 = {
|
|
3314
|
+
applyAlphaMaskToPixelData
|
|
3719
3315
|
};
|
|
3720
|
-
var
|
|
3316
|
+
var mutatorApplyAlphaMask = ((writer, deps = defaults11) => {
|
|
3721
3317
|
const {
|
|
3722
|
-
|
|
3318
|
+
applyAlphaMaskToPixelData: applyAlphaMaskToPixelData2 = defaults11.applyAlphaMaskToPixelData
|
|
3723
3319
|
} = deps;
|
|
3724
3320
|
return {
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3321
|
+
applyAlphaMask(mask, opts = {}) {
|
|
3322
|
+
let target = writer.config.target;
|
|
3323
|
+
const {
|
|
3324
|
+
x = 0,
|
|
3325
|
+
y = 0,
|
|
3326
|
+
w = target.width,
|
|
3327
|
+
h = target.height
|
|
3328
|
+
} = opts;
|
|
3329
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3330
|
+
return didChange(applyAlphaMaskToPixelData2(target, mask, opts));
|
|
3728
3331
|
}
|
|
3729
3332
|
};
|
|
3730
3333
|
});
|
|
3731
3334
|
|
|
3732
|
-
// src/PixelData/
|
|
3733
|
-
|
|
3734
|
-
function invertPixelData(pixelData, opts = {}) {
|
|
3735
|
-
const dst = pixelData;
|
|
3335
|
+
// src/PixelData/applyBinaryMaskToPixelData.ts
|
|
3336
|
+
function applyBinaryMaskToPixelData(dst, mask, opts = {}) {
|
|
3736
3337
|
const {
|
|
3737
3338
|
x: targetX = 0,
|
|
3738
3339
|
y: targetY = 0,
|
|
3739
|
-
w: width =
|
|
3740
|
-
h: height =
|
|
3741
|
-
|
|
3340
|
+
w: width = dst.width,
|
|
3341
|
+
h: height = dst.height,
|
|
3342
|
+
alpha: globalAlpha = 255,
|
|
3742
3343
|
mx = 0,
|
|
3743
3344
|
my = 0,
|
|
3744
3345
|
invertMask = false
|
|
3745
3346
|
} = opts;
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3347
|
+
if (globalAlpha === 0) return false;
|
|
3348
|
+
let x = targetX;
|
|
3349
|
+
let y = targetY;
|
|
3350
|
+
let w = width;
|
|
3351
|
+
let h = height;
|
|
3352
|
+
if (x < 0) {
|
|
3353
|
+
w += x;
|
|
3354
|
+
x = 0;
|
|
3355
|
+
}
|
|
3356
|
+
if (y < 0) {
|
|
3357
|
+
h += y;
|
|
3358
|
+
y = 0;
|
|
3359
|
+
}
|
|
3360
|
+
w = Math.min(w, dst.width - x);
|
|
3361
|
+
h = Math.min(h, dst.height - y);
|
|
3362
|
+
if (w <= 0 || h <= 0) return false;
|
|
3363
|
+
const mPitch = mask.w;
|
|
3364
|
+
if (mPitch <= 0) return false;
|
|
3365
|
+
const startX = mx + (x - targetX);
|
|
3366
|
+
const startY = my + (y - targetY);
|
|
3367
|
+
const sX0 = Math.max(0, startX);
|
|
3368
|
+
const sY0 = Math.max(0, startY);
|
|
3369
|
+
const sX1 = Math.min(mPitch, startX + w);
|
|
3370
|
+
const sY1 = Math.min(mask.h, startY + h);
|
|
3371
|
+
const finalW = sX1 - sX0;
|
|
3372
|
+
const finalH = sY1 - sY0;
|
|
3373
|
+
if (finalW <= 0 || finalH <= 0) {
|
|
3374
|
+
return false;
|
|
3375
|
+
}
|
|
3376
|
+
const xShift = sX0 - startX;
|
|
3377
|
+
const yShift = sY0 - startY;
|
|
3754
3378
|
const dst32 = dst.data32;
|
|
3755
3379
|
const dw = dst.width;
|
|
3756
|
-
const
|
|
3757
|
-
const
|
|
3758
|
-
const
|
|
3759
|
-
let dIdx = y * dw + x;
|
|
3760
|
-
let mIdx =
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
const
|
|
3768
|
-
const
|
|
3769
|
-
if (
|
|
3770
|
-
dst32[dIdx] =
|
|
3380
|
+
const dStride = dw - finalW;
|
|
3381
|
+
const mStride = mPitch - finalW;
|
|
3382
|
+
const maskData = mask.data;
|
|
3383
|
+
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
3384
|
+
let mIdx = sY0 * mPitch + sX0;
|
|
3385
|
+
let didChange = false;
|
|
3386
|
+
for (let iy = 0; iy < finalH; iy++) {
|
|
3387
|
+
for (let ix = 0; ix < finalW; ix++) {
|
|
3388
|
+
const mVal = maskData[mIdx];
|
|
3389
|
+
const isMaskedOut = invertMask ? mVal !== 0 : mVal === 0;
|
|
3390
|
+
if (isMaskedOut) {
|
|
3391
|
+
const current = dst32[dIdx];
|
|
3392
|
+
const next = (current & 16777215) >>> 0;
|
|
3393
|
+
if (current !== next) {
|
|
3394
|
+
dst32[dIdx] = next;
|
|
3395
|
+
didChange = true;
|
|
3396
|
+
}
|
|
3397
|
+
} else if (globalAlpha !== 255) {
|
|
3398
|
+
const d = dst32[dIdx];
|
|
3399
|
+
const da = d >>> 24;
|
|
3400
|
+
if (da !== 0) {
|
|
3401
|
+
const finalAlpha = da === 255 ? globalAlpha : da * globalAlpha + 128 >> 8;
|
|
3402
|
+
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
3403
|
+
if (d !== next) {
|
|
3404
|
+
dst32[dIdx] = next;
|
|
3405
|
+
didChange = true;
|
|
3406
|
+
}
|
|
3771
3407
|
}
|
|
3772
|
-
dIdx++;
|
|
3773
|
-
mIdx++;
|
|
3774
|
-
}
|
|
3775
|
-
dIdx += dStride;
|
|
3776
|
-
mIdx += mStride;
|
|
3777
|
-
}
|
|
3778
|
-
} else {
|
|
3779
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
3780
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
3781
|
-
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
3782
|
-
dIdx++;
|
|
3783
3408
|
}
|
|
3784
|
-
dIdx
|
|
3409
|
+
dIdx++;
|
|
3410
|
+
mIdx++;
|
|
3785
3411
|
}
|
|
3412
|
+
dIdx += dStride;
|
|
3413
|
+
mIdx += mStride;
|
|
3786
3414
|
}
|
|
3787
|
-
return
|
|
3415
|
+
return didChange;
|
|
3788
3416
|
}
|
|
3789
3417
|
|
|
3790
|
-
// src/History/PixelMutator/
|
|
3791
|
-
var
|
|
3792
|
-
|
|
3418
|
+
// src/History/PixelMutator/mutatorApplyBinaryMask.ts
|
|
3419
|
+
var defaults12 = {
|
|
3420
|
+
applyBinaryMaskToPixelData
|
|
3793
3421
|
};
|
|
3794
|
-
var
|
|
3422
|
+
var mutatorApplyBinaryMask = ((writer, deps = defaults12) => {
|
|
3795
3423
|
const {
|
|
3796
|
-
|
|
3424
|
+
applyBinaryMaskToPixelData: applyBinaryMaskToPixelData2 = defaults12.applyBinaryMaskToPixelData
|
|
3797
3425
|
} = deps;
|
|
3798
3426
|
return {
|
|
3799
|
-
|
|
3800
|
-
|
|
3427
|
+
applyBinaryMask(mask, opts = {}) {
|
|
3428
|
+
let target = writer.config.target;
|
|
3801
3429
|
const {
|
|
3802
3430
|
x = 0,
|
|
3803
3431
|
y = 0,
|
|
@@ -3805,125 +3433,200 @@ var mutatorInvert = ((writer, deps = defaults20) => {
|
|
|
3805
3433
|
h = target.height
|
|
3806
3434
|
} = opts;
|
|
3807
3435
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3808
|
-
return didChange(
|
|
3436
|
+
return didChange(applyBinaryMaskToPixelData2(target, mask, opts));
|
|
3809
3437
|
}
|
|
3810
3438
|
};
|
|
3811
3439
|
});
|
|
3812
3440
|
|
|
3813
|
-
// src/
|
|
3814
|
-
function
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
...mutatorFillRect(writer),
|
|
3836
|
-
...mutatorInvert(writer)
|
|
3837
|
-
};
|
|
3838
|
-
}
|
|
3839
|
-
|
|
3840
|
-
// src/PixelTile/PixelTile.ts
|
|
3841
|
-
var PixelTile = class {
|
|
3842
|
-
constructor(id, tx, ty, tileSize, tileArea) {
|
|
3843
|
-
this.id = id;
|
|
3844
|
-
this.tx = tx;
|
|
3845
|
-
this.ty = ty;
|
|
3846
|
-
this.width = this.height = tileSize;
|
|
3847
|
-
this.data32 = new Uint32Array(tileArea);
|
|
3848
|
-
const data8 = new Uint8ClampedArray(this.data32.buffer);
|
|
3849
|
-
this.imageData = new ImageData(data8, tileSize, tileSize);
|
|
3441
|
+
// src/PixelData/blendColorPixelDataAlphaMask.ts
|
|
3442
|
+
function blendColorPixelDataAlphaMask(dst, color, mask, opts = {}) {
|
|
3443
|
+
const targetX = opts.x ?? 0;
|
|
3444
|
+
const targetY = opts.y ?? 0;
|
|
3445
|
+
const w = opts.w ?? mask.w;
|
|
3446
|
+
const h = opts.h ?? mask.h;
|
|
3447
|
+
const globalAlpha = opts.alpha ?? 255;
|
|
3448
|
+
const blendFn = opts.blendFn ?? sourceOverPerfect;
|
|
3449
|
+
const mx = opts.mx ?? 0;
|
|
3450
|
+
const my = opts.my ?? 0;
|
|
3451
|
+
const invertMask = opts.invertMask ?? false;
|
|
3452
|
+
if (globalAlpha === 0) return false;
|
|
3453
|
+
const baseSrcAlpha = color >>> 24;
|
|
3454
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
3455
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
3456
|
+
let x = targetX;
|
|
3457
|
+
let y = targetY;
|
|
3458
|
+
let actualW = w;
|
|
3459
|
+
let actualH = h;
|
|
3460
|
+
if (x < 0) {
|
|
3461
|
+
actualW += x;
|
|
3462
|
+
x = 0;
|
|
3850
3463
|
}
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
imageData;
|
|
3855
|
-
};
|
|
3856
|
-
|
|
3857
|
-
// src/PixelTile/PixelTilePool.ts
|
|
3858
|
-
var PixelTilePool = class {
|
|
3859
|
-
pool;
|
|
3860
|
-
tileSize;
|
|
3861
|
-
tileArea;
|
|
3862
|
-
constructor(config) {
|
|
3863
|
-
this.pool = [];
|
|
3864
|
-
this.tileSize = config.tileSize;
|
|
3865
|
-
this.tileArea = config.tileArea;
|
|
3464
|
+
if (y < 0) {
|
|
3465
|
+
actualH += y;
|
|
3466
|
+
y = 0;
|
|
3866
3467
|
}
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3468
|
+
actualW = Math.min(actualW, dst.width - x);
|
|
3469
|
+
actualH = Math.min(actualH, dst.height - y);
|
|
3470
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
3471
|
+
const dx = x - targetX | 0;
|
|
3472
|
+
const dy = y - targetY | 0;
|
|
3473
|
+
const dst32 = dst.data32;
|
|
3474
|
+
const dw = dst.width;
|
|
3475
|
+
const mPitch = mask.w;
|
|
3476
|
+
const maskData = mask.data;
|
|
3477
|
+
let dIdx = y * dw + x | 0;
|
|
3478
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
3479
|
+
const dStride = dw - actualW | 0;
|
|
3480
|
+
const mStride = mPitch - actualW | 0;
|
|
3481
|
+
const isOpaque = globalAlpha === 255;
|
|
3482
|
+
const colorRGB = color & 16777215;
|
|
3483
|
+
let didChange = false;
|
|
3484
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
3485
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
3486
|
+
const mVal = maskData[mIdx];
|
|
3487
|
+
const effM = invertMask ? 255 - mVal : mVal;
|
|
3488
|
+
if (effM === 0) {
|
|
3489
|
+
dIdx++;
|
|
3490
|
+
mIdx++;
|
|
3491
|
+
continue;
|
|
3492
|
+
}
|
|
3493
|
+
let weight = globalAlpha;
|
|
3494
|
+
if (isOpaque) {
|
|
3495
|
+
weight = effM;
|
|
3496
|
+
} else if (effM !== 255) {
|
|
3497
|
+
weight = effM * globalAlpha + 128 >> 8;
|
|
3498
|
+
}
|
|
3499
|
+
if (weight === 0) {
|
|
3500
|
+
dIdx++;
|
|
3501
|
+
mIdx++;
|
|
3502
|
+
continue;
|
|
3503
|
+
}
|
|
3504
|
+
let finalCol = color;
|
|
3505
|
+
if (weight < 255) {
|
|
3506
|
+
const a = baseSrcAlpha * weight + 128 >> 8;
|
|
3507
|
+
if (a === 0 && !isOverwrite) {
|
|
3508
|
+
dIdx++;
|
|
3509
|
+
mIdx++;
|
|
3510
|
+
continue;
|
|
3511
|
+
}
|
|
3512
|
+
finalCol = (colorRGB | a << 24) >>> 0;
|
|
3513
|
+
}
|
|
3514
|
+
const current = dst32[dIdx];
|
|
3515
|
+
const next = blendFn(finalCol, current);
|
|
3516
|
+
if (current !== next) {
|
|
3517
|
+
dst32[dIdx] = next;
|
|
3518
|
+
didChange = true;
|
|
3519
|
+
}
|
|
3520
|
+
dIdx++;
|
|
3521
|
+
mIdx++;
|
|
3875
3522
|
}
|
|
3876
|
-
|
|
3523
|
+
dIdx += dStride;
|
|
3524
|
+
mIdx += mStride;
|
|
3877
3525
|
}
|
|
3878
|
-
|
|
3879
|
-
|
|
3526
|
+
return didChange;
|
|
3527
|
+
}
|
|
3528
|
+
|
|
3529
|
+
// src/PixelData/blendColorPixelDataBinaryMask.ts
|
|
3530
|
+
function blendColorPixelDataBinaryMask(dst, color, mask, opts = {}) {
|
|
3531
|
+
const targetX = opts.x ?? 0;
|
|
3532
|
+
const targetY = opts.y ?? 0;
|
|
3533
|
+
let w = opts.w ?? mask.w;
|
|
3534
|
+
let h = opts.h ?? mask.h;
|
|
3535
|
+
const globalAlpha = opts.alpha ?? 255;
|
|
3536
|
+
const blendFn = opts.blendFn ?? sourceOverPerfect;
|
|
3537
|
+
const mx = opts.mx ?? 0;
|
|
3538
|
+
const my = opts.my ?? 0;
|
|
3539
|
+
const invertMask = opts.invertMask ?? false;
|
|
3540
|
+
if (globalAlpha === 0) return false;
|
|
3541
|
+
const baseSrcAlpha = color >>> 24;
|
|
3542
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
3543
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
3544
|
+
let x = targetX;
|
|
3545
|
+
let y = targetY;
|
|
3546
|
+
if (x < 0) {
|
|
3547
|
+
w += x;
|
|
3548
|
+
x = 0;
|
|
3549
|
+
}
|
|
3550
|
+
if (y < 0) {
|
|
3551
|
+
h += y;
|
|
3552
|
+
y = 0;
|
|
3553
|
+
}
|
|
3554
|
+
const actualW = Math.min(w, dst.width - x);
|
|
3555
|
+
const actualH = Math.min(h, dst.height - y);
|
|
3556
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
3557
|
+
let baseColorWithGlobalAlpha = color;
|
|
3558
|
+
if (globalAlpha < 255) {
|
|
3559
|
+
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
3560
|
+
if (a === 0 && !isOverwrite) return false;
|
|
3561
|
+
baseColorWithGlobalAlpha = (color & 16777215 | a << 24) >>> 0;
|
|
3880
3562
|
}
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3563
|
+
const dx = x - targetX | 0;
|
|
3564
|
+
const dy = y - targetY | 0;
|
|
3565
|
+
const dst32 = dst.data32;
|
|
3566
|
+
const dw = dst.width;
|
|
3567
|
+
const mPitch = mask.w;
|
|
3568
|
+
const maskData = mask.data;
|
|
3569
|
+
let dIdx = y * dw + x | 0;
|
|
3570
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
3571
|
+
const dStride = dw - actualW | 0;
|
|
3572
|
+
const mStride = mPitch - actualW | 0;
|
|
3573
|
+
const skipVal = invertMask ? 1 : 0;
|
|
3574
|
+
let didChange = false;
|
|
3575
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
3576
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
3577
|
+
if (maskData[mIdx] === skipVal) {
|
|
3578
|
+
dIdx++;
|
|
3579
|
+
mIdx++;
|
|
3580
|
+
continue;
|
|
3581
|
+
}
|
|
3582
|
+
const current = dst32[dIdx];
|
|
3583
|
+
const next = blendFn(baseColorWithGlobalAlpha, current);
|
|
3584
|
+
if (current !== next) {
|
|
3585
|
+
dst32[dIdx] = next;
|
|
3586
|
+
didChange = true;
|
|
3887
3587
|
}
|
|
3588
|
+
dIdx++;
|
|
3589
|
+
mIdx++;
|
|
3888
3590
|
}
|
|
3889
|
-
|
|
3591
|
+
dIdx += dStride;
|
|
3592
|
+
mIdx += mStride;
|
|
3890
3593
|
}
|
|
3891
|
-
|
|
3594
|
+
return didChange;
|
|
3595
|
+
}
|
|
3892
3596
|
|
|
3893
|
-
// src/History/
|
|
3894
|
-
var
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
historyActionFactory;
|
|
3898
|
-
config;
|
|
3899
|
-
mutator;
|
|
3900
|
-
constructor(target, mutatorFactory, {
|
|
3901
|
-
tileSize = 256,
|
|
3902
|
-
maxHistorySteps = 50,
|
|
3903
|
-
historyManager = new HistoryManager(maxHistorySteps),
|
|
3904
|
-
historyActionFactory = makeHistoryAction,
|
|
3905
|
-
pixelTilePool
|
|
3906
|
-
} = {}) {
|
|
3907
|
-
this.config = new PixelEngineConfig(tileSize, target);
|
|
3908
|
-
this.historyManager = historyManager;
|
|
3909
|
-
pixelTilePool ??= new PixelTilePool(this.config);
|
|
3910
|
-
this.accumulator = new PixelAccumulator(this.config, pixelTilePool);
|
|
3911
|
-
this.historyActionFactory = historyActionFactory;
|
|
3912
|
-
this.mutator = mutatorFactory(this);
|
|
3913
|
-
}
|
|
3914
|
-
withHistory(cb, after, afterUndo, afterRedo) {
|
|
3915
|
-
try {
|
|
3916
|
-
cb(this.mutator);
|
|
3917
|
-
} catch (e) {
|
|
3918
|
-
this.accumulator.rollback();
|
|
3919
|
-
throw e;
|
|
3920
|
-
}
|
|
3921
|
-
if (this.accumulator.beforeTiles.length === 0) return;
|
|
3922
|
-
const patch = this.accumulator.extractPatch();
|
|
3923
|
-
const action = this.historyActionFactory(this, patch, after, afterUndo, afterRedo);
|
|
3924
|
-
this.historyManager.commit(action);
|
|
3925
|
-
}
|
|
3597
|
+
// src/History/PixelMutator/mutatorBlendPaintMask.ts
|
|
3598
|
+
var defaults13 = {
|
|
3599
|
+
blendColorPixelDataAlphaMask,
|
|
3600
|
+
blendColorPixelDataBinaryMask
|
|
3926
3601
|
};
|
|
3602
|
+
var mutatorBlendPaintMask = ((writer, deps = defaults13) => {
|
|
3603
|
+
const {
|
|
3604
|
+
blendColorPixelDataBinaryMask: blendColorPixelDataBinaryMask2 = defaults13.blendColorPixelDataBinaryMask,
|
|
3605
|
+
blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults13.blendColorPixelDataAlphaMask
|
|
3606
|
+
} = deps;
|
|
3607
|
+
const OPTS = {
|
|
3608
|
+
x: 0,
|
|
3609
|
+
y: 0,
|
|
3610
|
+
blendFn: sourceOverPerfect,
|
|
3611
|
+
alpha: 255
|
|
3612
|
+
};
|
|
3613
|
+
return {
|
|
3614
|
+
blendColorPaintMask(color, mask, x, y, alpha = 255, blendFn = sourceOverPerfect) {
|
|
3615
|
+
const tx = x + mask.centerOffsetX;
|
|
3616
|
+
const ty = y + mask.centerOffsetY;
|
|
3617
|
+
const didChange = writer.accumulator.storeRegionBeforeState(tx, ty, mask.w, mask.h);
|
|
3618
|
+
OPTS.x = tx;
|
|
3619
|
+
OPTS.y = ty;
|
|
3620
|
+
OPTS.alpha = alpha;
|
|
3621
|
+
OPTS.blendFn = blendFn;
|
|
3622
|
+
if (mask.type === 1 /* BINARY */) {
|
|
3623
|
+
return didChange(blendColorPixelDataBinaryMask2(writer.config.target, color, mask, OPTS));
|
|
3624
|
+
} else {
|
|
3625
|
+
return didChange(blendColorPixelDataAlphaMask2(writer.config.target, color, mask, OPTS));
|
|
3626
|
+
}
|
|
3627
|
+
}
|
|
3628
|
+
};
|
|
3629
|
+
});
|
|
3927
3630
|
|
|
3928
3631
|
// src/ImageData/copyImageData.ts
|
|
3929
3632
|
function copyImageData({
|
|
@@ -4046,35 +3749,6 @@ function resampleImageData(source, factor) {
|
|
|
4046
3749
|
return new ImageData(uint8ClampedArray, width, height);
|
|
4047
3750
|
}
|
|
4048
3751
|
|
|
4049
|
-
// src/ImageData/resizeImageData.ts
|
|
4050
|
-
function resizeImageData(target, newWidth, newHeight, offsetX = 0, offsetY = 0) {
|
|
4051
|
-
const result = new ImageData(newWidth, newHeight);
|
|
4052
|
-
const {
|
|
4053
|
-
width: oldW,
|
|
4054
|
-
height: oldH,
|
|
4055
|
-
data: oldData
|
|
4056
|
-
} = target;
|
|
4057
|
-
const newData = result.data;
|
|
4058
|
-
const x0 = Math.max(0, offsetX);
|
|
4059
|
-
const y0 = Math.max(0, offsetY);
|
|
4060
|
-
const x1 = Math.min(newWidth, offsetX + oldW);
|
|
4061
|
-
const y1 = Math.min(newHeight, offsetY + oldH);
|
|
4062
|
-
if (x1 <= x0 || y1 <= y0) {
|
|
4063
|
-
return result;
|
|
4064
|
-
}
|
|
4065
|
-
const rowCount = y1 - y0;
|
|
4066
|
-
const rowLen = (x1 - x0) * 4;
|
|
4067
|
-
for (let row = 0; row < rowCount; row++) {
|
|
4068
|
-
const dstY = y0 + row;
|
|
4069
|
-
const srcY = dstY - offsetY;
|
|
4070
|
-
const srcX = x0 - offsetX;
|
|
4071
|
-
const dstStart = (dstY * newWidth + x0) * 4;
|
|
4072
|
-
const srcStart = (srcY * oldW + srcX) * 4;
|
|
4073
|
-
newData.set(oldData.subarray(srcStart, srcStart + rowLen), dstStart);
|
|
4074
|
-
}
|
|
4075
|
-
return result;
|
|
4076
|
-
}
|
|
4077
|
-
|
|
4078
3752
|
// src/ImageData/ReusableImageData.ts
|
|
4079
3753
|
function makeReusableImageData() {
|
|
4080
3754
|
let imageData = null;
|
|
@@ -4489,62 +4163,6 @@ function makeBinaryMask(w, h, data) {
|
|
|
4489
4163
|
};
|
|
4490
4164
|
}
|
|
4491
4165
|
|
|
4492
|
-
// src/Mask/CircleAlphaMask.ts
|
|
4493
|
-
function makeCircleAlphaMask(size, fallOff = () => 1) {
|
|
4494
|
-
const area = size * size;
|
|
4495
|
-
const data = new Uint8Array(area);
|
|
4496
|
-
const radius = size / 2;
|
|
4497
|
-
const invR = 1 / radius;
|
|
4498
|
-
const minOffset = -Math.ceil(radius - 0.5);
|
|
4499
|
-
for (let y = 0; y < size; y++) {
|
|
4500
|
-
for (let x = 0; x < size; x++) {
|
|
4501
|
-
const dx = x - radius + 0.5;
|
|
4502
|
-
const dy = y - radius + 0.5;
|
|
4503
|
-
const distSqr = dx * dx + dy * dy;
|
|
4504
|
-
if (distSqr <= radius * radius) {
|
|
4505
|
-
const dist = Math.sqrt(distSqr);
|
|
4506
|
-
data[y * size + x] = fallOff(1 - dist * invR) * 255 | 0;
|
|
4507
|
-
}
|
|
4508
|
-
}
|
|
4509
|
-
}
|
|
4510
|
-
return {
|
|
4511
|
-
type: 0 /* ALPHA */,
|
|
4512
|
-
data,
|
|
4513
|
-
w: size,
|
|
4514
|
-
h: size,
|
|
4515
|
-
radius,
|
|
4516
|
-
size,
|
|
4517
|
-
minOffset
|
|
4518
|
-
};
|
|
4519
|
-
}
|
|
4520
|
-
|
|
4521
|
-
// src/Mask/CircleBinaryMask.ts
|
|
4522
|
-
function makeCircleBinaryMask(size) {
|
|
4523
|
-
const area = size * size;
|
|
4524
|
-
const data = new Uint8Array(area);
|
|
4525
|
-
const radius = size / 2;
|
|
4526
|
-
const minOffset = -Math.ceil(radius - 0.5);
|
|
4527
|
-
for (let y = 0; y < size; y++) {
|
|
4528
|
-
for (let x = 0; x < size; x++) {
|
|
4529
|
-
const dx = x - radius + 0.5;
|
|
4530
|
-
const dy = y - radius + 0.5;
|
|
4531
|
-
const distSqr = dx * dx + dy * dy;
|
|
4532
|
-
if (distSqr <= radius * radius) {
|
|
4533
|
-
data[y * size + x] = 1;
|
|
4534
|
-
}
|
|
4535
|
-
}
|
|
4536
|
-
}
|
|
4537
|
-
return {
|
|
4538
|
-
type: 1 /* BINARY */,
|
|
4539
|
-
data,
|
|
4540
|
-
w: size,
|
|
4541
|
-
h: size,
|
|
4542
|
-
radius,
|
|
4543
|
-
size,
|
|
4544
|
-
minOffset
|
|
4545
|
-
};
|
|
4546
|
-
}
|
|
4547
|
-
|
|
4548
4166
|
// src/Mask/applyBinaryMaskToAlphaMask.ts
|
|
4549
4167
|
function applyBinaryMaskToAlphaMask(alphaMaskDst, binaryMaskSrc, opts = {}) {
|
|
4550
4168
|
const {
|
|
@@ -5245,103 +4863,137 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
5245
4863
|
}
|
|
5246
4864
|
}
|
|
5247
4865
|
|
|
5248
|
-
// src/
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
4866
|
+
// src/PixelData/writePaintBufferToPixelData.ts
|
|
4867
|
+
function writePaintBufferToPixelData(target, paintBuffer, writePixelDataBufferFn = writePixelDataBuffer) {
|
|
4868
|
+
const tileShift = paintBuffer.config.tileShift;
|
|
4869
|
+
const lookup = paintBuffer.lookup;
|
|
4870
|
+
for (let i = 0; i < lookup.length; i++) {
|
|
4871
|
+
const tile = lookup[i];
|
|
4872
|
+
if (tile) {
|
|
4873
|
+
const dx = tile.tx << tileShift;
|
|
4874
|
+
const dy = tile.ty << tileShift;
|
|
4875
|
+
writePixelDataBufferFn(target, tile.data32, dx, dy, tile.width, tile.height);
|
|
4876
|
+
}
|
|
5254
4877
|
}
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
|
|
5268
|
-
|
|
5269
|
-
|
|
5270
|
-
|
|
5271
|
-
|
|
5272
|
-
|
|
5273
|
-
|
|
4878
|
+
}
|
|
4879
|
+
|
|
4880
|
+
// src/Paint/makeCirclePaintAlphaMask.ts
|
|
4881
|
+
function makeCirclePaintAlphaMask(size, fallOff = (d) => d) {
|
|
4882
|
+
const area = size * size;
|
|
4883
|
+
const data = new Uint8Array(area);
|
|
4884
|
+
const radius = size / 2;
|
|
4885
|
+
const invR = 1 / radius;
|
|
4886
|
+
const centerOffset = -Math.ceil(radius - 0.5);
|
|
4887
|
+
for (let y = 0; y < size; y++) {
|
|
4888
|
+
const rowOffset = y * size;
|
|
4889
|
+
const dy = y - radius + 0.5;
|
|
4890
|
+
const dy2 = dy * dy;
|
|
4891
|
+
for (let x = 0; x < size; x++) {
|
|
4892
|
+
const dx = x - radius + 0.5;
|
|
4893
|
+
const distSqr = dx * dx + dy2;
|
|
4894
|
+
if (distSqr <= radius * radius) {
|
|
4895
|
+
const dist = Math.sqrt(distSqr) * invR;
|
|
4896
|
+
const strength = fallOff(1 - dist);
|
|
4897
|
+
if (strength > 0) {
|
|
4898
|
+
const intensity = strength * 255 | 0;
|
|
4899
|
+
data[rowOffset + x] = Math.max(0, Math.min(255, intensity));
|
|
5274
4900
|
}
|
|
5275
|
-
const tileLeft = tx << tileShift;
|
|
5276
|
-
const startX = Math.max(mask.x, tileLeft);
|
|
5277
|
-
const endX = Math.min(mask.x + mask.w, tileLeft + this.config.tileSize);
|
|
5278
|
-
const startY = Math.max(mask.y, tileTop);
|
|
5279
|
-
const endY = Math.min(mask.y + mask.h, tileTop + this.config.tileSize);
|
|
5280
|
-
callback(tile, startX, startY, endX - startX, endY - startY, startX - mask.x, startY - mask.y);
|
|
5281
4901
|
}
|
|
5282
4902
|
}
|
|
5283
4903
|
}
|
|
5284
|
-
|
|
5285
|
-
|
|
5286
|
-
|
|
5287
|
-
|
|
5288
|
-
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
|
|
5295
|
-
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
4904
|
+
return {
|
|
4905
|
+
type: 0 /* ALPHA */,
|
|
4906
|
+
data,
|
|
4907
|
+
w: size,
|
|
4908
|
+
h: size,
|
|
4909
|
+
centerOffsetX: centerOffset,
|
|
4910
|
+
centerOffsetY: centerOffset
|
|
4911
|
+
};
|
|
4912
|
+
}
|
|
4913
|
+
|
|
4914
|
+
// src/Paint/makeCirclePaintBinaryMask.ts
|
|
4915
|
+
function makeCirclePaintBinaryMask(size) {
|
|
4916
|
+
const area = size * size;
|
|
4917
|
+
const data = new Uint8Array(area);
|
|
4918
|
+
const radius = size / 2;
|
|
4919
|
+
const centerOffset = -Math.ceil(radius - 0.5);
|
|
4920
|
+
for (let y = 0; y < size; y++) {
|
|
4921
|
+
for (let x = 0; x < size; x++) {
|
|
4922
|
+
const dx = x - radius + 0.5;
|
|
4923
|
+
const dy = y - radius + 0.5;
|
|
4924
|
+
const distSqr = dx * dx + dy * dy;
|
|
4925
|
+
if (distSqr <= radius * radius) {
|
|
4926
|
+
data[y * size + x] = 1;
|
|
5306
4927
|
}
|
|
5307
|
-
}
|
|
4928
|
+
}
|
|
5308
4929
|
}
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
4930
|
+
return {
|
|
4931
|
+
type: 1 /* BINARY */,
|
|
4932
|
+
data,
|
|
4933
|
+
w: size,
|
|
4934
|
+
h: size,
|
|
4935
|
+
centerOffsetX: centerOffset,
|
|
4936
|
+
centerOffsetY: centerOffset
|
|
4937
|
+
};
|
|
4938
|
+
}
|
|
4939
|
+
|
|
4940
|
+
// src/Paint/makePaintMask.ts
|
|
4941
|
+
function makePaintBinaryMask(mask) {
|
|
4942
|
+
return {
|
|
4943
|
+
type: 1 /* BINARY */,
|
|
4944
|
+
data: mask.data,
|
|
4945
|
+
w: mask.w,
|
|
4946
|
+
h: mask.h,
|
|
4947
|
+
centerOffsetX: -(mask.w >> 1),
|
|
4948
|
+
centerOffsetY: -(mask.h >> 1)
|
|
4949
|
+
};
|
|
4950
|
+
}
|
|
4951
|
+
function makePaintAlphaMask(mask) {
|
|
4952
|
+
return {
|
|
4953
|
+
type: 0 /* ALPHA */,
|
|
4954
|
+
data: mask.data,
|
|
4955
|
+
w: mask.w,
|
|
4956
|
+
h: mask.h,
|
|
4957
|
+
centerOffsetX: -(mask.w >> 1),
|
|
4958
|
+
centerOffsetY: -(mask.h >> 1)
|
|
4959
|
+
};
|
|
4960
|
+
}
|
|
4961
|
+
|
|
4962
|
+
// src/Paint/makeRectFalloffPaintAlphaMask.ts
|
|
4963
|
+
function makeRectFalloffPaintAlphaMask(width, height, fallOff = (d) => d) {
|
|
4964
|
+
const fPx = Math.floor(width / 2);
|
|
4965
|
+
const fPy = Math.floor(height / 2);
|
|
4966
|
+
const invHalfW = 2 / width;
|
|
4967
|
+
const invHalfH = 2 / height;
|
|
4968
|
+
const offX = width % 2 === 0 ? 0.5 : 0;
|
|
4969
|
+
const offY = height % 2 === 0 ? 0.5 : 0;
|
|
4970
|
+
const area = width * height;
|
|
4971
|
+
const data = new Uint8Array(area);
|
|
4972
|
+
for (let y = 0; y < height; y++) {
|
|
4973
|
+
const dy = Math.abs(y - fPy + offY) * invHalfH;
|
|
4974
|
+
const rowOffset = y * width;
|
|
4975
|
+
for (let x = 0; x < width; x++) {
|
|
4976
|
+
const dx = Math.abs(x - fPx + offX) * invHalfW;
|
|
4977
|
+
const dist = dx > dy ? dx : dy;
|
|
4978
|
+
const strength = fallOff(1 - dist);
|
|
4979
|
+
if (strength > 0) {
|
|
4980
|
+
const intensity = strength * 255 | 0;
|
|
4981
|
+
data[rowOffset + x] = Math.max(0, Math.min(255, intensity));
|
|
5335
4982
|
}
|
|
5336
|
-
}
|
|
5337
|
-
}
|
|
5338
|
-
clear() {
|
|
5339
|
-
this.tilePool.releaseTiles(this.lookup);
|
|
4983
|
+
}
|
|
5340
4984
|
}
|
|
5341
|
-
|
|
4985
|
+
return {
|
|
4986
|
+
type: 0 /* ALPHA */,
|
|
4987
|
+
data,
|
|
4988
|
+
w: width,
|
|
4989
|
+
h: height,
|
|
4990
|
+
centerOffsetX: -macro_halfAndFloor(width),
|
|
4991
|
+
centerOffsetY: -macro_halfAndFloor(height)
|
|
4992
|
+
};
|
|
4993
|
+
}
|
|
5342
4994
|
|
|
5343
|
-
// src/
|
|
5344
|
-
function
|
|
4995
|
+
// src/Paint/PaintBufferCanvasRenderer.ts
|
|
4996
|
+
function makePaintBufferCanvasRenderer(paintBuffer, offscreenCanvasClass = OffscreenCanvas) {
|
|
5345
4997
|
const config = paintBuffer.config;
|
|
5346
4998
|
const tileSize = config.tileSize;
|
|
5347
4999
|
const tileShift = config.tileShift;
|
|
@@ -5350,22 +5002,27 @@ function makePaintBufferRenderer(paintBuffer, offscreenCanvasClass = OffscreenCa
|
|
|
5350
5002
|
const ctx = canvas.getContext("2d");
|
|
5351
5003
|
if (!ctx) throw new Error(CANVAS_CTX_FAILED);
|
|
5352
5004
|
ctx.imageSmoothingEnabled = false;
|
|
5353
|
-
return function drawPaintBuffer(
|
|
5005
|
+
return function drawPaintBuffer(targetCtx, alpha = 255, compOperation = "source-over") {
|
|
5006
|
+
targetCtx.globalAlpha = alpha / 255;
|
|
5007
|
+
targetCtx.globalCompositeOperation = compOperation;
|
|
5354
5008
|
for (let i = 0; i < lookup.length; i++) {
|
|
5355
5009
|
const tile = lookup[i];
|
|
5356
5010
|
if (tile) {
|
|
5357
5011
|
const dx = tile.tx << tileShift;
|
|
5358
5012
|
const dy = tile.ty << tileShift;
|
|
5359
5013
|
ctx.putImageData(tile.imageData, 0, 0);
|
|
5360
|
-
|
|
5014
|
+
targetCtx.drawImage(canvas, dx, dy);
|
|
5361
5015
|
}
|
|
5362
5016
|
}
|
|
5017
|
+
targetCtx.globalAlpha = 1;
|
|
5018
|
+
targetCtx.globalCompositeOperation = "source-over";
|
|
5363
5019
|
};
|
|
5364
5020
|
}
|
|
5365
5021
|
export {
|
|
5366
5022
|
BASE_FAST_BLEND_MODE_FUNCTIONS,
|
|
5367
5023
|
BASE_PERFECT_BLEND_MODE_FUNCTIONS,
|
|
5368
5024
|
BaseBlendMode,
|
|
5025
|
+
CANVAS_COMPOSITE_MAP,
|
|
5369
5026
|
CANVAS_CTX_FAILED,
|
|
5370
5027
|
HistoryManager,
|
|
5371
5028
|
IndexedImage,
|
|
@@ -5384,13 +5041,11 @@ export {
|
|
|
5384
5041
|
applyBinaryMaskToAlphaMask,
|
|
5385
5042
|
applyBinaryMaskToPixelData,
|
|
5386
5043
|
applyPatchTiles,
|
|
5387
|
-
applyRectBrushToPixelData,
|
|
5388
5044
|
base64DecodeArrayBuffer,
|
|
5389
5045
|
base64EncodeArrayBuffer,
|
|
5390
5046
|
blendColorPixelData,
|
|
5391
5047
|
blendColorPixelDataAlphaMask,
|
|
5392
5048
|
blendColorPixelDataBinaryMask,
|
|
5393
|
-
blendColorPixelDataCircleMask,
|
|
5394
5049
|
blendPixel,
|
|
5395
5050
|
blendPixelData,
|
|
5396
5051
|
blendPixelDataAlphaMask,
|
|
@@ -5432,12 +5087,8 @@ export {
|
|
|
5432
5087
|
fillPixelDataFast,
|
|
5433
5088
|
floodFillSelection,
|
|
5434
5089
|
forEachLinePoint,
|
|
5435
|
-
getCircleBrushOrPencilBounds,
|
|
5436
|
-
getCircleBrushOrPencilStrokeBounds,
|
|
5437
5090
|
getImageDataFromClipboard,
|
|
5438
5091
|
getIndexedImageColorCounts,
|
|
5439
|
-
getRectBrushOrPencilBounds,
|
|
5440
|
-
getRectBrushOrPencilStrokeBounds,
|
|
5441
5092
|
getRectsBounds,
|
|
5442
5093
|
getSupportedPixelFormats,
|
|
5443
5094
|
hardLightFast,
|
|
@@ -5471,15 +5122,18 @@ export {
|
|
|
5471
5122
|
makeBinaryMask,
|
|
5472
5123
|
makeBlendModeRegistry,
|
|
5473
5124
|
makeCanvasFrameRenderer,
|
|
5474
|
-
|
|
5475
|
-
|
|
5125
|
+
makeCirclePaintAlphaMask,
|
|
5126
|
+
makeCirclePaintBinaryMask,
|
|
5476
5127
|
makeFastBlendModeRegistry,
|
|
5477
5128
|
makeFullPixelMutator,
|
|
5478
5129
|
makeHistoryAction,
|
|
5479
5130
|
makeImageDataLike,
|
|
5480
|
-
|
|
5131
|
+
makePaintAlphaMask,
|
|
5132
|
+
makePaintBinaryMask,
|
|
5133
|
+
makePaintBufferCanvasRenderer,
|
|
5481
5134
|
makePerfectBlendModeRegistry,
|
|
5482
5135
|
makePixelCanvas,
|
|
5136
|
+
makeRectFalloffPaintAlphaMask,
|
|
5483
5137
|
makeReusableCanvas,
|
|
5484
5138
|
makeReusableImageData,
|
|
5485
5139
|
makeReusableOffscreenCanvas,
|
|
@@ -5491,15 +5145,8 @@ export {
|
|
|
5491
5145
|
multiplyPerfect,
|
|
5492
5146
|
mutatorApplyAlphaMask,
|
|
5493
5147
|
mutatorApplyBinaryMask,
|
|
5494
|
-
mutatorApplyCircleBrushStroke,
|
|
5495
|
-
mutatorApplyCirclePencil,
|
|
5496
|
-
mutatorApplyCirclePencilStroke,
|
|
5497
|
-
mutatorApplyRectBrush,
|
|
5498
|
-
mutatorApplyRectBrushStroke,
|
|
5499
|
-
mutatorApplyRectPencil,
|
|
5500
|
-
mutatorApplyRectPencilStroke,
|
|
5501
5148
|
mutatorBlendColor,
|
|
5502
|
-
|
|
5149
|
+
mutatorBlendPaintMask,
|
|
5503
5150
|
mutatorBlendPixel,
|
|
5504
5151
|
mutatorBlendPixelData,
|
|
5505
5152
|
mutatorBlendPixelDataAlphaMask,
|
|
@@ -5539,6 +5186,7 @@ export {
|
|
|
5539
5186
|
subtractFast,
|
|
5540
5187
|
subtractPerfect,
|
|
5541
5188
|
toBlendModeIndexAndName,
|
|
5189
|
+
trimMaskRectBounds,
|
|
5542
5190
|
trimRectBounds,
|
|
5543
5191
|
uInt32ArrayToImageData,
|
|
5544
5192
|
uInt32ArrayToImageDataLike,
|
|
@@ -5554,6 +5202,7 @@ export {
|
|
|
5554
5202
|
writeImageDataBuffer,
|
|
5555
5203
|
writeImageDataToClipboard,
|
|
5556
5204
|
writeImgBlobToClipboard,
|
|
5205
|
+
writePaintBufferToPixelData,
|
|
5557
5206
|
writePixelDataBuffer
|
|
5558
5207
|
};
|
|
5559
5208
|
//# sourceMappingURL=index.dev.js.map
|