pixel-data-js 0.25.2 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.prod.cjs +1696 -1526
- package/dist/index.prod.cjs.map +1 -1
- package/dist/index.prod.d.ts +414 -311
- package/dist/index.prod.js +1676 -1519
- package/dist/index.prod.js.map +1 -1
- package/package.json +8 -9
- package/src/Algorithm/floodFillSelection.ts +49 -80
- package/src/Canvas/PixelCanvas.ts +1 -1
- package/src/Canvas/ReusableCanvas.ts +1 -1
- package/src/History/HistoryAction.ts +6 -5
- package/src/History/PixelMutator/mutatorApplyAlphaMask.ts +8 -10
- package/src/History/PixelMutator/mutatorApplyBinaryMask.ts +8 -10
- package/src/History/PixelMutator/mutatorApplyMask.ts +39 -0
- package/src/History/PixelMutator/{mutatorBlendPixelDataAlphaMask.ts → mutatorBlendAlphaMask.ts} +9 -9
- package/src/History/PixelMutator/{mutatorBlendPixelDataBinaryMask.ts → mutatorBlendBinaryMask.ts} +9 -9
- package/src/History/PixelMutator/mutatorBlendColor.ts +8 -9
- package/src/History/PixelMutator/mutatorBlendColorPaintAlphaMask.ts +51 -0
- package/src/History/PixelMutator/mutatorBlendColorPaintBinaryMask.ts +51 -0
- package/src/History/PixelMutator/{mutatorBlendPaintMask.ts → mutatorBlendColorPaintMask.ts} +3 -3
- package/src/History/PixelMutator/mutatorBlendMask.ts +43 -0
- package/src/History/PixelMutator/mutatorBlendPaintRect.ts +55 -0
- package/src/History/PixelMutator/mutatorBlendPixel.ts +2 -2
- package/src/History/PixelMutator/mutatorBlendPixelData.ts +8 -9
- package/src/History/PixelMutator/mutatorClear.ts +13 -11
- package/src/History/PixelMutator/mutatorFill.ts +2 -2
- package/src/History/PixelMutator/mutatorFillBinaryMask.ts +3 -4
- package/src/History/PixelMutator/mutatorInvert.ts +8 -9
- package/src/History/PixelMutator.ts +20 -4
- package/src/History/PixelWriter.ts +11 -13
- package/src/Input/fileToImageData.ts +1 -1
- package/src/Internal/helpers.ts +4 -1
- package/src/Mask/applyBinaryMaskToAlphaMask.ts +8 -10
- package/src/Paint/PaintBuffer.ts +3 -3
- package/src/Paint/PaintBufferCanvasRenderer.ts +1 -1
- package/src/Paint/makePaintMask.ts +5 -5
- package/src/Paint/makeRectFalloffPaintAlphaMask.ts +3 -3
- package/src/PixelData/applyAlphaMaskToPixelData.ts +14 -16
- package/src/PixelData/applyBinaryMaskToPixelData.ts +14 -16
- package/src/PixelData/applyMaskToPixelData.ts +22 -0
- package/src/PixelData/blendColorPixelData.ts +12 -15
- package/src/PixelData/blendColorPixelDataAlphaMask.ts +16 -16
- package/src/PixelData/blendColorPixelDataBinaryMask.ts +16 -16
- package/src/PixelData/blendColorPixelDataMask.ts +16 -0
- package/src/PixelData/blendColorPixelDataPaintAlphaMask.ts +30 -0
- package/src/PixelData/blendColorPixelDataPaintBinaryMask.ts +30 -0
- package/src/PixelData/blendColorPixelDataPaintMask.ts +35 -0
- package/src/PixelData/blendPixelData.ts +14 -16
- package/src/PixelData/blendPixelDataAlphaMask.ts +17 -19
- package/src/PixelData/blendPixelDataBinaryMask.ts +17 -19
- package/src/PixelData/blendPixelDataMask.ts +16 -0
- package/src/PixelData/blendPixelDataPaintBuffer.ts +1 -1
- package/src/PixelData/{clearPixelData.ts → clearPixelDataFast.ts} +2 -2
- package/src/PixelData/fillPixelDataBinaryMask.ts +8 -22
- package/src/PixelData/fillPixelDataFast.ts +2 -2
- package/src/PixelData/invertPixelData.ts +13 -16
- package/src/_types.ts +8 -7
- package/src/index.ts +41 -31
- package/dist/index.dev.cjs +0 -5419
- package/dist/index.dev.cjs.map +0 -1
- package/dist/index.dev.js +0 -5208
- package/dist/index.dev.js.map +0 -1
- package/src/Canvas/_constants.ts +0 -2
- package/src/PixelData/PixelBuffer32.ts +0 -28
package/dist/index.prod.cjs
CHANGED
|
@@ -24,14 +24,11 @@ __export(src_exports, {
|
|
|
24
24
|
BASE_PERFECT_BLEND_MODE_FUNCTIONS: () => BASE_PERFECT_BLEND_MODE_FUNCTIONS,
|
|
25
25
|
BaseBlendMode: () => BaseBlendMode,
|
|
26
26
|
CANVAS_COMPOSITE_MAP: () => CANVAS_COMPOSITE_MAP,
|
|
27
|
-
CANVAS_CTX_FAILED: () => CANVAS_CTX_FAILED,
|
|
28
27
|
HistoryManager: () => HistoryManager,
|
|
29
28
|
IndexedImage: () => IndexedImage,
|
|
30
29
|
MaskType: () => MaskType,
|
|
31
|
-
OFFSCREEN_CANVAS_CTX_FAILED: () => OFFSCREEN_CANVAS_CTX_FAILED,
|
|
32
30
|
PaintBuffer: () => PaintBuffer,
|
|
33
31
|
PixelAccumulator: () => PixelAccumulator,
|
|
34
|
-
PixelBuffer32: () => PixelBuffer32,
|
|
35
32
|
PixelData: () => PixelData,
|
|
36
33
|
PixelEngineConfig: () => PixelEngineConfig,
|
|
37
34
|
PixelTile: () => PixelTile,
|
|
@@ -41,18 +38,24 @@ __export(src_exports, {
|
|
|
41
38
|
applyAlphaMaskToPixelData: () => applyAlphaMaskToPixelData,
|
|
42
39
|
applyBinaryMaskToAlphaMask: () => applyBinaryMaskToAlphaMask,
|
|
43
40
|
applyBinaryMaskToPixelData: () => applyBinaryMaskToPixelData,
|
|
41
|
+
applyMaskToPixelData: () => applyMaskToPixelData,
|
|
44
42
|
applyPatchTiles: () => applyPatchTiles,
|
|
45
43
|
base64DecodeArrayBuffer: () => base64DecodeArrayBuffer,
|
|
46
44
|
base64EncodeArrayBuffer: () => base64EncodeArrayBuffer,
|
|
47
45
|
blendColorPixelData: () => blendColorPixelData,
|
|
48
46
|
blendColorPixelDataAlphaMask: () => blendColorPixelDataAlphaMask,
|
|
49
47
|
blendColorPixelDataBinaryMask: () => blendColorPixelDataBinaryMask,
|
|
48
|
+
blendColorPixelDataMask: () => blendColorPixelDataMask,
|
|
49
|
+
blendColorPixelDataPaintAlphaMask: () => blendColorPixelDataPaintAlphaMask,
|
|
50
|
+
blendColorPixelDataPaintBinaryMask: () => blendColorPixelDataPaintBinaryMask,
|
|
51
|
+
blendColorPixelDataPaintMask: () => blendColorPixelDataPaintMask,
|
|
50
52
|
blendPixel: () => blendPixel,
|
|
51
53
|
blendPixelData: () => blendPixelData,
|
|
52
54
|
blendPixelDataAlphaMask: () => blendPixelDataAlphaMask,
|
|
53
55
|
blendPixelDataBinaryMask: () => blendPixelDataBinaryMask,
|
|
56
|
+
blendPixelDataMask: () => blendPixelDataMask,
|
|
54
57
|
blendPixelDataPaintBuffer: () => blendPixelDataPaintBuffer,
|
|
55
|
-
|
|
58
|
+
clearPixelDataFast: () => clearPixelDataFast,
|
|
56
59
|
color32ToCssRGBA: () => color32ToCssRGBA,
|
|
57
60
|
color32ToHex: () => color32ToHex,
|
|
58
61
|
colorBurnFast: () => colorBurnFast,
|
|
@@ -125,6 +128,8 @@ __export(src_exports, {
|
|
|
125
128
|
makeCanvasFrameRenderer: () => makeCanvasFrameRenderer,
|
|
126
129
|
makeCirclePaintAlphaMask: () => makeCirclePaintAlphaMask,
|
|
127
130
|
makeCirclePaintBinaryMask: () => makeCirclePaintBinaryMask,
|
|
131
|
+
makeClippedBlit: () => makeClippedBlit,
|
|
132
|
+
makeClippedRect: () => makeClippedRect,
|
|
128
133
|
makeFastBlendModeRegistry: () => makeFastBlendModeRegistry,
|
|
129
134
|
makeFullPixelMutator: () => makeFullPixelMutator,
|
|
130
135
|
makeHistoryAction: () => makeHistoryAction,
|
|
@@ -146,12 +151,17 @@ __export(src_exports, {
|
|
|
146
151
|
multiplyPerfect: () => multiplyPerfect,
|
|
147
152
|
mutatorApplyAlphaMask: () => mutatorApplyAlphaMask,
|
|
148
153
|
mutatorApplyBinaryMask: () => mutatorApplyBinaryMask,
|
|
154
|
+
mutatorApplyMask: () => mutatorApplyMask,
|
|
155
|
+
mutatorBlendAlphaMask: () => mutatorBlendAlphaMask,
|
|
156
|
+
mutatorBlendBinaryMask: () => mutatorBlendBinaryMask,
|
|
149
157
|
mutatorBlendColor: () => mutatorBlendColor,
|
|
150
|
-
|
|
158
|
+
mutatorBlendColorPaintAlphaMask: () => mutatorBlendColorPaintAlphaMask,
|
|
159
|
+
mutatorBlendColorPaintBinaryMask: () => mutatorBlendColorPaintBinaryMask,
|
|
160
|
+
mutatorBlendColorPaintMask: () => mutatorBlendColorPaintMask,
|
|
161
|
+
mutatorBlendMask: () => mutatorBlendMask,
|
|
162
|
+
mutatorBlendPaintRect: () => mutatorBlendPaintRect,
|
|
151
163
|
mutatorBlendPixel: () => mutatorBlendPixel,
|
|
152
164
|
mutatorBlendPixelData: () => mutatorBlendPixelData,
|
|
153
|
-
mutatorBlendPixelDataAlphaMask: () => mutatorBlendPixelDataAlphaMask,
|
|
154
|
-
mutatorBlendPixelDataBinaryMask: () => mutatorBlendPixelDataBinaryMask,
|
|
155
165
|
mutatorClear: () => mutatorClear,
|
|
156
166
|
mutatorFill: () => mutatorFill,
|
|
157
167
|
mutatorFillBinaryMask: () => mutatorFillBinaryMask,
|
|
@@ -169,10 +179,13 @@ __export(src_exports, {
|
|
|
169
179
|
pixelDataToAlphaMask: () => pixelDataToAlphaMask,
|
|
170
180
|
reflectPixelDataHorizontal: () => reflectPixelDataHorizontal,
|
|
171
181
|
reflectPixelDataVertical: () => reflectPixelDataVertical,
|
|
182
|
+
resample32: () => resample32,
|
|
172
183
|
resampleImageData: () => resampleImageData,
|
|
173
184
|
resampleIndexedImage: () => resampleIndexedImage,
|
|
174
185
|
resamplePixelData: () => resamplePixelData,
|
|
175
186
|
resizeImageData: () => resizeImageData,
|
|
187
|
+
resolveBlitClipping: () => resolveBlitClipping,
|
|
188
|
+
resolveRectClipping: () => resolveRectClipping,
|
|
176
189
|
rotatePixelData: () => rotatePixelData,
|
|
177
190
|
screenFast: () => screenFast,
|
|
178
191
|
screenPerfect: () => screenPerfect,
|
|
@@ -507,37 +520,22 @@ function trimMaskRectBounds(target, bounds) {
|
|
|
507
520
|
}
|
|
508
521
|
|
|
509
522
|
// src/Algorithm/floodFillSelection.ts
|
|
510
|
-
function floodFillSelection(
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
imageData = img;
|
|
523
|
-
}
|
|
524
|
-
const {
|
|
525
|
-
width,
|
|
526
|
-
height
|
|
527
|
-
} = img;
|
|
528
|
-
const limit = bounds || {
|
|
529
|
-
x: 0,
|
|
530
|
-
y: 0,
|
|
531
|
-
w: width,
|
|
532
|
-
h: height
|
|
533
|
-
};
|
|
534
|
-
const xMin = Math.max(0, limit.x);
|
|
535
|
-
const xMax = Math.min(width - 1, limit.x + limit.w - 1);
|
|
536
|
-
const yMin = Math.max(0, limit.y);
|
|
537
|
-
const yMax = Math.min(height - 1, limit.y + limit.h - 1);
|
|
523
|
+
function floodFillSelection(target, startX, startY, contiguous = true, tolerance = 0, bounds, out) {
|
|
524
|
+
const data32 = target.data32;
|
|
525
|
+
const width = target.width;
|
|
526
|
+
const height = target.height;
|
|
527
|
+
const lx = bounds?.x ?? 0;
|
|
528
|
+
const ly = bounds?.y ?? 0;
|
|
529
|
+
const lw = bounds?.w ?? width;
|
|
530
|
+
const lh = bounds?.h ?? height;
|
|
531
|
+
const xMin = Math.max(0, lx);
|
|
532
|
+
const xMax = Math.min(width - 1, lx + lw - 1);
|
|
533
|
+
const yMin = Math.max(0, ly);
|
|
534
|
+
const yMax = Math.min(height - 1, ly + lh - 1);
|
|
538
535
|
if (startX < xMin || startX > xMax || startY < yMin || startY > yMax) {
|
|
539
536
|
return null;
|
|
540
537
|
}
|
|
538
|
+
out = out ?? {};
|
|
541
539
|
const baseColor = data32[startY * width + startX];
|
|
542
540
|
let matchCount = 0;
|
|
543
541
|
const matchX = new Uint16Array(width * height);
|
|
@@ -608,42 +606,33 @@ function floodFillSelection(img, startX, startY, {
|
|
|
608
606
|
}
|
|
609
607
|
}
|
|
610
608
|
}
|
|
611
|
-
if (matchCount === 0)
|
|
612
|
-
return null;
|
|
613
|
-
}
|
|
609
|
+
if (matchCount === 0) return null;
|
|
614
610
|
const w = maxX - minX + 1;
|
|
615
611
|
const h = maxY - minY + 1;
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
const
|
|
625
|
-
const sh = selectionRect.h;
|
|
626
|
-
const finalMask = selectionRect.data;
|
|
612
|
+
out.startX = startX;
|
|
613
|
+
out.startY = startY;
|
|
614
|
+
out.x = minX;
|
|
615
|
+
out.y = minY;
|
|
616
|
+
out.w = w;
|
|
617
|
+
out.h = h;
|
|
618
|
+
out.data = new Uint8Array(w * h);
|
|
619
|
+
out.type = 1 /* BINARY */;
|
|
620
|
+
const finalMask = out.data;
|
|
627
621
|
for (let i = 0; i < matchCount; i++) {
|
|
628
|
-
const mx = matchX[i] -
|
|
629
|
-
const my = matchY[i] -
|
|
630
|
-
if (mx >= 0 && mx <
|
|
631
|
-
finalMask[my *
|
|
622
|
+
const mx = matchX[i] - minX;
|
|
623
|
+
const my = matchY[i] - minY;
|
|
624
|
+
if (mx >= 0 && mx < w && my >= 0 && my < h) {
|
|
625
|
+
finalMask[my * w + mx] = 1;
|
|
632
626
|
}
|
|
633
627
|
}
|
|
634
|
-
trimMaskRectBounds(
|
|
628
|
+
trimMaskRectBounds(out, {
|
|
635
629
|
x: 0,
|
|
636
630
|
y: 0,
|
|
637
631
|
w: width,
|
|
638
632
|
h: height
|
|
639
633
|
});
|
|
640
|
-
|
|
641
|
-
return
|
|
642
|
-
startX,
|
|
643
|
-
startY,
|
|
644
|
-
selectionRect,
|
|
645
|
-
pixels: extracted
|
|
646
|
-
};
|
|
634
|
+
out.pixels = extractImageDataBuffer(target.imageData, out.x, out.y, out.w, out.h);
|
|
635
|
+
return out;
|
|
647
636
|
}
|
|
648
637
|
|
|
649
638
|
// src/Algorithm/forEachLinePoint.ts
|
|
@@ -666,35 +655,6 @@ function forEachLinePoint(x0, y0, x1, y1, callback) {
|
|
|
666
655
|
}
|
|
667
656
|
}
|
|
668
657
|
|
|
669
|
-
// src/BlendModes/blend-modes.ts
|
|
670
|
-
var BaseBlendMode = {
|
|
671
|
-
overwrite: 0,
|
|
672
|
-
sourceOver: 1,
|
|
673
|
-
darken: 2,
|
|
674
|
-
multiply: 3,
|
|
675
|
-
colorBurn: 4,
|
|
676
|
-
linearBurn: 5,
|
|
677
|
-
darkerColor: 6,
|
|
678
|
-
lighten: 7,
|
|
679
|
-
screen: 8,
|
|
680
|
-
colorDodge: 9,
|
|
681
|
-
linearDodge: 10,
|
|
682
|
-
lighterColor: 11,
|
|
683
|
-
overlay: 12,
|
|
684
|
-
softLight: 13,
|
|
685
|
-
hardLight: 14,
|
|
686
|
-
vividLight: 15,
|
|
687
|
-
linearLight: 16,
|
|
688
|
-
pinLight: 17,
|
|
689
|
-
hardMix: 18,
|
|
690
|
-
difference: 19,
|
|
691
|
-
exclusion: 20,
|
|
692
|
-
subtract: 21,
|
|
693
|
-
divide: 22
|
|
694
|
-
};
|
|
695
|
-
var overwriteBase = (src, _dst) => src;
|
|
696
|
-
overwriteBase.isOverwrite = true;
|
|
697
|
-
|
|
698
658
|
// src/BlendModes/BlendModeRegistry.ts
|
|
699
659
|
function makeBlendModeRegistry(blendModes, initialEntries, registryName = "anonymous") {
|
|
700
660
|
const blendToName = /* @__PURE__ */ new Map();
|
|
@@ -734,6 +694,35 @@ function makeBlendModeRegistry(blendModes, initialEntries, registryName = "anony
|
|
|
734
694
|
};
|
|
735
695
|
}
|
|
736
696
|
|
|
697
|
+
// src/BlendModes/blend-modes.ts
|
|
698
|
+
var BaseBlendMode = {
|
|
699
|
+
overwrite: 0,
|
|
700
|
+
sourceOver: 1,
|
|
701
|
+
darken: 2,
|
|
702
|
+
multiply: 3,
|
|
703
|
+
colorBurn: 4,
|
|
704
|
+
linearBurn: 5,
|
|
705
|
+
darkerColor: 6,
|
|
706
|
+
lighten: 7,
|
|
707
|
+
screen: 8,
|
|
708
|
+
colorDodge: 9,
|
|
709
|
+
linearDodge: 10,
|
|
710
|
+
lighterColor: 11,
|
|
711
|
+
overlay: 12,
|
|
712
|
+
softLight: 13,
|
|
713
|
+
hardLight: 14,
|
|
714
|
+
vividLight: 15,
|
|
715
|
+
linearLight: 16,
|
|
716
|
+
pinLight: 17,
|
|
717
|
+
hardMix: 18,
|
|
718
|
+
difference: 19,
|
|
719
|
+
exclusion: 20,
|
|
720
|
+
subtract: 21,
|
|
721
|
+
divide: 22
|
|
722
|
+
};
|
|
723
|
+
var overwriteBase = (src, _dst) => src;
|
|
724
|
+
overwriteBase.isOverwrite = true;
|
|
725
|
+
|
|
737
726
|
// src/BlendModes/blend-modes-fast.ts
|
|
738
727
|
var overwriteFast = overwriteBase;
|
|
739
728
|
var sourceOverFast = (src, dst) => {
|
|
@@ -1739,28 +1728,10 @@ var getKeyByValue = (obj, value) => {
|
|
|
1739
1728
|
}
|
|
1740
1729
|
};
|
|
1741
1730
|
|
|
1742
|
-
//
|
|
1731
|
+
// support/error-strings.ts
|
|
1743
1732
|
var OFFSCREEN_CANVAS_CTX_FAILED = "Failed to create OffscreenCanvas context";
|
|
1744
1733
|
var CANVAS_CTX_FAILED = "Failed to create Canvas context";
|
|
1745
1734
|
|
|
1746
|
-
// src/Canvas/canvas-blend-modes.ts
|
|
1747
|
-
var CANVAS_COMPOSITE_MAP = {
|
|
1748
|
-
[BaseBlendMode.overwrite]: "copy",
|
|
1749
|
-
[BaseBlendMode.sourceOver]: "source-over",
|
|
1750
|
-
[BaseBlendMode.darken]: "darken",
|
|
1751
|
-
[BaseBlendMode.multiply]: "multiply",
|
|
1752
|
-
[BaseBlendMode.colorBurn]: "color-burn",
|
|
1753
|
-
[BaseBlendMode.lighten]: "lighten",
|
|
1754
|
-
[BaseBlendMode.screen]: "screen",
|
|
1755
|
-
[BaseBlendMode.colorDodge]: "color-dodge",
|
|
1756
|
-
[BaseBlendMode.linearDodge]: "lighter",
|
|
1757
|
-
[BaseBlendMode.overlay]: "overlay",
|
|
1758
|
-
[BaseBlendMode.softLight]: "soft-light",
|
|
1759
|
-
[BaseBlendMode.hardLight]: "hard-light",
|
|
1760
|
-
[BaseBlendMode.difference]: "difference",
|
|
1761
|
-
[BaseBlendMode.exclusion]: "exclusion"
|
|
1762
|
-
};
|
|
1763
|
-
|
|
1764
1735
|
// src/Canvas/ReusableCanvas.ts
|
|
1765
1736
|
function makeReusableCanvas() {
|
|
1766
1737
|
return makeReusableCanvasMeta((w, h) => {
|
|
@@ -1859,6 +1830,24 @@ function makePixelCanvas(canvas) {
|
|
|
1859
1830
|
};
|
|
1860
1831
|
}
|
|
1861
1832
|
|
|
1833
|
+
// src/Canvas/canvas-blend-modes.ts
|
|
1834
|
+
var CANVAS_COMPOSITE_MAP = {
|
|
1835
|
+
[BaseBlendMode.overwrite]: "copy",
|
|
1836
|
+
[BaseBlendMode.sourceOver]: "source-over",
|
|
1837
|
+
[BaseBlendMode.darken]: "darken",
|
|
1838
|
+
[BaseBlendMode.multiply]: "multiply",
|
|
1839
|
+
[BaseBlendMode.colorBurn]: "color-burn",
|
|
1840
|
+
[BaseBlendMode.lighten]: "lighten",
|
|
1841
|
+
[BaseBlendMode.screen]: "screen",
|
|
1842
|
+
[BaseBlendMode.colorDodge]: "color-dodge",
|
|
1843
|
+
[BaseBlendMode.linearDodge]: "lighter",
|
|
1844
|
+
[BaseBlendMode.overlay]: "overlay",
|
|
1845
|
+
[BaseBlendMode.softLight]: "soft-light",
|
|
1846
|
+
[BaseBlendMode.hardLight]: "hard-light",
|
|
1847
|
+
[BaseBlendMode.difference]: "difference",
|
|
1848
|
+
[BaseBlendMode.exclusion]: "exclusion"
|
|
1849
|
+
};
|
|
1850
|
+
|
|
1862
1851
|
// src/ImageData/imgBlobToImageData.ts
|
|
1863
1852
|
async function imgBlobToImageData(blob) {
|
|
1864
1853
|
let bitmap = null;
|
|
@@ -1943,10 +1932,9 @@ function applyPatchTiles(target, tiles, tileSize) {
|
|
|
1943
1932
|
}
|
|
1944
1933
|
|
|
1945
1934
|
// src/History/HistoryAction.ts
|
|
1946
|
-
function makeHistoryAction(
|
|
1947
|
-
const target =
|
|
1948
|
-
const tileSize =
|
|
1949
|
-
const accumulator = writer.accumulator;
|
|
1935
|
+
function makeHistoryAction(config, accumulator, patch, after, afterUndo, afterRedo, applyPatchTilesFn = applyPatchTiles) {
|
|
1936
|
+
const target = config.target;
|
|
1937
|
+
const tileSize = config.tileSize;
|
|
1950
1938
|
return {
|
|
1951
1939
|
undo: () => {
|
|
1952
1940
|
applyPatchTilesFn(target, patch.beforeTiles, tileSize);
|
|
@@ -2216,20 +2204,17 @@ var PixelEngineConfig = class {
|
|
|
2216
2204
|
}
|
|
2217
2205
|
};
|
|
2218
2206
|
|
|
2219
|
-
// src/PixelData/
|
|
2220
|
-
function
|
|
2221
|
-
const
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2207
|
+
// src/PixelData/applyAlphaMaskToPixelData.ts
|
|
2208
|
+
function applyAlphaMaskToPixelData(target, mask, opts) {
|
|
2209
|
+
const targetX = opts?.x ?? 0;
|
|
2210
|
+
const targetY = opts?.y ?? 0;
|
|
2211
|
+
const width = opts?.w ?? target.width;
|
|
2212
|
+
const height = opts?.h ?? target.height;
|
|
2213
|
+
const globalAlpha = opts?.alpha ?? 255;
|
|
2214
|
+
const mx = opts?.mx ?? 0;
|
|
2215
|
+
const my = opts?.my ?? 0;
|
|
2216
|
+
const invertMask = opts?.invertMask ?? false;
|
|
2229
2217
|
if (globalAlpha === 0) return false;
|
|
2230
|
-
const baseSrcAlpha = color >>> 24;
|
|
2231
|
-
const isOverwrite = blendFn.isOverwrite || false;
|
|
2232
|
-
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
2233
2218
|
let x = targetX;
|
|
2234
2219
|
let y = targetY;
|
|
2235
2220
|
let w = width;
|
|
@@ -2242,112 +2227,318 @@ function blendColorPixelData(dst, color, opts = {}) {
|
|
|
2242
2227
|
h += y;
|
|
2243
2228
|
y = 0;
|
|
2244
2229
|
}
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
if (
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
const
|
|
2255
|
-
const
|
|
2256
|
-
|
|
2257
|
-
const
|
|
2230
|
+
w = Math.min(w, target.width - x);
|
|
2231
|
+
h = Math.min(h, target.height - y);
|
|
2232
|
+
if (w <= 0) return false;
|
|
2233
|
+
if (h <= 0) return false;
|
|
2234
|
+
const mPitch = mask.w;
|
|
2235
|
+
if (mPitch <= 0) return false;
|
|
2236
|
+
const startX = mx + (x - targetX);
|
|
2237
|
+
const startY = my + (y - targetY);
|
|
2238
|
+
const sX0 = Math.max(0, startX);
|
|
2239
|
+
const sY0 = Math.max(0, startY);
|
|
2240
|
+
const sX1 = Math.min(mPitch, startX + w);
|
|
2241
|
+
const sY1 = Math.min(mask.h, startY + h);
|
|
2242
|
+
const finalW = sX1 - sX0;
|
|
2243
|
+
const finalH = sY1 - sY0;
|
|
2244
|
+
if (finalW <= 0) return false;
|
|
2245
|
+
if (finalH <= 0) return false;
|
|
2246
|
+
const xShift = sX0 - startX;
|
|
2247
|
+
const yShift = sY0 - startY;
|
|
2248
|
+
const dst32 = target.data32;
|
|
2249
|
+
const dw = target.width;
|
|
2250
|
+
const dStride = dw - finalW;
|
|
2251
|
+
const mStride = mPitch - finalW;
|
|
2252
|
+
const maskData = mask.data;
|
|
2253
|
+
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
2254
|
+
let mIdx = sY0 * mPitch + sX0;
|
|
2258
2255
|
let didChange = false;
|
|
2259
|
-
for (let iy = 0; iy <
|
|
2260
|
-
for (let ix = 0; ix <
|
|
2261
|
-
const
|
|
2262
|
-
const
|
|
2263
|
-
|
|
2264
|
-
|
|
2256
|
+
for (let iy = 0; iy < h; iy++) {
|
|
2257
|
+
for (let ix = 0; ix < w; ix++) {
|
|
2258
|
+
const mVal = maskData[mIdx];
|
|
2259
|
+
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
2260
|
+
let weight = 0;
|
|
2261
|
+
if (effectiveM === 0) {
|
|
2262
|
+
weight = 0;
|
|
2263
|
+
} else if (effectiveM === 255) {
|
|
2264
|
+
weight = globalAlpha;
|
|
2265
|
+
} else if (globalAlpha === 255) {
|
|
2266
|
+
weight = effectiveM;
|
|
2267
|
+
} else {
|
|
2268
|
+
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
2269
|
+
}
|
|
2270
|
+
if (weight === 0) {
|
|
2271
|
+
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
2265
2272
|
didChange = true;
|
|
2273
|
+
} else if (weight !== 255) {
|
|
2274
|
+
const d = dst32[dIdx];
|
|
2275
|
+
const da = d >>> 24;
|
|
2276
|
+
if (da !== 0) {
|
|
2277
|
+
const finalAlpha = da === 255 ? weight : da * weight + 128 >> 8;
|
|
2278
|
+
const current = dst32[dIdx];
|
|
2279
|
+
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
2280
|
+
if (current !== next) {
|
|
2281
|
+
dst32[dIdx] = next;
|
|
2282
|
+
didChange = true;
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2266
2285
|
}
|
|
2267
2286
|
dIdx++;
|
|
2287
|
+
mIdx++;
|
|
2268
2288
|
}
|
|
2269
2289
|
dIdx += dStride;
|
|
2290
|
+
mIdx += mStride;
|
|
2270
2291
|
}
|
|
2271
2292
|
return didChange;
|
|
2272
2293
|
}
|
|
2273
2294
|
|
|
2274
|
-
// src/
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
};
|
|
2278
|
-
var mutatorBlendColor = ((writer, deps = defaults2) => {
|
|
2295
|
+
// src/ImageData/resizeImageData.ts
|
|
2296
|
+
function resizeImageData(target, newWidth, newHeight, offsetX = 0, offsetY = 0) {
|
|
2297
|
+
const result = new ImageData(newWidth, newHeight);
|
|
2279
2298
|
const {
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2292
|
-
return didChange(blendColorPixelData2(target, color, opts));
|
|
2293
|
-
}
|
|
2294
|
-
};
|
|
2295
|
-
});
|
|
2296
|
-
|
|
2297
|
-
// src/PixelData/blendPixel.ts
|
|
2298
|
-
function blendPixel(target, x, y, color, alpha = 255, blendFn = sourceOverPerfect) {
|
|
2299
|
-
if (alpha === 0) return false;
|
|
2300
|
-
let width = target.width;
|
|
2301
|
-
let height = target.height;
|
|
2302
|
-
if (x < 0 || x >= width || y < 0 || y >= height) return false;
|
|
2303
|
-
let srcAlpha = color >>> 24;
|
|
2304
|
-
let isOverwrite = blendFn.isOverwrite;
|
|
2305
|
-
if (srcAlpha === 0 && !isOverwrite) return false;
|
|
2306
|
-
let dst32 = target.data32;
|
|
2307
|
-
let index = y * width + x;
|
|
2308
|
-
let finalColor = color;
|
|
2309
|
-
if (alpha !== 255) {
|
|
2310
|
-
let finalAlpha = srcAlpha * alpha + 128 >> 8;
|
|
2311
|
-
if (finalAlpha === 0 && !isOverwrite) return false;
|
|
2312
|
-
finalColor = (color & 16777215 | finalAlpha << 24) >>> 0;
|
|
2299
|
+
width: oldW,
|
|
2300
|
+
height: oldH,
|
|
2301
|
+
data: oldData
|
|
2302
|
+
} = target;
|
|
2303
|
+
const newData = result.data;
|
|
2304
|
+
const x0 = Math.max(0, offsetX);
|
|
2305
|
+
const y0 = Math.max(0, offsetY);
|
|
2306
|
+
const x1 = Math.min(newWidth, offsetX + oldW);
|
|
2307
|
+
const y1 = Math.min(newHeight, offsetY + oldH);
|
|
2308
|
+
if (x1 <= x0 || y1 <= y0) {
|
|
2309
|
+
return result;
|
|
2313
2310
|
}
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2311
|
+
const rowCount = y1 - y0;
|
|
2312
|
+
const rowLen = (x1 - x0) * 4;
|
|
2313
|
+
for (let row = 0; row < rowCount; row++) {
|
|
2314
|
+
const dstY = y0 + row;
|
|
2315
|
+
const srcY = dstY - offsetY;
|
|
2316
|
+
const srcX = x0 - offsetX;
|
|
2317
|
+
const dstStart = (dstY * newWidth + x0) * 4;
|
|
2318
|
+
const srcStart = (srcY * oldW + srcX) * 4;
|
|
2319
|
+
newData.set(oldData.subarray(srcStart, srcStart + rowLen), dstStart);
|
|
2319
2320
|
}
|
|
2320
|
-
return
|
|
2321
|
+
return result;
|
|
2321
2322
|
}
|
|
2322
2323
|
|
|
2323
|
-
// src/
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
} = deps;
|
|
2331
|
-
return {
|
|
2332
|
-
blendPixel(x, y, color, alpha, blendFn) {
|
|
2333
|
-
const didChange = writer.accumulator.storePixelBeforeState(x, y);
|
|
2334
|
-
return didChange(blendPixel2(writer.config.target, x, y, color, alpha, blendFn));
|
|
2335
|
-
}
|
|
2324
|
+
// src/Rect/trimRectBounds.ts
|
|
2325
|
+
function trimRectBounds(x, y, w, h, targetWidth, targetHeight, out) {
|
|
2326
|
+
const res = out ?? {
|
|
2327
|
+
x: 0,
|
|
2328
|
+
y: 0,
|
|
2329
|
+
w: 0,
|
|
2330
|
+
h: 0
|
|
2336
2331
|
};
|
|
2337
|
-
|
|
2332
|
+
const left = Math.max(0, x);
|
|
2333
|
+
const top = Math.max(0, y);
|
|
2334
|
+
const right = Math.min(targetWidth, x + w);
|
|
2335
|
+
const bottom = Math.min(targetHeight, y + h);
|
|
2336
|
+
res.x = left;
|
|
2337
|
+
res.y = top;
|
|
2338
|
+
res.w = Math.max(0, right - left);
|
|
2339
|
+
res.h = Math.max(0, bottom - top);
|
|
2340
|
+
return res;
|
|
2341
|
+
}
|
|
2342
|
+
|
|
2343
|
+
// src/Paint/PaintBuffer.ts
|
|
2344
|
+
var PaintBuffer = class {
|
|
2345
|
+
constructor(config, tilePool) {
|
|
2346
|
+
this.config = config;
|
|
2347
|
+
this.tilePool = tilePool;
|
|
2348
|
+
this.lookup = [];
|
|
2349
|
+
}
|
|
2350
|
+
lookup;
|
|
2351
|
+
scratchBounds = {
|
|
2352
|
+
x: 0,
|
|
2353
|
+
y: 0,
|
|
2354
|
+
w: 0,
|
|
2355
|
+
h: 0
|
|
2356
|
+
};
|
|
2357
|
+
eachTileInBounds(bounds, callback) {
|
|
2358
|
+
const {
|
|
2359
|
+
tileShift,
|
|
2360
|
+
targetColumns,
|
|
2361
|
+
targetRows,
|
|
2362
|
+
tileSize
|
|
2363
|
+
} = this.config;
|
|
2364
|
+
const x1 = Math.max(0, bounds.x >> tileShift);
|
|
2365
|
+
const y1 = Math.max(0, bounds.y >> tileShift);
|
|
2366
|
+
const x2 = Math.min(targetColumns - 1, bounds.x + bounds.w - 1 >> tileShift);
|
|
2367
|
+
const y2 = Math.min(targetRows - 1, bounds.y + bounds.h - 1 >> tileShift);
|
|
2368
|
+
if (x1 > x2 || y1 > y2) return;
|
|
2369
|
+
const lookup = this.lookup;
|
|
2370
|
+
const tilePool = this.tilePool;
|
|
2371
|
+
for (let ty = y1; ty <= y2; ty++) {
|
|
2372
|
+
const rowOffset = ty * targetColumns;
|
|
2373
|
+
const tileTop = ty << tileShift;
|
|
2374
|
+
for (let tx = x1; tx <= x2; tx++) {
|
|
2375
|
+
const id = rowOffset + tx;
|
|
2376
|
+
const tile = lookup[id] ?? (lookup[id] = tilePool.getTile(id, tx, ty));
|
|
2377
|
+
const tileLeft = tx << tileShift;
|
|
2378
|
+
const startX = bounds.x > tileLeft ? bounds.x : tileLeft;
|
|
2379
|
+
const startY = bounds.y > tileTop ? bounds.y : tileTop;
|
|
2380
|
+
const maskEndX = bounds.x + bounds.w;
|
|
2381
|
+
const tileEndX = tileLeft + tileSize;
|
|
2382
|
+
const endX = maskEndX < tileEndX ? maskEndX : tileEndX;
|
|
2383
|
+
const maskEndY = bounds.y + bounds.h;
|
|
2384
|
+
const tileEndY = tileTop + tileSize;
|
|
2385
|
+
const endY = maskEndY < tileEndY ? maskEndY : tileEndY;
|
|
2386
|
+
callback(tile, startX, startY, endX - startX, endY - startY);
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
writePaintAlphaMaskStroke(color, brush, x0, y0, x1, y1) {
|
|
2391
|
+
const cA = color >>> 24;
|
|
2392
|
+
if (cA === 0) return false;
|
|
2393
|
+
const {
|
|
2394
|
+
tileShift,
|
|
2395
|
+
tileMask,
|
|
2396
|
+
target
|
|
2397
|
+
} = this.config;
|
|
2398
|
+
const {
|
|
2399
|
+
w: bW,
|
|
2400
|
+
h: bH,
|
|
2401
|
+
data: bD,
|
|
2402
|
+
centerOffsetX,
|
|
2403
|
+
centerOffsetY
|
|
2404
|
+
} = brush;
|
|
2405
|
+
const cRGB = color & 16777215;
|
|
2406
|
+
const scratch = this.scratchBounds;
|
|
2407
|
+
let changed = false;
|
|
2408
|
+
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
2409
|
+
const topLeftX = Math.floor(px + centerOffsetX);
|
|
2410
|
+
const topLeftY = Math.floor(py + centerOffsetY);
|
|
2411
|
+
trimRectBounds(topLeftX, topLeftY, bW, bH, target.width, target.height, scratch);
|
|
2412
|
+
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
2413
|
+
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
2414
|
+
const d32 = tile.data32;
|
|
2415
|
+
let tileChanged = false;
|
|
2416
|
+
for (let i = 0; i < bH_t; i++) {
|
|
2417
|
+
const canvasY = bY + i;
|
|
2418
|
+
const bOff = (canvasY - topLeftY) * bW;
|
|
2419
|
+
const tOff = (canvasY & tileMask) << tileShift;
|
|
2420
|
+
const dS = tOff + (bX & tileMask);
|
|
2421
|
+
for (let j = 0; j < bW_t; j++) {
|
|
2422
|
+
const canvasX = bX + j;
|
|
2423
|
+
const brushA = bD[bOff + (canvasX - topLeftX)];
|
|
2424
|
+
if (brushA === 0) continue;
|
|
2425
|
+
const t = cA * brushA + 128;
|
|
2426
|
+
const blendedA = t + (t >> 8) >> 8;
|
|
2427
|
+
const idx = dS + j;
|
|
2428
|
+
const cur = d32[idx];
|
|
2429
|
+
if (brushA > cur >>> 24) {
|
|
2430
|
+
const next = (cRGB | blendedA << 24) >>> 0;
|
|
2431
|
+
if (cur !== next) {
|
|
2432
|
+
d32[idx] = next;
|
|
2433
|
+
tileChanged = true;
|
|
2434
|
+
}
|
|
2435
|
+
}
|
|
2436
|
+
}
|
|
2437
|
+
}
|
|
2438
|
+
if (tileChanged) changed = true;
|
|
2439
|
+
});
|
|
2440
|
+
});
|
|
2441
|
+
return changed;
|
|
2442
|
+
}
|
|
2443
|
+
writePaintBinaryMaskStroke(color, brush, x0, y0, x1, y1) {
|
|
2444
|
+
const alphaIsZero = color >>> 24 === 0;
|
|
2445
|
+
if (alphaIsZero) return false;
|
|
2446
|
+
const {
|
|
2447
|
+
tileShift,
|
|
2448
|
+
tileMask,
|
|
2449
|
+
target
|
|
2450
|
+
} = this.config;
|
|
2451
|
+
const {
|
|
2452
|
+
w: bW,
|
|
2453
|
+
h: bH,
|
|
2454
|
+
data: bD,
|
|
2455
|
+
centerOffsetX,
|
|
2456
|
+
centerOffsetY
|
|
2457
|
+
} = brush;
|
|
2458
|
+
const scratch = this.scratchBounds;
|
|
2459
|
+
let changed = false;
|
|
2460
|
+
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
2461
|
+
const topLeftX = Math.floor(px + centerOffsetX);
|
|
2462
|
+
const topLeftY = Math.floor(py + centerOffsetY);
|
|
2463
|
+
trimRectBounds(topLeftX, topLeftY, bW, bH, target.width, target.height, scratch);
|
|
2464
|
+
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
2465
|
+
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
2466
|
+
const d32 = tile.data32;
|
|
2467
|
+
let tileChanged = false;
|
|
2468
|
+
for (let i = 0; i < bH_t; i++) {
|
|
2469
|
+
const canvasY = bY + i;
|
|
2470
|
+
const bOff = (canvasY - topLeftY) * bW;
|
|
2471
|
+
const tOff = (canvasY & tileMask) << tileShift;
|
|
2472
|
+
const dS = tOff + (bX & tileMask);
|
|
2473
|
+
for (let j = 0; j < bW_t; j++) {
|
|
2474
|
+
const canvasX = bX + j;
|
|
2475
|
+
if (bD[bOff + (canvasX - topLeftX)]) {
|
|
2476
|
+
const idx = dS + j;
|
|
2477
|
+
if (d32[idx] !== color) {
|
|
2478
|
+
d32[idx] = color;
|
|
2479
|
+
tileChanged = true;
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2484
|
+
if (tileChanged) changed = true;
|
|
2485
|
+
});
|
|
2486
|
+
});
|
|
2487
|
+
return changed;
|
|
2488
|
+
}
|
|
2489
|
+
writeRectStroke(color, brushWidth, brushHeight, x0, y0, x1, y1) {
|
|
2490
|
+
const alphaIsZero = color >>> 24 === 0;
|
|
2491
|
+
if (alphaIsZero) return false;
|
|
2492
|
+
const config = this.config;
|
|
2493
|
+
const tileShift = config.tileShift;
|
|
2494
|
+
const tileMask = config.tileMask;
|
|
2495
|
+
const target = config.target;
|
|
2496
|
+
const scratch = this.scratchBounds;
|
|
2497
|
+
const centerOffsetX = -(brushWidth - 1 >> 1);
|
|
2498
|
+
const centerOffsetY = -(brushHeight - 1 >> 1);
|
|
2499
|
+
let changed = false;
|
|
2500
|
+
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
2501
|
+
const topLeftX = Math.floor(px + centerOffsetX);
|
|
2502
|
+
const topLeftY = Math.floor(py + centerOffsetY);
|
|
2503
|
+
trimRectBounds(topLeftX, topLeftY, brushWidth, brushHeight, target.width, target.height, scratch);
|
|
2504
|
+
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
2505
|
+
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
2506
|
+
const d32 = tile.data32;
|
|
2507
|
+
let tileChanged = false;
|
|
2508
|
+
for (let i = 0; i < bH_t; i++) {
|
|
2509
|
+
const canvasY = bY + i;
|
|
2510
|
+
const tOff = (canvasY & tileMask) << tileShift;
|
|
2511
|
+
const dS = tOff + (bX & tileMask);
|
|
2512
|
+
for (let j = 0; j < bW_t; j++) {
|
|
2513
|
+
const idx = dS + j;
|
|
2514
|
+
if (d32[idx] !== color) {
|
|
2515
|
+
d32[idx] = color;
|
|
2516
|
+
tileChanged = true;
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2520
|
+
if (tileChanged) {
|
|
2521
|
+
changed = true;
|
|
2522
|
+
}
|
|
2523
|
+
});
|
|
2524
|
+
});
|
|
2525
|
+
return changed;
|
|
2526
|
+
}
|
|
2527
|
+
clear() {
|
|
2528
|
+
this.tilePool.releaseTiles(this.lookup);
|
|
2529
|
+
}
|
|
2530
|
+
};
|
|
2338
2531
|
|
|
2339
2532
|
// src/PixelData/blendPixelData.ts
|
|
2340
|
-
function blendPixelData(
|
|
2341
|
-
const
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
blendFn = sourceOverPerfect
|
|
2350
|
-
} = opts;
|
|
2533
|
+
function blendPixelData(target, src, opts) {
|
|
2534
|
+
const targetX = opts?.x ?? 0;
|
|
2535
|
+
const targetY = opts?.y ?? 0;
|
|
2536
|
+
const sourceX = opts?.sx ?? 0;
|
|
2537
|
+
const sourceY = opts?.sy ?? 0;
|
|
2538
|
+
const width = opts?.w ?? src.width;
|
|
2539
|
+
const height = opts?.h ?? src.height;
|
|
2540
|
+
const globalAlpha = opts?.alpha ?? 255;
|
|
2541
|
+
const blendFn = opts?.blendFn ?? sourceOverPerfect;
|
|
2351
2542
|
if (globalAlpha === 0) return false;
|
|
2352
2543
|
let x = targetX;
|
|
2353
2544
|
let y = targetY;
|
|
@@ -2377,12 +2568,12 @@ function blendPixelData(dst, src, opts = {}) {
|
|
|
2377
2568
|
h += y;
|
|
2378
2569
|
y = 0;
|
|
2379
2570
|
}
|
|
2380
|
-
const actualW = Math.min(w,
|
|
2381
|
-
const actualH = Math.min(h,
|
|
2571
|
+
const actualW = Math.min(w, target.width - x);
|
|
2572
|
+
const actualH = Math.min(h, target.height - y);
|
|
2382
2573
|
if (actualW <= 0 || actualH <= 0) return false;
|
|
2383
|
-
const dst32 =
|
|
2574
|
+
const dst32 = target.data32;
|
|
2384
2575
|
const src32 = src.data32;
|
|
2385
|
-
const dw =
|
|
2576
|
+
const dw = target.width;
|
|
2386
2577
|
const sw = src.width;
|
|
2387
2578
|
let dIdx = y * dw + x | 0;
|
|
2388
2579
|
let sIdx = sy * sw + sx | 0;
|
|
@@ -2425,44 +2616,334 @@ function blendPixelData(dst, src, opts = {}) {
|
|
|
2425
2616
|
return didChange;
|
|
2426
2617
|
}
|
|
2427
2618
|
|
|
2428
|
-
// src/
|
|
2429
|
-
var
|
|
2430
|
-
|
|
2619
|
+
// src/PixelTile/PixelTile.ts
|
|
2620
|
+
var PixelTile = class {
|
|
2621
|
+
constructor(id, tx, ty, tileSize, tileArea) {
|
|
2622
|
+
this.id = id;
|
|
2623
|
+
this.tx = tx;
|
|
2624
|
+
this.ty = ty;
|
|
2625
|
+
this.width = this.height = tileSize;
|
|
2626
|
+
this.data32 = new Uint32Array(tileArea);
|
|
2627
|
+
const data8 = new Uint8ClampedArray(this.data32.buffer);
|
|
2628
|
+
this.imageData = new ImageData(data8, tileSize, tileSize);
|
|
2629
|
+
}
|
|
2630
|
+
data32;
|
|
2631
|
+
width;
|
|
2632
|
+
height;
|
|
2633
|
+
imageData;
|
|
2431
2634
|
};
|
|
2432
|
-
var mutatorBlendPixelData = ((writer, deps = defaults4) => {
|
|
2433
|
-
const {
|
|
2434
|
-
blendPixelData: blendPixelData2 = defaults4.blendPixelData
|
|
2435
|
-
} = deps;
|
|
2436
|
-
return {
|
|
2437
|
-
blendPixelData(src, opts = {}) {
|
|
2438
|
-
const {
|
|
2439
|
-
x = 0,
|
|
2440
|
-
y = 0,
|
|
2441
|
-
w = src.width,
|
|
2442
|
-
h = src.height
|
|
2443
|
-
} = opts;
|
|
2444
|
-
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2445
|
-
return didChange(blendPixelData2(writer.config.target, src, opts));
|
|
2446
|
-
}
|
|
2447
|
-
};
|
|
2448
|
-
});
|
|
2449
2635
|
|
|
2450
|
-
// src/
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2636
|
+
// src/PixelTile/PixelTilePool.ts
|
|
2637
|
+
var PixelTilePool = class {
|
|
2638
|
+
pool;
|
|
2639
|
+
tileSize;
|
|
2640
|
+
tileArea;
|
|
2641
|
+
constructor(config) {
|
|
2642
|
+
this.pool = [];
|
|
2643
|
+
this.tileSize = config.tileSize;
|
|
2644
|
+
this.tileArea = config.tileArea;
|
|
2645
|
+
}
|
|
2646
|
+
getTile(id, tx, ty) {
|
|
2647
|
+
let tile = this.pool.pop();
|
|
2648
|
+
if (tile) {
|
|
2649
|
+
tile.id = id;
|
|
2650
|
+
tile.tx = tx;
|
|
2651
|
+
tile.ty = ty;
|
|
2652
|
+
tile.data32.fill(0);
|
|
2653
|
+
return tile;
|
|
2654
|
+
}
|
|
2655
|
+
return new PixelTile(id, tx, ty, this.tileSize, this.tileArea);
|
|
2656
|
+
}
|
|
2657
|
+
releaseTile(tile) {
|
|
2658
|
+
this.pool.push(tile);
|
|
2659
|
+
}
|
|
2660
|
+
releaseTiles(tiles) {
|
|
2661
|
+
let length = tiles.length;
|
|
2662
|
+
for (let i = 0; i < length; i++) {
|
|
2663
|
+
let tile = tiles[i];
|
|
2664
|
+
if (tile) {
|
|
2665
|
+
this.pool.push(tile);
|
|
2666
|
+
}
|
|
2667
|
+
}
|
|
2668
|
+
tiles.length = 0;
|
|
2669
|
+
}
|
|
2670
|
+
};
|
|
2671
|
+
|
|
2672
|
+
// src/History/PixelWriter.ts
|
|
2673
|
+
var PixelWriter = class {
|
|
2674
|
+
historyManager;
|
|
2675
|
+
accumulator;
|
|
2676
|
+
historyActionFactory;
|
|
2677
|
+
config;
|
|
2678
|
+
pixelTilePool;
|
|
2679
|
+
paintBuffer;
|
|
2680
|
+
mutator;
|
|
2681
|
+
blendPixelDataOpts = {
|
|
2682
|
+
alpha: 255,
|
|
2683
|
+
blendFn: sourceOverPerfect,
|
|
2684
|
+
x: 0,
|
|
2685
|
+
y: 0,
|
|
2686
|
+
w: 0,
|
|
2687
|
+
h: 0
|
|
2688
|
+
};
|
|
2689
|
+
_inProgress = false;
|
|
2690
|
+
constructor(target, mutatorFactory, options) {
|
|
2691
|
+
const tileSize = options?.tileSize ?? 256;
|
|
2692
|
+
const maxHistorySteps = options?.maxHistorySteps ?? 50;
|
|
2693
|
+
this.config = new PixelEngineConfig(tileSize, target);
|
|
2694
|
+
this.historyManager = options?.historyManager ?? new HistoryManager(maxHistorySteps);
|
|
2695
|
+
this.historyActionFactory = options?.historyActionFactory ?? makeHistoryAction;
|
|
2696
|
+
this.pixelTilePool = options?.pixelTilePool ?? new PixelTilePool(this.config);
|
|
2697
|
+
this.accumulator = options?.accumulator ?? new PixelAccumulator(this.config, this.pixelTilePool);
|
|
2698
|
+
this.mutator = mutatorFactory(this);
|
|
2699
|
+
this.paintBuffer = new PaintBuffer(this.config, this.pixelTilePool);
|
|
2700
|
+
}
|
|
2701
|
+
/**
|
|
2702
|
+
* Executes `transaction` and commits the resulting pixel changes as a single
|
|
2703
|
+
* undoable history action.
|
|
2704
|
+
*
|
|
2705
|
+
* - If `transaction` throws, all accumulated changes are rolled back and the error
|
|
2706
|
+
* is re-thrown. No action is committed.
|
|
2707
|
+
* - If `transaction` completes without modifying any pixels, no action is committed.
|
|
2708
|
+
* - `withHistory` is not re-entrant. Calling it again from inside `transaction` will
|
|
2709
|
+
* throw immediately to prevent silent data loss from a nested extractPatch.
|
|
2710
|
+
*
|
|
2711
|
+
* @param transaction Callback to be executed inside the transaction.
|
|
2712
|
+
* @param after Called after both undo and redo — use for generic change notifications.
|
|
2713
|
+
* @param afterUndo Called after undo only — use for dimension or state changes specific to undo.
|
|
2714
|
+
* @param afterRedo Called after redo only.
|
|
2715
|
+
*/
|
|
2716
|
+
withHistory(transaction, after, afterUndo, afterRedo) {
|
|
2717
|
+
if (this._inProgress) {
|
|
2718
|
+
throw new Error("withHistory is not re-entrant \u2014 commit or rollback the current operation first");
|
|
2719
|
+
}
|
|
2720
|
+
this._inProgress = true;
|
|
2721
|
+
try {
|
|
2722
|
+
transaction(this.mutator);
|
|
2723
|
+
} catch (e) {
|
|
2724
|
+
this.accumulator.rollbackAfterError();
|
|
2725
|
+
throw e;
|
|
2726
|
+
} finally {
|
|
2727
|
+
this._inProgress = false;
|
|
2728
|
+
}
|
|
2729
|
+
if (this.accumulator.beforeTiles.length === 0) return;
|
|
2730
|
+
const patch = this.accumulator.extractPatch();
|
|
2731
|
+
const action = this.historyActionFactory(this.config, this.accumulator, patch, after, afterUndo, afterRedo);
|
|
2732
|
+
this.historyManager.commit(action);
|
|
2733
|
+
}
|
|
2734
|
+
resize(newWidth, newHeight, offsetX = 0, offsetY = 0, after, afterUndo, afterRedo, resizeImageDataFn = resizeImageData) {
|
|
2735
|
+
if (this._inProgress) {
|
|
2736
|
+
throw new Error("Cannot resize inside a withHistory callback");
|
|
2737
|
+
}
|
|
2738
|
+
if (this.accumulator.beforeTiles.length > 0) {
|
|
2739
|
+
throw new Error("Cannot resize with an open accumulator \u2014 commit or rollback first");
|
|
2740
|
+
}
|
|
2741
|
+
const config = this.config;
|
|
2742
|
+
const target = config.target;
|
|
2743
|
+
const beforeImageData = target.imageData;
|
|
2744
|
+
const afterImageData = resizeImageDataFn(beforeImageData, newWidth, newHeight, offsetX, offsetY);
|
|
2745
|
+
target.set(afterImageData);
|
|
2746
|
+
this.historyManager.commit({
|
|
2747
|
+
undo: () => {
|
|
2748
|
+
target.set(beforeImageData);
|
|
2749
|
+
afterUndo?.(beforeImageData);
|
|
2750
|
+
after?.(beforeImageData);
|
|
2751
|
+
},
|
|
2752
|
+
redo: () => {
|
|
2753
|
+
target.set(afterImageData);
|
|
2754
|
+
afterRedo?.(afterImageData);
|
|
2755
|
+
after?.(afterImageData);
|
|
2756
|
+
}
|
|
2757
|
+
});
|
|
2758
|
+
}
|
|
2759
|
+
commitPaintBuffer(alpha = 255, blendFn = sourceOverPerfect, blendPixelDataFn = blendPixelData) {
|
|
2760
|
+
const paintBuffer = this.paintBuffer;
|
|
2761
|
+
const tileShift = paintBuffer.config.tileShift;
|
|
2762
|
+
const lookup = paintBuffer.lookup;
|
|
2763
|
+
const opts = this.blendPixelDataOpts;
|
|
2764
|
+
opts.alpha = alpha;
|
|
2765
|
+
opts.blendFn = blendFn;
|
|
2766
|
+
for (let i = 0; i < lookup.length; i++) {
|
|
2767
|
+
const tile = lookup[i];
|
|
2768
|
+
if (tile) {
|
|
2769
|
+
const didChange = this.accumulator.storeTileBeforeState(tile.id, tile.tx, tile.ty);
|
|
2770
|
+
const dx = tile.tx << tileShift;
|
|
2771
|
+
const dy = tile.ty << tileShift;
|
|
2772
|
+
opts.x = dx;
|
|
2773
|
+
opts.y = dy;
|
|
2774
|
+
opts.w = tile.width;
|
|
2775
|
+
opts.h = tile.height;
|
|
2776
|
+
didChange(blendPixelDataFn(this.config.target, tile, opts));
|
|
2777
|
+
}
|
|
2778
|
+
}
|
|
2779
|
+
paintBuffer.clear();
|
|
2780
|
+
}
|
|
2781
|
+
};
|
|
2782
|
+
|
|
2783
|
+
// src/History/PixelMutator/mutatorApplyAlphaMask.ts
|
|
2784
|
+
var defaults2 = {
|
|
2785
|
+
applyAlphaMaskToPixelData
|
|
2786
|
+
};
|
|
2787
|
+
var mutatorApplyAlphaMask = ((writer, deps = defaults2) => {
|
|
2788
|
+
const {
|
|
2789
|
+
applyAlphaMaskToPixelData: applyAlphaMaskToPixelData2 = defaults2.applyAlphaMaskToPixelData
|
|
2790
|
+
} = deps;
|
|
2791
|
+
return {
|
|
2792
|
+
applyAlphaMask(mask, opts) {
|
|
2793
|
+
const target = writer.config.target;
|
|
2794
|
+
const x = opts?.x ?? 0;
|
|
2795
|
+
const y = opts?.y ?? 0;
|
|
2796
|
+
const w = opts?.w ?? target.width;
|
|
2797
|
+
const h = opts?.h ?? target.height;
|
|
2798
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2799
|
+
return didChange(applyAlphaMaskToPixelData2(target, mask, opts));
|
|
2800
|
+
}
|
|
2801
|
+
};
|
|
2802
|
+
});
|
|
2803
|
+
|
|
2804
|
+
// src/PixelData/applyBinaryMaskToPixelData.ts
|
|
2805
|
+
function applyBinaryMaskToPixelData(target, mask, opts) {
|
|
2806
|
+
const targetX = opts?.x ?? 0;
|
|
2807
|
+
const targetY = opts?.y ?? 0;
|
|
2808
|
+
const width = opts?.w ?? target.width;
|
|
2809
|
+
const height = opts?.h ?? target.height;
|
|
2810
|
+
const globalAlpha = opts?.alpha ?? 255;
|
|
2811
|
+
const mx = opts?.mx ?? 0;
|
|
2812
|
+
const my = opts?.my ?? 0;
|
|
2813
|
+
const invertMask = opts?.invertMask ?? false;
|
|
2814
|
+
if (globalAlpha === 0) return false;
|
|
2815
|
+
let x = targetX;
|
|
2816
|
+
let y = targetY;
|
|
2817
|
+
let w = width;
|
|
2818
|
+
let h = height;
|
|
2819
|
+
if (x < 0) {
|
|
2820
|
+
w += x;
|
|
2821
|
+
x = 0;
|
|
2822
|
+
}
|
|
2823
|
+
if (y < 0) {
|
|
2824
|
+
h += y;
|
|
2825
|
+
y = 0;
|
|
2826
|
+
}
|
|
2827
|
+
w = Math.min(w, target.width - x);
|
|
2828
|
+
h = Math.min(h, target.height - y);
|
|
2829
|
+
if (w <= 0 || h <= 0) return false;
|
|
2830
|
+
const mPitch = mask.w;
|
|
2831
|
+
if (mPitch <= 0) return false;
|
|
2832
|
+
const startX = mx + (x - targetX);
|
|
2833
|
+
const startY = my + (y - targetY);
|
|
2834
|
+
const sX0 = Math.max(0, startX);
|
|
2835
|
+
const sY0 = Math.max(0, startY);
|
|
2836
|
+
const sX1 = Math.min(mPitch, startX + w);
|
|
2837
|
+
const sY1 = Math.min(mask.h, startY + h);
|
|
2838
|
+
const finalW = sX1 - sX0;
|
|
2839
|
+
const finalH = sY1 - sY0;
|
|
2840
|
+
if (finalW <= 0 || finalH <= 0) {
|
|
2841
|
+
return false;
|
|
2842
|
+
}
|
|
2843
|
+
const xShift = sX0 - startX;
|
|
2844
|
+
const yShift = sY0 - startY;
|
|
2845
|
+
const dst32 = target.data32;
|
|
2846
|
+
const dw = target.width;
|
|
2847
|
+
const dStride = dw - finalW;
|
|
2848
|
+
const mStride = mPitch - finalW;
|
|
2849
|
+
const maskData = mask.data;
|
|
2850
|
+
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
2851
|
+
let mIdx = sY0 * mPitch + sX0;
|
|
2852
|
+
let didChange = false;
|
|
2853
|
+
for (let iy = 0; iy < finalH; iy++) {
|
|
2854
|
+
for (let ix = 0; ix < finalW; ix++) {
|
|
2855
|
+
const mVal = maskData[mIdx];
|
|
2856
|
+
const isMaskedOut = invertMask ? mVal !== 0 : mVal === 0;
|
|
2857
|
+
if (isMaskedOut) {
|
|
2858
|
+
const current = dst32[dIdx];
|
|
2859
|
+
const next = (current & 16777215) >>> 0;
|
|
2860
|
+
if (current !== next) {
|
|
2861
|
+
dst32[dIdx] = next;
|
|
2862
|
+
didChange = true;
|
|
2863
|
+
}
|
|
2864
|
+
} else if (globalAlpha !== 255) {
|
|
2865
|
+
const d = dst32[dIdx];
|
|
2866
|
+
const da = d >>> 24;
|
|
2867
|
+
if (da !== 0) {
|
|
2868
|
+
const finalAlpha = da === 255 ? globalAlpha : da * globalAlpha + 128 >> 8;
|
|
2869
|
+
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
2870
|
+
if (d !== next) {
|
|
2871
|
+
dst32[dIdx] = next;
|
|
2872
|
+
didChange = true;
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2875
|
+
}
|
|
2876
|
+
dIdx++;
|
|
2877
|
+
mIdx++;
|
|
2878
|
+
}
|
|
2879
|
+
dIdx += dStride;
|
|
2880
|
+
mIdx += mStride;
|
|
2881
|
+
}
|
|
2882
|
+
return didChange;
|
|
2883
|
+
}
|
|
2884
|
+
|
|
2885
|
+
// src/History/PixelMutator/mutatorApplyBinaryMask.ts
|
|
2886
|
+
var defaults3 = {
|
|
2887
|
+
applyBinaryMaskToPixelData
|
|
2888
|
+
};
|
|
2889
|
+
var mutatorApplyBinaryMask = ((writer, deps = defaults3) => {
|
|
2890
|
+
const {
|
|
2891
|
+
applyBinaryMaskToPixelData: applyBinaryMaskToPixelData2 = defaults3.applyBinaryMaskToPixelData
|
|
2892
|
+
} = deps;
|
|
2893
|
+
return {
|
|
2894
|
+
applyBinaryMask(mask, opts) {
|
|
2895
|
+
const target = writer.config.target;
|
|
2896
|
+
const x = opts?.x ?? 0;
|
|
2897
|
+
const y = opts?.y ?? 0;
|
|
2898
|
+
const w = opts?.w ?? target.width;
|
|
2899
|
+
const h = opts?.h ?? target.height;
|
|
2900
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2901
|
+
return didChange(applyBinaryMaskToPixelData2(target, mask, opts));
|
|
2902
|
+
}
|
|
2903
|
+
};
|
|
2904
|
+
});
|
|
2905
|
+
|
|
2906
|
+
// src/History/PixelMutator/mutatorApplyMask.ts
|
|
2907
|
+
var defaults4 = {
|
|
2908
|
+
applyBinaryMaskToPixelData,
|
|
2909
|
+
applyAlphaMaskToPixelData
|
|
2910
|
+
};
|
|
2911
|
+
var mutatorApplyMask = ((writer, deps = defaults4) => {
|
|
2912
|
+
const {
|
|
2913
|
+
applyBinaryMaskToPixelData: applyBinaryMaskToPixelData2 = defaults4.applyBinaryMaskToPixelData,
|
|
2914
|
+
applyAlphaMaskToPixelData: applyAlphaMaskToPixelData2 = defaults4.applyAlphaMaskToPixelData
|
|
2915
|
+
} = deps;
|
|
2916
|
+
return {
|
|
2917
|
+
applyMask(mask, opts) {
|
|
2918
|
+
const target = writer.config.target;
|
|
2919
|
+
const x = opts?.x ?? 0;
|
|
2920
|
+
const y = opts?.y ?? 0;
|
|
2921
|
+
const w = opts?.w ?? target.width;
|
|
2922
|
+
const h = opts?.h ?? target.height;
|
|
2923
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2924
|
+
if (mask.type === 1 /* BINARY */) {
|
|
2925
|
+
return didChange(applyBinaryMaskToPixelData2(target, mask, opts));
|
|
2926
|
+
} else {
|
|
2927
|
+
return didChange(applyAlphaMaskToPixelData2(target, mask, opts));
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2930
|
+
};
|
|
2931
|
+
});
|
|
2932
|
+
|
|
2933
|
+
// src/PixelData/blendPixelDataAlphaMask.ts
|
|
2934
|
+
function blendPixelDataAlphaMask(target, src, alphaMask, opts) {
|
|
2935
|
+
const targetX = opts?.x ?? 0;
|
|
2936
|
+
const targetY = opts?.y ?? 0;
|
|
2937
|
+
const sourceX = opts?.sx ?? 0;
|
|
2938
|
+
const sourceY = opts?.sy ?? 0;
|
|
2939
|
+
const width = opts?.w ?? src.width;
|
|
2940
|
+
const height = opts?.h ?? src.height;
|
|
2941
|
+
const globalAlpha = opts?.alpha ?? 255;
|
|
2942
|
+
const blendFn = opts?.blendFn ?? sourceOverPerfect;
|
|
2943
|
+
const mx = opts?.mx ?? 0;
|
|
2944
|
+
const my = opts?.my ?? 0;
|
|
2945
|
+
const invertMask = opts?.invertMask ?? false;
|
|
2946
|
+
if (globalAlpha === 0) return false;
|
|
2466
2947
|
let x = targetX;
|
|
2467
2948
|
let y = targetY;
|
|
2468
2949
|
let sx = sourceX;
|
|
@@ -2491,16 +2972,16 @@ function blendPixelDataAlphaMask(dst, src, alphaMask, opts = {}) {
|
|
|
2491
2972
|
h += y;
|
|
2492
2973
|
y = 0;
|
|
2493
2974
|
}
|
|
2494
|
-
const actualW = Math.min(w,
|
|
2495
|
-
const actualH = Math.min(h,
|
|
2975
|
+
const actualW = Math.min(w, target.width - x);
|
|
2976
|
+
const actualH = Math.min(h, target.height - y);
|
|
2496
2977
|
if (actualW <= 0 || actualH <= 0) return false;
|
|
2497
|
-
const dw =
|
|
2978
|
+
const dw = target.width;
|
|
2498
2979
|
const sw = src.width;
|
|
2499
2980
|
const mPitch = alphaMask.w;
|
|
2500
2981
|
const maskData = alphaMask.data;
|
|
2501
2982
|
const dx = x - targetX | 0;
|
|
2502
2983
|
const dy = y - targetY | 0;
|
|
2503
|
-
const dst32 =
|
|
2984
|
+
const dst32 = target.data32;
|
|
2504
2985
|
const src32 = src.data32;
|
|
2505
2986
|
let dIdx = y * dw + x | 0;
|
|
2506
2987
|
let sIdx = sy * sw + sx | 0;
|
|
@@ -2569,20 +3050,20 @@ function blendPixelDataAlphaMask(dst, src, alphaMask, opts = {}) {
|
|
|
2569
3050
|
return didChange;
|
|
2570
3051
|
}
|
|
2571
3052
|
|
|
2572
|
-
// src/History/PixelMutator/
|
|
3053
|
+
// src/History/PixelMutator/mutatorBlendAlphaMask.ts
|
|
2573
3054
|
var defaults5 = {
|
|
2574
3055
|
blendPixelDataAlphaMask
|
|
2575
3056
|
};
|
|
2576
|
-
var
|
|
3057
|
+
var mutatorBlendAlphaMask = ((writer, deps = defaults5) => {
|
|
2577
3058
|
const {
|
|
2578
3059
|
blendPixelDataAlphaMask: blendPixelDataAlphaMask2 = defaults5.blendPixelDataAlphaMask
|
|
2579
3060
|
} = deps;
|
|
2580
3061
|
return {
|
|
2581
|
-
|
|
2582
|
-
const x = opts
|
|
2583
|
-
const y = opts
|
|
2584
|
-
const w = opts
|
|
2585
|
-
const h = opts
|
|
3062
|
+
blendAlphaMask(src, mask, opts) {
|
|
3063
|
+
const x = opts?.x ?? 0;
|
|
3064
|
+
const y = opts?.y ?? 0;
|
|
3065
|
+
const w = opts?.w ?? src.width;
|
|
3066
|
+
const h = opts?.h ?? src.height;
|
|
2586
3067
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2587
3068
|
return didChange(blendPixelDataAlphaMask2(writer.config.target, src, mask, opts));
|
|
2588
3069
|
}
|
|
@@ -2590,20 +3071,18 @@ var mutatorBlendPixelDataAlphaMask = ((writer, deps = defaults5) => {
|
|
|
2590
3071
|
});
|
|
2591
3072
|
|
|
2592
3073
|
// src/PixelData/blendPixelDataBinaryMask.ts
|
|
2593
|
-
function blendPixelDataBinaryMask(
|
|
2594
|
-
const
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
invertMask = false
|
|
2606
|
-
} = opts;
|
|
3074
|
+
function blendPixelDataBinaryMask(target, src, binaryMask, opts) {
|
|
3075
|
+
const targetX = opts?.x ?? 0;
|
|
3076
|
+
const targetY = opts?.y ?? 0;
|
|
3077
|
+
const sourceX = opts?.sx ?? 0;
|
|
3078
|
+
const sourceY = opts?.sy ?? 0;
|
|
3079
|
+
const width = opts?.w ?? src.width;
|
|
3080
|
+
const height = opts?.h ?? src.height;
|
|
3081
|
+
const globalAlpha = opts?.alpha ?? 255;
|
|
3082
|
+
const blendFn = opts?.blendFn ?? sourceOverPerfect;
|
|
3083
|
+
const mx = opts?.mx ?? 0;
|
|
3084
|
+
const my = opts?.my ?? 0;
|
|
3085
|
+
const invertMask = opts?.invertMask ?? false;
|
|
2607
3086
|
if (globalAlpha === 0) return false;
|
|
2608
3087
|
let x = targetX;
|
|
2609
3088
|
let y = targetY;
|
|
@@ -2633,14 +3112,14 @@ function blendPixelDataBinaryMask(dst, src, binaryMask, opts = {}) {
|
|
|
2633
3112
|
h += y;
|
|
2634
3113
|
y = 0;
|
|
2635
3114
|
}
|
|
2636
|
-
const actualW = Math.min(w,
|
|
2637
|
-
const actualH = Math.min(h,
|
|
3115
|
+
const actualW = Math.min(w, target.width - x);
|
|
3116
|
+
const actualH = Math.min(h, target.height - y);
|
|
2638
3117
|
if (actualW <= 0 || actualH <= 0) return false;
|
|
2639
3118
|
const dx = x - targetX | 0;
|
|
2640
3119
|
const dy = y - targetY | 0;
|
|
2641
|
-
const dst32 =
|
|
3120
|
+
const dst32 = target.data32;
|
|
2642
3121
|
const src32 = src.data32;
|
|
2643
|
-
const dw =
|
|
3122
|
+
const dw = target.width;
|
|
2644
3123
|
const sw = src.width;
|
|
2645
3124
|
const mPitch = binaryMask.w;
|
|
2646
3125
|
const maskData = binaryMask.data;
|
|
@@ -2698,1146 +3177,744 @@ function blendPixelDataBinaryMask(dst, src, binaryMask, opts = {}) {
|
|
|
2698
3177
|
return didChange;
|
|
2699
3178
|
}
|
|
2700
3179
|
|
|
2701
|
-
// src/History/PixelMutator/
|
|
3180
|
+
// src/History/PixelMutator/mutatorBlendBinaryMask.ts
|
|
2702
3181
|
var defaults6 = {
|
|
2703
3182
|
blendPixelDataBinaryMask
|
|
2704
3183
|
};
|
|
2705
|
-
var
|
|
3184
|
+
var mutatorBlendBinaryMask = ((writer, deps = defaults6) => {
|
|
2706
3185
|
const {
|
|
2707
3186
|
blendPixelDataBinaryMask: blendPixelDataBinaryMask2 = defaults6.blendPixelDataBinaryMask
|
|
2708
3187
|
} = deps;
|
|
2709
3188
|
return {
|
|
2710
|
-
|
|
2711
|
-
const x = opts
|
|
2712
|
-
const y = opts
|
|
2713
|
-
const w = opts
|
|
2714
|
-
const h = opts
|
|
3189
|
+
blendBinaryMask(src, mask, opts) {
|
|
3190
|
+
const x = opts?.x ?? 0;
|
|
3191
|
+
const y = opts?.y ?? 0;
|
|
3192
|
+
const w = opts?.w ?? src.width;
|
|
3193
|
+
const h = opts?.h ?? src.height;
|
|
2715
3194
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2716
3195
|
return didChange(blendPixelDataBinaryMask2(writer.config.target, src, mask, opts));
|
|
2717
3196
|
}
|
|
2718
3197
|
};
|
|
2719
3198
|
});
|
|
2720
3199
|
|
|
2721
|
-
// src/PixelData/
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
3200
|
+
// src/PixelData/blendColorPixelData.ts
|
|
3201
|
+
function blendColorPixelData(target, color, opts) {
|
|
3202
|
+
const targetX = opts?.x ?? 0;
|
|
3203
|
+
const targetY = opts?.y ?? 0;
|
|
3204
|
+
const width = opts?.w ?? target.width;
|
|
3205
|
+
const height = opts?.h ?? target.height;
|
|
3206
|
+
const globalAlpha = opts?.alpha ?? 255;
|
|
3207
|
+
const blendFn = opts?.blendFn ?? sourceOverPerfect;
|
|
3208
|
+
if (globalAlpha === 0) return false;
|
|
3209
|
+
const baseSrcAlpha = color >>> 24;
|
|
3210
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
3211
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
3212
|
+
let x = targetX;
|
|
3213
|
+
let y = targetY;
|
|
3214
|
+
let w = width;
|
|
3215
|
+
let h = height;
|
|
3216
|
+
if (x < 0) {
|
|
3217
|
+
w += x;
|
|
2739
3218
|
x = 0;
|
|
3219
|
+
}
|
|
3220
|
+
if (y < 0) {
|
|
3221
|
+
h += y;
|
|
2740
3222
|
y = 0;
|
|
2741
|
-
w = dst.width;
|
|
2742
|
-
h = dst.height;
|
|
2743
3223
|
}
|
|
2744
|
-
const
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
const dst32 = dst.data32;
|
|
2753
|
-
const dw = dst.width;
|
|
2754
|
-
if (actualW === dw && actualH === dst.height && finalX === 0 && finalY === 0) {
|
|
2755
|
-
dst32.fill(color);
|
|
2756
|
-
return;
|
|
3224
|
+
const actualW = Math.min(w, target.width - x);
|
|
3225
|
+
const actualH = Math.min(h, target.height - y);
|
|
3226
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
3227
|
+
let finalSrcColor = color;
|
|
3228
|
+
if (globalAlpha < 255) {
|
|
3229
|
+
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
3230
|
+
if (a === 0 && !isOverwrite) return false;
|
|
3231
|
+
finalSrcColor = (color & 16777215 | a << 24) >>> 0;
|
|
2757
3232
|
}
|
|
3233
|
+
const dst32 = target.data32;
|
|
3234
|
+
const dw = target.width;
|
|
3235
|
+
let dIdx = y * dw + x | 0;
|
|
3236
|
+
const dStride = dw - actualW | 0;
|
|
3237
|
+
let didChange = false;
|
|
2758
3238
|
for (let iy = 0; iy < actualH; iy++) {
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
3239
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
3240
|
+
const current = dst32[dIdx];
|
|
3241
|
+
const next = blendFn(finalSrcColor, current);
|
|
3242
|
+
if (current !== next) {
|
|
3243
|
+
dst32[dIdx] = next;
|
|
3244
|
+
didChange = true;
|
|
3245
|
+
}
|
|
3246
|
+
dIdx++;
|
|
3247
|
+
}
|
|
3248
|
+
dIdx += dStride;
|
|
2762
3249
|
}
|
|
3250
|
+
return didChange;
|
|
2763
3251
|
}
|
|
2764
3252
|
|
|
2765
|
-
// src/History/PixelMutator/
|
|
3253
|
+
// src/History/PixelMutator/mutatorBlendColor.ts
|
|
2766
3254
|
var defaults7 = {
|
|
2767
|
-
|
|
3255
|
+
blendColorPixelData
|
|
2768
3256
|
};
|
|
2769
|
-
var
|
|
3257
|
+
var mutatorBlendColor = ((writer, deps = defaults7) => {
|
|
2770
3258
|
const {
|
|
2771
|
-
|
|
3259
|
+
blendColorPixelData: blendColorPixelData2 = defaults7.blendColorPixelData
|
|
2772
3260
|
} = deps;
|
|
2773
3261
|
return {
|
|
2774
|
-
|
|
3262
|
+
blendColor(color, opts) {
|
|
2775
3263
|
const target = writer.config.target;
|
|
2776
|
-
const x =
|
|
2777
|
-
const y =
|
|
2778
|
-
const w =
|
|
2779
|
-
const h =
|
|
2780
|
-
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2781
|
-
|
|
3264
|
+
const x = opts?.x ?? 0;
|
|
3265
|
+
const y = opts?.y ?? 0;
|
|
3266
|
+
const w = opts?.w ?? target.width;
|
|
3267
|
+
const h = opts?.h ?? target.height;
|
|
3268
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3269
|
+
return didChange(blendColorPixelData2(target, color, opts));
|
|
2782
3270
|
}
|
|
2783
3271
|
};
|
|
2784
3272
|
});
|
|
2785
3273
|
|
|
2786
|
-
// src/PixelData/
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
3274
|
+
// src/PixelData/blendColorPixelDataAlphaMask.ts
|
|
3275
|
+
function blendColorPixelDataAlphaMask(target, color, mask, opts) {
|
|
3276
|
+
const targetX = opts?.x ?? 0;
|
|
3277
|
+
const targetY = opts?.y ?? 0;
|
|
3278
|
+
const w = opts?.w ?? mask.w;
|
|
3279
|
+
const h = opts?.h ?? mask.h;
|
|
3280
|
+
const globalAlpha = opts?.alpha ?? 255;
|
|
3281
|
+
const blendFn = opts?.blendFn ?? sourceOverPerfect;
|
|
3282
|
+
const mx = opts?.mx ?? 0;
|
|
3283
|
+
const my = opts?.my ?? 0;
|
|
3284
|
+
const invertMask = opts?.invertMask ?? false;
|
|
3285
|
+
if (globalAlpha === 0) return false;
|
|
3286
|
+
const baseSrcAlpha = color >>> 24;
|
|
3287
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
3288
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
3289
|
+
let x = targetX;
|
|
3290
|
+
let y = targetY;
|
|
3291
|
+
let actualW = w;
|
|
3292
|
+
let actualH = h;
|
|
3293
|
+
if (x < 0) {
|
|
3294
|
+
actualW += x;
|
|
2804
3295
|
x = 0;
|
|
3296
|
+
}
|
|
3297
|
+
if (y < 0) {
|
|
3298
|
+
actualH += y;
|
|
2805
3299
|
y = 0;
|
|
2806
|
-
w = dst.width;
|
|
2807
|
-
h = dst.height;
|
|
2808
3300
|
}
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
const
|
|
2818
|
-
|
|
2819
|
-
let
|
|
3301
|
+
actualW = Math.min(actualW, target.width - x);
|
|
3302
|
+
actualH = Math.min(actualH, target.height - y);
|
|
3303
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
3304
|
+
const dx = x - targetX | 0;
|
|
3305
|
+
const dy = y - targetY | 0;
|
|
3306
|
+
const dst32 = target.data32;
|
|
3307
|
+
const dw = target.width;
|
|
3308
|
+
const mPitch = mask.w;
|
|
3309
|
+
const maskData = mask.data;
|
|
3310
|
+
let dIdx = y * dw + x | 0;
|
|
3311
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
3312
|
+
const dStride = dw - actualW | 0;
|
|
3313
|
+
const mStride = mPitch - actualW | 0;
|
|
3314
|
+
const isOpaque = globalAlpha === 255;
|
|
3315
|
+
const colorRGB = color & 16777215;
|
|
3316
|
+
let didChange = false;
|
|
2820
3317
|
for (let iy = 0; iy < actualH; iy++) {
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
3318
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
3319
|
+
const mVal = maskData[mIdx];
|
|
3320
|
+
const effM = invertMask ? 255 - mVal : mVal;
|
|
3321
|
+
if (effM === 0) {
|
|
3322
|
+
dIdx++;
|
|
3323
|
+
mIdx++;
|
|
3324
|
+
continue;
|
|
3325
|
+
}
|
|
3326
|
+
let weight = globalAlpha;
|
|
3327
|
+
if (isOpaque) {
|
|
3328
|
+
weight = effM;
|
|
3329
|
+
} else if (effM !== 255) {
|
|
3330
|
+
weight = effM * globalAlpha + 128 >> 8;
|
|
2828
3331
|
}
|
|
3332
|
+
if (weight === 0) {
|
|
3333
|
+
dIdx++;
|
|
3334
|
+
mIdx++;
|
|
3335
|
+
continue;
|
|
3336
|
+
}
|
|
3337
|
+
let finalCol = color;
|
|
3338
|
+
if (weight < 255) {
|
|
3339
|
+
const a = baseSrcAlpha * weight + 128 >> 8;
|
|
3340
|
+
if (a === 0 && !isOverwrite) {
|
|
3341
|
+
dIdx++;
|
|
3342
|
+
mIdx++;
|
|
3343
|
+
continue;
|
|
3344
|
+
}
|
|
3345
|
+
finalCol = (colorRGB | a << 24) >>> 0;
|
|
3346
|
+
}
|
|
3347
|
+
const current = dst32[dIdx];
|
|
3348
|
+
const next = blendFn(finalCol, current);
|
|
3349
|
+
if (current !== next) {
|
|
3350
|
+
dst32[dIdx] = next;
|
|
3351
|
+
didChange = true;
|
|
3352
|
+
}
|
|
3353
|
+
dIdx++;
|
|
3354
|
+
mIdx++;
|
|
2829
3355
|
}
|
|
3356
|
+
dIdx += dStride;
|
|
3357
|
+
mIdx += mStride;
|
|
2830
3358
|
}
|
|
2831
|
-
return
|
|
3359
|
+
return didChange;
|
|
2832
3360
|
}
|
|
2833
3361
|
|
|
2834
|
-
// src/History/PixelMutator/
|
|
3362
|
+
// src/History/PixelMutator/mutatorBlendColorPaintAlphaMask.ts
|
|
2835
3363
|
var defaults8 = {
|
|
2836
|
-
|
|
3364
|
+
blendColorPixelDataAlphaMask
|
|
2837
3365
|
};
|
|
2838
|
-
var
|
|
3366
|
+
var mutatorBlendColorPaintAlphaMask = ((writer, deps = defaults8) => {
|
|
2839
3367
|
const {
|
|
2840
|
-
|
|
3368
|
+
blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults8.blendColorPixelDataAlphaMask
|
|
2841
3369
|
} = deps;
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
}
|
|
3370
|
+
const OPTS = {
|
|
3371
|
+
x: 0,
|
|
3372
|
+
y: 0,
|
|
3373
|
+
blendFn: sourceOverPerfect,
|
|
3374
|
+
alpha: 255
|
|
2848
3375
|
};
|
|
2849
|
-
});
|
|
2850
|
-
var mutatorFillRect = ((writer, deps = defaults8) => {
|
|
2851
|
-
const {
|
|
2852
|
-
fillPixelData: fillPixelData2 = defaults8.fillPixelData
|
|
2853
|
-
} = deps;
|
|
2854
3376
|
return {
|
|
2855
|
-
|
|
2856
|
-
const
|
|
2857
|
-
const
|
|
2858
|
-
|
|
3377
|
+
blendColorPaintAlphaMask(color, mask, x, y, alpha = 255, blendFn = sourceOverPerfect) {
|
|
3378
|
+
const tx = x + mask.centerOffsetX;
|
|
3379
|
+
const ty = y + mask.centerOffsetY;
|
|
3380
|
+
const didChange = writer.accumulator.storeRegionBeforeState(tx, ty, mask.w, mask.h);
|
|
3381
|
+
OPTS.x = tx;
|
|
3382
|
+
OPTS.y = ty;
|
|
3383
|
+
OPTS.alpha = alpha;
|
|
3384
|
+
OPTS.blendFn = blendFn;
|
|
3385
|
+
return didChange(blendColorPixelDataAlphaMask2(writer.config.target, color, mask, OPTS));
|
|
2859
3386
|
}
|
|
2860
3387
|
};
|
|
2861
3388
|
});
|
|
2862
3389
|
|
|
2863
|
-
// src/PixelData/
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
const
|
|
2870
|
-
|
|
2871
|
-
const
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
const colorRGB = color & 16777215;
|
|
2884
|
-
const a = baseSrcAlpha * alpha + 128 >> 8;
|
|
2885
|
-
finalCol = (colorRGB | a << 24) >>> 0;
|
|
2886
|
-
}
|
|
2887
|
-
let hasChanged = false;
|
|
2888
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
2889
|
-
const currentY = finalY + iy;
|
|
2890
|
-
const maskY = currentY - y;
|
|
2891
|
-
const maskOffset = maskY * maskW;
|
|
2892
|
-
const dstRowOffset = currentY * dw;
|
|
2893
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
2894
|
-
const currentX = finalX + ix;
|
|
2895
|
-
const maskX = currentX - x;
|
|
2896
|
-
const maskIndex = maskOffset + maskX;
|
|
2897
|
-
if (maskData[maskIndex]) {
|
|
2898
|
-
const current = dst32[dstRowOffset + currentX];
|
|
2899
|
-
if (current !== finalCol) {
|
|
2900
|
-
dst32[dstRowOffset + currentX] = finalCol;
|
|
2901
|
-
hasChanged = true;
|
|
2902
|
-
}
|
|
2903
|
-
}
|
|
2904
|
-
}
|
|
3390
|
+
// src/PixelData/blendColorPixelDataBinaryMask.ts
|
|
3391
|
+
function blendColorPixelDataBinaryMask(target, color, mask, opts) {
|
|
3392
|
+
const targetX = opts?.x ?? 0;
|
|
3393
|
+
const targetY = opts?.y ?? 0;
|
|
3394
|
+
let w = opts?.w ?? mask.w;
|
|
3395
|
+
let h = opts?.h ?? mask.h;
|
|
3396
|
+
const globalAlpha = opts?.alpha ?? 255;
|
|
3397
|
+
const blendFn = opts?.blendFn ?? sourceOverPerfect;
|
|
3398
|
+
const mx = opts?.mx ?? 0;
|
|
3399
|
+
const my = opts?.my ?? 0;
|
|
3400
|
+
const invertMask = opts?.invertMask ?? false;
|
|
3401
|
+
if (globalAlpha === 0) return false;
|
|
3402
|
+
const baseSrcAlpha = color >>> 24;
|
|
3403
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
3404
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
3405
|
+
let x = targetX;
|
|
3406
|
+
let y = targetY;
|
|
3407
|
+
if (x < 0) {
|
|
3408
|
+
w += x;
|
|
3409
|
+
x = 0;
|
|
2905
3410
|
}
|
|
2906
|
-
|
|
3411
|
+
if (y < 0) {
|
|
3412
|
+
h += y;
|
|
3413
|
+
y = 0;
|
|
3414
|
+
}
|
|
3415
|
+
const actualW = Math.min(w, target.width - x);
|
|
3416
|
+
const actualH = Math.min(h, target.height - y);
|
|
3417
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
3418
|
+
let baseColorWithGlobalAlpha = color;
|
|
3419
|
+
if (globalAlpha < 255) {
|
|
3420
|
+
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
3421
|
+
if (a === 0 && !isOverwrite) return false;
|
|
3422
|
+
baseColorWithGlobalAlpha = (color & 16777215 | a << 24) >>> 0;
|
|
3423
|
+
}
|
|
3424
|
+
const dx = x - targetX | 0;
|
|
3425
|
+
const dy = y - targetY | 0;
|
|
3426
|
+
const dst32 = target.data32;
|
|
3427
|
+
const dw = target.width;
|
|
3428
|
+
const mPitch = mask.w;
|
|
3429
|
+
const maskData = mask.data;
|
|
3430
|
+
let dIdx = y * dw + x | 0;
|
|
3431
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
3432
|
+
const dStride = dw - actualW | 0;
|
|
3433
|
+
const mStride = mPitch - actualW | 0;
|
|
3434
|
+
const skipVal = invertMask ? 1 : 0;
|
|
3435
|
+
let didChange = false;
|
|
3436
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
3437
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
3438
|
+
if (maskData[mIdx] === skipVal) {
|
|
3439
|
+
dIdx++;
|
|
3440
|
+
mIdx++;
|
|
3441
|
+
continue;
|
|
3442
|
+
}
|
|
3443
|
+
const current = dst32[dIdx];
|
|
3444
|
+
const next = blendFn(baseColorWithGlobalAlpha, current);
|
|
3445
|
+
if (current !== next) {
|
|
3446
|
+
dst32[dIdx] = next;
|
|
3447
|
+
didChange = true;
|
|
3448
|
+
}
|
|
3449
|
+
dIdx++;
|
|
3450
|
+
mIdx++;
|
|
3451
|
+
}
|
|
3452
|
+
dIdx += dStride;
|
|
3453
|
+
mIdx += mStride;
|
|
3454
|
+
}
|
|
3455
|
+
return didChange;
|
|
2907
3456
|
}
|
|
2908
3457
|
|
|
2909
|
-
// src/History/PixelMutator/
|
|
3458
|
+
// src/History/PixelMutator/mutatorBlendColorPaintBinaryMask.ts
|
|
2910
3459
|
var defaults9 = {
|
|
2911
|
-
|
|
3460
|
+
blendColorPixelDataBinaryMask
|
|
2912
3461
|
};
|
|
2913
|
-
var
|
|
3462
|
+
var mutatorBlendColorPaintBinaryMask = ((writer, deps = defaults9) => {
|
|
2914
3463
|
const {
|
|
2915
|
-
|
|
3464
|
+
blendColorPixelDataBinaryMask: blendColorPixelDataBinaryMask2 = defaults9.blendColorPixelDataBinaryMask
|
|
2916
3465
|
} = deps;
|
|
3466
|
+
const OPTS = {
|
|
3467
|
+
x: 0,
|
|
3468
|
+
y: 0,
|
|
3469
|
+
blendFn: sourceOverPerfect,
|
|
3470
|
+
alpha: 255
|
|
3471
|
+
};
|
|
2917
3472
|
return {
|
|
2918
|
-
|
|
2919
|
-
const
|
|
2920
|
-
|
|
3473
|
+
blendColorPaintBinaryMask(color, mask, x, y, alpha = 255, blendFn = sourceOverPerfect) {
|
|
3474
|
+
const tx = x + mask.centerOffsetX;
|
|
3475
|
+
const ty = y + mask.centerOffsetY;
|
|
3476
|
+
const didChange = writer.accumulator.storeRegionBeforeState(tx, ty, mask.w, mask.h);
|
|
3477
|
+
OPTS.x = tx;
|
|
3478
|
+
OPTS.y = ty;
|
|
3479
|
+
OPTS.alpha = alpha;
|
|
3480
|
+
OPTS.blendFn = blendFn;
|
|
3481
|
+
return didChange(blendColorPixelDataBinaryMask2(writer.config.target, color, mask, OPTS));
|
|
2921
3482
|
}
|
|
2922
3483
|
};
|
|
2923
3484
|
});
|
|
2924
3485
|
|
|
2925
|
-
// src/
|
|
2926
|
-
var
|
|
2927
|
-
|
|
2928
|
-
|
|
3486
|
+
// src/History/PixelMutator/mutatorBlendColorPaintMask.ts
|
|
3487
|
+
var defaults10 = {
|
|
3488
|
+
blendColorPixelDataAlphaMask,
|
|
3489
|
+
blendColorPixelDataBinaryMask
|
|
3490
|
+
};
|
|
3491
|
+
var mutatorBlendColorPaintMask = ((writer, deps = defaults10) => {
|
|
2929
3492
|
const {
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
}
|
|
2939
|
-
|
|
3493
|
+
blendColorPixelDataBinaryMask: blendColorPixelDataBinaryMask2 = defaults10.blendColorPixelDataBinaryMask,
|
|
3494
|
+
blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults10.blendColorPixelDataAlphaMask
|
|
3495
|
+
} = deps;
|
|
3496
|
+
const OPTS = {
|
|
3497
|
+
x: 0,
|
|
3498
|
+
y: 0,
|
|
3499
|
+
blendFn: sourceOverPerfect,
|
|
3500
|
+
alpha: 255
|
|
3501
|
+
};
|
|
3502
|
+
return {
|
|
3503
|
+
blendColorPaintMask(color, mask, x, y, alpha = 255, blendFn = sourceOverPerfect) {
|
|
3504
|
+
const tx = x + mask.centerOffsetX;
|
|
3505
|
+
const ty = y + mask.centerOffsetY;
|
|
3506
|
+
const didChange = writer.accumulator.storeRegionBeforeState(tx, ty, mask.w, mask.h);
|
|
3507
|
+
OPTS.x = tx;
|
|
3508
|
+
OPTS.y = ty;
|
|
3509
|
+
OPTS.alpha = alpha;
|
|
3510
|
+
OPTS.blendFn = blendFn;
|
|
3511
|
+
if (mask.type === 1 /* BINARY */) {
|
|
3512
|
+
return didChange(blendColorPixelDataBinaryMask2(writer.config.target, color, mask, OPTS));
|
|
3513
|
+
} else {
|
|
3514
|
+
return didChange(blendColorPixelDataAlphaMask2(writer.config.target, color, mask, OPTS));
|
|
3515
|
+
}
|
|
3516
|
+
}
|
|
3517
|
+
};
|
|
3518
|
+
});
|
|
3519
|
+
|
|
3520
|
+
// src/History/PixelMutator/mutatorBlendMask.ts
|
|
3521
|
+
var defaults11 = {
|
|
3522
|
+
blendPixelDataAlphaMask,
|
|
3523
|
+
blendPixelDataBinaryMask
|
|
3524
|
+
};
|
|
3525
|
+
var mutatorBlendMask = ((writer, deps = defaults11) => {
|
|
3526
|
+
const {
|
|
3527
|
+
blendPixelDataAlphaMask: blendPixelDataAlphaMask2 = defaults11.blendPixelDataAlphaMask,
|
|
3528
|
+
blendPixelDataBinaryMask: blendPixelDataBinaryMask2 = defaults11.blendPixelDataBinaryMask
|
|
3529
|
+
} = deps;
|
|
3530
|
+
return {
|
|
3531
|
+
blendMask(src, mask, opts) {
|
|
3532
|
+
const x = opts?.x ?? 0;
|
|
3533
|
+
const y = opts?.y ?? 0;
|
|
3534
|
+
const w = opts?.w ?? src.width;
|
|
3535
|
+
const h = opts?.h ?? src.height;
|
|
3536
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3537
|
+
if (mask.type === 1 /* BINARY */) {
|
|
3538
|
+
return didChange(blendPixelDataBinaryMask2(writer.config.target, src, mask, opts));
|
|
3539
|
+
} else {
|
|
3540
|
+
return didChange(blendPixelDataAlphaMask2(writer.config.target, src, mask, opts));
|
|
3541
|
+
}
|
|
3542
|
+
}
|
|
3543
|
+
};
|
|
3544
|
+
});
|
|
3545
|
+
|
|
3546
|
+
// src/History/PixelMutator/mutatorBlendPaintRect.ts
|
|
3547
|
+
var defaults12 = {
|
|
3548
|
+
blendColorPixelData
|
|
3549
|
+
};
|
|
3550
|
+
var mutatorBlendPaintRect = ((writer, deps = defaults12) => {
|
|
3551
|
+
const {
|
|
3552
|
+
blendColorPixelData: blendColorPixelData2 = defaults12.blendColorPixelData
|
|
3553
|
+
} = deps;
|
|
3554
|
+
const OPTS = {
|
|
3555
|
+
x: 0,
|
|
3556
|
+
y: 0,
|
|
3557
|
+
w: 0,
|
|
3558
|
+
h: 0,
|
|
3559
|
+
blendFn: sourceOverPerfect,
|
|
3560
|
+
alpha: 255
|
|
3561
|
+
};
|
|
3562
|
+
return {
|
|
3563
|
+
blendPaintRect(color, centerX, centerY, brushWidth, brushHeight, alpha = 255, blendFn = sourceOverPerfect) {
|
|
3564
|
+
const target = writer.config.target;
|
|
3565
|
+
const topLeftX = centerX + -(brushWidth - 1 >> 1);
|
|
3566
|
+
const topLeftY = centerY + -(brushHeight - 1 >> 1);
|
|
3567
|
+
OPTS.x = topLeftX;
|
|
3568
|
+
OPTS.y = topLeftY;
|
|
3569
|
+
OPTS.w = brushWidth;
|
|
3570
|
+
OPTS.h = brushHeight;
|
|
3571
|
+
OPTS.blendFn = blendFn;
|
|
3572
|
+
OPTS.alpha = alpha;
|
|
3573
|
+
const didChange = writer.accumulator.storeRegionBeforeState(topLeftX, topLeftY, brushWidth, brushHeight);
|
|
3574
|
+
return didChange(blendColorPixelData2(target, color, OPTS));
|
|
3575
|
+
}
|
|
3576
|
+
};
|
|
3577
|
+
});
|
|
3578
|
+
|
|
3579
|
+
// src/PixelData/blendPixel.ts
|
|
3580
|
+
function blendPixel(target, x, y, color, alpha = 255, blendFn = sourceOverPerfect) {
|
|
3581
|
+
if (alpha === 0) return false;
|
|
3582
|
+
let width = target.width;
|
|
3583
|
+
let height = target.height;
|
|
3584
|
+
if (x < 0 || x >= width || y < 0 || y >= height) return false;
|
|
3585
|
+
let srcAlpha = color >>> 24;
|
|
3586
|
+
let isOverwrite = blendFn.isOverwrite;
|
|
3587
|
+
if (srcAlpha === 0 && !isOverwrite) return false;
|
|
3588
|
+
let dst32 = target.data32;
|
|
3589
|
+
let index = y * width + x;
|
|
3590
|
+
let finalColor = color;
|
|
3591
|
+
if (alpha !== 255) {
|
|
3592
|
+
let finalAlpha = srcAlpha * alpha + 128 >> 8;
|
|
3593
|
+
if (finalAlpha === 0 && !isOverwrite) return false;
|
|
3594
|
+
finalColor = (color & 16777215 | finalAlpha << 24) >>> 0;
|
|
3595
|
+
}
|
|
3596
|
+
let current = dst32[index];
|
|
3597
|
+
let next = blendFn(finalColor, current);
|
|
3598
|
+
if (current !== next) {
|
|
3599
|
+
dst32[index] = next;
|
|
3600
|
+
return true;
|
|
3601
|
+
}
|
|
3602
|
+
return false;
|
|
3603
|
+
}
|
|
3604
|
+
|
|
3605
|
+
// src/History/PixelMutator/mutatorBlendPixel.ts
|
|
3606
|
+
var defaults13 = {
|
|
3607
|
+
blendPixel
|
|
3608
|
+
};
|
|
3609
|
+
var mutatorBlendPixel = ((writer, deps = defaults13) => {
|
|
3610
|
+
const {
|
|
3611
|
+
blendPixel: blendPixel2 = defaults13.blendPixel
|
|
3612
|
+
} = deps;
|
|
3613
|
+
return {
|
|
3614
|
+
blendPixel(x, y, color, alpha, blendFn) {
|
|
3615
|
+
const didChange = writer.accumulator.storePixelBeforeState(x, y);
|
|
3616
|
+
return didChange(blendPixel2(writer.config.target, x, y, color, alpha, blendFn));
|
|
3617
|
+
}
|
|
3618
|
+
};
|
|
3619
|
+
});
|
|
3620
|
+
|
|
3621
|
+
// src/History/PixelMutator/mutatorBlendPixelData.ts
|
|
3622
|
+
var defaults14 = {
|
|
3623
|
+
blendPixelData
|
|
3624
|
+
};
|
|
3625
|
+
var mutatorBlendPixelData = ((writer, deps = defaults14) => {
|
|
3626
|
+
const {
|
|
3627
|
+
blendPixelData: blendPixelData2 = defaults14.blendPixelData
|
|
3628
|
+
} = deps;
|
|
3629
|
+
return {
|
|
3630
|
+
blendPixelData(src, opts) {
|
|
3631
|
+
const x = opts?.x ?? 0;
|
|
3632
|
+
const y = opts?.y ?? 0;
|
|
3633
|
+
const w = opts?.w ?? src.width;
|
|
3634
|
+
const h = opts?.h ?? src.height;
|
|
3635
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3636
|
+
return didChange(blendPixelData2(writer.config.target, src, opts));
|
|
3637
|
+
}
|
|
3638
|
+
};
|
|
3639
|
+
});
|
|
3640
|
+
|
|
3641
|
+
// src/PixelData/fillPixelData.ts
|
|
3642
|
+
var SCRATCH_RECT = makeClippedRect();
|
|
3643
|
+
function fillPixelData(dst, color, _x, _y, _w, _h) {
|
|
3644
|
+
let x;
|
|
3645
|
+
let y;
|
|
3646
|
+
let w;
|
|
3647
|
+
let h;
|
|
3648
|
+
if (typeof _x === "object") {
|
|
3649
|
+
x = _x.x ?? 0;
|
|
3650
|
+
y = _x.y ?? 0;
|
|
3651
|
+
w = _x.w ?? dst.width;
|
|
3652
|
+
h = _x.h ?? dst.height;
|
|
3653
|
+
} else if (typeof _x === "number") {
|
|
3654
|
+
x = _x;
|
|
3655
|
+
y = _y;
|
|
3656
|
+
w = _w;
|
|
3657
|
+
h = _h;
|
|
3658
|
+
} else {
|
|
3659
|
+
x = 0;
|
|
3660
|
+
y = 0;
|
|
3661
|
+
w = dst.width;
|
|
3662
|
+
h = dst.height;
|
|
3663
|
+
}
|
|
3664
|
+
const clip = resolveRectClipping(x, y, w, h, dst.width, dst.height, SCRATCH_RECT);
|
|
2940
3665
|
if (!clip.inBounds) return false;
|
|
2941
3666
|
const {
|
|
2942
|
-
x,
|
|
2943
|
-
y,
|
|
3667
|
+
x: finalX,
|
|
3668
|
+
y: finalY,
|
|
2944
3669
|
w: actualW,
|
|
2945
3670
|
h: actualH
|
|
2946
3671
|
} = clip;
|
|
2947
3672
|
const dst32 = dst.data32;
|
|
2948
3673
|
const dw = dst.width;
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
2959
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
2960
|
-
const mVal = maskData[mIdx];
|
|
2961
|
-
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
2962
|
-
if (isHit) {
|
|
2963
|
-
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
2964
|
-
}
|
|
2965
|
-
dIdx++;
|
|
2966
|
-
mIdx++;
|
|
2967
|
-
}
|
|
2968
|
-
dIdx += dStride;
|
|
2969
|
-
mIdx += mStride;
|
|
2970
|
-
}
|
|
2971
|
-
} else {
|
|
2972
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
2973
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
2974
|
-
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
2975
|
-
dIdx++;
|
|
3674
|
+
let hasChanged = false;
|
|
3675
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
3676
|
+
const rowOffset = (finalY + iy) * dw;
|
|
3677
|
+
const start = rowOffset + finalX;
|
|
3678
|
+
const end = start + actualW;
|
|
3679
|
+
for (let i = start; i < end; i++) {
|
|
3680
|
+
if (dst32[i] !== color) {
|
|
3681
|
+
dst32[i] = color;
|
|
3682
|
+
hasChanged = true;
|
|
2976
3683
|
}
|
|
2977
|
-
dIdx += dStride;
|
|
2978
3684
|
}
|
|
2979
3685
|
}
|
|
2980
|
-
return
|
|
3686
|
+
return hasChanged;
|
|
2981
3687
|
}
|
|
2982
3688
|
|
|
2983
|
-
// src/History/PixelMutator/
|
|
2984
|
-
var
|
|
2985
|
-
|
|
3689
|
+
// src/History/PixelMutator/mutatorClear.ts
|
|
3690
|
+
var defaults15 = {
|
|
3691
|
+
fillPixelData
|
|
2986
3692
|
};
|
|
2987
|
-
var
|
|
3693
|
+
var mutatorClear = ((writer, deps = defaults15) => {
|
|
2988
3694
|
const {
|
|
2989
|
-
|
|
3695
|
+
fillPixelData: fillPixelData2 = defaults15.fillPixelData
|
|
2990
3696
|
} = deps;
|
|
2991
3697
|
return {
|
|
2992
|
-
|
|
3698
|
+
clear(rect) {
|
|
2993
3699
|
const target = writer.config.target;
|
|
2994
|
-
const
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
h = target.height
|
|
2999
|
-
} = opts;
|
|
3700
|
+
const x = rect?.x ?? 0;
|
|
3701
|
+
const y = rect?.y ?? 0;
|
|
3702
|
+
const w = rect?.w ?? target.width;
|
|
3703
|
+
const h = rect?.h ?? target.height;
|
|
3000
3704
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3001
|
-
return didChange(
|
|
3705
|
+
return didChange(fillPixelData2(target, 0, x, y, w, h));
|
|
3002
3706
|
}
|
|
3003
3707
|
};
|
|
3004
3708
|
});
|
|
3005
3709
|
|
|
3006
|
-
// src/History/PixelMutator.ts
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
// @sort
|
|
3010
|
-
...mutatorBlendColor(writer),
|
|
3011
|
-
...mutatorBlendPixel(writer),
|
|
3012
|
-
...mutatorBlendPixelData(writer),
|
|
3013
|
-
...mutatorBlendPixelDataAlphaMask(writer),
|
|
3014
|
-
...mutatorBlendPixelDataBinaryMask(writer),
|
|
3015
|
-
...mutatorClear(writer),
|
|
3016
|
-
...mutatorFill(writer),
|
|
3017
|
-
...mutatorFillBinaryMask(writer),
|
|
3018
|
-
...mutatorFillRect(writer),
|
|
3019
|
-
...mutatorInvert(writer)
|
|
3020
|
-
};
|
|
3021
|
-
}
|
|
3022
|
-
|
|
3023
|
-
// src/ImageData/resizeImageData.ts
|
|
3024
|
-
function resizeImageData(target, newWidth, newHeight, offsetX = 0, offsetY = 0) {
|
|
3025
|
-
const result = new ImageData(newWidth, newHeight);
|
|
3026
|
-
const {
|
|
3027
|
-
width: oldW,
|
|
3028
|
-
height: oldH,
|
|
3029
|
-
data: oldData
|
|
3030
|
-
} = target;
|
|
3031
|
-
const newData = result.data;
|
|
3032
|
-
const x0 = Math.max(0, offsetX);
|
|
3033
|
-
const y0 = Math.max(0, offsetY);
|
|
3034
|
-
const x1 = Math.min(newWidth, offsetX + oldW);
|
|
3035
|
-
const y1 = Math.min(newHeight, offsetY + oldH);
|
|
3036
|
-
if (x1 <= x0 || y1 <= y0) {
|
|
3037
|
-
return result;
|
|
3038
|
-
}
|
|
3039
|
-
const rowCount = y1 - y0;
|
|
3040
|
-
const rowLen = (x1 - x0) * 4;
|
|
3041
|
-
for (let row = 0; row < rowCount; row++) {
|
|
3042
|
-
const dstY = y0 + row;
|
|
3043
|
-
const srcY = dstY - offsetY;
|
|
3044
|
-
const srcX = x0 - offsetX;
|
|
3045
|
-
const dstStart = (dstY * newWidth + x0) * 4;
|
|
3046
|
-
const srcStart = (srcY * oldW + srcX) * 4;
|
|
3047
|
-
newData.set(oldData.subarray(srcStart, srcStart + rowLen), dstStart);
|
|
3048
|
-
}
|
|
3049
|
-
return result;
|
|
3050
|
-
}
|
|
3051
|
-
|
|
3052
|
-
// src/Internal/helpers.ts
|
|
3053
|
-
var macro_halfAndFloor = (value) => value >> 1;
|
|
3054
|
-
|
|
3055
|
-
// src/Rect/trimRectBounds.ts
|
|
3056
|
-
function trimRectBounds(x, y, w, h, targetWidth, targetHeight, out) {
|
|
3057
|
-
const res = out ?? {
|
|
3058
|
-
x: 0,
|
|
3059
|
-
y: 0,
|
|
3060
|
-
w: 0,
|
|
3061
|
-
h: 0
|
|
3062
|
-
};
|
|
3063
|
-
const left = Math.max(0, x);
|
|
3064
|
-
const top = Math.max(0, y);
|
|
3065
|
-
const right = Math.min(targetWidth, x + w);
|
|
3066
|
-
const bottom = Math.min(targetHeight, y + h);
|
|
3067
|
-
res.x = left;
|
|
3068
|
-
res.y = top;
|
|
3069
|
-
res.w = Math.max(0, right - left);
|
|
3070
|
-
res.h = Math.max(0, bottom - top);
|
|
3071
|
-
return res;
|
|
3072
|
-
}
|
|
3073
|
-
|
|
3074
|
-
// src/Paint/PaintBuffer.ts
|
|
3075
|
-
var PaintBuffer = class {
|
|
3076
|
-
constructor(config, tilePool) {
|
|
3077
|
-
this.config = config;
|
|
3078
|
-
this.tilePool = tilePool;
|
|
3079
|
-
this.lookup = [];
|
|
3080
|
-
}
|
|
3081
|
-
lookup;
|
|
3082
|
-
scratchBounds = {
|
|
3083
|
-
x: 0,
|
|
3084
|
-
y: 0,
|
|
3085
|
-
w: 0,
|
|
3086
|
-
h: 0
|
|
3087
|
-
};
|
|
3088
|
-
eachTileInBounds(bounds, callback) {
|
|
3089
|
-
const {
|
|
3090
|
-
tileShift,
|
|
3091
|
-
targetColumns,
|
|
3092
|
-
targetRows,
|
|
3093
|
-
tileSize
|
|
3094
|
-
} = this.config;
|
|
3095
|
-
const x1 = Math.max(0, bounds.x >> tileShift);
|
|
3096
|
-
const y1 = Math.max(0, bounds.y >> tileShift);
|
|
3097
|
-
const x2 = Math.min(targetColumns - 1, bounds.x + bounds.w - 1 >> tileShift);
|
|
3098
|
-
const y2 = Math.min(targetRows - 1, bounds.y + bounds.h - 1 >> tileShift);
|
|
3099
|
-
if (x1 > x2 || y1 > y2) return;
|
|
3100
|
-
const lookup = this.lookup;
|
|
3101
|
-
const tilePool = this.tilePool;
|
|
3102
|
-
for (let ty = y1; ty <= y2; ty++) {
|
|
3103
|
-
const rowOffset = ty * targetColumns;
|
|
3104
|
-
const tileTop = ty << tileShift;
|
|
3105
|
-
for (let tx = x1; tx <= x2; tx++) {
|
|
3106
|
-
const id = rowOffset + tx;
|
|
3107
|
-
const tile = lookup[id] ?? (lookup[id] = tilePool.getTile(id, tx, ty));
|
|
3108
|
-
const tileLeft = tx << tileShift;
|
|
3109
|
-
const startX = bounds.x > tileLeft ? bounds.x : tileLeft;
|
|
3110
|
-
const startY = bounds.y > tileTop ? bounds.y : tileTop;
|
|
3111
|
-
const maskEndX = bounds.x + bounds.w;
|
|
3112
|
-
const tileEndX = tileLeft + tileSize;
|
|
3113
|
-
const endX = maskEndX < tileEndX ? maskEndX : tileEndX;
|
|
3114
|
-
const maskEndY = bounds.y + bounds.h;
|
|
3115
|
-
const tileEndY = tileTop + tileSize;
|
|
3116
|
-
const endY = maskEndY < tileEndY ? maskEndY : tileEndY;
|
|
3117
|
-
callback(tile, startX, startY, endX - startX, endY - startY);
|
|
3118
|
-
}
|
|
3119
|
-
}
|
|
3120
|
-
}
|
|
3121
|
-
writePaintAlphaMaskStroke(color, brush, x0, y0, x1, y1) {
|
|
3122
|
-
const cA = color >>> 24;
|
|
3123
|
-
if (cA === 0) return false;
|
|
3124
|
-
const {
|
|
3125
|
-
tileShift,
|
|
3126
|
-
tileMask,
|
|
3127
|
-
target
|
|
3128
|
-
} = this.config;
|
|
3129
|
-
const {
|
|
3130
|
-
w: bW,
|
|
3131
|
-
h: bH,
|
|
3132
|
-
data: bD,
|
|
3133
|
-
centerOffsetX,
|
|
3134
|
-
centerOffsetY
|
|
3135
|
-
} = brush;
|
|
3136
|
-
const cRGB = color & 16777215;
|
|
3137
|
-
const scratch = this.scratchBounds;
|
|
3138
|
-
let changed = false;
|
|
3139
|
-
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
3140
|
-
const topLeftX = Math.floor(px + centerOffsetX);
|
|
3141
|
-
const topLeftY = Math.floor(py + centerOffsetY);
|
|
3142
|
-
trimRectBounds(topLeftX, topLeftY, bW, bH, target.width, target.height, scratch);
|
|
3143
|
-
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
3144
|
-
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
3145
|
-
const d32 = tile.data32;
|
|
3146
|
-
let tileChanged = false;
|
|
3147
|
-
for (let i = 0; i < bH_t; i++) {
|
|
3148
|
-
const canvasY = bY + i;
|
|
3149
|
-
const bOff = (canvasY - topLeftY) * bW;
|
|
3150
|
-
const tOff = (canvasY & tileMask) << tileShift;
|
|
3151
|
-
const dS = tOff + (bX & tileMask);
|
|
3152
|
-
for (let j = 0; j < bW_t; j++) {
|
|
3153
|
-
const canvasX = bX + j;
|
|
3154
|
-
const brushA = bD[bOff + (canvasX - topLeftX)];
|
|
3155
|
-
if (brushA === 0) continue;
|
|
3156
|
-
const t = cA * brushA + 128;
|
|
3157
|
-
const blendedA = t + (t >> 8) >> 8;
|
|
3158
|
-
const idx = dS + j;
|
|
3159
|
-
const cur = d32[idx];
|
|
3160
|
-
if (brushA > cur >>> 24) {
|
|
3161
|
-
const next = (cRGB | blendedA << 24) >>> 0;
|
|
3162
|
-
if (cur !== next) {
|
|
3163
|
-
d32[idx] = next;
|
|
3164
|
-
tileChanged = true;
|
|
3165
|
-
}
|
|
3166
|
-
}
|
|
3167
|
-
}
|
|
3168
|
-
}
|
|
3169
|
-
if (tileChanged) changed = true;
|
|
3170
|
-
});
|
|
3171
|
-
});
|
|
3172
|
-
return changed;
|
|
3173
|
-
}
|
|
3174
|
-
writePaintBinaryMaskStroke(color, brush, x0, y0, x1, y1) {
|
|
3175
|
-
const alphaIsZero = color >>> 24 === 0;
|
|
3176
|
-
if (alphaIsZero) return false;
|
|
3177
|
-
const {
|
|
3178
|
-
tileShift,
|
|
3179
|
-
tileMask,
|
|
3180
|
-
target
|
|
3181
|
-
} = this.config;
|
|
3182
|
-
const {
|
|
3183
|
-
w: bW,
|
|
3184
|
-
h: bH,
|
|
3185
|
-
data: bD,
|
|
3186
|
-
centerOffsetX,
|
|
3187
|
-
centerOffsetY
|
|
3188
|
-
} = brush;
|
|
3189
|
-
const scratch = this.scratchBounds;
|
|
3190
|
-
let changed = false;
|
|
3191
|
-
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
3192
|
-
const topLeftX = Math.floor(px + centerOffsetX);
|
|
3193
|
-
const topLeftY = Math.floor(py + centerOffsetY);
|
|
3194
|
-
trimRectBounds(topLeftX, topLeftY, bW, bH, target.width, target.height, scratch);
|
|
3195
|
-
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
3196
|
-
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
3197
|
-
const d32 = tile.data32;
|
|
3198
|
-
let tileChanged = false;
|
|
3199
|
-
for (let i = 0; i < bH_t; i++) {
|
|
3200
|
-
const canvasY = bY + i;
|
|
3201
|
-
const bOff = (canvasY - topLeftY) * bW;
|
|
3202
|
-
const tOff = (canvasY & tileMask) << tileShift;
|
|
3203
|
-
const dS = tOff + (bX & tileMask);
|
|
3204
|
-
for (let j = 0; j < bW_t; j++) {
|
|
3205
|
-
const canvasX = bX + j;
|
|
3206
|
-
if (bD[bOff + (canvasX - topLeftX)]) {
|
|
3207
|
-
const idx = dS + j;
|
|
3208
|
-
if (d32[idx] !== color) {
|
|
3209
|
-
d32[idx] = color;
|
|
3210
|
-
tileChanged = true;
|
|
3211
|
-
}
|
|
3212
|
-
}
|
|
3213
|
-
}
|
|
3214
|
-
}
|
|
3215
|
-
if (tileChanged) changed = true;
|
|
3216
|
-
});
|
|
3217
|
-
});
|
|
3218
|
-
return changed;
|
|
3219
|
-
}
|
|
3220
|
-
writeRectStroke(color, brushWidth, brushHeight, x0, y0, x1, y1) {
|
|
3221
|
-
const alphaIsZero = color >>> 24 === 0;
|
|
3222
|
-
if (alphaIsZero) return false;
|
|
3223
|
-
const config = this.config;
|
|
3224
|
-
const tileShift = config.tileShift;
|
|
3225
|
-
const tileMask = config.tileMask;
|
|
3226
|
-
const target = config.target;
|
|
3227
|
-
const scratch = this.scratchBounds;
|
|
3228
|
-
const centerOffsetX = macro_halfAndFloor(brushWidth - 1);
|
|
3229
|
-
const centerOffsetY = macro_halfAndFloor(brushHeight - 1);
|
|
3230
|
-
let changed = false;
|
|
3231
|
-
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
3232
|
-
const topLeftX = Math.floor(px + centerOffsetX);
|
|
3233
|
-
const topLeftY = Math.floor(py + centerOffsetY);
|
|
3234
|
-
trimRectBounds(topLeftX, topLeftY, brushWidth, brushHeight, target.width, target.height, scratch);
|
|
3235
|
-
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
3236
|
-
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
3237
|
-
const d32 = tile.data32;
|
|
3238
|
-
let tileChanged = false;
|
|
3239
|
-
for (let i = 0; i < bH_t; i++) {
|
|
3240
|
-
const canvasY = bY + i;
|
|
3241
|
-
const tOff = (canvasY & tileMask) << tileShift;
|
|
3242
|
-
const dS = tOff + (bX & tileMask);
|
|
3243
|
-
for (let j = 0; j < bW_t; j++) {
|
|
3244
|
-
const idx = dS + j;
|
|
3245
|
-
if (d32[idx] !== color) {
|
|
3246
|
-
d32[idx] = color;
|
|
3247
|
-
tileChanged = true;
|
|
3248
|
-
}
|
|
3249
|
-
}
|
|
3250
|
-
}
|
|
3251
|
-
if (tileChanged) {
|
|
3252
|
-
changed = true;
|
|
3253
|
-
}
|
|
3254
|
-
});
|
|
3255
|
-
});
|
|
3256
|
-
return changed;
|
|
3257
|
-
}
|
|
3258
|
-
clear() {
|
|
3259
|
-
this.tilePool.releaseTiles(this.lookup);
|
|
3260
|
-
}
|
|
3261
|
-
};
|
|
3262
|
-
|
|
3263
|
-
// src/PixelTile/PixelTile.ts
|
|
3264
|
-
var PixelTile = class {
|
|
3265
|
-
constructor(id, tx, ty, tileSize, tileArea) {
|
|
3266
|
-
this.id = id;
|
|
3267
|
-
this.tx = tx;
|
|
3268
|
-
this.ty = ty;
|
|
3269
|
-
this.width = this.height = tileSize;
|
|
3270
|
-
this.data32 = new Uint32Array(tileArea);
|
|
3271
|
-
const data8 = new Uint8ClampedArray(this.data32.buffer);
|
|
3272
|
-
this.imageData = new ImageData(data8, tileSize, tileSize);
|
|
3273
|
-
}
|
|
3274
|
-
data32;
|
|
3275
|
-
width;
|
|
3276
|
-
height;
|
|
3277
|
-
imageData;
|
|
3278
|
-
};
|
|
3279
|
-
|
|
3280
|
-
// src/PixelTile/PixelTilePool.ts
|
|
3281
|
-
var PixelTilePool = class {
|
|
3282
|
-
pool;
|
|
3283
|
-
tileSize;
|
|
3284
|
-
tileArea;
|
|
3285
|
-
constructor(config) {
|
|
3286
|
-
this.pool = [];
|
|
3287
|
-
this.tileSize = config.tileSize;
|
|
3288
|
-
this.tileArea = config.tileArea;
|
|
3289
|
-
}
|
|
3290
|
-
getTile(id, tx, ty) {
|
|
3291
|
-
let tile = this.pool.pop();
|
|
3292
|
-
if (tile) {
|
|
3293
|
-
tile.id = id;
|
|
3294
|
-
tile.tx = tx;
|
|
3295
|
-
tile.ty = ty;
|
|
3296
|
-
tile.data32.fill(0);
|
|
3297
|
-
return tile;
|
|
3298
|
-
}
|
|
3299
|
-
return new PixelTile(id, tx, ty, this.tileSize, this.tileArea);
|
|
3300
|
-
}
|
|
3301
|
-
releaseTile(tile) {
|
|
3302
|
-
this.pool.push(tile);
|
|
3303
|
-
}
|
|
3304
|
-
releaseTiles(tiles) {
|
|
3305
|
-
let length = tiles.length;
|
|
3306
|
-
for (let i = 0; i < length; i++) {
|
|
3307
|
-
let tile = tiles[i];
|
|
3308
|
-
if (tile) {
|
|
3309
|
-
this.pool.push(tile);
|
|
3310
|
-
}
|
|
3311
|
-
}
|
|
3312
|
-
tiles.length = 0;
|
|
3313
|
-
}
|
|
3314
|
-
};
|
|
3315
|
-
|
|
3316
|
-
// src/History/PixelWriter.ts
|
|
3317
|
-
var PixelWriter = class {
|
|
3318
|
-
historyManager;
|
|
3319
|
-
accumulator;
|
|
3320
|
-
historyActionFactory;
|
|
3321
|
-
config;
|
|
3322
|
-
pixelTilePool;
|
|
3323
|
-
paintBuffer;
|
|
3324
|
-
mutator;
|
|
3325
|
-
blendPixelDataOpts = {
|
|
3326
|
-
alpha: 255,
|
|
3327
|
-
blendFn: sourceOverPerfect,
|
|
3328
|
-
x: 0,
|
|
3329
|
-
y: 0,
|
|
3330
|
-
w: 0,
|
|
3331
|
-
h: 0
|
|
3332
|
-
};
|
|
3333
|
-
_inProgress = false;
|
|
3334
|
-
constructor(target, mutatorFactory, {
|
|
3335
|
-
tileSize = 256,
|
|
3336
|
-
maxHistorySteps = 50,
|
|
3337
|
-
historyManager = new HistoryManager(maxHistorySteps),
|
|
3338
|
-
historyActionFactory = makeHistoryAction,
|
|
3339
|
-
pixelTilePool,
|
|
3340
|
-
accumulator
|
|
3341
|
-
} = {}) {
|
|
3342
|
-
this.config = new PixelEngineConfig(tileSize, target);
|
|
3343
|
-
this.historyManager = historyManager;
|
|
3344
|
-
this.pixelTilePool = pixelTilePool ?? new PixelTilePool(this.config);
|
|
3345
|
-
this.accumulator = accumulator ?? new PixelAccumulator(this.config, this.pixelTilePool);
|
|
3346
|
-
this.historyActionFactory = historyActionFactory;
|
|
3347
|
-
this.mutator = mutatorFactory(this);
|
|
3348
|
-
this.paintBuffer = new PaintBuffer(this.config, this.pixelTilePool);
|
|
3349
|
-
}
|
|
3350
|
-
/**
|
|
3351
|
-
* Executes `transaction` and commits the resulting pixel changes as a single
|
|
3352
|
-
* undoable history action.
|
|
3353
|
-
*
|
|
3354
|
-
* - If `transaction` throws, all accumulated changes are rolled back and the error
|
|
3355
|
-
* is re-thrown. No action is committed.
|
|
3356
|
-
* - If `transaction` completes without modifying any pixels, no action is committed.
|
|
3357
|
-
* - `withHistory` is not re-entrant. Calling it again from inside `transaction` will
|
|
3358
|
-
* throw immediately to prevent silent data loss from a nested extractPatch.
|
|
3359
|
-
*
|
|
3360
|
-
* @param transaction Callback to be executed inside the transaction.
|
|
3361
|
-
* @param after Called after both undo and redo — use for generic change notifications.
|
|
3362
|
-
* @param afterUndo Called after undo only — use for dimension or state changes specific to undo.
|
|
3363
|
-
* @param afterRedo Called after redo only.
|
|
3364
|
-
*/
|
|
3365
|
-
withHistory(transaction, after, afterUndo, afterRedo) {
|
|
3366
|
-
if (this._inProgress) {
|
|
3367
|
-
throw new Error("withHistory is not re-entrant \u2014 commit or rollback the current operation first");
|
|
3368
|
-
}
|
|
3369
|
-
this._inProgress = true;
|
|
3370
|
-
try {
|
|
3371
|
-
transaction(this.mutator);
|
|
3372
|
-
} catch (e) {
|
|
3373
|
-
this.accumulator.rollbackAfterError();
|
|
3374
|
-
throw e;
|
|
3375
|
-
} finally {
|
|
3376
|
-
this._inProgress = false;
|
|
3377
|
-
}
|
|
3378
|
-
if (this.accumulator.beforeTiles.length === 0) return;
|
|
3379
|
-
const patch = this.accumulator.extractPatch();
|
|
3380
|
-
const action = this.historyActionFactory(this, patch, after, afterUndo, afterRedo);
|
|
3381
|
-
this.historyManager.commit(action);
|
|
3382
|
-
}
|
|
3383
|
-
resize(newWidth, newHeight, offsetX = 0, offsetY = 0, after, afterUndo, afterRedo, resizeImageDataFn = resizeImageData) {
|
|
3384
|
-
if (this._inProgress) {
|
|
3385
|
-
throw new Error("Cannot resize inside a withHistory callback");
|
|
3386
|
-
}
|
|
3387
|
-
if (this.accumulator.beforeTiles.length > 0) {
|
|
3388
|
-
throw new Error("Cannot resize with an open accumulator \u2014 commit or rollback first");
|
|
3389
|
-
}
|
|
3390
|
-
const config = this.config;
|
|
3391
|
-
const target = config.target;
|
|
3392
|
-
const beforeImageData = target.imageData;
|
|
3393
|
-
const afterImageData = resizeImageDataFn(beforeImageData, newWidth, newHeight, offsetX, offsetY);
|
|
3394
|
-
target.set(afterImageData);
|
|
3395
|
-
this.historyManager.commit({
|
|
3396
|
-
undo: () => {
|
|
3397
|
-
target.set(beforeImageData);
|
|
3398
|
-
afterUndo?.(beforeImageData);
|
|
3399
|
-
after?.(beforeImageData);
|
|
3400
|
-
},
|
|
3401
|
-
redo: () => {
|
|
3402
|
-
target.set(afterImageData);
|
|
3403
|
-
afterRedo?.(afterImageData);
|
|
3404
|
-
after?.(afterImageData);
|
|
3405
|
-
}
|
|
3406
|
-
});
|
|
3407
|
-
}
|
|
3408
|
-
commitPaintBuffer(alpha = 255, blendFn = sourceOverPerfect, blendPixelDataFn = blendPixelData) {
|
|
3409
|
-
const paintBuffer = this.paintBuffer;
|
|
3410
|
-
const tileShift = paintBuffer.config.tileShift;
|
|
3411
|
-
const lookup = paintBuffer.lookup;
|
|
3412
|
-
const opts = this.blendPixelDataOpts;
|
|
3413
|
-
opts.alpha = alpha;
|
|
3414
|
-
opts.blendFn = blendFn;
|
|
3415
|
-
for (let i = 0; i < lookup.length; i++) {
|
|
3416
|
-
const tile = lookup[i];
|
|
3417
|
-
if (tile) {
|
|
3418
|
-
const didChange = this.accumulator.storeTileBeforeState(tile.id, tile.tx, tile.ty);
|
|
3419
|
-
const dx = tile.tx << tileShift;
|
|
3420
|
-
const dy = tile.ty << tileShift;
|
|
3421
|
-
opts.x = dx;
|
|
3422
|
-
opts.y = dy;
|
|
3423
|
-
opts.w = tile.width;
|
|
3424
|
-
opts.h = tile.height;
|
|
3425
|
-
didChange(blendPixelDataFn(this.config.target, tile, opts));
|
|
3426
|
-
}
|
|
3427
|
-
}
|
|
3428
|
-
paintBuffer.clear();
|
|
3429
|
-
}
|
|
3710
|
+
// src/History/PixelMutator/mutatorFill.ts
|
|
3711
|
+
var defaults16 = {
|
|
3712
|
+
fillPixelData
|
|
3430
3713
|
};
|
|
3431
|
-
|
|
3432
|
-
// src/PixelData/applyAlphaMaskToPixelData.ts
|
|
3433
|
-
function applyAlphaMaskToPixelData(dst, mask, opts = {}) {
|
|
3714
|
+
var mutatorFill = ((writer, deps = defaults16) => {
|
|
3434
3715
|
const {
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
invertMask = false
|
|
3443
|
-
} = opts;
|
|
3444
|
-
if (globalAlpha === 0) return false;
|
|
3445
|
-
let x = targetX;
|
|
3446
|
-
let y = targetY;
|
|
3447
|
-
let w = width;
|
|
3448
|
-
let h = height;
|
|
3449
|
-
if (x < 0) {
|
|
3450
|
-
w += x;
|
|
3451
|
-
x = 0;
|
|
3452
|
-
}
|
|
3453
|
-
if (y < 0) {
|
|
3454
|
-
h += y;
|
|
3455
|
-
y = 0;
|
|
3456
|
-
}
|
|
3457
|
-
w = Math.min(w, dst.width - x);
|
|
3458
|
-
h = Math.min(h, dst.height - y);
|
|
3459
|
-
if (w <= 0) return false;
|
|
3460
|
-
if (h <= 0) return false;
|
|
3461
|
-
const mPitch = mask.w;
|
|
3462
|
-
if (mPitch <= 0) return false;
|
|
3463
|
-
const startX = mx + (x - targetX);
|
|
3464
|
-
const startY = my + (y - targetY);
|
|
3465
|
-
const sX0 = Math.max(0, startX);
|
|
3466
|
-
const sY0 = Math.max(0, startY);
|
|
3467
|
-
const sX1 = Math.min(mPitch, startX + w);
|
|
3468
|
-
const sY1 = Math.min(mask.h, startY + h);
|
|
3469
|
-
const finalW = sX1 - sX0;
|
|
3470
|
-
const finalH = sY1 - sY0;
|
|
3471
|
-
if (finalW <= 0) return false;
|
|
3472
|
-
if (finalH <= 0) return false;
|
|
3473
|
-
const xShift = sX0 - startX;
|
|
3474
|
-
const yShift = sY0 - startY;
|
|
3475
|
-
const dst32 = dst.data32;
|
|
3476
|
-
const dw = dst.width;
|
|
3477
|
-
const dStride = dw - finalW;
|
|
3478
|
-
const mStride = mPitch - finalW;
|
|
3479
|
-
const maskData = mask.data;
|
|
3480
|
-
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
3481
|
-
let mIdx = sY0 * mPitch + sX0;
|
|
3482
|
-
let didChange = false;
|
|
3483
|
-
for (let iy = 0; iy < h; iy++) {
|
|
3484
|
-
for (let ix = 0; ix < w; ix++) {
|
|
3485
|
-
const mVal = maskData[mIdx];
|
|
3486
|
-
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
3487
|
-
let weight = 0;
|
|
3488
|
-
if (effectiveM === 0) {
|
|
3489
|
-
weight = 0;
|
|
3490
|
-
} else if (effectiveM === 255) {
|
|
3491
|
-
weight = globalAlpha;
|
|
3492
|
-
} else if (globalAlpha === 255) {
|
|
3493
|
-
weight = effectiveM;
|
|
3494
|
-
} else {
|
|
3495
|
-
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
3496
|
-
}
|
|
3497
|
-
if (weight === 0) {
|
|
3498
|
-
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
3499
|
-
didChange = true;
|
|
3500
|
-
} else if (weight !== 255) {
|
|
3501
|
-
const d = dst32[dIdx];
|
|
3502
|
-
const da = d >>> 24;
|
|
3503
|
-
if (da !== 0) {
|
|
3504
|
-
const finalAlpha = da === 255 ? weight : da * weight + 128 >> 8;
|
|
3505
|
-
const current = dst32[dIdx];
|
|
3506
|
-
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
3507
|
-
if (current !== next) {
|
|
3508
|
-
dst32[dIdx] = next;
|
|
3509
|
-
didChange = true;
|
|
3510
|
-
}
|
|
3511
|
-
}
|
|
3512
|
-
}
|
|
3513
|
-
dIdx++;
|
|
3514
|
-
mIdx++;
|
|
3716
|
+
fillPixelData: fillPixelData2 = defaults16.fillPixelData
|
|
3717
|
+
} = deps;
|
|
3718
|
+
return {
|
|
3719
|
+
fill(color, x = 0, y = 0, w = writer.config.target.width, h = writer.config.target.height) {
|
|
3720
|
+
const target = writer.config.target;
|
|
3721
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3722
|
+
return didChange(fillPixelData2(target, color, x, y, w, h));
|
|
3515
3723
|
}
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
return didChange;
|
|
3520
|
-
}
|
|
3521
|
-
|
|
3522
|
-
// src/History/PixelMutator/mutatorApplyAlphaMask.ts
|
|
3523
|
-
var defaults11 = {
|
|
3524
|
-
applyAlphaMaskToPixelData
|
|
3525
|
-
};
|
|
3526
|
-
var mutatorApplyAlphaMask = ((writer, deps = defaults11) => {
|
|
3724
|
+
};
|
|
3725
|
+
});
|
|
3726
|
+
var mutatorFillRect = ((writer, deps = defaults16) => {
|
|
3527
3727
|
const {
|
|
3528
|
-
|
|
3728
|
+
fillPixelData: fillPixelData2 = defaults16.fillPixelData
|
|
3529
3729
|
} = deps;
|
|
3530
3730
|
return {
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
const
|
|
3534
|
-
|
|
3535
|
-
y = 0,
|
|
3536
|
-
w = target.width,
|
|
3537
|
-
h = target.height
|
|
3538
|
-
} = opts;
|
|
3539
|
-
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3540
|
-
return didChange(applyAlphaMaskToPixelData2(target, mask, opts));
|
|
3731
|
+
fillRect(color, rect) {
|
|
3732
|
+
const target = writer.config.target;
|
|
3733
|
+
const didChange = writer.accumulator.storeRegionBeforeState(rect.x, rect.y, rect.w, rect.h);
|
|
3734
|
+
return didChange(fillPixelData2(target, color, rect.x, rect.y, rect.w, rect.h));
|
|
3541
3735
|
}
|
|
3542
3736
|
};
|
|
3543
3737
|
});
|
|
3544
3738
|
|
|
3545
|
-
// src/PixelData/
|
|
3546
|
-
|
|
3739
|
+
// src/PixelData/fillPixelDataBinaryMask.ts
|
|
3740
|
+
var SCRATCH_RECT2 = makeClippedRect();
|
|
3741
|
+
function fillPixelDataBinaryMask(target, color, mask, x = 0, y = 0) {
|
|
3742
|
+
const maskW = mask.w;
|
|
3743
|
+
const maskH = mask.h;
|
|
3744
|
+
const clip = resolveRectClipping(x, y, maskW, maskH, target.width, target.height, SCRATCH_RECT2);
|
|
3745
|
+
if (!clip.inBounds) return false;
|
|
3547
3746
|
const {
|
|
3548
|
-
x:
|
|
3549
|
-
y:
|
|
3550
|
-
w:
|
|
3551
|
-
h:
|
|
3552
|
-
|
|
3553
|
-
mx = 0,
|
|
3554
|
-
my = 0,
|
|
3555
|
-
invertMask = false
|
|
3556
|
-
} = opts;
|
|
3557
|
-
if (globalAlpha === 0) return false;
|
|
3558
|
-
let x = targetX;
|
|
3559
|
-
let y = targetY;
|
|
3560
|
-
let w = width;
|
|
3561
|
-
let h = height;
|
|
3562
|
-
if (x < 0) {
|
|
3563
|
-
w += x;
|
|
3564
|
-
x = 0;
|
|
3565
|
-
}
|
|
3566
|
-
if (y < 0) {
|
|
3567
|
-
h += y;
|
|
3568
|
-
y = 0;
|
|
3569
|
-
}
|
|
3570
|
-
w = Math.min(w, dst.width - x);
|
|
3571
|
-
h = Math.min(h, dst.height - y);
|
|
3572
|
-
if (w <= 0 || h <= 0) return false;
|
|
3573
|
-
const mPitch = mask.w;
|
|
3574
|
-
if (mPitch <= 0) return false;
|
|
3575
|
-
const startX = mx + (x - targetX);
|
|
3576
|
-
const startY = my + (y - targetY);
|
|
3577
|
-
const sX0 = Math.max(0, startX);
|
|
3578
|
-
const sY0 = Math.max(0, startY);
|
|
3579
|
-
const sX1 = Math.min(mPitch, startX + w);
|
|
3580
|
-
const sY1 = Math.min(mask.h, startY + h);
|
|
3581
|
-
const finalW = sX1 - sX0;
|
|
3582
|
-
const finalH = sY1 - sY0;
|
|
3583
|
-
if (finalW <= 0 || finalH <= 0) {
|
|
3584
|
-
return false;
|
|
3585
|
-
}
|
|
3586
|
-
const xShift = sX0 - startX;
|
|
3587
|
-
const yShift = sY0 - startY;
|
|
3588
|
-
const dst32 = dst.data32;
|
|
3589
|
-
const dw = dst.width;
|
|
3590
|
-
const dStride = dw - finalW;
|
|
3591
|
-
const mStride = mPitch - finalW;
|
|
3747
|
+
x: finalX,
|
|
3748
|
+
y: finalY,
|
|
3749
|
+
w: actualW,
|
|
3750
|
+
h: actualH
|
|
3751
|
+
} = clip;
|
|
3592
3752
|
const maskData = mask.data;
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
let
|
|
3596
|
-
for (let iy = 0; iy <
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
if (da !== 0) {
|
|
3611
|
-
const finalAlpha = da === 255 ? globalAlpha : da * globalAlpha + 128 >> 8;
|
|
3612
|
-
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
3613
|
-
if (d !== next) {
|
|
3614
|
-
dst32[dIdx] = next;
|
|
3615
|
-
didChange = true;
|
|
3616
|
-
}
|
|
3753
|
+
const dst32 = target.data32;
|
|
3754
|
+
const dw = target.width;
|
|
3755
|
+
let hasChanged = false;
|
|
3756
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
3757
|
+
const currentY = finalY + iy;
|
|
3758
|
+
const maskY = currentY - y;
|
|
3759
|
+
const maskOffset = maskY * maskW;
|
|
3760
|
+
const dstRowOffset = currentY * dw;
|
|
3761
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
3762
|
+
const currentX = finalX + ix;
|
|
3763
|
+
const maskX = currentX - x;
|
|
3764
|
+
const maskIndex = maskOffset + maskX;
|
|
3765
|
+
if (maskData[maskIndex]) {
|
|
3766
|
+
const current = dst32[dstRowOffset + currentX];
|
|
3767
|
+
if (current !== color) {
|
|
3768
|
+
dst32[dstRowOffset + currentX] = color;
|
|
3769
|
+
hasChanged = true;
|
|
3617
3770
|
}
|
|
3618
3771
|
}
|
|
3619
|
-
dIdx++;
|
|
3620
|
-
mIdx++;
|
|
3621
3772
|
}
|
|
3622
|
-
dIdx += dStride;
|
|
3623
|
-
mIdx += mStride;
|
|
3624
3773
|
}
|
|
3625
|
-
return
|
|
3774
|
+
return hasChanged;
|
|
3626
3775
|
}
|
|
3627
3776
|
|
|
3628
|
-
// src/History/PixelMutator/
|
|
3629
|
-
var
|
|
3630
|
-
|
|
3777
|
+
// src/History/PixelMutator/mutatorFillBinaryMask.ts
|
|
3778
|
+
var defaults17 = {
|
|
3779
|
+
fillPixelDataBinaryMask
|
|
3631
3780
|
};
|
|
3632
|
-
var
|
|
3781
|
+
var mutatorFillBinaryMask = ((writer, deps = defaults17) => {
|
|
3633
3782
|
const {
|
|
3634
|
-
|
|
3783
|
+
fillPixelDataBinaryMask: fillPixelDataBinaryMask2 = defaults17.fillPixelDataBinaryMask
|
|
3635
3784
|
} = deps;
|
|
3636
3785
|
return {
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
x = 0,
|
|
3641
|
-
y = 0,
|
|
3642
|
-
w = target.width,
|
|
3643
|
-
h = target.height
|
|
3644
|
-
} = opts;
|
|
3645
|
-
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3646
|
-
return didChange(applyBinaryMaskToPixelData2(target, mask, opts));
|
|
3786
|
+
fillBinaryMask(color, mask, x = 0, y = 0) {
|
|
3787
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, mask.w, mask.h);
|
|
3788
|
+
return didChange(fillPixelDataBinaryMask2(writer.config.target, color, mask, x, y));
|
|
3647
3789
|
}
|
|
3648
3790
|
};
|
|
3649
3791
|
});
|
|
3650
3792
|
|
|
3651
|
-
// src/PixelData/
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
const
|
|
3655
|
-
const
|
|
3656
|
-
const
|
|
3657
|
-
const
|
|
3658
|
-
const
|
|
3659
|
-
const
|
|
3660
|
-
const
|
|
3661
|
-
const invertMask = opts
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
const
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
let dIdx = y * dw + x | 0;
|
|
3688
|
-
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
3689
|
-
const dStride = dw - actualW | 0;
|
|
3690
|
-
const mStride = mPitch - actualW | 0;
|
|
3691
|
-
const isOpaque = globalAlpha === 255;
|
|
3692
|
-
const colorRGB = color & 16777215;
|
|
3693
|
-
let didChange = false;
|
|
3694
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
3695
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
3696
|
-
const mVal = maskData[mIdx];
|
|
3697
|
-
const effM = invertMask ? 255 - mVal : mVal;
|
|
3698
|
-
if (effM === 0) {
|
|
3699
|
-
dIdx++;
|
|
3700
|
-
mIdx++;
|
|
3701
|
-
continue;
|
|
3702
|
-
}
|
|
3703
|
-
let weight = globalAlpha;
|
|
3704
|
-
if (isOpaque) {
|
|
3705
|
-
weight = effM;
|
|
3706
|
-
} else if (effM !== 255) {
|
|
3707
|
-
weight = effM * globalAlpha + 128 >> 8;
|
|
3708
|
-
}
|
|
3709
|
-
if (weight === 0) {
|
|
3710
|
-
dIdx++;
|
|
3711
|
-
mIdx++;
|
|
3712
|
-
continue;
|
|
3713
|
-
}
|
|
3714
|
-
let finalCol = color;
|
|
3715
|
-
if (weight < 255) {
|
|
3716
|
-
const a = baseSrcAlpha * weight + 128 >> 8;
|
|
3717
|
-
if (a === 0 && !isOverwrite) {
|
|
3718
|
-
dIdx++;
|
|
3719
|
-
mIdx++;
|
|
3720
|
-
continue;
|
|
3793
|
+
// src/PixelData/invertPixelData.ts
|
|
3794
|
+
var SCRATCH_RECT3 = makeClippedRect();
|
|
3795
|
+
function invertPixelData(target, opts) {
|
|
3796
|
+
const mask = opts?.mask;
|
|
3797
|
+
const targetX = opts?.x ?? 0;
|
|
3798
|
+
const targetY = opts?.y ?? 0;
|
|
3799
|
+
const mx = opts?.mx ?? 0;
|
|
3800
|
+
const my = opts?.my ?? 0;
|
|
3801
|
+
const width = opts?.w ?? target.width;
|
|
3802
|
+
const height = opts?.h ?? target.height;
|
|
3803
|
+
const invertMask = opts?.invertMask ?? false;
|
|
3804
|
+
const clip = resolveRectClipping(targetX, targetY, width, height, target.width, target.height, SCRATCH_RECT3);
|
|
3805
|
+
if (!clip.inBounds) return false;
|
|
3806
|
+
const {
|
|
3807
|
+
x,
|
|
3808
|
+
y,
|
|
3809
|
+
w: actualW,
|
|
3810
|
+
h: actualH
|
|
3811
|
+
} = clip;
|
|
3812
|
+
const dst32 = target.data32;
|
|
3813
|
+
const dw = target.width;
|
|
3814
|
+
const mPitch = mask?.w ?? width;
|
|
3815
|
+
const dx = x - targetX;
|
|
3816
|
+
const dy = y - targetY;
|
|
3817
|
+
let dIdx = y * dw + x;
|
|
3818
|
+
let mIdx = (my + dy) * mPitch + (mx + dx);
|
|
3819
|
+
const dStride = dw - actualW;
|
|
3820
|
+
const mStride = mPitch - actualW;
|
|
3821
|
+
if (mask) {
|
|
3822
|
+
const maskData = mask.data;
|
|
3823
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
3824
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
3825
|
+
const mVal = maskData[mIdx];
|
|
3826
|
+
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
3827
|
+
if (isHit) {
|
|
3828
|
+
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
3721
3829
|
}
|
|
3722
|
-
finalCol = (colorRGB | a << 24) >>> 0;
|
|
3723
|
-
}
|
|
3724
|
-
const current = dst32[dIdx];
|
|
3725
|
-
const next = blendFn(finalCol, current);
|
|
3726
|
-
if (current !== next) {
|
|
3727
|
-
dst32[dIdx] = next;
|
|
3728
|
-
didChange = true;
|
|
3729
|
-
}
|
|
3730
|
-
dIdx++;
|
|
3731
|
-
mIdx++;
|
|
3732
|
-
}
|
|
3733
|
-
dIdx += dStride;
|
|
3734
|
-
mIdx += mStride;
|
|
3735
|
-
}
|
|
3736
|
-
return didChange;
|
|
3737
|
-
}
|
|
3738
|
-
|
|
3739
|
-
// src/PixelData/blendColorPixelDataBinaryMask.ts
|
|
3740
|
-
function blendColorPixelDataBinaryMask(dst, color, mask, opts = {}) {
|
|
3741
|
-
const targetX = opts.x ?? 0;
|
|
3742
|
-
const targetY = opts.y ?? 0;
|
|
3743
|
-
let w = opts.w ?? mask.w;
|
|
3744
|
-
let h = opts.h ?? mask.h;
|
|
3745
|
-
const globalAlpha = opts.alpha ?? 255;
|
|
3746
|
-
const blendFn = opts.blendFn ?? sourceOverPerfect;
|
|
3747
|
-
const mx = opts.mx ?? 0;
|
|
3748
|
-
const my = opts.my ?? 0;
|
|
3749
|
-
const invertMask = opts.invertMask ?? false;
|
|
3750
|
-
if (globalAlpha === 0) return false;
|
|
3751
|
-
const baseSrcAlpha = color >>> 24;
|
|
3752
|
-
const isOverwrite = blendFn.isOverwrite || false;
|
|
3753
|
-
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
3754
|
-
let x = targetX;
|
|
3755
|
-
let y = targetY;
|
|
3756
|
-
if (x < 0) {
|
|
3757
|
-
w += x;
|
|
3758
|
-
x = 0;
|
|
3759
|
-
}
|
|
3760
|
-
if (y < 0) {
|
|
3761
|
-
h += y;
|
|
3762
|
-
y = 0;
|
|
3763
|
-
}
|
|
3764
|
-
const actualW = Math.min(w, dst.width - x);
|
|
3765
|
-
const actualH = Math.min(h, dst.height - y);
|
|
3766
|
-
if (actualW <= 0 || actualH <= 0) return false;
|
|
3767
|
-
let baseColorWithGlobalAlpha = color;
|
|
3768
|
-
if (globalAlpha < 255) {
|
|
3769
|
-
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
3770
|
-
if (a === 0 && !isOverwrite) return false;
|
|
3771
|
-
baseColorWithGlobalAlpha = (color & 16777215 | a << 24) >>> 0;
|
|
3772
|
-
}
|
|
3773
|
-
const dx = x - targetX | 0;
|
|
3774
|
-
const dy = y - targetY | 0;
|
|
3775
|
-
const dst32 = dst.data32;
|
|
3776
|
-
const dw = dst.width;
|
|
3777
|
-
const mPitch = mask.w;
|
|
3778
|
-
const maskData = mask.data;
|
|
3779
|
-
let dIdx = y * dw + x | 0;
|
|
3780
|
-
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
3781
|
-
const dStride = dw - actualW | 0;
|
|
3782
|
-
const mStride = mPitch - actualW | 0;
|
|
3783
|
-
const skipVal = invertMask ? 1 : 0;
|
|
3784
|
-
let didChange = false;
|
|
3785
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
3786
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
3787
|
-
if (maskData[mIdx] === skipVal) {
|
|
3788
3830
|
dIdx++;
|
|
3789
3831
|
mIdx++;
|
|
3790
|
-
continue;
|
|
3791
3832
|
}
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3833
|
+
dIdx += dStride;
|
|
3834
|
+
mIdx += mStride;
|
|
3835
|
+
}
|
|
3836
|
+
} else {
|
|
3837
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
3838
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
3839
|
+
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
3840
|
+
dIdx++;
|
|
3797
3841
|
}
|
|
3798
|
-
dIdx
|
|
3799
|
-
mIdx++;
|
|
3842
|
+
dIdx += dStride;
|
|
3800
3843
|
}
|
|
3801
|
-
dIdx += dStride;
|
|
3802
|
-
mIdx += mStride;
|
|
3803
3844
|
}
|
|
3804
|
-
return
|
|
3845
|
+
return true;
|
|
3805
3846
|
}
|
|
3806
3847
|
|
|
3807
|
-
// src/History/PixelMutator/
|
|
3808
|
-
var
|
|
3809
|
-
|
|
3810
|
-
blendColorPixelDataBinaryMask
|
|
3848
|
+
// src/History/PixelMutator/mutatorInvert.ts
|
|
3849
|
+
var defaults18 = {
|
|
3850
|
+
invertPixelData
|
|
3811
3851
|
};
|
|
3812
|
-
var
|
|
3852
|
+
var mutatorInvert = ((writer, deps = defaults18) => {
|
|
3813
3853
|
const {
|
|
3814
|
-
|
|
3815
|
-
blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults13.blendColorPixelDataAlphaMask
|
|
3854
|
+
invertPixelData: invertPixelData2 = defaults18.invertPixelData
|
|
3816
3855
|
} = deps;
|
|
3817
|
-
const OPTS = {
|
|
3818
|
-
x: 0,
|
|
3819
|
-
y: 0,
|
|
3820
|
-
blendFn: sourceOverPerfect,
|
|
3821
|
-
alpha: 255
|
|
3822
|
-
};
|
|
3823
3856
|
return {
|
|
3824
|
-
|
|
3825
|
-
const
|
|
3826
|
-
const
|
|
3827
|
-
const
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
if (mask.type === 1 /* BINARY */) {
|
|
3833
|
-
return didChange(blendColorPixelDataBinaryMask2(writer.config.target, color, mask, OPTS));
|
|
3834
|
-
} else {
|
|
3835
|
-
return didChange(blendColorPixelDataAlphaMask2(writer.config.target, color, mask, OPTS));
|
|
3836
|
-
}
|
|
3857
|
+
invert(opts) {
|
|
3858
|
+
const target = writer.config.target;
|
|
3859
|
+
const x = opts?.x ?? 0;
|
|
3860
|
+
const y = opts?.y ?? 0;
|
|
3861
|
+
const w = opts?.w ?? target.width;
|
|
3862
|
+
const h = opts?.h ?? target.height;
|
|
3863
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3864
|
+
return didChange(invertPixelData2(target, opts));
|
|
3837
3865
|
}
|
|
3838
3866
|
};
|
|
3839
3867
|
});
|
|
3840
3868
|
|
|
3869
|
+
// src/History/PixelMutator.ts
|
|
3870
|
+
function makeFullPixelMutator(writer) {
|
|
3871
|
+
return {
|
|
3872
|
+
// @sort
|
|
3873
|
+
...mutatorApplyAlphaMask(writer),
|
|
3874
|
+
...mutatorApplyBinaryMask(writer),
|
|
3875
|
+
...mutatorApplyMask(writer),
|
|
3876
|
+
...mutatorBlendAlphaMask(writer),
|
|
3877
|
+
...mutatorBlendBinaryMask(writer),
|
|
3878
|
+
...mutatorBlendColor(writer),
|
|
3879
|
+
...mutatorBlendColorPaintAlphaMask(writer),
|
|
3880
|
+
...mutatorBlendColorPaintBinaryMask(writer),
|
|
3881
|
+
...mutatorBlendColorPaintMask(writer),
|
|
3882
|
+
...mutatorBlendMask(writer),
|
|
3883
|
+
...mutatorBlendPaintRect(writer),
|
|
3884
|
+
...mutatorBlendPixel(writer),
|
|
3885
|
+
...mutatorBlendPixelData(writer),
|
|
3886
|
+
...mutatorClear(writer),
|
|
3887
|
+
...mutatorFill(writer),
|
|
3888
|
+
...mutatorFillBinaryMask(writer),
|
|
3889
|
+
...mutatorFillRect(writer),
|
|
3890
|
+
...mutatorInvert(writer)
|
|
3891
|
+
};
|
|
3892
|
+
}
|
|
3893
|
+
|
|
3894
|
+
// src/ImageData/ImageDataLike.ts
|
|
3895
|
+
function makeImageDataLike(width, height, data) {
|
|
3896
|
+
const size = width * height * 4;
|
|
3897
|
+
const buffer = data ? new Uint8ClampedArray(data.buffer, data.byteOffset, size) : new Uint8ClampedArray(size);
|
|
3898
|
+
return {
|
|
3899
|
+
width,
|
|
3900
|
+
height,
|
|
3901
|
+
data: buffer
|
|
3902
|
+
};
|
|
3903
|
+
}
|
|
3904
|
+
|
|
3905
|
+
// src/ImageData/ReusableImageData.ts
|
|
3906
|
+
function makeReusableImageData() {
|
|
3907
|
+
let imageData = null;
|
|
3908
|
+
return function getReusableImageData(width, height) {
|
|
3909
|
+
if (imageData === null || imageData.width !== width || imageData.height !== height) {
|
|
3910
|
+
imageData = new ImageData(width, height);
|
|
3911
|
+
} else {
|
|
3912
|
+
imageData.data.fill(0);
|
|
3913
|
+
}
|
|
3914
|
+
return imageData;
|
|
3915
|
+
};
|
|
3916
|
+
}
|
|
3917
|
+
|
|
3841
3918
|
// src/ImageData/copyImageData.ts
|
|
3842
3919
|
function copyImageData({
|
|
3843
3920
|
data,
|
|
@@ -3858,17 +3935,6 @@ function copyImageDataLike({
|
|
|
3858
3935
|
};
|
|
3859
3936
|
}
|
|
3860
3937
|
|
|
3861
|
-
// src/ImageData/ImageDataLike.ts
|
|
3862
|
-
function makeImageDataLike(width, height, data) {
|
|
3863
|
-
const size = width * height * 4;
|
|
3864
|
-
const buffer = data ? new Uint8ClampedArray(data.buffer, data.byteOffset, size) : new Uint8ClampedArray(size);
|
|
3865
|
-
return {
|
|
3866
|
-
width,
|
|
3867
|
-
height,
|
|
3868
|
-
data: buffer
|
|
3869
|
-
};
|
|
3870
|
-
}
|
|
3871
|
-
|
|
3872
3938
|
// src/ImageData/imageDataToAlphaMaskBuffer.ts
|
|
3873
3939
|
function imageDataToAlphaMaskBuffer(imageData) {
|
|
3874
3940
|
const {
|
|
@@ -3959,19 +4025,6 @@ function resampleImageData(source, factor) {
|
|
|
3959
4025
|
return new ImageData(uint8ClampedArray, width, height);
|
|
3960
4026
|
}
|
|
3961
4027
|
|
|
3962
|
-
// src/ImageData/ReusableImageData.ts
|
|
3963
|
-
function makeReusableImageData() {
|
|
3964
|
-
let imageData = null;
|
|
3965
|
-
return function getReusableImageData(width, height) {
|
|
3966
|
-
if (imageData === null || imageData.width !== width || imageData.height !== height) {
|
|
3967
|
-
imageData = new ImageData(width, height);
|
|
3968
|
-
} else {
|
|
3969
|
-
imageData.data.fill(0);
|
|
3970
|
-
}
|
|
3971
|
-
return imageData;
|
|
3972
|
-
};
|
|
3973
|
-
}
|
|
3974
|
-
|
|
3975
4028
|
// src/ImageData/serialization.ts
|
|
3976
4029
|
function base64EncodeArrayBuffer(buffer) {
|
|
3977
4030
|
const uint8 = new Uint8Array(buffer);
|
|
@@ -4126,18 +4179,6 @@ function writeImageDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
4126
4179
|
}
|
|
4127
4180
|
}
|
|
4128
4181
|
|
|
4129
|
-
// src/IndexedImage/getIndexedImageColorCounts.ts
|
|
4130
|
-
function getIndexedImageColorCounts(indexedImage) {
|
|
4131
|
-
const data = indexedImage.data;
|
|
4132
|
-
const palette = indexedImage.palette;
|
|
4133
|
-
const frequencies = new Int32Array(palette.length);
|
|
4134
|
-
for (let i = 0; i < data.length; i++) {
|
|
4135
|
-
const colorIndex = data[i];
|
|
4136
|
-
frequencies[colorIndex]++;
|
|
4137
|
-
}
|
|
4138
|
-
return frequencies;
|
|
4139
|
-
}
|
|
4140
|
-
|
|
4141
4182
|
// src/IndexedImage/IndexedImage.ts
|
|
4142
4183
|
var IndexedImage = class _IndexedImage {
|
|
4143
4184
|
/** The width of the image in pixels. */
|
|
@@ -4216,6 +4257,18 @@ var IndexedImage = class _IndexedImage {
|
|
|
4216
4257
|
}
|
|
4217
4258
|
};
|
|
4218
4259
|
|
|
4260
|
+
// src/IndexedImage/getIndexedImageColorCounts.ts
|
|
4261
|
+
function getIndexedImageColorCounts(indexedImage) {
|
|
4262
|
+
const data = indexedImage.data;
|
|
4263
|
+
const palette = indexedImage.palette;
|
|
4264
|
+
const frequencies = new Int32Array(palette.length);
|
|
4265
|
+
for (let i = 0; i < data.length; i++) {
|
|
4266
|
+
const colorIndex = data[i];
|
|
4267
|
+
frequencies[colorIndex]++;
|
|
4268
|
+
}
|
|
4269
|
+
return frequencies;
|
|
4270
|
+
}
|
|
4271
|
+
|
|
4219
4272
|
// src/IndexedImage/indexedImageToAverageColor.ts
|
|
4220
4273
|
function indexedImageToAverageColor(indexedImage, includeTransparent = false) {
|
|
4221
4274
|
const {
|
|
@@ -4374,16 +4427,14 @@ function makeBinaryMask(w, h, data) {
|
|
|
4374
4427
|
}
|
|
4375
4428
|
|
|
4376
4429
|
// src/Mask/applyBinaryMaskToAlphaMask.ts
|
|
4377
|
-
function applyBinaryMaskToAlphaMask(alphaMaskDst, binaryMaskSrc, opts
|
|
4378
|
-
const
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
invertMask = false
|
|
4386
|
-
} = opts;
|
|
4430
|
+
function applyBinaryMaskToAlphaMask(alphaMaskDst, binaryMaskSrc, opts) {
|
|
4431
|
+
const targetX = opts?.x ?? 0;
|
|
4432
|
+
const targetY = opts?.y ?? 0;
|
|
4433
|
+
const reqWidth = opts?.w ?? 0;
|
|
4434
|
+
const reqHeight = opts?.h ?? 0;
|
|
4435
|
+
const mx = opts?.mx ?? 0;
|
|
4436
|
+
const my = opts?.my ?? 0;
|
|
4437
|
+
const invertMask = opts?.invertMask ?? false;
|
|
4387
4438
|
const dstWidth = alphaMaskDst.w;
|
|
4388
4439
|
if (dstWidth <= 0) return;
|
|
4389
4440
|
if (binaryMaskSrc.data.length === 0) return;
|
|
@@ -4796,14 +4847,156 @@ function pushPiece(dest, r, x, y, w, h) {
|
|
|
4796
4847
|
for (let row = 0; row < h; row++) {
|
|
4797
4848
|
data.set(r.data.subarray((ly + row) * r.w + lx, (ly + row) * r.w + lx + w), row * w);
|
|
4798
4849
|
}
|
|
4799
|
-
dest.push({
|
|
4800
|
-
x,
|
|
4801
|
-
y,
|
|
4802
|
-
w,
|
|
4803
|
-
h,
|
|
4850
|
+
dest.push({
|
|
4851
|
+
x,
|
|
4852
|
+
y,
|
|
4853
|
+
w,
|
|
4854
|
+
h,
|
|
4855
|
+
data,
|
|
4856
|
+
type: 1 /* BINARY */
|
|
4857
|
+
});
|
|
4858
|
+
}
|
|
4859
|
+
|
|
4860
|
+
// src/Paint/PaintBufferCanvasRenderer.ts
|
|
4861
|
+
function makePaintBufferCanvasRenderer(paintBuffer, offscreenCanvasClass = OffscreenCanvas) {
|
|
4862
|
+
const config = paintBuffer.config;
|
|
4863
|
+
const tileSize = config.tileSize;
|
|
4864
|
+
const tileShift = config.tileShift;
|
|
4865
|
+
const lookup = paintBuffer.lookup;
|
|
4866
|
+
const canvas = new offscreenCanvasClass(tileSize, tileSize);
|
|
4867
|
+
const ctx = canvas.getContext("2d");
|
|
4868
|
+
if (!ctx) throw new Error(CANVAS_CTX_FAILED);
|
|
4869
|
+
ctx.imageSmoothingEnabled = false;
|
|
4870
|
+
return function drawPaintBuffer(targetCtx, alpha = 255, compOperation = "source-over") {
|
|
4871
|
+
targetCtx.globalAlpha = alpha / 255;
|
|
4872
|
+
targetCtx.globalCompositeOperation = compOperation;
|
|
4873
|
+
for (let i = 0; i < lookup.length; i++) {
|
|
4874
|
+
const tile = lookup[i];
|
|
4875
|
+
if (tile) {
|
|
4876
|
+
const dx = tile.tx << tileShift;
|
|
4877
|
+
const dy = tile.ty << tileShift;
|
|
4878
|
+
ctx.putImageData(tile.imageData, 0, 0);
|
|
4879
|
+
targetCtx.drawImage(canvas, dx, dy);
|
|
4880
|
+
}
|
|
4881
|
+
}
|
|
4882
|
+
targetCtx.globalAlpha = 1;
|
|
4883
|
+
targetCtx.globalCompositeOperation = "source-over";
|
|
4884
|
+
};
|
|
4885
|
+
}
|
|
4886
|
+
|
|
4887
|
+
// src/Paint/makeCirclePaintAlphaMask.ts
|
|
4888
|
+
function makeCirclePaintAlphaMask(size, fallOff = (d) => d) {
|
|
4889
|
+
const area = size * size;
|
|
4890
|
+
const data = new Uint8Array(area);
|
|
4891
|
+
const radius = size / 2;
|
|
4892
|
+
const invR = 1 / radius;
|
|
4893
|
+
const centerOffset = -Math.ceil(radius - 0.5);
|
|
4894
|
+
for (let y = 0; y < size; y++) {
|
|
4895
|
+
const rowOffset = y * size;
|
|
4896
|
+
const dy = y - radius + 0.5;
|
|
4897
|
+
const dy2 = dy * dy;
|
|
4898
|
+
for (let x = 0; x < size; x++) {
|
|
4899
|
+
const dx = x - radius + 0.5;
|
|
4900
|
+
const distSqr = dx * dx + dy2;
|
|
4901
|
+
if (distSqr <= radius * radius) {
|
|
4902
|
+
const dist = Math.sqrt(distSqr) * invR;
|
|
4903
|
+
const strength = fallOff(1 - dist);
|
|
4904
|
+
if (strength > 0) {
|
|
4905
|
+
const intensity = strength * 255 | 0;
|
|
4906
|
+
data[rowOffset + x] = Math.max(0, Math.min(255, intensity));
|
|
4907
|
+
}
|
|
4908
|
+
}
|
|
4909
|
+
}
|
|
4910
|
+
}
|
|
4911
|
+
return {
|
|
4912
|
+
type: 0 /* ALPHA */,
|
|
4913
|
+
data,
|
|
4914
|
+
w: size,
|
|
4915
|
+
h: size,
|
|
4916
|
+
centerOffsetX: centerOffset,
|
|
4917
|
+
centerOffsetY: centerOffset
|
|
4918
|
+
};
|
|
4919
|
+
}
|
|
4920
|
+
|
|
4921
|
+
// src/Paint/makeCirclePaintBinaryMask.ts
|
|
4922
|
+
function makeCirclePaintBinaryMask(size) {
|
|
4923
|
+
const area = size * size;
|
|
4924
|
+
const data = new Uint8Array(area);
|
|
4925
|
+
const radius = size / 2;
|
|
4926
|
+
const centerOffset = -Math.ceil(radius - 0.5);
|
|
4927
|
+
for (let y = 0; y < size; y++) {
|
|
4928
|
+
for (let x = 0; x < size; x++) {
|
|
4929
|
+
const dx = x - radius + 0.5;
|
|
4930
|
+
const dy = y - radius + 0.5;
|
|
4931
|
+
const distSqr = dx * dx + dy * dy;
|
|
4932
|
+
if (distSqr <= radius * radius) {
|
|
4933
|
+
data[y * size + x] = 1;
|
|
4934
|
+
}
|
|
4935
|
+
}
|
|
4936
|
+
}
|
|
4937
|
+
return {
|
|
4938
|
+
type: 1 /* BINARY */,
|
|
4939
|
+
data,
|
|
4940
|
+
w: size,
|
|
4941
|
+
h: size,
|
|
4942
|
+
centerOffsetX: centerOffset,
|
|
4943
|
+
centerOffsetY: centerOffset
|
|
4944
|
+
};
|
|
4945
|
+
}
|
|
4946
|
+
|
|
4947
|
+
// src/Paint/makePaintMask.ts
|
|
4948
|
+
function makePaintBinaryMask(mask) {
|
|
4949
|
+
return {
|
|
4950
|
+
type: 1 /* BINARY */,
|
|
4951
|
+
data: mask.data,
|
|
4952
|
+
w: mask.w,
|
|
4953
|
+
h: mask.h,
|
|
4954
|
+
centerOffsetX: -(mask.w >> 1),
|
|
4955
|
+
centerOffsetY: -(mask.h >> 1)
|
|
4956
|
+
};
|
|
4957
|
+
}
|
|
4958
|
+
function makePaintAlphaMask(mask) {
|
|
4959
|
+
return {
|
|
4960
|
+
type: 0 /* ALPHA */,
|
|
4961
|
+
data: mask.data,
|
|
4962
|
+
w: mask.w,
|
|
4963
|
+
h: mask.h,
|
|
4964
|
+
centerOffsetX: -(mask.w >> 1),
|
|
4965
|
+
centerOffsetY: -(mask.h >> 1)
|
|
4966
|
+
};
|
|
4967
|
+
}
|
|
4968
|
+
|
|
4969
|
+
// src/Paint/makeRectFalloffPaintAlphaMask.ts
|
|
4970
|
+
function makeRectFalloffPaintAlphaMask(width, height, fallOff = (d) => d) {
|
|
4971
|
+
const fPx = Math.floor(width / 2);
|
|
4972
|
+
const fPy = Math.floor(height / 2);
|
|
4973
|
+
const invHalfW = 2 / width;
|
|
4974
|
+
const invHalfH = 2 / height;
|
|
4975
|
+
const offX = width % 2 === 0 ? 0.5 : 0;
|
|
4976
|
+
const offY = height % 2 === 0 ? 0.5 : 0;
|
|
4977
|
+
const area = width * height;
|
|
4978
|
+
const data = new Uint8Array(area);
|
|
4979
|
+
for (let y = 0; y < height; y++) {
|
|
4980
|
+
const dy = Math.abs(y - fPy + offY) * invHalfH;
|
|
4981
|
+
const rowOffset = y * width;
|
|
4982
|
+
for (let x = 0; x < width; x++) {
|
|
4983
|
+
const dx = Math.abs(x - fPx + offX) * invHalfW;
|
|
4984
|
+
const dist = dx > dy ? dx : dy;
|
|
4985
|
+
const strength = fallOff(1 - dist);
|
|
4986
|
+
if (strength > 0) {
|
|
4987
|
+
const intensity = strength * 255 | 0;
|
|
4988
|
+
data[rowOffset + x] = Math.max(0, Math.min(255, intensity));
|
|
4989
|
+
}
|
|
4990
|
+
}
|
|
4991
|
+
}
|
|
4992
|
+
return {
|
|
4993
|
+
type: 0 /* ALPHA */,
|
|
4804
4994
|
data,
|
|
4805
|
-
|
|
4806
|
-
|
|
4995
|
+
w: width,
|
|
4996
|
+
h: height,
|
|
4997
|
+
centerOffsetX: -(width >> 1),
|
|
4998
|
+
centerOffsetY: -(height >> 1)
|
|
4999
|
+
};
|
|
4807
5000
|
}
|
|
4808
5001
|
|
|
4809
5002
|
// src/PixelData/PixelData.ts
|
|
@@ -4827,14 +5020,96 @@ var PixelData = class {
|
|
|
4827
5020
|
}
|
|
4828
5021
|
};
|
|
4829
5022
|
|
|
4830
|
-
// src/PixelData/
|
|
5023
|
+
// src/PixelData/applyMaskToPixelData.ts
|
|
5024
|
+
function applyMaskToPixelData(dst, mask, opts) {
|
|
5025
|
+
if (mask.type === 1 /* BINARY */) {
|
|
5026
|
+
return applyBinaryMaskToPixelData(dst, mask, opts);
|
|
5027
|
+
} else {
|
|
5028
|
+
return applyAlphaMaskToPixelData(dst, mask, opts);
|
|
5029
|
+
}
|
|
5030
|
+
}
|
|
5031
|
+
|
|
5032
|
+
// src/PixelData/blendColorPixelDataMask.ts
|
|
5033
|
+
function blendColorPixelDataMask(dst, color, mask, opts) {
|
|
5034
|
+
if (mask.type === 1 /* BINARY */) {
|
|
5035
|
+
return blendColorPixelDataBinaryMask(dst, color, mask, opts);
|
|
5036
|
+
} else {
|
|
5037
|
+
return blendColorPixelDataAlphaMask(dst, color, mask, opts);
|
|
5038
|
+
}
|
|
5039
|
+
}
|
|
5040
|
+
|
|
5041
|
+
// src/PixelData/blendColorPixelDataPaintAlphaMask.ts
|
|
4831
5042
|
var SCRATCH_OPTS = {
|
|
5043
|
+
x: 0,
|
|
5044
|
+
y: 0,
|
|
5045
|
+
alpha: 255,
|
|
5046
|
+
blendFn: sourceOverPerfect
|
|
5047
|
+
};
|
|
5048
|
+
function blendColorPixelDataPaintAlphaMask(dst, color, mask, x, y, alpha = 255, blendFn = sourceOverPerfect) {
|
|
5049
|
+
const tx = x + mask.centerOffsetX;
|
|
5050
|
+
const ty = y + mask.centerOffsetY;
|
|
5051
|
+
SCRATCH_OPTS.x = tx;
|
|
5052
|
+
SCRATCH_OPTS.y = ty;
|
|
5053
|
+
SCRATCH_OPTS.alpha = alpha;
|
|
5054
|
+
SCRATCH_OPTS.blendFn = blendFn;
|
|
5055
|
+
return blendColorPixelDataAlphaMask(dst, color, mask, SCRATCH_OPTS);
|
|
5056
|
+
}
|
|
5057
|
+
|
|
5058
|
+
// src/PixelData/blendColorPixelDataPaintBinaryMask.ts
|
|
5059
|
+
var SCRATCH_OPTS2 = {
|
|
5060
|
+
x: 0,
|
|
5061
|
+
y: 0,
|
|
5062
|
+
alpha: 255,
|
|
5063
|
+
blendFn: sourceOverPerfect
|
|
5064
|
+
};
|
|
5065
|
+
function blendColorPixelDataPaintBinaryMask(dst, color, mask, x, y, alpha = 255, blendFn = sourceOverPerfect) {
|
|
5066
|
+
const tx = x + mask.centerOffsetX;
|
|
5067
|
+
const ty = y + mask.centerOffsetY;
|
|
5068
|
+
SCRATCH_OPTS2.x = tx;
|
|
5069
|
+
SCRATCH_OPTS2.y = ty;
|
|
5070
|
+
SCRATCH_OPTS2.alpha = alpha;
|
|
5071
|
+
SCRATCH_OPTS2.blendFn = blendFn;
|
|
5072
|
+
return blendColorPixelDataBinaryMask(dst, color, mask, SCRATCH_OPTS2);
|
|
5073
|
+
}
|
|
5074
|
+
|
|
5075
|
+
// src/PixelData/blendColorPixelDataPaintMask.ts
|
|
5076
|
+
var SCRATCH_OPTS3 = {
|
|
5077
|
+
x: 0,
|
|
5078
|
+
y: 0,
|
|
5079
|
+
alpha: 255,
|
|
5080
|
+
blendFn: sourceOverPerfect
|
|
5081
|
+
};
|
|
5082
|
+
function blendColorPixelDataPaintMask(dst, color, mask, x, y, alpha = 255, blendFn = sourceOverPerfect) {
|
|
5083
|
+
const tx = x + mask.centerOffsetX;
|
|
5084
|
+
const ty = y + mask.centerOffsetY;
|
|
5085
|
+
SCRATCH_OPTS3.x = tx;
|
|
5086
|
+
SCRATCH_OPTS3.y = ty;
|
|
5087
|
+
SCRATCH_OPTS3.alpha = alpha;
|
|
5088
|
+
SCRATCH_OPTS3.blendFn = blendFn;
|
|
5089
|
+
if (mask.type === 1 /* BINARY */) {
|
|
5090
|
+
return blendColorPixelDataBinaryMask(dst, color, mask, SCRATCH_OPTS3);
|
|
5091
|
+
} else {
|
|
5092
|
+
return blendColorPixelDataAlphaMask(dst, color, mask, SCRATCH_OPTS3);
|
|
5093
|
+
}
|
|
5094
|
+
}
|
|
5095
|
+
|
|
5096
|
+
// src/PixelData/blendPixelDataMask.ts
|
|
5097
|
+
function blendPixelDataMask(target, src, mask, opts) {
|
|
5098
|
+
if (mask.type === 1 /* BINARY */) {
|
|
5099
|
+
return blendPixelDataBinaryMask(target, src, mask, opts);
|
|
5100
|
+
} else {
|
|
5101
|
+
return blendPixelDataAlphaMask(target, src, mask, opts);
|
|
5102
|
+
}
|
|
5103
|
+
}
|
|
5104
|
+
|
|
5105
|
+
// src/PixelData/blendPixelDataPaintBuffer.ts
|
|
5106
|
+
var SCRATCH_OPTS4 = {
|
|
4832
5107
|
x: 0,
|
|
4833
5108
|
y: 0,
|
|
4834
5109
|
alpha: 255,
|
|
4835
5110
|
blendFn: void 0
|
|
4836
5111
|
};
|
|
4837
|
-
function blendPixelDataPaintBuffer(
|
|
5112
|
+
function blendPixelDataPaintBuffer(target, paintBuffer, alpha = 255, blendFn, blendPixelDataFn = blendPixelData) {
|
|
4838
5113
|
const tileShift = paintBuffer.config.tileShift;
|
|
4839
5114
|
const lookup = paintBuffer.lookup;
|
|
4840
5115
|
for (let i = 0; i < lookup.length; i++) {
|
|
@@ -4842,17 +5117,61 @@ function blendPixelDataPaintBuffer(paintBuffer, target, alpha = 255, blendFn, bl
|
|
|
4842
5117
|
if (tile) {
|
|
4843
5118
|
const x = tile.tx << tileShift;
|
|
4844
5119
|
const y = tile.ty << tileShift;
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
blendPixelDataFn(target, tile,
|
|
5120
|
+
SCRATCH_OPTS4.x = x;
|
|
5121
|
+
SCRATCH_OPTS4.y = y;
|
|
5122
|
+
SCRATCH_OPTS4.alpha = alpha;
|
|
5123
|
+
SCRATCH_OPTS4.blendFn = blendFn;
|
|
5124
|
+
blendPixelDataFn(target, tile, SCRATCH_OPTS4);
|
|
4850
5125
|
}
|
|
4851
5126
|
}
|
|
4852
5127
|
}
|
|
4853
5128
|
|
|
4854
|
-
// src/PixelData/
|
|
4855
|
-
|
|
5129
|
+
// src/PixelData/fillPixelDataFast.ts
|
|
5130
|
+
var SCRATCH_RECT4 = makeClippedRect();
|
|
5131
|
+
function fillPixelDataFast(dst, color, _x, _y, _w, _h) {
|
|
5132
|
+
let x;
|
|
5133
|
+
let y;
|
|
5134
|
+
let w;
|
|
5135
|
+
let h;
|
|
5136
|
+
if (typeof _x === "object") {
|
|
5137
|
+
x = _x.x ?? 0;
|
|
5138
|
+
y = _x.y ?? 0;
|
|
5139
|
+
w = _x.w ?? dst.width;
|
|
5140
|
+
h = _x.h ?? dst.height;
|
|
5141
|
+
} else if (typeof _x === "number") {
|
|
5142
|
+
x = _x;
|
|
5143
|
+
y = _y;
|
|
5144
|
+
w = _w;
|
|
5145
|
+
h = _h;
|
|
5146
|
+
} else {
|
|
5147
|
+
x = 0;
|
|
5148
|
+
y = 0;
|
|
5149
|
+
w = dst.width;
|
|
5150
|
+
h = dst.height;
|
|
5151
|
+
}
|
|
5152
|
+
const clip = resolveRectClipping(x, y, w, h, dst.width, dst.height, SCRATCH_RECT4);
|
|
5153
|
+
if (!clip.inBounds) return;
|
|
5154
|
+
const {
|
|
5155
|
+
x: finalX,
|
|
5156
|
+
y: finalY,
|
|
5157
|
+
w: actualW,
|
|
5158
|
+
h: actualH
|
|
5159
|
+
} = clip;
|
|
5160
|
+
const dst32 = dst.data32;
|
|
5161
|
+
const dw = dst.width;
|
|
5162
|
+
if (actualW === dw && actualH === dst.height && finalX === 0 && finalY === 0) {
|
|
5163
|
+
dst32.fill(color);
|
|
5164
|
+
return;
|
|
5165
|
+
}
|
|
5166
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
5167
|
+
const start = (finalY + iy) * dw + finalX;
|
|
5168
|
+
const end = start + actualW;
|
|
5169
|
+
dst32.fill(color, start, end);
|
|
5170
|
+
}
|
|
5171
|
+
}
|
|
5172
|
+
|
|
5173
|
+
// src/PixelData/clearPixelDataFast.ts
|
|
5174
|
+
function clearPixelDataFast(dst, rect) {
|
|
4856
5175
|
fillPixelDataFast(dst, 0, rect);
|
|
4857
5176
|
}
|
|
4858
5177
|
|
|
@@ -4915,26 +5234,6 @@ function extractPixelData(source, _x, _y, _w, _h) {
|
|
|
4915
5234
|
return result;
|
|
4916
5235
|
}
|
|
4917
5236
|
|
|
4918
|
-
// src/PixelData/PixelBuffer32.ts
|
|
4919
|
-
var PixelBuffer32 = class _PixelBuffer32 {
|
|
4920
|
-
constructor(width, height, data32) {
|
|
4921
|
-
this.width = width;
|
|
4922
|
-
this.height = height;
|
|
4923
|
-
this.data32 = data32 ?? new Uint32Array(width * height);
|
|
4924
|
-
}
|
|
4925
|
-
data32;
|
|
4926
|
-
set(width, height, data32) {
|
|
4927
|
-
;
|
|
4928
|
-
this.data32 = data32 ?? new Uint32Array(width * height);
|
|
4929
|
-
this.width = width;
|
|
4930
|
-
this.height = height;
|
|
4931
|
-
}
|
|
4932
|
-
copy() {
|
|
4933
|
-
const newData32 = new Uint32Array(this.data32);
|
|
4934
|
-
return new _PixelBuffer32(this.width, this.height, newData32);
|
|
4935
|
-
}
|
|
4936
|
-
};
|
|
4937
|
-
|
|
4938
5237
|
// src/PixelData/pixelDataToAlphaMask.ts
|
|
4939
5238
|
function pixelDataToAlphaMask(pixelData) {
|
|
4940
5239
|
const {
|
|
@@ -5086,162 +5385,17 @@ function writePaintBufferToPixelData(target, paintBuffer, writePixelDataBufferFn
|
|
|
5086
5385
|
}
|
|
5087
5386
|
}
|
|
5088
5387
|
}
|
|
5089
|
-
|
|
5090
|
-
// src/Paint/makeCirclePaintAlphaMask.ts
|
|
5091
|
-
function makeCirclePaintAlphaMask(size, fallOff = (d) => d) {
|
|
5092
|
-
const area = size * size;
|
|
5093
|
-
const data = new Uint8Array(area);
|
|
5094
|
-
const radius = size / 2;
|
|
5095
|
-
const invR = 1 / radius;
|
|
5096
|
-
const centerOffset = -Math.ceil(radius - 0.5);
|
|
5097
|
-
for (let y = 0; y < size; y++) {
|
|
5098
|
-
const rowOffset = y * size;
|
|
5099
|
-
const dy = y - radius + 0.5;
|
|
5100
|
-
const dy2 = dy * dy;
|
|
5101
|
-
for (let x = 0; x < size; x++) {
|
|
5102
|
-
const dx = x - radius + 0.5;
|
|
5103
|
-
const distSqr = dx * dx + dy2;
|
|
5104
|
-
if (distSqr <= radius * radius) {
|
|
5105
|
-
const dist = Math.sqrt(distSqr) * invR;
|
|
5106
|
-
const strength = fallOff(1 - dist);
|
|
5107
|
-
if (strength > 0) {
|
|
5108
|
-
const intensity = strength * 255 | 0;
|
|
5109
|
-
data[rowOffset + x] = Math.max(0, Math.min(255, intensity));
|
|
5110
|
-
}
|
|
5111
|
-
}
|
|
5112
|
-
}
|
|
5113
|
-
}
|
|
5114
|
-
return {
|
|
5115
|
-
type: 0 /* ALPHA */,
|
|
5116
|
-
data,
|
|
5117
|
-
w: size,
|
|
5118
|
-
h: size,
|
|
5119
|
-
centerOffsetX: centerOffset,
|
|
5120
|
-
centerOffsetY: centerOffset
|
|
5121
|
-
};
|
|
5122
|
-
}
|
|
5123
|
-
|
|
5124
|
-
// src/Paint/makeCirclePaintBinaryMask.ts
|
|
5125
|
-
function makeCirclePaintBinaryMask(size) {
|
|
5126
|
-
const area = size * size;
|
|
5127
|
-
const data = new Uint8Array(area);
|
|
5128
|
-
const radius = size / 2;
|
|
5129
|
-
const centerOffset = -Math.ceil(radius - 0.5);
|
|
5130
|
-
for (let y = 0; y < size; y++) {
|
|
5131
|
-
for (let x = 0; x < size; x++) {
|
|
5132
|
-
const dx = x - radius + 0.5;
|
|
5133
|
-
const dy = y - radius + 0.5;
|
|
5134
|
-
const distSqr = dx * dx + dy * dy;
|
|
5135
|
-
if (distSqr <= radius * radius) {
|
|
5136
|
-
data[y * size + x] = 1;
|
|
5137
|
-
}
|
|
5138
|
-
}
|
|
5139
|
-
}
|
|
5140
|
-
return {
|
|
5141
|
-
type: 1 /* BINARY */,
|
|
5142
|
-
data,
|
|
5143
|
-
w: size,
|
|
5144
|
-
h: size,
|
|
5145
|
-
centerOffsetX: centerOffset,
|
|
5146
|
-
centerOffsetY: centerOffset
|
|
5147
|
-
};
|
|
5148
|
-
}
|
|
5149
|
-
|
|
5150
|
-
// src/Paint/makePaintMask.ts
|
|
5151
|
-
function makePaintBinaryMask(mask) {
|
|
5152
|
-
return {
|
|
5153
|
-
type: 1 /* BINARY */,
|
|
5154
|
-
data: mask.data,
|
|
5155
|
-
w: mask.w,
|
|
5156
|
-
h: mask.h,
|
|
5157
|
-
centerOffsetX: -(mask.w >> 1),
|
|
5158
|
-
centerOffsetY: -(mask.h >> 1)
|
|
5159
|
-
};
|
|
5160
|
-
}
|
|
5161
|
-
function makePaintAlphaMask(mask) {
|
|
5162
|
-
return {
|
|
5163
|
-
type: 0 /* ALPHA */,
|
|
5164
|
-
data: mask.data,
|
|
5165
|
-
w: mask.w,
|
|
5166
|
-
h: mask.h,
|
|
5167
|
-
centerOffsetX: -(mask.w >> 1),
|
|
5168
|
-
centerOffsetY: -(mask.h >> 1)
|
|
5169
|
-
};
|
|
5170
|
-
}
|
|
5171
|
-
|
|
5172
|
-
// src/Paint/makeRectFalloffPaintAlphaMask.ts
|
|
5173
|
-
function makeRectFalloffPaintAlphaMask(width, height, fallOff = (d) => d) {
|
|
5174
|
-
const fPx = Math.floor(width / 2);
|
|
5175
|
-
const fPy = Math.floor(height / 2);
|
|
5176
|
-
const invHalfW = 2 / width;
|
|
5177
|
-
const invHalfH = 2 / height;
|
|
5178
|
-
const offX = width % 2 === 0 ? 0.5 : 0;
|
|
5179
|
-
const offY = height % 2 === 0 ? 0.5 : 0;
|
|
5180
|
-
const area = width * height;
|
|
5181
|
-
const data = new Uint8Array(area);
|
|
5182
|
-
for (let y = 0; y < height; y++) {
|
|
5183
|
-
const dy = Math.abs(y - fPy + offY) * invHalfH;
|
|
5184
|
-
const rowOffset = y * width;
|
|
5185
|
-
for (let x = 0; x < width; x++) {
|
|
5186
|
-
const dx = Math.abs(x - fPx + offX) * invHalfW;
|
|
5187
|
-
const dist = dx > dy ? dx : dy;
|
|
5188
|
-
const strength = fallOff(1 - dist);
|
|
5189
|
-
if (strength > 0) {
|
|
5190
|
-
const intensity = strength * 255 | 0;
|
|
5191
|
-
data[rowOffset + x] = Math.max(0, Math.min(255, intensity));
|
|
5192
|
-
}
|
|
5193
|
-
}
|
|
5194
|
-
}
|
|
5195
|
-
return {
|
|
5196
|
-
type: 0 /* ALPHA */,
|
|
5197
|
-
data,
|
|
5198
|
-
w: width,
|
|
5199
|
-
h: height,
|
|
5200
|
-
centerOffsetX: -macro_halfAndFloor(width),
|
|
5201
|
-
centerOffsetY: -macro_halfAndFloor(height)
|
|
5202
|
-
};
|
|
5203
|
-
}
|
|
5204
|
-
|
|
5205
|
-
// src/Paint/PaintBufferCanvasRenderer.ts
|
|
5206
|
-
function makePaintBufferCanvasRenderer(paintBuffer, offscreenCanvasClass = OffscreenCanvas) {
|
|
5207
|
-
const config = paintBuffer.config;
|
|
5208
|
-
const tileSize = config.tileSize;
|
|
5209
|
-
const tileShift = config.tileShift;
|
|
5210
|
-
const lookup = paintBuffer.lookup;
|
|
5211
|
-
const canvas = new offscreenCanvasClass(tileSize, tileSize);
|
|
5212
|
-
const ctx = canvas.getContext("2d");
|
|
5213
|
-
if (!ctx) throw new Error(CANVAS_CTX_FAILED);
|
|
5214
|
-
ctx.imageSmoothingEnabled = false;
|
|
5215
|
-
return function drawPaintBuffer(targetCtx, alpha = 255, compOperation = "source-over") {
|
|
5216
|
-
targetCtx.globalAlpha = alpha / 255;
|
|
5217
|
-
targetCtx.globalCompositeOperation = compOperation;
|
|
5218
|
-
for (let i = 0; i < lookup.length; i++) {
|
|
5219
|
-
const tile = lookup[i];
|
|
5220
|
-
if (tile) {
|
|
5221
|
-
const dx = tile.tx << tileShift;
|
|
5222
|
-
const dy = tile.ty << tileShift;
|
|
5223
|
-
ctx.putImageData(tile.imageData, 0, 0);
|
|
5224
|
-
targetCtx.drawImage(canvas, dx, dy);
|
|
5225
|
-
}
|
|
5226
|
-
}
|
|
5227
|
-
targetCtx.globalAlpha = 1;
|
|
5228
|
-
targetCtx.globalCompositeOperation = "source-over";
|
|
5229
|
-
};
|
|
5230
|
-
}
|
|
5231
5388
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5232
5389
|
0 && (module.exports = {
|
|
5233
5390
|
BASE_FAST_BLEND_MODE_FUNCTIONS,
|
|
5234
5391
|
BASE_PERFECT_BLEND_MODE_FUNCTIONS,
|
|
5235
5392
|
BaseBlendMode,
|
|
5236
5393
|
CANVAS_COMPOSITE_MAP,
|
|
5237
|
-
CANVAS_CTX_FAILED,
|
|
5238
5394
|
HistoryManager,
|
|
5239
5395
|
IndexedImage,
|
|
5240
5396
|
MaskType,
|
|
5241
|
-
OFFSCREEN_CANVAS_CTX_FAILED,
|
|
5242
5397
|
PaintBuffer,
|
|
5243
5398
|
PixelAccumulator,
|
|
5244
|
-
PixelBuffer32,
|
|
5245
5399
|
PixelData,
|
|
5246
5400
|
PixelEngineConfig,
|
|
5247
5401
|
PixelTile,
|
|
@@ -5251,18 +5405,24 @@ function makePaintBufferCanvasRenderer(paintBuffer, offscreenCanvasClass = Offsc
|
|
|
5251
5405
|
applyAlphaMaskToPixelData,
|
|
5252
5406
|
applyBinaryMaskToAlphaMask,
|
|
5253
5407
|
applyBinaryMaskToPixelData,
|
|
5408
|
+
applyMaskToPixelData,
|
|
5254
5409
|
applyPatchTiles,
|
|
5255
5410
|
base64DecodeArrayBuffer,
|
|
5256
5411
|
base64EncodeArrayBuffer,
|
|
5257
5412
|
blendColorPixelData,
|
|
5258
5413
|
blendColorPixelDataAlphaMask,
|
|
5259
5414
|
blendColorPixelDataBinaryMask,
|
|
5415
|
+
blendColorPixelDataMask,
|
|
5416
|
+
blendColorPixelDataPaintAlphaMask,
|
|
5417
|
+
blendColorPixelDataPaintBinaryMask,
|
|
5418
|
+
blendColorPixelDataPaintMask,
|
|
5260
5419
|
blendPixel,
|
|
5261
5420
|
blendPixelData,
|
|
5262
5421
|
blendPixelDataAlphaMask,
|
|
5263
5422
|
blendPixelDataBinaryMask,
|
|
5423
|
+
blendPixelDataMask,
|
|
5264
5424
|
blendPixelDataPaintBuffer,
|
|
5265
|
-
|
|
5425
|
+
clearPixelDataFast,
|
|
5266
5426
|
color32ToCssRGBA,
|
|
5267
5427
|
color32ToHex,
|
|
5268
5428
|
colorBurnFast,
|
|
@@ -5335,6 +5495,8 @@ function makePaintBufferCanvasRenderer(paintBuffer, offscreenCanvasClass = Offsc
|
|
|
5335
5495
|
makeCanvasFrameRenderer,
|
|
5336
5496
|
makeCirclePaintAlphaMask,
|
|
5337
5497
|
makeCirclePaintBinaryMask,
|
|
5498
|
+
makeClippedBlit,
|
|
5499
|
+
makeClippedRect,
|
|
5338
5500
|
makeFastBlendModeRegistry,
|
|
5339
5501
|
makeFullPixelMutator,
|
|
5340
5502
|
makeHistoryAction,
|
|
@@ -5356,12 +5518,17 @@ function makePaintBufferCanvasRenderer(paintBuffer, offscreenCanvasClass = Offsc
|
|
|
5356
5518
|
multiplyPerfect,
|
|
5357
5519
|
mutatorApplyAlphaMask,
|
|
5358
5520
|
mutatorApplyBinaryMask,
|
|
5521
|
+
mutatorApplyMask,
|
|
5522
|
+
mutatorBlendAlphaMask,
|
|
5523
|
+
mutatorBlendBinaryMask,
|
|
5359
5524
|
mutatorBlendColor,
|
|
5360
|
-
|
|
5525
|
+
mutatorBlendColorPaintAlphaMask,
|
|
5526
|
+
mutatorBlendColorPaintBinaryMask,
|
|
5527
|
+
mutatorBlendColorPaintMask,
|
|
5528
|
+
mutatorBlendMask,
|
|
5529
|
+
mutatorBlendPaintRect,
|
|
5361
5530
|
mutatorBlendPixel,
|
|
5362
5531
|
mutatorBlendPixelData,
|
|
5363
|
-
mutatorBlendPixelDataAlphaMask,
|
|
5364
|
-
mutatorBlendPixelDataBinaryMask,
|
|
5365
5532
|
mutatorClear,
|
|
5366
5533
|
mutatorFill,
|
|
5367
5534
|
mutatorFillBinaryMask,
|
|
@@ -5379,10 +5546,13 @@ function makePaintBufferCanvasRenderer(paintBuffer, offscreenCanvasClass = Offsc
|
|
|
5379
5546
|
pixelDataToAlphaMask,
|
|
5380
5547
|
reflectPixelDataHorizontal,
|
|
5381
5548
|
reflectPixelDataVertical,
|
|
5549
|
+
resample32,
|
|
5382
5550
|
resampleImageData,
|
|
5383
5551
|
resampleIndexedImage,
|
|
5384
5552
|
resamplePixelData,
|
|
5385
5553
|
resizeImageData,
|
|
5554
|
+
resolveBlitClipping,
|
|
5555
|
+
resolveRectClipping,
|
|
5386
5556
|
rotatePixelData,
|
|
5387
5557
|
screenFast,
|
|
5388
5558
|
screenPerfect,
|