pixel-data-js 0.25.0 → 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 +1832 -1606
- package/dist/index.prod.cjs.map +1 -1
- package/dist/index.prod.d.ts +458 -324
- package/dist/index.prod.js +1811 -1600
- 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/mutatorBlendColorPaintMask.ts +60 -0
- 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 -29
- package/dist/index.dev.cjs +0 -5363
- package/dist/index.dev.cjs.map +0 -1
- package/dist/index.dev.js +0 -5154
- 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
|
@@ -23,14 +23,12 @@ __export(src_exports, {
|
|
|
23
23
|
BASE_FAST_BLEND_MODE_FUNCTIONS: () => BASE_FAST_BLEND_MODE_FUNCTIONS,
|
|
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
27
|
HistoryManager: () => HistoryManager,
|
|
28
28
|
IndexedImage: () => IndexedImage,
|
|
29
29
|
MaskType: () => MaskType,
|
|
30
|
-
OFFSCREEN_CANVAS_CTX_FAILED: () => OFFSCREEN_CANVAS_CTX_FAILED,
|
|
31
30
|
PaintBuffer: () => PaintBuffer,
|
|
32
31
|
PixelAccumulator: () => PixelAccumulator,
|
|
33
|
-
PixelBuffer32: () => PixelBuffer32,
|
|
34
32
|
PixelData: () => PixelData,
|
|
35
33
|
PixelEngineConfig: () => PixelEngineConfig,
|
|
36
34
|
PixelTile: () => PixelTile,
|
|
@@ -40,18 +38,24 @@ __export(src_exports, {
|
|
|
40
38
|
applyAlphaMaskToPixelData: () => applyAlphaMaskToPixelData,
|
|
41
39
|
applyBinaryMaskToAlphaMask: () => applyBinaryMaskToAlphaMask,
|
|
42
40
|
applyBinaryMaskToPixelData: () => applyBinaryMaskToPixelData,
|
|
41
|
+
applyMaskToPixelData: () => applyMaskToPixelData,
|
|
43
42
|
applyPatchTiles: () => applyPatchTiles,
|
|
44
43
|
base64DecodeArrayBuffer: () => base64DecodeArrayBuffer,
|
|
45
44
|
base64EncodeArrayBuffer: () => base64EncodeArrayBuffer,
|
|
46
45
|
blendColorPixelData: () => blendColorPixelData,
|
|
47
46
|
blendColorPixelDataAlphaMask: () => blendColorPixelDataAlphaMask,
|
|
48
47
|
blendColorPixelDataBinaryMask: () => blendColorPixelDataBinaryMask,
|
|
48
|
+
blendColorPixelDataMask: () => blendColorPixelDataMask,
|
|
49
|
+
blendColorPixelDataPaintAlphaMask: () => blendColorPixelDataPaintAlphaMask,
|
|
50
|
+
blendColorPixelDataPaintBinaryMask: () => blendColorPixelDataPaintBinaryMask,
|
|
51
|
+
blendColorPixelDataPaintMask: () => blendColorPixelDataPaintMask,
|
|
49
52
|
blendPixel: () => blendPixel,
|
|
50
53
|
blendPixelData: () => blendPixelData,
|
|
51
54
|
blendPixelDataAlphaMask: () => blendPixelDataAlphaMask,
|
|
52
55
|
blendPixelDataBinaryMask: () => blendPixelDataBinaryMask,
|
|
56
|
+
blendPixelDataMask: () => blendPixelDataMask,
|
|
53
57
|
blendPixelDataPaintBuffer: () => blendPixelDataPaintBuffer,
|
|
54
|
-
|
|
58
|
+
clearPixelDataFast: () => clearPixelDataFast,
|
|
55
59
|
color32ToCssRGBA: () => color32ToCssRGBA,
|
|
56
60
|
color32ToHex: () => color32ToHex,
|
|
57
61
|
colorBurnFast: () => colorBurnFast,
|
|
@@ -124,6 +128,8 @@ __export(src_exports, {
|
|
|
124
128
|
makeCanvasFrameRenderer: () => makeCanvasFrameRenderer,
|
|
125
129
|
makeCirclePaintAlphaMask: () => makeCirclePaintAlphaMask,
|
|
126
130
|
makeCirclePaintBinaryMask: () => makeCirclePaintBinaryMask,
|
|
131
|
+
makeClippedBlit: () => makeClippedBlit,
|
|
132
|
+
makeClippedRect: () => makeClippedRect,
|
|
127
133
|
makeFastBlendModeRegistry: () => makeFastBlendModeRegistry,
|
|
128
134
|
makeFullPixelMutator: () => makeFullPixelMutator,
|
|
129
135
|
makeHistoryAction: () => makeHistoryAction,
|
|
@@ -145,11 +151,17 @@ __export(src_exports, {
|
|
|
145
151
|
multiplyPerfect: () => multiplyPerfect,
|
|
146
152
|
mutatorApplyAlphaMask: () => mutatorApplyAlphaMask,
|
|
147
153
|
mutatorApplyBinaryMask: () => mutatorApplyBinaryMask,
|
|
154
|
+
mutatorApplyMask: () => mutatorApplyMask,
|
|
155
|
+
mutatorBlendAlphaMask: () => mutatorBlendAlphaMask,
|
|
156
|
+
mutatorBlendBinaryMask: () => mutatorBlendBinaryMask,
|
|
148
157
|
mutatorBlendColor: () => mutatorBlendColor,
|
|
158
|
+
mutatorBlendColorPaintAlphaMask: () => mutatorBlendColorPaintAlphaMask,
|
|
159
|
+
mutatorBlendColorPaintBinaryMask: () => mutatorBlendColorPaintBinaryMask,
|
|
160
|
+
mutatorBlendColorPaintMask: () => mutatorBlendColorPaintMask,
|
|
161
|
+
mutatorBlendMask: () => mutatorBlendMask,
|
|
162
|
+
mutatorBlendPaintRect: () => mutatorBlendPaintRect,
|
|
149
163
|
mutatorBlendPixel: () => mutatorBlendPixel,
|
|
150
164
|
mutatorBlendPixelData: () => mutatorBlendPixelData,
|
|
151
|
-
mutatorBlendPixelDataAlphaMask: () => mutatorBlendPixelDataAlphaMask,
|
|
152
|
-
mutatorBlendPixelDataBinaryMask: () => mutatorBlendPixelDataBinaryMask,
|
|
153
165
|
mutatorClear: () => mutatorClear,
|
|
154
166
|
mutatorFill: () => mutatorFill,
|
|
155
167
|
mutatorFillBinaryMask: () => mutatorFillBinaryMask,
|
|
@@ -167,10 +179,13 @@ __export(src_exports, {
|
|
|
167
179
|
pixelDataToAlphaMask: () => pixelDataToAlphaMask,
|
|
168
180
|
reflectPixelDataHorizontal: () => reflectPixelDataHorizontal,
|
|
169
181
|
reflectPixelDataVertical: () => reflectPixelDataVertical,
|
|
182
|
+
resample32: () => resample32,
|
|
170
183
|
resampleImageData: () => resampleImageData,
|
|
171
184
|
resampleIndexedImage: () => resampleIndexedImage,
|
|
172
185
|
resamplePixelData: () => resamplePixelData,
|
|
173
186
|
resizeImageData: () => resizeImageData,
|
|
187
|
+
resolveBlitClipping: () => resolveBlitClipping,
|
|
188
|
+
resolveRectClipping: () => resolveRectClipping,
|
|
174
189
|
rotatePixelData: () => rotatePixelData,
|
|
175
190
|
screenFast: () => screenFast,
|
|
176
191
|
screenPerfect: () => screenPerfect,
|
|
@@ -505,37 +520,22 @@ function trimMaskRectBounds(target, bounds) {
|
|
|
505
520
|
}
|
|
506
521
|
|
|
507
522
|
// src/Algorithm/floodFillSelection.ts
|
|
508
|
-
function floodFillSelection(
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
imageData = img;
|
|
521
|
-
}
|
|
522
|
-
const {
|
|
523
|
-
width,
|
|
524
|
-
height
|
|
525
|
-
} = img;
|
|
526
|
-
const limit = bounds || {
|
|
527
|
-
x: 0,
|
|
528
|
-
y: 0,
|
|
529
|
-
w: width,
|
|
530
|
-
h: height
|
|
531
|
-
};
|
|
532
|
-
const xMin = Math.max(0, limit.x);
|
|
533
|
-
const xMax = Math.min(width - 1, limit.x + limit.w - 1);
|
|
534
|
-
const yMin = Math.max(0, limit.y);
|
|
535
|
-
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);
|
|
536
535
|
if (startX < xMin || startX > xMax || startY < yMin || startY > yMax) {
|
|
537
536
|
return null;
|
|
538
537
|
}
|
|
538
|
+
out = out ?? {};
|
|
539
539
|
const baseColor = data32[startY * width + startX];
|
|
540
540
|
let matchCount = 0;
|
|
541
541
|
const matchX = new Uint16Array(width * height);
|
|
@@ -606,42 +606,33 @@ function floodFillSelection(img, startX, startY, {
|
|
|
606
606
|
}
|
|
607
607
|
}
|
|
608
608
|
}
|
|
609
|
-
if (matchCount === 0)
|
|
610
|
-
return null;
|
|
611
|
-
}
|
|
609
|
+
if (matchCount === 0) return null;
|
|
612
610
|
const w = maxX - minX + 1;
|
|
613
611
|
const h = maxY - minY + 1;
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
const
|
|
623
|
-
const sh = selectionRect.h;
|
|
624
|
-
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;
|
|
625
621
|
for (let i = 0; i < matchCount; i++) {
|
|
626
|
-
const mx = matchX[i] -
|
|
627
|
-
const my = matchY[i] -
|
|
628
|
-
if (mx >= 0 && mx <
|
|
629
|
-
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;
|
|
630
626
|
}
|
|
631
627
|
}
|
|
632
|
-
trimMaskRectBounds(
|
|
628
|
+
trimMaskRectBounds(out, {
|
|
633
629
|
x: 0,
|
|
634
630
|
y: 0,
|
|
635
631
|
w: width,
|
|
636
632
|
h: height
|
|
637
633
|
});
|
|
638
|
-
|
|
639
|
-
return
|
|
640
|
-
startX,
|
|
641
|
-
startY,
|
|
642
|
-
selectionRect,
|
|
643
|
-
pixels: extracted
|
|
644
|
-
};
|
|
634
|
+
out.pixels = extractImageDataBuffer(target.imageData, out.x, out.y, out.w, out.h);
|
|
635
|
+
return out;
|
|
645
636
|
}
|
|
646
637
|
|
|
647
638
|
// src/Algorithm/forEachLinePoint.ts
|
|
@@ -664,35 +655,6 @@ function forEachLinePoint(x0, y0, x1, y1, callback) {
|
|
|
664
655
|
}
|
|
665
656
|
}
|
|
666
657
|
|
|
667
|
-
// src/BlendModes/blend-modes.ts
|
|
668
|
-
var BaseBlendMode = {
|
|
669
|
-
overwrite: 0,
|
|
670
|
-
sourceOver: 1,
|
|
671
|
-
darken: 2,
|
|
672
|
-
multiply: 3,
|
|
673
|
-
colorBurn: 4,
|
|
674
|
-
linearBurn: 5,
|
|
675
|
-
darkerColor: 6,
|
|
676
|
-
lighten: 7,
|
|
677
|
-
screen: 8,
|
|
678
|
-
colorDodge: 9,
|
|
679
|
-
linearDodge: 10,
|
|
680
|
-
lighterColor: 11,
|
|
681
|
-
overlay: 12,
|
|
682
|
-
softLight: 13,
|
|
683
|
-
hardLight: 14,
|
|
684
|
-
vividLight: 15,
|
|
685
|
-
linearLight: 16,
|
|
686
|
-
pinLight: 17,
|
|
687
|
-
hardMix: 18,
|
|
688
|
-
difference: 19,
|
|
689
|
-
exclusion: 20,
|
|
690
|
-
subtract: 21,
|
|
691
|
-
divide: 22
|
|
692
|
-
};
|
|
693
|
-
var overwriteBase = (src, _dst) => src;
|
|
694
|
-
overwriteBase.isOverwrite = true;
|
|
695
|
-
|
|
696
658
|
// src/BlendModes/BlendModeRegistry.ts
|
|
697
659
|
function makeBlendModeRegistry(blendModes, initialEntries, registryName = "anonymous") {
|
|
698
660
|
const blendToName = /* @__PURE__ */ new Map();
|
|
@@ -732,6 +694,35 @@ function makeBlendModeRegistry(blendModes, initialEntries, registryName = "anony
|
|
|
732
694
|
};
|
|
733
695
|
}
|
|
734
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
|
+
|
|
735
726
|
// src/BlendModes/blend-modes-fast.ts
|
|
736
727
|
var overwriteFast = overwriteBase;
|
|
737
728
|
var sourceOverFast = (src, dst) => {
|
|
@@ -1737,7 +1728,7 @@ var getKeyByValue = (obj, value) => {
|
|
|
1737
1728
|
}
|
|
1738
1729
|
};
|
|
1739
1730
|
|
|
1740
|
-
//
|
|
1731
|
+
// support/error-strings.ts
|
|
1741
1732
|
var OFFSCREEN_CANVAS_CTX_FAILED = "Failed to create OffscreenCanvas context";
|
|
1742
1733
|
var CANVAS_CTX_FAILED = "Failed to create Canvas context";
|
|
1743
1734
|
|
|
@@ -1839,6 +1830,24 @@ function makePixelCanvas(canvas) {
|
|
|
1839
1830
|
};
|
|
1840
1831
|
}
|
|
1841
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
|
+
|
|
1842
1851
|
// src/ImageData/imgBlobToImageData.ts
|
|
1843
1852
|
async function imgBlobToImageData(blob) {
|
|
1844
1853
|
let bitmap = null;
|
|
@@ -1923,10 +1932,9 @@ function applyPatchTiles(target, tiles, tileSize) {
|
|
|
1923
1932
|
}
|
|
1924
1933
|
|
|
1925
1934
|
// src/History/HistoryAction.ts
|
|
1926
|
-
function makeHistoryAction(
|
|
1927
|
-
const target =
|
|
1928
|
-
const tileSize =
|
|
1929
|
-
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;
|
|
1930
1938
|
return {
|
|
1931
1939
|
undo: () => {
|
|
1932
1940
|
applyPatchTilesFn(target, patch.beforeTiles, tileSize);
|
|
@@ -2196,20 +2204,17 @@ var PixelEngineConfig = class {
|
|
|
2196
2204
|
}
|
|
2197
2205
|
};
|
|
2198
2206
|
|
|
2199
|
-
// src/PixelData/
|
|
2200
|
-
function
|
|
2201
|
-
const
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
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;
|
|
2209
2217
|
if (globalAlpha === 0) return false;
|
|
2210
|
-
const baseSrcAlpha = color >>> 24;
|
|
2211
|
-
const isOverwrite = blendFn.isOverwrite || false;
|
|
2212
|
-
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
2213
2218
|
let x = targetX;
|
|
2214
2219
|
let y = targetY;
|
|
2215
2220
|
let w = width;
|
|
@@ -2222,114 +2227,320 @@ function blendColorPixelData(dst, color, opts = {}) {
|
|
|
2222
2227
|
h += y;
|
|
2223
2228
|
y = 0;
|
|
2224
2229
|
}
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
if (
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
const
|
|
2235
|
-
const
|
|
2236
|
-
|
|
2237
|
-
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;
|
|
2238
2255
|
let didChange = false;
|
|
2239
|
-
for (let iy = 0; iy <
|
|
2240
|
-
for (let ix = 0; ix <
|
|
2241
|
-
const
|
|
2242
|
-
const
|
|
2243
|
-
|
|
2244
|
-
|
|
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;
|
|
2245
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
|
+
}
|
|
2246
2285
|
}
|
|
2247
2286
|
dIdx++;
|
|
2287
|
+
mIdx++;
|
|
2248
2288
|
}
|
|
2249
2289
|
dIdx += dStride;
|
|
2290
|
+
mIdx += mStride;
|
|
2250
2291
|
}
|
|
2251
2292
|
return didChange;
|
|
2252
2293
|
}
|
|
2253
2294
|
|
|
2254
|
-
// src/
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
};
|
|
2258
|
-
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);
|
|
2259
2298
|
const {
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2272
|
-
return didChange(blendColorPixelData2(target, color, opts));
|
|
2273
|
-
}
|
|
2274
|
-
};
|
|
2275
|
-
});
|
|
2276
|
-
|
|
2277
|
-
// src/PixelData/blendPixel.ts
|
|
2278
|
-
function blendPixel(target, x, y, color, alpha = 255, blendFn = sourceOverPerfect) {
|
|
2279
|
-
if (alpha === 0) return false;
|
|
2280
|
-
let width = target.width;
|
|
2281
|
-
let height = target.height;
|
|
2282
|
-
if (x < 0 || x >= width || y < 0 || y >= height) return false;
|
|
2283
|
-
let srcAlpha = color >>> 24;
|
|
2284
|
-
let isOverwrite = blendFn.isOverwrite;
|
|
2285
|
-
if (srcAlpha === 0 && !isOverwrite) return false;
|
|
2286
|
-
let dst32 = target.data32;
|
|
2287
|
-
let index = y * width + x;
|
|
2288
|
-
let finalColor = color;
|
|
2289
|
-
if (alpha !== 255) {
|
|
2290
|
-
let finalAlpha = srcAlpha * alpha + 128 >> 8;
|
|
2291
|
-
if (finalAlpha === 0 && !isOverwrite) return false;
|
|
2292
|
-
finalColor = (color & 16777215 | finalAlpha << 24) >>> 0;
|
|
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;
|
|
2293
2310
|
}
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
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);
|
|
2299
2320
|
}
|
|
2300
|
-
return
|
|
2321
|
+
return result;
|
|
2301
2322
|
}
|
|
2302
2323
|
|
|
2303
|
-
// src/
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
} = deps;
|
|
2311
|
-
return {
|
|
2312
|
-
blendPixel(x, y, color, alpha, blendFn) {
|
|
2313
|
-
const didChange = writer.accumulator.storePixelBeforeState(x, y);
|
|
2314
|
-
return didChange(blendPixel2(writer.config.target, x, y, color, alpha, blendFn));
|
|
2315
|
-
}
|
|
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
|
|
2316
2331
|
};
|
|
2317
|
-
|
|
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
|
+
}
|
|
2318
2342
|
|
|
2319
|
-
// src/
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
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
|
+
};
|
|
2531
|
+
|
|
2532
|
+
// src/PixelData/blendPixelData.ts
|
|
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;
|
|
2542
|
+
if (globalAlpha === 0) return false;
|
|
2543
|
+
let x = targetX;
|
|
2333
2544
|
let y = targetY;
|
|
2334
2545
|
let sx = sourceX;
|
|
2335
2546
|
let sy = sourceY;
|
|
@@ -2357,12 +2568,12 @@ function blendPixelData(dst, src, opts = {}) {
|
|
|
2357
2568
|
h += y;
|
|
2358
2569
|
y = 0;
|
|
2359
2570
|
}
|
|
2360
|
-
const actualW = Math.min(w,
|
|
2361
|
-
const actualH = Math.min(h,
|
|
2571
|
+
const actualW = Math.min(w, target.width - x);
|
|
2572
|
+
const actualH = Math.min(h, target.height - y);
|
|
2362
2573
|
if (actualW <= 0 || actualH <= 0) return false;
|
|
2363
|
-
const dst32 =
|
|
2574
|
+
const dst32 = target.data32;
|
|
2364
2575
|
const src32 = src.data32;
|
|
2365
|
-
const dw =
|
|
2576
|
+
const dw = target.width;
|
|
2366
2577
|
const sw = src.width;
|
|
2367
2578
|
let dIdx = y * dw + x | 0;
|
|
2368
2579
|
let sIdx = sy * sw + sx | 0;
|
|
@@ -2405,240 +2616,528 @@ function blendPixelData(dst, src, opts = {}) {
|
|
|
2405
2616
|
return didChange;
|
|
2406
2617
|
}
|
|
2407
2618
|
|
|
2408
|
-
// src/
|
|
2409
|
-
var
|
|
2410
|
-
|
|
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;
|
|
2411
2634
|
};
|
|
2412
|
-
var mutatorBlendPixelData = ((writer, deps = defaults4) => {
|
|
2413
|
-
const {
|
|
2414
|
-
blendPixelData: blendPixelData2 = defaults4.blendPixelData
|
|
2415
|
-
} = deps;
|
|
2416
|
-
return {
|
|
2417
|
-
blendPixelData(src, opts = {}) {
|
|
2418
|
-
const {
|
|
2419
|
-
x = 0,
|
|
2420
|
-
y = 0,
|
|
2421
|
-
w = src.width,
|
|
2422
|
-
h = src.height
|
|
2423
|
-
} = opts;
|
|
2424
|
-
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2425
|
-
return didChange(blendPixelData2(writer.config.target, src, opts));
|
|
2426
|
-
}
|
|
2427
|
-
};
|
|
2428
|
-
});
|
|
2429
2635
|
|
|
2430
|
-
// src/
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
alpha: globalAlpha = 255,
|
|
2440
|
-
blendFn = sourceOverPerfect,
|
|
2441
|
-
mx = 0,
|
|
2442
|
-
my = 0,
|
|
2443
|
-
invertMask = false
|
|
2444
|
-
} = opts;
|
|
2445
|
-
if (globalAlpha === 0) return false;
|
|
2446
|
-
let x = targetX;
|
|
2447
|
-
let y = targetY;
|
|
2448
|
-
let sx = sourceX;
|
|
2449
|
-
let sy = sourceY;
|
|
2450
|
-
let w = width;
|
|
2451
|
-
let h = height;
|
|
2452
|
-
if (sx < 0) {
|
|
2453
|
-
x -= sx;
|
|
2454
|
-
w += sx;
|
|
2455
|
-
sx = 0;
|
|
2456
|
-
}
|
|
2457
|
-
if (sy < 0) {
|
|
2458
|
-
y -= sy;
|
|
2459
|
-
h += sy;
|
|
2460
|
-
sy = 0;
|
|
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;
|
|
2461
2645
|
}
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
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);
|
|
2468
2656
|
}
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
h += y;
|
|
2472
|
-
y = 0;
|
|
2657
|
+
releaseTile(tile) {
|
|
2658
|
+
this.pool.push(tile);
|
|
2473
2659
|
}
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
const maskData = alphaMask.data;
|
|
2481
|
-
const dx = x - targetX | 0;
|
|
2482
|
-
const dy = y - targetY | 0;
|
|
2483
|
-
const dst32 = dst.data32;
|
|
2484
|
-
const src32 = src.data32;
|
|
2485
|
-
let dIdx = y * dw + x | 0;
|
|
2486
|
-
let sIdx = sy * sw + sx | 0;
|
|
2487
|
-
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
2488
|
-
const dStride = dw - actualW | 0;
|
|
2489
|
-
const sStride = sw - actualW | 0;
|
|
2490
|
-
const mStride = mPitch - actualW | 0;
|
|
2491
|
-
const isOpaque = globalAlpha === 255;
|
|
2492
|
-
const isOverwrite = blendFn.isOverwrite || false;
|
|
2493
|
-
let didChange = false;
|
|
2494
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
2495
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
2496
|
-
const mVal = maskData[mIdx];
|
|
2497
|
-
const effM = invertMask ? 255 - mVal : mVal;
|
|
2498
|
-
if (effM === 0) {
|
|
2499
|
-
dIdx++;
|
|
2500
|
-
sIdx++;
|
|
2501
|
-
mIdx++;
|
|
2502
|
-
continue;
|
|
2503
|
-
}
|
|
2504
|
-
const srcCol = src32[sIdx];
|
|
2505
|
-
const srcAlpha = srcCol >>> 24;
|
|
2506
|
-
if (srcAlpha === 0 && !isOverwrite) {
|
|
2507
|
-
dIdx++;
|
|
2508
|
-
sIdx++;
|
|
2509
|
-
mIdx++;
|
|
2510
|
-
continue;
|
|
2511
|
-
}
|
|
2512
|
-
let weight = globalAlpha;
|
|
2513
|
-
if (isOpaque) {
|
|
2514
|
-
weight = effM;
|
|
2515
|
-
} else if (effM !== 255) {
|
|
2516
|
-
weight = effM * globalAlpha + 128 >> 8;
|
|
2517
|
-
}
|
|
2518
|
-
if (weight === 0) {
|
|
2519
|
-
dIdx++;
|
|
2520
|
-
sIdx++;
|
|
2521
|
-
mIdx++;
|
|
2522
|
-
continue;
|
|
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);
|
|
2523
2666
|
}
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
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);
|
|
2534
2756
|
}
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
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));
|
|
2540
2777
|
}
|
|
2541
|
-
dIdx++;
|
|
2542
|
-
sIdx++;
|
|
2543
|
-
mIdx++;
|
|
2544
2778
|
}
|
|
2545
|
-
|
|
2546
|
-
sIdx += sStride;
|
|
2547
|
-
mIdx += mStride;
|
|
2779
|
+
paintBuffer.clear();
|
|
2548
2780
|
}
|
|
2549
|
-
|
|
2550
|
-
}
|
|
2781
|
+
};
|
|
2551
2782
|
|
|
2552
|
-
// src/History/PixelMutator/
|
|
2553
|
-
var
|
|
2554
|
-
|
|
2783
|
+
// src/History/PixelMutator/mutatorApplyAlphaMask.ts
|
|
2784
|
+
var defaults2 = {
|
|
2785
|
+
applyAlphaMaskToPixelData
|
|
2555
2786
|
};
|
|
2556
|
-
var
|
|
2787
|
+
var mutatorApplyAlphaMask = ((writer, deps = defaults2) => {
|
|
2557
2788
|
const {
|
|
2558
|
-
|
|
2789
|
+
applyAlphaMaskToPixelData: applyAlphaMaskToPixelData2 = defaults2.applyAlphaMaskToPixelData
|
|
2559
2790
|
} = deps;
|
|
2560
2791
|
return {
|
|
2561
|
-
|
|
2562
|
-
const
|
|
2563
|
-
const
|
|
2564
|
-
const
|
|
2565
|
-
const
|
|
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;
|
|
2566
2798
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2567
|
-
return didChange(
|
|
2799
|
+
return didChange(applyAlphaMaskToPixelData2(target, mask, opts));
|
|
2568
2800
|
}
|
|
2569
2801
|
};
|
|
2570
2802
|
});
|
|
2571
2803
|
|
|
2572
|
-
// src/PixelData/
|
|
2573
|
-
function
|
|
2574
|
-
const
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
blendFn = sourceOverPerfect,
|
|
2583
|
-
mx = 0,
|
|
2584
|
-
my = 0,
|
|
2585
|
-
invertMask = false
|
|
2586
|
-
} = opts;
|
|
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;
|
|
2587
2814
|
if (globalAlpha === 0) return false;
|
|
2588
2815
|
let x = targetX;
|
|
2589
2816
|
let y = targetY;
|
|
2590
|
-
let sx = sourceX;
|
|
2591
|
-
let sy = sourceY;
|
|
2592
2817
|
let w = width;
|
|
2593
2818
|
let h = height;
|
|
2594
|
-
if (sx < 0) {
|
|
2595
|
-
x -= sx;
|
|
2596
|
-
w += sx;
|
|
2597
|
-
sx = 0;
|
|
2598
|
-
}
|
|
2599
|
-
if (sy < 0) {
|
|
2600
|
-
y -= sy;
|
|
2601
|
-
h += sy;
|
|
2602
|
-
sy = 0;
|
|
2603
|
-
}
|
|
2604
|
-
w = Math.min(w, src.width - sx);
|
|
2605
|
-
h = Math.min(h, src.height - sy);
|
|
2606
2819
|
if (x < 0) {
|
|
2607
|
-
sx -= x;
|
|
2608
2820
|
w += x;
|
|
2609
2821
|
x = 0;
|
|
2610
2822
|
}
|
|
2611
2823
|
if (y < 0) {
|
|
2612
|
-
sy -= y;
|
|
2613
2824
|
h += y;
|
|
2614
2825
|
y = 0;
|
|
2615
2826
|
}
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
if (
|
|
2619
|
-
const
|
|
2620
|
-
|
|
2621
|
-
const
|
|
2622
|
-
const
|
|
2623
|
-
const
|
|
2624
|
-
const
|
|
2625
|
-
const
|
|
2626
|
-
const
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
const
|
|
2633
|
-
const
|
|
2634
|
-
const
|
|
2635
|
-
const
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
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;
|
|
2947
|
+
let x = targetX;
|
|
2948
|
+
let y = targetY;
|
|
2949
|
+
let sx = sourceX;
|
|
2950
|
+
let sy = sourceY;
|
|
2951
|
+
let w = width;
|
|
2952
|
+
let h = height;
|
|
2953
|
+
if (sx < 0) {
|
|
2954
|
+
x -= sx;
|
|
2955
|
+
w += sx;
|
|
2956
|
+
sx = 0;
|
|
2957
|
+
}
|
|
2958
|
+
if (sy < 0) {
|
|
2959
|
+
y -= sy;
|
|
2960
|
+
h += sy;
|
|
2961
|
+
sy = 0;
|
|
2962
|
+
}
|
|
2963
|
+
w = Math.min(w, src.width - sx);
|
|
2964
|
+
h = Math.min(h, src.height - sy);
|
|
2965
|
+
if (x < 0) {
|
|
2966
|
+
sx -= x;
|
|
2967
|
+
w += x;
|
|
2968
|
+
x = 0;
|
|
2969
|
+
}
|
|
2970
|
+
if (y < 0) {
|
|
2971
|
+
sy -= y;
|
|
2972
|
+
h += y;
|
|
2973
|
+
y = 0;
|
|
2974
|
+
}
|
|
2975
|
+
const actualW = Math.min(w, target.width - x);
|
|
2976
|
+
const actualH = Math.min(h, target.height - y);
|
|
2977
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
2978
|
+
const dw = target.width;
|
|
2979
|
+
const sw = src.width;
|
|
2980
|
+
const mPitch = alphaMask.w;
|
|
2981
|
+
const maskData = alphaMask.data;
|
|
2982
|
+
const dx = x - targetX | 0;
|
|
2983
|
+
const dy = y - targetY | 0;
|
|
2984
|
+
const dst32 = target.data32;
|
|
2985
|
+
const src32 = src.data32;
|
|
2986
|
+
let dIdx = y * dw + x | 0;
|
|
2987
|
+
let sIdx = sy * sw + sx | 0;
|
|
2988
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
2989
|
+
const dStride = dw - actualW | 0;
|
|
2990
|
+
const sStride = sw - actualW | 0;
|
|
2991
|
+
const mStride = mPitch - actualW | 0;
|
|
2992
|
+
const isOpaque = globalAlpha === 255;
|
|
2993
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
2994
|
+
let didChange = false;
|
|
2995
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2996
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2997
|
+
const mVal = maskData[mIdx];
|
|
2998
|
+
const effM = invertMask ? 255 - mVal : mVal;
|
|
2999
|
+
if (effM === 0) {
|
|
3000
|
+
dIdx++;
|
|
3001
|
+
sIdx++;
|
|
3002
|
+
mIdx++;
|
|
3003
|
+
continue;
|
|
3004
|
+
}
|
|
3005
|
+
const srcCol = src32[sIdx];
|
|
3006
|
+
const srcAlpha = srcCol >>> 24;
|
|
3007
|
+
if (srcAlpha === 0 && !isOverwrite) {
|
|
3008
|
+
dIdx++;
|
|
3009
|
+
sIdx++;
|
|
3010
|
+
mIdx++;
|
|
3011
|
+
continue;
|
|
3012
|
+
}
|
|
3013
|
+
let weight = globalAlpha;
|
|
3014
|
+
if (isOpaque) {
|
|
3015
|
+
weight = effM;
|
|
3016
|
+
} else if (effM !== 255) {
|
|
3017
|
+
weight = effM * globalAlpha + 128 >> 8;
|
|
3018
|
+
}
|
|
3019
|
+
if (weight === 0) {
|
|
3020
|
+
dIdx++;
|
|
3021
|
+
sIdx++;
|
|
3022
|
+
mIdx++;
|
|
3023
|
+
continue;
|
|
3024
|
+
}
|
|
3025
|
+
let finalCol = srcCol;
|
|
3026
|
+
if (weight < 255) {
|
|
3027
|
+
const a = srcAlpha * weight + 128 >> 8;
|
|
3028
|
+
if (a === 0 && !isOverwrite) {
|
|
3029
|
+
dIdx++;
|
|
3030
|
+
sIdx++;
|
|
3031
|
+
mIdx++;
|
|
3032
|
+
continue;
|
|
3033
|
+
}
|
|
3034
|
+
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
3035
|
+
}
|
|
3036
|
+
const current = dst32[dIdx];
|
|
3037
|
+
const next = blendFn(finalCol, dst32[dIdx]);
|
|
3038
|
+
if (current !== next) {
|
|
3039
|
+
dst32[dIdx] = next;
|
|
3040
|
+
didChange = true;
|
|
3041
|
+
}
|
|
3042
|
+
dIdx++;
|
|
3043
|
+
sIdx++;
|
|
3044
|
+
mIdx++;
|
|
3045
|
+
}
|
|
3046
|
+
dIdx += dStride;
|
|
3047
|
+
sIdx += sStride;
|
|
3048
|
+
mIdx += mStride;
|
|
3049
|
+
}
|
|
3050
|
+
return didChange;
|
|
3051
|
+
}
|
|
3052
|
+
|
|
3053
|
+
// src/History/PixelMutator/mutatorBlendAlphaMask.ts
|
|
3054
|
+
var defaults5 = {
|
|
3055
|
+
blendPixelDataAlphaMask
|
|
3056
|
+
};
|
|
3057
|
+
var mutatorBlendAlphaMask = ((writer, deps = defaults5) => {
|
|
3058
|
+
const {
|
|
3059
|
+
blendPixelDataAlphaMask: blendPixelDataAlphaMask2 = defaults5.blendPixelDataAlphaMask
|
|
3060
|
+
} = deps;
|
|
3061
|
+
return {
|
|
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;
|
|
3067
|
+
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3068
|
+
return didChange(blendPixelDataAlphaMask2(writer.config.target, src, mask, opts));
|
|
3069
|
+
}
|
|
3070
|
+
};
|
|
3071
|
+
});
|
|
3072
|
+
|
|
3073
|
+
// src/PixelData/blendPixelDataBinaryMask.ts
|
|
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;
|
|
3086
|
+
if (globalAlpha === 0) return false;
|
|
3087
|
+
let x = targetX;
|
|
3088
|
+
let y = targetY;
|
|
3089
|
+
let sx = sourceX;
|
|
3090
|
+
let sy = sourceY;
|
|
3091
|
+
let w = width;
|
|
3092
|
+
let h = height;
|
|
3093
|
+
if (sx < 0) {
|
|
3094
|
+
x -= sx;
|
|
3095
|
+
w += sx;
|
|
3096
|
+
sx = 0;
|
|
3097
|
+
}
|
|
3098
|
+
if (sy < 0) {
|
|
3099
|
+
y -= sy;
|
|
3100
|
+
h += sy;
|
|
3101
|
+
sy = 0;
|
|
3102
|
+
}
|
|
3103
|
+
w = Math.min(w, src.width - sx);
|
|
3104
|
+
h = Math.min(h, src.height - sy);
|
|
3105
|
+
if (x < 0) {
|
|
3106
|
+
sx -= x;
|
|
3107
|
+
w += x;
|
|
3108
|
+
x = 0;
|
|
3109
|
+
}
|
|
3110
|
+
if (y < 0) {
|
|
3111
|
+
sy -= y;
|
|
3112
|
+
h += y;
|
|
3113
|
+
y = 0;
|
|
3114
|
+
}
|
|
3115
|
+
const actualW = Math.min(w, target.width - x);
|
|
3116
|
+
const actualH = Math.min(h, target.height - y);
|
|
3117
|
+
if (actualW <= 0 || actualH <= 0) return false;
|
|
3118
|
+
const dx = x - targetX | 0;
|
|
3119
|
+
const dy = y - targetY | 0;
|
|
3120
|
+
const dst32 = target.data32;
|
|
3121
|
+
const src32 = src.data32;
|
|
3122
|
+
const dw = target.width;
|
|
3123
|
+
const sw = src.width;
|
|
3124
|
+
const mPitch = binaryMask.w;
|
|
3125
|
+
const maskData = binaryMask.data;
|
|
3126
|
+
let dIdx = y * dw + x | 0;
|
|
3127
|
+
let sIdx = sy * sw + sx | 0;
|
|
3128
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
3129
|
+
const dStride = dw - actualW | 0;
|
|
3130
|
+
const sStride = sw - actualW | 0;
|
|
3131
|
+
const mStride = mPitch - actualW | 0;
|
|
3132
|
+
const skipVal = invertMask ? 1 : 0;
|
|
3133
|
+
const isOpaque = globalAlpha === 255;
|
|
3134
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
3135
|
+
let didChange = false;
|
|
3136
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
3137
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
3138
|
+
if (maskData[mIdx] === skipVal) {
|
|
3139
|
+
dIdx++;
|
|
3140
|
+
sIdx++;
|
|
2642
3141
|
mIdx++;
|
|
2643
3142
|
continue;
|
|
2644
3143
|
}
|
|
@@ -2678,953 +3177,744 @@ function blendPixelDataBinaryMask(dst, src, binaryMask, opts = {}) {
|
|
|
2678
3177
|
return didChange;
|
|
2679
3178
|
}
|
|
2680
3179
|
|
|
2681
|
-
// src/History/PixelMutator/
|
|
3180
|
+
// src/History/PixelMutator/mutatorBlendBinaryMask.ts
|
|
2682
3181
|
var defaults6 = {
|
|
2683
3182
|
blendPixelDataBinaryMask
|
|
2684
3183
|
};
|
|
2685
|
-
var
|
|
3184
|
+
var mutatorBlendBinaryMask = ((writer, deps = defaults6) => {
|
|
2686
3185
|
const {
|
|
2687
3186
|
blendPixelDataBinaryMask: blendPixelDataBinaryMask2 = defaults6.blendPixelDataBinaryMask
|
|
2688
3187
|
} = deps;
|
|
2689
3188
|
return {
|
|
2690
|
-
|
|
2691
|
-
const x = opts
|
|
2692
|
-
const y = opts
|
|
2693
|
-
const w = opts
|
|
2694
|
-
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;
|
|
2695
3194
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2696
3195
|
return didChange(blendPixelDataBinaryMask2(writer.config.target, src, mask, opts));
|
|
2697
3196
|
}
|
|
2698
3197
|
};
|
|
2699
3198
|
});
|
|
2700
3199
|
|
|
2701
|
-
// src/PixelData/
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
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;
|
|
2719
3218
|
x = 0;
|
|
3219
|
+
}
|
|
3220
|
+
if (y < 0) {
|
|
3221
|
+
h += y;
|
|
2720
3222
|
y = 0;
|
|
2721
|
-
w = dst.width;
|
|
2722
|
-
h = dst.height;
|
|
2723
3223
|
}
|
|
2724
|
-
const
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
const dst32 = dst.data32;
|
|
2733
|
-
const dw = dst.width;
|
|
2734
|
-
if (actualW === dw && actualH === dst.height && finalX === 0 && finalY === 0) {
|
|
2735
|
-
dst32.fill(color);
|
|
2736
|
-
return;
|
|
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;
|
|
2737
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;
|
|
2738
3238
|
for (let iy = 0; iy < actualH; iy++) {
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
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;
|
|
2742
3249
|
}
|
|
3250
|
+
return didChange;
|
|
2743
3251
|
}
|
|
2744
3252
|
|
|
2745
|
-
// src/History/PixelMutator/
|
|
3253
|
+
// src/History/PixelMutator/mutatorBlendColor.ts
|
|
2746
3254
|
var defaults7 = {
|
|
2747
|
-
|
|
3255
|
+
blendColorPixelData
|
|
2748
3256
|
};
|
|
2749
|
-
var
|
|
3257
|
+
var mutatorBlendColor = ((writer, deps = defaults7) => {
|
|
2750
3258
|
const {
|
|
2751
|
-
|
|
3259
|
+
blendColorPixelData: blendColorPixelData2 = defaults7.blendColorPixelData
|
|
2752
3260
|
} = deps;
|
|
2753
3261
|
return {
|
|
2754
|
-
|
|
3262
|
+
blendColor(color, opts) {
|
|
2755
3263
|
const target = writer.config.target;
|
|
2756
|
-
const x =
|
|
2757
|
-
const y =
|
|
2758
|
-
const w =
|
|
2759
|
-
const h =
|
|
2760
|
-
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2761
|
-
|
|
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));
|
|
2762
3270
|
}
|
|
2763
3271
|
};
|
|
2764
3272
|
});
|
|
2765
3273
|
|
|
2766
|
-
// src/PixelData/
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
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;
|
|
2784
3295
|
x = 0;
|
|
3296
|
+
}
|
|
3297
|
+
if (y < 0) {
|
|
3298
|
+
actualH += y;
|
|
2785
3299
|
y = 0;
|
|
2786
|
-
w = dst.width;
|
|
2787
|
-
h = dst.height;
|
|
2788
3300
|
}
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
const
|
|
2798
|
-
|
|
2799
|
-
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;
|
|
2800
3317
|
for (let iy = 0; iy < actualH; iy++) {
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
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;
|
|
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;
|
|
2808
3352
|
}
|
|
3353
|
+
dIdx++;
|
|
3354
|
+
mIdx++;
|
|
2809
3355
|
}
|
|
3356
|
+
dIdx += dStride;
|
|
3357
|
+
mIdx += mStride;
|
|
2810
3358
|
}
|
|
2811
|
-
return
|
|
3359
|
+
return didChange;
|
|
2812
3360
|
}
|
|
2813
3361
|
|
|
2814
|
-
// src/History/PixelMutator/
|
|
3362
|
+
// src/History/PixelMutator/mutatorBlendColorPaintAlphaMask.ts
|
|
2815
3363
|
var defaults8 = {
|
|
2816
|
-
|
|
3364
|
+
blendColorPixelDataAlphaMask
|
|
2817
3365
|
};
|
|
2818
|
-
var
|
|
3366
|
+
var mutatorBlendColorPaintAlphaMask = ((writer, deps = defaults8) => {
|
|
2819
3367
|
const {
|
|
2820
|
-
|
|
3368
|
+
blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults8.blendColorPixelDataAlphaMask
|
|
2821
3369
|
} = deps;
|
|
3370
|
+
const OPTS = {
|
|
3371
|
+
x: 0,
|
|
3372
|
+
y: 0,
|
|
3373
|
+
blendFn: sourceOverPerfect,
|
|
3374
|
+
alpha: 255
|
|
3375
|
+
};
|
|
2822
3376
|
return {
|
|
2823
|
-
|
|
2824
|
-
const
|
|
2825
|
-
const
|
|
2826
|
-
|
|
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));
|
|
2827
3386
|
}
|
|
2828
3387
|
};
|
|
2829
3388
|
});
|
|
2830
|
-
|
|
3389
|
+
|
|
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;
|
|
3410
|
+
}
|
|
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;
|
|
3456
|
+
}
|
|
3457
|
+
|
|
3458
|
+
// src/History/PixelMutator/mutatorBlendColorPaintBinaryMask.ts
|
|
3459
|
+
var defaults9 = {
|
|
3460
|
+
blendColorPixelDataBinaryMask
|
|
3461
|
+
};
|
|
3462
|
+
var mutatorBlendColorPaintBinaryMask = ((writer, deps = defaults9) => {
|
|
2831
3463
|
const {
|
|
2832
|
-
|
|
3464
|
+
blendColorPixelDataBinaryMask: blendColorPixelDataBinaryMask2 = defaults9.blendColorPixelDataBinaryMask
|
|
2833
3465
|
} = deps;
|
|
3466
|
+
const OPTS = {
|
|
3467
|
+
x: 0,
|
|
3468
|
+
y: 0,
|
|
3469
|
+
blendFn: sourceOverPerfect,
|
|
3470
|
+
alpha: 255
|
|
3471
|
+
};
|
|
2834
3472
|
return {
|
|
2835
|
-
|
|
2836
|
-
const
|
|
2837
|
-
const
|
|
2838
|
-
|
|
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));
|
|
2839
3482
|
}
|
|
2840
3483
|
};
|
|
2841
3484
|
});
|
|
2842
3485
|
|
|
2843
|
-
// src/
|
|
2844
|
-
var
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
const maskW = mask.w;
|
|
2848
|
-
const maskH = mask.h;
|
|
2849
|
-
const clip = resolveRectClipping(x, y, maskW, maskH, dst.width, dst.height, SCRATCH_RECT3);
|
|
2850
|
-
if (!clip.inBounds) return false;
|
|
2851
|
-
const {
|
|
2852
|
-
x: finalX,
|
|
2853
|
-
y: finalY,
|
|
2854
|
-
w: actualW,
|
|
2855
|
-
h: actualH
|
|
2856
|
-
} = clip;
|
|
2857
|
-
const maskData = mask.data;
|
|
2858
|
-
const dst32 = dst.data32;
|
|
2859
|
-
const dw = dst.width;
|
|
2860
|
-
let finalCol = color;
|
|
2861
|
-
if (alpha < 255) {
|
|
2862
|
-
const baseSrcAlpha = color >>> 24;
|
|
2863
|
-
const colorRGB = color & 16777215;
|
|
2864
|
-
const a = baseSrcAlpha * alpha + 128 >> 8;
|
|
2865
|
-
finalCol = (colorRGB | a << 24) >>> 0;
|
|
2866
|
-
}
|
|
2867
|
-
let hasChanged = false;
|
|
2868
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
2869
|
-
const currentY = finalY + iy;
|
|
2870
|
-
const maskY = currentY - y;
|
|
2871
|
-
const maskOffset = maskY * maskW;
|
|
2872
|
-
const dstRowOffset = currentY * dw;
|
|
2873
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
2874
|
-
const currentX = finalX + ix;
|
|
2875
|
-
const maskX = currentX - x;
|
|
2876
|
-
const maskIndex = maskOffset + maskX;
|
|
2877
|
-
if (maskData[maskIndex]) {
|
|
2878
|
-
const current = dst32[dstRowOffset + currentX];
|
|
2879
|
-
if (current !== finalCol) {
|
|
2880
|
-
dst32[dstRowOffset + currentX] = finalCol;
|
|
2881
|
-
hasChanged = true;
|
|
2882
|
-
}
|
|
2883
|
-
}
|
|
2884
|
-
}
|
|
2885
|
-
}
|
|
2886
|
-
return hasChanged;
|
|
2887
|
-
}
|
|
2888
|
-
|
|
2889
|
-
// src/History/PixelMutator/mutatorFillBinaryMask.ts
|
|
2890
|
-
var defaults9 = {
|
|
2891
|
-
fillPixelDataBinaryMask
|
|
3486
|
+
// src/History/PixelMutator/mutatorBlendColorPaintMask.ts
|
|
3487
|
+
var defaults10 = {
|
|
3488
|
+
blendColorPixelDataAlphaMask,
|
|
3489
|
+
blendColorPixelDataBinaryMask
|
|
2892
3490
|
};
|
|
2893
|
-
var
|
|
3491
|
+
var mutatorBlendColorPaintMask = ((writer, deps = defaults10) => {
|
|
2894
3492
|
const {
|
|
2895
|
-
|
|
3493
|
+
blendColorPixelDataBinaryMask: blendColorPixelDataBinaryMask2 = defaults10.blendColorPixelDataBinaryMask,
|
|
3494
|
+
blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults10.blendColorPixelDataAlphaMask
|
|
2896
3495
|
} = deps;
|
|
3496
|
+
const OPTS = {
|
|
3497
|
+
x: 0,
|
|
3498
|
+
y: 0,
|
|
3499
|
+
blendFn: sourceOverPerfect,
|
|
3500
|
+
alpha: 255
|
|
3501
|
+
};
|
|
2897
3502
|
return {
|
|
2898
|
-
|
|
2899
|
-
const
|
|
2900
|
-
|
|
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
|
+
}
|
|
2901
3516
|
}
|
|
2902
3517
|
};
|
|
2903
3518
|
});
|
|
2904
3519
|
|
|
2905
|
-
// src/
|
|
2906
|
-
var
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
y: targetY = 0,
|
|
2912
|
-
w: width = pixelData.width,
|
|
2913
|
-
h: height = pixelData.height,
|
|
2914
|
-
mask,
|
|
2915
|
-
mx = 0,
|
|
2916
|
-
my = 0,
|
|
2917
|
-
invertMask = false
|
|
2918
|
-
} = opts;
|
|
2919
|
-
const clip = resolveRectClipping(targetX, targetY, width, height, dst.width, dst.height, SCRATCH_RECT4);
|
|
2920
|
-
if (!clip.inBounds) return false;
|
|
3520
|
+
// src/History/PixelMutator/mutatorBlendMask.ts
|
|
3521
|
+
var defaults11 = {
|
|
3522
|
+
blendPixelDataAlphaMask,
|
|
3523
|
+
blendPixelDataBinaryMask
|
|
3524
|
+
};
|
|
3525
|
+
var mutatorBlendMask = ((writer, deps = defaults11) => {
|
|
2921
3526
|
const {
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
if (mask) {
|
|
2937
|
-
const maskData = mask.data;
|
|
2938
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
2939
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
2940
|
-
const mVal = maskData[mIdx];
|
|
2941
|
-
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
2942
|
-
if (isHit) {
|
|
2943
|
-
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
2944
|
-
}
|
|
2945
|
-
dIdx++;
|
|
2946
|
-
mIdx++;
|
|
2947
|
-
}
|
|
2948
|
-
dIdx += dStride;
|
|
2949
|
-
mIdx += mStride;
|
|
2950
|
-
}
|
|
2951
|
-
} else {
|
|
2952
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
2953
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
2954
|
-
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
2955
|
-
dIdx++;
|
|
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));
|
|
2956
3541
|
}
|
|
2957
|
-
dIdx += dStride;
|
|
2958
3542
|
}
|
|
2959
|
-
}
|
|
2960
|
-
|
|
2961
|
-
}
|
|
3543
|
+
};
|
|
3544
|
+
});
|
|
2962
3545
|
|
|
2963
|
-
// src/History/PixelMutator/
|
|
2964
|
-
var
|
|
2965
|
-
|
|
3546
|
+
// src/History/PixelMutator/mutatorBlendPaintRect.ts
|
|
3547
|
+
var defaults12 = {
|
|
3548
|
+
blendColorPixelData
|
|
2966
3549
|
};
|
|
2967
|
-
var
|
|
3550
|
+
var mutatorBlendPaintRect = ((writer, deps = defaults12) => {
|
|
2968
3551
|
const {
|
|
2969
|
-
|
|
3552
|
+
blendColorPixelData: blendColorPixelData2 = defaults12.blendColorPixelData
|
|
2970
3553
|
} = deps;
|
|
3554
|
+
const OPTS = {
|
|
3555
|
+
x: 0,
|
|
3556
|
+
y: 0,
|
|
3557
|
+
w: 0,
|
|
3558
|
+
h: 0,
|
|
3559
|
+
blendFn: sourceOverPerfect,
|
|
3560
|
+
alpha: 255
|
|
3561
|
+
};
|
|
2971
3562
|
return {
|
|
2972
|
-
|
|
3563
|
+
blendPaintRect(color, centerX, centerY, brushWidth, brushHeight, alpha = 255, blendFn = sourceOverPerfect) {
|
|
2973
3564
|
const target = writer.config.target;
|
|
2974
|
-
const
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
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));
|
|
2982
3575
|
}
|
|
2983
3576
|
};
|
|
2984
3577
|
});
|
|
2985
3578
|
|
|
2986
|
-
// src/
|
|
2987
|
-
function
|
|
2988
|
-
return
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
// src/ImageData/resizeImageData.ts
|
|
3004
|
-
function resizeImageData(target, newWidth, newHeight, offsetX = 0, offsetY = 0) {
|
|
3005
|
-
const result = new ImageData(newWidth, newHeight);
|
|
3006
|
-
const {
|
|
3007
|
-
width: oldW,
|
|
3008
|
-
height: oldH,
|
|
3009
|
-
data: oldData
|
|
3010
|
-
} = target;
|
|
3011
|
-
const newData = result.data;
|
|
3012
|
-
const x0 = Math.max(0, offsetX);
|
|
3013
|
-
const y0 = Math.max(0, offsetY);
|
|
3014
|
-
const x1 = Math.min(newWidth, offsetX + oldW);
|
|
3015
|
-
const y1 = Math.min(newHeight, offsetY + oldH);
|
|
3016
|
-
if (x1 <= x0 || y1 <= y0) {
|
|
3017
|
-
return result;
|
|
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;
|
|
3018
3595
|
}
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
const srcX = x0 - offsetX;
|
|
3025
|
-
const dstStart = (dstY * newWidth + x0) * 4;
|
|
3026
|
-
const srcStart = (srcY * oldW + srcX) * 4;
|
|
3027
|
-
newData.set(oldData.subarray(srcStart, srcStart + rowLen), dstStart);
|
|
3596
|
+
let current = dst32[index];
|
|
3597
|
+
let next = blendFn(finalColor, current);
|
|
3598
|
+
if (current !== next) {
|
|
3599
|
+
dst32[index] = next;
|
|
3600
|
+
return true;
|
|
3028
3601
|
}
|
|
3029
|
-
return
|
|
3602
|
+
return false;
|
|
3030
3603
|
}
|
|
3031
3604
|
|
|
3032
|
-
// src/
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
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
|
+
}
|
|
3039
3618
|
};
|
|
3040
|
-
|
|
3041
|
-
const top = Math.max(0, y);
|
|
3042
|
-
const right = Math.min(targetWidth, x + w);
|
|
3043
|
-
const bottom = Math.min(targetHeight, y + h);
|
|
3044
|
-
res.x = left;
|
|
3045
|
-
res.y = top;
|
|
3046
|
-
res.w = Math.max(0, right - left);
|
|
3047
|
-
res.h = Math.max(0, bottom - top);
|
|
3048
|
-
return res;
|
|
3049
|
-
}
|
|
3619
|
+
});
|
|
3050
3620
|
|
|
3051
|
-
// src/
|
|
3052
|
-
var
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
tileShift,
|
|
3068
|
-
targetColumns,
|
|
3069
|
-
targetRows,
|
|
3070
|
-
tileSize
|
|
3071
|
-
} = this.config;
|
|
3072
|
-
const x1 = Math.max(0, bounds.x >> tileShift);
|
|
3073
|
-
const y1 = Math.max(0, bounds.y >> tileShift);
|
|
3074
|
-
const x2 = Math.min(targetColumns - 1, bounds.x + bounds.w - 1 >> tileShift);
|
|
3075
|
-
const y2 = Math.min(targetRows - 1, bounds.y + bounds.h - 1 >> tileShift);
|
|
3076
|
-
if (x1 > x2 || y1 > y2) return;
|
|
3077
|
-
const lookup = this.lookup;
|
|
3078
|
-
const tilePool = this.tilePool;
|
|
3079
|
-
for (let ty = y1; ty <= y2; ty++) {
|
|
3080
|
-
const rowOffset = ty * targetColumns;
|
|
3081
|
-
const tileTop = ty << tileShift;
|
|
3082
|
-
for (let tx = x1; tx <= x2; tx++) {
|
|
3083
|
-
const id = rowOffset + tx;
|
|
3084
|
-
const tile = lookup[id] ?? (lookup[id] = tilePool.getTile(id, tx, ty));
|
|
3085
|
-
const tileLeft = tx << tileShift;
|
|
3086
|
-
const startX = bounds.x > tileLeft ? bounds.x : tileLeft;
|
|
3087
|
-
const startY = bounds.y > tileTop ? bounds.y : tileTop;
|
|
3088
|
-
const maskEndX = bounds.x + bounds.w;
|
|
3089
|
-
const tileEndX = tileLeft + tileSize;
|
|
3090
|
-
const endX = maskEndX < tileEndX ? maskEndX : tileEndX;
|
|
3091
|
-
const maskEndY = bounds.y + bounds.h;
|
|
3092
|
-
const tileEndY = tileTop + tileSize;
|
|
3093
|
-
const endY = maskEndY < tileEndY ? maskEndY : tileEndY;
|
|
3094
|
-
callback(tile, startX, startY, endX - startX, endY - startY);
|
|
3095
|
-
}
|
|
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));
|
|
3096
3637
|
}
|
|
3097
|
-
}
|
|
3098
|
-
writePaintAlphaMaskStroke(color, brush, x0, y0, x1, y1) {
|
|
3099
|
-
const cA = color >>> 24;
|
|
3100
|
-
if (cA === 0) return false;
|
|
3101
|
-
const {
|
|
3102
|
-
tileShift,
|
|
3103
|
-
tileMask,
|
|
3104
|
-
target
|
|
3105
|
-
} = this.config;
|
|
3106
|
-
const {
|
|
3107
|
-
w: bW,
|
|
3108
|
-
h: bH,
|
|
3109
|
-
data: bD,
|
|
3110
|
-
centerOffsetX,
|
|
3111
|
-
centerOffsetY
|
|
3112
|
-
} = brush;
|
|
3113
|
-
const cRGB = color & 16777215;
|
|
3114
|
-
const scratch = this.scratchBounds;
|
|
3115
|
-
let changed = false;
|
|
3116
|
-
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
3117
|
-
const topLeftX = Math.floor(px + centerOffsetX);
|
|
3118
|
-
const topLeftY = Math.floor(py + centerOffsetY);
|
|
3119
|
-
trimRectBounds(topLeftX, topLeftY, bW, bH, target.width, target.height, scratch);
|
|
3120
|
-
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
3121
|
-
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
3122
|
-
const d32 = tile.data32;
|
|
3123
|
-
let tileChanged = false;
|
|
3124
|
-
for (let i = 0; i < bH_t; i++) {
|
|
3125
|
-
const canvasY = bY + i;
|
|
3126
|
-
const bOff = (canvasY - topLeftY) * bW;
|
|
3127
|
-
const tOff = (canvasY & tileMask) << tileShift;
|
|
3128
|
-
const dS = tOff + (bX & tileMask);
|
|
3129
|
-
for (let j = 0; j < bW_t; j++) {
|
|
3130
|
-
const canvasX = bX + j;
|
|
3131
|
-
const brushA = bD[bOff + (canvasX - topLeftX)];
|
|
3132
|
-
if (brushA === 0) continue;
|
|
3133
|
-
const t = cA * brushA + 128;
|
|
3134
|
-
const blendedA = t + (t >> 8) >> 8;
|
|
3135
|
-
const idx = dS + j;
|
|
3136
|
-
const cur = d32[idx];
|
|
3137
|
-
if (brushA > cur >>> 24) {
|
|
3138
|
-
const next = (cRGB | blendedA << 24) >>> 0;
|
|
3139
|
-
if (cur !== next) {
|
|
3140
|
-
d32[idx] = next;
|
|
3141
|
-
tileChanged = true;
|
|
3142
|
-
}
|
|
3143
|
-
}
|
|
3144
|
-
}
|
|
3145
|
-
}
|
|
3146
|
-
if (tileChanged) changed = true;
|
|
3147
|
-
});
|
|
3148
|
-
});
|
|
3149
|
-
return changed;
|
|
3150
|
-
}
|
|
3151
|
-
writePaintBinaryMaskStroke(color, brush, x0, y0, x1, y1) {
|
|
3152
|
-
const alphaIsZero = color >>> 24 === 0;
|
|
3153
|
-
if (alphaIsZero) return false;
|
|
3154
|
-
const {
|
|
3155
|
-
tileShift,
|
|
3156
|
-
tileMask,
|
|
3157
|
-
target
|
|
3158
|
-
} = this.config;
|
|
3159
|
-
const {
|
|
3160
|
-
w: bW,
|
|
3161
|
-
h: bH,
|
|
3162
|
-
data: bD,
|
|
3163
|
-
centerOffsetX,
|
|
3164
|
-
centerOffsetY
|
|
3165
|
-
} = brush;
|
|
3166
|
-
const scratch = this.scratchBounds;
|
|
3167
|
-
let changed = false;
|
|
3168
|
-
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
3169
|
-
const topLeftX = Math.floor(px + centerOffsetX);
|
|
3170
|
-
const topLeftY = Math.floor(py + centerOffsetY);
|
|
3171
|
-
trimRectBounds(topLeftX, topLeftY, bW, bH, target.width, target.height, scratch);
|
|
3172
|
-
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
3173
|
-
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
3174
|
-
const d32 = tile.data32;
|
|
3175
|
-
let tileChanged = false;
|
|
3176
|
-
for (let i = 0; i < bH_t; i++) {
|
|
3177
|
-
const canvasY = bY + i;
|
|
3178
|
-
const bOff = (canvasY - topLeftY) * bW;
|
|
3179
|
-
const tOff = (canvasY & tileMask) << tileShift;
|
|
3180
|
-
const dS = tOff + (bX & tileMask);
|
|
3181
|
-
for (let j = 0; j < bW_t; j++) {
|
|
3182
|
-
const canvasX = bX + j;
|
|
3183
|
-
if (bD[bOff + (canvasX - topLeftX)]) {
|
|
3184
|
-
const idx = dS + j;
|
|
3185
|
-
if (d32[idx] !== color) {
|
|
3186
|
-
d32[idx] = color;
|
|
3187
|
-
tileChanged = true;
|
|
3188
|
-
}
|
|
3189
|
-
}
|
|
3190
|
-
}
|
|
3191
|
-
}
|
|
3192
|
-
if (tileChanged) changed = true;
|
|
3193
|
-
});
|
|
3194
|
-
});
|
|
3195
|
-
return changed;
|
|
3196
|
-
}
|
|
3197
|
-
writeRectStroke(color, brushWidth, brushHeight, x0, y0, x1, y1) {
|
|
3198
|
-
const alphaIsZero = color >>> 24 === 0;
|
|
3199
|
-
if (alphaIsZero) return false;
|
|
3200
|
-
const config = this.config;
|
|
3201
|
-
const tileShift = config.tileShift;
|
|
3202
|
-
const tileMask = config.tileMask;
|
|
3203
|
-
const target = config.target;
|
|
3204
|
-
const scratch = this.scratchBounds;
|
|
3205
|
-
const centerOffsetX = brushWidth - 1 >> 1;
|
|
3206
|
-
const centerOffsetY = brushHeight - 1 >> 1;
|
|
3207
|
-
let changed = false;
|
|
3208
|
-
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
3209
|
-
const topLeftX = Math.floor(px + centerOffsetX);
|
|
3210
|
-
const topLeftY = Math.floor(py + centerOffsetY);
|
|
3211
|
-
trimRectBounds(topLeftX, topLeftY, brushWidth, brushHeight, target.width, target.height, scratch);
|
|
3212
|
-
if (scratch.w <= 0 || scratch.h <= 0) return;
|
|
3213
|
-
this.eachTileInBounds(scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
3214
|
-
const d32 = tile.data32;
|
|
3215
|
-
let tileChanged = false;
|
|
3216
|
-
for (let i = 0; i < bH_t; i++) {
|
|
3217
|
-
const canvasY = bY + i;
|
|
3218
|
-
const tOff = (canvasY & tileMask) << tileShift;
|
|
3219
|
-
const dS = tOff + (bX & tileMask);
|
|
3220
|
-
for (let j = 0; j < bW_t; j++) {
|
|
3221
|
-
const idx = dS + j;
|
|
3222
|
-
if (d32[idx] !== color) {
|
|
3223
|
-
d32[idx] = color;
|
|
3224
|
-
tileChanged = true;
|
|
3225
|
-
}
|
|
3226
|
-
}
|
|
3227
|
-
}
|
|
3228
|
-
if (tileChanged) {
|
|
3229
|
-
changed = true;
|
|
3230
|
-
}
|
|
3231
|
-
});
|
|
3232
|
-
});
|
|
3233
|
-
return changed;
|
|
3234
|
-
}
|
|
3235
|
-
clear() {
|
|
3236
|
-
this.tilePool.releaseTiles(this.lookup);
|
|
3237
|
-
}
|
|
3238
|
-
};
|
|
3239
|
-
|
|
3240
|
-
// src/PixelTile/PixelTile.ts
|
|
3241
|
-
var PixelTile = class {
|
|
3242
|
-
constructor(id, tx, ty, tileSize, tileArea) {
|
|
3243
|
-
this.id = id;
|
|
3244
|
-
this.tx = tx;
|
|
3245
|
-
this.ty = ty;
|
|
3246
|
-
this.width = this.height = tileSize;
|
|
3247
|
-
this.data32 = new Uint32Array(tileArea);
|
|
3248
|
-
const data8 = new Uint8ClampedArray(this.data32.buffer);
|
|
3249
|
-
this.imageData = new ImageData(data8, tileSize, tileSize);
|
|
3250
|
-
}
|
|
3251
|
-
data32;
|
|
3252
|
-
width;
|
|
3253
|
-
height;
|
|
3254
|
-
imageData;
|
|
3255
|
-
};
|
|
3256
|
-
|
|
3257
|
-
// src/PixelTile/PixelTilePool.ts
|
|
3258
|
-
var PixelTilePool = class {
|
|
3259
|
-
pool;
|
|
3260
|
-
tileSize;
|
|
3261
|
-
tileArea;
|
|
3262
|
-
constructor(config) {
|
|
3263
|
-
this.pool = [];
|
|
3264
|
-
this.tileSize = config.tileSize;
|
|
3265
|
-
this.tileArea = config.tileArea;
|
|
3266
|
-
}
|
|
3267
|
-
getTile(id, tx, ty) {
|
|
3268
|
-
let tile = this.pool.pop();
|
|
3269
|
-
if (tile) {
|
|
3270
|
-
tile.id = id;
|
|
3271
|
-
tile.tx = tx;
|
|
3272
|
-
tile.ty = ty;
|
|
3273
|
-
tile.data32.fill(0);
|
|
3274
|
-
return tile;
|
|
3275
|
-
}
|
|
3276
|
-
return new PixelTile(id, tx, ty, this.tileSize, this.tileArea);
|
|
3277
|
-
}
|
|
3278
|
-
releaseTile(tile) {
|
|
3279
|
-
this.pool.push(tile);
|
|
3280
|
-
}
|
|
3281
|
-
releaseTiles(tiles) {
|
|
3282
|
-
let length = tiles.length;
|
|
3283
|
-
for (let i = 0; i < length; i++) {
|
|
3284
|
-
let tile = tiles[i];
|
|
3285
|
-
if (tile) {
|
|
3286
|
-
this.pool.push(tile);
|
|
3287
|
-
}
|
|
3288
|
-
}
|
|
3289
|
-
tiles.length = 0;
|
|
3290
|
-
}
|
|
3291
|
-
};
|
|
3292
|
-
|
|
3293
|
-
// src/History/PixelWriter.ts
|
|
3294
|
-
var PixelWriter = class {
|
|
3295
|
-
historyManager;
|
|
3296
|
-
accumulator;
|
|
3297
|
-
historyActionFactory;
|
|
3298
|
-
config;
|
|
3299
|
-
pixelTilePool;
|
|
3300
|
-
paintBuffer;
|
|
3301
|
-
mutator;
|
|
3302
|
-
blendPixelDataOpts = {
|
|
3303
|
-
alpha: 255,
|
|
3304
|
-
blendFn: sourceOverPerfect,
|
|
3305
|
-
x: 0,
|
|
3306
|
-
y: 0,
|
|
3307
|
-
w: 0,
|
|
3308
|
-
h: 0
|
|
3309
3638
|
};
|
|
3310
|
-
|
|
3311
|
-
constructor(target, mutatorFactory, {
|
|
3312
|
-
tileSize = 256,
|
|
3313
|
-
maxHistorySteps = 50,
|
|
3314
|
-
historyManager = new HistoryManager(maxHistorySteps),
|
|
3315
|
-
historyActionFactory = makeHistoryAction,
|
|
3316
|
-
pixelTilePool,
|
|
3317
|
-
accumulator
|
|
3318
|
-
} = {}) {
|
|
3319
|
-
this.config = new PixelEngineConfig(tileSize, target);
|
|
3320
|
-
this.historyManager = historyManager;
|
|
3321
|
-
this.pixelTilePool = pixelTilePool ?? new PixelTilePool(this.config);
|
|
3322
|
-
this.accumulator = accumulator ?? new PixelAccumulator(this.config, this.pixelTilePool);
|
|
3323
|
-
this.historyActionFactory = historyActionFactory;
|
|
3324
|
-
this.mutator = mutatorFactory(this);
|
|
3325
|
-
this.paintBuffer = new PaintBuffer(this.config, this.pixelTilePool);
|
|
3326
|
-
}
|
|
3327
|
-
/**
|
|
3328
|
-
* Executes `transaction` and commits the resulting pixel changes as a single
|
|
3329
|
-
* undoable history action.
|
|
3330
|
-
*
|
|
3331
|
-
* - If `transaction` throws, all accumulated changes are rolled back and the error
|
|
3332
|
-
* is re-thrown. No action is committed.
|
|
3333
|
-
* - If `transaction` completes without modifying any pixels, no action is committed.
|
|
3334
|
-
* - `withHistory` is not re-entrant. Calling it again from inside `transaction` will
|
|
3335
|
-
* throw immediately to prevent silent data loss from a nested extractPatch.
|
|
3336
|
-
*
|
|
3337
|
-
* @param transaction Callback to be executed inside the transaction.
|
|
3338
|
-
* @param after Called after both undo and redo — use for generic change notifications.
|
|
3339
|
-
* @param afterUndo Called after undo only — use for dimension or state changes specific to undo.
|
|
3340
|
-
* @param afterRedo Called after redo only.
|
|
3341
|
-
*/
|
|
3342
|
-
withHistory(transaction, after, afterUndo, afterRedo) {
|
|
3343
|
-
if (this._inProgress) {
|
|
3344
|
-
throw new Error("withHistory is not re-entrant \u2014 commit or rollback the current operation first");
|
|
3345
|
-
}
|
|
3346
|
-
this._inProgress = true;
|
|
3347
|
-
try {
|
|
3348
|
-
transaction(this.mutator);
|
|
3349
|
-
} catch (e) {
|
|
3350
|
-
this.accumulator.rollbackAfterError();
|
|
3351
|
-
throw e;
|
|
3352
|
-
} finally {
|
|
3353
|
-
this._inProgress = false;
|
|
3354
|
-
}
|
|
3355
|
-
if (this.accumulator.beforeTiles.length === 0) return;
|
|
3356
|
-
const patch = this.accumulator.extractPatch();
|
|
3357
|
-
const action = this.historyActionFactory(this, patch, after, afterUndo, afterRedo);
|
|
3358
|
-
this.historyManager.commit(action);
|
|
3359
|
-
}
|
|
3360
|
-
resize(newWidth, newHeight, offsetX = 0, offsetY = 0, after, afterUndo, afterRedo, resizeImageDataFn = resizeImageData) {
|
|
3361
|
-
if (this._inProgress) {
|
|
3362
|
-
throw new Error("Cannot resize inside a withHistory callback");
|
|
3363
|
-
}
|
|
3364
|
-
if (this.accumulator.beforeTiles.length > 0) {
|
|
3365
|
-
throw new Error("Cannot resize with an open accumulator \u2014 commit or rollback first");
|
|
3366
|
-
}
|
|
3367
|
-
const config = this.config;
|
|
3368
|
-
const target = config.target;
|
|
3369
|
-
const beforeImageData = target.imageData;
|
|
3370
|
-
const afterImageData = resizeImageDataFn(beforeImageData, newWidth, newHeight, offsetX, offsetY);
|
|
3371
|
-
target.set(afterImageData);
|
|
3372
|
-
this.historyManager.commit({
|
|
3373
|
-
undo: () => {
|
|
3374
|
-
target.set(beforeImageData);
|
|
3375
|
-
afterUndo?.(beforeImageData);
|
|
3376
|
-
after?.(beforeImageData);
|
|
3377
|
-
},
|
|
3378
|
-
redo: () => {
|
|
3379
|
-
target.set(afterImageData);
|
|
3380
|
-
afterRedo?.(afterImageData);
|
|
3381
|
-
after?.(afterImageData);
|
|
3382
|
-
}
|
|
3383
|
-
});
|
|
3384
|
-
}
|
|
3385
|
-
commitPaintBuffer(alpha = 255, blendFn = sourceOverPerfect, blendPixelDataFn = blendPixelData) {
|
|
3386
|
-
const paintBuffer = this.paintBuffer;
|
|
3387
|
-
const tileShift = paintBuffer.config.tileShift;
|
|
3388
|
-
const lookup = paintBuffer.lookup;
|
|
3389
|
-
const opts = this.blendPixelDataOpts;
|
|
3390
|
-
opts.alpha = alpha;
|
|
3391
|
-
opts.blendFn = blendFn;
|
|
3392
|
-
for (let i = 0; i < lookup.length; i++) {
|
|
3393
|
-
const tile = lookup[i];
|
|
3394
|
-
if (tile) {
|
|
3395
|
-
const didChange = this.accumulator.storeTileBeforeState(tile.id, tile.tx, tile.ty);
|
|
3396
|
-
const dx = tile.tx << tileShift;
|
|
3397
|
-
const dy = tile.ty << tileShift;
|
|
3398
|
-
opts.x = dx;
|
|
3399
|
-
opts.y = dy;
|
|
3400
|
-
opts.w = tile.width;
|
|
3401
|
-
opts.h = tile.height;
|
|
3402
|
-
didChange(blendPixelDataFn(this.config.target, tile, opts));
|
|
3403
|
-
}
|
|
3404
|
-
}
|
|
3405
|
-
paintBuffer.clear();
|
|
3406
|
-
}
|
|
3407
|
-
};
|
|
3639
|
+
});
|
|
3408
3640
|
|
|
3409
|
-
// src/PixelData/
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
if (
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
w += x;
|
|
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 {
|
|
3428
3659
|
x = 0;
|
|
3429
|
-
}
|
|
3430
|
-
if (y < 0) {
|
|
3431
|
-
h += y;
|
|
3432
3660
|
y = 0;
|
|
3661
|
+
w = dst.width;
|
|
3662
|
+
h = dst.height;
|
|
3433
3663
|
}
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
const sX0 = Math.max(0, startX);
|
|
3443
|
-
const sY0 = Math.max(0, startY);
|
|
3444
|
-
const sX1 = Math.min(mPitch, startX + w);
|
|
3445
|
-
const sY1 = Math.min(mask.h, startY + h);
|
|
3446
|
-
const finalW = sX1 - sX0;
|
|
3447
|
-
const finalH = sY1 - sY0;
|
|
3448
|
-
if (finalW <= 0) return false;
|
|
3449
|
-
if (finalH <= 0) return false;
|
|
3450
|
-
const xShift = sX0 - startX;
|
|
3451
|
-
const yShift = sY0 - startY;
|
|
3664
|
+
const clip = resolveRectClipping(x, y, w, h, dst.width, dst.height, SCRATCH_RECT);
|
|
3665
|
+
if (!clip.inBounds) return false;
|
|
3666
|
+
const {
|
|
3667
|
+
x: finalX,
|
|
3668
|
+
y: finalY,
|
|
3669
|
+
w: actualW,
|
|
3670
|
+
h: actualH
|
|
3671
|
+
} = clip;
|
|
3452
3672
|
const dst32 = dst.data32;
|
|
3453
3673
|
const dw = dst.width;
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
3464
|
-
let weight = 0;
|
|
3465
|
-
if (effectiveM === 0) {
|
|
3466
|
-
weight = 0;
|
|
3467
|
-
} else if (effectiveM === 255) {
|
|
3468
|
-
weight = globalAlpha;
|
|
3469
|
-
} else if (globalAlpha === 255) {
|
|
3470
|
-
weight = effectiveM;
|
|
3471
|
-
} else {
|
|
3472
|
-
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
3473
|
-
}
|
|
3474
|
-
if (weight === 0) {
|
|
3475
|
-
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
3476
|
-
didChange = true;
|
|
3477
|
-
} else if (weight !== 255) {
|
|
3478
|
-
const d = dst32[dIdx];
|
|
3479
|
-
const da = d >>> 24;
|
|
3480
|
-
if (da !== 0) {
|
|
3481
|
-
const finalAlpha = da === 255 ? weight : da * weight + 128 >> 8;
|
|
3482
|
-
const current = dst32[dIdx];
|
|
3483
|
-
const next = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
3484
|
-
if (current !== next) {
|
|
3485
|
-
dst32[dIdx] = next;
|
|
3486
|
-
didChange = true;
|
|
3487
|
-
}
|
|
3488
|
-
}
|
|
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;
|
|
3489
3683
|
}
|
|
3490
|
-
dIdx++;
|
|
3491
|
-
mIdx++;
|
|
3492
3684
|
}
|
|
3493
|
-
dIdx += dStride;
|
|
3494
|
-
mIdx += mStride;
|
|
3495
3685
|
}
|
|
3496
|
-
return
|
|
3686
|
+
return hasChanged;
|
|
3497
3687
|
}
|
|
3498
3688
|
|
|
3499
|
-
// src/History/PixelMutator/
|
|
3500
|
-
var
|
|
3501
|
-
|
|
3689
|
+
// src/History/PixelMutator/mutatorClear.ts
|
|
3690
|
+
var defaults15 = {
|
|
3691
|
+
fillPixelData
|
|
3502
3692
|
};
|
|
3503
|
-
var
|
|
3693
|
+
var mutatorClear = ((writer, deps = defaults15) => {
|
|
3504
3694
|
const {
|
|
3505
|
-
|
|
3695
|
+
fillPixelData: fillPixelData2 = defaults15.fillPixelData
|
|
3506
3696
|
} = deps;
|
|
3507
3697
|
return {
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
const
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
h = target.height
|
|
3515
|
-
} = opts;
|
|
3698
|
+
clear(rect) {
|
|
3699
|
+
const target = writer.config.target;
|
|
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;
|
|
3516
3704
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3517
|
-
return didChange(
|
|
3705
|
+
return didChange(fillPixelData2(target, 0, x, y, w, h));
|
|
3518
3706
|
}
|
|
3519
3707
|
};
|
|
3520
3708
|
});
|
|
3521
3709
|
|
|
3522
|
-
// src/
|
|
3523
|
-
|
|
3710
|
+
// src/History/PixelMutator/mutatorFill.ts
|
|
3711
|
+
var defaults16 = {
|
|
3712
|
+
fillPixelData
|
|
3713
|
+
};
|
|
3714
|
+
var mutatorFill = ((writer, deps = defaults16) => {
|
|
3524
3715
|
const {
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
}
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
const
|
|
3553
|
-
const
|
|
3554
|
-
|
|
3555
|
-
const
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
return false;
|
|
3562
|
-
}
|
|
3563
|
-
const xShift = sX0 - startX;
|
|
3564
|
-
const yShift = sY0 - startY;
|
|
3565
|
-
const dst32 = dst.data32;
|
|
3566
|
-
const dw = dst.width;
|
|
3567
|
-
const dStride = dw - finalW;
|
|
3568
|
-
const mStride = mPitch - finalW;
|
|
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));
|
|
3723
|
+
}
|
|
3724
|
+
};
|
|
3725
|
+
});
|
|
3726
|
+
var mutatorFillRect = ((writer, deps = defaults16) => {
|
|
3727
|
+
const {
|
|
3728
|
+
fillPixelData: fillPixelData2 = defaults16.fillPixelData
|
|
3729
|
+
} = deps;
|
|
3730
|
+
return {
|
|
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));
|
|
3735
|
+
}
|
|
3736
|
+
};
|
|
3737
|
+
});
|
|
3738
|
+
|
|
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;
|
|
3746
|
+
const {
|
|
3747
|
+
x: finalX,
|
|
3748
|
+
y: finalY,
|
|
3749
|
+
w: actualW,
|
|
3750
|
+
h: actualH
|
|
3751
|
+
} = clip;
|
|
3569
3752
|
const maskData = mask.data;
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
let
|
|
3573
|
-
for (let iy = 0; iy <
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
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;
|
|
3583
3770
|
}
|
|
3584
|
-
}
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3771
|
+
}
|
|
3772
|
+
}
|
|
3773
|
+
}
|
|
3774
|
+
return hasChanged;
|
|
3775
|
+
}
|
|
3776
|
+
|
|
3777
|
+
// src/History/PixelMutator/mutatorFillBinaryMask.ts
|
|
3778
|
+
var defaults17 = {
|
|
3779
|
+
fillPixelDataBinaryMask
|
|
3780
|
+
};
|
|
3781
|
+
var mutatorFillBinaryMask = ((writer, deps = defaults17) => {
|
|
3782
|
+
const {
|
|
3783
|
+
fillPixelDataBinaryMask: fillPixelDataBinaryMask2 = defaults17.fillPixelDataBinaryMask
|
|
3784
|
+
} = deps;
|
|
3785
|
+
return {
|
|
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));
|
|
3789
|
+
}
|
|
3790
|
+
};
|
|
3791
|
+
});
|
|
3792
|
+
|
|
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;
|
|
3594
3829
|
}
|
|
3830
|
+
dIdx++;
|
|
3831
|
+
mIdx++;
|
|
3595
3832
|
}
|
|
3596
|
-
dIdx
|
|
3597
|
-
mIdx
|
|
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++;
|
|
3841
|
+
}
|
|
3842
|
+
dIdx += dStride;
|
|
3598
3843
|
}
|
|
3599
|
-
dIdx += dStride;
|
|
3600
|
-
mIdx += mStride;
|
|
3601
3844
|
}
|
|
3602
|
-
return
|
|
3845
|
+
return true;
|
|
3603
3846
|
}
|
|
3604
3847
|
|
|
3605
|
-
// src/History/PixelMutator/
|
|
3606
|
-
var
|
|
3607
|
-
|
|
3848
|
+
// src/History/PixelMutator/mutatorInvert.ts
|
|
3849
|
+
var defaults18 = {
|
|
3850
|
+
invertPixelData
|
|
3608
3851
|
};
|
|
3609
|
-
var
|
|
3852
|
+
var mutatorInvert = ((writer, deps = defaults18) => {
|
|
3610
3853
|
const {
|
|
3611
|
-
|
|
3854
|
+
invertPixelData: invertPixelData2 = defaults18.invertPixelData
|
|
3612
3855
|
} = deps;
|
|
3613
3856
|
return {
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
const
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
h = target.height
|
|
3621
|
-
} = opts;
|
|
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;
|
|
3622
3863
|
const didChange = writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3623
|
-
return didChange(
|
|
3864
|
+
return didChange(invertPixelData2(target, opts));
|
|
3624
3865
|
}
|
|
3625
3866
|
};
|
|
3626
3867
|
});
|
|
3627
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
|
+
|
|
3628
3918
|
// src/ImageData/copyImageData.ts
|
|
3629
3919
|
function copyImageData({
|
|
3630
3920
|
data,
|
|
@@ -3645,17 +3935,6 @@ function copyImageDataLike({
|
|
|
3645
3935
|
};
|
|
3646
3936
|
}
|
|
3647
3937
|
|
|
3648
|
-
// src/ImageData/ImageDataLike.ts
|
|
3649
|
-
function makeImageDataLike(width, height, data) {
|
|
3650
|
-
const size = width * height * 4;
|
|
3651
|
-
const buffer = data ? new Uint8ClampedArray(data.buffer, data.byteOffset, size) : new Uint8ClampedArray(size);
|
|
3652
|
-
return {
|
|
3653
|
-
width,
|
|
3654
|
-
height,
|
|
3655
|
-
data: buffer
|
|
3656
|
-
};
|
|
3657
|
-
}
|
|
3658
|
-
|
|
3659
3938
|
// src/ImageData/imageDataToAlphaMaskBuffer.ts
|
|
3660
3939
|
function imageDataToAlphaMaskBuffer(imageData) {
|
|
3661
3940
|
const {
|
|
@@ -3740,23 +4019,10 @@ function resampleImageData(source, factor) {
|
|
|
3740
4019
|
const {
|
|
3741
4020
|
data,
|
|
3742
4021
|
width,
|
|
3743
|
-
height
|
|
3744
|
-
} = resample32(src32, source.width, source.height, factor);
|
|
3745
|
-
const uint8ClampedArray = new Uint8ClampedArray(data.buffer);
|
|
3746
|
-
return new ImageData(uint8ClampedArray, width, height);
|
|
3747
|
-
}
|
|
3748
|
-
|
|
3749
|
-
// src/ImageData/ReusableImageData.ts
|
|
3750
|
-
function makeReusableImageData() {
|
|
3751
|
-
let imageData = null;
|
|
3752
|
-
return function getReusableImageData(width, height) {
|
|
3753
|
-
if (imageData === null || imageData.width !== width || imageData.height !== height) {
|
|
3754
|
-
imageData = new ImageData(width, height);
|
|
3755
|
-
} else {
|
|
3756
|
-
imageData.data.fill(0);
|
|
3757
|
-
}
|
|
3758
|
-
return imageData;
|
|
3759
|
-
};
|
|
4022
|
+
height
|
|
4023
|
+
} = resample32(src32, source.width, source.height, factor);
|
|
4024
|
+
const uint8ClampedArray = new Uint8ClampedArray(data.buffer);
|
|
4025
|
+
return new ImageData(uint8ClampedArray, width, height);
|
|
3760
4026
|
}
|
|
3761
4027
|
|
|
3762
4028
|
// src/ImageData/serialization.ts
|
|
@@ -3913,18 +4179,6 @@ function writeImageDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
3913
4179
|
}
|
|
3914
4180
|
}
|
|
3915
4181
|
|
|
3916
|
-
// src/IndexedImage/getIndexedImageColorCounts.ts
|
|
3917
|
-
function getIndexedImageColorCounts(indexedImage) {
|
|
3918
|
-
const data = indexedImage.data;
|
|
3919
|
-
const palette = indexedImage.palette;
|
|
3920
|
-
const frequencies = new Int32Array(palette.length);
|
|
3921
|
-
for (let i = 0; i < data.length; i++) {
|
|
3922
|
-
const colorIndex = data[i];
|
|
3923
|
-
frequencies[colorIndex]++;
|
|
3924
|
-
}
|
|
3925
|
-
return frequencies;
|
|
3926
|
-
}
|
|
3927
|
-
|
|
3928
4182
|
// src/IndexedImage/IndexedImage.ts
|
|
3929
4183
|
var IndexedImage = class _IndexedImage {
|
|
3930
4184
|
/** The width of the image in pixels. */
|
|
@@ -4003,6 +4257,18 @@ var IndexedImage = class _IndexedImage {
|
|
|
4003
4257
|
}
|
|
4004
4258
|
};
|
|
4005
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
|
+
|
|
4006
4272
|
// src/IndexedImage/indexedImageToAverageColor.ts
|
|
4007
4273
|
function indexedImageToAverageColor(indexedImage, includeTransparent = false) {
|
|
4008
4274
|
const {
|
|
@@ -4161,16 +4427,14 @@ function makeBinaryMask(w, h, data) {
|
|
|
4161
4427
|
}
|
|
4162
4428
|
|
|
4163
4429
|
// src/Mask/applyBinaryMaskToAlphaMask.ts
|
|
4164
|
-
function applyBinaryMaskToAlphaMask(alphaMaskDst, binaryMaskSrc, opts
|
|
4165
|
-
const
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
invertMask = false
|
|
4173
|
-
} = 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;
|
|
4174
4438
|
const dstWidth = alphaMaskDst.w;
|
|
4175
4439
|
if (dstWidth <= 0) return;
|
|
4176
4440
|
if (binaryMaskSrc.data.length === 0) return;
|
|
@@ -4593,6 +4857,148 @@ function pushPiece(dest, r, x, y, w, h) {
|
|
|
4593
4857
|
});
|
|
4594
4858
|
}
|
|
4595
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 */,
|
|
4994
|
+
data,
|
|
4995
|
+
w: width,
|
|
4996
|
+
h: height,
|
|
4997
|
+
centerOffsetX: -(width >> 1),
|
|
4998
|
+
centerOffsetY: -(height >> 1)
|
|
4999
|
+
};
|
|
5000
|
+
}
|
|
5001
|
+
|
|
4596
5002
|
// src/PixelData/PixelData.ts
|
|
4597
5003
|
var PixelData = class {
|
|
4598
5004
|
data32;
|
|
@@ -4614,170 +5020,96 @@ var PixelData = class {
|
|
|
4614
5020
|
}
|
|
4615
5021
|
};
|
|
4616
5022
|
|
|
4617
|
-
// src/PixelData/
|
|
4618
|
-
function
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
const globalAlpha = opts.alpha ?? 255;
|
|
4624
|
-
const blendFn = opts.blendFn ?? sourceOverPerfect;
|
|
4625
|
-
const mx = opts.mx ?? 0;
|
|
4626
|
-
const my = opts.my ?? 0;
|
|
4627
|
-
const invertMask = opts.invertMask ?? false;
|
|
4628
|
-
if (globalAlpha === 0) return false;
|
|
4629
|
-
const baseSrcAlpha = color >>> 24;
|
|
4630
|
-
const isOverwrite = blendFn.isOverwrite || false;
|
|
4631
|
-
if (baseSrcAlpha === 0 && !isOverwrite) return false;
|
|
4632
|
-
let x = targetX;
|
|
4633
|
-
let y = targetY;
|
|
4634
|
-
let actualW = w;
|
|
4635
|
-
let actualH = h;
|
|
4636
|
-
if (x < 0) {
|
|
4637
|
-
actualW += x;
|
|
4638
|
-
x = 0;
|
|
4639
|
-
}
|
|
4640
|
-
if (y < 0) {
|
|
4641
|
-
actualH += y;
|
|
4642
|
-
y = 0;
|
|
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);
|
|
4643
5029
|
}
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
const maskData = mask.data;
|
|
4653
|
-
let dIdx = y * dw + x | 0;
|
|
4654
|
-
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
4655
|
-
const dStride = dw - actualW | 0;
|
|
4656
|
-
const mStride = mPitch - actualW | 0;
|
|
4657
|
-
const isOpaque = globalAlpha === 255;
|
|
4658
|
-
const colorRGB = color & 16777215;
|
|
4659
|
-
let didChange = false;
|
|
4660
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
4661
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
4662
|
-
const mVal = maskData[mIdx];
|
|
4663
|
-
const effM = invertMask ? 255 - mVal : mVal;
|
|
4664
|
-
if (effM === 0) {
|
|
4665
|
-
dIdx++;
|
|
4666
|
-
mIdx++;
|
|
4667
|
-
continue;
|
|
4668
|
-
}
|
|
4669
|
-
let weight = globalAlpha;
|
|
4670
|
-
if (isOpaque) {
|
|
4671
|
-
weight = effM;
|
|
4672
|
-
} else if (effM !== 255) {
|
|
4673
|
-
weight = effM * globalAlpha + 128 >> 8;
|
|
4674
|
-
}
|
|
4675
|
-
if (weight === 0) {
|
|
4676
|
-
dIdx++;
|
|
4677
|
-
mIdx++;
|
|
4678
|
-
continue;
|
|
4679
|
-
}
|
|
4680
|
-
let finalCol = color;
|
|
4681
|
-
if (weight < 255) {
|
|
4682
|
-
const a = baseSrcAlpha * weight + 128 >> 8;
|
|
4683
|
-
if (a === 0 && !isOverwrite) {
|
|
4684
|
-
dIdx++;
|
|
4685
|
-
mIdx++;
|
|
4686
|
-
continue;
|
|
4687
|
-
}
|
|
4688
|
-
finalCol = (colorRGB | a << 24) >>> 0;
|
|
4689
|
-
}
|
|
4690
|
-
const current = dst32[dIdx];
|
|
4691
|
-
const next = blendFn(finalCol, current);
|
|
4692
|
-
if (current !== next) {
|
|
4693
|
-
dst32[dIdx] = next;
|
|
4694
|
-
didChange = true;
|
|
4695
|
-
}
|
|
4696
|
-
dIdx++;
|
|
4697
|
-
mIdx++;
|
|
4698
|
-
}
|
|
4699
|
-
dIdx += dStride;
|
|
4700
|
-
mIdx += mStride;
|
|
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);
|
|
4701
5038
|
}
|
|
4702
|
-
return didChange;
|
|
4703
5039
|
}
|
|
4704
5040
|
|
|
4705
|
-
// src/PixelData/
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
const
|
|
4714
|
-
const
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
const
|
|
4731
|
-
const
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
5041
|
+
// src/PixelData/blendColorPixelDataPaintAlphaMask.ts
|
|
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);
|
|
4738
5093
|
}
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
const dStride = dw - actualW | 0;
|
|
4748
|
-
const mStride = mPitch - actualW | 0;
|
|
4749
|
-
const skipVal = invertMask ? 1 : 0;
|
|
4750
|
-
let didChange = false;
|
|
4751
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
4752
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
4753
|
-
if (maskData[mIdx] === skipVal) {
|
|
4754
|
-
dIdx++;
|
|
4755
|
-
mIdx++;
|
|
4756
|
-
continue;
|
|
4757
|
-
}
|
|
4758
|
-
const current = dst32[dIdx];
|
|
4759
|
-
const next = blendFn(baseColorWithGlobalAlpha, current);
|
|
4760
|
-
if (current !== next) {
|
|
4761
|
-
dst32[dIdx] = next;
|
|
4762
|
-
didChange = true;
|
|
4763
|
-
}
|
|
4764
|
-
dIdx++;
|
|
4765
|
-
mIdx++;
|
|
4766
|
-
}
|
|
4767
|
-
dIdx += dStride;
|
|
4768
|
-
mIdx += mStride;
|
|
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);
|
|
4769
5102
|
}
|
|
4770
|
-
return didChange;
|
|
4771
5103
|
}
|
|
4772
5104
|
|
|
4773
5105
|
// src/PixelData/blendPixelDataPaintBuffer.ts
|
|
4774
|
-
var
|
|
5106
|
+
var SCRATCH_OPTS4 = {
|
|
4775
5107
|
x: 0,
|
|
4776
5108
|
y: 0,
|
|
4777
5109
|
alpha: 255,
|
|
4778
5110
|
blendFn: void 0
|
|
4779
5111
|
};
|
|
4780
|
-
function blendPixelDataPaintBuffer(
|
|
5112
|
+
function blendPixelDataPaintBuffer(target, paintBuffer, alpha = 255, blendFn, blendPixelDataFn = blendPixelData) {
|
|
4781
5113
|
const tileShift = paintBuffer.config.tileShift;
|
|
4782
5114
|
const lookup = paintBuffer.lookup;
|
|
4783
5115
|
for (let i = 0; i < lookup.length; i++) {
|
|
@@ -4785,17 +5117,61 @@ function blendPixelDataPaintBuffer(paintBuffer, target, alpha = 255, blendFn, bl
|
|
|
4785
5117
|
if (tile) {
|
|
4786
5118
|
const x = tile.tx << tileShift;
|
|
4787
5119
|
const y = tile.ty << tileShift;
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
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);
|
|
4793
5125
|
}
|
|
4794
5126
|
}
|
|
4795
5127
|
}
|
|
4796
5128
|
|
|
4797
|
-
// src/PixelData/
|
|
4798
|
-
|
|
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) {
|
|
4799
5175
|
fillPixelDataFast(dst, 0, rect);
|
|
4800
5176
|
}
|
|
4801
5177
|
|
|
@@ -4858,26 +5234,6 @@ function extractPixelData(source, _x, _y, _w, _h) {
|
|
|
4858
5234
|
return result;
|
|
4859
5235
|
}
|
|
4860
5236
|
|
|
4861
|
-
// src/PixelData/PixelBuffer32.ts
|
|
4862
|
-
var PixelBuffer32 = class _PixelBuffer32 {
|
|
4863
|
-
constructor(width, height, data32) {
|
|
4864
|
-
this.width = width;
|
|
4865
|
-
this.height = height;
|
|
4866
|
-
this.data32 = data32 ?? new Uint32Array(width * height);
|
|
4867
|
-
}
|
|
4868
|
-
data32;
|
|
4869
|
-
set(width, height, data32) {
|
|
4870
|
-
;
|
|
4871
|
-
this.data32 = data32 ?? new Uint32Array(width * height);
|
|
4872
|
-
this.width = width;
|
|
4873
|
-
this.height = height;
|
|
4874
|
-
}
|
|
4875
|
-
copy() {
|
|
4876
|
-
const newData32 = new Uint32Array(this.data32);
|
|
4877
|
-
return new _PixelBuffer32(this.width, this.height, newData32);
|
|
4878
|
-
}
|
|
4879
|
-
};
|
|
4880
|
-
|
|
4881
5237
|
// src/PixelData/pixelDataToAlphaMask.ts
|
|
4882
5238
|
function pixelDataToAlphaMask(pixelData) {
|
|
4883
5239
|
const {
|
|
@@ -5029,164 +5385,17 @@ function writePaintBufferToPixelData(target, paintBuffer, writePixelDataBufferFn
|
|
|
5029
5385
|
}
|
|
5030
5386
|
}
|
|
5031
5387
|
}
|
|
5032
|
-
|
|
5033
|
-
// src/Paint/makeCirclePaintAlphaMask.ts
|
|
5034
|
-
function makeCirclePaintAlphaMask(size, fallOff = (d) => d) {
|
|
5035
|
-
const area = size * size;
|
|
5036
|
-
const data = new Uint8Array(area);
|
|
5037
|
-
const radius = size / 2;
|
|
5038
|
-
const invR = 1 / radius;
|
|
5039
|
-
const centerOffset = -Math.ceil(radius - 0.5);
|
|
5040
|
-
for (let y = 0; y < size; y++) {
|
|
5041
|
-
const rowOffset = y * size;
|
|
5042
|
-
const dy = y - radius + 0.5;
|
|
5043
|
-
const dy2 = dy * dy;
|
|
5044
|
-
for (let x = 0; x < size; x++) {
|
|
5045
|
-
const dx = x - radius + 0.5;
|
|
5046
|
-
const distSqr = dx * dx + dy2;
|
|
5047
|
-
if (distSqr <= radius * radius) {
|
|
5048
|
-
const dist = Math.sqrt(distSqr) * invR;
|
|
5049
|
-
const strength = fallOff(1 - dist);
|
|
5050
|
-
if (strength > 0) {
|
|
5051
|
-
const intensity = strength * 255 | 0;
|
|
5052
|
-
data[rowOffset + x] = Math.max(0, Math.min(255, intensity));
|
|
5053
|
-
}
|
|
5054
|
-
}
|
|
5055
|
-
}
|
|
5056
|
-
}
|
|
5057
|
-
return {
|
|
5058
|
-
type: 0 /* ALPHA */,
|
|
5059
|
-
data,
|
|
5060
|
-
w: size,
|
|
5061
|
-
h: size,
|
|
5062
|
-
centerOffsetX: centerOffset,
|
|
5063
|
-
centerOffsetY: centerOffset
|
|
5064
|
-
};
|
|
5065
|
-
}
|
|
5066
|
-
|
|
5067
|
-
// src/Paint/makeCirclePaintBinaryMask.ts
|
|
5068
|
-
function makeCirclePaintBinaryMask(size) {
|
|
5069
|
-
const area = size * size;
|
|
5070
|
-
const data = new Uint8Array(area);
|
|
5071
|
-
const radius = size / 2;
|
|
5072
|
-
const centerOffset = -Math.ceil(radius - 0.5);
|
|
5073
|
-
for (let y = 0; y < size; y++) {
|
|
5074
|
-
for (let x = 0; x < size; x++) {
|
|
5075
|
-
const dx = x - radius + 0.5;
|
|
5076
|
-
const dy = y - radius + 0.5;
|
|
5077
|
-
const distSqr = dx * dx + dy * dy;
|
|
5078
|
-
if (distSqr <= radius * radius) {
|
|
5079
|
-
data[y * size + x] = 1;
|
|
5080
|
-
}
|
|
5081
|
-
}
|
|
5082
|
-
}
|
|
5083
|
-
return {
|
|
5084
|
-
type: 1 /* BINARY */,
|
|
5085
|
-
data,
|
|
5086
|
-
w: size,
|
|
5087
|
-
h: size,
|
|
5088
|
-
centerOffsetX: centerOffset,
|
|
5089
|
-
centerOffsetY: centerOffset
|
|
5090
|
-
};
|
|
5091
|
-
}
|
|
5092
|
-
|
|
5093
|
-
// src/Internal/helpers.ts
|
|
5094
|
-
var macro_halfAndFloor = (value) => value >> 1;
|
|
5095
|
-
|
|
5096
|
-
// src/Paint/makePaintMask.ts
|
|
5097
|
-
function makePaintBinaryMask(mask) {
|
|
5098
|
-
return {
|
|
5099
|
-
type: 1 /* BINARY */,
|
|
5100
|
-
data: mask.data,
|
|
5101
|
-
w: mask.w,
|
|
5102
|
-
h: mask.h,
|
|
5103
|
-
centerOffsetX: -macro_halfAndFloor(mask.w),
|
|
5104
|
-
centerOffsetY: -macro_halfAndFloor(mask.h)
|
|
5105
|
-
};
|
|
5106
|
-
}
|
|
5107
|
-
function makePaintAlphaMask(mask) {
|
|
5108
|
-
return {
|
|
5109
|
-
type: 0 /* ALPHA */,
|
|
5110
|
-
data: mask.data,
|
|
5111
|
-
w: mask.w,
|
|
5112
|
-
h: mask.h,
|
|
5113
|
-
centerOffsetX: -macro_halfAndFloor(mask.w),
|
|
5114
|
-
centerOffsetY: -macro_halfAndFloor(mask.h)
|
|
5115
|
-
};
|
|
5116
|
-
}
|
|
5117
|
-
|
|
5118
|
-
// src/Paint/makeRectFalloffPaintAlphaMask.ts
|
|
5119
|
-
function makeRectFalloffPaintAlphaMask(width, height, fallOff = (d) => d) {
|
|
5120
|
-
const fPx = Math.floor(width / 2);
|
|
5121
|
-
const fPy = Math.floor(height / 2);
|
|
5122
|
-
const invHalfW = 2 / width;
|
|
5123
|
-
const invHalfH = 2 / height;
|
|
5124
|
-
const offX = width % 2 === 0 ? 0.5 : 0;
|
|
5125
|
-
const offY = height % 2 === 0 ? 0.5 : 0;
|
|
5126
|
-
const area = width * height;
|
|
5127
|
-
const data = new Uint8Array(area);
|
|
5128
|
-
for (let y = 0; y < height; y++) {
|
|
5129
|
-
const dy = Math.abs(y - fPy + offY) * invHalfH;
|
|
5130
|
-
const rowOffset = y * width;
|
|
5131
|
-
for (let x = 0; x < width; x++) {
|
|
5132
|
-
const dx = Math.abs(x - fPx + offX) * invHalfW;
|
|
5133
|
-
const dist = dx > dy ? dx : dy;
|
|
5134
|
-
const strength = fallOff(1 - dist);
|
|
5135
|
-
if (strength > 0) {
|
|
5136
|
-
const intensity = strength * 255 | 0;
|
|
5137
|
-
data[rowOffset + x] = Math.max(0, Math.min(255, intensity));
|
|
5138
|
-
}
|
|
5139
|
-
}
|
|
5140
|
-
}
|
|
5141
|
-
return {
|
|
5142
|
-
type: 0 /* ALPHA */,
|
|
5143
|
-
data,
|
|
5144
|
-
w: width,
|
|
5145
|
-
h: height,
|
|
5146
|
-
centerOffsetX: -macro_halfAndFloor(width),
|
|
5147
|
-
centerOffsetY: -macro_halfAndFloor(height)
|
|
5148
|
-
};
|
|
5149
|
-
}
|
|
5150
|
-
|
|
5151
|
-
// src/Paint/PaintBufferCanvasRenderer.ts
|
|
5152
|
-
function makePaintBufferCanvasRenderer(paintBuffer, offscreenCanvasClass = OffscreenCanvas) {
|
|
5153
|
-
const config = paintBuffer.config;
|
|
5154
|
-
const tileSize = config.tileSize;
|
|
5155
|
-
const tileShift = config.tileShift;
|
|
5156
|
-
const lookup = paintBuffer.lookup;
|
|
5157
|
-
const canvas = new offscreenCanvasClass(tileSize, tileSize);
|
|
5158
|
-
const ctx = canvas.getContext("2d");
|
|
5159
|
-
if (!ctx) throw new Error(CANVAS_CTX_FAILED);
|
|
5160
|
-
ctx.imageSmoothingEnabled = false;
|
|
5161
|
-
return function drawPaintBuffer(targetCtx, alpha = 255, compOperation = "source-over") {
|
|
5162
|
-
targetCtx.globalAlpha = alpha / 255;
|
|
5163
|
-
targetCtx.globalCompositeOperation = compOperation;
|
|
5164
|
-
for (let i = 0; i < lookup.length; i++) {
|
|
5165
|
-
const tile = lookup[i];
|
|
5166
|
-
if (tile) {
|
|
5167
|
-
const dx = tile.tx << tileShift;
|
|
5168
|
-
const dy = tile.ty << tileShift;
|
|
5169
|
-
ctx.putImageData(tile.imageData, 0, 0);
|
|
5170
|
-
targetCtx.drawImage(canvas, dx, dy);
|
|
5171
|
-
}
|
|
5172
|
-
}
|
|
5173
|
-
targetCtx.globalAlpha = 1;
|
|
5174
|
-
targetCtx.globalCompositeOperation = "source-over";
|
|
5175
|
-
};
|
|
5176
|
-
}
|
|
5177
5388
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5178
5389
|
0 && (module.exports = {
|
|
5179
5390
|
BASE_FAST_BLEND_MODE_FUNCTIONS,
|
|
5180
5391
|
BASE_PERFECT_BLEND_MODE_FUNCTIONS,
|
|
5181
5392
|
BaseBlendMode,
|
|
5182
|
-
|
|
5393
|
+
CANVAS_COMPOSITE_MAP,
|
|
5183
5394
|
HistoryManager,
|
|
5184
5395
|
IndexedImage,
|
|
5185
5396
|
MaskType,
|
|
5186
|
-
OFFSCREEN_CANVAS_CTX_FAILED,
|
|
5187
5397
|
PaintBuffer,
|
|
5188
5398
|
PixelAccumulator,
|
|
5189
|
-
PixelBuffer32,
|
|
5190
5399
|
PixelData,
|
|
5191
5400
|
PixelEngineConfig,
|
|
5192
5401
|
PixelTile,
|
|
@@ -5196,18 +5405,24 @@ function makePaintBufferCanvasRenderer(paintBuffer, offscreenCanvasClass = Offsc
|
|
|
5196
5405
|
applyAlphaMaskToPixelData,
|
|
5197
5406
|
applyBinaryMaskToAlphaMask,
|
|
5198
5407
|
applyBinaryMaskToPixelData,
|
|
5408
|
+
applyMaskToPixelData,
|
|
5199
5409
|
applyPatchTiles,
|
|
5200
5410
|
base64DecodeArrayBuffer,
|
|
5201
5411
|
base64EncodeArrayBuffer,
|
|
5202
5412
|
blendColorPixelData,
|
|
5203
5413
|
blendColorPixelDataAlphaMask,
|
|
5204
5414
|
blendColorPixelDataBinaryMask,
|
|
5415
|
+
blendColorPixelDataMask,
|
|
5416
|
+
blendColorPixelDataPaintAlphaMask,
|
|
5417
|
+
blendColorPixelDataPaintBinaryMask,
|
|
5418
|
+
blendColorPixelDataPaintMask,
|
|
5205
5419
|
blendPixel,
|
|
5206
5420
|
blendPixelData,
|
|
5207
5421
|
blendPixelDataAlphaMask,
|
|
5208
5422
|
blendPixelDataBinaryMask,
|
|
5423
|
+
blendPixelDataMask,
|
|
5209
5424
|
blendPixelDataPaintBuffer,
|
|
5210
|
-
|
|
5425
|
+
clearPixelDataFast,
|
|
5211
5426
|
color32ToCssRGBA,
|
|
5212
5427
|
color32ToHex,
|
|
5213
5428
|
colorBurnFast,
|
|
@@ -5280,6 +5495,8 @@ function makePaintBufferCanvasRenderer(paintBuffer, offscreenCanvasClass = Offsc
|
|
|
5280
5495
|
makeCanvasFrameRenderer,
|
|
5281
5496
|
makeCirclePaintAlphaMask,
|
|
5282
5497
|
makeCirclePaintBinaryMask,
|
|
5498
|
+
makeClippedBlit,
|
|
5499
|
+
makeClippedRect,
|
|
5283
5500
|
makeFastBlendModeRegistry,
|
|
5284
5501
|
makeFullPixelMutator,
|
|
5285
5502
|
makeHistoryAction,
|
|
@@ -5301,11 +5518,17 @@ function makePaintBufferCanvasRenderer(paintBuffer, offscreenCanvasClass = Offsc
|
|
|
5301
5518
|
multiplyPerfect,
|
|
5302
5519
|
mutatorApplyAlphaMask,
|
|
5303
5520
|
mutatorApplyBinaryMask,
|
|
5521
|
+
mutatorApplyMask,
|
|
5522
|
+
mutatorBlendAlphaMask,
|
|
5523
|
+
mutatorBlendBinaryMask,
|
|
5304
5524
|
mutatorBlendColor,
|
|
5525
|
+
mutatorBlendColorPaintAlphaMask,
|
|
5526
|
+
mutatorBlendColorPaintBinaryMask,
|
|
5527
|
+
mutatorBlendColorPaintMask,
|
|
5528
|
+
mutatorBlendMask,
|
|
5529
|
+
mutatorBlendPaintRect,
|
|
5305
5530
|
mutatorBlendPixel,
|
|
5306
5531
|
mutatorBlendPixelData,
|
|
5307
|
-
mutatorBlendPixelDataAlphaMask,
|
|
5308
|
-
mutatorBlendPixelDataBinaryMask,
|
|
5309
5532
|
mutatorClear,
|
|
5310
5533
|
mutatorFill,
|
|
5311
5534
|
mutatorFillBinaryMask,
|
|
@@ -5323,10 +5546,13 @@ function makePaintBufferCanvasRenderer(paintBuffer, offscreenCanvasClass = Offsc
|
|
|
5323
5546
|
pixelDataToAlphaMask,
|
|
5324
5547
|
reflectPixelDataHorizontal,
|
|
5325
5548
|
reflectPixelDataVertical,
|
|
5549
|
+
resample32,
|
|
5326
5550
|
resampleImageData,
|
|
5327
5551
|
resampleIndexedImage,
|
|
5328
5552
|
resamplePixelData,
|
|
5329
5553
|
resizeImageData,
|
|
5554
|
+
resolveBlitClipping,
|
|
5555
|
+
resolveRectClipping,
|
|
5330
5556
|
rotatePixelData,
|
|
5331
5557
|
screenFast,
|
|
5332
5558
|
screenPerfect,
|