pixel-data-js 0.20.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 +722 -357
- package/dist/index.dev.cjs.map +1 -1
- package/dist/index.dev.js +709 -356
- package/dist/index.dev.js.map +1 -1
- package/dist/index.prod.cjs +722 -357
- package/dist/index.prod.cjs.map +1 -1
- package/dist/index.prod.d.ts +283 -128
- package/dist/index.prod.js +709 -356
- 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 +11 -8
- package/src/History/PixelMutator/mutatorFill.ts +4 -0
- 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/clearPixelData.ts +2 -2
- 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,12 +3320,10 @@ 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
|
-
} = 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;
|
|
3331
3327
|
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3332
3328
|
fillPixelData2(writer.target, 0, x, y, w, h);
|
|
3333
3329
|
}
|
|
@@ -3366,7 +3362,6 @@ function invertPixelData(pixelData, opts = {}) {
|
|
|
3366
3362
|
w: width = pixelData.width,
|
|
3367
3363
|
h: height = pixelData.height,
|
|
3368
3364
|
mask,
|
|
3369
|
-
mw,
|
|
3370
3365
|
mx = 0,
|
|
3371
3366
|
my = 0,
|
|
3372
3367
|
invertMask = false
|
|
@@ -3381,7 +3376,7 @@ function invertPixelData(pixelData, opts = {}) {
|
|
|
3381
3376
|
} = clip;
|
|
3382
3377
|
const dst32 = dst.data32;
|
|
3383
3378
|
const dw = dst.width;
|
|
3384
|
-
const mPitch =
|
|
3379
|
+
const mPitch = mask?.w ?? width;
|
|
3385
3380
|
const dx = x - targetX;
|
|
3386
3381
|
const dy = y - targetY;
|
|
3387
3382
|
let dIdx = y * dw + x;
|
|
@@ -3389,9 +3384,10 @@ function invertPixelData(pixelData, opts = {}) {
|
|
|
3389
3384
|
const dStride = dw - actualW;
|
|
3390
3385
|
const mStride = mPitch - actualW;
|
|
3391
3386
|
if (mask) {
|
|
3387
|
+
const maskData = mask.data;
|
|
3392
3388
|
for (let iy = 0; iy < actualH; iy++) {
|
|
3393
3389
|
for (let ix = 0; ix < actualW; ix++) {
|
|
3394
|
-
const mVal =
|
|
3390
|
+
const mVal = maskData[mIdx];
|
|
3395
3391
|
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
3396
3392
|
if (isHit) {
|
|
3397
3393
|
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
@@ -3502,14 +3498,12 @@ var PixelWriter = class {
|
|
|
3502
3498
|
// src/History/PixelMutator/mutatorApplyCirclePencil.ts
|
|
3503
3499
|
var defaults15 = {
|
|
3504
3500
|
applyCircleBrushToPixelData,
|
|
3505
|
-
getCircleBrushOrPencilBounds
|
|
3506
|
-
fallOff: () => 1
|
|
3501
|
+
getCircleBrushOrPencilBounds
|
|
3507
3502
|
};
|
|
3508
3503
|
var mutatorApplyCirclePencil = ((writer, deps = defaults15) => {
|
|
3509
3504
|
const {
|
|
3510
3505
|
applyCircleBrushToPixelData: applyCircleBrushToPixelData2 = defaults15.applyCircleBrushToPixelData,
|
|
3511
|
-
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults15.getCircleBrushOrPencilBounds
|
|
3512
|
-
fallOff = defaults15.fallOff
|
|
3506
|
+
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults15.getCircleBrushOrPencilBounds
|
|
3513
3507
|
} = deps;
|
|
3514
3508
|
const boundsOut = {
|
|
3515
3509
|
x: 0,
|
|
@@ -3518,8 +3512,8 @@ var mutatorApplyCirclePencil = ((writer, deps = defaults15) => {
|
|
|
3518
3512
|
h: 0
|
|
3519
3513
|
};
|
|
3520
3514
|
return {
|
|
3521
|
-
applyCirclePencil(color, centerX, centerY,
|
|
3522
|
-
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);
|
|
3523
3517
|
const {
|
|
3524
3518
|
x,
|
|
3525
3519
|
y,
|
|
@@ -3527,7 +3521,63 @@ var mutatorApplyCirclePencil = ((writer, deps = defaults15) => {
|
|
|
3527
3521
|
h
|
|
3528
3522
|
} = bounds;
|
|
3529
3523
|
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3530
|
-
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);
|
|
3531
3581
|
}
|
|
3532
3582
|
};
|
|
3533
3583
|
});
|
|
@@ -3563,8 +3613,8 @@ function makeImageDataLike(width, height, data) {
|
|
|
3563
3613
|
};
|
|
3564
3614
|
}
|
|
3565
3615
|
|
|
3566
|
-
// src/ImageData/
|
|
3567
|
-
function
|
|
3616
|
+
// src/ImageData/imageDataToAlphaMaskBuffer.ts
|
|
3617
|
+
function imageDataToAlphaMaskBuffer(imageData) {
|
|
3568
3618
|
const {
|
|
3569
3619
|
width,
|
|
3570
3620
|
height,
|
|
@@ -3654,13 +3704,13 @@ function resampleImageData(source, factor) {
|
|
|
3654
3704
|
}
|
|
3655
3705
|
|
|
3656
3706
|
// src/ImageData/resizeImageData.ts
|
|
3657
|
-
function resizeImageData(
|
|
3707
|
+
function resizeImageData(target, newWidth, newHeight, offsetX = 0, offsetY = 0) {
|
|
3658
3708
|
const result = new ImageData(newWidth, newHeight);
|
|
3659
3709
|
const {
|
|
3660
3710
|
width: oldW,
|
|
3661
3711
|
height: oldH,
|
|
3662
3712
|
data: oldData
|
|
3663
|
-
} =
|
|
3713
|
+
} = target;
|
|
3664
3714
|
const newData = result.data;
|
|
3665
3715
|
const x0 = Math.max(0, offsetX);
|
|
3666
3716
|
const y0 = Math.max(0, offsetY);
|
|
@@ -3815,7 +3865,7 @@ function writeImageData(target, source, x, y, sx = 0, sy = 0, sw = source.width,
|
|
|
3815
3865
|
|
|
3816
3866
|
// src/ImageData/writeImageDataBuffer.ts
|
|
3817
3867
|
var SCRATCH_BLIT3 = makeClippedBlit();
|
|
3818
|
-
function writeImageDataBuffer(
|
|
3868
|
+
function writeImageDataBuffer(target, data, _x, _y, _w, _h) {
|
|
3819
3869
|
const {
|
|
3820
3870
|
x,
|
|
3821
3871
|
y,
|
|
@@ -3831,7 +3881,7 @@ function writeImageDataBuffer(imageData, data, _x, _y, _w, _h) {
|
|
|
3831
3881
|
width: dstW,
|
|
3832
3882
|
height: dstH,
|
|
3833
3883
|
data: dst
|
|
3834
|
-
} =
|
|
3884
|
+
} = target;
|
|
3835
3885
|
const clip = resolveBlitClipping(x, y, 0, 0, w, h, dstW, dstH, w, h, SCRATCH_BLIT3);
|
|
3836
3886
|
if (!clip.inBounds) return;
|
|
3837
3887
|
const {
|
|
@@ -4077,8 +4127,84 @@ async function getSupportedPixelFormats(rasterMimes = defaultRasterMimes) {
|
|
|
4077
4127
|
return formatsPromise;
|
|
4078
4128
|
}
|
|
4079
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
|
+
|
|
4080
4206
|
// src/Mask/applyBinaryMaskToAlphaMask.ts
|
|
4081
|
-
function applyBinaryMaskToAlphaMask(alphaMaskDst,
|
|
4207
|
+
function applyBinaryMaskToAlphaMask(alphaMaskDst, binaryMaskSrc, opts = {}) {
|
|
4082
4208
|
const {
|
|
4083
4209
|
x: targetX = 0,
|
|
4084
4210
|
y: targetY = 0,
|
|
@@ -4088,11 +4214,13 @@ function applyBinaryMaskToAlphaMask(alphaMaskDst, dstWidth, binaryMaskSrc, srcWi
|
|
|
4088
4214
|
my = 0,
|
|
4089
4215
|
invertMask = false
|
|
4090
4216
|
} = opts;
|
|
4217
|
+
const dstWidth = alphaMaskDst.w;
|
|
4091
4218
|
if (dstWidth <= 0) return;
|
|
4092
|
-
if (binaryMaskSrc.length === 0) return;
|
|
4219
|
+
if (binaryMaskSrc.data.length === 0) return;
|
|
4220
|
+
const srcWidth = binaryMaskSrc.w;
|
|
4093
4221
|
if (srcWidth <= 0) return;
|
|
4094
|
-
const dstHeight = alphaMaskDst.length / dstWidth | 0;
|
|
4095
|
-
const srcHeight = binaryMaskSrc.length / srcWidth | 0;
|
|
4222
|
+
const dstHeight = alphaMaskDst.data.length / dstWidth | 0;
|
|
4223
|
+
const srcHeight = binaryMaskSrc.data.length / srcWidth | 0;
|
|
4096
4224
|
if (dstHeight <= 0) return;
|
|
4097
4225
|
if (srcHeight <= 0) return;
|
|
4098
4226
|
const dstX0 = Math.max(0, targetX);
|
|
@@ -4109,6 +4237,8 @@ function applyBinaryMaskToAlphaMask(alphaMaskDst, dstWidth, binaryMaskSrc, srcWi
|
|
|
4109
4237
|
if (srcY0 + (dstY1 - dstY0) <= 0) return;
|
|
4110
4238
|
const iterW = Math.min(dstX1 - dstX0, srcWidth - srcX0);
|
|
4111
4239
|
const iterH = Math.min(dstY1 - dstY0, srcHeight - srcY0);
|
|
4240
|
+
const srcData = binaryMaskSrc.data;
|
|
4241
|
+
const dstData = alphaMaskDst.data;
|
|
4112
4242
|
let dstIdx = dstY0 * dstWidth + dstX0;
|
|
4113
4243
|
let srcIdx = srcY0 * srcWidth + srcX0;
|
|
4114
4244
|
if (invertMask) {
|
|
@@ -4117,8 +4247,8 @@ function applyBinaryMaskToAlphaMask(alphaMaskDst, dstWidth, binaryMaskSrc, srcWi
|
|
|
4117
4247
|
let d = dstIdx;
|
|
4118
4248
|
let s = srcIdx;
|
|
4119
4249
|
while (d < dstEnd) {
|
|
4120
|
-
if (
|
|
4121
|
-
|
|
4250
|
+
if (srcData[s] !== 0) {
|
|
4251
|
+
dstData[d] = 0;
|
|
4122
4252
|
}
|
|
4123
4253
|
d++;
|
|
4124
4254
|
s++;
|
|
@@ -4132,8 +4262,8 @@ function applyBinaryMaskToAlphaMask(alphaMaskDst, dstWidth, binaryMaskSrc, srcWi
|
|
|
4132
4262
|
let d = dstIdx;
|
|
4133
4263
|
let s = srcIdx;
|
|
4134
4264
|
while (d < dstEnd) {
|
|
4135
|
-
if (
|
|
4136
|
-
|
|
4265
|
+
if (srcData[s] === 0) {
|
|
4266
|
+
dstData[d] = 0;
|
|
4137
4267
|
}
|
|
4138
4268
|
d++;
|
|
4139
4269
|
s++;
|
|
@@ -4146,25 +4276,72 @@ function applyBinaryMaskToAlphaMask(alphaMaskDst, dstWidth, binaryMaskSrc, srcWi
|
|
|
4146
4276
|
|
|
4147
4277
|
// src/Mask/copyMask.ts
|
|
4148
4278
|
function copyMask(src) {
|
|
4149
|
-
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;
|
|
4150
4325
|
}
|
|
4151
4326
|
|
|
4152
4327
|
// src/Mask/invertMask.ts
|
|
4153
4328
|
function invertBinaryMask(dst) {
|
|
4154
|
-
const
|
|
4329
|
+
const data = dst.data;
|
|
4330
|
+
const len = data.length;
|
|
4155
4331
|
for (let i = 0; i < len; i++) {
|
|
4156
|
-
|
|
4332
|
+
data[i] = data[i] === 0 ? 1 : 0;
|
|
4157
4333
|
}
|
|
4158
4334
|
}
|
|
4159
4335
|
function invertAlphaMask(dst) {
|
|
4160
|
-
const
|
|
4336
|
+
const data = dst.data;
|
|
4337
|
+
const len = data.length;
|
|
4161
4338
|
for (let i = 0; i < len; i++) {
|
|
4162
|
-
|
|
4339
|
+
data[i] = 255 - data[i];
|
|
4163
4340
|
}
|
|
4164
4341
|
}
|
|
4165
4342
|
|
|
4166
4343
|
// src/Mask/mergeAlphaMasks.ts
|
|
4167
|
-
function mergeAlphaMasks(dst,
|
|
4344
|
+
function mergeAlphaMasks(dst, src, opts) {
|
|
4168
4345
|
const {
|
|
4169
4346
|
x: targetX = 0,
|
|
4170
4347
|
y: targetY = 0,
|
|
@@ -4175,15 +4352,17 @@ function mergeAlphaMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4175
4352
|
my = 0,
|
|
4176
4353
|
invertMask = false
|
|
4177
4354
|
} = opts;
|
|
4178
|
-
const dstHeight = dst.length / dstWidth | 0;
|
|
4179
|
-
const srcHeight = src.length / srcWidth | 0;
|
|
4180
4355
|
if (width <= 0) return;
|
|
4181
4356
|
if (height <= 0) return;
|
|
4182
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;
|
|
4183
4362
|
const startX = Math.max(0, -targetX, -mx);
|
|
4184
4363
|
const startY = Math.max(0, -targetY, -my);
|
|
4185
4364
|
const endX = Math.min(width, dstWidth - targetX, srcWidth - mx);
|
|
4186
|
-
const endY = Math.min(height,
|
|
4365
|
+
const endY = Math.min(height, dst.h - targetY, src.h - my);
|
|
4187
4366
|
if (startX >= endX) return;
|
|
4188
4367
|
if (startY >= endY) return;
|
|
4189
4368
|
for (let iy = startY; iy < endY; iy++) {
|
|
@@ -4192,7 +4371,7 @@ function mergeAlphaMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4192
4371
|
let dIdx = dy * dstWidth + targetX + startX;
|
|
4193
4372
|
let sIdx = sy * srcWidth + mx + startX;
|
|
4194
4373
|
for (let ix = startX; ix < endX; ix++) {
|
|
4195
|
-
const rawM =
|
|
4374
|
+
const rawM = srcData[sIdx];
|
|
4196
4375
|
const effectiveM = invertMask ? 255 - rawM : rawM;
|
|
4197
4376
|
let weight = 0;
|
|
4198
4377
|
if (effectiveM === 0) {
|
|
@@ -4206,13 +4385,13 @@ function mergeAlphaMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4206
4385
|
}
|
|
4207
4386
|
if (weight !== 255) {
|
|
4208
4387
|
if (weight === 0) {
|
|
4209
|
-
|
|
4388
|
+
dstData[dIdx] = 0;
|
|
4210
4389
|
} else {
|
|
4211
|
-
const da =
|
|
4390
|
+
const da = dstData[dIdx];
|
|
4212
4391
|
if (da === 255) {
|
|
4213
|
-
|
|
4392
|
+
dstData[dIdx] = weight;
|
|
4214
4393
|
} else if (da !== 0) {
|
|
4215
|
-
|
|
4394
|
+
dstData[dIdx] = da * weight + 128 >> 8;
|
|
4216
4395
|
}
|
|
4217
4396
|
}
|
|
4218
4397
|
}
|
|
@@ -4223,7 +4402,7 @@ function mergeAlphaMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4223
4402
|
}
|
|
4224
4403
|
|
|
4225
4404
|
// src/Mask/mergeBinaryMasks.ts
|
|
4226
|
-
function mergeBinaryMasks(dst,
|
|
4405
|
+
function mergeBinaryMasks(dst, src, opts) {
|
|
4227
4406
|
const {
|
|
4228
4407
|
x: targetX = 0,
|
|
4229
4408
|
y: targetY = 0,
|
|
@@ -4233,10 +4412,12 @@ function mergeBinaryMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4233
4412
|
my = 0,
|
|
4234
4413
|
invertMask = false
|
|
4235
4414
|
} = opts;
|
|
4415
|
+
const dstData = dst.data;
|
|
4416
|
+
const srcData = src.data;
|
|
4417
|
+
const srcWidth = src.w;
|
|
4418
|
+
const dstWidth = dst.w;
|
|
4236
4419
|
if (dstWidth <= 0) return;
|
|
4237
4420
|
if (srcWidth <= 0) return;
|
|
4238
|
-
const dstHeight = dst.length / dstWidth | 0;
|
|
4239
|
-
const srcHeight = src.length / srcWidth | 0;
|
|
4240
4421
|
let x = targetX;
|
|
4241
4422
|
let y = targetY;
|
|
4242
4423
|
let w = width;
|
|
@@ -4250,7 +4431,7 @@ function mergeBinaryMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4250
4431
|
y = 0;
|
|
4251
4432
|
}
|
|
4252
4433
|
w = Math.min(w, dstWidth - x);
|
|
4253
|
-
h = Math.min(h,
|
|
4434
|
+
h = Math.min(h, dst.h - y);
|
|
4254
4435
|
if (w <= 0) return;
|
|
4255
4436
|
if (h <= 0) return;
|
|
4256
4437
|
const startX = mx + (x - targetX);
|
|
@@ -4258,7 +4439,7 @@ function mergeBinaryMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4258
4439
|
const sX0 = Math.max(0, startX);
|
|
4259
4440
|
const sY0 = Math.max(0, startY);
|
|
4260
4441
|
const sX1 = Math.min(srcWidth, startX + w);
|
|
4261
|
-
const sY1 = Math.min(
|
|
4442
|
+
const sY1 = Math.min(src.h, startY + h);
|
|
4262
4443
|
const finalW = sX1 - sX0;
|
|
4263
4444
|
const finalH = sY1 - sY0;
|
|
4264
4445
|
if (finalW <= 0) return;
|
|
@@ -4271,10 +4452,10 @@ function mergeBinaryMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4271
4452
|
let sIdx = sY0 * srcWidth + sX0;
|
|
4272
4453
|
for (let iy = 0; iy < finalH; iy++) {
|
|
4273
4454
|
for (let ix = 0; ix < finalW; ix++) {
|
|
4274
|
-
const mVal =
|
|
4455
|
+
const mVal = srcData[sIdx];
|
|
4275
4456
|
const isMaskedOut = invertMask ? mVal !== 0 : mVal === 0;
|
|
4276
4457
|
if (isMaskedOut) {
|
|
4277
|
-
|
|
4458
|
+
dstData[dIdx] = 0;
|
|
4278
4459
|
}
|
|
4279
4460
|
dIdx++;
|
|
4280
4461
|
sIdx++;
|
|
@@ -4284,6 +4465,177 @@ function mergeBinaryMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
|
4284
4465
|
}
|
|
4285
4466
|
}
|
|
4286
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
|
+
|
|
4287
4639
|
// src/PixelData/PixelData.ts
|
|
4288
4640
|
var PixelData = class _PixelData {
|
|
4289
4641
|
data32;
|
|
@@ -4335,7 +4687,6 @@ function blendPixelDataAlphaMask(dst, src, alphaMask, opts = {}) {
|
|
|
4335
4687
|
h: height = src.height,
|
|
4336
4688
|
alpha: globalAlpha = 255,
|
|
4337
4689
|
blendFn = sourceOverPerfect,
|
|
4338
|
-
mw = src.width,
|
|
4339
4690
|
mx = 0,
|
|
4340
4691
|
my = 0,
|
|
4341
4692
|
invertMask = false
|
|
@@ -4374,7 +4725,8 @@ function blendPixelDataAlphaMask(dst, src, alphaMask, opts = {}) {
|
|
|
4374
4725
|
if (actualW <= 0 || actualH <= 0) return;
|
|
4375
4726
|
const dw = dst.width;
|
|
4376
4727
|
const sw = src.width;
|
|
4377
|
-
const mPitch =
|
|
4728
|
+
const mPitch = alphaMask.w;
|
|
4729
|
+
const maskData = alphaMask.data;
|
|
4378
4730
|
const dx = x - targetX | 0;
|
|
4379
4731
|
const dy = y - targetY | 0;
|
|
4380
4732
|
const dst32 = dst.data32;
|
|
@@ -4389,7 +4741,7 @@ function blendPixelDataAlphaMask(dst, src, alphaMask, opts = {}) {
|
|
|
4389
4741
|
const isOverwrite = blendFn.isOverwrite || false;
|
|
4390
4742
|
for (let iy = 0; iy < actualH; iy++) {
|
|
4391
4743
|
for (let ix = 0; ix < actualW; ix++) {
|
|
4392
|
-
const mVal =
|
|
4744
|
+
const mVal = maskData[mIdx];
|
|
4393
4745
|
const effM = invertMask ? 255 - mVal : mVal;
|
|
4394
4746
|
if (effM === 0) {
|
|
4395
4747
|
dIdx++;
|
|
@@ -4450,7 +4802,6 @@ function blendPixelDataBinaryMask(dst, src, binaryMask, opts) {
|
|
|
4450
4802
|
h: height = src.height,
|
|
4451
4803
|
alpha: globalAlpha = 255,
|
|
4452
4804
|
blendFn = sourceOverPerfect,
|
|
4453
|
-
mw = src.width,
|
|
4454
4805
|
mx = 0,
|
|
4455
4806
|
my = 0,
|
|
4456
4807
|
invertMask = false
|
|
@@ -4493,7 +4844,8 @@ function blendPixelDataBinaryMask(dst, src, binaryMask, opts) {
|
|
|
4493
4844
|
const src32 = src.data32;
|
|
4494
4845
|
const dw = dst.width;
|
|
4495
4846
|
const sw = src.width;
|
|
4496
|
-
const mPitch =
|
|
4847
|
+
const mPitch = binaryMask.w;
|
|
4848
|
+
const maskData = binaryMask.data;
|
|
4497
4849
|
let dIdx = y * dw + x | 0;
|
|
4498
4850
|
let sIdx = sy * sw + sx | 0;
|
|
4499
4851
|
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
@@ -4505,7 +4857,7 @@ function blendPixelDataBinaryMask(dst, src, binaryMask, opts) {
|
|
|
4505
4857
|
const isOverwrite = blendFn.isOverwrite || false;
|
|
4506
4858
|
for (let iy = 0; iy < actualH; iy++) {
|
|
4507
4859
|
for (let ix = 0; ix < actualW; ix++) {
|
|
4508
|
-
if (
|
|
4860
|
+
if (maskData[mIdx] === skipVal) {
|
|
4509
4861
|
dIdx++;
|
|
4510
4862
|
sIdx++;
|
|
4511
4863
|
mIdx++;
|
|
@@ -4633,10 +4985,11 @@ function pixelDataToAlphaMask(pixelData) {
|
|
|
4633
4985
|
height
|
|
4634
4986
|
} = pixelData;
|
|
4635
4987
|
const len = data32.length;
|
|
4636
|
-
const mask =
|
|
4988
|
+
const mask = makeAlphaMask(width, height);
|
|
4989
|
+
const maskData = mask.data;
|
|
4637
4990
|
for (let i = 0; i < len; i++) {
|
|
4638
4991
|
const val = data32[i];
|
|
4639
|
-
|
|
4992
|
+
maskData[i] = val >>> 24 & 255;
|
|
4640
4993
|
}
|
|
4641
4994
|
return mask;
|
|
4642
4995
|
}
|
|
@@ -4818,11 +5171,13 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
4818
5171
|
exclusionPerfect,
|
|
4819
5172
|
extractImageDataBuffer,
|
|
4820
5173
|
extractMask,
|
|
5174
|
+
extractMaskBuffer,
|
|
4821
5175
|
extractPixelData,
|
|
4822
5176
|
extractPixelDataBuffer,
|
|
4823
5177
|
fileInputChangeToImageData,
|
|
4824
5178
|
fileToImageData,
|
|
4825
5179
|
fillPixelData,
|
|
5180
|
+
fillPixelDataBinaryMask,
|
|
4826
5181
|
floodFillSelection,
|
|
4827
5182
|
forEachLinePoint,
|
|
4828
5183
|
getCircleBrushOrPencilBounds,
|
|
@@ -4831,12 +5186,13 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
4831
5186
|
getIndexedImageColorCounts,
|
|
4832
5187
|
getRectBrushOrPencilBounds,
|
|
4833
5188
|
getRectBrushOrPencilStrokeBounds,
|
|
5189
|
+
getRectsBounds,
|
|
4834
5190
|
getSupportedPixelFormats,
|
|
4835
5191
|
hardLightFast,
|
|
4836
5192
|
hardLightPerfect,
|
|
4837
5193
|
hardMixFast,
|
|
4838
5194
|
hardMixPerfect,
|
|
4839
|
-
|
|
5195
|
+
imageDataToAlphaMaskBuffer,
|
|
4840
5196
|
imageDataToDataUrl,
|
|
4841
5197
|
imageDataToImgBlob,
|
|
4842
5198
|
imageDataToUInt32Array,
|
|
@@ -4859,7 +5215,11 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
4859
5215
|
linearDodgePerfect,
|
|
4860
5216
|
linearLightFast,
|
|
4861
5217
|
linearLightPerfect,
|
|
5218
|
+
makeAlphaMask,
|
|
5219
|
+
makeBinaryMask,
|
|
4862
5220
|
makeBlendModeRegistry,
|
|
5221
|
+
makeCircleBrushAlphaMask,
|
|
5222
|
+
makeCircleBrushBinaryMask,
|
|
4863
5223
|
makeFastBlendModeRegistry,
|
|
4864
5224
|
makeFullPixelMutator,
|
|
4865
5225
|
makeImageDataLike,
|
|
@@ -4867,7 +5227,9 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
4867
5227
|
makePixelCanvas,
|
|
4868
5228
|
makeReusableCanvas,
|
|
4869
5229
|
makeReusableImageData,
|
|
5230
|
+
merge2BinaryMaskRects,
|
|
4870
5231
|
mergeAlphaMasks,
|
|
5232
|
+
mergeBinaryMaskRects,
|
|
4871
5233
|
mergeBinaryMasks,
|
|
4872
5234
|
multiplyFast,
|
|
4873
5235
|
multiplyPerfect,
|
|
@@ -4886,6 +5248,7 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
4886
5248
|
mutatorBlendPixelData,
|
|
4887
5249
|
mutatorClear,
|
|
4888
5250
|
mutatorFill,
|
|
5251
|
+
mutatorFillBinaryMask,
|
|
4889
5252
|
mutatorInvert,
|
|
4890
5253
|
overlayFast,
|
|
4891
5254
|
overlayPerfect,
|
|
@@ -4908,10 +5271,12 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
4908
5271
|
screenPerfect,
|
|
4909
5272
|
serializeImageData,
|
|
4910
5273
|
serializeNullableImageData,
|
|
5274
|
+
setMaskData,
|
|
4911
5275
|
softLightFast,
|
|
4912
5276
|
softLightPerfect,
|
|
4913
5277
|
sourceOverFast,
|
|
4914
5278
|
sourceOverPerfect,
|
|
5279
|
+
subtractBinaryMaskRects,
|
|
4915
5280
|
subtractFast,
|
|
4916
5281
|
subtractPerfect,
|
|
4917
5282
|
toBlendModeIndexAndName,
|