pixel-data-js 0.21.0 → 0.22.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.dev.cjs +725 -362
- package/dist/index.dev.cjs.map +1 -1
- package/dist/index.dev.js +712 -361
- package/dist/index.dev.js.map +1 -1
- package/dist/index.prod.cjs +725 -362
- package/dist/index.prod.cjs.map +1 -1
- package/dist/index.prod.d.ts +282 -127
- package/dist/index.prod.js +712 -361
- package/dist/index.prod.js.map +1 -1
- package/package.json +1 -1
- package/src/Algorithm/floodFillSelection.ts +12 -14
- package/src/BlendModes/toBlendModeIndexAndName.ts +0 -7
- package/src/Clipboard/writeImgBlobToClipboard.ts +1 -1
- package/src/History/PixelMutator/mutatorApplyAlphaMask.ts +3 -0
- package/src/History/PixelMutator/mutatorApplyBinaryMask.ts +3 -0
- package/src/History/PixelMutator/mutatorApplyCircleBrush.ts +25 -6
- package/src/History/PixelMutator/mutatorApplyCircleBrushStroke.ts +89 -46
- package/src/History/PixelMutator/mutatorApplyCirclePencil.ts +7 -7
- package/src/History/PixelMutator/mutatorApplyCirclePencilStroke.ts +81 -41
- package/src/History/PixelMutator/mutatorApplyRectBrush.ts +3 -0
- package/src/History/PixelMutator/mutatorApplyRectBrushStroke.ts +18 -5
- package/src/History/PixelMutator/mutatorApplyRectPencil.ts +3 -0
- package/src/History/PixelMutator/mutatorApplyRectPencilStroke.ts +19 -4
- package/src/History/PixelMutator/mutatorBlendColor.ts +4 -0
- package/src/History/PixelMutator/mutatorBlendPixelData.ts +4 -0
- package/src/History/PixelMutator/mutatorClear.ts +10 -8
- package/src/History/PixelMutator/mutatorFill.ts +7 -4
- package/src/History/PixelMutator/mutatorFillBinaryMask.ts +28 -0
- package/src/History/PixelMutator/mutatorInvert.ts +3 -0
- package/src/ImageData/extractImageDataBuffer.ts +3 -3
- package/src/ImageData/{imageDataToAlphaMask.ts → imageDataToAlphaMaskBuffer.ts} +3 -4
- package/src/ImageData/resizeImageData.ts +3 -5
- package/src/ImageData/writeImageDataBuffer.ts +7 -7
- package/src/Mask/AlphaMask.ts +16 -0
- package/src/Mask/BinaryMask.ts +16 -0
- package/src/Mask/CircleBrushAlphaMask.ts +32 -0
- package/src/Mask/CircleBrushBinaryMask.ts +30 -0
- package/src/Mask/applyBinaryMaskToAlphaMask.ts +12 -9
- package/src/Mask/copyMask.ts +9 -3
- package/src/Mask/extractMask.ts +33 -31
- package/src/Mask/extractMaskBuffer.ts +87 -0
- package/src/Mask/invertMask.ts +6 -4
- package/src/Mask/mergeAlphaMasks.ts +11 -10
- package/src/Mask/mergeBinaryMasks.ts +10 -9
- package/src/Mask/setMaskData.ts +7 -0
- package/src/MaskRect/merge2BinaryMaskRects.ts +81 -0
- package/src/MaskRect/mergeBinaryMaskRects.ts +39 -0
- package/src/MaskRect/subtractBinaryMaskRects.ts +80 -0
- package/src/PixelData/applyAlphaMaskToPixelData.ts +8 -5
- package/src/PixelData/applyBinaryMaskToPixelData.ts +8 -9
- package/src/PixelData/applyCircleBrushToPixelData.ts +54 -62
- package/src/PixelData/blendColorPixelDataAlphaMask.ts +35 -25
- package/src/PixelData/blendColorPixelDataBinaryMask.ts +26 -19
- package/src/PixelData/blendPixelDataAlphaMask.ts +3 -3
- package/src/PixelData/blendPixelDataBinaryMask.ts +3 -3
- package/src/PixelData/fillPixelData.ts +15 -42
- package/src/PixelData/fillPixelDataBinaryMask.ts +79 -0
- package/src/PixelData/invertPixelData.ts +3 -3
- package/src/PixelData/pixelDataToAlphaMask.ts +4 -2
- package/src/PixelData/writePixelDataBuffer.ts +2 -3
- package/src/Rect/getRectsBounds.ts +22 -0
- package/src/Rect/trimRectBounds.ts +20 -17
- package/src/_types.ts +55 -29
- package/src/index.ts +16 -1
package/dist/index.prod.js
CHANGED
|
@@ -196,8 +196,8 @@ function extractImageDataBuffer(imageData, _x, _y, _w, _h) {
|
|
|
196
196
|
return out;
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
-
// src/Mask/
|
|
200
|
-
function
|
|
199
|
+
// src/Mask/extractMaskBuffer.ts
|
|
200
|
+
function extractMaskBuffer(maskBuffer, maskWidth, xOrRect, y, w, h) {
|
|
201
201
|
let finalX;
|
|
202
202
|
let finalY;
|
|
203
203
|
let finalW;
|
|
@@ -214,7 +214,7 @@ function extractMask(mask, maskWidth, xOrRect, y, w, h) {
|
|
|
214
214
|
finalH = h;
|
|
215
215
|
}
|
|
216
216
|
const out = new Uint8Array(finalW * finalH);
|
|
217
|
-
const srcH =
|
|
217
|
+
const srcH = maskBuffer.length / maskWidth;
|
|
218
218
|
for (let row = 0; row < finalH; row++) {
|
|
219
219
|
const currentSrcY = finalY + row;
|
|
220
220
|
if (currentSrcY < 0 || currentSrcY >= srcH) {
|
|
@@ -226,7 +226,7 @@ function extractMask(mask, maskWidth, xOrRect, y, w, h) {
|
|
|
226
226
|
const srcOffset = currentSrcY * maskWidth + start;
|
|
227
227
|
const dstOffset = row * finalW + (start - finalX);
|
|
228
228
|
const count = end - start;
|
|
229
|
-
out.set(
|
|
229
|
+
out.set(maskBuffer.subarray(srcOffset, srcOffset + count), dstOffset);
|
|
230
230
|
}
|
|
231
231
|
}
|
|
232
232
|
return out;
|
|
@@ -244,8 +244,8 @@ function trimRectBounds(target, bounds) {
|
|
|
244
244
|
if (intersectedMaxX <= intersectedX || intersectedMaxY <= intersectedY) {
|
|
245
245
|
target.w = 0;
|
|
246
246
|
target.h = 0;
|
|
247
|
-
if ("
|
|
248
|
-
target.
|
|
247
|
+
if ("data" in target && target.data) {
|
|
248
|
+
target.data = new Uint8Array(0);
|
|
249
249
|
}
|
|
250
250
|
return;
|
|
251
251
|
}
|
|
@@ -257,15 +257,15 @@ function trimRectBounds(target, bounds) {
|
|
|
257
257
|
target.y = intersectedY;
|
|
258
258
|
target.w = intersectedW;
|
|
259
259
|
target.h = intersectedH;
|
|
260
|
-
if ("
|
|
261
|
-
const
|
|
260
|
+
if ("data" in target && target.data) {
|
|
261
|
+
const currentMaskBuffer = extractMaskBuffer(target.data, originalW, offsetX, offsetY, intersectedW, intersectedH);
|
|
262
262
|
let minX = intersectedW;
|
|
263
263
|
let maxX = -1;
|
|
264
264
|
let minY = intersectedH;
|
|
265
265
|
let maxY = -1;
|
|
266
266
|
for (let y = 0; y < intersectedH; y++) {
|
|
267
267
|
for (let x = 0; x < intersectedW; x++) {
|
|
268
|
-
if (
|
|
268
|
+
if (currentMaskBuffer[y * intersectedW + x] !== 0) {
|
|
269
269
|
if (x < minX) minX = x;
|
|
270
270
|
if (x > maxX) maxX = x;
|
|
271
271
|
if (y < minY) minY = y;
|
|
@@ -276,19 +276,22 @@ function trimRectBounds(target, bounds) {
|
|
|
276
276
|
if (maxX === -1) {
|
|
277
277
|
target.w = 0;
|
|
278
278
|
target.h = 0;
|
|
279
|
-
target.
|
|
279
|
+
target.data = new Uint8Array(0);
|
|
280
280
|
return;
|
|
281
281
|
}
|
|
282
282
|
const finalW = maxX - minX + 1;
|
|
283
283
|
const finalH = maxY - minY + 1;
|
|
284
284
|
if (finalW !== intersectedW || finalH !== intersectedH) {
|
|
285
|
-
|
|
285
|
+
const newMaskBuffer = extractMaskBuffer(currentMaskBuffer, intersectedW, minX, minY, finalW, finalH);
|
|
286
286
|
target.x += minX;
|
|
287
287
|
target.y += minY;
|
|
288
288
|
target.w = finalW;
|
|
289
289
|
target.h = finalH;
|
|
290
|
+
target.data = newMaskBuffer;
|
|
290
291
|
} else {
|
|
291
|
-
target.
|
|
292
|
+
target.w = finalW;
|
|
293
|
+
target.h = finalH;
|
|
294
|
+
target.data = currentMaskBuffer;
|
|
292
295
|
}
|
|
293
296
|
}
|
|
294
297
|
}
|
|
@@ -398,17 +401,19 @@ function floodFillSelection(img, startX, startY, {
|
|
|
398
401
|
if (matchCount === 0) {
|
|
399
402
|
return null;
|
|
400
403
|
}
|
|
404
|
+
const w = maxX - minX + 1;
|
|
405
|
+
const h = maxY - minY + 1;
|
|
401
406
|
const selectionRect = {
|
|
402
407
|
x: minX,
|
|
403
408
|
y: minY,
|
|
404
|
-
w
|
|
405
|
-
h
|
|
406
|
-
|
|
407
|
-
|
|
409
|
+
w,
|
|
410
|
+
h,
|
|
411
|
+
data: new Uint8Array(w * h),
|
|
412
|
+
type: 1 /* BINARY */
|
|
408
413
|
};
|
|
409
414
|
const sw = selectionRect.w;
|
|
410
415
|
const sh = selectionRect.h;
|
|
411
|
-
const finalMask = selectionRect.
|
|
416
|
+
const finalMask = selectionRect.data;
|
|
412
417
|
for (let i = 0; i < matchCount; i++) {
|
|
413
418
|
const mx = matchX[i] - selectionRect.x;
|
|
414
419
|
const my = matchY[i] - selectionRect.y;
|
|
@@ -1483,16 +1488,7 @@ function toBlendModeIndexAndName(input) {
|
|
|
1483
1488
|
const num = Number(trimmed);
|
|
1484
1489
|
const isNumeric = trimmed !== "" && !Number.isNaN(num);
|
|
1485
1490
|
if (isNumeric && Number.isInteger(num)) {
|
|
1486
|
-
console.log({
|
|
1487
|
-
trimmed,
|
|
1488
|
-
num,
|
|
1489
|
-
isNumeric,
|
|
1490
|
-
isInt: Number.isInteger(num)
|
|
1491
|
-
});
|
|
1492
1491
|
const name = getKeyByValue(BaseBlendMode, num);
|
|
1493
|
-
console.log({
|
|
1494
|
-
name
|
|
1495
|
-
});
|
|
1496
1492
|
if (name === void 0) throw new Error(`Invalid index: ${num}`);
|
|
1497
1493
|
return {
|
|
1498
1494
|
blendIndex: num,
|
|
@@ -1866,7 +1862,6 @@ function applyAlphaMaskToPixelData(dst, mask, opts = {}) {
|
|
|
1866
1862
|
w: width = dst.width,
|
|
1867
1863
|
h: height = dst.height,
|
|
1868
1864
|
alpha: globalAlpha = 255,
|
|
1869
|
-
mw,
|
|
1870
1865
|
mx = 0,
|
|
1871
1866
|
my = 0,
|
|
1872
1867
|
invertMask = false
|
|
@@ -1888,15 +1883,14 @@ function applyAlphaMaskToPixelData(dst, mask, opts = {}) {
|
|
|
1888
1883
|
h = Math.min(h, dst.height - y);
|
|
1889
1884
|
if (w <= 0) return;
|
|
1890
1885
|
if (h <= 0) return;
|
|
1891
|
-
const mPitch =
|
|
1886
|
+
const mPitch = mask.w;
|
|
1892
1887
|
if (mPitch <= 0) return;
|
|
1893
|
-
const maskHeight = mask.length / mPitch | 0;
|
|
1894
1888
|
const startX = mx + (x - targetX);
|
|
1895
1889
|
const startY = my + (y - targetY);
|
|
1896
1890
|
const sX0 = Math.max(0, startX);
|
|
1897
1891
|
const sY0 = Math.max(0, startY);
|
|
1898
1892
|
const sX1 = Math.min(mPitch, startX + w);
|
|
1899
|
-
const sY1 = Math.min(
|
|
1893
|
+
const sY1 = Math.min(mask.h, startY + h);
|
|
1900
1894
|
const finalW = sX1 - sX0;
|
|
1901
1895
|
const finalH = sY1 - sY0;
|
|
1902
1896
|
if (finalW <= 0) return;
|
|
@@ -1907,11 +1901,12 @@ function applyAlphaMaskToPixelData(dst, mask, opts = {}) {
|
|
|
1907
1901
|
const dw = dst.width;
|
|
1908
1902
|
const dStride = dw - finalW;
|
|
1909
1903
|
const mStride = mPitch - finalW;
|
|
1904
|
+
const maskData = mask.data;
|
|
1910
1905
|
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
1911
1906
|
let mIdx = sY0 * mPitch + sX0;
|
|
1912
1907
|
for (let iy = 0; iy < h; iy++) {
|
|
1913
1908
|
for (let ix = 0; ix < w; ix++) {
|
|
1914
|
-
const mVal =
|
|
1909
|
+
const mVal = maskData[mIdx];
|
|
1915
1910
|
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
1916
1911
|
let weight = 0;
|
|
1917
1912
|
if (effectiveM === 0) {
|
|
@@ -1971,13 +1966,12 @@ function applyBinaryMaskToPixelData(dst, mask, opts = {}) {
|
|
|
1971
1966
|
y: targetY = 0,
|
|
1972
1967
|
w: width = dst.width,
|
|
1973
1968
|
h: height = dst.height,
|
|
1974
|
-
alpha = 255,
|
|
1975
|
-
mw,
|
|
1969
|
+
alpha: globalAlpha = 255,
|
|
1976
1970
|
mx = 0,
|
|
1977
1971
|
my = 0,
|
|
1978
1972
|
invertMask = false
|
|
1979
1973
|
} = opts;
|
|
1980
|
-
if (
|
|
1974
|
+
if (globalAlpha === 0) return;
|
|
1981
1975
|
let x = targetX;
|
|
1982
1976
|
let y = targetY;
|
|
1983
1977
|
let w = width;
|
|
@@ -1994,15 +1988,14 @@ function applyBinaryMaskToPixelData(dst, mask, opts = {}) {
|
|
|
1994
1988
|
h = Math.min(h, dst.height - y);
|
|
1995
1989
|
if (w <= 0) return;
|
|
1996
1990
|
if (h <= 0) return;
|
|
1997
|
-
const mPitch =
|
|
1991
|
+
const mPitch = mask.w;
|
|
1998
1992
|
if (mPitch <= 0) return;
|
|
1999
|
-
const maskHeight = mask.length / mPitch | 0;
|
|
2000
1993
|
const startX = mx + (x - targetX);
|
|
2001
1994
|
const startY = my + (y - targetY);
|
|
2002
1995
|
const sX0 = Math.max(0, startX);
|
|
2003
1996
|
const sY0 = Math.max(0, startY);
|
|
2004
1997
|
const sX1 = Math.min(mPitch, startX + w);
|
|
2005
|
-
const sY1 = Math.min(
|
|
1998
|
+
const sY1 = Math.min(mask.h, startY + h);
|
|
2006
1999
|
const finalW = sX1 - sX0;
|
|
2007
2000
|
const finalH = sY1 - sY0;
|
|
2008
2001
|
if (finalW <= 0) return;
|
|
@@ -2013,19 +2006,20 @@ function applyBinaryMaskToPixelData(dst, mask, opts = {}) {
|
|
|
2013
2006
|
const dw = dst.width;
|
|
2014
2007
|
const dStride = dw - finalW;
|
|
2015
2008
|
const mStride = mPitch - finalW;
|
|
2009
|
+
const maskData = mask.data;
|
|
2016
2010
|
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
2017
2011
|
let mIdx = sY0 * mPitch + sX0;
|
|
2018
2012
|
for (let iy = 0; iy < h; iy++) {
|
|
2019
2013
|
for (let ix = 0; ix < w; ix++) {
|
|
2020
|
-
const mVal =
|
|
2014
|
+
const mVal = maskData[mIdx];
|
|
2021
2015
|
const isMaskedOut = invertMask ? mVal !== 0 : mVal === 0;
|
|
2022
2016
|
if (isMaskedOut) {
|
|
2023
2017
|
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
2024
|
-
} else if (
|
|
2018
|
+
} else if (globalAlpha !== 255) {
|
|
2025
2019
|
const d = dst32[dIdx];
|
|
2026
2020
|
const da = d >>> 24;
|
|
2027
2021
|
if (da !== 0) {
|
|
2028
|
-
const finalAlpha = da === 255 ?
|
|
2022
|
+
const finalAlpha = da === 255 ? globalAlpha : da * globalAlpha + 128 >> 8;
|
|
2029
2023
|
dst32[dIdx] = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
2030
2024
|
}
|
|
2031
2025
|
}
|
|
@@ -2088,144 +2082,42 @@ function getCircleBrushOrPencilBounds(centerX, centerY, brushSize, targetWidth,
|
|
|
2088
2082
|
return res;
|
|
2089
2083
|
}
|
|
2090
2084
|
|
|
2091
|
-
// src/PixelData/applyCircleBrushToPixelData.ts
|
|
2092
|
-
function applyCircleBrushToPixelData(target, color, centerX, centerY, brushSize, alpha = 255, fallOff, blendFn = sourceOverPerfect, bounds) {
|
|
2093
|
-
const targetWidth = target.width;
|
|
2094
|
-
const targetHeight = target.height;
|
|
2095
|
-
const b = bounds ?? getCircleBrushOrPencilBounds(centerX, centerY, brushSize, targetWidth, targetHeight);
|
|
2096
|
-
if (b.w <= 0 || b.h <= 0) return;
|
|
2097
|
-
const data32 = target.data32;
|
|
2098
|
-
const r = brushSize / 2;
|
|
2099
|
-
const rSqr = r * r;
|
|
2100
|
-
const invR = 1 / r;
|
|
2101
|
-
const centerOffset = brushSize % 2 === 0 ? 0.5 : 0;
|
|
2102
|
-
const endX = b.x + b.w;
|
|
2103
|
-
const endY = b.y + b.h;
|
|
2104
|
-
const fCenterX = Math.floor(centerX);
|
|
2105
|
-
const fCenterY = Math.floor(centerY);
|
|
2106
|
-
const baseSrcAlpha = color >>> 24;
|
|
2107
|
-
const colorRGB = color & 16777215;
|
|
2108
|
-
const isOpaque = alpha === 255;
|
|
2109
|
-
const isOverwrite = blendFn.isOverwrite;
|
|
2110
|
-
for (let cy = b.y; cy < endY; cy++) {
|
|
2111
|
-
const relY = cy - fCenterY + centerOffset;
|
|
2112
|
-
const dySqr = relY * relY;
|
|
2113
|
-
const rowOffset = cy * targetWidth;
|
|
2114
|
-
for (let cx = b.x; cx < endX; cx++) {
|
|
2115
|
-
const relX = cx - fCenterX + centerOffset;
|
|
2116
|
-
const dSqr = relX * relX + dySqr;
|
|
2117
|
-
if (dSqr <= rSqr) {
|
|
2118
|
-
const idx = rowOffset + cx;
|
|
2119
|
-
let weight = alpha;
|
|
2120
|
-
const strength = fallOff(1 - Math.sqrt(dSqr) * invR);
|
|
2121
|
-
const maskVal = strength * 255 | 0;
|
|
2122
|
-
if (maskVal === 0) continue;
|
|
2123
|
-
if (isOpaque) {
|
|
2124
|
-
weight = maskVal;
|
|
2125
|
-
} else if (maskVal !== 255) {
|
|
2126
|
-
weight = maskVal * alpha + 128 >> 8;
|
|
2127
|
-
}
|
|
2128
|
-
let finalCol = color;
|
|
2129
|
-
if (weight < 255) {
|
|
2130
|
-
const a = baseSrcAlpha * weight + 128 >> 8;
|
|
2131
|
-
if (a === 0 && !isOverwrite) continue;
|
|
2132
|
-
finalCol = (colorRGB | a << 24) >>> 0;
|
|
2133
|
-
}
|
|
2134
|
-
data32[idx] = blendFn(finalCol, data32[idx]);
|
|
2135
|
-
}
|
|
2136
|
-
}
|
|
2137
|
-
}
|
|
2138
|
-
}
|
|
2139
|
-
|
|
2140
|
-
// src/History/PixelMutator/mutatorApplyCircleBrush.ts
|
|
2141
|
-
var defaults3 = {
|
|
2142
|
-
applyCircleBrushToPixelData,
|
|
2143
|
-
getCircleBrushOrPencilBounds
|
|
2144
|
-
};
|
|
2145
|
-
var mutatorApplyCircleBrush = ((writer, deps = defaults3) => {
|
|
2146
|
-
const {
|
|
2147
|
-
applyCircleBrushToPixelData: applyCircleBrushToPixelData2 = defaults3.applyCircleBrushToPixelData,
|
|
2148
|
-
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults3.getCircleBrushOrPencilBounds
|
|
2149
|
-
} = deps;
|
|
2150
|
-
const boundsOut = {
|
|
2151
|
-
x: 0,
|
|
2152
|
-
y: 0,
|
|
2153
|
-
w: 0,
|
|
2154
|
-
h: 0
|
|
2155
|
-
};
|
|
2156
|
-
return {
|
|
2157
|
-
applyCircleBrush(color, centerX, centerY, brushSize, alpha = 255, fallOff, blendFn) {
|
|
2158
|
-
const bounds = getCircleBrushOrPencilBounds2(centerX, centerY, brushSize, writer.target.width, writer.target.height, boundsOut);
|
|
2159
|
-
const {
|
|
2160
|
-
x,
|
|
2161
|
-
y,
|
|
2162
|
-
w,
|
|
2163
|
-
h
|
|
2164
|
-
} = bounds;
|
|
2165
|
-
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2166
|
-
applyCircleBrushToPixelData2(writer.target, color, centerX, centerY, brushSize, alpha, fallOff, blendFn, bounds);
|
|
2167
|
-
}
|
|
2168
|
-
};
|
|
2169
|
-
});
|
|
2170
|
-
|
|
2171
|
-
// src/Algorithm/forEachLinePoint.ts
|
|
2172
|
-
function forEachLinePoint(x0, y0, x1, y1, callback) {
|
|
2173
|
-
const dx = x1 - x0;
|
|
2174
|
-
const dy = y1 - y0;
|
|
2175
|
-
const steps = Math.max(Math.abs(dx), Math.abs(dy));
|
|
2176
|
-
if (steps === 0) {
|
|
2177
|
-
callback(x0, y0);
|
|
2178
|
-
return;
|
|
2179
|
-
}
|
|
2180
|
-
const xInc = dx / steps;
|
|
2181
|
-
const yInc = dy / steps;
|
|
2182
|
-
let curX = x0;
|
|
2183
|
-
let curY = y0;
|
|
2184
|
-
for (let i = 0; i <= steps; i++) {
|
|
2185
|
-
callback(curX, curY);
|
|
2186
|
-
curX += xInc;
|
|
2187
|
-
curY += yInc;
|
|
2188
|
-
}
|
|
2189
|
-
}
|
|
2190
|
-
|
|
2191
2085
|
// src/PixelData/blendColorPixelDataAlphaMask.ts
|
|
2192
|
-
function blendColorPixelDataAlphaMask(dst, color, mask, opts) {
|
|
2193
|
-
const
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
invertMask = false
|
|
2204
|
-
} = opts;
|
|
2205
|
-
if (globalAlpha === 0 || !mask) return;
|
|
2086
|
+
function blendColorPixelDataAlphaMask(dst, color, mask, opts = {}) {
|
|
2087
|
+
const targetX = opts.x ?? 0;
|
|
2088
|
+
const targetY = opts.y ?? 0;
|
|
2089
|
+
const w = opts.w ?? mask.w;
|
|
2090
|
+
const h = opts.h ?? mask.h;
|
|
2091
|
+
const globalAlpha = opts.alpha ?? 255;
|
|
2092
|
+
const blendFn = opts.blendFn ?? sourceOverPerfect;
|
|
2093
|
+
const mx = opts.mx ?? 0;
|
|
2094
|
+
const my = opts.my ?? 0;
|
|
2095
|
+
const invertMask = opts.invertMask ?? false;
|
|
2096
|
+
if (globalAlpha === 0) return;
|
|
2206
2097
|
const baseSrcAlpha = color >>> 24;
|
|
2207
2098
|
const isOverwrite = blendFn.isOverwrite || false;
|
|
2208
2099
|
if (baseSrcAlpha === 0 && !isOverwrite) return;
|
|
2209
2100
|
let x = targetX;
|
|
2210
2101
|
let y = targetY;
|
|
2211
|
-
let
|
|
2212
|
-
let
|
|
2102
|
+
let actualW = w;
|
|
2103
|
+
let actualH = h;
|
|
2213
2104
|
if (x < 0) {
|
|
2214
|
-
|
|
2105
|
+
actualW += x;
|
|
2215
2106
|
x = 0;
|
|
2216
2107
|
}
|
|
2217
2108
|
if (y < 0) {
|
|
2218
|
-
|
|
2109
|
+
actualH += y;
|
|
2219
2110
|
y = 0;
|
|
2220
2111
|
}
|
|
2221
|
-
|
|
2222
|
-
|
|
2112
|
+
actualW = Math.min(actualW, dst.width - x);
|
|
2113
|
+
actualH = Math.min(actualH, dst.height - y);
|
|
2223
2114
|
if (actualW <= 0 || actualH <= 0) return;
|
|
2224
2115
|
const dx = x - targetX | 0;
|
|
2225
2116
|
const dy = y - targetY | 0;
|
|
2226
2117
|
const dst32 = dst.data32;
|
|
2227
2118
|
const dw = dst.width;
|
|
2228
|
-
const mPitch =
|
|
2119
|
+
const mPitch = mask.w;
|
|
2120
|
+
const maskData = mask.data;
|
|
2229
2121
|
let dIdx = y * dw + x | 0;
|
|
2230
2122
|
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
2231
2123
|
const dStride = dw - actualW | 0;
|
|
@@ -2234,7 +2126,7 @@ function blendColorPixelDataAlphaMask(dst, color, mask, opts) {
|
|
|
2234
2126
|
const colorRGB = color & 16777215;
|
|
2235
2127
|
for (let iy = 0; iy < actualH; iy++) {
|
|
2236
2128
|
for (let ix = 0; ix < actualW; ix++) {
|
|
2237
|
-
const mVal =
|
|
2129
|
+
const mVal = maskData[mIdx];
|
|
2238
2130
|
const effM = invertMask ? 255 - mVal : mVal;
|
|
2239
2131
|
if (effM === 0) {
|
|
2240
2132
|
dIdx++;
|
|
@@ -2271,6 +2163,155 @@ function blendColorPixelDataAlphaMask(dst, color, mask, opts) {
|
|
|
2271
2163
|
}
|
|
2272
2164
|
}
|
|
2273
2165
|
|
|
2166
|
+
// src/PixelData/blendColorPixelDataBinaryMask.ts
|
|
2167
|
+
function blendColorPixelDataBinaryMask(dst, color, mask, opts = {}) {
|
|
2168
|
+
const targetX = opts.x ?? 0;
|
|
2169
|
+
const targetY = opts.y ?? 0;
|
|
2170
|
+
let w = opts.w ?? mask.w;
|
|
2171
|
+
let h = opts.h ?? mask.h;
|
|
2172
|
+
const globalAlpha = opts.alpha ?? 255;
|
|
2173
|
+
const blendFn = opts.blendFn ?? sourceOverPerfect;
|
|
2174
|
+
const mx = opts.mx ?? 0;
|
|
2175
|
+
const my = opts.my ?? 0;
|
|
2176
|
+
const invertMask = opts.invertMask ?? false;
|
|
2177
|
+
if (globalAlpha === 0) return;
|
|
2178
|
+
const baseSrcAlpha = color >>> 24;
|
|
2179
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
2180
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return;
|
|
2181
|
+
let x = targetX;
|
|
2182
|
+
let y = targetY;
|
|
2183
|
+
if (x < 0) {
|
|
2184
|
+
w += x;
|
|
2185
|
+
x = 0;
|
|
2186
|
+
}
|
|
2187
|
+
if (y < 0) {
|
|
2188
|
+
h += y;
|
|
2189
|
+
y = 0;
|
|
2190
|
+
}
|
|
2191
|
+
const actualW = Math.min(w, dst.width - x);
|
|
2192
|
+
const actualH = Math.min(h, dst.height - y);
|
|
2193
|
+
if (actualW <= 0 || actualH <= 0) return;
|
|
2194
|
+
let baseColorWithGlobalAlpha = color;
|
|
2195
|
+
if (globalAlpha < 255) {
|
|
2196
|
+
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
2197
|
+
if (a === 0 && !isOverwrite) return;
|
|
2198
|
+
baseColorWithGlobalAlpha = (color & 16777215 | a << 24) >>> 0;
|
|
2199
|
+
}
|
|
2200
|
+
const dx = x - targetX | 0;
|
|
2201
|
+
const dy = y - targetY | 0;
|
|
2202
|
+
const dst32 = dst.data32;
|
|
2203
|
+
const dw = dst.width;
|
|
2204
|
+
const mPitch = mask.w;
|
|
2205
|
+
const maskData = mask.data;
|
|
2206
|
+
let dIdx = y * dw + x | 0;
|
|
2207
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
2208
|
+
const dStride = dw - actualW | 0;
|
|
2209
|
+
const mStride = mPitch - actualW | 0;
|
|
2210
|
+
const skipVal = invertMask ? 1 : 0;
|
|
2211
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2212
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2213
|
+
if (maskData[mIdx] === skipVal) {
|
|
2214
|
+
dIdx++;
|
|
2215
|
+
mIdx++;
|
|
2216
|
+
continue;
|
|
2217
|
+
}
|
|
2218
|
+
dst32[dIdx] = blendFn(baseColorWithGlobalAlpha, dst32[dIdx]);
|
|
2219
|
+
dIdx++;
|
|
2220
|
+
mIdx++;
|
|
2221
|
+
}
|
|
2222
|
+
dIdx += dStride;
|
|
2223
|
+
mIdx += mStride;
|
|
2224
|
+
}
|
|
2225
|
+
}
|
|
2226
|
+
|
|
2227
|
+
// src/PixelData/applyCircleBrushToPixelData.ts
|
|
2228
|
+
function applyCircleBrushToPixelData(target, color, centerX, centerY, brush, alpha = 255, blendFn = sourceOverPerfect, scratchOptions = {}, bounds) {
|
|
2229
|
+
const b = bounds ?? getCircleBrushOrPencilBounds(centerX, centerY, brush.size, target.width, target.height);
|
|
2230
|
+
if (b.w <= 0 || b.h <= 0) return;
|
|
2231
|
+
const unclippedStartX = Math.floor(centerX + brush.minOffset);
|
|
2232
|
+
const unclippedStartY = Math.floor(centerY + brush.minOffset);
|
|
2233
|
+
const ix = Math.max(unclippedStartX, b.x);
|
|
2234
|
+
const iy = Math.max(unclippedStartY, b.y);
|
|
2235
|
+
const ir = Math.min(unclippedStartX + brush.w, b.x + b.w);
|
|
2236
|
+
const ib = Math.min(unclippedStartY + brush.h, b.y + b.h);
|
|
2237
|
+
const iw = ir - ix;
|
|
2238
|
+
const ih = ib - iy;
|
|
2239
|
+
if (iw <= 0 || ih <= 0) return;
|
|
2240
|
+
scratchOptions.x = ix;
|
|
2241
|
+
scratchOptions.y = iy;
|
|
2242
|
+
scratchOptions.w = iw;
|
|
2243
|
+
scratchOptions.h = ih;
|
|
2244
|
+
scratchOptions.mx = ix - unclippedStartX;
|
|
2245
|
+
scratchOptions.my = iy - unclippedStartY;
|
|
2246
|
+
scratchOptions.alpha = alpha;
|
|
2247
|
+
scratchOptions.blendFn = blendFn;
|
|
2248
|
+
if (brush.type === 0 /* ALPHA */) {
|
|
2249
|
+
blendColorPixelDataAlphaMask(target, color, brush, scratchOptions);
|
|
2250
|
+
}
|
|
2251
|
+
if (brush.type === 1 /* BINARY */) {
|
|
2252
|
+
blendColorPixelDataBinaryMask(target, color, brush, scratchOptions);
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
|
|
2256
|
+
// src/History/PixelMutator/mutatorApplyCircleBrush.ts
|
|
2257
|
+
var defaults3 = {
|
|
2258
|
+
applyCircleBrushToPixelData,
|
|
2259
|
+
getCircleBrushOrPencilBounds
|
|
2260
|
+
};
|
|
2261
|
+
var mutatorApplyCircleBrush = ((writer, deps = defaults3) => {
|
|
2262
|
+
const {
|
|
2263
|
+
applyCircleBrushToPixelData: applyCircleBrushToPixelData2 = defaults3.applyCircleBrushToPixelData,
|
|
2264
|
+
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults3.getCircleBrushOrPencilBounds
|
|
2265
|
+
} = deps;
|
|
2266
|
+
const boundsOut = {
|
|
2267
|
+
x: 0,
|
|
2268
|
+
y: 0,
|
|
2269
|
+
w: 0,
|
|
2270
|
+
h: 0
|
|
2271
|
+
};
|
|
2272
|
+
const blendColorPixelOptions = {
|
|
2273
|
+
alpha: 255,
|
|
2274
|
+
blendFn: sourceOverPerfect,
|
|
2275
|
+
x: 0,
|
|
2276
|
+
y: 0,
|
|
2277
|
+
w: 0,
|
|
2278
|
+
h: 0
|
|
2279
|
+
};
|
|
2280
|
+
return {
|
|
2281
|
+
applyCircleBrush(color, centerX, centerY, brush, alpha = 255, blendFn) {
|
|
2282
|
+
const bounds = getCircleBrushOrPencilBounds2(centerX, centerY, brush.size, writer.target.width, writer.target.height, boundsOut);
|
|
2283
|
+
const {
|
|
2284
|
+
x,
|
|
2285
|
+
y,
|
|
2286
|
+
w,
|
|
2287
|
+
h
|
|
2288
|
+
} = bounds;
|
|
2289
|
+
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2290
|
+
applyCircleBrushToPixelData2(writer.target, color, centerX, centerY, brush, alpha, blendFn, blendColorPixelOptions, bounds);
|
|
2291
|
+
}
|
|
2292
|
+
};
|
|
2293
|
+
});
|
|
2294
|
+
|
|
2295
|
+
// src/Algorithm/forEachLinePoint.ts
|
|
2296
|
+
function forEachLinePoint(x0, y0, x1, y1, callback) {
|
|
2297
|
+
const dx = x1 - x0;
|
|
2298
|
+
const dy = y1 - y0;
|
|
2299
|
+
const steps = Math.max(Math.abs(dx), Math.abs(dy));
|
|
2300
|
+
if (steps === 0) {
|
|
2301
|
+
callback(x0, y0);
|
|
2302
|
+
return;
|
|
2303
|
+
}
|
|
2304
|
+
const xInc = dx / steps;
|
|
2305
|
+
const yInc = dy / steps;
|
|
2306
|
+
let curX = x0;
|
|
2307
|
+
let curY = y0;
|
|
2308
|
+
for (let i = 0; i <= steps; i++) {
|
|
2309
|
+
callback(curX, curY);
|
|
2310
|
+
curX += xInc;
|
|
2311
|
+
curY += yInc;
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
|
|
2274
2315
|
// src/Rect/getCircleBrushOrPencilStrokeBounds.ts
|
|
2275
2316
|
function getCircleBrushOrPencilStrokeBounds(x0, y0, x1, y1, brushSize, result) {
|
|
2276
2317
|
const r = Math.ceil(brushSize / 2);
|
|
@@ -2319,8 +2360,15 @@ var mutatorApplyCircleBrushStroke = ((writer, deps = defaults4) => {
|
|
|
2319
2360
|
w: 0,
|
|
2320
2361
|
h: 0
|
|
2321
2362
|
};
|
|
2363
|
+
const mask = {
|
|
2364
|
+
type: 0 /* ALPHA */,
|
|
2365
|
+
data: null,
|
|
2366
|
+
w: 0,
|
|
2367
|
+
h: 0
|
|
2368
|
+
};
|
|
2322
2369
|
return {
|
|
2323
|
-
applyCircleBrushStroke(color, x0, y0, x1, y1,
|
|
2370
|
+
applyCircleBrushStroke(color, x0, y0, x1, y1, brush, alpha = 255, blendFn = sourceOverPerfect) {
|
|
2371
|
+
const brushSize = brush.size;
|
|
2324
2372
|
const {
|
|
2325
2373
|
x: bx,
|
|
2326
2374
|
y: by,
|
|
@@ -2328,11 +2376,12 @@ var mutatorApplyCircleBrushStroke = ((writer, deps = defaults4) => {
|
|
|
2328
2376
|
h: bh
|
|
2329
2377
|
} = getCircleBrushOrPencilStrokeBounds2(x0, y0, x1, y1, brushSize, strokeBoundsOut);
|
|
2330
2378
|
if (bw <= 0 || bh <= 0) return;
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
const
|
|
2335
|
-
const
|
|
2379
|
+
mask.data = new Uint8Array(bw * bh);
|
|
2380
|
+
mask.w = bw;
|
|
2381
|
+
mask.h = bh;
|
|
2382
|
+
const maskData = mask.data;
|
|
2383
|
+
const brushData = brush.data;
|
|
2384
|
+
const minOffset = brush.minOffset;
|
|
2336
2385
|
const targetWidth = writer.target.width;
|
|
2337
2386
|
const targetHeight = writer.target.height;
|
|
2338
2387
|
forEachLinePoint2(x0, y0, x1, y1, (px, py) => {
|
|
@@ -2347,21 +2396,20 @@ var mutatorApplyCircleBrushStroke = ((writer, deps = defaults4) => {
|
|
|
2347
2396
|
const startY = Math.max(by, cby);
|
|
2348
2397
|
const endX = Math.min(bx + bw, cbx + cbw);
|
|
2349
2398
|
const endY = Math.min(by + bh, cby + cbh);
|
|
2350
|
-
const
|
|
2351
|
-
const
|
|
2399
|
+
const unclippedStartX = Math.floor(px + minOffset);
|
|
2400
|
+
const unclippedStartY = Math.floor(py + minOffset);
|
|
2352
2401
|
for (let my = startY; my < endY; my++) {
|
|
2353
|
-
const
|
|
2354
|
-
const
|
|
2355
|
-
const
|
|
2402
|
+
const strokeMaskY = my - by;
|
|
2403
|
+
const strokeMaskRowOffset = strokeMaskY * bw;
|
|
2404
|
+
const brushY = my - unclippedStartY;
|
|
2405
|
+
const brushRowOffset = brushY * brushSize;
|
|
2356
2406
|
for (let mx = startX; mx < endX; mx++) {
|
|
2357
|
-
const
|
|
2358
|
-
const
|
|
2359
|
-
if (
|
|
2360
|
-
const
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
if (intensity > mask[maskIdx]) {
|
|
2364
|
-
mask[maskIdx] = intensity;
|
|
2407
|
+
const brushX = mx - unclippedStartX;
|
|
2408
|
+
const brushVal = brushData[brushRowOffset + brushX];
|
|
2409
|
+
if (brushVal > 0) {
|
|
2410
|
+
const strokeMaskIdx = strokeMaskRowOffset + (mx - bx);
|
|
2411
|
+
if (brushVal > maskData[strokeMaskIdx]) {
|
|
2412
|
+
maskData[strokeMaskIdx] = brushVal;
|
|
2365
2413
|
}
|
|
2366
2414
|
}
|
|
2367
2415
|
}
|
|
@@ -2378,71 +2426,6 @@ var mutatorApplyCircleBrushStroke = ((writer, deps = defaults4) => {
|
|
|
2378
2426
|
};
|
|
2379
2427
|
});
|
|
2380
2428
|
|
|
2381
|
-
// src/PixelData/blendColorPixelDataBinaryMask.ts
|
|
2382
|
-
function blendColorPixelDataBinaryMask(dst, color, mask, opts = {}) {
|
|
2383
|
-
const {
|
|
2384
|
-
x: targetX = 0,
|
|
2385
|
-
y: targetY = 0,
|
|
2386
|
-
w: width = dst.width,
|
|
2387
|
-
h: height = dst.height,
|
|
2388
|
-
alpha: globalAlpha = 255,
|
|
2389
|
-
blendFn = sourceOverPerfect,
|
|
2390
|
-
mw = width,
|
|
2391
|
-
mx = 0,
|
|
2392
|
-
my = 0,
|
|
2393
|
-
invertMask = false
|
|
2394
|
-
} = opts;
|
|
2395
|
-
if (globalAlpha === 0 || !mask) return;
|
|
2396
|
-
const baseSrcAlpha = color >>> 24;
|
|
2397
|
-
const isOverwrite = blendFn.isOverwrite || false;
|
|
2398
|
-
if (baseSrcAlpha === 0 && !isOverwrite) return;
|
|
2399
|
-
let x = targetX;
|
|
2400
|
-
let y = targetY;
|
|
2401
|
-
let w = width;
|
|
2402
|
-
let h = height;
|
|
2403
|
-
if (x < 0) {
|
|
2404
|
-
w += x;
|
|
2405
|
-
x = 0;
|
|
2406
|
-
}
|
|
2407
|
-
if (y < 0) {
|
|
2408
|
-
h += y;
|
|
2409
|
-
y = 0;
|
|
2410
|
-
}
|
|
2411
|
-
const actualW = Math.min(w, dst.width - x);
|
|
2412
|
-
const actualH = Math.min(h, dst.height - y);
|
|
2413
|
-
if (actualW <= 0 || actualH <= 0) return;
|
|
2414
|
-
let baseColorWithGlobalAlpha = color;
|
|
2415
|
-
if (globalAlpha < 255) {
|
|
2416
|
-
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
2417
|
-
if (a === 0 && !isOverwrite) return;
|
|
2418
|
-
baseColorWithGlobalAlpha = (color & 16777215 | a << 24) >>> 0;
|
|
2419
|
-
}
|
|
2420
|
-
const dx = x - targetX | 0;
|
|
2421
|
-
const dy = y - targetY | 0;
|
|
2422
|
-
const dst32 = dst.data32;
|
|
2423
|
-
const dw = dst.width;
|
|
2424
|
-
const mPitch = mw;
|
|
2425
|
-
let dIdx = y * dw + x | 0;
|
|
2426
|
-
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
2427
|
-
const dStride = dw - actualW | 0;
|
|
2428
|
-
const mStride = mPitch - actualW | 0;
|
|
2429
|
-
const skipVal = invertMask ? 1 : 0;
|
|
2430
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
2431
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
2432
|
-
if (mask[mIdx] === skipVal) {
|
|
2433
|
-
dIdx++;
|
|
2434
|
-
mIdx++;
|
|
2435
|
-
continue;
|
|
2436
|
-
}
|
|
2437
|
-
dst32[dIdx] = blendFn(baseColorWithGlobalAlpha, dst32[dIdx]);
|
|
2438
|
-
dIdx++;
|
|
2439
|
-
mIdx++;
|
|
2440
|
-
}
|
|
2441
|
-
dIdx += dStride;
|
|
2442
|
-
mIdx += mStride;
|
|
2443
|
-
}
|
|
2444
|
-
}
|
|
2445
|
-
|
|
2446
2429
|
// src/History/PixelMutator/mutatorApplyCirclePencilStroke.ts
|
|
2447
2430
|
var defaults5 = {
|
|
2448
2431
|
forEachLinePoint,
|
|
@@ -2477,19 +2460,25 @@ var mutatorApplyCirclePencilStroke = ((writer, deps = defaults5) => {
|
|
|
2477
2460
|
w: 0,
|
|
2478
2461
|
h: 0
|
|
2479
2462
|
};
|
|
2463
|
+
const mask = {
|
|
2464
|
+
type: 1 /* BINARY */,
|
|
2465
|
+
data: null,
|
|
2466
|
+
w: 0,
|
|
2467
|
+
h: 0
|
|
2468
|
+
};
|
|
2480
2469
|
return {
|
|
2481
|
-
applyCirclePencilStroke(color, x0, y0, x1, y1,
|
|
2470
|
+
applyCirclePencilStroke(color, x0, y0, x1, y1, brush, alpha = 255, blendFn = sourceOverPerfect) {
|
|
2482
2471
|
const {
|
|
2483
2472
|
x: bx,
|
|
2484
2473
|
y: by,
|
|
2485
2474
|
w: bw,
|
|
2486
2475
|
h: bh
|
|
2487
|
-
} = getCircleBrushOrPencilStrokeBounds2(x0, y0, x1, y1,
|
|
2476
|
+
} = getCircleBrushOrPencilStrokeBounds2(x0, y0, x1, y1, brush.size, strokeBoundsOut);
|
|
2488
2477
|
if (bw <= 0 || bh <= 0) return;
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
const
|
|
2478
|
+
mask.data = new Uint8Array(bw * bh);
|
|
2479
|
+
mask.w = bw;
|
|
2480
|
+
mask.h = bh;
|
|
2481
|
+
const maskData = mask.data;
|
|
2493
2482
|
const targetWidth = writer.target.width;
|
|
2494
2483
|
const targetHeight = writer.target.height;
|
|
2495
2484
|
forEachLinePoint2(x0, y0, x1, y1, (px, py) => {
|
|
@@ -2498,24 +2487,24 @@ var mutatorApplyCirclePencilStroke = ((writer, deps = defaults5) => {
|
|
|
2498
2487
|
y: cby,
|
|
2499
2488
|
w: cbw,
|
|
2500
2489
|
h: cbh
|
|
2501
|
-
} = getCircleBrushOrPencilBounds2(px, py,
|
|
2490
|
+
} = getCircleBrushOrPencilBounds2(px, py, brush.size, targetWidth, targetHeight, circlePencilBounds);
|
|
2502
2491
|
writer.accumulator.storeRegionBeforeState(cbx, cby, cbw, cbh);
|
|
2503
|
-
const
|
|
2504
|
-
const
|
|
2505
|
-
const
|
|
2506
|
-
const
|
|
2507
|
-
const
|
|
2508
|
-
const
|
|
2492
|
+
const unclippedStartX = Math.floor(px + brush.minOffset);
|
|
2493
|
+
const unclippedStartY = Math.floor(py + brush.minOffset);
|
|
2494
|
+
const startX = Math.max(bx, unclippedStartX);
|
|
2495
|
+
const startY = Math.max(by, unclippedStartY);
|
|
2496
|
+
const endX = Math.min(bx + bw, unclippedStartX + brush.w);
|
|
2497
|
+
const endY = Math.min(by + bh, unclippedStartY + brush.h);
|
|
2509
2498
|
for (let my = startY; my < endY; my++) {
|
|
2510
|
-
const
|
|
2511
|
-
const dySqr = dy * dy;
|
|
2499
|
+
const brushY = my - unclippedStartY;
|
|
2512
2500
|
const maskRowOffset = (my - by) * bw;
|
|
2501
|
+
const brushRowOffset = brushY * brush.w;
|
|
2513
2502
|
for (let mx = startX; mx < endX; mx++) {
|
|
2514
|
-
const
|
|
2515
|
-
const
|
|
2516
|
-
if (
|
|
2503
|
+
const brushX = mx - unclippedStartX;
|
|
2504
|
+
const brushAlpha = brush.data[brushRowOffset + brushX];
|
|
2505
|
+
if (brushAlpha > 0) {
|
|
2517
2506
|
const maskIdx = maskRowOffset + (mx - bx);
|
|
2518
|
-
|
|
2507
|
+
maskData[maskIdx] = brushAlpha;
|
|
2519
2508
|
}
|
|
2520
2509
|
}
|
|
2521
2510
|
}
|
|
@@ -2682,6 +2671,12 @@ var mutatorApplyRectBrushStroke = ((writer, deps = defaults7) => {
|
|
|
2682
2671
|
w: 0,
|
|
2683
2672
|
h: 0
|
|
2684
2673
|
};
|
|
2674
|
+
const mask = {
|
|
2675
|
+
type: 0 /* ALPHA */,
|
|
2676
|
+
data: null,
|
|
2677
|
+
w: 0,
|
|
2678
|
+
h: 0
|
|
2679
|
+
};
|
|
2685
2680
|
return {
|
|
2686
2681
|
applyRectBrushStroke(color, x0, y0, x1, y1, brushWidth, brushHeight, alpha = 255, fallOff, blendFn = sourceOverPerfect) {
|
|
2687
2682
|
const {
|
|
@@ -2691,7 +2686,10 @@ var mutatorApplyRectBrushStroke = ((writer, deps = defaults7) => {
|
|
|
2691
2686
|
h: bh
|
|
2692
2687
|
} = getRectBrushOrPencilStrokeBounds2(x0, y0, x1, y1, brushWidth, brushHeight, strokeBoundsOut);
|
|
2693
2688
|
if (bw <= 0 || bh <= 0) return;
|
|
2694
|
-
|
|
2689
|
+
mask.data = new Uint8Array(bw * bh);
|
|
2690
|
+
mask.w = bw;
|
|
2691
|
+
mask.h = bh;
|
|
2692
|
+
const maskData = mask.data;
|
|
2695
2693
|
const halfW = brushWidth / 2;
|
|
2696
2694
|
const halfH = brushHeight / 2;
|
|
2697
2695
|
const invHalfW = 1 / halfW;
|
|
@@ -2724,8 +2722,8 @@ var mutatorApplyRectBrushStroke = ((writer, deps = defaults7) => {
|
|
|
2724
2722
|
const strength = fallOff(dist);
|
|
2725
2723
|
if (strength > 0) {
|
|
2726
2724
|
const intensity = strength * 255 | 0;
|
|
2727
|
-
if (intensity >
|
|
2728
|
-
|
|
2725
|
+
if (intensity > maskData[maskIdx]) {
|
|
2726
|
+
maskData[maskIdx] = intensity;
|
|
2729
2727
|
}
|
|
2730
2728
|
}
|
|
2731
2729
|
}
|
|
@@ -2809,6 +2807,12 @@ var mutatorApplyRectPencilStroke = ((writer, deps = defaults9) => {
|
|
|
2809
2807
|
w: 0,
|
|
2810
2808
|
h: 0
|
|
2811
2809
|
};
|
|
2810
|
+
const mask = {
|
|
2811
|
+
type: 1 /* BINARY */,
|
|
2812
|
+
data: null,
|
|
2813
|
+
w: 0,
|
|
2814
|
+
h: 0
|
|
2815
|
+
};
|
|
2812
2816
|
return {
|
|
2813
2817
|
applyRectPencilStroke(color, x0, y0, x1, y1, brushWidth, brushHeight, alpha = 255, blendFn = sourceOverPerfect) {
|
|
2814
2818
|
const {
|
|
@@ -2818,7 +2822,10 @@ var mutatorApplyRectPencilStroke = ((writer, deps = defaults9) => {
|
|
|
2818
2822
|
h: bh
|
|
2819
2823
|
} = getRectBrushOrPencilStrokeBounds2(x0, y0, x1, y1, brushWidth, brushHeight, strokeBoundsOut);
|
|
2820
2824
|
if (bw <= 0 || bh <= 0) return;
|
|
2821
|
-
|
|
2825
|
+
mask.data = new Uint8Array(bw * bh);
|
|
2826
|
+
mask.w = bw;
|
|
2827
|
+
mask.h = bh;
|
|
2828
|
+
const maskData = mask.data;
|
|
2822
2829
|
const halfW = brushWidth / 2;
|
|
2823
2830
|
const halfH = brushHeight / 2;
|
|
2824
2831
|
const centerOffset = brushWidth % 2 === 0 ? 0.5 : 0;
|
|
@@ -2845,7 +2852,7 @@ var mutatorApplyRectPencilStroke = ((writer, deps = defaults9) => {
|
|
|
2845
2852
|
const dx = Math.abs(mx - fPx + centerOffset);
|
|
2846
2853
|
const maskIdx = maskRowOffset + (mx - bx);
|
|
2847
2854
|
if (dx <= halfW && dy <= halfH) {
|
|
2848
|
-
|
|
2855
|
+
maskData[maskIdx] = 1;
|
|
2849
2856
|
}
|
|
2850
2857
|
}
|
|
2851
2858
|
}
|
|
@@ -3056,24 +3063,21 @@ var mutatorBlendPixelData = ((writer, deps = defaults11) => {
|
|
|
3056
3063
|
|
|
3057
3064
|
// src/PixelData/fillPixelData.ts
|
|
3058
3065
|
var SCRATCH_RECT = makeClippedRect();
|
|
3059
|
-
function fillPixelData(dst, color, _x, _y, _w, _h
|
|
3066
|
+
function fillPixelData(dst, color, _x, _y, _w, _h) {
|
|
3060
3067
|
let x;
|
|
3061
3068
|
let y;
|
|
3062
3069
|
let w;
|
|
3063
3070
|
let h;
|
|
3064
|
-
let mask;
|
|
3065
3071
|
if (typeof _x === "object") {
|
|
3066
3072
|
x = _x.x ?? 0;
|
|
3067
3073
|
y = _x.y ?? 0;
|
|
3068
3074
|
w = _x.w ?? dst.width;
|
|
3069
3075
|
h = _x.h ?? dst.height;
|
|
3070
|
-
mask = _x.mask;
|
|
3071
3076
|
} else if (typeof _x === "number") {
|
|
3072
3077
|
x = _x;
|
|
3073
3078
|
y = _y;
|
|
3074
3079
|
w = _w;
|
|
3075
3080
|
h = _h;
|
|
3076
|
-
mask = _mask;
|
|
3077
3081
|
} else {
|
|
3078
3082
|
x = 0;
|
|
3079
3083
|
y = 0;
|
|
@@ -3094,28 +3098,10 @@ function fillPixelData(dst, color, _x, _y, _w, _h, _mask) {
|
|
|
3094
3098
|
dst32.fill(color);
|
|
3095
3099
|
return;
|
|
3096
3100
|
}
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
const maskOffset = maskY * w;
|
|
3102
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
3103
|
-
const currentX = finalX + ix;
|
|
3104
|
-
const maskX = currentX - x;
|
|
3105
|
-
const maskIndex = maskOffset + maskX;
|
|
3106
|
-
const isMasked = mask[maskIndex];
|
|
3107
|
-
if (isMasked) {
|
|
3108
|
-
const dstIndex = currentY * dw + currentX;
|
|
3109
|
-
dst32[dstIndex] = color;
|
|
3110
|
-
}
|
|
3111
|
-
}
|
|
3112
|
-
}
|
|
3113
|
-
} else {
|
|
3114
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
3115
|
-
const start = (finalY + iy) * dw + finalX;
|
|
3116
|
-
const end = start + actualW;
|
|
3117
|
-
dst32.fill(color, start, end);
|
|
3118
|
-
}
|
|
3101
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
3102
|
+
const start = (finalY + iy) * dw + finalX;
|
|
3103
|
+
const end = start + actualW;
|
|
3104
|
+
dst32.fill(color, start, end);
|
|
3119
3105
|
}
|
|
3120
3106
|
}
|
|
3121
3107
|
|
|
@@ -3129,15 +3115,12 @@ var mutatorClear = ((writer, deps = defaults12) => {
|
|
|
3129
3115
|
} = deps;
|
|
3130
3116
|
return {
|
|
3131
3117
|
clear(rect = {}) {
|
|
3132
|
-
const
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
h = writer.target.height,
|
|
3137
|
-
mask = void 0
|
|
3138
|
-
} = rect;
|
|
3118
|
+
const x = rect.x ?? 0;
|
|
3119
|
+
const y = rect.y ?? 0;
|
|
3120
|
+
const w = rect.w ?? writer.target.width;
|
|
3121
|
+
const h = rect.h ?? writer.target.height;
|
|
3139
3122
|
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3140
|
-
fillPixelData2(writer.target, 0, x, y, w, h
|
|
3123
|
+
fillPixelData2(writer.target, 0, x, y, w, h);
|
|
3141
3124
|
}
|
|
3142
3125
|
};
|
|
3143
3126
|
});
|
|
@@ -3156,11 +3139,10 @@ var mutatorFill = ((writer, deps = defaults13) => {
|
|
|
3156
3139
|
x = 0,
|
|
3157
3140
|
y = 0,
|
|
3158
3141
|
w = writer.target.width,
|
|
3159
|
-
h = writer.target.height
|
|
3160
|
-
mask = void 0
|
|
3142
|
+
h = writer.target.height
|
|
3161
3143
|
} = rect;
|
|
3162
3144
|
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3163
|
-
fillPixelData2(writer.target, color, x, y, w, h
|
|
3145
|
+
fillPixelData2(writer.target, color, x, y, w, h);
|
|
3164
3146
|
}
|
|
3165
3147
|
};
|
|
3166
3148
|
});
|
|
@@ -3175,7 +3157,6 @@ function invertPixelData(pixelData, opts = {}) {
|
|
|
3175
3157
|
w: width = pixelData.width,
|
|
3176
3158
|
h: height = pixelData.height,
|
|
3177
3159
|
mask,
|
|
3178
|
-
mw,
|
|
3179
3160
|
mx = 0,
|
|
3180
3161
|
my = 0,
|
|
3181
3162
|
invertMask = false
|
|
@@ -3190,7 +3171,7 @@ function invertPixelData(pixelData, opts = {}) {
|
|
|
3190
3171
|
} = clip;
|
|
3191
3172
|
const dst32 = dst.data32;
|
|
3192
3173
|
const dw = dst.width;
|
|
3193
|
-
const mPitch =
|
|
3174
|
+
const mPitch = mask?.w ?? width;
|
|
3194
3175
|
const dx = x - targetX;
|
|
3195
3176
|
const dy = y - targetY;
|
|
3196
3177
|
let dIdx = y * dw + x;
|
|
@@ -3198,9 +3179,10 @@ function invertPixelData(pixelData, opts = {}) {
|
|
|
3198
3179
|
const dStride = dw - actualW;
|
|
3199
3180
|
const mStride = mPitch - actualW;
|
|
3200
3181
|
if (mask) {
|
|
3182
|
+
const maskData = mask.data;
|
|
3201
3183
|
for (let iy = 0; iy < actualH; iy++) {
|
|
3202
3184
|
for (let ix = 0; ix < actualW; ix++) {
|
|
3203
|
-
const mVal =
|
|
3185
|
+
const mVal = maskData[mIdx];
|
|
3204
3186
|
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
3205
3187
|
if (isHit) {
|
|
3206
3188
|
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
@@ -3311,14 +3293,12 @@ var PixelWriter = class {
|
|
|
3311
3293
|
// src/History/PixelMutator/mutatorApplyCirclePencil.ts
|
|
3312
3294
|
var defaults15 = {
|
|
3313
3295
|
applyCircleBrushToPixelData,
|
|
3314
|
-
getCircleBrushOrPencilBounds
|
|
3315
|
-
fallOff: () => 1
|
|
3296
|
+
getCircleBrushOrPencilBounds
|
|
3316
3297
|
};
|
|
3317
3298
|
var mutatorApplyCirclePencil = ((writer, deps = defaults15) => {
|
|
3318
3299
|
const {
|
|
3319
3300
|
applyCircleBrushToPixelData: applyCircleBrushToPixelData2 = defaults15.applyCircleBrushToPixelData,
|
|
3320
|
-
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults15.getCircleBrushOrPencilBounds
|
|
3321
|
-
fallOff = defaults15.fallOff
|
|
3301
|
+
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults15.getCircleBrushOrPencilBounds
|
|
3322
3302
|
} = deps;
|
|
3323
3303
|
const boundsOut = {
|
|
3324
3304
|
x: 0,
|
|
@@ -3327,8 +3307,8 @@ var mutatorApplyCirclePencil = ((writer, deps = defaults15) => {
|
|
|
3327
3307
|
h: 0
|
|
3328
3308
|
};
|
|
3329
3309
|
return {
|
|
3330
|
-
applyCirclePencil(color, centerX, centerY,
|
|
3331
|
-
const bounds = getCircleBrushOrPencilBounds2(centerX, centerY,
|
|
3310
|
+
applyCirclePencil(color, centerX, centerY, brush, alpha = 255, blendFn) {
|
|
3311
|
+
const bounds = getCircleBrushOrPencilBounds2(centerX, centerY, brush.size, writer.target.width, writer.target.height, boundsOut);
|
|
3332
3312
|
const {
|
|
3333
3313
|
x,
|
|
3334
3314
|
y,
|
|
@@ -3336,7 +3316,63 @@ var mutatorApplyCirclePencil = ((writer, deps = defaults15) => {
|
|
|
3336
3316
|
h
|
|
3337
3317
|
} = bounds;
|
|
3338
3318
|
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3339
|
-
applyCircleBrushToPixelData2(writer.target, color, centerX, centerY,
|
|
3319
|
+
applyCircleBrushToPixelData2(writer.target, color, centerX, centerY, brush, alpha, blendFn, bounds);
|
|
3320
|
+
}
|
|
3321
|
+
};
|
|
3322
|
+
});
|
|
3323
|
+
|
|
3324
|
+
// src/PixelData/fillPixelDataBinaryMask.ts
|
|
3325
|
+
var SCRATCH_RECT3 = makeClippedRect();
|
|
3326
|
+
function fillPixelDataBinaryMask(dst, color, mask, alpha = 255, x = 0, y = 0) {
|
|
3327
|
+
if (alpha === 0) return;
|
|
3328
|
+
const maskW = mask.w;
|
|
3329
|
+
const maskH = mask.h;
|
|
3330
|
+
const clip = resolveRectClipping(x, y, maskW, maskH, dst.width, dst.height, SCRATCH_RECT3);
|
|
3331
|
+
if (!clip.inBounds) return;
|
|
3332
|
+
const {
|
|
3333
|
+
x: finalX,
|
|
3334
|
+
y: finalY,
|
|
3335
|
+
w: actualW,
|
|
3336
|
+
h: actualH
|
|
3337
|
+
} = clip;
|
|
3338
|
+
const maskData = mask.data;
|
|
3339
|
+
const dst32 = dst.data32;
|
|
3340
|
+
const dw = dst.width;
|
|
3341
|
+
let finalCol = color;
|
|
3342
|
+
if (alpha < 255) {
|
|
3343
|
+
const baseSrcAlpha = color >>> 24;
|
|
3344
|
+
const colorRGB = color & 16777215;
|
|
3345
|
+
const a = baseSrcAlpha * alpha + 128 >> 8;
|
|
3346
|
+
finalCol = (colorRGB | a << 24) >>> 0;
|
|
3347
|
+
}
|
|
3348
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
3349
|
+
const currentY = finalY + iy;
|
|
3350
|
+
const maskY = currentY - y;
|
|
3351
|
+
const maskOffset = maskY * maskW;
|
|
3352
|
+
const dstRowOffset = currentY * dw;
|
|
3353
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
3354
|
+
const currentX = finalX + ix;
|
|
3355
|
+
const maskX = currentX - x;
|
|
3356
|
+
const maskIndex = maskOffset + maskX;
|
|
3357
|
+
if (maskData[maskIndex]) {
|
|
3358
|
+
dst32[dstRowOffset + currentX] = finalCol;
|
|
3359
|
+
}
|
|
3360
|
+
}
|
|
3361
|
+
}
|
|
3362
|
+
}
|
|
3363
|
+
|
|
3364
|
+
// src/History/PixelMutator/mutatorFillBinaryMask.ts
|
|
3365
|
+
var defaults16 = {
|
|
3366
|
+
fillPixelDataBinaryMask
|
|
3367
|
+
};
|
|
3368
|
+
var mutatorFillBinaryMask = ((writer, deps = defaults16) => {
|
|
3369
|
+
const {
|
|
3370
|
+
fillPixelDataBinaryMask: fillPixelDataBinaryMask2 = defaults16.fillPixelDataBinaryMask
|
|
3371
|
+
} = deps;
|
|
3372
|
+
return {
|
|
3373
|
+
fillBinaryMask(color, mask, alpha = 255, x = 0, y = 0) {
|
|
3374
|
+
writer.accumulator.storeRegionBeforeState(x, y, mask.w, mask.h);
|
|
3375
|
+
fillPixelDataBinaryMask2(writer.target, color, mask, alpha, x, y);
|
|
3340
3376
|
}
|
|
3341
3377
|
};
|
|
3342
3378
|
});
|
|
@@ -3372,8 +3408,8 @@ function makeImageDataLike(width, height, data) {
|
|
|
3372
3408
|
};
|
|
3373
3409
|
}
|
|
3374
3410
|
|
|
3375
|
-
// src/ImageData/
|
|
3376
|
-
function
|
|
3411
|
+
// src/ImageData/imageDataToAlphaMaskBuffer.ts
|
|
3412
|
+
function imageDataToAlphaMaskBuffer(imageData) {
|
|
3377
3413
|
const {
|
|
3378
3414
|
width,
|
|
3379
3415
|
height,
|
|
@@ -3463,13 +3499,13 @@ function resampleImageData(source, factor) {
|
|
|
3463
3499
|
}
|
|
3464
3500
|
|
|
3465
3501
|
// src/ImageData/resizeImageData.ts
|
|
3466
|
-
function resizeImageData(
|
|
3502
|
+
function resizeImageData(target, newWidth, newHeight, offsetX = 0, offsetY = 0) {
|
|
3467
3503
|
const result = new ImageData(newWidth, newHeight);
|
|
3468
3504
|
const {
|
|
3469
3505
|
width: oldW,
|
|
3470
3506
|
height: oldH,
|
|
3471
3507
|
data: oldData
|
|
3472
|
-
} =
|
|
3508
|
+
} = target;
|
|
3473
3509
|
const newData = result.data;
|
|
3474
3510
|
const x0 = Math.max(0, offsetX);
|
|
3475
3511
|
const y0 = Math.max(0, offsetY);
|
|
@@ -3624,7 +3660,7 @@ function writeImageData(target, source, x, y, sx = 0, sy = 0, sw = source.width,
|
|
|
3624
3660
|
|
|
3625
3661
|
// src/ImageData/writeImageDataBuffer.ts
|
|
3626
3662
|
var SCRATCH_BLIT3 = makeClippedBlit();
|
|
3627
|
-
function writeImageDataBuffer(
|
|
3663
|
+
function writeImageDataBuffer(target, data, _x, _y, _w, _h) {
|
|
3628
3664
|
const {
|
|
3629
3665
|
x,
|
|
3630
3666
|
y,
|
|
@@ -3640,7 +3676,7 @@ function writeImageDataBuffer(imageData, data, _x, _y, _w, _h) {
|
|
|
3640
3676
|
width: dstW,
|
|
3641
3677
|
height: dstH,
|
|
3642
3678
|
data: dst
|
|
3643
|
-
} =
|
|
3679
|
+
} = target;
|
|
3644
3680
|
const clip = resolveBlitClipping(x, y, 0, 0, w, h, dstW, dstH, w, h, SCRATCH_BLIT3);
|
|
3645
3681
|
if (!clip.inBounds) return;
|
|
3646
3682
|
const {
|
|
@@ -3886,8 +3922,84 @@ async function getSupportedPixelFormats(rasterMimes = defaultRasterMimes) {
|
|
|
3886
3922
|
return formatsPromise;
|
|
3887
3923
|
}
|
|
3888
3924
|
|
|
3925
|
+
// src/Mask/AlphaMask.ts
|
|
3926
|
+
function makeAlphaMask(w, h, data) {
|
|
3927
|
+
return {
|
|
3928
|
+
type: 0 /* ALPHA */,
|
|
3929
|
+
data: data ?? new Uint8Array(w * h),
|
|
3930
|
+
w,
|
|
3931
|
+
h
|
|
3932
|
+
};
|
|
3933
|
+
}
|
|
3934
|
+
|
|
3935
|
+
// src/Mask/BinaryMask.ts
|
|
3936
|
+
function makeBinaryMask(w, h, data) {
|
|
3937
|
+
return {
|
|
3938
|
+
type: 1 /* BINARY */,
|
|
3939
|
+
data: data ?? new Uint8Array(w * h),
|
|
3940
|
+
w,
|
|
3941
|
+
h
|
|
3942
|
+
};
|
|
3943
|
+
}
|
|
3944
|
+
|
|
3945
|
+
// src/Mask/CircleBrushAlphaMask.ts
|
|
3946
|
+
function makeCircleBrushAlphaMask(size, fallOff = () => 1) {
|
|
3947
|
+
const area = size * size;
|
|
3948
|
+
const data = new Uint8Array(area);
|
|
3949
|
+
const radius = size / 2;
|
|
3950
|
+
const invR = 1 / radius;
|
|
3951
|
+
const minOffset = -Math.ceil(radius - 0.5);
|
|
3952
|
+
for (let y = 0; y < size; y++) {
|
|
3953
|
+
for (let x = 0; x < size; x++) {
|
|
3954
|
+
const dx = x - radius + 0.5;
|
|
3955
|
+
const dy = y - radius + 0.5;
|
|
3956
|
+
const distSqr = dx * dx + dy * dy;
|
|
3957
|
+
if (distSqr <= radius * radius) {
|
|
3958
|
+
const dist = Math.sqrt(distSqr);
|
|
3959
|
+
data[y * size + x] = fallOff(1 - dist * invR) * 255 | 0;
|
|
3960
|
+
}
|
|
3961
|
+
}
|
|
3962
|
+
}
|
|
3963
|
+
return {
|
|
3964
|
+
type: 0 /* ALPHA */,
|
|
3965
|
+
data,
|
|
3966
|
+
w: size,
|
|
3967
|
+
h: size,
|
|
3968
|
+
radius,
|
|
3969
|
+
size,
|
|
3970
|
+
minOffset
|
|
3971
|
+
};
|
|
3972
|
+
}
|
|
3973
|
+
|
|
3974
|
+
// src/Mask/CircleBrushBinaryMask.ts
|
|
3975
|
+
function makeCircleBrushBinaryMask(size) {
|
|
3976
|
+
const area = size * size;
|
|
3977
|
+
const data = new Uint8Array(area);
|
|
3978
|
+
const radius = size / 2;
|
|
3979
|
+
const minOffset = -Math.ceil(radius - 0.5);
|
|
3980
|
+
for (let y = 0; y < size; y++) {
|
|
3981
|
+
for (let x = 0; x < size; x++) {
|
|
3982
|
+
const dx = x - radius + 0.5;
|
|
3983
|
+
const dy = y - radius + 0.5;
|
|
3984
|
+
const distSqr = dx * dx + dy * dy;
|
|
3985
|
+
if (distSqr <= radius * radius) {
|
|
3986
|
+
data[y * size + x] = 1;
|
|
3987
|
+
}
|
|
3988
|
+
}
|
|
3989
|
+
}
|
|
3990
|
+
return {
|
|
3991
|
+
type: 1 /* BINARY */,
|
|
3992
|
+
data,
|
|
3993
|
+
w: size,
|
|
3994
|
+
h: size,
|
|
3995
|
+
radius,
|
|
3996
|
+
size,
|
|
3997
|
+
minOffset
|
|
3998
|
+
};
|
|
3999
|
+
}
|
|
4000
|
+
|
|
3889
4001
|
// src/Mask/applyBinaryMaskToAlphaMask.ts
|
|
3890
|
-
function applyBinaryMaskToAlphaMask(alphaMaskDst,
|
|
4002
|
+
function applyBinaryMaskToAlphaMask(alphaMaskDst, binaryMaskSrc, opts = {}) {
|
|
3891
4003
|
const {
|
|
3892
4004
|
x: targetX = 0,
|
|
3893
4005
|
y: targetY = 0,
|
|
@@ -3897,11 +4009,13 @@ function applyBinaryMaskToAlphaMask(alphaMaskDst, dstWidth, binaryMaskSrc, srcWi
|
|
|
3897
4009
|
my = 0,
|
|
3898
4010
|
invertMask = false
|
|
3899
4011
|
} = opts;
|
|
4012
|
+
const dstWidth = alphaMaskDst.w;
|
|
3900
4013
|
if (dstWidth <= 0) return;
|
|
3901
|
-
if (binaryMaskSrc.length === 0) return;
|
|
4014
|
+
if (binaryMaskSrc.data.length === 0) return;
|
|
4015
|
+
const srcWidth = binaryMaskSrc.w;
|
|
3902
4016
|
if (srcWidth <= 0) return;
|
|
3903
|
-
const dstHeight = alphaMaskDst.length / dstWidth | 0;
|
|
3904
|
-
const srcHeight = binaryMaskSrc.length / srcWidth | 0;
|
|
4017
|
+
const dstHeight = alphaMaskDst.data.length / dstWidth | 0;
|
|
4018
|
+
const srcHeight = binaryMaskSrc.data.length / srcWidth | 0;
|
|
3905
4019
|
if (dstHeight <= 0) return;
|
|
3906
4020
|
if (srcHeight <= 0) return;
|
|
3907
4021
|
const dstX0 = Math.max(0, targetX);
|
|
@@ -3918,6 +4032,8 @@ function applyBinaryMaskToAlphaMask(alphaMaskDst, dstWidth, binaryMaskSrc, srcWi
|
|
|
3918
4032
|
if (srcY0 + (dstY1 - dstY0) <= 0) return;
|
|
3919
4033
|
const iterW = Math.min(dstX1 - dstX0, srcWidth - srcX0);
|
|
3920
4034
|
const iterH = Math.min(dstY1 - dstY0, srcHeight - srcY0);
|
|
4035
|
+
const srcData = binaryMaskSrc.data;
|
|
4036
|
+
const dstData = alphaMaskDst.data;
|
|
3921
4037
|
let dstIdx = dstY0 * dstWidth + dstX0;
|
|
3922
4038
|
let srcIdx = srcY0 * srcWidth + srcX0;
|
|
3923
4039
|
if (invertMask) {
|
|
@@ -3926,8 +4042,8 @@ function applyBinaryMaskToAlphaMask(alphaMaskDst, dstWidth, binaryMaskSrc, srcWi
|
|
|
3926
4042
|
let d = dstIdx;
|
|
3927
4043
|
let s = srcIdx;
|
|
3928
4044
|
while (d < dstEnd) {
|
|
3929
|
-
if (
|
|
3930
|
-
|
|
4045
|
+
if (srcData[s] !== 0) {
|
|
4046
|
+
dstData[d] = 0;
|
|
3931
4047
|
}
|
|
3932
4048
|
d++;
|
|
3933
4049
|
s++;
|
|
@@ -3941,8 +4057,8 @@ function applyBinaryMaskToAlphaMask(alphaMaskDst, dstWidth, binaryMaskSrc, srcWi
|
|
|
3941
4057
|
let d = dstIdx;
|
|
3942
4058
|
let s = srcIdx;
|
|
3943
4059
|
while (d < dstEnd) {
|
|
3944
|
-
if (
|
|
3945
|
-
|
|
4060
|
+
if (srcData[s] === 0) {
|
|
4061
|
+
dstData[d] = 0;
|
|
3946
4062
|
}
|
|
3947
4063
|
d++;
|
|
3948
4064
|
s++;
|
|
@@ -3955,25 +4071,72 @@ function applyBinaryMaskToAlphaMask(alphaMaskDst, dstWidth, binaryMaskSrc, srcWi
|
|
|
3955
4071
|
|
|
3956
4072
|
// src/Mask/copyMask.ts
|
|
3957
4073
|
function copyMask(src) {
|
|
3958
|
-
return
|
|
4074
|
+
return {
|
|
4075
|
+
type: src.type,
|
|
4076
|
+
data: src.data.slice(),
|
|
4077
|
+
w: src.w,
|
|
4078
|
+
h: src.h
|
|
4079
|
+
};
|
|
4080
|
+
}
|
|
4081
|
+
|
|
4082
|
+
// src/Mask/extractMask.ts
|
|
4083
|
+
function extractMask(mask, xOrRect, y, w, h) {
|
|
4084
|
+
let finalX;
|
|
4085
|
+
let finalY;
|
|
4086
|
+
let finalW;
|
|
4087
|
+
let finalH;
|
|
4088
|
+
if (typeof xOrRect === "object") {
|
|
4089
|
+
finalX = xOrRect.x;
|
|
4090
|
+
finalY = xOrRect.y;
|
|
4091
|
+
finalW = xOrRect.w;
|
|
4092
|
+
finalH = xOrRect.h;
|
|
4093
|
+
} else {
|
|
4094
|
+
finalX = xOrRect;
|
|
4095
|
+
finalY = y;
|
|
4096
|
+
finalW = w;
|
|
4097
|
+
finalH = h;
|
|
4098
|
+
}
|
|
4099
|
+
const out = {
|
|
4100
|
+
type: mask.type,
|
|
4101
|
+
w: finalW,
|
|
4102
|
+
h: finalH,
|
|
4103
|
+
data: new Uint8Array(finalW * finalH)
|
|
4104
|
+
};
|
|
4105
|
+
const srcH = mask.h;
|
|
4106
|
+
const stride = mask.w;
|
|
4107
|
+
for (let row = 0; row < finalH; row++) {
|
|
4108
|
+
const currentSrcY = finalY + row;
|
|
4109
|
+
if (currentSrcY < 0 || currentSrcY >= srcH) continue;
|
|
4110
|
+
const start = Math.max(0, finalX);
|
|
4111
|
+
const end = Math.min(stride, finalX + finalW);
|
|
4112
|
+
if (start < end) {
|
|
4113
|
+
const srcOffset = currentSrcY * stride + start;
|
|
4114
|
+
const dstOffset = row * finalW + (start - finalX);
|
|
4115
|
+
const count = end - start;
|
|
4116
|
+
out.data.set(mask.data.subarray(srcOffset, srcOffset + count), dstOffset);
|
|
4117
|
+
}
|
|
4118
|
+
}
|
|
4119
|
+
return out;
|
|
3959
4120
|
}
|
|
3960
4121
|
|
|
3961
4122
|
// src/Mask/invertMask.ts
|
|
3962
4123
|
function invertBinaryMask(dst) {
|
|
3963
|
-
const
|
|
4124
|
+
const data = dst.data;
|
|
4125
|
+
const len = data.length;
|
|
3964
4126
|
for (let i = 0; i < len; i++) {
|
|
3965
|
-
|
|
4127
|
+
data[i] = data[i] === 0 ? 1 : 0;
|
|
3966
4128
|
}
|
|
3967
4129
|
}
|
|
3968
4130
|
function invertAlphaMask(dst) {
|
|
3969
|
-
const
|
|
4131
|
+
const data = dst.data;
|
|
4132
|
+
const len = data.length;
|
|
3970
4133
|
for (let i = 0; i < len; i++) {
|
|
3971
|
-
|
|
4134
|
+
data[i] = 255 - data[i];
|
|
3972
4135
|
}
|
|
3973
4136
|
}
|
|
3974
4137
|
|
|
3975
4138
|
// src/Mask/mergeAlphaMasks.ts
|
|
3976
|
-
function mergeAlphaMasks(dst,
|
|
4139
|
+
function mergeAlphaMasks(dst, src, opts) {
|
|
3977
4140
|
const {
|
|
3978
4141
|
x: targetX = 0,
|
|
3979
4142
|
y: targetY = 0,
|
|
@@ -3984,15 +4147,17 @@ function mergeAlphaMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
3984
4147
|
my = 0,
|
|
3985
4148
|
invertMask = false
|
|
3986
4149
|
} = opts;
|
|
3987
|
-
const dstHeight = dst.length / dstWidth | 0;
|
|
3988
|
-
const srcHeight = src.length / srcWidth | 0;
|
|
3989
4150
|
if (width <= 0) return;
|
|
3990
4151
|
if (height <= 0) return;
|
|
3991
4152
|
if (globalAlpha === 0) return;
|
|
4153
|
+
const dstData = dst.data;
|
|
4154
|
+
const srcData = src.data;
|
|
4155
|
+
const srcWidth = src.w;
|
|
4156
|
+
const dstWidth = dst.w;
|
|
3992
4157
|
const startX = Math.max(0, -targetX, -mx);
|
|
3993
4158
|
const startY = Math.max(0, -targetY, -my);
|
|
3994
4159
|
const endX = Math.min(width, dstWidth - targetX, srcWidth - mx);
|
|
3995
|
-
const endY = Math.min(height,
|
|
4160
|
+
const endY = Math.min(height, dst.h - targetY, src.h - my);
|
|
3996
4161
|
if (startX >= endX) return;
|
|
3997
4162
|
if (startY >= endY) return;
|
|
3998
4163
|
for (let iy = startY; iy < endY; iy++) {
|
|
@@ -4001,7 +4166,7 @@ function mergeAlphaMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4001
4166
|
let dIdx = dy * dstWidth + targetX + startX;
|
|
4002
4167
|
let sIdx = sy * srcWidth + mx + startX;
|
|
4003
4168
|
for (let ix = startX; ix < endX; ix++) {
|
|
4004
|
-
const rawM =
|
|
4169
|
+
const rawM = srcData[sIdx];
|
|
4005
4170
|
const effectiveM = invertMask ? 255 - rawM : rawM;
|
|
4006
4171
|
let weight = 0;
|
|
4007
4172
|
if (effectiveM === 0) {
|
|
@@ -4015,13 +4180,13 @@ function mergeAlphaMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4015
4180
|
}
|
|
4016
4181
|
if (weight !== 255) {
|
|
4017
4182
|
if (weight === 0) {
|
|
4018
|
-
|
|
4183
|
+
dstData[dIdx] = 0;
|
|
4019
4184
|
} else {
|
|
4020
|
-
const da =
|
|
4185
|
+
const da = dstData[dIdx];
|
|
4021
4186
|
if (da === 255) {
|
|
4022
|
-
|
|
4187
|
+
dstData[dIdx] = weight;
|
|
4023
4188
|
} else if (da !== 0) {
|
|
4024
|
-
|
|
4189
|
+
dstData[dIdx] = da * weight + 128 >> 8;
|
|
4025
4190
|
}
|
|
4026
4191
|
}
|
|
4027
4192
|
}
|
|
@@ -4032,7 +4197,7 @@ function mergeAlphaMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4032
4197
|
}
|
|
4033
4198
|
|
|
4034
4199
|
// src/Mask/mergeBinaryMasks.ts
|
|
4035
|
-
function mergeBinaryMasks(dst,
|
|
4200
|
+
function mergeBinaryMasks(dst, src, opts) {
|
|
4036
4201
|
const {
|
|
4037
4202
|
x: targetX = 0,
|
|
4038
4203
|
y: targetY = 0,
|
|
@@ -4042,10 +4207,12 @@ function mergeBinaryMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4042
4207
|
my = 0,
|
|
4043
4208
|
invertMask = false
|
|
4044
4209
|
} = opts;
|
|
4210
|
+
const dstData = dst.data;
|
|
4211
|
+
const srcData = src.data;
|
|
4212
|
+
const srcWidth = src.w;
|
|
4213
|
+
const dstWidth = dst.w;
|
|
4045
4214
|
if (dstWidth <= 0) return;
|
|
4046
4215
|
if (srcWidth <= 0) return;
|
|
4047
|
-
const dstHeight = dst.length / dstWidth | 0;
|
|
4048
|
-
const srcHeight = src.length / srcWidth | 0;
|
|
4049
4216
|
let x = targetX;
|
|
4050
4217
|
let y = targetY;
|
|
4051
4218
|
let w = width;
|
|
@@ -4059,7 +4226,7 @@ function mergeBinaryMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4059
4226
|
y = 0;
|
|
4060
4227
|
}
|
|
4061
4228
|
w = Math.min(w, dstWidth - x);
|
|
4062
|
-
h = Math.min(h,
|
|
4229
|
+
h = Math.min(h, dst.h - y);
|
|
4063
4230
|
if (w <= 0) return;
|
|
4064
4231
|
if (h <= 0) return;
|
|
4065
4232
|
const startX = mx + (x - targetX);
|
|
@@ -4067,7 +4234,7 @@ function mergeBinaryMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4067
4234
|
const sX0 = Math.max(0, startX);
|
|
4068
4235
|
const sY0 = Math.max(0, startY);
|
|
4069
4236
|
const sX1 = Math.min(srcWidth, startX + w);
|
|
4070
|
-
const sY1 = Math.min(
|
|
4237
|
+
const sY1 = Math.min(src.h, startY + h);
|
|
4071
4238
|
const finalW = sX1 - sX0;
|
|
4072
4239
|
const finalH = sY1 - sY0;
|
|
4073
4240
|
if (finalW <= 0) return;
|
|
@@ -4080,10 +4247,10 @@ function mergeBinaryMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4080
4247
|
let sIdx = sY0 * srcWidth + sX0;
|
|
4081
4248
|
for (let iy = 0; iy < finalH; iy++) {
|
|
4082
4249
|
for (let ix = 0; ix < finalW; ix++) {
|
|
4083
|
-
const mVal =
|
|
4250
|
+
const mVal = srcData[sIdx];
|
|
4084
4251
|
const isMaskedOut = invertMask ? mVal !== 0 : mVal === 0;
|
|
4085
4252
|
if (isMaskedOut) {
|
|
4086
|
-
|
|
4253
|
+
dstData[dIdx] = 0;
|
|
4087
4254
|
}
|
|
4088
4255
|
dIdx++;
|
|
4089
4256
|
sIdx++;
|
|
@@ -4093,6 +4260,177 @@ function mergeBinaryMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4093
4260
|
}
|
|
4094
4261
|
}
|
|
4095
4262
|
|
|
4263
|
+
// src/Mask/setMaskData.ts
|
|
4264
|
+
function setMaskData(mask, width, height, data) {
|
|
4265
|
+
;
|
|
4266
|
+
mask.w = width;
|
|
4267
|
+
mask.h = height;
|
|
4268
|
+
mask.data = data;
|
|
4269
|
+
}
|
|
4270
|
+
|
|
4271
|
+
// src/MaskRect/subtractBinaryMaskRects.ts
|
|
4272
|
+
function subtractBinaryMaskRects(current, subtracting) {
|
|
4273
|
+
let result = [...current];
|
|
4274
|
+
for (const sub of subtracting) {
|
|
4275
|
+
const next = [];
|
|
4276
|
+
for (const r of result) {
|
|
4277
|
+
const ix = Math.max(r.x, sub.x);
|
|
4278
|
+
const iy = Math.max(r.y, sub.y);
|
|
4279
|
+
const ix2 = Math.min(r.x + r.w, sub.x + sub.w);
|
|
4280
|
+
const iy2 = Math.min(r.y + r.h, sub.y + sub.h);
|
|
4281
|
+
if (ix >= ix2 || iy >= iy2) {
|
|
4282
|
+
next.push(r);
|
|
4283
|
+
continue;
|
|
4284
|
+
}
|
|
4285
|
+
if (r.y < iy) pushPiece(next, r, r.x, r.y, r.w, iy - r.y);
|
|
4286
|
+
if (iy2 < r.y + r.h) pushPiece(next, r, r.x, iy2, r.w, r.y + r.h - iy2);
|
|
4287
|
+
if (r.x < ix) pushPiece(next, r, r.x, iy, ix - r.x, iy2 - iy);
|
|
4288
|
+
if (ix2 < r.x + r.w) pushPiece(next, r, ix2, iy, r.x + r.w - ix2, iy2 - iy);
|
|
4289
|
+
}
|
|
4290
|
+
result = next;
|
|
4291
|
+
}
|
|
4292
|
+
return result;
|
|
4293
|
+
}
|
|
4294
|
+
function pushPiece(dest, r, x, y, w, h) {
|
|
4295
|
+
if (r.data === null || r.data === void 0) {
|
|
4296
|
+
dest.push({
|
|
4297
|
+
x,
|
|
4298
|
+
y,
|
|
4299
|
+
w,
|
|
4300
|
+
h,
|
|
4301
|
+
data: null,
|
|
4302
|
+
type: null
|
|
4303
|
+
});
|
|
4304
|
+
return;
|
|
4305
|
+
}
|
|
4306
|
+
const lx = x - r.x;
|
|
4307
|
+
const ly = y - r.y;
|
|
4308
|
+
const data = new Uint8Array(w * h);
|
|
4309
|
+
for (let row = 0; row < h; row++) {
|
|
4310
|
+
data.set(r.data.subarray((ly + row) * r.w + lx, (ly + row) * r.w + lx + w), row * w);
|
|
4311
|
+
}
|
|
4312
|
+
dest.push({
|
|
4313
|
+
x,
|
|
4314
|
+
y,
|
|
4315
|
+
w,
|
|
4316
|
+
h,
|
|
4317
|
+
data,
|
|
4318
|
+
type: 1 /* BINARY */
|
|
4319
|
+
});
|
|
4320
|
+
}
|
|
4321
|
+
|
|
4322
|
+
// src/Rect/getRectsBounds.ts
|
|
4323
|
+
function getRectsBounds(rects) {
|
|
4324
|
+
if (rects.length === 1) return {
|
|
4325
|
+
...rects[0]
|
|
4326
|
+
};
|
|
4327
|
+
let minX = Infinity, minY = Infinity;
|
|
4328
|
+
let maxX = -Infinity, maxY = -Infinity;
|
|
4329
|
+
for (let i = 0; i < rects.length; i++) {
|
|
4330
|
+
const r = rects[i];
|
|
4331
|
+
const x1 = r.x;
|
|
4332
|
+
const y1 = r.y;
|
|
4333
|
+
const x2 = x1 + r.w;
|
|
4334
|
+
const y2 = y1 + r.h;
|
|
4335
|
+
if (x1 < minX) minX = x1;
|
|
4336
|
+
if (y1 < minY) minY = y1;
|
|
4337
|
+
if (x2 > maxX) maxX = x2;
|
|
4338
|
+
if (y2 > maxY) maxY = y2;
|
|
4339
|
+
}
|
|
4340
|
+
return {
|
|
4341
|
+
x: minX,
|
|
4342
|
+
y: minY,
|
|
4343
|
+
w: maxX - minX,
|
|
4344
|
+
h: maxY - minY
|
|
4345
|
+
};
|
|
4346
|
+
}
|
|
4347
|
+
|
|
4348
|
+
// src/MaskRect/merge2BinaryMaskRects.ts
|
|
4349
|
+
function merge2BinaryMaskRects(a, b) {
|
|
4350
|
+
const bounds = getRectsBounds([a, b]);
|
|
4351
|
+
if ((a.data === null || a.data === void 0) && (b.data === null || b.data === void 0)) {
|
|
4352
|
+
const ix = Math.max(a.x, b.x);
|
|
4353
|
+
const iy = Math.max(a.y, b.y);
|
|
4354
|
+
const ir = Math.min(a.x + a.w, b.x + b.w);
|
|
4355
|
+
const ib = Math.min(a.y + a.h, b.y + b.h);
|
|
4356
|
+
const iw = Math.max(0, ir - ix);
|
|
4357
|
+
const ih = Math.max(0, ib - iy);
|
|
4358
|
+
const intersectionArea = iw * ih;
|
|
4359
|
+
const areaA = a.w * a.h;
|
|
4360
|
+
const areaB = b.w * b.h;
|
|
4361
|
+
const boundsArea = bounds.w * bounds.h;
|
|
4362
|
+
if (boundsArea === areaA + areaB - intersectionArea) {
|
|
4363
|
+
return {
|
|
4364
|
+
...bounds,
|
|
4365
|
+
data: null,
|
|
4366
|
+
type: null
|
|
4367
|
+
};
|
|
4368
|
+
}
|
|
4369
|
+
}
|
|
4370
|
+
const maskData = new Uint8Array(bounds.w * bounds.h);
|
|
4371
|
+
const aOffY = a.y - bounds.y;
|
|
4372
|
+
const aOffX = a.x - bounds.x;
|
|
4373
|
+
if (a.data === void 0 || a.data === null) {
|
|
4374
|
+
for (let ay = 0; ay < a.h; ay++) {
|
|
4375
|
+
const destRow = (aOffY + ay) * bounds.w + aOffX;
|
|
4376
|
+
maskData.fill(1, destRow, destRow + a.w);
|
|
4377
|
+
}
|
|
4378
|
+
} else {
|
|
4379
|
+
for (let ay = 0; ay < a.h; ay++) {
|
|
4380
|
+
const srcRow = ay * a.w;
|
|
4381
|
+
const destRow = (aOffY + ay) * bounds.w + aOffX;
|
|
4382
|
+
maskData.set(a.data.subarray(srcRow, srcRow + a.w), destRow);
|
|
4383
|
+
}
|
|
4384
|
+
}
|
|
4385
|
+
const bOffY = b.y - bounds.y;
|
|
4386
|
+
const bOffX = b.x - bounds.x;
|
|
4387
|
+
if (b.data === void 0 || b.data === null) {
|
|
4388
|
+
for (let by = 0; by < b.h; by++) {
|
|
4389
|
+
const destRow = (bOffY + by) * bounds.w + bOffX;
|
|
4390
|
+
maskData.fill(1, destRow, destRow + b.w);
|
|
4391
|
+
}
|
|
4392
|
+
} else {
|
|
4393
|
+
for (let by = 0; by < b.h; by++) {
|
|
4394
|
+
const srcRow = by * b.w;
|
|
4395
|
+
const destRow = (bOffY + by) * bounds.w + bOffX;
|
|
4396
|
+
for (let bx = 0; bx < b.w; bx++) {
|
|
4397
|
+
maskData[destRow + bx] |= b.data[srcRow + bx];
|
|
4398
|
+
}
|
|
4399
|
+
}
|
|
4400
|
+
}
|
|
4401
|
+
return {
|
|
4402
|
+
...bounds,
|
|
4403
|
+
data: maskData,
|
|
4404
|
+
type: 1 /* BINARY */
|
|
4405
|
+
};
|
|
4406
|
+
}
|
|
4407
|
+
|
|
4408
|
+
// src/MaskRect/mergeBinaryMaskRects.ts
|
|
4409
|
+
function mergeBinaryMaskRects(current, adding) {
|
|
4410
|
+
const rects = [...current, ...adding];
|
|
4411
|
+
let changed = true;
|
|
4412
|
+
while (changed) {
|
|
4413
|
+
changed = false;
|
|
4414
|
+
const next = [];
|
|
4415
|
+
for (const r of rects) {
|
|
4416
|
+
let merged = false;
|
|
4417
|
+
for (let i = 0; i < next.length; i++) {
|
|
4418
|
+
const n = next[i];
|
|
4419
|
+
const overlap = r.x <= n.x + n.w && r.x + r.w >= n.x && r.y <= n.y + n.h && r.y + r.h >= n.y;
|
|
4420
|
+
if (overlap) {
|
|
4421
|
+
next[i] = merge2BinaryMaskRects(n, r);
|
|
4422
|
+
merged = true;
|
|
4423
|
+
changed = true;
|
|
4424
|
+
break;
|
|
4425
|
+
}
|
|
4426
|
+
}
|
|
4427
|
+
if (!merged) next.push(r);
|
|
4428
|
+
}
|
|
4429
|
+
rects.splice(0, rects.length, ...next);
|
|
4430
|
+
}
|
|
4431
|
+
return rects;
|
|
4432
|
+
}
|
|
4433
|
+
|
|
4096
4434
|
// src/PixelData/PixelData.ts
|
|
4097
4435
|
var PixelData = class _PixelData {
|
|
4098
4436
|
data32;
|
|
@@ -4144,7 +4482,6 @@ function blendPixelDataAlphaMask(dst, src, alphaMask, opts = {}) {
|
|
|
4144
4482
|
h: height = src.height,
|
|
4145
4483
|
alpha: globalAlpha = 255,
|
|
4146
4484
|
blendFn = sourceOverPerfect,
|
|
4147
|
-
mw = src.width,
|
|
4148
4485
|
mx = 0,
|
|
4149
4486
|
my = 0,
|
|
4150
4487
|
invertMask = false
|
|
@@ -4183,7 +4520,8 @@ function blendPixelDataAlphaMask(dst, src, alphaMask, opts = {}) {
|
|
|
4183
4520
|
if (actualW <= 0 || actualH <= 0) return;
|
|
4184
4521
|
const dw = dst.width;
|
|
4185
4522
|
const sw = src.width;
|
|
4186
|
-
const mPitch =
|
|
4523
|
+
const mPitch = alphaMask.w;
|
|
4524
|
+
const maskData = alphaMask.data;
|
|
4187
4525
|
const dx = x - targetX | 0;
|
|
4188
4526
|
const dy = y - targetY | 0;
|
|
4189
4527
|
const dst32 = dst.data32;
|
|
@@ -4198,7 +4536,7 @@ function blendPixelDataAlphaMask(dst, src, alphaMask, opts = {}) {
|
|
|
4198
4536
|
const isOverwrite = blendFn.isOverwrite || false;
|
|
4199
4537
|
for (let iy = 0; iy < actualH; iy++) {
|
|
4200
4538
|
for (let ix = 0; ix < actualW; ix++) {
|
|
4201
|
-
const mVal =
|
|
4539
|
+
const mVal = maskData[mIdx];
|
|
4202
4540
|
const effM = invertMask ? 255 - mVal : mVal;
|
|
4203
4541
|
if (effM === 0) {
|
|
4204
4542
|
dIdx++;
|
|
@@ -4259,7 +4597,6 @@ function blendPixelDataBinaryMask(dst, src, binaryMask, opts) {
|
|
|
4259
4597
|
h: height = src.height,
|
|
4260
4598
|
alpha: globalAlpha = 255,
|
|
4261
4599
|
blendFn = sourceOverPerfect,
|
|
4262
|
-
mw = src.width,
|
|
4263
4600
|
mx = 0,
|
|
4264
4601
|
my = 0,
|
|
4265
4602
|
invertMask = false
|
|
@@ -4302,7 +4639,8 @@ function blendPixelDataBinaryMask(dst, src, binaryMask, opts) {
|
|
|
4302
4639
|
const src32 = src.data32;
|
|
4303
4640
|
const dw = dst.width;
|
|
4304
4641
|
const sw = src.width;
|
|
4305
|
-
const mPitch =
|
|
4642
|
+
const mPitch = binaryMask.w;
|
|
4643
|
+
const maskData = binaryMask.data;
|
|
4306
4644
|
let dIdx = y * dw + x | 0;
|
|
4307
4645
|
let sIdx = sy * sw + sx | 0;
|
|
4308
4646
|
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
@@ -4314,7 +4652,7 @@ function blendPixelDataBinaryMask(dst, src, binaryMask, opts) {
|
|
|
4314
4652
|
const isOverwrite = blendFn.isOverwrite || false;
|
|
4315
4653
|
for (let iy = 0; iy < actualH; iy++) {
|
|
4316
4654
|
for (let ix = 0; ix < actualW; ix++) {
|
|
4317
|
-
if (
|
|
4655
|
+
if (maskData[mIdx] === skipVal) {
|
|
4318
4656
|
dIdx++;
|
|
4319
4657
|
sIdx++;
|
|
4320
4658
|
mIdx++;
|
|
@@ -4442,10 +4780,11 @@ function pixelDataToAlphaMask(pixelData) {
|
|
|
4442
4780
|
height
|
|
4443
4781
|
} = pixelData;
|
|
4444
4782
|
const len = data32.length;
|
|
4445
|
-
const mask =
|
|
4783
|
+
const mask = makeAlphaMask(width, height);
|
|
4784
|
+
const maskData = mask.data;
|
|
4446
4785
|
for (let i = 0; i < len; i++) {
|
|
4447
4786
|
const val = data32[i];
|
|
4448
|
-
|
|
4787
|
+
maskData[i] = val >>> 24 & 255;
|
|
4449
4788
|
}
|
|
4450
4789
|
return mask;
|
|
4451
4790
|
}
|
|
@@ -4626,11 +4965,13 @@ export {
|
|
|
4626
4965
|
exclusionPerfect,
|
|
4627
4966
|
extractImageDataBuffer,
|
|
4628
4967
|
extractMask,
|
|
4968
|
+
extractMaskBuffer,
|
|
4629
4969
|
extractPixelData,
|
|
4630
4970
|
extractPixelDataBuffer,
|
|
4631
4971
|
fileInputChangeToImageData,
|
|
4632
4972
|
fileToImageData,
|
|
4633
4973
|
fillPixelData,
|
|
4974
|
+
fillPixelDataBinaryMask,
|
|
4634
4975
|
floodFillSelection,
|
|
4635
4976
|
forEachLinePoint,
|
|
4636
4977
|
getCircleBrushOrPencilBounds,
|
|
@@ -4639,12 +4980,13 @@ export {
|
|
|
4639
4980
|
getIndexedImageColorCounts,
|
|
4640
4981
|
getRectBrushOrPencilBounds,
|
|
4641
4982
|
getRectBrushOrPencilStrokeBounds,
|
|
4983
|
+
getRectsBounds,
|
|
4642
4984
|
getSupportedPixelFormats,
|
|
4643
4985
|
hardLightFast,
|
|
4644
4986
|
hardLightPerfect,
|
|
4645
4987
|
hardMixFast,
|
|
4646
4988
|
hardMixPerfect,
|
|
4647
|
-
|
|
4989
|
+
imageDataToAlphaMaskBuffer,
|
|
4648
4990
|
imageDataToDataUrl,
|
|
4649
4991
|
imageDataToImgBlob,
|
|
4650
4992
|
imageDataToUInt32Array,
|
|
@@ -4667,7 +5009,11 @@ export {
|
|
|
4667
5009
|
linearDodgePerfect,
|
|
4668
5010
|
linearLightFast,
|
|
4669
5011
|
linearLightPerfect,
|
|
5012
|
+
makeAlphaMask,
|
|
5013
|
+
makeBinaryMask,
|
|
4670
5014
|
makeBlendModeRegistry,
|
|
5015
|
+
makeCircleBrushAlphaMask,
|
|
5016
|
+
makeCircleBrushBinaryMask,
|
|
4671
5017
|
makeFastBlendModeRegistry,
|
|
4672
5018
|
makeFullPixelMutator,
|
|
4673
5019
|
makeImageDataLike,
|
|
@@ -4675,7 +5021,9 @@ export {
|
|
|
4675
5021
|
makePixelCanvas,
|
|
4676
5022
|
makeReusableCanvas,
|
|
4677
5023
|
makeReusableImageData,
|
|
5024
|
+
merge2BinaryMaskRects,
|
|
4678
5025
|
mergeAlphaMasks,
|
|
5026
|
+
mergeBinaryMaskRects,
|
|
4679
5027
|
mergeBinaryMasks,
|
|
4680
5028
|
multiplyFast,
|
|
4681
5029
|
multiplyPerfect,
|
|
@@ -4694,6 +5042,7 @@ export {
|
|
|
4694
5042
|
mutatorBlendPixelData,
|
|
4695
5043
|
mutatorClear,
|
|
4696
5044
|
mutatorFill,
|
|
5045
|
+
mutatorFillBinaryMask,
|
|
4697
5046
|
mutatorInvert,
|
|
4698
5047
|
overlayFast,
|
|
4699
5048
|
overlayPerfect,
|
|
@@ -4716,10 +5065,12 @@ export {
|
|
|
4716
5065
|
screenPerfect,
|
|
4717
5066
|
serializeImageData,
|
|
4718
5067
|
serializeNullableImageData,
|
|
5068
|
+
setMaskData,
|
|
4719
5069
|
softLightFast,
|
|
4720
5070
|
softLightPerfect,
|
|
4721
5071
|
sourceOverFast,
|
|
4722
5072
|
sourceOverPerfect,
|
|
5073
|
+
subtractBinaryMaskRects,
|
|
4723
5074
|
subtractFast,
|
|
4724
5075
|
subtractPerfect,
|
|
4725
5076
|
toBlendModeIndexAndName,
|