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.prod.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,912 @@ 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/Rect/trimRectBounds.ts
|
|
3033
|
+
function trimRectBounds(x, y, w, h, targetWidth, targetHeight, out) {
|
|
3034
|
+
const res = out ?? {
|
|
3029
3035
|
x: 0,
|
|
3030
3036
|
y: 0,
|
|
3031
3037
|
w: 0,
|
|
3032
3038
|
h: 0
|
|
3033
3039
|
};
|
|
3034
|
-
const
|
|
3040
|
+
const left = Math.max(0, x);
|
|
3041
|
+
const top = Math.max(0, y);
|
|
3042
|
+
const right = Math.min(targetWidth, x + w);
|
|
3043
|
+
const bottom = Math.min(targetHeight, y + h);
|
|
3044
|
+
res.x = left;
|
|
3045
|
+
res.y = top;
|
|
3046
|
+
res.w = Math.max(0, right - left);
|
|
3047
|
+
res.h = Math.max(0, bottom - top);
|
|
3048
|
+
return res;
|
|
3049
|
+
}
|
|
3050
|
+
|
|
3051
|
+
// src/Paint/PaintBuffer.ts
|
|
3052
|
+
var PaintBuffer = class {
|
|
3053
|
+
constructor(config, tilePool) {
|
|
3054
|
+
this.config = config;
|
|
3055
|
+
this.tilePool = tilePool;
|
|
3056
|
+
this.lookup = [];
|
|
3057
|
+
}
|
|
3058
|
+
lookup;
|
|
3059
|
+
scratchBounds = {
|
|
3035
3060
|
x: 0,
|
|
3036
3061
|
y: 0,
|
|
3037
3062
|
w: 0,
|
|
3038
3063
|
h: 0
|
|
3039
3064
|
};
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
const
|
|
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
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3065
|
+
eachTileInBounds(bounds, callback) {
|
|
3066
|
+
const {
|
|
3067
|
+
tileShift,
|
|
3068
|
+
targetColumns,
|
|
3069
|
+
targetRows,
|
|
3070
|
+
tileSize
|
|
3071
|
+
} = this.config;
|
|
3072
|
+
const x1 = Math.max(0, bounds.x >> tileShift);
|
|
3073
|
+
const y1 = Math.max(0, bounds.y >> tileShift);
|
|
3074
|
+
const x2 = Math.min(targetColumns - 1, bounds.x + bounds.w - 1 >> tileShift);
|
|
3075
|
+
const y2 = Math.min(targetRows - 1, bounds.y + bounds.h - 1 >> tileShift);
|
|
3076
|
+
if (x1 > x2 || y1 > y2) return;
|
|
3077
|
+
const lookup = this.lookup;
|
|
3078
|
+
const tilePool = this.tilePool;
|
|
3079
|
+
for (let ty = y1; ty <= y2; ty++) {
|
|
3080
|
+
const rowOffset = ty * targetColumns;
|
|
3081
|
+
const tileTop = ty << tileShift;
|
|
3082
|
+
for (let tx = x1; tx <= x2; tx++) {
|
|
3083
|
+
const id = rowOffset + tx;
|
|
3084
|
+
const tile = lookup[id] ?? (lookup[id] = tilePool.getTile(id, tx, ty));
|
|
3085
|
+
const tileLeft = tx << tileShift;
|
|
3086
|
+
const startX = bounds.x > tileLeft ? bounds.x : tileLeft;
|
|
3087
|
+
const startY = bounds.y > tileTop ? bounds.y : tileTop;
|
|
3088
|
+
const maskEndX = bounds.x + bounds.w;
|
|
3089
|
+
const tileEndX = tileLeft + tileSize;
|
|
3090
|
+
const endX = maskEndX < tileEndX ? maskEndX : tileEndX;
|
|
3091
|
+
const maskEndY = bounds.y + bounds.h;
|
|
3092
|
+
const tileEndY = tileTop + tileSize;
|
|
3093
|
+
const endY = maskEndY < tileEndY ? maskEndY : tileEndY;
|
|
3094
|
+
callback(tile, startX, startY, endX - startX, endY - startY);
|
|
3095
|
+
}
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
3098
|
+
writePaintAlphaMaskStroke(color, brush, x0, y0, x1, y1) {
|
|
3099
|
+
const cA = color >>> 24;
|
|
3100
|
+
if (cA === 0) return false;
|
|
3101
|
+
const {
|
|
3102
|
+
tileShift,
|
|
3103
|
+
tileMask,
|
|
3104
|
+
target
|
|
3105
|
+
} = this.config;
|
|
3106
|
+
const {
|
|
3107
|
+
w: bW,
|
|
3108
|
+
h: bH,
|
|
3109
|
+
data: bD,
|
|
3110
|
+
centerOffsetX,
|
|
3111
|
+
centerOffsetY
|
|
3112
|
+
} = brush;
|
|
3113
|
+
const cRGB = color & 16777215;
|
|
3114
|
+
const scratch = this.scratchBounds;
|
|
3115
|
+
let changed = false;
|
|
3116
|
+
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
3117
|
+
const topLeftX = Math.floor(px + centerOffsetX);
|
|
3118
|
+
const topLeftY = Math.floor(py + centerOffsetY);
|
|
3119
|
+
trimRectBounds(topLeftX, topLeftY, bW, bH, target.width, target.height, scratch);
|
|
3120
|
+
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
3121
|
+
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
3122
|
+
const d32 = tile.data32;
|
|
3123
|
+
let tileChanged = false;
|
|
3124
|
+
for (let i = 0; i < bH_t; i++) {
|
|
3125
|
+
const canvasY = bY + i;
|
|
3126
|
+
const bOff = (canvasY - topLeftY) * bW;
|
|
3127
|
+
const tOff = (canvasY & tileMask) << tileShift;
|
|
3128
|
+
const dS = tOff + (bX & tileMask);
|
|
3129
|
+
for (let j = 0; j < bW_t; j++) {
|
|
3130
|
+
const canvasX = bX + j;
|
|
3131
|
+
const brushA = bD[bOff + (canvasX - topLeftX)];
|
|
3132
|
+
if (brushA === 0) continue;
|
|
3133
|
+
const t = cA * brushA + 128;
|
|
3134
|
+
const blendedA = t + (t >> 8) >> 8;
|
|
3135
|
+
const idx = dS + j;
|
|
3136
|
+
const cur = d32[idx];
|
|
3137
|
+
if (brushA > cur >>> 24) {
|
|
3138
|
+
const next = (cRGB | blendedA << 24) >>> 0;
|
|
3139
|
+
if (cur !== next) {
|
|
3140
|
+
d32[idx] = next;
|
|
3141
|
+
tileChanged = true;
|
|
3142
|
+
}
|
|
3143
|
+
}
|
|
3144
|
+
}
|
|
3145
|
+
}
|
|
3146
|
+
if (tileChanged) changed = true;
|
|
3147
|
+
});
|
|
3148
|
+
});
|
|
3149
|
+
return changed;
|
|
3150
|
+
}
|
|
3151
|
+
writePaintBinaryMaskStroke(color, brush, x0, y0, x1, y1) {
|
|
3152
|
+
const alphaIsZero = color >>> 24 === 0;
|
|
3153
|
+
if (alphaIsZero) return false;
|
|
3154
|
+
const {
|
|
3155
|
+
tileShift,
|
|
3156
|
+
tileMask,
|
|
3157
|
+
target
|
|
3158
|
+
} = this.config;
|
|
3159
|
+
const {
|
|
3160
|
+
w: bW,
|
|
3161
|
+
h: bH,
|
|
3162
|
+
data: bD,
|
|
3163
|
+
centerOffsetX,
|
|
3164
|
+
centerOffsetY
|
|
3165
|
+
} = brush;
|
|
3166
|
+
const scratch = this.scratchBounds;
|
|
3167
|
+
let changed = false;
|
|
3168
|
+
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
3169
|
+
const topLeftX = Math.floor(px + centerOffsetX);
|
|
3170
|
+
const topLeftY = Math.floor(py + centerOffsetY);
|
|
3171
|
+
trimRectBounds(topLeftX, topLeftY, bW, bH, target.width, target.height, scratch);
|
|
3172
|
+
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
3173
|
+
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
3174
|
+
const d32 = tile.data32;
|
|
3175
|
+
let tileChanged = false;
|
|
3176
|
+
for (let i = 0; i < bH_t; i++) {
|
|
3177
|
+
const canvasY = bY + i;
|
|
3178
|
+
const bOff = (canvasY - topLeftY) * bW;
|
|
3179
|
+
const tOff = (canvasY & tileMask) << tileShift;
|
|
3180
|
+
const dS = tOff + (bX & tileMask);
|
|
3181
|
+
for (let j = 0; j < bW_t; j++) {
|
|
3182
|
+
const canvasX = bX + j;
|
|
3183
|
+
if (bD[bOff + (canvasX - topLeftX)]) {
|
|
3184
|
+
const idx = dS + j;
|
|
3185
|
+
if (d32[idx] !== color) {
|
|
3186
|
+
d32[idx] = color;
|
|
3187
|
+
tileChanged = true;
|
|
3188
|
+
}
|
|
3189
|
+
}
|
|
3190
|
+
}
|
|
3191
|
+
}
|
|
3192
|
+
if (tileChanged) changed = true;
|
|
3193
|
+
});
|
|
3194
|
+
});
|
|
3195
|
+
return changed;
|
|
3196
|
+
}
|
|
3197
|
+
writeRectStroke(color, brushWidth, brushHeight, x0, y0, x1, y1) {
|
|
3198
|
+
const alphaIsZero = color >>> 24 === 0;
|
|
3199
|
+
if (alphaIsZero) return false;
|
|
3200
|
+
const config = this.config;
|
|
3201
|
+
const tileShift = config.tileShift;
|
|
3202
|
+
const tileMask = config.tileMask;
|
|
3203
|
+
const target = config.target;
|
|
3204
|
+
const scratch = this.scratchBounds;
|
|
3205
|
+
const centerOffsetX = brushWidth - 1 >> 1;
|
|
3206
|
+
const centerOffsetY = brushHeight - 1 >> 1;
|
|
3207
|
+
let changed = false;
|
|
3208
|
+
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
3209
|
+
const topLeftX = Math.floor(px + centerOffsetX);
|
|
3210
|
+
const topLeftY = Math.floor(py + centerOffsetY);
|
|
3211
|
+
trimRectBounds(topLeftX, topLeftY, brushWidth, brushHeight, target.width, target.height, scratch);
|
|
3212
|
+
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
3213
|
+
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
3214
|
+
const d32 = tile.data32;
|
|
3215
|
+
let tileChanged = false;
|
|
3216
|
+
for (let i = 0; i < bH_t; i++) {
|
|
3217
|
+
const canvasY = bY + i;
|
|
3218
|
+
const tOff = (canvasY & tileMask) << tileShift;
|
|
3219
|
+
const dS = tOff + (bX & tileMask);
|
|
3220
|
+
for (let j = 0; j < bW_t; j++) {
|
|
3221
|
+
const idx = dS + j;
|
|
3222
|
+
if (d32[idx] !== color) {
|
|
3223
|
+
d32[idx] = color;
|
|
3224
|
+
tileChanged = true;
|
|
3094
3225
|
}
|
|
3095
3226
|
}
|
|
3096
3227
|
}
|
|
3228
|
+
if (tileChanged) {
|
|
3229
|
+
changed = true;
|
|
3230
|
+
}
|
|
3097
3231
|
});
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3232
|
+
});
|
|
3233
|
+
return changed;
|
|
3234
|
+
}
|
|
3235
|
+
clear() {
|
|
3236
|
+
this.tilePool.releaseTiles(this.lookup);
|
|
3237
|
+
}
|
|
3238
|
+
};
|
|
3239
|
+
|
|
3240
|
+
// src/PixelTile/PixelTile.ts
|
|
3241
|
+
var PixelTile = class {
|
|
3242
|
+
constructor(id, tx, ty, tileSize, tileArea) {
|
|
3243
|
+
this.id = id;
|
|
3244
|
+
this.tx = tx;
|
|
3245
|
+
this.ty = ty;
|
|
3246
|
+
this.width = this.height = tileSize;
|
|
3247
|
+
this.data32 = new Uint32Array(tileArea);
|
|
3248
|
+
const data8 = new Uint8ClampedArray(this.data32.buffer);
|
|
3249
|
+
this.imageData = new ImageData(data8, tileSize, tileSize);
|
|
3250
|
+
}
|
|
3251
|
+
data32;
|
|
3252
|
+
width;
|
|
3253
|
+
height;
|
|
3254
|
+
imageData;
|
|
3255
|
+
};
|
|
3256
|
+
|
|
3257
|
+
// src/PixelTile/PixelTilePool.ts
|
|
3258
|
+
var PixelTilePool = class {
|
|
3259
|
+
pool;
|
|
3260
|
+
tileSize;
|
|
3261
|
+
tileArea;
|
|
3262
|
+
constructor(config) {
|
|
3263
|
+
this.pool = [];
|
|
3264
|
+
this.tileSize = config.tileSize;
|
|
3265
|
+
this.tileArea = config.tileArea;
|
|
3266
|
+
}
|
|
3267
|
+
getTile(id, tx, ty) {
|
|
3268
|
+
let tile = this.pool.pop();
|
|
3269
|
+
if (tile) {
|
|
3270
|
+
tile.id = id;
|
|
3271
|
+
tile.tx = tx;
|
|
3272
|
+
tile.ty = ty;
|
|
3273
|
+
tile.data32.fill(0);
|
|
3274
|
+
return tile;
|
|
3275
|
+
}
|
|
3276
|
+
return new PixelTile(id, tx, ty, this.tileSize, this.tileArea);
|
|
3277
|
+
}
|
|
3278
|
+
releaseTile(tile) {
|
|
3279
|
+
this.pool.push(tile);
|
|
3280
|
+
}
|
|
3281
|
+
releaseTiles(tiles) {
|
|
3282
|
+
let length = tiles.length;
|
|
3283
|
+
for (let i = 0; i < length; i++) {
|
|
3284
|
+
let tile = tiles[i];
|
|
3285
|
+
if (tile) {
|
|
3286
|
+
this.pool.push(tile);
|
|
3287
|
+
}
|
|
3105
3288
|
}
|
|
3289
|
+
tiles.length = 0;
|
|
3290
|
+
}
|
|
3291
|
+
};
|
|
3292
|
+
|
|
3293
|
+
// src/History/PixelWriter.ts
|
|
3294
|
+
var PixelWriter = class {
|
|
3295
|
+
historyManager;
|
|
3296
|
+
accumulator;
|
|
3297
|
+
historyActionFactory;
|
|
3298
|
+
config;
|
|
3299
|
+
pixelTilePool;
|
|
3300
|
+
paintBuffer;
|
|
3301
|
+
mutator;
|
|
3302
|
+
blendPixelDataOpts = {
|
|
3303
|
+
alpha: 255,
|
|
3304
|
+
blendFn: sourceOverPerfect,
|
|
3305
|
+
x: 0,
|
|
3306
|
+
y: 0,
|
|
3307
|
+
w: 0,
|
|
3308
|
+
h: 0
|
|
3106
3309
|
};
|
|
3107
|
-
|
|
3310
|
+
_inProgress = false;
|
|
3311
|
+
constructor(target, mutatorFactory, {
|
|
3312
|
+
tileSize = 256,
|
|
3313
|
+
maxHistorySteps = 50,
|
|
3314
|
+
historyManager = new HistoryManager(maxHistorySteps),
|
|
3315
|
+
historyActionFactory = makeHistoryAction,
|
|
3316
|
+
pixelTilePool,
|
|
3317
|
+
accumulator
|
|
3318
|
+
} = {}) {
|
|
3319
|
+
this.config = new PixelEngineConfig(tileSize, target);
|
|
3320
|
+
this.historyManager = historyManager;
|
|
3321
|
+
this.pixelTilePool = pixelTilePool ?? new PixelTilePool(this.config);
|
|
3322
|
+
this.accumulator = accumulator ?? new PixelAccumulator(this.config, this.pixelTilePool);
|
|
3323
|
+
this.historyActionFactory = historyActionFactory;
|
|
3324
|
+
this.mutator = mutatorFactory(this);
|
|
3325
|
+
this.paintBuffer = new PaintBuffer(this.config, this.pixelTilePool);
|
|
3326
|
+
}
|
|
3327
|
+
/**
|
|
3328
|
+
* Executes `transaction` and commits the resulting pixel changes as a single
|
|
3329
|
+
* undoable history action.
|
|
3330
|
+
*
|
|
3331
|
+
* - If `transaction` throws, all accumulated changes are rolled back and the error
|
|
3332
|
+
* is re-thrown. No action is committed.
|
|
3333
|
+
* - If `transaction` completes without modifying any pixels, no action is committed.
|
|
3334
|
+
* - `withHistory` is not re-entrant. Calling it again from inside `transaction` will
|
|
3335
|
+
* throw immediately to prevent silent data loss from a nested extractPatch.
|
|
3336
|
+
*
|
|
3337
|
+
* @param transaction Callback to be executed inside the transaction.
|
|
3338
|
+
* @param after Called after both undo and redo — use for generic change notifications.
|
|
3339
|
+
* @param afterUndo Called after undo only — use for dimension or state changes specific to undo.
|
|
3340
|
+
* @param afterRedo Called after redo only.
|
|
3341
|
+
*/
|
|
3342
|
+
withHistory(transaction, after, afterUndo, afterRedo) {
|
|
3343
|
+
if (this._inProgress) {
|
|
3344
|
+
throw new Error("withHistory is not re-entrant \u2014 commit or rollback the current operation first");
|
|
3345
|
+
}
|
|
3346
|
+
this._inProgress = true;
|
|
3347
|
+
try {
|
|
3348
|
+
transaction(this.mutator);
|
|
3349
|
+
} catch (e) {
|
|
3350
|
+
this.accumulator.rollbackAfterError();
|
|
3351
|
+
throw e;
|
|
3352
|
+
} finally {
|
|
3353
|
+
this._inProgress = false;
|
|
3354
|
+
}
|
|
3355
|
+
if (this.accumulator.beforeTiles.length === 0) return;
|
|
3356
|
+
const patch = this.accumulator.extractPatch();
|
|
3357
|
+
const action = this.historyActionFactory(this, patch, after, afterUndo, afterRedo);
|
|
3358
|
+
this.historyManager.commit(action);
|
|
3359
|
+
}
|
|
3360
|
+
resize(newWidth, newHeight, offsetX = 0, offsetY = 0, after, afterUndo, afterRedo, resizeImageDataFn = resizeImageData) {
|
|
3361
|
+
if (this._inProgress) {
|
|
3362
|
+
throw new Error("Cannot resize inside a withHistory callback");
|
|
3363
|
+
}
|
|
3364
|
+
if (this.accumulator.beforeTiles.length > 0) {
|
|
3365
|
+
throw new Error("Cannot resize with an open accumulator \u2014 commit or rollback first");
|
|
3366
|
+
}
|
|
3367
|
+
const config = this.config;
|
|
3368
|
+
const target = config.target;
|
|
3369
|
+
const beforeImageData = target.imageData;
|
|
3370
|
+
const afterImageData = resizeImageDataFn(beforeImageData, newWidth, newHeight, offsetX, offsetY);
|
|
3371
|
+
target.set(afterImageData);
|
|
3372
|
+
this.historyManager.commit({
|
|
3373
|
+
undo: () => {
|
|
3374
|
+
target.set(beforeImageData);
|
|
3375
|
+
afterUndo?.(beforeImageData);
|
|
3376
|
+
after?.(beforeImageData);
|
|
3377
|
+
},
|
|
3378
|
+
redo: () => {
|
|
3379
|
+
target.set(afterImageData);
|
|
3380
|
+
afterRedo?.(afterImageData);
|
|
3381
|
+
after?.(afterImageData);
|
|
3382
|
+
}
|
|
3383
|
+
});
|
|
3384
|
+
}
|
|
3385
|
+
commitPaintBuffer(alpha = 255, blendFn = sourceOverPerfect, blendPixelDataFn = blendPixelData) {
|
|
3386
|
+
const paintBuffer = this.paintBuffer;
|
|
3387
|
+
const tileShift = paintBuffer.config.tileShift;
|
|
3388
|
+
const lookup = paintBuffer.lookup;
|
|
3389
|
+
const opts = this.blendPixelDataOpts;
|
|
3390
|
+
opts.alpha = alpha;
|
|
3391
|
+
opts.blendFn = blendFn;
|
|
3392
|
+
for (let i = 0; i < lookup.length; i++) {
|
|
3393
|
+
const tile = lookup[i];
|
|
3394
|
+
if (tile) {
|
|
3395
|
+
const didChange = this.accumulator.storeTileBeforeState(tile.id, tile.tx, tile.ty);
|
|
3396
|
+
const dx = tile.tx << tileShift;
|
|
3397
|
+
const dy = tile.ty << tileShift;
|
|
3398
|
+
opts.x = dx;
|
|
3399
|
+
opts.y = dy;
|
|
3400
|
+
opts.w = tile.width;
|
|
3401
|
+
opts.h = tile.height;
|
|
3402
|
+
didChange(blendPixelDataFn(this.config.target, tile, opts));
|
|
3403
|
+
}
|
|
3404
|
+
}
|
|
3405
|
+
paintBuffer.clear();
|
|
3406
|
+
}
|
|
3407
|
+
};
|
|
3108
3408
|
|
|
3109
|
-
// src/PixelData/
|
|
3110
|
-
function
|
|
3409
|
+
// src/PixelData/applyAlphaMaskToPixelData.ts
|
|
3410
|
+
function applyAlphaMaskToPixelData(dst, mask, opts = {}) {
|
|
3111
3411
|
const {
|
|
3112
3412
|
x: targetX = 0,
|
|
3113
3413
|
y: targetY = 0,
|
|
3114
3414
|
w: width = dst.width,
|
|
3115
3415
|
h: height = dst.height,
|
|
3116
3416
|
alpha: globalAlpha = 255,
|
|
3117
|
-
|
|
3417
|
+
mx = 0,
|
|
3418
|
+
my = 0,
|
|
3419
|
+
invertMask = false
|
|
3118
3420
|
} = opts;
|
|
3119
|
-
if (globalAlpha === 0) return;
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
let
|
|
3421
|
+
if (globalAlpha === 0) return false;
|
|
3422
|
+
let x = targetX;
|
|
3423
|
+
let y = targetY;
|
|
3424
|
+
let w = width;
|
|
3425
|
+
let h = height;
|
|
3124
3426
|
if (x < 0) {
|
|
3125
3427
|
w += x;
|
|
3126
3428
|
x = 0;
|
|
@@ -3129,723 +3431,200 @@ function blendColorPixelData(dst, color, opts = {}) {
|
|
|
3129
3431
|
h += y;
|
|
3130
3432
|
y = 0;
|
|
3131
3433
|
}
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
if (
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3434
|
+
w = Math.min(w, dst.width - x);
|
|
3435
|
+
h = Math.min(h, dst.height - y);
|
|
3436
|
+
if (w <= 0) return false;
|
|
3437
|
+
if (h <= 0) return false;
|
|
3438
|
+
const mPitch = mask.w;
|
|
3439
|
+
if (mPitch <= 0) return false;
|
|
3440
|
+
const startX = mx + (x - targetX);
|
|
3441
|
+
const startY = my + (y - targetY);
|
|
3442
|
+
const sX0 = Math.max(0, startX);
|
|
3443
|
+
const sY0 = Math.max(0, startY);
|
|
3444
|
+
const sX1 = Math.min(mPitch, startX + w);
|
|
3445
|
+
const sY1 = Math.min(mask.h, startY + h);
|
|
3446
|
+
const finalW = sX1 - sX0;
|
|
3447
|
+
const finalH = sY1 - sY0;
|
|
3448
|
+
if (finalW <= 0) return false;
|
|
3449
|
+
if (finalH <= 0) return false;
|
|
3450
|
+
const xShift = sX0 - startX;
|
|
3451
|
+
const yShift = sY0 - startY;
|
|
3141
3452
|
const dst32 = dst.data32;
|
|
3142
3453
|
const dw = dst.width;
|
|
3143
|
-
|
|
3144
|
-
const
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3454
|
+
const dStride = dw - finalW;
|
|
3455
|
+
const mStride = mPitch - finalW;
|
|
3456
|
+
const maskData = mask.data;
|
|
3457
|
+
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
3458
|
+
let mIdx = sY0 * mPitch + sX0;
|
|
3459
|
+
let didChange = false;
|
|
3460
|
+
for (let iy = 0; iy < h; iy++) {
|
|
3461
|
+
for (let ix = 0; ix < w; ix++) {
|
|
3462
|
+
const mVal = maskData[mIdx];
|
|
3463
|
+
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
3464
|
+
let weight = 0;
|
|
3465
|
+
if (effectiveM === 0) {
|
|
3466
|
+
weight = 0;
|
|
3467
|
+
} else if (effectiveM === 255) {
|
|
3468
|
+
weight = globalAlpha;
|
|
3469
|
+
} else if (globalAlpha === 255) {
|
|
3470
|
+
weight = effectiveM;
|
|
3471
|
+
} else {
|
|
3472
|
+
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
3473
|
+
}
|
|
3474
|
+
if (weight === 0) {
|
|
3475
|
+
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
3476
|
+
didChange = true;
|
|
3477
|
+
} else if (weight !== 255) {
|
|
3478
|
+
const d = dst32[dIdx];
|
|
3479
|
+
const da = d >>> 24;
|
|
3480
|
+
if (da !== 0) {
|
|
3481
|
+
const finalAlpha = da === 255 ? weight : da * weight + 128 >> 8;
|
|
3482
|
+
const current = dst32[dIdx];
|
|
3483
|
+
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
3484
|
+
if (current !== next) {
|
|
3485
|
+
dst32[dIdx] = next;
|
|
3486
|
+
didChange = true;
|
|
3487
|
+
}
|
|
3488
|
+
}
|
|
3489
|
+
}
|
|
3148
3490
|
dIdx++;
|
|
3491
|
+
mIdx++;
|
|
3149
3492
|
}
|
|
3150
3493
|
dIdx += dStride;
|
|
3494
|
+
mIdx += mStride;
|
|
3151
3495
|
}
|
|
3496
|
+
return didChange;
|
|
3152
3497
|
}
|
|
3153
3498
|
|
|
3154
|
-
// src/History/PixelMutator/
|
|
3499
|
+
// src/History/PixelMutator/mutatorApplyAlphaMask.ts
|
|
3155
3500
|
var defaults11 = {
|
|
3156
|
-
|
|
3501
|
+
applyAlphaMaskToPixelData
|
|
3157
3502
|
};
|
|
3158
|
-
var
|
|
3503
|
+
var mutatorApplyAlphaMask = ((writer, deps = defaults11) => {
|
|
3159
3504
|
const {
|
|
3160
|
-
|
|
3505
|
+
applyAlphaMaskToPixelData: applyAlphaMaskToPixelData2 = defaults11.applyAlphaMaskToPixelData
|
|
3161
3506
|
} = deps;
|
|
3162
3507
|
return {
|
|
3163
|
-
|
|
3508
|
+
applyAlphaMask(mask, opts = {}) {
|
|
3509
|
+
let target = writer.config.target;
|
|
3164
3510
|
const {
|
|
3165
3511
|
x = 0,
|
|
3166
3512
|
y = 0,
|
|
3167
|
-
w =
|
|
3168
|
-
h =
|
|
3513
|
+
w = target.width,
|
|
3514
|
+
h = target.height
|
|
3169
3515
|
} = opts;
|
|
3170
|
-
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3171
|
-
|
|
3516
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3517
|
+
return didChange(applyAlphaMaskToPixelData2(target, mask, opts));
|
|
3172
3518
|
}
|
|
3173
3519
|
};
|
|
3174
3520
|
});
|
|
3175
3521
|
|
|
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 = {}) {
|
|
3522
|
+
// src/PixelData/applyBinaryMaskToPixelData.ts
|
|
3523
|
+
function applyBinaryMaskToPixelData(dst, mask, opts = {}) {
|
|
3200
3524
|
const {
|
|
3201
3525
|
x: targetX = 0,
|
|
3202
3526
|
y: targetY = 0,
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
w: width = src.width,
|
|
3206
|
-
h: height = src.height,
|
|
3527
|
+
w: width = dst.width,
|
|
3528
|
+
h: height = dst.height,
|
|
3207
3529
|
alpha: globalAlpha = 255,
|
|
3208
|
-
|
|
3530
|
+
mx = 0,
|
|
3531
|
+
my = 0,
|
|
3532
|
+
invertMask = false
|
|
3209
3533
|
} = opts;
|
|
3210
|
-
if (globalAlpha === 0) return;
|
|
3534
|
+
if (globalAlpha === 0) return false;
|
|
3211
3535
|
let x = targetX;
|
|
3212
3536
|
let y = targetY;
|
|
3213
|
-
let sx = sourceX;
|
|
3214
|
-
let sy = sourceY;
|
|
3215
3537
|
let w = width;
|
|
3216
3538
|
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
3539
|
if (x < 0) {
|
|
3230
|
-
sx -= x;
|
|
3231
3540
|
w += x;
|
|
3232
3541
|
x = 0;
|
|
3233
3542
|
}
|
|
3234
3543
|
if (y < 0) {
|
|
3235
|
-
sy -= y;
|
|
3236
3544
|
h += y;
|
|
3237
3545
|
y = 0;
|
|
3238
3546
|
}
|
|
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;
|
|
3547
|
+
w = Math.min(w, dst.width - x);
|
|
3548
|
+
h = Math.min(h, dst.height - y);
|
|
3549
|
+
if (w <= 0 || h <= 0) return false;
|
|
3550
|
+
const mPitch = mask.w;
|
|
3551
|
+
if (mPitch <= 0) return false;
|
|
3552
|
+
const startX = mx + (x - targetX);
|
|
3553
|
+
const startY = my + (y - targetY);
|
|
3554
|
+
const sX0 = Math.max(0, startX);
|
|
3555
|
+
const sY0 = Math.max(0, startY);
|
|
3556
|
+
const sX1 = Math.min(mPitch, startX + w);
|
|
3557
|
+
const sY1 = Math.min(mask.h, startY + h);
|
|
3558
|
+
const finalW = sX1 - sX0;
|
|
3559
|
+
const finalH = sY1 - sY0;
|
|
3560
|
+
if (finalW <= 0 || finalH <= 0) {
|
|
3561
|
+
return false;
|
|
3562
|
+
}
|
|
3563
|
+
const xShift = sX0 - startX;
|
|
3564
|
+
const yShift = sY0 - startY;
|
|
3723
3565
|
const dst32 = dst.data32;
|
|
3724
3566
|
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] =
|
|
3567
|
+
const dStride = dw - finalW;
|
|
3568
|
+
const mStride = mPitch - finalW;
|
|
3569
|
+
const maskData = mask.data;
|
|
3570
|
+
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
3571
|
+
let mIdx = sY0 * mPitch + sX0;
|
|
3572
|
+
let didChange = false;
|
|
3573
|
+
for (let iy = 0; iy < finalH; iy++) {
|
|
3574
|
+
for (let ix = 0; ix < finalW; ix++) {
|
|
3575
|
+
const mVal = maskData[mIdx];
|
|
3576
|
+
const isMaskedOut = invertMask ? mVal !== 0 : mVal === 0;
|
|
3577
|
+
if (isMaskedOut) {
|
|
3578
|
+
const current = dst32[dIdx];
|
|
3579
|
+
const next = (current & 16777215) >>> 0;
|
|
3580
|
+
if (current !== next) {
|
|
3581
|
+
dst32[dIdx] = next;
|
|
3582
|
+
didChange = true;
|
|
3583
|
+
}
|
|
3584
|
+
} else if (globalAlpha !== 255) {
|
|
3585
|
+
const d = dst32[dIdx];
|
|
3586
|
+
const da = d >>> 24;
|
|
3587
|
+
if (da !== 0) {
|
|
3588
|
+
const finalAlpha = da === 255 ? globalAlpha : da * globalAlpha + 128 >> 8;
|
|
3589
|
+
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
3590
|
+
if (d !== next) {
|
|
3591
|
+
dst32[dIdx] = next;
|
|
3592
|
+
didChange = true;
|
|
3593
|
+
}
|
|
3740
3594
|
}
|
|
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
3595
|
}
|
|
3753
|
-
dIdx
|
|
3596
|
+
dIdx++;
|
|
3597
|
+
mIdx++;
|
|
3754
3598
|
}
|
|
3599
|
+
dIdx += dStride;
|
|
3600
|
+
mIdx += mStride;
|
|
3755
3601
|
}
|
|
3602
|
+
return didChange;
|
|
3756
3603
|
}
|
|
3757
3604
|
|
|
3758
|
-
// src/History/PixelMutator/
|
|
3759
|
-
var
|
|
3760
|
-
|
|
3605
|
+
// src/History/PixelMutator/mutatorApplyBinaryMask.ts
|
|
3606
|
+
var defaults12 = {
|
|
3607
|
+
applyBinaryMaskToPixelData
|
|
3761
3608
|
};
|
|
3762
|
-
var
|
|
3609
|
+
var mutatorApplyBinaryMask = ((writer, deps = defaults12) => {
|
|
3763
3610
|
const {
|
|
3764
|
-
|
|
3611
|
+
applyBinaryMaskToPixelData: applyBinaryMaskToPixelData2 = defaults12.applyBinaryMaskToPixelData
|
|
3765
3612
|
} = deps;
|
|
3766
3613
|
return {
|
|
3767
|
-
|
|
3614
|
+
applyBinaryMask(mask, opts = {}) {
|
|
3615
|
+
let target = writer.config.target;
|
|
3768
3616
|
const {
|
|
3769
3617
|
x = 0,
|
|
3770
3618
|
y = 0,
|
|
3771
|
-
w =
|
|
3772
|
-
h =
|
|
3619
|
+
w = target.width,
|
|
3620
|
+
h = target.height
|
|
3773
3621
|
} = opts;
|
|
3774
|
-
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3775
|
-
|
|
3622
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3623
|
+
return didChange(applyBinaryMaskToPixelData2(target, mask, opts));
|
|
3776
3624
|
}
|
|
3777
3625
|
};
|
|
3778
3626
|
});
|
|
3779
3627
|
|
|
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
3628
|
// src/ImageData/copyImageData.ts
|
|
3850
3629
|
function copyImageData({
|
|
3851
3630
|
data,
|
|
@@ -3967,44 +3746,14 @@ function resampleImageData(source, factor) {
|
|
|
3967
3746
|
return new ImageData(uint8ClampedArray, width, height);
|
|
3968
3747
|
}
|
|
3969
3748
|
|
|
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
3749
|
// src/ImageData/ReusableImageData.ts
|
|
4000
3750
|
function makeReusableImageData() {
|
|
4001
3751
|
let imageData = null;
|
|
4002
3752
|
return function getReusableImageData(width, height) {
|
|
4003
|
-
|
|
4004
|
-
const widthMatches = hasInstance && imageData.width === width;
|
|
4005
|
-
const heightMatches = hasInstance && imageData.height === height;
|
|
4006
|
-
if (!widthMatches || !heightMatches) {
|
|
3753
|
+
if (imageData === null || imageData.width !== width || imageData.height !== height) {
|
|
4007
3754
|
imageData = new ImageData(width, height);
|
|
3755
|
+
} else {
|
|
3756
|
+
imageData.data.fill(0);
|
|
4008
3757
|
}
|
|
4009
3758
|
return imageData;
|
|
4010
3759
|
};
|
|
@@ -4411,62 +4160,6 @@ function makeBinaryMask(w, h, data) {
|
|
|
4411
4160
|
};
|
|
4412
4161
|
}
|
|
4413
4162
|
|
|
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
4163
|
// src/Mask/applyBinaryMaskToAlphaMask.ts
|
|
4471
4164
|
function applyBinaryMaskToAlphaMask(alphaMaskDst, binaryMaskSrc, opts = {}) {
|
|
4472
4165
|
const {
|
|
@@ -4737,57 +4430,6 @@ function setMaskData(mask, width, height, data) {
|
|
|
4737
4430
|
mask.data = data;
|
|
4738
4431
|
}
|
|
4739
4432
|
|
|
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
4433
|
// src/Rect/getRectsBounds.ts
|
|
4792
4434
|
function getRectsBounds(rects) {
|
|
4793
4435
|
if (rects.length === 1) return {
|
|
@@ -4895,13 +4537,64 @@ function mergeBinaryMaskRects(current, adding) {
|
|
|
4895
4537
|
}
|
|
4896
4538
|
if (!merged) next.push(r);
|
|
4897
4539
|
}
|
|
4898
|
-
rects.splice(0, rects.length, ...next);
|
|
4540
|
+
rects.splice(0, rects.length, ...next);
|
|
4541
|
+
}
|
|
4542
|
+
return rects;
|
|
4543
|
+
}
|
|
4544
|
+
|
|
4545
|
+
// src/MaskRect/subtractBinaryMaskRects.ts
|
|
4546
|
+
function subtractBinaryMaskRects(current, subtracting) {
|
|
4547
|
+
let result = [...current];
|
|
4548
|
+
for (const sub of subtracting) {
|
|
4549
|
+
const next = [];
|
|
4550
|
+
for (const r of result) {
|
|
4551
|
+
const ix = Math.max(r.x, sub.x);
|
|
4552
|
+
const iy = Math.max(r.y, sub.y);
|
|
4553
|
+
const ix2 = Math.min(r.x + r.w, sub.x + sub.w);
|
|
4554
|
+
const iy2 = Math.min(r.y + r.h, sub.y + sub.h);
|
|
4555
|
+
if (ix >= ix2 || iy >= iy2) {
|
|
4556
|
+
next.push(r);
|
|
4557
|
+
continue;
|
|
4558
|
+
}
|
|
4559
|
+
if (r.y < iy) pushPiece(next, r, r.x, r.y, r.w, iy - r.y);
|
|
4560
|
+
if (iy2 < r.y + r.h) pushPiece(next, r, r.x, iy2, r.w, r.y + r.h - iy2);
|
|
4561
|
+
if (r.x < ix) pushPiece(next, r, r.x, iy, ix - r.x, iy2 - iy);
|
|
4562
|
+
if (ix2 < r.x + r.w) pushPiece(next, r, ix2, iy, r.x + r.w - ix2, iy2 - iy);
|
|
4563
|
+
}
|
|
4564
|
+
result = next;
|
|
4899
4565
|
}
|
|
4900
|
-
return
|
|
4566
|
+
return result;
|
|
4567
|
+
}
|
|
4568
|
+
function pushPiece(dest, r, x, y, w, h) {
|
|
4569
|
+
if (r.data === null || r.data === void 0) {
|
|
4570
|
+
dest.push({
|
|
4571
|
+
x,
|
|
4572
|
+
y,
|
|
4573
|
+
w,
|
|
4574
|
+
h,
|
|
4575
|
+
data: null,
|
|
4576
|
+
type: null
|
|
4577
|
+
});
|
|
4578
|
+
return;
|
|
4579
|
+
}
|
|
4580
|
+
const lx = x - r.x;
|
|
4581
|
+
const ly = y - r.y;
|
|
4582
|
+
const data = new Uint8Array(w * h);
|
|
4583
|
+
for (let row = 0; row < h; row++) {
|
|
4584
|
+
data.set(r.data.subarray((ly + row) * r.w + lx, (ly + row) * r.w + lx + w), row * w);
|
|
4585
|
+
}
|
|
4586
|
+
dest.push({
|
|
4587
|
+
x,
|
|
4588
|
+
y,
|
|
4589
|
+
w,
|
|
4590
|
+
h,
|
|
4591
|
+
data,
|
|
4592
|
+
type: 1 /* BINARY */
|
|
4593
|
+
});
|
|
4901
4594
|
}
|
|
4902
4595
|
|
|
4903
4596
|
// src/PixelData/PixelData.ts
|
|
4904
|
-
var PixelData = class
|
|
4597
|
+
var PixelData = class {
|
|
4905
4598
|
data32;
|
|
4906
4599
|
imageData;
|
|
4907
4600
|
width;
|
|
@@ -4919,30 +4612,191 @@ var PixelData = class _PixelData {
|
|
|
4919
4612
|
this.width = imageData.width;
|
|
4920
4613
|
this.height = imageData.height;
|
|
4921
4614
|
}
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
|
|
4615
|
+
};
|
|
4616
|
+
|
|
4617
|
+
// src/PixelData/blendColorPixelDataAlphaMask.ts
|
|
4618
|
+
function blendColorPixelDataAlphaMask(dst, color, mask, opts = {}) {
|
|
4619
|
+
const targetX = opts.x ?? 0;
|
|
4620
|
+
const targetY = opts.y ?? 0;
|
|
4621
|
+
const w = opts.w ?? mask.w;
|
|
4622
|
+
const h = opts.h ?? mask.h;
|
|
4623
|
+
const globalAlpha = opts.alpha ?? 255;
|
|
4624
|
+
const blendFn = opts.blendFn ?? sourceOverPerfect;
|
|
4625
|
+
const mx = opts.mx ?? 0;
|
|
4626
|
+
const my = opts.my ?? 0;
|
|
4627
|
+
const invertMask = opts.invertMask ?? false;
|
|
4628
|
+
if (globalAlpha === 0) return false;
|
|
4629
|
+
const baseSrcAlpha = color >>> 24;
|
|
4630
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
4631
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
4632
|
+
let x = targetX;
|
|
4633
|
+
let y = targetY;
|
|
4634
|
+
let actualW = w;
|
|
4635
|
+
let actualH = h;
|
|
4636
|
+
if (x < 0) {
|
|
4637
|
+
actualW += x;
|
|
4638
|
+
x = 0;
|
|
4639
|
+
}
|
|
4640
|
+
if (y < 0) {
|
|
4641
|
+
actualH += y;
|
|
4642
|
+
y = 0;
|
|
4643
|
+
}
|
|
4644
|
+
actualW = Math.min(actualW, dst.width - x);
|
|
4645
|
+
actualH = Math.min(actualH, dst.height - y);
|
|
4646
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
4647
|
+
const dx = x - targetX | 0;
|
|
4648
|
+
const dy = y - targetY | 0;
|
|
4649
|
+
const dst32 = dst.data32;
|
|
4650
|
+
const dw = dst.width;
|
|
4651
|
+
const mPitch = mask.w;
|
|
4652
|
+
const maskData = mask.data;
|
|
4653
|
+
let dIdx = y * dw + x | 0;
|
|
4654
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
4655
|
+
const dStride = dw - actualW | 0;
|
|
4656
|
+
const mStride = mPitch - actualW | 0;
|
|
4657
|
+
const isOpaque = globalAlpha === 255;
|
|
4658
|
+
const colorRGB = color & 16777215;
|
|
4659
|
+
let didChange = false;
|
|
4660
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
4661
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
4662
|
+
const mVal = maskData[mIdx];
|
|
4663
|
+
const effM = invertMask ? 255 - mVal : mVal;
|
|
4664
|
+
if (effM === 0) {
|
|
4665
|
+
dIdx++;
|
|
4666
|
+
mIdx++;
|
|
4667
|
+
continue;
|
|
4668
|
+
}
|
|
4669
|
+
let weight = globalAlpha;
|
|
4670
|
+
if (isOpaque) {
|
|
4671
|
+
weight = effM;
|
|
4672
|
+
} else if (effM !== 255) {
|
|
4673
|
+
weight = effM * globalAlpha + 128 >> 8;
|
|
4674
|
+
}
|
|
4675
|
+
if (weight === 0) {
|
|
4676
|
+
dIdx++;
|
|
4677
|
+
mIdx++;
|
|
4678
|
+
continue;
|
|
4679
|
+
}
|
|
4680
|
+
let finalCol = color;
|
|
4681
|
+
if (weight < 255) {
|
|
4682
|
+
const a = baseSrcAlpha * weight + 128 >> 8;
|
|
4683
|
+
if (a === 0 && !isOverwrite) {
|
|
4684
|
+
dIdx++;
|
|
4685
|
+
mIdx++;
|
|
4686
|
+
continue;
|
|
4687
|
+
}
|
|
4688
|
+
finalCol = (colorRGB | a << 24) >>> 0;
|
|
4689
|
+
}
|
|
4690
|
+
const current = dst32[dIdx];
|
|
4691
|
+
const next = blendFn(finalCol, current);
|
|
4692
|
+
if (current !== next) {
|
|
4693
|
+
dst32[dIdx] = next;
|
|
4694
|
+
didChange = true;
|
|
4695
|
+
}
|
|
4696
|
+
dIdx++;
|
|
4697
|
+
mIdx++;
|
|
4698
|
+
}
|
|
4699
|
+
dIdx += dStride;
|
|
4700
|
+
mIdx += mStride;
|
|
4701
|
+
}
|
|
4702
|
+
return didChange;
|
|
4703
|
+
}
|
|
4704
|
+
|
|
4705
|
+
// src/PixelData/blendColorPixelDataBinaryMask.ts
|
|
4706
|
+
function blendColorPixelDataBinaryMask(dst, color, mask, opts = {}) {
|
|
4707
|
+
const targetX = opts.x ?? 0;
|
|
4708
|
+
const targetY = opts.y ?? 0;
|
|
4709
|
+
let w = opts.w ?? mask.w;
|
|
4710
|
+
let h = opts.h ?? mask.h;
|
|
4711
|
+
const globalAlpha = opts.alpha ?? 255;
|
|
4712
|
+
const blendFn = opts.blendFn ?? sourceOverPerfect;
|
|
4713
|
+
const mx = opts.mx ?? 0;
|
|
4714
|
+
const my = opts.my ?? 0;
|
|
4715
|
+
const invertMask = opts.invertMask ?? false;
|
|
4716
|
+
if (globalAlpha === 0) return false;
|
|
4717
|
+
const baseSrcAlpha = color >>> 24;
|
|
4718
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
4719
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
4720
|
+
let x = targetX;
|
|
4721
|
+
let y = targetY;
|
|
4722
|
+
if (x < 0) {
|
|
4723
|
+
w += x;
|
|
4724
|
+
x = 0;
|
|
4725
|
+
}
|
|
4726
|
+
if (y < 0) {
|
|
4727
|
+
h += y;
|
|
4728
|
+
y = 0;
|
|
4729
|
+
}
|
|
4730
|
+
const actualW = Math.min(w, dst.width - x);
|
|
4731
|
+
const actualH = Math.min(h, dst.height - y);
|
|
4732
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
4733
|
+
let baseColorWithGlobalAlpha = color;
|
|
4734
|
+
if (globalAlpha < 255) {
|
|
4735
|
+
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
4736
|
+
if (a === 0 && !isOverwrite) return false;
|
|
4737
|
+
baseColorWithGlobalAlpha = (color & 16777215 | a << 24) >>> 0;
|
|
4738
|
+
}
|
|
4739
|
+
const dx = x - targetX | 0;
|
|
4740
|
+
const dy = y - targetY | 0;
|
|
4741
|
+
const dst32 = dst.data32;
|
|
4742
|
+
const dw = dst.width;
|
|
4743
|
+
const mPitch = mask.w;
|
|
4744
|
+
const maskData = mask.data;
|
|
4745
|
+
let dIdx = y * dw + x | 0;
|
|
4746
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
4747
|
+
const dStride = dw - actualW | 0;
|
|
4748
|
+
const mStride = mPitch - actualW | 0;
|
|
4749
|
+
const skipVal = invertMask ? 1 : 0;
|
|
4750
|
+
let didChange = false;
|
|
4751
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
4752
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
4753
|
+
if (maskData[mIdx] === skipVal) {
|
|
4754
|
+
dIdx++;
|
|
4755
|
+
mIdx++;
|
|
4756
|
+
continue;
|
|
4757
|
+
}
|
|
4758
|
+
const current = dst32[dIdx];
|
|
4759
|
+
const next = blendFn(baseColorWithGlobalAlpha, current);
|
|
4760
|
+
if (current !== next) {
|
|
4761
|
+
dst32[dIdx] = next;
|
|
4762
|
+
didChange = true;
|
|
4763
|
+
}
|
|
4764
|
+
dIdx++;
|
|
4765
|
+
mIdx++;
|
|
4938
4766
|
}
|
|
4939
|
-
|
|
4767
|
+
dIdx += dStride;
|
|
4768
|
+
mIdx += mStride;
|
|
4940
4769
|
}
|
|
4770
|
+
return didChange;
|
|
4771
|
+
}
|
|
4772
|
+
|
|
4773
|
+
// src/PixelData/blendPixelDataPaintBuffer.ts
|
|
4774
|
+
var SCRATCH_OPTS = {
|
|
4775
|
+
x: 0,
|
|
4776
|
+
y: 0,
|
|
4777
|
+
alpha: 255,
|
|
4778
|
+
blendFn: void 0
|
|
4941
4779
|
};
|
|
4780
|
+
function blendPixelDataPaintBuffer(paintBuffer, target, alpha = 255, blendFn, blendPixelDataFn = blendPixelData) {
|
|
4781
|
+
const tileShift = paintBuffer.config.tileShift;
|
|
4782
|
+
const lookup = paintBuffer.lookup;
|
|
4783
|
+
for (let i = 0; i < lookup.length; i++) {
|
|
4784
|
+
const tile = lookup[i];
|
|
4785
|
+
if (tile) {
|
|
4786
|
+
const x = tile.tx << tileShift;
|
|
4787
|
+
const y = tile.ty << tileShift;
|
|
4788
|
+
SCRATCH_OPTS.x = x;
|
|
4789
|
+
SCRATCH_OPTS.y = y;
|
|
4790
|
+
SCRATCH_OPTS.alpha = alpha;
|
|
4791
|
+
SCRATCH_OPTS.blendFn = blendFn;
|
|
4792
|
+
blendPixelDataFn(target, tile, SCRATCH_OPTS);
|
|
4793
|
+
}
|
|
4794
|
+
}
|
|
4795
|
+
}
|
|
4942
4796
|
|
|
4943
4797
|
// src/PixelData/clearPixelData.ts
|
|
4944
4798
|
function clearPixelData(dst, rect) {
|
|
4945
|
-
|
|
4799
|
+
fillPixelDataFast(dst, 0, rect);
|
|
4946
4800
|
}
|
|
4947
4801
|
|
|
4948
4802
|
// src/PixelData/extractPixelDataBuffer.ts
|
|
@@ -5161,6 +5015,165 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
5161
5015
|
dstData.set(data.subarray(srcStart, srcStart + copyW), dstStart);
|
|
5162
5016
|
}
|
|
5163
5017
|
}
|
|
5018
|
+
|
|
5019
|
+
// src/PixelData/writePaintBufferToPixelData.ts
|
|
5020
|
+
function writePaintBufferToPixelData(target, paintBuffer, writePixelDataBufferFn = writePixelDataBuffer) {
|
|
5021
|
+
const tileShift = paintBuffer.config.tileShift;
|
|
5022
|
+
const lookup = paintBuffer.lookup;
|
|
5023
|
+
for (let i = 0; i < lookup.length; i++) {
|
|
5024
|
+
const tile = lookup[i];
|
|
5025
|
+
if (tile) {
|
|
5026
|
+
const dx = tile.tx << tileShift;
|
|
5027
|
+
const dy = tile.ty << tileShift;
|
|
5028
|
+
writePixelDataBufferFn(target, tile.data32, dx, dy, tile.width, tile.height);
|
|
5029
|
+
}
|
|
5030
|
+
}
|
|
5031
|
+
}
|
|
5032
|
+
|
|
5033
|
+
// src/Paint/makeCirclePaintAlphaMask.ts
|
|
5034
|
+
function makeCirclePaintAlphaMask(size, fallOff = (d) => d) {
|
|
5035
|
+
const area = size * size;
|
|
5036
|
+
const data = new Uint8Array(area);
|
|
5037
|
+
const radius = size / 2;
|
|
5038
|
+
const invR = 1 / radius;
|
|
5039
|
+
const centerOffset = -Math.ceil(radius - 0.5);
|
|
5040
|
+
for (let y = 0; y < size; y++) {
|
|
5041
|
+
const rowOffset = y * size;
|
|
5042
|
+
const dy = y - radius + 0.5;
|
|
5043
|
+
const dy2 = dy * dy;
|
|
5044
|
+
for (let x = 0; x < size; x++) {
|
|
5045
|
+
const dx = x - radius + 0.5;
|
|
5046
|
+
const distSqr = dx * dx + dy2;
|
|
5047
|
+
if (distSqr <= radius * radius) {
|
|
5048
|
+
const dist = Math.sqrt(distSqr) * invR;
|
|
5049
|
+
const strength = fallOff(1 - dist);
|
|
5050
|
+
if (strength > 0) {
|
|
5051
|
+
const intensity = strength * 255 | 0;
|
|
5052
|
+
data[rowOffset + x] = Math.max(0, Math.min(255, intensity));
|
|
5053
|
+
}
|
|
5054
|
+
}
|
|
5055
|
+
}
|
|
5056
|
+
}
|
|
5057
|
+
return {
|
|
5058
|
+
type: 0 /* ALPHA */,
|
|
5059
|
+
data,
|
|
5060
|
+
w: size,
|
|
5061
|
+
h: size,
|
|
5062
|
+
centerOffsetX: centerOffset,
|
|
5063
|
+
centerOffsetY: centerOffset
|
|
5064
|
+
};
|
|
5065
|
+
}
|
|
5066
|
+
|
|
5067
|
+
// src/Paint/makeCirclePaintBinaryMask.ts
|
|
5068
|
+
function makeCirclePaintBinaryMask(size) {
|
|
5069
|
+
const area = size * size;
|
|
5070
|
+
const data = new Uint8Array(area);
|
|
5071
|
+
const radius = size / 2;
|
|
5072
|
+
const centerOffset = -Math.ceil(radius - 0.5);
|
|
5073
|
+
for (let y = 0; y < size; y++) {
|
|
5074
|
+
for (let x = 0; x < size; x++) {
|
|
5075
|
+
const dx = x - radius + 0.5;
|
|
5076
|
+
const dy = y - radius + 0.5;
|
|
5077
|
+
const distSqr = dx * dx + dy * dy;
|
|
5078
|
+
if (distSqr <= radius * radius) {
|
|
5079
|
+
data[y * size + x] = 1;
|
|
5080
|
+
}
|
|
5081
|
+
}
|
|
5082
|
+
}
|
|
5083
|
+
return {
|
|
5084
|
+
type: 1 /* BINARY */,
|
|
5085
|
+
data,
|
|
5086
|
+
w: size,
|
|
5087
|
+
h: size,
|
|
5088
|
+
centerOffsetX: centerOffset,
|
|
5089
|
+
centerOffsetY: centerOffset
|
|
5090
|
+
};
|
|
5091
|
+
}
|
|
5092
|
+
|
|
5093
|
+
// src/Internal/helpers.ts
|
|
5094
|
+
var macro_halfAndFloor = (value) => value >> 1;
|
|
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: -macro_halfAndFloor(mask.w),
|
|
5104
|
+
centerOffsetY: -macro_halfAndFloor(mask.h)
|
|
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: -macro_halfAndFloor(mask.w),
|
|
5114
|
+
centerOffsetY: -macro_halfAndFloor(mask.h)
|
|
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.prod.cjs.map
|