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.dev.cjs
CHANGED
|
@@ -75,11 +75,13 @@ __export(src_exports, {
|
|
|
75
75
|
exclusionPerfect: () => exclusionPerfect,
|
|
76
76
|
extractImageDataBuffer: () => extractImageDataBuffer,
|
|
77
77
|
extractMask: () => extractMask,
|
|
78
|
+
extractMaskBuffer: () => extractMaskBuffer,
|
|
78
79
|
extractPixelData: () => extractPixelData,
|
|
79
80
|
extractPixelDataBuffer: () => extractPixelDataBuffer,
|
|
80
81
|
fileInputChangeToImageData: () => fileInputChangeToImageData,
|
|
81
82
|
fileToImageData: () => fileToImageData,
|
|
82
83
|
fillPixelData: () => fillPixelData,
|
|
84
|
+
fillPixelDataBinaryMask: () => fillPixelDataBinaryMask,
|
|
83
85
|
floodFillSelection: () => floodFillSelection,
|
|
84
86
|
forEachLinePoint: () => forEachLinePoint,
|
|
85
87
|
getCircleBrushOrPencilBounds: () => getCircleBrushOrPencilBounds,
|
|
@@ -88,12 +90,13 @@ __export(src_exports, {
|
|
|
88
90
|
getIndexedImageColorCounts: () => getIndexedImageColorCounts,
|
|
89
91
|
getRectBrushOrPencilBounds: () => getRectBrushOrPencilBounds,
|
|
90
92
|
getRectBrushOrPencilStrokeBounds: () => getRectBrushOrPencilStrokeBounds,
|
|
93
|
+
getRectsBounds: () => getRectsBounds,
|
|
91
94
|
getSupportedPixelFormats: () => getSupportedPixelFormats,
|
|
92
95
|
hardLightFast: () => hardLightFast,
|
|
93
96
|
hardLightPerfect: () => hardLightPerfect,
|
|
94
97
|
hardMixFast: () => hardMixFast,
|
|
95
98
|
hardMixPerfect: () => hardMixPerfect,
|
|
96
|
-
|
|
99
|
+
imageDataToAlphaMaskBuffer: () => imageDataToAlphaMaskBuffer,
|
|
97
100
|
imageDataToDataUrl: () => imageDataToDataUrl,
|
|
98
101
|
imageDataToImgBlob: () => imageDataToImgBlob,
|
|
99
102
|
imageDataToUInt32Array: () => imageDataToUInt32Array,
|
|
@@ -116,7 +119,11 @@ __export(src_exports, {
|
|
|
116
119
|
linearDodgePerfect: () => linearDodgePerfect,
|
|
117
120
|
linearLightFast: () => linearLightFast,
|
|
118
121
|
linearLightPerfect: () => linearLightPerfect,
|
|
122
|
+
makeAlphaMask: () => makeAlphaMask,
|
|
123
|
+
makeBinaryMask: () => makeBinaryMask,
|
|
119
124
|
makeBlendModeRegistry: () => makeBlendModeRegistry,
|
|
125
|
+
makeCircleBrushAlphaMask: () => makeCircleBrushAlphaMask,
|
|
126
|
+
makeCircleBrushBinaryMask: () => makeCircleBrushBinaryMask,
|
|
120
127
|
makeFastBlendModeRegistry: () => makeFastBlendModeRegistry,
|
|
121
128
|
makeFullPixelMutator: () => makeFullPixelMutator,
|
|
122
129
|
makeImageDataLike: () => makeImageDataLike,
|
|
@@ -124,7 +131,9 @@ __export(src_exports, {
|
|
|
124
131
|
makePixelCanvas: () => makePixelCanvas,
|
|
125
132
|
makeReusableCanvas: () => makeReusableCanvas,
|
|
126
133
|
makeReusableImageData: () => makeReusableImageData,
|
|
134
|
+
merge2BinaryMaskRects: () => merge2BinaryMaskRects,
|
|
127
135
|
mergeAlphaMasks: () => mergeAlphaMasks,
|
|
136
|
+
mergeBinaryMaskRects: () => mergeBinaryMaskRects,
|
|
128
137
|
mergeBinaryMasks: () => mergeBinaryMasks,
|
|
129
138
|
multiplyFast: () => multiplyFast,
|
|
130
139
|
multiplyPerfect: () => multiplyPerfect,
|
|
@@ -143,6 +152,7 @@ __export(src_exports, {
|
|
|
143
152
|
mutatorBlendPixelData: () => mutatorBlendPixelData,
|
|
144
153
|
mutatorClear: () => mutatorClear,
|
|
145
154
|
mutatorFill: () => mutatorFill,
|
|
155
|
+
mutatorFillBinaryMask: () => mutatorFillBinaryMask,
|
|
146
156
|
mutatorInvert: () => mutatorInvert,
|
|
147
157
|
overlayFast: () => overlayFast,
|
|
148
158
|
overlayPerfect: () => overlayPerfect,
|
|
@@ -165,10 +175,12 @@ __export(src_exports, {
|
|
|
165
175
|
screenPerfect: () => screenPerfect,
|
|
166
176
|
serializeImageData: () => serializeImageData,
|
|
167
177
|
serializeNullableImageData: () => serializeNullableImageData,
|
|
178
|
+
setMaskData: () => setMaskData,
|
|
168
179
|
softLightFast: () => softLightFast,
|
|
169
180
|
softLightPerfect: () => softLightPerfect,
|
|
170
181
|
sourceOverFast: () => sourceOverFast,
|
|
171
182
|
sourceOverPerfect: () => sourceOverPerfect,
|
|
183
|
+
subtractBinaryMaskRects: () => subtractBinaryMaskRects,
|
|
172
184
|
subtractFast: () => subtractFast,
|
|
173
185
|
subtractPerfect: () => subtractPerfect,
|
|
174
186
|
toBlendModeIndexAndName: () => toBlendModeIndexAndName,
|
|
@@ -389,8 +401,8 @@ function extractImageDataBuffer(imageData, _x, _y, _w, _h) {
|
|
|
389
401
|
return out;
|
|
390
402
|
}
|
|
391
403
|
|
|
392
|
-
// src/Mask/
|
|
393
|
-
function
|
|
404
|
+
// src/Mask/extractMaskBuffer.ts
|
|
405
|
+
function extractMaskBuffer(maskBuffer, maskWidth, xOrRect, y, w, h) {
|
|
394
406
|
let finalX;
|
|
395
407
|
let finalY;
|
|
396
408
|
let finalW;
|
|
@@ -407,7 +419,7 @@ function extractMask(mask, maskWidth, xOrRect, y, w, h) {
|
|
|
407
419
|
finalH = h;
|
|
408
420
|
}
|
|
409
421
|
const out = new Uint8Array(finalW * finalH);
|
|
410
|
-
const srcH =
|
|
422
|
+
const srcH = maskBuffer.length / maskWidth;
|
|
411
423
|
for (let row = 0; row < finalH; row++) {
|
|
412
424
|
const currentSrcY = finalY + row;
|
|
413
425
|
if (currentSrcY < 0 || currentSrcY >= srcH) {
|
|
@@ -419,7 +431,7 @@ function extractMask(mask, maskWidth, xOrRect, y, w, h) {
|
|
|
419
431
|
const srcOffset = currentSrcY * maskWidth + start;
|
|
420
432
|
const dstOffset = row * finalW + (start - finalX);
|
|
421
433
|
const count = end - start;
|
|
422
|
-
out.set(
|
|
434
|
+
out.set(maskBuffer.subarray(srcOffset, srcOffset + count), dstOffset);
|
|
423
435
|
}
|
|
424
436
|
}
|
|
425
437
|
return out;
|
|
@@ -437,8 +449,8 @@ function trimRectBounds(target, bounds) {
|
|
|
437
449
|
if (intersectedMaxX <= intersectedX || intersectedMaxY <= intersectedY) {
|
|
438
450
|
target.w = 0;
|
|
439
451
|
target.h = 0;
|
|
440
|
-
if ("
|
|
441
|
-
target.
|
|
452
|
+
if ("data" in target && target.data) {
|
|
453
|
+
target.data = new Uint8Array(0);
|
|
442
454
|
}
|
|
443
455
|
return;
|
|
444
456
|
}
|
|
@@ -450,15 +462,15 @@ function trimRectBounds(target, bounds) {
|
|
|
450
462
|
target.y = intersectedY;
|
|
451
463
|
target.w = intersectedW;
|
|
452
464
|
target.h = intersectedH;
|
|
453
|
-
if ("
|
|
454
|
-
const
|
|
465
|
+
if ("data" in target && target.data) {
|
|
466
|
+
const currentMaskBuffer = extractMaskBuffer(target.data, originalW, offsetX, offsetY, intersectedW, intersectedH);
|
|
455
467
|
let minX = intersectedW;
|
|
456
468
|
let maxX = -1;
|
|
457
469
|
let minY = intersectedH;
|
|
458
470
|
let maxY = -1;
|
|
459
471
|
for (let y = 0; y < intersectedH; y++) {
|
|
460
472
|
for (let x = 0; x < intersectedW; x++) {
|
|
461
|
-
if (
|
|
473
|
+
if (currentMaskBuffer[y * intersectedW + x] !== 0) {
|
|
462
474
|
if (x < minX) minX = x;
|
|
463
475
|
if (x > maxX) maxX = x;
|
|
464
476
|
if (y < minY) minY = y;
|
|
@@ -469,19 +481,22 @@ function trimRectBounds(target, bounds) {
|
|
|
469
481
|
if (maxX === -1) {
|
|
470
482
|
target.w = 0;
|
|
471
483
|
target.h = 0;
|
|
472
|
-
target.
|
|
484
|
+
target.data = new Uint8Array(0);
|
|
473
485
|
return;
|
|
474
486
|
}
|
|
475
487
|
const finalW = maxX - minX + 1;
|
|
476
488
|
const finalH = maxY - minY + 1;
|
|
477
489
|
if (finalW !== intersectedW || finalH !== intersectedH) {
|
|
478
|
-
|
|
490
|
+
const newMaskBuffer = extractMaskBuffer(currentMaskBuffer, intersectedW, minX, minY, finalW, finalH);
|
|
479
491
|
target.x += minX;
|
|
480
492
|
target.y += minY;
|
|
481
493
|
target.w = finalW;
|
|
482
494
|
target.h = finalH;
|
|
495
|
+
target.data = newMaskBuffer;
|
|
483
496
|
} else {
|
|
484
|
-
target.
|
|
497
|
+
target.w = finalW;
|
|
498
|
+
target.h = finalH;
|
|
499
|
+
target.data = currentMaskBuffer;
|
|
485
500
|
}
|
|
486
501
|
}
|
|
487
502
|
}
|
|
@@ -591,17 +606,19 @@ function floodFillSelection(img, startX, startY, {
|
|
|
591
606
|
if (matchCount === 0) {
|
|
592
607
|
return null;
|
|
593
608
|
}
|
|
609
|
+
const w = maxX - minX + 1;
|
|
610
|
+
const h = maxY - minY + 1;
|
|
594
611
|
const selectionRect = {
|
|
595
612
|
x: minX,
|
|
596
613
|
y: minY,
|
|
597
|
-
w
|
|
598
|
-
h
|
|
599
|
-
|
|
600
|
-
|
|
614
|
+
w,
|
|
615
|
+
h,
|
|
616
|
+
data: new Uint8Array(w * h),
|
|
617
|
+
type: 1 /* BINARY */
|
|
601
618
|
};
|
|
602
619
|
const sw = selectionRect.w;
|
|
603
620
|
const sh = selectionRect.h;
|
|
604
|
-
const finalMask = selectionRect.
|
|
621
|
+
const finalMask = selectionRect.data;
|
|
605
622
|
for (let i = 0; i < matchCount; i++) {
|
|
606
623
|
const mx = matchX[i] - selectionRect.x;
|
|
607
624
|
const my = matchY[i] - selectionRect.y;
|
|
@@ -1676,16 +1693,7 @@ function toBlendModeIndexAndName(input) {
|
|
|
1676
1693
|
const num = Number(trimmed);
|
|
1677
1694
|
const isNumeric = trimmed !== "" && !Number.isNaN(num);
|
|
1678
1695
|
if (isNumeric && Number.isInteger(num)) {
|
|
1679
|
-
console.log({
|
|
1680
|
-
trimmed,
|
|
1681
|
-
num,
|
|
1682
|
-
isNumeric,
|
|
1683
|
-
isInt: Number.isInteger(num)
|
|
1684
|
-
});
|
|
1685
1696
|
const name = getKeyByValue(BaseBlendMode, num);
|
|
1686
|
-
console.log({
|
|
1687
|
-
name
|
|
1688
|
-
});
|
|
1689
1697
|
if (name === void 0) throw new Error(`Invalid index: ${num}`);
|
|
1690
1698
|
return {
|
|
1691
1699
|
blendIndex: num,
|
|
@@ -2059,7 +2067,6 @@ function applyAlphaMaskToPixelData(dst, mask, opts = {}) {
|
|
|
2059
2067
|
w: width = dst.width,
|
|
2060
2068
|
h: height = dst.height,
|
|
2061
2069
|
alpha: globalAlpha = 255,
|
|
2062
|
-
mw,
|
|
2063
2070
|
mx = 0,
|
|
2064
2071
|
my = 0,
|
|
2065
2072
|
invertMask = false
|
|
@@ -2081,15 +2088,14 @@ function applyAlphaMaskToPixelData(dst, mask, opts = {}) {
|
|
|
2081
2088
|
h = Math.min(h, dst.height - y);
|
|
2082
2089
|
if (w <= 0) return;
|
|
2083
2090
|
if (h <= 0) return;
|
|
2084
|
-
const mPitch =
|
|
2091
|
+
const mPitch = mask.w;
|
|
2085
2092
|
if (mPitch <= 0) return;
|
|
2086
|
-
const maskHeight = mask.length / mPitch | 0;
|
|
2087
2093
|
const startX = mx + (x - targetX);
|
|
2088
2094
|
const startY = my + (y - targetY);
|
|
2089
2095
|
const sX0 = Math.max(0, startX);
|
|
2090
2096
|
const sY0 = Math.max(0, startY);
|
|
2091
2097
|
const sX1 = Math.min(mPitch, startX + w);
|
|
2092
|
-
const sY1 = Math.min(
|
|
2098
|
+
const sY1 = Math.min(mask.h, startY + h);
|
|
2093
2099
|
const finalW = sX1 - sX0;
|
|
2094
2100
|
const finalH = sY1 - sY0;
|
|
2095
2101
|
if (finalW <= 0) return;
|
|
@@ -2100,11 +2106,12 @@ function applyAlphaMaskToPixelData(dst, mask, opts = {}) {
|
|
|
2100
2106
|
const dw = dst.width;
|
|
2101
2107
|
const dStride = dw - finalW;
|
|
2102
2108
|
const mStride = mPitch - finalW;
|
|
2109
|
+
const maskData = mask.data;
|
|
2103
2110
|
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
2104
2111
|
let mIdx = sY0 * mPitch + sX0;
|
|
2105
2112
|
for (let iy = 0; iy < h; iy++) {
|
|
2106
2113
|
for (let ix = 0; ix < w; ix++) {
|
|
2107
|
-
const mVal =
|
|
2114
|
+
const mVal = maskData[mIdx];
|
|
2108
2115
|
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
2109
2116
|
let weight = 0;
|
|
2110
2117
|
if (effectiveM === 0) {
|
|
@@ -2164,13 +2171,12 @@ function applyBinaryMaskToPixelData(dst, mask, opts = {}) {
|
|
|
2164
2171
|
y: targetY = 0,
|
|
2165
2172
|
w: width = dst.width,
|
|
2166
2173
|
h: height = dst.height,
|
|
2167
|
-
alpha = 255,
|
|
2168
|
-
mw,
|
|
2174
|
+
alpha: globalAlpha = 255,
|
|
2169
2175
|
mx = 0,
|
|
2170
2176
|
my = 0,
|
|
2171
2177
|
invertMask = false
|
|
2172
2178
|
} = opts;
|
|
2173
|
-
if (
|
|
2179
|
+
if (globalAlpha === 0) return;
|
|
2174
2180
|
let x = targetX;
|
|
2175
2181
|
let y = targetY;
|
|
2176
2182
|
let w = width;
|
|
@@ -2187,15 +2193,14 @@ function applyBinaryMaskToPixelData(dst, mask, opts = {}) {
|
|
|
2187
2193
|
h = Math.min(h, dst.height - y);
|
|
2188
2194
|
if (w <= 0) return;
|
|
2189
2195
|
if (h <= 0) return;
|
|
2190
|
-
const mPitch =
|
|
2196
|
+
const mPitch = mask.w;
|
|
2191
2197
|
if (mPitch <= 0) return;
|
|
2192
|
-
const maskHeight = mask.length / mPitch | 0;
|
|
2193
2198
|
const startX = mx + (x - targetX);
|
|
2194
2199
|
const startY = my + (y - targetY);
|
|
2195
2200
|
const sX0 = Math.max(0, startX);
|
|
2196
2201
|
const sY0 = Math.max(0, startY);
|
|
2197
2202
|
const sX1 = Math.min(mPitch, startX + w);
|
|
2198
|
-
const sY1 = Math.min(
|
|
2203
|
+
const sY1 = Math.min(mask.h, startY + h);
|
|
2199
2204
|
const finalW = sX1 - sX0;
|
|
2200
2205
|
const finalH = sY1 - sY0;
|
|
2201
2206
|
if (finalW <= 0) return;
|
|
@@ -2206,19 +2211,20 @@ function applyBinaryMaskToPixelData(dst, mask, opts = {}) {
|
|
|
2206
2211
|
const dw = dst.width;
|
|
2207
2212
|
const dStride = dw - finalW;
|
|
2208
2213
|
const mStride = mPitch - finalW;
|
|
2214
|
+
const maskData = mask.data;
|
|
2209
2215
|
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
2210
2216
|
let mIdx = sY0 * mPitch + sX0;
|
|
2211
2217
|
for (let iy = 0; iy < h; iy++) {
|
|
2212
2218
|
for (let ix = 0; ix < w; ix++) {
|
|
2213
|
-
const mVal =
|
|
2219
|
+
const mVal = maskData[mIdx];
|
|
2214
2220
|
const isMaskedOut = invertMask ? mVal !== 0 : mVal === 0;
|
|
2215
2221
|
if (isMaskedOut) {
|
|
2216
2222
|
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
2217
|
-
} else if (
|
|
2223
|
+
} else if (globalAlpha !== 255) {
|
|
2218
2224
|
const d = dst32[dIdx];
|
|
2219
2225
|
const da = d >>> 24;
|
|
2220
2226
|
if (da !== 0) {
|
|
2221
|
-
const finalAlpha = da === 255 ?
|
|
2227
|
+
const finalAlpha = da === 255 ? globalAlpha : da * globalAlpha + 128 >> 8;
|
|
2222
2228
|
dst32[dIdx] = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
2223
2229
|
}
|
|
2224
2230
|
}
|
|
@@ -2281,144 +2287,42 @@ function getCircleBrushOrPencilBounds(centerX, centerY, brushSize, targetWidth,
|
|
|
2281
2287
|
return res;
|
|
2282
2288
|
}
|
|
2283
2289
|
|
|
2284
|
-
// src/PixelData/applyCircleBrushToPixelData.ts
|
|
2285
|
-
function applyCircleBrushToPixelData(target, color, centerX, centerY, brushSize, alpha = 255, fallOff, blendFn = sourceOverPerfect, bounds) {
|
|
2286
|
-
const targetWidth = target.width;
|
|
2287
|
-
const targetHeight = target.height;
|
|
2288
|
-
const b = bounds ?? getCircleBrushOrPencilBounds(centerX, centerY, brushSize, targetWidth, targetHeight);
|
|
2289
|
-
if (b.w <= 0 || b.h <= 0) return;
|
|
2290
|
-
const data32 = target.data32;
|
|
2291
|
-
const r = brushSize / 2;
|
|
2292
|
-
const rSqr = r * r;
|
|
2293
|
-
const invR = 1 / r;
|
|
2294
|
-
const centerOffset = brushSize % 2 === 0 ? 0.5 : 0;
|
|
2295
|
-
const endX = b.x + b.w;
|
|
2296
|
-
const endY = b.y + b.h;
|
|
2297
|
-
const fCenterX = Math.floor(centerX);
|
|
2298
|
-
const fCenterY = Math.floor(centerY);
|
|
2299
|
-
const baseSrcAlpha = color >>> 24;
|
|
2300
|
-
const colorRGB = color & 16777215;
|
|
2301
|
-
const isOpaque = alpha === 255;
|
|
2302
|
-
const isOverwrite = blendFn.isOverwrite;
|
|
2303
|
-
for (let cy = b.y; cy < endY; cy++) {
|
|
2304
|
-
const relY = cy - fCenterY + centerOffset;
|
|
2305
|
-
const dySqr = relY * relY;
|
|
2306
|
-
const rowOffset = cy * targetWidth;
|
|
2307
|
-
for (let cx = b.x; cx < endX; cx++) {
|
|
2308
|
-
const relX = cx - fCenterX + centerOffset;
|
|
2309
|
-
const dSqr = relX * relX + dySqr;
|
|
2310
|
-
if (dSqr <= rSqr) {
|
|
2311
|
-
const idx = rowOffset + cx;
|
|
2312
|
-
let weight = alpha;
|
|
2313
|
-
const strength = fallOff(1 - Math.sqrt(dSqr) * invR);
|
|
2314
|
-
const maskVal = strength * 255 | 0;
|
|
2315
|
-
if (maskVal === 0) continue;
|
|
2316
|
-
if (isOpaque) {
|
|
2317
|
-
weight = maskVal;
|
|
2318
|
-
} else if (maskVal !== 255) {
|
|
2319
|
-
weight = maskVal * alpha + 128 >> 8;
|
|
2320
|
-
}
|
|
2321
|
-
let finalCol = color;
|
|
2322
|
-
if (weight < 255) {
|
|
2323
|
-
const a = baseSrcAlpha * weight + 128 >> 8;
|
|
2324
|
-
if (a === 0 && !isOverwrite) continue;
|
|
2325
|
-
finalCol = (colorRGB | a << 24) >>> 0;
|
|
2326
|
-
}
|
|
2327
|
-
data32[idx] = blendFn(finalCol, data32[idx]);
|
|
2328
|
-
}
|
|
2329
|
-
}
|
|
2330
|
-
}
|
|
2331
|
-
}
|
|
2332
|
-
|
|
2333
|
-
// src/History/PixelMutator/mutatorApplyCircleBrush.ts
|
|
2334
|
-
var defaults3 = {
|
|
2335
|
-
applyCircleBrushToPixelData,
|
|
2336
|
-
getCircleBrushOrPencilBounds
|
|
2337
|
-
};
|
|
2338
|
-
var mutatorApplyCircleBrush = ((writer, deps = defaults3) => {
|
|
2339
|
-
const {
|
|
2340
|
-
applyCircleBrushToPixelData: applyCircleBrushToPixelData2 = defaults3.applyCircleBrushToPixelData,
|
|
2341
|
-
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults3.getCircleBrushOrPencilBounds
|
|
2342
|
-
} = deps;
|
|
2343
|
-
const boundsOut = {
|
|
2344
|
-
x: 0,
|
|
2345
|
-
y: 0,
|
|
2346
|
-
w: 0,
|
|
2347
|
-
h: 0
|
|
2348
|
-
};
|
|
2349
|
-
return {
|
|
2350
|
-
applyCircleBrush(color, centerX, centerY, brushSize, alpha = 255, fallOff, blendFn) {
|
|
2351
|
-
const bounds = getCircleBrushOrPencilBounds2(centerX, centerY, brushSize, writer.target.width, writer.target.height, boundsOut);
|
|
2352
|
-
const {
|
|
2353
|
-
x,
|
|
2354
|
-
y,
|
|
2355
|
-
w,
|
|
2356
|
-
h
|
|
2357
|
-
} = bounds;
|
|
2358
|
-
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2359
|
-
applyCircleBrushToPixelData2(writer.target, color, centerX, centerY, brushSize, alpha, fallOff, blendFn, bounds);
|
|
2360
|
-
}
|
|
2361
|
-
};
|
|
2362
|
-
});
|
|
2363
|
-
|
|
2364
|
-
// src/Algorithm/forEachLinePoint.ts
|
|
2365
|
-
function forEachLinePoint(x0, y0, x1, y1, callback) {
|
|
2366
|
-
const dx = x1 - x0;
|
|
2367
|
-
const dy = y1 - y0;
|
|
2368
|
-
const steps = Math.max(Math.abs(dx), Math.abs(dy));
|
|
2369
|
-
if (steps === 0) {
|
|
2370
|
-
callback(x0, y0);
|
|
2371
|
-
return;
|
|
2372
|
-
}
|
|
2373
|
-
const xInc = dx / steps;
|
|
2374
|
-
const yInc = dy / steps;
|
|
2375
|
-
let curX = x0;
|
|
2376
|
-
let curY = y0;
|
|
2377
|
-
for (let i = 0; i <= steps; i++) {
|
|
2378
|
-
callback(curX, curY);
|
|
2379
|
-
curX += xInc;
|
|
2380
|
-
curY += yInc;
|
|
2381
|
-
}
|
|
2382
|
-
}
|
|
2383
|
-
|
|
2384
2290
|
// src/PixelData/blendColorPixelDataAlphaMask.ts
|
|
2385
|
-
function blendColorPixelDataAlphaMask(dst, color, mask, opts) {
|
|
2386
|
-
const
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
invertMask = false
|
|
2397
|
-
} = opts;
|
|
2398
|
-
if (globalAlpha === 0 || !mask) return;
|
|
2291
|
+
function blendColorPixelDataAlphaMask(dst, color, mask, opts = {}) {
|
|
2292
|
+
const targetX = opts.x ?? 0;
|
|
2293
|
+
const targetY = opts.y ?? 0;
|
|
2294
|
+
const w = opts.w ?? mask.w;
|
|
2295
|
+
const h = opts.h ?? mask.h;
|
|
2296
|
+
const globalAlpha = opts.alpha ?? 255;
|
|
2297
|
+
const blendFn = opts.blendFn ?? sourceOverPerfect;
|
|
2298
|
+
const mx = opts.mx ?? 0;
|
|
2299
|
+
const my = opts.my ?? 0;
|
|
2300
|
+
const invertMask = opts.invertMask ?? false;
|
|
2301
|
+
if (globalAlpha === 0) return;
|
|
2399
2302
|
const baseSrcAlpha = color >>> 24;
|
|
2400
2303
|
const isOverwrite = blendFn.isOverwrite || false;
|
|
2401
2304
|
if (baseSrcAlpha === 0 && !isOverwrite) return;
|
|
2402
2305
|
let x = targetX;
|
|
2403
2306
|
let y = targetY;
|
|
2404
|
-
let
|
|
2405
|
-
let
|
|
2307
|
+
let actualW = w;
|
|
2308
|
+
let actualH = h;
|
|
2406
2309
|
if (x < 0) {
|
|
2407
|
-
|
|
2310
|
+
actualW += x;
|
|
2408
2311
|
x = 0;
|
|
2409
2312
|
}
|
|
2410
2313
|
if (y < 0) {
|
|
2411
|
-
|
|
2314
|
+
actualH += y;
|
|
2412
2315
|
y = 0;
|
|
2413
2316
|
}
|
|
2414
|
-
|
|
2415
|
-
|
|
2317
|
+
actualW = Math.min(actualW, dst.width - x);
|
|
2318
|
+
actualH = Math.min(actualH, dst.height - y);
|
|
2416
2319
|
if (actualW <= 0 || actualH <= 0) return;
|
|
2417
2320
|
const dx = x - targetX | 0;
|
|
2418
2321
|
const dy = y - targetY | 0;
|
|
2419
2322
|
const dst32 = dst.data32;
|
|
2420
2323
|
const dw = dst.width;
|
|
2421
|
-
const mPitch =
|
|
2324
|
+
const mPitch = mask.w;
|
|
2325
|
+
const maskData = mask.data;
|
|
2422
2326
|
let dIdx = y * dw + x | 0;
|
|
2423
2327
|
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
2424
2328
|
const dStride = dw - actualW | 0;
|
|
@@ -2427,7 +2331,7 @@ function blendColorPixelDataAlphaMask(dst, color, mask, opts) {
|
|
|
2427
2331
|
const colorRGB = color & 16777215;
|
|
2428
2332
|
for (let iy = 0; iy < actualH; iy++) {
|
|
2429
2333
|
for (let ix = 0; ix < actualW; ix++) {
|
|
2430
|
-
const mVal =
|
|
2334
|
+
const mVal = maskData[mIdx];
|
|
2431
2335
|
const effM = invertMask ? 255 - mVal : mVal;
|
|
2432
2336
|
if (effM === 0) {
|
|
2433
2337
|
dIdx++;
|
|
@@ -2464,6 +2368,155 @@ function blendColorPixelDataAlphaMask(dst, color, mask, opts) {
|
|
|
2464
2368
|
}
|
|
2465
2369
|
}
|
|
2466
2370
|
|
|
2371
|
+
// src/PixelData/blendColorPixelDataBinaryMask.ts
|
|
2372
|
+
function blendColorPixelDataBinaryMask(dst, color, mask, opts = {}) {
|
|
2373
|
+
const targetX = opts.x ?? 0;
|
|
2374
|
+
const targetY = opts.y ?? 0;
|
|
2375
|
+
let w = opts.w ?? mask.w;
|
|
2376
|
+
let h = opts.h ?? mask.h;
|
|
2377
|
+
const globalAlpha = opts.alpha ?? 255;
|
|
2378
|
+
const blendFn = opts.blendFn ?? sourceOverPerfect;
|
|
2379
|
+
const mx = opts.mx ?? 0;
|
|
2380
|
+
const my = opts.my ?? 0;
|
|
2381
|
+
const invertMask = opts.invertMask ?? false;
|
|
2382
|
+
if (globalAlpha === 0) return;
|
|
2383
|
+
const baseSrcAlpha = color >>> 24;
|
|
2384
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
2385
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return;
|
|
2386
|
+
let x = targetX;
|
|
2387
|
+
let y = targetY;
|
|
2388
|
+
if (x < 0) {
|
|
2389
|
+
w += x;
|
|
2390
|
+
x = 0;
|
|
2391
|
+
}
|
|
2392
|
+
if (y < 0) {
|
|
2393
|
+
h += y;
|
|
2394
|
+
y = 0;
|
|
2395
|
+
}
|
|
2396
|
+
const actualW = Math.min(w, dst.width - x);
|
|
2397
|
+
const actualH = Math.min(h, dst.height - y);
|
|
2398
|
+
if (actualW <= 0 || actualH <= 0) return;
|
|
2399
|
+
let baseColorWithGlobalAlpha = color;
|
|
2400
|
+
if (globalAlpha < 255) {
|
|
2401
|
+
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
2402
|
+
if (a === 0 && !isOverwrite) return;
|
|
2403
|
+
baseColorWithGlobalAlpha = (color & 16777215 | a << 24) >>> 0;
|
|
2404
|
+
}
|
|
2405
|
+
const dx = x - targetX | 0;
|
|
2406
|
+
const dy = y - targetY | 0;
|
|
2407
|
+
const dst32 = dst.data32;
|
|
2408
|
+
const dw = dst.width;
|
|
2409
|
+
const mPitch = mask.w;
|
|
2410
|
+
const maskData = mask.data;
|
|
2411
|
+
let dIdx = y * dw + x | 0;
|
|
2412
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
2413
|
+
const dStride = dw - actualW | 0;
|
|
2414
|
+
const mStride = mPitch - actualW | 0;
|
|
2415
|
+
const skipVal = invertMask ? 1 : 0;
|
|
2416
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2417
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2418
|
+
if (maskData[mIdx] === skipVal) {
|
|
2419
|
+
dIdx++;
|
|
2420
|
+
mIdx++;
|
|
2421
|
+
continue;
|
|
2422
|
+
}
|
|
2423
|
+
dst32[dIdx] = blendFn(baseColorWithGlobalAlpha, dst32[dIdx]);
|
|
2424
|
+
dIdx++;
|
|
2425
|
+
mIdx++;
|
|
2426
|
+
}
|
|
2427
|
+
dIdx += dStride;
|
|
2428
|
+
mIdx += mStride;
|
|
2429
|
+
}
|
|
2430
|
+
}
|
|
2431
|
+
|
|
2432
|
+
// src/PixelData/applyCircleBrushToPixelData.ts
|
|
2433
|
+
function applyCircleBrushToPixelData(target, color, centerX, centerY, brush, alpha = 255, blendFn = sourceOverPerfect, scratchOptions = {}, bounds) {
|
|
2434
|
+
const b = bounds ?? getCircleBrushOrPencilBounds(centerX, centerY, brush.size, target.width, target.height);
|
|
2435
|
+
if (b.w <= 0 || b.h <= 0) return;
|
|
2436
|
+
const unclippedStartX = Math.floor(centerX + brush.minOffset);
|
|
2437
|
+
const unclippedStartY = Math.floor(centerY + brush.minOffset);
|
|
2438
|
+
const ix = Math.max(unclippedStartX, b.x);
|
|
2439
|
+
const iy = Math.max(unclippedStartY, b.y);
|
|
2440
|
+
const ir = Math.min(unclippedStartX + brush.w, b.x + b.w);
|
|
2441
|
+
const ib = Math.min(unclippedStartY + brush.h, b.y + b.h);
|
|
2442
|
+
const iw = ir - ix;
|
|
2443
|
+
const ih = ib - iy;
|
|
2444
|
+
if (iw <= 0 || ih <= 0) return;
|
|
2445
|
+
scratchOptions.x = ix;
|
|
2446
|
+
scratchOptions.y = iy;
|
|
2447
|
+
scratchOptions.w = iw;
|
|
2448
|
+
scratchOptions.h = ih;
|
|
2449
|
+
scratchOptions.mx = ix - unclippedStartX;
|
|
2450
|
+
scratchOptions.my = iy - unclippedStartY;
|
|
2451
|
+
scratchOptions.alpha = alpha;
|
|
2452
|
+
scratchOptions.blendFn = blendFn;
|
|
2453
|
+
if (brush.type === 0 /* ALPHA */) {
|
|
2454
|
+
blendColorPixelDataAlphaMask(target, color, brush, scratchOptions);
|
|
2455
|
+
}
|
|
2456
|
+
if (brush.type === 1 /* BINARY */) {
|
|
2457
|
+
blendColorPixelDataBinaryMask(target, color, brush, scratchOptions);
|
|
2458
|
+
}
|
|
2459
|
+
}
|
|
2460
|
+
|
|
2461
|
+
// src/History/PixelMutator/mutatorApplyCircleBrush.ts
|
|
2462
|
+
var defaults3 = {
|
|
2463
|
+
applyCircleBrushToPixelData,
|
|
2464
|
+
getCircleBrushOrPencilBounds
|
|
2465
|
+
};
|
|
2466
|
+
var mutatorApplyCircleBrush = ((writer, deps = defaults3) => {
|
|
2467
|
+
const {
|
|
2468
|
+
applyCircleBrushToPixelData: applyCircleBrushToPixelData2 = defaults3.applyCircleBrushToPixelData,
|
|
2469
|
+
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults3.getCircleBrushOrPencilBounds
|
|
2470
|
+
} = deps;
|
|
2471
|
+
const boundsOut = {
|
|
2472
|
+
x: 0,
|
|
2473
|
+
y: 0,
|
|
2474
|
+
w: 0,
|
|
2475
|
+
h: 0
|
|
2476
|
+
};
|
|
2477
|
+
const blendColorPixelOptions = {
|
|
2478
|
+
alpha: 255,
|
|
2479
|
+
blendFn: sourceOverPerfect,
|
|
2480
|
+
x: 0,
|
|
2481
|
+
y: 0,
|
|
2482
|
+
w: 0,
|
|
2483
|
+
h: 0
|
|
2484
|
+
};
|
|
2485
|
+
return {
|
|
2486
|
+
applyCircleBrush(color, centerX, centerY, brush, alpha = 255, blendFn) {
|
|
2487
|
+
const bounds = getCircleBrushOrPencilBounds2(centerX, centerY, brush.size, writer.target.width, writer.target.height, boundsOut);
|
|
2488
|
+
const {
|
|
2489
|
+
x,
|
|
2490
|
+
y,
|
|
2491
|
+
w,
|
|
2492
|
+
h
|
|
2493
|
+
} = bounds;
|
|
2494
|
+
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2495
|
+
applyCircleBrushToPixelData2(writer.target, color, centerX, centerY, brush, alpha, blendFn, blendColorPixelOptions, bounds);
|
|
2496
|
+
}
|
|
2497
|
+
};
|
|
2498
|
+
});
|
|
2499
|
+
|
|
2500
|
+
// src/Algorithm/forEachLinePoint.ts
|
|
2501
|
+
function forEachLinePoint(x0, y0, x1, y1, callback) {
|
|
2502
|
+
const dx = x1 - x0;
|
|
2503
|
+
const dy = y1 - y0;
|
|
2504
|
+
const steps = Math.max(Math.abs(dx), Math.abs(dy));
|
|
2505
|
+
if (steps === 0) {
|
|
2506
|
+
callback(x0, y0);
|
|
2507
|
+
return;
|
|
2508
|
+
}
|
|
2509
|
+
const xInc = dx / steps;
|
|
2510
|
+
const yInc = dy / steps;
|
|
2511
|
+
let curX = x0;
|
|
2512
|
+
let curY = y0;
|
|
2513
|
+
for (let i = 0; i <= steps; i++) {
|
|
2514
|
+
callback(curX, curY);
|
|
2515
|
+
curX += xInc;
|
|
2516
|
+
curY += yInc;
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2519
|
+
|
|
2467
2520
|
// src/Rect/getCircleBrushOrPencilStrokeBounds.ts
|
|
2468
2521
|
function getCircleBrushOrPencilStrokeBounds(x0, y0, x1, y1, brushSize, result) {
|
|
2469
2522
|
const r = Math.ceil(brushSize / 2);
|
|
@@ -2512,8 +2565,15 @@ var mutatorApplyCircleBrushStroke = ((writer, deps = defaults4) => {
|
|
|
2512
2565
|
w: 0,
|
|
2513
2566
|
h: 0
|
|
2514
2567
|
};
|
|
2568
|
+
const mask = {
|
|
2569
|
+
type: 0 /* ALPHA */,
|
|
2570
|
+
data: null,
|
|
2571
|
+
w: 0,
|
|
2572
|
+
h: 0
|
|
2573
|
+
};
|
|
2515
2574
|
return {
|
|
2516
|
-
applyCircleBrushStroke(color, x0, y0, x1, y1,
|
|
2575
|
+
applyCircleBrushStroke(color, x0, y0, x1, y1, brush, alpha = 255, blendFn = sourceOverPerfect) {
|
|
2576
|
+
const brushSize = brush.size;
|
|
2517
2577
|
const {
|
|
2518
2578
|
x: bx,
|
|
2519
2579
|
y: by,
|
|
@@ -2521,11 +2581,12 @@ var mutatorApplyCircleBrushStroke = ((writer, deps = defaults4) => {
|
|
|
2521
2581
|
h: bh
|
|
2522
2582
|
} = getCircleBrushOrPencilStrokeBounds2(x0, y0, x1, y1, brushSize, strokeBoundsOut);
|
|
2523
2583
|
if (bw <= 0 || bh <= 0) return;
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
const
|
|
2528
|
-
const
|
|
2584
|
+
mask.data = new Uint8Array(bw * bh);
|
|
2585
|
+
mask.w = bw;
|
|
2586
|
+
mask.h = bh;
|
|
2587
|
+
const maskData = mask.data;
|
|
2588
|
+
const brushData = brush.data;
|
|
2589
|
+
const minOffset = brush.minOffset;
|
|
2529
2590
|
const targetWidth = writer.target.width;
|
|
2530
2591
|
const targetHeight = writer.target.height;
|
|
2531
2592
|
forEachLinePoint2(x0, y0, x1, y1, (px, py) => {
|
|
@@ -2540,21 +2601,20 @@ var mutatorApplyCircleBrushStroke = ((writer, deps = defaults4) => {
|
|
|
2540
2601
|
const startY = Math.max(by, cby);
|
|
2541
2602
|
const endX = Math.min(bx + bw, cbx + cbw);
|
|
2542
2603
|
const endY = Math.min(by + bh, cby + cbh);
|
|
2543
|
-
const
|
|
2544
|
-
const
|
|
2604
|
+
const unclippedStartX = Math.floor(px + minOffset);
|
|
2605
|
+
const unclippedStartY = Math.floor(py + minOffset);
|
|
2545
2606
|
for (let my = startY; my < endY; my++) {
|
|
2546
|
-
const
|
|
2547
|
-
const
|
|
2548
|
-
const
|
|
2607
|
+
const strokeMaskY = my - by;
|
|
2608
|
+
const strokeMaskRowOffset = strokeMaskY * bw;
|
|
2609
|
+
const brushY = my - unclippedStartY;
|
|
2610
|
+
const brushRowOffset = brushY * brushSize;
|
|
2549
2611
|
for (let mx = startX; mx < endX; mx++) {
|
|
2550
|
-
const
|
|
2551
|
-
const
|
|
2552
|
-
if (
|
|
2553
|
-
const
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
if (intensity > mask[maskIdx]) {
|
|
2557
|
-
mask[maskIdx] = intensity;
|
|
2612
|
+
const brushX = mx - unclippedStartX;
|
|
2613
|
+
const brushVal = brushData[brushRowOffset + brushX];
|
|
2614
|
+
if (brushVal > 0) {
|
|
2615
|
+
const strokeMaskIdx = strokeMaskRowOffset + (mx - bx);
|
|
2616
|
+
if (brushVal > maskData[strokeMaskIdx]) {
|
|
2617
|
+
maskData[strokeMaskIdx] = brushVal;
|
|
2558
2618
|
}
|
|
2559
2619
|
}
|
|
2560
2620
|
}
|
|
@@ -2571,71 +2631,6 @@ var mutatorApplyCircleBrushStroke = ((writer, deps = defaults4) => {
|
|
|
2571
2631
|
};
|
|
2572
2632
|
});
|
|
2573
2633
|
|
|
2574
|
-
// src/PixelData/blendColorPixelDataBinaryMask.ts
|
|
2575
|
-
function blendColorPixelDataBinaryMask(dst, color, mask, opts = {}) {
|
|
2576
|
-
const {
|
|
2577
|
-
x: targetX = 0,
|
|
2578
|
-
y: targetY = 0,
|
|
2579
|
-
w: width = dst.width,
|
|
2580
|
-
h: height = dst.height,
|
|
2581
|
-
alpha: globalAlpha = 255,
|
|
2582
|
-
blendFn = sourceOverPerfect,
|
|
2583
|
-
mw = width,
|
|
2584
|
-
mx = 0,
|
|
2585
|
-
my = 0,
|
|
2586
|
-
invertMask = false
|
|
2587
|
-
} = opts;
|
|
2588
|
-
if (globalAlpha === 0 || !mask) return;
|
|
2589
|
-
const baseSrcAlpha = color >>> 24;
|
|
2590
|
-
const isOverwrite = blendFn.isOverwrite || false;
|
|
2591
|
-
if (baseSrcAlpha === 0 && !isOverwrite) return;
|
|
2592
|
-
let x = targetX;
|
|
2593
|
-
let y = targetY;
|
|
2594
|
-
let w = width;
|
|
2595
|
-
let h = height;
|
|
2596
|
-
if (x < 0) {
|
|
2597
|
-
w += x;
|
|
2598
|
-
x = 0;
|
|
2599
|
-
}
|
|
2600
|
-
if (y < 0) {
|
|
2601
|
-
h += y;
|
|
2602
|
-
y = 0;
|
|
2603
|
-
}
|
|
2604
|
-
const actualW = Math.min(w, dst.width - x);
|
|
2605
|
-
const actualH = Math.min(h, dst.height - y);
|
|
2606
|
-
if (actualW <= 0 || actualH <= 0) return;
|
|
2607
|
-
let baseColorWithGlobalAlpha = color;
|
|
2608
|
-
if (globalAlpha < 255) {
|
|
2609
|
-
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
2610
|
-
if (a === 0 && !isOverwrite) return;
|
|
2611
|
-
baseColorWithGlobalAlpha = (color & 16777215 | a << 24) >>> 0;
|
|
2612
|
-
}
|
|
2613
|
-
const dx = x - targetX | 0;
|
|
2614
|
-
const dy = y - targetY | 0;
|
|
2615
|
-
const dst32 = dst.data32;
|
|
2616
|
-
const dw = dst.width;
|
|
2617
|
-
const mPitch = mw;
|
|
2618
|
-
let dIdx = y * dw + x | 0;
|
|
2619
|
-
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
2620
|
-
const dStride = dw - actualW | 0;
|
|
2621
|
-
const mStride = mPitch - actualW | 0;
|
|
2622
|
-
const skipVal = invertMask ? 1 : 0;
|
|
2623
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
2624
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
2625
|
-
if (mask[mIdx] === skipVal) {
|
|
2626
|
-
dIdx++;
|
|
2627
|
-
mIdx++;
|
|
2628
|
-
continue;
|
|
2629
|
-
}
|
|
2630
|
-
dst32[dIdx] = blendFn(baseColorWithGlobalAlpha, dst32[dIdx]);
|
|
2631
|
-
dIdx++;
|
|
2632
|
-
mIdx++;
|
|
2633
|
-
}
|
|
2634
|
-
dIdx += dStride;
|
|
2635
|
-
mIdx += mStride;
|
|
2636
|
-
}
|
|
2637
|
-
}
|
|
2638
|
-
|
|
2639
2634
|
// src/History/PixelMutator/mutatorApplyCirclePencilStroke.ts
|
|
2640
2635
|
var defaults5 = {
|
|
2641
2636
|
forEachLinePoint,
|
|
@@ -2670,19 +2665,25 @@ var mutatorApplyCirclePencilStroke = ((writer, deps = defaults5) => {
|
|
|
2670
2665
|
w: 0,
|
|
2671
2666
|
h: 0
|
|
2672
2667
|
};
|
|
2668
|
+
const mask = {
|
|
2669
|
+
type: 1 /* BINARY */,
|
|
2670
|
+
data: null,
|
|
2671
|
+
w: 0,
|
|
2672
|
+
h: 0
|
|
2673
|
+
};
|
|
2673
2674
|
return {
|
|
2674
|
-
applyCirclePencilStroke(color, x0, y0, x1, y1,
|
|
2675
|
+
applyCirclePencilStroke(color, x0, y0, x1, y1, brush, alpha = 255, blendFn = sourceOverPerfect) {
|
|
2675
2676
|
const {
|
|
2676
2677
|
x: bx,
|
|
2677
2678
|
y: by,
|
|
2678
2679
|
w: bw,
|
|
2679
2680
|
h: bh
|
|
2680
|
-
} = getCircleBrushOrPencilStrokeBounds2(x0, y0, x1, y1,
|
|
2681
|
+
} = getCircleBrushOrPencilStrokeBounds2(x0, y0, x1, y1, brush.size, strokeBoundsOut);
|
|
2681
2682
|
if (bw <= 0 || bh <= 0) return;
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
const
|
|
2683
|
+
mask.data = new Uint8Array(bw * bh);
|
|
2684
|
+
mask.w = bw;
|
|
2685
|
+
mask.h = bh;
|
|
2686
|
+
const maskData = mask.data;
|
|
2686
2687
|
const targetWidth = writer.target.width;
|
|
2687
2688
|
const targetHeight = writer.target.height;
|
|
2688
2689
|
forEachLinePoint2(x0, y0, x1, y1, (px, py) => {
|
|
@@ -2691,24 +2692,24 @@ var mutatorApplyCirclePencilStroke = ((writer, deps = defaults5) => {
|
|
|
2691
2692
|
y: cby,
|
|
2692
2693
|
w: cbw,
|
|
2693
2694
|
h: cbh
|
|
2694
|
-
} = getCircleBrushOrPencilBounds2(px, py,
|
|
2695
|
+
} = getCircleBrushOrPencilBounds2(px, py, brush.size, targetWidth, targetHeight, circlePencilBounds);
|
|
2695
2696
|
writer.accumulator.storeRegionBeforeState(cbx, cby, cbw, cbh);
|
|
2696
|
-
const
|
|
2697
|
-
const
|
|
2698
|
-
const
|
|
2699
|
-
const
|
|
2700
|
-
const
|
|
2701
|
-
const
|
|
2697
|
+
const unclippedStartX = Math.floor(px + brush.minOffset);
|
|
2698
|
+
const unclippedStartY = Math.floor(py + brush.minOffset);
|
|
2699
|
+
const startX = Math.max(bx, unclippedStartX);
|
|
2700
|
+
const startY = Math.max(by, unclippedStartY);
|
|
2701
|
+
const endX = Math.min(bx + bw, unclippedStartX + brush.w);
|
|
2702
|
+
const endY = Math.min(by + bh, unclippedStartY + brush.h);
|
|
2702
2703
|
for (let my = startY; my < endY; my++) {
|
|
2703
|
-
const
|
|
2704
|
-
const dySqr = dy * dy;
|
|
2704
|
+
const brushY = my - unclippedStartY;
|
|
2705
2705
|
const maskRowOffset = (my - by) * bw;
|
|
2706
|
+
const brushRowOffset = brushY * brush.w;
|
|
2706
2707
|
for (let mx = startX; mx < endX; mx++) {
|
|
2707
|
-
const
|
|
2708
|
-
const
|
|
2709
|
-
if (
|
|
2708
|
+
const brushX = mx - unclippedStartX;
|
|
2709
|
+
const brushAlpha = brush.data[brushRowOffset + brushX];
|
|
2710
|
+
if (brushAlpha > 0) {
|
|
2710
2711
|
const maskIdx = maskRowOffset + (mx - bx);
|
|
2711
|
-
|
|
2712
|
+
maskData[maskIdx] = brushAlpha;
|
|
2712
2713
|
}
|
|
2713
2714
|
}
|
|
2714
2715
|
}
|
|
@@ -2875,6 +2876,12 @@ var mutatorApplyRectBrushStroke = ((writer, deps = defaults7) => {
|
|
|
2875
2876
|
w: 0,
|
|
2876
2877
|
h: 0
|
|
2877
2878
|
};
|
|
2879
|
+
const mask = {
|
|
2880
|
+
type: 0 /* ALPHA */,
|
|
2881
|
+
data: null,
|
|
2882
|
+
w: 0,
|
|
2883
|
+
h: 0
|
|
2884
|
+
};
|
|
2878
2885
|
return {
|
|
2879
2886
|
applyRectBrushStroke(color, x0, y0, x1, y1, brushWidth, brushHeight, alpha = 255, fallOff, blendFn = sourceOverPerfect) {
|
|
2880
2887
|
const {
|
|
@@ -2884,7 +2891,10 @@ var mutatorApplyRectBrushStroke = ((writer, deps = defaults7) => {
|
|
|
2884
2891
|
h: bh
|
|
2885
2892
|
} = getRectBrushOrPencilStrokeBounds2(x0, y0, x1, y1, brushWidth, brushHeight, strokeBoundsOut);
|
|
2886
2893
|
if (bw <= 0 || bh <= 0) return;
|
|
2887
|
-
|
|
2894
|
+
mask.data = new Uint8Array(bw * bh);
|
|
2895
|
+
mask.w = bw;
|
|
2896
|
+
mask.h = bh;
|
|
2897
|
+
const maskData = mask.data;
|
|
2888
2898
|
const halfW = brushWidth / 2;
|
|
2889
2899
|
const halfH = brushHeight / 2;
|
|
2890
2900
|
const invHalfW = 1 / halfW;
|
|
@@ -2917,8 +2927,8 @@ var mutatorApplyRectBrushStroke = ((writer, deps = defaults7) => {
|
|
|
2917
2927
|
const strength = fallOff(dist);
|
|
2918
2928
|
if (strength > 0) {
|
|
2919
2929
|
const intensity = strength * 255 | 0;
|
|
2920
|
-
if (intensity >
|
|
2921
|
-
|
|
2930
|
+
if (intensity > maskData[maskIdx]) {
|
|
2931
|
+
maskData[maskIdx] = intensity;
|
|
2922
2932
|
}
|
|
2923
2933
|
}
|
|
2924
2934
|
}
|
|
@@ -3002,6 +3012,12 @@ var mutatorApplyRectPencilStroke = ((writer, deps = defaults9) => {
|
|
|
3002
3012
|
w: 0,
|
|
3003
3013
|
h: 0
|
|
3004
3014
|
};
|
|
3015
|
+
const mask = {
|
|
3016
|
+
type: 1 /* BINARY */,
|
|
3017
|
+
data: null,
|
|
3018
|
+
w: 0,
|
|
3019
|
+
h: 0
|
|
3020
|
+
};
|
|
3005
3021
|
return {
|
|
3006
3022
|
applyRectPencilStroke(color, x0, y0, x1, y1, brushWidth, brushHeight, alpha = 255, blendFn = sourceOverPerfect) {
|
|
3007
3023
|
const {
|
|
@@ -3011,7 +3027,10 @@ var mutatorApplyRectPencilStroke = ((writer, deps = defaults9) => {
|
|
|
3011
3027
|
h: bh
|
|
3012
3028
|
} = getRectBrushOrPencilStrokeBounds2(x0, y0, x1, y1, brushWidth, brushHeight, strokeBoundsOut);
|
|
3013
3029
|
if (bw <= 0 || bh <= 0) return;
|
|
3014
|
-
|
|
3030
|
+
mask.data = new Uint8Array(bw * bh);
|
|
3031
|
+
mask.w = bw;
|
|
3032
|
+
mask.h = bh;
|
|
3033
|
+
const maskData = mask.data;
|
|
3015
3034
|
const halfW = brushWidth / 2;
|
|
3016
3035
|
const halfH = brushHeight / 2;
|
|
3017
3036
|
const centerOffset = brushWidth % 2 === 0 ? 0.5 : 0;
|
|
@@ -3038,7 +3057,7 @@ var mutatorApplyRectPencilStroke = ((writer, deps = defaults9) => {
|
|
|
3038
3057
|
const dx = Math.abs(mx - fPx + centerOffset);
|
|
3039
3058
|
const maskIdx = maskRowOffset + (mx - bx);
|
|
3040
3059
|
if (dx <= halfW && dy <= halfH) {
|
|
3041
|
-
|
|
3060
|
+
maskData[maskIdx] = 1;
|
|
3042
3061
|
}
|
|
3043
3062
|
}
|
|
3044
3063
|
}
|
|
@@ -3249,24 +3268,21 @@ var mutatorBlendPixelData = ((writer, deps = defaults11) => {
|
|
|
3249
3268
|
|
|
3250
3269
|
// src/PixelData/fillPixelData.ts
|
|
3251
3270
|
var SCRATCH_RECT = makeClippedRect();
|
|
3252
|
-
function fillPixelData(dst, color, _x, _y, _w, _h
|
|
3271
|
+
function fillPixelData(dst, color, _x, _y, _w, _h) {
|
|
3253
3272
|
let x;
|
|
3254
3273
|
let y;
|
|
3255
3274
|
let w;
|
|
3256
3275
|
let h;
|
|
3257
|
-
let mask;
|
|
3258
3276
|
if (typeof _x === "object") {
|
|
3259
3277
|
x = _x.x ?? 0;
|
|
3260
3278
|
y = _x.y ?? 0;
|
|
3261
3279
|
w = _x.w ?? dst.width;
|
|
3262
3280
|
h = _x.h ?? dst.height;
|
|
3263
|
-
mask = _x.mask;
|
|
3264
3281
|
} else if (typeof _x === "number") {
|
|
3265
3282
|
x = _x;
|
|
3266
3283
|
y = _y;
|
|
3267
3284
|
w = _w;
|
|
3268
3285
|
h = _h;
|
|
3269
|
-
mask = _mask;
|
|
3270
3286
|
} else {
|
|
3271
3287
|
x = 0;
|
|
3272
3288
|
y = 0;
|
|
@@ -3287,28 +3303,10 @@ function fillPixelData(dst, color, _x, _y, _w, _h, _mask) {
|
|
|
3287
3303
|
dst32.fill(color);
|
|
3288
3304
|
return;
|
|
3289
3305
|
}
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
const maskOffset = maskY * w;
|
|
3295
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
3296
|
-
const currentX = finalX + ix;
|
|
3297
|
-
const maskX = currentX - x;
|
|
3298
|
-
const maskIndex = maskOffset + maskX;
|
|
3299
|
-
const isMasked = mask[maskIndex];
|
|
3300
|
-
if (isMasked) {
|
|
3301
|
-
const dstIndex = currentY * dw + currentX;
|
|
3302
|
-
dst32[dstIndex] = color;
|
|
3303
|
-
}
|
|
3304
|
-
}
|
|
3305
|
-
}
|
|
3306
|
-
} else {
|
|
3307
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
3308
|
-
const start = (finalY + iy) * dw + finalX;
|
|
3309
|
-
const end = start + actualW;
|
|
3310
|
-
dst32.fill(color, start, end);
|
|
3311
|
-
}
|
|
3306
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
3307
|
+
const start = (finalY + iy) * dw + finalX;
|
|
3308
|
+
const end = start + actualW;
|
|
3309
|
+
dst32.fill(color, start, end);
|
|
3312
3310
|
}
|
|
3313
3311
|
}
|
|
3314
3312
|
|
|
@@ -3322,15 +3320,12 @@ var mutatorClear = ((writer, deps = defaults12) => {
|
|
|
3322
3320
|
} = deps;
|
|
3323
3321
|
return {
|
|
3324
3322
|
clear(rect = {}) {
|
|
3325
|
-
const
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
h = writer.target.height,
|
|
3330
|
-
mask = void 0
|
|
3331
|
-
} = rect;
|
|
3323
|
+
const x = rect.x ?? 0;
|
|
3324
|
+
const y = rect.y ?? 0;
|
|
3325
|
+
const w = rect.w ?? writer.target.width;
|
|
3326
|
+
const h = rect.h ?? writer.target.height;
|
|
3332
3327
|
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3333
|
-
fillPixelData2(writer.target, 0, x, y, w, h
|
|
3328
|
+
fillPixelData2(writer.target, 0, x, y, w, h);
|
|
3334
3329
|
}
|
|
3335
3330
|
};
|
|
3336
3331
|
});
|
|
@@ -3349,11 +3344,10 @@ var mutatorFill = ((writer, deps = defaults13) => {
|
|
|
3349
3344
|
x = 0,
|
|
3350
3345
|
y = 0,
|
|
3351
3346
|
w = writer.target.width,
|
|
3352
|
-
h = writer.target.height
|
|
3353
|
-
mask = void 0
|
|
3347
|
+
h = writer.target.height
|
|
3354
3348
|
} = rect;
|
|
3355
3349
|
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3356
|
-
fillPixelData2(writer.target, color, x, y, w, h
|
|
3350
|
+
fillPixelData2(writer.target, color, x, y, w, h);
|
|
3357
3351
|
}
|
|
3358
3352
|
};
|
|
3359
3353
|
});
|
|
@@ -3368,7 +3362,6 @@ function invertPixelData(pixelData, opts = {}) {
|
|
|
3368
3362
|
w: width = pixelData.width,
|
|
3369
3363
|
h: height = pixelData.height,
|
|
3370
3364
|
mask,
|
|
3371
|
-
mw,
|
|
3372
3365
|
mx = 0,
|
|
3373
3366
|
my = 0,
|
|
3374
3367
|
invertMask = false
|
|
@@ -3383,7 +3376,7 @@ function invertPixelData(pixelData, opts = {}) {
|
|
|
3383
3376
|
} = clip;
|
|
3384
3377
|
const dst32 = dst.data32;
|
|
3385
3378
|
const dw = dst.width;
|
|
3386
|
-
const mPitch =
|
|
3379
|
+
const mPitch = mask?.w ?? width;
|
|
3387
3380
|
const dx = x - targetX;
|
|
3388
3381
|
const dy = y - targetY;
|
|
3389
3382
|
let dIdx = y * dw + x;
|
|
@@ -3391,9 +3384,10 @@ function invertPixelData(pixelData, opts = {}) {
|
|
|
3391
3384
|
const dStride = dw - actualW;
|
|
3392
3385
|
const mStride = mPitch - actualW;
|
|
3393
3386
|
if (mask) {
|
|
3387
|
+
const maskData = mask.data;
|
|
3394
3388
|
for (let iy = 0; iy < actualH; iy++) {
|
|
3395
3389
|
for (let ix = 0; ix < actualW; ix++) {
|
|
3396
|
-
const mVal =
|
|
3390
|
+
const mVal = maskData[mIdx];
|
|
3397
3391
|
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
3398
3392
|
if (isHit) {
|
|
3399
3393
|
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
@@ -3504,14 +3498,12 @@ var PixelWriter = class {
|
|
|
3504
3498
|
// src/History/PixelMutator/mutatorApplyCirclePencil.ts
|
|
3505
3499
|
var defaults15 = {
|
|
3506
3500
|
applyCircleBrushToPixelData,
|
|
3507
|
-
getCircleBrushOrPencilBounds
|
|
3508
|
-
fallOff: () => 1
|
|
3501
|
+
getCircleBrushOrPencilBounds
|
|
3509
3502
|
};
|
|
3510
3503
|
var mutatorApplyCirclePencil = ((writer, deps = defaults15) => {
|
|
3511
3504
|
const {
|
|
3512
3505
|
applyCircleBrushToPixelData: applyCircleBrushToPixelData2 = defaults15.applyCircleBrushToPixelData,
|
|
3513
|
-
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults15.getCircleBrushOrPencilBounds
|
|
3514
|
-
fallOff = defaults15.fallOff
|
|
3506
|
+
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults15.getCircleBrushOrPencilBounds
|
|
3515
3507
|
} = deps;
|
|
3516
3508
|
const boundsOut = {
|
|
3517
3509
|
x: 0,
|
|
@@ -3520,8 +3512,8 @@ var mutatorApplyCirclePencil = ((writer, deps = defaults15) => {
|
|
|
3520
3512
|
h: 0
|
|
3521
3513
|
};
|
|
3522
3514
|
return {
|
|
3523
|
-
applyCirclePencil(color, centerX, centerY,
|
|
3524
|
-
const bounds = getCircleBrushOrPencilBounds2(centerX, centerY,
|
|
3515
|
+
applyCirclePencil(color, centerX, centerY, brush, alpha = 255, blendFn) {
|
|
3516
|
+
const bounds = getCircleBrushOrPencilBounds2(centerX, centerY, brush.size, writer.target.width, writer.target.height, boundsOut);
|
|
3525
3517
|
const {
|
|
3526
3518
|
x,
|
|
3527
3519
|
y,
|
|
@@ -3529,7 +3521,63 @@ var mutatorApplyCirclePencil = ((writer, deps = defaults15) => {
|
|
|
3529
3521
|
h
|
|
3530
3522
|
} = bounds;
|
|
3531
3523
|
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3532
|
-
applyCircleBrushToPixelData2(writer.target, color, centerX, centerY,
|
|
3524
|
+
applyCircleBrushToPixelData2(writer.target, color, centerX, centerY, brush, alpha, blendFn, bounds);
|
|
3525
|
+
}
|
|
3526
|
+
};
|
|
3527
|
+
});
|
|
3528
|
+
|
|
3529
|
+
// src/PixelData/fillPixelDataBinaryMask.ts
|
|
3530
|
+
var SCRATCH_RECT3 = makeClippedRect();
|
|
3531
|
+
function fillPixelDataBinaryMask(dst, color, mask, alpha = 255, x = 0, y = 0) {
|
|
3532
|
+
if (alpha === 0) return;
|
|
3533
|
+
const maskW = mask.w;
|
|
3534
|
+
const maskH = mask.h;
|
|
3535
|
+
const clip = resolveRectClipping(x, y, maskW, maskH, dst.width, dst.height, SCRATCH_RECT3);
|
|
3536
|
+
if (!clip.inBounds) return;
|
|
3537
|
+
const {
|
|
3538
|
+
x: finalX,
|
|
3539
|
+
y: finalY,
|
|
3540
|
+
w: actualW,
|
|
3541
|
+
h: actualH
|
|
3542
|
+
} = clip;
|
|
3543
|
+
const maskData = mask.data;
|
|
3544
|
+
const dst32 = dst.data32;
|
|
3545
|
+
const dw = dst.width;
|
|
3546
|
+
let finalCol = color;
|
|
3547
|
+
if (alpha < 255) {
|
|
3548
|
+
const baseSrcAlpha = color >>> 24;
|
|
3549
|
+
const colorRGB = color & 16777215;
|
|
3550
|
+
const a = baseSrcAlpha * alpha + 128 >> 8;
|
|
3551
|
+
finalCol = (colorRGB | a << 24) >>> 0;
|
|
3552
|
+
}
|
|
3553
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
3554
|
+
const currentY = finalY + iy;
|
|
3555
|
+
const maskY = currentY - y;
|
|
3556
|
+
const maskOffset = maskY * maskW;
|
|
3557
|
+
const dstRowOffset = currentY * dw;
|
|
3558
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
3559
|
+
const currentX = finalX + ix;
|
|
3560
|
+
const maskX = currentX - x;
|
|
3561
|
+
const maskIndex = maskOffset + maskX;
|
|
3562
|
+
if (maskData[maskIndex]) {
|
|
3563
|
+
dst32[dstRowOffset + currentX] = finalCol;
|
|
3564
|
+
}
|
|
3565
|
+
}
|
|
3566
|
+
}
|
|
3567
|
+
}
|
|
3568
|
+
|
|
3569
|
+
// src/History/PixelMutator/mutatorFillBinaryMask.ts
|
|
3570
|
+
var defaults16 = {
|
|
3571
|
+
fillPixelDataBinaryMask
|
|
3572
|
+
};
|
|
3573
|
+
var mutatorFillBinaryMask = ((writer, deps = defaults16) => {
|
|
3574
|
+
const {
|
|
3575
|
+
fillPixelDataBinaryMask: fillPixelDataBinaryMask2 = defaults16.fillPixelDataBinaryMask
|
|
3576
|
+
} = deps;
|
|
3577
|
+
return {
|
|
3578
|
+
fillBinaryMask(color, mask, alpha = 255, x = 0, y = 0) {
|
|
3579
|
+
writer.accumulator.storeRegionBeforeState(x, y, mask.w, mask.h);
|
|
3580
|
+
fillPixelDataBinaryMask2(writer.target, color, mask, alpha, x, y);
|
|
3533
3581
|
}
|
|
3534
3582
|
};
|
|
3535
3583
|
});
|
|
@@ -3565,8 +3613,8 @@ function makeImageDataLike(width, height, data) {
|
|
|
3565
3613
|
};
|
|
3566
3614
|
}
|
|
3567
3615
|
|
|
3568
|
-
// src/ImageData/
|
|
3569
|
-
function
|
|
3616
|
+
// src/ImageData/imageDataToAlphaMaskBuffer.ts
|
|
3617
|
+
function imageDataToAlphaMaskBuffer(imageData) {
|
|
3570
3618
|
const {
|
|
3571
3619
|
width,
|
|
3572
3620
|
height,
|
|
@@ -3656,13 +3704,13 @@ function resampleImageData(source, factor) {
|
|
|
3656
3704
|
}
|
|
3657
3705
|
|
|
3658
3706
|
// src/ImageData/resizeImageData.ts
|
|
3659
|
-
function resizeImageData(
|
|
3707
|
+
function resizeImageData(target, newWidth, newHeight, offsetX = 0, offsetY = 0) {
|
|
3660
3708
|
const result = new ImageData(newWidth, newHeight);
|
|
3661
3709
|
const {
|
|
3662
3710
|
width: oldW,
|
|
3663
3711
|
height: oldH,
|
|
3664
3712
|
data: oldData
|
|
3665
|
-
} =
|
|
3713
|
+
} = target;
|
|
3666
3714
|
const newData = result.data;
|
|
3667
3715
|
const x0 = Math.max(0, offsetX);
|
|
3668
3716
|
const y0 = Math.max(0, offsetY);
|
|
@@ -3817,7 +3865,7 @@ function writeImageData(target, source, x, y, sx = 0, sy = 0, sw = source.width,
|
|
|
3817
3865
|
|
|
3818
3866
|
// src/ImageData/writeImageDataBuffer.ts
|
|
3819
3867
|
var SCRATCH_BLIT3 = makeClippedBlit();
|
|
3820
|
-
function writeImageDataBuffer(
|
|
3868
|
+
function writeImageDataBuffer(target, data, _x, _y, _w, _h) {
|
|
3821
3869
|
const {
|
|
3822
3870
|
x,
|
|
3823
3871
|
y,
|
|
@@ -3833,7 +3881,7 @@ function writeImageDataBuffer(imageData, data, _x, _y, _w, _h) {
|
|
|
3833
3881
|
width: dstW,
|
|
3834
3882
|
height: dstH,
|
|
3835
3883
|
data: dst
|
|
3836
|
-
} =
|
|
3884
|
+
} = target;
|
|
3837
3885
|
const clip = resolveBlitClipping(x, y, 0, 0, w, h, dstW, dstH, w, h, SCRATCH_BLIT3);
|
|
3838
3886
|
if (!clip.inBounds) return;
|
|
3839
3887
|
const {
|
|
@@ -4079,8 +4127,84 @@ async function getSupportedPixelFormats(rasterMimes = defaultRasterMimes) {
|
|
|
4079
4127
|
return formatsPromise;
|
|
4080
4128
|
}
|
|
4081
4129
|
|
|
4130
|
+
// src/Mask/AlphaMask.ts
|
|
4131
|
+
function makeAlphaMask(w, h, data) {
|
|
4132
|
+
return {
|
|
4133
|
+
type: 0 /* ALPHA */,
|
|
4134
|
+
data: data ?? new Uint8Array(w * h),
|
|
4135
|
+
w,
|
|
4136
|
+
h
|
|
4137
|
+
};
|
|
4138
|
+
}
|
|
4139
|
+
|
|
4140
|
+
// src/Mask/BinaryMask.ts
|
|
4141
|
+
function makeBinaryMask(w, h, data) {
|
|
4142
|
+
return {
|
|
4143
|
+
type: 1 /* BINARY */,
|
|
4144
|
+
data: data ?? new Uint8Array(w * h),
|
|
4145
|
+
w,
|
|
4146
|
+
h
|
|
4147
|
+
};
|
|
4148
|
+
}
|
|
4149
|
+
|
|
4150
|
+
// src/Mask/CircleBrushAlphaMask.ts
|
|
4151
|
+
function makeCircleBrushAlphaMask(size, fallOff = () => 1) {
|
|
4152
|
+
const area = size * size;
|
|
4153
|
+
const data = new Uint8Array(area);
|
|
4154
|
+
const radius = size / 2;
|
|
4155
|
+
const invR = 1 / radius;
|
|
4156
|
+
const minOffset = -Math.ceil(radius - 0.5);
|
|
4157
|
+
for (let y = 0; y < size; y++) {
|
|
4158
|
+
for (let x = 0; x < size; x++) {
|
|
4159
|
+
const dx = x - radius + 0.5;
|
|
4160
|
+
const dy = y - radius + 0.5;
|
|
4161
|
+
const distSqr = dx * dx + dy * dy;
|
|
4162
|
+
if (distSqr <= radius * radius) {
|
|
4163
|
+
const dist = Math.sqrt(distSqr);
|
|
4164
|
+
data[y * size + x] = fallOff(1 - dist * invR) * 255 | 0;
|
|
4165
|
+
}
|
|
4166
|
+
}
|
|
4167
|
+
}
|
|
4168
|
+
return {
|
|
4169
|
+
type: 0 /* ALPHA */,
|
|
4170
|
+
data,
|
|
4171
|
+
w: size,
|
|
4172
|
+
h: size,
|
|
4173
|
+
radius,
|
|
4174
|
+
size,
|
|
4175
|
+
minOffset
|
|
4176
|
+
};
|
|
4177
|
+
}
|
|
4178
|
+
|
|
4179
|
+
// src/Mask/CircleBrushBinaryMask.ts
|
|
4180
|
+
function makeCircleBrushBinaryMask(size) {
|
|
4181
|
+
const area = size * size;
|
|
4182
|
+
const data = new Uint8Array(area);
|
|
4183
|
+
const radius = size / 2;
|
|
4184
|
+
const minOffset = -Math.ceil(radius - 0.5);
|
|
4185
|
+
for (let y = 0; y < size; y++) {
|
|
4186
|
+
for (let x = 0; x < size; x++) {
|
|
4187
|
+
const dx = x - radius + 0.5;
|
|
4188
|
+
const dy = y - radius + 0.5;
|
|
4189
|
+
const distSqr = dx * dx + dy * dy;
|
|
4190
|
+
if (distSqr <= radius * radius) {
|
|
4191
|
+
data[y * size + x] = 1;
|
|
4192
|
+
}
|
|
4193
|
+
}
|
|
4194
|
+
}
|
|
4195
|
+
return {
|
|
4196
|
+
type: 1 /* BINARY */,
|
|
4197
|
+
data,
|
|
4198
|
+
w: size,
|
|
4199
|
+
h: size,
|
|
4200
|
+
radius,
|
|
4201
|
+
size,
|
|
4202
|
+
minOffset
|
|
4203
|
+
};
|
|
4204
|
+
}
|
|
4205
|
+
|
|
4082
4206
|
// src/Mask/applyBinaryMaskToAlphaMask.ts
|
|
4083
|
-
function applyBinaryMaskToAlphaMask(alphaMaskDst,
|
|
4207
|
+
function applyBinaryMaskToAlphaMask(alphaMaskDst, binaryMaskSrc, opts = {}) {
|
|
4084
4208
|
const {
|
|
4085
4209
|
x: targetX = 0,
|
|
4086
4210
|
y: targetY = 0,
|
|
@@ -4090,11 +4214,13 @@ function applyBinaryMaskToAlphaMask(alphaMaskDst, dstWidth, binaryMaskSrc, srcWi
|
|
|
4090
4214
|
my = 0,
|
|
4091
4215
|
invertMask = false
|
|
4092
4216
|
} = opts;
|
|
4217
|
+
const dstWidth = alphaMaskDst.w;
|
|
4093
4218
|
if (dstWidth <= 0) return;
|
|
4094
|
-
if (binaryMaskSrc.length === 0) return;
|
|
4219
|
+
if (binaryMaskSrc.data.length === 0) return;
|
|
4220
|
+
const srcWidth = binaryMaskSrc.w;
|
|
4095
4221
|
if (srcWidth <= 0) return;
|
|
4096
|
-
const dstHeight = alphaMaskDst.length / dstWidth | 0;
|
|
4097
|
-
const srcHeight = binaryMaskSrc.length / srcWidth | 0;
|
|
4222
|
+
const dstHeight = alphaMaskDst.data.length / dstWidth | 0;
|
|
4223
|
+
const srcHeight = binaryMaskSrc.data.length / srcWidth | 0;
|
|
4098
4224
|
if (dstHeight <= 0) return;
|
|
4099
4225
|
if (srcHeight <= 0) return;
|
|
4100
4226
|
const dstX0 = Math.max(0, targetX);
|
|
@@ -4111,6 +4237,8 @@ function applyBinaryMaskToAlphaMask(alphaMaskDst, dstWidth, binaryMaskSrc, srcWi
|
|
|
4111
4237
|
if (srcY0 + (dstY1 - dstY0) <= 0) return;
|
|
4112
4238
|
const iterW = Math.min(dstX1 - dstX0, srcWidth - srcX0);
|
|
4113
4239
|
const iterH = Math.min(dstY1 - dstY0, srcHeight - srcY0);
|
|
4240
|
+
const srcData = binaryMaskSrc.data;
|
|
4241
|
+
const dstData = alphaMaskDst.data;
|
|
4114
4242
|
let dstIdx = dstY0 * dstWidth + dstX0;
|
|
4115
4243
|
let srcIdx = srcY0 * srcWidth + srcX0;
|
|
4116
4244
|
if (invertMask) {
|
|
@@ -4119,8 +4247,8 @@ function applyBinaryMaskToAlphaMask(alphaMaskDst, dstWidth, binaryMaskSrc, srcWi
|
|
|
4119
4247
|
let d = dstIdx;
|
|
4120
4248
|
let s = srcIdx;
|
|
4121
4249
|
while (d < dstEnd) {
|
|
4122
|
-
if (
|
|
4123
|
-
|
|
4250
|
+
if (srcData[s] !== 0) {
|
|
4251
|
+
dstData[d] = 0;
|
|
4124
4252
|
}
|
|
4125
4253
|
d++;
|
|
4126
4254
|
s++;
|
|
@@ -4134,8 +4262,8 @@ function applyBinaryMaskToAlphaMask(alphaMaskDst, dstWidth, binaryMaskSrc, srcWi
|
|
|
4134
4262
|
let d = dstIdx;
|
|
4135
4263
|
let s = srcIdx;
|
|
4136
4264
|
while (d < dstEnd) {
|
|
4137
|
-
if (
|
|
4138
|
-
|
|
4265
|
+
if (srcData[s] === 0) {
|
|
4266
|
+
dstData[d] = 0;
|
|
4139
4267
|
}
|
|
4140
4268
|
d++;
|
|
4141
4269
|
s++;
|
|
@@ -4148,25 +4276,72 @@ function applyBinaryMaskToAlphaMask(alphaMaskDst, dstWidth, binaryMaskSrc, srcWi
|
|
|
4148
4276
|
|
|
4149
4277
|
// src/Mask/copyMask.ts
|
|
4150
4278
|
function copyMask(src) {
|
|
4151
|
-
return
|
|
4279
|
+
return {
|
|
4280
|
+
type: src.type,
|
|
4281
|
+
data: src.data.slice(),
|
|
4282
|
+
w: src.w,
|
|
4283
|
+
h: src.h
|
|
4284
|
+
};
|
|
4285
|
+
}
|
|
4286
|
+
|
|
4287
|
+
// src/Mask/extractMask.ts
|
|
4288
|
+
function extractMask(mask, xOrRect, y, w, h) {
|
|
4289
|
+
let finalX;
|
|
4290
|
+
let finalY;
|
|
4291
|
+
let finalW;
|
|
4292
|
+
let finalH;
|
|
4293
|
+
if (typeof xOrRect === "object") {
|
|
4294
|
+
finalX = xOrRect.x;
|
|
4295
|
+
finalY = xOrRect.y;
|
|
4296
|
+
finalW = xOrRect.w;
|
|
4297
|
+
finalH = xOrRect.h;
|
|
4298
|
+
} else {
|
|
4299
|
+
finalX = xOrRect;
|
|
4300
|
+
finalY = y;
|
|
4301
|
+
finalW = w;
|
|
4302
|
+
finalH = h;
|
|
4303
|
+
}
|
|
4304
|
+
const out = {
|
|
4305
|
+
type: mask.type,
|
|
4306
|
+
w: finalW,
|
|
4307
|
+
h: finalH,
|
|
4308
|
+
data: new Uint8Array(finalW * finalH)
|
|
4309
|
+
};
|
|
4310
|
+
const srcH = mask.h;
|
|
4311
|
+
const stride = mask.w;
|
|
4312
|
+
for (let row = 0; row < finalH; row++) {
|
|
4313
|
+
const currentSrcY = finalY + row;
|
|
4314
|
+
if (currentSrcY < 0 || currentSrcY >= srcH) continue;
|
|
4315
|
+
const start = Math.max(0, finalX);
|
|
4316
|
+
const end = Math.min(stride, finalX + finalW);
|
|
4317
|
+
if (start < end) {
|
|
4318
|
+
const srcOffset = currentSrcY * stride + start;
|
|
4319
|
+
const dstOffset = row * finalW + (start - finalX);
|
|
4320
|
+
const count = end - start;
|
|
4321
|
+
out.data.set(mask.data.subarray(srcOffset, srcOffset + count), dstOffset);
|
|
4322
|
+
}
|
|
4323
|
+
}
|
|
4324
|
+
return out;
|
|
4152
4325
|
}
|
|
4153
4326
|
|
|
4154
4327
|
// src/Mask/invertMask.ts
|
|
4155
4328
|
function invertBinaryMask(dst) {
|
|
4156
|
-
const
|
|
4329
|
+
const data = dst.data;
|
|
4330
|
+
const len = data.length;
|
|
4157
4331
|
for (let i = 0; i < len; i++) {
|
|
4158
|
-
|
|
4332
|
+
data[i] = data[i] === 0 ? 1 : 0;
|
|
4159
4333
|
}
|
|
4160
4334
|
}
|
|
4161
4335
|
function invertAlphaMask(dst) {
|
|
4162
|
-
const
|
|
4336
|
+
const data = dst.data;
|
|
4337
|
+
const len = data.length;
|
|
4163
4338
|
for (let i = 0; i < len; i++) {
|
|
4164
|
-
|
|
4339
|
+
data[i] = 255 - data[i];
|
|
4165
4340
|
}
|
|
4166
4341
|
}
|
|
4167
4342
|
|
|
4168
4343
|
// src/Mask/mergeAlphaMasks.ts
|
|
4169
|
-
function mergeAlphaMasks(dst,
|
|
4344
|
+
function mergeAlphaMasks(dst, src, opts) {
|
|
4170
4345
|
const {
|
|
4171
4346
|
x: targetX = 0,
|
|
4172
4347
|
y: targetY = 0,
|
|
@@ -4177,15 +4352,17 @@ function mergeAlphaMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4177
4352
|
my = 0,
|
|
4178
4353
|
invertMask = false
|
|
4179
4354
|
} = opts;
|
|
4180
|
-
const dstHeight = dst.length / dstWidth | 0;
|
|
4181
|
-
const srcHeight = src.length / srcWidth | 0;
|
|
4182
4355
|
if (width <= 0) return;
|
|
4183
4356
|
if (height <= 0) return;
|
|
4184
4357
|
if (globalAlpha === 0) return;
|
|
4358
|
+
const dstData = dst.data;
|
|
4359
|
+
const srcData = src.data;
|
|
4360
|
+
const srcWidth = src.w;
|
|
4361
|
+
const dstWidth = dst.w;
|
|
4185
4362
|
const startX = Math.max(0, -targetX, -mx);
|
|
4186
4363
|
const startY = Math.max(0, -targetY, -my);
|
|
4187
4364
|
const endX = Math.min(width, dstWidth - targetX, srcWidth - mx);
|
|
4188
|
-
const endY = Math.min(height,
|
|
4365
|
+
const endY = Math.min(height, dst.h - targetY, src.h - my);
|
|
4189
4366
|
if (startX >= endX) return;
|
|
4190
4367
|
if (startY >= endY) return;
|
|
4191
4368
|
for (let iy = startY; iy < endY; iy++) {
|
|
@@ -4194,7 +4371,7 @@ function mergeAlphaMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4194
4371
|
let dIdx = dy * dstWidth + targetX + startX;
|
|
4195
4372
|
let sIdx = sy * srcWidth + mx + startX;
|
|
4196
4373
|
for (let ix = startX; ix < endX; ix++) {
|
|
4197
|
-
const rawM =
|
|
4374
|
+
const rawM = srcData[sIdx];
|
|
4198
4375
|
const effectiveM = invertMask ? 255 - rawM : rawM;
|
|
4199
4376
|
let weight = 0;
|
|
4200
4377
|
if (effectiveM === 0) {
|
|
@@ -4208,13 +4385,13 @@ function mergeAlphaMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4208
4385
|
}
|
|
4209
4386
|
if (weight !== 255) {
|
|
4210
4387
|
if (weight === 0) {
|
|
4211
|
-
|
|
4388
|
+
dstData[dIdx] = 0;
|
|
4212
4389
|
} else {
|
|
4213
|
-
const da =
|
|
4390
|
+
const da = dstData[dIdx];
|
|
4214
4391
|
if (da === 255) {
|
|
4215
|
-
|
|
4392
|
+
dstData[dIdx] = weight;
|
|
4216
4393
|
} else if (da !== 0) {
|
|
4217
|
-
|
|
4394
|
+
dstData[dIdx] = da * weight + 128 >> 8;
|
|
4218
4395
|
}
|
|
4219
4396
|
}
|
|
4220
4397
|
}
|
|
@@ -4225,7 +4402,7 @@ function mergeAlphaMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4225
4402
|
}
|
|
4226
4403
|
|
|
4227
4404
|
// src/Mask/mergeBinaryMasks.ts
|
|
4228
|
-
function mergeBinaryMasks(dst,
|
|
4405
|
+
function mergeBinaryMasks(dst, src, opts) {
|
|
4229
4406
|
const {
|
|
4230
4407
|
x: targetX = 0,
|
|
4231
4408
|
y: targetY = 0,
|
|
@@ -4235,10 +4412,12 @@ function mergeBinaryMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4235
4412
|
my = 0,
|
|
4236
4413
|
invertMask = false
|
|
4237
4414
|
} = opts;
|
|
4415
|
+
const dstData = dst.data;
|
|
4416
|
+
const srcData = src.data;
|
|
4417
|
+
const srcWidth = src.w;
|
|
4418
|
+
const dstWidth = dst.w;
|
|
4238
4419
|
if (dstWidth <= 0) return;
|
|
4239
4420
|
if (srcWidth <= 0) return;
|
|
4240
|
-
const dstHeight = dst.length / dstWidth | 0;
|
|
4241
|
-
const srcHeight = src.length / srcWidth | 0;
|
|
4242
4421
|
let x = targetX;
|
|
4243
4422
|
let y = targetY;
|
|
4244
4423
|
let w = width;
|
|
@@ -4252,7 +4431,7 @@ function mergeBinaryMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4252
4431
|
y = 0;
|
|
4253
4432
|
}
|
|
4254
4433
|
w = Math.min(w, dstWidth - x);
|
|
4255
|
-
h = Math.min(h,
|
|
4434
|
+
h = Math.min(h, dst.h - y);
|
|
4256
4435
|
if (w <= 0) return;
|
|
4257
4436
|
if (h <= 0) return;
|
|
4258
4437
|
const startX = mx + (x - targetX);
|
|
@@ -4260,7 +4439,7 @@ function mergeBinaryMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4260
4439
|
const sX0 = Math.max(0, startX);
|
|
4261
4440
|
const sY0 = Math.max(0, startY);
|
|
4262
4441
|
const sX1 = Math.min(srcWidth, startX + w);
|
|
4263
|
-
const sY1 = Math.min(
|
|
4442
|
+
const sY1 = Math.min(src.h, startY + h);
|
|
4264
4443
|
const finalW = sX1 - sX0;
|
|
4265
4444
|
const finalH = sY1 - sY0;
|
|
4266
4445
|
if (finalW <= 0) return;
|
|
@@ -4273,10 +4452,10 @@ function mergeBinaryMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4273
4452
|
let sIdx = sY0 * srcWidth + sX0;
|
|
4274
4453
|
for (let iy = 0; iy < finalH; iy++) {
|
|
4275
4454
|
for (let ix = 0; ix < finalW; ix++) {
|
|
4276
|
-
const mVal =
|
|
4455
|
+
const mVal = srcData[sIdx];
|
|
4277
4456
|
const isMaskedOut = invertMask ? mVal !== 0 : mVal === 0;
|
|
4278
4457
|
if (isMaskedOut) {
|
|
4279
|
-
|
|
4458
|
+
dstData[dIdx] = 0;
|
|
4280
4459
|
}
|
|
4281
4460
|
dIdx++;
|
|
4282
4461
|
sIdx++;
|
|
@@ -4286,6 +4465,177 @@ function mergeBinaryMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4286
4465
|
}
|
|
4287
4466
|
}
|
|
4288
4467
|
|
|
4468
|
+
// src/Mask/setMaskData.ts
|
|
4469
|
+
function setMaskData(mask, width, height, data) {
|
|
4470
|
+
;
|
|
4471
|
+
mask.w = width;
|
|
4472
|
+
mask.h = height;
|
|
4473
|
+
mask.data = data;
|
|
4474
|
+
}
|
|
4475
|
+
|
|
4476
|
+
// src/MaskRect/subtractBinaryMaskRects.ts
|
|
4477
|
+
function subtractBinaryMaskRects(current, subtracting) {
|
|
4478
|
+
let result = [...current];
|
|
4479
|
+
for (const sub of subtracting) {
|
|
4480
|
+
const next = [];
|
|
4481
|
+
for (const r of result) {
|
|
4482
|
+
const ix = Math.max(r.x, sub.x);
|
|
4483
|
+
const iy = Math.max(r.y, sub.y);
|
|
4484
|
+
const ix2 = Math.min(r.x + r.w, sub.x + sub.w);
|
|
4485
|
+
const iy2 = Math.min(r.y + r.h, sub.y + sub.h);
|
|
4486
|
+
if (ix >= ix2 || iy >= iy2) {
|
|
4487
|
+
next.push(r);
|
|
4488
|
+
continue;
|
|
4489
|
+
}
|
|
4490
|
+
if (r.y < iy) pushPiece(next, r, r.x, r.y, r.w, iy - r.y);
|
|
4491
|
+
if (iy2 < r.y + r.h) pushPiece(next, r, r.x, iy2, r.w, r.y + r.h - iy2);
|
|
4492
|
+
if (r.x < ix) pushPiece(next, r, r.x, iy, ix - r.x, iy2 - iy);
|
|
4493
|
+
if (ix2 < r.x + r.w) pushPiece(next, r, ix2, iy, r.x + r.w - ix2, iy2 - iy);
|
|
4494
|
+
}
|
|
4495
|
+
result = next;
|
|
4496
|
+
}
|
|
4497
|
+
return result;
|
|
4498
|
+
}
|
|
4499
|
+
function pushPiece(dest, r, x, y, w, h) {
|
|
4500
|
+
if (r.data === null || r.data === void 0) {
|
|
4501
|
+
dest.push({
|
|
4502
|
+
x,
|
|
4503
|
+
y,
|
|
4504
|
+
w,
|
|
4505
|
+
h,
|
|
4506
|
+
data: null,
|
|
4507
|
+
type: null
|
|
4508
|
+
});
|
|
4509
|
+
return;
|
|
4510
|
+
}
|
|
4511
|
+
const lx = x - r.x;
|
|
4512
|
+
const ly = y - r.y;
|
|
4513
|
+
const data = new Uint8Array(w * h);
|
|
4514
|
+
for (let row = 0; row < h; row++) {
|
|
4515
|
+
data.set(r.data.subarray((ly + row) * r.w + lx, (ly + row) * r.w + lx + w), row * w);
|
|
4516
|
+
}
|
|
4517
|
+
dest.push({
|
|
4518
|
+
x,
|
|
4519
|
+
y,
|
|
4520
|
+
w,
|
|
4521
|
+
h,
|
|
4522
|
+
data,
|
|
4523
|
+
type: 1 /* BINARY */
|
|
4524
|
+
});
|
|
4525
|
+
}
|
|
4526
|
+
|
|
4527
|
+
// src/Rect/getRectsBounds.ts
|
|
4528
|
+
function getRectsBounds(rects) {
|
|
4529
|
+
if (rects.length === 1) return {
|
|
4530
|
+
...rects[0]
|
|
4531
|
+
};
|
|
4532
|
+
let minX = Infinity, minY = Infinity;
|
|
4533
|
+
let maxX = -Infinity, maxY = -Infinity;
|
|
4534
|
+
for (let i = 0; i < rects.length; i++) {
|
|
4535
|
+
const r = rects[i];
|
|
4536
|
+
const x1 = r.x;
|
|
4537
|
+
const y1 = r.y;
|
|
4538
|
+
const x2 = x1 + r.w;
|
|
4539
|
+
const y2 = y1 + r.h;
|
|
4540
|
+
if (x1 < minX) minX = x1;
|
|
4541
|
+
if (y1 < minY) minY = y1;
|
|
4542
|
+
if (x2 > maxX) maxX = x2;
|
|
4543
|
+
if (y2 > maxY) maxY = y2;
|
|
4544
|
+
}
|
|
4545
|
+
return {
|
|
4546
|
+
x: minX,
|
|
4547
|
+
y: minY,
|
|
4548
|
+
w: maxX - minX,
|
|
4549
|
+
h: maxY - minY
|
|
4550
|
+
};
|
|
4551
|
+
}
|
|
4552
|
+
|
|
4553
|
+
// src/MaskRect/merge2BinaryMaskRects.ts
|
|
4554
|
+
function merge2BinaryMaskRects(a, b) {
|
|
4555
|
+
const bounds = getRectsBounds([a, b]);
|
|
4556
|
+
if ((a.data === null || a.data === void 0) && (b.data === null || b.data === void 0)) {
|
|
4557
|
+
const ix = Math.max(a.x, b.x);
|
|
4558
|
+
const iy = Math.max(a.y, b.y);
|
|
4559
|
+
const ir = Math.min(a.x + a.w, b.x + b.w);
|
|
4560
|
+
const ib = Math.min(a.y + a.h, b.y + b.h);
|
|
4561
|
+
const iw = Math.max(0, ir - ix);
|
|
4562
|
+
const ih = Math.max(0, ib - iy);
|
|
4563
|
+
const intersectionArea = iw * ih;
|
|
4564
|
+
const areaA = a.w * a.h;
|
|
4565
|
+
const areaB = b.w * b.h;
|
|
4566
|
+
const boundsArea = bounds.w * bounds.h;
|
|
4567
|
+
if (boundsArea === areaA + areaB - intersectionArea) {
|
|
4568
|
+
return {
|
|
4569
|
+
...bounds,
|
|
4570
|
+
data: null,
|
|
4571
|
+
type: null
|
|
4572
|
+
};
|
|
4573
|
+
}
|
|
4574
|
+
}
|
|
4575
|
+
const maskData = new Uint8Array(bounds.w * bounds.h);
|
|
4576
|
+
const aOffY = a.y - bounds.y;
|
|
4577
|
+
const aOffX = a.x - bounds.x;
|
|
4578
|
+
if (a.data === void 0 || a.data === null) {
|
|
4579
|
+
for (let ay = 0; ay < a.h; ay++) {
|
|
4580
|
+
const destRow = (aOffY + ay) * bounds.w + aOffX;
|
|
4581
|
+
maskData.fill(1, destRow, destRow + a.w);
|
|
4582
|
+
}
|
|
4583
|
+
} else {
|
|
4584
|
+
for (let ay = 0; ay < a.h; ay++) {
|
|
4585
|
+
const srcRow = ay * a.w;
|
|
4586
|
+
const destRow = (aOffY + ay) * bounds.w + aOffX;
|
|
4587
|
+
maskData.set(a.data.subarray(srcRow, srcRow + a.w), destRow);
|
|
4588
|
+
}
|
|
4589
|
+
}
|
|
4590
|
+
const bOffY = b.y - bounds.y;
|
|
4591
|
+
const bOffX = b.x - bounds.x;
|
|
4592
|
+
if (b.data === void 0 || b.data === null) {
|
|
4593
|
+
for (let by = 0; by < b.h; by++) {
|
|
4594
|
+
const destRow = (bOffY + by) * bounds.w + bOffX;
|
|
4595
|
+
maskData.fill(1, destRow, destRow + b.w);
|
|
4596
|
+
}
|
|
4597
|
+
} else {
|
|
4598
|
+
for (let by = 0; by < b.h; by++) {
|
|
4599
|
+
const srcRow = by * b.w;
|
|
4600
|
+
const destRow = (bOffY + by) * bounds.w + bOffX;
|
|
4601
|
+
for (let bx = 0; bx < b.w; bx++) {
|
|
4602
|
+
maskData[destRow + bx] |= b.data[srcRow + bx];
|
|
4603
|
+
}
|
|
4604
|
+
}
|
|
4605
|
+
}
|
|
4606
|
+
return {
|
|
4607
|
+
...bounds,
|
|
4608
|
+
data: maskData,
|
|
4609
|
+
type: 1 /* BINARY */
|
|
4610
|
+
};
|
|
4611
|
+
}
|
|
4612
|
+
|
|
4613
|
+
// src/MaskRect/mergeBinaryMaskRects.ts
|
|
4614
|
+
function mergeBinaryMaskRects(current, adding) {
|
|
4615
|
+
const rects = [...current, ...adding];
|
|
4616
|
+
let changed = true;
|
|
4617
|
+
while (changed) {
|
|
4618
|
+
changed = false;
|
|
4619
|
+
const next = [];
|
|
4620
|
+
for (const r of rects) {
|
|
4621
|
+
let merged = false;
|
|
4622
|
+
for (let i = 0; i < next.length; i++) {
|
|
4623
|
+
const n = next[i];
|
|
4624
|
+
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;
|
|
4625
|
+
if (overlap) {
|
|
4626
|
+
next[i] = merge2BinaryMaskRects(n, r);
|
|
4627
|
+
merged = true;
|
|
4628
|
+
changed = true;
|
|
4629
|
+
break;
|
|
4630
|
+
}
|
|
4631
|
+
}
|
|
4632
|
+
if (!merged) next.push(r);
|
|
4633
|
+
}
|
|
4634
|
+
rects.splice(0, rects.length, ...next);
|
|
4635
|
+
}
|
|
4636
|
+
return rects;
|
|
4637
|
+
}
|
|
4638
|
+
|
|
4289
4639
|
// src/PixelData/PixelData.ts
|
|
4290
4640
|
var PixelData = class _PixelData {
|
|
4291
4641
|
data32;
|
|
@@ -4337,7 +4687,6 @@ function blendPixelDataAlphaMask(dst, src, alphaMask, opts = {}) {
|
|
|
4337
4687
|
h: height = src.height,
|
|
4338
4688
|
alpha: globalAlpha = 255,
|
|
4339
4689
|
blendFn = sourceOverPerfect,
|
|
4340
|
-
mw = src.width,
|
|
4341
4690
|
mx = 0,
|
|
4342
4691
|
my = 0,
|
|
4343
4692
|
invertMask = false
|
|
@@ -4376,7 +4725,8 @@ function blendPixelDataAlphaMask(dst, src, alphaMask, opts = {}) {
|
|
|
4376
4725
|
if (actualW <= 0 || actualH <= 0) return;
|
|
4377
4726
|
const dw = dst.width;
|
|
4378
4727
|
const sw = src.width;
|
|
4379
|
-
const mPitch =
|
|
4728
|
+
const mPitch = alphaMask.w;
|
|
4729
|
+
const maskData = alphaMask.data;
|
|
4380
4730
|
const dx = x - targetX | 0;
|
|
4381
4731
|
const dy = y - targetY | 0;
|
|
4382
4732
|
const dst32 = dst.data32;
|
|
@@ -4391,7 +4741,7 @@ function blendPixelDataAlphaMask(dst, src, alphaMask, opts = {}) {
|
|
|
4391
4741
|
const isOverwrite = blendFn.isOverwrite || false;
|
|
4392
4742
|
for (let iy = 0; iy < actualH; iy++) {
|
|
4393
4743
|
for (let ix = 0; ix < actualW; ix++) {
|
|
4394
|
-
const mVal =
|
|
4744
|
+
const mVal = maskData[mIdx];
|
|
4395
4745
|
const effM = invertMask ? 255 - mVal : mVal;
|
|
4396
4746
|
if (effM === 0) {
|
|
4397
4747
|
dIdx++;
|
|
@@ -4452,7 +4802,6 @@ function blendPixelDataBinaryMask(dst, src, binaryMask, opts) {
|
|
|
4452
4802
|
h: height = src.height,
|
|
4453
4803
|
alpha: globalAlpha = 255,
|
|
4454
4804
|
blendFn = sourceOverPerfect,
|
|
4455
|
-
mw = src.width,
|
|
4456
4805
|
mx = 0,
|
|
4457
4806
|
my = 0,
|
|
4458
4807
|
invertMask = false
|
|
@@ -4495,7 +4844,8 @@ function blendPixelDataBinaryMask(dst, src, binaryMask, opts) {
|
|
|
4495
4844
|
const src32 = src.data32;
|
|
4496
4845
|
const dw = dst.width;
|
|
4497
4846
|
const sw = src.width;
|
|
4498
|
-
const mPitch =
|
|
4847
|
+
const mPitch = binaryMask.w;
|
|
4848
|
+
const maskData = binaryMask.data;
|
|
4499
4849
|
let dIdx = y * dw + x | 0;
|
|
4500
4850
|
let sIdx = sy * sw + sx | 0;
|
|
4501
4851
|
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
@@ -4507,7 +4857,7 @@ function blendPixelDataBinaryMask(dst, src, binaryMask, opts) {
|
|
|
4507
4857
|
const isOverwrite = blendFn.isOverwrite || false;
|
|
4508
4858
|
for (let iy = 0; iy < actualH; iy++) {
|
|
4509
4859
|
for (let ix = 0; ix < actualW; ix++) {
|
|
4510
|
-
if (
|
|
4860
|
+
if (maskData[mIdx] === skipVal) {
|
|
4511
4861
|
dIdx++;
|
|
4512
4862
|
sIdx++;
|
|
4513
4863
|
mIdx++;
|
|
@@ -4635,10 +4985,11 @@ function pixelDataToAlphaMask(pixelData) {
|
|
|
4635
4985
|
height
|
|
4636
4986
|
} = pixelData;
|
|
4637
4987
|
const len = data32.length;
|
|
4638
|
-
const mask =
|
|
4988
|
+
const mask = makeAlphaMask(width, height);
|
|
4989
|
+
const maskData = mask.data;
|
|
4639
4990
|
for (let i = 0; i < len; i++) {
|
|
4640
4991
|
const val = data32[i];
|
|
4641
|
-
|
|
4992
|
+
maskData[i] = val >>> 24 & 255;
|
|
4642
4993
|
}
|
|
4643
4994
|
return mask;
|
|
4644
4995
|
}
|
|
@@ -4820,11 +5171,13 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
4820
5171
|
exclusionPerfect,
|
|
4821
5172
|
extractImageDataBuffer,
|
|
4822
5173
|
extractMask,
|
|
5174
|
+
extractMaskBuffer,
|
|
4823
5175
|
extractPixelData,
|
|
4824
5176
|
extractPixelDataBuffer,
|
|
4825
5177
|
fileInputChangeToImageData,
|
|
4826
5178
|
fileToImageData,
|
|
4827
5179
|
fillPixelData,
|
|
5180
|
+
fillPixelDataBinaryMask,
|
|
4828
5181
|
floodFillSelection,
|
|
4829
5182
|
forEachLinePoint,
|
|
4830
5183
|
getCircleBrushOrPencilBounds,
|
|
@@ -4833,12 +5186,13 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
4833
5186
|
getIndexedImageColorCounts,
|
|
4834
5187
|
getRectBrushOrPencilBounds,
|
|
4835
5188
|
getRectBrushOrPencilStrokeBounds,
|
|
5189
|
+
getRectsBounds,
|
|
4836
5190
|
getSupportedPixelFormats,
|
|
4837
5191
|
hardLightFast,
|
|
4838
5192
|
hardLightPerfect,
|
|
4839
5193
|
hardMixFast,
|
|
4840
5194
|
hardMixPerfect,
|
|
4841
|
-
|
|
5195
|
+
imageDataToAlphaMaskBuffer,
|
|
4842
5196
|
imageDataToDataUrl,
|
|
4843
5197
|
imageDataToImgBlob,
|
|
4844
5198
|
imageDataToUInt32Array,
|
|
@@ -4861,7 +5215,11 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
4861
5215
|
linearDodgePerfect,
|
|
4862
5216
|
linearLightFast,
|
|
4863
5217
|
linearLightPerfect,
|
|
5218
|
+
makeAlphaMask,
|
|
5219
|
+
makeBinaryMask,
|
|
4864
5220
|
makeBlendModeRegistry,
|
|
5221
|
+
makeCircleBrushAlphaMask,
|
|
5222
|
+
makeCircleBrushBinaryMask,
|
|
4865
5223
|
makeFastBlendModeRegistry,
|
|
4866
5224
|
makeFullPixelMutator,
|
|
4867
5225
|
makeImageDataLike,
|
|
@@ -4869,7 +5227,9 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
4869
5227
|
makePixelCanvas,
|
|
4870
5228
|
makeReusableCanvas,
|
|
4871
5229
|
makeReusableImageData,
|
|
5230
|
+
merge2BinaryMaskRects,
|
|
4872
5231
|
mergeAlphaMasks,
|
|
5232
|
+
mergeBinaryMaskRects,
|
|
4873
5233
|
mergeBinaryMasks,
|
|
4874
5234
|
multiplyFast,
|
|
4875
5235
|
multiplyPerfect,
|
|
@@ -4888,6 +5248,7 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
4888
5248
|
mutatorBlendPixelData,
|
|
4889
5249
|
mutatorClear,
|
|
4890
5250
|
mutatorFill,
|
|
5251
|
+
mutatorFillBinaryMask,
|
|
4891
5252
|
mutatorInvert,
|
|
4892
5253
|
overlayFast,
|
|
4893
5254
|
overlayPerfect,
|
|
@@ -4910,10 +5271,12 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
4910
5271
|
screenPerfect,
|
|
4911
5272
|
serializeImageData,
|
|
4912
5273
|
serializeNullableImageData,
|
|
5274
|
+
setMaskData,
|
|
4913
5275
|
softLightFast,
|
|
4914
5276
|
softLightPerfect,
|
|
4915
5277
|
sourceOverFast,
|
|
4916
5278
|
sourceOverPerfect,
|
|
5279
|
+
subtractBinaryMaskRects,
|
|
4917
5280
|
subtractFast,
|
|
4918
5281
|
subtractPerfect,
|
|
4919
5282
|
toBlendModeIndexAndName,
|