pixel-data-js 0.24.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.dev.cjs +1431 -1845
- package/dist/index.dev.cjs.map +1 -1
- package/dist/index.dev.js +1297 -1702
- package/dist/index.dev.js.map +1 -1
- package/dist/index.prod.cjs +1305 -1719
- package/dist/index.prod.cjs.map +1 -1
- package/dist/index.prod.d.ts +220 -328
- package/dist/index.prod.js +1423 -1828
- package/dist/index.prod.js.map +1 -1
- package/package.json +1 -1
- package/src/Algorithm/floodFillSelection.ts +2 -2
- package/src/Canvas/canvas-blend-modes.ts +28 -0
- package/src/History/PixelAccumulator.ts +52 -29
- package/src/History/PixelEngineConfig.ts +7 -9
- package/src/History/PixelMutator/mutatorBlendPixelData.ts +2 -2
- package/src/History/PixelMutator/mutatorBlendPixelDataAlphaMask.ts +2 -2
- package/src/History/PixelMutator/mutatorBlendPixelDataBinaryMask.ts +2 -2
- package/src/History/PixelMutator.ts +0 -20
- package/src/History/PixelPatchTiles.ts +2 -2
- package/src/History/PixelWriter.ts +132 -9
- package/src/Internal/helpers.ts +2 -0
- package/src/Paint/PaintBuffer.ts +269 -0
- package/src/{PixelTile/PaintBufferRenderer.ts → Paint/PaintBufferCanvasRenderer.ts} +13 -5
- package/src/Paint/makeCirclePaintAlphaMask.ts +41 -0
- package/src/{Mask/CircleBinaryMask.ts → Paint/makeCirclePaintBinaryMask.ts} +5 -6
- package/src/Paint/makePaintMask.ts +28 -0
- package/src/Paint/makeRectFalloffPaintAlphaMask.ts +47 -0
- package/src/PixelData/PixelBuffer32.ts +2 -2
- package/src/PixelData/PixelData.ts +1 -1
- package/src/PixelData/applyAlphaMaskToPixelData.ts +2 -2
- package/src/PixelData/applyBinaryMaskToPixelData.ts +2 -2
- package/src/PixelData/blendColorPixelData.ts +2 -2
- package/src/PixelData/blendColorPixelDataAlphaMask.ts +3 -3
- package/src/PixelData/blendColorPixelDataBinaryMask.ts +3 -3
- package/src/PixelData/blendPixel.ts +2 -2
- package/src/PixelData/blendPixelData.ts +3 -3
- package/src/PixelData/blendPixelDataAlphaMask.ts +3 -3
- package/src/PixelData/blendPixelDataBinaryMask.ts +3 -3
- package/src/PixelData/blendPixelDataPaintBuffer.ts +3 -3
- package/src/PixelData/clearPixelData.ts +2 -2
- package/src/PixelData/extractPixelData.ts +4 -4
- package/src/PixelData/extractPixelDataBuffer.ts +4 -4
- package/src/PixelData/fillPixelData.ts +5 -5
- package/src/PixelData/fillPixelDataBinaryMask.ts +3 -3
- package/src/PixelData/fillPixelDataFast.ts +5 -5
- package/src/PixelData/invertPixelData.ts +2 -2
- package/src/PixelData/pixelDataToAlphaMask.ts +2 -2
- package/src/PixelData/reflectPixelData.ts +3 -3
- package/src/PixelData/resamplePixelData.ts +2 -2
- package/src/PixelData/writePaintBufferToPixelData.ts +26 -0
- package/src/PixelData/writePixelDataBuffer.ts +5 -5
- package/src/Rect/trimMaskRectBounds.ts +121 -0
- package/src/Rect/trimRectBounds.ts +25 -116
- package/src/_types.ts +16 -15
- package/src/index.ts +9 -24
- package/src/History/PixelMutator/mutatorApplyCircleBrushStroke.ts +0 -182
- package/src/History/PixelMutator/mutatorApplyCirclePencil.ts +0 -59
- package/src/History/PixelMutator/mutatorApplyCirclePencilStroke.ts +0 -172
- package/src/History/PixelMutator/mutatorApplyRectBrush.ts +0 -64
- package/src/History/PixelMutator/mutatorApplyRectBrushStroke.ts +0 -184
- package/src/History/PixelMutator/mutatorApplyRectPencil.ts +0 -65
- package/src/History/PixelMutator/mutatorApplyRectPencilStroke.ts +0 -166
- package/src/History/PixelMutator/mutatorBlendColorCircleMask.ts +0 -71
- package/src/Mask/CircleAlphaMask.ts +0 -32
- package/src/PixelData/applyRectBrushToPixelData.ts +0 -98
- package/src/PixelData/blendColorPixelDataCircleMask.ts +0 -92
- package/src/PixelTile/PaintBuffer.ts +0 -122
- package/src/Rect/getCircleBrushOrPencilBounds.ts +0 -43
- package/src/Rect/getCircleBrushOrPencilStrokeBounds.ts +0 -24
- package/src/Rect/getRectBrushOrPencilBounds.ts +0 -38
- package/src/Rect/getRectBrushOrPencilStrokeBounds.ts +0 -26
package/dist/index.dev.cjs
CHANGED
|
@@ -41,13 +41,11 @@ __export(src_exports, {
|
|
|
41
41
|
applyBinaryMaskToAlphaMask: () => applyBinaryMaskToAlphaMask,
|
|
42
42
|
applyBinaryMaskToPixelData: () => applyBinaryMaskToPixelData,
|
|
43
43
|
applyPatchTiles: () => applyPatchTiles,
|
|
44
|
-
applyRectBrushToPixelData: () => applyRectBrushToPixelData,
|
|
45
44
|
base64DecodeArrayBuffer: () => base64DecodeArrayBuffer,
|
|
46
45
|
base64EncodeArrayBuffer: () => base64EncodeArrayBuffer,
|
|
47
46
|
blendColorPixelData: () => blendColorPixelData,
|
|
48
47
|
blendColorPixelDataAlphaMask: () => blendColorPixelDataAlphaMask,
|
|
49
48
|
blendColorPixelDataBinaryMask: () => blendColorPixelDataBinaryMask,
|
|
50
|
-
blendColorPixelDataCircleMask: () => blendColorPixelDataCircleMask,
|
|
51
49
|
blendPixel: () => blendPixel,
|
|
52
50
|
blendPixelData: () => blendPixelData,
|
|
53
51
|
blendPixelDataAlphaMask: () => blendPixelDataAlphaMask,
|
|
@@ -89,12 +87,8 @@ __export(src_exports, {
|
|
|
89
87
|
fillPixelDataFast: () => fillPixelDataFast,
|
|
90
88
|
floodFillSelection: () => floodFillSelection,
|
|
91
89
|
forEachLinePoint: () => forEachLinePoint,
|
|
92
|
-
getCircleBrushOrPencilBounds: () => getCircleBrushOrPencilBounds,
|
|
93
|
-
getCircleBrushOrPencilStrokeBounds: () => getCircleBrushOrPencilStrokeBounds,
|
|
94
90
|
getImageDataFromClipboard: () => getImageDataFromClipboard,
|
|
95
91
|
getIndexedImageColorCounts: () => getIndexedImageColorCounts,
|
|
96
|
-
getRectBrushOrPencilBounds: () => getRectBrushOrPencilBounds,
|
|
97
|
-
getRectBrushOrPencilStrokeBounds: () => getRectBrushOrPencilStrokeBounds,
|
|
98
92
|
getRectsBounds: () => getRectsBounds,
|
|
99
93
|
getSupportedPixelFormats: () => getSupportedPixelFormats,
|
|
100
94
|
hardLightFast: () => hardLightFast,
|
|
@@ -128,15 +122,18 @@ __export(src_exports, {
|
|
|
128
122
|
makeBinaryMask: () => makeBinaryMask,
|
|
129
123
|
makeBlendModeRegistry: () => makeBlendModeRegistry,
|
|
130
124
|
makeCanvasFrameRenderer: () => makeCanvasFrameRenderer,
|
|
131
|
-
|
|
132
|
-
|
|
125
|
+
makeCirclePaintAlphaMask: () => makeCirclePaintAlphaMask,
|
|
126
|
+
makeCirclePaintBinaryMask: () => makeCirclePaintBinaryMask,
|
|
133
127
|
makeFastBlendModeRegistry: () => makeFastBlendModeRegistry,
|
|
134
128
|
makeFullPixelMutator: () => makeFullPixelMutator,
|
|
135
129
|
makeHistoryAction: () => makeHistoryAction,
|
|
136
130
|
makeImageDataLike: () => makeImageDataLike,
|
|
137
|
-
|
|
131
|
+
makePaintAlphaMask: () => makePaintAlphaMask,
|
|
132
|
+
makePaintBinaryMask: () => makePaintBinaryMask,
|
|
133
|
+
makePaintBufferCanvasRenderer: () => makePaintBufferCanvasRenderer,
|
|
138
134
|
makePerfectBlendModeRegistry: () => makePerfectBlendModeRegistry,
|
|
139
135
|
makePixelCanvas: () => makePixelCanvas,
|
|
136
|
+
makeRectFalloffPaintAlphaMask: () => makeRectFalloffPaintAlphaMask,
|
|
140
137
|
makeReusableCanvas: () => makeReusableCanvas,
|
|
141
138
|
makeReusableImageData: () => makeReusableImageData,
|
|
142
139
|
makeReusableOffscreenCanvas: () => makeReusableOffscreenCanvas,
|
|
@@ -148,15 +145,7 @@ __export(src_exports, {
|
|
|
148
145
|
multiplyPerfect: () => multiplyPerfect,
|
|
149
146
|
mutatorApplyAlphaMask: () => mutatorApplyAlphaMask,
|
|
150
147
|
mutatorApplyBinaryMask: () => mutatorApplyBinaryMask,
|
|
151
|
-
mutatorApplyCircleBrushStroke: () => mutatorApplyCircleBrushStroke,
|
|
152
|
-
mutatorApplyCirclePencil: () => mutatorApplyCirclePencil,
|
|
153
|
-
mutatorApplyCirclePencilStroke: () => mutatorApplyCirclePencilStroke,
|
|
154
|
-
mutatorApplyRectBrush: () => mutatorApplyRectBrush,
|
|
155
|
-
mutatorApplyRectBrushStroke: () => mutatorApplyRectBrushStroke,
|
|
156
|
-
mutatorApplyRectPencil: () => mutatorApplyRectPencil,
|
|
157
|
-
mutatorApplyRectPencilStroke: () => mutatorApplyRectPencilStroke,
|
|
158
148
|
mutatorBlendColor: () => mutatorBlendColor,
|
|
159
|
-
mutatorBlendColorCircleMask: () => mutatorBlendColorCircleMask,
|
|
160
149
|
mutatorBlendPixel: () => mutatorBlendPixel,
|
|
161
150
|
mutatorBlendPixelData: () => mutatorBlendPixelData,
|
|
162
151
|
mutatorBlendPixelDataAlphaMask: () => mutatorBlendPixelDataAlphaMask,
|
|
@@ -196,6 +185,7 @@ __export(src_exports, {
|
|
|
196
185
|
subtractFast: () => subtractFast,
|
|
197
186
|
subtractPerfect: () => subtractPerfect,
|
|
198
187
|
toBlendModeIndexAndName: () => toBlendModeIndexAndName,
|
|
188
|
+
trimMaskRectBounds: () => trimMaskRectBounds,
|
|
199
189
|
trimRectBounds: () => trimRectBounds,
|
|
200
190
|
uInt32ArrayToImageData: () => uInt32ArrayToImageData,
|
|
201
191
|
uInt32ArrayToImageDataLike: () => uInt32ArrayToImageDataLike,
|
|
@@ -211,6 +201,7 @@ __export(src_exports, {
|
|
|
211
201
|
writeImageDataBuffer: () => writeImageDataBuffer,
|
|
212
202
|
writeImageDataToClipboard: () => writeImageDataToClipboard,
|
|
213
203
|
writeImgBlobToClipboard: () => writeImgBlobToClipboard,
|
|
204
|
+
writePaintBufferToPixelData: () => writePaintBufferToPixelData,
|
|
214
205
|
writePixelDataBuffer: () => writePixelDataBuffer
|
|
215
206
|
});
|
|
216
207
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -449,8 +440,8 @@ function extractMaskBuffer(maskBuffer, maskWidth, xOrRect, y, w, h) {
|
|
|
449
440
|
return out;
|
|
450
441
|
}
|
|
451
442
|
|
|
452
|
-
// src/Rect/
|
|
453
|
-
function
|
|
443
|
+
// src/Rect/trimMaskRectBounds.ts
|
|
444
|
+
function trimMaskRectBounds(target, bounds) {
|
|
454
445
|
const originalX = target.x;
|
|
455
446
|
const originalY = target.y;
|
|
456
447
|
const originalW = target.w;
|
|
@@ -638,7 +629,7 @@ function floodFillSelection(img, startX, startY, {
|
|
|
638
629
|
finalMask[my * sw + mx] = 1;
|
|
639
630
|
}
|
|
640
631
|
}
|
|
641
|
-
|
|
632
|
+
trimMaskRectBounds(selectionRect, {
|
|
642
633
|
x: 0,
|
|
643
634
|
y: 0,
|
|
644
635
|
w: width,
|
|
@@ -2028,11 +2019,11 @@ var PixelAccumulator = class {
|
|
|
2028
2019
|
* @param y pixel y coordinate
|
|
2029
2020
|
*/
|
|
2030
2021
|
storePixelBeforeState(x, y) {
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
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;
|
|
2036
2027
|
let tile = this.lookup[id];
|
|
2037
2028
|
let added = false;
|
|
2038
2029
|
if (!tile) {
|
|
@@ -2058,16 +2049,16 @@ var PixelAccumulator = class {
|
|
|
2058
2049
|
* @param h pixel height
|
|
2059
2050
|
*/
|
|
2060
2051
|
storeRegionBeforeState(x, y, w, h) {
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
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;
|
|
2068
2059
|
for (let ty = startY; ty <= endY; ty++) {
|
|
2069
2060
|
for (let tx = startX; tx <= endX; tx++) {
|
|
2070
|
-
|
|
2061
|
+
const id = ty * columns + tx;
|
|
2071
2062
|
let tile = this.lookup[id];
|
|
2072
2063
|
if (!tile) {
|
|
2073
2064
|
tile = this.tilePool.getTile(id, tx, ty);
|
|
@@ -2079,7 +2070,7 @@ var PixelAccumulator = class {
|
|
|
2079
2070
|
}
|
|
2080
2071
|
return (didChange) => {
|
|
2081
2072
|
if (!didChange) {
|
|
2082
|
-
|
|
2073
|
+
const length = this.beforeTiles.length;
|
|
2083
2074
|
for (let i = startIndex; i < length; i++) {
|
|
2084
2075
|
let t = this.beforeTiles[i];
|
|
2085
2076
|
if (t) {
|
|
@@ -2092,15 +2083,34 @@ var PixelAccumulator = class {
|
|
|
2092
2083
|
return didChange;
|
|
2093
2084
|
};
|
|
2094
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
|
+
};
|
|
2104
|
+
}
|
|
2095
2105
|
extractState(tile) {
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
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;
|
|
2104
2114
|
if (startX >= targetWidth || startX + TILE_SIZE <= 0 || startY >= targetHeight || startY + TILE_SIZE <= 0) {
|
|
2105
2115
|
dst.fill(0);
|
|
2106
2116
|
return;
|
|
@@ -2126,8 +2136,8 @@ var PixelAccumulator = class {
|
|
|
2126
2136
|
}
|
|
2127
2137
|
}
|
|
2128
2138
|
extractPatch() {
|
|
2129
|
-
|
|
2130
|
-
|
|
2139
|
+
const afterTiles = [];
|
|
2140
|
+
const length = this.beforeTiles.length;
|
|
2131
2141
|
for (let i = 0; i < length; i++) {
|
|
2132
2142
|
let beforeTile = this.beforeTiles[i];
|
|
2133
2143
|
if (beforeTile) {
|
|
@@ -2136,7 +2146,7 @@ var PixelAccumulator = class {
|
|
|
2136
2146
|
afterTiles.push(afterTile);
|
|
2137
2147
|
}
|
|
2138
2148
|
}
|
|
2139
|
-
|
|
2149
|
+
const beforeTiles = this.beforeTiles;
|
|
2140
2150
|
this.beforeTiles = [];
|
|
2141
2151
|
this.lookup.length = 0;
|
|
2142
2152
|
return {
|
|
@@ -2144,10 +2154,10 @@ var PixelAccumulator = class {
|
|
|
2144
2154
|
afterTiles
|
|
2145
2155
|
};
|
|
2146
2156
|
}
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2157
|
+
rollbackAfterError() {
|
|
2158
|
+
const target = this.config.target;
|
|
2159
|
+
const tileSize = this.config.tileSize;
|
|
2160
|
+
const length = this.beforeTiles.length;
|
|
2151
2161
|
applyPatchTiles(target, this.beforeTiles, tileSize);
|
|
2152
2162
|
for (let i = 0; i < length; i++) {
|
|
2153
2163
|
let tile = this.beforeTiles[i];
|
|
@@ -2171,6 +2181,7 @@ var PixelEngineConfig = class {
|
|
|
2171
2181
|
tileArea;
|
|
2172
2182
|
target;
|
|
2173
2183
|
targetColumns = 0;
|
|
2184
|
+
targetRows = 0;
|
|
2174
2185
|
constructor(tileSize, target) {
|
|
2175
2186
|
if ((tileSize & tileSize - 1) !== 0) {
|
|
2176
2187
|
throw new Error("tileSize must be a power of 2");
|
|
@@ -2179,28 +2190,26 @@ var PixelEngineConfig = class {
|
|
|
2179
2190
|
this.tileShift = 31 - Math.clz32(tileSize);
|
|
2180
2191
|
this.tileMask = tileSize - 1;
|
|
2181
2192
|
this.tileArea = tileSize * tileSize;
|
|
2182
|
-
this.setTarget(target);
|
|
2183
|
-
}
|
|
2184
|
-
setTarget(target) {
|
|
2185
|
-
;
|
|
2186
2193
|
this.target = target;
|
|
2187
2194
|
this.targetColumns = target.width + this.tileMask >> this.tileShift;
|
|
2195
|
+
this.targetRows = target.height + this.tileMask >> this.tileShift;
|
|
2188
2196
|
}
|
|
2189
2197
|
};
|
|
2190
2198
|
|
|
2191
|
-
// src/PixelData/
|
|
2192
|
-
function
|
|
2199
|
+
// src/PixelData/blendColorPixelData.ts
|
|
2200
|
+
function blendColorPixelData(dst, color, opts = {}) {
|
|
2193
2201
|
const {
|
|
2194
2202
|
x: targetX = 0,
|
|
2195
2203
|
y: targetY = 0,
|
|
2196
2204
|
w: width = dst.width,
|
|
2197
2205
|
h: height = dst.height,
|
|
2198
2206
|
alpha: globalAlpha = 255,
|
|
2199
|
-
|
|
2200
|
-
my = 0,
|
|
2201
|
-
invertMask = false
|
|
2207
|
+
blendFn = sourceOverPerfect
|
|
2202
2208
|
} = opts;
|
|
2203
2209
|
if (globalAlpha === 0) return false;
|
|
2210
|
+
const baseSrcAlpha = color >>> 24;
|
|
2211
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
2212
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
2204
2213
|
let x = targetX;
|
|
2205
2214
|
let y = targetY;
|
|
2206
2215
|
let w = width;
|
|
@@ -2213,82 +2222,46 @@ function applyAlphaMaskToPixelData(dst, mask, opts = {}) {
|
|
|
2213
2222
|
h += y;
|
|
2214
2223
|
y = 0;
|
|
2215
2224
|
}
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
if (
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
const sY0 = Math.max(0, startY);
|
|
2226
|
-
const sX1 = Math.min(mPitch, startX + w);
|
|
2227
|
-
const sY1 = Math.min(mask.h, startY + h);
|
|
2228
|
-
const finalW = sX1 - sX0;
|
|
2229
|
-
const finalH = sY1 - sY0;
|
|
2230
|
-
if (finalW <= 0) return false;
|
|
2231
|
-
if (finalH <= 0) return false;
|
|
2232
|
-
const xShift = sX0 - startX;
|
|
2233
|
-
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
|
+
}
|
|
2234
2234
|
const dst32 = dst.data32;
|
|
2235
2235
|
const dw = dst.width;
|
|
2236
|
-
|
|
2237
|
-
const
|
|
2238
|
-
const maskData = mask.data;
|
|
2239
|
-
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
2240
|
-
let mIdx = sY0 * mPitch + sX0;
|
|
2236
|
+
let dIdx = y * dw + x | 0;
|
|
2237
|
+
const dStride = dw - actualW | 0;
|
|
2241
2238
|
let didChange = false;
|
|
2242
|
-
for (let iy = 0; iy <
|
|
2243
|
-
for (let ix = 0; ix <
|
|
2244
|
-
const
|
|
2245
|
-
const
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
weight = 0;
|
|
2249
|
-
} else if (effectiveM === 255) {
|
|
2250
|
-
weight = globalAlpha;
|
|
2251
|
-
} else if (globalAlpha === 255) {
|
|
2252
|
-
weight = effectiveM;
|
|
2253
|
-
} else {
|
|
2254
|
-
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
2255
|
-
}
|
|
2256
|
-
if (weight === 0) {
|
|
2257
|
-
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
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;
|
|
2258
2245
|
didChange = true;
|
|
2259
|
-
} else if (weight !== 255) {
|
|
2260
|
-
const d = dst32[dIdx];
|
|
2261
|
-
const da = d >>> 24;
|
|
2262
|
-
if (da !== 0) {
|
|
2263
|
-
const finalAlpha = da === 255 ? weight : da * weight + 128 >> 8;
|
|
2264
|
-
const current = dst32[dIdx];
|
|
2265
|
-
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
2266
|
-
if (current !== next) {
|
|
2267
|
-
dst32[dIdx] = next;
|
|
2268
|
-
didChange = true;
|
|
2269
|
-
}
|
|
2270
|
-
}
|
|
2271
2246
|
}
|
|
2272
2247
|
dIdx++;
|
|
2273
|
-
mIdx++;
|
|
2274
2248
|
}
|
|
2275
2249
|
dIdx += dStride;
|
|
2276
|
-
mIdx += mStride;
|
|
2277
2250
|
}
|
|
2278
2251
|
return didChange;
|
|
2279
2252
|
}
|
|
2280
2253
|
|
|
2281
|
-
// src/History/PixelMutator/
|
|
2254
|
+
// src/History/PixelMutator/mutatorBlendColor.ts
|
|
2282
2255
|
var defaults2 = {
|
|
2283
|
-
|
|
2256
|
+
blendColorPixelData
|
|
2284
2257
|
};
|
|
2285
|
-
var
|
|
2258
|
+
var mutatorBlendColor = ((writer, deps = defaults2) => {
|
|
2286
2259
|
const {
|
|
2287
|
-
|
|
2260
|
+
blendColorPixelData: blendColorPixelData2 = defaults2.blendColorPixelData
|
|
2288
2261
|
} = deps;
|
|
2289
2262
|
return {
|
|
2290
|
-
|
|
2291
|
-
|
|
2263
|
+
blendColor(color, opts = {}) {
|
|
2264
|
+
const target = writer.config.target;
|
|
2292
2265
|
const {
|
|
2293
2266
|
x = 0,
|
|
2294
2267
|
y = 0,
|
|
@@ -2296,159 +2269,227 @@ var mutatorApplyAlphaMask = ((writer, deps = defaults2) => {
|
|
|
2296
2269
|
h = target.height
|
|
2297
2270
|
} = opts;
|
|
2298
2271
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2299
|
-
return didChange(
|
|
2272
|
+
return didChange(blendColorPixelData2(target, color, opts));
|
|
2300
2273
|
}
|
|
2301
2274
|
};
|
|
2302
2275
|
});
|
|
2303
2276
|
|
|
2304
|
-
// src/PixelData/
|
|
2305
|
-
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 = {}) {
|
|
2306
2321
|
const {
|
|
2307
2322
|
x: targetX = 0,
|
|
2308
2323
|
y: targetY = 0,
|
|
2309
|
-
|
|
2310
|
-
|
|
2324
|
+
sx: sourceX = 0,
|
|
2325
|
+
sy: sourceY = 0,
|
|
2326
|
+
w: width = src.width,
|
|
2327
|
+
h: height = src.height,
|
|
2311
2328
|
alpha: globalAlpha = 255,
|
|
2312
|
-
|
|
2313
|
-
my = 0,
|
|
2314
|
-
invertMask = false
|
|
2329
|
+
blendFn = sourceOverPerfect
|
|
2315
2330
|
} = opts;
|
|
2316
2331
|
if (globalAlpha === 0) return false;
|
|
2317
2332
|
let x = targetX;
|
|
2318
2333
|
let y = targetY;
|
|
2334
|
+
let sx = sourceX;
|
|
2335
|
+
let sy = sourceY;
|
|
2319
2336
|
let w = width;
|
|
2320
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);
|
|
2321
2350
|
if (x < 0) {
|
|
2351
|
+
sx -= x;
|
|
2322
2352
|
w += x;
|
|
2323
2353
|
x = 0;
|
|
2324
2354
|
}
|
|
2325
2355
|
if (y < 0) {
|
|
2356
|
+
sy -= y;
|
|
2326
2357
|
h += y;
|
|
2327
2358
|
y = 0;
|
|
2328
2359
|
}
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
if (
|
|
2332
|
-
const mPitch = mask.w;
|
|
2333
|
-
if (mPitch <= 0) return false;
|
|
2334
|
-
const startX = mx + (x - targetX);
|
|
2335
|
-
const startY = my + (y - targetY);
|
|
2336
|
-
const sX0 = Math.max(0, startX);
|
|
2337
|
-
const sY0 = Math.max(0, startY);
|
|
2338
|
-
const sX1 = Math.min(mPitch, startX + w);
|
|
2339
|
-
const sY1 = Math.min(mask.h, startY + h);
|
|
2340
|
-
const finalW = sX1 - sX0;
|
|
2341
|
-
const finalH = sY1 - sY0;
|
|
2342
|
-
if (finalW <= 0 || finalH <= 0) {
|
|
2343
|
-
return false;
|
|
2344
|
-
}
|
|
2345
|
-
const xShift = sX0 - startX;
|
|
2346
|
-
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;
|
|
2347
2363
|
const dst32 = dst.data32;
|
|
2364
|
+
const src32 = src.data32;
|
|
2348
2365
|
const dw = dst.width;
|
|
2349
|
-
const
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
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;
|
|
2354
2373
|
let didChange = false;
|
|
2355
|
-
for (let iy = 0; iy <
|
|
2356
|
-
for (let ix = 0; ix <
|
|
2357
|
-
const
|
|
2358
|
-
const
|
|
2359
|
-
if (
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
2372
|
-
if (d !== next) {
|
|
2373
|
-
dst32[dIdx] = next;
|
|
2374
|
-
didChange = true;
|
|
2375
|
-
}
|
|
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;
|
|
2376
2390
|
}
|
|
2391
|
+
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
2377
2392
|
}
|
|
2378
|
-
dIdx
|
|
2379
|
-
|
|
2393
|
+
const current = dst32[dIdx];
|
|
2394
|
+
const next = blendFn(finalCol, dst32[dIdx]);
|
|
2395
|
+
if (current !== next) {
|
|
2396
|
+
dst32[dIdx] = next;
|
|
2397
|
+
didChange = true;
|
|
2398
|
+
}
|
|
2399
|
+
dIdx++;
|
|
2400
|
+
sIdx++;
|
|
2380
2401
|
}
|
|
2381
2402
|
dIdx += dStride;
|
|
2382
|
-
|
|
2403
|
+
sIdx += sStride;
|
|
2383
2404
|
}
|
|
2384
2405
|
return didChange;
|
|
2385
2406
|
}
|
|
2386
2407
|
|
|
2387
|
-
// src/History/PixelMutator/
|
|
2388
|
-
var
|
|
2389
|
-
|
|
2408
|
+
// src/History/PixelMutator/mutatorBlendPixelData.ts
|
|
2409
|
+
var defaults4 = {
|
|
2410
|
+
blendPixelData
|
|
2390
2411
|
};
|
|
2391
|
-
var
|
|
2412
|
+
var mutatorBlendPixelData = ((writer, deps = defaults4) => {
|
|
2392
2413
|
const {
|
|
2393
|
-
|
|
2414
|
+
blendPixelData: blendPixelData2 = defaults4.blendPixelData
|
|
2394
2415
|
} = deps;
|
|
2395
2416
|
return {
|
|
2396
|
-
|
|
2397
|
-
let target = writer.config.target;
|
|
2417
|
+
blendPixelData(src, opts = {}) {
|
|
2398
2418
|
const {
|
|
2399
2419
|
x = 0,
|
|
2400
2420
|
y = 0,
|
|
2401
|
-
w =
|
|
2402
|
-
h =
|
|
2421
|
+
w = src.width,
|
|
2422
|
+
h = src.height
|
|
2403
2423
|
} = opts;
|
|
2404
2424
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2405
|
-
return didChange(
|
|
2425
|
+
return didChange(blendPixelData2(writer.config.target, src, opts));
|
|
2406
2426
|
}
|
|
2407
2427
|
};
|
|
2408
2428
|
});
|
|
2409
2429
|
|
|
2410
|
-
// src/PixelData/
|
|
2411
|
-
function
|
|
2412
|
-
const
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
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;
|
|
2421
2445
|
if (globalAlpha === 0) return false;
|
|
2422
|
-
const baseSrcAlpha = color >>> 24;
|
|
2423
|
-
const isOverwrite = blendFn.isOverwrite || false;
|
|
2424
|
-
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
2425
2446
|
let x = targetX;
|
|
2426
2447
|
let y = targetY;
|
|
2427
|
-
let
|
|
2428
|
-
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);
|
|
2429
2464
|
if (x < 0) {
|
|
2430
|
-
|
|
2465
|
+
sx -= x;
|
|
2466
|
+
w += x;
|
|
2431
2467
|
x = 0;
|
|
2432
2468
|
}
|
|
2433
2469
|
if (y < 0) {
|
|
2434
|
-
|
|
2470
|
+
sy -= y;
|
|
2471
|
+
h += y;
|
|
2435
2472
|
y = 0;
|
|
2436
2473
|
}
|
|
2437
|
-
actualW = Math.min(
|
|
2438
|
-
actualH = Math.min(
|
|
2474
|
+
const actualW = Math.min(w, dst.width - x);
|
|
2475
|
+
const actualH = Math.min(h, dst.height - y);
|
|
2439
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;
|
|
2440
2481
|
const dx = x - targetX | 0;
|
|
2441
2482
|
const dy = y - targetY | 0;
|
|
2442
2483
|
const dst32 = dst.data32;
|
|
2443
|
-
const
|
|
2444
|
-
const mPitch = mask.w;
|
|
2445
|
-
const maskData = mask.data;
|
|
2484
|
+
const src32 = src.data32;
|
|
2446
2485
|
let dIdx = y * dw + x | 0;
|
|
2486
|
+
let sIdx = sy * sw + sx | 0;
|
|
2447
2487
|
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
2448
2488
|
const dStride = dw - actualW | 0;
|
|
2489
|
+
const sStride = sw - actualW | 0;
|
|
2449
2490
|
const mStride = mPitch - actualW | 0;
|
|
2450
2491
|
const isOpaque = globalAlpha === 255;
|
|
2451
|
-
const
|
|
2492
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
2452
2493
|
let didChange = false;
|
|
2453
2494
|
for (let iy = 0; iy < actualH; iy++) {
|
|
2454
2495
|
for (let ix = 0; ix < actualW; ix++) {
|
|
@@ -2456,6 +2497,15 @@ function blendColorPixelDataAlphaMask(dst, color, mask, opts = {}) {
|
|
|
2456
2497
|
const effM = invertMask ? 255 - mVal : mVal;
|
|
2457
2498
|
if (effM === 0) {
|
|
2458
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++;
|
|
2459
2509
|
mIdx++;
|
|
2460
2510
|
continue;
|
|
2461
2511
|
}
|
|
@@ -2467,844 +2517,459 @@ function blendColorPixelDataAlphaMask(dst, color, mask, opts = {}) {
|
|
|
2467
2517
|
}
|
|
2468
2518
|
if (weight === 0) {
|
|
2469
2519
|
dIdx++;
|
|
2520
|
+
sIdx++;
|
|
2470
2521
|
mIdx++;
|
|
2471
2522
|
continue;
|
|
2472
2523
|
}
|
|
2473
|
-
let finalCol =
|
|
2524
|
+
let finalCol = srcCol;
|
|
2474
2525
|
if (weight < 255) {
|
|
2475
|
-
const a =
|
|
2526
|
+
const a = srcAlpha * weight + 128 >> 8;
|
|
2476
2527
|
if (a === 0 && !isOverwrite) {
|
|
2477
2528
|
dIdx++;
|
|
2529
|
+
sIdx++;
|
|
2478
2530
|
mIdx++;
|
|
2479
2531
|
continue;
|
|
2480
2532
|
}
|
|
2481
|
-
finalCol = (
|
|
2533
|
+
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
2482
2534
|
}
|
|
2483
2535
|
const current = dst32[dIdx];
|
|
2484
|
-
const next = blendFn(finalCol,
|
|
2536
|
+
const next = blendFn(finalCol, dst32[dIdx]);
|
|
2485
2537
|
if (current !== next) {
|
|
2486
2538
|
dst32[dIdx] = next;
|
|
2487
2539
|
didChange = true;
|
|
2488
2540
|
}
|
|
2489
2541
|
dIdx++;
|
|
2542
|
+
sIdx++;
|
|
2490
2543
|
mIdx++;
|
|
2491
2544
|
}
|
|
2492
2545
|
dIdx += dStride;
|
|
2546
|
+
sIdx += sStride;
|
|
2493
2547
|
mIdx += mStride;
|
|
2494
2548
|
}
|
|
2495
2549
|
return didChange;
|
|
2496
2550
|
}
|
|
2497
2551
|
|
|
2498
|
-
// src/
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
const minOffset = -Math.ceil(r - 0.5);
|
|
2502
|
-
const maxOffset = Math.floor(r - 0.5);
|
|
2503
|
-
const startX = Math.floor(centerX + minOffset);
|
|
2504
|
-
const startY = Math.floor(centerY + minOffset);
|
|
2505
|
-
const endX = Math.floor(centerX + maxOffset) + 1;
|
|
2506
|
-
const endY = Math.floor(centerY + maxOffset) + 1;
|
|
2507
|
-
const res = out ?? {
|
|
2508
|
-
x: 0,
|
|
2509
|
-
y: 0,
|
|
2510
|
-
w: 0,
|
|
2511
|
-
h: 0
|
|
2512
|
-
};
|
|
2513
|
-
const cStartX = Math.max(0, startX);
|
|
2514
|
-
const cStartY = Math.max(0, startY);
|
|
2515
|
-
const cEndX = Math.min(targetWidth, endX);
|
|
2516
|
-
const cEndY = Math.min(targetHeight, endY);
|
|
2517
|
-
const w = cEndX - cStartX;
|
|
2518
|
-
const h = cEndY - cStartY;
|
|
2519
|
-
res.x = cStartX;
|
|
2520
|
-
res.y = cStartY;
|
|
2521
|
-
res.w = w < 0 ? 0 : w;
|
|
2522
|
-
res.h = h < 0 ? 0 : h;
|
|
2523
|
-
return res;
|
|
2524
|
-
}
|
|
2525
|
-
|
|
2526
|
-
// src/Rect/getCircleBrushOrPencilStrokeBounds.ts
|
|
2527
|
-
function getCircleBrushOrPencilStrokeBounds(x0, y0, x1, y1, brushSize, result) {
|
|
2528
|
-
const r = Math.ceil(brushSize / 2);
|
|
2529
|
-
const minX = Math.min(x0, x1) - r;
|
|
2530
|
-
const minY = Math.min(y0, y1) - r;
|
|
2531
|
-
const maxX = Math.max(x0, x1) + r;
|
|
2532
|
-
const maxY = Math.max(x0, y1) + r;
|
|
2533
|
-
result.x = Math.floor(minX);
|
|
2534
|
-
result.y = Math.floor(minY);
|
|
2535
|
-
result.w = Math.ceil(maxX - minX);
|
|
2536
|
-
result.h = Math.ceil(maxY - minY);
|
|
2537
|
-
return result;
|
|
2538
|
-
}
|
|
2539
|
-
|
|
2540
|
-
// src/History/PixelMutator/mutatorApplyCircleBrushStroke.ts
|
|
2541
|
-
var defaults4 = {
|
|
2542
|
-
forEachLinePoint,
|
|
2543
|
-
blendColorPixelDataAlphaMask,
|
|
2544
|
-
getCircleBrushOrPencilBounds,
|
|
2545
|
-
getCircleBrushOrPencilStrokeBounds
|
|
2552
|
+
// src/History/PixelMutator/mutatorBlendPixelDataAlphaMask.ts
|
|
2553
|
+
var defaults5 = {
|
|
2554
|
+
blendPixelDataAlphaMask
|
|
2546
2555
|
};
|
|
2547
|
-
var
|
|
2556
|
+
var mutatorBlendPixelDataAlphaMask = ((writer, deps = defaults5) => {
|
|
2548
2557
|
const {
|
|
2549
|
-
|
|
2550
|
-
blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults4.blendColorPixelDataAlphaMask,
|
|
2551
|
-
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults4.getCircleBrushOrPencilBounds,
|
|
2552
|
-
getCircleBrushOrPencilStrokeBounds: getCircleBrushOrPencilStrokeBounds2 = defaults4.getCircleBrushOrPencilStrokeBounds
|
|
2558
|
+
blendPixelDataAlphaMask: blendPixelDataAlphaMask2 = defaults5.blendPixelDataAlphaMask
|
|
2553
2559
|
} = deps;
|
|
2554
|
-
const strokeBoundsOut = {
|
|
2555
|
-
x: 0,
|
|
2556
|
-
y: 0,
|
|
2557
|
-
w: 0,
|
|
2558
|
-
h: 0
|
|
2559
|
-
};
|
|
2560
|
-
const circleBrushBounds = {
|
|
2561
|
-
x: 0,
|
|
2562
|
-
y: 0,
|
|
2563
|
-
w: 0,
|
|
2564
|
-
h: 0
|
|
2565
|
-
};
|
|
2566
|
-
const blendColorPixelOptions = {
|
|
2567
|
-
alpha: 255,
|
|
2568
|
-
blendFn: sourceOverPerfect,
|
|
2569
|
-
x: 0,
|
|
2570
|
-
y: 0,
|
|
2571
|
-
w: 0,
|
|
2572
|
-
h: 0
|
|
2573
|
-
};
|
|
2574
|
-
const mask = {
|
|
2575
|
-
type: 0 /* ALPHA */,
|
|
2576
|
-
data: null,
|
|
2577
|
-
w: 0,
|
|
2578
|
-
h: 0
|
|
2579
|
-
};
|
|
2580
2560
|
return {
|
|
2581
|
-
|
|
2582
|
-
const
|
|
2583
|
-
const
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
} = getCircleBrushOrPencilStrokeBounds2(x0, y0, x1, y1, brushSize, strokeBoundsOut);
|
|
2589
|
-
if (bw <= 0 || bh <= 0) return;
|
|
2590
|
-
mask.data = new Uint8Array(bw * bh);
|
|
2591
|
-
mask.w = bw;
|
|
2592
|
-
mask.h = bh;
|
|
2593
|
-
const maskData = mask.data;
|
|
2594
|
-
const brushData = brush.data;
|
|
2595
|
-
const minOffset = brush.minOffset;
|
|
2596
|
-
const target = writer.config.target;
|
|
2597
|
-
const targetWidth = target.width;
|
|
2598
|
-
const targetHeight = target.height;
|
|
2599
|
-
forEachLinePoint2(x0, y0, x1, y1, (px, py) => {
|
|
2600
|
-
const {
|
|
2601
|
-
x: cbx,
|
|
2602
|
-
y: cby,
|
|
2603
|
-
w: cbw,
|
|
2604
|
-
h: cbh
|
|
2605
|
-
} = getCircleBrushOrPencilBounds2(px, py, brushSize, targetWidth, targetHeight, circleBrushBounds);
|
|
2606
|
-
writer.accumulator.storeRegionBeforeState(cbx, cby, cbw, cbh);
|
|
2607
|
-
const startX = Math.max(bx, cbx);
|
|
2608
|
-
const startY = Math.max(by, cby);
|
|
2609
|
-
const endX = Math.min(bx + bw, cbx + cbw);
|
|
2610
|
-
const endY = Math.min(by + bh, cby + cbh);
|
|
2611
|
-
const unclippedStartX = Math.floor(px + minOffset);
|
|
2612
|
-
const unclippedStartY = Math.floor(py + minOffset);
|
|
2613
|
-
for (let my = startY; my < endY; my++) {
|
|
2614
|
-
const strokeMaskY = my - by;
|
|
2615
|
-
const strokeMaskRowOffset = strokeMaskY * bw;
|
|
2616
|
-
const brushY = my - unclippedStartY;
|
|
2617
|
-
const brushRowOffset = brushY * brushSize;
|
|
2618
|
-
for (let mx = startX; mx < endX; mx++) {
|
|
2619
|
-
const brushX = mx - unclippedStartX;
|
|
2620
|
-
const brushVal = brushData[brushRowOffset + brushX];
|
|
2621
|
-
if (brushVal > 0) {
|
|
2622
|
-
const strokeMaskIdx = strokeMaskRowOffset + (mx - bx);
|
|
2623
|
-
if (brushVal > maskData[strokeMaskIdx]) {
|
|
2624
|
-
maskData[strokeMaskIdx] = brushVal;
|
|
2625
|
-
}
|
|
2626
|
-
}
|
|
2627
|
-
}
|
|
2628
|
-
}
|
|
2629
|
-
});
|
|
2630
|
-
blendColorPixelOptions.blendFn = blendFn;
|
|
2631
|
-
blendColorPixelOptions.alpha = alpha;
|
|
2632
|
-
blendColorPixelOptions.x = bx;
|
|
2633
|
-
blendColorPixelOptions.y = by;
|
|
2634
|
-
blendColorPixelOptions.w = bw;
|
|
2635
|
-
blendColorPixelOptions.h = bh;
|
|
2636
|
-
blendColorPixelDataAlphaMask2(target, color, mask, blendColorPixelOptions);
|
|
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));
|
|
2637
2568
|
}
|
|
2638
2569
|
};
|
|
2639
2570
|
});
|
|
2640
2571
|
|
|
2641
|
-
// src/PixelData/
|
|
2642
|
-
function
|
|
2643
|
-
const
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
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;
|
|
2652
2587
|
if (globalAlpha === 0) return false;
|
|
2653
|
-
const baseSrcAlpha = color >>> 24;
|
|
2654
|
-
const isOverwrite = blendFn.isOverwrite || false;
|
|
2655
|
-
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
2656
2588
|
let x = targetX;
|
|
2657
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);
|
|
2658
2606
|
if (x < 0) {
|
|
2607
|
+
sx -= x;
|
|
2659
2608
|
w += x;
|
|
2660
2609
|
x = 0;
|
|
2661
2610
|
}
|
|
2662
2611
|
if (y < 0) {
|
|
2612
|
+
sy -= y;
|
|
2663
2613
|
h += y;
|
|
2664
2614
|
y = 0;
|
|
2665
2615
|
}
|
|
2666
2616
|
const actualW = Math.min(w, dst.width - x);
|
|
2667
2617
|
const actualH = Math.min(h, dst.height - y);
|
|
2668
2618
|
if (actualW <= 0 || actualH <= 0) return false;
|
|
2669
|
-
let baseColorWithGlobalAlpha = color;
|
|
2670
|
-
if (globalAlpha < 255) {
|
|
2671
|
-
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
2672
|
-
if (a === 0 && !isOverwrite) return false;
|
|
2673
|
-
baseColorWithGlobalAlpha = (color & 16777215 | a << 24) >>> 0;
|
|
2674
|
-
}
|
|
2675
2619
|
const dx = x - targetX | 0;
|
|
2676
2620
|
const dy = y - targetY | 0;
|
|
2677
2621
|
const dst32 = dst.data32;
|
|
2622
|
+
const src32 = src.data32;
|
|
2678
2623
|
const dw = dst.width;
|
|
2679
|
-
const
|
|
2680
|
-
const
|
|
2624
|
+
const sw = src.width;
|
|
2625
|
+
const mPitch = binaryMask.w;
|
|
2626
|
+
const maskData = binaryMask.data;
|
|
2681
2627
|
let dIdx = y * dw + x | 0;
|
|
2628
|
+
let sIdx = sy * sw + sx | 0;
|
|
2682
2629
|
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
2683
2630
|
const dStride = dw - actualW | 0;
|
|
2631
|
+
const sStride = sw - actualW | 0;
|
|
2684
2632
|
const mStride = mPitch - actualW | 0;
|
|
2685
2633
|
const skipVal = invertMask ? 1 : 0;
|
|
2634
|
+
const isOpaque = globalAlpha === 255;
|
|
2635
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
2686
2636
|
let didChange = false;
|
|
2687
2637
|
for (let iy = 0; iy < actualH; iy++) {
|
|
2688
2638
|
for (let ix = 0; ix < actualW; ix++) {
|
|
2689
2639
|
if (maskData[mIdx] === skipVal) {
|
|
2690
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++;
|
|
2691
2650
|
mIdx++;
|
|
2692
2651
|
continue;
|
|
2693
2652
|
}
|
|
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
|
+
}
|
|
2694
2664
|
const current = dst32[dIdx];
|
|
2695
|
-
const next = blendFn(
|
|
2665
|
+
const next = blendFn(finalCol, dst32[dIdx]);
|
|
2696
2666
|
if (current !== next) {
|
|
2697
2667
|
dst32[dIdx] = next;
|
|
2698
2668
|
didChange = true;
|
|
2699
2669
|
}
|
|
2700
2670
|
dIdx++;
|
|
2671
|
+
sIdx++;
|
|
2701
2672
|
mIdx++;
|
|
2702
2673
|
}
|
|
2703
2674
|
dIdx += dStride;
|
|
2675
|
+
sIdx += sStride;
|
|
2704
2676
|
mIdx += mStride;
|
|
2705
2677
|
}
|
|
2706
2678
|
return didChange;
|
|
2707
2679
|
}
|
|
2708
2680
|
|
|
2709
|
-
// src/
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
if (b.w <= 0 || b.h <= 0) return false;
|
|
2713
|
-
const unclippedStartX = Math.floor(centerX + brush.minOffset);
|
|
2714
|
-
const unclippedStartY = Math.floor(centerY + brush.minOffset);
|
|
2715
|
-
const ix = Math.max(unclippedStartX, b.x);
|
|
2716
|
-
const iy = Math.max(unclippedStartY, b.y);
|
|
2717
|
-
const ir = Math.min(unclippedStartX + brush.w, b.x + b.w);
|
|
2718
|
-
const ib = Math.min(unclippedStartY + brush.h, b.y + b.h);
|
|
2719
|
-
const iw = ir - ix;
|
|
2720
|
-
const ih = ib - iy;
|
|
2721
|
-
if (iw <= 0 || ih <= 0) return false;
|
|
2722
|
-
scratchOptions.x = ix;
|
|
2723
|
-
scratchOptions.y = iy;
|
|
2724
|
-
scratchOptions.w = iw;
|
|
2725
|
-
scratchOptions.h = ih;
|
|
2726
|
-
scratchOptions.mx = ix - unclippedStartX;
|
|
2727
|
-
scratchOptions.my = iy - unclippedStartY;
|
|
2728
|
-
scratchOptions.alpha = alpha;
|
|
2729
|
-
scratchOptions.blendFn = blendFn;
|
|
2730
|
-
if (brush.type === 0 /* ALPHA */) {
|
|
2731
|
-
return blendColorPixelDataAlphaMask(target, color, brush, scratchOptions);
|
|
2732
|
-
}
|
|
2733
|
-
if (brush.type === 1 /* BINARY */) {
|
|
2734
|
-
return blendColorPixelDataBinaryMask(target, color, brush, scratchOptions);
|
|
2735
|
-
}
|
|
2736
|
-
return false;
|
|
2737
|
-
}
|
|
2738
|
-
|
|
2739
|
-
// src/History/PixelMutator/mutatorBlendColorCircleMask.ts
|
|
2740
|
-
var defaults5 = {
|
|
2741
|
-
blendColorPixelDataCircleMask,
|
|
2742
|
-
getCircleBrushOrPencilBounds
|
|
2681
|
+
// src/History/PixelMutator/mutatorBlendPixelDataBinaryMask.ts
|
|
2682
|
+
var defaults6 = {
|
|
2683
|
+
blendPixelDataBinaryMask
|
|
2743
2684
|
};
|
|
2744
|
-
var
|
|
2685
|
+
var mutatorBlendPixelDataBinaryMask = ((writer, deps = defaults6) => {
|
|
2745
2686
|
const {
|
|
2746
|
-
|
|
2747
|
-
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults5.getCircleBrushOrPencilBounds
|
|
2687
|
+
blendPixelDataBinaryMask: blendPixelDataBinaryMask2 = defaults6.blendPixelDataBinaryMask
|
|
2748
2688
|
} = deps;
|
|
2749
|
-
const boundsOut = {
|
|
2750
|
-
x: 0,
|
|
2751
|
-
y: 0,
|
|
2752
|
-
w: 0,
|
|
2753
|
-
h: 0
|
|
2754
|
-
};
|
|
2755
|
-
const blendColorPixelOptions = {
|
|
2756
|
-
alpha: 255,
|
|
2757
|
-
blendFn: sourceOverPerfect,
|
|
2758
|
-
x: 0,
|
|
2759
|
-
y: 0,
|
|
2760
|
-
w: 0,
|
|
2761
|
-
h: 0
|
|
2762
|
-
};
|
|
2763
2689
|
return {
|
|
2764
|
-
|
|
2765
|
-
const
|
|
2766
|
-
const
|
|
2767
|
-
const
|
|
2768
|
-
|
|
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));
|
|
2769
2697
|
}
|
|
2770
2698
|
};
|
|
2771
2699
|
});
|
|
2772
2700
|
|
|
2773
|
-
// src/
|
|
2774
|
-
var
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
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;
|
|
2779
2726
|
const {
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
});
|
|
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);
|
|
2736
|
+
return;
|
|
2737
|
+
}
|
|
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);
|
|
2742
|
+
}
|
|
2743
|
+
}
|
|
2798
2744
|
|
|
2799
|
-
// src/History/PixelMutator/
|
|
2745
|
+
// src/History/PixelMutator/mutatorClear.ts
|
|
2800
2746
|
var defaults7 = {
|
|
2801
|
-
|
|
2802
|
-
blendColorPixelDataBinaryMask,
|
|
2803
|
-
getCircleBrushOrPencilBounds,
|
|
2804
|
-
getCircleBrushOrPencilStrokeBounds
|
|
2747
|
+
fillPixelData: fillPixelDataFast
|
|
2805
2748
|
};
|
|
2806
|
-
var
|
|
2749
|
+
var mutatorClear = ((writer, deps = defaults7) => {
|
|
2807
2750
|
const {
|
|
2808
|
-
|
|
2809
|
-
blendColorPixelDataBinaryMask: blendColorPixelDataBinaryMask2 = defaults7.blendColorPixelDataBinaryMask,
|
|
2810
|
-
getCircleBrushOrPencilStrokeBounds: getCircleBrushOrPencilStrokeBounds2 = defaults7.getCircleBrushOrPencilStrokeBounds,
|
|
2811
|
-
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults7.getCircleBrushOrPencilBounds
|
|
2751
|
+
fillPixelData: fillPixelData2 = defaults7.fillPixelData
|
|
2812
2752
|
} = deps;
|
|
2813
|
-
const strokeBoundsOut = {
|
|
2814
|
-
x: 0,
|
|
2815
|
-
y: 0,
|
|
2816
|
-
w: 0,
|
|
2817
|
-
h: 0
|
|
2818
|
-
};
|
|
2819
|
-
const circlePencilBounds = {
|
|
2820
|
-
x: 0,
|
|
2821
|
-
y: 0,
|
|
2822
|
-
w: 0,
|
|
2823
|
-
h: 0
|
|
2824
|
-
};
|
|
2825
|
-
const blendColorPixelOptions = {
|
|
2826
|
-
alpha: 255,
|
|
2827
|
-
blendFn: sourceOverPerfect,
|
|
2828
|
-
x: 0,
|
|
2829
|
-
y: 0,
|
|
2830
|
-
w: 0,
|
|
2831
|
-
h: 0
|
|
2832
|
-
};
|
|
2833
|
-
const mask = {
|
|
2834
|
-
type: 1 /* BINARY */,
|
|
2835
|
-
data: null,
|
|
2836
|
-
w: 0,
|
|
2837
|
-
h: 0
|
|
2838
|
-
};
|
|
2839
2753
|
return {
|
|
2840
|
-
|
|
2841
|
-
const {
|
|
2842
|
-
x: bx,
|
|
2843
|
-
y: by,
|
|
2844
|
-
w: bw,
|
|
2845
|
-
h: bh
|
|
2846
|
-
} = getCircleBrushOrPencilStrokeBounds2(x0, y0, x1, y1, brush.size, strokeBoundsOut);
|
|
2847
|
-
if (bw <= 0 || bh <= 0) return;
|
|
2848
|
-
mask.data = new Uint8Array(bw * bh);
|
|
2849
|
-
mask.w = bw;
|
|
2850
|
-
mask.h = bh;
|
|
2851
|
-
const maskData = mask.data;
|
|
2754
|
+
clear(rect = {}) {
|
|
2852
2755
|
const target = writer.config.target;
|
|
2853
|
-
const
|
|
2854
|
-
const
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
w: cbw,
|
|
2860
|
-
h: cbh
|
|
2861
|
-
} = getCircleBrushOrPencilBounds2(px, py, brush.size, targetWidth, targetHeight, circlePencilBounds);
|
|
2862
|
-
writer.accumulator.storeRegionBeforeState(cbx, cby, cbw, cbh);
|
|
2863
|
-
const unclippedStartX = Math.floor(px + brush.minOffset);
|
|
2864
|
-
const unclippedStartY = Math.floor(py + brush.minOffset);
|
|
2865
|
-
const startX = Math.max(bx, unclippedStartX);
|
|
2866
|
-
const startY = Math.max(by, unclippedStartY);
|
|
2867
|
-
const endX = Math.min(bx + bw, unclippedStartX + brush.w);
|
|
2868
|
-
const endY = Math.min(by + bh, unclippedStartY + brush.h);
|
|
2869
|
-
for (let my = startY; my < endY; my++) {
|
|
2870
|
-
const brushY = my - unclippedStartY;
|
|
2871
|
-
const maskRowOffset = (my - by) * bw;
|
|
2872
|
-
const brushRowOffset = brushY * brush.w;
|
|
2873
|
-
for (let mx = startX; mx < endX; mx++) {
|
|
2874
|
-
const brushX = mx - unclippedStartX;
|
|
2875
|
-
const brushAlpha = brush.data[brushRowOffset + brushX];
|
|
2876
|
-
if (brushAlpha > 0) {
|
|
2877
|
-
const maskIdx = maskRowOffset + (mx - bx);
|
|
2878
|
-
maskData[maskIdx] = brushAlpha;
|
|
2879
|
-
}
|
|
2880
|
-
}
|
|
2881
|
-
}
|
|
2882
|
-
});
|
|
2883
|
-
blendColorPixelOptions.blendFn = blendFn;
|
|
2884
|
-
blendColorPixelOptions.alpha = alpha;
|
|
2885
|
-
blendColorPixelOptions.x = bx;
|
|
2886
|
-
blendColorPixelOptions.y = by;
|
|
2887
|
-
blendColorPixelOptions.w = bw;
|
|
2888
|
-
blendColorPixelOptions.h = bh;
|
|
2889
|
-
blendColorPixelDataBinaryMask2(target, color, mask, blendColorPixelOptions);
|
|
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);
|
|
2890
2762
|
}
|
|
2891
2763
|
};
|
|
2892
2764
|
});
|
|
2893
2765
|
|
|
2894
|
-
// src/
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
return res;
|
|
2917
|
-
}
|
|
2918
|
-
|
|
2919
|
-
// src/PixelData/applyRectBrushToPixelData.ts
|
|
2920
|
-
function applyRectBrushToPixelData(target, color, centerX, centerY, brushWidth, brushHeight, alpha = 255, fallOff, blendFn = sourceOverPerfect, bounds) {
|
|
2921
|
-
const targetWidth = target.width;
|
|
2922
|
-
const targetHeight = target.height;
|
|
2923
|
-
const b = bounds ?? getRectBrushOrPencilBounds(centerX, centerY, brushWidth, brushHeight, targetWidth, targetHeight);
|
|
2924
|
-
if (b.w <= 0 || b.h <= 0) {
|
|
2925
|
-
return false;
|
|
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;
|
|
2926
2788
|
}
|
|
2927
|
-
const
|
|
2928
|
-
|
|
2929
|
-
const
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
const
|
|
2936
|
-
const
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
const dx = Math.abs(px - fCenterX + centerOffsetX) * invHalfW;
|
|
2947
|
-
const dist = dx > dy ? dx : dy;
|
|
2948
|
-
const strength = fallOff(dist);
|
|
2949
|
-
const maskVal = strength * 255 | 0;
|
|
2950
|
-
if (maskVal <= 0) continue;
|
|
2951
|
-
let weight = alpha;
|
|
2952
|
-
if (isOpaque) {
|
|
2953
|
-
weight = maskVal;
|
|
2954
|
-
} else if (maskVal !== 255) {
|
|
2955
|
-
weight = maskVal * alpha + 128 >> 8;
|
|
2956
|
-
}
|
|
2957
|
-
let finalCol = color;
|
|
2958
|
-
if (weight < 255) {
|
|
2959
|
-
const a = baseSrcAlpha * weight + 128 >> 8;
|
|
2960
|
-
if (a === 0 && !isOverwrite) continue;
|
|
2961
|
-
finalCol = (a << 24 | baseColor) >>> 0;
|
|
2962
|
-
}
|
|
2963
|
-
const current = data32[idx];
|
|
2964
|
-
const next = blendFn(finalCol, current);
|
|
2965
|
-
if (current !== next) {
|
|
2966
|
-
data32[idx] = next;
|
|
2967
|
-
didChange = true;
|
|
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;
|
|
2968
2808
|
}
|
|
2969
2809
|
}
|
|
2970
2810
|
}
|
|
2971
|
-
return
|
|
2811
|
+
return hasChanged;
|
|
2972
2812
|
}
|
|
2973
2813
|
|
|
2974
|
-
// src/History/PixelMutator/
|
|
2814
|
+
// src/History/PixelMutator/mutatorFill.ts
|
|
2975
2815
|
var defaults8 = {
|
|
2976
|
-
|
|
2977
|
-
getRectBrushOrPencilBounds
|
|
2816
|
+
fillPixelData
|
|
2978
2817
|
};
|
|
2979
|
-
var
|
|
2818
|
+
var mutatorFill = ((writer, deps = defaults8) => {
|
|
2980
2819
|
const {
|
|
2981
|
-
|
|
2982
|
-
getRectBrushOrPencilBounds: getRectBrushOrPencilBounds2 = defaults8.getRectBrushOrPencilBounds
|
|
2820
|
+
fillPixelData: fillPixelData2 = defaults8.fillPixelData
|
|
2983
2821
|
} = deps;
|
|
2984
|
-
const boundsOut = {
|
|
2985
|
-
x: 0,
|
|
2986
|
-
y: 0,
|
|
2987
|
-
w: 0,
|
|
2988
|
-
h: 0
|
|
2989
|
-
};
|
|
2990
2822
|
return {
|
|
2991
|
-
|
|
2823
|
+
fill(color, x = 0, y = 0, w = writer.config.target.width, h = writer.config.target.height) {
|
|
2992
2824
|
const target = writer.config.target;
|
|
2993
|
-
const
|
|
2994
|
-
|
|
2995
|
-
return didChange(applyRectBrushToPixelData2(target, color, centerX, centerY, brushWidth, brushHeight, alpha, fallOff, blendFn, b));
|
|
2825
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2826
|
+
return didChange(fillPixelData2(target, color, x, y, w, h));
|
|
2996
2827
|
}
|
|
2997
2828
|
};
|
|
2998
2829
|
});
|
|
2999
|
-
|
|
3000
|
-
// src/Rect/getRectBrushOrPencilStrokeBounds.ts
|
|
3001
|
-
function getRectBrushOrPencilStrokeBounds(x0, y0, x1, y1, brushWidth, brushHeight, result) {
|
|
3002
|
-
const halfW = brushWidth / 2;
|
|
3003
|
-
const halfH = brushHeight / 2;
|
|
3004
|
-
const minX = Math.min(x0, x1) - halfW;
|
|
3005
|
-
const minY = Math.min(y0, y1) - halfH;
|
|
3006
|
-
const maxX = Math.max(x0, x1) + halfW;
|
|
3007
|
-
const maxY = Math.max(y0, y1) + halfH;
|
|
3008
|
-
result.x = Math.floor(minX);
|
|
3009
|
-
result.y = Math.floor(minY);
|
|
3010
|
-
result.w = Math.ceil(maxX - minX);
|
|
3011
|
-
result.h = Math.ceil(maxY - minY);
|
|
3012
|
-
return result;
|
|
3013
|
-
}
|
|
3014
|
-
|
|
3015
|
-
// src/History/PixelMutator/mutatorApplyRectBrushStroke.ts
|
|
3016
|
-
var defaults9 = {
|
|
3017
|
-
forEachLinePoint,
|
|
3018
|
-
blendColorPixelDataAlphaMask,
|
|
3019
|
-
getRectBrushOrPencilBounds,
|
|
3020
|
-
getRectBrushOrPencilStrokeBounds
|
|
3021
|
-
};
|
|
3022
|
-
var mutatorApplyRectBrushStroke = ((writer, deps = defaults9) => {
|
|
2830
|
+
var mutatorFillRect = ((writer, deps = defaults8) => {
|
|
3023
2831
|
const {
|
|
3024
|
-
|
|
3025
|
-
blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults9.blendColorPixelDataAlphaMask,
|
|
3026
|
-
getRectBrushOrPencilBounds: getRectBrushOrPencilBounds2 = defaults9.getRectBrushOrPencilBounds,
|
|
3027
|
-
getRectBrushOrPencilStrokeBounds: getRectBrushOrPencilStrokeBounds2 = defaults9.getRectBrushOrPencilStrokeBounds
|
|
2832
|
+
fillPixelData: fillPixelData2 = defaults8.fillPixelData
|
|
3028
2833
|
} = deps;
|
|
3029
|
-
const strokeBoundsOut = {
|
|
3030
|
-
x: 0,
|
|
3031
|
-
y: 0,
|
|
3032
|
-
w: 0,
|
|
3033
|
-
h: 0
|
|
3034
|
-
};
|
|
3035
|
-
const rectBrushBounds = {
|
|
3036
|
-
x: 0,
|
|
3037
|
-
y: 0,
|
|
3038
|
-
w: 0,
|
|
3039
|
-
h: 0
|
|
3040
|
-
};
|
|
3041
|
-
const blendColorPixelOptions = {
|
|
3042
|
-
alpha: 255,
|
|
3043
|
-
blendFn: sourceOverPerfect,
|
|
3044
|
-
x: 0,
|
|
3045
|
-
y: 0,
|
|
3046
|
-
w: 0,
|
|
3047
|
-
h: 0
|
|
3048
|
-
};
|
|
3049
|
-
const mask = {
|
|
3050
|
-
type: 0 /* ALPHA */,
|
|
3051
|
-
data: null,
|
|
3052
|
-
w: 0,
|
|
3053
|
-
h: 0
|
|
3054
|
-
};
|
|
3055
2834
|
return {
|
|
3056
|
-
|
|
3057
|
-
const {
|
|
3058
|
-
x: bx,
|
|
3059
|
-
y: by,
|
|
3060
|
-
w: bw,
|
|
3061
|
-
h: bh
|
|
3062
|
-
} = getRectBrushOrPencilStrokeBounds2(x0, y0, x1, y1, brushWidth, brushHeight, strokeBoundsOut);
|
|
3063
|
-
if (bw <= 0 || bh <= 0) return;
|
|
3064
|
-
mask.data = new Uint8Array(bw * bh);
|
|
3065
|
-
mask.w = bw;
|
|
3066
|
-
mask.h = bh;
|
|
3067
|
-
const maskData = mask.data;
|
|
3068
|
-
const halfW = brushWidth / 2;
|
|
3069
|
-
const halfH = brushHeight / 2;
|
|
3070
|
-
const invHalfW = 1 / halfW;
|
|
3071
|
-
const invHalfH = 1 / halfH;
|
|
3072
|
-
const centerOffsetX = brushWidth % 2 === 0 ? 0.5 : 0;
|
|
3073
|
-
const centerOffsetY = brushHeight % 2 === 0 ? 0.5 : 0;
|
|
2835
|
+
fillRect(color, rect) {
|
|
3074
2836
|
const target = writer.config.target;
|
|
3075
|
-
const
|
|
3076
|
-
|
|
3077
|
-
forEachLinePoint2(x0, y0, x1, y1, (px, py) => {
|
|
3078
|
-
const {
|
|
3079
|
-
x: rbx,
|
|
3080
|
-
y: rby,
|
|
3081
|
-
w: rbw,
|
|
3082
|
-
h: rbh
|
|
3083
|
-
} = getRectBrushOrPencilBounds2(px, py, brushWidth, brushHeight, targetWidth, targetHeight, rectBrushBounds);
|
|
3084
|
-
writer.accumulator.storeRegionBeforeState(rbx, rby, rbw, rbh);
|
|
3085
|
-
const startX = Math.max(bx, rbx);
|
|
3086
|
-
const startY = Math.max(by, rby);
|
|
3087
|
-
const endX = Math.min(bx + bw, rbx + rbw);
|
|
3088
|
-
const endY = Math.min(by + bh, rby + rbh);
|
|
3089
|
-
const fPx = Math.floor(px);
|
|
3090
|
-
const fPy = Math.floor(py);
|
|
3091
|
-
for (let my = startY; my < endY; my++) {
|
|
3092
|
-
const dy = Math.abs(my - fPy + centerOffsetY) * invHalfH;
|
|
3093
|
-
const maskRowOffset = (my - by) * bw;
|
|
3094
|
-
for (let mx = startX; mx < endX; mx++) {
|
|
3095
|
-
const dx = Math.abs(mx - fPx + centerOffsetX) * invHalfW;
|
|
3096
|
-
const maskIdx = maskRowOffset + (mx - bx);
|
|
3097
|
-
const dist = dx > dy ? dx : dy;
|
|
3098
|
-
const strength = fallOff(dist);
|
|
3099
|
-
if (strength > 0) {
|
|
3100
|
-
const intensity = strength * 255 | 0;
|
|
3101
|
-
if (intensity > maskData[maskIdx]) {
|
|
3102
|
-
maskData[maskIdx] = intensity;
|
|
3103
|
-
}
|
|
3104
|
-
}
|
|
3105
|
-
}
|
|
3106
|
-
}
|
|
3107
|
-
});
|
|
3108
|
-
blendColorPixelOptions.blendFn = blendFn;
|
|
3109
|
-
blendColorPixelOptions.alpha = alpha;
|
|
3110
|
-
blendColorPixelOptions.x = bx;
|
|
3111
|
-
blendColorPixelOptions.y = by;
|
|
3112
|
-
blendColorPixelOptions.w = bw;
|
|
3113
|
-
blendColorPixelOptions.h = bh;
|
|
3114
|
-
blendColorPixelDataAlphaMask2(target, color, mask, blendColorPixelOptions);
|
|
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));
|
|
3115
2839
|
}
|
|
3116
2840
|
};
|
|
3117
2841
|
});
|
|
3118
2842
|
|
|
3119
|
-
// src/
|
|
3120
|
-
var
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
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;
|
|
3126
2851
|
const {
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
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
|
+
}
|
|
2883
|
+
}
|
|
2884
|
+
}
|
|
2885
|
+
}
|
|
2886
|
+
return hasChanged;
|
|
2887
|
+
}
|
|
2888
|
+
|
|
2889
|
+
// src/History/PixelMutator/mutatorFillBinaryMask.ts
|
|
2890
|
+
var defaults9 = {
|
|
2891
|
+
fillPixelDataBinaryMask
|
|
3153
2892
|
};
|
|
3154
|
-
var
|
|
2893
|
+
var mutatorFillBinaryMask = ((writer, deps = defaults9) => {
|
|
3155
2894
|
const {
|
|
3156
|
-
|
|
3157
|
-
blendColorPixelDataBinaryMask: blendColorPixelDataBinaryMask2 = defaults11.blendColorPixelDataBinaryMask,
|
|
3158
|
-
getRectBrushOrPencilBounds: getRectBrushOrPencilBounds2 = defaults11.getRectBrushOrPencilBounds,
|
|
3159
|
-
getRectBrushOrPencilStrokeBounds: getRectBrushOrPencilStrokeBounds2 = defaults11.getRectBrushOrPencilStrokeBounds
|
|
2895
|
+
fillPixelDataBinaryMask: fillPixelDataBinaryMask2 = defaults9.fillPixelDataBinaryMask
|
|
3160
2896
|
} = deps;
|
|
3161
|
-
const strokeBoundsOut = {
|
|
3162
|
-
x: 0,
|
|
3163
|
-
y: 0,
|
|
3164
|
-
w: 0,
|
|
3165
|
-
h: 0
|
|
3166
|
-
};
|
|
3167
|
-
const rectPencilBounds = {
|
|
3168
|
-
x: 0,
|
|
3169
|
-
y: 0,
|
|
3170
|
-
w: 0,
|
|
3171
|
-
h: 0
|
|
3172
|
-
};
|
|
3173
|
-
const blendColorPixelOptions = {
|
|
3174
|
-
alpha: 255,
|
|
3175
|
-
blendFn: sourceOverPerfect,
|
|
3176
|
-
x: 0,
|
|
3177
|
-
y: 0,
|
|
3178
|
-
w: 0,
|
|
3179
|
-
h: 0
|
|
3180
|
-
};
|
|
3181
|
-
const mask = {
|
|
3182
|
-
type: 1 /* BINARY */,
|
|
3183
|
-
data: null,
|
|
3184
|
-
w: 0,
|
|
3185
|
-
h: 0
|
|
3186
|
-
};
|
|
3187
2897
|
return {
|
|
3188
|
-
|
|
3189
|
-
const
|
|
3190
|
-
|
|
3191
|
-
y: by,
|
|
3192
|
-
w: bw,
|
|
3193
|
-
h: bh
|
|
3194
|
-
} = getRectBrushOrPencilStrokeBounds2(x0, y0, x1, y1, brushWidth, brushHeight, strokeBoundsOut);
|
|
3195
|
-
if (bw <= 0 || bh <= 0) return;
|
|
3196
|
-
mask.data = new Uint8Array(bw * bh);
|
|
3197
|
-
mask.w = bw;
|
|
3198
|
-
mask.h = bh;
|
|
3199
|
-
const maskData = mask.data;
|
|
3200
|
-
const halfW = brushWidth / 2;
|
|
3201
|
-
const halfH = brushHeight / 2;
|
|
3202
|
-
const centerOffset = brushWidth % 2 === 0 ? 0.5 : 0;
|
|
3203
|
-
const target = writer.config.target;
|
|
3204
|
-
const targetWidth = target.width;
|
|
3205
|
-
const targetHeight = target.height;
|
|
3206
|
-
forEachLinePoint2(x0, y0, x1, y1, (px, py) => {
|
|
3207
|
-
const {
|
|
3208
|
-
x: rbx,
|
|
3209
|
-
y: rby,
|
|
3210
|
-
w: rbw,
|
|
3211
|
-
h: rbh
|
|
3212
|
-
} = getRectBrushOrPencilBounds2(px, py, brushWidth, brushHeight, targetWidth, targetHeight, rectPencilBounds);
|
|
3213
|
-
writer.accumulator.storeRegionBeforeState(rbx, rby, rbw, rbh);
|
|
3214
|
-
const startX = Math.max(bx, rbx);
|
|
3215
|
-
const startY = Math.max(by, rby);
|
|
3216
|
-
const endX = Math.min(bx + bw, rbx + rbw);
|
|
3217
|
-
const endY = Math.min(by + bh, rby + rbh);
|
|
3218
|
-
const fPx = Math.floor(px);
|
|
3219
|
-
const fPy = Math.floor(py);
|
|
3220
|
-
for (let my = startY; my < endY; my++) {
|
|
3221
|
-
const dy = Math.abs(my - fPy + centerOffset);
|
|
3222
|
-
const maskRowOffset = (my - by) * bw;
|
|
3223
|
-
for (let mx = startX; mx < endX; mx++) {
|
|
3224
|
-
const dx = Math.abs(mx - fPx + centerOffset);
|
|
3225
|
-
const maskIdx = maskRowOffset + (mx - bx);
|
|
3226
|
-
if (dx <= halfW && dy <= halfH) {
|
|
3227
|
-
maskData[maskIdx] = 1;
|
|
3228
|
-
}
|
|
3229
|
-
}
|
|
3230
|
-
}
|
|
3231
|
-
});
|
|
3232
|
-
blendColorPixelOptions.blendFn = blendFn;
|
|
3233
|
-
blendColorPixelOptions.alpha = alpha;
|
|
3234
|
-
blendColorPixelOptions.x = bx;
|
|
3235
|
-
blendColorPixelOptions.y = by;
|
|
3236
|
-
blendColorPixelOptions.w = bw;
|
|
3237
|
-
blendColorPixelOptions.h = bh;
|
|
3238
|
-
blendColorPixelDataBinaryMask2(target, color, mask, blendColorPixelOptions);
|
|
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));
|
|
3239
2901
|
}
|
|
3240
2902
|
};
|
|
3241
2903
|
});
|
|
3242
2904
|
|
|
3243
|
-
// src/PixelData/
|
|
3244
|
-
|
|
2905
|
+
// src/PixelData/invertPixelData.ts
|
|
2906
|
+
var SCRATCH_RECT4 = makeClippedRect();
|
|
2907
|
+
function invertPixelData(pixelData, opts = {}) {
|
|
2908
|
+
const dst = pixelData;
|
|
3245
2909
|
const {
|
|
3246
2910
|
x: targetX = 0,
|
|
3247
2911
|
y: targetY = 0,
|
|
3248
|
-
w: width =
|
|
3249
|
-
h: height =
|
|
3250
|
-
|
|
3251
|
-
|
|
2912
|
+
w: width = pixelData.width,
|
|
2913
|
+
h: height = pixelData.height,
|
|
2914
|
+
mask,
|
|
2915
|
+
mx = 0,
|
|
2916
|
+
my = 0,
|
|
2917
|
+
invertMask = false
|
|
3252
2918
|
} = opts;
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
const
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
if (x < 0) {
|
|
3262
|
-
w += x;
|
|
3263
|
-
x = 0;
|
|
3264
|
-
}
|
|
3265
|
-
if (y < 0) {
|
|
3266
|
-
h += y;
|
|
3267
|
-
y = 0;
|
|
3268
|
-
}
|
|
3269
|
-
const actualW = Math.min(w, dst.width - x);
|
|
3270
|
-
const actualH = Math.min(h, dst.height - y);
|
|
3271
|
-
if (actualW <= 0 || actualH <= 0) return false;
|
|
3272
|
-
let finalSrcColor = color;
|
|
3273
|
-
if (globalAlpha < 255) {
|
|
3274
|
-
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
3275
|
-
if (a === 0 && !isOverwrite) return false;
|
|
3276
|
-
finalSrcColor = (color & 16777215 | a << 24) >>> 0;
|
|
3277
|
-
}
|
|
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;
|
|
3278
2927
|
const dst32 = dst.data32;
|
|
3279
2928
|
const dw = dst.width;
|
|
3280
|
-
|
|
3281
|
-
const
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
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++;
|
|
3290
2947
|
}
|
|
3291
|
-
dIdx
|
|
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;
|
|
3292
2958
|
}
|
|
3293
|
-
dIdx += dStride;
|
|
3294
2959
|
}
|
|
3295
|
-
return
|
|
2960
|
+
return true;
|
|
3296
2961
|
}
|
|
3297
2962
|
|
|
3298
|
-
// src/History/PixelMutator/
|
|
3299
|
-
var
|
|
3300
|
-
|
|
2963
|
+
// src/History/PixelMutator/mutatorInvert.ts
|
|
2964
|
+
var defaults10 = {
|
|
2965
|
+
invertPixelData
|
|
3301
2966
|
};
|
|
3302
|
-
var
|
|
2967
|
+
var mutatorInvert = ((writer, deps = defaults10) => {
|
|
3303
2968
|
const {
|
|
3304
|
-
|
|
2969
|
+
invertPixelData: invertPixelData2 = defaults10.invertPixelData
|
|
3305
2970
|
} = deps;
|
|
3306
2971
|
return {
|
|
3307
|
-
|
|
2972
|
+
invert(opts = {}) {
|
|
3308
2973
|
const target = writer.config.target;
|
|
3309
2974
|
const {
|
|
3310
2975
|
x = 0,
|
|
@@ -3313,708 +2978,644 @@ var mutatorBlendColor = ((writer, deps = defaults12) => {
|
|
|
3313
2978
|
h = target.height
|
|
3314
2979
|
} = opts;
|
|
3315
2980
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3316
|
-
return didChange(
|
|
2981
|
+
return didChange(invertPixelData2(target, opts));
|
|
3317
2982
|
}
|
|
3318
2983
|
};
|
|
3319
2984
|
});
|
|
3320
2985
|
|
|
3321
|
-
// src/
|
|
3322
|
-
function
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
2986
|
+
// src/History/PixelMutator.ts
|
|
2987
|
+
function makeFullPixelMutator(writer) {
|
|
2988
|
+
return {
|
|
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)
|
|
3000
|
+
};
|
|
3001
|
+
}
|
|
3002
|
+
|
|
3003
|
+
// src/ImageData/resizeImageData.ts
|
|
3004
|
+
function resizeImageData(target, newWidth, newHeight, offsetX = 0, offsetY = 0) {
|
|
3005
|
+
const result = new ImageData(newWidth, newHeight);
|
|
3006
|
+
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;
|
|
3337
3018
|
}
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
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);
|
|
3343
3028
|
}
|
|
3344
|
-
return
|
|
3029
|
+
return result;
|
|
3345
3030
|
}
|
|
3346
3031
|
|
|
3347
|
-
// src/
|
|
3348
|
-
var
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
const {
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
const didChange = writer.accumulator.storePixelBeforeState(x, y);
|
|
3358
|
-
return didChange(blendPixel2(writer.config.target, x, y, color, alpha, blendFn));
|
|
3359
|
-
}
|
|
3032
|
+
// src/Internal/helpers.ts
|
|
3033
|
+
var macro_halfAndFloor = (value) => value >> 1;
|
|
3034
|
+
|
|
3035
|
+
// src/Rect/trimRectBounds.ts
|
|
3036
|
+
function trimRectBounds(x, y, w, h, targetWidth, targetHeight, out) {
|
|
3037
|
+
const res = out ?? {
|
|
3038
|
+
x: 0,
|
|
3039
|
+
y: 0,
|
|
3040
|
+
w: 0,
|
|
3041
|
+
h: 0
|
|
3360
3042
|
};
|
|
3361
|
-
|
|
3043
|
+
const left = Math.max(0, x);
|
|
3044
|
+
const top = Math.max(0, y);
|
|
3045
|
+
const right = Math.min(targetWidth, x + w);
|
|
3046
|
+
const bottom = Math.min(targetHeight, y + h);
|
|
3047
|
+
res.x = left;
|
|
3048
|
+
res.y = top;
|
|
3049
|
+
res.w = Math.max(0, right - left);
|
|
3050
|
+
res.h = Math.max(0, bottom - top);
|
|
3051
|
+
return res;
|
|
3052
|
+
}
|
|
3362
3053
|
|
|
3363
|
-
// src/
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
sy: sourceY = 0,
|
|
3370
|
-
w: width = src.width,
|
|
3371
|
-
h: height = src.height,
|
|
3372
|
-
alpha: globalAlpha = 255,
|
|
3373
|
-
blendFn = sourceOverPerfect
|
|
3374
|
-
} = opts;
|
|
3375
|
-
if (globalAlpha === 0) return false;
|
|
3376
|
-
let x = targetX;
|
|
3377
|
-
let y = targetY;
|
|
3378
|
-
let sx = sourceX;
|
|
3379
|
-
let sy = sourceY;
|
|
3380
|
-
let w = width;
|
|
3381
|
-
let h = height;
|
|
3382
|
-
if (sx < 0) {
|
|
3383
|
-
x -= sx;
|
|
3384
|
-
w += sx;
|
|
3385
|
-
sx = 0;
|
|
3386
|
-
}
|
|
3387
|
-
if (sy < 0) {
|
|
3388
|
-
y -= sy;
|
|
3389
|
-
h += sy;
|
|
3390
|
-
sy = 0;
|
|
3391
|
-
}
|
|
3392
|
-
w = Math.min(w, src.width - sx);
|
|
3393
|
-
h = Math.min(h, src.height - sy);
|
|
3394
|
-
if (x < 0) {
|
|
3395
|
-
sx -= x;
|
|
3396
|
-
w += x;
|
|
3397
|
-
x = 0;
|
|
3398
|
-
}
|
|
3399
|
-
if (y < 0) {
|
|
3400
|
-
sy -= y;
|
|
3401
|
-
h += y;
|
|
3402
|
-
y = 0;
|
|
3403
|
-
}
|
|
3404
|
-
const actualW = Math.min(w, dst.width - x);
|
|
3405
|
-
const actualH = Math.min(h, dst.height - y);
|
|
3406
|
-
if (actualW <= 0 || actualH <= 0) return false;
|
|
3407
|
-
const dst32 = dst.data32;
|
|
3408
|
-
const src32 = src.data32;
|
|
3409
|
-
const dw = dst.width;
|
|
3410
|
-
const sw = src.width;
|
|
3411
|
-
let dIdx = y * dw + x | 0;
|
|
3412
|
-
let sIdx = sy * sw + sx | 0;
|
|
3413
|
-
const dStride = dw - actualW | 0;
|
|
3414
|
-
const sStride = sw - actualW | 0;
|
|
3415
|
-
const isOpaque = globalAlpha === 255;
|
|
3416
|
-
const isOverwrite = blendFn.isOverwrite;
|
|
3417
|
-
let didChange = false;
|
|
3418
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
3419
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
3420
|
-
const srcCol = src32[sIdx];
|
|
3421
|
-
const srcAlpha = srcCol >>> 24;
|
|
3422
|
-
if (srcAlpha === 0 && !isOverwrite) {
|
|
3423
|
-
dIdx++;
|
|
3424
|
-
sIdx++;
|
|
3425
|
-
continue;
|
|
3426
|
-
}
|
|
3427
|
-
let finalCol = srcCol;
|
|
3428
|
-
if (!isOpaque) {
|
|
3429
|
-
const a = srcAlpha * globalAlpha + 128 >> 8;
|
|
3430
|
-
if (a === 0 && !isOverwrite) {
|
|
3431
|
-
dIdx++;
|
|
3432
|
-
sIdx++;
|
|
3433
|
-
continue;
|
|
3434
|
-
}
|
|
3435
|
-
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
3436
|
-
}
|
|
3437
|
-
const current = dst32[dIdx];
|
|
3438
|
-
const next = blendFn(finalCol, dst32[dIdx]);
|
|
3439
|
-
if (current !== next) {
|
|
3440
|
-
dst32[dIdx] = next;
|
|
3441
|
-
didChange = true;
|
|
3442
|
-
}
|
|
3443
|
-
dIdx++;
|
|
3444
|
-
sIdx++;
|
|
3445
|
-
}
|
|
3446
|
-
dIdx += dStride;
|
|
3447
|
-
sIdx += sStride;
|
|
3448
|
-
}
|
|
3449
|
-
return didChange;
|
|
3450
|
-
}
|
|
3451
|
-
|
|
3452
|
-
// src/History/PixelMutator/mutatorBlendPixelData.ts
|
|
3453
|
-
var defaults14 = {
|
|
3454
|
-
blendPixelData
|
|
3455
|
-
};
|
|
3456
|
-
var mutatorBlendPixelData = ((writer, deps = defaults14) => {
|
|
3457
|
-
const {
|
|
3458
|
-
blendPixelData: blendPixelData2 = defaults14.blendPixelData
|
|
3459
|
-
} = deps;
|
|
3460
|
-
return {
|
|
3461
|
-
blendPixelData(src, opts = {}) {
|
|
3462
|
-
const {
|
|
3463
|
-
x = 0,
|
|
3464
|
-
y = 0,
|
|
3465
|
-
w = src.width,
|
|
3466
|
-
h = src.height
|
|
3467
|
-
} = opts;
|
|
3468
|
-
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3469
|
-
return didChange(blendPixelData2(writer.config.target, src, opts));
|
|
3470
|
-
}
|
|
3471
|
-
};
|
|
3472
|
-
});
|
|
3473
|
-
|
|
3474
|
-
// src/PixelData/blendPixelDataAlphaMask.ts
|
|
3475
|
-
function blendPixelDataAlphaMask(dst, src, alphaMask, opts = {}) {
|
|
3476
|
-
const {
|
|
3477
|
-
x: targetX = 0,
|
|
3478
|
-
y: targetY = 0,
|
|
3479
|
-
sx: sourceX = 0,
|
|
3480
|
-
sy: sourceY = 0,
|
|
3481
|
-
w: width = src.width,
|
|
3482
|
-
h: height = src.height,
|
|
3483
|
-
alpha: globalAlpha = 255,
|
|
3484
|
-
blendFn = sourceOverPerfect,
|
|
3485
|
-
mx = 0,
|
|
3486
|
-
my = 0,
|
|
3487
|
-
invertMask = false
|
|
3488
|
-
} = opts;
|
|
3489
|
-
if (globalAlpha === 0) return false;
|
|
3490
|
-
let x = targetX;
|
|
3491
|
-
let y = targetY;
|
|
3492
|
-
let sx = sourceX;
|
|
3493
|
-
let sy = sourceY;
|
|
3494
|
-
let w = width;
|
|
3495
|
-
let h = height;
|
|
3496
|
-
if (sx < 0) {
|
|
3497
|
-
x -= sx;
|
|
3498
|
-
w += sx;
|
|
3499
|
-
sx = 0;
|
|
3500
|
-
}
|
|
3501
|
-
if (sy < 0) {
|
|
3502
|
-
y -= sy;
|
|
3503
|
-
h += sy;
|
|
3504
|
-
sy = 0;
|
|
3505
|
-
}
|
|
3506
|
-
w = Math.min(w, src.width - sx);
|
|
3507
|
-
h = Math.min(h, src.height - sy);
|
|
3508
|
-
if (x < 0) {
|
|
3509
|
-
sx -= x;
|
|
3510
|
-
w += x;
|
|
3511
|
-
x = 0;
|
|
3512
|
-
}
|
|
3513
|
-
if (y < 0) {
|
|
3514
|
-
sy -= y;
|
|
3515
|
-
h += y;
|
|
3516
|
-
y = 0;
|
|
3517
|
-
}
|
|
3518
|
-
const actualW = Math.min(w, dst.width - x);
|
|
3519
|
-
const actualH = Math.min(h, dst.height - y);
|
|
3520
|
-
if (actualW <= 0 || actualH <= 0) return false;
|
|
3521
|
-
const dw = dst.width;
|
|
3522
|
-
const sw = src.width;
|
|
3523
|
-
const mPitch = alphaMask.w;
|
|
3524
|
-
const maskData = alphaMask.data;
|
|
3525
|
-
const dx = x - targetX | 0;
|
|
3526
|
-
const dy = y - targetY | 0;
|
|
3527
|
-
const dst32 = dst.data32;
|
|
3528
|
-
const src32 = src.data32;
|
|
3529
|
-
let dIdx = y * dw + x | 0;
|
|
3530
|
-
let sIdx = sy * sw + sx | 0;
|
|
3531
|
-
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
3532
|
-
const dStride = dw - actualW | 0;
|
|
3533
|
-
const sStride = sw - actualW | 0;
|
|
3534
|
-
const mStride = mPitch - actualW | 0;
|
|
3535
|
-
const isOpaque = globalAlpha === 255;
|
|
3536
|
-
const isOverwrite = blendFn.isOverwrite || false;
|
|
3537
|
-
let didChange = false;
|
|
3538
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
3539
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
3540
|
-
const mVal = maskData[mIdx];
|
|
3541
|
-
const effM = invertMask ? 255 - mVal : mVal;
|
|
3542
|
-
if (effM === 0) {
|
|
3543
|
-
dIdx++;
|
|
3544
|
-
sIdx++;
|
|
3545
|
-
mIdx++;
|
|
3546
|
-
continue;
|
|
3547
|
-
}
|
|
3548
|
-
const srcCol = src32[sIdx];
|
|
3549
|
-
const srcAlpha = srcCol >>> 24;
|
|
3550
|
-
if (srcAlpha === 0 && !isOverwrite) {
|
|
3551
|
-
dIdx++;
|
|
3552
|
-
sIdx++;
|
|
3553
|
-
mIdx++;
|
|
3554
|
-
continue;
|
|
3555
|
-
}
|
|
3556
|
-
let weight = globalAlpha;
|
|
3557
|
-
if (isOpaque) {
|
|
3558
|
-
weight = effM;
|
|
3559
|
-
} else if (effM !== 255) {
|
|
3560
|
-
weight = effM * globalAlpha + 128 >> 8;
|
|
3561
|
-
}
|
|
3562
|
-
if (weight === 0) {
|
|
3563
|
-
dIdx++;
|
|
3564
|
-
sIdx++;
|
|
3565
|
-
mIdx++;
|
|
3566
|
-
continue;
|
|
3567
|
-
}
|
|
3568
|
-
let finalCol = srcCol;
|
|
3569
|
-
if (weight < 255) {
|
|
3570
|
-
const a = srcAlpha * weight + 128 >> 8;
|
|
3571
|
-
if (a === 0 && !isOverwrite) {
|
|
3572
|
-
dIdx++;
|
|
3573
|
-
sIdx++;
|
|
3574
|
-
mIdx++;
|
|
3575
|
-
continue;
|
|
3576
|
-
}
|
|
3577
|
-
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
3578
|
-
}
|
|
3579
|
-
const current = dst32[dIdx];
|
|
3580
|
-
const next = blendFn(finalCol, dst32[dIdx]);
|
|
3581
|
-
if (current !== next) {
|
|
3582
|
-
dst32[dIdx] = next;
|
|
3583
|
-
didChange = true;
|
|
3584
|
-
}
|
|
3585
|
-
dIdx++;
|
|
3586
|
-
sIdx++;
|
|
3587
|
-
mIdx++;
|
|
3588
|
-
}
|
|
3589
|
-
dIdx += dStride;
|
|
3590
|
-
sIdx += sStride;
|
|
3591
|
-
mIdx += mStride;
|
|
3592
|
-
}
|
|
3593
|
-
return didChange;
|
|
3594
|
-
}
|
|
3595
|
-
|
|
3596
|
-
// src/History/PixelMutator/mutatorBlendPixelDataAlphaMask.ts
|
|
3597
|
-
var defaults15 = {
|
|
3598
|
-
blendPixelDataAlphaMask
|
|
3599
|
-
};
|
|
3600
|
-
var mutatorBlendPixelDataAlphaMask = ((writer, deps = defaults15) => {
|
|
3601
|
-
const {
|
|
3602
|
-
blendPixelDataAlphaMask: blendPixelDataAlphaMask2 = defaults15.blendPixelDataAlphaMask
|
|
3603
|
-
} = deps;
|
|
3604
|
-
return {
|
|
3605
|
-
blendPixelDataAlphaMask(src, mask, opts = {}) {
|
|
3606
|
-
const x = opts.x ?? 0;
|
|
3607
|
-
const y = opts.y ?? 0;
|
|
3608
|
-
const w = opts.w ?? src.width;
|
|
3609
|
-
const h = opts.h ?? src.height;
|
|
3610
|
-
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3611
|
-
return didChange(blendPixelDataAlphaMask2(writer.config.target, src, mask, opts));
|
|
3612
|
-
}
|
|
3613
|
-
};
|
|
3614
|
-
});
|
|
3615
|
-
|
|
3616
|
-
// src/PixelData/blendPixelDataBinaryMask.ts
|
|
3617
|
-
function blendPixelDataBinaryMask(dst, src, binaryMask, opts = {}) {
|
|
3618
|
-
const {
|
|
3619
|
-
x: targetX = 0,
|
|
3620
|
-
y: targetY = 0,
|
|
3621
|
-
sx: sourceX = 0,
|
|
3622
|
-
sy: sourceY = 0,
|
|
3623
|
-
w: width = src.width,
|
|
3624
|
-
h: height = src.height,
|
|
3625
|
-
alpha: globalAlpha = 255,
|
|
3626
|
-
blendFn = sourceOverPerfect,
|
|
3627
|
-
mx = 0,
|
|
3628
|
-
my = 0,
|
|
3629
|
-
invertMask = false
|
|
3630
|
-
} = opts;
|
|
3631
|
-
if (globalAlpha === 0) return false;
|
|
3632
|
-
let x = targetX;
|
|
3633
|
-
let y = targetY;
|
|
3634
|
-
let sx = sourceX;
|
|
3635
|
-
let sy = sourceY;
|
|
3636
|
-
let w = width;
|
|
3637
|
-
let h = height;
|
|
3638
|
-
if (sx < 0) {
|
|
3639
|
-
x -= sx;
|
|
3640
|
-
w += sx;
|
|
3641
|
-
sx = 0;
|
|
3642
|
-
}
|
|
3643
|
-
if (sy < 0) {
|
|
3644
|
-
y -= sy;
|
|
3645
|
-
h += sy;
|
|
3646
|
-
sy = 0;
|
|
3647
|
-
}
|
|
3648
|
-
w = Math.min(w, src.width - sx);
|
|
3649
|
-
h = Math.min(h, src.height - sy);
|
|
3650
|
-
if (x < 0) {
|
|
3651
|
-
sx -= x;
|
|
3652
|
-
w += x;
|
|
3653
|
-
x = 0;
|
|
3654
|
-
}
|
|
3655
|
-
if (y < 0) {
|
|
3656
|
-
sy -= y;
|
|
3657
|
-
h += y;
|
|
3658
|
-
y = 0;
|
|
3054
|
+
// src/Paint/PaintBuffer.ts
|
|
3055
|
+
var PaintBuffer = class {
|
|
3056
|
+
constructor(config, tilePool) {
|
|
3057
|
+
this.config = config;
|
|
3058
|
+
this.tilePool = tilePool;
|
|
3059
|
+
this.lookup = [];
|
|
3659
3060
|
}
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
let finalCol = srcCol;
|
|
3698
|
-
if (!isOpaque) {
|
|
3699
|
-
const a = srcAlpha * globalAlpha + 128 >> 8;
|
|
3700
|
-
if (a === 0 && !isOverwrite) {
|
|
3701
|
-
dIdx++;
|
|
3702
|
-
sIdx++;
|
|
3703
|
-
mIdx++;
|
|
3704
|
-
continue;
|
|
3705
|
-
}
|
|
3706
|
-
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
3707
|
-
}
|
|
3708
|
-
const current = dst32[dIdx];
|
|
3709
|
-
const next = blendFn(finalCol, dst32[dIdx]);
|
|
3710
|
-
if (current !== next) {
|
|
3711
|
-
dst32[dIdx] = next;
|
|
3712
|
-
didChange = true;
|
|
3061
|
+
lookup;
|
|
3062
|
+
scratchBounds = {
|
|
3063
|
+
x: 0,
|
|
3064
|
+
y: 0,
|
|
3065
|
+
w: 0,
|
|
3066
|
+
h: 0
|
|
3067
|
+
};
|
|
3068
|
+
eachTileInBounds(bounds, callback) {
|
|
3069
|
+
const {
|
|
3070
|
+
tileShift,
|
|
3071
|
+
targetColumns,
|
|
3072
|
+
targetRows,
|
|
3073
|
+
tileSize
|
|
3074
|
+
} = this.config;
|
|
3075
|
+
const x1 = Math.max(0, bounds.x >> tileShift);
|
|
3076
|
+
const y1 = Math.max(0, bounds.y >> tileShift);
|
|
3077
|
+
const x2 = Math.min(targetColumns - 1, bounds.x + bounds.w - 1 >> tileShift);
|
|
3078
|
+
const y2 = Math.min(targetRows - 1, bounds.y + bounds.h - 1 >> tileShift);
|
|
3079
|
+
if (x1 > x2 || y1 > y2) return;
|
|
3080
|
+
const lookup = this.lookup;
|
|
3081
|
+
const tilePool = this.tilePool;
|
|
3082
|
+
for (let ty = y1; ty <= y2; ty++) {
|
|
3083
|
+
const rowOffset = ty * targetColumns;
|
|
3084
|
+
const tileTop = ty << tileShift;
|
|
3085
|
+
for (let tx = x1; tx <= x2; tx++) {
|
|
3086
|
+
const id = rowOffset + tx;
|
|
3087
|
+
const tile = lookup[id] ?? (lookup[id] = tilePool.getTile(id, tx, ty));
|
|
3088
|
+
const tileLeft = tx << tileShift;
|
|
3089
|
+
const startX = bounds.x > tileLeft ? bounds.x : tileLeft;
|
|
3090
|
+
const startY = bounds.y > tileTop ? bounds.y : tileTop;
|
|
3091
|
+
const maskEndX = bounds.x + bounds.w;
|
|
3092
|
+
const tileEndX = tileLeft + tileSize;
|
|
3093
|
+
const endX = maskEndX < tileEndX ? maskEndX : tileEndX;
|
|
3094
|
+
const maskEndY = bounds.y + bounds.h;
|
|
3095
|
+
const tileEndY = tileTop + tileSize;
|
|
3096
|
+
const endY = maskEndY < tileEndY ? maskEndY : tileEndY;
|
|
3097
|
+
callback(tile, startX, startY, endX - startX, endY - startY);
|
|
3713
3098
|
}
|
|
3714
|
-
dIdx++;
|
|
3715
|
-
sIdx++;
|
|
3716
|
-
mIdx++;
|
|
3717
3099
|
}
|
|
3718
|
-
dIdx += dStride;
|
|
3719
|
-
sIdx += sStride;
|
|
3720
|
-
mIdx += mStride;
|
|
3721
3100
|
}
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3101
|
+
writePaintAlphaMaskStroke(color, brush, x0, y0, x1, y1) {
|
|
3102
|
+
const cA = color >>> 24;
|
|
3103
|
+
if (cA === 0) return false;
|
|
3104
|
+
const {
|
|
3105
|
+
tileShift,
|
|
3106
|
+
tileMask,
|
|
3107
|
+
target
|
|
3108
|
+
} = this.config;
|
|
3109
|
+
const {
|
|
3110
|
+
w: bW,
|
|
3111
|
+
h: bH,
|
|
3112
|
+
data: bD,
|
|
3113
|
+
centerOffsetX,
|
|
3114
|
+
centerOffsetY
|
|
3115
|
+
} = brush;
|
|
3116
|
+
const cRGB = color & 16777215;
|
|
3117
|
+
const scratch = this.scratchBounds;
|
|
3118
|
+
let changed = false;
|
|
3119
|
+
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
3120
|
+
const topLeftX = Math.floor(px + centerOffsetX);
|
|
3121
|
+
const topLeftY = Math.floor(py + centerOffsetY);
|
|
3122
|
+
trimRectBounds(topLeftX, topLeftY, bW, bH, target.width, target.height, scratch);
|
|
3123
|
+
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
3124
|
+
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
3125
|
+
const d32 = tile.data32;
|
|
3126
|
+
let tileChanged = false;
|
|
3127
|
+
for (let i = 0; i < bH_t; i++) {
|
|
3128
|
+
const canvasY = bY + i;
|
|
3129
|
+
const bOff = (canvasY - topLeftY) * bW;
|
|
3130
|
+
const tOff = (canvasY & tileMask) << tileShift;
|
|
3131
|
+
const dS = tOff + (bX & tileMask);
|
|
3132
|
+
for (let j = 0; j < bW_t; j++) {
|
|
3133
|
+
const canvasX = bX + j;
|
|
3134
|
+
const brushA = bD[bOff + (canvasX - topLeftX)];
|
|
3135
|
+
if (brushA === 0) continue;
|
|
3136
|
+
const t = cA * brushA + 128;
|
|
3137
|
+
const blendedA = t + (t >> 8) >> 8;
|
|
3138
|
+
const idx = dS + j;
|
|
3139
|
+
const cur = d32[idx];
|
|
3140
|
+
if (brushA > cur >>> 24) {
|
|
3141
|
+
const next = (cRGB | blendedA << 24) >>> 0;
|
|
3142
|
+
if (cur !== next) {
|
|
3143
|
+
d32[idx] = next;
|
|
3144
|
+
tileChanged = true;
|
|
3145
|
+
}
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
}
|
|
3149
|
+
if (tileChanged) changed = true;
|
|
3150
|
+
});
|
|
3151
|
+
});
|
|
3152
|
+
return changed;
|
|
3767
3153
|
}
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3154
|
+
writePaintBinaryMaskStroke(color, brush, x0, y0, x1, y1) {
|
|
3155
|
+
const alphaIsZero = color >>> 24 === 0;
|
|
3156
|
+
if (alphaIsZero) return false;
|
|
3157
|
+
const {
|
|
3158
|
+
tileShift,
|
|
3159
|
+
tileMask,
|
|
3160
|
+
target
|
|
3161
|
+
} = this.config;
|
|
3162
|
+
const {
|
|
3163
|
+
w: bW,
|
|
3164
|
+
h: bH,
|
|
3165
|
+
data: bD,
|
|
3166
|
+
centerOffsetX,
|
|
3167
|
+
centerOffsetY
|
|
3168
|
+
} = brush;
|
|
3169
|
+
const scratch = this.scratchBounds;
|
|
3170
|
+
let changed = false;
|
|
3171
|
+
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
3172
|
+
const topLeftX = Math.floor(px + centerOffsetX);
|
|
3173
|
+
const topLeftY = Math.floor(py + centerOffsetY);
|
|
3174
|
+
trimRectBounds(topLeftX, topLeftY, bW, bH, target.width, target.height, scratch);
|
|
3175
|
+
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
3176
|
+
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
3177
|
+
const d32 = tile.data32;
|
|
3178
|
+
let tileChanged = false;
|
|
3179
|
+
for (let i = 0; i < bH_t; i++) {
|
|
3180
|
+
const canvasY = bY + i;
|
|
3181
|
+
const bOff = (canvasY - topLeftY) * bW;
|
|
3182
|
+
const tOff = (canvasY & tileMask) << tileShift;
|
|
3183
|
+
const dS = tOff + (bX & tileMask);
|
|
3184
|
+
for (let j = 0; j < bW_t; j++) {
|
|
3185
|
+
const canvasX = bX + j;
|
|
3186
|
+
if (bD[bOff + (canvasX - topLeftX)]) {
|
|
3187
|
+
const idx = dS + j;
|
|
3188
|
+
if (d32[idx] !== color) {
|
|
3189
|
+
d32[idx] = color;
|
|
3190
|
+
tileChanged = true;
|
|
3191
|
+
}
|
|
3192
|
+
}
|
|
3193
|
+
}
|
|
3194
|
+
}
|
|
3195
|
+
if (tileChanged) changed = true;
|
|
3196
|
+
});
|
|
3197
|
+
});
|
|
3198
|
+
return changed;
|
|
3199
|
+
}
|
|
3200
|
+
writeRectStroke(color, brushWidth, brushHeight, x0, y0, x1, y1) {
|
|
3201
|
+
const alphaIsZero = color >>> 24 === 0;
|
|
3202
|
+
if (alphaIsZero) return false;
|
|
3203
|
+
const config = this.config;
|
|
3204
|
+
const tileShift = config.tileShift;
|
|
3205
|
+
const tileMask = config.tileMask;
|
|
3206
|
+
const target = config.target;
|
|
3207
|
+
const scratch = this.scratchBounds;
|
|
3208
|
+
const centerOffsetX = macro_halfAndFloor(brushWidth - 1);
|
|
3209
|
+
const centerOffsetY = macro_halfAndFloor(brushHeight - 1);
|
|
3210
|
+
let changed = false;
|
|
3211
|
+
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
3212
|
+
const topLeftX = Math.floor(px + centerOffsetX);
|
|
3213
|
+
const topLeftY = Math.floor(py + centerOffsetY);
|
|
3214
|
+
trimRectBounds(topLeftX, topLeftY, brushWidth, brushHeight, target.width, target.height, scratch);
|
|
3215
|
+
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
3216
|
+
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
3217
|
+
const d32 = tile.data32;
|
|
3218
|
+
let tileChanged = false;
|
|
3219
|
+
for (let i = 0; i < bH_t; i++) {
|
|
3220
|
+
const canvasY = bY + i;
|
|
3221
|
+
const tOff = (canvasY & tileMask) << tileShift;
|
|
3222
|
+
const dS = tOff + (bX & tileMask);
|
|
3223
|
+
for (let j = 0; j < bW_t; j++) {
|
|
3224
|
+
const idx = dS + j;
|
|
3225
|
+
if (d32[idx] !== color) {
|
|
3226
|
+
d32[idx] = color;
|
|
3227
|
+
tileChanged = true;
|
|
3228
|
+
}
|
|
3229
|
+
}
|
|
3230
|
+
}
|
|
3231
|
+
if (tileChanged) {
|
|
3232
|
+
changed = true;
|
|
3233
|
+
}
|
|
3234
|
+
});
|
|
3235
|
+
});
|
|
3236
|
+
return changed;
|
|
3781
3237
|
}
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
const end = start + actualW;
|
|
3785
|
-
dst32.fill(color, start, end);
|
|
3238
|
+
clear() {
|
|
3239
|
+
this.tilePool.releaseTiles(this.lookup);
|
|
3786
3240
|
}
|
|
3787
|
-
}
|
|
3241
|
+
};
|
|
3788
3242
|
|
|
3789
|
-
// src/
|
|
3790
|
-
var
|
|
3791
|
-
|
|
3243
|
+
// src/PixelTile/PixelTile.ts
|
|
3244
|
+
var PixelTile = class {
|
|
3245
|
+
constructor(id, tx, ty, tileSize, tileArea) {
|
|
3246
|
+
this.id = id;
|
|
3247
|
+
this.tx = tx;
|
|
3248
|
+
this.ty = ty;
|
|
3249
|
+
this.width = this.height = tileSize;
|
|
3250
|
+
this.data32 = new Uint32Array(tileArea);
|
|
3251
|
+
const data8 = new Uint8ClampedArray(this.data32.buffer);
|
|
3252
|
+
this.imageData = new ImageData(data8, tileSize, tileSize);
|
|
3253
|
+
}
|
|
3254
|
+
data32;
|
|
3255
|
+
width;
|
|
3256
|
+
height;
|
|
3257
|
+
imageData;
|
|
3792
3258
|
};
|
|
3793
|
-
var mutatorClear = ((writer, deps = defaults17) => {
|
|
3794
|
-
const {
|
|
3795
|
-
fillPixelData: fillPixelData2 = defaults17.fillPixelData
|
|
3796
|
-
} = deps;
|
|
3797
|
-
return {
|
|
3798
|
-
clear(rect = {}) {
|
|
3799
|
-
const target = writer.config.target;
|
|
3800
|
-
const x = rect.x ?? 0;
|
|
3801
|
-
const y = rect.y ?? 0;
|
|
3802
|
-
const w = rect.w ?? target.width;
|
|
3803
|
-
const h = rect.h ?? target.height;
|
|
3804
|
-
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3805
|
-
fillPixelData2(target, 0, x, y, w, h);
|
|
3806
|
-
}
|
|
3807
|
-
};
|
|
3808
|
-
});
|
|
3809
3259
|
|
|
3810
|
-
// src/
|
|
3811
|
-
var
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
y = _x.y ?? 0;
|
|
3820
|
-
w = _x.w ?? dst.width;
|
|
3821
|
-
h = _x.h ?? dst.height;
|
|
3822
|
-
} else if (typeof _x === "number") {
|
|
3823
|
-
x = _x;
|
|
3824
|
-
y = _y;
|
|
3825
|
-
w = _w;
|
|
3826
|
-
h = _h;
|
|
3827
|
-
} else {
|
|
3828
|
-
x = 0;
|
|
3829
|
-
y = 0;
|
|
3830
|
-
w = dst.width;
|
|
3831
|
-
h = dst.height;
|
|
3260
|
+
// src/PixelTile/PixelTilePool.ts
|
|
3261
|
+
var PixelTilePool = class {
|
|
3262
|
+
pool;
|
|
3263
|
+
tileSize;
|
|
3264
|
+
tileArea;
|
|
3265
|
+
constructor(config) {
|
|
3266
|
+
this.pool = [];
|
|
3267
|
+
this.tileSize = config.tileSize;
|
|
3268
|
+
this.tileArea = config.tileArea;
|
|
3832
3269
|
}
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3270
|
+
getTile(id, tx, ty) {
|
|
3271
|
+
let tile = this.pool.pop();
|
|
3272
|
+
if (tile) {
|
|
3273
|
+
tile.id = id;
|
|
3274
|
+
tile.tx = tx;
|
|
3275
|
+
tile.ty = ty;
|
|
3276
|
+
tile.data32.fill(0);
|
|
3277
|
+
return tile;
|
|
3278
|
+
}
|
|
3279
|
+
return new PixelTile(id, tx, ty, this.tileSize, this.tileArea);
|
|
3280
|
+
}
|
|
3281
|
+
releaseTile(tile) {
|
|
3282
|
+
this.pool.push(tile);
|
|
3283
|
+
}
|
|
3284
|
+
releaseTiles(tiles) {
|
|
3285
|
+
let length = tiles.length;
|
|
3286
|
+
for (let i = 0; i < length; i++) {
|
|
3287
|
+
let tile = tiles[i];
|
|
3288
|
+
if (tile) {
|
|
3289
|
+
this.pool.push(tile);
|
|
3852
3290
|
}
|
|
3853
3291
|
}
|
|
3292
|
+
tiles.length = 0;
|
|
3854
3293
|
}
|
|
3855
|
-
return hasChanged;
|
|
3856
|
-
}
|
|
3857
|
-
|
|
3858
|
-
// src/History/PixelMutator/mutatorFill.ts
|
|
3859
|
-
var defaults18 = {
|
|
3860
|
-
fillPixelData
|
|
3861
3294
|
};
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3295
|
+
|
|
3296
|
+
// src/History/PixelWriter.ts
|
|
3297
|
+
var PixelWriter = class {
|
|
3298
|
+
historyManager;
|
|
3299
|
+
accumulator;
|
|
3300
|
+
historyActionFactory;
|
|
3301
|
+
config;
|
|
3302
|
+
pixelTilePool;
|
|
3303
|
+
paintBuffer;
|
|
3304
|
+
mutator;
|
|
3305
|
+
blendPixelDataOpts = {
|
|
3306
|
+
alpha: 255,
|
|
3307
|
+
blendFn: sourceOverPerfect,
|
|
3308
|
+
x: 0,
|
|
3309
|
+
y: 0,
|
|
3310
|
+
w: 0,
|
|
3311
|
+
h: 0
|
|
3872
3312
|
};
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3313
|
+
_inProgress = false;
|
|
3314
|
+
constructor(target, mutatorFactory, {
|
|
3315
|
+
tileSize = 256,
|
|
3316
|
+
maxHistorySteps = 50,
|
|
3317
|
+
historyManager = new HistoryManager(maxHistorySteps),
|
|
3318
|
+
historyActionFactory = makeHistoryAction,
|
|
3319
|
+
pixelTilePool,
|
|
3320
|
+
accumulator
|
|
3321
|
+
} = {}) {
|
|
3322
|
+
this.config = new PixelEngineConfig(tileSize, target);
|
|
3323
|
+
this.historyManager = historyManager;
|
|
3324
|
+
this.pixelTilePool = pixelTilePool ?? new PixelTilePool(this.config);
|
|
3325
|
+
this.accumulator = accumulator ?? new PixelAccumulator(this.config, this.pixelTilePool);
|
|
3326
|
+
this.historyActionFactory = historyActionFactory;
|
|
3327
|
+
this.mutator = mutatorFactory(this);
|
|
3328
|
+
this.paintBuffer = new PaintBuffer(this.config, this.pixelTilePool);
|
|
3329
|
+
}
|
|
3330
|
+
/**
|
|
3331
|
+
* Executes `transaction` and commits the resulting pixel changes as a single
|
|
3332
|
+
* undoable history action.
|
|
3333
|
+
*
|
|
3334
|
+
* - If `transaction` throws, all accumulated changes are rolled back and the error
|
|
3335
|
+
* is re-thrown. No action is committed.
|
|
3336
|
+
* - If `transaction` completes without modifying any pixels, no action is committed.
|
|
3337
|
+
* - `withHistory` is not re-entrant. Calling it again from inside `transaction` will
|
|
3338
|
+
* throw immediately to prevent silent data loss from a nested extractPatch.
|
|
3339
|
+
*
|
|
3340
|
+
* @param transaction Callback to be executed inside the transaction.
|
|
3341
|
+
* @param after Called after both undo and redo — use for generic change notifications.
|
|
3342
|
+
* @param afterUndo Called after undo only — use for dimension or state changes specific to undo.
|
|
3343
|
+
* @param afterRedo Called after redo only.
|
|
3344
|
+
*/
|
|
3345
|
+
withHistory(transaction, after, afterUndo, afterRedo) {
|
|
3346
|
+
if (this._inProgress) {
|
|
3347
|
+
throw new Error("withHistory is not re-entrant \u2014 commit or rollback the current operation first");
|
|
3883
3348
|
}
|
|
3884
|
-
|
|
3885
|
-
|
|
3349
|
+
this._inProgress = true;
|
|
3350
|
+
try {
|
|
3351
|
+
transaction(this.mutator);
|
|
3352
|
+
} catch (e) {
|
|
3353
|
+
this.accumulator.rollbackAfterError();
|
|
3354
|
+
throw e;
|
|
3355
|
+
} finally {
|
|
3356
|
+
this._inProgress = false;
|
|
3357
|
+
}
|
|
3358
|
+
if (this.accumulator.beforeTiles.length === 0) return;
|
|
3359
|
+
const patch = this.accumulator.extractPatch();
|
|
3360
|
+
const action = this.historyActionFactory(this, patch, after, afterUndo, afterRedo);
|
|
3361
|
+
this.historyManager.commit(action);
|
|
3362
|
+
}
|
|
3363
|
+
resize(newWidth, newHeight, offsetX = 0, offsetY = 0, after, afterUndo, afterRedo, resizeImageDataFn = resizeImageData) {
|
|
3364
|
+
if (this._inProgress) {
|
|
3365
|
+
throw new Error("Cannot resize inside a withHistory callback");
|
|
3366
|
+
}
|
|
3367
|
+
if (this.accumulator.beforeTiles.length > 0) {
|
|
3368
|
+
throw new Error("Cannot resize with an open accumulator \u2014 commit or rollback first");
|
|
3369
|
+
}
|
|
3370
|
+
const config = this.config;
|
|
3371
|
+
const target = config.target;
|
|
3372
|
+
const beforeImageData = target.imageData;
|
|
3373
|
+
const afterImageData = resizeImageDataFn(beforeImageData, newWidth, newHeight, offsetX, offsetY);
|
|
3374
|
+
target.set(afterImageData);
|
|
3375
|
+
this.historyManager.commit({
|
|
3376
|
+
undo: () => {
|
|
3377
|
+
target.set(beforeImageData);
|
|
3378
|
+
afterUndo?.(beforeImageData);
|
|
3379
|
+
after?.(beforeImageData);
|
|
3380
|
+
},
|
|
3381
|
+
redo: () => {
|
|
3382
|
+
target.set(afterImageData);
|
|
3383
|
+
afterRedo?.(afterImageData);
|
|
3384
|
+
after?.(afterImageData);
|
|
3385
|
+
}
|
|
3386
|
+
});
|
|
3387
|
+
}
|
|
3388
|
+
commitPaintBuffer(alpha = 255, blendFn = sourceOverPerfect, blendPixelDataFn = blendPixelData) {
|
|
3389
|
+
const paintBuffer = this.paintBuffer;
|
|
3390
|
+
const tileShift = paintBuffer.config.tileShift;
|
|
3391
|
+
const lookup = paintBuffer.lookup;
|
|
3392
|
+
const opts = this.blendPixelDataOpts;
|
|
3393
|
+
opts.alpha = alpha;
|
|
3394
|
+
opts.blendFn = blendFn;
|
|
3395
|
+
for (let i = 0; i < lookup.length; i++) {
|
|
3396
|
+
const tile = lookup[i];
|
|
3397
|
+
if (tile) {
|
|
3398
|
+
const didChange = this.accumulator.storeTileBeforeState(tile.id, tile.tx, tile.ty);
|
|
3399
|
+
const dx = tile.tx << tileShift;
|
|
3400
|
+
const dy = tile.ty << tileShift;
|
|
3401
|
+
opts.x = dx;
|
|
3402
|
+
opts.y = dy;
|
|
3403
|
+
opts.w = tile.width;
|
|
3404
|
+
opts.h = tile.height;
|
|
3405
|
+
didChange(blendPixelDataFn(this.config.target, tile, opts));
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
paintBuffer.clear();
|
|
3409
|
+
}
|
|
3410
|
+
};
|
|
3886
3411
|
|
|
3887
|
-
// src/PixelData/
|
|
3888
|
-
|
|
3889
|
-
function fillPixelDataBinaryMask(dst, color, mask, alpha = 255, x = 0, y = 0) {
|
|
3890
|
-
if (alpha === 0) return false;
|
|
3891
|
-
const maskW = mask.w;
|
|
3892
|
-
const maskH = mask.h;
|
|
3893
|
-
const clip = resolveRectClipping(x, y, maskW, maskH, dst.width, dst.height, SCRATCH_RECT3);
|
|
3894
|
-
if (!clip.inBounds) return false;
|
|
3412
|
+
// src/PixelData/applyAlphaMaskToPixelData.ts
|
|
3413
|
+
function applyAlphaMaskToPixelData(dst, mask, opts = {}) {
|
|
3895
3414
|
const {
|
|
3896
|
-
x:
|
|
3897
|
-
y:
|
|
3898
|
-
w:
|
|
3899
|
-
h:
|
|
3900
|
-
|
|
3901
|
-
|
|
3415
|
+
x: targetX = 0,
|
|
3416
|
+
y: targetY = 0,
|
|
3417
|
+
w: width = dst.width,
|
|
3418
|
+
h: height = dst.height,
|
|
3419
|
+
alpha: globalAlpha = 255,
|
|
3420
|
+
mx = 0,
|
|
3421
|
+
my = 0,
|
|
3422
|
+
invertMask = false
|
|
3423
|
+
} = opts;
|
|
3424
|
+
if (globalAlpha === 0) return false;
|
|
3425
|
+
let x = targetX;
|
|
3426
|
+
let y = targetY;
|
|
3427
|
+
let w = width;
|
|
3428
|
+
let h = height;
|
|
3429
|
+
if (x < 0) {
|
|
3430
|
+
w += x;
|
|
3431
|
+
x = 0;
|
|
3432
|
+
}
|
|
3433
|
+
if (y < 0) {
|
|
3434
|
+
h += y;
|
|
3435
|
+
y = 0;
|
|
3436
|
+
}
|
|
3437
|
+
w = Math.min(w, dst.width - x);
|
|
3438
|
+
h = Math.min(h, dst.height - y);
|
|
3439
|
+
if (w <= 0) return false;
|
|
3440
|
+
if (h <= 0) return false;
|
|
3441
|
+
const mPitch = mask.w;
|
|
3442
|
+
if (mPitch <= 0) return false;
|
|
3443
|
+
const startX = mx + (x - targetX);
|
|
3444
|
+
const startY = my + (y - targetY);
|
|
3445
|
+
const sX0 = Math.max(0, startX);
|
|
3446
|
+
const sY0 = Math.max(0, startY);
|
|
3447
|
+
const sX1 = Math.min(mPitch, startX + w);
|
|
3448
|
+
const sY1 = Math.min(mask.h, startY + h);
|
|
3449
|
+
const finalW = sX1 - sX0;
|
|
3450
|
+
const finalH = sY1 - sY0;
|
|
3451
|
+
if (finalW <= 0) return false;
|
|
3452
|
+
if (finalH <= 0) return false;
|
|
3453
|
+
const xShift = sX0 - startX;
|
|
3454
|
+
const yShift = sY0 - startY;
|
|
3902
3455
|
const dst32 = dst.data32;
|
|
3903
3456
|
const dw = dst.width;
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3457
|
+
const dStride = dw - finalW;
|
|
3458
|
+
const mStride = mPitch - finalW;
|
|
3459
|
+
const maskData = mask.data;
|
|
3460
|
+
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
3461
|
+
let mIdx = sY0 * mPitch + sX0;
|
|
3462
|
+
let didChange = false;
|
|
3463
|
+
for (let iy = 0; iy < h; iy++) {
|
|
3464
|
+
for (let ix = 0; ix < w; ix++) {
|
|
3465
|
+
const mVal = maskData[mIdx];
|
|
3466
|
+
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
3467
|
+
let weight = 0;
|
|
3468
|
+
if (effectiveM === 0) {
|
|
3469
|
+
weight = 0;
|
|
3470
|
+
} else if (effectiveM === 255) {
|
|
3471
|
+
weight = globalAlpha;
|
|
3472
|
+
} else if (globalAlpha === 255) {
|
|
3473
|
+
weight = effectiveM;
|
|
3474
|
+
} else {
|
|
3475
|
+
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
3476
|
+
}
|
|
3477
|
+
if (weight === 0) {
|
|
3478
|
+
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
3479
|
+
didChange = true;
|
|
3480
|
+
} else if (weight !== 255) {
|
|
3481
|
+
const d = dst32[dIdx];
|
|
3482
|
+
const da = d >>> 24;
|
|
3483
|
+
if (da !== 0) {
|
|
3484
|
+
const finalAlpha = da === 255 ? weight : da * weight + 128 >> 8;
|
|
3485
|
+
const current = dst32[dIdx];
|
|
3486
|
+
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
3487
|
+
if (current !== next) {
|
|
3488
|
+
dst32[dIdx] = next;
|
|
3489
|
+
didChange = true;
|
|
3490
|
+
}
|
|
3926
3491
|
}
|
|
3927
3492
|
}
|
|
3493
|
+
dIdx++;
|
|
3494
|
+
mIdx++;
|
|
3928
3495
|
}
|
|
3496
|
+
dIdx += dStride;
|
|
3497
|
+
mIdx += mStride;
|
|
3929
3498
|
}
|
|
3930
|
-
return
|
|
3499
|
+
return didChange;
|
|
3931
3500
|
}
|
|
3932
3501
|
|
|
3933
|
-
// src/History/PixelMutator/
|
|
3934
|
-
var
|
|
3935
|
-
|
|
3502
|
+
// src/History/PixelMutator/mutatorApplyAlphaMask.ts
|
|
3503
|
+
var defaults11 = {
|
|
3504
|
+
applyAlphaMaskToPixelData
|
|
3936
3505
|
};
|
|
3937
|
-
var
|
|
3506
|
+
var mutatorApplyAlphaMask = ((writer, deps = defaults11) => {
|
|
3938
3507
|
const {
|
|
3939
|
-
|
|
3508
|
+
applyAlphaMaskToPixelData: applyAlphaMaskToPixelData2 = defaults11.applyAlphaMaskToPixelData
|
|
3940
3509
|
} = deps;
|
|
3941
3510
|
return {
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3511
|
+
applyAlphaMask(mask, opts = {}) {
|
|
3512
|
+
let target = writer.config.target;
|
|
3513
|
+
const {
|
|
3514
|
+
x = 0,
|
|
3515
|
+
y = 0,
|
|
3516
|
+
w = target.width,
|
|
3517
|
+
h = target.height
|
|
3518
|
+
} = opts;
|
|
3519
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3520
|
+
return didChange(applyAlphaMaskToPixelData2(target, mask, opts));
|
|
3945
3521
|
}
|
|
3946
3522
|
};
|
|
3947
3523
|
});
|
|
3948
3524
|
|
|
3949
|
-
// src/PixelData/
|
|
3950
|
-
|
|
3951
|
-
function invertPixelData(pixelData, opts = {}) {
|
|
3952
|
-
const dst = pixelData;
|
|
3525
|
+
// src/PixelData/applyBinaryMaskToPixelData.ts
|
|
3526
|
+
function applyBinaryMaskToPixelData(dst, mask, opts = {}) {
|
|
3953
3527
|
const {
|
|
3954
3528
|
x: targetX = 0,
|
|
3955
3529
|
y: targetY = 0,
|
|
3956
|
-
w: width =
|
|
3957
|
-
h: height =
|
|
3958
|
-
|
|
3530
|
+
w: width = dst.width,
|
|
3531
|
+
h: height = dst.height,
|
|
3532
|
+
alpha: globalAlpha = 255,
|
|
3959
3533
|
mx = 0,
|
|
3960
3534
|
my = 0,
|
|
3961
3535
|
invertMask = false
|
|
3962
3536
|
} = opts;
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3537
|
+
if (globalAlpha === 0) return false;
|
|
3538
|
+
let x = targetX;
|
|
3539
|
+
let y = targetY;
|
|
3540
|
+
let w = width;
|
|
3541
|
+
let h = height;
|
|
3542
|
+
if (x < 0) {
|
|
3543
|
+
w += x;
|
|
3544
|
+
x = 0;
|
|
3545
|
+
}
|
|
3546
|
+
if (y < 0) {
|
|
3547
|
+
h += y;
|
|
3548
|
+
y = 0;
|
|
3549
|
+
}
|
|
3550
|
+
w = Math.min(w, dst.width - x);
|
|
3551
|
+
h = Math.min(h, dst.height - y);
|
|
3552
|
+
if (w <= 0 || h <= 0) return false;
|
|
3553
|
+
const mPitch = mask.w;
|
|
3554
|
+
if (mPitch <= 0) return false;
|
|
3555
|
+
const startX = mx + (x - targetX);
|
|
3556
|
+
const startY = my + (y - targetY);
|
|
3557
|
+
const sX0 = Math.max(0, startX);
|
|
3558
|
+
const sY0 = Math.max(0, startY);
|
|
3559
|
+
const sX1 = Math.min(mPitch, startX + w);
|
|
3560
|
+
const sY1 = Math.min(mask.h, startY + h);
|
|
3561
|
+
const finalW = sX1 - sX0;
|
|
3562
|
+
const finalH = sY1 - sY0;
|
|
3563
|
+
if (finalW <= 0 || finalH <= 0) {
|
|
3564
|
+
return false;
|
|
3565
|
+
}
|
|
3566
|
+
const xShift = sX0 - startX;
|
|
3567
|
+
const yShift = sY0 - startY;
|
|
3971
3568
|
const dst32 = dst.data32;
|
|
3972
3569
|
const dw = dst.width;
|
|
3973
|
-
const
|
|
3974
|
-
const
|
|
3975
|
-
const
|
|
3976
|
-
let dIdx = y * dw + x;
|
|
3977
|
-
let mIdx =
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
const
|
|
3985
|
-
const
|
|
3986
|
-
if (
|
|
3987
|
-
dst32[dIdx] =
|
|
3570
|
+
const dStride = dw - finalW;
|
|
3571
|
+
const mStride = mPitch - finalW;
|
|
3572
|
+
const maskData = mask.data;
|
|
3573
|
+
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
3574
|
+
let mIdx = sY0 * mPitch + sX0;
|
|
3575
|
+
let didChange = false;
|
|
3576
|
+
for (let iy = 0; iy < finalH; iy++) {
|
|
3577
|
+
for (let ix = 0; ix < finalW; ix++) {
|
|
3578
|
+
const mVal = maskData[mIdx];
|
|
3579
|
+
const isMaskedOut = invertMask ? mVal !== 0 : mVal === 0;
|
|
3580
|
+
if (isMaskedOut) {
|
|
3581
|
+
const current = dst32[dIdx];
|
|
3582
|
+
const next = (current & 16777215) >>> 0;
|
|
3583
|
+
if (current !== next) {
|
|
3584
|
+
dst32[dIdx] = next;
|
|
3585
|
+
didChange = true;
|
|
3586
|
+
}
|
|
3587
|
+
} else if (globalAlpha !== 255) {
|
|
3588
|
+
const d = dst32[dIdx];
|
|
3589
|
+
const da = d >>> 24;
|
|
3590
|
+
if (da !== 0) {
|
|
3591
|
+
const finalAlpha = da === 255 ? globalAlpha : da * globalAlpha + 128 >> 8;
|
|
3592
|
+
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
3593
|
+
if (d !== next) {
|
|
3594
|
+
dst32[dIdx] = next;
|
|
3595
|
+
didChange = true;
|
|
3596
|
+
}
|
|
3988
3597
|
}
|
|
3989
|
-
dIdx++;
|
|
3990
|
-
mIdx++;
|
|
3991
|
-
}
|
|
3992
|
-
dIdx += dStride;
|
|
3993
|
-
mIdx += mStride;
|
|
3994
|
-
}
|
|
3995
|
-
} else {
|
|
3996
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
3997
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
3998
|
-
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
3999
|
-
dIdx++;
|
|
4000
3598
|
}
|
|
4001
|
-
dIdx
|
|
3599
|
+
dIdx++;
|
|
3600
|
+
mIdx++;
|
|
4002
3601
|
}
|
|
3602
|
+
dIdx += dStride;
|
|
3603
|
+
mIdx += mStride;
|
|
4003
3604
|
}
|
|
4004
|
-
return
|
|
3605
|
+
return didChange;
|
|
4005
3606
|
}
|
|
4006
3607
|
|
|
4007
|
-
// src/History/PixelMutator/
|
|
4008
|
-
var
|
|
4009
|
-
|
|
3608
|
+
// src/History/PixelMutator/mutatorApplyBinaryMask.ts
|
|
3609
|
+
var defaults12 = {
|
|
3610
|
+
applyBinaryMaskToPixelData
|
|
4010
3611
|
};
|
|
4011
|
-
var
|
|
3612
|
+
var mutatorApplyBinaryMask = ((writer, deps = defaults12) => {
|
|
4012
3613
|
const {
|
|
4013
|
-
|
|
3614
|
+
applyBinaryMaskToPixelData: applyBinaryMaskToPixelData2 = defaults12.applyBinaryMaskToPixelData
|
|
4014
3615
|
} = deps;
|
|
4015
3616
|
return {
|
|
4016
|
-
|
|
4017
|
-
|
|
3617
|
+
applyBinaryMask(mask, opts = {}) {
|
|
3618
|
+
let target = writer.config.target;
|
|
4018
3619
|
const {
|
|
4019
3620
|
x = 0,
|
|
4020
3621
|
y = 0,
|
|
@@ -4022,126 +3623,11 @@ var mutatorInvert = ((writer, deps = defaults20) => {
|
|
|
4022
3623
|
h = target.height
|
|
4023
3624
|
} = opts;
|
|
4024
3625
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
4025
|
-
return didChange(
|
|
3626
|
+
return didChange(applyBinaryMaskToPixelData2(target, mask, opts));
|
|
4026
3627
|
}
|
|
4027
3628
|
};
|
|
4028
3629
|
});
|
|
4029
3630
|
|
|
4030
|
-
// src/History/PixelMutator.ts
|
|
4031
|
-
function makeFullPixelMutator(writer) {
|
|
4032
|
-
return {
|
|
4033
|
-
// @sort
|
|
4034
|
-
...mutatorApplyAlphaMask(writer),
|
|
4035
|
-
...mutatorApplyBinaryMask(writer),
|
|
4036
|
-
...mutatorApplyCircleBrushStroke(writer),
|
|
4037
|
-
...mutatorApplyCirclePencil(writer),
|
|
4038
|
-
...mutatorApplyCirclePencilStroke(writer),
|
|
4039
|
-
...mutatorApplyRectBrush(writer),
|
|
4040
|
-
...mutatorApplyRectBrushStroke(writer),
|
|
4041
|
-
...mutatorApplyRectPencil(writer),
|
|
4042
|
-
...mutatorApplyRectPencilStroke(writer),
|
|
4043
|
-
...mutatorBlendColor(writer),
|
|
4044
|
-
...mutatorBlendColorCircleMask(writer),
|
|
4045
|
-
...mutatorBlendPixel(writer),
|
|
4046
|
-
...mutatorBlendPixelData(writer),
|
|
4047
|
-
...mutatorBlendPixelDataAlphaMask(writer),
|
|
4048
|
-
...mutatorBlendPixelDataBinaryMask(writer),
|
|
4049
|
-
...mutatorClear(writer),
|
|
4050
|
-
...mutatorFill(writer),
|
|
4051
|
-
...mutatorFillBinaryMask(writer),
|
|
4052
|
-
...mutatorFillRect(writer),
|
|
4053
|
-
...mutatorInvert(writer)
|
|
4054
|
-
};
|
|
4055
|
-
}
|
|
4056
|
-
|
|
4057
|
-
// src/PixelTile/PixelTile.ts
|
|
4058
|
-
var PixelTile = class {
|
|
4059
|
-
constructor(id, tx, ty, tileSize, tileArea) {
|
|
4060
|
-
this.id = id;
|
|
4061
|
-
this.tx = tx;
|
|
4062
|
-
this.ty = ty;
|
|
4063
|
-
this.width = this.height = tileSize;
|
|
4064
|
-
this.data32 = new Uint32Array(tileArea);
|
|
4065
|
-
const data8 = new Uint8ClampedArray(this.data32.buffer);
|
|
4066
|
-
this.imageData = new ImageData(data8, tileSize, tileSize);
|
|
4067
|
-
}
|
|
4068
|
-
data32;
|
|
4069
|
-
width;
|
|
4070
|
-
height;
|
|
4071
|
-
imageData;
|
|
4072
|
-
};
|
|
4073
|
-
|
|
4074
|
-
// src/PixelTile/PixelTilePool.ts
|
|
4075
|
-
var PixelTilePool = class {
|
|
4076
|
-
pool;
|
|
4077
|
-
tileSize;
|
|
4078
|
-
tileArea;
|
|
4079
|
-
constructor(config) {
|
|
4080
|
-
this.pool = [];
|
|
4081
|
-
this.tileSize = config.tileSize;
|
|
4082
|
-
this.tileArea = config.tileArea;
|
|
4083
|
-
}
|
|
4084
|
-
getTile(id, tx, ty) {
|
|
4085
|
-
let tile = this.pool.pop();
|
|
4086
|
-
if (tile) {
|
|
4087
|
-
tile.id = id;
|
|
4088
|
-
tile.tx = tx;
|
|
4089
|
-
tile.ty = ty;
|
|
4090
|
-
tile.data32.fill(0);
|
|
4091
|
-
return tile;
|
|
4092
|
-
}
|
|
4093
|
-
return new PixelTile(id, tx, ty, this.tileSize, this.tileArea);
|
|
4094
|
-
}
|
|
4095
|
-
releaseTile(tile) {
|
|
4096
|
-
this.pool.push(tile);
|
|
4097
|
-
}
|
|
4098
|
-
releaseTiles(tiles) {
|
|
4099
|
-
let length = tiles.length;
|
|
4100
|
-
for (let i = 0; i < length; i++) {
|
|
4101
|
-
let tile = tiles[i];
|
|
4102
|
-
if (tile) {
|
|
4103
|
-
this.pool.push(tile);
|
|
4104
|
-
}
|
|
4105
|
-
}
|
|
4106
|
-
tiles.length = 0;
|
|
4107
|
-
}
|
|
4108
|
-
};
|
|
4109
|
-
|
|
4110
|
-
// src/History/PixelWriter.ts
|
|
4111
|
-
var PixelWriter = class {
|
|
4112
|
-
historyManager;
|
|
4113
|
-
accumulator;
|
|
4114
|
-
historyActionFactory;
|
|
4115
|
-
config;
|
|
4116
|
-
mutator;
|
|
4117
|
-
constructor(target, mutatorFactory, {
|
|
4118
|
-
tileSize = 256,
|
|
4119
|
-
maxHistorySteps = 50,
|
|
4120
|
-
historyManager = new HistoryManager(maxHistorySteps),
|
|
4121
|
-
historyActionFactory = makeHistoryAction,
|
|
4122
|
-
pixelTilePool
|
|
4123
|
-
} = {}) {
|
|
4124
|
-
this.config = new PixelEngineConfig(tileSize, target);
|
|
4125
|
-
this.historyManager = historyManager;
|
|
4126
|
-
pixelTilePool ??= new PixelTilePool(this.config);
|
|
4127
|
-
this.accumulator = new PixelAccumulator(this.config, pixelTilePool);
|
|
4128
|
-
this.historyActionFactory = historyActionFactory;
|
|
4129
|
-
this.mutator = mutatorFactory(this);
|
|
4130
|
-
}
|
|
4131
|
-
withHistory(cb, after, afterUndo, afterRedo) {
|
|
4132
|
-
try {
|
|
4133
|
-
cb(this.mutator);
|
|
4134
|
-
} catch (e) {
|
|
4135
|
-
this.accumulator.rollback();
|
|
4136
|
-
throw e;
|
|
4137
|
-
}
|
|
4138
|
-
if (this.accumulator.beforeTiles.length === 0) return;
|
|
4139
|
-
const patch = this.accumulator.extractPatch();
|
|
4140
|
-
const action = this.historyActionFactory(this, patch, after, afterUndo, afterRedo);
|
|
4141
|
-
this.historyManager.commit(action);
|
|
4142
|
-
}
|
|
4143
|
-
};
|
|
4144
|
-
|
|
4145
3631
|
// src/ImageData/copyImageData.ts
|
|
4146
3632
|
function copyImageData({
|
|
4147
3633
|
data,
|
|
@@ -4263,35 +3749,6 @@ function resampleImageData(source, factor) {
|
|
|
4263
3749
|
return new ImageData(uint8ClampedArray, width, height);
|
|
4264
3750
|
}
|
|
4265
3751
|
|
|
4266
|
-
// src/ImageData/resizeImageData.ts
|
|
4267
|
-
function resizeImageData(target, newWidth, newHeight, offsetX = 0, offsetY = 0) {
|
|
4268
|
-
const result = new ImageData(newWidth, newHeight);
|
|
4269
|
-
const {
|
|
4270
|
-
width: oldW,
|
|
4271
|
-
height: oldH,
|
|
4272
|
-
data: oldData
|
|
4273
|
-
} = target;
|
|
4274
|
-
const newData = result.data;
|
|
4275
|
-
const x0 = Math.max(0, offsetX);
|
|
4276
|
-
const y0 = Math.max(0, offsetY);
|
|
4277
|
-
const x1 = Math.min(newWidth, offsetX + oldW);
|
|
4278
|
-
const y1 = Math.min(newHeight, offsetY + oldH);
|
|
4279
|
-
if (x1 <= x0 || y1 <= y0) {
|
|
4280
|
-
return result;
|
|
4281
|
-
}
|
|
4282
|
-
const rowCount = y1 - y0;
|
|
4283
|
-
const rowLen = (x1 - x0) * 4;
|
|
4284
|
-
for (let row = 0; row < rowCount; row++) {
|
|
4285
|
-
const dstY = y0 + row;
|
|
4286
|
-
const srcY = dstY - offsetY;
|
|
4287
|
-
const srcX = x0 - offsetX;
|
|
4288
|
-
const dstStart = (dstY * newWidth + x0) * 4;
|
|
4289
|
-
const srcStart = (srcY * oldW + srcX) * 4;
|
|
4290
|
-
newData.set(oldData.subarray(srcStart, srcStart + rowLen), dstStart);
|
|
4291
|
-
}
|
|
4292
|
-
return result;
|
|
4293
|
-
}
|
|
4294
|
-
|
|
4295
3752
|
// src/ImageData/ReusableImageData.ts
|
|
4296
3753
|
function makeReusableImageData() {
|
|
4297
3754
|
let imageData = null;
|
|
@@ -4706,62 +4163,6 @@ function makeBinaryMask(w, h, data) {
|
|
|
4706
4163
|
};
|
|
4707
4164
|
}
|
|
4708
4165
|
|
|
4709
|
-
// src/Mask/CircleAlphaMask.ts
|
|
4710
|
-
function makeCircleAlphaMask(size, fallOff = () => 1) {
|
|
4711
|
-
const area = size * size;
|
|
4712
|
-
const data = new Uint8Array(area);
|
|
4713
|
-
const radius = size / 2;
|
|
4714
|
-
const invR = 1 / radius;
|
|
4715
|
-
const minOffset = -Math.ceil(radius - 0.5);
|
|
4716
|
-
for (let y = 0; y < size; y++) {
|
|
4717
|
-
for (let x = 0; x < size; x++) {
|
|
4718
|
-
const dx = x - radius + 0.5;
|
|
4719
|
-
const dy = y - radius + 0.5;
|
|
4720
|
-
const distSqr = dx * dx + dy * dy;
|
|
4721
|
-
if (distSqr <= radius * radius) {
|
|
4722
|
-
const dist = Math.sqrt(distSqr);
|
|
4723
|
-
data[y * size + x] = fallOff(1 - dist * invR) * 255 | 0;
|
|
4724
|
-
}
|
|
4725
|
-
}
|
|
4726
|
-
}
|
|
4727
|
-
return {
|
|
4728
|
-
type: 0 /* ALPHA */,
|
|
4729
|
-
data,
|
|
4730
|
-
w: size,
|
|
4731
|
-
h: size,
|
|
4732
|
-
radius,
|
|
4733
|
-
size,
|
|
4734
|
-
minOffset
|
|
4735
|
-
};
|
|
4736
|
-
}
|
|
4737
|
-
|
|
4738
|
-
// src/Mask/CircleBinaryMask.ts
|
|
4739
|
-
function makeCircleBinaryMask(size) {
|
|
4740
|
-
const area = size * size;
|
|
4741
|
-
const data = new Uint8Array(area);
|
|
4742
|
-
const radius = size / 2;
|
|
4743
|
-
const minOffset = -Math.ceil(radius - 0.5);
|
|
4744
|
-
for (let y = 0; y < size; y++) {
|
|
4745
|
-
for (let x = 0; x < size; x++) {
|
|
4746
|
-
const dx = x - radius + 0.5;
|
|
4747
|
-
const dy = y - radius + 0.5;
|
|
4748
|
-
const distSqr = dx * dx + dy * dy;
|
|
4749
|
-
if (distSqr <= radius * radius) {
|
|
4750
|
-
data[y * size + x] = 1;
|
|
4751
|
-
}
|
|
4752
|
-
}
|
|
4753
|
-
}
|
|
4754
|
-
return {
|
|
4755
|
-
type: 1 /* BINARY */,
|
|
4756
|
-
data,
|
|
4757
|
-
w: size,
|
|
4758
|
-
h: size,
|
|
4759
|
-
radius,
|
|
4760
|
-
size,
|
|
4761
|
-
minOffset
|
|
4762
|
-
};
|
|
4763
|
-
}
|
|
4764
|
-
|
|
4765
4166
|
// src/Mask/applyBinaryMaskToAlphaMask.ts
|
|
4766
4167
|
function applyBinaryMaskToAlphaMask(alphaMaskDst, binaryMaskSrc, opts = {}) {
|
|
4767
4168
|
const {
|
|
@@ -5216,6 +4617,162 @@ var PixelData = class {
|
|
|
5216
4617
|
}
|
|
5217
4618
|
};
|
|
5218
4619
|
|
|
4620
|
+
// src/PixelData/blendColorPixelDataAlphaMask.ts
|
|
4621
|
+
function blendColorPixelDataAlphaMask(dst, color, mask, opts = {}) {
|
|
4622
|
+
const targetX = opts.x ?? 0;
|
|
4623
|
+
const targetY = opts.y ?? 0;
|
|
4624
|
+
const w = opts.w ?? mask.w;
|
|
4625
|
+
const h = opts.h ?? mask.h;
|
|
4626
|
+
const globalAlpha = opts.alpha ?? 255;
|
|
4627
|
+
const blendFn = opts.blendFn ?? sourceOverPerfect;
|
|
4628
|
+
const mx = opts.mx ?? 0;
|
|
4629
|
+
const my = opts.my ?? 0;
|
|
4630
|
+
const invertMask = opts.invertMask ?? false;
|
|
4631
|
+
if (globalAlpha === 0) return false;
|
|
4632
|
+
const baseSrcAlpha = color >>> 24;
|
|
4633
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
4634
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
4635
|
+
let x = targetX;
|
|
4636
|
+
let y = targetY;
|
|
4637
|
+
let actualW = w;
|
|
4638
|
+
let actualH = h;
|
|
4639
|
+
if (x < 0) {
|
|
4640
|
+
actualW += x;
|
|
4641
|
+
x = 0;
|
|
4642
|
+
}
|
|
4643
|
+
if (y < 0) {
|
|
4644
|
+
actualH += y;
|
|
4645
|
+
y = 0;
|
|
4646
|
+
}
|
|
4647
|
+
actualW = Math.min(actualW, dst.width - x);
|
|
4648
|
+
actualH = Math.min(actualH, dst.height - y);
|
|
4649
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
4650
|
+
const dx = x - targetX | 0;
|
|
4651
|
+
const dy = y - targetY | 0;
|
|
4652
|
+
const dst32 = dst.data32;
|
|
4653
|
+
const dw = dst.width;
|
|
4654
|
+
const mPitch = mask.w;
|
|
4655
|
+
const maskData = mask.data;
|
|
4656
|
+
let dIdx = y * dw + x | 0;
|
|
4657
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
4658
|
+
const dStride = dw - actualW | 0;
|
|
4659
|
+
const mStride = mPitch - actualW | 0;
|
|
4660
|
+
const isOpaque = globalAlpha === 255;
|
|
4661
|
+
const colorRGB = color & 16777215;
|
|
4662
|
+
let didChange = false;
|
|
4663
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
4664
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
4665
|
+
const mVal = maskData[mIdx];
|
|
4666
|
+
const effM = invertMask ? 255 - mVal : mVal;
|
|
4667
|
+
if (effM === 0) {
|
|
4668
|
+
dIdx++;
|
|
4669
|
+
mIdx++;
|
|
4670
|
+
continue;
|
|
4671
|
+
}
|
|
4672
|
+
let weight = globalAlpha;
|
|
4673
|
+
if (isOpaque) {
|
|
4674
|
+
weight = effM;
|
|
4675
|
+
} else if (effM !== 255) {
|
|
4676
|
+
weight = effM * globalAlpha + 128 >> 8;
|
|
4677
|
+
}
|
|
4678
|
+
if (weight === 0) {
|
|
4679
|
+
dIdx++;
|
|
4680
|
+
mIdx++;
|
|
4681
|
+
continue;
|
|
4682
|
+
}
|
|
4683
|
+
let finalCol = color;
|
|
4684
|
+
if (weight < 255) {
|
|
4685
|
+
const a = baseSrcAlpha * weight + 128 >> 8;
|
|
4686
|
+
if (a === 0 && !isOverwrite) {
|
|
4687
|
+
dIdx++;
|
|
4688
|
+
mIdx++;
|
|
4689
|
+
continue;
|
|
4690
|
+
}
|
|
4691
|
+
finalCol = (colorRGB | a << 24) >>> 0;
|
|
4692
|
+
}
|
|
4693
|
+
const current = dst32[dIdx];
|
|
4694
|
+
const next = blendFn(finalCol, current);
|
|
4695
|
+
if (current !== next) {
|
|
4696
|
+
dst32[dIdx] = next;
|
|
4697
|
+
didChange = true;
|
|
4698
|
+
}
|
|
4699
|
+
dIdx++;
|
|
4700
|
+
mIdx++;
|
|
4701
|
+
}
|
|
4702
|
+
dIdx += dStride;
|
|
4703
|
+
mIdx += mStride;
|
|
4704
|
+
}
|
|
4705
|
+
return didChange;
|
|
4706
|
+
}
|
|
4707
|
+
|
|
4708
|
+
// src/PixelData/blendColorPixelDataBinaryMask.ts
|
|
4709
|
+
function blendColorPixelDataBinaryMask(dst, color, mask, opts = {}) {
|
|
4710
|
+
const targetX = opts.x ?? 0;
|
|
4711
|
+
const targetY = opts.y ?? 0;
|
|
4712
|
+
let w = opts.w ?? mask.w;
|
|
4713
|
+
let h = opts.h ?? mask.h;
|
|
4714
|
+
const globalAlpha = opts.alpha ?? 255;
|
|
4715
|
+
const blendFn = opts.blendFn ?? sourceOverPerfect;
|
|
4716
|
+
const mx = opts.mx ?? 0;
|
|
4717
|
+
const my = opts.my ?? 0;
|
|
4718
|
+
const invertMask = opts.invertMask ?? false;
|
|
4719
|
+
if (globalAlpha === 0) return false;
|
|
4720
|
+
const baseSrcAlpha = color >>> 24;
|
|
4721
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
4722
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
4723
|
+
let x = targetX;
|
|
4724
|
+
let y = targetY;
|
|
4725
|
+
if (x < 0) {
|
|
4726
|
+
w += x;
|
|
4727
|
+
x = 0;
|
|
4728
|
+
}
|
|
4729
|
+
if (y < 0) {
|
|
4730
|
+
h += y;
|
|
4731
|
+
y = 0;
|
|
4732
|
+
}
|
|
4733
|
+
const actualW = Math.min(w, dst.width - x);
|
|
4734
|
+
const actualH = Math.min(h, dst.height - y);
|
|
4735
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
4736
|
+
let baseColorWithGlobalAlpha = color;
|
|
4737
|
+
if (globalAlpha < 255) {
|
|
4738
|
+
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
4739
|
+
if (a === 0 && !isOverwrite) return false;
|
|
4740
|
+
baseColorWithGlobalAlpha = (color & 16777215 | a << 24) >>> 0;
|
|
4741
|
+
}
|
|
4742
|
+
const dx = x - targetX | 0;
|
|
4743
|
+
const dy = y - targetY | 0;
|
|
4744
|
+
const dst32 = dst.data32;
|
|
4745
|
+
const dw = dst.width;
|
|
4746
|
+
const mPitch = mask.w;
|
|
4747
|
+
const maskData = mask.data;
|
|
4748
|
+
let dIdx = y * dw + x | 0;
|
|
4749
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
4750
|
+
const dStride = dw - actualW | 0;
|
|
4751
|
+
const mStride = mPitch - actualW | 0;
|
|
4752
|
+
const skipVal = invertMask ? 1 : 0;
|
|
4753
|
+
let didChange = false;
|
|
4754
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
4755
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
4756
|
+
if (maskData[mIdx] === skipVal) {
|
|
4757
|
+
dIdx++;
|
|
4758
|
+
mIdx++;
|
|
4759
|
+
continue;
|
|
4760
|
+
}
|
|
4761
|
+
const current = dst32[dIdx];
|
|
4762
|
+
const next = blendFn(baseColorWithGlobalAlpha, current);
|
|
4763
|
+
if (current !== next) {
|
|
4764
|
+
dst32[dIdx] = next;
|
|
4765
|
+
didChange = true;
|
|
4766
|
+
}
|
|
4767
|
+
dIdx++;
|
|
4768
|
+
mIdx++;
|
|
4769
|
+
}
|
|
4770
|
+
dIdx += dStride;
|
|
4771
|
+
mIdx += mStride;
|
|
4772
|
+
}
|
|
4773
|
+
return didChange;
|
|
4774
|
+
}
|
|
4775
|
+
|
|
5219
4776
|
// src/PixelData/blendPixelDataPaintBuffer.ts
|
|
5220
4777
|
var SCRATCH_OPTS = {
|
|
5221
4778
|
x: 0,
|
|
@@ -5462,103 +5019,137 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
5462
5019
|
}
|
|
5463
5020
|
}
|
|
5464
5021
|
|
|
5465
|
-
// src/
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5022
|
+
// src/PixelData/writePaintBufferToPixelData.ts
|
|
5023
|
+
function writePaintBufferToPixelData(target, paintBuffer, writePixelDataBufferFn = writePixelDataBuffer) {
|
|
5024
|
+
const tileShift = paintBuffer.config.tileShift;
|
|
5025
|
+
const lookup = paintBuffer.lookup;
|
|
5026
|
+
for (let i = 0; i < lookup.length; i++) {
|
|
5027
|
+
const tile = lookup[i];
|
|
5028
|
+
if (tile) {
|
|
5029
|
+
const dx = tile.tx << tileShift;
|
|
5030
|
+
const dy = tile.ty << tileShift;
|
|
5031
|
+
writePixelDataBufferFn(target, tile.data32, dx, dy, tile.width, tile.height);
|
|
5032
|
+
}
|
|
5471
5033
|
}
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5034
|
+
}
|
|
5035
|
+
|
|
5036
|
+
// src/Paint/makeCirclePaintAlphaMask.ts
|
|
5037
|
+
function makeCirclePaintAlphaMask(size, fallOff = (d) => d) {
|
|
5038
|
+
const area = size * size;
|
|
5039
|
+
const data = new Uint8Array(area);
|
|
5040
|
+
const radius = size / 2;
|
|
5041
|
+
const invR = 1 / radius;
|
|
5042
|
+
const centerOffset = -Math.ceil(radius - 0.5);
|
|
5043
|
+
for (let y = 0; y < size; y++) {
|
|
5044
|
+
const rowOffset = y * size;
|
|
5045
|
+
const dy = y - radius + 0.5;
|
|
5046
|
+
const dy2 = dy * dy;
|
|
5047
|
+
for (let x = 0; x < size; x++) {
|
|
5048
|
+
const dx = x - radius + 0.5;
|
|
5049
|
+
const distSqr = dx * dx + dy2;
|
|
5050
|
+
if (distSqr <= radius * radius) {
|
|
5051
|
+
const dist = Math.sqrt(distSqr) * invR;
|
|
5052
|
+
const strength = fallOff(1 - dist);
|
|
5053
|
+
if (strength > 0) {
|
|
5054
|
+
const intensity = strength * 255 | 0;
|
|
5055
|
+
data[rowOffset + x] = Math.max(0, Math.min(255, intensity));
|
|
5491
5056
|
}
|
|
5492
|
-
const tileLeft = tx << tileShift;
|
|
5493
|
-
const startX = Math.max(mask.x, tileLeft);
|
|
5494
|
-
const endX = Math.min(mask.x + mask.w, tileLeft + this.config.tileSize);
|
|
5495
|
-
const startY = Math.max(mask.y, tileTop);
|
|
5496
|
-
const endY = Math.min(mask.y + mask.h, tileTop + this.config.tileSize);
|
|
5497
|
-
callback(tile, startX, startY, endX - startX, endY - startY, startX - mask.x, startY - mask.y);
|
|
5498
5057
|
}
|
|
5499
5058
|
}
|
|
5500
5059
|
}
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5520
|
-
|
|
5521
|
-
|
|
5522
|
-
|
|
5060
|
+
return {
|
|
5061
|
+
type: 0 /* ALPHA */,
|
|
5062
|
+
data,
|
|
5063
|
+
w: size,
|
|
5064
|
+
h: size,
|
|
5065
|
+
centerOffsetX: centerOffset,
|
|
5066
|
+
centerOffsetY: centerOffset
|
|
5067
|
+
};
|
|
5068
|
+
}
|
|
5069
|
+
|
|
5070
|
+
// src/Paint/makeCirclePaintBinaryMask.ts
|
|
5071
|
+
function makeCirclePaintBinaryMask(size) {
|
|
5072
|
+
const area = size * size;
|
|
5073
|
+
const data = new Uint8Array(area);
|
|
5074
|
+
const radius = size / 2;
|
|
5075
|
+
const centerOffset = -Math.ceil(radius - 0.5);
|
|
5076
|
+
for (let y = 0; y < size; y++) {
|
|
5077
|
+
for (let x = 0; x < size; x++) {
|
|
5078
|
+
const dx = x - radius + 0.5;
|
|
5079
|
+
const dy = y - radius + 0.5;
|
|
5080
|
+
const distSqr = dx * dx + dy * dy;
|
|
5081
|
+
if (distSqr <= radius * radius) {
|
|
5082
|
+
data[y * size + x] = 1;
|
|
5523
5083
|
}
|
|
5524
|
-
}
|
|
5084
|
+
}
|
|
5525
5085
|
}
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
|
|
5535
|
-
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
|
|
5548
|
-
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5086
|
+
return {
|
|
5087
|
+
type: 1 /* BINARY */,
|
|
5088
|
+
data,
|
|
5089
|
+
w: size,
|
|
5090
|
+
h: size,
|
|
5091
|
+
centerOffsetX: centerOffset,
|
|
5092
|
+
centerOffsetY: centerOffset
|
|
5093
|
+
};
|
|
5094
|
+
}
|
|
5095
|
+
|
|
5096
|
+
// src/Paint/makePaintMask.ts
|
|
5097
|
+
function makePaintBinaryMask(mask) {
|
|
5098
|
+
return {
|
|
5099
|
+
type: 1 /* BINARY */,
|
|
5100
|
+
data: mask.data,
|
|
5101
|
+
w: mask.w,
|
|
5102
|
+
h: mask.h,
|
|
5103
|
+
centerOffsetX: -(mask.w >> 1),
|
|
5104
|
+
centerOffsetY: -(mask.h >> 1)
|
|
5105
|
+
};
|
|
5106
|
+
}
|
|
5107
|
+
function makePaintAlphaMask(mask) {
|
|
5108
|
+
return {
|
|
5109
|
+
type: 0 /* ALPHA */,
|
|
5110
|
+
data: mask.data,
|
|
5111
|
+
w: mask.w,
|
|
5112
|
+
h: mask.h,
|
|
5113
|
+
centerOffsetX: -(mask.w >> 1),
|
|
5114
|
+
centerOffsetY: -(mask.h >> 1)
|
|
5115
|
+
};
|
|
5116
|
+
}
|
|
5117
|
+
|
|
5118
|
+
// src/Paint/makeRectFalloffPaintAlphaMask.ts
|
|
5119
|
+
function makeRectFalloffPaintAlphaMask(width, height, fallOff = (d) => d) {
|
|
5120
|
+
const fPx = Math.floor(width / 2);
|
|
5121
|
+
const fPy = Math.floor(height / 2);
|
|
5122
|
+
const invHalfW = 2 / width;
|
|
5123
|
+
const invHalfH = 2 / height;
|
|
5124
|
+
const offX = width % 2 === 0 ? 0.5 : 0;
|
|
5125
|
+
const offY = height % 2 === 0 ? 0.5 : 0;
|
|
5126
|
+
const area = width * height;
|
|
5127
|
+
const data = new Uint8Array(area);
|
|
5128
|
+
for (let y = 0; y < height; y++) {
|
|
5129
|
+
const dy = Math.abs(y - fPy + offY) * invHalfH;
|
|
5130
|
+
const rowOffset = y * width;
|
|
5131
|
+
for (let x = 0; x < width; x++) {
|
|
5132
|
+
const dx = Math.abs(x - fPx + offX) * invHalfW;
|
|
5133
|
+
const dist = dx > dy ? dx : dy;
|
|
5134
|
+
const strength = fallOff(1 - dist);
|
|
5135
|
+
if (strength > 0) {
|
|
5136
|
+
const intensity = strength * 255 | 0;
|
|
5137
|
+
data[rowOffset + x] = Math.max(0, Math.min(255, intensity));
|
|
5552
5138
|
}
|
|
5553
|
-
}
|
|
5554
|
-
}
|
|
5555
|
-
clear() {
|
|
5556
|
-
this.tilePool.releaseTiles(this.lookup);
|
|
5139
|
+
}
|
|
5557
5140
|
}
|
|
5558
|
-
|
|
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
|
+
}
|
|
5559
5150
|
|
|
5560
|
-
// src/
|
|
5561
|
-
function
|
|
5151
|
+
// src/Paint/PaintBufferCanvasRenderer.ts
|
|
5152
|
+
function makePaintBufferCanvasRenderer(paintBuffer, offscreenCanvasClass = OffscreenCanvas) {
|
|
5562
5153
|
const config = paintBuffer.config;
|
|
5563
5154
|
const tileSize = config.tileSize;
|
|
5564
5155
|
const tileShift = config.tileShift;
|
|
@@ -5567,16 +5158,20 @@ function makePaintBufferRenderer(paintBuffer, offscreenCanvasClass = OffscreenCa
|
|
|
5567
5158
|
const ctx = canvas.getContext("2d");
|
|
5568
5159
|
if (!ctx) throw new Error(CANVAS_CTX_FAILED);
|
|
5569
5160
|
ctx.imageSmoothingEnabled = false;
|
|
5570
|
-
return function drawPaintBuffer(
|
|
5161
|
+
return function drawPaintBuffer(targetCtx, alpha = 255, compOperation = "source-over") {
|
|
5162
|
+
targetCtx.globalAlpha = alpha / 255;
|
|
5163
|
+
targetCtx.globalCompositeOperation = compOperation;
|
|
5571
5164
|
for (let i = 0; i < lookup.length; i++) {
|
|
5572
5165
|
const tile = lookup[i];
|
|
5573
5166
|
if (tile) {
|
|
5574
5167
|
const dx = tile.tx << tileShift;
|
|
5575
5168
|
const dy = tile.ty << tileShift;
|
|
5576
5169
|
ctx.putImageData(tile.imageData, 0, 0);
|
|
5577
|
-
|
|
5170
|
+
targetCtx.drawImage(canvas, dx, dy);
|
|
5578
5171
|
}
|
|
5579
5172
|
}
|
|
5173
|
+
targetCtx.globalAlpha = 1;
|
|
5174
|
+
targetCtx.globalCompositeOperation = "source-over";
|
|
5580
5175
|
};
|
|
5581
5176
|
}
|
|
5582
5177
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -5602,13 +5197,11 @@ function makePaintBufferRenderer(paintBuffer, offscreenCanvasClass = OffscreenCa
|
|
|
5602
5197
|
applyBinaryMaskToAlphaMask,
|
|
5603
5198
|
applyBinaryMaskToPixelData,
|
|
5604
5199
|
applyPatchTiles,
|
|
5605
|
-
applyRectBrushToPixelData,
|
|
5606
5200
|
base64DecodeArrayBuffer,
|
|
5607
5201
|
base64EncodeArrayBuffer,
|
|
5608
5202
|
blendColorPixelData,
|
|
5609
5203
|
blendColorPixelDataAlphaMask,
|
|
5610
5204
|
blendColorPixelDataBinaryMask,
|
|
5611
|
-
blendColorPixelDataCircleMask,
|
|
5612
5205
|
blendPixel,
|
|
5613
5206
|
blendPixelData,
|
|
5614
5207
|
blendPixelDataAlphaMask,
|
|
@@ -5650,12 +5243,8 @@ function makePaintBufferRenderer(paintBuffer, offscreenCanvasClass = OffscreenCa
|
|
|
5650
5243
|
fillPixelDataFast,
|
|
5651
5244
|
floodFillSelection,
|
|
5652
5245
|
forEachLinePoint,
|
|
5653
|
-
getCircleBrushOrPencilBounds,
|
|
5654
|
-
getCircleBrushOrPencilStrokeBounds,
|
|
5655
5246
|
getImageDataFromClipboard,
|
|
5656
5247
|
getIndexedImageColorCounts,
|
|
5657
|
-
getRectBrushOrPencilBounds,
|
|
5658
|
-
getRectBrushOrPencilStrokeBounds,
|
|
5659
5248
|
getRectsBounds,
|
|
5660
5249
|
getSupportedPixelFormats,
|
|
5661
5250
|
hardLightFast,
|
|
@@ -5689,15 +5278,18 @@ function makePaintBufferRenderer(paintBuffer, offscreenCanvasClass = OffscreenCa
|
|
|
5689
5278
|
makeBinaryMask,
|
|
5690
5279
|
makeBlendModeRegistry,
|
|
5691
5280
|
makeCanvasFrameRenderer,
|
|
5692
|
-
|
|
5693
|
-
|
|
5281
|
+
makeCirclePaintAlphaMask,
|
|
5282
|
+
makeCirclePaintBinaryMask,
|
|
5694
5283
|
makeFastBlendModeRegistry,
|
|
5695
5284
|
makeFullPixelMutator,
|
|
5696
5285
|
makeHistoryAction,
|
|
5697
5286
|
makeImageDataLike,
|
|
5698
|
-
|
|
5287
|
+
makePaintAlphaMask,
|
|
5288
|
+
makePaintBinaryMask,
|
|
5289
|
+
makePaintBufferCanvasRenderer,
|
|
5699
5290
|
makePerfectBlendModeRegistry,
|
|
5700
5291
|
makePixelCanvas,
|
|
5292
|
+
makeRectFalloffPaintAlphaMask,
|
|
5701
5293
|
makeReusableCanvas,
|
|
5702
5294
|
makeReusableImageData,
|
|
5703
5295
|
makeReusableOffscreenCanvas,
|
|
@@ -5709,15 +5301,7 @@ function makePaintBufferRenderer(paintBuffer, offscreenCanvasClass = OffscreenCa
|
|
|
5709
5301
|
multiplyPerfect,
|
|
5710
5302
|
mutatorApplyAlphaMask,
|
|
5711
5303
|
mutatorApplyBinaryMask,
|
|
5712
|
-
mutatorApplyCircleBrushStroke,
|
|
5713
|
-
mutatorApplyCirclePencil,
|
|
5714
|
-
mutatorApplyCirclePencilStroke,
|
|
5715
|
-
mutatorApplyRectBrush,
|
|
5716
|
-
mutatorApplyRectBrushStroke,
|
|
5717
|
-
mutatorApplyRectPencil,
|
|
5718
|
-
mutatorApplyRectPencilStroke,
|
|
5719
5304
|
mutatorBlendColor,
|
|
5720
|
-
mutatorBlendColorCircleMask,
|
|
5721
5305
|
mutatorBlendPixel,
|
|
5722
5306
|
mutatorBlendPixelData,
|
|
5723
5307
|
mutatorBlendPixelDataAlphaMask,
|
|
@@ -5757,6 +5341,7 @@ function makePaintBufferRenderer(paintBuffer, offscreenCanvasClass = OffscreenCa
|
|
|
5757
5341
|
subtractFast,
|
|
5758
5342
|
subtractPerfect,
|
|
5759
5343
|
toBlendModeIndexAndName,
|
|
5344
|
+
trimMaskRectBounds,
|
|
5760
5345
|
trimRectBounds,
|
|
5761
5346
|
uInt32ArrayToImageData,
|
|
5762
5347
|
uInt32ArrayToImageDataLike,
|
|
@@ -5772,6 +5357,7 @@ function makePaintBufferRenderer(paintBuffer, offscreenCanvasClass = OffscreenCa
|
|
|
5772
5357
|
writeImageDataBuffer,
|
|
5773
5358
|
writeImageDataToClipboard,
|
|
5774
5359
|
writeImgBlobToClipboard,
|
|
5360
|
+
writePaintBufferToPixelData,
|
|
5775
5361
|
writePixelDataBuffer
|
|
5776
5362
|
});
|
|
5777
5363
|
//# sourceMappingURL=index.dev.cjs.map
|