pixel-data-js 0.24.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.dev.cjs +1431 -1845
- package/dist/index.dev.cjs.map +1 -1
- package/dist/index.dev.js +1297 -1702
- package/dist/index.dev.js.map +1 -1
- package/dist/index.prod.cjs +1305 -1719
- package/dist/index.prod.cjs.map +1 -1
- package/dist/index.prod.d.ts +220 -328
- package/dist/index.prod.js +1423 -1828
- 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/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 +9 -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.prod.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,
|
|
@@ -1811,11 +1811,11 @@ var PixelAccumulator = class {
|
|
|
1811
1811
|
* @param y pixel y coordinate
|
|
1812
1812
|
*/
|
|
1813
1813
|
storePixelBeforeState(x, y) {
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1814
|
+
const shift = this.config.tileShift;
|
|
1815
|
+
const columns = this.config.targetColumns;
|
|
1816
|
+
const tx = x >> shift;
|
|
1817
|
+
const ty = y >> shift;
|
|
1818
|
+
const id = ty * columns + tx;
|
|
1819
1819
|
let tile = this.lookup[id];
|
|
1820
1820
|
let added = false;
|
|
1821
1821
|
if (!tile) {
|
|
@@ -1841,16 +1841,16 @@ var PixelAccumulator = class {
|
|
|
1841
1841
|
* @param h pixel height
|
|
1842
1842
|
*/
|
|
1843
1843
|
storeRegionBeforeState(x, y, w, h) {
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1844
|
+
const shift = this.config.tileShift;
|
|
1845
|
+
const columns = this.config.targetColumns;
|
|
1846
|
+
const startX = x >> shift;
|
|
1847
|
+
const startY = y >> shift;
|
|
1848
|
+
const endX = x + w - 1 >> shift;
|
|
1849
|
+
const endY = y + h - 1 >> shift;
|
|
1850
|
+
const startIndex = this.beforeTiles.length;
|
|
1851
1851
|
for (let ty = startY; ty <= endY; ty++) {
|
|
1852
1852
|
for (let tx = startX; tx <= endX; tx++) {
|
|
1853
|
-
|
|
1853
|
+
const id = ty * columns + tx;
|
|
1854
1854
|
let tile = this.lookup[id];
|
|
1855
1855
|
if (!tile) {
|
|
1856
1856
|
tile = this.tilePool.getTile(id, tx, ty);
|
|
@@ -1862,7 +1862,7 @@ var PixelAccumulator = class {
|
|
|
1862
1862
|
}
|
|
1863
1863
|
return (didChange) => {
|
|
1864
1864
|
if (!didChange) {
|
|
1865
|
-
|
|
1865
|
+
const length = this.beforeTiles.length;
|
|
1866
1866
|
for (let i = startIndex; i < length; i++) {
|
|
1867
1867
|
let t = this.beforeTiles[i];
|
|
1868
1868
|
if (t) {
|
|
@@ -1875,15 +1875,34 @@ var PixelAccumulator = class {
|
|
|
1875
1875
|
return didChange;
|
|
1876
1876
|
};
|
|
1877
1877
|
}
|
|
1878
|
+
storeTileBeforeState(id, tx, ty) {
|
|
1879
|
+
let tile = this.lookup[id];
|
|
1880
|
+
let added = false;
|
|
1881
|
+
if (!tile) {
|
|
1882
|
+
tile = this.tilePool.getTile(id, tx, ty);
|
|
1883
|
+
this.extractState(tile);
|
|
1884
|
+
this.lookup[id] = tile;
|
|
1885
|
+
this.beforeTiles.push(tile);
|
|
1886
|
+
added = true;
|
|
1887
|
+
}
|
|
1888
|
+
return (didChange) => {
|
|
1889
|
+
if (!didChange && added) {
|
|
1890
|
+
this.beforeTiles.pop();
|
|
1891
|
+
this.lookup[id] = void 0;
|
|
1892
|
+
this.tilePool.releaseTile(tile);
|
|
1893
|
+
}
|
|
1894
|
+
return didChange;
|
|
1895
|
+
};
|
|
1896
|
+
}
|
|
1878
1897
|
extractState(tile) {
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1898
|
+
const target = this.config.target;
|
|
1899
|
+
const TILE_SIZE = this.config.tileSize;
|
|
1900
|
+
const dst = tile.data32;
|
|
1901
|
+
const src = target.data32;
|
|
1902
|
+
const startX = tile.tx * TILE_SIZE;
|
|
1903
|
+
const startY = tile.ty * TILE_SIZE;
|
|
1904
|
+
const targetWidth = target.width;
|
|
1905
|
+
const targetHeight = target.height;
|
|
1887
1906
|
if (startX >= targetWidth || startX + TILE_SIZE <= 0 || startY >= targetHeight || startY + TILE_SIZE <= 0) {
|
|
1888
1907
|
dst.fill(0);
|
|
1889
1908
|
return;
|
|
@@ -1909,8 +1928,8 @@ var PixelAccumulator = class {
|
|
|
1909
1928
|
}
|
|
1910
1929
|
}
|
|
1911
1930
|
extractPatch() {
|
|
1912
|
-
|
|
1913
|
-
|
|
1931
|
+
const afterTiles = [];
|
|
1932
|
+
const length = this.beforeTiles.length;
|
|
1914
1933
|
for (let i = 0; i < length; i++) {
|
|
1915
1934
|
let beforeTile = this.beforeTiles[i];
|
|
1916
1935
|
if (beforeTile) {
|
|
@@ -1919,7 +1938,7 @@ var PixelAccumulator = class {
|
|
|
1919
1938
|
afterTiles.push(afterTile);
|
|
1920
1939
|
}
|
|
1921
1940
|
}
|
|
1922
|
-
|
|
1941
|
+
const beforeTiles = this.beforeTiles;
|
|
1923
1942
|
this.beforeTiles = [];
|
|
1924
1943
|
this.lookup.length = 0;
|
|
1925
1944
|
return {
|
|
@@ -1927,10 +1946,10 @@ var PixelAccumulator = class {
|
|
|
1927
1946
|
afterTiles
|
|
1928
1947
|
};
|
|
1929
1948
|
}
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1949
|
+
rollbackAfterError() {
|
|
1950
|
+
const target = this.config.target;
|
|
1951
|
+
const tileSize = this.config.tileSize;
|
|
1952
|
+
const length = this.beforeTiles.length;
|
|
1934
1953
|
applyPatchTiles(target, this.beforeTiles, tileSize);
|
|
1935
1954
|
for (let i = 0; i < length; i++) {
|
|
1936
1955
|
let tile = this.beforeTiles[i];
|
|
@@ -1954,6 +1973,7 @@ var PixelEngineConfig = class {
|
|
|
1954
1973
|
tileArea;
|
|
1955
1974
|
target;
|
|
1956
1975
|
targetColumns = 0;
|
|
1976
|
+
targetRows = 0;
|
|
1957
1977
|
constructor(tileSize, target) {
|
|
1958
1978
|
if ((tileSize & tileSize - 1) !== 0) {
|
|
1959
1979
|
throw new Error("tileSize must be a power of 2");
|
|
@@ -1962,28 +1982,26 @@ var PixelEngineConfig = class {
|
|
|
1962
1982
|
this.tileShift = 31 - Math.clz32(tileSize);
|
|
1963
1983
|
this.tileMask = tileSize - 1;
|
|
1964
1984
|
this.tileArea = tileSize * tileSize;
|
|
1965
|
-
this.setTarget(target);
|
|
1966
|
-
}
|
|
1967
|
-
setTarget(target) {
|
|
1968
|
-
;
|
|
1969
1985
|
this.target = target;
|
|
1970
1986
|
this.targetColumns = target.width + this.tileMask >> this.tileShift;
|
|
1987
|
+
this.targetRows = target.height + this.tileMask >> this.tileShift;
|
|
1971
1988
|
}
|
|
1972
1989
|
};
|
|
1973
1990
|
|
|
1974
|
-
// src/PixelData/
|
|
1975
|
-
function
|
|
1991
|
+
// src/PixelData/blendColorPixelData.ts
|
|
1992
|
+
function blendColorPixelData(dst, color, opts = {}) {
|
|
1976
1993
|
const {
|
|
1977
1994
|
x: targetX = 0,
|
|
1978
1995
|
y: targetY = 0,
|
|
1979
1996
|
w: width = dst.width,
|
|
1980
1997
|
h: height = dst.height,
|
|
1981
1998
|
alpha: globalAlpha = 255,
|
|
1982
|
-
|
|
1983
|
-
my = 0,
|
|
1984
|
-
invertMask = false
|
|
1999
|
+
blendFn = sourceOverPerfect
|
|
1985
2000
|
} = opts;
|
|
1986
2001
|
if (globalAlpha === 0) return false;
|
|
2002
|
+
const baseSrcAlpha = color >>> 24;
|
|
2003
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
2004
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
1987
2005
|
let x = targetX;
|
|
1988
2006
|
let y = targetY;
|
|
1989
2007
|
let w = width;
|
|
@@ -1996,82 +2014,46 @@ function applyAlphaMaskToPixelData(dst, mask, opts = {}) {
|
|
|
1996
2014
|
h += y;
|
|
1997
2015
|
y = 0;
|
|
1998
2016
|
}
|
|
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;
|
|
2017
|
+
const actualW = Math.min(w, dst.width - x);
|
|
2018
|
+
const actualH = Math.min(h, dst.height - y);
|
|
2019
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
2020
|
+
let finalSrcColor = color;
|
|
2021
|
+
if (globalAlpha < 255) {
|
|
2022
|
+
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
2023
|
+
if (a === 0 && !isOverwrite) return false;
|
|
2024
|
+
finalSrcColor = (color & 16777215 | a << 24) >>> 0;
|
|
2025
|
+
}
|
|
2017
2026
|
const dst32 = dst.data32;
|
|
2018
2027
|
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;
|
|
2028
|
+
let dIdx = y * dw + x | 0;
|
|
2029
|
+
const dStride = dw - actualW | 0;
|
|
2024
2030
|
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;
|
|
2031
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2032
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2033
|
+
const current = dst32[dIdx];
|
|
2034
|
+
const next = blendFn(finalSrcColor, current);
|
|
2035
|
+
if (current !== next) {
|
|
2036
|
+
dst32[dIdx] = next;
|
|
2041
2037
|
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
2038
|
}
|
|
2055
2039
|
dIdx++;
|
|
2056
|
-
mIdx++;
|
|
2057
2040
|
}
|
|
2058
2041
|
dIdx += dStride;
|
|
2059
|
-
mIdx += mStride;
|
|
2060
2042
|
}
|
|
2061
2043
|
return didChange;
|
|
2062
2044
|
}
|
|
2063
2045
|
|
|
2064
|
-
// src/History/PixelMutator/
|
|
2046
|
+
// src/History/PixelMutator/mutatorBlendColor.ts
|
|
2065
2047
|
var defaults2 = {
|
|
2066
|
-
|
|
2048
|
+
blendColorPixelData
|
|
2067
2049
|
};
|
|
2068
|
-
var
|
|
2050
|
+
var mutatorBlendColor = ((writer, deps = defaults2) => {
|
|
2069
2051
|
const {
|
|
2070
|
-
|
|
2052
|
+
blendColorPixelData: blendColorPixelData2 = defaults2.blendColorPixelData
|
|
2071
2053
|
} = deps;
|
|
2072
2054
|
return {
|
|
2073
|
-
|
|
2074
|
-
|
|
2055
|
+
blendColor(color, opts = {}) {
|
|
2056
|
+
const target = writer.config.target;
|
|
2075
2057
|
const {
|
|
2076
2058
|
x = 0,
|
|
2077
2059
|
y = 0,
|
|
@@ -2079,159 +2061,227 @@ var mutatorApplyAlphaMask = ((writer, deps = defaults2) => {
|
|
|
2079
2061
|
h = target.height
|
|
2080
2062
|
} = opts;
|
|
2081
2063
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2082
|
-
return didChange(
|
|
2064
|
+
return didChange(blendColorPixelData2(target, color, opts));
|
|
2083
2065
|
}
|
|
2084
2066
|
};
|
|
2085
2067
|
});
|
|
2086
2068
|
|
|
2087
|
-
// src/PixelData/
|
|
2088
|
-
function
|
|
2069
|
+
// src/PixelData/blendPixel.ts
|
|
2070
|
+
function blendPixel(target, x, y, color, alpha = 255, blendFn = sourceOverPerfect) {
|
|
2071
|
+
if (alpha === 0) return false;
|
|
2072
|
+
let width = target.width;
|
|
2073
|
+
let height = target.height;
|
|
2074
|
+
if (x < 0 || x >= width || y < 0 || y >= height) return false;
|
|
2075
|
+
let srcAlpha = color >>> 24;
|
|
2076
|
+
let isOverwrite = blendFn.isOverwrite;
|
|
2077
|
+
if (srcAlpha === 0 && !isOverwrite) return false;
|
|
2078
|
+
let dst32 = target.data32;
|
|
2079
|
+
let index = y * width + x;
|
|
2080
|
+
let finalColor = color;
|
|
2081
|
+
if (alpha !== 255) {
|
|
2082
|
+
let finalAlpha = srcAlpha * alpha + 128 >> 8;
|
|
2083
|
+
if (finalAlpha === 0 && !isOverwrite) return false;
|
|
2084
|
+
finalColor = (color & 16777215 | finalAlpha << 24) >>> 0;
|
|
2085
|
+
}
|
|
2086
|
+
let current = dst32[index];
|
|
2087
|
+
let next = blendFn(finalColor, current);
|
|
2088
|
+
if (current !== next) {
|
|
2089
|
+
dst32[index] = next;
|
|
2090
|
+
return true;
|
|
2091
|
+
}
|
|
2092
|
+
return false;
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
// src/History/PixelMutator/mutatorBlendPixel.ts
|
|
2096
|
+
var defaults3 = {
|
|
2097
|
+
blendPixel
|
|
2098
|
+
};
|
|
2099
|
+
var mutatorBlendPixel = ((writer, deps = defaults3) => {
|
|
2100
|
+
const {
|
|
2101
|
+
blendPixel: blendPixel2 = defaults3.blendPixel
|
|
2102
|
+
} = deps;
|
|
2103
|
+
return {
|
|
2104
|
+
blendPixel(x, y, color, alpha, blendFn) {
|
|
2105
|
+
const didChange = writer.accumulator.storePixelBeforeState(x, y);
|
|
2106
|
+
return didChange(blendPixel2(writer.config.target, x, y, color, alpha, blendFn));
|
|
2107
|
+
}
|
|
2108
|
+
};
|
|
2109
|
+
});
|
|
2110
|
+
|
|
2111
|
+
// src/PixelData/blendPixelData.ts
|
|
2112
|
+
function blendPixelData(dst, src, opts = {}) {
|
|
2089
2113
|
const {
|
|
2090
2114
|
x: targetX = 0,
|
|
2091
2115
|
y: targetY = 0,
|
|
2092
|
-
|
|
2093
|
-
|
|
2116
|
+
sx: sourceX = 0,
|
|
2117
|
+
sy: sourceY = 0,
|
|
2118
|
+
w: width = src.width,
|
|
2119
|
+
h: height = src.height,
|
|
2094
2120
|
alpha: globalAlpha = 255,
|
|
2095
|
-
|
|
2096
|
-
my = 0,
|
|
2097
|
-
invertMask = false
|
|
2121
|
+
blendFn = sourceOverPerfect
|
|
2098
2122
|
} = opts;
|
|
2099
2123
|
if (globalAlpha === 0) return false;
|
|
2100
2124
|
let x = targetX;
|
|
2101
2125
|
let y = targetY;
|
|
2126
|
+
let sx = sourceX;
|
|
2127
|
+
let sy = sourceY;
|
|
2102
2128
|
let w = width;
|
|
2103
2129
|
let h = height;
|
|
2130
|
+
if (sx < 0) {
|
|
2131
|
+
x -= sx;
|
|
2132
|
+
w += sx;
|
|
2133
|
+
sx = 0;
|
|
2134
|
+
}
|
|
2135
|
+
if (sy < 0) {
|
|
2136
|
+
y -= sy;
|
|
2137
|
+
h += sy;
|
|
2138
|
+
sy = 0;
|
|
2139
|
+
}
|
|
2140
|
+
w = Math.min(w, src.width - sx);
|
|
2141
|
+
h = Math.min(h, src.height - sy);
|
|
2104
2142
|
if (x < 0) {
|
|
2143
|
+
sx -= x;
|
|
2105
2144
|
w += x;
|
|
2106
2145
|
x = 0;
|
|
2107
2146
|
}
|
|
2108
2147
|
if (y < 0) {
|
|
2148
|
+
sy -= y;
|
|
2109
2149
|
h += y;
|
|
2110
2150
|
y = 0;
|
|
2111
2151
|
}
|
|
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;
|
|
2152
|
+
const actualW = Math.min(w, dst.width - x);
|
|
2153
|
+
const actualH = Math.min(h, dst.height - y);
|
|
2154
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
2130
2155
|
const dst32 = dst.data32;
|
|
2156
|
+
const src32 = src.data32;
|
|
2131
2157
|
const dw = dst.width;
|
|
2132
|
-
const
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2158
|
+
const sw = src.width;
|
|
2159
|
+
let dIdx = y * dw + x | 0;
|
|
2160
|
+
let sIdx = sy * sw + sx | 0;
|
|
2161
|
+
const dStride = dw - actualW | 0;
|
|
2162
|
+
const sStride = sw - actualW | 0;
|
|
2163
|
+
const isOpaque = globalAlpha === 255;
|
|
2164
|
+
const isOverwrite = blendFn.isOverwrite;
|
|
2137
2165
|
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
|
-
}
|
|
2166
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2167
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2168
|
+
const srcCol = src32[sIdx];
|
|
2169
|
+
const srcAlpha = srcCol >>> 24;
|
|
2170
|
+
if (srcAlpha === 0 && !isOverwrite) {
|
|
2171
|
+
dIdx++;
|
|
2172
|
+
sIdx++;
|
|
2173
|
+
continue;
|
|
2174
|
+
}
|
|
2175
|
+
let finalCol = srcCol;
|
|
2176
|
+
if (!isOpaque) {
|
|
2177
|
+
const a = srcAlpha * globalAlpha + 128 >> 8;
|
|
2178
|
+
if (a === 0 && !isOverwrite) {
|
|
2179
|
+
dIdx++;
|
|
2180
|
+
sIdx++;
|
|
2181
|
+
continue;
|
|
2159
2182
|
}
|
|
2183
|
+
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
2160
2184
|
}
|
|
2161
|
-
dIdx
|
|
2162
|
-
|
|
2185
|
+
const current = dst32[dIdx];
|
|
2186
|
+
const next = blendFn(finalCol, dst32[dIdx]);
|
|
2187
|
+
if (current !== next) {
|
|
2188
|
+
dst32[dIdx] = next;
|
|
2189
|
+
didChange = true;
|
|
2190
|
+
}
|
|
2191
|
+
dIdx++;
|
|
2192
|
+
sIdx++;
|
|
2163
2193
|
}
|
|
2164
2194
|
dIdx += dStride;
|
|
2165
|
-
|
|
2195
|
+
sIdx += sStride;
|
|
2166
2196
|
}
|
|
2167
2197
|
return didChange;
|
|
2168
2198
|
}
|
|
2169
2199
|
|
|
2170
|
-
// src/History/PixelMutator/
|
|
2171
|
-
var
|
|
2172
|
-
|
|
2200
|
+
// src/History/PixelMutator/mutatorBlendPixelData.ts
|
|
2201
|
+
var defaults4 = {
|
|
2202
|
+
blendPixelData
|
|
2173
2203
|
};
|
|
2174
|
-
var
|
|
2204
|
+
var mutatorBlendPixelData = ((writer, deps = defaults4) => {
|
|
2175
2205
|
const {
|
|
2176
|
-
|
|
2206
|
+
blendPixelData: blendPixelData2 = defaults4.blendPixelData
|
|
2177
2207
|
} = deps;
|
|
2178
2208
|
return {
|
|
2179
|
-
|
|
2180
|
-
let target = writer.config.target;
|
|
2209
|
+
blendPixelData(src, opts = {}) {
|
|
2181
2210
|
const {
|
|
2182
2211
|
x = 0,
|
|
2183
2212
|
y = 0,
|
|
2184
|
-
w =
|
|
2185
|
-
h =
|
|
2213
|
+
w = src.width,
|
|
2214
|
+
h = src.height
|
|
2186
2215
|
} = opts;
|
|
2187
2216
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2188
|
-
return didChange(
|
|
2217
|
+
return didChange(blendPixelData2(writer.config.target, src, opts));
|
|
2189
2218
|
}
|
|
2190
2219
|
};
|
|
2191
2220
|
});
|
|
2192
2221
|
|
|
2193
|
-
// src/PixelData/
|
|
2194
|
-
function
|
|
2195
|
-
const
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2222
|
+
// src/PixelData/blendPixelDataAlphaMask.ts
|
|
2223
|
+
function blendPixelDataAlphaMask(dst, src, alphaMask, opts = {}) {
|
|
2224
|
+
const {
|
|
2225
|
+
x: targetX = 0,
|
|
2226
|
+
y: targetY = 0,
|
|
2227
|
+
sx: sourceX = 0,
|
|
2228
|
+
sy: sourceY = 0,
|
|
2229
|
+
w: width = src.width,
|
|
2230
|
+
h: height = src.height,
|
|
2231
|
+
alpha: globalAlpha = 255,
|
|
2232
|
+
blendFn = sourceOverPerfect,
|
|
2233
|
+
mx = 0,
|
|
2234
|
+
my = 0,
|
|
2235
|
+
invertMask = false
|
|
2236
|
+
} = opts;
|
|
2204
2237
|
if (globalAlpha === 0) return false;
|
|
2205
|
-
const baseSrcAlpha = color >>> 24;
|
|
2206
|
-
const isOverwrite = blendFn.isOverwrite || false;
|
|
2207
|
-
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
2208
2238
|
let x = targetX;
|
|
2209
2239
|
let y = targetY;
|
|
2210
|
-
let
|
|
2211
|
-
let
|
|
2240
|
+
let sx = sourceX;
|
|
2241
|
+
let sy = sourceY;
|
|
2242
|
+
let w = width;
|
|
2243
|
+
let h = height;
|
|
2244
|
+
if (sx < 0) {
|
|
2245
|
+
x -= sx;
|
|
2246
|
+
w += sx;
|
|
2247
|
+
sx = 0;
|
|
2248
|
+
}
|
|
2249
|
+
if (sy < 0) {
|
|
2250
|
+
y -= sy;
|
|
2251
|
+
h += sy;
|
|
2252
|
+
sy = 0;
|
|
2253
|
+
}
|
|
2254
|
+
w = Math.min(w, src.width - sx);
|
|
2255
|
+
h = Math.min(h, src.height - sy);
|
|
2212
2256
|
if (x < 0) {
|
|
2213
|
-
|
|
2257
|
+
sx -= x;
|
|
2258
|
+
w += x;
|
|
2214
2259
|
x = 0;
|
|
2215
2260
|
}
|
|
2216
2261
|
if (y < 0) {
|
|
2217
|
-
|
|
2262
|
+
sy -= y;
|
|
2263
|
+
h += y;
|
|
2218
2264
|
y = 0;
|
|
2219
2265
|
}
|
|
2220
|
-
actualW = Math.min(
|
|
2221
|
-
actualH = Math.min(
|
|
2266
|
+
const actualW = Math.min(w, dst.width - x);
|
|
2267
|
+
const actualH = Math.min(h, dst.height - y);
|
|
2222
2268
|
if (actualW <= 0 || actualH <= 0) return false;
|
|
2269
|
+
const dw = dst.width;
|
|
2270
|
+
const sw = src.width;
|
|
2271
|
+
const mPitch = alphaMask.w;
|
|
2272
|
+
const maskData = alphaMask.data;
|
|
2223
2273
|
const dx = x - targetX | 0;
|
|
2224
2274
|
const dy = y - targetY | 0;
|
|
2225
2275
|
const dst32 = dst.data32;
|
|
2226
|
-
const
|
|
2227
|
-
const mPitch = mask.w;
|
|
2228
|
-
const maskData = mask.data;
|
|
2276
|
+
const src32 = src.data32;
|
|
2229
2277
|
let dIdx = y * dw + x | 0;
|
|
2278
|
+
let sIdx = sy * sw + sx | 0;
|
|
2230
2279
|
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
2231
2280
|
const dStride = dw - actualW | 0;
|
|
2281
|
+
const sStride = sw - actualW | 0;
|
|
2232
2282
|
const mStride = mPitch - actualW | 0;
|
|
2233
2283
|
const isOpaque = globalAlpha === 255;
|
|
2234
|
-
const
|
|
2284
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
2235
2285
|
let didChange = false;
|
|
2236
2286
|
for (let iy = 0; iy < actualH; iy++) {
|
|
2237
2287
|
for (let ix = 0; ix < actualW; ix++) {
|
|
@@ -2239,6 +2289,15 @@ function blendColorPixelDataAlphaMask(dst, color, mask, opts = {}) {
|
|
|
2239
2289
|
const effM = invertMask ? 255 - mVal : mVal;
|
|
2240
2290
|
if (effM === 0) {
|
|
2241
2291
|
dIdx++;
|
|
2292
|
+
sIdx++;
|
|
2293
|
+
mIdx++;
|
|
2294
|
+
continue;
|
|
2295
|
+
}
|
|
2296
|
+
const srcCol = src32[sIdx];
|
|
2297
|
+
const srcAlpha = srcCol >>> 24;
|
|
2298
|
+
if (srcAlpha === 0 && !isOverwrite) {
|
|
2299
|
+
dIdx++;
|
|
2300
|
+
sIdx++;
|
|
2242
2301
|
mIdx++;
|
|
2243
2302
|
continue;
|
|
2244
2303
|
}
|
|
@@ -2250,844 +2309,459 @@ function blendColorPixelDataAlphaMask(dst, color, mask, opts = {}) {
|
|
|
2250
2309
|
}
|
|
2251
2310
|
if (weight === 0) {
|
|
2252
2311
|
dIdx++;
|
|
2312
|
+
sIdx++;
|
|
2253
2313
|
mIdx++;
|
|
2254
2314
|
continue;
|
|
2255
2315
|
}
|
|
2256
|
-
let finalCol =
|
|
2316
|
+
let finalCol = srcCol;
|
|
2257
2317
|
if (weight < 255) {
|
|
2258
|
-
const a =
|
|
2318
|
+
const a = srcAlpha * weight + 128 >> 8;
|
|
2259
2319
|
if (a === 0 && !isOverwrite) {
|
|
2260
2320
|
dIdx++;
|
|
2321
|
+
sIdx++;
|
|
2261
2322
|
mIdx++;
|
|
2262
2323
|
continue;
|
|
2263
2324
|
}
|
|
2264
|
-
finalCol = (
|
|
2325
|
+
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
2265
2326
|
}
|
|
2266
2327
|
const current = dst32[dIdx];
|
|
2267
|
-
const next = blendFn(finalCol,
|
|
2328
|
+
const next = blendFn(finalCol, dst32[dIdx]);
|
|
2268
2329
|
if (current !== next) {
|
|
2269
2330
|
dst32[dIdx] = next;
|
|
2270
2331
|
didChange = true;
|
|
2271
2332
|
}
|
|
2272
2333
|
dIdx++;
|
|
2334
|
+
sIdx++;
|
|
2273
2335
|
mIdx++;
|
|
2274
2336
|
}
|
|
2275
2337
|
dIdx += dStride;
|
|
2338
|
+
sIdx += sStride;
|
|
2276
2339
|
mIdx += mStride;
|
|
2277
2340
|
}
|
|
2278
2341
|
return didChange;
|
|
2279
2342
|
}
|
|
2280
2343
|
|
|
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
|
|
2344
|
+
// src/History/PixelMutator/mutatorBlendPixelDataAlphaMask.ts
|
|
2345
|
+
var defaults5 = {
|
|
2346
|
+
blendPixelDataAlphaMask
|
|
2329
2347
|
};
|
|
2330
|
-
var
|
|
2348
|
+
var mutatorBlendPixelDataAlphaMask = ((writer, deps = defaults5) => {
|
|
2331
2349
|
const {
|
|
2332
|
-
|
|
2333
|
-
blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults4.blendColorPixelDataAlphaMask,
|
|
2334
|
-
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults4.getCircleBrushOrPencilBounds,
|
|
2335
|
-
getCircleBrushOrPencilStrokeBounds: getCircleBrushOrPencilStrokeBounds2 = defaults4.getCircleBrushOrPencilStrokeBounds
|
|
2350
|
+
blendPixelDataAlphaMask: blendPixelDataAlphaMask2 = defaults5.blendPixelDataAlphaMask
|
|
2336
2351
|
} = 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
2352
|
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);
|
|
2353
|
+
blendPixelDataAlphaMask(src, mask, opts = {}) {
|
|
2354
|
+
const x = opts.x ?? 0;
|
|
2355
|
+
const y = opts.y ?? 0;
|
|
2356
|
+
const w = opts.w ?? src.width;
|
|
2357
|
+
const h = opts.h ?? src.height;
|
|
2358
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2359
|
+
return didChange(blendPixelDataAlphaMask2(writer.config.target, src, mask, opts));
|
|
2420
2360
|
}
|
|
2421
2361
|
};
|
|
2422
2362
|
});
|
|
2423
2363
|
|
|
2424
|
-
// src/PixelData/
|
|
2425
|
-
function
|
|
2426
|
-
const
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2364
|
+
// src/PixelData/blendPixelDataBinaryMask.ts
|
|
2365
|
+
function blendPixelDataBinaryMask(dst, src, binaryMask, opts = {}) {
|
|
2366
|
+
const {
|
|
2367
|
+
x: targetX = 0,
|
|
2368
|
+
y: targetY = 0,
|
|
2369
|
+
sx: sourceX = 0,
|
|
2370
|
+
sy: sourceY = 0,
|
|
2371
|
+
w: width = src.width,
|
|
2372
|
+
h: height = src.height,
|
|
2373
|
+
alpha: globalAlpha = 255,
|
|
2374
|
+
blendFn = sourceOverPerfect,
|
|
2375
|
+
mx = 0,
|
|
2376
|
+
my = 0,
|
|
2377
|
+
invertMask = false
|
|
2378
|
+
} = opts;
|
|
2435
2379
|
if (globalAlpha === 0) return false;
|
|
2436
|
-
const baseSrcAlpha = color >>> 24;
|
|
2437
|
-
const isOverwrite = blendFn.isOverwrite || false;
|
|
2438
|
-
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
2439
2380
|
let x = targetX;
|
|
2440
2381
|
let y = targetY;
|
|
2382
|
+
let sx = sourceX;
|
|
2383
|
+
let sy = sourceY;
|
|
2384
|
+
let w = width;
|
|
2385
|
+
let h = height;
|
|
2386
|
+
if (sx < 0) {
|
|
2387
|
+
x -= sx;
|
|
2388
|
+
w += sx;
|
|
2389
|
+
sx = 0;
|
|
2390
|
+
}
|
|
2391
|
+
if (sy < 0) {
|
|
2392
|
+
y -= sy;
|
|
2393
|
+
h += sy;
|
|
2394
|
+
sy = 0;
|
|
2395
|
+
}
|
|
2396
|
+
w = Math.min(w, src.width - sx);
|
|
2397
|
+
h = Math.min(h, src.height - sy);
|
|
2441
2398
|
if (x < 0) {
|
|
2399
|
+
sx -= x;
|
|
2442
2400
|
w += x;
|
|
2443
2401
|
x = 0;
|
|
2444
2402
|
}
|
|
2445
2403
|
if (y < 0) {
|
|
2404
|
+
sy -= y;
|
|
2446
2405
|
h += y;
|
|
2447
2406
|
y = 0;
|
|
2448
2407
|
}
|
|
2449
2408
|
const actualW = Math.min(w, dst.width - x);
|
|
2450
2409
|
const actualH = Math.min(h, dst.height - y);
|
|
2451
2410
|
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
2411
|
const dx = x - targetX | 0;
|
|
2459
2412
|
const dy = y - targetY | 0;
|
|
2460
2413
|
const dst32 = dst.data32;
|
|
2414
|
+
const src32 = src.data32;
|
|
2461
2415
|
const dw = dst.width;
|
|
2462
|
-
const
|
|
2463
|
-
const
|
|
2416
|
+
const sw = src.width;
|
|
2417
|
+
const mPitch = binaryMask.w;
|
|
2418
|
+
const maskData = binaryMask.data;
|
|
2464
2419
|
let dIdx = y * dw + x | 0;
|
|
2420
|
+
let sIdx = sy * sw + sx | 0;
|
|
2465
2421
|
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
2466
2422
|
const dStride = dw - actualW | 0;
|
|
2423
|
+
const sStride = sw - actualW | 0;
|
|
2467
2424
|
const mStride = mPitch - actualW | 0;
|
|
2468
2425
|
const skipVal = invertMask ? 1 : 0;
|
|
2426
|
+
const isOpaque = globalAlpha === 255;
|
|
2427
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
2469
2428
|
let didChange = false;
|
|
2470
2429
|
for (let iy = 0; iy < actualH; iy++) {
|
|
2471
2430
|
for (let ix = 0; ix < actualW; ix++) {
|
|
2472
2431
|
if (maskData[mIdx] === skipVal) {
|
|
2473
2432
|
dIdx++;
|
|
2433
|
+
sIdx++;
|
|
2434
|
+
mIdx++;
|
|
2435
|
+
continue;
|
|
2436
|
+
}
|
|
2437
|
+
const srcCol = src32[sIdx];
|
|
2438
|
+
const srcAlpha = srcCol >>> 24;
|
|
2439
|
+
if (srcAlpha === 0 && !isOverwrite) {
|
|
2440
|
+
dIdx++;
|
|
2441
|
+
sIdx++;
|
|
2474
2442
|
mIdx++;
|
|
2475
2443
|
continue;
|
|
2476
2444
|
}
|
|
2445
|
+
let finalCol = srcCol;
|
|
2446
|
+
if (!isOpaque) {
|
|
2447
|
+
const a = srcAlpha * globalAlpha + 128 >> 8;
|
|
2448
|
+
if (a === 0 && !isOverwrite) {
|
|
2449
|
+
dIdx++;
|
|
2450
|
+
sIdx++;
|
|
2451
|
+
mIdx++;
|
|
2452
|
+
continue;
|
|
2453
|
+
}
|
|
2454
|
+
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
2455
|
+
}
|
|
2477
2456
|
const current = dst32[dIdx];
|
|
2478
|
-
const next = blendFn(
|
|
2457
|
+
const next = blendFn(finalCol, dst32[dIdx]);
|
|
2479
2458
|
if (current !== next) {
|
|
2480
2459
|
dst32[dIdx] = next;
|
|
2481
2460
|
didChange = true;
|
|
2482
2461
|
}
|
|
2483
2462
|
dIdx++;
|
|
2463
|
+
sIdx++;
|
|
2484
2464
|
mIdx++;
|
|
2485
2465
|
}
|
|
2486
2466
|
dIdx += dStride;
|
|
2467
|
+
sIdx += sStride;
|
|
2487
2468
|
mIdx += mStride;
|
|
2488
2469
|
}
|
|
2489
2470
|
return didChange;
|
|
2490
2471
|
}
|
|
2491
2472
|
|
|
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
|
|
2473
|
+
// src/History/PixelMutator/mutatorBlendPixelDataBinaryMask.ts
|
|
2474
|
+
var defaults6 = {
|
|
2475
|
+
blendPixelDataBinaryMask
|
|
2526
2476
|
};
|
|
2527
|
-
var
|
|
2477
|
+
var mutatorBlendPixelDataBinaryMask = ((writer, deps = defaults6) => {
|
|
2528
2478
|
const {
|
|
2529
|
-
|
|
2530
|
-
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults5.getCircleBrushOrPencilBounds
|
|
2479
|
+
blendPixelDataBinaryMask: blendPixelDataBinaryMask2 = defaults6.blendPixelDataBinaryMask
|
|
2531
2480
|
} = 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
2481
|
return {
|
|
2547
|
-
|
|
2548
|
-
const
|
|
2549
|
-
const
|
|
2550
|
-
const
|
|
2551
|
-
|
|
2482
|
+
blendPixelDataBinaryMask(src, mask, opts = {}) {
|
|
2483
|
+
const x = opts.x ?? 0;
|
|
2484
|
+
const y = opts.y ?? 0;
|
|
2485
|
+
const w = opts.w ?? src.width;
|
|
2486
|
+
const h = opts.h ?? src.height;
|
|
2487
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2488
|
+
return didChange(blendPixelDataBinaryMask2(writer.config.target, src, mask, opts));
|
|
2552
2489
|
}
|
|
2553
2490
|
};
|
|
2554
2491
|
});
|
|
2555
2492
|
|
|
2556
|
-
// src/
|
|
2557
|
-
var
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2493
|
+
// src/PixelData/fillPixelDataFast.ts
|
|
2494
|
+
var SCRATCH_RECT = makeClippedRect();
|
|
2495
|
+
function fillPixelDataFast(dst, color, _x, _y, _w, _h) {
|
|
2496
|
+
let x;
|
|
2497
|
+
let y;
|
|
2498
|
+
let w;
|
|
2499
|
+
let h;
|
|
2500
|
+
if (typeof _x === "object") {
|
|
2501
|
+
x = _x.x ?? 0;
|
|
2502
|
+
y = _x.y ?? 0;
|
|
2503
|
+
w = _x.w ?? dst.width;
|
|
2504
|
+
h = _x.h ?? dst.height;
|
|
2505
|
+
} else if (typeof _x === "number") {
|
|
2506
|
+
x = _x;
|
|
2507
|
+
y = _y;
|
|
2508
|
+
w = _w;
|
|
2509
|
+
h = _h;
|
|
2510
|
+
} else {
|
|
2511
|
+
x = 0;
|
|
2512
|
+
y = 0;
|
|
2513
|
+
w = dst.width;
|
|
2514
|
+
h = dst.height;
|
|
2515
|
+
}
|
|
2516
|
+
const clip = resolveRectClipping(x, y, w, h, dst.width, dst.height, SCRATCH_RECT);
|
|
2517
|
+
if (!clip.inBounds) return;
|
|
2562
2518
|
const {
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
});
|
|
2519
|
+
x: finalX,
|
|
2520
|
+
y: finalY,
|
|
2521
|
+
w: actualW,
|
|
2522
|
+
h: actualH
|
|
2523
|
+
} = clip;
|
|
2524
|
+
const dst32 = dst.data32;
|
|
2525
|
+
const dw = dst.width;
|
|
2526
|
+
if (actualW === dw && actualH === dst.height && finalX === 0 && finalY === 0) {
|
|
2527
|
+
dst32.fill(color);
|
|
2528
|
+
return;
|
|
2529
|
+
}
|
|
2530
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2531
|
+
const start = (finalY + iy) * dw + finalX;
|
|
2532
|
+
const end = start + actualW;
|
|
2533
|
+
dst32.fill(color, start, end);
|
|
2534
|
+
}
|
|
2535
|
+
}
|
|
2581
2536
|
|
|
2582
|
-
// src/History/PixelMutator/
|
|
2537
|
+
// src/History/PixelMutator/mutatorClear.ts
|
|
2583
2538
|
var defaults7 = {
|
|
2584
|
-
|
|
2585
|
-
blendColorPixelDataBinaryMask,
|
|
2586
|
-
getCircleBrushOrPencilBounds,
|
|
2587
|
-
getCircleBrushOrPencilStrokeBounds
|
|
2539
|
+
fillPixelData: fillPixelDataFast
|
|
2588
2540
|
};
|
|
2589
|
-
var
|
|
2541
|
+
var mutatorClear = ((writer, deps = defaults7) => {
|
|
2590
2542
|
const {
|
|
2591
|
-
|
|
2592
|
-
blendColorPixelDataBinaryMask: blendColorPixelDataBinaryMask2 = defaults7.blendColorPixelDataBinaryMask,
|
|
2593
|
-
getCircleBrushOrPencilStrokeBounds: getCircleBrushOrPencilStrokeBounds2 = defaults7.getCircleBrushOrPencilStrokeBounds,
|
|
2594
|
-
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults7.getCircleBrushOrPencilBounds
|
|
2543
|
+
fillPixelData: fillPixelData2 = defaults7.fillPixelData
|
|
2595
2544
|
} = 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
2545
|
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;
|
|
2546
|
+
clear(rect = {}) {
|
|
2635
2547
|
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);
|
|
2548
|
+
const x = rect.x ?? 0;
|
|
2549
|
+
const y = rect.y ?? 0;
|
|
2550
|
+
const w = rect.w ?? target.width;
|
|
2551
|
+
const h = rect.h ?? target.height;
|
|
2552
|
+
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2553
|
+
fillPixelData2(target, 0, x, y, w, h);
|
|
2673
2554
|
}
|
|
2674
2555
|
};
|
|
2675
2556
|
});
|
|
2676
2557
|
|
|
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;
|
|
2558
|
+
// src/PixelData/fillPixelData.ts
|
|
2559
|
+
var SCRATCH_RECT2 = makeClippedRect();
|
|
2560
|
+
function fillPixelData(dst, color, _x, _y, _w, _h) {
|
|
2561
|
+
let x;
|
|
2562
|
+
let y;
|
|
2563
|
+
let w;
|
|
2564
|
+
let h;
|
|
2565
|
+
if (typeof _x === "object") {
|
|
2566
|
+
x = _x.x ?? 0;
|
|
2567
|
+
y = _x.y ?? 0;
|
|
2568
|
+
w = _x.w ?? dst.width;
|
|
2569
|
+
h = _x.h ?? dst.height;
|
|
2570
|
+
} else if (typeof _x === "number") {
|
|
2571
|
+
x = _x;
|
|
2572
|
+
y = _y;
|
|
2573
|
+
w = _w;
|
|
2574
|
+
h = _h;
|
|
2575
|
+
} else {
|
|
2576
|
+
x = 0;
|
|
2577
|
+
y = 0;
|
|
2578
|
+
w = dst.width;
|
|
2579
|
+
h = dst.height;
|
|
2709
2580
|
}
|
|
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;
|
|
2581
|
+
const clip = resolveRectClipping(x, y, w, h, dst.width, dst.height, SCRATCH_RECT2);
|
|
2582
|
+
if (!clip.inBounds) return false;
|
|
2583
|
+
const {
|
|
2584
|
+
x: finalX,
|
|
2585
|
+
y: finalY,
|
|
2586
|
+
w: actualW,
|
|
2587
|
+
h: actualH
|
|
2588
|
+
} = clip;
|
|
2589
|
+
const dst32 = dst.data32;
|
|
2590
|
+
const dw = dst.width;
|
|
2591
|
+
let hasChanged = false;
|
|
2592
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2593
|
+
const rowOffset = (finalY + iy) * dw;
|
|
2594
|
+
const start = rowOffset + finalX;
|
|
2595
|
+
const end = start + actualW;
|
|
2596
|
+
for (let i = start; i < end; i++) {
|
|
2597
|
+
if (dst32[i] !== color) {
|
|
2598
|
+
dst32[i] = color;
|
|
2599
|
+
hasChanged = true;
|
|
2751
2600
|
}
|
|
2752
2601
|
}
|
|
2753
2602
|
}
|
|
2754
|
-
return
|
|
2603
|
+
return hasChanged;
|
|
2755
2604
|
}
|
|
2756
2605
|
|
|
2757
|
-
// src/History/PixelMutator/
|
|
2606
|
+
// src/History/PixelMutator/mutatorFill.ts
|
|
2758
2607
|
var defaults8 = {
|
|
2759
|
-
|
|
2760
|
-
getRectBrushOrPencilBounds
|
|
2608
|
+
fillPixelData
|
|
2761
2609
|
};
|
|
2762
|
-
var
|
|
2610
|
+
var mutatorFill = ((writer, deps = defaults8) => {
|
|
2763
2611
|
const {
|
|
2764
|
-
|
|
2765
|
-
getRectBrushOrPencilBounds: getRectBrushOrPencilBounds2 = defaults8.getRectBrushOrPencilBounds
|
|
2612
|
+
fillPixelData: fillPixelData2 = defaults8.fillPixelData
|
|
2766
2613
|
} = deps;
|
|
2767
|
-
const boundsOut = {
|
|
2768
|
-
x: 0,
|
|
2769
|
-
y: 0,
|
|
2770
|
-
w: 0,
|
|
2771
|
-
h: 0
|
|
2772
|
-
};
|
|
2773
2614
|
return {
|
|
2774
|
-
|
|
2615
|
+
fill(color, x = 0, y = 0, w = writer.config.target.width, h = writer.config.target.height) {
|
|
2775
2616
|
const target = writer.config.target;
|
|
2776
|
-
const
|
|
2777
|
-
|
|
2778
|
-
return didChange(applyRectBrushToPixelData2(target, color, centerX, centerY, brushWidth, brushHeight, alpha, fallOff, blendFn, b));
|
|
2617
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2618
|
+
return didChange(fillPixelData2(target, color, x, y, w, h));
|
|
2779
2619
|
}
|
|
2780
2620
|
};
|
|
2781
2621
|
});
|
|
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) => {
|
|
2622
|
+
var mutatorFillRect = ((writer, deps = defaults8) => {
|
|
2806
2623
|
const {
|
|
2807
|
-
|
|
2808
|
-
blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults9.blendColorPixelDataAlphaMask,
|
|
2809
|
-
getRectBrushOrPencilBounds: getRectBrushOrPencilBounds2 = defaults9.getRectBrushOrPencilBounds,
|
|
2810
|
-
getRectBrushOrPencilStrokeBounds: getRectBrushOrPencilStrokeBounds2 = defaults9.getRectBrushOrPencilStrokeBounds
|
|
2624
|
+
fillPixelData: fillPixelData2 = defaults8.fillPixelData
|
|
2811
2625
|
} = 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
2626
|
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;
|
|
2627
|
+
fillRect(color, rect) {
|
|
2857
2628
|
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);
|
|
2629
|
+
const didChange = writer.accumulator.storeRegionBeforeState(rect.x, rect.y, rect.w, rect.h);
|
|
2630
|
+
return didChange(fillPixelData2(target, color, rect.x, rect.y, rect.w, rect.h));
|
|
2898
2631
|
}
|
|
2899
2632
|
};
|
|
2900
2633
|
});
|
|
2901
2634
|
|
|
2902
|
-
// src/
|
|
2903
|
-
var
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2635
|
+
// src/PixelData/fillPixelDataBinaryMask.ts
|
|
2636
|
+
var SCRATCH_RECT3 = makeClippedRect();
|
|
2637
|
+
function fillPixelDataBinaryMask(dst, color, mask, alpha = 255, x = 0, y = 0) {
|
|
2638
|
+
if (alpha === 0) return false;
|
|
2639
|
+
const maskW = mask.w;
|
|
2640
|
+
const maskH = mask.h;
|
|
2641
|
+
const clip = resolveRectClipping(x, y, maskW, maskH, dst.width, dst.height, SCRATCH_RECT3);
|
|
2642
|
+
if (!clip.inBounds) return false;
|
|
2909
2643
|
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
|
-
|
|
2644
|
+
x: finalX,
|
|
2645
|
+
y: finalY,
|
|
2646
|
+
w: actualW,
|
|
2647
|
+
h: actualH
|
|
2648
|
+
} = clip;
|
|
2649
|
+
const maskData = mask.data;
|
|
2650
|
+
const dst32 = dst.data32;
|
|
2651
|
+
const dw = dst.width;
|
|
2652
|
+
let finalCol = color;
|
|
2653
|
+
if (alpha < 255) {
|
|
2654
|
+
const baseSrcAlpha = color >>> 24;
|
|
2655
|
+
const colorRGB = color & 16777215;
|
|
2656
|
+
const a = baseSrcAlpha * alpha + 128 >> 8;
|
|
2657
|
+
finalCol = (colorRGB | a << 24) >>> 0;
|
|
2658
|
+
}
|
|
2659
|
+
let hasChanged = false;
|
|
2660
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2661
|
+
const currentY = finalY + iy;
|
|
2662
|
+
const maskY = currentY - y;
|
|
2663
|
+
const maskOffset = maskY * maskW;
|
|
2664
|
+
const dstRowOffset = currentY * dw;
|
|
2665
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2666
|
+
const currentX = finalX + ix;
|
|
2667
|
+
const maskX = currentX - x;
|
|
2668
|
+
const maskIndex = maskOffset + maskX;
|
|
2669
|
+
if (maskData[maskIndex]) {
|
|
2670
|
+
const current = dst32[dstRowOffset + currentX];
|
|
2671
|
+
if (current !== finalCol) {
|
|
2672
|
+
dst32[dstRowOffset + currentX] = finalCol;
|
|
2673
|
+
hasChanged = true;
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
}
|
|
2677
|
+
}
|
|
2678
|
+
return hasChanged;
|
|
2679
|
+
}
|
|
2680
|
+
|
|
2681
|
+
// src/History/PixelMutator/mutatorFillBinaryMask.ts
|
|
2682
|
+
var defaults9 = {
|
|
2683
|
+
fillPixelDataBinaryMask
|
|
2936
2684
|
};
|
|
2937
|
-
var
|
|
2685
|
+
var mutatorFillBinaryMask = ((writer, deps = defaults9) => {
|
|
2938
2686
|
const {
|
|
2939
|
-
|
|
2940
|
-
blendColorPixelDataBinaryMask: blendColorPixelDataBinaryMask2 = defaults11.blendColorPixelDataBinaryMask,
|
|
2941
|
-
getRectBrushOrPencilBounds: getRectBrushOrPencilBounds2 = defaults11.getRectBrushOrPencilBounds,
|
|
2942
|
-
getRectBrushOrPencilStrokeBounds: getRectBrushOrPencilStrokeBounds2 = defaults11.getRectBrushOrPencilStrokeBounds
|
|
2687
|
+
fillPixelDataBinaryMask: fillPixelDataBinaryMask2 = defaults9.fillPixelDataBinaryMask
|
|
2943
2688
|
} = 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
2689
|
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);
|
|
2690
|
+
fillBinaryMask(color, mask, alpha = 255, x = 0, y = 0) {
|
|
2691
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, mask.w, mask.h);
|
|
2692
|
+
return didChange(fillPixelDataBinaryMask2(writer.config.target, color, mask, alpha, x, y));
|
|
3022
2693
|
}
|
|
3023
2694
|
};
|
|
3024
2695
|
});
|
|
3025
2696
|
|
|
3026
|
-
// src/PixelData/
|
|
3027
|
-
|
|
2697
|
+
// src/PixelData/invertPixelData.ts
|
|
2698
|
+
var SCRATCH_RECT4 = makeClippedRect();
|
|
2699
|
+
function invertPixelData(pixelData, opts = {}) {
|
|
2700
|
+
const dst = pixelData;
|
|
3028
2701
|
const {
|
|
3029
2702
|
x: targetX = 0,
|
|
3030
2703
|
y: targetY = 0,
|
|
3031
|
-
w: width =
|
|
3032
|
-
h: height =
|
|
3033
|
-
|
|
3034
|
-
|
|
2704
|
+
w: width = pixelData.width,
|
|
2705
|
+
h: height = pixelData.height,
|
|
2706
|
+
mask,
|
|
2707
|
+
mx = 0,
|
|
2708
|
+
my = 0,
|
|
2709
|
+
invertMask = false
|
|
3035
2710
|
} = 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
|
-
}
|
|
2711
|
+
const clip = resolveRectClipping(targetX, targetY, width, height, dst.width, dst.height, SCRATCH_RECT4);
|
|
2712
|
+
if (!clip.inBounds) return false;
|
|
2713
|
+
const {
|
|
2714
|
+
x,
|
|
2715
|
+
y,
|
|
2716
|
+
w: actualW,
|
|
2717
|
+
h: actualH
|
|
2718
|
+
} = clip;
|
|
3061
2719
|
const dst32 = dst.data32;
|
|
3062
2720
|
const dw = dst.width;
|
|
3063
|
-
|
|
3064
|
-
const
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
2721
|
+
const mPitch = mask?.w ?? width;
|
|
2722
|
+
const dx = x - targetX;
|
|
2723
|
+
const dy = y - targetY;
|
|
2724
|
+
let dIdx = y * dw + x;
|
|
2725
|
+
let mIdx = (my + dy) * mPitch + (mx + dx);
|
|
2726
|
+
const dStride = dw - actualW;
|
|
2727
|
+
const mStride = mPitch - actualW;
|
|
2728
|
+
if (mask) {
|
|
2729
|
+
const maskData = mask.data;
|
|
2730
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2731
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2732
|
+
const mVal = maskData[mIdx];
|
|
2733
|
+
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
2734
|
+
if (isHit) {
|
|
2735
|
+
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
2736
|
+
}
|
|
2737
|
+
dIdx++;
|
|
2738
|
+
mIdx++;
|
|
3073
2739
|
}
|
|
3074
|
-
dIdx
|
|
2740
|
+
dIdx += dStride;
|
|
2741
|
+
mIdx += mStride;
|
|
2742
|
+
}
|
|
2743
|
+
} else {
|
|
2744
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2745
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2746
|
+
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
2747
|
+
dIdx++;
|
|
2748
|
+
}
|
|
2749
|
+
dIdx += dStride;
|
|
3075
2750
|
}
|
|
3076
|
-
dIdx += dStride;
|
|
3077
2751
|
}
|
|
3078
|
-
return
|
|
2752
|
+
return true;
|
|
3079
2753
|
}
|
|
3080
2754
|
|
|
3081
|
-
// src/History/PixelMutator/
|
|
3082
|
-
var
|
|
3083
|
-
|
|
2755
|
+
// src/History/PixelMutator/mutatorInvert.ts
|
|
2756
|
+
var defaults10 = {
|
|
2757
|
+
invertPixelData
|
|
3084
2758
|
};
|
|
3085
|
-
var
|
|
2759
|
+
var mutatorInvert = ((writer, deps = defaults10) => {
|
|
3086
2760
|
const {
|
|
3087
|
-
|
|
2761
|
+
invertPixelData: invertPixelData2 = defaults10.invertPixelData
|
|
3088
2762
|
} = deps;
|
|
3089
2763
|
return {
|
|
3090
|
-
|
|
2764
|
+
invert(opts = {}) {
|
|
3091
2765
|
const target = writer.config.target;
|
|
3092
2766
|
const {
|
|
3093
2767
|
x = 0,
|
|
@@ -3096,708 +2770,644 @@ var mutatorBlendColor = ((writer, deps = defaults12) => {
|
|
|
3096
2770
|
h = target.height
|
|
3097
2771
|
} = opts;
|
|
3098
2772
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3099
|
-
return didChange(
|
|
2773
|
+
return didChange(invertPixelData2(target, opts));
|
|
3100
2774
|
}
|
|
3101
2775
|
};
|
|
3102
2776
|
});
|
|
3103
2777
|
|
|
3104
|
-
// src/
|
|
3105
|
-
function
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
2778
|
+
// src/History/PixelMutator.ts
|
|
2779
|
+
function makeFullPixelMutator(writer) {
|
|
2780
|
+
return {
|
|
2781
|
+
// @sort
|
|
2782
|
+
...mutatorBlendColor(writer),
|
|
2783
|
+
...mutatorBlendPixel(writer),
|
|
2784
|
+
...mutatorBlendPixelData(writer),
|
|
2785
|
+
...mutatorBlendPixelDataAlphaMask(writer),
|
|
2786
|
+
...mutatorBlendPixelDataBinaryMask(writer),
|
|
2787
|
+
...mutatorClear(writer),
|
|
2788
|
+
...mutatorFill(writer),
|
|
2789
|
+
...mutatorFillBinaryMask(writer),
|
|
2790
|
+
...mutatorFillRect(writer),
|
|
2791
|
+
...mutatorInvert(writer)
|
|
2792
|
+
};
|
|
2793
|
+
}
|
|
2794
|
+
|
|
2795
|
+
// src/ImageData/resizeImageData.ts
|
|
2796
|
+
function resizeImageData(target, newWidth, newHeight, offsetX = 0, offsetY = 0) {
|
|
2797
|
+
const result = new ImageData(newWidth, newHeight);
|
|
2798
|
+
const {
|
|
2799
|
+
width: oldW,
|
|
2800
|
+
height: oldH,
|
|
2801
|
+
data: oldData
|
|
2802
|
+
} = target;
|
|
2803
|
+
const newData = result.data;
|
|
2804
|
+
const x0 = Math.max(0, offsetX);
|
|
2805
|
+
const y0 = Math.max(0, offsetY);
|
|
2806
|
+
const x1 = Math.min(newWidth, offsetX + oldW);
|
|
2807
|
+
const y1 = Math.min(newHeight, offsetY + oldH);
|
|
2808
|
+
if (x1 <= x0 || y1 <= y0) {
|
|
2809
|
+
return result;
|
|
3120
2810
|
}
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
2811
|
+
const rowCount = y1 - y0;
|
|
2812
|
+
const rowLen = (x1 - x0) * 4;
|
|
2813
|
+
for (let row = 0; row < rowCount; row++) {
|
|
2814
|
+
const dstY = y0 + row;
|
|
2815
|
+
const srcY = dstY - offsetY;
|
|
2816
|
+
const srcX = x0 - offsetX;
|
|
2817
|
+
const dstStart = (dstY * newWidth + x0) * 4;
|
|
2818
|
+
const srcStart = (srcY * oldW + srcX) * 4;
|
|
2819
|
+
newData.set(oldData.subarray(srcStart, srcStart + rowLen), dstStart);
|
|
3126
2820
|
}
|
|
3127
|
-
return
|
|
2821
|
+
return result;
|
|
3128
2822
|
}
|
|
3129
2823
|
|
|
3130
|
-
// src/
|
|
3131
|
-
var
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
const {
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
const didChange = writer.accumulator.storePixelBeforeState(x, y);
|
|
3141
|
-
return didChange(blendPixel2(writer.config.target, x, y, color, alpha, blendFn));
|
|
3142
|
-
}
|
|
2824
|
+
// src/Internal/helpers.ts
|
|
2825
|
+
var macro_halfAndFloor = (value) => value >> 1;
|
|
2826
|
+
|
|
2827
|
+
// src/Rect/trimRectBounds.ts
|
|
2828
|
+
function trimRectBounds(x, y, w, h, targetWidth, targetHeight, out) {
|
|
2829
|
+
const res = out ?? {
|
|
2830
|
+
x: 0,
|
|
2831
|
+
y: 0,
|
|
2832
|
+
w: 0,
|
|
2833
|
+
h: 0
|
|
3143
2834
|
};
|
|
3144
|
-
|
|
2835
|
+
const left = Math.max(0, x);
|
|
2836
|
+
const top = Math.max(0, y);
|
|
2837
|
+
const right = Math.min(targetWidth, x + w);
|
|
2838
|
+
const bottom = Math.min(targetHeight, y + h);
|
|
2839
|
+
res.x = left;
|
|
2840
|
+
res.y = top;
|
|
2841
|
+
res.w = Math.max(0, right - left);
|
|
2842
|
+
res.h = Math.max(0, bottom - top);
|
|
2843
|
+
return res;
|
|
2844
|
+
}
|
|
3145
2845
|
|
|
3146
|
-
// src/
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
sy: sourceY = 0,
|
|
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
|
-
}
|
|
3396
|
-
};
|
|
3397
|
-
});
|
|
3398
|
-
|
|
3399
|
-
// src/PixelData/blendPixelDataBinaryMask.ts
|
|
3400
|
-
function blendPixelDataBinaryMask(dst, src, binaryMask, opts = {}) {
|
|
3401
|
-
const {
|
|
3402
|
-
x: targetX = 0,
|
|
3403
|
-
y: targetY = 0,
|
|
3404
|
-
sx: sourceX = 0,
|
|
3405
|
-
sy: sourceY = 0,
|
|
3406
|
-
w: width = src.width,
|
|
3407
|
-
h: height = src.height,
|
|
3408
|
-
alpha: globalAlpha = 255,
|
|
3409
|
-
blendFn = sourceOverPerfect,
|
|
3410
|
-
mx = 0,
|
|
3411
|
-
my = 0,
|
|
3412
|
-
invertMask = false
|
|
3413
|
-
} = opts;
|
|
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;
|
|
2846
|
+
// src/Paint/PaintBuffer.ts
|
|
2847
|
+
var PaintBuffer = class {
|
|
2848
|
+
constructor(config, tilePool) {
|
|
2849
|
+
this.config = config;
|
|
2850
|
+
this.tilePool = tilePool;
|
|
2851
|
+
this.lookup = [];
|
|
3442
2852
|
}
|
|
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;
|
|
2853
|
+
lookup;
|
|
2854
|
+
scratchBounds = {
|
|
2855
|
+
x: 0,
|
|
2856
|
+
y: 0,
|
|
2857
|
+
w: 0,
|
|
2858
|
+
h: 0
|
|
2859
|
+
};
|
|
2860
|
+
eachTileInBounds(bounds, callback) {
|
|
2861
|
+
const {
|
|
2862
|
+
tileShift,
|
|
2863
|
+
targetColumns,
|
|
2864
|
+
targetRows,
|
|
2865
|
+
tileSize
|
|
2866
|
+
} = this.config;
|
|
2867
|
+
const x1 = Math.max(0, bounds.x >> tileShift);
|
|
2868
|
+
const y1 = Math.max(0, bounds.y >> tileShift);
|
|
2869
|
+
const x2 = Math.min(targetColumns - 1, bounds.x + bounds.w - 1 >> tileShift);
|
|
2870
|
+
const y2 = Math.min(targetRows - 1, bounds.y + bounds.h - 1 >> tileShift);
|
|
2871
|
+
if (x1 > x2 || y1 > y2) return;
|
|
2872
|
+
const lookup = this.lookup;
|
|
2873
|
+
const tilePool = this.tilePool;
|
|
2874
|
+
for (let ty = y1; ty <= y2; ty++) {
|
|
2875
|
+
const rowOffset = ty * targetColumns;
|
|
2876
|
+
const tileTop = ty << tileShift;
|
|
2877
|
+
for (let tx = x1; tx <= x2; tx++) {
|
|
2878
|
+
const id = rowOffset + tx;
|
|
2879
|
+
const tile = lookup[id] ?? (lookup[id] = tilePool.getTile(id, tx, ty));
|
|
2880
|
+
const tileLeft = tx << tileShift;
|
|
2881
|
+
const startX = bounds.x > tileLeft ? bounds.x : tileLeft;
|
|
2882
|
+
const startY = bounds.y > tileTop ? bounds.y : tileTop;
|
|
2883
|
+
const maskEndX = bounds.x + bounds.w;
|
|
2884
|
+
const tileEndX = tileLeft + tileSize;
|
|
2885
|
+
const endX = maskEndX < tileEndX ? maskEndX : tileEndX;
|
|
2886
|
+
const maskEndY = bounds.y + bounds.h;
|
|
2887
|
+
const tileEndY = tileTop + tileSize;
|
|
2888
|
+
const endY = maskEndY < tileEndY ? maskEndY : tileEndY;
|
|
2889
|
+
callback(tile, startX, startY, endX - startX, endY - startY);
|
|
3496
2890
|
}
|
|
3497
|
-
dIdx++;
|
|
3498
|
-
sIdx++;
|
|
3499
|
-
mIdx++;
|
|
3500
2891
|
}
|
|
3501
|
-
dIdx += dStride;
|
|
3502
|
-
sIdx += sStride;
|
|
3503
|
-
mIdx += mStride;
|
|
3504
2892
|
}
|
|
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
|
-
|
|
2893
|
+
writePaintAlphaMaskStroke(color, brush, x0, y0, x1, y1) {
|
|
2894
|
+
const cA = color >>> 24;
|
|
2895
|
+
if (cA === 0) return false;
|
|
2896
|
+
const {
|
|
2897
|
+
tileShift,
|
|
2898
|
+
tileMask,
|
|
2899
|
+
target
|
|
2900
|
+
} = this.config;
|
|
2901
|
+
const {
|
|
2902
|
+
w: bW,
|
|
2903
|
+
h: bH,
|
|
2904
|
+
data: bD,
|
|
2905
|
+
centerOffsetX,
|
|
2906
|
+
centerOffsetY
|
|
2907
|
+
} = brush;
|
|
2908
|
+
const cRGB = color & 16777215;
|
|
2909
|
+
const scratch = this.scratchBounds;
|
|
2910
|
+
let changed = false;
|
|
2911
|
+
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
2912
|
+
const topLeftX = Math.floor(px + centerOffsetX);
|
|
2913
|
+
const topLeftY = Math.floor(py + centerOffsetY);
|
|
2914
|
+
trimRectBounds(topLeftX, topLeftY, bW, bH, target.width, target.height, scratch);
|
|
2915
|
+
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
2916
|
+
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
2917
|
+
const d32 = tile.data32;
|
|
2918
|
+
let tileChanged = false;
|
|
2919
|
+
for (let i = 0; i < bH_t; i++) {
|
|
2920
|
+
const canvasY = bY + i;
|
|
2921
|
+
const bOff = (canvasY - topLeftY) * bW;
|
|
2922
|
+
const tOff = (canvasY & tileMask) << tileShift;
|
|
2923
|
+
const dS = tOff + (bX & tileMask);
|
|
2924
|
+
for (let j = 0; j < bW_t; j++) {
|
|
2925
|
+
const canvasX = bX + j;
|
|
2926
|
+
const brushA = bD[bOff + (canvasX - topLeftX)];
|
|
2927
|
+
if (brushA === 0) continue;
|
|
2928
|
+
const t = cA * brushA + 128;
|
|
2929
|
+
const blendedA = t + (t >> 8) >> 8;
|
|
2930
|
+
const idx = dS + j;
|
|
2931
|
+
const cur = d32[idx];
|
|
2932
|
+
if (brushA > cur >>> 24) {
|
|
2933
|
+
const next = (cRGB | blendedA << 24) >>> 0;
|
|
2934
|
+
if (cur !== next) {
|
|
2935
|
+
d32[idx] = next;
|
|
2936
|
+
tileChanged = true;
|
|
2937
|
+
}
|
|
2938
|
+
}
|
|
2939
|
+
}
|
|
2940
|
+
}
|
|
2941
|
+
if (tileChanged) changed = true;
|
|
2942
|
+
});
|
|
2943
|
+
});
|
|
2944
|
+
return changed;
|
|
3550
2945
|
}
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
2946
|
+
writePaintBinaryMaskStroke(color, brush, x0, y0, x1, y1) {
|
|
2947
|
+
const alphaIsZero = color >>> 24 === 0;
|
|
2948
|
+
if (alphaIsZero) return false;
|
|
2949
|
+
const {
|
|
2950
|
+
tileShift,
|
|
2951
|
+
tileMask,
|
|
2952
|
+
target
|
|
2953
|
+
} = this.config;
|
|
2954
|
+
const {
|
|
2955
|
+
w: bW,
|
|
2956
|
+
h: bH,
|
|
2957
|
+
data: bD,
|
|
2958
|
+
centerOffsetX,
|
|
2959
|
+
centerOffsetY
|
|
2960
|
+
} = brush;
|
|
2961
|
+
const scratch = this.scratchBounds;
|
|
2962
|
+
let changed = false;
|
|
2963
|
+
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
2964
|
+
const topLeftX = Math.floor(px + centerOffsetX);
|
|
2965
|
+
const topLeftY = Math.floor(py + centerOffsetY);
|
|
2966
|
+
trimRectBounds(topLeftX, topLeftY, bW, bH, target.width, target.height, scratch);
|
|
2967
|
+
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
2968
|
+
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
2969
|
+
const d32 = tile.data32;
|
|
2970
|
+
let tileChanged = false;
|
|
2971
|
+
for (let i = 0; i < bH_t; i++) {
|
|
2972
|
+
const canvasY = bY + i;
|
|
2973
|
+
const bOff = (canvasY - topLeftY) * bW;
|
|
2974
|
+
const tOff = (canvasY & tileMask) << tileShift;
|
|
2975
|
+
const dS = tOff + (bX & tileMask);
|
|
2976
|
+
for (let j = 0; j < bW_t; j++) {
|
|
2977
|
+
const canvasX = bX + j;
|
|
2978
|
+
if (bD[bOff + (canvasX - topLeftX)]) {
|
|
2979
|
+
const idx = dS + j;
|
|
2980
|
+
if (d32[idx] !== color) {
|
|
2981
|
+
d32[idx] = color;
|
|
2982
|
+
tileChanged = true;
|
|
2983
|
+
}
|
|
2984
|
+
}
|
|
2985
|
+
}
|
|
2986
|
+
}
|
|
2987
|
+
if (tileChanged) changed = true;
|
|
2988
|
+
});
|
|
2989
|
+
});
|
|
2990
|
+
return changed;
|
|
2991
|
+
}
|
|
2992
|
+
writeRectStroke(color, brushWidth, brushHeight, x0, y0, x1, y1) {
|
|
2993
|
+
const alphaIsZero = color >>> 24 === 0;
|
|
2994
|
+
if (alphaIsZero) return false;
|
|
2995
|
+
const config = this.config;
|
|
2996
|
+
const tileShift = config.tileShift;
|
|
2997
|
+
const tileMask = config.tileMask;
|
|
2998
|
+
const target = config.target;
|
|
2999
|
+
const scratch = this.scratchBounds;
|
|
3000
|
+
const centerOffsetX = macro_halfAndFloor(brushWidth - 1);
|
|
3001
|
+
const centerOffsetY = macro_halfAndFloor(brushHeight - 1);
|
|
3002
|
+
let changed = false;
|
|
3003
|
+
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
3004
|
+
const topLeftX = Math.floor(px + centerOffsetX);
|
|
3005
|
+
const topLeftY = Math.floor(py + centerOffsetY);
|
|
3006
|
+
trimRectBounds(topLeftX, topLeftY, brushWidth, brushHeight, target.width, target.height, scratch);
|
|
3007
|
+
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
3008
|
+
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
3009
|
+
const d32 = tile.data32;
|
|
3010
|
+
let tileChanged = false;
|
|
3011
|
+
for (let i = 0; i < bH_t; i++) {
|
|
3012
|
+
const canvasY = bY + i;
|
|
3013
|
+
const tOff = (canvasY & tileMask) << tileShift;
|
|
3014
|
+
const dS = tOff + (bX & tileMask);
|
|
3015
|
+
for (let j = 0; j < bW_t; j++) {
|
|
3016
|
+
const idx = dS + j;
|
|
3017
|
+
if (d32[idx] !== color) {
|
|
3018
|
+
d32[idx] = color;
|
|
3019
|
+
tileChanged = true;
|
|
3020
|
+
}
|
|
3021
|
+
}
|
|
3022
|
+
}
|
|
3023
|
+
if (tileChanged) {
|
|
3024
|
+
changed = true;
|
|
3025
|
+
}
|
|
3026
|
+
});
|
|
3027
|
+
});
|
|
3028
|
+
return changed;
|
|
3564
3029
|
}
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
const end = start + actualW;
|
|
3568
|
-
dst32.fill(color, start, end);
|
|
3030
|
+
clear() {
|
|
3031
|
+
this.tilePool.releaseTiles(this.lookup);
|
|
3569
3032
|
}
|
|
3570
|
-
}
|
|
3033
|
+
};
|
|
3571
3034
|
|
|
3572
|
-
// src/
|
|
3573
|
-
var
|
|
3574
|
-
|
|
3035
|
+
// src/PixelTile/PixelTile.ts
|
|
3036
|
+
var PixelTile = class {
|
|
3037
|
+
constructor(id, tx, ty, tileSize, tileArea) {
|
|
3038
|
+
this.id = id;
|
|
3039
|
+
this.tx = tx;
|
|
3040
|
+
this.ty = ty;
|
|
3041
|
+
this.width = this.height = tileSize;
|
|
3042
|
+
this.data32 = new Uint32Array(tileArea);
|
|
3043
|
+
const data8 = new Uint8ClampedArray(this.data32.buffer);
|
|
3044
|
+
this.imageData = new ImageData(data8, tileSize, tileSize);
|
|
3045
|
+
}
|
|
3046
|
+
data32;
|
|
3047
|
+
width;
|
|
3048
|
+
height;
|
|
3049
|
+
imageData;
|
|
3575
3050
|
};
|
|
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
3051
|
|
|
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;
|
|
3052
|
+
// src/PixelTile/PixelTilePool.ts
|
|
3053
|
+
var PixelTilePool = class {
|
|
3054
|
+
pool;
|
|
3055
|
+
tileSize;
|
|
3056
|
+
tileArea;
|
|
3057
|
+
constructor(config) {
|
|
3058
|
+
this.pool = [];
|
|
3059
|
+
this.tileSize = config.tileSize;
|
|
3060
|
+
this.tileArea = config.tileArea;
|
|
3615
3061
|
}
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3062
|
+
getTile(id, tx, ty) {
|
|
3063
|
+
let tile = this.pool.pop();
|
|
3064
|
+
if (tile) {
|
|
3065
|
+
tile.id = id;
|
|
3066
|
+
tile.tx = tx;
|
|
3067
|
+
tile.ty = ty;
|
|
3068
|
+
tile.data32.fill(0);
|
|
3069
|
+
return tile;
|
|
3070
|
+
}
|
|
3071
|
+
return new PixelTile(id, tx, ty, this.tileSize, this.tileArea);
|
|
3072
|
+
}
|
|
3073
|
+
releaseTile(tile) {
|
|
3074
|
+
this.pool.push(tile);
|
|
3075
|
+
}
|
|
3076
|
+
releaseTiles(tiles) {
|
|
3077
|
+
let length = tiles.length;
|
|
3078
|
+
for (let i = 0; i < length; i++) {
|
|
3079
|
+
let tile = tiles[i];
|
|
3080
|
+
if (tile) {
|
|
3081
|
+
this.pool.push(tile);
|
|
3635
3082
|
}
|
|
3636
3083
|
}
|
|
3084
|
+
tiles.length = 0;
|
|
3637
3085
|
}
|
|
3638
|
-
return hasChanged;
|
|
3639
|
-
}
|
|
3640
|
-
|
|
3641
|
-
// src/History/PixelMutator/mutatorFill.ts
|
|
3642
|
-
var defaults18 = {
|
|
3643
|
-
fillPixelData
|
|
3644
3086
|
};
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3087
|
+
|
|
3088
|
+
// src/History/PixelWriter.ts
|
|
3089
|
+
var PixelWriter = class {
|
|
3090
|
+
historyManager;
|
|
3091
|
+
accumulator;
|
|
3092
|
+
historyActionFactory;
|
|
3093
|
+
config;
|
|
3094
|
+
pixelTilePool;
|
|
3095
|
+
paintBuffer;
|
|
3096
|
+
mutator;
|
|
3097
|
+
blendPixelDataOpts = {
|
|
3098
|
+
alpha: 255,
|
|
3099
|
+
blendFn: sourceOverPerfect,
|
|
3100
|
+
x: 0,
|
|
3101
|
+
y: 0,
|
|
3102
|
+
w: 0,
|
|
3103
|
+
h: 0
|
|
3655
3104
|
};
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3105
|
+
_inProgress = false;
|
|
3106
|
+
constructor(target, mutatorFactory, {
|
|
3107
|
+
tileSize = 256,
|
|
3108
|
+
maxHistorySteps = 50,
|
|
3109
|
+
historyManager = new HistoryManager(maxHistorySteps),
|
|
3110
|
+
historyActionFactory = makeHistoryAction,
|
|
3111
|
+
pixelTilePool,
|
|
3112
|
+
accumulator
|
|
3113
|
+
} = {}) {
|
|
3114
|
+
this.config = new PixelEngineConfig(tileSize, target);
|
|
3115
|
+
this.historyManager = historyManager;
|
|
3116
|
+
this.pixelTilePool = pixelTilePool ?? new PixelTilePool(this.config);
|
|
3117
|
+
this.accumulator = accumulator ?? new PixelAccumulator(this.config, this.pixelTilePool);
|
|
3118
|
+
this.historyActionFactory = historyActionFactory;
|
|
3119
|
+
this.mutator = mutatorFactory(this);
|
|
3120
|
+
this.paintBuffer = new PaintBuffer(this.config, this.pixelTilePool);
|
|
3121
|
+
}
|
|
3122
|
+
/**
|
|
3123
|
+
* Executes `transaction` and commits the resulting pixel changes as a single
|
|
3124
|
+
* undoable history action.
|
|
3125
|
+
*
|
|
3126
|
+
* - If `transaction` throws, all accumulated changes are rolled back and the error
|
|
3127
|
+
* is re-thrown. No action is committed.
|
|
3128
|
+
* - If `transaction` completes without modifying any pixels, no action is committed.
|
|
3129
|
+
* - `withHistory` is not re-entrant. Calling it again from inside `transaction` will
|
|
3130
|
+
* throw immediately to prevent silent data loss from a nested extractPatch.
|
|
3131
|
+
*
|
|
3132
|
+
* @param transaction Callback to be executed inside the transaction.
|
|
3133
|
+
* @param after Called after both undo and redo — use for generic change notifications.
|
|
3134
|
+
* @param afterUndo Called after undo only — use for dimension or state changes specific to undo.
|
|
3135
|
+
* @param afterRedo Called after redo only.
|
|
3136
|
+
*/
|
|
3137
|
+
withHistory(transaction, after, afterUndo, afterRedo) {
|
|
3138
|
+
if (this._inProgress) {
|
|
3139
|
+
throw new Error("withHistory is not re-entrant \u2014 commit or rollback the current operation first");
|
|
3666
3140
|
}
|
|
3667
|
-
|
|
3668
|
-
|
|
3141
|
+
this._inProgress = true;
|
|
3142
|
+
try {
|
|
3143
|
+
transaction(this.mutator);
|
|
3144
|
+
} catch (e) {
|
|
3145
|
+
this.accumulator.rollbackAfterError();
|
|
3146
|
+
throw e;
|
|
3147
|
+
} finally {
|
|
3148
|
+
this._inProgress = false;
|
|
3149
|
+
}
|
|
3150
|
+
if (this.accumulator.beforeTiles.length === 0) return;
|
|
3151
|
+
const patch = this.accumulator.extractPatch();
|
|
3152
|
+
const action = this.historyActionFactory(this, patch, after, afterUndo, afterRedo);
|
|
3153
|
+
this.historyManager.commit(action);
|
|
3154
|
+
}
|
|
3155
|
+
resize(newWidth, newHeight, offsetX = 0, offsetY = 0, after, afterUndo, afterRedo, resizeImageDataFn = resizeImageData) {
|
|
3156
|
+
if (this._inProgress) {
|
|
3157
|
+
throw new Error("Cannot resize inside a withHistory callback");
|
|
3158
|
+
}
|
|
3159
|
+
if (this.accumulator.beforeTiles.length > 0) {
|
|
3160
|
+
throw new Error("Cannot resize with an open accumulator \u2014 commit or rollback first");
|
|
3161
|
+
}
|
|
3162
|
+
const config = this.config;
|
|
3163
|
+
const target = config.target;
|
|
3164
|
+
const beforeImageData = target.imageData;
|
|
3165
|
+
const afterImageData = resizeImageDataFn(beforeImageData, newWidth, newHeight, offsetX, offsetY);
|
|
3166
|
+
target.set(afterImageData);
|
|
3167
|
+
this.historyManager.commit({
|
|
3168
|
+
undo: () => {
|
|
3169
|
+
target.set(beforeImageData);
|
|
3170
|
+
afterUndo?.(beforeImageData);
|
|
3171
|
+
after?.(beforeImageData);
|
|
3172
|
+
},
|
|
3173
|
+
redo: () => {
|
|
3174
|
+
target.set(afterImageData);
|
|
3175
|
+
afterRedo?.(afterImageData);
|
|
3176
|
+
after?.(afterImageData);
|
|
3177
|
+
}
|
|
3178
|
+
});
|
|
3179
|
+
}
|
|
3180
|
+
commitPaintBuffer(alpha = 255, blendFn = sourceOverPerfect, blendPixelDataFn = blendPixelData) {
|
|
3181
|
+
const paintBuffer = this.paintBuffer;
|
|
3182
|
+
const tileShift = paintBuffer.config.tileShift;
|
|
3183
|
+
const lookup = paintBuffer.lookup;
|
|
3184
|
+
const opts = this.blendPixelDataOpts;
|
|
3185
|
+
opts.alpha = alpha;
|
|
3186
|
+
opts.blendFn = blendFn;
|
|
3187
|
+
for (let i = 0; i < lookup.length; i++) {
|
|
3188
|
+
const tile = lookup[i];
|
|
3189
|
+
if (tile) {
|
|
3190
|
+
const didChange = this.accumulator.storeTileBeforeState(tile.id, tile.tx, tile.ty);
|
|
3191
|
+
const dx = tile.tx << tileShift;
|
|
3192
|
+
const dy = tile.ty << tileShift;
|
|
3193
|
+
opts.x = dx;
|
|
3194
|
+
opts.y = dy;
|
|
3195
|
+
opts.w = tile.width;
|
|
3196
|
+
opts.h = tile.height;
|
|
3197
|
+
didChange(blendPixelDataFn(this.config.target, tile, opts));
|
|
3198
|
+
}
|
|
3199
|
+
}
|
|
3200
|
+
paintBuffer.clear();
|
|
3201
|
+
}
|
|
3202
|
+
};
|
|
3669
3203
|
|
|
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;
|
|
3204
|
+
// src/PixelData/applyAlphaMaskToPixelData.ts
|
|
3205
|
+
function applyAlphaMaskToPixelData(dst, mask, opts = {}) {
|
|
3678
3206
|
const {
|
|
3679
|
-
x:
|
|
3680
|
-
y:
|
|
3681
|
-
w:
|
|
3682
|
-
h:
|
|
3683
|
-
|
|
3684
|
-
|
|
3207
|
+
x: targetX = 0,
|
|
3208
|
+
y: targetY = 0,
|
|
3209
|
+
w: width = dst.width,
|
|
3210
|
+
h: height = dst.height,
|
|
3211
|
+
alpha: globalAlpha = 255,
|
|
3212
|
+
mx = 0,
|
|
3213
|
+
my = 0,
|
|
3214
|
+
invertMask = false
|
|
3215
|
+
} = opts;
|
|
3216
|
+
if (globalAlpha === 0) return false;
|
|
3217
|
+
let x = targetX;
|
|
3218
|
+
let y = targetY;
|
|
3219
|
+
let w = width;
|
|
3220
|
+
let h = height;
|
|
3221
|
+
if (x < 0) {
|
|
3222
|
+
w += x;
|
|
3223
|
+
x = 0;
|
|
3224
|
+
}
|
|
3225
|
+
if (y < 0) {
|
|
3226
|
+
h += y;
|
|
3227
|
+
y = 0;
|
|
3228
|
+
}
|
|
3229
|
+
w = Math.min(w, dst.width - x);
|
|
3230
|
+
h = Math.min(h, dst.height - y);
|
|
3231
|
+
if (w <= 0) return false;
|
|
3232
|
+
if (h <= 0) return false;
|
|
3233
|
+
const mPitch = mask.w;
|
|
3234
|
+
if (mPitch <= 0) return false;
|
|
3235
|
+
const startX = mx + (x - targetX);
|
|
3236
|
+
const startY = my + (y - targetY);
|
|
3237
|
+
const sX0 = Math.max(0, startX);
|
|
3238
|
+
const sY0 = Math.max(0, startY);
|
|
3239
|
+
const sX1 = Math.min(mPitch, startX + w);
|
|
3240
|
+
const sY1 = Math.min(mask.h, startY + h);
|
|
3241
|
+
const finalW = sX1 - sX0;
|
|
3242
|
+
const finalH = sY1 - sY0;
|
|
3243
|
+
if (finalW <= 0) return false;
|
|
3244
|
+
if (finalH <= 0) return false;
|
|
3245
|
+
const xShift = sX0 - startX;
|
|
3246
|
+
const yShift = sY0 - startY;
|
|
3685
3247
|
const dst32 = dst.data32;
|
|
3686
3248
|
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
|
-
|
|
3249
|
+
const dStride = dw - finalW;
|
|
3250
|
+
const mStride = mPitch - finalW;
|
|
3251
|
+
const maskData = mask.data;
|
|
3252
|
+
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
3253
|
+
let mIdx = sY0 * mPitch + sX0;
|
|
3254
|
+
let didChange = false;
|
|
3255
|
+
for (let iy = 0; iy < h; iy++) {
|
|
3256
|
+
for (let ix = 0; ix < w; ix++) {
|
|
3257
|
+
const mVal = maskData[mIdx];
|
|
3258
|
+
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
3259
|
+
let weight = 0;
|
|
3260
|
+
if (effectiveM === 0) {
|
|
3261
|
+
weight = 0;
|
|
3262
|
+
} else if (effectiveM === 255) {
|
|
3263
|
+
weight = globalAlpha;
|
|
3264
|
+
} else if (globalAlpha === 255) {
|
|
3265
|
+
weight = effectiveM;
|
|
3266
|
+
} else {
|
|
3267
|
+
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
3268
|
+
}
|
|
3269
|
+
if (weight === 0) {
|
|
3270
|
+
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
3271
|
+
didChange = true;
|
|
3272
|
+
} else if (weight !== 255) {
|
|
3273
|
+
const d = dst32[dIdx];
|
|
3274
|
+
const da = d >>> 24;
|
|
3275
|
+
if (da !== 0) {
|
|
3276
|
+
const finalAlpha = da === 255 ? weight : da * weight + 128 >> 8;
|
|
3277
|
+
const current = dst32[dIdx];
|
|
3278
|
+
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
3279
|
+
if (current !== next) {
|
|
3280
|
+
dst32[dIdx] = next;
|
|
3281
|
+
didChange = true;
|
|
3282
|
+
}
|
|
3709
3283
|
}
|
|
3710
3284
|
}
|
|
3285
|
+
dIdx++;
|
|
3286
|
+
mIdx++;
|
|
3711
3287
|
}
|
|
3288
|
+
dIdx += dStride;
|
|
3289
|
+
mIdx += mStride;
|
|
3712
3290
|
}
|
|
3713
|
-
return
|
|
3291
|
+
return didChange;
|
|
3714
3292
|
}
|
|
3715
3293
|
|
|
3716
|
-
// src/History/PixelMutator/
|
|
3717
|
-
var
|
|
3718
|
-
|
|
3294
|
+
// src/History/PixelMutator/mutatorApplyAlphaMask.ts
|
|
3295
|
+
var defaults11 = {
|
|
3296
|
+
applyAlphaMaskToPixelData
|
|
3719
3297
|
};
|
|
3720
|
-
var
|
|
3298
|
+
var mutatorApplyAlphaMask = ((writer, deps = defaults11) => {
|
|
3721
3299
|
const {
|
|
3722
|
-
|
|
3300
|
+
applyAlphaMaskToPixelData: applyAlphaMaskToPixelData2 = defaults11.applyAlphaMaskToPixelData
|
|
3723
3301
|
} = deps;
|
|
3724
3302
|
return {
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3303
|
+
applyAlphaMask(mask, opts = {}) {
|
|
3304
|
+
let target = writer.config.target;
|
|
3305
|
+
const {
|
|
3306
|
+
x = 0,
|
|
3307
|
+
y = 0,
|
|
3308
|
+
w = target.width,
|
|
3309
|
+
h = target.height
|
|
3310
|
+
} = opts;
|
|
3311
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3312
|
+
return didChange(applyAlphaMaskToPixelData2(target, mask, opts));
|
|
3728
3313
|
}
|
|
3729
3314
|
};
|
|
3730
3315
|
});
|
|
3731
3316
|
|
|
3732
|
-
// src/PixelData/
|
|
3733
|
-
|
|
3734
|
-
function invertPixelData(pixelData, opts = {}) {
|
|
3735
|
-
const dst = pixelData;
|
|
3317
|
+
// src/PixelData/applyBinaryMaskToPixelData.ts
|
|
3318
|
+
function applyBinaryMaskToPixelData(dst, mask, opts = {}) {
|
|
3736
3319
|
const {
|
|
3737
3320
|
x: targetX = 0,
|
|
3738
3321
|
y: targetY = 0,
|
|
3739
|
-
w: width =
|
|
3740
|
-
h: height =
|
|
3741
|
-
|
|
3322
|
+
w: width = dst.width,
|
|
3323
|
+
h: height = dst.height,
|
|
3324
|
+
alpha: globalAlpha = 255,
|
|
3742
3325
|
mx = 0,
|
|
3743
3326
|
my = 0,
|
|
3744
3327
|
invertMask = false
|
|
3745
3328
|
} = opts;
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3329
|
+
if (globalAlpha === 0) return false;
|
|
3330
|
+
let x = targetX;
|
|
3331
|
+
let y = targetY;
|
|
3332
|
+
let w = width;
|
|
3333
|
+
let h = height;
|
|
3334
|
+
if (x < 0) {
|
|
3335
|
+
w += x;
|
|
3336
|
+
x = 0;
|
|
3337
|
+
}
|
|
3338
|
+
if (y < 0) {
|
|
3339
|
+
h += y;
|
|
3340
|
+
y = 0;
|
|
3341
|
+
}
|
|
3342
|
+
w = Math.min(w, dst.width - x);
|
|
3343
|
+
h = Math.min(h, dst.height - y);
|
|
3344
|
+
if (w <= 0 || h <= 0) return false;
|
|
3345
|
+
const mPitch = mask.w;
|
|
3346
|
+
if (mPitch <= 0) return false;
|
|
3347
|
+
const startX = mx + (x - targetX);
|
|
3348
|
+
const startY = my + (y - targetY);
|
|
3349
|
+
const sX0 = Math.max(0, startX);
|
|
3350
|
+
const sY0 = Math.max(0, startY);
|
|
3351
|
+
const sX1 = Math.min(mPitch, startX + w);
|
|
3352
|
+
const sY1 = Math.min(mask.h, startY + h);
|
|
3353
|
+
const finalW = sX1 - sX0;
|
|
3354
|
+
const finalH = sY1 - sY0;
|
|
3355
|
+
if (finalW <= 0 || finalH <= 0) {
|
|
3356
|
+
return false;
|
|
3357
|
+
}
|
|
3358
|
+
const xShift = sX0 - startX;
|
|
3359
|
+
const yShift = sY0 - startY;
|
|
3754
3360
|
const dst32 = dst.data32;
|
|
3755
3361
|
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] =
|
|
3362
|
+
const dStride = dw - finalW;
|
|
3363
|
+
const mStride = mPitch - finalW;
|
|
3364
|
+
const maskData = mask.data;
|
|
3365
|
+
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
3366
|
+
let mIdx = sY0 * mPitch + sX0;
|
|
3367
|
+
let didChange = false;
|
|
3368
|
+
for (let iy = 0; iy < finalH; iy++) {
|
|
3369
|
+
for (let ix = 0; ix < finalW; ix++) {
|
|
3370
|
+
const mVal = maskData[mIdx];
|
|
3371
|
+
const isMaskedOut = invertMask ? mVal !== 0 : mVal === 0;
|
|
3372
|
+
if (isMaskedOut) {
|
|
3373
|
+
const current = dst32[dIdx];
|
|
3374
|
+
const next = (current & 16777215) >>> 0;
|
|
3375
|
+
if (current !== next) {
|
|
3376
|
+
dst32[dIdx] = next;
|
|
3377
|
+
didChange = true;
|
|
3378
|
+
}
|
|
3379
|
+
} else if (globalAlpha !== 255) {
|
|
3380
|
+
const d = dst32[dIdx];
|
|
3381
|
+
const da = d >>> 24;
|
|
3382
|
+
if (da !== 0) {
|
|
3383
|
+
const finalAlpha = da === 255 ? globalAlpha : da * globalAlpha + 128 >> 8;
|
|
3384
|
+
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
3385
|
+
if (d !== next) {
|
|
3386
|
+
dst32[dIdx] = next;
|
|
3387
|
+
didChange = true;
|
|
3388
|
+
}
|
|
3771
3389
|
}
|
|
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
3390
|
}
|
|
3784
|
-
dIdx
|
|
3391
|
+
dIdx++;
|
|
3392
|
+
mIdx++;
|
|
3785
3393
|
}
|
|
3394
|
+
dIdx += dStride;
|
|
3395
|
+
mIdx += mStride;
|
|
3786
3396
|
}
|
|
3787
|
-
return
|
|
3397
|
+
return didChange;
|
|
3788
3398
|
}
|
|
3789
3399
|
|
|
3790
|
-
// src/History/PixelMutator/
|
|
3791
|
-
var
|
|
3792
|
-
|
|
3400
|
+
// src/History/PixelMutator/mutatorApplyBinaryMask.ts
|
|
3401
|
+
var defaults12 = {
|
|
3402
|
+
applyBinaryMaskToPixelData
|
|
3793
3403
|
};
|
|
3794
|
-
var
|
|
3404
|
+
var mutatorApplyBinaryMask = ((writer, deps = defaults12) => {
|
|
3795
3405
|
const {
|
|
3796
|
-
|
|
3406
|
+
applyBinaryMaskToPixelData: applyBinaryMaskToPixelData2 = defaults12.applyBinaryMaskToPixelData
|
|
3797
3407
|
} = deps;
|
|
3798
3408
|
return {
|
|
3799
|
-
|
|
3800
|
-
|
|
3409
|
+
applyBinaryMask(mask, opts = {}) {
|
|
3410
|
+
let target = writer.config.target;
|
|
3801
3411
|
const {
|
|
3802
3412
|
x = 0,
|
|
3803
3413
|
y = 0,
|
|
@@ -3805,126 +3415,11 @@ var mutatorInvert = ((writer, deps = defaults20) => {
|
|
|
3805
3415
|
h = target.height
|
|
3806
3416
|
} = opts;
|
|
3807
3417
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3808
|
-
return didChange(
|
|
3418
|
+
return didChange(applyBinaryMaskToPixelData2(target, mask, opts));
|
|
3809
3419
|
}
|
|
3810
3420
|
};
|
|
3811
3421
|
});
|
|
3812
3422
|
|
|
3813
|
-
// src/History/PixelMutator.ts
|
|
3814
|
-
function makeFullPixelMutator(writer) {
|
|
3815
|
-
return {
|
|
3816
|
-
// @sort
|
|
3817
|
-
...mutatorApplyAlphaMask(writer),
|
|
3818
|
-
...mutatorApplyBinaryMask(writer),
|
|
3819
|
-
...mutatorApplyCircleBrushStroke(writer),
|
|
3820
|
-
...mutatorApplyCirclePencil(writer),
|
|
3821
|
-
...mutatorApplyCirclePencilStroke(writer),
|
|
3822
|
-
...mutatorApplyRectBrush(writer),
|
|
3823
|
-
...mutatorApplyRectBrushStroke(writer),
|
|
3824
|
-
...mutatorApplyRectPencil(writer),
|
|
3825
|
-
...mutatorApplyRectPencilStroke(writer),
|
|
3826
|
-
...mutatorBlendColor(writer),
|
|
3827
|
-
...mutatorBlendColorCircleMask(writer),
|
|
3828
|
-
...mutatorBlendPixel(writer),
|
|
3829
|
-
...mutatorBlendPixelData(writer),
|
|
3830
|
-
...mutatorBlendPixelDataAlphaMask(writer),
|
|
3831
|
-
...mutatorBlendPixelDataBinaryMask(writer),
|
|
3832
|
-
...mutatorClear(writer),
|
|
3833
|
-
...mutatorFill(writer),
|
|
3834
|
-
...mutatorFillBinaryMask(writer),
|
|
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);
|
|
3850
|
-
}
|
|
3851
|
-
data32;
|
|
3852
|
-
width;
|
|
3853
|
-
height;
|
|
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;
|
|
3866
|
-
}
|
|
3867
|
-
getTile(id, tx, ty) {
|
|
3868
|
-
let tile = this.pool.pop();
|
|
3869
|
-
if (tile) {
|
|
3870
|
-
tile.id = id;
|
|
3871
|
-
tile.tx = tx;
|
|
3872
|
-
tile.ty = ty;
|
|
3873
|
-
tile.data32.fill(0);
|
|
3874
|
-
return tile;
|
|
3875
|
-
}
|
|
3876
|
-
return new PixelTile(id, tx, ty, this.tileSize, this.tileArea);
|
|
3877
|
-
}
|
|
3878
|
-
releaseTile(tile) {
|
|
3879
|
-
this.pool.push(tile);
|
|
3880
|
-
}
|
|
3881
|
-
releaseTiles(tiles) {
|
|
3882
|
-
let length = tiles.length;
|
|
3883
|
-
for (let i = 0; i < length; i++) {
|
|
3884
|
-
let tile = tiles[i];
|
|
3885
|
-
if (tile) {
|
|
3886
|
-
this.pool.push(tile);
|
|
3887
|
-
}
|
|
3888
|
-
}
|
|
3889
|
-
tiles.length = 0;
|
|
3890
|
-
}
|
|
3891
|
-
};
|
|
3892
|
-
|
|
3893
|
-
// src/History/PixelWriter.ts
|
|
3894
|
-
var PixelWriter = class {
|
|
3895
|
-
historyManager;
|
|
3896
|
-
accumulator;
|
|
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
|
-
}
|
|
3926
|
-
};
|
|
3927
|
-
|
|
3928
3423
|
// src/ImageData/copyImageData.ts
|
|
3929
3424
|
function copyImageData({
|
|
3930
3425
|
data,
|
|
@@ -4046,35 +3541,6 @@ function resampleImageData(source, factor) {
|
|
|
4046
3541
|
return new ImageData(uint8ClampedArray, width, height);
|
|
4047
3542
|
}
|
|
4048
3543
|
|
|
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
3544
|
// src/ImageData/ReusableImageData.ts
|
|
4079
3545
|
function makeReusableImageData() {
|
|
4080
3546
|
let imageData = null;
|
|
@@ -4489,62 +3955,6 @@ function makeBinaryMask(w, h, data) {
|
|
|
4489
3955
|
};
|
|
4490
3956
|
}
|
|
4491
3957
|
|
|
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
3958
|
// src/Mask/applyBinaryMaskToAlphaMask.ts
|
|
4549
3959
|
function applyBinaryMaskToAlphaMask(alphaMaskDst, binaryMaskSrc, opts = {}) {
|
|
4550
3960
|
const {
|
|
@@ -4999,6 +4409,162 @@ var PixelData = class {
|
|
|
4999
4409
|
}
|
|
5000
4410
|
};
|
|
5001
4411
|
|
|
4412
|
+
// src/PixelData/blendColorPixelDataAlphaMask.ts
|
|
4413
|
+
function blendColorPixelDataAlphaMask(dst, color, mask, opts = {}) {
|
|
4414
|
+
const targetX = opts.x ?? 0;
|
|
4415
|
+
const targetY = opts.y ?? 0;
|
|
4416
|
+
const w = opts.w ?? mask.w;
|
|
4417
|
+
const h = opts.h ?? mask.h;
|
|
4418
|
+
const globalAlpha = opts.alpha ?? 255;
|
|
4419
|
+
const blendFn = opts.blendFn ?? sourceOverPerfect;
|
|
4420
|
+
const mx = opts.mx ?? 0;
|
|
4421
|
+
const my = opts.my ?? 0;
|
|
4422
|
+
const invertMask = opts.invertMask ?? false;
|
|
4423
|
+
if (globalAlpha === 0) return false;
|
|
4424
|
+
const baseSrcAlpha = color >>> 24;
|
|
4425
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
4426
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
4427
|
+
let x = targetX;
|
|
4428
|
+
let y = targetY;
|
|
4429
|
+
let actualW = w;
|
|
4430
|
+
let actualH = h;
|
|
4431
|
+
if (x < 0) {
|
|
4432
|
+
actualW += x;
|
|
4433
|
+
x = 0;
|
|
4434
|
+
}
|
|
4435
|
+
if (y < 0) {
|
|
4436
|
+
actualH += y;
|
|
4437
|
+
y = 0;
|
|
4438
|
+
}
|
|
4439
|
+
actualW = Math.min(actualW, dst.width - x);
|
|
4440
|
+
actualH = Math.min(actualH, dst.height - y);
|
|
4441
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
4442
|
+
const dx = x - targetX | 0;
|
|
4443
|
+
const dy = y - targetY | 0;
|
|
4444
|
+
const dst32 = dst.data32;
|
|
4445
|
+
const dw = dst.width;
|
|
4446
|
+
const mPitch = mask.w;
|
|
4447
|
+
const maskData = mask.data;
|
|
4448
|
+
let dIdx = y * dw + x | 0;
|
|
4449
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
4450
|
+
const dStride = dw - actualW | 0;
|
|
4451
|
+
const mStride = mPitch - actualW | 0;
|
|
4452
|
+
const isOpaque = globalAlpha === 255;
|
|
4453
|
+
const colorRGB = color & 16777215;
|
|
4454
|
+
let didChange = false;
|
|
4455
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
4456
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
4457
|
+
const mVal = maskData[mIdx];
|
|
4458
|
+
const effM = invertMask ? 255 - mVal : mVal;
|
|
4459
|
+
if (effM === 0) {
|
|
4460
|
+
dIdx++;
|
|
4461
|
+
mIdx++;
|
|
4462
|
+
continue;
|
|
4463
|
+
}
|
|
4464
|
+
let weight = globalAlpha;
|
|
4465
|
+
if (isOpaque) {
|
|
4466
|
+
weight = effM;
|
|
4467
|
+
} else if (effM !== 255) {
|
|
4468
|
+
weight = effM * globalAlpha + 128 >> 8;
|
|
4469
|
+
}
|
|
4470
|
+
if (weight === 0) {
|
|
4471
|
+
dIdx++;
|
|
4472
|
+
mIdx++;
|
|
4473
|
+
continue;
|
|
4474
|
+
}
|
|
4475
|
+
let finalCol = color;
|
|
4476
|
+
if (weight < 255) {
|
|
4477
|
+
const a = baseSrcAlpha * weight + 128 >> 8;
|
|
4478
|
+
if (a === 0 && !isOverwrite) {
|
|
4479
|
+
dIdx++;
|
|
4480
|
+
mIdx++;
|
|
4481
|
+
continue;
|
|
4482
|
+
}
|
|
4483
|
+
finalCol = (colorRGB | a << 24) >>> 0;
|
|
4484
|
+
}
|
|
4485
|
+
const current = dst32[dIdx];
|
|
4486
|
+
const next = blendFn(finalCol, current);
|
|
4487
|
+
if (current !== next) {
|
|
4488
|
+
dst32[dIdx] = next;
|
|
4489
|
+
didChange = true;
|
|
4490
|
+
}
|
|
4491
|
+
dIdx++;
|
|
4492
|
+
mIdx++;
|
|
4493
|
+
}
|
|
4494
|
+
dIdx += dStride;
|
|
4495
|
+
mIdx += mStride;
|
|
4496
|
+
}
|
|
4497
|
+
return didChange;
|
|
4498
|
+
}
|
|
4499
|
+
|
|
4500
|
+
// src/PixelData/blendColorPixelDataBinaryMask.ts
|
|
4501
|
+
function blendColorPixelDataBinaryMask(dst, color, mask, opts = {}) {
|
|
4502
|
+
const targetX = opts.x ?? 0;
|
|
4503
|
+
const targetY = opts.y ?? 0;
|
|
4504
|
+
let w = opts.w ?? mask.w;
|
|
4505
|
+
let h = opts.h ?? mask.h;
|
|
4506
|
+
const globalAlpha = opts.alpha ?? 255;
|
|
4507
|
+
const blendFn = opts.blendFn ?? sourceOverPerfect;
|
|
4508
|
+
const mx = opts.mx ?? 0;
|
|
4509
|
+
const my = opts.my ?? 0;
|
|
4510
|
+
const invertMask = opts.invertMask ?? false;
|
|
4511
|
+
if (globalAlpha === 0) return false;
|
|
4512
|
+
const baseSrcAlpha = color >>> 24;
|
|
4513
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
4514
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
4515
|
+
let x = targetX;
|
|
4516
|
+
let y = targetY;
|
|
4517
|
+
if (x < 0) {
|
|
4518
|
+
w += x;
|
|
4519
|
+
x = 0;
|
|
4520
|
+
}
|
|
4521
|
+
if (y < 0) {
|
|
4522
|
+
h += y;
|
|
4523
|
+
y = 0;
|
|
4524
|
+
}
|
|
4525
|
+
const actualW = Math.min(w, dst.width - x);
|
|
4526
|
+
const actualH = Math.min(h, dst.height - y);
|
|
4527
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
4528
|
+
let baseColorWithGlobalAlpha = color;
|
|
4529
|
+
if (globalAlpha < 255) {
|
|
4530
|
+
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
4531
|
+
if (a === 0 && !isOverwrite) return false;
|
|
4532
|
+
baseColorWithGlobalAlpha = (color & 16777215 | a << 24) >>> 0;
|
|
4533
|
+
}
|
|
4534
|
+
const dx = x - targetX | 0;
|
|
4535
|
+
const dy = y - targetY | 0;
|
|
4536
|
+
const dst32 = dst.data32;
|
|
4537
|
+
const dw = dst.width;
|
|
4538
|
+
const mPitch = mask.w;
|
|
4539
|
+
const maskData = mask.data;
|
|
4540
|
+
let dIdx = y * dw + x | 0;
|
|
4541
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
4542
|
+
const dStride = dw - actualW | 0;
|
|
4543
|
+
const mStride = mPitch - actualW | 0;
|
|
4544
|
+
const skipVal = invertMask ? 1 : 0;
|
|
4545
|
+
let didChange = false;
|
|
4546
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
4547
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
4548
|
+
if (maskData[mIdx] === skipVal) {
|
|
4549
|
+
dIdx++;
|
|
4550
|
+
mIdx++;
|
|
4551
|
+
continue;
|
|
4552
|
+
}
|
|
4553
|
+
const current = dst32[dIdx];
|
|
4554
|
+
const next = blendFn(baseColorWithGlobalAlpha, current);
|
|
4555
|
+
if (current !== next) {
|
|
4556
|
+
dst32[dIdx] = next;
|
|
4557
|
+
didChange = true;
|
|
4558
|
+
}
|
|
4559
|
+
dIdx++;
|
|
4560
|
+
mIdx++;
|
|
4561
|
+
}
|
|
4562
|
+
dIdx += dStride;
|
|
4563
|
+
mIdx += mStride;
|
|
4564
|
+
}
|
|
4565
|
+
return didChange;
|
|
4566
|
+
}
|
|
4567
|
+
|
|
5002
4568
|
// src/PixelData/blendPixelDataPaintBuffer.ts
|
|
5003
4569
|
var SCRATCH_OPTS = {
|
|
5004
4570
|
x: 0,
|
|
@@ -5245,103 +4811,137 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
5245
4811
|
}
|
|
5246
4812
|
}
|
|
5247
4813
|
|
|
5248
|
-
// src/
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
4814
|
+
// src/PixelData/writePaintBufferToPixelData.ts
|
|
4815
|
+
function writePaintBufferToPixelData(target, paintBuffer, writePixelDataBufferFn = writePixelDataBuffer) {
|
|
4816
|
+
const tileShift = paintBuffer.config.tileShift;
|
|
4817
|
+
const lookup = paintBuffer.lookup;
|
|
4818
|
+
for (let i = 0; i < lookup.length; i++) {
|
|
4819
|
+
const tile = lookup[i];
|
|
4820
|
+
if (tile) {
|
|
4821
|
+
const dx = tile.tx << tileShift;
|
|
4822
|
+
const dy = tile.ty << tileShift;
|
|
4823
|
+
writePixelDataBufferFn(target, tile.data32, dx, dy, tile.width, tile.height);
|
|
4824
|
+
}
|
|
5254
4825
|
}
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
|
|
5268
|
-
|
|
5269
|
-
|
|
5270
|
-
|
|
5271
|
-
|
|
5272
|
-
|
|
5273
|
-
|
|
4826
|
+
}
|
|
4827
|
+
|
|
4828
|
+
// src/Paint/makeCirclePaintAlphaMask.ts
|
|
4829
|
+
function makeCirclePaintAlphaMask(size, fallOff = (d) => d) {
|
|
4830
|
+
const area = size * size;
|
|
4831
|
+
const data = new Uint8Array(area);
|
|
4832
|
+
const radius = size / 2;
|
|
4833
|
+
const invR = 1 / radius;
|
|
4834
|
+
const centerOffset = -Math.ceil(radius - 0.5);
|
|
4835
|
+
for (let y = 0; y < size; y++) {
|
|
4836
|
+
const rowOffset = y * size;
|
|
4837
|
+
const dy = y - radius + 0.5;
|
|
4838
|
+
const dy2 = dy * dy;
|
|
4839
|
+
for (let x = 0; x < size; x++) {
|
|
4840
|
+
const dx = x - radius + 0.5;
|
|
4841
|
+
const distSqr = dx * dx + dy2;
|
|
4842
|
+
if (distSqr <= radius * radius) {
|
|
4843
|
+
const dist = Math.sqrt(distSqr) * invR;
|
|
4844
|
+
const strength = fallOff(1 - dist);
|
|
4845
|
+
if (strength > 0) {
|
|
4846
|
+
const intensity = strength * 255 | 0;
|
|
4847
|
+
data[rowOffset + x] = Math.max(0, Math.min(255, intensity));
|
|
5274
4848
|
}
|
|
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
4849
|
}
|
|
5282
4850
|
}
|
|
5283
4851
|
}
|
|
5284
|
-
|
|
5285
|
-
|
|
5286
|
-
|
|
5287
|
-
|
|
5288
|
-
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
|
|
5295
|
-
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
4852
|
+
return {
|
|
4853
|
+
type: 0 /* ALPHA */,
|
|
4854
|
+
data,
|
|
4855
|
+
w: size,
|
|
4856
|
+
h: size,
|
|
4857
|
+
centerOffsetX: centerOffset,
|
|
4858
|
+
centerOffsetY: centerOffset
|
|
4859
|
+
};
|
|
4860
|
+
}
|
|
4861
|
+
|
|
4862
|
+
// src/Paint/makeCirclePaintBinaryMask.ts
|
|
4863
|
+
function makeCirclePaintBinaryMask(size) {
|
|
4864
|
+
const area = size * size;
|
|
4865
|
+
const data = new Uint8Array(area);
|
|
4866
|
+
const radius = size / 2;
|
|
4867
|
+
const centerOffset = -Math.ceil(radius - 0.5);
|
|
4868
|
+
for (let y = 0; y < size; y++) {
|
|
4869
|
+
for (let x = 0; x < size; x++) {
|
|
4870
|
+
const dx = x - radius + 0.5;
|
|
4871
|
+
const dy = y - radius + 0.5;
|
|
4872
|
+
const distSqr = dx * dx + dy * dy;
|
|
4873
|
+
if (distSqr <= radius * radius) {
|
|
4874
|
+
data[y * size + x] = 1;
|
|
5306
4875
|
}
|
|
5307
|
-
}
|
|
4876
|
+
}
|
|
5308
4877
|
}
|
|
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
|
-
|
|
4878
|
+
return {
|
|
4879
|
+
type: 1 /* BINARY */,
|
|
4880
|
+
data,
|
|
4881
|
+
w: size,
|
|
4882
|
+
h: size,
|
|
4883
|
+
centerOffsetX: centerOffset,
|
|
4884
|
+
centerOffsetY: centerOffset
|
|
4885
|
+
};
|
|
4886
|
+
}
|
|
4887
|
+
|
|
4888
|
+
// src/Paint/makePaintMask.ts
|
|
4889
|
+
function makePaintBinaryMask(mask) {
|
|
4890
|
+
return {
|
|
4891
|
+
type: 1 /* BINARY */,
|
|
4892
|
+
data: mask.data,
|
|
4893
|
+
w: mask.w,
|
|
4894
|
+
h: mask.h,
|
|
4895
|
+
centerOffsetX: -macro_halfAndFloor(mask.w),
|
|
4896
|
+
centerOffsetY: -macro_halfAndFloor(mask.h)
|
|
4897
|
+
};
|
|
4898
|
+
}
|
|
4899
|
+
function makePaintAlphaMask(mask) {
|
|
4900
|
+
return {
|
|
4901
|
+
type: 0 /* ALPHA */,
|
|
4902
|
+
data: mask.data,
|
|
4903
|
+
w: mask.w,
|
|
4904
|
+
h: mask.h,
|
|
4905
|
+
centerOffsetX: -macro_halfAndFloor(mask.w),
|
|
4906
|
+
centerOffsetY: -macro_halfAndFloor(mask.h)
|
|
4907
|
+
};
|
|
4908
|
+
}
|
|
4909
|
+
|
|
4910
|
+
// src/Paint/makeRectFalloffPaintAlphaMask.ts
|
|
4911
|
+
function makeRectFalloffPaintAlphaMask(width, height, fallOff = (d) => d) {
|
|
4912
|
+
const fPx = Math.floor(width / 2);
|
|
4913
|
+
const fPy = Math.floor(height / 2);
|
|
4914
|
+
const invHalfW = 2 / width;
|
|
4915
|
+
const invHalfH = 2 / height;
|
|
4916
|
+
const offX = width % 2 === 0 ? 0.5 : 0;
|
|
4917
|
+
const offY = height % 2 === 0 ? 0.5 : 0;
|
|
4918
|
+
const area = width * height;
|
|
4919
|
+
const data = new Uint8Array(area);
|
|
4920
|
+
for (let y = 0; y < height; y++) {
|
|
4921
|
+
const dy = Math.abs(y - fPy + offY) * invHalfH;
|
|
4922
|
+
const rowOffset = y * width;
|
|
4923
|
+
for (let x = 0; x < width; x++) {
|
|
4924
|
+
const dx = Math.abs(x - fPx + offX) * invHalfW;
|
|
4925
|
+
const dist = dx > dy ? dx : dy;
|
|
4926
|
+
const strength = fallOff(1 - dist);
|
|
4927
|
+
if (strength > 0) {
|
|
4928
|
+
const intensity = strength * 255 | 0;
|
|
4929
|
+
data[rowOffset + x] = Math.max(0, Math.min(255, intensity));
|
|
5335
4930
|
}
|
|
5336
|
-
}
|
|
5337
|
-
}
|
|
5338
|
-
clear() {
|
|
5339
|
-
this.tilePool.releaseTiles(this.lookup);
|
|
4931
|
+
}
|
|
5340
4932
|
}
|
|
5341
|
-
|
|
4933
|
+
return {
|
|
4934
|
+
type: 0 /* ALPHA */,
|
|
4935
|
+
data,
|
|
4936
|
+
w: width,
|
|
4937
|
+
h: height,
|
|
4938
|
+
centerOffsetX: -(width >> 1),
|
|
4939
|
+
centerOffsetY: -(height >> 1)
|
|
4940
|
+
};
|
|
4941
|
+
}
|
|
5342
4942
|
|
|
5343
|
-
// src/
|
|
5344
|
-
function
|
|
4943
|
+
// src/Paint/PaintBufferCanvasRenderer.ts
|
|
4944
|
+
function makePaintBufferCanvasRenderer(paintBuffer, offscreenCanvasClass = OffscreenCanvas) {
|
|
5345
4945
|
const config = paintBuffer.config;
|
|
5346
4946
|
const tileSize = config.tileSize;
|
|
5347
4947
|
const tileShift = config.tileShift;
|
|
@@ -5350,16 +4950,20 @@ function makePaintBufferRenderer(paintBuffer, offscreenCanvasClass = OffscreenCa
|
|
|
5350
4950
|
const ctx = canvas.getContext("2d");
|
|
5351
4951
|
if (!ctx) throw new Error(CANVAS_CTX_FAILED);
|
|
5352
4952
|
ctx.imageSmoothingEnabled = false;
|
|
5353
|
-
return function drawPaintBuffer(
|
|
4953
|
+
return function drawPaintBuffer(targetCtx, alpha = 255, compOperation = "source-over") {
|
|
4954
|
+
targetCtx.globalAlpha = alpha / 255;
|
|
4955
|
+
targetCtx.globalCompositeOperation = compOperation;
|
|
5354
4956
|
for (let i = 0; i < lookup.length; i++) {
|
|
5355
4957
|
const tile = lookup[i];
|
|
5356
4958
|
if (tile) {
|
|
5357
4959
|
const dx = tile.tx << tileShift;
|
|
5358
4960
|
const dy = tile.ty << tileShift;
|
|
5359
4961
|
ctx.putImageData(tile.imageData, 0, 0);
|
|
5360
|
-
|
|
4962
|
+
targetCtx.drawImage(canvas, dx, dy);
|
|
5361
4963
|
}
|
|
5362
4964
|
}
|
|
4965
|
+
targetCtx.globalAlpha = 1;
|
|
4966
|
+
targetCtx.globalCompositeOperation = "source-over";
|
|
5363
4967
|
};
|
|
5364
4968
|
}
|
|
5365
4969
|
export {
|
|
@@ -5384,13 +4988,11 @@ export {
|
|
|
5384
4988
|
applyBinaryMaskToAlphaMask,
|
|
5385
4989
|
applyBinaryMaskToPixelData,
|
|
5386
4990
|
applyPatchTiles,
|
|
5387
|
-
applyRectBrushToPixelData,
|
|
5388
4991
|
base64DecodeArrayBuffer,
|
|
5389
4992
|
base64EncodeArrayBuffer,
|
|
5390
4993
|
blendColorPixelData,
|
|
5391
4994
|
blendColorPixelDataAlphaMask,
|
|
5392
4995
|
blendColorPixelDataBinaryMask,
|
|
5393
|
-
blendColorPixelDataCircleMask,
|
|
5394
4996
|
blendPixel,
|
|
5395
4997
|
blendPixelData,
|
|
5396
4998
|
blendPixelDataAlphaMask,
|
|
@@ -5432,12 +5034,8 @@ export {
|
|
|
5432
5034
|
fillPixelDataFast,
|
|
5433
5035
|
floodFillSelection,
|
|
5434
5036
|
forEachLinePoint,
|
|
5435
|
-
getCircleBrushOrPencilBounds,
|
|
5436
|
-
getCircleBrushOrPencilStrokeBounds,
|
|
5437
5037
|
getImageDataFromClipboard,
|
|
5438
5038
|
getIndexedImageColorCounts,
|
|
5439
|
-
getRectBrushOrPencilBounds,
|
|
5440
|
-
getRectBrushOrPencilStrokeBounds,
|
|
5441
5039
|
getRectsBounds,
|
|
5442
5040
|
getSupportedPixelFormats,
|
|
5443
5041
|
hardLightFast,
|
|
@@ -5471,15 +5069,18 @@ export {
|
|
|
5471
5069
|
makeBinaryMask,
|
|
5472
5070
|
makeBlendModeRegistry,
|
|
5473
5071
|
makeCanvasFrameRenderer,
|
|
5474
|
-
|
|
5475
|
-
|
|
5072
|
+
makeCirclePaintAlphaMask,
|
|
5073
|
+
makeCirclePaintBinaryMask,
|
|
5476
5074
|
makeFastBlendModeRegistry,
|
|
5477
5075
|
makeFullPixelMutator,
|
|
5478
5076
|
makeHistoryAction,
|
|
5479
5077
|
makeImageDataLike,
|
|
5480
|
-
|
|
5078
|
+
makePaintAlphaMask,
|
|
5079
|
+
makePaintBinaryMask,
|
|
5080
|
+
makePaintBufferCanvasRenderer,
|
|
5481
5081
|
makePerfectBlendModeRegistry,
|
|
5482
5082
|
makePixelCanvas,
|
|
5083
|
+
makeRectFalloffPaintAlphaMask,
|
|
5483
5084
|
makeReusableCanvas,
|
|
5484
5085
|
makeReusableImageData,
|
|
5485
5086
|
makeReusableOffscreenCanvas,
|
|
@@ -5491,15 +5092,7 @@ export {
|
|
|
5491
5092
|
multiplyPerfect,
|
|
5492
5093
|
mutatorApplyAlphaMask,
|
|
5493
5094
|
mutatorApplyBinaryMask,
|
|
5494
|
-
mutatorApplyCircleBrushStroke,
|
|
5495
|
-
mutatorApplyCirclePencil,
|
|
5496
|
-
mutatorApplyCirclePencilStroke,
|
|
5497
|
-
mutatorApplyRectBrush,
|
|
5498
|
-
mutatorApplyRectBrushStroke,
|
|
5499
|
-
mutatorApplyRectPencil,
|
|
5500
|
-
mutatorApplyRectPencilStroke,
|
|
5501
5095
|
mutatorBlendColor,
|
|
5502
|
-
mutatorBlendColorCircleMask,
|
|
5503
5096
|
mutatorBlendPixel,
|
|
5504
5097
|
mutatorBlendPixelData,
|
|
5505
5098
|
mutatorBlendPixelDataAlphaMask,
|
|
@@ -5539,6 +5132,7 @@ export {
|
|
|
5539
5132
|
subtractFast,
|
|
5540
5133
|
subtractPerfect,
|
|
5541
5134
|
toBlendModeIndexAndName,
|
|
5135
|
+
trimMaskRectBounds,
|
|
5542
5136
|
trimRectBounds,
|
|
5543
5137
|
uInt32ArrayToImageData,
|
|
5544
5138
|
uInt32ArrayToImageDataLike,
|
|
@@ -5554,6 +5148,7 @@ export {
|
|
|
5554
5148
|
writeImageDataBuffer,
|
|
5555
5149
|
writeImageDataToClipboard,
|
|
5556
5150
|
writeImgBlobToClipboard,
|
|
5151
|
+
writePaintBufferToPixelData,
|
|
5557
5152
|
writePixelDataBuffer
|
|
5558
5153
|
};
|
|
5559
5154
|
//# sourceMappingURL=index.prod.js.map
|