pixel-data-js 0.23.1 → 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 +1816 -1802
- package/dist/index.dev.cjs.map +1 -1
- package/dist/index.dev.js +1799 -1786
- package/dist/index.dev.js.map +1 -1
- package/dist/index.prod.cjs +1816 -1802
- package/dist/index.prod.cjs.map +1 -1
- package/dist/index.prod.d.ts +349 -342
- package/dist/index.prod.js +1799 -1786
- package/dist/index.prod.js.map +1 -1
- package/package.json +3 -2
- package/src/Algorithm/floodFillSelection.ts +2 -2
- package/src/Canvas/CanvasFrameRenderer.ts +57 -0
- package/src/Canvas/ReusableCanvas.ts +60 -11
- package/src/Canvas/canvas-blend-modes.ts +28 -0
- package/src/History/HistoryAction.ts +38 -0
- package/src/History/HistoryManager.ts +4 -8
- package/src/History/PixelAccumulator.ts +137 -99
- package/src/History/PixelEngineConfig.ts +16 -6
- package/src/History/PixelMutator/mutatorApplyAlphaMask.ts +6 -6
- package/src/History/PixelMutator/mutatorApplyBinaryMask.ts +6 -6
- package/src/History/PixelMutator/mutatorBlendColor.ts +8 -5
- package/src/History/PixelMutator/mutatorBlendPixel.ts +22 -26
- package/src/History/PixelMutator/mutatorBlendPixelData.ts +7 -5
- package/src/History/PixelMutator/mutatorBlendPixelDataAlphaMask.ts +7 -5
- package/src/History/PixelMutator/mutatorBlendPixelDataBinaryMask.ts +7 -5
- package/src/History/PixelMutator/mutatorClear.ts +6 -5
- package/src/History/PixelMutator/mutatorFill.ts +34 -9
- package/src/History/PixelMutator/mutatorFillBinaryMask.ts +4 -2
- package/src/History/PixelMutator/mutatorInvert.ts +8 -4
- package/src/History/PixelMutator.ts +2 -21
- package/src/History/PixelPatchTiles.ts +4 -16
- package/src/History/PixelWriter.ts +150 -31
- package/src/ImageData/ReusableImageData.ts +3 -5
- package/src/Internal/helpers.ts +2 -0
- package/src/Paint/PaintBuffer.ts +269 -0
- package/src/Paint/PaintBufferCanvasRenderer.ts +48 -0
- package/src/Paint/makeCirclePaintAlphaMask.ts +41 -0
- package/src/{Mask/CircleBrushBinaryMask.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 +2 -28
- package/src/PixelData/applyAlphaMaskToPixelData.ts +20 -10
- package/src/PixelData/applyBinaryMaskToPixelData.ts +26 -19
- package/src/PixelData/blendColorPixelData.ts +33 -9
- package/src/PixelData/blendColorPixelDataAlphaMask.ts +19 -9
- package/src/PixelData/blendColorPixelDataBinaryMask.ts +19 -10
- package/src/PixelData/blendPixel.ts +47 -0
- package/src/PixelData/blendPixelData.ts +17 -7
- package/src/PixelData/blendPixelDataAlphaMask.ts +15 -7
- package/src/PixelData/blendPixelDataBinaryMask.ts +16 -7
- package/src/PixelData/blendPixelDataPaintBuffer.ts +37 -0
- package/src/PixelData/clearPixelData.ts +4 -4
- package/src/PixelData/extractPixelData.ts +4 -4
- package/src/PixelData/extractPixelDataBuffer.ts +4 -4
- package/src/PixelData/fillPixelData.ts +31 -21
- package/src/PixelData/fillPixelDataBinaryMask.ts +15 -7
- package/src/PixelData/fillPixelDataFast.ts +94 -0
- package/src/PixelData/invertPixelData.ts +6 -4
- 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/PixelTile/PixelTile.ts +21 -0
- package/src/PixelTile/PixelTilePool.ts +63 -0
- package/src/Rect/trimMaskRectBounds.ts +121 -0
- package/src/Rect/trimRectBounds.ts +25 -116
- package/src/_types.ts +17 -16
- package/src/index.ts +19 -24
- package/src/History/PixelMutator/mutatorApplyCircleBrush.ts +0 -78
- package/src/History/PixelMutator/mutatorApplyCircleBrushStroke.ts +0 -181
- package/src/History/PixelMutator/mutatorApplyCirclePencil.ts +0 -59
- package/src/History/PixelMutator/mutatorApplyCirclePencilStroke.ts +0 -171
- package/src/History/PixelMutator/mutatorApplyRectBrush.ts +0 -64
- package/src/History/PixelMutator/mutatorApplyRectBrushStroke.ts +0 -182
- package/src/History/PixelMutator/mutatorApplyRectPencil.ts +0 -65
- package/src/History/PixelMutator/mutatorApplyRectPencilStroke.ts +0 -164
- package/src/Mask/CircleBrushAlphaMask.ts +0 -32
- package/src/PixelData/applyCircleBrushToPixelData.ts +0 -91
- package/src/PixelData/applyRectBrushToPixelData.ts +0 -85
- package/src/Rect/getCircleBrushOrPencilBounds.ts +0 -43
- package/src/Rect/getCircleBrushOrPencilStrokeBounds.ts +0 -24
- package/src/Rect/getRectBrushOrPencilBounds.ts +0 -38
- package/src/Rect/getRectBrushOrPencilStrokeBounds.ts +0 -26
package/dist/index.dev.cjs
CHANGED
|
@@ -28,27 +28,29 @@ __export(src_exports, {
|
|
|
28
28
|
IndexedImage: () => IndexedImage,
|
|
29
29
|
MaskType: () => MaskType,
|
|
30
30
|
OFFSCREEN_CANVAS_CTX_FAILED: () => OFFSCREEN_CANVAS_CTX_FAILED,
|
|
31
|
+
PaintBuffer: () => PaintBuffer,
|
|
31
32
|
PixelAccumulator: () => PixelAccumulator,
|
|
32
33
|
PixelBuffer32: () => PixelBuffer32,
|
|
33
34
|
PixelData: () => PixelData,
|
|
34
35
|
PixelEngineConfig: () => PixelEngineConfig,
|
|
35
36
|
PixelTile: () => PixelTile,
|
|
37
|
+
PixelTilePool: () => PixelTilePool,
|
|
36
38
|
PixelWriter: () => PixelWriter,
|
|
37
39
|
UnsupportedFormatError: () => UnsupportedFormatError,
|
|
38
40
|
applyAlphaMaskToPixelData: () => applyAlphaMaskToPixelData,
|
|
39
41
|
applyBinaryMaskToAlphaMask: () => applyBinaryMaskToAlphaMask,
|
|
40
42
|
applyBinaryMaskToPixelData: () => applyBinaryMaskToPixelData,
|
|
41
|
-
applyCircleBrushToPixelData: () => applyCircleBrushToPixelData,
|
|
42
43
|
applyPatchTiles: () => applyPatchTiles,
|
|
43
|
-
applyRectBrushToPixelData: () => applyRectBrushToPixelData,
|
|
44
44
|
base64DecodeArrayBuffer: () => base64DecodeArrayBuffer,
|
|
45
45
|
base64EncodeArrayBuffer: () => base64EncodeArrayBuffer,
|
|
46
46
|
blendColorPixelData: () => blendColorPixelData,
|
|
47
47
|
blendColorPixelDataAlphaMask: () => blendColorPixelDataAlphaMask,
|
|
48
48
|
blendColorPixelDataBinaryMask: () => blendColorPixelDataBinaryMask,
|
|
49
|
+
blendPixel: () => blendPixel,
|
|
49
50
|
blendPixelData: () => blendPixelData,
|
|
50
51
|
blendPixelDataAlphaMask: () => blendPixelDataAlphaMask,
|
|
51
52
|
blendPixelDataBinaryMask: () => blendPixelDataBinaryMask,
|
|
53
|
+
blendPixelDataPaintBuffer: () => blendPixelDataPaintBuffer,
|
|
52
54
|
clearPixelData: () => clearPixelData,
|
|
53
55
|
color32ToCssRGBA: () => color32ToCssRGBA,
|
|
54
56
|
color32ToHex: () => color32ToHex,
|
|
@@ -82,14 +84,11 @@ __export(src_exports, {
|
|
|
82
84
|
fileToImageData: () => fileToImageData,
|
|
83
85
|
fillPixelData: () => fillPixelData,
|
|
84
86
|
fillPixelDataBinaryMask: () => fillPixelDataBinaryMask,
|
|
87
|
+
fillPixelDataFast: () => fillPixelDataFast,
|
|
85
88
|
floodFillSelection: () => floodFillSelection,
|
|
86
89
|
forEachLinePoint: () => forEachLinePoint,
|
|
87
|
-
getCircleBrushOrPencilBounds: () => getCircleBrushOrPencilBounds,
|
|
88
|
-
getCircleBrushOrPencilStrokeBounds: () => getCircleBrushOrPencilStrokeBounds,
|
|
89
90
|
getImageDataFromClipboard: () => getImageDataFromClipboard,
|
|
90
91
|
getIndexedImageColorCounts: () => getIndexedImageColorCounts,
|
|
91
|
-
getRectBrushOrPencilBounds: () => getRectBrushOrPencilBounds,
|
|
92
|
-
getRectBrushOrPencilStrokeBounds: () => getRectBrushOrPencilStrokeBounds,
|
|
93
92
|
getRectsBounds: () => getRectsBounds,
|
|
94
93
|
getSupportedPixelFormats: () => getSupportedPixelFormats,
|
|
95
94
|
hardLightFast: () => hardLightFast,
|
|
@@ -122,15 +121,22 @@ __export(src_exports, {
|
|
|
122
121
|
makeAlphaMask: () => makeAlphaMask,
|
|
123
122
|
makeBinaryMask: () => makeBinaryMask,
|
|
124
123
|
makeBlendModeRegistry: () => makeBlendModeRegistry,
|
|
125
|
-
|
|
126
|
-
|
|
124
|
+
makeCanvasFrameRenderer: () => makeCanvasFrameRenderer,
|
|
125
|
+
makeCirclePaintAlphaMask: () => makeCirclePaintAlphaMask,
|
|
126
|
+
makeCirclePaintBinaryMask: () => makeCirclePaintBinaryMask,
|
|
127
127
|
makeFastBlendModeRegistry: () => makeFastBlendModeRegistry,
|
|
128
128
|
makeFullPixelMutator: () => makeFullPixelMutator,
|
|
129
|
+
makeHistoryAction: () => makeHistoryAction,
|
|
129
130
|
makeImageDataLike: () => makeImageDataLike,
|
|
131
|
+
makePaintAlphaMask: () => makePaintAlphaMask,
|
|
132
|
+
makePaintBinaryMask: () => makePaintBinaryMask,
|
|
133
|
+
makePaintBufferCanvasRenderer: () => makePaintBufferCanvasRenderer,
|
|
130
134
|
makePerfectBlendModeRegistry: () => makePerfectBlendModeRegistry,
|
|
131
135
|
makePixelCanvas: () => makePixelCanvas,
|
|
136
|
+
makeRectFalloffPaintAlphaMask: () => makeRectFalloffPaintAlphaMask,
|
|
132
137
|
makeReusableCanvas: () => makeReusableCanvas,
|
|
133
138
|
makeReusableImageData: () => makeReusableImageData,
|
|
139
|
+
makeReusableOffscreenCanvas: () => makeReusableOffscreenCanvas,
|
|
134
140
|
merge2BinaryMaskRects: () => merge2BinaryMaskRects,
|
|
135
141
|
mergeAlphaMasks: () => mergeAlphaMasks,
|
|
136
142
|
mergeBinaryMaskRects: () => mergeBinaryMaskRects,
|
|
@@ -139,14 +145,6 @@ __export(src_exports, {
|
|
|
139
145
|
multiplyPerfect: () => multiplyPerfect,
|
|
140
146
|
mutatorApplyAlphaMask: () => mutatorApplyAlphaMask,
|
|
141
147
|
mutatorApplyBinaryMask: () => mutatorApplyBinaryMask,
|
|
142
|
-
mutatorApplyCircleBrush: () => mutatorApplyCircleBrush,
|
|
143
|
-
mutatorApplyCircleBrushStroke: () => mutatorApplyCircleBrushStroke,
|
|
144
|
-
mutatorApplyCirclePencil: () => mutatorApplyCirclePencil,
|
|
145
|
-
mutatorApplyCirclePencilStroke: () => mutatorApplyCirclePencilStroke,
|
|
146
|
-
mutatorApplyRectBrush: () => mutatorApplyRectBrush,
|
|
147
|
-
mutatorApplyRectBrushStroke: () => mutatorApplyRectBrushStroke,
|
|
148
|
-
mutatorApplyRectPencil: () => mutatorApplyRectPencil,
|
|
149
|
-
mutatorApplyRectPencilStroke: () => mutatorApplyRectPencilStroke,
|
|
150
148
|
mutatorBlendColor: () => mutatorBlendColor,
|
|
151
149
|
mutatorBlendPixel: () => mutatorBlendPixel,
|
|
152
150
|
mutatorBlendPixelData: () => mutatorBlendPixelData,
|
|
@@ -155,6 +153,7 @@ __export(src_exports, {
|
|
|
155
153
|
mutatorClear: () => mutatorClear,
|
|
156
154
|
mutatorFill: () => mutatorFill,
|
|
157
155
|
mutatorFillBinaryMask: () => mutatorFillBinaryMask,
|
|
156
|
+
mutatorFillRect: () => mutatorFillRect,
|
|
158
157
|
mutatorInvert: () => mutatorInvert,
|
|
159
158
|
overlayFast: () => overlayFast,
|
|
160
159
|
overlayPerfect: () => overlayPerfect,
|
|
@@ -186,6 +185,7 @@ __export(src_exports, {
|
|
|
186
185
|
subtractFast: () => subtractFast,
|
|
187
186
|
subtractPerfect: () => subtractPerfect,
|
|
188
187
|
toBlendModeIndexAndName: () => toBlendModeIndexAndName,
|
|
188
|
+
trimMaskRectBounds: () => trimMaskRectBounds,
|
|
189
189
|
trimRectBounds: () => trimRectBounds,
|
|
190
190
|
uInt32ArrayToImageData: () => uInt32ArrayToImageData,
|
|
191
191
|
uInt32ArrayToImageDataLike: () => uInt32ArrayToImageDataLike,
|
|
@@ -201,6 +201,7 @@ __export(src_exports, {
|
|
|
201
201
|
writeImageDataBuffer: () => writeImageDataBuffer,
|
|
202
202
|
writeImageDataToClipboard: () => writeImageDataToClipboard,
|
|
203
203
|
writeImgBlobToClipboard: () => writeImgBlobToClipboard,
|
|
204
|
+
writePaintBufferToPixelData: () => writePaintBufferToPixelData,
|
|
204
205
|
writePixelDataBuffer: () => writePixelDataBuffer
|
|
205
206
|
});
|
|
206
207
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -439,8 +440,8 @@ function extractMaskBuffer(maskBuffer, maskWidth, xOrRect, y, w, h) {
|
|
|
439
440
|
return out;
|
|
440
441
|
}
|
|
441
442
|
|
|
442
|
-
// src/Rect/
|
|
443
|
-
function
|
|
443
|
+
// src/Rect/trimMaskRectBounds.ts
|
|
444
|
+
function trimMaskRectBounds(target, bounds) {
|
|
444
445
|
const originalX = target.x;
|
|
445
446
|
const originalY = target.y;
|
|
446
447
|
const originalW = target.w;
|
|
@@ -628,7 +629,7 @@ function floodFillSelection(img, startX, startY, {
|
|
|
628
629
|
finalMask[my * sw + mx] = 1;
|
|
629
630
|
}
|
|
630
631
|
}
|
|
631
|
-
|
|
632
|
+
trimMaskRectBounds(selectionRect, {
|
|
632
633
|
x: 0,
|
|
633
634
|
y: 0,
|
|
634
635
|
w: width,
|
|
@@ -643,6 +644,26 @@ function floodFillSelection(img, startX, startY, {
|
|
|
643
644
|
};
|
|
644
645
|
}
|
|
645
646
|
|
|
647
|
+
// src/Algorithm/forEachLinePoint.ts
|
|
648
|
+
function forEachLinePoint(x0, y0, x1, y1, callback) {
|
|
649
|
+
const dx = x1 - x0;
|
|
650
|
+
const dy = y1 - y0;
|
|
651
|
+
const steps = Math.max(Math.abs(dx), Math.abs(dy));
|
|
652
|
+
if (steps === 0) {
|
|
653
|
+
callback(x0, y0);
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
const xInc = dx / steps;
|
|
657
|
+
const yInc = dy / steps;
|
|
658
|
+
let curX = x0;
|
|
659
|
+
let curY = y0;
|
|
660
|
+
for (let i = 0; i <= steps; i++) {
|
|
661
|
+
callback(curX, curY);
|
|
662
|
+
curX += xInc;
|
|
663
|
+
curY += yInc;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
646
667
|
// src/BlendModes/blend-modes.ts
|
|
647
668
|
var BaseBlendMode = {
|
|
648
669
|
overwrite: 0,
|
|
@@ -1720,51 +1741,104 @@ var getKeyByValue = (obj, value) => {
|
|
|
1720
1741
|
var OFFSCREEN_CANVAS_CTX_FAILED = "Failed to create OffscreenCanvas context";
|
|
1721
1742
|
var CANVAS_CTX_FAILED = "Failed to create Canvas context";
|
|
1722
1743
|
|
|
1723
|
-
// src/Canvas/PixelCanvas.ts
|
|
1724
|
-
function makePixelCanvas(canvas) {
|
|
1725
|
-
const ctx = canvas.getContext("2d");
|
|
1726
|
-
if (!ctx) throw new Error(CANVAS_CTX_FAILED);
|
|
1727
|
-
ctx.imageSmoothingEnabled = false;
|
|
1728
|
-
return {
|
|
1729
|
-
canvas,
|
|
1730
|
-
ctx,
|
|
1731
|
-
resize(w, h) {
|
|
1732
|
-
canvas.width = w;
|
|
1733
|
-
canvas.height = h;
|
|
1734
|
-
ctx.imageSmoothingEnabled = false;
|
|
1735
|
-
}
|
|
1736
|
-
};
|
|
1737
|
-
}
|
|
1738
|
-
|
|
1739
1744
|
// src/Canvas/ReusableCanvas.ts
|
|
1740
1745
|
function makeReusableCanvas() {
|
|
1746
|
+
return makeReusableCanvasMeta((w, h) => {
|
|
1747
|
+
const canvas = document.createElement("canvas");
|
|
1748
|
+
canvas.width = w;
|
|
1749
|
+
canvas.height = h;
|
|
1750
|
+
return canvas;
|
|
1751
|
+
});
|
|
1752
|
+
}
|
|
1753
|
+
function makeReusableOffscreenCanvas() {
|
|
1754
|
+
return makeReusableCanvasMeta((w, h) => new OffscreenCanvas(w, h));
|
|
1755
|
+
}
|
|
1756
|
+
function makeReusableCanvasMeta(factory) {
|
|
1741
1757
|
let canvas = null;
|
|
1742
1758
|
let ctx = null;
|
|
1759
|
+
const result = {
|
|
1760
|
+
canvas: null,
|
|
1761
|
+
ctx: null
|
|
1762
|
+
};
|
|
1743
1763
|
function get2(width, height) {
|
|
1744
1764
|
if (canvas === null) {
|
|
1745
|
-
canvas =
|
|
1765
|
+
canvas = factory(width, height);
|
|
1746
1766
|
ctx = canvas.getContext("2d");
|
|
1747
|
-
if (!ctx)
|
|
1767
|
+
if (!ctx) {
|
|
1768
|
+
throw new Error(CANVAS_CTX_FAILED);
|
|
1769
|
+
}
|
|
1770
|
+
ctx.imageSmoothingEnabled = false;
|
|
1771
|
+
result.canvas = canvas;
|
|
1772
|
+
result.ctx = ctx;
|
|
1773
|
+
return result;
|
|
1748
1774
|
}
|
|
1749
1775
|
if (canvas.width !== width || canvas.height !== height) {
|
|
1750
1776
|
canvas.width = width;
|
|
1751
1777
|
canvas.height = height;
|
|
1752
1778
|
ctx.imageSmoothingEnabled = false;
|
|
1753
1779
|
} else {
|
|
1780
|
+
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
1754
1781
|
ctx.clearRect(0, 0, width, height);
|
|
1755
1782
|
}
|
|
1756
|
-
return
|
|
1757
|
-
canvas,
|
|
1758
|
-
ctx
|
|
1759
|
-
};
|
|
1783
|
+
return result;
|
|
1760
1784
|
}
|
|
1761
1785
|
get2.reset = () => {
|
|
1762
1786
|
canvas = null;
|
|
1763
1787
|
ctx = null;
|
|
1788
|
+
result.canvas = null;
|
|
1789
|
+
result.ctx = null;
|
|
1764
1790
|
};
|
|
1765
1791
|
return get2;
|
|
1766
1792
|
}
|
|
1767
1793
|
|
|
1794
|
+
// src/Canvas/CanvasFrameRenderer.ts
|
|
1795
|
+
var defaults = {
|
|
1796
|
+
makeReusableCanvas
|
|
1797
|
+
};
|
|
1798
|
+
function makeCanvasFrameRenderer(deps = defaults) {
|
|
1799
|
+
const {
|
|
1800
|
+
makeReusableCanvas: makeReusableCanvas2 = defaults.makeReusableCanvas
|
|
1801
|
+
} = deps;
|
|
1802
|
+
const bufferCanvas = makeReusableCanvas2();
|
|
1803
|
+
return function renderCanvasFrame(pixelCanvas, scale, getImageData, drawPixelLayer, drawScreenLayer) {
|
|
1804
|
+
const {
|
|
1805
|
+
canvas,
|
|
1806
|
+
ctx
|
|
1807
|
+
} = pixelCanvas;
|
|
1808
|
+
const {
|
|
1809
|
+
ctx: pxCtx,
|
|
1810
|
+
canvas: pxCanvas
|
|
1811
|
+
} = bufferCanvas(canvas.width, canvas.height);
|
|
1812
|
+
const img = getImageData();
|
|
1813
|
+
if (img) {
|
|
1814
|
+
pxCtx.putImageData(img, 0, 0);
|
|
1815
|
+
}
|
|
1816
|
+
drawPixelLayer?.(pxCtx);
|
|
1817
|
+
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
1818
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
1819
|
+
ctx.setTransform(scale, 0, 0, scale, 0, 0);
|
|
1820
|
+
ctx.drawImage(pxCanvas, 0, 0);
|
|
1821
|
+
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
1822
|
+
drawScreenLayer?.(ctx, scale);
|
|
1823
|
+
};
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
// src/Canvas/PixelCanvas.ts
|
|
1827
|
+
function makePixelCanvas(canvas) {
|
|
1828
|
+
const ctx = canvas.getContext("2d");
|
|
1829
|
+
if (!ctx) throw new Error(CANVAS_CTX_FAILED);
|
|
1830
|
+
ctx.imageSmoothingEnabled = false;
|
|
1831
|
+
return {
|
|
1832
|
+
canvas,
|
|
1833
|
+
ctx,
|
|
1834
|
+
resize(w, h) {
|
|
1835
|
+
canvas.width = w;
|
|
1836
|
+
canvas.height = h;
|
|
1837
|
+
ctx.imageSmoothingEnabled = false;
|
|
1838
|
+
}
|
|
1839
|
+
};
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1768
1842
|
// src/ImageData/imgBlobToImageData.ts
|
|
1769
1843
|
async function imgBlobToImageData(blob) {
|
|
1770
1844
|
let bitmap = null;
|
|
@@ -1824,6 +1898,50 @@ async function writeImageDataToClipboard(imageData) {
|
|
|
1824
1898
|
return writeImgBlobToClipboard(blob);
|
|
1825
1899
|
}
|
|
1826
1900
|
|
|
1901
|
+
// src/History/PixelPatchTiles.ts
|
|
1902
|
+
function applyPatchTiles(target, tiles, tileSize) {
|
|
1903
|
+
for (let i = 0; i < tiles.length; i++) {
|
|
1904
|
+
const tile = tiles[i];
|
|
1905
|
+
if (!tile) continue;
|
|
1906
|
+
const dst = target.data32;
|
|
1907
|
+
const src = tile.data32;
|
|
1908
|
+
const dstWidth = target.width;
|
|
1909
|
+
const dstHeight = target.height;
|
|
1910
|
+
const startX = tile.tx * tileSize;
|
|
1911
|
+
const startY = tile.ty * tileSize;
|
|
1912
|
+
const copyWidth = Math.max(0, Math.min(tileSize, dstWidth - startX));
|
|
1913
|
+
if (copyWidth <= 0) continue;
|
|
1914
|
+
for (let ly = 0; ly < tileSize; ly++) {
|
|
1915
|
+
const globalY = startY + ly;
|
|
1916
|
+
if (globalY >= dstHeight) break;
|
|
1917
|
+
const dstIndex = globalY * dstWidth + startX;
|
|
1918
|
+
const srcIndex = ly * tileSize;
|
|
1919
|
+
const rowData = src.subarray(srcIndex, srcIndex + copyWidth);
|
|
1920
|
+
dst.set(rowData, dstIndex);
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
// src/History/HistoryAction.ts
|
|
1926
|
+
function makeHistoryAction(writer, patch, after, afterUndo, afterRedo, applyPatchTilesFn = applyPatchTiles) {
|
|
1927
|
+
const target = writer.config.target;
|
|
1928
|
+
const tileSize = writer.config.tileSize;
|
|
1929
|
+
const accumulator = writer.accumulator;
|
|
1930
|
+
return {
|
|
1931
|
+
undo: () => {
|
|
1932
|
+
applyPatchTilesFn(target, patch.beforeTiles, tileSize);
|
|
1933
|
+
afterUndo?.();
|
|
1934
|
+
after?.();
|
|
1935
|
+
},
|
|
1936
|
+
redo: () => {
|
|
1937
|
+
applyPatchTilesFn(target, patch.afterTiles, tileSize);
|
|
1938
|
+
afterRedo?.();
|
|
1939
|
+
after?.();
|
|
1940
|
+
},
|
|
1941
|
+
dispose: () => accumulator.recyclePatch(patch)
|
|
1942
|
+
};
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1827
1945
|
// src/History/HistoryManager.ts
|
|
1828
1946
|
var HistoryManager = class {
|
|
1829
1947
|
constructor(maxSteps = 50) {
|
|
@@ -1882,134 +2000,123 @@ var HistoryManager = class {
|
|
|
1882
2000
|
}
|
|
1883
2001
|
};
|
|
1884
2002
|
|
|
1885
|
-
// src/History/PixelPatchTiles.ts
|
|
1886
|
-
var PixelTile = class {
|
|
1887
|
-
constructor(id, tx, ty, tileArea) {
|
|
1888
|
-
this.id = id;
|
|
1889
|
-
this.tx = tx;
|
|
1890
|
-
this.ty = ty;
|
|
1891
|
-
this.data32 = new Uint32Array(tileArea);
|
|
1892
|
-
}
|
|
1893
|
-
data32;
|
|
1894
|
-
};
|
|
1895
|
-
function applyPatchTiles(target, tiles, tileSize = 256) {
|
|
1896
|
-
for (let i = 0; i < tiles.length; i++) {
|
|
1897
|
-
const tile = tiles[i];
|
|
1898
|
-
if (!tile) continue;
|
|
1899
|
-
const dst = target.data32;
|
|
1900
|
-
const src = tile.data32;
|
|
1901
|
-
const dstWidth = target.width;
|
|
1902
|
-
const dstHeight = target.height;
|
|
1903
|
-
const startX = tile.tx * tileSize;
|
|
1904
|
-
const startY = tile.ty * tileSize;
|
|
1905
|
-
const copyWidth = Math.max(0, Math.min(tileSize, dstWidth - startX));
|
|
1906
|
-
if (copyWidth <= 0) return;
|
|
1907
|
-
for (let ly = 0; ly < tileSize; ly++) {
|
|
1908
|
-
const globalY = startY + ly;
|
|
1909
|
-
if (globalY >= dstHeight) break;
|
|
1910
|
-
const dstIndex = globalY * dstWidth + startX;
|
|
1911
|
-
const srcIndex = ly * tileSize;
|
|
1912
|
-
const rowData = src.subarray(srcIndex, srcIndex + copyWidth);
|
|
1913
|
-
dst.set(rowData, dstIndex);
|
|
1914
|
-
}
|
|
1915
|
-
}
|
|
1916
|
-
}
|
|
1917
|
-
|
|
1918
2003
|
// src/History/PixelAccumulator.ts
|
|
1919
2004
|
var PixelAccumulator = class {
|
|
1920
|
-
constructor(
|
|
1921
|
-
this.target = target;
|
|
2005
|
+
constructor(config, tilePool) {
|
|
1922
2006
|
this.config = config;
|
|
2007
|
+
this.tilePool = tilePool;
|
|
1923
2008
|
this.lookup = [];
|
|
1924
2009
|
this.beforeTiles = [];
|
|
1925
|
-
this.pool = [];
|
|
1926
2010
|
}
|
|
1927
2011
|
lookup;
|
|
1928
2012
|
beforeTiles;
|
|
1929
|
-
pool;
|
|
1930
|
-
getTile(id, tx, ty) {
|
|
1931
|
-
let tile = this.pool.pop();
|
|
1932
|
-
if (tile) {
|
|
1933
|
-
tile.id = id;
|
|
1934
|
-
tile.tx = tx;
|
|
1935
|
-
tile.ty = ty;
|
|
1936
|
-
return tile;
|
|
1937
|
-
}
|
|
1938
|
-
return new PixelTile(id, tx, ty, this.config.tileArea);
|
|
1939
|
-
}
|
|
1940
2013
|
recyclePatch(patch) {
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
let tile = before[i];
|
|
1944
|
-
if (tile) {
|
|
1945
|
-
this.pool.push(tile);
|
|
1946
|
-
}
|
|
1947
|
-
}
|
|
1948
|
-
const after = patch.afterTiles;
|
|
1949
|
-
for (let i = 0; i < after.length; i++) {
|
|
1950
|
-
let tile = after[i];
|
|
1951
|
-
if (tile) {
|
|
1952
|
-
this.pool.push(tile);
|
|
1953
|
-
}
|
|
1954
|
-
}
|
|
2014
|
+
this.tilePool.releaseTiles(patch.beforeTiles);
|
|
2015
|
+
this.tilePool.releaseTiles(patch.afterTiles);
|
|
1955
2016
|
}
|
|
1956
2017
|
/**
|
|
1957
2018
|
* @param x pixel x coordinate
|
|
1958
2019
|
* @param y pixel y coordinate
|
|
1959
2020
|
*/
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
let id = ty * columns + tx;
|
|
2021
|
+
storePixelBeforeState(x, y) {
|
|
2022
|
+
const shift = this.config.tileShift;
|
|
2023
|
+
const columns = this.config.targetColumns;
|
|
2024
|
+
const tx = x >> shift;
|
|
2025
|
+
const ty = y >> shift;
|
|
2026
|
+
const id = ty * columns + tx;
|
|
1967
2027
|
let tile = this.lookup[id];
|
|
2028
|
+
let added = false;
|
|
1968
2029
|
if (!tile) {
|
|
1969
|
-
tile = this.getTile(id, tx, ty);
|
|
2030
|
+
tile = this.tilePool.getTile(id, tx, ty);
|
|
1970
2031
|
this.extractState(tile);
|
|
1971
2032
|
this.lookup[id] = tile;
|
|
1972
2033
|
this.beforeTiles.push(tile);
|
|
2034
|
+
added = true;
|
|
1973
2035
|
}
|
|
2036
|
+
return (didChange) => {
|
|
2037
|
+
if (!didChange && added) {
|
|
2038
|
+
this.beforeTiles.pop();
|
|
2039
|
+
this.lookup[id] = void 0;
|
|
2040
|
+
this.tilePool.releaseTile(tile);
|
|
2041
|
+
}
|
|
2042
|
+
return didChange;
|
|
2043
|
+
};
|
|
1974
2044
|
}
|
|
1975
2045
|
/**
|
|
1976
|
-
*
|
|
1977
2046
|
* @param x pixel x coordinate
|
|
1978
2047
|
* @param y pixel y coordinate
|
|
1979
2048
|
* @param w pixel width
|
|
1980
2049
|
* @param h pixel height
|
|
1981
2050
|
*/
|
|
1982
2051
|
storeRegionBeforeState(x, y, w, h) {
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
2052
|
+
const shift = this.config.tileShift;
|
|
2053
|
+
const columns = this.config.targetColumns;
|
|
2054
|
+
const startX = x >> shift;
|
|
2055
|
+
const startY = y >> shift;
|
|
2056
|
+
const endX = x + w - 1 >> shift;
|
|
2057
|
+
const endY = y + h - 1 >> shift;
|
|
2058
|
+
const startIndex = this.beforeTiles.length;
|
|
1990
2059
|
for (let ty = startY; ty <= endY; ty++) {
|
|
1991
2060
|
for (let tx = startX; tx <= endX; tx++) {
|
|
1992
|
-
|
|
2061
|
+
const id = ty * columns + tx;
|
|
1993
2062
|
let tile = this.lookup[id];
|
|
1994
2063
|
if (!tile) {
|
|
1995
|
-
tile = this.getTile(id, tx, ty);
|
|
2064
|
+
tile = this.tilePool.getTile(id, tx, ty);
|
|
1996
2065
|
this.extractState(tile);
|
|
1997
2066
|
this.lookup[id] = tile;
|
|
1998
2067
|
this.beforeTiles.push(tile);
|
|
1999
2068
|
}
|
|
2000
2069
|
}
|
|
2001
2070
|
}
|
|
2071
|
+
return (didChange) => {
|
|
2072
|
+
if (!didChange) {
|
|
2073
|
+
const length = this.beforeTiles.length;
|
|
2074
|
+
for (let i = startIndex; i < length; i++) {
|
|
2075
|
+
let t = this.beforeTiles[i];
|
|
2076
|
+
if (t) {
|
|
2077
|
+
this.lookup[t.id] = void 0;
|
|
2078
|
+
this.tilePool.releaseTile(t);
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
this.beforeTiles.length = startIndex;
|
|
2082
|
+
}
|
|
2083
|
+
return didChange;
|
|
2084
|
+
};
|
|
2085
|
+
}
|
|
2086
|
+
storeTileBeforeState(id, tx, ty) {
|
|
2087
|
+
let tile = this.lookup[id];
|
|
2088
|
+
let added = false;
|
|
2089
|
+
if (!tile) {
|
|
2090
|
+
tile = this.tilePool.getTile(id, tx, ty);
|
|
2091
|
+
this.extractState(tile);
|
|
2092
|
+
this.lookup[id] = tile;
|
|
2093
|
+
this.beforeTiles.push(tile);
|
|
2094
|
+
added = true;
|
|
2095
|
+
}
|
|
2096
|
+
return (didChange) => {
|
|
2097
|
+
if (!didChange && added) {
|
|
2098
|
+
this.beforeTiles.pop();
|
|
2099
|
+
this.lookup[id] = void 0;
|
|
2100
|
+
this.tilePool.releaseTile(tile);
|
|
2101
|
+
}
|
|
2102
|
+
return didChange;
|
|
2103
|
+
};
|
|
2002
2104
|
}
|
|
2003
2105
|
extractState(tile) {
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2106
|
+
const target = this.config.target;
|
|
2107
|
+
const TILE_SIZE = this.config.tileSize;
|
|
2108
|
+
const dst = tile.data32;
|
|
2109
|
+
const src = target.data32;
|
|
2110
|
+
const startX = tile.tx * TILE_SIZE;
|
|
2111
|
+
const startY = tile.ty * TILE_SIZE;
|
|
2112
|
+
const targetWidth = target.width;
|
|
2113
|
+
const targetHeight = target.height;
|
|
2114
|
+
if (startX >= targetWidth || startX + TILE_SIZE <= 0 || startY >= targetHeight || startY + TILE_SIZE <= 0) {
|
|
2115
|
+
dst.fill(0);
|
|
2116
|
+
return;
|
|
2117
|
+
}
|
|
2118
|
+
let srcOffsetX = Math.max(0, -startX);
|
|
2119
|
+
let copyWidth = Math.max(0, Math.min(TILE_SIZE - srcOffsetX, targetWidth - Math.max(0, startX)));
|
|
2013
2120
|
for (let ly = 0; ly < TILE_SIZE; ly++) {
|
|
2014
2121
|
let globalY = startY + ly;
|
|
2015
2122
|
let dstIndex = ly * TILE_SIZE;
|
|
@@ -2017,63 +2124,92 @@ var PixelAccumulator = class {
|
|
|
2017
2124
|
dst.fill(0, dstIndex, dstIndex + TILE_SIZE);
|
|
2018
2125
|
continue;
|
|
2019
2126
|
}
|
|
2020
|
-
let srcIndex = globalY * targetWidth + startX;
|
|
2127
|
+
let srcIndex = globalY * targetWidth + Math.max(0, startX);
|
|
2021
2128
|
let rowData = src.subarray(srcIndex, srcIndex + copyWidth);
|
|
2022
|
-
dst.set(rowData, dstIndex);
|
|
2023
|
-
if (
|
|
2024
|
-
dst.fill(0, dstIndex
|
|
2129
|
+
dst.set(rowData, dstIndex + srcOffsetX);
|
|
2130
|
+
if (srcOffsetX > 0) {
|
|
2131
|
+
dst.fill(0, dstIndex, dstIndex + srcOffsetX);
|
|
2132
|
+
}
|
|
2133
|
+
if (srcOffsetX + copyWidth < TILE_SIZE) {
|
|
2134
|
+
dst.fill(0, dstIndex + srcOffsetX + copyWidth, dstIndex + TILE_SIZE);
|
|
2025
2135
|
}
|
|
2026
2136
|
}
|
|
2027
2137
|
}
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2138
|
+
extractPatch() {
|
|
2139
|
+
const afterTiles = [];
|
|
2140
|
+
const length = this.beforeTiles.length;
|
|
2031
2141
|
for (let i = 0; i < length; i++) {
|
|
2032
2142
|
let beforeTile = this.beforeTiles[i];
|
|
2033
2143
|
if (beforeTile) {
|
|
2034
|
-
let afterTile = this.getTile(beforeTile.id, beforeTile.tx, beforeTile.ty);
|
|
2144
|
+
let afterTile = this.tilePool.getTile(beforeTile.id, beforeTile.tx, beforeTile.ty);
|
|
2035
2145
|
this.extractState(afterTile);
|
|
2036
2146
|
afterTiles.push(afterTile);
|
|
2037
2147
|
}
|
|
2038
2148
|
}
|
|
2039
|
-
|
|
2040
|
-
}
|
|
2041
|
-
reset() {
|
|
2042
|
-
this.lookup = [];
|
|
2149
|
+
const beforeTiles = this.beforeTiles;
|
|
2043
2150
|
this.beforeTiles = [];
|
|
2151
|
+
this.lookup.length = 0;
|
|
2152
|
+
return {
|
|
2153
|
+
beforeTiles,
|
|
2154
|
+
afterTiles
|
|
2155
|
+
};
|
|
2156
|
+
}
|
|
2157
|
+
rollbackAfterError() {
|
|
2158
|
+
const target = this.config.target;
|
|
2159
|
+
const tileSize = this.config.tileSize;
|
|
2160
|
+
const length = this.beforeTiles.length;
|
|
2161
|
+
applyPatchTiles(target, this.beforeTiles, tileSize);
|
|
2162
|
+
for (let i = 0; i < length; i++) {
|
|
2163
|
+
let tile = this.beforeTiles[i];
|
|
2164
|
+
if (tile) {
|
|
2165
|
+
this.lookup[tile.id] = void 0;
|
|
2166
|
+
this.tilePool.releaseTile(tile);
|
|
2167
|
+
}
|
|
2168
|
+
}
|
|
2169
|
+
this.beforeTiles.length = 0;
|
|
2170
|
+
this.lookup.length = 0;
|
|
2044
2171
|
}
|
|
2045
2172
|
};
|
|
2046
2173
|
|
|
2047
2174
|
// src/History/PixelEngineConfig.ts
|
|
2048
2175
|
var PixelEngineConfig = class {
|
|
2049
2176
|
tileSize;
|
|
2177
|
+
// pixelX = tileX << tileShift
|
|
2178
|
+
// pixelY = tileY << tileShift
|
|
2050
2179
|
tileShift;
|
|
2051
2180
|
tileMask;
|
|
2052
2181
|
tileArea;
|
|
2053
|
-
|
|
2182
|
+
target;
|
|
2183
|
+
targetColumns = 0;
|
|
2184
|
+
targetRows = 0;
|
|
2185
|
+
constructor(tileSize, target) {
|
|
2054
2186
|
if ((tileSize & tileSize - 1) !== 0) {
|
|
2055
2187
|
throw new Error("tileSize must be a power of 2");
|
|
2056
2188
|
}
|
|
2057
2189
|
this.tileSize = tileSize;
|
|
2058
|
-
this.tileShift = Math.
|
|
2190
|
+
this.tileShift = 31 - Math.clz32(tileSize);
|
|
2059
2191
|
this.tileMask = tileSize - 1;
|
|
2060
2192
|
this.tileArea = tileSize * tileSize;
|
|
2193
|
+
this.target = target;
|
|
2194
|
+
this.targetColumns = target.width + this.tileMask >> this.tileShift;
|
|
2195
|
+
this.targetRows = target.height + this.tileMask >> this.tileShift;
|
|
2061
2196
|
}
|
|
2062
2197
|
};
|
|
2063
2198
|
|
|
2064
|
-
// src/PixelData/
|
|
2065
|
-
function
|
|
2199
|
+
// src/PixelData/blendColorPixelData.ts
|
|
2200
|
+
function blendColorPixelData(dst, color, opts = {}) {
|
|
2066
2201
|
const {
|
|
2067
2202
|
x: targetX = 0,
|
|
2068
2203
|
y: targetY = 0,
|
|
2069
2204
|
w: width = dst.width,
|
|
2070
2205
|
h: height = dst.height,
|
|
2071
2206
|
alpha: globalAlpha = 255,
|
|
2072
|
-
|
|
2073
|
-
my = 0,
|
|
2074
|
-
invertMask = false
|
|
2207
|
+
blendFn = sourceOverPerfect
|
|
2075
2208
|
} = opts;
|
|
2076
|
-
if (globalAlpha === 0) return;
|
|
2209
|
+
if (globalAlpha === 0) return false;
|
|
2210
|
+
const baseSrcAlpha = color >>> 24;
|
|
2211
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
2212
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
2077
2213
|
let x = targetX;
|
|
2078
2214
|
let y = targetY;
|
|
2079
2215
|
let w = width;
|
|
@@ -2086,257 +2222,290 @@ function applyAlphaMaskToPixelData(dst, mask, opts = {}) {
|
|
|
2086
2222
|
h += y;
|
|
2087
2223
|
y = 0;
|
|
2088
2224
|
}
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
if (
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
const sY0 = Math.max(0, startY);
|
|
2099
|
-
const sX1 = Math.min(mPitch, startX + w);
|
|
2100
|
-
const sY1 = Math.min(mask.h, startY + h);
|
|
2101
|
-
const finalW = sX1 - sX0;
|
|
2102
|
-
const finalH = sY1 - sY0;
|
|
2103
|
-
if (finalW <= 0) return;
|
|
2104
|
-
if (finalH <= 0) return;
|
|
2105
|
-
const xShift = sX0 - startX;
|
|
2106
|
-
const yShift = sY0 - startY;
|
|
2225
|
+
const actualW = Math.min(w, dst.width - x);
|
|
2226
|
+
const actualH = Math.min(h, dst.height - y);
|
|
2227
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
2228
|
+
let finalSrcColor = color;
|
|
2229
|
+
if (globalAlpha < 255) {
|
|
2230
|
+
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
2231
|
+
if (a === 0 && !isOverwrite) return false;
|
|
2232
|
+
finalSrcColor = (color & 16777215 | a << 24) >>> 0;
|
|
2233
|
+
}
|
|
2107
2234
|
const dst32 = dst.data32;
|
|
2108
2235
|
const dw = dst.width;
|
|
2109
|
-
|
|
2110
|
-
const
|
|
2111
|
-
|
|
2112
|
-
let
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
if (effectiveM === 0) {
|
|
2120
|
-
weight = 0;
|
|
2121
|
-
} else if (effectiveM === 255) {
|
|
2122
|
-
weight = globalAlpha;
|
|
2123
|
-
} else if (globalAlpha === 255) {
|
|
2124
|
-
weight = effectiveM;
|
|
2125
|
-
} else {
|
|
2126
|
-
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
2127
|
-
}
|
|
2128
|
-
if (weight === 0) {
|
|
2129
|
-
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
2130
|
-
} else if (weight !== 255) {
|
|
2131
|
-
const d = dst32[dIdx];
|
|
2132
|
-
const da = d >>> 24;
|
|
2133
|
-
if (da !== 0) {
|
|
2134
|
-
const finalAlpha = da === 255 ? weight : da * weight + 128 >> 8;
|
|
2135
|
-
dst32[dIdx] = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
2136
|
-
}
|
|
2236
|
+
let dIdx = y * dw + x | 0;
|
|
2237
|
+
const dStride = dw - actualW | 0;
|
|
2238
|
+
let didChange = false;
|
|
2239
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2240
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2241
|
+
const current = dst32[dIdx];
|
|
2242
|
+
const next = blendFn(finalSrcColor, current);
|
|
2243
|
+
if (current !== next) {
|
|
2244
|
+
dst32[dIdx] = next;
|
|
2245
|
+
didChange = true;
|
|
2137
2246
|
}
|
|
2138
2247
|
dIdx++;
|
|
2139
|
-
mIdx++;
|
|
2140
2248
|
}
|
|
2141
2249
|
dIdx += dStride;
|
|
2142
|
-
mIdx += mStride;
|
|
2143
2250
|
}
|
|
2251
|
+
return didChange;
|
|
2144
2252
|
}
|
|
2145
2253
|
|
|
2146
|
-
// src/History/PixelMutator/
|
|
2147
|
-
var
|
|
2148
|
-
|
|
2149
|
-
};
|
|
2150
|
-
var
|
|
2254
|
+
// src/History/PixelMutator/mutatorBlendColor.ts
|
|
2255
|
+
var defaults2 = {
|
|
2256
|
+
blendColorPixelData
|
|
2257
|
+
};
|
|
2258
|
+
var mutatorBlendColor = ((writer, deps = defaults2) => {
|
|
2151
2259
|
const {
|
|
2152
|
-
|
|
2260
|
+
blendColorPixelData: blendColorPixelData2 = defaults2.blendColorPixelData
|
|
2153
2261
|
} = deps;
|
|
2154
2262
|
return {
|
|
2155
|
-
|
|
2156
|
-
|
|
2263
|
+
blendColor(color, opts = {}) {
|
|
2264
|
+
const target = writer.config.target;
|
|
2157
2265
|
const {
|
|
2158
2266
|
x = 0,
|
|
2159
2267
|
y = 0,
|
|
2160
|
-
w =
|
|
2161
|
-
h =
|
|
2268
|
+
w = target.width,
|
|
2269
|
+
h = target.height
|
|
2162
2270
|
} = opts;
|
|
2163
|
-
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2164
|
-
|
|
2271
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2272
|
+
return didChange(blendColorPixelData2(target, color, opts));
|
|
2165
2273
|
}
|
|
2166
2274
|
};
|
|
2167
2275
|
});
|
|
2168
2276
|
|
|
2169
|
-
// src/PixelData/
|
|
2170
|
-
function
|
|
2277
|
+
// src/PixelData/blendPixel.ts
|
|
2278
|
+
function blendPixel(target, x, y, color, alpha = 255, blendFn = sourceOverPerfect) {
|
|
2279
|
+
if (alpha === 0) return false;
|
|
2280
|
+
let width = target.width;
|
|
2281
|
+
let height = target.height;
|
|
2282
|
+
if (x < 0 || x >= width || y < 0 || y >= height) return false;
|
|
2283
|
+
let srcAlpha = color >>> 24;
|
|
2284
|
+
let isOverwrite = blendFn.isOverwrite;
|
|
2285
|
+
if (srcAlpha === 0 && !isOverwrite) return false;
|
|
2286
|
+
let dst32 = target.data32;
|
|
2287
|
+
let index = y * width + x;
|
|
2288
|
+
let finalColor = color;
|
|
2289
|
+
if (alpha !== 255) {
|
|
2290
|
+
let finalAlpha = srcAlpha * alpha + 128 >> 8;
|
|
2291
|
+
if (finalAlpha === 0 && !isOverwrite) return false;
|
|
2292
|
+
finalColor = (color & 16777215 | finalAlpha << 24) >>> 0;
|
|
2293
|
+
}
|
|
2294
|
+
let current = dst32[index];
|
|
2295
|
+
let next = blendFn(finalColor, current);
|
|
2296
|
+
if (current !== next) {
|
|
2297
|
+
dst32[index] = next;
|
|
2298
|
+
return true;
|
|
2299
|
+
}
|
|
2300
|
+
return false;
|
|
2301
|
+
}
|
|
2302
|
+
|
|
2303
|
+
// src/History/PixelMutator/mutatorBlendPixel.ts
|
|
2304
|
+
var defaults3 = {
|
|
2305
|
+
blendPixel
|
|
2306
|
+
};
|
|
2307
|
+
var mutatorBlendPixel = ((writer, deps = defaults3) => {
|
|
2308
|
+
const {
|
|
2309
|
+
blendPixel: blendPixel2 = defaults3.blendPixel
|
|
2310
|
+
} = deps;
|
|
2311
|
+
return {
|
|
2312
|
+
blendPixel(x, y, color, alpha, blendFn) {
|
|
2313
|
+
const didChange = writer.accumulator.storePixelBeforeState(x, y);
|
|
2314
|
+
return didChange(blendPixel2(writer.config.target, x, y, color, alpha, blendFn));
|
|
2315
|
+
}
|
|
2316
|
+
};
|
|
2317
|
+
});
|
|
2318
|
+
|
|
2319
|
+
// src/PixelData/blendPixelData.ts
|
|
2320
|
+
function blendPixelData(dst, src, opts = {}) {
|
|
2171
2321
|
const {
|
|
2172
2322
|
x: targetX = 0,
|
|
2173
2323
|
y: targetY = 0,
|
|
2174
|
-
|
|
2175
|
-
|
|
2324
|
+
sx: sourceX = 0,
|
|
2325
|
+
sy: sourceY = 0,
|
|
2326
|
+
w: width = src.width,
|
|
2327
|
+
h: height = src.height,
|
|
2176
2328
|
alpha: globalAlpha = 255,
|
|
2177
|
-
|
|
2178
|
-
my = 0,
|
|
2179
|
-
invertMask = false
|
|
2329
|
+
blendFn = sourceOverPerfect
|
|
2180
2330
|
} = opts;
|
|
2181
|
-
if (globalAlpha === 0) return;
|
|
2331
|
+
if (globalAlpha === 0) return false;
|
|
2182
2332
|
let x = targetX;
|
|
2183
2333
|
let y = targetY;
|
|
2334
|
+
let sx = sourceX;
|
|
2335
|
+
let sy = sourceY;
|
|
2184
2336
|
let w = width;
|
|
2185
2337
|
let h = height;
|
|
2338
|
+
if (sx < 0) {
|
|
2339
|
+
x -= sx;
|
|
2340
|
+
w += sx;
|
|
2341
|
+
sx = 0;
|
|
2342
|
+
}
|
|
2343
|
+
if (sy < 0) {
|
|
2344
|
+
y -= sy;
|
|
2345
|
+
h += sy;
|
|
2346
|
+
sy = 0;
|
|
2347
|
+
}
|
|
2348
|
+
w = Math.min(w, src.width - sx);
|
|
2349
|
+
h = Math.min(h, src.height - sy);
|
|
2186
2350
|
if (x < 0) {
|
|
2351
|
+
sx -= x;
|
|
2187
2352
|
w += x;
|
|
2188
2353
|
x = 0;
|
|
2189
2354
|
}
|
|
2190
2355
|
if (y < 0) {
|
|
2356
|
+
sy -= y;
|
|
2191
2357
|
h += y;
|
|
2192
2358
|
y = 0;
|
|
2193
2359
|
}
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
if (
|
|
2197
|
-
if (h <= 0) return;
|
|
2198
|
-
const mPitch = mask.w;
|
|
2199
|
-
if (mPitch <= 0) return;
|
|
2200
|
-
const startX = mx + (x - targetX);
|
|
2201
|
-
const startY = my + (y - targetY);
|
|
2202
|
-
const sX0 = Math.max(0, startX);
|
|
2203
|
-
const sY0 = Math.max(0, startY);
|
|
2204
|
-
const sX1 = Math.min(mPitch, startX + w);
|
|
2205
|
-
const sY1 = Math.min(mask.h, startY + h);
|
|
2206
|
-
const finalW = sX1 - sX0;
|
|
2207
|
-
const finalH = sY1 - sY0;
|
|
2208
|
-
if (finalW <= 0) return;
|
|
2209
|
-
if (finalH <= 0) return;
|
|
2210
|
-
const xShift = sX0 - startX;
|
|
2211
|
-
const yShift = sY0 - startY;
|
|
2360
|
+
const actualW = Math.min(w, dst.width - x);
|
|
2361
|
+
const actualH = Math.min(h, dst.height - y);
|
|
2362
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
2212
2363
|
const dst32 = dst.data32;
|
|
2364
|
+
const src32 = src.data32;
|
|
2213
2365
|
const dw = dst.width;
|
|
2214
|
-
const
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2366
|
+
const sw = src.width;
|
|
2367
|
+
let dIdx = y * dw + x | 0;
|
|
2368
|
+
let sIdx = sy * sw + sx | 0;
|
|
2369
|
+
const dStride = dw - actualW | 0;
|
|
2370
|
+
const sStride = sw - actualW | 0;
|
|
2371
|
+
const isOpaque = globalAlpha === 255;
|
|
2372
|
+
const isOverwrite = blendFn.isOverwrite;
|
|
2373
|
+
let didChange = false;
|
|
2374
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2375
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2376
|
+
const srcCol = src32[sIdx];
|
|
2377
|
+
const srcAlpha = srcCol >>> 24;
|
|
2378
|
+
if (srcAlpha === 0 && !isOverwrite) {
|
|
2379
|
+
dIdx++;
|
|
2380
|
+
sIdx++;
|
|
2381
|
+
continue;
|
|
2382
|
+
}
|
|
2383
|
+
let finalCol = srcCol;
|
|
2384
|
+
if (!isOpaque) {
|
|
2385
|
+
const a = srcAlpha * globalAlpha + 128 >> 8;
|
|
2386
|
+
if (a === 0 && !isOverwrite) {
|
|
2387
|
+
dIdx++;
|
|
2388
|
+
sIdx++;
|
|
2389
|
+
continue;
|
|
2231
2390
|
}
|
|
2391
|
+
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
2392
|
+
}
|
|
2393
|
+
const current = dst32[dIdx];
|
|
2394
|
+
const next = blendFn(finalCol, dst32[dIdx]);
|
|
2395
|
+
if (current !== next) {
|
|
2396
|
+
dst32[dIdx] = next;
|
|
2397
|
+
didChange = true;
|
|
2232
2398
|
}
|
|
2233
2399
|
dIdx++;
|
|
2234
|
-
|
|
2400
|
+
sIdx++;
|
|
2235
2401
|
}
|
|
2236
2402
|
dIdx += dStride;
|
|
2237
|
-
|
|
2403
|
+
sIdx += sStride;
|
|
2238
2404
|
}
|
|
2405
|
+
return didChange;
|
|
2239
2406
|
}
|
|
2240
2407
|
|
|
2241
|
-
// src/History/PixelMutator/
|
|
2242
|
-
var
|
|
2243
|
-
|
|
2408
|
+
// src/History/PixelMutator/mutatorBlendPixelData.ts
|
|
2409
|
+
var defaults4 = {
|
|
2410
|
+
blendPixelData
|
|
2244
2411
|
};
|
|
2245
|
-
var
|
|
2412
|
+
var mutatorBlendPixelData = ((writer, deps = defaults4) => {
|
|
2246
2413
|
const {
|
|
2247
|
-
|
|
2414
|
+
blendPixelData: blendPixelData2 = defaults4.blendPixelData
|
|
2248
2415
|
} = deps;
|
|
2249
2416
|
return {
|
|
2250
|
-
|
|
2251
|
-
let target = writer.target;
|
|
2417
|
+
blendPixelData(src, opts = {}) {
|
|
2252
2418
|
const {
|
|
2253
2419
|
x = 0,
|
|
2254
2420
|
y = 0,
|
|
2255
|
-
w =
|
|
2256
|
-
h =
|
|
2421
|
+
w = src.width,
|
|
2422
|
+
h = src.height
|
|
2257
2423
|
} = opts;
|
|
2258
|
-
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2259
|
-
|
|
2424
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2425
|
+
return didChange(blendPixelData2(writer.config.target, src, opts));
|
|
2260
2426
|
}
|
|
2261
2427
|
};
|
|
2262
2428
|
});
|
|
2263
2429
|
|
|
2264
|
-
// src/
|
|
2265
|
-
function
|
|
2266
|
-
const
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
};
|
|
2279
|
-
|
|
2280
|
-
const cStartY = Math.max(0, startY);
|
|
2281
|
-
const cEndX = Math.min(targetWidth, endX);
|
|
2282
|
-
const cEndY = Math.min(targetHeight, endY);
|
|
2283
|
-
const w = cEndX - cStartX;
|
|
2284
|
-
const h = cEndY - cStartY;
|
|
2285
|
-
res.x = cStartX;
|
|
2286
|
-
res.y = cStartY;
|
|
2287
|
-
res.w = w < 0 ? 0 : w;
|
|
2288
|
-
res.h = h < 0 ? 0 : h;
|
|
2289
|
-
return res;
|
|
2290
|
-
}
|
|
2291
|
-
|
|
2292
|
-
// src/PixelData/blendColorPixelDataAlphaMask.ts
|
|
2293
|
-
function blendColorPixelDataAlphaMask(dst, color, mask, opts = {}) {
|
|
2294
|
-
const targetX = opts.x ?? 0;
|
|
2295
|
-
const targetY = opts.y ?? 0;
|
|
2296
|
-
const w = opts.w ?? mask.w;
|
|
2297
|
-
const h = opts.h ?? mask.h;
|
|
2298
|
-
const globalAlpha = opts.alpha ?? 255;
|
|
2299
|
-
const blendFn = opts.blendFn ?? sourceOverPerfect;
|
|
2300
|
-
const mx = opts.mx ?? 0;
|
|
2301
|
-
const my = opts.my ?? 0;
|
|
2302
|
-
const invertMask = opts.invertMask ?? false;
|
|
2303
|
-
if (globalAlpha === 0) return;
|
|
2304
|
-
const baseSrcAlpha = color >>> 24;
|
|
2305
|
-
const isOverwrite = blendFn.isOverwrite || false;
|
|
2306
|
-
if (baseSrcAlpha === 0 && !isOverwrite) return;
|
|
2430
|
+
// src/PixelData/blendPixelDataAlphaMask.ts
|
|
2431
|
+
function blendPixelDataAlphaMask(dst, src, alphaMask, opts = {}) {
|
|
2432
|
+
const {
|
|
2433
|
+
x: targetX = 0,
|
|
2434
|
+
y: targetY = 0,
|
|
2435
|
+
sx: sourceX = 0,
|
|
2436
|
+
sy: sourceY = 0,
|
|
2437
|
+
w: width = src.width,
|
|
2438
|
+
h: height = src.height,
|
|
2439
|
+
alpha: globalAlpha = 255,
|
|
2440
|
+
blendFn = sourceOverPerfect,
|
|
2441
|
+
mx = 0,
|
|
2442
|
+
my = 0,
|
|
2443
|
+
invertMask = false
|
|
2444
|
+
} = opts;
|
|
2445
|
+
if (globalAlpha === 0) return false;
|
|
2307
2446
|
let x = targetX;
|
|
2308
2447
|
let y = targetY;
|
|
2309
|
-
let
|
|
2310
|
-
let
|
|
2448
|
+
let sx = sourceX;
|
|
2449
|
+
let sy = sourceY;
|
|
2450
|
+
let w = width;
|
|
2451
|
+
let h = height;
|
|
2452
|
+
if (sx < 0) {
|
|
2453
|
+
x -= sx;
|
|
2454
|
+
w += sx;
|
|
2455
|
+
sx = 0;
|
|
2456
|
+
}
|
|
2457
|
+
if (sy < 0) {
|
|
2458
|
+
y -= sy;
|
|
2459
|
+
h += sy;
|
|
2460
|
+
sy = 0;
|
|
2461
|
+
}
|
|
2462
|
+
w = Math.min(w, src.width - sx);
|
|
2463
|
+
h = Math.min(h, src.height - sy);
|
|
2311
2464
|
if (x < 0) {
|
|
2312
|
-
|
|
2465
|
+
sx -= x;
|
|
2466
|
+
w += x;
|
|
2313
2467
|
x = 0;
|
|
2314
2468
|
}
|
|
2315
2469
|
if (y < 0) {
|
|
2316
|
-
|
|
2470
|
+
sy -= y;
|
|
2471
|
+
h += y;
|
|
2317
2472
|
y = 0;
|
|
2318
2473
|
}
|
|
2319
|
-
actualW = Math.min(
|
|
2320
|
-
actualH = Math.min(
|
|
2321
|
-
if (actualW <= 0 || actualH <= 0) return;
|
|
2474
|
+
const actualW = Math.min(w, dst.width - x);
|
|
2475
|
+
const actualH = Math.min(h, dst.height - y);
|
|
2476
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
2477
|
+
const dw = dst.width;
|
|
2478
|
+
const sw = src.width;
|
|
2479
|
+
const mPitch = alphaMask.w;
|
|
2480
|
+
const maskData = alphaMask.data;
|
|
2322
2481
|
const dx = x - targetX | 0;
|
|
2323
2482
|
const dy = y - targetY | 0;
|
|
2324
2483
|
const dst32 = dst.data32;
|
|
2325
|
-
const
|
|
2326
|
-
const mPitch = mask.w;
|
|
2327
|
-
const maskData = mask.data;
|
|
2484
|
+
const src32 = src.data32;
|
|
2328
2485
|
let dIdx = y * dw + x | 0;
|
|
2486
|
+
let sIdx = sy * sw + sx | 0;
|
|
2329
2487
|
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
2330
2488
|
const dStride = dw - actualW | 0;
|
|
2331
|
-
|
|
2489
|
+
const sStride = sw - actualW | 0;
|
|
2490
|
+
const mStride = mPitch - actualW | 0;
|
|
2332
2491
|
const isOpaque = globalAlpha === 255;
|
|
2333
|
-
const
|
|
2492
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
2493
|
+
let didChange = false;
|
|
2334
2494
|
for (let iy = 0; iy < actualH; iy++) {
|
|
2335
2495
|
for (let ix = 0; ix < actualW; ix++) {
|
|
2336
2496
|
const mVal = maskData[mIdx];
|
|
2337
2497
|
const effM = invertMask ? 255 - mVal : mVal;
|
|
2338
2498
|
if (effM === 0) {
|
|
2339
2499
|
dIdx++;
|
|
2500
|
+
sIdx++;
|
|
2501
|
+
mIdx++;
|
|
2502
|
+
continue;
|
|
2503
|
+
}
|
|
2504
|
+
const srcCol = src32[sIdx];
|
|
2505
|
+
const srcAlpha = srcCol >>> 24;
|
|
2506
|
+
if (srcAlpha === 0 && !isOverwrite) {
|
|
2507
|
+
dIdx++;
|
|
2508
|
+
sIdx++;
|
|
2340
2509
|
mIdx++;
|
|
2341
2510
|
continue;
|
|
2342
2511
|
}
|
|
@@ -2348,779 +2517,915 @@ function blendColorPixelDataAlphaMask(dst, color, mask, opts = {}) {
|
|
|
2348
2517
|
}
|
|
2349
2518
|
if (weight === 0) {
|
|
2350
2519
|
dIdx++;
|
|
2520
|
+
sIdx++;
|
|
2351
2521
|
mIdx++;
|
|
2352
2522
|
continue;
|
|
2353
2523
|
}
|
|
2354
|
-
let finalCol =
|
|
2524
|
+
let finalCol = srcCol;
|
|
2355
2525
|
if (weight < 255) {
|
|
2356
|
-
const a =
|
|
2526
|
+
const a = srcAlpha * weight + 128 >> 8;
|
|
2357
2527
|
if (a === 0 && !isOverwrite) {
|
|
2358
2528
|
dIdx++;
|
|
2529
|
+
sIdx++;
|
|
2359
2530
|
mIdx++;
|
|
2360
2531
|
continue;
|
|
2361
2532
|
}
|
|
2362
|
-
finalCol = (
|
|
2533
|
+
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
2534
|
+
}
|
|
2535
|
+
const current = dst32[dIdx];
|
|
2536
|
+
const next = blendFn(finalCol, dst32[dIdx]);
|
|
2537
|
+
if (current !== next) {
|
|
2538
|
+
dst32[dIdx] = next;
|
|
2539
|
+
didChange = true;
|
|
2363
2540
|
}
|
|
2364
|
-
dst32[dIdx] = blendFn(finalCol, dst32[dIdx]);
|
|
2365
2541
|
dIdx++;
|
|
2542
|
+
sIdx++;
|
|
2366
2543
|
mIdx++;
|
|
2367
2544
|
}
|
|
2368
2545
|
dIdx += dStride;
|
|
2546
|
+
sIdx += sStride;
|
|
2369
2547
|
mIdx += mStride;
|
|
2370
2548
|
}
|
|
2549
|
+
return didChange;
|
|
2371
2550
|
}
|
|
2372
2551
|
|
|
2373
|
-
// src/
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2552
|
+
// src/History/PixelMutator/mutatorBlendPixelDataAlphaMask.ts
|
|
2553
|
+
var defaults5 = {
|
|
2554
|
+
blendPixelDataAlphaMask
|
|
2555
|
+
};
|
|
2556
|
+
var mutatorBlendPixelDataAlphaMask = ((writer, deps = defaults5) => {
|
|
2557
|
+
const {
|
|
2558
|
+
blendPixelDataAlphaMask: blendPixelDataAlphaMask2 = defaults5.blendPixelDataAlphaMask
|
|
2559
|
+
} = deps;
|
|
2560
|
+
return {
|
|
2561
|
+
blendPixelDataAlphaMask(src, mask, opts = {}) {
|
|
2562
|
+
const x = opts.x ?? 0;
|
|
2563
|
+
const y = opts.y ?? 0;
|
|
2564
|
+
const w = opts.w ?? src.width;
|
|
2565
|
+
const h = opts.h ?? src.height;
|
|
2566
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2567
|
+
return didChange(blendPixelDataAlphaMask2(writer.config.target, src, mask, opts));
|
|
2568
|
+
}
|
|
2569
|
+
};
|
|
2570
|
+
});
|
|
2571
|
+
|
|
2572
|
+
// src/PixelData/blendPixelDataBinaryMask.ts
|
|
2573
|
+
function blendPixelDataBinaryMask(dst, src, binaryMask, opts = {}) {
|
|
2574
|
+
const {
|
|
2575
|
+
x: targetX = 0,
|
|
2576
|
+
y: targetY = 0,
|
|
2577
|
+
sx: sourceX = 0,
|
|
2578
|
+
sy: sourceY = 0,
|
|
2579
|
+
w: width = src.width,
|
|
2580
|
+
h: height = src.height,
|
|
2581
|
+
alpha: globalAlpha = 255,
|
|
2582
|
+
blendFn = sourceOverPerfect,
|
|
2583
|
+
mx = 0,
|
|
2584
|
+
my = 0,
|
|
2585
|
+
invertMask = false
|
|
2586
|
+
} = opts;
|
|
2587
|
+
if (globalAlpha === 0) return false;
|
|
2588
|
+
let x = targetX;
|
|
2589
|
+
let y = targetY;
|
|
2590
|
+
let sx = sourceX;
|
|
2591
|
+
let sy = sourceY;
|
|
2592
|
+
let w = width;
|
|
2593
|
+
let h = height;
|
|
2594
|
+
if (sx < 0) {
|
|
2595
|
+
x -= sx;
|
|
2596
|
+
w += sx;
|
|
2597
|
+
sx = 0;
|
|
2598
|
+
}
|
|
2599
|
+
if (sy < 0) {
|
|
2600
|
+
y -= sy;
|
|
2601
|
+
h += sy;
|
|
2602
|
+
sy = 0;
|
|
2603
|
+
}
|
|
2604
|
+
w = Math.min(w, src.width - sx);
|
|
2605
|
+
h = Math.min(h, src.height - sy);
|
|
2606
|
+
if (x < 0) {
|
|
2607
|
+
sx -= x;
|
|
2608
|
+
w += x;
|
|
2609
|
+
x = 0;
|
|
2610
|
+
}
|
|
2611
|
+
if (y < 0) {
|
|
2612
|
+
sy -= y;
|
|
2613
|
+
h += y;
|
|
2614
|
+
y = 0;
|
|
2615
|
+
}
|
|
2616
|
+
const actualW = Math.min(w, dst.width - x);
|
|
2617
|
+
const actualH = Math.min(h, dst.height - y);
|
|
2618
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
2619
|
+
const dx = x - targetX | 0;
|
|
2620
|
+
const dy = y - targetY | 0;
|
|
2409
2621
|
const dst32 = dst.data32;
|
|
2622
|
+
const src32 = src.data32;
|
|
2410
2623
|
const dw = dst.width;
|
|
2411
|
-
const
|
|
2412
|
-
const
|
|
2624
|
+
const sw = src.width;
|
|
2625
|
+
const mPitch = binaryMask.w;
|
|
2626
|
+
const maskData = binaryMask.data;
|
|
2413
2627
|
let dIdx = y * dw + x | 0;
|
|
2628
|
+
let sIdx = sy * sw + sx | 0;
|
|
2414
2629
|
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
2415
2630
|
const dStride = dw - actualW | 0;
|
|
2631
|
+
const sStride = sw - actualW | 0;
|
|
2416
2632
|
const mStride = mPitch - actualW | 0;
|
|
2417
2633
|
const skipVal = invertMask ? 1 : 0;
|
|
2634
|
+
const isOpaque = globalAlpha === 255;
|
|
2635
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
2636
|
+
let didChange = false;
|
|
2418
2637
|
for (let iy = 0; iy < actualH; iy++) {
|
|
2419
2638
|
for (let ix = 0; ix < actualW; ix++) {
|
|
2420
2639
|
if (maskData[mIdx] === skipVal) {
|
|
2421
2640
|
dIdx++;
|
|
2641
|
+
sIdx++;
|
|
2642
|
+
mIdx++;
|
|
2643
|
+
continue;
|
|
2644
|
+
}
|
|
2645
|
+
const srcCol = src32[sIdx];
|
|
2646
|
+
const srcAlpha = srcCol >>> 24;
|
|
2647
|
+
if (srcAlpha === 0 && !isOverwrite) {
|
|
2648
|
+
dIdx++;
|
|
2649
|
+
sIdx++;
|
|
2422
2650
|
mIdx++;
|
|
2423
2651
|
continue;
|
|
2424
2652
|
}
|
|
2425
|
-
|
|
2653
|
+
let finalCol = srcCol;
|
|
2654
|
+
if (!isOpaque) {
|
|
2655
|
+
const a = srcAlpha * globalAlpha + 128 >> 8;
|
|
2656
|
+
if (a === 0 && !isOverwrite) {
|
|
2657
|
+
dIdx++;
|
|
2658
|
+
sIdx++;
|
|
2659
|
+
mIdx++;
|
|
2660
|
+
continue;
|
|
2661
|
+
}
|
|
2662
|
+
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
2663
|
+
}
|
|
2664
|
+
const current = dst32[dIdx];
|
|
2665
|
+
const next = blendFn(finalCol, dst32[dIdx]);
|
|
2666
|
+
if (current !== next) {
|
|
2667
|
+
dst32[dIdx] = next;
|
|
2668
|
+
didChange = true;
|
|
2669
|
+
}
|
|
2426
2670
|
dIdx++;
|
|
2671
|
+
sIdx++;
|
|
2427
2672
|
mIdx++;
|
|
2428
2673
|
}
|
|
2429
2674
|
dIdx += dStride;
|
|
2675
|
+
sIdx += sStride;
|
|
2430
2676
|
mIdx += mStride;
|
|
2431
2677
|
}
|
|
2678
|
+
return didChange;
|
|
2432
2679
|
}
|
|
2433
2680
|
|
|
2434
|
-
// src/
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
if (b.w <= 0 || b.h <= 0) return;
|
|
2438
|
-
const unclippedStartX = Math.floor(centerX + brush.minOffset);
|
|
2439
|
-
const unclippedStartY = Math.floor(centerY + brush.minOffset);
|
|
2440
|
-
const ix = Math.max(unclippedStartX, b.x);
|
|
2441
|
-
const iy = Math.max(unclippedStartY, b.y);
|
|
2442
|
-
const ir = Math.min(unclippedStartX + brush.w, b.x + b.w);
|
|
2443
|
-
const ib = Math.min(unclippedStartY + brush.h, b.y + b.h);
|
|
2444
|
-
const iw = ir - ix;
|
|
2445
|
-
const ih = ib - iy;
|
|
2446
|
-
if (iw <= 0 || ih <= 0) return;
|
|
2447
|
-
scratchOptions.x = ix;
|
|
2448
|
-
scratchOptions.y = iy;
|
|
2449
|
-
scratchOptions.w = iw;
|
|
2450
|
-
scratchOptions.h = ih;
|
|
2451
|
-
scratchOptions.mx = ix - unclippedStartX;
|
|
2452
|
-
scratchOptions.my = iy - unclippedStartY;
|
|
2453
|
-
scratchOptions.alpha = alpha;
|
|
2454
|
-
scratchOptions.blendFn = blendFn;
|
|
2455
|
-
if (brush.type === 0 /* ALPHA */) {
|
|
2456
|
-
blendColorPixelDataAlphaMask(target, color, brush, scratchOptions);
|
|
2457
|
-
}
|
|
2458
|
-
if (brush.type === 1 /* BINARY */) {
|
|
2459
|
-
blendColorPixelDataBinaryMask(target, color, brush, scratchOptions);
|
|
2460
|
-
}
|
|
2461
|
-
}
|
|
2462
|
-
|
|
2463
|
-
// src/History/PixelMutator/mutatorApplyCircleBrush.ts
|
|
2464
|
-
var defaults3 = {
|
|
2465
|
-
applyCircleBrushToPixelData,
|
|
2466
|
-
getCircleBrushOrPencilBounds
|
|
2681
|
+
// src/History/PixelMutator/mutatorBlendPixelDataBinaryMask.ts
|
|
2682
|
+
var defaults6 = {
|
|
2683
|
+
blendPixelDataBinaryMask
|
|
2467
2684
|
};
|
|
2468
|
-
var
|
|
2685
|
+
var mutatorBlendPixelDataBinaryMask = ((writer, deps = defaults6) => {
|
|
2469
2686
|
const {
|
|
2470
|
-
|
|
2471
|
-
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults3.getCircleBrushOrPencilBounds
|
|
2687
|
+
blendPixelDataBinaryMask: blendPixelDataBinaryMask2 = defaults6.blendPixelDataBinaryMask
|
|
2472
2688
|
} = deps;
|
|
2473
|
-
const boundsOut = {
|
|
2474
|
-
x: 0,
|
|
2475
|
-
y: 0,
|
|
2476
|
-
w: 0,
|
|
2477
|
-
h: 0
|
|
2478
|
-
};
|
|
2479
|
-
const blendColorPixelOptions = {
|
|
2480
|
-
alpha: 255,
|
|
2481
|
-
blendFn: sourceOverPerfect,
|
|
2482
|
-
x: 0,
|
|
2483
|
-
y: 0,
|
|
2484
|
-
w: 0,
|
|
2485
|
-
h: 0
|
|
2486
|
-
};
|
|
2487
2689
|
return {
|
|
2488
|
-
|
|
2489
|
-
const
|
|
2490
|
-
const
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
} = bounds;
|
|
2496
|
-
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2497
|
-
applyCircleBrushToPixelData2(writer.target, color, centerX, centerY, brush, alpha, blendFn, blendColorPixelOptions, bounds);
|
|
2690
|
+
blendPixelDataBinaryMask(src, mask, opts = {}) {
|
|
2691
|
+
const x = opts.x ?? 0;
|
|
2692
|
+
const y = opts.y ?? 0;
|
|
2693
|
+
const w = opts.w ?? src.width;
|
|
2694
|
+
const h = opts.h ?? src.height;
|
|
2695
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2696
|
+
return didChange(blendPixelDataBinaryMask2(writer.config.target, src, mask, opts));
|
|
2498
2697
|
}
|
|
2499
2698
|
};
|
|
2500
2699
|
});
|
|
2501
2700
|
|
|
2502
|
-
// src/
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2701
|
+
// src/PixelData/fillPixelDataFast.ts
|
|
2702
|
+
var SCRATCH_RECT = makeClippedRect();
|
|
2703
|
+
function fillPixelDataFast(dst, color, _x, _y, _w, _h) {
|
|
2704
|
+
let x;
|
|
2705
|
+
let y;
|
|
2706
|
+
let w;
|
|
2707
|
+
let h;
|
|
2708
|
+
if (typeof _x === "object") {
|
|
2709
|
+
x = _x.x ?? 0;
|
|
2710
|
+
y = _x.y ?? 0;
|
|
2711
|
+
w = _x.w ?? dst.width;
|
|
2712
|
+
h = _x.h ?? dst.height;
|
|
2713
|
+
} else if (typeof _x === "number") {
|
|
2714
|
+
x = _x;
|
|
2715
|
+
y = _y;
|
|
2716
|
+
w = _w;
|
|
2717
|
+
h = _h;
|
|
2718
|
+
} else {
|
|
2719
|
+
x = 0;
|
|
2720
|
+
y = 0;
|
|
2721
|
+
w = dst.width;
|
|
2722
|
+
h = dst.height;
|
|
2723
|
+
}
|
|
2724
|
+
const clip = resolveRectClipping(x, y, w, h, dst.width, dst.height, SCRATCH_RECT);
|
|
2725
|
+
if (!clip.inBounds) return;
|
|
2726
|
+
const {
|
|
2727
|
+
x: finalX,
|
|
2728
|
+
y: finalY,
|
|
2729
|
+
w: actualW,
|
|
2730
|
+
h: actualH
|
|
2731
|
+
} = clip;
|
|
2732
|
+
const dst32 = dst.data32;
|
|
2733
|
+
const dw = dst.width;
|
|
2734
|
+
if (actualW === dw && actualH === dst.height && finalX === 0 && finalY === 0) {
|
|
2735
|
+
dst32.fill(color);
|
|
2509
2736
|
return;
|
|
2510
2737
|
}
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
for (let i = 0; i <= steps; i++) {
|
|
2516
|
-
callback(curX, curY);
|
|
2517
|
-
curX += xInc;
|
|
2518
|
-
curY += yInc;
|
|
2738
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2739
|
+
const start = (finalY + iy) * dw + finalX;
|
|
2740
|
+
const end = start + actualW;
|
|
2741
|
+
dst32.fill(color, start, end);
|
|
2519
2742
|
}
|
|
2520
2743
|
}
|
|
2521
2744
|
|
|
2522
|
-
// src/
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
const minX = Math.min(x0, x1) - r;
|
|
2526
|
-
const minY = Math.min(y0, y1) - r;
|
|
2527
|
-
const maxX = Math.max(x0, x1) + r;
|
|
2528
|
-
const maxY = Math.max(x0, y1) + r;
|
|
2529
|
-
result.x = Math.floor(minX);
|
|
2530
|
-
result.y = Math.floor(minY);
|
|
2531
|
-
result.w = Math.ceil(maxX - minX);
|
|
2532
|
-
result.h = Math.ceil(maxY - minY);
|
|
2533
|
-
return result;
|
|
2534
|
-
}
|
|
2535
|
-
|
|
2536
|
-
// src/History/PixelMutator/mutatorApplyCircleBrushStroke.ts
|
|
2537
|
-
var defaults4 = {
|
|
2538
|
-
forEachLinePoint,
|
|
2539
|
-
blendColorPixelDataAlphaMask,
|
|
2540
|
-
getCircleBrushOrPencilBounds,
|
|
2541
|
-
getCircleBrushOrPencilStrokeBounds
|
|
2745
|
+
// src/History/PixelMutator/mutatorClear.ts
|
|
2746
|
+
var defaults7 = {
|
|
2747
|
+
fillPixelData: fillPixelDataFast
|
|
2542
2748
|
};
|
|
2543
|
-
var
|
|
2749
|
+
var mutatorClear = ((writer, deps = defaults7) => {
|
|
2544
2750
|
const {
|
|
2545
|
-
|
|
2546
|
-
blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults4.blendColorPixelDataAlphaMask,
|
|
2547
|
-
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults4.getCircleBrushOrPencilBounds,
|
|
2548
|
-
getCircleBrushOrPencilStrokeBounds: getCircleBrushOrPencilStrokeBounds2 = defaults4.getCircleBrushOrPencilStrokeBounds
|
|
2751
|
+
fillPixelData: fillPixelData2 = defaults7.fillPixelData
|
|
2549
2752
|
} = deps;
|
|
2550
|
-
const strokeBoundsOut = {
|
|
2551
|
-
x: 0,
|
|
2552
|
-
y: 0,
|
|
2553
|
-
w: 0,
|
|
2554
|
-
h: 0
|
|
2555
|
-
};
|
|
2556
|
-
const circleBrushBounds = {
|
|
2557
|
-
x: 0,
|
|
2558
|
-
y: 0,
|
|
2559
|
-
w: 0,
|
|
2560
|
-
h: 0
|
|
2561
|
-
};
|
|
2562
|
-
const blendColorPixelOptions = {
|
|
2563
|
-
alpha: 255,
|
|
2564
|
-
blendFn: sourceOverPerfect,
|
|
2565
|
-
x: 0,
|
|
2566
|
-
y: 0,
|
|
2567
|
-
w: 0,
|
|
2568
|
-
h: 0
|
|
2569
|
-
};
|
|
2570
|
-
const mask = {
|
|
2571
|
-
type: 0 /* ALPHA */,
|
|
2572
|
-
data: null,
|
|
2573
|
-
w: 0,
|
|
2574
|
-
h: 0
|
|
2575
|
-
};
|
|
2576
2753
|
return {
|
|
2577
|
-
|
|
2578
|
-
const
|
|
2579
|
-
const
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
if (bw <= 0 || bh <= 0) return;
|
|
2586
|
-
mask.data = new Uint8Array(bw * bh);
|
|
2587
|
-
mask.w = bw;
|
|
2588
|
-
mask.h = bh;
|
|
2589
|
-
const maskData = mask.data;
|
|
2590
|
-
const brushData = brush.data;
|
|
2591
|
-
const minOffset = brush.minOffset;
|
|
2592
|
-
const targetWidth = writer.target.width;
|
|
2593
|
-
const targetHeight = writer.target.height;
|
|
2594
|
-
forEachLinePoint2(x0, y0, x1, y1, (px, py) => {
|
|
2595
|
-
const {
|
|
2596
|
-
x: cbx,
|
|
2597
|
-
y: cby,
|
|
2598
|
-
w: cbw,
|
|
2599
|
-
h: cbh
|
|
2600
|
-
} = getCircleBrushOrPencilBounds2(px, py, brushSize, targetWidth, targetHeight, circleBrushBounds);
|
|
2601
|
-
writer.accumulator.storeRegionBeforeState(cbx, cby, cbw, cbh);
|
|
2602
|
-
const startX = Math.max(bx, cbx);
|
|
2603
|
-
const startY = Math.max(by, cby);
|
|
2604
|
-
const endX = Math.min(bx + bw, cbx + cbw);
|
|
2605
|
-
const endY = Math.min(by + bh, cby + cbh);
|
|
2606
|
-
const unclippedStartX = Math.floor(px + minOffset);
|
|
2607
|
-
const unclippedStartY = Math.floor(py + minOffset);
|
|
2608
|
-
for (let my = startY; my < endY; my++) {
|
|
2609
|
-
const strokeMaskY = my - by;
|
|
2610
|
-
const strokeMaskRowOffset = strokeMaskY * bw;
|
|
2611
|
-
const brushY = my - unclippedStartY;
|
|
2612
|
-
const brushRowOffset = brushY * brushSize;
|
|
2613
|
-
for (let mx = startX; mx < endX; mx++) {
|
|
2614
|
-
const brushX = mx - unclippedStartX;
|
|
2615
|
-
const brushVal = brushData[brushRowOffset + brushX];
|
|
2616
|
-
if (brushVal > 0) {
|
|
2617
|
-
const strokeMaskIdx = strokeMaskRowOffset + (mx - bx);
|
|
2618
|
-
if (brushVal > maskData[strokeMaskIdx]) {
|
|
2619
|
-
maskData[strokeMaskIdx] = brushVal;
|
|
2620
|
-
}
|
|
2621
|
-
}
|
|
2622
|
-
}
|
|
2623
|
-
}
|
|
2624
|
-
});
|
|
2625
|
-
blendColorPixelOptions.blendFn = blendFn;
|
|
2626
|
-
blendColorPixelOptions.alpha = alpha;
|
|
2627
|
-
blendColorPixelOptions.x = bx;
|
|
2628
|
-
blendColorPixelOptions.y = by;
|
|
2629
|
-
blendColorPixelOptions.w = bw;
|
|
2630
|
-
blendColorPixelOptions.h = bh;
|
|
2631
|
-
blendColorPixelDataAlphaMask2(writer.target, color, mask, blendColorPixelOptions);
|
|
2754
|
+
clear(rect = {}) {
|
|
2755
|
+
const target = writer.config.target;
|
|
2756
|
+
const x = rect.x ?? 0;
|
|
2757
|
+
const y = rect.y ?? 0;
|
|
2758
|
+
const w = rect.w ?? target.width;
|
|
2759
|
+
const h = rect.h ?? target.height;
|
|
2760
|
+
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2761
|
+
fillPixelData2(target, 0, x, y, w, h);
|
|
2632
2762
|
}
|
|
2633
2763
|
};
|
|
2634
2764
|
});
|
|
2635
2765
|
|
|
2636
|
-
// src/
|
|
2637
|
-
var
|
|
2638
|
-
|
|
2639
|
-
|
|
2766
|
+
// src/PixelData/fillPixelData.ts
|
|
2767
|
+
var SCRATCH_RECT2 = makeClippedRect();
|
|
2768
|
+
function fillPixelData(dst, color, _x, _y, _w, _h) {
|
|
2769
|
+
let x;
|
|
2770
|
+
let y;
|
|
2771
|
+
let w;
|
|
2772
|
+
let h;
|
|
2773
|
+
if (typeof _x === "object") {
|
|
2774
|
+
x = _x.x ?? 0;
|
|
2775
|
+
y = _x.y ?? 0;
|
|
2776
|
+
w = _x.w ?? dst.width;
|
|
2777
|
+
h = _x.h ?? dst.height;
|
|
2778
|
+
} else if (typeof _x === "number") {
|
|
2779
|
+
x = _x;
|
|
2780
|
+
y = _y;
|
|
2781
|
+
w = _w;
|
|
2782
|
+
h = _h;
|
|
2783
|
+
} else {
|
|
2784
|
+
x = 0;
|
|
2785
|
+
y = 0;
|
|
2786
|
+
w = dst.width;
|
|
2787
|
+
h = dst.height;
|
|
2788
|
+
}
|
|
2789
|
+
const clip = resolveRectClipping(x, y, w, h, dst.width, dst.height, SCRATCH_RECT2);
|
|
2790
|
+
if (!clip.inBounds) return false;
|
|
2791
|
+
const {
|
|
2792
|
+
x: finalX,
|
|
2793
|
+
y: finalY,
|
|
2794
|
+
w: actualW,
|
|
2795
|
+
h: actualH
|
|
2796
|
+
} = clip;
|
|
2797
|
+
const dst32 = dst.data32;
|
|
2798
|
+
const dw = dst.width;
|
|
2799
|
+
let hasChanged = false;
|
|
2800
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2801
|
+
const rowOffset = (finalY + iy) * dw;
|
|
2802
|
+
const start = rowOffset + finalX;
|
|
2803
|
+
const end = start + actualW;
|
|
2804
|
+
for (let i = start; i < end; i++) {
|
|
2805
|
+
if (dst32[i] !== color) {
|
|
2806
|
+
dst32[i] = color;
|
|
2807
|
+
hasChanged = true;
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
}
|
|
2811
|
+
return hasChanged;
|
|
2812
|
+
}
|
|
2813
|
+
|
|
2814
|
+
// src/History/PixelMutator/mutatorFill.ts
|
|
2815
|
+
var defaults8 = {
|
|
2816
|
+
fillPixelData
|
|
2640
2817
|
};
|
|
2641
|
-
var
|
|
2818
|
+
var mutatorFill = ((writer, deps = defaults8) => {
|
|
2642
2819
|
const {
|
|
2643
|
-
|
|
2644
|
-
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults5.getCircleBrushOrPencilBounds
|
|
2820
|
+
fillPixelData: fillPixelData2 = defaults8.fillPixelData
|
|
2645
2821
|
} = deps;
|
|
2646
|
-
const boundsOut = {
|
|
2647
|
-
x: 0,
|
|
2648
|
-
y: 0,
|
|
2649
|
-
w: 0,
|
|
2650
|
-
h: 0
|
|
2651
|
-
};
|
|
2652
2822
|
return {
|
|
2653
|
-
|
|
2654
|
-
const
|
|
2655
|
-
const
|
|
2656
|
-
|
|
2657
|
-
y,
|
|
2658
|
-
w,
|
|
2659
|
-
h
|
|
2660
|
-
} = bounds;
|
|
2661
|
-
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2662
|
-
applyCircleBrushToPixelData2(writer.target, color, centerX, centerY, brush, alpha, blendFn, bounds);
|
|
2823
|
+
fill(color, x = 0, y = 0, w = writer.config.target.width, h = writer.config.target.height) {
|
|
2824
|
+
const target = writer.config.target;
|
|
2825
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2826
|
+
return didChange(fillPixelData2(target, color, x, y, w, h));
|
|
2663
2827
|
}
|
|
2664
2828
|
};
|
|
2665
2829
|
});
|
|
2666
|
-
|
|
2667
|
-
// src/History/PixelMutator/mutatorApplyCirclePencilStroke.ts
|
|
2668
|
-
var defaults6 = {
|
|
2669
|
-
forEachLinePoint,
|
|
2670
|
-
blendColorPixelDataBinaryMask,
|
|
2671
|
-
getCircleBrushOrPencilBounds,
|
|
2672
|
-
getCircleBrushOrPencilStrokeBounds
|
|
2673
|
-
};
|
|
2674
|
-
var mutatorApplyCirclePencilStroke = ((writer, deps = defaults6) => {
|
|
2830
|
+
var mutatorFillRect = ((writer, deps = defaults8) => {
|
|
2675
2831
|
const {
|
|
2676
|
-
|
|
2677
|
-
blendColorPixelDataBinaryMask: blendColorPixelDataBinaryMask2 = defaults6.blendColorPixelDataBinaryMask,
|
|
2678
|
-
getCircleBrushOrPencilStrokeBounds: getCircleBrushOrPencilStrokeBounds2 = defaults6.getCircleBrushOrPencilStrokeBounds,
|
|
2679
|
-
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults6.getCircleBrushOrPencilBounds
|
|
2832
|
+
fillPixelData: fillPixelData2 = defaults8.fillPixelData
|
|
2680
2833
|
} = deps;
|
|
2681
|
-
const strokeBoundsOut = {
|
|
2682
|
-
x: 0,
|
|
2683
|
-
y: 0,
|
|
2684
|
-
w: 0,
|
|
2685
|
-
h: 0
|
|
2686
|
-
};
|
|
2687
|
-
const circlePencilBounds = {
|
|
2688
|
-
x: 0,
|
|
2689
|
-
y: 0,
|
|
2690
|
-
w: 0,
|
|
2691
|
-
h: 0
|
|
2692
|
-
};
|
|
2693
|
-
const blendColorPixelOptions = {
|
|
2694
|
-
alpha: 255,
|
|
2695
|
-
blendFn: sourceOverPerfect,
|
|
2696
|
-
x: 0,
|
|
2697
|
-
y: 0,
|
|
2698
|
-
w: 0,
|
|
2699
|
-
h: 0
|
|
2700
|
-
};
|
|
2701
|
-
const mask = {
|
|
2702
|
-
type: 1 /* BINARY */,
|
|
2703
|
-
data: null,
|
|
2704
|
-
w: 0,
|
|
2705
|
-
h: 0
|
|
2706
|
-
};
|
|
2707
2834
|
return {
|
|
2708
|
-
|
|
2709
|
-
const
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
w: bw,
|
|
2713
|
-
h: bh
|
|
2714
|
-
} = getCircleBrushOrPencilStrokeBounds2(x0, y0, x1, y1, brush.size, strokeBoundsOut);
|
|
2715
|
-
if (bw <= 0 || bh <= 0) return;
|
|
2716
|
-
mask.data = new Uint8Array(bw * bh);
|
|
2717
|
-
mask.w = bw;
|
|
2718
|
-
mask.h = bh;
|
|
2719
|
-
const maskData = mask.data;
|
|
2720
|
-
const targetWidth = writer.target.width;
|
|
2721
|
-
const targetHeight = writer.target.height;
|
|
2722
|
-
forEachLinePoint2(x0, y0, x1, y1, (px, py) => {
|
|
2723
|
-
const {
|
|
2724
|
-
x: cbx,
|
|
2725
|
-
y: cby,
|
|
2726
|
-
w: cbw,
|
|
2727
|
-
h: cbh
|
|
2728
|
-
} = getCircleBrushOrPencilBounds2(px, py, brush.size, targetWidth, targetHeight, circlePencilBounds);
|
|
2729
|
-
writer.accumulator.storeRegionBeforeState(cbx, cby, cbw, cbh);
|
|
2730
|
-
const unclippedStartX = Math.floor(px + brush.minOffset);
|
|
2731
|
-
const unclippedStartY = Math.floor(py + brush.minOffset);
|
|
2732
|
-
const startX = Math.max(bx, unclippedStartX);
|
|
2733
|
-
const startY = Math.max(by, unclippedStartY);
|
|
2734
|
-
const endX = Math.min(bx + bw, unclippedStartX + brush.w);
|
|
2735
|
-
const endY = Math.min(by + bh, unclippedStartY + brush.h);
|
|
2736
|
-
for (let my = startY; my < endY; my++) {
|
|
2737
|
-
const brushY = my - unclippedStartY;
|
|
2738
|
-
const maskRowOffset = (my - by) * bw;
|
|
2739
|
-
const brushRowOffset = brushY * brush.w;
|
|
2740
|
-
for (let mx = startX; mx < endX; mx++) {
|
|
2741
|
-
const brushX = mx - unclippedStartX;
|
|
2742
|
-
const brushAlpha = brush.data[brushRowOffset + brushX];
|
|
2743
|
-
if (brushAlpha > 0) {
|
|
2744
|
-
const maskIdx = maskRowOffset + (mx - bx);
|
|
2745
|
-
maskData[maskIdx] = brushAlpha;
|
|
2746
|
-
}
|
|
2747
|
-
}
|
|
2748
|
-
}
|
|
2749
|
-
});
|
|
2750
|
-
blendColorPixelOptions.blendFn = blendFn;
|
|
2751
|
-
blendColorPixelOptions.alpha = alpha;
|
|
2752
|
-
blendColorPixelOptions.x = bx;
|
|
2753
|
-
blendColorPixelOptions.y = by;
|
|
2754
|
-
blendColorPixelOptions.w = bw;
|
|
2755
|
-
blendColorPixelOptions.h = bh;
|
|
2756
|
-
blendColorPixelDataBinaryMask2(writer.target, color, mask, blendColorPixelOptions);
|
|
2835
|
+
fillRect(color, rect) {
|
|
2836
|
+
const target = writer.config.target;
|
|
2837
|
+
const didChange = writer.accumulator.storeRegionBeforeState(rect.x, rect.y, rect.w, rect.h);
|
|
2838
|
+
return didChange(fillPixelData2(target, color, rect.x, rect.y, rect.w, rect.h));
|
|
2757
2839
|
}
|
|
2758
2840
|
};
|
|
2759
2841
|
});
|
|
2760
2842
|
|
|
2761
|
-
// src/
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
const
|
|
2766
|
-
const
|
|
2767
|
-
const
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
const
|
|
2776
|
-
const
|
|
2777
|
-
const
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
}
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
const fCenterY = Math.floor(centerY);
|
|
2802
|
-
const endX = b.x + b.w;
|
|
2803
|
-
const endY = b.y + b.h;
|
|
2804
|
-
const isOverwrite = blendFn.isOverwrite;
|
|
2805
|
-
for (let py = b.y; py < endY; py++) {
|
|
2806
|
-
const rowOffset = py * targetWidth;
|
|
2807
|
-
const dy = Math.abs(py - fCenterY + centerOffsetY) * invHalfH;
|
|
2808
|
-
for (let px = b.x; px < endX; px++) {
|
|
2809
|
-
const idx = rowOffset + px;
|
|
2810
|
-
const dx = Math.abs(px - fCenterX + centerOffsetX) * invHalfW;
|
|
2811
|
-
const dist = dx > dy ? dx : dy;
|
|
2812
|
-
const strength = fallOff(dist);
|
|
2813
|
-
const maskVal = strength * 255 | 0;
|
|
2814
|
-
if (maskVal <= 0) continue;
|
|
2815
|
-
let weight = alpha;
|
|
2816
|
-
if (isOpaque) {
|
|
2817
|
-
weight = maskVal;
|
|
2818
|
-
} else if (maskVal !== 255) {
|
|
2819
|
-
weight = maskVal * alpha + 128 >> 8;
|
|
2820
|
-
}
|
|
2821
|
-
let finalCol = color;
|
|
2822
|
-
if (weight < 255) {
|
|
2823
|
-
const a = baseSrcAlpha * weight + 128 >> 8;
|
|
2824
|
-
if (a === 0 && !isOverwrite) continue;
|
|
2825
|
-
finalCol = (a << 24 | baseColor) >>> 0;
|
|
2843
|
+
// src/PixelData/fillPixelDataBinaryMask.ts
|
|
2844
|
+
var SCRATCH_RECT3 = makeClippedRect();
|
|
2845
|
+
function fillPixelDataBinaryMask(dst, color, mask, alpha = 255, x = 0, y = 0) {
|
|
2846
|
+
if (alpha === 0) return false;
|
|
2847
|
+
const maskW = mask.w;
|
|
2848
|
+
const maskH = mask.h;
|
|
2849
|
+
const clip = resolveRectClipping(x, y, maskW, maskH, dst.width, dst.height, SCRATCH_RECT3);
|
|
2850
|
+
if (!clip.inBounds) return false;
|
|
2851
|
+
const {
|
|
2852
|
+
x: finalX,
|
|
2853
|
+
y: finalY,
|
|
2854
|
+
w: actualW,
|
|
2855
|
+
h: actualH
|
|
2856
|
+
} = clip;
|
|
2857
|
+
const maskData = mask.data;
|
|
2858
|
+
const dst32 = dst.data32;
|
|
2859
|
+
const dw = dst.width;
|
|
2860
|
+
let finalCol = color;
|
|
2861
|
+
if (alpha < 255) {
|
|
2862
|
+
const baseSrcAlpha = color >>> 24;
|
|
2863
|
+
const colorRGB = color & 16777215;
|
|
2864
|
+
const a = baseSrcAlpha * alpha + 128 >> 8;
|
|
2865
|
+
finalCol = (colorRGB | a << 24) >>> 0;
|
|
2866
|
+
}
|
|
2867
|
+
let hasChanged = false;
|
|
2868
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2869
|
+
const currentY = finalY + iy;
|
|
2870
|
+
const maskY = currentY - y;
|
|
2871
|
+
const maskOffset = maskY * maskW;
|
|
2872
|
+
const dstRowOffset = currentY * dw;
|
|
2873
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2874
|
+
const currentX = finalX + ix;
|
|
2875
|
+
const maskX = currentX - x;
|
|
2876
|
+
const maskIndex = maskOffset + maskX;
|
|
2877
|
+
if (maskData[maskIndex]) {
|
|
2878
|
+
const current = dst32[dstRowOffset + currentX];
|
|
2879
|
+
if (current !== finalCol) {
|
|
2880
|
+
dst32[dstRowOffset + currentX] = finalCol;
|
|
2881
|
+
hasChanged = true;
|
|
2882
|
+
}
|
|
2826
2883
|
}
|
|
2827
|
-
data32[idx] = blendFn(finalCol, data32[idx]);
|
|
2828
2884
|
}
|
|
2829
2885
|
}
|
|
2886
|
+
return hasChanged;
|
|
2830
2887
|
}
|
|
2831
2888
|
|
|
2832
|
-
// src/History/PixelMutator/
|
|
2833
|
-
var
|
|
2834
|
-
|
|
2835
|
-
getRectBrushOrPencilBounds
|
|
2889
|
+
// src/History/PixelMutator/mutatorFillBinaryMask.ts
|
|
2890
|
+
var defaults9 = {
|
|
2891
|
+
fillPixelDataBinaryMask
|
|
2836
2892
|
};
|
|
2837
|
-
var
|
|
2893
|
+
var mutatorFillBinaryMask = ((writer, deps = defaults9) => {
|
|
2838
2894
|
const {
|
|
2839
|
-
|
|
2840
|
-
getRectBrushOrPencilBounds: getRectBrushOrPencilBounds2 = defaults7.getRectBrushOrPencilBounds
|
|
2895
|
+
fillPixelDataBinaryMask: fillPixelDataBinaryMask2 = defaults9.fillPixelDataBinaryMask
|
|
2841
2896
|
} = deps;
|
|
2842
|
-
const boundsOut = {
|
|
2843
|
-
x: 0,
|
|
2844
|
-
y: 0,
|
|
2845
|
-
w: 0,
|
|
2846
|
-
h: 0
|
|
2847
|
-
};
|
|
2848
2897
|
return {
|
|
2849
|
-
|
|
2850
|
-
const
|
|
2851
|
-
|
|
2852
|
-
x,
|
|
2853
|
-
y,
|
|
2854
|
-
w,
|
|
2855
|
-
h
|
|
2856
|
-
} = bounds;
|
|
2857
|
-
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2858
|
-
applyRectBrushToPixelData2(writer.target, color, centerX, centerY, brushWidth, brushHeight, alpha, fallOff, blendFn, bounds);
|
|
2898
|
+
fillBinaryMask(color, mask, alpha = 255, x = 0, y = 0) {
|
|
2899
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, mask.w, mask.h);
|
|
2900
|
+
return didChange(fillPixelDataBinaryMask2(writer.config.target, color, mask, alpha, x, y));
|
|
2859
2901
|
}
|
|
2860
2902
|
};
|
|
2861
2903
|
});
|
|
2862
2904
|
|
|
2863
|
-
// src/
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
const
|
|
2867
|
-
const
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2905
|
+
// src/PixelData/invertPixelData.ts
|
|
2906
|
+
var SCRATCH_RECT4 = makeClippedRect();
|
|
2907
|
+
function invertPixelData(pixelData, opts = {}) {
|
|
2908
|
+
const dst = pixelData;
|
|
2909
|
+
const {
|
|
2910
|
+
x: targetX = 0,
|
|
2911
|
+
y: targetY = 0,
|
|
2912
|
+
w: width = pixelData.width,
|
|
2913
|
+
h: height = pixelData.height,
|
|
2914
|
+
mask,
|
|
2915
|
+
mx = 0,
|
|
2916
|
+
my = 0,
|
|
2917
|
+
invertMask = false
|
|
2918
|
+
} = opts;
|
|
2919
|
+
const clip = resolveRectClipping(targetX, targetY, width, height, dst.width, dst.height, SCRATCH_RECT4);
|
|
2920
|
+
if (!clip.inBounds) return false;
|
|
2921
|
+
const {
|
|
2922
|
+
x,
|
|
2923
|
+
y,
|
|
2924
|
+
w: actualW,
|
|
2925
|
+
h: actualH
|
|
2926
|
+
} = clip;
|
|
2927
|
+
const dst32 = dst.data32;
|
|
2928
|
+
const dw = dst.width;
|
|
2929
|
+
const mPitch = mask?.w ?? width;
|
|
2930
|
+
const dx = x - targetX;
|
|
2931
|
+
const dy = y - targetY;
|
|
2932
|
+
let dIdx = y * dw + x;
|
|
2933
|
+
let mIdx = (my + dy) * mPitch + (mx + dx);
|
|
2934
|
+
const dStride = dw - actualW;
|
|
2935
|
+
const mStride = mPitch - actualW;
|
|
2936
|
+
if (mask) {
|
|
2937
|
+
const maskData = mask.data;
|
|
2938
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2939
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2940
|
+
const mVal = maskData[mIdx];
|
|
2941
|
+
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
2942
|
+
if (isHit) {
|
|
2943
|
+
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
2944
|
+
}
|
|
2945
|
+
dIdx++;
|
|
2946
|
+
mIdx++;
|
|
2947
|
+
}
|
|
2948
|
+
dIdx += dStride;
|
|
2949
|
+
mIdx += mStride;
|
|
2950
|
+
}
|
|
2951
|
+
} else {
|
|
2952
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2953
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2954
|
+
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
2955
|
+
dIdx++;
|
|
2956
|
+
}
|
|
2957
|
+
dIdx += dStride;
|
|
2958
|
+
}
|
|
2959
|
+
}
|
|
2960
|
+
return true;
|
|
2876
2961
|
}
|
|
2877
2962
|
|
|
2878
|
-
// src/History/PixelMutator/
|
|
2879
|
-
var
|
|
2880
|
-
|
|
2881
|
-
blendColorPixelDataAlphaMask,
|
|
2882
|
-
getRectBrushOrPencilBounds,
|
|
2883
|
-
getRectBrushOrPencilStrokeBounds
|
|
2963
|
+
// src/History/PixelMutator/mutatorInvert.ts
|
|
2964
|
+
var defaults10 = {
|
|
2965
|
+
invertPixelData
|
|
2884
2966
|
};
|
|
2885
|
-
var
|
|
2967
|
+
var mutatorInvert = ((writer, deps = defaults10) => {
|
|
2886
2968
|
const {
|
|
2887
|
-
|
|
2888
|
-
blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults8.blendColorPixelDataAlphaMask,
|
|
2889
|
-
getRectBrushOrPencilBounds: getRectBrushOrPencilBounds2 = defaults8.getRectBrushOrPencilBounds,
|
|
2890
|
-
getRectBrushOrPencilStrokeBounds: getRectBrushOrPencilStrokeBounds2 = defaults8.getRectBrushOrPencilStrokeBounds
|
|
2969
|
+
invertPixelData: invertPixelData2 = defaults10.invertPixelData
|
|
2891
2970
|
} = deps;
|
|
2892
|
-
const strokeBoundsOut = {
|
|
2893
|
-
x: 0,
|
|
2894
|
-
y: 0,
|
|
2895
|
-
w: 0,
|
|
2896
|
-
h: 0
|
|
2897
|
-
};
|
|
2898
|
-
const rectBrushBounds = {
|
|
2899
|
-
x: 0,
|
|
2900
|
-
y: 0,
|
|
2901
|
-
w: 0,
|
|
2902
|
-
h: 0
|
|
2903
|
-
};
|
|
2904
|
-
const blendColorPixelOptions = {
|
|
2905
|
-
alpha: 255,
|
|
2906
|
-
blendFn: sourceOverPerfect,
|
|
2907
|
-
x: 0,
|
|
2908
|
-
y: 0,
|
|
2909
|
-
w: 0,
|
|
2910
|
-
h: 0
|
|
2911
|
-
};
|
|
2912
|
-
const mask = {
|
|
2913
|
-
type: 0 /* ALPHA */,
|
|
2914
|
-
data: null,
|
|
2915
|
-
w: 0,
|
|
2916
|
-
h: 0
|
|
2917
|
-
};
|
|
2918
2971
|
return {
|
|
2919
|
-
|
|
2972
|
+
invert(opts = {}) {
|
|
2973
|
+
const target = writer.config.target;
|
|
2920
2974
|
const {
|
|
2921
|
-
x
|
|
2922
|
-
y
|
|
2923
|
-
w
|
|
2924
|
-
h
|
|
2925
|
-
} =
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
mask.w = bw;
|
|
2929
|
-
mask.h = bh;
|
|
2930
|
-
const maskData = mask.data;
|
|
2931
|
-
const halfW = brushWidth / 2;
|
|
2932
|
-
const halfH = brushHeight / 2;
|
|
2933
|
-
const invHalfW = 1 / halfW;
|
|
2934
|
-
const invHalfH = 1 / halfH;
|
|
2935
|
-
const centerOffsetX = brushWidth % 2 === 0 ? 0.5 : 0;
|
|
2936
|
-
const centerOffsetY = brushHeight % 2 === 0 ? 0.5 : 0;
|
|
2937
|
-
const targetWidth = writer.target.width;
|
|
2938
|
-
const targetHeight = writer.target.height;
|
|
2939
|
-
forEachLinePoint2(x0, y0, x1, y1, (px, py) => {
|
|
2940
|
-
const {
|
|
2941
|
-
x: rbx,
|
|
2942
|
-
y: rby,
|
|
2943
|
-
w: rbw,
|
|
2944
|
-
h: rbh
|
|
2945
|
-
} = getRectBrushOrPencilBounds2(px, py, brushWidth, brushHeight, targetWidth, targetHeight, rectBrushBounds);
|
|
2946
|
-
writer.accumulator.storeRegionBeforeState(rbx, rby, rbw, rbh);
|
|
2947
|
-
const startX = Math.max(bx, rbx);
|
|
2948
|
-
const startY = Math.max(by, rby);
|
|
2949
|
-
const endX = Math.min(bx + bw, rbx + rbw);
|
|
2950
|
-
const endY = Math.min(by + bh, rby + rbh);
|
|
2951
|
-
const fPx = Math.floor(px);
|
|
2952
|
-
const fPy = Math.floor(py);
|
|
2953
|
-
for (let my = startY; my < endY; my++) {
|
|
2954
|
-
const dy = Math.abs(my - fPy + centerOffsetY) * invHalfH;
|
|
2955
|
-
const maskRowOffset = (my - by) * bw;
|
|
2956
|
-
for (let mx = startX; mx < endX; mx++) {
|
|
2957
|
-
const dx = Math.abs(mx - fPx + centerOffsetX) * invHalfW;
|
|
2958
|
-
const maskIdx = maskRowOffset + (mx - bx);
|
|
2959
|
-
const dist = dx > dy ? dx : dy;
|
|
2960
|
-
const strength = fallOff(dist);
|
|
2961
|
-
if (strength > 0) {
|
|
2962
|
-
const intensity = strength * 255 | 0;
|
|
2963
|
-
if (intensity > maskData[maskIdx]) {
|
|
2964
|
-
maskData[maskIdx] = intensity;
|
|
2965
|
-
}
|
|
2966
|
-
}
|
|
2967
|
-
}
|
|
2968
|
-
}
|
|
2969
|
-
});
|
|
2970
|
-
blendColorPixelOptions.blendFn = blendFn;
|
|
2971
|
-
blendColorPixelOptions.alpha = alpha;
|
|
2972
|
-
blendColorPixelOptions.x = bx;
|
|
2973
|
-
blendColorPixelOptions.y = by;
|
|
2974
|
-
blendColorPixelOptions.w = bw;
|
|
2975
|
-
blendColorPixelOptions.h = bh;
|
|
2976
|
-
blendColorPixelDataAlphaMask2(writer.target, color, mask, blendColorPixelOptions);
|
|
2975
|
+
x = 0,
|
|
2976
|
+
y = 0,
|
|
2977
|
+
w = target.width,
|
|
2978
|
+
h = target.height
|
|
2979
|
+
} = opts;
|
|
2980
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2981
|
+
return didChange(invertPixelData2(target, opts));
|
|
2977
2982
|
}
|
|
2978
2983
|
};
|
|
2979
2984
|
});
|
|
2980
2985
|
|
|
2981
|
-
// src/History/PixelMutator
|
|
2982
|
-
|
|
2983
|
-
applyRectBrushToPixelData,
|
|
2984
|
-
getRectBrushOrPencilBounds,
|
|
2985
|
-
fallOff: () => 1
|
|
2986
|
-
};
|
|
2987
|
-
var mutatorApplyRectPencil = ((writer, deps = defaults9) => {
|
|
2988
|
-
const {
|
|
2989
|
-
applyRectBrushToPixelData: applyRectBrushToPixelData2 = defaults9.applyRectBrushToPixelData,
|
|
2990
|
-
getRectBrushOrPencilBounds: getRectBrushOrPencilBounds2 = defaults9.getRectBrushOrPencilBounds,
|
|
2991
|
-
fallOff = defaults9.fallOff
|
|
2992
|
-
} = deps;
|
|
2993
|
-
const boundsOut = {
|
|
2994
|
-
x: 0,
|
|
2995
|
-
y: 0,
|
|
2996
|
-
w: 0,
|
|
2997
|
-
h: 0
|
|
2998
|
-
};
|
|
2986
|
+
// src/History/PixelMutator.ts
|
|
2987
|
+
function makeFullPixelMutator(writer) {
|
|
2999
2988
|
return {
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
2989
|
+
// @sort
|
|
2990
|
+
...mutatorBlendColor(writer),
|
|
2991
|
+
...mutatorBlendPixel(writer),
|
|
2992
|
+
...mutatorBlendPixelData(writer),
|
|
2993
|
+
...mutatorBlendPixelDataAlphaMask(writer),
|
|
2994
|
+
...mutatorBlendPixelDataBinaryMask(writer),
|
|
2995
|
+
...mutatorClear(writer),
|
|
2996
|
+
...mutatorFill(writer),
|
|
2997
|
+
...mutatorFillBinaryMask(writer),
|
|
2998
|
+
...mutatorFillRect(writer),
|
|
2999
|
+
...mutatorInvert(writer)
|
|
3011
3000
|
};
|
|
3012
|
-
}
|
|
3001
|
+
}
|
|
3013
3002
|
|
|
3014
|
-
// src/
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
getRectBrushOrPencilBounds,
|
|
3018
|
-
getRectBrushOrPencilStrokeBounds,
|
|
3019
|
-
blendColorPixelDataBinaryMask
|
|
3020
|
-
};
|
|
3021
|
-
var mutatorApplyRectPencilStroke = ((writer, deps = defaults10) => {
|
|
3003
|
+
// src/ImageData/resizeImageData.ts
|
|
3004
|
+
function resizeImageData(target, newWidth, newHeight, offsetX = 0, offsetY = 0) {
|
|
3005
|
+
const result = new ImageData(newWidth, newHeight);
|
|
3022
3006
|
const {
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
const
|
|
3007
|
+
width: oldW,
|
|
3008
|
+
height: oldH,
|
|
3009
|
+
data: oldData
|
|
3010
|
+
} = target;
|
|
3011
|
+
const newData = result.data;
|
|
3012
|
+
const x0 = Math.max(0, offsetX);
|
|
3013
|
+
const y0 = Math.max(0, offsetY);
|
|
3014
|
+
const x1 = Math.min(newWidth, offsetX + oldW);
|
|
3015
|
+
const y1 = Math.min(newHeight, offsetY + oldH);
|
|
3016
|
+
if (x1 <= x0 || y1 <= y0) {
|
|
3017
|
+
return result;
|
|
3018
|
+
}
|
|
3019
|
+
const rowCount = y1 - y0;
|
|
3020
|
+
const rowLen = (x1 - x0) * 4;
|
|
3021
|
+
for (let row = 0; row < rowCount; row++) {
|
|
3022
|
+
const dstY = y0 + row;
|
|
3023
|
+
const srcY = dstY - offsetY;
|
|
3024
|
+
const srcX = x0 - offsetX;
|
|
3025
|
+
const dstStart = (dstY * newWidth + x0) * 4;
|
|
3026
|
+
const srcStart = (srcY * oldW + srcX) * 4;
|
|
3027
|
+
newData.set(oldData.subarray(srcStart, srcStart + rowLen), dstStart);
|
|
3028
|
+
}
|
|
3029
|
+
return result;
|
|
3030
|
+
}
|
|
3031
|
+
|
|
3032
|
+
// src/Internal/helpers.ts
|
|
3033
|
+
var macro_halfAndFloor = (value) => value >> 1;
|
|
3034
|
+
|
|
3035
|
+
// src/Rect/trimRectBounds.ts
|
|
3036
|
+
function trimRectBounds(x, y, w, h, targetWidth, targetHeight, out) {
|
|
3037
|
+
const res = out ?? {
|
|
3029
3038
|
x: 0,
|
|
3030
3039
|
y: 0,
|
|
3031
3040
|
w: 0,
|
|
3032
3041
|
h: 0
|
|
3033
3042
|
};
|
|
3034
|
-
const
|
|
3043
|
+
const left = Math.max(0, x);
|
|
3044
|
+
const top = Math.max(0, y);
|
|
3045
|
+
const right = Math.min(targetWidth, x + w);
|
|
3046
|
+
const bottom = Math.min(targetHeight, y + h);
|
|
3047
|
+
res.x = left;
|
|
3048
|
+
res.y = top;
|
|
3049
|
+
res.w = Math.max(0, right - left);
|
|
3050
|
+
res.h = Math.max(0, bottom - top);
|
|
3051
|
+
return res;
|
|
3052
|
+
}
|
|
3053
|
+
|
|
3054
|
+
// src/Paint/PaintBuffer.ts
|
|
3055
|
+
var PaintBuffer = class {
|
|
3056
|
+
constructor(config, tilePool) {
|
|
3057
|
+
this.config = config;
|
|
3058
|
+
this.tilePool = tilePool;
|
|
3059
|
+
this.lookup = [];
|
|
3060
|
+
}
|
|
3061
|
+
lookup;
|
|
3062
|
+
scratchBounds = {
|
|
3035
3063
|
x: 0,
|
|
3036
3064
|
y: 0,
|
|
3037
3065
|
w: 0,
|
|
3038
3066
|
h: 0
|
|
3039
3067
|
};
|
|
3040
|
-
|
|
3041
|
-
|
|
3068
|
+
eachTileInBounds(bounds, callback) {
|
|
3069
|
+
const {
|
|
3070
|
+
tileShift,
|
|
3071
|
+
targetColumns,
|
|
3072
|
+
targetRows,
|
|
3073
|
+
tileSize
|
|
3074
|
+
} = this.config;
|
|
3075
|
+
const x1 = Math.max(0, bounds.x >> tileShift);
|
|
3076
|
+
const y1 = Math.max(0, bounds.y >> tileShift);
|
|
3077
|
+
const x2 = Math.min(targetColumns - 1, bounds.x + bounds.w - 1 >> tileShift);
|
|
3078
|
+
const y2 = Math.min(targetRows - 1, bounds.y + bounds.h - 1 >> tileShift);
|
|
3079
|
+
if (x1 > x2 || y1 > y2) return;
|
|
3080
|
+
const lookup = this.lookup;
|
|
3081
|
+
const tilePool = this.tilePool;
|
|
3082
|
+
for (let ty = y1; ty <= y2; ty++) {
|
|
3083
|
+
const rowOffset = ty * targetColumns;
|
|
3084
|
+
const tileTop = ty << tileShift;
|
|
3085
|
+
for (let tx = x1; tx <= x2; tx++) {
|
|
3086
|
+
const id = rowOffset + tx;
|
|
3087
|
+
const tile = lookup[id] ?? (lookup[id] = tilePool.getTile(id, tx, ty));
|
|
3088
|
+
const tileLeft = tx << tileShift;
|
|
3089
|
+
const startX = bounds.x > tileLeft ? bounds.x : tileLeft;
|
|
3090
|
+
const startY = bounds.y > tileTop ? bounds.y : tileTop;
|
|
3091
|
+
const maskEndX = bounds.x + bounds.w;
|
|
3092
|
+
const tileEndX = tileLeft + tileSize;
|
|
3093
|
+
const endX = maskEndX < tileEndX ? maskEndX : tileEndX;
|
|
3094
|
+
const maskEndY = bounds.y + bounds.h;
|
|
3095
|
+
const tileEndY = tileTop + tileSize;
|
|
3096
|
+
const endY = maskEndY < tileEndY ? maskEndY : tileEndY;
|
|
3097
|
+
callback(tile, startX, startY, endX - startX, endY - startY);
|
|
3098
|
+
}
|
|
3099
|
+
}
|
|
3100
|
+
}
|
|
3101
|
+
writePaintAlphaMaskStroke(color, brush, x0, y0, x1, y1) {
|
|
3102
|
+
const cA = color >>> 24;
|
|
3103
|
+
if (cA === 0) return false;
|
|
3104
|
+
const {
|
|
3105
|
+
tileShift,
|
|
3106
|
+
tileMask,
|
|
3107
|
+
target
|
|
3108
|
+
} = this.config;
|
|
3109
|
+
const {
|
|
3110
|
+
w: bW,
|
|
3111
|
+
h: bH,
|
|
3112
|
+
data: bD,
|
|
3113
|
+
centerOffsetX,
|
|
3114
|
+
centerOffsetY
|
|
3115
|
+
} = brush;
|
|
3116
|
+
const cRGB = color & 16777215;
|
|
3117
|
+
const scratch = this.scratchBounds;
|
|
3118
|
+
let changed = false;
|
|
3119
|
+
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
3120
|
+
const topLeftX = Math.floor(px + centerOffsetX);
|
|
3121
|
+
const topLeftY = Math.floor(py + centerOffsetY);
|
|
3122
|
+
trimRectBounds(topLeftX, topLeftY, bW, bH, target.width, target.height, scratch);
|
|
3123
|
+
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
3124
|
+
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
3125
|
+
const d32 = tile.data32;
|
|
3126
|
+
let tileChanged = false;
|
|
3127
|
+
for (let i = 0; i < bH_t; i++) {
|
|
3128
|
+
const canvasY = bY + i;
|
|
3129
|
+
const bOff = (canvasY - topLeftY) * bW;
|
|
3130
|
+
const tOff = (canvasY & tileMask) << tileShift;
|
|
3131
|
+
const dS = tOff + (bX & tileMask);
|
|
3132
|
+
for (let j = 0; j < bW_t; j++) {
|
|
3133
|
+
const canvasX = bX + j;
|
|
3134
|
+
const brushA = bD[bOff + (canvasX - topLeftX)];
|
|
3135
|
+
if (brushA === 0) continue;
|
|
3136
|
+
const t = cA * brushA + 128;
|
|
3137
|
+
const blendedA = t + (t >> 8) >> 8;
|
|
3138
|
+
const idx = dS + j;
|
|
3139
|
+
const cur = d32[idx];
|
|
3140
|
+
if (brushA > cur >>> 24) {
|
|
3141
|
+
const next = (cRGB | blendedA << 24) >>> 0;
|
|
3142
|
+
if (cur !== next) {
|
|
3143
|
+
d32[idx] = next;
|
|
3144
|
+
tileChanged = true;
|
|
3145
|
+
}
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
}
|
|
3149
|
+
if (tileChanged) changed = true;
|
|
3150
|
+
});
|
|
3151
|
+
});
|
|
3152
|
+
return changed;
|
|
3153
|
+
}
|
|
3154
|
+
writePaintBinaryMaskStroke(color, brush, x0, y0, x1, y1) {
|
|
3155
|
+
const alphaIsZero = color >>> 24 === 0;
|
|
3156
|
+
if (alphaIsZero) return false;
|
|
3157
|
+
const {
|
|
3158
|
+
tileShift,
|
|
3159
|
+
tileMask,
|
|
3160
|
+
target
|
|
3161
|
+
} = this.config;
|
|
3162
|
+
const {
|
|
3163
|
+
w: bW,
|
|
3164
|
+
h: bH,
|
|
3165
|
+
data: bD,
|
|
3166
|
+
centerOffsetX,
|
|
3167
|
+
centerOffsetY
|
|
3168
|
+
} = brush;
|
|
3169
|
+
const scratch = this.scratchBounds;
|
|
3170
|
+
let changed = false;
|
|
3171
|
+
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
3172
|
+
const topLeftX = Math.floor(px + centerOffsetX);
|
|
3173
|
+
const topLeftY = Math.floor(py + centerOffsetY);
|
|
3174
|
+
trimRectBounds(topLeftX, topLeftY, bW, bH, target.width, target.height, scratch);
|
|
3175
|
+
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
3176
|
+
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
3177
|
+
const d32 = tile.data32;
|
|
3178
|
+
let tileChanged = false;
|
|
3179
|
+
for (let i = 0; i < bH_t; i++) {
|
|
3180
|
+
const canvasY = bY + i;
|
|
3181
|
+
const bOff = (canvasY - topLeftY) * bW;
|
|
3182
|
+
const tOff = (canvasY & tileMask) << tileShift;
|
|
3183
|
+
const dS = tOff + (bX & tileMask);
|
|
3184
|
+
for (let j = 0; j < bW_t; j++) {
|
|
3185
|
+
const canvasX = bX + j;
|
|
3186
|
+
if (bD[bOff + (canvasX - topLeftX)]) {
|
|
3187
|
+
const idx = dS + j;
|
|
3188
|
+
if (d32[idx] !== color) {
|
|
3189
|
+
d32[idx] = color;
|
|
3190
|
+
tileChanged = true;
|
|
3191
|
+
}
|
|
3192
|
+
}
|
|
3193
|
+
}
|
|
3194
|
+
}
|
|
3195
|
+
if (tileChanged) changed = true;
|
|
3196
|
+
});
|
|
3197
|
+
});
|
|
3198
|
+
return changed;
|
|
3199
|
+
}
|
|
3200
|
+
writeRectStroke(color, brushWidth, brushHeight, x0, y0, x1, y1) {
|
|
3201
|
+
const alphaIsZero = color >>> 24 === 0;
|
|
3202
|
+
if (alphaIsZero) return false;
|
|
3203
|
+
const config = this.config;
|
|
3204
|
+
const tileShift = config.tileShift;
|
|
3205
|
+
const tileMask = config.tileMask;
|
|
3206
|
+
const target = config.target;
|
|
3207
|
+
const scratch = this.scratchBounds;
|
|
3208
|
+
const centerOffsetX = macro_halfAndFloor(brushWidth - 1);
|
|
3209
|
+
const centerOffsetY = macro_halfAndFloor(brushHeight - 1);
|
|
3210
|
+
let changed = false;
|
|
3211
|
+
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
3212
|
+
const topLeftX = Math.floor(px + centerOffsetX);
|
|
3213
|
+
const topLeftY = Math.floor(py + centerOffsetY);
|
|
3214
|
+
trimRectBounds(topLeftX, topLeftY, brushWidth, brushHeight, target.width, target.height, scratch);
|
|
3215
|
+
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
3216
|
+
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
3217
|
+
const d32 = tile.data32;
|
|
3218
|
+
let tileChanged = false;
|
|
3219
|
+
for (let i = 0; i < bH_t; i++) {
|
|
3220
|
+
const canvasY = bY + i;
|
|
3221
|
+
const tOff = (canvasY & tileMask) << tileShift;
|
|
3222
|
+
const dS = tOff + (bX & tileMask);
|
|
3223
|
+
for (let j = 0; j < bW_t; j++) {
|
|
3224
|
+
const idx = dS + j;
|
|
3225
|
+
if (d32[idx] !== color) {
|
|
3226
|
+
d32[idx] = color;
|
|
3227
|
+
tileChanged = true;
|
|
3228
|
+
}
|
|
3229
|
+
}
|
|
3230
|
+
}
|
|
3231
|
+
if (tileChanged) {
|
|
3232
|
+
changed = true;
|
|
3233
|
+
}
|
|
3234
|
+
});
|
|
3235
|
+
});
|
|
3236
|
+
return changed;
|
|
3237
|
+
}
|
|
3238
|
+
clear() {
|
|
3239
|
+
this.tilePool.releaseTiles(this.lookup);
|
|
3240
|
+
}
|
|
3241
|
+
};
|
|
3242
|
+
|
|
3243
|
+
// src/PixelTile/PixelTile.ts
|
|
3244
|
+
var PixelTile = class {
|
|
3245
|
+
constructor(id, tx, ty, tileSize, tileArea) {
|
|
3246
|
+
this.id = id;
|
|
3247
|
+
this.tx = tx;
|
|
3248
|
+
this.ty = ty;
|
|
3249
|
+
this.width = this.height = tileSize;
|
|
3250
|
+
this.data32 = new Uint32Array(tileArea);
|
|
3251
|
+
const data8 = new Uint8ClampedArray(this.data32.buffer);
|
|
3252
|
+
this.imageData = new ImageData(data8, tileSize, tileSize);
|
|
3253
|
+
}
|
|
3254
|
+
data32;
|
|
3255
|
+
width;
|
|
3256
|
+
height;
|
|
3257
|
+
imageData;
|
|
3258
|
+
};
|
|
3259
|
+
|
|
3260
|
+
// src/PixelTile/PixelTilePool.ts
|
|
3261
|
+
var PixelTilePool = class {
|
|
3262
|
+
pool;
|
|
3263
|
+
tileSize;
|
|
3264
|
+
tileArea;
|
|
3265
|
+
constructor(config) {
|
|
3266
|
+
this.pool = [];
|
|
3267
|
+
this.tileSize = config.tileSize;
|
|
3268
|
+
this.tileArea = config.tileArea;
|
|
3269
|
+
}
|
|
3270
|
+
getTile(id, tx, ty) {
|
|
3271
|
+
let tile = this.pool.pop();
|
|
3272
|
+
if (tile) {
|
|
3273
|
+
tile.id = id;
|
|
3274
|
+
tile.tx = tx;
|
|
3275
|
+
tile.ty = ty;
|
|
3276
|
+
tile.data32.fill(0);
|
|
3277
|
+
return tile;
|
|
3278
|
+
}
|
|
3279
|
+
return new PixelTile(id, tx, ty, this.tileSize, this.tileArea);
|
|
3280
|
+
}
|
|
3281
|
+
releaseTile(tile) {
|
|
3282
|
+
this.pool.push(tile);
|
|
3283
|
+
}
|
|
3284
|
+
releaseTiles(tiles) {
|
|
3285
|
+
let length = tiles.length;
|
|
3286
|
+
for (let i = 0; i < length; i++) {
|
|
3287
|
+
let tile = tiles[i];
|
|
3288
|
+
if (tile) {
|
|
3289
|
+
this.pool.push(tile);
|
|
3290
|
+
}
|
|
3291
|
+
}
|
|
3292
|
+
tiles.length = 0;
|
|
3293
|
+
}
|
|
3294
|
+
};
|
|
3295
|
+
|
|
3296
|
+
// src/History/PixelWriter.ts
|
|
3297
|
+
var PixelWriter = class {
|
|
3298
|
+
historyManager;
|
|
3299
|
+
accumulator;
|
|
3300
|
+
historyActionFactory;
|
|
3301
|
+
config;
|
|
3302
|
+
pixelTilePool;
|
|
3303
|
+
paintBuffer;
|
|
3304
|
+
mutator;
|
|
3305
|
+
blendPixelDataOpts = {
|
|
3306
|
+
alpha: 255,
|
|
3042
3307
|
blendFn: sourceOverPerfect,
|
|
3043
3308
|
x: 0,
|
|
3044
3309
|
y: 0,
|
|
3045
3310
|
w: 0,
|
|
3046
3311
|
h: 0
|
|
3047
3312
|
};
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
const endY = Math.min(by + bh, rby + rbh);
|
|
3084
|
-
const fPx = Math.floor(px);
|
|
3085
|
-
const fPy = Math.floor(py);
|
|
3086
|
-
for (let my = startY; my < endY; my++) {
|
|
3087
|
-
const dy = Math.abs(my - fPy + centerOffset);
|
|
3088
|
-
const maskRowOffset = (my - by) * bw;
|
|
3089
|
-
for (let mx = startX; mx < endX; mx++) {
|
|
3090
|
-
const dx = Math.abs(mx - fPx + centerOffset);
|
|
3091
|
-
const maskIdx = maskRowOffset + (mx - bx);
|
|
3092
|
-
if (dx <= halfW && dy <= halfH) {
|
|
3093
|
-
maskData[maskIdx] = 1;
|
|
3094
|
-
}
|
|
3095
|
-
}
|
|
3096
|
-
}
|
|
3097
|
-
});
|
|
3098
|
-
blendColorPixelOptions.blendFn = blendFn;
|
|
3099
|
-
blendColorPixelOptions.alpha = alpha;
|
|
3100
|
-
blendColorPixelOptions.x = bx;
|
|
3101
|
-
blendColorPixelOptions.y = by;
|
|
3102
|
-
blendColorPixelOptions.w = bw;
|
|
3103
|
-
blendColorPixelOptions.h = bh;
|
|
3104
|
-
blendColorPixelDataBinaryMask2(writer.target, color, mask, blendColorPixelOptions);
|
|
3313
|
+
_inProgress = false;
|
|
3314
|
+
constructor(target, mutatorFactory, {
|
|
3315
|
+
tileSize = 256,
|
|
3316
|
+
maxHistorySteps = 50,
|
|
3317
|
+
historyManager = new HistoryManager(maxHistorySteps),
|
|
3318
|
+
historyActionFactory = makeHistoryAction,
|
|
3319
|
+
pixelTilePool,
|
|
3320
|
+
accumulator
|
|
3321
|
+
} = {}) {
|
|
3322
|
+
this.config = new PixelEngineConfig(tileSize, target);
|
|
3323
|
+
this.historyManager = historyManager;
|
|
3324
|
+
this.pixelTilePool = pixelTilePool ?? new PixelTilePool(this.config);
|
|
3325
|
+
this.accumulator = accumulator ?? new PixelAccumulator(this.config, this.pixelTilePool);
|
|
3326
|
+
this.historyActionFactory = historyActionFactory;
|
|
3327
|
+
this.mutator = mutatorFactory(this);
|
|
3328
|
+
this.paintBuffer = new PaintBuffer(this.config, this.pixelTilePool);
|
|
3329
|
+
}
|
|
3330
|
+
/**
|
|
3331
|
+
* Executes `transaction` and commits the resulting pixel changes as a single
|
|
3332
|
+
* undoable history action.
|
|
3333
|
+
*
|
|
3334
|
+
* - If `transaction` throws, all accumulated changes are rolled back and the error
|
|
3335
|
+
* is re-thrown. No action is committed.
|
|
3336
|
+
* - If `transaction` completes without modifying any pixels, no action is committed.
|
|
3337
|
+
* - `withHistory` is not re-entrant. Calling it again from inside `transaction` will
|
|
3338
|
+
* throw immediately to prevent silent data loss from a nested extractPatch.
|
|
3339
|
+
*
|
|
3340
|
+
* @param transaction Callback to be executed inside the transaction.
|
|
3341
|
+
* @param after Called after both undo and redo — use for generic change notifications.
|
|
3342
|
+
* @param afterUndo Called after undo only — use for dimension or state changes specific to undo.
|
|
3343
|
+
* @param afterRedo Called after redo only.
|
|
3344
|
+
*/
|
|
3345
|
+
withHistory(transaction, after, afterUndo, afterRedo) {
|
|
3346
|
+
if (this._inProgress) {
|
|
3347
|
+
throw new Error("withHistory is not re-entrant \u2014 commit or rollback the current operation first");
|
|
3105
3348
|
}
|
|
3106
|
-
|
|
3107
|
-
|
|
3349
|
+
this._inProgress = true;
|
|
3350
|
+
try {
|
|
3351
|
+
transaction(this.mutator);
|
|
3352
|
+
} catch (e) {
|
|
3353
|
+
this.accumulator.rollbackAfterError();
|
|
3354
|
+
throw e;
|
|
3355
|
+
} finally {
|
|
3356
|
+
this._inProgress = false;
|
|
3357
|
+
}
|
|
3358
|
+
if (this.accumulator.beforeTiles.length === 0) return;
|
|
3359
|
+
const patch = this.accumulator.extractPatch();
|
|
3360
|
+
const action = this.historyActionFactory(this, patch, after, afterUndo, afterRedo);
|
|
3361
|
+
this.historyManager.commit(action);
|
|
3362
|
+
}
|
|
3363
|
+
resize(newWidth, newHeight, offsetX = 0, offsetY = 0, after, afterUndo, afterRedo, resizeImageDataFn = resizeImageData) {
|
|
3364
|
+
if (this._inProgress) {
|
|
3365
|
+
throw new Error("Cannot resize inside a withHistory callback");
|
|
3366
|
+
}
|
|
3367
|
+
if (this.accumulator.beforeTiles.length > 0) {
|
|
3368
|
+
throw new Error("Cannot resize with an open accumulator \u2014 commit or rollback first");
|
|
3369
|
+
}
|
|
3370
|
+
const config = this.config;
|
|
3371
|
+
const target = config.target;
|
|
3372
|
+
const beforeImageData = target.imageData;
|
|
3373
|
+
const afterImageData = resizeImageDataFn(beforeImageData, newWidth, newHeight, offsetX, offsetY);
|
|
3374
|
+
target.set(afterImageData);
|
|
3375
|
+
this.historyManager.commit({
|
|
3376
|
+
undo: () => {
|
|
3377
|
+
target.set(beforeImageData);
|
|
3378
|
+
afterUndo?.(beforeImageData);
|
|
3379
|
+
after?.(beforeImageData);
|
|
3380
|
+
},
|
|
3381
|
+
redo: () => {
|
|
3382
|
+
target.set(afterImageData);
|
|
3383
|
+
afterRedo?.(afterImageData);
|
|
3384
|
+
after?.(afterImageData);
|
|
3385
|
+
}
|
|
3386
|
+
});
|
|
3387
|
+
}
|
|
3388
|
+
commitPaintBuffer(alpha = 255, blendFn = sourceOverPerfect, blendPixelDataFn = blendPixelData) {
|
|
3389
|
+
const paintBuffer = this.paintBuffer;
|
|
3390
|
+
const tileShift = paintBuffer.config.tileShift;
|
|
3391
|
+
const lookup = paintBuffer.lookup;
|
|
3392
|
+
const opts = this.blendPixelDataOpts;
|
|
3393
|
+
opts.alpha = alpha;
|
|
3394
|
+
opts.blendFn = blendFn;
|
|
3395
|
+
for (let i = 0; i < lookup.length; i++) {
|
|
3396
|
+
const tile = lookup[i];
|
|
3397
|
+
if (tile) {
|
|
3398
|
+
const didChange = this.accumulator.storeTileBeforeState(tile.id, tile.tx, tile.ty);
|
|
3399
|
+
const dx = tile.tx << tileShift;
|
|
3400
|
+
const dy = tile.ty << tileShift;
|
|
3401
|
+
opts.x = dx;
|
|
3402
|
+
opts.y = dy;
|
|
3403
|
+
opts.w = tile.width;
|
|
3404
|
+
opts.h = tile.height;
|
|
3405
|
+
didChange(blendPixelDataFn(this.config.target, tile, opts));
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
paintBuffer.clear();
|
|
3409
|
+
}
|
|
3410
|
+
};
|
|
3108
3411
|
|
|
3109
|
-
// src/PixelData/
|
|
3110
|
-
function
|
|
3412
|
+
// src/PixelData/applyAlphaMaskToPixelData.ts
|
|
3413
|
+
function applyAlphaMaskToPixelData(dst, mask, opts = {}) {
|
|
3111
3414
|
const {
|
|
3112
3415
|
x: targetX = 0,
|
|
3113
3416
|
y: targetY = 0,
|
|
3114
3417
|
w: width = dst.width,
|
|
3115
3418
|
h: height = dst.height,
|
|
3116
3419
|
alpha: globalAlpha = 255,
|
|
3117
|
-
|
|
3420
|
+
mx = 0,
|
|
3421
|
+
my = 0,
|
|
3422
|
+
invertMask = false
|
|
3118
3423
|
} = opts;
|
|
3119
|
-
if (globalAlpha === 0) return;
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
let
|
|
3424
|
+
if (globalAlpha === 0) return false;
|
|
3425
|
+
let x = targetX;
|
|
3426
|
+
let y = targetY;
|
|
3427
|
+
let w = width;
|
|
3428
|
+
let h = height;
|
|
3124
3429
|
if (x < 0) {
|
|
3125
3430
|
w += x;
|
|
3126
3431
|
x = 0;
|
|
@@ -3129,723 +3434,200 @@ function blendColorPixelData(dst, color, opts = {}) {
|
|
|
3129
3434
|
h += y;
|
|
3130
3435
|
y = 0;
|
|
3131
3436
|
}
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
if (
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3437
|
+
w = Math.min(w, dst.width - x);
|
|
3438
|
+
h = Math.min(h, dst.height - y);
|
|
3439
|
+
if (w <= 0) return false;
|
|
3440
|
+
if (h <= 0) return false;
|
|
3441
|
+
const mPitch = mask.w;
|
|
3442
|
+
if (mPitch <= 0) return false;
|
|
3443
|
+
const startX = mx + (x - targetX);
|
|
3444
|
+
const startY = my + (y - targetY);
|
|
3445
|
+
const sX0 = Math.max(0, startX);
|
|
3446
|
+
const sY0 = Math.max(0, startY);
|
|
3447
|
+
const sX1 = Math.min(mPitch, startX + w);
|
|
3448
|
+
const sY1 = Math.min(mask.h, startY + h);
|
|
3449
|
+
const finalW = sX1 - sX0;
|
|
3450
|
+
const finalH = sY1 - sY0;
|
|
3451
|
+
if (finalW <= 0) return false;
|
|
3452
|
+
if (finalH <= 0) return false;
|
|
3453
|
+
const xShift = sX0 - startX;
|
|
3454
|
+
const yShift = sY0 - startY;
|
|
3141
3455
|
const dst32 = dst.data32;
|
|
3142
3456
|
const dw = dst.width;
|
|
3143
|
-
|
|
3144
|
-
const
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3457
|
+
const dStride = dw - finalW;
|
|
3458
|
+
const mStride = mPitch - finalW;
|
|
3459
|
+
const maskData = mask.data;
|
|
3460
|
+
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
3461
|
+
let mIdx = sY0 * mPitch + sX0;
|
|
3462
|
+
let didChange = false;
|
|
3463
|
+
for (let iy = 0; iy < h; iy++) {
|
|
3464
|
+
for (let ix = 0; ix < w; ix++) {
|
|
3465
|
+
const mVal = maskData[mIdx];
|
|
3466
|
+
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
3467
|
+
let weight = 0;
|
|
3468
|
+
if (effectiveM === 0) {
|
|
3469
|
+
weight = 0;
|
|
3470
|
+
} else if (effectiveM === 255) {
|
|
3471
|
+
weight = globalAlpha;
|
|
3472
|
+
} else if (globalAlpha === 255) {
|
|
3473
|
+
weight = effectiveM;
|
|
3474
|
+
} else {
|
|
3475
|
+
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
3476
|
+
}
|
|
3477
|
+
if (weight === 0) {
|
|
3478
|
+
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
3479
|
+
didChange = true;
|
|
3480
|
+
} else if (weight !== 255) {
|
|
3481
|
+
const d = dst32[dIdx];
|
|
3482
|
+
const da = d >>> 24;
|
|
3483
|
+
if (da !== 0) {
|
|
3484
|
+
const finalAlpha = da === 255 ? weight : da * weight + 128 >> 8;
|
|
3485
|
+
const current = dst32[dIdx];
|
|
3486
|
+
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
3487
|
+
if (current !== next) {
|
|
3488
|
+
dst32[dIdx] = next;
|
|
3489
|
+
didChange = true;
|
|
3490
|
+
}
|
|
3491
|
+
}
|
|
3492
|
+
}
|
|
3148
3493
|
dIdx++;
|
|
3494
|
+
mIdx++;
|
|
3149
3495
|
}
|
|
3150
3496
|
dIdx += dStride;
|
|
3497
|
+
mIdx += mStride;
|
|
3151
3498
|
}
|
|
3499
|
+
return didChange;
|
|
3152
3500
|
}
|
|
3153
3501
|
|
|
3154
|
-
// src/History/PixelMutator/
|
|
3502
|
+
// src/History/PixelMutator/mutatorApplyAlphaMask.ts
|
|
3155
3503
|
var defaults11 = {
|
|
3156
|
-
|
|
3504
|
+
applyAlphaMaskToPixelData
|
|
3157
3505
|
};
|
|
3158
|
-
var
|
|
3506
|
+
var mutatorApplyAlphaMask = ((writer, deps = defaults11) => {
|
|
3159
3507
|
const {
|
|
3160
|
-
|
|
3508
|
+
applyAlphaMaskToPixelData: applyAlphaMaskToPixelData2 = defaults11.applyAlphaMaskToPixelData
|
|
3161
3509
|
} = deps;
|
|
3162
3510
|
return {
|
|
3163
|
-
|
|
3511
|
+
applyAlphaMask(mask, opts = {}) {
|
|
3512
|
+
let target = writer.config.target;
|
|
3164
3513
|
const {
|
|
3165
3514
|
x = 0,
|
|
3166
3515
|
y = 0,
|
|
3167
|
-
w =
|
|
3168
|
-
h =
|
|
3516
|
+
w = target.width,
|
|
3517
|
+
h = target.height
|
|
3169
3518
|
} = opts;
|
|
3170
|
-
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3171
|
-
|
|
3519
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3520
|
+
return didChange(applyAlphaMaskToPixelData2(target, mask, opts));
|
|
3172
3521
|
}
|
|
3173
3522
|
};
|
|
3174
3523
|
});
|
|
3175
3524
|
|
|
3176
|
-
// src/
|
|
3177
|
-
function
|
|
3178
|
-
return {
|
|
3179
|
-
blendPixel(x, y, color, alpha = 255, blendFn = overwriteFast) {
|
|
3180
|
-
let target = writer.target;
|
|
3181
|
-
let width = target.width;
|
|
3182
|
-
let height = target.height;
|
|
3183
|
-
if (x < 0 || x >= width || y < 0 || y >= height) return;
|
|
3184
|
-
writer.accumulator.storeTileBeforeState(x, y);
|
|
3185
|
-
let index = y * width + x;
|
|
3186
|
-
let bg = target.data32[index];
|
|
3187
|
-
let finalColor = color;
|
|
3188
|
-
if (alpha < 255) {
|
|
3189
|
-
let baseSrcAlpha = color >>> 24;
|
|
3190
|
-
let finalAlpha = baseSrcAlpha * alpha + 128 >> 8;
|
|
3191
|
-
finalColor = (color & 16777215 | finalAlpha << 24) >>> 0;
|
|
3192
|
-
}
|
|
3193
|
-
target.data32[index] = blendFn(finalColor, bg);
|
|
3194
|
-
}
|
|
3195
|
-
};
|
|
3196
|
-
}
|
|
3197
|
-
|
|
3198
|
-
// src/PixelData/blendPixelData.ts
|
|
3199
|
-
function blendPixelData(dst, src, opts = {}) {
|
|
3525
|
+
// src/PixelData/applyBinaryMaskToPixelData.ts
|
|
3526
|
+
function applyBinaryMaskToPixelData(dst, mask, opts = {}) {
|
|
3200
3527
|
const {
|
|
3201
3528
|
x: targetX = 0,
|
|
3202
3529
|
y: targetY = 0,
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
w: width = src.width,
|
|
3206
|
-
h: height = src.height,
|
|
3530
|
+
w: width = dst.width,
|
|
3531
|
+
h: height = dst.height,
|
|
3207
3532
|
alpha: globalAlpha = 255,
|
|
3208
|
-
|
|
3533
|
+
mx = 0,
|
|
3534
|
+
my = 0,
|
|
3535
|
+
invertMask = false
|
|
3209
3536
|
} = opts;
|
|
3210
|
-
if (globalAlpha === 0) return;
|
|
3537
|
+
if (globalAlpha === 0) return false;
|
|
3211
3538
|
let x = targetX;
|
|
3212
3539
|
let y = targetY;
|
|
3213
|
-
let sx = sourceX;
|
|
3214
|
-
let sy = sourceY;
|
|
3215
3540
|
let w = width;
|
|
3216
3541
|
let h = height;
|
|
3217
|
-
if (sx < 0) {
|
|
3218
|
-
x -= sx;
|
|
3219
|
-
w += sx;
|
|
3220
|
-
sx = 0;
|
|
3221
|
-
}
|
|
3222
|
-
if (sy < 0) {
|
|
3223
|
-
y -= sy;
|
|
3224
|
-
h += sy;
|
|
3225
|
-
sy = 0;
|
|
3226
|
-
}
|
|
3227
|
-
w = Math.min(w, src.width - sx);
|
|
3228
|
-
h = Math.min(h, src.height - sy);
|
|
3229
3542
|
if (x < 0) {
|
|
3230
|
-
sx -= x;
|
|
3231
3543
|
w += x;
|
|
3232
3544
|
x = 0;
|
|
3233
3545
|
}
|
|
3234
3546
|
if (y < 0) {
|
|
3235
|
-
sy -= y;
|
|
3236
3547
|
h += y;
|
|
3237
3548
|
y = 0;
|
|
3238
|
-
}
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
if (
|
|
3242
|
-
const
|
|
3243
|
-
|
|
3244
|
-
const
|
|
3245
|
-
const
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
const
|
|
3249
|
-
const
|
|
3250
|
-
const
|
|
3251
|
-
const
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
dIdx++;
|
|
3258
|
-
sIdx++;
|
|
3259
|
-
continue;
|
|
3260
|
-
}
|
|
3261
|
-
let finalCol = srcCol;
|
|
3262
|
-
if (!isOpaque) {
|
|
3263
|
-
const a = srcAlpha * globalAlpha + 128 >> 8;
|
|
3264
|
-
if (a === 0 && !isOverwrite) {
|
|
3265
|
-
dIdx++;
|
|
3266
|
-
sIdx++;
|
|
3267
|
-
continue;
|
|
3268
|
-
}
|
|
3269
|
-
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
3270
|
-
}
|
|
3271
|
-
dst32[dIdx] = blendFn(finalCol, dst32[dIdx]);
|
|
3272
|
-
dIdx++;
|
|
3273
|
-
sIdx++;
|
|
3274
|
-
}
|
|
3275
|
-
dIdx += dStride;
|
|
3276
|
-
sIdx += sStride;
|
|
3277
|
-
}
|
|
3278
|
-
}
|
|
3279
|
-
|
|
3280
|
-
// src/History/PixelMutator/mutatorBlendPixelData.ts
|
|
3281
|
-
var defaults12 = {
|
|
3282
|
-
blendPixelData
|
|
3283
|
-
};
|
|
3284
|
-
var mutatorBlendPixelData = ((writer, deps = defaults12) => {
|
|
3285
|
-
const {
|
|
3286
|
-
blendPixelData: blendPixelData2 = defaults12.blendPixelData
|
|
3287
|
-
} = deps;
|
|
3288
|
-
return {
|
|
3289
|
-
blendPixelData(src, opts = {}) {
|
|
3290
|
-
const {
|
|
3291
|
-
x = 0,
|
|
3292
|
-
y = 0,
|
|
3293
|
-
w = src.width,
|
|
3294
|
-
h = src.height
|
|
3295
|
-
} = opts;
|
|
3296
|
-
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3297
|
-
blendPixelData2(writer.target, src, opts);
|
|
3298
|
-
}
|
|
3299
|
-
};
|
|
3300
|
-
});
|
|
3301
|
-
|
|
3302
|
-
// src/PixelData/blendPixelDataAlphaMask.ts
|
|
3303
|
-
function blendPixelDataAlphaMask(dst, src, alphaMask, opts = {}) {
|
|
3304
|
-
const {
|
|
3305
|
-
x: targetX = 0,
|
|
3306
|
-
y: targetY = 0,
|
|
3307
|
-
sx: sourceX = 0,
|
|
3308
|
-
sy: sourceY = 0,
|
|
3309
|
-
w: width = src.width,
|
|
3310
|
-
h: height = src.height,
|
|
3311
|
-
alpha: globalAlpha = 255,
|
|
3312
|
-
blendFn = sourceOverPerfect,
|
|
3313
|
-
mx = 0,
|
|
3314
|
-
my = 0,
|
|
3315
|
-
invertMask = false
|
|
3316
|
-
} = opts;
|
|
3317
|
-
if (globalAlpha === 0) return;
|
|
3318
|
-
let x = targetX;
|
|
3319
|
-
let y = targetY;
|
|
3320
|
-
let sx = sourceX;
|
|
3321
|
-
let sy = sourceY;
|
|
3322
|
-
let w = width;
|
|
3323
|
-
let h = height;
|
|
3324
|
-
if (sx < 0) {
|
|
3325
|
-
x -= sx;
|
|
3326
|
-
w += sx;
|
|
3327
|
-
sx = 0;
|
|
3328
|
-
}
|
|
3329
|
-
if (sy < 0) {
|
|
3330
|
-
y -= sy;
|
|
3331
|
-
h += sy;
|
|
3332
|
-
sy = 0;
|
|
3333
|
-
}
|
|
3334
|
-
w = Math.min(w, src.width - sx);
|
|
3335
|
-
h = Math.min(h, src.height - sy);
|
|
3336
|
-
if (x < 0) {
|
|
3337
|
-
sx -= x;
|
|
3338
|
-
w += x;
|
|
3339
|
-
x = 0;
|
|
3340
|
-
}
|
|
3341
|
-
if (y < 0) {
|
|
3342
|
-
sy -= y;
|
|
3343
|
-
h += y;
|
|
3344
|
-
y = 0;
|
|
3345
|
-
}
|
|
3346
|
-
const actualW = Math.min(w, dst.width - x);
|
|
3347
|
-
const actualH = Math.min(h, dst.height - y);
|
|
3348
|
-
if (actualW <= 0 || actualH <= 0) return;
|
|
3349
|
-
const dw = dst.width;
|
|
3350
|
-
const sw = src.width;
|
|
3351
|
-
const mPitch = alphaMask.w;
|
|
3352
|
-
const maskData = alphaMask.data;
|
|
3353
|
-
const dx = x - targetX | 0;
|
|
3354
|
-
const dy = y - targetY | 0;
|
|
3355
|
-
const dst32 = dst.data32;
|
|
3356
|
-
const src32 = src.data32;
|
|
3357
|
-
let dIdx = y * dw + x | 0;
|
|
3358
|
-
let sIdx = sy * sw + sx | 0;
|
|
3359
|
-
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
3360
|
-
const dStride = dw - actualW | 0;
|
|
3361
|
-
const sStride = sw - actualW | 0;
|
|
3362
|
-
const mStride = mPitch - actualW | 0;
|
|
3363
|
-
const isOpaque = globalAlpha === 255;
|
|
3364
|
-
const isOverwrite = blendFn.isOverwrite || false;
|
|
3365
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
3366
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
3367
|
-
const mVal = maskData[mIdx];
|
|
3368
|
-
const effM = invertMask ? 255 - mVal : mVal;
|
|
3369
|
-
if (effM === 0) {
|
|
3370
|
-
dIdx++;
|
|
3371
|
-
sIdx++;
|
|
3372
|
-
mIdx++;
|
|
3373
|
-
continue;
|
|
3374
|
-
}
|
|
3375
|
-
const srcCol = src32[sIdx];
|
|
3376
|
-
const srcAlpha = srcCol >>> 24;
|
|
3377
|
-
if (srcAlpha === 0 && !isOverwrite) {
|
|
3378
|
-
dIdx++;
|
|
3379
|
-
sIdx++;
|
|
3380
|
-
mIdx++;
|
|
3381
|
-
continue;
|
|
3382
|
-
}
|
|
3383
|
-
let weight = globalAlpha;
|
|
3384
|
-
if (isOpaque) {
|
|
3385
|
-
weight = effM;
|
|
3386
|
-
} else if (effM !== 255) {
|
|
3387
|
-
weight = effM * globalAlpha + 128 >> 8;
|
|
3388
|
-
}
|
|
3389
|
-
if (weight === 0) {
|
|
3390
|
-
dIdx++;
|
|
3391
|
-
sIdx++;
|
|
3392
|
-
mIdx++;
|
|
3393
|
-
continue;
|
|
3394
|
-
}
|
|
3395
|
-
let finalCol = srcCol;
|
|
3396
|
-
if (weight < 255) {
|
|
3397
|
-
const a = srcAlpha * weight + 128 >> 8;
|
|
3398
|
-
if (a === 0 && !isOverwrite) {
|
|
3399
|
-
dIdx++;
|
|
3400
|
-
sIdx++;
|
|
3401
|
-
mIdx++;
|
|
3402
|
-
continue;
|
|
3403
|
-
}
|
|
3404
|
-
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
3405
|
-
}
|
|
3406
|
-
dst32[dIdx] = blendFn(finalCol, dst32[dIdx]);
|
|
3407
|
-
dIdx++;
|
|
3408
|
-
sIdx++;
|
|
3409
|
-
mIdx++;
|
|
3410
|
-
}
|
|
3411
|
-
dIdx += dStride;
|
|
3412
|
-
sIdx += sStride;
|
|
3413
|
-
mIdx += mStride;
|
|
3414
|
-
}
|
|
3415
|
-
}
|
|
3416
|
-
|
|
3417
|
-
// src/History/PixelMutator/mutatorBlendPixelDataAlphaMask.ts
|
|
3418
|
-
var defaults13 = {
|
|
3419
|
-
blendPixelDataAlphaMask
|
|
3420
|
-
};
|
|
3421
|
-
var mutatorBlendPixelDataAlphaMask = ((writer, deps = defaults13) => {
|
|
3422
|
-
const {
|
|
3423
|
-
blendPixelDataAlphaMask: blendPixelDataAlphaMask2 = defaults13.blendPixelDataAlphaMask
|
|
3424
|
-
} = deps;
|
|
3425
|
-
return {
|
|
3426
|
-
blendPixelDataAlphaMask(src, mask, opts = {}) {
|
|
3427
|
-
const x = opts.x ?? 0;
|
|
3428
|
-
const y = opts.y ?? 0;
|
|
3429
|
-
const w = opts.w ?? src.width;
|
|
3430
|
-
const h = opts.h ?? src.height;
|
|
3431
|
-
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3432
|
-
blendPixelDataAlphaMask2(writer.target, src, mask, opts);
|
|
3433
|
-
}
|
|
3434
|
-
};
|
|
3435
|
-
});
|
|
3436
|
-
|
|
3437
|
-
// src/PixelData/blendPixelDataBinaryMask.ts
|
|
3438
|
-
function blendPixelDataBinaryMask(dst, src, binaryMask, opts = {}) {
|
|
3439
|
-
const {
|
|
3440
|
-
x: targetX = 0,
|
|
3441
|
-
y: targetY = 0,
|
|
3442
|
-
sx: sourceX = 0,
|
|
3443
|
-
sy: sourceY = 0,
|
|
3444
|
-
w: width = src.width,
|
|
3445
|
-
h: height = src.height,
|
|
3446
|
-
alpha: globalAlpha = 255,
|
|
3447
|
-
blendFn = sourceOverPerfect,
|
|
3448
|
-
mx = 0,
|
|
3449
|
-
my = 0,
|
|
3450
|
-
invertMask = false
|
|
3451
|
-
} = opts;
|
|
3452
|
-
if (globalAlpha === 0) return;
|
|
3453
|
-
let x = targetX;
|
|
3454
|
-
let y = targetY;
|
|
3455
|
-
let sx = sourceX;
|
|
3456
|
-
let sy = sourceY;
|
|
3457
|
-
let w = width;
|
|
3458
|
-
let h = height;
|
|
3459
|
-
if (sx < 0) {
|
|
3460
|
-
x -= sx;
|
|
3461
|
-
w += sx;
|
|
3462
|
-
sx = 0;
|
|
3463
|
-
}
|
|
3464
|
-
if (sy < 0) {
|
|
3465
|
-
y -= sy;
|
|
3466
|
-
h += sy;
|
|
3467
|
-
sy = 0;
|
|
3468
|
-
}
|
|
3469
|
-
w = Math.min(w, src.width - sx);
|
|
3470
|
-
h = Math.min(h, src.height - sy);
|
|
3471
|
-
if (x < 0) {
|
|
3472
|
-
sx -= x;
|
|
3473
|
-
w += x;
|
|
3474
|
-
x = 0;
|
|
3475
|
-
}
|
|
3476
|
-
if (y < 0) {
|
|
3477
|
-
sy -= y;
|
|
3478
|
-
h += y;
|
|
3479
|
-
y = 0;
|
|
3480
|
-
}
|
|
3481
|
-
const actualW = Math.min(w, dst.width - x);
|
|
3482
|
-
const actualH = Math.min(h, dst.height - y);
|
|
3483
|
-
if (actualW <= 0 || actualH <= 0) return;
|
|
3484
|
-
const dx = x - targetX | 0;
|
|
3485
|
-
const dy = y - targetY | 0;
|
|
3486
|
-
const dst32 = dst.data32;
|
|
3487
|
-
const src32 = src.data32;
|
|
3488
|
-
const dw = dst.width;
|
|
3489
|
-
const sw = src.width;
|
|
3490
|
-
const mPitch = binaryMask.w;
|
|
3491
|
-
const maskData = binaryMask.data;
|
|
3492
|
-
let dIdx = y * dw + x | 0;
|
|
3493
|
-
let sIdx = sy * sw + sx | 0;
|
|
3494
|
-
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
3495
|
-
const dStride = dw - actualW | 0;
|
|
3496
|
-
const sStride = sw - actualW | 0;
|
|
3497
|
-
const mStride = mPitch - actualW | 0;
|
|
3498
|
-
const skipVal = invertMask ? 1 : 0;
|
|
3499
|
-
const isOpaque = globalAlpha === 255;
|
|
3500
|
-
const isOverwrite = blendFn.isOverwrite || false;
|
|
3501
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
3502
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
3503
|
-
if (maskData[mIdx] === skipVal) {
|
|
3504
|
-
dIdx++;
|
|
3505
|
-
sIdx++;
|
|
3506
|
-
mIdx++;
|
|
3507
|
-
continue;
|
|
3508
|
-
}
|
|
3509
|
-
const srcCol = src32[sIdx];
|
|
3510
|
-
const srcAlpha = srcCol >>> 24;
|
|
3511
|
-
if (srcAlpha === 0 && !isOverwrite) {
|
|
3512
|
-
dIdx++;
|
|
3513
|
-
sIdx++;
|
|
3514
|
-
mIdx++;
|
|
3515
|
-
continue;
|
|
3516
|
-
}
|
|
3517
|
-
let finalCol = srcCol;
|
|
3518
|
-
if (!isOpaque) {
|
|
3519
|
-
const a = srcAlpha * globalAlpha + 128 >> 8;
|
|
3520
|
-
if (a === 0 && !isOverwrite) {
|
|
3521
|
-
dIdx++;
|
|
3522
|
-
sIdx++;
|
|
3523
|
-
mIdx++;
|
|
3524
|
-
continue;
|
|
3525
|
-
}
|
|
3526
|
-
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
3527
|
-
}
|
|
3528
|
-
dst32[dIdx] = blendFn(finalCol, dst32[dIdx]);
|
|
3529
|
-
dIdx++;
|
|
3530
|
-
sIdx++;
|
|
3531
|
-
mIdx++;
|
|
3532
|
-
}
|
|
3533
|
-
dIdx += dStride;
|
|
3534
|
-
sIdx += sStride;
|
|
3535
|
-
mIdx += mStride;
|
|
3536
|
-
}
|
|
3537
|
-
}
|
|
3538
|
-
|
|
3539
|
-
// src/History/PixelMutator/mutatorBlendPixelDataBinaryMask.ts
|
|
3540
|
-
var defaults14 = {
|
|
3541
|
-
blendPixelDataBinaryMask
|
|
3542
|
-
};
|
|
3543
|
-
var mutatorBlendPixelDataBinaryMask = ((writer, deps = defaults14) => {
|
|
3544
|
-
const {
|
|
3545
|
-
blendPixelDataBinaryMask: blendPixelDataBinaryMask2 = defaults14.blendPixelDataBinaryMask
|
|
3546
|
-
} = deps;
|
|
3547
|
-
return {
|
|
3548
|
-
blendPixelDataBinaryMask(src, mask, opts = {}) {
|
|
3549
|
-
const x = opts.x ?? 0;
|
|
3550
|
-
const y = opts.y ?? 0;
|
|
3551
|
-
const w = opts.w ?? src.width;
|
|
3552
|
-
const h = opts.h ?? src.height;
|
|
3553
|
-
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3554
|
-
blendPixelDataBinaryMask2(writer.target, src, mask, opts);
|
|
3555
|
-
}
|
|
3556
|
-
};
|
|
3557
|
-
});
|
|
3558
|
-
|
|
3559
|
-
// src/PixelData/fillPixelData.ts
|
|
3560
|
-
var SCRATCH_RECT = makeClippedRect();
|
|
3561
|
-
function fillPixelData(dst, color, _x, _y, _w, _h) {
|
|
3562
|
-
let x;
|
|
3563
|
-
let y;
|
|
3564
|
-
let w;
|
|
3565
|
-
let h;
|
|
3566
|
-
if (typeof _x === "object") {
|
|
3567
|
-
x = _x.x ?? 0;
|
|
3568
|
-
y = _x.y ?? 0;
|
|
3569
|
-
w = _x.w ?? dst.width;
|
|
3570
|
-
h = _x.h ?? dst.height;
|
|
3571
|
-
} else if (typeof _x === "number") {
|
|
3572
|
-
x = _x;
|
|
3573
|
-
y = _y;
|
|
3574
|
-
w = _w;
|
|
3575
|
-
h = _h;
|
|
3576
|
-
} else {
|
|
3577
|
-
x = 0;
|
|
3578
|
-
y = 0;
|
|
3579
|
-
w = dst.width;
|
|
3580
|
-
h = dst.height;
|
|
3581
|
-
}
|
|
3582
|
-
const clip = resolveRectClipping(x, y, w, h, dst.width, dst.height, SCRATCH_RECT);
|
|
3583
|
-
if (!clip.inBounds) return;
|
|
3584
|
-
const {
|
|
3585
|
-
x: finalX,
|
|
3586
|
-
y: finalY,
|
|
3587
|
-
w: actualW,
|
|
3588
|
-
h: actualH
|
|
3589
|
-
} = clip;
|
|
3590
|
-
const dst32 = dst.data32;
|
|
3591
|
-
const dw = dst.width;
|
|
3592
|
-
if (actualW === dw && actualH === dst.height && finalX === 0 && finalY === 0) {
|
|
3593
|
-
dst32.fill(color);
|
|
3594
|
-
return;
|
|
3595
|
-
}
|
|
3596
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
3597
|
-
const start = (finalY + iy) * dw + finalX;
|
|
3598
|
-
const end = start + actualW;
|
|
3599
|
-
dst32.fill(color, start, end);
|
|
3600
|
-
}
|
|
3601
|
-
}
|
|
3602
|
-
|
|
3603
|
-
// src/History/PixelMutator/mutatorClear.ts
|
|
3604
|
-
var defaults15 = {
|
|
3605
|
-
fillPixelData
|
|
3606
|
-
};
|
|
3607
|
-
var mutatorClear = ((writer, deps = defaults15) => {
|
|
3608
|
-
const {
|
|
3609
|
-
fillPixelData: fillPixelData2 = defaults15.fillPixelData
|
|
3610
|
-
} = deps;
|
|
3611
|
-
return {
|
|
3612
|
-
clear(rect = {}) {
|
|
3613
|
-
const x = rect.x ?? 0;
|
|
3614
|
-
const y = rect.y ?? 0;
|
|
3615
|
-
const w = rect.w ?? writer.target.width;
|
|
3616
|
-
const h = rect.h ?? writer.target.height;
|
|
3617
|
-
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3618
|
-
fillPixelData2(writer.target, 0, x, y, w, h);
|
|
3619
|
-
}
|
|
3620
|
-
};
|
|
3621
|
-
});
|
|
3622
|
-
|
|
3623
|
-
// src/History/PixelMutator/mutatorFill.ts
|
|
3624
|
-
var defaults16 = {
|
|
3625
|
-
fillPixelData
|
|
3626
|
-
};
|
|
3627
|
-
var mutatorFill = ((writer, deps = defaults16) => {
|
|
3628
|
-
const {
|
|
3629
|
-
fillPixelData: fillPixelData2 = defaults16.fillPixelData
|
|
3630
|
-
} = deps;
|
|
3631
|
-
return {
|
|
3632
|
-
fill(color, rect = {}) {
|
|
3633
|
-
const {
|
|
3634
|
-
x = 0,
|
|
3635
|
-
y = 0,
|
|
3636
|
-
w = writer.target.width,
|
|
3637
|
-
h = writer.target.height
|
|
3638
|
-
} = rect;
|
|
3639
|
-
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3640
|
-
fillPixelData2(writer.target, color, x, y, w, h);
|
|
3641
|
-
}
|
|
3642
|
-
};
|
|
3643
|
-
});
|
|
3644
|
-
|
|
3645
|
-
// src/PixelData/fillPixelDataBinaryMask.ts
|
|
3646
|
-
var SCRATCH_RECT2 = makeClippedRect();
|
|
3647
|
-
function fillPixelDataBinaryMask(dst, color, mask, alpha = 255, x = 0, y = 0) {
|
|
3648
|
-
if (alpha === 0) return;
|
|
3649
|
-
const maskW = mask.w;
|
|
3650
|
-
const maskH = mask.h;
|
|
3651
|
-
const clip = resolveRectClipping(x, y, maskW, maskH, dst.width, dst.height, SCRATCH_RECT2);
|
|
3652
|
-
if (!clip.inBounds) return;
|
|
3653
|
-
const {
|
|
3654
|
-
x: finalX,
|
|
3655
|
-
y: finalY,
|
|
3656
|
-
w: actualW,
|
|
3657
|
-
h: actualH
|
|
3658
|
-
} = clip;
|
|
3659
|
-
const maskData = mask.data;
|
|
3660
|
-
const dst32 = dst.data32;
|
|
3661
|
-
const dw = dst.width;
|
|
3662
|
-
let finalCol = color;
|
|
3663
|
-
if (alpha < 255) {
|
|
3664
|
-
const baseSrcAlpha = color >>> 24;
|
|
3665
|
-
const colorRGB = color & 16777215;
|
|
3666
|
-
const a = baseSrcAlpha * alpha + 128 >> 8;
|
|
3667
|
-
finalCol = (colorRGB | a << 24) >>> 0;
|
|
3668
|
-
}
|
|
3669
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
3670
|
-
const currentY = finalY + iy;
|
|
3671
|
-
const maskY = currentY - y;
|
|
3672
|
-
const maskOffset = maskY * maskW;
|
|
3673
|
-
const dstRowOffset = currentY * dw;
|
|
3674
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
3675
|
-
const currentX = finalX + ix;
|
|
3676
|
-
const maskX = currentX - x;
|
|
3677
|
-
const maskIndex = maskOffset + maskX;
|
|
3678
|
-
if (maskData[maskIndex]) {
|
|
3679
|
-
dst32[dstRowOffset + currentX] = finalCol;
|
|
3680
|
-
}
|
|
3681
|
-
}
|
|
3682
|
-
}
|
|
3683
|
-
}
|
|
3684
|
-
|
|
3685
|
-
// src/History/PixelMutator/mutatorFillBinaryMask.ts
|
|
3686
|
-
var defaults17 = {
|
|
3687
|
-
fillPixelDataBinaryMask
|
|
3688
|
-
};
|
|
3689
|
-
var mutatorFillBinaryMask = ((writer, deps = defaults17) => {
|
|
3690
|
-
const {
|
|
3691
|
-
fillPixelDataBinaryMask: fillPixelDataBinaryMask2 = defaults17.fillPixelDataBinaryMask
|
|
3692
|
-
} = deps;
|
|
3693
|
-
return {
|
|
3694
|
-
fillBinaryMask(color, mask, alpha = 255, x = 0, y = 0) {
|
|
3695
|
-
writer.accumulator.storeRegionBeforeState(x, y, mask.w, mask.h);
|
|
3696
|
-
fillPixelDataBinaryMask2(writer.target, color, mask, alpha, x, y);
|
|
3697
|
-
}
|
|
3698
|
-
};
|
|
3699
|
-
});
|
|
3700
|
-
|
|
3701
|
-
// src/PixelData/invertPixelData.ts
|
|
3702
|
-
var SCRATCH_RECT3 = makeClippedRect();
|
|
3703
|
-
function invertPixelData(pixelData, opts = {}) {
|
|
3704
|
-
const dst = pixelData;
|
|
3705
|
-
const {
|
|
3706
|
-
x: targetX = 0,
|
|
3707
|
-
y: targetY = 0,
|
|
3708
|
-
w: width = pixelData.width,
|
|
3709
|
-
h: height = pixelData.height,
|
|
3710
|
-
mask,
|
|
3711
|
-
mx = 0,
|
|
3712
|
-
my = 0,
|
|
3713
|
-
invertMask = false
|
|
3714
|
-
} = opts;
|
|
3715
|
-
const clip = resolveRectClipping(targetX, targetY, width, height, dst.width, dst.height, SCRATCH_RECT3);
|
|
3716
|
-
if (!clip.inBounds) return;
|
|
3717
|
-
const {
|
|
3718
|
-
x,
|
|
3719
|
-
y,
|
|
3720
|
-
w: actualW,
|
|
3721
|
-
h: actualH
|
|
3722
|
-
} = clip;
|
|
3549
|
+
}
|
|
3550
|
+
w = Math.min(w, dst.width - x);
|
|
3551
|
+
h = Math.min(h, dst.height - y);
|
|
3552
|
+
if (w <= 0 || h <= 0) return false;
|
|
3553
|
+
const mPitch = mask.w;
|
|
3554
|
+
if (mPitch <= 0) return false;
|
|
3555
|
+
const startX = mx + (x - targetX);
|
|
3556
|
+
const startY = my + (y - targetY);
|
|
3557
|
+
const sX0 = Math.max(0, startX);
|
|
3558
|
+
const sY0 = Math.max(0, startY);
|
|
3559
|
+
const sX1 = Math.min(mPitch, startX + w);
|
|
3560
|
+
const sY1 = Math.min(mask.h, startY + h);
|
|
3561
|
+
const finalW = sX1 - sX0;
|
|
3562
|
+
const finalH = sY1 - sY0;
|
|
3563
|
+
if (finalW <= 0 || finalH <= 0) {
|
|
3564
|
+
return false;
|
|
3565
|
+
}
|
|
3566
|
+
const xShift = sX0 - startX;
|
|
3567
|
+
const yShift = sY0 - startY;
|
|
3723
3568
|
const dst32 = dst.data32;
|
|
3724
3569
|
const dw = dst.width;
|
|
3725
|
-
const
|
|
3726
|
-
const
|
|
3727
|
-
const
|
|
3728
|
-
let dIdx = y * dw + x;
|
|
3729
|
-
let mIdx =
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
const
|
|
3737
|
-
const
|
|
3738
|
-
if (
|
|
3739
|
-
dst32[dIdx] =
|
|
3570
|
+
const dStride = dw - finalW;
|
|
3571
|
+
const mStride = mPitch - finalW;
|
|
3572
|
+
const maskData = mask.data;
|
|
3573
|
+
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
3574
|
+
let mIdx = sY0 * mPitch + sX0;
|
|
3575
|
+
let didChange = false;
|
|
3576
|
+
for (let iy = 0; iy < finalH; iy++) {
|
|
3577
|
+
for (let ix = 0; ix < finalW; ix++) {
|
|
3578
|
+
const mVal = maskData[mIdx];
|
|
3579
|
+
const isMaskedOut = invertMask ? mVal !== 0 : mVal === 0;
|
|
3580
|
+
if (isMaskedOut) {
|
|
3581
|
+
const current = dst32[dIdx];
|
|
3582
|
+
const next = (current & 16777215) >>> 0;
|
|
3583
|
+
if (current !== next) {
|
|
3584
|
+
dst32[dIdx] = next;
|
|
3585
|
+
didChange = true;
|
|
3586
|
+
}
|
|
3587
|
+
} else if (globalAlpha !== 255) {
|
|
3588
|
+
const d = dst32[dIdx];
|
|
3589
|
+
const da = d >>> 24;
|
|
3590
|
+
if (da !== 0) {
|
|
3591
|
+
const finalAlpha = da === 255 ? globalAlpha : da * globalAlpha + 128 >> 8;
|
|
3592
|
+
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
3593
|
+
if (d !== next) {
|
|
3594
|
+
dst32[dIdx] = next;
|
|
3595
|
+
didChange = true;
|
|
3596
|
+
}
|
|
3740
3597
|
}
|
|
3741
|
-
dIdx++;
|
|
3742
|
-
mIdx++;
|
|
3743
|
-
}
|
|
3744
|
-
dIdx += dStride;
|
|
3745
|
-
mIdx += mStride;
|
|
3746
|
-
}
|
|
3747
|
-
} else {
|
|
3748
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
3749
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
3750
|
-
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
3751
|
-
dIdx++;
|
|
3752
3598
|
}
|
|
3753
|
-
dIdx
|
|
3599
|
+
dIdx++;
|
|
3600
|
+
mIdx++;
|
|
3754
3601
|
}
|
|
3602
|
+
dIdx += dStride;
|
|
3603
|
+
mIdx += mStride;
|
|
3755
3604
|
}
|
|
3605
|
+
return didChange;
|
|
3756
3606
|
}
|
|
3757
3607
|
|
|
3758
|
-
// src/History/PixelMutator/
|
|
3759
|
-
var
|
|
3760
|
-
|
|
3608
|
+
// src/History/PixelMutator/mutatorApplyBinaryMask.ts
|
|
3609
|
+
var defaults12 = {
|
|
3610
|
+
applyBinaryMaskToPixelData
|
|
3761
3611
|
};
|
|
3762
|
-
var
|
|
3612
|
+
var mutatorApplyBinaryMask = ((writer, deps = defaults12) => {
|
|
3763
3613
|
const {
|
|
3764
|
-
|
|
3614
|
+
applyBinaryMaskToPixelData: applyBinaryMaskToPixelData2 = defaults12.applyBinaryMaskToPixelData
|
|
3765
3615
|
} = deps;
|
|
3766
3616
|
return {
|
|
3767
|
-
|
|
3617
|
+
applyBinaryMask(mask, opts = {}) {
|
|
3618
|
+
let target = writer.config.target;
|
|
3768
3619
|
const {
|
|
3769
3620
|
x = 0,
|
|
3770
3621
|
y = 0,
|
|
3771
|
-
w =
|
|
3772
|
-
h =
|
|
3622
|
+
w = target.width,
|
|
3623
|
+
h = target.height
|
|
3773
3624
|
} = opts;
|
|
3774
|
-
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3775
|
-
|
|
3625
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3626
|
+
return didChange(applyBinaryMaskToPixelData2(target, mask, opts));
|
|
3776
3627
|
}
|
|
3777
3628
|
};
|
|
3778
3629
|
});
|
|
3779
3630
|
|
|
3780
|
-
// src/History/PixelMutator.ts
|
|
3781
|
-
function makeFullPixelMutator(writer) {
|
|
3782
|
-
return {
|
|
3783
|
-
// @sort
|
|
3784
|
-
...mutatorApplyAlphaMask(writer),
|
|
3785
|
-
...mutatorApplyBinaryMask(writer),
|
|
3786
|
-
...mutatorApplyCircleBrush(writer),
|
|
3787
|
-
...mutatorApplyCircleBrushStroke(writer),
|
|
3788
|
-
...mutatorApplyCirclePencil(writer),
|
|
3789
|
-
...mutatorApplyCirclePencilStroke(writer),
|
|
3790
|
-
...mutatorApplyRectBrush(writer),
|
|
3791
|
-
...mutatorApplyRectBrushStroke(writer),
|
|
3792
|
-
...mutatorApplyRectPencil(writer),
|
|
3793
|
-
...mutatorApplyRectPencilStroke(writer),
|
|
3794
|
-
...mutatorBlendColor(writer),
|
|
3795
|
-
...mutatorBlendPixel(writer),
|
|
3796
|
-
...mutatorBlendPixelData(writer),
|
|
3797
|
-
...mutatorBlendPixelDataAlphaMask(writer),
|
|
3798
|
-
...mutatorBlendPixelDataBinaryMask(writer),
|
|
3799
|
-
...mutatorClear(writer),
|
|
3800
|
-
...mutatorFill(writer),
|
|
3801
|
-
...mutatorFillBinaryMask(writer),
|
|
3802
|
-
...mutatorInvert(writer)
|
|
3803
|
-
};
|
|
3804
|
-
}
|
|
3805
|
-
|
|
3806
|
-
// src/History/PixelWriter.ts
|
|
3807
|
-
var PixelWriter = class {
|
|
3808
|
-
target;
|
|
3809
|
-
historyManager;
|
|
3810
|
-
accumulator;
|
|
3811
|
-
config;
|
|
3812
|
-
mutator;
|
|
3813
|
-
constructor(target, mutatorFactory, {
|
|
3814
|
-
tileSize = 256,
|
|
3815
|
-
maxHistorySteps = 50,
|
|
3816
|
-
historyManager = new HistoryManager(maxHistorySteps)
|
|
3817
|
-
} = {}) {
|
|
3818
|
-
this.target = target;
|
|
3819
|
-
this.config = new PixelEngineConfig(tileSize);
|
|
3820
|
-
this.historyManager = historyManager;
|
|
3821
|
-
this.accumulator = new PixelAccumulator(target, this.config);
|
|
3822
|
-
this.mutator = mutatorFactory(this);
|
|
3823
|
-
}
|
|
3824
|
-
withHistory(cb) {
|
|
3825
|
-
cb(this.mutator);
|
|
3826
|
-
this.captureHistory();
|
|
3827
|
-
}
|
|
3828
|
-
captureHistory() {
|
|
3829
|
-
const beforeTiles = this.accumulator.beforeTiles;
|
|
3830
|
-
if (beforeTiles.length === 0) return;
|
|
3831
|
-
const afterTiles = this.accumulator.extractAfterTiles();
|
|
3832
|
-
const patch = {
|
|
3833
|
-
beforeTiles,
|
|
3834
|
-
afterTiles
|
|
3835
|
-
};
|
|
3836
|
-
const target = this.target;
|
|
3837
|
-
const tileSize = this.config.tileSize;
|
|
3838
|
-
const accumulator = this.accumulator;
|
|
3839
|
-
const action = {
|
|
3840
|
-
undo: () => applyPatchTiles(target, patch.beforeTiles, tileSize),
|
|
3841
|
-
redo: () => applyPatchTiles(target, patch.afterTiles, tileSize),
|
|
3842
|
-
dispose: () => accumulator.recyclePatch(patch)
|
|
3843
|
-
};
|
|
3844
|
-
this.historyManager.commit(action);
|
|
3845
|
-
this.accumulator.reset();
|
|
3846
|
-
}
|
|
3847
|
-
};
|
|
3848
|
-
|
|
3849
3631
|
// src/ImageData/copyImageData.ts
|
|
3850
3632
|
function copyImageData({
|
|
3851
3633
|
data,
|
|
@@ -3967,44 +3749,14 @@ function resampleImageData(source, factor) {
|
|
|
3967
3749
|
return new ImageData(uint8ClampedArray, width, height);
|
|
3968
3750
|
}
|
|
3969
3751
|
|
|
3970
|
-
// src/ImageData/resizeImageData.ts
|
|
3971
|
-
function resizeImageData(target, newWidth, newHeight, offsetX = 0, offsetY = 0) {
|
|
3972
|
-
const result = new ImageData(newWidth, newHeight);
|
|
3973
|
-
const {
|
|
3974
|
-
width: oldW,
|
|
3975
|
-
height: oldH,
|
|
3976
|
-
data: oldData
|
|
3977
|
-
} = target;
|
|
3978
|
-
const newData = result.data;
|
|
3979
|
-
const x0 = Math.max(0, offsetX);
|
|
3980
|
-
const y0 = Math.max(0, offsetY);
|
|
3981
|
-
const x1 = Math.min(newWidth, offsetX + oldW);
|
|
3982
|
-
const y1 = Math.min(newHeight, offsetY + oldH);
|
|
3983
|
-
if (x1 <= x0 || y1 <= y0) {
|
|
3984
|
-
return result;
|
|
3985
|
-
}
|
|
3986
|
-
const rowCount = y1 - y0;
|
|
3987
|
-
const rowLen = (x1 - x0) * 4;
|
|
3988
|
-
for (let row = 0; row < rowCount; row++) {
|
|
3989
|
-
const dstY = y0 + row;
|
|
3990
|
-
const srcY = dstY - offsetY;
|
|
3991
|
-
const srcX = x0 - offsetX;
|
|
3992
|
-
const dstStart = (dstY * newWidth + x0) * 4;
|
|
3993
|
-
const srcStart = (srcY * oldW + srcX) * 4;
|
|
3994
|
-
newData.set(oldData.subarray(srcStart, srcStart + rowLen), dstStart);
|
|
3995
|
-
}
|
|
3996
|
-
return result;
|
|
3997
|
-
}
|
|
3998
|
-
|
|
3999
3752
|
// src/ImageData/ReusableImageData.ts
|
|
4000
3753
|
function makeReusableImageData() {
|
|
4001
3754
|
let imageData = null;
|
|
4002
3755
|
return function getReusableImageData(width, height) {
|
|
4003
|
-
|
|
4004
|
-
const widthMatches = hasInstance && imageData.width === width;
|
|
4005
|
-
const heightMatches = hasInstance && imageData.height === height;
|
|
4006
|
-
if (!widthMatches || !heightMatches) {
|
|
3756
|
+
if (imageData === null || imageData.width !== width || imageData.height !== height) {
|
|
4007
3757
|
imageData = new ImageData(width, height);
|
|
3758
|
+
} else {
|
|
3759
|
+
imageData.data.fill(0);
|
|
4008
3760
|
}
|
|
4009
3761
|
return imageData;
|
|
4010
3762
|
};
|
|
@@ -4411,62 +4163,6 @@ function makeBinaryMask(w, h, data) {
|
|
|
4411
4163
|
};
|
|
4412
4164
|
}
|
|
4413
4165
|
|
|
4414
|
-
// src/Mask/CircleBrushAlphaMask.ts
|
|
4415
|
-
function makeCircleBrushAlphaMask(size, fallOff = () => 1) {
|
|
4416
|
-
const area = size * size;
|
|
4417
|
-
const data = new Uint8Array(area);
|
|
4418
|
-
const radius = size / 2;
|
|
4419
|
-
const invR = 1 / radius;
|
|
4420
|
-
const minOffset = -Math.ceil(radius - 0.5);
|
|
4421
|
-
for (let y = 0; y < size; y++) {
|
|
4422
|
-
for (let x = 0; x < size; x++) {
|
|
4423
|
-
const dx = x - radius + 0.5;
|
|
4424
|
-
const dy = y - radius + 0.5;
|
|
4425
|
-
const distSqr = dx * dx + dy * dy;
|
|
4426
|
-
if (distSqr <= radius * radius) {
|
|
4427
|
-
const dist = Math.sqrt(distSqr);
|
|
4428
|
-
data[y * size + x] = fallOff(1 - dist * invR) * 255 | 0;
|
|
4429
|
-
}
|
|
4430
|
-
}
|
|
4431
|
-
}
|
|
4432
|
-
return {
|
|
4433
|
-
type: 0 /* ALPHA */,
|
|
4434
|
-
data,
|
|
4435
|
-
w: size,
|
|
4436
|
-
h: size,
|
|
4437
|
-
radius,
|
|
4438
|
-
size,
|
|
4439
|
-
minOffset
|
|
4440
|
-
};
|
|
4441
|
-
}
|
|
4442
|
-
|
|
4443
|
-
// src/Mask/CircleBrushBinaryMask.ts
|
|
4444
|
-
function makeCircleBrushBinaryMask(size) {
|
|
4445
|
-
const area = size * size;
|
|
4446
|
-
const data = new Uint8Array(area);
|
|
4447
|
-
const radius = size / 2;
|
|
4448
|
-
const minOffset = -Math.ceil(radius - 0.5);
|
|
4449
|
-
for (let y = 0; y < size; y++) {
|
|
4450
|
-
for (let x = 0; x < size; x++) {
|
|
4451
|
-
const dx = x - radius + 0.5;
|
|
4452
|
-
const dy = y - radius + 0.5;
|
|
4453
|
-
const distSqr = dx * dx + dy * dy;
|
|
4454
|
-
if (distSqr <= radius * radius) {
|
|
4455
|
-
data[y * size + x] = 1;
|
|
4456
|
-
}
|
|
4457
|
-
}
|
|
4458
|
-
}
|
|
4459
|
-
return {
|
|
4460
|
-
type: 1 /* BINARY */,
|
|
4461
|
-
data,
|
|
4462
|
-
w: size,
|
|
4463
|
-
h: size,
|
|
4464
|
-
radius,
|
|
4465
|
-
size,
|
|
4466
|
-
minOffset
|
|
4467
|
-
};
|
|
4468
|
-
}
|
|
4469
|
-
|
|
4470
4166
|
// src/Mask/applyBinaryMaskToAlphaMask.ts
|
|
4471
4167
|
function applyBinaryMaskToAlphaMask(alphaMaskDst, binaryMaskSrc, opts = {}) {
|
|
4472
4168
|
const {
|
|
@@ -4737,57 +4433,6 @@ function setMaskData(mask, width, height, data) {
|
|
|
4737
4433
|
mask.data = data;
|
|
4738
4434
|
}
|
|
4739
4435
|
|
|
4740
|
-
// src/MaskRect/subtractBinaryMaskRects.ts
|
|
4741
|
-
function subtractBinaryMaskRects(current, subtracting) {
|
|
4742
|
-
let result = [...current];
|
|
4743
|
-
for (const sub of subtracting) {
|
|
4744
|
-
const next = [];
|
|
4745
|
-
for (const r of result) {
|
|
4746
|
-
const ix = Math.max(r.x, sub.x);
|
|
4747
|
-
const iy = Math.max(r.y, sub.y);
|
|
4748
|
-
const ix2 = Math.min(r.x + r.w, sub.x + sub.w);
|
|
4749
|
-
const iy2 = Math.min(r.y + r.h, sub.y + sub.h);
|
|
4750
|
-
if (ix >= ix2 || iy >= iy2) {
|
|
4751
|
-
next.push(r);
|
|
4752
|
-
continue;
|
|
4753
|
-
}
|
|
4754
|
-
if (r.y < iy) pushPiece(next, r, r.x, r.y, r.w, iy - r.y);
|
|
4755
|
-
if (iy2 < r.y + r.h) pushPiece(next, r, r.x, iy2, r.w, r.y + r.h - iy2);
|
|
4756
|
-
if (r.x < ix) pushPiece(next, r, r.x, iy, ix - r.x, iy2 - iy);
|
|
4757
|
-
if (ix2 < r.x + r.w) pushPiece(next, r, ix2, iy, r.x + r.w - ix2, iy2 - iy);
|
|
4758
|
-
}
|
|
4759
|
-
result = next;
|
|
4760
|
-
}
|
|
4761
|
-
return result;
|
|
4762
|
-
}
|
|
4763
|
-
function pushPiece(dest, r, x, y, w, h) {
|
|
4764
|
-
if (r.data === null || r.data === void 0) {
|
|
4765
|
-
dest.push({
|
|
4766
|
-
x,
|
|
4767
|
-
y,
|
|
4768
|
-
w,
|
|
4769
|
-
h,
|
|
4770
|
-
data: null,
|
|
4771
|
-
type: null
|
|
4772
|
-
});
|
|
4773
|
-
return;
|
|
4774
|
-
}
|
|
4775
|
-
const lx = x - r.x;
|
|
4776
|
-
const ly = y - r.y;
|
|
4777
|
-
const data = new Uint8Array(w * h);
|
|
4778
|
-
for (let row = 0; row < h; row++) {
|
|
4779
|
-
data.set(r.data.subarray((ly + row) * r.w + lx, (ly + row) * r.w + lx + w), row * w);
|
|
4780
|
-
}
|
|
4781
|
-
dest.push({
|
|
4782
|
-
x,
|
|
4783
|
-
y,
|
|
4784
|
-
w,
|
|
4785
|
-
h,
|
|
4786
|
-
data,
|
|
4787
|
-
type: 1 /* BINARY */
|
|
4788
|
-
});
|
|
4789
|
-
}
|
|
4790
|
-
|
|
4791
4436
|
// src/Rect/getRectsBounds.ts
|
|
4792
4437
|
function getRectsBounds(rects) {
|
|
4793
4438
|
if (rects.length === 1) return {
|
|
@@ -4895,13 +4540,64 @@ function mergeBinaryMaskRects(current, adding) {
|
|
|
4895
4540
|
}
|
|
4896
4541
|
if (!merged) next.push(r);
|
|
4897
4542
|
}
|
|
4898
|
-
rects.splice(0, rects.length, ...next);
|
|
4543
|
+
rects.splice(0, rects.length, ...next);
|
|
4544
|
+
}
|
|
4545
|
+
return rects;
|
|
4546
|
+
}
|
|
4547
|
+
|
|
4548
|
+
// src/MaskRect/subtractBinaryMaskRects.ts
|
|
4549
|
+
function subtractBinaryMaskRects(current, subtracting) {
|
|
4550
|
+
let result = [...current];
|
|
4551
|
+
for (const sub of subtracting) {
|
|
4552
|
+
const next = [];
|
|
4553
|
+
for (const r of result) {
|
|
4554
|
+
const ix = Math.max(r.x, sub.x);
|
|
4555
|
+
const iy = Math.max(r.y, sub.y);
|
|
4556
|
+
const ix2 = Math.min(r.x + r.w, sub.x + sub.w);
|
|
4557
|
+
const iy2 = Math.min(r.y + r.h, sub.y + sub.h);
|
|
4558
|
+
if (ix >= ix2 || iy >= iy2) {
|
|
4559
|
+
next.push(r);
|
|
4560
|
+
continue;
|
|
4561
|
+
}
|
|
4562
|
+
if (r.y < iy) pushPiece(next, r, r.x, r.y, r.w, iy - r.y);
|
|
4563
|
+
if (iy2 < r.y + r.h) pushPiece(next, r, r.x, iy2, r.w, r.y + r.h - iy2);
|
|
4564
|
+
if (r.x < ix) pushPiece(next, r, r.x, iy, ix - r.x, iy2 - iy);
|
|
4565
|
+
if (ix2 < r.x + r.w) pushPiece(next, r, ix2, iy, r.x + r.w - ix2, iy2 - iy);
|
|
4566
|
+
}
|
|
4567
|
+
result = next;
|
|
4899
4568
|
}
|
|
4900
|
-
return
|
|
4569
|
+
return result;
|
|
4570
|
+
}
|
|
4571
|
+
function pushPiece(dest, r, x, y, w, h) {
|
|
4572
|
+
if (r.data === null || r.data === void 0) {
|
|
4573
|
+
dest.push({
|
|
4574
|
+
x,
|
|
4575
|
+
y,
|
|
4576
|
+
w,
|
|
4577
|
+
h,
|
|
4578
|
+
data: null,
|
|
4579
|
+
type: null
|
|
4580
|
+
});
|
|
4581
|
+
return;
|
|
4582
|
+
}
|
|
4583
|
+
const lx = x - r.x;
|
|
4584
|
+
const ly = y - r.y;
|
|
4585
|
+
const data = new Uint8Array(w * h);
|
|
4586
|
+
for (let row = 0; row < h; row++) {
|
|
4587
|
+
data.set(r.data.subarray((ly + row) * r.w + lx, (ly + row) * r.w + lx + w), row * w);
|
|
4588
|
+
}
|
|
4589
|
+
dest.push({
|
|
4590
|
+
x,
|
|
4591
|
+
y,
|
|
4592
|
+
w,
|
|
4593
|
+
h,
|
|
4594
|
+
data,
|
|
4595
|
+
type: 1 /* BINARY */
|
|
4596
|
+
});
|
|
4901
4597
|
}
|
|
4902
4598
|
|
|
4903
4599
|
// src/PixelData/PixelData.ts
|
|
4904
|
-
var PixelData = class
|
|
4600
|
+
var PixelData = class {
|
|
4905
4601
|
data32;
|
|
4906
4602
|
imageData;
|
|
4907
4603
|
width;
|
|
@@ -4919,30 +4615,191 @@ var PixelData = class _PixelData {
|
|
|
4919
4615
|
this.width = imageData.width;
|
|
4920
4616
|
this.height = imageData.height;
|
|
4921
4617
|
}
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
|
|
4618
|
+
};
|
|
4619
|
+
|
|
4620
|
+
// src/PixelData/blendColorPixelDataAlphaMask.ts
|
|
4621
|
+
function blendColorPixelDataAlphaMask(dst, color, mask, opts = {}) {
|
|
4622
|
+
const targetX = opts.x ?? 0;
|
|
4623
|
+
const targetY = opts.y ?? 0;
|
|
4624
|
+
const w = opts.w ?? mask.w;
|
|
4625
|
+
const h = opts.h ?? mask.h;
|
|
4626
|
+
const globalAlpha = opts.alpha ?? 255;
|
|
4627
|
+
const blendFn = opts.blendFn ?? sourceOverPerfect;
|
|
4628
|
+
const mx = opts.mx ?? 0;
|
|
4629
|
+
const my = opts.my ?? 0;
|
|
4630
|
+
const invertMask = opts.invertMask ?? false;
|
|
4631
|
+
if (globalAlpha === 0) return false;
|
|
4632
|
+
const baseSrcAlpha = color >>> 24;
|
|
4633
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
4634
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
4635
|
+
let x = targetX;
|
|
4636
|
+
let y = targetY;
|
|
4637
|
+
let actualW = w;
|
|
4638
|
+
let actualH = h;
|
|
4639
|
+
if (x < 0) {
|
|
4640
|
+
actualW += x;
|
|
4641
|
+
x = 0;
|
|
4642
|
+
}
|
|
4643
|
+
if (y < 0) {
|
|
4644
|
+
actualH += y;
|
|
4645
|
+
y = 0;
|
|
4646
|
+
}
|
|
4647
|
+
actualW = Math.min(actualW, dst.width - x);
|
|
4648
|
+
actualH = Math.min(actualH, dst.height - y);
|
|
4649
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
4650
|
+
const dx = x - targetX | 0;
|
|
4651
|
+
const dy = y - targetY | 0;
|
|
4652
|
+
const dst32 = dst.data32;
|
|
4653
|
+
const dw = dst.width;
|
|
4654
|
+
const mPitch = mask.w;
|
|
4655
|
+
const maskData = mask.data;
|
|
4656
|
+
let dIdx = y * dw + x | 0;
|
|
4657
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
4658
|
+
const dStride = dw - actualW | 0;
|
|
4659
|
+
const mStride = mPitch - actualW | 0;
|
|
4660
|
+
const isOpaque = globalAlpha === 255;
|
|
4661
|
+
const colorRGB = color & 16777215;
|
|
4662
|
+
let didChange = false;
|
|
4663
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
4664
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
4665
|
+
const mVal = maskData[mIdx];
|
|
4666
|
+
const effM = invertMask ? 255 - mVal : mVal;
|
|
4667
|
+
if (effM === 0) {
|
|
4668
|
+
dIdx++;
|
|
4669
|
+
mIdx++;
|
|
4670
|
+
continue;
|
|
4671
|
+
}
|
|
4672
|
+
let weight = globalAlpha;
|
|
4673
|
+
if (isOpaque) {
|
|
4674
|
+
weight = effM;
|
|
4675
|
+
} else if (effM !== 255) {
|
|
4676
|
+
weight = effM * globalAlpha + 128 >> 8;
|
|
4677
|
+
}
|
|
4678
|
+
if (weight === 0) {
|
|
4679
|
+
dIdx++;
|
|
4680
|
+
mIdx++;
|
|
4681
|
+
continue;
|
|
4682
|
+
}
|
|
4683
|
+
let finalCol = color;
|
|
4684
|
+
if (weight < 255) {
|
|
4685
|
+
const a = baseSrcAlpha * weight + 128 >> 8;
|
|
4686
|
+
if (a === 0 && !isOverwrite) {
|
|
4687
|
+
dIdx++;
|
|
4688
|
+
mIdx++;
|
|
4689
|
+
continue;
|
|
4690
|
+
}
|
|
4691
|
+
finalCol = (colorRGB | a << 24) >>> 0;
|
|
4692
|
+
}
|
|
4693
|
+
const current = dst32[dIdx];
|
|
4694
|
+
const next = blendFn(finalCol, current);
|
|
4695
|
+
if (current !== next) {
|
|
4696
|
+
dst32[dIdx] = next;
|
|
4697
|
+
didChange = true;
|
|
4698
|
+
}
|
|
4699
|
+
dIdx++;
|
|
4700
|
+
mIdx++;
|
|
4701
|
+
}
|
|
4702
|
+
dIdx += dStride;
|
|
4703
|
+
mIdx += mStride;
|
|
4704
|
+
}
|
|
4705
|
+
return didChange;
|
|
4706
|
+
}
|
|
4707
|
+
|
|
4708
|
+
// src/PixelData/blendColorPixelDataBinaryMask.ts
|
|
4709
|
+
function blendColorPixelDataBinaryMask(dst, color, mask, opts = {}) {
|
|
4710
|
+
const targetX = opts.x ?? 0;
|
|
4711
|
+
const targetY = opts.y ?? 0;
|
|
4712
|
+
let w = opts.w ?? mask.w;
|
|
4713
|
+
let h = opts.h ?? mask.h;
|
|
4714
|
+
const globalAlpha = opts.alpha ?? 255;
|
|
4715
|
+
const blendFn = opts.blendFn ?? sourceOverPerfect;
|
|
4716
|
+
const mx = opts.mx ?? 0;
|
|
4717
|
+
const my = opts.my ?? 0;
|
|
4718
|
+
const invertMask = opts.invertMask ?? false;
|
|
4719
|
+
if (globalAlpha === 0) return false;
|
|
4720
|
+
const baseSrcAlpha = color >>> 24;
|
|
4721
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
4722
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
4723
|
+
let x = targetX;
|
|
4724
|
+
let y = targetY;
|
|
4725
|
+
if (x < 0) {
|
|
4726
|
+
w += x;
|
|
4727
|
+
x = 0;
|
|
4728
|
+
}
|
|
4729
|
+
if (y < 0) {
|
|
4730
|
+
h += y;
|
|
4731
|
+
y = 0;
|
|
4732
|
+
}
|
|
4733
|
+
const actualW = Math.min(w, dst.width - x);
|
|
4734
|
+
const actualH = Math.min(h, dst.height - y);
|
|
4735
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
4736
|
+
let baseColorWithGlobalAlpha = color;
|
|
4737
|
+
if (globalAlpha < 255) {
|
|
4738
|
+
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
4739
|
+
if (a === 0 && !isOverwrite) return false;
|
|
4740
|
+
baseColorWithGlobalAlpha = (color & 16777215 | a << 24) >>> 0;
|
|
4741
|
+
}
|
|
4742
|
+
const dx = x - targetX | 0;
|
|
4743
|
+
const dy = y - targetY | 0;
|
|
4744
|
+
const dst32 = dst.data32;
|
|
4745
|
+
const dw = dst.width;
|
|
4746
|
+
const mPitch = mask.w;
|
|
4747
|
+
const maskData = mask.data;
|
|
4748
|
+
let dIdx = y * dw + x | 0;
|
|
4749
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
4750
|
+
const dStride = dw - actualW | 0;
|
|
4751
|
+
const mStride = mPitch - actualW | 0;
|
|
4752
|
+
const skipVal = invertMask ? 1 : 0;
|
|
4753
|
+
let didChange = false;
|
|
4754
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
4755
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
4756
|
+
if (maskData[mIdx] === skipVal) {
|
|
4757
|
+
dIdx++;
|
|
4758
|
+
mIdx++;
|
|
4759
|
+
continue;
|
|
4760
|
+
}
|
|
4761
|
+
const current = dst32[dIdx];
|
|
4762
|
+
const next = blendFn(baseColorWithGlobalAlpha, current);
|
|
4763
|
+
if (current !== next) {
|
|
4764
|
+
dst32[dIdx] = next;
|
|
4765
|
+
didChange = true;
|
|
4766
|
+
}
|
|
4767
|
+
dIdx++;
|
|
4768
|
+
mIdx++;
|
|
4938
4769
|
}
|
|
4939
|
-
|
|
4770
|
+
dIdx += dStride;
|
|
4771
|
+
mIdx += mStride;
|
|
4940
4772
|
}
|
|
4773
|
+
return didChange;
|
|
4774
|
+
}
|
|
4775
|
+
|
|
4776
|
+
// src/PixelData/blendPixelDataPaintBuffer.ts
|
|
4777
|
+
var SCRATCH_OPTS = {
|
|
4778
|
+
x: 0,
|
|
4779
|
+
y: 0,
|
|
4780
|
+
alpha: 255,
|
|
4781
|
+
blendFn: void 0
|
|
4941
4782
|
};
|
|
4783
|
+
function blendPixelDataPaintBuffer(paintBuffer, target, alpha = 255, blendFn, blendPixelDataFn = blendPixelData) {
|
|
4784
|
+
const tileShift = paintBuffer.config.tileShift;
|
|
4785
|
+
const lookup = paintBuffer.lookup;
|
|
4786
|
+
for (let i = 0; i < lookup.length; i++) {
|
|
4787
|
+
const tile = lookup[i];
|
|
4788
|
+
if (tile) {
|
|
4789
|
+
const x = tile.tx << tileShift;
|
|
4790
|
+
const y = tile.ty << tileShift;
|
|
4791
|
+
SCRATCH_OPTS.x = x;
|
|
4792
|
+
SCRATCH_OPTS.y = y;
|
|
4793
|
+
SCRATCH_OPTS.alpha = alpha;
|
|
4794
|
+
SCRATCH_OPTS.blendFn = blendFn;
|
|
4795
|
+
blendPixelDataFn(target, tile, SCRATCH_OPTS);
|
|
4796
|
+
}
|
|
4797
|
+
}
|
|
4798
|
+
}
|
|
4942
4799
|
|
|
4943
4800
|
// src/PixelData/clearPixelData.ts
|
|
4944
4801
|
function clearPixelData(dst, rect) {
|
|
4945
|
-
|
|
4802
|
+
fillPixelDataFast(dst, 0, rect);
|
|
4946
4803
|
}
|
|
4947
4804
|
|
|
4948
4805
|
// src/PixelData/extractPixelDataBuffer.ts
|
|
@@ -5161,6 +5018,162 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
5161
5018
|
dstData.set(data.subarray(srcStart, srcStart + copyW), dstStart);
|
|
5162
5019
|
}
|
|
5163
5020
|
}
|
|
5021
|
+
|
|
5022
|
+
// src/PixelData/writePaintBufferToPixelData.ts
|
|
5023
|
+
function writePaintBufferToPixelData(target, paintBuffer, writePixelDataBufferFn = writePixelDataBuffer) {
|
|
5024
|
+
const tileShift = paintBuffer.config.tileShift;
|
|
5025
|
+
const lookup = paintBuffer.lookup;
|
|
5026
|
+
for (let i = 0; i < lookup.length; i++) {
|
|
5027
|
+
const tile = lookup[i];
|
|
5028
|
+
if (tile) {
|
|
5029
|
+
const dx = tile.tx << tileShift;
|
|
5030
|
+
const dy = tile.ty << tileShift;
|
|
5031
|
+
writePixelDataBufferFn(target, tile.data32, dx, dy, tile.width, tile.height);
|
|
5032
|
+
}
|
|
5033
|
+
}
|
|
5034
|
+
}
|
|
5035
|
+
|
|
5036
|
+
// src/Paint/makeCirclePaintAlphaMask.ts
|
|
5037
|
+
function makeCirclePaintAlphaMask(size, fallOff = (d) => d) {
|
|
5038
|
+
const area = size * size;
|
|
5039
|
+
const data = new Uint8Array(area);
|
|
5040
|
+
const radius = size / 2;
|
|
5041
|
+
const invR = 1 / radius;
|
|
5042
|
+
const centerOffset = -Math.ceil(radius - 0.5);
|
|
5043
|
+
for (let y = 0; y < size; y++) {
|
|
5044
|
+
const rowOffset = y * size;
|
|
5045
|
+
const dy = y - radius + 0.5;
|
|
5046
|
+
const dy2 = dy * dy;
|
|
5047
|
+
for (let x = 0; x < size; x++) {
|
|
5048
|
+
const dx = x - radius + 0.5;
|
|
5049
|
+
const distSqr = dx * dx + dy2;
|
|
5050
|
+
if (distSqr <= radius * radius) {
|
|
5051
|
+
const dist = Math.sqrt(distSqr) * invR;
|
|
5052
|
+
const strength = fallOff(1 - dist);
|
|
5053
|
+
if (strength > 0) {
|
|
5054
|
+
const intensity = strength * 255 | 0;
|
|
5055
|
+
data[rowOffset + x] = Math.max(0, Math.min(255, intensity));
|
|
5056
|
+
}
|
|
5057
|
+
}
|
|
5058
|
+
}
|
|
5059
|
+
}
|
|
5060
|
+
return {
|
|
5061
|
+
type: 0 /* ALPHA */,
|
|
5062
|
+
data,
|
|
5063
|
+
w: size,
|
|
5064
|
+
h: size,
|
|
5065
|
+
centerOffsetX: centerOffset,
|
|
5066
|
+
centerOffsetY: centerOffset
|
|
5067
|
+
};
|
|
5068
|
+
}
|
|
5069
|
+
|
|
5070
|
+
// src/Paint/makeCirclePaintBinaryMask.ts
|
|
5071
|
+
function makeCirclePaintBinaryMask(size) {
|
|
5072
|
+
const area = size * size;
|
|
5073
|
+
const data = new Uint8Array(area);
|
|
5074
|
+
const radius = size / 2;
|
|
5075
|
+
const centerOffset = -Math.ceil(radius - 0.5);
|
|
5076
|
+
for (let y = 0; y < size; y++) {
|
|
5077
|
+
for (let x = 0; x < size; x++) {
|
|
5078
|
+
const dx = x - radius + 0.5;
|
|
5079
|
+
const dy = y - radius + 0.5;
|
|
5080
|
+
const distSqr = dx * dx + dy * dy;
|
|
5081
|
+
if (distSqr <= radius * radius) {
|
|
5082
|
+
data[y * size + x] = 1;
|
|
5083
|
+
}
|
|
5084
|
+
}
|
|
5085
|
+
}
|
|
5086
|
+
return {
|
|
5087
|
+
type: 1 /* BINARY */,
|
|
5088
|
+
data,
|
|
5089
|
+
w: size,
|
|
5090
|
+
h: size,
|
|
5091
|
+
centerOffsetX: centerOffset,
|
|
5092
|
+
centerOffsetY: centerOffset
|
|
5093
|
+
};
|
|
5094
|
+
}
|
|
5095
|
+
|
|
5096
|
+
// src/Paint/makePaintMask.ts
|
|
5097
|
+
function makePaintBinaryMask(mask) {
|
|
5098
|
+
return {
|
|
5099
|
+
type: 1 /* BINARY */,
|
|
5100
|
+
data: mask.data,
|
|
5101
|
+
w: mask.w,
|
|
5102
|
+
h: mask.h,
|
|
5103
|
+
centerOffsetX: -(mask.w >> 1),
|
|
5104
|
+
centerOffsetY: -(mask.h >> 1)
|
|
5105
|
+
};
|
|
5106
|
+
}
|
|
5107
|
+
function makePaintAlphaMask(mask) {
|
|
5108
|
+
return {
|
|
5109
|
+
type: 0 /* ALPHA */,
|
|
5110
|
+
data: mask.data,
|
|
5111
|
+
w: mask.w,
|
|
5112
|
+
h: mask.h,
|
|
5113
|
+
centerOffsetX: -(mask.w >> 1),
|
|
5114
|
+
centerOffsetY: -(mask.h >> 1)
|
|
5115
|
+
};
|
|
5116
|
+
}
|
|
5117
|
+
|
|
5118
|
+
// src/Paint/makeRectFalloffPaintAlphaMask.ts
|
|
5119
|
+
function makeRectFalloffPaintAlphaMask(width, height, fallOff = (d) => d) {
|
|
5120
|
+
const fPx = Math.floor(width / 2);
|
|
5121
|
+
const fPy = Math.floor(height / 2);
|
|
5122
|
+
const invHalfW = 2 / width;
|
|
5123
|
+
const invHalfH = 2 / height;
|
|
5124
|
+
const offX = width % 2 === 0 ? 0.5 : 0;
|
|
5125
|
+
const offY = height % 2 === 0 ? 0.5 : 0;
|
|
5126
|
+
const area = width * height;
|
|
5127
|
+
const data = new Uint8Array(area);
|
|
5128
|
+
for (let y = 0; y < height; y++) {
|
|
5129
|
+
const dy = Math.abs(y - fPy + offY) * invHalfH;
|
|
5130
|
+
const rowOffset = y * width;
|
|
5131
|
+
for (let x = 0; x < width; x++) {
|
|
5132
|
+
const dx = Math.abs(x - fPx + offX) * invHalfW;
|
|
5133
|
+
const dist = dx > dy ? dx : dy;
|
|
5134
|
+
const strength = fallOff(1 - dist);
|
|
5135
|
+
if (strength > 0) {
|
|
5136
|
+
const intensity = strength * 255 | 0;
|
|
5137
|
+
data[rowOffset + x] = Math.max(0, Math.min(255, intensity));
|
|
5138
|
+
}
|
|
5139
|
+
}
|
|
5140
|
+
}
|
|
5141
|
+
return {
|
|
5142
|
+
type: 0 /* ALPHA */,
|
|
5143
|
+
data,
|
|
5144
|
+
w: width,
|
|
5145
|
+
h: height,
|
|
5146
|
+
centerOffsetX: -macro_halfAndFloor(width),
|
|
5147
|
+
centerOffsetY: -macro_halfAndFloor(height)
|
|
5148
|
+
};
|
|
5149
|
+
}
|
|
5150
|
+
|
|
5151
|
+
// src/Paint/PaintBufferCanvasRenderer.ts
|
|
5152
|
+
function makePaintBufferCanvasRenderer(paintBuffer, offscreenCanvasClass = OffscreenCanvas) {
|
|
5153
|
+
const config = paintBuffer.config;
|
|
5154
|
+
const tileSize = config.tileSize;
|
|
5155
|
+
const tileShift = config.tileShift;
|
|
5156
|
+
const lookup = paintBuffer.lookup;
|
|
5157
|
+
const canvas = new offscreenCanvasClass(tileSize, tileSize);
|
|
5158
|
+
const ctx = canvas.getContext("2d");
|
|
5159
|
+
if (!ctx) throw new Error(CANVAS_CTX_FAILED);
|
|
5160
|
+
ctx.imageSmoothingEnabled = false;
|
|
5161
|
+
return function drawPaintBuffer(targetCtx, alpha = 255, compOperation = "source-over") {
|
|
5162
|
+
targetCtx.globalAlpha = alpha / 255;
|
|
5163
|
+
targetCtx.globalCompositeOperation = compOperation;
|
|
5164
|
+
for (let i = 0; i < lookup.length; i++) {
|
|
5165
|
+
const tile = lookup[i];
|
|
5166
|
+
if (tile) {
|
|
5167
|
+
const dx = tile.tx << tileShift;
|
|
5168
|
+
const dy = tile.ty << tileShift;
|
|
5169
|
+
ctx.putImageData(tile.imageData, 0, 0);
|
|
5170
|
+
targetCtx.drawImage(canvas, dx, dy);
|
|
5171
|
+
}
|
|
5172
|
+
}
|
|
5173
|
+
targetCtx.globalAlpha = 1;
|
|
5174
|
+
targetCtx.globalCompositeOperation = "source-over";
|
|
5175
|
+
};
|
|
5176
|
+
}
|
|
5164
5177
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5165
5178
|
0 && (module.exports = {
|
|
5166
5179
|
BASE_FAST_BLEND_MODE_FUNCTIONS,
|
|
@@ -5171,27 +5184,29 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
5171
5184
|
IndexedImage,
|
|
5172
5185
|
MaskType,
|
|
5173
5186
|
OFFSCREEN_CANVAS_CTX_FAILED,
|
|
5187
|
+
PaintBuffer,
|
|
5174
5188
|
PixelAccumulator,
|
|
5175
5189
|
PixelBuffer32,
|
|
5176
5190
|
PixelData,
|
|
5177
5191
|
PixelEngineConfig,
|
|
5178
5192
|
PixelTile,
|
|
5193
|
+
PixelTilePool,
|
|
5179
5194
|
PixelWriter,
|
|
5180
5195
|
UnsupportedFormatError,
|
|
5181
5196
|
applyAlphaMaskToPixelData,
|
|
5182
5197
|
applyBinaryMaskToAlphaMask,
|
|
5183
5198
|
applyBinaryMaskToPixelData,
|
|
5184
|
-
applyCircleBrushToPixelData,
|
|
5185
5199
|
applyPatchTiles,
|
|
5186
|
-
applyRectBrushToPixelData,
|
|
5187
5200
|
base64DecodeArrayBuffer,
|
|
5188
5201
|
base64EncodeArrayBuffer,
|
|
5189
5202
|
blendColorPixelData,
|
|
5190
5203
|
blendColorPixelDataAlphaMask,
|
|
5191
5204
|
blendColorPixelDataBinaryMask,
|
|
5205
|
+
blendPixel,
|
|
5192
5206
|
blendPixelData,
|
|
5193
5207
|
blendPixelDataAlphaMask,
|
|
5194
5208
|
blendPixelDataBinaryMask,
|
|
5209
|
+
blendPixelDataPaintBuffer,
|
|
5195
5210
|
clearPixelData,
|
|
5196
5211
|
color32ToCssRGBA,
|
|
5197
5212
|
color32ToHex,
|
|
@@ -5225,14 +5240,11 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
5225
5240
|
fileToImageData,
|
|
5226
5241
|
fillPixelData,
|
|
5227
5242
|
fillPixelDataBinaryMask,
|
|
5243
|
+
fillPixelDataFast,
|
|
5228
5244
|
floodFillSelection,
|
|
5229
5245
|
forEachLinePoint,
|
|
5230
|
-
getCircleBrushOrPencilBounds,
|
|
5231
|
-
getCircleBrushOrPencilStrokeBounds,
|
|
5232
5246
|
getImageDataFromClipboard,
|
|
5233
5247
|
getIndexedImageColorCounts,
|
|
5234
|
-
getRectBrushOrPencilBounds,
|
|
5235
|
-
getRectBrushOrPencilStrokeBounds,
|
|
5236
5248
|
getRectsBounds,
|
|
5237
5249
|
getSupportedPixelFormats,
|
|
5238
5250
|
hardLightFast,
|
|
@@ -5265,15 +5277,22 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
5265
5277
|
makeAlphaMask,
|
|
5266
5278
|
makeBinaryMask,
|
|
5267
5279
|
makeBlendModeRegistry,
|
|
5268
|
-
|
|
5269
|
-
|
|
5280
|
+
makeCanvasFrameRenderer,
|
|
5281
|
+
makeCirclePaintAlphaMask,
|
|
5282
|
+
makeCirclePaintBinaryMask,
|
|
5270
5283
|
makeFastBlendModeRegistry,
|
|
5271
5284
|
makeFullPixelMutator,
|
|
5285
|
+
makeHistoryAction,
|
|
5272
5286
|
makeImageDataLike,
|
|
5287
|
+
makePaintAlphaMask,
|
|
5288
|
+
makePaintBinaryMask,
|
|
5289
|
+
makePaintBufferCanvasRenderer,
|
|
5273
5290
|
makePerfectBlendModeRegistry,
|
|
5274
5291
|
makePixelCanvas,
|
|
5292
|
+
makeRectFalloffPaintAlphaMask,
|
|
5275
5293
|
makeReusableCanvas,
|
|
5276
5294
|
makeReusableImageData,
|
|
5295
|
+
makeReusableOffscreenCanvas,
|
|
5277
5296
|
merge2BinaryMaskRects,
|
|
5278
5297
|
mergeAlphaMasks,
|
|
5279
5298
|
mergeBinaryMaskRects,
|
|
@@ -5282,14 +5301,6 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
5282
5301
|
multiplyPerfect,
|
|
5283
5302
|
mutatorApplyAlphaMask,
|
|
5284
5303
|
mutatorApplyBinaryMask,
|
|
5285
|
-
mutatorApplyCircleBrush,
|
|
5286
|
-
mutatorApplyCircleBrushStroke,
|
|
5287
|
-
mutatorApplyCirclePencil,
|
|
5288
|
-
mutatorApplyCirclePencilStroke,
|
|
5289
|
-
mutatorApplyRectBrush,
|
|
5290
|
-
mutatorApplyRectBrushStroke,
|
|
5291
|
-
mutatorApplyRectPencil,
|
|
5292
|
-
mutatorApplyRectPencilStroke,
|
|
5293
5304
|
mutatorBlendColor,
|
|
5294
5305
|
mutatorBlendPixel,
|
|
5295
5306
|
mutatorBlendPixelData,
|
|
@@ -5298,6 +5309,7 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
5298
5309
|
mutatorClear,
|
|
5299
5310
|
mutatorFill,
|
|
5300
5311
|
mutatorFillBinaryMask,
|
|
5312
|
+
mutatorFillRect,
|
|
5301
5313
|
mutatorInvert,
|
|
5302
5314
|
overlayFast,
|
|
5303
5315
|
overlayPerfect,
|
|
@@ -5329,6 +5341,7 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
5329
5341
|
subtractFast,
|
|
5330
5342
|
subtractPerfect,
|
|
5331
5343
|
toBlendModeIndexAndName,
|
|
5344
|
+
trimMaskRectBounds,
|
|
5332
5345
|
trimRectBounds,
|
|
5333
5346
|
uInt32ArrayToImageData,
|
|
5334
5347
|
uInt32ArrayToImageDataLike,
|
|
@@ -5344,6 +5357,7 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
5344
5357
|
writeImageDataBuffer,
|
|
5345
5358
|
writeImageDataToClipboard,
|
|
5346
5359
|
writeImgBlobToClipboard,
|
|
5360
|
+
writePaintBufferToPixelData,
|
|
5347
5361
|
writePixelDataBuffer
|
|
5348
5362
|
});
|
|
5349
5363
|
//# sourceMappingURL=index.dev.cjs.map
|