pixel-data-js 0.17.1 → 0.19.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/README.md +6 -1
- package/dist/index.dev.cjs +2747 -1397
- package/dist/index.dev.cjs.map +1 -1
- package/dist/index.dev.js +2725 -1403
- package/dist/index.dev.js.map +1 -1
- package/dist/index.prod.cjs +2747 -1397
- package/dist/index.prod.cjs.map +1 -1
- package/dist/index.prod.d.ts +401 -241
- package/dist/index.prod.js +2725 -1403
- package/dist/index.prod.js.map +1 -1
- package/package.json +21 -6
- package/src/Algorithm/forEachLinePoint.ts +36 -0
- package/src/BlendModes/BlendModeRegistry.ts +2 -0
- package/src/BlendModes/blend-modes-fast.ts +2 -2
- package/src/BlendModes/blend-modes-perfect.ts +5 -4
- package/src/BlendModes/toBlendModeIndexAndName.ts +41 -0
- package/src/History/PixelAccumulator.ts +2 -2
- package/src/History/PixelMutator/mutatorApplyAlphaMask.ts +30 -0
- package/src/History/PixelMutator/mutatorApplyBinaryMask.ts +30 -0
- package/src/History/PixelMutator/mutatorApplyCircleBrush.ts +59 -0
- package/src/History/PixelMutator/mutatorApplyCircleBrushStroke.ts +138 -0
- package/src/History/PixelMutator/mutatorApplyCirclePencil.ts +59 -0
- package/src/History/PixelMutator/mutatorApplyCirclePencilStroke.ts +131 -0
- package/src/History/PixelMutator/mutatorApplyRectBrush.ts +61 -0
- package/src/History/PixelMutator/mutatorApplyRectBrushStroke.ts +169 -0
- package/src/History/PixelMutator/mutatorApplyRectPencil.ts +62 -0
- package/src/History/PixelMutator/mutatorApplyRectPencilStroke.ts +149 -0
- package/src/History/PixelMutator/mutatorBlendColor.ts +9 -4
- package/src/History/PixelMutator/mutatorBlendPixelData.ts +10 -5
- package/src/History/PixelMutator/mutatorClear.ts +27 -0
- package/src/History/PixelMutator/{mutatorFillPixelData.ts → mutatorFill.ts} +9 -3
- package/src/History/PixelMutator/mutatorInvert.ts +10 -3
- package/src/History/PixelMutator.ts +27 -3
- package/src/History/PixelPatchTiles.ts +2 -2
- package/src/History/PixelWriter.ts +7 -3
- package/src/ImageData/ImageDataLike.ts +13 -0
- package/src/ImageData/ReusableImageData.ts +1 -4
- package/src/ImageData/extractImageDataBuffer.ts +22 -15
- package/src/ImageData/serialization.ts +4 -4
- package/src/ImageData/uInt32ArrayToImageData.ts +29 -0
- package/src/ImageData/writeImageData.ts +26 -18
- package/src/ImageData/writeImageDataBuffer.ts +30 -18
- package/src/IndexedImage/indexedImageToAverageColor.ts +1 -1
- package/src/Internal/resolveClipping.ts +140 -0
- package/src/Mask/applyBinaryMaskToAlphaMask.ts +89 -0
- package/src/Mask/copyMask.ts +1 -3
- package/src/Mask/mergeAlphaMasks.ts +81 -0
- package/src/Mask/mergeBinaryMasks.ts +89 -0
- package/src/PixelData/PixelBuffer32.ts +28 -0
- package/src/PixelData/PixelData.ts +38 -33
- package/src/PixelData/applyAlphaMaskToPixelData.ts +119 -0
- package/src/PixelData/applyBinaryMaskToPixelData.ts +111 -0
- package/src/PixelData/applyCircleBrushToPixelData.ts +58 -28
- package/src/PixelData/applyRectBrushToPixelData.ts +56 -73
- package/src/PixelData/blendColorPixelData.ts +18 -111
- package/src/PixelData/blendColorPixelDataAlphaMask.ts +111 -0
- package/src/PixelData/blendColorPixelDataBinaryMask.ts +89 -0
- package/src/PixelData/blendPixelData.ts +19 -107
- package/src/PixelData/blendPixelDataAlphaMask.ts +149 -0
- package/src/PixelData/blendPixelDataBinaryMask.ts +133 -0
- package/src/PixelData/clearPixelData.ts +2 -3
- package/src/PixelData/extractPixelData.ts +4 -4
- package/src/PixelData/extractPixelDataBuffer.ts +38 -26
- package/src/PixelData/fillPixelData.ts +18 -20
- package/src/PixelData/invertPixelData.ts +13 -21
- package/src/PixelData/pixelDataToAlphaMask.ts +2 -3
- package/src/PixelData/reflectPixelData.ts +3 -3
- package/src/PixelData/resamplePixelData.ts +2 -6
- package/src/PixelData/writePixelDataBuffer.ts +34 -20
- package/src/Rect/getCircleBrushOrPencilBounds.ts +43 -0
- package/src/Rect/getCircleBrushOrPencilStrokeBounds.ts +24 -0
- package/src/Rect/getRectBrushOrPencilBounds.ts +38 -0
- package/src/Rect/getRectBrushOrPencilStrokeBounds.ts +26 -0
- package/src/_types.ts +49 -33
- package/src/index.ts +47 -11
- package/src/History/PixelMutator/mutatorApplyMask.ts +0 -20
- package/src/Mask/mergeMasks.ts +0 -100
- package/src/PixelData/applyMaskToPixelData.ts +0 -129
package/dist/index.dev.js
CHANGED
|
@@ -1,614 +1,235 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
1
|
+
// src/_types.ts
|
|
2
|
+
var MaskType = /* @__PURE__ */ ((MaskType2) => {
|
|
3
|
+
MaskType2[MaskType2["ALPHA"] = 0] = "ALPHA";
|
|
4
|
+
MaskType2[MaskType2["BINARY"] = 1] = "BINARY";
|
|
5
|
+
return MaskType2;
|
|
6
|
+
})(MaskType || {});
|
|
7
|
+
|
|
8
|
+
// src/color.ts
|
|
9
|
+
function packColor(r, g, b, a) {
|
|
10
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
11
|
+
}
|
|
12
|
+
function packRGBA({
|
|
13
|
+
r,
|
|
14
|
+
g,
|
|
15
|
+
b,
|
|
16
|
+
a
|
|
17
|
+
}) {
|
|
18
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
19
|
+
}
|
|
20
|
+
var unpackRed = (packed) => packed >>> 0 & 255;
|
|
21
|
+
var unpackGreen = (packed) => packed >>> 8 & 255;
|
|
22
|
+
var unpackBlue = (packed) => packed >>> 16 & 255;
|
|
23
|
+
var unpackAlpha = (packed) => packed >>> 24 & 255;
|
|
24
|
+
function unpackColor(packed) {
|
|
25
|
+
return {
|
|
26
|
+
r: packed >>> 0 & 255,
|
|
27
|
+
g: packed >>> 8 & 255,
|
|
28
|
+
b: packed >>> 16 & 255,
|
|
29
|
+
a: packed >>> 24 & 255
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
var SCRATCH_RGBA = {
|
|
33
|
+
r: 0,
|
|
34
|
+
g: 0,
|
|
35
|
+
b: 0,
|
|
36
|
+
a: 0
|
|
26
37
|
};
|
|
27
|
-
|
|
28
|
-
|
|
38
|
+
function unpackColorTo(packed, scratch = SCRATCH_RGBA) {
|
|
39
|
+
scratch.r = packed >>> 0 & 255;
|
|
40
|
+
scratch.g = packed >>> 8 & 255;
|
|
41
|
+
scratch.b = packed >>> 16 & 255;
|
|
42
|
+
scratch.a = packed >>> 24 & 255;
|
|
43
|
+
return scratch;
|
|
44
|
+
}
|
|
45
|
+
function colorDistance(a, b) {
|
|
46
|
+
const dr = (a & 255) - (b & 255);
|
|
47
|
+
const dg = (a >>> 8 & 255) - (b >>> 8 & 255);
|
|
48
|
+
const db = (a >>> 16 & 255) - (b >>> 16 & 255);
|
|
49
|
+
const da = (a >>> 24 & 255) - (b >>> 24 & 255);
|
|
50
|
+
return dr * dr + dg * dg + db * db + da * da;
|
|
51
|
+
}
|
|
52
|
+
function lerpColor32(a, b, t) {
|
|
53
|
+
const r = (a & 255) + t * ((b & 255) - (a & 255));
|
|
54
|
+
const g = (a >>> 8 & 255) + t * ((b >>> 8 & 255) - (a >>> 8 & 255));
|
|
55
|
+
const b_ = (a >>> 16 & 255) + t * ((b >>> 16 & 255) - (a >>> 16 & 255));
|
|
56
|
+
const a_ = (a >>> 24 & 255) + t * ((b >>> 24 & 255) - (a >>> 24 & 255));
|
|
57
|
+
return (a_ << 24 | b_ << 16 | g << 8 | r) >>> 0;
|
|
58
|
+
}
|
|
59
|
+
function lerpColor32Fast(src, dst, w) {
|
|
60
|
+
const invA = 255 - w;
|
|
61
|
+
const rb = (src & 16711935) * w + (dst & 16711935) * invA >>> 8 & 16711935;
|
|
62
|
+
const ga = (src >>> 8 & 16711935) * w + (dst >>> 8 & 16711935) * invA >>> 8 & 16711935;
|
|
63
|
+
return (rb | ga << 8) >>> 0;
|
|
64
|
+
}
|
|
65
|
+
function color32ToHex(color) {
|
|
66
|
+
const r = (color & 255).toString(16).padStart(2, "0");
|
|
67
|
+
const g = (color >>> 8 & 255).toString(16).padStart(2, "0");
|
|
68
|
+
const b = (color >>> 16 & 255).toString(16).padStart(2, "0");
|
|
69
|
+
const a = (color >>> 24 & 255).toString(16).padStart(2, "0");
|
|
70
|
+
return `#${r}${g}${b}${a}`;
|
|
71
|
+
}
|
|
72
|
+
function color32ToCssRGBA(color) {
|
|
73
|
+
const r = color & 255;
|
|
74
|
+
const g = color >>> 8 & 255;
|
|
75
|
+
const b = color >>> 16 & 255;
|
|
76
|
+
const a = color >>> 24 & 255;
|
|
77
|
+
const alpha = Number((a / 255).toFixed(3));
|
|
78
|
+
return `rgba(${r},${g},${b},${alpha})`;
|
|
79
|
+
}
|
|
29
80
|
|
|
30
|
-
// src/
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
81
|
+
// src/Internal/resolveClipping.ts
|
|
82
|
+
var makeClippedRect = () => ({
|
|
83
|
+
x: 0,
|
|
84
|
+
y: 0,
|
|
85
|
+
w: 0,
|
|
86
|
+
h: 0,
|
|
87
|
+
inBounds: false
|
|
88
|
+
});
|
|
89
|
+
var makeClippedBlit = () => ({
|
|
90
|
+
x: 0,
|
|
91
|
+
y: 0,
|
|
92
|
+
sx: 0,
|
|
93
|
+
sy: 0,
|
|
94
|
+
w: 0,
|
|
95
|
+
h: 0,
|
|
96
|
+
inBounds: false
|
|
97
|
+
});
|
|
98
|
+
function resolveRectClipping(x, y, w, h, boundaryW, boundaryH, out) {
|
|
99
|
+
if (x < 0) {
|
|
100
|
+
w += x;
|
|
101
|
+
x = 0;
|
|
102
|
+
}
|
|
103
|
+
if (y < 0) {
|
|
104
|
+
h += y;
|
|
105
|
+
y = 0;
|
|
106
|
+
}
|
|
107
|
+
const actualW = Math.min(w, boundaryW - x);
|
|
108
|
+
const actualH = Math.min(h, boundaryH - y);
|
|
109
|
+
if (actualW <= 0 || actualH <= 0) {
|
|
110
|
+
out.inBounds = false;
|
|
111
|
+
return out;
|
|
112
|
+
}
|
|
113
|
+
out.x = x;
|
|
114
|
+
out.y = y;
|
|
115
|
+
out.w = actualW;
|
|
116
|
+
out.h = actualH;
|
|
117
|
+
out.inBounds = true;
|
|
118
|
+
return out;
|
|
119
|
+
}
|
|
120
|
+
function resolveBlitClipping(x, y, sx, sy, w, h, dstW, dstH, srcW, srcH, out) {
|
|
121
|
+
if (sx < 0) {
|
|
122
|
+
x -= sx;
|
|
123
|
+
w += sx;
|
|
124
|
+
sx = 0;
|
|
125
|
+
}
|
|
126
|
+
if (sy < 0) {
|
|
127
|
+
y -= sy;
|
|
128
|
+
h += sy;
|
|
129
|
+
sy = 0;
|
|
130
|
+
}
|
|
131
|
+
w = Math.min(w, srcW - sx);
|
|
132
|
+
h = Math.min(h, srcH - sy);
|
|
133
|
+
if (x < 0) {
|
|
134
|
+
sx -= x;
|
|
135
|
+
w += x;
|
|
136
|
+
x = 0;
|
|
137
|
+
}
|
|
138
|
+
if (y < 0) {
|
|
139
|
+
sy -= y;
|
|
140
|
+
h += y;
|
|
141
|
+
y = 0;
|
|
142
|
+
}
|
|
143
|
+
const actualW = Math.min(w, dstW - x);
|
|
144
|
+
const actualH = Math.min(h, dstH - y);
|
|
145
|
+
if (actualW <= 0 || actualH <= 0) {
|
|
146
|
+
out.inBounds = false;
|
|
147
|
+
return out;
|
|
148
|
+
}
|
|
149
|
+
out.x = x;
|
|
150
|
+
out.y = y;
|
|
151
|
+
out.sx = sx;
|
|
152
|
+
out.sy = sy;
|
|
153
|
+
out.w = actualW;
|
|
154
|
+
out.h = actualH;
|
|
155
|
+
out.inBounds = true;
|
|
156
|
+
return out;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// src/ImageData/extractImageDataBuffer.ts
|
|
160
|
+
var SCRATCH_BLIT = makeClippedBlit();
|
|
161
|
+
function extractImageDataBuffer(imageData, _x, _y, _w, _h) {
|
|
162
|
+
const {
|
|
163
|
+
x,
|
|
164
|
+
y,
|
|
165
|
+
w,
|
|
166
|
+
h
|
|
167
|
+
} = typeof _x === "object" ? _x : {
|
|
168
|
+
x: _x,
|
|
169
|
+
y: _y,
|
|
170
|
+
w: _w,
|
|
171
|
+
h: _h
|
|
172
|
+
};
|
|
173
|
+
const {
|
|
174
|
+
width: srcW,
|
|
175
|
+
height: srcH,
|
|
176
|
+
data: src
|
|
177
|
+
} = imageData;
|
|
178
|
+
if (w <= 0 || h <= 0) return new Uint8ClampedArray(0);
|
|
179
|
+
const out = new Uint8ClampedArray(w * h * 4);
|
|
180
|
+
const clip = resolveBlitClipping(0, 0, x, y, w, h, w, h, srcW, srcH, SCRATCH_BLIT);
|
|
181
|
+
if (!clip.inBounds) return out;
|
|
182
|
+
const {
|
|
183
|
+
x: dstX,
|
|
184
|
+
y: dstY,
|
|
185
|
+
sx: srcX,
|
|
186
|
+
sy: srcY,
|
|
187
|
+
w: copyW,
|
|
188
|
+
h: copyH
|
|
189
|
+
} = clip;
|
|
190
|
+
const rowLen = copyW * 4;
|
|
191
|
+
for (let row = 0; row < copyH; row++) {
|
|
192
|
+
const srcStart = ((srcY + row) * srcW + srcX) * 4;
|
|
193
|
+
const dstStart = ((dstY + row) * w + dstX) * 4;
|
|
194
|
+
out.set(src.subarray(srcStart, srcStart + rowLen), dstStart);
|
|
195
|
+
}
|
|
196
|
+
return out;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// src/Mask/extractMask.ts
|
|
200
|
+
function extractMask(mask, maskWidth, xOrRect, y, w, h) {
|
|
201
|
+
let finalX;
|
|
202
|
+
let finalY;
|
|
203
|
+
let finalW;
|
|
204
|
+
let finalH;
|
|
205
|
+
if (typeof xOrRect === "object") {
|
|
206
|
+
finalX = xOrRect.x;
|
|
207
|
+
finalY = xOrRect.y;
|
|
208
|
+
finalW = xOrRect.w;
|
|
209
|
+
finalH = xOrRect.h;
|
|
210
|
+
} else {
|
|
211
|
+
finalX = xOrRect;
|
|
212
|
+
finalY = y;
|
|
213
|
+
finalW = w;
|
|
214
|
+
finalH = h;
|
|
215
|
+
}
|
|
216
|
+
const out = new Uint8Array(finalW * finalH);
|
|
217
|
+
const srcH = mask.length / maskWidth;
|
|
218
|
+
for (let row = 0; row < finalH; row++) {
|
|
219
|
+
const currentSrcY = finalY + row;
|
|
220
|
+
if (currentSrcY < 0 || currentSrcY >= srcH) {
|
|
221
|
+
continue;
|
|
41
222
|
}
|
|
42
|
-
|
|
43
|
-
|
|
223
|
+
const start = Math.max(0, finalX);
|
|
224
|
+
const end = Math.min(maskWidth, finalX + finalW);
|
|
225
|
+
if (start < end) {
|
|
226
|
+
const srcOffset = currentSrcY * maskWidth + start;
|
|
227
|
+
const dstOffset = row * finalW + (start - finalX);
|
|
228
|
+
const count = end - start;
|
|
229
|
+
out.set(mask.subarray(srcOffset, srcOffset + count), dstOffset);
|
|
44
230
|
}
|
|
45
|
-
indexToName[index] = name;
|
|
46
|
-
indexToBlend[index] = blendFn;
|
|
47
|
-
blendToIndex.set(blendFn, index);
|
|
48
|
-
blendToName.set(blendFn, name);
|
|
49
|
-
nameToBlend[name] = blendFn;
|
|
50
|
-
nameToIndex[name] = index;
|
|
51
|
-
};
|
|
52
|
-
for (const [name, index] of Object.entries(blendModes)) {
|
|
53
|
-
const blend = initialEntries[index];
|
|
54
|
-
add(name, index, blend);
|
|
55
231
|
}
|
|
56
|
-
return
|
|
57
|
-
nameToBlend,
|
|
58
|
-
nameToIndex,
|
|
59
|
-
blendToIndex,
|
|
60
|
-
blendToName,
|
|
61
|
-
indexToBlend,
|
|
62
|
-
indexToName,
|
|
63
|
-
indexType: null,
|
|
64
|
-
nameType: null
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// src/BlendModes/blend-modes-fast.ts
|
|
69
|
-
var overwriteFast = overwriteBase;
|
|
70
|
-
var sourceOverFast = (src, dst) => {
|
|
71
|
-
const sa = src >>> 24 & 255;
|
|
72
|
-
if (sa === 255) return src;
|
|
73
|
-
if (sa === 0) return dst;
|
|
74
|
-
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
75
|
-
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
76
|
-
const da = dst >>> 24 & 255;
|
|
77
|
-
const invA = 255 - sa;
|
|
78
|
-
const r = sr * sa + dr * invA >> 8;
|
|
79
|
-
const g = sg * sa + dg * invA >> 8;
|
|
80
|
-
const b = sb * sa + db * invA >> 8;
|
|
81
|
-
const a = 255 * sa + da * invA >> 8;
|
|
82
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
83
|
-
};
|
|
84
|
-
var darkenFast = (src, dst) => {
|
|
85
|
-
const sa = src >>> 24 & 255;
|
|
86
|
-
if (sa === 0) return dst;
|
|
87
|
-
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
88
|
-
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
89
|
-
const br = sr < dr ? sr : dr;
|
|
90
|
-
const bg = sg < dg ? sg : dg;
|
|
91
|
-
const bb = sb < db ? sb : db;
|
|
92
|
-
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
93
|
-
const invA = 255 - sa;
|
|
94
|
-
const r = br * sa + dr * invA >> 8;
|
|
95
|
-
const g = bg * sa + dg * invA >> 8;
|
|
96
|
-
const b = bb * sa + db * invA >> 8;
|
|
97
|
-
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
98
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
99
|
-
};
|
|
100
|
-
var multiplyFast = (src, dst) => {
|
|
101
|
-
const sa = src >>> 24 & 255;
|
|
102
|
-
if (sa === 0) return dst;
|
|
103
|
-
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
104
|
-
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
105
|
-
const br = sr * dr >> 8;
|
|
106
|
-
const bg = sg * dg >> 8;
|
|
107
|
-
const bb = sb * db >> 8;
|
|
108
|
-
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
109
|
-
const invA = 255 - sa;
|
|
110
|
-
const da = dst >>> 24 & 255;
|
|
111
|
-
const r = br * sa + dr * invA >> 8;
|
|
112
|
-
const g = bg * sa + dg * invA >> 8;
|
|
113
|
-
const b = bb * sa + db * invA >> 8;
|
|
114
|
-
const a = 255 * sa + da * invA >> 8;
|
|
115
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
116
|
-
};
|
|
117
|
-
var colorBurnFast = (src, dst) => {
|
|
118
|
-
const sa = src >>> 24 & 255;
|
|
119
|
-
if (sa === 0) return dst;
|
|
120
|
-
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
121
|
-
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
122
|
-
const br = dr === 255 ? 255 : sr === 0 ? 0 : Math.max(0, 255 - (255 - dr << 8) / sr | 0);
|
|
123
|
-
const bg = dg === 255 ? 255 : sg === 0 ? 0 : Math.max(0, 255 - (255 - dg << 8) / sg | 0);
|
|
124
|
-
const bb = db === 255 ? 255 : sb === 0 ? 0 : Math.max(0, 255 - (255 - db << 8) / sb | 0);
|
|
125
|
-
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
126
|
-
const invA = 255 - sa;
|
|
127
|
-
const da = dst >>> 24 & 255;
|
|
128
|
-
const r = br * sa + dr * invA >> 8;
|
|
129
|
-
const g = bg * sa + dg * invA >> 8;
|
|
130
|
-
const b = bb * sa + db * invA >> 8;
|
|
131
|
-
const a = 255 * sa + da * invA >> 8;
|
|
132
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
133
|
-
};
|
|
134
|
-
var linearBurnFast = (src, dst) => {
|
|
135
|
-
const sa = src >>> 24 & 255;
|
|
136
|
-
if (sa === 0) return dst;
|
|
137
|
-
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
138
|
-
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
139
|
-
const brU = dr + sr - 255;
|
|
140
|
-
const bgU = dg + sg - 255;
|
|
141
|
-
const bbU = db + sb - 255;
|
|
142
|
-
const br = brU < 0 ? 0 : brU;
|
|
143
|
-
const bg = bgU < 0 ? 0 : bgU;
|
|
144
|
-
const bb = bbU < 0 ? 0 : bbU;
|
|
145
|
-
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
146
|
-
const invA = 255 - sa;
|
|
147
|
-
const r = br * sa + dr * invA >> 8;
|
|
148
|
-
const g = bg * sa + dg * invA >> 8;
|
|
149
|
-
const b = bb * sa + db * invA >> 8;
|
|
150
|
-
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
151
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
152
|
-
};
|
|
153
|
-
var darkerFast = (src, dst) => {
|
|
154
|
-
const sa = src >>> 24 & 255;
|
|
155
|
-
if (sa === 0) return dst;
|
|
156
|
-
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
157
|
-
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
158
|
-
const lumSrc = sr * 77 + sg * 151 + sb * 28;
|
|
159
|
-
const lumDst = dr * 77 + dg * 151 + db * 28;
|
|
160
|
-
let br, bg, bb;
|
|
161
|
-
if (lumSrc < lumDst) {
|
|
162
|
-
br = sr;
|
|
163
|
-
bg = sg;
|
|
164
|
-
bb = sb;
|
|
165
|
-
} else {
|
|
166
|
-
br = dr;
|
|
167
|
-
bg = dg;
|
|
168
|
-
bb = db;
|
|
169
|
-
}
|
|
170
|
-
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
171
|
-
const invA = 255 - sa;
|
|
172
|
-
const r = br * sa + dr * invA >> 8;
|
|
173
|
-
const g = bg * sa + dg * invA >> 8;
|
|
174
|
-
const b = bb * sa + db * invA >> 8;
|
|
175
|
-
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
176
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
177
|
-
};
|
|
178
|
-
var lightenFast = (src, dst) => {
|
|
179
|
-
const sa = src >>> 24 & 255;
|
|
180
|
-
if (sa === 0) return dst;
|
|
181
|
-
const br = Math.max(src & 255, dst & 255);
|
|
182
|
-
const bg = Math.max(src >> 8 & 255, dst >> 8 & 255);
|
|
183
|
-
const bb = Math.max(src >> 16 & 255, dst >> 16 & 255);
|
|
184
|
-
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
185
|
-
const dr = dst & 255;
|
|
186
|
-
const dg = dst >> 8 & 255;
|
|
187
|
-
const db = dst >> 16 & 255;
|
|
188
|
-
const invA = 255 - sa;
|
|
189
|
-
const r = br * sa + dr * invA >> 8;
|
|
190
|
-
const g = bg * sa + dg * invA >> 8;
|
|
191
|
-
const b = bb * sa + db * invA >> 8;
|
|
192
|
-
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
193
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
194
|
-
};
|
|
195
|
-
var screenFast = (src, dst) => {
|
|
196
|
-
const sa = src >>> 24 & 255;
|
|
197
|
-
if (sa === 0) return dst;
|
|
198
|
-
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
199
|
-
const br = 255 - ((255 - (src & 255)) * (255 - dr) >> 8);
|
|
200
|
-
const bg = 255 - ((255 - (src >>> 8 & 255)) * (255 - dg) >> 8);
|
|
201
|
-
const bb = 255 - ((255 - (src >>> 16 & 255)) * (255 - db) >> 8);
|
|
202
|
-
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
203
|
-
const invA = 255 - sa;
|
|
204
|
-
const r = br * sa + dr * invA >> 8;
|
|
205
|
-
const g = bg * sa + dg * invA >> 8;
|
|
206
|
-
const b = bb * sa + db * invA >> 8;
|
|
207
|
-
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
208
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
209
|
-
};
|
|
210
|
-
var colorDodgeFast = (src, dst) => {
|
|
211
|
-
const sa = src >>> 24 & 255;
|
|
212
|
-
if (sa === 0) return dst;
|
|
213
|
-
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
214
|
-
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
215
|
-
const br = sr === 255 ? 255 : Math.min(255, (dr << 8) / (255 - sr) | 0);
|
|
216
|
-
const bg = sg === 255 ? 255 : Math.min(255, (dg << 8) / (255 - sg) | 0);
|
|
217
|
-
const bb = sb === 255 ? 255 : Math.min(255, (db << 8) / (255 - sb) | 0);
|
|
218
|
-
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
219
|
-
const invA = 255 - sa;
|
|
220
|
-
const r = br * sa + dr * invA >> 8;
|
|
221
|
-
const g = bg * sa + dg * invA >> 8;
|
|
222
|
-
const b = bb * sa + db * invA >> 8;
|
|
223
|
-
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
224
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
225
|
-
};
|
|
226
|
-
var linearDodgeFast = (src, dst) => {
|
|
227
|
-
const sa = src >>> 24 & 255;
|
|
228
|
-
if (sa === 0) return dst;
|
|
229
|
-
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
230
|
-
const brU = (src & 255) + dr;
|
|
231
|
-
const bgU = (src >>> 8 & 255) + dg;
|
|
232
|
-
const bbU = (src >>> 16 & 255) + db;
|
|
233
|
-
const br = brU > 255 ? 255 : brU;
|
|
234
|
-
const bg = bgU > 255 ? 255 : bgU;
|
|
235
|
-
const bb = bbU > 255 ? 255 : bbU;
|
|
236
|
-
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
237
|
-
const invA = 255 - sa;
|
|
238
|
-
const r = br * sa + dr * invA >> 8;
|
|
239
|
-
const g = bg * sa + dg * invA >> 8;
|
|
240
|
-
const b = bb * sa + db * invA >> 8;
|
|
241
|
-
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
242
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
243
|
-
};
|
|
244
|
-
var lighterFast = (src, dst) => {
|
|
245
|
-
const sa = src >>> 24 & 255;
|
|
246
|
-
if (sa === 0) return dst;
|
|
247
|
-
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
248
|
-
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
249
|
-
const lumSrc = sr * 77 + sg * 151 + sb * 28;
|
|
250
|
-
const lumDst = dr * 77 + dg * 151 + db * 28;
|
|
251
|
-
let br, bg, bb;
|
|
252
|
-
if (lumSrc > lumDst) {
|
|
253
|
-
br = sr;
|
|
254
|
-
bg = sg;
|
|
255
|
-
bb = sb;
|
|
256
|
-
} else {
|
|
257
|
-
br = dr;
|
|
258
|
-
bg = dg;
|
|
259
|
-
bb = db;
|
|
260
|
-
}
|
|
261
|
-
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
262
|
-
const invA = 255 - sa;
|
|
263
|
-
const r = br * sa + dr * invA >> 8;
|
|
264
|
-
const g = bg * sa + dg * invA >> 8;
|
|
265
|
-
const b = bb * sa + db * invA >> 8;
|
|
266
|
-
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
267
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
268
|
-
};
|
|
269
|
-
var overlayFast = (src, dst) => {
|
|
270
|
-
const sa = src >>> 24 & 255;
|
|
271
|
-
if (sa === 0) return dst;
|
|
272
|
-
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
273
|
-
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
274
|
-
const br = dr < 128 ? 2 * sr * dr >> 8 : 255 - (2 * (255 - sr) * (255 - dr) >> 8);
|
|
275
|
-
const bg = dg < 128 ? 2 * sg * dg >> 8 : 255 - (2 * (255 - sg) * (255 - dg) >> 8);
|
|
276
|
-
const bb = db < 128 ? 2 * sb * db >> 8 : 255 - (2 * (255 - sb) * (255 - db) >> 8);
|
|
277
|
-
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
278
|
-
const invA = 255 - sa;
|
|
279
|
-
const r = br * sa + dr * invA >> 8;
|
|
280
|
-
const g = bg * sa + dg * invA >> 8;
|
|
281
|
-
const b = bb * sa + db * invA >> 8;
|
|
282
|
-
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
283
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
284
|
-
};
|
|
285
|
-
var softLightFast = (src, dst) => {
|
|
286
|
-
const sa = src >>> 24 & 255;
|
|
287
|
-
if (sa === 0) return dst;
|
|
288
|
-
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
289
|
-
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
290
|
-
const br = (255 - dr) * (sr * dr >> 8) + dr * (255 - ((255 - sr) * (255 - dr) >> 8)) >> 8;
|
|
291
|
-
const bg = (255 - dg) * (sg * dg >> 8) + dg * (255 - ((255 - sg) * (255 - dg) >> 8)) >> 8;
|
|
292
|
-
const bb = (255 - db) * (sb * db >> 8) + db * (255 - ((255 - sb) * (255 - db) >> 8)) >> 8;
|
|
293
|
-
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
294
|
-
const invA = 255 - sa;
|
|
295
|
-
const r = br * sa + dr * invA >> 8;
|
|
296
|
-
const g = bg * sa + dg * invA >> 8;
|
|
297
|
-
const b = bb * sa + db * invA >> 8;
|
|
298
|
-
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
299
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
300
|
-
};
|
|
301
|
-
var hardLightFast = (src, dst) => {
|
|
302
|
-
const sa = src >>> 24 & 255;
|
|
303
|
-
if (sa === 0) return dst;
|
|
304
|
-
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
305
|
-
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
306
|
-
const br = sr < 128 ? 2 * sr * dr >> 8 : 255 - (2 * (255 - sr) * (255 - dr) >> 8);
|
|
307
|
-
const bg = sg < 128 ? 2 * sg * dg >> 8 : 255 - (2 * (255 - sg) * (255 - dg) >> 8);
|
|
308
|
-
const bb = sb < 128 ? 2 * sb * db >> 8 : 255 - (2 * (255 - sb) * (255 - db) >> 8);
|
|
309
|
-
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
310
|
-
const invA = 255 - sa;
|
|
311
|
-
const r = br * sa + dr * invA >> 8;
|
|
312
|
-
const g = bg * sa + dg * invA >> 8;
|
|
313
|
-
const b = bb * sa + db * invA >> 8;
|
|
314
|
-
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
315
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
316
|
-
};
|
|
317
|
-
var vividLightFast = (src, dst) => {
|
|
318
|
-
const sa = src >>> 24 & 255;
|
|
319
|
-
if (sa === 0) return dst;
|
|
320
|
-
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
321
|
-
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
322
|
-
const br = sr < 128 ? sr === 0 ? 0 : Math.max(0, 255 - (255 - dr << 8) / (2 * sr) | 0) : sr === 255 ? 255 : Math.min(255, (dr << 8) / (2 * (255 - sr)) | 0);
|
|
323
|
-
const bg = sg < 128 ? sg === 0 ? 0 : Math.max(0, 255 - (255 - dg << 8) / (2 * sg) | 0) : sg === 255 ? 255 : Math.min(255, (dg << 8) / (2 * (255 - sg)) | 0);
|
|
324
|
-
const bb = sb < 128 ? sb === 0 ? 0 : Math.max(0, 255 - (255 - db << 8) / (2 * sb) | 0) : sb === 255 ? 255 : Math.min(255, (db << 8) / (2 * (255 - sb)) | 0);
|
|
325
|
-
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
326
|
-
const invA = 255 - sa;
|
|
327
|
-
const r = br * sa + dr * invA >> 8;
|
|
328
|
-
const g = bg * sa + dg * invA >> 8;
|
|
329
|
-
const b = bb * sa + db * invA >> 8;
|
|
330
|
-
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
331
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
332
|
-
};
|
|
333
|
-
var linearLightFast = (src, dst) => {
|
|
334
|
-
const sa = src >>> 24 & 255;
|
|
335
|
-
if (sa === 0) return dst;
|
|
336
|
-
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
337
|
-
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
338
|
-
const brU = dr + 2 * sr - 255;
|
|
339
|
-
const bgU = dg + 2 * sg - 255;
|
|
340
|
-
const bbU = db + 2 * sb - 255;
|
|
341
|
-
const br = brU < 0 ? 0 : brU > 255 ? 255 : brU;
|
|
342
|
-
const bg = bgU < 0 ? 0 : bgU > 255 ? 255 : bgU;
|
|
343
|
-
const bb = bbU < 0 ? 0 : bbU > 255 ? 255 : bbU;
|
|
344
|
-
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
345
|
-
const invA = 255 - sa;
|
|
346
|
-
const r = br * sa + dr * invA >> 8;
|
|
347
|
-
const g = bg * sa + dg * invA >> 8;
|
|
348
|
-
const b = bb * sa + db * invA >> 8;
|
|
349
|
-
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
350
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
351
|
-
};
|
|
352
|
-
var pinLightFast = (src, dst) => {
|
|
353
|
-
const sa = src >>> 24 & 255;
|
|
354
|
-
if (sa === 0) return dst;
|
|
355
|
-
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
356
|
-
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
357
|
-
const br = sr < 128 ? dr < 2 * sr ? dr : 2 * sr : dr > 2 * sr - 256 ? dr : 2 * sr - 256;
|
|
358
|
-
const bg = sg < 128 ? dg < 2 * sg ? dg : 2 * sg : dg > 2 * sg - 256 ? dg : 2 * sg - 256;
|
|
359
|
-
const bb = sb < 128 ? db < 2 * sb ? db : 2 * sb : db > 2 * sb - 256 ? db : 2 * sb - 256;
|
|
360
|
-
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
361
|
-
const invA = 255 - sa;
|
|
362
|
-
const r = br * sa + dr * invA >> 8;
|
|
363
|
-
const g = bg * sa + dg * invA >> 8;
|
|
364
|
-
const b = bb * sa + db * invA >> 8;
|
|
365
|
-
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
366
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
367
|
-
};
|
|
368
|
-
var hardMixFast = (src, dst) => {
|
|
369
|
-
const sa = src >>> 24 & 255;
|
|
370
|
-
if (sa === 0) return dst;
|
|
371
|
-
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
372
|
-
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
373
|
-
const br = (sr < 128 ? sr === 0 ? 0 : Math.max(0, 255 - (255 - dr << 8) / (2 * sr) | 0) : sr === 255 ? 255 : Math.min(255, (dr << 8) / (2 * (255 - sr)) | 0)) < 128 ? 0 : 255;
|
|
374
|
-
const bg = (sg < 128 ? sg === 0 ? 0 : Math.max(0, 255 - (255 - dg << 8) / (2 * sg) | 0) : sg === 255 ? 255 : Math.min(255, (dg << 8) / (2 * (255 - sg)) | 0)) < 128 ? 0 : 255;
|
|
375
|
-
const bb = (sb < 128 ? sb === 0 ? 0 : Math.max(0, 255 - (255 - db << 8) / (2 * sb) | 0) : sb === 255 ? 255 : Math.min(255, (db << 8) / (2 * (255 - sb)) | 0)) < 128 ? 0 : 255;
|
|
376
|
-
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
377
|
-
const invA = 255 - sa;
|
|
378
|
-
const r = br * sa + dr * invA >> 8;
|
|
379
|
-
const g = bg * sa + dg * invA >> 8;
|
|
380
|
-
const b = bb * sa + db * invA >> 8;
|
|
381
|
-
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
382
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
383
|
-
};
|
|
384
|
-
var differenceFast = (src, dst) => {
|
|
385
|
-
const sa = src >>> 24 & 255;
|
|
386
|
-
if (sa === 0) return dst;
|
|
387
|
-
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
388
|
-
const brD = (src & 255) - dr;
|
|
389
|
-
const bgD = (src >>> 8 & 255) - dg;
|
|
390
|
-
const bbD = (src >>> 16 & 255) - db;
|
|
391
|
-
const br = brD < 0 ? -brD : brD;
|
|
392
|
-
const bg = bgD < 0 ? -bgD : bgD;
|
|
393
|
-
const bb = bbD < 0 ? -bbD : bbD;
|
|
394
|
-
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
395
|
-
const invA = 255 - sa;
|
|
396
|
-
const r = br * sa + dr * invA >> 8;
|
|
397
|
-
const g = bg * sa + dg * invA >> 8;
|
|
398
|
-
const b = bb * sa + db * invA >> 8;
|
|
399
|
-
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
400
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
401
|
-
};
|
|
402
|
-
var exclusionFast = (src, dst) => {
|
|
403
|
-
const sa = src >>> 24 & 255;
|
|
404
|
-
if (sa === 0) return dst;
|
|
405
|
-
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
406
|
-
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
407
|
-
const br = dr + sr - (dr * sr >> 7);
|
|
408
|
-
const bg = dg + sg - (dg * sg >> 7);
|
|
409
|
-
const bb = db + sb - (db * sb >> 7);
|
|
410
|
-
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
411
|
-
const invA = 255 - sa;
|
|
412
|
-
const r = br * sa + dr * invA >> 8;
|
|
413
|
-
const g = bg * sa + dg * invA >> 8;
|
|
414
|
-
const b = bb * sa + db * invA >> 8;
|
|
415
|
-
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
416
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
417
|
-
};
|
|
418
|
-
var subtractFast = (src, dst) => {
|
|
419
|
-
const sa = src >>> 24 & 255;
|
|
420
|
-
if (sa === 0) return dst;
|
|
421
|
-
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
422
|
-
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
423
|
-
const brU = dr - sr;
|
|
424
|
-
const bgU = dg - sg;
|
|
425
|
-
const bbU = db - sb;
|
|
426
|
-
const br = brU < 0 ? 0 : brU;
|
|
427
|
-
const bg = bgU < 0 ? 0 : bgU;
|
|
428
|
-
const bb = bbU < 0 ? 0 : bbU;
|
|
429
|
-
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
430
|
-
const invA = 255 - sa;
|
|
431
|
-
const r = br * sa + dr * invA >> 8;
|
|
432
|
-
const g = bg * sa + dg * invA >> 8;
|
|
433
|
-
const b = bb * sa + db * invA >> 8;
|
|
434
|
-
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
435
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
436
|
-
};
|
|
437
|
-
var divideFast = (src, dst) => {
|
|
438
|
-
const sa = src >>> 24 & 255;
|
|
439
|
-
if (sa === 0) return dst;
|
|
440
|
-
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
441
|
-
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
442
|
-
const br = sr === 0 ? 255 : Math.min(255, (dr << 8) / sr | 0);
|
|
443
|
-
const bg = sg === 0 ? 255 : Math.min(255, (dg << 8) / sg | 0);
|
|
444
|
-
const bb = sb === 0 ? 255 : Math.min(255, (db << 8) / sb | 0);
|
|
445
|
-
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
446
|
-
const invA = 255 - sa;
|
|
447
|
-
const r = br * sa + dr * invA >> 8;
|
|
448
|
-
const g = bg * sa + dg * invA >> 8;
|
|
449
|
-
const b = bb * sa + db * invA >> 8;
|
|
450
|
-
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
451
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
452
|
-
};
|
|
453
|
-
var BASE_FAST_BLEND_MODE_FUNCTIONS = {
|
|
454
|
-
[BaseBlendMode.overwrite]: overwriteFast,
|
|
455
|
-
[BaseBlendMode.sourceOver]: sourceOverFast,
|
|
456
|
-
[BaseBlendMode.darken]: darkenFast,
|
|
457
|
-
[BaseBlendMode.multiply]: multiplyFast,
|
|
458
|
-
[BaseBlendMode.colorBurn]: colorBurnFast,
|
|
459
|
-
[BaseBlendMode.linearBurn]: linearBurnFast,
|
|
460
|
-
[BaseBlendMode.darkerColor]: darkerFast,
|
|
461
|
-
[BaseBlendMode.lighten]: lightenFast,
|
|
462
|
-
[BaseBlendMode.screen]: screenFast,
|
|
463
|
-
[BaseBlendMode.colorDodge]: colorDodgeFast,
|
|
464
|
-
[BaseBlendMode.linearDodge]: linearDodgeFast,
|
|
465
|
-
[BaseBlendMode.lighterColor]: lighterFast,
|
|
466
|
-
[BaseBlendMode.overlay]: overlayFast,
|
|
467
|
-
[BaseBlendMode.softLight]: softLightFast,
|
|
468
|
-
[BaseBlendMode.hardLight]: hardLightFast,
|
|
469
|
-
[BaseBlendMode.vividLight]: vividLightFast,
|
|
470
|
-
[BaseBlendMode.linearLight]: linearLightFast,
|
|
471
|
-
[BaseBlendMode.pinLight]: pinLightFast,
|
|
472
|
-
[BaseBlendMode.hardMix]: hardMixFast,
|
|
473
|
-
[BaseBlendMode.difference]: differenceFast,
|
|
474
|
-
[BaseBlendMode.exclusion]: exclusionFast,
|
|
475
|
-
[BaseBlendMode.subtract]: subtractFast,
|
|
476
|
-
[BaseBlendMode.divide]: divideFast
|
|
477
|
-
};
|
|
478
|
-
function makeFastBlendModeRegistry() {
|
|
479
|
-
return makeBlendModeRegistry(BaseBlendMode, BASE_FAST_BLEND_MODE_FUNCTIONS);
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
// src/_types.ts
|
|
483
|
-
var MaskType = /* @__PURE__ */ ((MaskType2) => {
|
|
484
|
-
MaskType2[MaskType2["ALPHA"] = 0] = "ALPHA";
|
|
485
|
-
MaskType2[MaskType2["BINARY"] = 1] = "BINARY";
|
|
486
|
-
return MaskType2;
|
|
487
|
-
})(MaskType || {});
|
|
488
|
-
|
|
489
|
-
// src/color.ts
|
|
490
|
-
function packColor(r, g, b, a) {
|
|
491
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
492
|
-
}
|
|
493
|
-
function packRGBA({ r, g, b, a }) {
|
|
494
|
-
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
495
|
-
}
|
|
496
|
-
var unpackRed = (packed) => packed >>> 0 & 255;
|
|
497
|
-
var unpackGreen = (packed) => packed >>> 8 & 255;
|
|
498
|
-
var unpackBlue = (packed) => packed >>> 16 & 255;
|
|
499
|
-
var unpackAlpha = (packed) => packed >>> 24 & 255;
|
|
500
|
-
function unpackColor(packed) {
|
|
501
|
-
return {
|
|
502
|
-
r: packed >>> 0 & 255,
|
|
503
|
-
g: packed >>> 8 & 255,
|
|
504
|
-
b: packed >>> 16 & 255,
|
|
505
|
-
a: packed >>> 24 & 255
|
|
506
|
-
};
|
|
507
|
-
}
|
|
508
|
-
var SCRATCH_RGBA = { r: 0, g: 0, b: 0, a: 0 };
|
|
509
|
-
function unpackColorTo(packed, scratch = SCRATCH_RGBA) {
|
|
510
|
-
scratch.r = packed >>> 0 & 255;
|
|
511
|
-
scratch.g = packed >>> 8 & 255;
|
|
512
|
-
scratch.b = packed >>> 16 & 255;
|
|
513
|
-
scratch.a = packed >>> 24 & 255;
|
|
514
|
-
return scratch;
|
|
515
|
-
}
|
|
516
|
-
function colorDistance(a, b) {
|
|
517
|
-
const dr = (a & 255) - (b & 255);
|
|
518
|
-
const dg = (a >>> 8 & 255) - (b >>> 8 & 255);
|
|
519
|
-
const db = (a >>> 16 & 255) - (b >>> 16 & 255);
|
|
520
|
-
const da = (a >>> 24 & 255) - (b >>> 24 & 255);
|
|
521
|
-
return dr * dr + dg * dg + db * db + da * da;
|
|
522
|
-
}
|
|
523
|
-
function lerpColor32(a, b, t) {
|
|
524
|
-
const r = (a & 255) + t * ((b & 255) - (a & 255));
|
|
525
|
-
const g = (a >>> 8 & 255) + t * ((b >>> 8 & 255) - (a >>> 8 & 255));
|
|
526
|
-
const b_ = (a >>> 16 & 255) + t * ((b >>> 16 & 255) - (a >>> 16 & 255));
|
|
527
|
-
const a_ = (a >>> 24 & 255) + t * ((b >>> 24 & 255) - (a >>> 24 & 255));
|
|
528
|
-
return (a_ << 24 | b_ << 16 | g << 8 | r) >>> 0;
|
|
529
|
-
}
|
|
530
|
-
function lerpColor32Fast(src, dst, w) {
|
|
531
|
-
const invA = 255 - w;
|
|
532
|
-
const rb = (src & 16711935) * w + (dst & 16711935) * invA >>> 8 & 16711935;
|
|
533
|
-
const ga = (src >>> 8 & 16711935) * w + (dst >>> 8 & 16711935) * invA >>> 8 & 16711935;
|
|
534
|
-
return (rb | ga << 8) >>> 0;
|
|
535
|
-
}
|
|
536
|
-
function color32ToHex(color) {
|
|
537
|
-
const r = (color & 255).toString(16).padStart(2, "0");
|
|
538
|
-
const g = (color >>> 8 & 255).toString(16).padStart(2, "0");
|
|
539
|
-
const b = (color >>> 16 & 255).toString(16).padStart(2, "0");
|
|
540
|
-
const a = (color >>> 24 & 255).toString(16).padStart(2, "0");
|
|
541
|
-
return `#${r}${g}${b}${a}`;
|
|
542
|
-
}
|
|
543
|
-
function color32ToCssRGBA(color) {
|
|
544
|
-
const r = color & 255;
|
|
545
|
-
const g = color >>> 8 & 255;
|
|
546
|
-
const b = color >>> 16 & 255;
|
|
547
|
-
const a = color >>> 24 & 255;
|
|
548
|
-
const alpha = Number((a / 255).toFixed(3));
|
|
549
|
-
return `rgba(${r},${g},${b},${alpha})`;
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
// src/ImageData/extractImageDataBuffer.ts
|
|
553
|
-
function extractImageDataBuffer(imageData, _x, _y, _w, _h) {
|
|
554
|
-
const { x, y, w, h } = typeof _x === "object" ? _x : { x: _x, y: _y, w: _w, h: _h };
|
|
555
|
-
const { width: srcW, height: srcH, data: src } = imageData;
|
|
556
|
-
if (w <= 0 || h <= 0) return new Uint8ClampedArray(0);
|
|
557
|
-
const out = new Uint8ClampedArray(w * h * 4);
|
|
558
|
-
const x0 = Math.max(0, x);
|
|
559
|
-
const y0 = Math.max(0, y);
|
|
560
|
-
const x1 = Math.min(srcW, x + w);
|
|
561
|
-
const y1 = Math.min(srcH, y + h);
|
|
562
|
-
if (x1 <= x0 || y1 <= y0) return out;
|
|
563
|
-
for (let row = 0; row < y1 - y0; row++) {
|
|
564
|
-
const srcRow = y0 + row;
|
|
565
|
-
const srcStart = (srcRow * srcW + x0) * 4;
|
|
566
|
-
const rowLen = (x1 - x0) * 4;
|
|
567
|
-
const dstRow = y0 - y + row;
|
|
568
|
-
const dstCol = x0 - x;
|
|
569
|
-
const dstStart = (dstRow * w + dstCol) * 4;
|
|
570
|
-
out.set(src.subarray(srcStart, srcStart + rowLen), dstStart);
|
|
571
|
-
}
|
|
572
|
-
return out;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
// src/Mask/extractMask.ts
|
|
576
|
-
function extractMask(mask, maskWidth, xOrRect, y, w, h) {
|
|
577
|
-
let finalX;
|
|
578
|
-
let finalY;
|
|
579
|
-
let finalW;
|
|
580
|
-
let finalH;
|
|
581
|
-
if (typeof xOrRect === "object") {
|
|
582
|
-
finalX = xOrRect.x;
|
|
583
|
-
finalY = xOrRect.y;
|
|
584
|
-
finalW = xOrRect.w;
|
|
585
|
-
finalH = xOrRect.h;
|
|
586
|
-
} else {
|
|
587
|
-
finalX = xOrRect;
|
|
588
|
-
finalY = y;
|
|
589
|
-
finalW = w;
|
|
590
|
-
finalH = h;
|
|
591
|
-
}
|
|
592
|
-
const out = new Uint8Array(finalW * finalH);
|
|
593
|
-
const srcH = mask.length / maskWidth;
|
|
594
|
-
for (let row = 0; row < finalH; row++) {
|
|
595
|
-
const currentSrcY = finalY + row;
|
|
596
|
-
if (currentSrcY < 0 || currentSrcY >= srcH) {
|
|
597
|
-
continue;
|
|
598
|
-
}
|
|
599
|
-
const start = Math.max(0, finalX);
|
|
600
|
-
const end = Math.min(maskWidth, finalX + finalW);
|
|
601
|
-
if (start < end) {
|
|
602
|
-
const srcOffset = currentSrcY * maskWidth + start;
|
|
603
|
-
const dstOffset = row * finalW + (start - finalX);
|
|
604
|
-
const count = end - start;
|
|
605
|
-
out.set(
|
|
606
|
-
mask.subarray(srcOffset, srcOffset + count),
|
|
607
|
-
dstOffset
|
|
608
|
-
);
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
return out;
|
|
232
|
+
return out;
|
|
612
233
|
}
|
|
613
234
|
|
|
614
235
|
// src/Rect/trimRectBounds.ts
|
|
@@ -618,14 +239,8 @@ function trimRectBounds(target, bounds) {
|
|
|
618
239
|
const originalW = target.w;
|
|
619
240
|
const intersectedX = Math.max(target.x, bounds.x);
|
|
620
241
|
const intersectedY = Math.max(target.y, bounds.y);
|
|
621
|
-
const intersectedMaxX = Math.min(
|
|
622
|
-
|
|
623
|
-
bounds.x + bounds.w
|
|
624
|
-
);
|
|
625
|
-
const intersectedMaxY = Math.min(
|
|
626
|
-
target.y + target.h,
|
|
627
|
-
bounds.y + bounds.h
|
|
628
|
-
);
|
|
242
|
+
const intersectedMaxX = Math.min(target.x + target.w, bounds.x + bounds.w);
|
|
243
|
+
const intersectedMaxY = Math.min(target.y + target.h, bounds.y + bounds.h);
|
|
629
244
|
if (intersectedMaxX <= intersectedX || intersectedMaxY <= intersectedY) {
|
|
630
245
|
target.w = 0;
|
|
631
246
|
target.h = 0;
|
|
@@ -643,14 +258,7 @@ function trimRectBounds(target, bounds) {
|
|
|
643
258
|
target.w = intersectedW;
|
|
644
259
|
target.h = intersectedH;
|
|
645
260
|
if ("mask" in target && target.mask) {
|
|
646
|
-
const currentMask = extractMask(
|
|
647
|
-
target.mask,
|
|
648
|
-
originalW,
|
|
649
|
-
offsetX,
|
|
650
|
-
offsetY,
|
|
651
|
-
intersectedW,
|
|
652
|
-
intersectedH
|
|
653
|
-
);
|
|
261
|
+
const currentMask = extractMask(target.mask, originalW, offsetX, offsetY, intersectedW, intersectedH);
|
|
654
262
|
let minX = intersectedW;
|
|
655
263
|
let maxX = -1;
|
|
656
264
|
let minY = intersectedH;
|
|
@@ -674,14 +282,7 @@ function trimRectBounds(target, bounds) {
|
|
|
674
282
|
const finalW = maxX - minX + 1;
|
|
675
283
|
const finalH = maxY - minY + 1;
|
|
676
284
|
if (finalW !== intersectedW || finalH !== intersectedH) {
|
|
677
|
-
target.mask = extractMask(
|
|
678
|
-
currentMask,
|
|
679
|
-
intersectedW,
|
|
680
|
-
minX,
|
|
681
|
-
minY,
|
|
682
|
-
finalW,
|
|
683
|
-
finalH
|
|
684
|
-
);
|
|
285
|
+
target.mask = extractMask(currentMask, intersectedW, minX, minY, finalW, finalH);
|
|
685
286
|
target.x += minX;
|
|
686
287
|
target.y += minY;
|
|
687
288
|
target.w = finalW;
|
|
@@ -704,11 +305,7 @@ function floodFillSelection(img, startX, startY, {
|
|
|
704
305
|
data32 = img.data32;
|
|
705
306
|
imageData = img.imageData;
|
|
706
307
|
} else {
|
|
707
|
-
data32 = new Uint32Array(
|
|
708
|
-
img.data.buffer,
|
|
709
|
-
img.data.byteOffset,
|
|
710
|
-
img.data.byteLength >> 2
|
|
711
|
-
);
|
|
308
|
+
data32 = new Uint32Array(img.data.buffer, img.data.byteOffset, img.data.byteLength >> 2);
|
|
712
309
|
imageData = img;
|
|
713
310
|
}
|
|
714
311
|
const {
|
|
@@ -783,59 +380,537 @@ function floodFillSelection(img, startX, startY, {
|
|
|
783
380
|
}
|
|
784
381
|
}
|
|
785
382
|
} else {
|
|
786
|
-
for (let y = yMin; y <= yMax; y++) {
|
|
787
|
-
for (let x = xMin; x <= xMax; x++) {
|
|
788
|
-
const color = data32[y * width + x];
|
|
789
|
-
if (colorDistance(color, baseColor) <= tolerance) {
|
|
790
|
-
matchX[matchCount] = x;
|
|
791
|
-
matchY[matchCount] = y;
|
|
792
|
-
matchCount++;
|
|
793
|
-
if (x < minX) minX = x;
|
|
794
|
-
if (x > maxX) maxX = x;
|
|
795
|
-
if (y < minY) minY = y;
|
|
796
|
-
if (y > maxY) maxY = y;
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
if (matchCount === 0) {
|
|
802
|
-
return null;
|
|
383
|
+
for (let y = yMin; y <= yMax; y++) {
|
|
384
|
+
for (let x = xMin; x <= xMax; x++) {
|
|
385
|
+
const color = data32[y * width + x];
|
|
386
|
+
if (colorDistance(color, baseColor) <= tolerance) {
|
|
387
|
+
matchX[matchCount] = x;
|
|
388
|
+
matchY[matchCount] = y;
|
|
389
|
+
matchCount++;
|
|
390
|
+
if (x < minX) minX = x;
|
|
391
|
+
if (x > maxX) maxX = x;
|
|
392
|
+
if (y < minY) minY = y;
|
|
393
|
+
if (y > maxY) maxY = y;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
if (matchCount === 0) {
|
|
399
|
+
return null;
|
|
400
|
+
}
|
|
401
|
+
const selectionRect = {
|
|
402
|
+
x: minX,
|
|
403
|
+
y: minY,
|
|
404
|
+
w: maxX - minX + 1,
|
|
405
|
+
h: maxY - minY + 1,
|
|
406
|
+
mask: new Uint8Array((maxX - minX + 1) * (maxY - minY + 1)),
|
|
407
|
+
maskType: 1 /* BINARY */
|
|
408
|
+
};
|
|
409
|
+
const sw = selectionRect.w;
|
|
410
|
+
const sh = selectionRect.h;
|
|
411
|
+
const finalMask = selectionRect.mask;
|
|
412
|
+
for (let i = 0; i < matchCount; i++) {
|
|
413
|
+
const mx = matchX[i] - selectionRect.x;
|
|
414
|
+
const my = matchY[i] - selectionRect.y;
|
|
415
|
+
if (mx >= 0 && mx < sw && my >= 0 && my < sh) {
|
|
416
|
+
finalMask[my * sw + mx] = 1;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
trimRectBounds(selectionRect, {
|
|
420
|
+
x: 0,
|
|
421
|
+
y: 0,
|
|
422
|
+
w: width,
|
|
423
|
+
h: height
|
|
424
|
+
});
|
|
425
|
+
const extracted = extractImageDataBuffer(imageData, selectionRect.x, selectionRect.y, selectionRect.w, selectionRect.h);
|
|
426
|
+
return {
|
|
427
|
+
startX,
|
|
428
|
+
startY,
|
|
429
|
+
selectionRect,
|
|
430
|
+
pixels: extracted
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// src/BlendModes/blend-modes.ts
|
|
435
|
+
var BaseBlendMode = {
|
|
436
|
+
overwrite: 0,
|
|
437
|
+
sourceOver: 1,
|
|
438
|
+
darken: 2,
|
|
439
|
+
multiply: 3,
|
|
440
|
+
colorBurn: 4,
|
|
441
|
+
linearBurn: 5,
|
|
442
|
+
darkerColor: 6,
|
|
443
|
+
lighten: 7,
|
|
444
|
+
screen: 8,
|
|
445
|
+
colorDodge: 9,
|
|
446
|
+
linearDodge: 10,
|
|
447
|
+
lighterColor: 11,
|
|
448
|
+
overlay: 12,
|
|
449
|
+
softLight: 13,
|
|
450
|
+
hardLight: 14,
|
|
451
|
+
vividLight: 15,
|
|
452
|
+
linearLight: 16,
|
|
453
|
+
pinLight: 17,
|
|
454
|
+
hardMix: 18,
|
|
455
|
+
difference: 19,
|
|
456
|
+
exclusion: 20,
|
|
457
|
+
subtract: 21,
|
|
458
|
+
divide: 22
|
|
459
|
+
};
|
|
460
|
+
var overwriteBase = (src, _dst) => src;
|
|
461
|
+
overwriteBase.isOverwrite = true;
|
|
462
|
+
|
|
463
|
+
// src/BlendModes/BlendModeRegistry.ts
|
|
464
|
+
function makeBlendModeRegistry(blendModes, initialEntries, registryName = "anonymous") {
|
|
465
|
+
const blendToName = /* @__PURE__ */ new Map();
|
|
466
|
+
const blendToIndex = /* @__PURE__ */ new Map();
|
|
467
|
+
const indexToName = [];
|
|
468
|
+
const indexToBlend = [];
|
|
469
|
+
const nameToBlend = {};
|
|
470
|
+
const nameToIndex = {};
|
|
471
|
+
const add = (name, index, blendFn) => {
|
|
472
|
+
if (!Number.isFinite(index)) {
|
|
473
|
+
throw new Error(`Index "${index}" is not a number. Attempting to add name: "${name}", index: "${index}"`);
|
|
474
|
+
}
|
|
475
|
+
if (indexToBlend[index]) {
|
|
476
|
+
throw new Error(`Blend Mode index: ${index} is already used. Attempting to add name: "${name}", index: "${index}"`);
|
|
477
|
+
}
|
|
478
|
+
indexToName[index] = name;
|
|
479
|
+
indexToBlend[index] = blendFn;
|
|
480
|
+
blendToIndex.set(blendFn, index);
|
|
481
|
+
blendToName.set(blendFn, name);
|
|
482
|
+
nameToBlend[name] = blendFn;
|
|
483
|
+
nameToIndex[name] = index;
|
|
484
|
+
};
|
|
485
|
+
for (const [name, index] of Object.entries(blendModes)) {
|
|
486
|
+
const blend = initialEntries[index];
|
|
487
|
+
add(name, index, blend);
|
|
488
|
+
}
|
|
489
|
+
return {
|
|
490
|
+
registryName,
|
|
491
|
+
nameToBlend,
|
|
492
|
+
nameToIndex,
|
|
493
|
+
blendToIndex,
|
|
494
|
+
blendToName,
|
|
495
|
+
indexToBlend,
|
|
496
|
+
indexToName,
|
|
497
|
+
indexType: null,
|
|
498
|
+
nameType: null
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// src/BlendModes/blend-modes-fast.ts
|
|
503
|
+
var overwriteFast = overwriteBase;
|
|
504
|
+
var sourceOverFast = (src, dst) => {
|
|
505
|
+
const sa = src >>> 24 & 255;
|
|
506
|
+
if (sa === 255) return src;
|
|
507
|
+
if (sa === 0) return dst;
|
|
508
|
+
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
509
|
+
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
510
|
+
const da = dst >>> 24 & 255;
|
|
511
|
+
const invA = 255 - sa;
|
|
512
|
+
const r = sr * sa + dr * invA >> 8;
|
|
513
|
+
const g = sg * sa + dg * invA >> 8;
|
|
514
|
+
const b = sb * sa + db * invA >> 8;
|
|
515
|
+
const a = 255 * sa + da * invA >> 8;
|
|
516
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
517
|
+
};
|
|
518
|
+
var darkenFast = (src, dst) => {
|
|
519
|
+
const sa = src >>> 24 & 255;
|
|
520
|
+
if (sa === 0) return dst;
|
|
521
|
+
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
522
|
+
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
523
|
+
const br = sr < dr ? sr : dr;
|
|
524
|
+
const bg = sg < dg ? sg : dg;
|
|
525
|
+
const bb = sb < db ? sb : db;
|
|
526
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
527
|
+
const invA = 255 - sa;
|
|
528
|
+
const r = br * sa + dr * invA >> 8;
|
|
529
|
+
const g = bg * sa + dg * invA >> 8;
|
|
530
|
+
const b = bb * sa + db * invA >> 8;
|
|
531
|
+
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
532
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
533
|
+
};
|
|
534
|
+
var multiplyFast = (src, dst) => {
|
|
535
|
+
const sa = src >>> 24 & 255;
|
|
536
|
+
if (sa === 0) return dst;
|
|
537
|
+
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
538
|
+
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
539
|
+
const br = sr * dr >> 8;
|
|
540
|
+
const bg = sg * dg >> 8;
|
|
541
|
+
const bb = sb * db >> 8;
|
|
542
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
543
|
+
const invA = 255 - sa;
|
|
544
|
+
const da = dst >>> 24 & 255;
|
|
545
|
+
const r = br * sa + dr * invA >> 8;
|
|
546
|
+
const g = bg * sa + dg * invA >> 8;
|
|
547
|
+
const b = bb * sa + db * invA >> 8;
|
|
548
|
+
const a = 255 * sa + da * invA >> 8;
|
|
549
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
550
|
+
};
|
|
551
|
+
var colorBurnFast = (src, dst) => {
|
|
552
|
+
const sa = src >>> 24 & 255;
|
|
553
|
+
if (sa === 0) return dst;
|
|
554
|
+
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
555
|
+
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
556
|
+
const br = dr === 255 ? 255 : sr === 0 ? 0 : Math.max(0, 255 - (255 - dr << 8) / sr | 0);
|
|
557
|
+
const bg = dg === 255 ? 255 : sg === 0 ? 0 : Math.max(0, 255 - (255 - dg << 8) / sg | 0);
|
|
558
|
+
const bb = db === 255 ? 255 : sb === 0 ? 0 : Math.max(0, 255 - (255 - db << 8) / sb | 0);
|
|
559
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
560
|
+
const invA = 255 - sa;
|
|
561
|
+
const da = dst >>> 24 & 255;
|
|
562
|
+
const r = br * sa + dr * invA >> 8;
|
|
563
|
+
const g = bg * sa + dg * invA >> 8;
|
|
564
|
+
const b = bb * sa + db * invA >> 8;
|
|
565
|
+
const a = 255 * sa + da * invA >> 8;
|
|
566
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
567
|
+
};
|
|
568
|
+
var linearBurnFast = (src, dst) => {
|
|
569
|
+
const sa = src >>> 24 & 255;
|
|
570
|
+
if (sa === 0) return dst;
|
|
571
|
+
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
572
|
+
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
573
|
+
const brU = dr + sr - 255;
|
|
574
|
+
const bgU = dg + sg - 255;
|
|
575
|
+
const bbU = db + sb - 255;
|
|
576
|
+
const br = brU < 0 ? 0 : brU;
|
|
577
|
+
const bg = bgU < 0 ? 0 : bgU;
|
|
578
|
+
const bb = bbU < 0 ? 0 : bbU;
|
|
579
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
580
|
+
const invA = 255 - sa;
|
|
581
|
+
const r = br * sa + dr * invA >> 8;
|
|
582
|
+
const g = bg * sa + dg * invA >> 8;
|
|
583
|
+
const b = bb * sa + db * invA >> 8;
|
|
584
|
+
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
585
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
586
|
+
};
|
|
587
|
+
var darkerFast = (src, dst) => {
|
|
588
|
+
const sa = src >>> 24 & 255;
|
|
589
|
+
if (sa === 0) return dst;
|
|
590
|
+
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
591
|
+
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
592
|
+
const lumSrc = sr * 77 + sg * 151 + sb * 28;
|
|
593
|
+
const lumDst = dr * 77 + dg * 151 + db * 28;
|
|
594
|
+
let br, bg, bb;
|
|
595
|
+
if (lumSrc < lumDst) {
|
|
596
|
+
br = sr;
|
|
597
|
+
bg = sg;
|
|
598
|
+
bb = sb;
|
|
599
|
+
} else {
|
|
600
|
+
br = dr;
|
|
601
|
+
bg = dg;
|
|
602
|
+
bb = db;
|
|
803
603
|
}
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
const
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
604
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
605
|
+
const invA = 255 - sa;
|
|
606
|
+
const r = br * sa + dr * invA >> 8;
|
|
607
|
+
const g = bg * sa + dg * invA >> 8;
|
|
608
|
+
const b = bb * sa + db * invA >> 8;
|
|
609
|
+
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
610
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
611
|
+
};
|
|
612
|
+
var lightenFast = (src, dst) => {
|
|
613
|
+
const sa = src >>> 24 & 255;
|
|
614
|
+
if (sa === 0) return dst;
|
|
615
|
+
const br = Math.max(src & 255, dst & 255);
|
|
616
|
+
const bg = Math.max(src >> 8 & 255, dst >> 8 & 255);
|
|
617
|
+
const bb = Math.max(src >> 16 & 255, dst >> 16 & 255);
|
|
618
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
619
|
+
const dr = dst & 255;
|
|
620
|
+
const dg = dst >> 8 & 255;
|
|
621
|
+
const db = dst >> 16 & 255;
|
|
622
|
+
const invA = 255 - sa;
|
|
623
|
+
const r = br * sa + dr * invA >> 8;
|
|
624
|
+
const g = bg * sa + dg * invA >> 8;
|
|
625
|
+
const b = bb * sa + db * invA >> 8;
|
|
626
|
+
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
627
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
628
|
+
};
|
|
629
|
+
var screenFast = (src, dst) => {
|
|
630
|
+
const sa = src >>> 24 & 255;
|
|
631
|
+
if (sa === 0) return dst;
|
|
632
|
+
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
633
|
+
const br = 255 - ((255 - (src & 255)) * (255 - dr) >> 8);
|
|
634
|
+
const bg = 255 - ((255 - (src >>> 8 & 255)) * (255 - dg) >> 8);
|
|
635
|
+
const bb = 255 - ((255 - (src >>> 16 & 255)) * (255 - db) >> 8);
|
|
636
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
637
|
+
const invA = 255 - sa;
|
|
638
|
+
const r = br * sa + dr * invA >> 8;
|
|
639
|
+
const g = bg * sa + dg * invA >> 8;
|
|
640
|
+
const b = bb * sa + db * invA >> 8;
|
|
641
|
+
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
642
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
643
|
+
};
|
|
644
|
+
var colorDodgeFast = (src, dst) => {
|
|
645
|
+
const sa = src >>> 24 & 255;
|
|
646
|
+
if (sa === 0) return dst;
|
|
647
|
+
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
648
|
+
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
649
|
+
const br = sr === 255 ? 255 : Math.min(255, (dr << 8) / (255 - sr) | 0);
|
|
650
|
+
const bg = sg === 255 ? 255 : Math.min(255, (dg << 8) / (255 - sg) | 0);
|
|
651
|
+
const bb = sb === 255 ? 255 : Math.min(255, (db << 8) / (255 - sb) | 0);
|
|
652
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
653
|
+
const invA = 255 - sa;
|
|
654
|
+
const r = br * sa + dr * invA >> 8;
|
|
655
|
+
const g = bg * sa + dg * invA >> 8;
|
|
656
|
+
const b = bb * sa + db * invA >> 8;
|
|
657
|
+
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
658
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
659
|
+
};
|
|
660
|
+
var linearDodgeFast = (src, dst) => {
|
|
661
|
+
const sa = src >>> 24 & 255;
|
|
662
|
+
if (sa === 0) return dst;
|
|
663
|
+
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
664
|
+
const brU = (src & 255) + dr;
|
|
665
|
+
const bgU = (src >>> 8 & 255) + dg;
|
|
666
|
+
const bbU = (src >>> 16 & 255) + db;
|
|
667
|
+
const br = brU > 255 ? 255 : brU;
|
|
668
|
+
const bg = bgU > 255 ? 255 : bgU;
|
|
669
|
+
const bb = bbU > 255 ? 255 : bbU;
|
|
670
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
671
|
+
const invA = 255 - sa;
|
|
672
|
+
const r = br * sa + dr * invA >> 8;
|
|
673
|
+
const g = bg * sa + dg * invA >> 8;
|
|
674
|
+
const b = bb * sa + db * invA >> 8;
|
|
675
|
+
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
676
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
677
|
+
};
|
|
678
|
+
var lighterFast = (src, dst) => {
|
|
679
|
+
const sa = src >>> 24 & 255;
|
|
680
|
+
if (sa === 0) return dst;
|
|
681
|
+
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
682
|
+
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
683
|
+
const lumSrc = sr * 77 + sg * 151 + sb * 28;
|
|
684
|
+
const lumDst = dr * 77 + dg * 151 + db * 28;
|
|
685
|
+
let br, bg, bb;
|
|
686
|
+
if (lumSrc > lumDst) {
|
|
687
|
+
br = sr;
|
|
688
|
+
bg = sg;
|
|
689
|
+
bb = sb;
|
|
690
|
+
} else {
|
|
691
|
+
br = dr;
|
|
692
|
+
bg = dg;
|
|
693
|
+
bb = db;
|
|
821
694
|
}
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
const
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
);
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
695
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
696
|
+
const invA = 255 - sa;
|
|
697
|
+
const r = br * sa + dr * invA >> 8;
|
|
698
|
+
const g = bg * sa + dg * invA >> 8;
|
|
699
|
+
const b = bb * sa + db * invA >> 8;
|
|
700
|
+
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
701
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
702
|
+
};
|
|
703
|
+
var overlayFast = (src, dst) => {
|
|
704
|
+
const sa = src >>> 24 & 255;
|
|
705
|
+
if (sa === 0) return dst;
|
|
706
|
+
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
707
|
+
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
708
|
+
const br = dr < 128 ? 2 * sr * dr >> 8 : 255 - (2 * (255 - sr) * (255 - dr) >> 8);
|
|
709
|
+
const bg = dg < 128 ? 2 * sg * dg >> 8 : 255 - (2 * (255 - sg) * (255 - dg) >> 8);
|
|
710
|
+
const bb = db < 128 ? 2 * sb * db >> 8 : 255 - (2 * (255 - sb) * (255 - db) >> 8);
|
|
711
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
712
|
+
const invA = 255 - sa;
|
|
713
|
+
const r = br * sa + dr * invA >> 8;
|
|
714
|
+
const g = bg * sa + dg * invA >> 8;
|
|
715
|
+
const b = bb * sa + db * invA >> 8;
|
|
716
|
+
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
717
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
718
|
+
};
|
|
719
|
+
var softLightFast = (src, dst) => {
|
|
720
|
+
const sa = src >>> 24 & 255;
|
|
721
|
+
if (sa === 0) return dst;
|
|
722
|
+
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
723
|
+
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
724
|
+
const br = (255 - dr) * (sr * dr >> 8) + dr * (255 - ((255 - sr) * (255 - dr) >> 8)) >> 8;
|
|
725
|
+
const bg = (255 - dg) * (sg * dg >> 8) + dg * (255 - ((255 - sg) * (255 - dg) >> 8)) >> 8;
|
|
726
|
+
const bb = (255 - db) * (sb * db >> 8) + db * (255 - ((255 - sb) * (255 - db) >> 8)) >> 8;
|
|
727
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
728
|
+
const invA = 255 - sa;
|
|
729
|
+
const r = br * sa + dr * invA >> 8;
|
|
730
|
+
const g = bg * sa + dg * invA >> 8;
|
|
731
|
+
const b = bb * sa + db * invA >> 8;
|
|
732
|
+
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
733
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
734
|
+
};
|
|
735
|
+
var hardLightFast = (src, dst) => {
|
|
736
|
+
const sa = src >>> 24 & 255;
|
|
737
|
+
if (sa === 0) return dst;
|
|
738
|
+
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
739
|
+
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
740
|
+
const br = sr < 128 ? 2 * sr * dr >> 8 : 255 - (2 * (255 - sr) * (255 - dr) >> 8);
|
|
741
|
+
const bg = sg < 128 ? 2 * sg * dg >> 8 : 255 - (2 * (255 - sg) * (255 - dg) >> 8);
|
|
742
|
+
const bb = sb < 128 ? 2 * sb * db >> 8 : 255 - (2 * (255 - sb) * (255 - db) >> 8);
|
|
743
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
744
|
+
const invA = 255 - sa;
|
|
745
|
+
const r = br * sa + dr * invA >> 8;
|
|
746
|
+
const g = bg * sa + dg * invA >> 8;
|
|
747
|
+
const b = bb * sa + db * invA >> 8;
|
|
748
|
+
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
749
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
750
|
+
};
|
|
751
|
+
var vividLightFast = (src, dst) => {
|
|
752
|
+
const sa = src >>> 24 & 255;
|
|
753
|
+
if (sa === 0) return dst;
|
|
754
|
+
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
755
|
+
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
756
|
+
const br = sr < 128 ? sr === 0 ? 0 : Math.max(0, 255 - (255 - dr << 8) / (2 * sr) | 0) : sr === 255 ? 255 : Math.min(255, (dr << 8) / (2 * (255 - sr)) | 0);
|
|
757
|
+
const bg = sg < 128 ? sg === 0 ? 0 : Math.max(0, 255 - (255 - dg << 8) / (2 * sg) | 0) : sg === 255 ? 255 : Math.min(255, (dg << 8) / (2 * (255 - sg)) | 0);
|
|
758
|
+
const bb = sb < 128 ? sb === 0 ? 0 : Math.max(0, 255 - (255 - db << 8) / (2 * sb) | 0) : sb === 255 ? 255 : Math.min(255, (db << 8) / (2 * (255 - sb)) | 0);
|
|
759
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
760
|
+
const invA = 255 - sa;
|
|
761
|
+
const r = br * sa + dr * invA >> 8;
|
|
762
|
+
const g = bg * sa + dg * invA >> 8;
|
|
763
|
+
const b = bb * sa + db * invA >> 8;
|
|
764
|
+
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
765
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
766
|
+
};
|
|
767
|
+
var linearLightFast = (src, dst) => {
|
|
768
|
+
const sa = src >>> 24 & 255;
|
|
769
|
+
if (sa === 0) return dst;
|
|
770
|
+
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
771
|
+
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
772
|
+
const brU = dr + 2 * sr - 255;
|
|
773
|
+
const bgU = dg + 2 * sg - 255;
|
|
774
|
+
const bbU = db + 2 * sb - 255;
|
|
775
|
+
const br = brU < 0 ? 0 : brU > 255 ? 255 : brU;
|
|
776
|
+
const bg = bgU < 0 ? 0 : bgU > 255 ? 255 : bgU;
|
|
777
|
+
const bb = bbU < 0 ? 0 : bbU > 255 ? 255 : bbU;
|
|
778
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
779
|
+
const invA = 255 - sa;
|
|
780
|
+
const r = br * sa + dr * invA >> 8;
|
|
781
|
+
const g = bg * sa + dg * invA >> 8;
|
|
782
|
+
const b = bb * sa + db * invA >> 8;
|
|
783
|
+
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
784
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
785
|
+
};
|
|
786
|
+
var pinLightFast = (src, dst) => {
|
|
787
|
+
const sa = src >>> 24 & 255;
|
|
788
|
+
if (sa === 0) return dst;
|
|
789
|
+
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
790
|
+
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
791
|
+
const br = sr < 128 ? dr < 2 * sr ? dr : 2 * sr : dr > 2 * sr - 256 ? dr : 2 * sr - 256;
|
|
792
|
+
const bg = sg < 128 ? dg < 2 * sg ? dg : 2 * sg : dg > 2 * sg - 256 ? dg : 2 * sg - 256;
|
|
793
|
+
const bb = sb < 128 ? db < 2 * sb ? db : 2 * sb : db > 2 * sb - 256 ? db : 2 * sb - 256;
|
|
794
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
795
|
+
const invA = 255 - sa;
|
|
796
|
+
const r = br * sa + dr * invA >> 8;
|
|
797
|
+
const g = bg * sa + dg * invA >> 8;
|
|
798
|
+
const b = bb * sa + db * invA >> 8;
|
|
799
|
+
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
800
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
801
|
+
};
|
|
802
|
+
var hardMixFast = (src, dst) => {
|
|
803
|
+
const sa = src >>> 24 & 255;
|
|
804
|
+
if (sa === 0) return dst;
|
|
805
|
+
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
806
|
+
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
807
|
+
const br = (sr < 128 ? sr === 0 ? 0 : Math.max(0, 255 - (255 - dr << 8) / (2 * sr) | 0) : sr === 255 ? 255 : Math.min(255, (dr << 8) / (2 * (255 - sr)) | 0)) < 128 ? 0 : 255;
|
|
808
|
+
const bg = (sg < 128 ? sg === 0 ? 0 : Math.max(0, 255 - (255 - dg << 8) / (2 * sg) | 0) : sg === 255 ? 255 : Math.min(255, (dg << 8) / (2 * (255 - sg)) | 0)) < 128 ? 0 : 255;
|
|
809
|
+
const bb = (sb < 128 ? sb === 0 ? 0 : Math.max(0, 255 - (255 - db << 8) / (2 * sb) | 0) : sb === 255 ? 255 : Math.min(255, (db << 8) / (2 * (255 - sb)) | 0)) < 128 ? 0 : 255;
|
|
810
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
811
|
+
const invA = 255 - sa;
|
|
812
|
+
const r = br * sa + dr * invA >> 8;
|
|
813
|
+
const g = bg * sa + dg * invA >> 8;
|
|
814
|
+
const b = bb * sa + db * invA >> 8;
|
|
815
|
+
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
816
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
817
|
+
};
|
|
818
|
+
var differenceFast = (src, dst) => {
|
|
819
|
+
const sa = src >>> 24 & 255;
|
|
820
|
+
if (sa === 0) return dst;
|
|
821
|
+
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
822
|
+
const brD = (src & 255) - dr;
|
|
823
|
+
const bgD = (src >>> 8 & 255) - dg;
|
|
824
|
+
const bbD = (src >>> 16 & 255) - db;
|
|
825
|
+
const br = brD < 0 ? -brD : brD;
|
|
826
|
+
const bg = bgD < 0 ? -bgD : bgD;
|
|
827
|
+
const bb = bbD < 0 ? -bbD : bbD;
|
|
828
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
829
|
+
const invA = 255 - sa;
|
|
830
|
+
const r = br * sa + dr * invA >> 8;
|
|
831
|
+
const g = bg * sa + dg * invA >> 8;
|
|
832
|
+
const b = bb * sa + db * invA >> 8;
|
|
833
|
+
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
834
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
835
|
+
};
|
|
836
|
+
var exclusionFast = (src, dst) => {
|
|
837
|
+
const sa = src >>> 24 & 255;
|
|
838
|
+
if (sa === 0) return dst;
|
|
839
|
+
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
840
|
+
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
841
|
+
const br = dr + sr - (dr * sr >> 7);
|
|
842
|
+
const bg = dg + sg - (dg * sg >> 7);
|
|
843
|
+
const bb = db + sb - (db * sb >> 7);
|
|
844
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
845
|
+
const invA = 255 - sa;
|
|
846
|
+
const r = br * sa + dr * invA >> 8;
|
|
847
|
+
const g = bg * sa + dg * invA >> 8;
|
|
848
|
+
const b = bb * sa + db * invA >> 8;
|
|
849
|
+
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
850
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
851
|
+
};
|
|
852
|
+
var subtractFast = (src, dst) => {
|
|
853
|
+
const sa = src >>> 24 & 255;
|
|
854
|
+
if (sa === 0) return dst;
|
|
855
|
+
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
856
|
+
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
857
|
+
const brU = dr - sr;
|
|
858
|
+
const bgU = dg - sg;
|
|
859
|
+
const bbU = db - sb;
|
|
860
|
+
const br = brU < 0 ? 0 : brU;
|
|
861
|
+
const bg = bgU < 0 ? 0 : bgU;
|
|
862
|
+
const bb = bbU < 0 ? 0 : bbU;
|
|
863
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
864
|
+
const invA = 255 - sa;
|
|
865
|
+
const r = br * sa + dr * invA >> 8;
|
|
866
|
+
const g = bg * sa + dg * invA >> 8;
|
|
867
|
+
const b = bb * sa + db * invA >> 8;
|
|
868
|
+
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
869
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
870
|
+
};
|
|
871
|
+
var divideFast = (src, dst) => {
|
|
872
|
+
const sa = src >>> 24 & 255;
|
|
873
|
+
if (sa === 0) return dst;
|
|
874
|
+
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
875
|
+
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
876
|
+
const br = sr === 0 ? 255 : Math.min(255, (dr << 8) / sr | 0);
|
|
877
|
+
const bg = sg === 0 ? 255 : Math.min(255, (dg << 8) / sg | 0);
|
|
878
|
+
const bb = sb === 0 ? 255 : Math.min(255, (db << 8) / sb | 0);
|
|
879
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
880
|
+
const invA = 255 - sa;
|
|
881
|
+
const r = br * sa + dr * invA >> 8;
|
|
882
|
+
const g = bg * sa + dg * invA >> 8;
|
|
883
|
+
const b = bb * sa + db * invA >> 8;
|
|
884
|
+
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
885
|
+
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
886
|
+
};
|
|
887
|
+
var BASE_FAST_BLEND_MODE_FUNCTIONS = {
|
|
888
|
+
[BaseBlendMode.overwrite]: overwriteFast,
|
|
889
|
+
[BaseBlendMode.sourceOver]: sourceOverFast,
|
|
890
|
+
[BaseBlendMode.darken]: darkenFast,
|
|
891
|
+
[BaseBlendMode.multiply]: multiplyFast,
|
|
892
|
+
[BaseBlendMode.colorBurn]: colorBurnFast,
|
|
893
|
+
[BaseBlendMode.linearBurn]: linearBurnFast,
|
|
894
|
+
[BaseBlendMode.darkerColor]: darkerFast,
|
|
895
|
+
[BaseBlendMode.lighten]: lightenFast,
|
|
896
|
+
[BaseBlendMode.screen]: screenFast,
|
|
897
|
+
[BaseBlendMode.colorDodge]: colorDodgeFast,
|
|
898
|
+
[BaseBlendMode.linearDodge]: linearDodgeFast,
|
|
899
|
+
[BaseBlendMode.lighterColor]: lighterFast,
|
|
900
|
+
[BaseBlendMode.overlay]: overlayFast,
|
|
901
|
+
[BaseBlendMode.softLight]: softLightFast,
|
|
902
|
+
[BaseBlendMode.hardLight]: hardLightFast,
|
|
903
|
+
[BaseBlendMode.vividLight]: vividLightFast,
|
|
904
|
+
[BaseBlendMode.linearLight]: linearLightFast,
|
|
905
|
+
[BaseBlendMode.pinLight]: pinLightFast,
|
|
906
|
+
[BaseBlendMode.hardMix]: hardMixFast,
|
|
907
|
+
[BaseBlendMode.difference]: differenceFast,
|
|
908
|
+
[BaseBlendMode.exclusion]: exclusionFast,
|
|
909
|
+
[BaseBlendMode.subtract]: subtractFast,
|
|
910
|
+
[BaseBlendMode.divide]: divideFast
|
|
911
|
+
};
|
|
912
|
+
function makeFastBlendModeRegistry(name = "fast") {
|
|
913
|
+
return makeBlendModeRegistry(BaseBlendMode, BASE_FAST_BLEND_MODE_FUNCTIONS, name);
|
|
839
914
|
}
|
|
840
915
|
|
|
841
916
|
// src/BlendModes/blend-modes-perfect.ts
|
|
@@ -844,10 +919,11 @@ var sourceOverPerfect = (src, dst) => {
|
|
|
844
919
|
const sa = src >>> 24 & 255;
|
|
845
920
|
if (sa === 255) return src;
|
|
846
921
|
if (sa === 0) return dst;
|
|
847
|
-
const
|
|
922
|
+
const da = dst >>> 24 & 255;
|
|
923
|
+
if (da === 0) return src;
|
|
848
924
|
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
849
925
|
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
850
|
-
const
|
|
926
|
+
const invA = 255 - sa;
|
|
851
927
|
const tR = sr * sa + dr * invA;
|
|
852
928
|
const r = tR + 1 + (tR >> 8) >> 8;
|
|
853
929
|
const tG = sg * sa + dg * invA;
|
|
@@ -1389,9 +1465,53 @@ var BASE_PERFECT_BLEND_MODE_FUNCTIONS = {
|
|
|
1389
1465
|
[BaseBlendMode.subtract]: subtractPerfect,
|
|
1390
1466
|
[BaseBlendMode.divide]: dividePerfect
|
|
1391
1467
|
};
|
|
1392
|
-
function makePerfectBlendModeRegistry() {
|
|
1393
|
-
return makeBlendModeRegistry(BaseBlendMode, BASE_PERFECT_BLEND_MODE_FUNCTIONS);
|
|
1468
|
+
function makePerfectBlendModeRegistry(name = "perfect") {
|
|
1469
|
+
return makeBlendModeRegistry(BaseBlendMode, BASE_PERFECT_BLEND_MODE_FUNCTIONS, name);
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
// src/BlendModes/toBlendModeIndexAndName.ts
|
|
1473
|
+
function toBlendModeIndexAndName(input) {
|
|
1474
|
+
if (typeof input === "number") {
|
|
1475
|
+
const name = getKeyByValue(BaseBlendMode, input);
|
|
1476
|
+
if (name === void 0) throw new Error(`Invalid index: ${input}`);
|
|
1477
|
+
return {
|
|
1478
|
+
blendIndex: input,
|
|
1479
|
+
blendName: name
|
|
1480
|
+
};
|
|
1481
|
+
}
|
|
1482
|
+
const trimmed = input.trim();
|
|
1483
|
+
const num = Number(trimmed);
|
|
1484
|
+
const isNumeric = trimmed !== "" && !Number.isNaN(num);
|
|
1485
|
+
if (isNumeric && Number.isInteger(num)) {
|
|
1486
|
+
console.log({
|
|
1487
|
+
trimmed,
|
|
1488
|
+
num,
|
|
1489
|
+
isNumeric,
|
|
1490
|
+
isInt: Number.isInteger(num)
|
|
1491
|
+
});
|
|
1492
|
+
const name = getKeyByValue(BaseBlendMode, num);
|
|
1493
|
+
console.log({
|
|
1494
|
+
name
|
|
1495
|
+
});
|
|
1496
|
+
if (name === void 0) throw new Error(`Invalid index: ${num}`);
|
|
1497
|
+
return {
|
|
1498
|
+
blendIndex: num,
|
|
1499
|
+
blendName: name
|
|
1500
|
+
};
|
|
1501
|
+
}
|
|
1502
|
+
if (trimmed in BaseBlendMode) {
|
|
1503
|
+
return {
|
|
1504
|
+
blendIndex: BaseBlendMode[trimmed],
|
|
1505
|
+
blendName: trimmed
|
|
1506
|
+
};
|
|
1507
|
+
}
|
|
1508
|
+
throw new Error(`Invalid blend mode: ${JSON.stringify(input)}`);
|
|
1394
1509
|
}
|
|
1510
|
+
var getKeyByValue = (obj, value) => {
|
|
1511
|
+
for (const key in obj) {
|
|
1512
|
+
if (obj[key] === value) return key;
|
|
1513
|
+
}
|
|
1514
|
+
};
|
|
1395
1515
|
|
|
1396
1516
|
// src/Canvas/_constants.ts
|
|
1397
1517
|
var OFFSCREEN_CANVAS_CTX_FAILED = "Failed to create OffscreenCanvas context";
|
|
@@ -1430,7 +1550,10 @@ function makeReusableCanvas() {
|
|
|
1430
1550
|
} else {
|
|
1431
1551
|
ctx.clearRect(0, 0, width, height);
|
|
1432
1552
|
}
|
|
1433
|
-
return {
|
|
1553
|
+
return {
|
|
1554
|
+
canvas,
|
|
1555
|
+
ctx
|
|
1556
|
+
};
|
|
1434
1557
|
}
|
|
1435
1558
|
get2.reset = () => {
|
|
1436
1559
|
canvas = null;
|
|
@@ -1444,21 +1567,13 @@ async function imgBlobToImageData(blob) {
|
|
|
1444
1567
|
let bitmap = null;
|
|
1445
1568
|
try {
|
|
1446
1569
|
bitmap = await createImageBitmap(blob);
|
|
1447
|
-
const canvas = new OffscreenCanvas(
|
|
1448
|
-
bitmap.width,
|
|
1449
|
-
bitmap.height
|
|
1450
|
-
);
|
|
1570
|
+
const canvas = new OffscreenCanvas(bitmap.width, bitmap.height);
|
|
1451
1571
|
const ctx = canvas.getContext("2d");
|
|
1452
1572
|
if (!ctx) {
|
|
1453
1573
|
throw new Error("Failed to get 2D context");
|
|
1454
1574
|
}
|
|
1455
1575
|
ctx.drawImage(bitmap, 0, 0);
|
|
1456
|
-
return ctx.getImageData(
|
|
1457
|
-
0,
|
|
1458
|
-
0,
|
|
1459
|
-
bitmap.width,
|
|
1460
|
-
bitmap.height
|
|
1461
|
-
);
|
|
1576
|
+
return ctx.getImageData(0, 0, bitmap.width, bitmap.height);
|
|
1462
1577
|
} finally {
|
|
1463
1578
|
bitmap?.close();
|
|
1464
1579
|
}
|
|
@@ -1506,6 +1621,64 @@ async function writeImageDataToClipboard(imageData) {
|
|
|
1506
1621
|
return writeImgBlobToClipboard(blob);
|
|
1507
1622
|
}
|
|
1508
1623
|
|
|
1624
|
+
// src/History/HistoryManager.ts
|
|
1625
|
+
var HistoryManager = class {
|
|
1626
|
+
constructor(maxSteps = 50) {
|
|
1627
|
+
this.maxSteps = maxSteps;
|
|
1628
|
+
this.undoStack = [];
|
|
1629
|
+
this.redoStack = [];
|
|
1630
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
1631
|
+
}
|
|
1632
|
+
undoStack;
|
|
1633
|
+
redoStack;
|
|
1634
|
+
listeners;
|
|
1635
|
+
get canUndo() {
|
|
1636
|
+
return this.undoStack.length > 0;
|
|
1637
|
+
}
|
|
1638
|
+
get canRedo() {
|
|
1639
|
+
return this.redoStack.length > 0;
|
|
1640
|
+
}
|
|
1641
|
+
subscribe(fn) {
|
|
1642
|
+
this.listeners.add(fn);
|
|
1643
|
+
return () => this.listeners.delete(fn);
|
|
1644
|
+
}
|
|
1645
|
+
notify() {
|
|
1646
|
+
this.listeners.forEach((fn) => fn());
|
|
1647
|
+
}
|
|
1648
|
+
commit(action) {
|
|
1649
|
+
this.undoStack.push(action);
|
|
1650
|
+
this.clearRedoStack();
|
|
1651
|
+
if (this.undoStack.length > this.maxSteps) {
|
|
1652
|
+
this.undoStack.shift()?.dispose?.();
|
|
1653
|
+
}
|
|
1654
|
+
this.notify();
|
|
1655
|
+
}
|
|
1656
|
+
undo() {
|
|
1657
|
+
let action = this.undoStack.pop();
|
|
1658
|
+
if (!action) return;
|
|
1659
|
+
this.redoStack.push(action);
|
|
1660
|
+
action.undo();
|
|
1661
|
+
this.notify();
|
|
1662
|
+
}
|
|
1663
|
+
redo() {
|
|
1664
|
+
let action = this.redoStack.pop();
|
|
1665
|
+
if (!action) return;
|
|
1666
|
+
this.undoStack.push(action);
|
|
1667
|
+
action.redo();
|
|
1668
|
+
this.notify();
|
|
1669
|
+
}
|
|
1670
|
+
clearRedoStack() {
|
|
1671
|
+
let length = this.redoStack.length;
|
|
1672
|
+
for (let i = 0; i < length; i++) {
|
|
1673
|
+
let action = this.redoStack[i];
|
|
1674
|
+
if (action) {
|
|
1675
|
+
action.dispose?.();
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
this.redoStack.length = 0;
|
|
1679
|
+
}
|
|
1680
|
+
};
|
|
1681
|
+
|
|
1509
1682
|
// src/History/PixelPatchTiles.ts
|
|
1510
1683
|
var PixelTile = class {
|
|
1511
1684
|
constructor(id, tx, ty, tileArea) {
|
|
@@ -1559,12 +1732,7 @@ var PixelAccumulator = class {
|
|
|
1559
1732
|
tile.ty = ty;
|
|
1560
1733
|
return tile;
|
|
1561
1734
|
}
|
|
1562
|
-
return new PixelTile(
|
|
1563
|
-
id,
|
|
1564
|
-
tx,
|
|
1565
|
-
ty,
|
|
1566
|
-
this.config.tileArea
|
|
1567
|
-
);
|
|
1735
|
+
return new PixelTile(id, tx, ty, this.config.tileArea);
|
|
1568
1736
|
}
|
|
1569
1737
|
recyclePatch(patch) {
|
|
1570
1738
|
const before = patch.beforeTiles;
|
|
@@ -1595,11 +1763,7 @@ var PixelAccumulator = class {
|
|
|
1595
1763
|
let id = ty * columns + tx;
|
|
1596
1764
|
let tile = this.lookup[id];
|
|
1597
1765
|
if (!tile) {
|
|
1598
|
-
tile = this.getTile(
|
|
1599
|
-
id,
|
|
1600
|
-
tx,
|
|
1601
|
-
ty
|
|
1602
|
-
);
|
|
1766
|
+
tile = this.getTile(id, tx, ty);
|
|
1603
1767
|
this.extractState(tile);
|
|
1604
1768
|
this.lookup[id] = tile;
|
|
1605
1769
|
this.beforeTiles.push(tile);
|
|
@@ -1625,11 +1789,7 @@ var PixelAccumulator = class {
|
|
|
1625
1789
|
let id = ty * columns + tx;
|
|
1626
1790
|
let tile = this.lookup[id];
|
|
1627
1791
|
if (!tile) {
|
|
1628
|
-
tile = this.getTile(
|
|
1629
|
-
id,
|
|
1630
|
-
tx,
|
|
1631
|
-
ty
|
|
1632
|
-
);
|
|
1792
|
+
tile = this.getTile(id, tx, ty);
|
|
1633
1793
|
this.extractState(tile);
|
|
1634
1794
|
this.lookup[id] = tile;
|
|
1635
1795
|
this.beforeTiles.push(tile);
|
|
@@ -1656,90 +1816,28 @@ var PixelAccumulator = class {
|
|
|
1656
1816
|
}
|
|
1657
1817
|
let srcIndex = globalY * targetWidth + startX;
|
|
1658
1818
|
let rowData = src.subarray(srcIndex, srcIndex + copyWidth);
|
|
1659
|
-
dst.set(rowData, dstIndex);
|
|
1660
|
-
if (copyWidth < TILE_SIZE) {
|
|
1661
|
-
dst.fill(0, dstIndex + copyWidth, dstIndex + TILE_SIZE);
|
|
1662
|
-
}
|
|
1663
|
-
}
|
|
1664
|
-
}
|
|
1665
|
-
extractAfterTiles() {
|
|
1666
|
-
let afterTiles = [];
|
|
1667
|
-
let length = this.beforeTiles.length;
|
|
1668
|
-
for (let i = 0; i < length; i++) {
|
|
1669
|
-
let beforeTile = this.beforeTiles[i];
|
|
1670
|
-
if (beforeTile) {
|
|
1671
|
-
let afterTile = this.getTile(
|
|
1672
|
-
beforeTile.id,
|
|
1673
|
-
beforeTile.tx,
|
|
1674
|
-
beforeTile.ty
|
|
1675
|
-
);
|
|
1676
|
-
this.extractState(afterTile);
|
|
1677
|
-
afterTiles.push(afterTile);
|
|
1678
|
-
}
|
|
1679
|
-
}
|
|
1680
|
-
return afterTiles;
|
|
1681
|
-
}
|
|
1682
|
-
reset() {
|
|
1683
|
-
this.lookup = [];
|
|
1684
|
-
this.beforeTiles = [];
|
|
1685
|
-
}
|
|
1686
|
-
};
|
|
1687
|
-
|
|
1688
|
-
// src/History/HistoryManager.ts
|
|
1689
|
-
var HistoryManager = class {
|
|
1690
|
-
constructor(maxSteps = 50) {
|
|
1691
|
-
this.maxSteps = maxSteps;
|
|
1692
|
-
this.undoStack = [];
|
|
1693
|
-
this.redoStack = [];
|
|
1694
|
-
this.listeners = /* @__PURE__ */ new Set();
|
|
1695
|
-
}
|
|
1696
|
-
undoStack;
|
|
1697
|
-
redoStack;
|
|
1698
|
-
listeners;
|
|
1699
|
-
get canUndo() {
|
|
1700
|
-
return this.undoStack.length > 0;
|
|
1701
|
-
}
|
|
1702
|
-
get canRedo() {
|
|
1703
|
-
return this.redoStack.length > 0;
|
|
1704
|
-
}
|
|
1705
|
-
subscribe(fn) {
|
|
1706
|
-
this.listeners.add(fn);
|
|
1707
|
-
return () => this.listeners.delete(fn);
|
|
1708
|
-
}
|
|
1709
|
-
notify() {
|
|
1710
|
-
this.listeners.forEach((fn) => fn());
|
|
1711
|
-
}
|
|
1712
|
-
commit(action) {
|
|
1713
|
-
this.undoStack.push(action);
|
|
1714
|
-
this.clearRedoStack();
|
|
1715
|
-
if (this.undoStack.length > this.maxSteps) {
|
|
1716
|
-
this.undoStack.shift()?.dispose?.();
|
|
1717
|
-
}
|
|
1718
|
-
this.notify();
|
|
1719
|
-
}
|
|
1720
|
-
undo() {
|
|
1721
|
-
let action = this.undoStack.pop();
|
|
1722
|
-
if (!action) return;
|
|
1723
|
-
this.redoStack.push(action);
|
|
1724
|
-
action.undo();
|
|
1725
|
-
this.notify();
|
|
1726
|
-
}
|
|
1727
|
-
redo() {
|
|
1728
|
-
let action = this.redoStack.pop();
|
|
1729
|
-
if (!action) return;
|
|
1730
|
-
this.undoStack.push(action);
|
|
1731
|
-
action.redo();
|
|
1732
|
-
this.notify();
|
|
1819
|
+
dst.set(rowData, dstIndex);
|
|
1820
|
+
if (copyWidth < TILE_SIZE) {
|
|
1821
|
+
dst.fill(0, dstIndex + copyWidth, dstIndex + TILE_SIZE);
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1733
1824
|
}
|
|
1734
|
-
|
|
1735
|
-
let
|
|
1825
|
+
extractAfterTiles() {
|
|
1826
|
+
let afterTiles = [];
|
|
1827
|
+
let length = this.beforeTiles.length;
|
|
1736
1828
|
for (let i = 0; i < length; i++) {
|
|
1737
|
-
let
|
|
1738
|
-
if (
|
|
1739
|
-
|
|
1829
|
+
let beforeTile = this.beforeTiles[i];
|
|
1830
|
+
if (beforeTile) {
|
|
1831
|
+
let afterTile = this.getTile(beforeTile.id, beforeTile.tx, beforeTile.ty);
|
|
1832
|
+
this.extractState(afterTile);
|
|
1833
|
+
afterTiles.push(afterTile);
|
|
1740
1834
|
}
|
|
1741
1835
|
}
|
|
1742
|
-
|
|
1836
|
+
return afterTiles;
|
|
1837
|
+
}
|
|
1838
|
+
reset() {
|
|
1839
|
+
this.lookup = [];
|
|
1840
|
+
this.beforeTiles = [];
|
|
1743
1841
|
}
|
|
1744
1842
|
};
|
|
1745
1843
|
|
|
@@ -1760,20 +1858,20 @@ var PixelEngineConfig = class {
|
|
|
1760
1858
|
}
|
|
1761
1859
|
};
|
|
1762
1860
|
|
|
1763
|
-
// src/PixelData/
|
|
1764
|
-
function
|
|
1861
|
+
// src/PixelData/applyAlphaMaskToPixelData.ts
|
|
1862
|
+
function applyAlphaMaskToPixelData(dst, mask, opts = {}) {
|
|
1765
1863
|
const {
|
|
1766
1864
|
x: targetX = 0,
|
|
1767
1865
|
y: targetY = 0,
|
|
1768
1866
|
w: width = dst.width,
|
|
1769
1867
|
h: height = dst.height,
|
|
1770
1868
|
alpha: globalAlpha = 255,
|
|
1771
|
-
maskType = 0 /* ALPHA */,
|
|
1772
1869
|
mw,
|
|
1773
1870
|
mx = 0,
|
|
1774
1871
|
my = 0,
|
|
1775
1872
|
invertMask = false
|
|
1776
1873
|
} = opts;
|
|
1874
|
+
if (globalAlpha === 0) return;
|
|
1777
1875
|
let x = targetX;
|
|
1778
1876
|
let y = targetY;
|
|
1779
1877
|
let w = width;
|
|
@@ -1786,59 +1884,557 @@ function applyMaskToPixelData(dst, mask, opts = {}) {
|
|
|
1786
1884
|
h += y;
|
|
1787
1885
|
y = 0;
|
|
1788
1886
|
}
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
if (
|
|
1887
|
+
w = Math.min(w, dst.width - x);
|
|
1888
|
+
h = Math.min(h, dst.height - y);
|
|
1889
|
+
if (w <= 0) return;
|
|
1890
|
+
if (h <= 0) return;
|
|
1891
|
+
const mPitch = mw ?? width;
|
|
1892
|
+
if (mPitch <= 0) return;
|
|
1893
|
+
const maskHeight = mask.length / mPitch | 0;
|
|
1894
|
+
const startX = mx + (x - targetX);
|
|
1895
|
+
const startY = my + (y - targetY);
|
|
1896
|
+
const sX0 = Math.max(0, startX);
|
|
1897
|
+
const sY0 = Math.max(0, startY);
|
|
1898
|
+
const sX1 = Math.min(mPitch, startX + w);
|
|
1899
|
+
const sY1 = Math.min(maskHeight, startY + h);
|
|
1900
|
+
const finalW = sX1 - sX0;
|
|
1901
|
+
const finalH = sY1 - sY0;
|
|
1902
|
+
if (finalW <= 0) return;
|
|
1903
|
+
if (finalH <= 0) return;
|
|
1904
|
+
const xShift = sX0 - startX;
|
|
1905
|
+
const yShift = sY0 - startY;
|
|
1906
|
+
const dst32 = dst.data32;
|
|
1907
|
+
const dw = dst.width;
|
|
1908
|
+
const dStride = dw - finalW;
|
|
1909
|
+
const mStride = mPitch - finalW;
|
|
1910
|
+
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
1911
|
+
let mIdx = sY0 * mPitch + sX0;
|
|
1912
|
+
for (let iy = 0; iy < h; iy++) {
|
|
1913
|
+
for (let ix = 0; ix < w; ix++) {
|
|
1914
|
+
const mVal = mask[mIdx];
|
|
1915
|
+
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
1916
|
+
let weight = 0;
|
|
1917
|
+
if (effectiveM === 0) {
|
|
1918
|
+
weight = 0;
|
|
1919
|
+
} else if (effectiveM === 255) {
|
|
1920
|
+
weight = globalAlpha;
|
|
1921
|
+
} else if (globalAlpha === 255) {
|
|
1922
|
+
weight = effectiveM;
|
|
1923
|
+
} else {
|
|
1924
|
+
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
1925
|
+
}
|
|
1926
|
+
if (weight === 0) {
|
|
1927
|
+
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
1928
|
+
} else if (weight !== 255) {
|
|
1929
|
+
const d = dst32[dIdx];
|
|
1930
|
+
const da = d >>> 24;
|
|
1931
|
+
if (da !== 0) {
|
|
1932
|
+
const finalAlpha = da === 255 ? weight : da * weight + 128 >> 8;
|
|
1933
|
+
dst32[dIdx] = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
dIdx++;
|
|
1937
|
+
mIdx++;
|
|
1938
|
+
}
|
|
1939
|
+
dIdx += dStride;
|
|
1940
|
+
mIdx += mStride;
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
// src/History/PixelMutator/mutatorApplyAlphaMask.ts
|
|
1945
|
+
var defaults = {
|
|
1946
|
+
applyAlphaMaskToPixelData
|
|
1947
|
+
};
|
|
1948
|
+
var mutatorApplyAlphaMask = ((writer, deps = defaults) => {
|
|
1949
|
+
const {
|
|
1950
|
+
applyAlphaMaskToPixelData: applyAlphaMaskToPixelData2 = defaults.applyAlphaMaskToPixelData
|
|
1951
|
+
} = deps;
|
|
1952
|
+
return {
|
|
1953
|
+
applyAlphaMask: (mask, opts = {}) => {
|
|
1954
|
+
let target = writer.target;
|
|
1955
|
+
const {
|
|
1956
|
+
x = 0,
|
|
1957
|
+
y = 0,
|
|
1958
|
+
w = writer.target.width,
|
|
1959
|
+
h = writer.target.height
|
|
1960
|
+
} = opts;
|
|
1961
|
+
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
1962
|
+
applyAlphaMaskToPixelData2(target, mask, opts);
|
|
1963
|
+
}
|
|
1964
|
+
};
|
|
1965
|
+
});
|
|
1966
|
+
|
|
1967
|
+
// src/PixelData/applyBinaryMaskToPixelData.ts
|
|
1968
|
+
function applyBinaryMaskToPixelData(dst, mask, opts = {}) {
|
|
1969
|
+
const {
|
|
1970
|
+
x: targetX = 0,
|
|
1971
|
+
y: targetY = 0,
|
|
1972
|
+
w: width = dst.width,
|
|
1973
|
+
h: height = dst.height,
|
|
1974
|
+
alpha = 255,
|
|
1975
|
+
mw,
|
|
1976
|
+
mx = 0,
|
|
1977
|
+
my = 0,
|
|
1978
|
+
invertMask = false
|
|
1979
|
+
} = opts;
|
|
1980
|
+
if (alpha === 0) return;
|
|
1981
|
+
let x = targetX;
|
|
1982
|
+
let y = targetY;
|
|
1983
|
+
let w = width;
|
|
1984
|
+
let h = height;
|
|
1985
|
+
if (x < 0) {
|
|
1986
|
+
w += x;
|
|
1987
|
+
x = 0;
|
|
1988
|
+
}
|
|
1989
|
+
if (y < 0) {
|
|
1990
|
+
h += y;
|
|
1991
|
+
y = 0;
|
|
1992
|
+
}
|
|
1993
|
+
w = Math.min(w, dst.width - x);
|
|
1994
|
+
h = Math.min(h, dst.height - y);
|
|
1995
|
+
if (w <= 0) return;
|
|
1996
|
+
if (h <= 0) return;
|
|
1997
|
+
const mPitch = mw ?? width;
|
|
1998
|
+
if (mPitch <= 0) return;
|
|
1999
|
+
const maskHeight = mask.length / mPitch | 0;
|
|
2000
|
+
const startX = mx + (x - targetX);
|
|
2001
|
+
const startY = my + (y - targetY);
|
|
2002
|
+
const sX0 = Math.max(0, startX);
|
|
2003
|
+
const sY0 = Math.max(0, startY);
|
|
2004
|
+
const sX1 = Math.min(mPitch, startX + w);
|
|
2005
|
+
const sY1 = Math.min(maskHeight, startY + h);
|
|
2006
|
+
const finalW = sX1 - sX0;
|
|
2007
|
+
const finalH = sY1 - sY0;
|
|
2008
|
+
if (finalW <= 0) return;
|
|
2009
|
+
if (finalH <= 0) return;
|
|
2010
|
+
const xShift = sX0 - startX;
|
|
2011
|
+
const yShift = sY0 - startY;
|
|
2012
|
+
const dst32 = dst.data32;
|
|
2013
|
+
const dw = dst.width;
|
|
2014
|
+
const dStride = dw - finalW;
|
|
2015
|
+
const mStride = mPitch - finalW;
|
|
2016
|
+
let dIdx = (y + yShift) * dw + (x + xShift);
|
|
2017
|
+
let mIdx = sY0 * mPitch + sX0;
|
|
2018
|
+
for (let iy = 0; iy < h; iy++) {
|
|
2019
|
+
for (let ix = 0; ix < w; ix++) {
|
|
2020
|
+
const mVal = mask[mIdx];
|
|
2021
|
+
const isMaskedOut = invertMask ? mVal !== 0 : mVal === 0;
|
|
2022
|
+
if (isMaskedOut) {
|
|
2023
|
+
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
2024
|
+
} else if (alpha !== 255) {
|
|
2025
|
+
const d = dst32[dIdx];
|
|
2026
|
+
const da = d >>> 24;
|
|
2027
|
+
if (da !== 0) {
|
|
2028
|
+
const finalAlpha = da === 255 ? alpha : da * alpha + 128 >> 8;
|
|
2029
|
+
dst32[dIdx] = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
dIdx++;
|
|
2033
|
+
mIdx++;
|
|
2034
|
+
}
|
|
2035
|
+
dIdx += dStride;
|
|
2036
|
+
mIdx += mStride;
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
|
|
2040
|
+
// src/History/PixelMutator/mutatorApplyBinaryMask.ts
|
|
2041
|
+
var defaults2 = {
|
|
2042
|
+
applyBinaryMaskToPixelData
|
|
2043
|
+
};
|
|
2044
|
+
var mutatorApplyBinaryMask = ((writer, deps = defaults2) => {
|
|
2045
|
+
const {
|
|
2046
|
+
applyBinaryMaskToPixelData: applyBinaryMaskToPixelData2 = defaults2.applyBinaryMaskToPixelData
|
|
2047
|
+
} = deps;
|
|
2048
|
+
return {
|
|
2049
|
+
applyBinaryMask: (mask, opts = {}) => {
|
|
2050
|
+
let target = writer.target;
|
|
2051
|
+
const {
|
|
2052
|
+
x = 0,
|
|
2053
|
+
y = 0,
|
|
2054
|
+
w = writer.target.width,
|
|
2055
|
+
h = writer.target.height
|
|
2056
|
+
} = opts;
|
|
2057
|
+
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2058
|
+
applyBinaryMaskToPixelData2(target, mask, opts);
|
|
2059
|
+
}
|
|
2060
|
+
};
|
|
2061
|
+
});
|
|
2062
|
+
|
|
2063
|
+
// src/Rect/getCircleBrushOrPencilBounds.ts
|
|
2064
|
+
function getCircleBrushOrPencilBounds(centerX, centerY, brushSize, targetWidth, targetHeight, out) {
|
|
2065
|
+
const r = brushSize / 2;
|
|
2066
|
+
const minOffset = -Math.ceil(r - 0.5);
|
|
2067
|
+
const maxOffset = Math.floor(r - 0.5);
|
|
2068
|
+
const startX = Math.floor(centerX + minOffset);
|
|
2069
|
+
const startY = Math.floor(centerY + minOffset);
|
|
2070
|
+
const endX = Math.floor(centerX + maxOffset) + 1;
|
|
2071
|
+
const endY = Math.floor(centerY + maxOffset) + 1;
|
|
2072
|
+
const res = out ?? {
|
|
2073
|
+
x: 0,
|
|
2074
|
+
y: 0,
|
|
2075
|
+
w: 0,
|
|
2076
|
+
h: 0
|
|
2077
|
+
};
|
|
2078
|
+
const cStartX = Math.max(0, startX);
|
|
2079
|
+
const cStartY = Math.max(0, startY);
|
|
2080
|
+
const cEndX = Math.min(targetWidth, endX);
|
|
2081
|
+
const cEndY = Math.min(targetHeight, endY);
|
|
2082
|
+
const w = cEndX - cStartX;
|
|
2083
|
+
const h = cEndY - cStartY;
|
|
2084
|
+
res.x = cStartX;
|
|
2085
|
+
res.y = cStartY;
|
|
2086
|
+
res.w = w < 0 ? 0 : w;
|
|
2087
|
+
res.h = h < 0 ? 0 : h;
|
|
2088
|
+
return res;
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
// src/PixelData/applyCircleBrushToPixelData.ts
|
|
2092
|
+
function applyCircleBrushToPixelData(target, color, centerX, centerY, brushSize, alpha = 255, fallOff, blendFn = sourceOverPerfect, bounds) {
|
|
2093
|
+
const targetWidth = target.width;
|
|
2094
|
+
const targetHeight = target.height;
|
|
2095
|
+
const b = bounds ?? getCircleBrushOrPencilBounds(centerX, centerY, brushSize, targetWidth, targetHeight);
|
|
2096
|
+
if (b.w <= 0 || b.h <= 0) return;
|
|
2097
|
+
const data32 = target.data32;
|
|
2098
|
+
const r = brushSize / 2;
|
|
2099
|
+
const rSqr = r * r;
|
|
2100
|
+
const invR = 1 / r;
|
|
2101
|
+
const centerOffset = brushSize % 2 === 0 ? 0.5 : 0;
|
|
2102
|
+
const endX = b.x + b.w;
|
|
2103
|
+
const endY = b.y + b.h;
|
|
2104
|
+
const fCenterX = Math.floor(centerX);
|
|
2105
|
+
const fCenterY = Math.floor(centerY);
|
|
2106
|
+
const baseSrcAlpha = color >>> 24;
|
|
2107
|
+
const colorRGB = color & 16777215;
|
|
2108
|
+
const isOpaque = alpha === 255;
|
|
2109
|
+
const isOverwrite = blendFn.isOverwrite;
|
|
2110
|
+
for (let cy = b.y; cy < endY; cy++) {
|
|
2111
|
+
const relY = cy - fCenterY + centerOffset;
|
|
2112
|
+
const dySqr = relY * relY;
|
|
2113
|
+
const rowOffset = cy * targetWidth;
|
|
2114
|
+
for (let cx = b.x; cx < endX; cx++) {
|
|
2115
|
+
const relX = cx - fCenterX + centerOffset;
|
|
2116
|
+
const dSqr = relX * relX + dySqr;
|
|
2117
|
+
if (dSqr <= rSqr) {
|
|
2118
|
+
const idx = rowOffset + cx;
|
|
2119
|
+
let weight = alpha;
|
|
2120
|
+
const strength = fallOff(1 - Math.sqrt(dSqr) * invR);
|
|
2121
|
+
const maskVal = strength * 255 | 0;
|
|
2122
|
+
if (maskVal === 0) continue;
|
|
2123
|
+
if (isOpaque) {
|
|
2124
|
+
weight = maskVal;
|
|
2125
|
+
} else if (maskVal !== 255) {
|
|
2126
|
+
weight = maskVal * alpha + 128 >> 8;
|
|
2127
|
+
}
|
|
2128
|
+
let finalCol = color;
|
|
2129
|
+
if (weight < 255) {
|
|
2130
|
+
const a = baseSrcAlpha * weight + 128 >> 8;
|
|
2131
|
+
if (a === 0 && !isOverwrite) continue;
|
|
2132
|
+
finalCol = (colorRGB | a << 24) >>> 0;
|
|
2133
|
+
}
|
|
2134
|
+
data32[idx] = blendFn(finalCol, data32[idx]);
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2140
|
+
// src/History/PixelMutator/mutatorApplyCircleBrush.ts
|
|
2141
|
+
var defaults3 = {
|
|
2142
|
+
applyCircleBrushToPixelData,
|
|
2143
|
+
getCircleBrushOrPencilBounds
|
|
2144
|
+
};
|
|
2145
|
+
var mutatorApplyCircleBrush = ((writer, deps = defaults3) => {
|
|
2146
|
+
const {
|
|
2147
|
+
applyCircleBrushToPixelData: applyCircleBrushToPixelData2 = defaults3.applyCircleBrushToPixelData,
|
|
2148
|
+
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults3.getCircleBrushOrPencilBounds
|
|
2149
|
+
} = deps;
|
|
2150
|
+
const boundsOut = {
|
|
2151
|
+
x: 0,
|
|
2152
|
+
y: 0,
|
|
2153
|
+
w: 0,
|
|
2154
|
+
h: 0
|
|
2155
|
+
};
|
|
2156
|
+
return {
|
|
2157
|
+
applyCircleBrush(color, centerX, centerY, brushSize, alpha = 255, fallOff, blendFn) {
|
|
2158
|
+
const bounds = getCircleBrushOrPencilBounds2(centerX, centerY, brushSize, writer.target.width, writer.target.height, boundsOut);
|
|
2159
|
+
const {
|
|
2160
|
+
x,
|
|
2161
|
+
y,
|
|
2162
|
+
w,
|
|
2163
|
+
h
|
|
2164
|
+
} = bounds;
|
|
2165
|
+
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2166
|
+
applyCircleBrushToPixelData2(writer.target, color, centerX, centerY, brushSize, alpha, fallOff, blendFn, bounds);
|
|
2167
|
+
}
|
|
2168
|
+
};
|
|
2169
|
+
});
|
|
2170
|
+
|
|
2171
|
+
// src/Algorithm/forEachLinePoint.ts
|
|
2172
|
+
function forEachLinePoint(x0, y0, x1, y1, callback) {
|
|
2173
|
+
const dx = x1 - x0;
|
|
2174
|
+
const dy = y1 - y0;
|
|
2175
|
+
const steps = Math.max(Math.abs(dx), Math.abs(dy));
|
|
2176
|
+
if (steps === 0) {
|
|
2177
|
+
callback(x0, y0);
|
|
1792
2178
|
return;
|
|
1793
2179
|
}
|
|
2180
|
+
const xInc = dx / steps;
|
|
2181
|
+
const yInc = dy / steps;
|
|
2182
|
+
let curX = x0;
|
|
2183
|
+
let curY = y0;
|
|
2184
|
+
for (let i = 0; i <= steps; i++) {
|
|
2185
|
+
callback(curX, curY);
|
|
2186
|
+
curX += xInc;
|
|
2187
|
+
curY += yInc;
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2190
|
+
|
|
2191
|
+
// src/PixelData/blendColorPixelDataAlphaMask.ts
|
|
2192
|
+
function blendColorPixelDataAlphaMask(dst, color, mask, opts) {
|
|
2193
|
+
const {
|
|
2194
|
+
x: targetX = 0,
|
|
2195
|
+
y: targetY = 0,
|
|
2196
|
+
w: width = dst.width,
|
|
2197
|
+
h: height = dst.height,
|
|
2198
|
+
alpha: globalAlpha = 255,
|
|
2199
|
+
blendFn = sourceOverPerfect,
|
|
2200
|
+
mw = width,
|
|
2201
|
+
mx = 0,
|
|
2202
|
+
my = 0,
|
|
2203
|
+
invertMask = false
|
|
2204
|
+
} = opts;
|
|
2205
|
+
if (globalAlpha === 0 || !mask) return;
|
|
2206
|
+
const baseSrcAlpha = color >>> 24;
|
|
2207
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
2208
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return;
|
|
2209
|
+
let x = targetX;
|
|
2210
|
+
let y = targetY;
|
|
2211
|
+
let w = width;
|
|
2212
|
+
let h = height;
|
|
2213
|
+
if (x < 0) {
|
|
2214
|
+
w += x;
|
|
2215
|
+
x = 0;
|
|
2216
|
+
}
|
|
2217
|
+
if (y < 0) {
|
|
2218
|
+
h += y;
|
|
2219
|
+
y = 0;
|
|
2220
|
+
}
|
|
2221
|
+
const actualW = Math.min(w, dst.width - x);
|
|
2222
|
+
const actualH = Math.min(h, dst.height - y);
|
|
2223
|
+
if (actualW <= 0 || actualH <= 0) return;
|
|
2224
|
+
const dx = x - targetX | 0;
|
|
2225
|
+
const dy = y - targetY | 0;
|
|
1794
2226
|
const dst32 = dst.data32;
|
|
1795
2227
|
const dw = dst.width;
|
|
1796
|
-
const mPitch = mw
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
const
|
|
1800
|
-
let
|
|
1801
|
-
|
|
1802
|
-
const
|
|
1803
|
-
const mStride = mPitch - actualW;
|
|
2228
|
+
const mPitch = mw;
|
|
2229
|
+
let dIdx = y * dw + x | 0;
|
|
2230
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
2231
|
+
const dStride = dw - actualW | 0;
|
|
2232
|
+
let mStride = mPitch - actualW | 0;
|
|
2233
|
+
const isOpaque = globalAlpha === 255;
|
|
2234
|
+
const colorRGB = color & 16777215;
|
|
1804
2235
|
for (let iy = 0; iy < actualH; iy++) {
|
|
1805
2236
|
for (let ix = 0; ix < actualW; ix++) {
|
|
1806
2237
|
const mVal = mask[mIdx];
|
|
2238
|
+
const effM = invertMask ? 255 - mVal : mVal;
|
|
2239
|
+
if (effM === 0) {
|
|
2240
|
+
dIdx++;
|
|
2241
|
+
mIdx++;
|
|
2242
|
+
continue;
|
|
2243
|
+
}
|
|
1807
2244
|
let weight = globalAlpha;
|
|
1808
|
-
if (
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
}
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
2245
|
+
if (isOpaque) {
|
|
2246
|
+
weight = effM;
|
|
2247
|
+
} else if (effM !== 255) {
|
|
2248
|
+
weight = effM * globalAlpha + 128 >> 8;
|
|
2249
|
+
}
|
|
2250
|
+
if (weight === 0) {
|
|
2251
|
+
dIdx++;
|
|
2252
|
+
mIdx++;
|
|
2253
|
+
continue;
|
|
2254
|
+
}
|
|
2255
|
+
let finalCol = color;
|
|
2256
|
+
if (weight < 255) {
|
|
2257
|
+
const a = baseSrcAlpha * weight + 128 >> 8;
|
|
2258
|
+
if (a === 0 && !isOverwrite) {
|
|
1821
2259
|
dIdx++;
|
|
1822
2260
|
mIdx++;
|
|
1823
2261
|
continue;
|
|
1824
2262
|
}
|
|
1825
|
-
|
|
2263
|
+
finalCol = (colorRGB | a << 24) >>> 0;
|
|
1826
2264
|
}
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
2265
|
+
dst32[dIdx] = blendFn(finalCol, dst32[dIdx]);
|
|
2266
|
+
dIdx++;
|
|
2267
|
+
mIdx++;
|
|
2268
|
+
}
|
|
2269
|
+
dIdx += dStride;
|
|
2270
|
+
mIdx += mStride;
|
|
2271
|
+
}
|
|
2272
|
+
}
|
|
2273
|
+
|
|
2274
|
+
// src/Rect/getCircleBrushOrPencilStrokeBounds.ts
|
|
2275
|
+
function getCircleBrushOrPencilStrokeBounds(x0, y0, x1, y1, brushSize, result) {
|
|
2276
|
+
const r = Math.ceil(brushSize / 2);
|
|
2277
|
+
const minX = Math.min(x0, x1) - r;
|
|
2278
|
+
const minY = Math.min(y0, y1) - r;
|
|
2279
|
+
const maxX = Math.max(x0, x1) + r;
|
|
2280
|
+
const maxY = Math.max(x0, y1) + r;
|
|
2281
|
+
result.x = Math.floor(minX);
|
|
2282
|
+
result.y = Math.floor(minY);
|
|
2283
|
+
result.w = Math.ceil(maxX - minX);
|
|
2284
|
+
result.h = Math.ceil(maxY - minY);
|
|
2285
|
+
return result;
|
|
2286
|
+
}
|
|
2287
|
+
|
|
2288
|
+
// src/History/PixelMutator/mutatorApplyCircleBrushStroke.ts
|
|
2289
|
+
var defaults4 = {
|
|
2290
|
+
forEachLinePoint,
|
|
2291
|
+
blendColorPixelDataAlphaMask,
|
|
2292
|
+
getCircleBrushOrPencilBounds,
|
|
2293
|
+
getCircleBrushOrPencilStrokeBounds
|
|
2294
|
+
};
|
|
2295
|
+
var mutatorApplyCircleBrushStroke = ((writer, deps = defaults4) => {
|
|
2296
|
+
const {
|
|
2297
|
+
forEachLinePoint: forEachLinePoint2 = defaults4.forEachLinePoint,
|
|
2298
|
+
blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults4.blendColorPixelDataAlphaMask,
|
|
2299
|
+
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults4.getCircleBrushOrPencilBounds,
|
|
2300
|
+
getCircleBrushOrPencilStrokeBounds: getCircleBrushOrPencilStrokeBounds2 = defaults4.getCircleBrushOrPencilStrokeBounds
|
|
2301
|
+
} = deps;
|
|
2302
|
+
const strokeBoundsOut = {
|
|
2303
|
+
x: 0,
|
|
2304
|
+
y: 0,
|
|
2305
|
+
w: 0,
|
|
2306
|
+
h: 0
|
|
2307
|
+
};
|
|
2308
|
+
const circleBrushBounds = {
|
|
2309
|
+
x: 0,
|
|
2310
|
+
y: 0,
|
|
2311
|
+
w: 0,
|
|
2312
|
+
h: 0
|
|
2313
|
+
};
|
|
2314
|
+
const blendColorPixelOptions = {
|
|
2315
|
+
alpha: 255,
|
|
2316
|
+
blendFn: sourceOverPerfect,
|
|
2317
|
+
x: 0,
|
|
2318
|
+
y: 0,
|
|
2319
|
+
w: 0,
|
|
2320
|
+
h: 0
|
|
2321
|
+
};
|
|
2322
|
+
return {
|
|
2323
|
+
applyCircleBrushStroke(color, x0, y0, x1, y1, brushSize, alpha = 255, fallOff, blendFn = sourceOverPerfect) {
|
|
2324
|
+
const {
|
|
2325
|
+
x: bx,
|
|
2326
|
+
y: by,
|
|
2327
|
+
w: bw,
|
|
2328
|
+
h: bh
|
|
2329
|
+
} = getCircleBrushOrPencilStrokeBounds2(x0, y0, x1, y1, brushSize, strokeBoundsOut);
|
|
2330
|
+
if (bw <= 0 || bh <= 0) return;
|
|
2331
|
+
const mask = new Uint8Array(bw * bh);
|
|
2332
|
+
const r = brushSize / 2;
|
|
2333
|
+
const rSqr = r * r;
|
|
2334
|
+
const invR = 1 / r;
|
|
2335
|
+
const centerOffset = brushSize % 2 === 0 ? 0.5 : 0;
|
|
2336
|
+
const targetWidth = writer.target.width;
|
|
2337
|
+
const targetHeight = writer.target.height;
|
|
2338
|
+
forEachLinePoint2(x0, y0, x1, y1, (px, py) => {
|
|
2339
|
+
const {
|
|
2340
|
+
x: cbx,
|
|
2341
|
+
y: cby,
|
|
2342
|
+
w: cbw,
|
|
2343
|
+
h: cbh
|
|
2344
|
+
} = getCircleBrushOrPencilBounds2(px, py, brushSize, targetWidth, targetHeight, circleBrushBounds);
|
|
2345
|
+
writer.accumulator.storeRegionBeforeState(cbx, cby, cbw, cbh);
|
|
2346
|
+
const startX = Math.max(bx, cbx);
|
|
2347
|
+
const startY = Math.max(by, cby);
|
|
2348
|
+
const endX = Math.min(bx + bw, cbx + cbw);
|
|
2349
|
+
const endY = Math.min(by + bh, cby + cbh);
|
|
2350
|
+
const fPx = Math.floor(px);
|
|
2351
|
+
const fPy = Math.floor(py);
|
|
2352
|
+
for (let my = startY; my < endY; my++) {
|
|
2353
|
+
const dy = my - fPy + centerOffset;
|
|
2354
|
+
const dySqr = dy * dy;
|
|
2355
|
+
const maskRowOffset = (my - by) * bw;
|
|
2356
|
+
for (let mx = startX; mx < endX; mx++) {
|
|
2357
|
+
const dx = mx - fPx + centerOffset;
|
|
2358
|
+
const dSqr = dx * dx + dySqr;
|
|
2359
|
+
if (dSqr <= rSqr) {
|
|
2360
|
+
const maskIdx = maskRowOffset + (mx - bx);
|
|
2361
|
+
const dist = Math.sqrt(dSqr) * invR;
|
|
2362
|
+
const intensity = fallOff(1 - dist) * 255 | 0;
|
|
2363
|
+
if (intensity > mask[maskIdx]) {
|
|
2364
|
+
mask[maskIdx] = intensity;
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
1839
2368
|
}
|
|
1840
|
-
|
|
2369
|
+
});
|
|
2370
|
+
blendColorPixelOptions.blendFn = blendFn;
|
|
2371
|
+
blendColorPixelOptions.alpha = alpha;
|
|
2372
|
+
blendColorPixelOptions.x = bx;
|
|
2373
|
+
blendColorPixelOptions.y = by;
|
|
2374
|
+
blendColorPixelOptions.w = bw;
|
|
2375
|
+
blendColorPixelOptions.h = bh;
|
|
2376
|
+
blendColorPixelDataAlphaMask2(writer.target, color, mask, blendColorPixelOptions);
|
|
2377
|
+
}
|
|
2378
|
+
};
|
|
2379
|
+
});
|
|
2380
|
+
|
|
2381
|
+
// src/PixelData/blendColorPixelDataBinaryMask.ts
|
|
2382
|
+
function blendColorPixelDataBinaryMask(dst, color, mask, opts = {}) {
|
|
2383
|
+
const {
|
|
2384
|
+
x: targetX = 0,
|
|
2385
|
+
y: targetY = 0,
|
|
2386
|
+
w: width = dst.width,
|
|
2387
|
+
h: height = dst.height,
|
|
2388
|
+
alpha: globalAlpha = 255,
|
|
2389
|
+
blendFn = sourceOverPerfect,
|
|
2390
|
+
mw = width,
|
|
2391
|
+
mx = 0,
|
|
2392
|
+
my = 0,
|
|
2393
|
+
invertMask = false
|
|
2394
|
+
} = opts;
|
|
2395
|
+
if (globalAlpha === 0 || !mask) return;
|
|
2396
|
+
const baseSrcAlpha = color >>> 24;
|
|
2397
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
2398
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return;
|
|
2399
|
+
let x = targetX;
|
|
2400
|
+
let y = targetY;
|
|
2401
|
+
let w = width;
|
|
2402
|
+
let h = height;
|
|
2403
|
+
if (x < 0) {
|
|
2404
|
+
w += x;
|
|
2405
|
+
x = 0;
|
|
2406
|
+
}
|
|
2407
|
+
if (y < 0) {
|
|
2408
|
+
h += y;
|
|
2409
|
+
y = 0;
|
|
2410
|
+
}
|
|
2411
|
+
const actualW = Math.min(w, dst.width - x);
|
|
2412
|
+
const actualH = Math.min(h, dst.height - y);
|
|
2413
|
+
if (actualW <= 0 || actualH <= 0) return;
|
|
2414
|
+
let baseColorWithGlobalAlpha = color;
|
|
2415
|
+
if (globalAlpha < 255) {
|
|
2416
|
+
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
2417
|
+
if (a === 0 && !isOverwrite) return;
|
|
2418
|
+
baseColorWithGlobalAlpha = (color & 16777215 | a << 24) >>> 0;
|
|
2419
|
+
}
|
|
2420
|
+
const dx = x - targetX | 0;
|
|
2421
|
+
const dy = y - targetY | 0;
|
|
2422
|
+
const dst32 = dst.data32;
|
|
2423
|
+
const dw = dst.width;
|
|
2424
|
+
const mPitch = mw;
|
|
2425
|
+
let dIdx = y * dw + x | 0;
|
|
2426
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
2427
|
+
const dStride = dw - actualW | 0;
|
|
2428
|
+
const mStride = mPitch - actualW | 0;
|
|
2429
|
+
const skipVal = invertMask ? 1 : 0;
|
|
2430
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2431
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2432
|
+
if (mask[mIdx] === skipVal) {
|
|
2433
|
+
dIdx++;
|
|
2434
|
+
mIdx++;
|
|
2435
|
+
continue;
|
|
1841
2436
|
}
|
|
2437
|
+
dst32[dIdx] = blendFn(baseColorWithGlobalAlpha, dst32[dIdx]);
|
|
1842
2438
|
dIdx++;
|
|
1843
2439
|
mIdx++;
|
|
1844
2440
|
}
|
|
@@ -1847,63 +2443,424 @@ function applyMaskToPixelData(dst, mask, opts = {}) {
|
|
|
1847
2443
|
}
|
|
1848
2444
|
}
|
|
1849
2445
|
|
|
1850
|
-
// src/History/
|
|
1851
|
-
var
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
mutator;
|
|
1857
|
-
constructor(target, mutatorFactory, {
|
|
1858
|
-
tileSize = 256,
|
|
1859
|
-
maxHistorySteps = 50,
|
|
1860
|
-
historyManager = new HistoryManager(maxHistorySteps)
|
|
1861
|
-
} = {}) {
|
|
1862
|
-
this.target = target;
|
|
1863
|
-
this.config = new PixelEngineConfig(tileSize);
|
|
1864
|
-
this.historyManager = historyManager;
|
|
1865
|
-
this.accumulator = new PixelAccumulator(target, this.config);
|
|
1866
|
-
this.mutator = mutatorFactory(this);
|
|
1867
|
-
}
|
|
1868
|
-
withHistory(cb) {
|
|
1869
|
-
cb(this.mutator);
|
|
1870
|
-
const beforeTiles = this.accumulator.beforeTiles;
|
|
1871
|
-
if (beforeTiles.length === 0) return;
|
|
1872
|
-
const afterTiles = this.accumulator.extractAfterTiles();
|
|
1873
|
-
const patch = {
|
|
1874
|
-
beforeTiles,
|
|
1875
|
-
afterTiles
|
|
1876
|
-
};
|
|
1877
|
-
const target = this.target;
|
|
1878
|
-
const tileSize = this.config.tileSize;
|
|
1879
|
-
const accumulator = this.accumulator;
|
|
1880
|
-
const action = {
|
|
1881
|
-
undo: () => applyPatchTiles(target, patch.beforeTiles, tileSize),
|
|
1882
|
-
redo: () => applyPatchTiles(target, patch.afterTiles, tileSize),
|
|
1883
|
-
dispose: () => accumulator.recyclePatch(patch)
|
|
1884
|
-
};
|
|
1885
|
-
this.historyManager.commit(action);
|
|
1886
|
-
this.accumulator.reset();
|
|
1887
|
-
}
|
|
2446
|
+
// src/History/PixelMutator/mutatorApplyCirclePencilStroke.ts
|
|
2447
|
+
var defaults5 = {
|
|
2448
|
+
forEachLinePoint,
|
|
2449
|
+
blendColorPixelDataBinaryMask,
|
|
2450
|
+
getCircleBrushOrPencilBounds,
|
|
2451
|
+
getCircleBrushOrPencilStrokeBounds
|
|
1888
2452
|
};
|
|
2453
|
+
var mutatorApplyCirclePencilStroke = ((writer, deps = defaults5) => {
|
|
2454
|
+
const {
|
|
2455
|
+
forEachLinePoint: forEachLinePoint2 = defaults5.forEachLinePoint,
|
|
2456
|
+
blendColorPixelDataBinaryMask: blendColorPixelDataBinaryMask2 = defaults5.blendColorPixelDataBinaryMask,
|
|
2457
|
+
getCircleBrushOrPencilStrokeBounds: getCircleBrushOrPencilStrokeBounds2 = defaults5.getCircleBrushOrPencilStrokeBounds,
|
|
2458
|
+
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults5.getCircleBrushOrPencilBounds
|
|
2459
|
+
} = deps;
|
|
2460
|
+
const strokeBoundsOut = {
|
|
2461
|
+
x: 0,
|
|
2462
|
+
y: 0,
|
|
2463
|
+
w: 0,
|
|
2464
|
+
h: 0
|
|
2465
|
+
};
|
|
2466
|
+
const circlePencilBounds = {
|
|
2467
|
+
x: 0,
|
|
2468
|
+
y: 0,
|
|
2469
|
+
w: 0,
|
|
2470
|
+
h: 0
|
|
2471
|
+
};
|
|
2472
|
+
const blendColorPixelOptions = {
|
|
2473
|
+
alpha: 255,
|
|
2474
|
+
blendFn: sourceOverPerfect,
|
|
2475
|
+
x: 0,
|
|
2476
|
+
y: 0,
|
|
2477
|
+
w: 0,
|
|
2478
|
+
h: 0
|
|
2479
|
+
};
|
|
2480
|
+
return {
|
|
2481
|
+
applyCirclePencilStroke(color, x0, y0, x1, y1, brushSize, alpha = 255, blendFn = sourceOverPerfect) {
|
|
2482
|
+
const {
|
|
2483
|
+
x: bx,
|
|
2484
|
+
y: by,
|
|
2485
|
+
w: bw,
|
|
2486
|
+
h: bh
|
|
2487
|
+
} = getCircleBrushOrPencilStrokeBounds2(x0, y0, x1, y1, brushSize, strokeBoundsOut);
|
|
2488
|
+
if (bw <= 0 || bh <= 0) return;
|
|
2489
|
+
const mask = new Uint8Array(bw * bh);
|
|
2490
|
+
const r = brushSize / 2;
|
|
2491
|
+
const rSqr = r * r;
|
|
2492
|
+
const centerOffset = brushSize % 2 === 0 ? 0.5 : 0;
|
|
2493
|
+
const targetWidth = writer.target.width;
|
|
2494
|
+
const targetHeight = writer.target.height;
|
|
2495
|
+
forEachLinePoint2(x0, y0, x1, y1, (px, py) => {
|
|
2496
|
+
const {
|
|
2497
|
+
x: cbx,
|
|
2498
|
+
y: cby,
|
|
2499
|
+
w: cbw,
|
|
2500
|
+
h: cbh
|
|
2501
|
+
} = getCircleBrushOrPencilBounds2(px, py, brushSize, targetWidth, targetHeight, circlePencilBounds);
|
|
2502
|
+
writer.accumulator.storeRegionBeforeState(cbx, cby, cbw, cbh);
|
|
2503
|
+
const startX = Math.max(bx, cbx);
|
|
2504
|
+
const startY = Math.max(by, cby);
|
|
2505
|
+
const endX = Math.min(bx + bw, cbx + cbw);
|
|
2506
|
+
const endY = Math.min(by + bh, cby + cbh);
|
|
2507
|
+
const fPx = Math.floor(px);
|
|
2508
|
+
const fPy = Math.floor(py);
|
|
2509
|
+
for (let my = startY; my < endY; my++) {
|
|
2510
|
+
const dy = my - fPy + centerOffset;
|
|
2511
|
+
const dySqr = dy * dy;
|
|
2512
|
+
const maskRowOffset = (my - by) * bw;
|
|
2513
|
+
for (let mx = startX; mx < endX; mx++) {
|
|
2514
|
+
const dx = mx - fPx + centerOffset;
|
|
2515
|
+
const dSqr = dx * dx + dySqr;
|
|
2516
|
+
if (dSqr <= rSqr) {
|
|
2517
|
+
const maskIdx = maskRowOffset + (mx - bx);
|
|
2518
|
+
mask[maskIdx] = 1;
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
});
|
|
2523
|
+
blendColorPixelOptions.blendFn = blendFn;
|
|
2524
|
+
blendColorPixelOptions.alpha = alpha;
|
|
2525
|
+
blendColorPixelOptions.x = bx;
|
|
2526
|
+
blendColorPixelOptions.y = by;
|
|
2527
|
+
blendColorPixelOptions.w = bw;
|
|
2528
|
+
blendColorPixelOptions.h = bh;
|
|
2529
|
+
blendColorPixelDataBinaryMask2(writer.target, color, mask, blendColorPixelOptions);
|
|
2530
|
+
}
|
|
2531
|
+
};
|
|
2532
|
+
});
|
|
2533
|
+
|
|
2534
|
+
// src/Rect/getRectBrushOrPencilBounds.ts
|
|
2535
|
+
function getRectBrushOrPencilBounds(centerX, centerY, brushWidth, brushHeight, targetWidth, targetHeight, out) {
|
|
2536
|
+
const startX = Math.floor(centerX - brushWidth / 2);
|
|
2537
|
+
const startY = Math.floor(centerY - brushHeight / 2);
|
|
2538
|
+
const endX = startX + brushWidth;
|
|
2539
|
+
const endY = startY + brushHeight;
|
|
2540
|
+
const res = out ?? {
|
|
2541
|
+
x: 0,
|
|
2542
|
+
y: 0,
|
|
2543
|
+
w: 0,
|
|
2544
|
+
h: 0
|
|
2545
|
+
};
|
|
2546
|
+
const cStartX = Math.max(0, startX);
|
|
2547
|
+
const cStartY = Math.max(0, startY);
|
|
2548
|
+
const cEndX = Math.min(targetWidth, endX);
|
|
2549
|
+
const cEndY = Math.min(targetHeight, endY);
|
|
2550
|
+
const w = cEndX - cStartX;
|
|
2551
|
+
const h = cEndY - cStartY;
|
|
2552
|
+
res.x = cStartX;
|
|
2553
|
+
res.y = cStartY;
|
|
2554
|
+
res.w = w < 0 ? 0 : w;
|
|
2555
|
+
res.h = h < 0 ? 0 : h;
|
|
2556
|
+
return res;
|
|
2557
|
+
}
|
|
2558
|
+
|
|
2559
|
+
// src/PixelData/applyRectBrushToPixelData.ts
|
|
2560
|
+
function applyRectBrushToPixelData(target, color, centerX, centerY, brushWidth, brushHeight, alpha = 255, fallOff, blendFn = sourceOverPerfect, bounds) {
|
|
2561
|
+
const targetWidth = target.width;
|
|
2562
|
+
const targetHeight = target.height;
|
|
2563
|
+
const b = bounds ?? getRectBrushOrPencilBounds(centerX, centerY, brushWidth, brushHeight, targetWidth, targetHeight);
|
|
2564
|
+
if (b.w <= 0 || b.h <= 0) return;
|
|
2565
|
+
const data32 = target.data32;
|
|
2566
|
+
const baseColor = color & 16777215;
|
|
2567
|
+
const baseSrcAlpha = color >>> 24;
|
|
2568
|
+
const isOpaque = alpha === 255;
|
|
2569
|
+
const invHalfW = 1 / (brushWidth / 2);
|
|
2570
|
+
const invHalfH = 1 / (brushHeight / 2);
|
|
2571
|
+
const centerOffsetX = brushWidth % 2 === 0 ? 0.5 : 0;
|
|
2572
|
+
const centerOffsetY = brushHeight % 2 === 0 ? 0.5 : 0;
|
|
2573
|
+
const fCenterX = Math.floor(centerX);
|
|
2574
|
+
const fCenterY = Math.floor(centerY);
|
|
2575
|
+
const endX = b.x + b.w;
|
|
2576
|
+
const endY = b.y + b.h;
|
|
2577
|
+
const isOverwrite = blendFn.isOverwrite;
|
|
2578
|
+
for (let py = b.y; py < endY; py++) {
|
|
2579
|
+
const rowOffset = py * targetWidth;
|
|
2580
|
+
const dy = Math.abs(py - fCenterY + centerOffsetY) * invHalfH;
|
|
2581
|
+
for (let px = b.x; px < endX; px++) {
|
|
2582
|
+
const idx = rowOffset + px;
|
|
2583
|
+
const dx = Math.abs(px - fCenterX + centerOffsetX) * invHalfW;
|
|
2584
|
+
const dist = dx > dy ? dx : dy;
|
|
2585
|
+
const strength = fallOff(dist);
|
|
2586
|
+
const maskVal = strength * 255 | 0;
|
|
2587
|
+
if (maskVal <= 0) continue;
|
|
2588
|
+
let weight = alpha;
|
|
2589
|
+
if (isOpaque) {
|
|
2590
|
+
weight = maskVal;
|
|
2591
|
+
} else if (maskVal !== 255) {
|
|
2592
|
+
weight = maskVal * alpha + 128 >> 8;
|
|
2593
|
+
}
|
|
2594
|
+
let finalCol = color;
|
|
2595
|
+
if (weight < 255) {
|
|
2596
|
+
const a = baseSrcAlpha * weight + 128 >> 8;
|
|
2597
|
+
if (a === 0 && !isOverwrite) continue;
|
|
2598
|
+
finalCol = (a << 24 | baseColor) >>> 0;
|
|
2599
|
+
}
|
|
2600
|
+
data32[idx] = blendFn(finalCol, data32[idx]);
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
1889
2604
|
|
|
1890
|
-
// src/History/PixelMutator/
|
|
1891
|
-
|
|
2605
|
+
// src/History/PixelMutator/mutatorApplyRectBrush.ts
|
|
2606
|
+
var defaults6 = {
|
|
2607
|
+
applyRectBrushToPixelData,
|
|
2608
|
+
getRectBrushOrPencilBounds
|
|
2609
|
+
};
|
|
2610
|
+
var mutatorApplyRectBrush = ((writer, deps = defaults6) => {
|
|
2611
|
+
const {
|
|
2612
|
+
applyRectBrushToPixelData: applyRectBrushToPixelData2 = defaults6.applyRectBrushToPixelData,
|
|
2613
|
+
getRectBrushOrPencilBounds: getRectBrushOrPencilBounds2 = defaults6.getRectBrushOrPencilBounds
|
|
2614
|
+
} = deps;
|
|
2615
|
+
const boundsOut = {
|
|
2616
|
+
x: 0,
|
|
2617
|
+
y: 0,
|
|
2618
|
+
w: 0,
|
|
2619
|
+
h: 0
|
|
2620
|
+
};
|
|
1892
2621
|
return {
|
|
1893
|
-
|
|
1894
|
-
|
|
2622
|
+
applyRectBrush(color, centerX, centerY, brushWidth, brushHeight, alpha = 255, fallOff, blendFn) {
|
|
2623
|
+
const bounds = getRectBrushOrPencilBounds2(centerX, centerY, brushWidth, brushHeight, writer.target.width, writer.target.height, boundsOut);
|
|
1895
2624
|
const {
|
|
1896
|
-
x
|
|
1897
|
-
y
|
|
1898
|
-
w
|
|
1899
|
-
h
|
|
1900
|
-
} =
|
|
2625
|
+
x,
|
|
2626
|
+
y,
|
|
2627
|
+
w,
|
|
2628
|
+
h
|
|
2629
|
+
} = bounds;
|
|
1901
2630
|
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
1902
|
-
|
|
2631
|
+
applyRectBrushToPixelData2(writer.target, color, centerX, centerY, brushWidth, brushHeight, alpha, fallOff, blendFn, bounds);
|
|
1903
2632
|
}
|
|
1904
2633
|
};
|
|
2634
|
+
});
|
|
2635
|
+
|
|
2636
|
+
// src/Rect/getRectBrushOrPencilStrokeBounds.ts
|
|
2637
|
+
function getRectBrushOrPencilStrokeBounds(x0, y0, x1, y1, brushWidth, brushHeight, result) {
|
|
2638
|
+
const halfW = brushWidth / 2;
|
|
2639
|
+
const halfH = brushHeight / 2;
|
|
2640
|
+
const minX = Math.min(x0, x1) - halfW;
|
|
2641
|
+
const minY = Math.min(y0, y1) - halfH;
|
|
2642
|
+
const maxX = Math.max(x0, x1) + halfW;
|
|
2643
|
+
const maxY = Math.max(y0, y1) + halfH;
|
|
2644
|
+
result.x = Math.floor(minX);
|
|
2645
|
+
result.y = Math.floor(minY);
|
|
2646
|
+
result.w = Math.ceil(maxX - minX);
|
|
2647
|
+
result.h = Math.ceil(maxY - minY);
|
|
2648
|
+
return result;
|
|
1905
2649
|
}
|
|
1906
2650
|
|
|
2651
|
+
// src/History/PixelMutator/mutatorApplyRectBrushStroke.ts
|
|
2652
|
+
var defaults7 = {
|
|
2653
|
+
forEachLinePoint,
|
|
2654
|
+
blendColorPixelDataAlphaMask,
|
|
2655
|
+
getRectBrushOrPencilBounds,
|
|
2656
|
+
getRectBrushOrPencilStrokeBounds
|
|
2657
|
+
};
|
|
2658
|
+
var mutatorApplyRectBrushStroke = ((writer, deps = defaults7) => {
|
|
2659
|
+
const {
|
|
2660
|
+
forEachLinePoint: forEachLinePoint2 = defaults7.forEachLinePoint,
|
|
2661
|
+
blendColorPixelDataAlphaMask: blendColorPixelDataAlphaMask2 = defaults7.blendColorPixelDataAlphaMask,
|
|
2662
|
+
getRectBrushOrPencilBounds: getRectBrushOrPencilBounds2 = defaults7.getRectBrushOrPencilBounds,
|
|
2663
|
+
getRectBrushOrPencilStrokeBounds: getRectBrushOrPencilStrokeBounds2 = defaults7.getRectBrushOrPencilStrokeBounds
|
|
2664
|
+
} = deps;
|
|
2665
|
+
const strokeBoundsOut = {
|
|
2666
|
+
x: 0,
|
|
2667
|
+
y: 0,
|
|
2668
|
+
w: 0,
|
|
2669
|
+
h: 0
|
|
2670
|
+
};
|
|
2671
|
+
const rectBrushBounds = {
|
|
2672
|
+
x: 0,
|
|
2673
|
+
y: 0,
|
|
2674
|
+
w: 0,
|
|
2675
|
+
h: 0
|
|
2676
|
+
};
|
|
2677
|
+
const blendColorPixelOptions = {
|
|
2678
|
+
alpha: 255,
|
|
2679
|
+
blendFn: sourceOverPerfect,
|
|
2680
|
+
x: 0,
|
|
2681
|
+
y: 0,
|
|
2682
|
+
w: 0,
|
|
2683
|
+
h: 0
|
|
2684
|
+
};
|
|
2685
|
+
return {
|
|
2686
|
+
applyRectBrushStroke(color, x0, y0, x1, y1, brushWidth, brushHeight, alpha = 255, fallOff, blendFn = sourceOverPerfect) {
|
|
2687
|
+
const {
|
|
2688
|
+
x: bx,
|
|
2689
|
+
y: by,
|
|
2690
|
+
w: bw,
|
|
2691
|
+
h: bh
|
|
2692
|
+
} = getRectBrushOrPencilStrokeBounds2(x0, y0, x1, y1, brushWidth, brushHeight, strokeBoundsOut);
|
|
2693
|
+
if (bw <= 0 || bh <= 0) return;
|
|
2694
|
+
const mask = new Uint8Array(bw * bh);
|
|
2695
|
+
const halfW = brushWidth / 2;
|
|
2696
|
+
const halfH = brushHeight / 2;
|
|
2697
|
+
const invHalfW = 1 / halfW;
|
|
2698
|
+
const invHalfH = 1 / halfH;
|
|
2699
|
+
const centerOffsetX = brushWidth % 2 === 0 ? 0.5 : 0;
|
|
2700
|
+
const centerOffsetY = brushHeight % 2 === 0 ? 0.5 : 0;
|
|
2701
|
+
const targetWidth = writer.target.width;
|
|
2702
|
+
const targetHeight = writer.target.height;
|
|
2703
|
+
forEachLinePoint2(x0, y0, x1, y1, (px, py) => {
|
|
2704
|
+
const {
|
|
2705
|
+
x: rbx,
|
|
2706
|
+
y: rby,
|
|
2707
|
+
w: rbw,
|
|
2708
|
+
h: rbh
|
|
2709
|
+
} = getRectBrushOrPencilBounds2(px, py, brushWidth, brushHeight, targetWidth, targetHeight, rectBrushBounds);
|
|
2710
|
+
writer.accumulator.storeRegionBeforeState(rbx, rby, rbw, rbh);
|
|
2711
|
+
const startX = Math.max(bx, rbx);
|
|
2712
|
+
const startY = Math.max(by, rby);
|
|
2713
|
+
const endX = Math.min(bx + bw, rbx + rbw);
|
|
2714
|
+
const endY = Math.min(by + bh, rby + rbh);
|
|
2715
|
+
const fPx = Math.floor(px);
|
|
2716
|
+
const fPy = Math.floor(py);
|
|
2717
|
+
for (let my = startY; my < endY; my++) {
|
|
2718
|
+
const dy = Math.abs(my - fPy + centerOffsetY) * invHalfH;
|
|
2719
|
+
const maskRowOffset = (my - by) * bw;
|
|
2720
|
+
for (let mx = startX; mx < endX; mx++) {
|
|
2721
|
+
const dx = Math.abs(mx - fPx + centerOffsetX) * invHalfW;
|
|
2722
|
+
const maskIdx = maskRowOffset + (mx - bx);
|
|
2723
|
+
const dist = dx > dy ? dx : dy;
|
|
2724
|
+
const strength = fallOff(dist);
|
|
2725
|
+
if (strength > 0) {
|
|
2726
|
+
const intensity = strength * 255 | 0;
|
|
2727
|
+
if (intensity > mask[maskIdx]) {
|
|
2728
|
+
mask[maskIdx] = intensity;
|
|
2729
|
+
}
|
|
2730
|
+
}
|
|
2731
|
+
}
|
|
2732
|
+
}
|
|
2733
|
+
});
|
|
2734
|
+
blendColorPixelOptions.blendFn = blendFn;
|
|
2735
|
+
blendColorPixelOptions.alpha = alpha;
|
|
2736
|
+
blendColorPixelOptions.x = bx;
|
|
2737
|
+
blendColorPixelOptions.y = by;
|
|
2738
|
+
blendColorPixelOptions.w = bw;
|
|
2739
|
+
blendColorPixelOptions.h = bh;
|
|
2740
|
+
blendColorPixelDataAlphaMask2(writer.target, color, mask, blendColorPixelOptions);
|
|
2741
|
+
}
|
|
2742
|
+
};
|
|
2743
|
+
});
|
|
2744
|
+
|
|
2745
|
+
// src/History/PixelMutator/mutatorApplyRectPencil.ts
|
|
2746
|
+
var defaults8 = {
|
|
2747
|
+
applyRectBrushToPixelData,
|
|
2748
|
+
getRectBrushOrPencilBounds,
|
|
2749
|
+
fallOff: () => 1
|
|
2750
|
+
};
|
|
2751
|
+
var mutatorApplyRectPencil = ((writer, deps = defaults8) => {
|
|
2752
|
+
const {
|
|
2753
|
+
applyRectBrushToPixelData: applyRectBrushToPixelData2 = defaults8.applyRectBrushToPixelData,
|
|
2754
|
+
getRectBrushOrPencilBounds: getRectBrushOrPencilBounds2 = defaults8.getRectBrushOrPencilBounds,
|
|
2755
|
+
fallOff = defaults8.fallOff
|
|
2756
|
+
} = deps;
|
|
2757
|
+
const boundsOut = {
|
|
2758
|
+
x: 0,
|
|
2759
|
+
y: 0,
|
|
2760
|
+
w: 0,
|
|
2761
|
+
h: 0
|
|
2762
|
+
};
|
|
2763
|
+
return {
|
|
2764
|
+
applyRectPencil(color, centerX, centerY, brushWidth, brushHeight, alpha = 255, blendFn) {
|
|
2765
|
+
const bounds = getRectBrushOrPencilBounds2(centerX, centerY, brushWidth, brushHeight, writer.target.width, writer.target.height, boundsOut);
|
|
2766
|
+
const {
|
|
2767
|
+
x,
|
|
2768
|
+
y,
|
|
2769
|
+
w,
|
|
2770
|
+
h
|
|
2771
|
+
} = bounds;
|
|
2772
|
+
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2773
|
+
applyRectBrushToPixelData2(writer.target, color, centerX, centerY, brushWidth, brushHeight, alpha, fallOff, blendFn, bounds);
|
|
2774
|
+
}
|
|
2775
|
+
};
|
|
2776
|
+
});
|
|
2777
|
+
|
|
2778
|
+
// src/History/PixelMutator/mutatorApplyRectPencilStroke.ts
|
|
2779
|
+
var defaults9 = {
|
|
2780
|
+
forEachLinePoint,
|
|
2781
|
+
getRectBrushOrPencilBounds,
|
|
2782
|
+
getRectBrushOrPencilStrokeBounds,
|
|
2783
|
+
blendColorPixelDataBinaryMask
|
|
2784
|
+
};
|
|
2785
|
+
var mutatorApplyRectPencilStroke = ((writer, deps = defaults9) => {
|
|
2786
|
+
const {
|
|
2787
|
+
forEachLinePoint: forEachLinePoint2 = defaults9.forEachLinePoint,
|
|
2788
|
+
blendColorPixelDataBinaryMask: blendColorPixelDataBinaryMask2 = defaults9.blendColorPixelDataBinaryMask,
|
|
2789
|
+
getRectBrushOrPencilBounds: getRectBrushOrPencilBounds2 = defaults9.getRectBrushOrPencilBounds,
|
|
2790
|
+
getRectBrushOrPencilStrokeBounds: getRectBrushOrPencilStrokeBounds2 = defaults9.getRectBrushOrPencilStrokeBounds
|
|
2791
|
+
} = deps;
|
|
2792
|
+
const strokeBoundsOut = {
|
|
2793
|
+
x: 0,
|
|
2794
|
+
y: 0,
|
|
2795
|
+
w: 0,
|
|
2796
|
+
h: 0
|
|
2797
|
+
};
|
|
2798
|
+
const rectPencilBounds = {
|
|
2799
|
+
x: 0,
|
|
2800
|
+
y: 0,
|
|
2801
|
+
w: 0,
|
|
2802
|
+
h: 0
|
|
2803
|
+
};
|
|
2804
|
+
const blendColorPixelOptions = {
|
|
2805
|
+
alpha: 255,
|
|
2806
|
+
blendFn: sourceOverPerfect,
|
|
2807
|
+
x: 0,
|
|
2808
|
+
y: 0,
|
|
2809
|
+
w: 0,
|
|
2810
|
+
h: 0
|
|
2811
|
+
};
|
|
2812
|
+
return {
|
|
2813
|
+
applyRectPencilStroke(color, x0, y0, x1, y1, brushWidth, brushHeight, alpha = 255, blendFn = sourceOverPerfect) {
|
|
2814
|
+
const {
|
|
2815
|
+
x: bx,
|
|
2816
|
+
y: by,
|
|
2817
|
+
w: bw,
|
|
2818
|
+
h: bh
|
|
2819
|
+
} = getRectBrushOrPencilStrokeBounds2(x0, y0, x1, y1, brushWidth, brushHeight, strokeBoundsOut);
|
|
2820
|
+
if (bw <= 0 || bh <= 0) return;
|
|
2821
|
+
const mask = new Uint8Array(bw * bh);
|
|
2822
|
+
const halfW = brushWidth / 2;
|
|
2823
|
+
const halfH = brushHeight / 2;
|
|
2824
|
+
const centerOffset = brushWidth % 2 === 0 ? 0.5 : 0;
|
|
2825
|
+
const targetWidth = writer.target.width;
|
|
2826
|
+
const targetHeight = writer.target.height;
|
|
2827
|
+
forEachLinePoint2(x0, y0, x1, y1, (px, py) => {
|
|
2828
|
+
const {
|
|
2829
|
+
x: rbx,
|
|
2830
|
+
y: rby,
|
|
2831
|
+
w: rbw,
|
|
2832
|
+
h: rbh
|
|
2833
|
+
} = getRectBrushOrPencilBounds2(px, py, brushWidth, brushHeight, targetWidth, targetHeight, rectPencilBounds);
|
|
2834
|
+
writer.accumulator.storeRegionBeforeState(rbx, rby, rbw, rbh);
|
|
2835
|
+
const startX = Math.max(bx, rbx);
|
|
2836
|
+
const startY = Math.max(by, rby);
|
|
2837
|
+
const endX = Math.min(bx + bw, rbx + rbw);
|
|
2838
|
+
const endY = Math.min(by + bh, rby + rbh);
|
|
2839
|
+
const fPx = Math.floor(px);
|
|
2840
|
+
const fPy = Math.floor(py);
|
|
2841
|
+
for (let my = startY; my < endY; my++) {
|
|
2842
|
+
const dy = Math.abs(my - fPy + centerOffset);
|
|
2843
|
+
const maskRowOffset = (my - by) * bw;
|
|
2844
|
+
for (let mx = startX; mx < endX; mx++) {
|
|
2845
|
+
const dx = Math.abs(mx - fPx + centerOffset);
|
|
2846
|
+
const maskIdx = maskRowOffset + (mx - bx);
|
|
2847
|
+
if (dx <= halfW && dy <= halfH) {
|
|
2848
|
+
mask[maskIdx] = 1;
|
|
2849
|
+
}
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
});
|
|
2853
|
+
blendColorPixelOptions.blendFn = blendFn;
|
|
2854
|
+
blendColorPixelOptions.alpha = alpha;
|
|
2855
|
+
blendColorPixelOptions.x = bx;
|
|
2856
|
+
blendColorPixelOptions.y = by;
|
|
2857
|
+
blendColorPixelOptions.w = bw;
|
|
2858
|
+
blendColorPixelOptions.h = bh;
|
|
2859
|
+
blendColorPixelDataBinaryMask2(writer.target, color, mask, blendColorPixelOptions);
|
|
2860
|
+
}
|
|
2861
|
+
};
|
|
2862
|
+
});
|
|
2863
|
+
|
|
1907
2864
|
// src/PixelData/blendColorPixelData.ts
|
|
1908
2865
|
function blendColorPixelData(dst, color, opts = {}) {
|
|
1909
2866
|
const {
|
|
@@ -1912,22 +2869,13 @@ function blendColorPixelData(dst, color, opts = {}) {
|
|
|
1912
2869
|
w: width = dst.width,
|
|
1913
2870
|
h: height = dst.height,
|
|
1914
2871
|
alpha: globalAlpha = 255,
|
|
1915
|
-
blendFn =
|
|
1916
|
-
mask,
|
|
1917
|
-
maskType = 0 /* ALPHA */,
|
|
1918
|
-
mw,
|
|
1919
|
-
mx = 0,
|
|
1920
|
-
my = 0,
|
|
1921
|
-
invertMask = false
|
|
2872
|
+
blendFn = sourceOverPerfect
|
|
1922
2873
|
} = opts;
|
|
1923
2874
|
if (globalAlpha === 0) return;
|
|
1924
2875
|
const baseSrcAlpha = color >>> 24;
|
|
1925
|
-
const isOverwrite = blendFn.isOverwrite;
|
|
2876
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
1926
2877
|
if (baseSrcAlpha === 0 && !isOverwrite) return;
|
|
1927
|
-
let x = targetX;
|
|
1928
|
-
let y = targetY;
|
|
1929
|
-
let w = width;
|
|
1930
|
-
let h = height;
|
|
2878
|
+
let x = targetX, y = targetY, w = width, h = height;
|
|
1931
2879
|
if (x < 0) {
|
|
1932
2880
|
w += x;
|
|
1933
2881
|
x = 0;
|
|
@@ -1939,76 +2887,33 @@ function blendColorPixelData(dst, color, opts = {}) {
|
|
|
1939
2887
|
const actualW = Math.min(w, dst.width - x);
|
|
1940
2888
|
const actualH = Math.min(h, dst.height - y);
|
|
1941
2889
|
if (actualW <= 0 || actualH <= 0) return;
|
|
2890
|
+
let finalSrcColor = color;
|
|
2891
|
+
if (globalAlpha < 255) {
|
|
2892
|
+
const a = baseSrcAlpha * globalAlpha + 128 >> 8;
|
|
2893
|
+
if (a === 0 && !isOverwrite) return;
|
|
2894
|
+
finalSrcColor = (color & 16777215 | a << 24) >>> 0;
|
|
2895
|
+
}
|
|
1942
2896
|
const dst32 = dst.data32;
|
|
1943
2897
|
const dw = dst.width;
|
|
1944
|
-
|
|
1945
|
-
const
|
|
1946
|
-
const dx = x - targetX;
|
|
1947
|
-
const dy = y - targetY;
|
|
1948
|
-
let dIdx = y * dw + x;
|
|
1949
|
-
let mIdx = (my + dy) * mPitch + (mx + dx);
|
|
1950
|
-
const dStride = dw - actualW;
|
|
1951
|
-
const mStride = mPitch - actualW;
|
|
2898
|
+
let dIdx = y * dw + x | 0;
|
|
2899
|
+
const dStride = dw - actualW | 0;
|
|
1952
2900
|
for (let iy = 0; iy < actualH; iy++) {
|
|
1953
2901
|
for (let ix = 0; ix < actualW; ix++) {
|
|
1954
|
-
|
|
1955
|
-
if (mask) {
|
|
1956
|
-
const mVal = mask[mIdx];
|
|
1957
|
-
if (isAlphaMask) {
|
|
1958
|
-
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
1959
|
-
if (effectiveM === 0) {
|
|
1960
|
-
dIdx++;
|
|
1961
|
-
mIdx++;
|
|
1962
|
-
continue;
|
|
1963
|
-
}
|
|
1964
|
-
if (globalAlpha === 255) {
|
|
1965
|
-
weight = effectiveM;
|
|
1966
|
-
} else if (effectiveM === 255) {
|
|
1967
|
-
weight = globalAlpha;
|
|
1968
|
-
} else {
|
|
1969
|
-
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
1970
|
-
}
|
|
1971
|
-
} else {
|
|
1972
|
-
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
1973
|
-
if (!isHit) {
|
|
1974
|
-
dIdx++;
|
|
1975
|
-
mIdx++;
|
|
1976
|
-
continue;
|
|
1977
|
-
}
|
|
1978
|
-
weight = globalAlpha;
|
|
1979
|
-
}
|
|
1980
|
-
if (weight === 0) {
|
|
1981
|
-
dIdx++;
|
|
1982
|
-
mIdx++;
|
|
1983
|
-
continue;
|
|
1984
|
-
}
|
|
1985
|
-
}
|
|
1986
|
-
let currentSrcColor = color;
|
|
1987
|
-
if (weight < 255) {
|
|
1988
|
-
let currentSrcAlpha = baseSrcAlpha;
|
|
1989
|
-
if (baseSrcAlpha === 255) {
|
|
1990
|
-
currentSrcAlpha = weight;
|
|
1991
|
-
} else {
|
|
1992
|
-
currentSrcAlpha = baseSrcAlpha * weight + 128 >> 8;
|
|
1993
|
-
}
|
|
1994
|
-
if (!isOverwrite && currentSrcAlpha === 0) {
|
|
1995
|
-
dIdx++;
|
|
1996
|
-
mIdx++;
|
|
1997
|
-
continue;
|
|
1998
|
-
}
|
|
1999
|
-
currentSrcColor = (color & 16777215 | currentSrcAlpha << 24) >>> 0;
|
|
2000
|
-
}
|
|
2001
|
-
dst32[dIdx] = blendFn(currentSrcColor, dst32[dIdx]);
|
|
2902
|
+
dst32[dIdx] = blendFn(finalSrcColor, dst32[dIdx]);
|
|
2002
2903
|
dIdx++;
|
|
2003
|
-
mIdx++;
|
|
2004
2904
|
}
|
|
2005
2905
|
dIdx += dStride;
|
|
2006
|
-
mIdx += mStride;
|
|
2007
2906
|
}
|
|
2008
2907
|
}
|
|
2009
2908
|
|
|
2010
2909
|
// src/History/PixelMutator/mutatorBlendColor.ts
|
|
2011
|
-
|
|
2910
|
+
var defaults10 = {
|
|
2911
|
+
blendColorPixelData
|
|
2912
|
+
};
|
|
2913
|
+
var mutatorBlendColor = ((writer, deps = defaults10) => {
|
|
2914
|
+
const {
|
|
2915
|
+
blendColorPixelData: blendColorPixelData2 = defaults10.blendColorPixelData
|
|
2916
|
+
} = deps;
|
|
2012
2917
|
return {
|
|
2013
2918
|
blendColor(color, opts = {}) {
|
|
2014
2919
|
const {
|
|
@@ -2018,10 +2923,10 @@ function mutatorBlendColor(writer) {
|
|
|
2018
2923
|
h = writer.target.height
|
|
2019
2924
|
} = opts;
|
|
2020
2925
|
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2021
|
-
|
|
2926
|
+
blendColorPixelData2(writer.target, color, opts);
|
|
2022
2927
|
}
|
|
2023
2928
|
};
|
|
2024
|
-
}
|
|
2929
|
+
});
|
|
2025
2930
|
|
|
2026
2931
|
// src/History/PixelMutator/mutatorBlendPixel.ts
|
|
2027
2932
|
function mutatorBlendPixel(writer) {
|
|
@@ -2055,13 +2960,7 @@ function blendPixelData(dst, src, opts) {
|
|
|
2055
2960
|
w: width = src.width,
|
|
2056
2961
|
h: height = src.height,
|
|
2057
2962
|
alpha: globalAlpha = 255,
|
|
2058
|
-
blendFn =
|
|
2059
|
-
mask,
|
|
2060
|
-
maskType = 0 /* ALPHA */,
|
|
2061
|
-
mw,
|
|
2062
|
-
mx = 0,
|
|
2063
|
-
my = 0,
|
|
2064
|
-
invertMask = false
|
|
2963
|
+
blendFn = sourceOverPerfect
|
|
2065
2964
|
} = opts;
|
|
2066
2965
|
if (globalAlpha === 0) return;
|
|
2067
2966
|
let x = targetX;
|
|
@@ -2099,91 +2998,48 @@ function blendPixelData(dst, src, opts) {
|
|
|
2099
2998
|
const src32 = src.data32;
|
|
2100
2999
|
const dw = dst.width;
|
|
2101
3000
|
const sw = src.width;
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
const
|
|
2105
|
-
const
|
|
2106
|
-
|
|
2107
|
-
let sIdx = sy * sw + sx;
|
|
2108
|
-
let mIdx = (my + dy) * mPitch + (mx + dx);
|
|
2109
|
-
const dStride = dw - actualW;
|
|
2110
|
-
const sStride = sw - actualW;
|
|
2111
|
-
const mStride = mPitch - actualW;
|
|
3001
|
+
let dIdx = y * dw + x | 0;
|
|
3002
|
+
let sIdx = sy * sw + sx | 0;
|
|
3003
|
+
const dStride = dw - actualW | 0;
|
|
3004
|
+
const sStride = sw - actualW | 0;
|
|
3005
|
+
const isOpaque = globalAlpha === 255;
|
|
2112
3006
|
const isOverwrite = blendFn.isOverwrite;
|
|
2113
3007
|
for (let iy = 0; iy < actualH; iy++) {
|
|
2114
3008
|
for (let ix = 0; ix < actualW; ix++) {
|
|
2115
|
-
const
|
|
2116
|
-
const
|
|
2117
|
-
if (
|
|
3009
|
+
const srcCol = src32[sIdx];
|
|
3010
|
+
const srcAlpha = srcCol >>> 24;
|
|
3011
|
+
if (srcAlpha === 0 && !isOverwrite) {
|
|
2118
3012
|
dIdx++;
|
|
2119
3013
|
sIdx++;
|
|
2120
|
-
mIdx++;
|
|
2121
3014
|
continue;
|
|
2122
3015
|
}
|
|
2123
|
-
let
|
|
2124
|
-
if (
|
|
2125
|
-
const
|
|
2126
|
-
if (
|
|
2127
|
-
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
2128
|
-
if (effectiveM === 0) {
|
|
2129
|
-
dIdx++;
|
|
2130
|
-
sIdx++;
|
|
2131
|
-
mIdx++;
|
|
2132
|
-
continue;
|
|
2133
|
-
}
|
|
2134
|
-
if (globalAlpha === 255) {
|
|
2135
|
-
weight = effectiveM;
|
|
2136
|
-
} else if (effectiveM === 255) {
|
|
2137
|
-
weight = globalAlpha;
|
|
2138
|
-
} else {
|
|
2139
|
-
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
2140
|
-
}
|
|
2141
|
-
} else {
|
|
2142
|
-
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
2143
|
-
if (!isHit) {
|
|
2144
|
-
dIdx++;
|
|
2145
|
-
sIdx++;
|
|
2146
|
-
mIdx++;
|
|
2147
|
-
continue;
|
|
2148
|
-
}
|
|
2149
|
-
weight = globalAlpha;
|
|
2150
|
-
}
|
|
2151
|
-
if (weight === 0) {
|
|
2152
|
-
dIdx++;
|
|
2153
|
-
sIdx++;
|
|
2154
|
-
mIdx++;
|
|
2155
|
-
continue;
|
|
2156
|
-
}
|
|
2157
|
-
}
|
|
2158
|
-
let currentSrcColor = baseSrcColor;
|
|
2159
|
-
if (weight < 255) {
|
|
2160
|
-
let currentSrcAlpha = baseSrcAlpha;
|
|
2161
|
-
if (baseSrcAlpha === 255) {
|
|
2162
|
-
currentSrcAlpha = weight;
|
|
2163
|
-
} else {
|
|
2164
|
-
currentSrcAlpha = baseSrcAlpha * weight + 128 >> 8;
|
|
2165
|
-
}
|
|
2166
|
-
if (!isOverwrite && currentSrcAlpha === 0) {
|
|
3016
|
+
let finalCol = srcCol;
|
|
3017
|
+
if (!isOpaque) {
|
|
3018
|
+
const a = srcAlpha * globalAlpha + 128 >> 8;
|
|
3019
|
+
if (a === 0 && !isOverwrite) {
|
|
2167
3020
|
dIdx++;
|
|
2168
3021
|
sIdx++;
|
|
2169
|
-
mIdx++;
|
|
2170
3022
|
continue;
|
|
2171
3023
|
}
|
|
2172
|
-
|
|
3024
|
+
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
2173
3025
|
}
|
|
2174
|
-
dst32[dIdx] = blendFn(
|
|
3026
|
+
dst32[dIdx] = blendFn(finalCol, dst32[dIdx]);
|
|
2175
3027
|
dIdx++;
|
|
2176
3028
|
sIdx++;
|
|
2177
|
-
mIdx++;
|
|
2178
3029
|
}
|
|
2179
3030
|
dIdx += dStride;
|
|
2180
3031
|
sIdx += sStride;
|
|
2181
|
-
mIdx += mStride;
|
|
2182
3032
|
}
|
|
2183
3033
|
}
|
|
2184
3034
|
|
|
2185
3035
|
// src/History/PixelMutator/mutatorBlendPixelData.ts
|
|
2186
|
-
|
|
3036
|
+
var defaults11 = {
|
|
3037
|
+
blendPixelData
|
|
3038
|
+
};
|
|
3039
|
+
var mutatorBlendPixelData = ((writer, deps = defaults11) => {
|
|
3040
|
+
const {
|
|
3041
|
+
blendPixelData: blendPixelData2 = defaults11.blendPixelData
|
|
3042
|
+
} = deps;
|
|
2187
3043
|
return {
|
|
2188
3044
|
blendPixelData(src, opts) {
|
|
2189
3045
|
const {
|
|
@@ -2193,12 +3049,13 @@ function mutatorBlendPixelData(writer) {
|
|
|
2193
3049
|
h = src.height
|
|
2194
3050
|
} = opts;
|
|
2195
3051
|
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2196
|
-
|
|
3052
|
+
blendPixelData2(writer.target, src, opts);
|
|
2197
3053
|
}
|
|
2198
3054
|
};
|
|
2199
|
-
}
|
|
3055
|
+
});
|
|
2200
3056
|
|
|
2201
3057
|
// src/PixelData/fillPixelData.ts
|
|
3058
|
+
var SCRATCH_RECT = makeClippedRect();
|
|
2202
3059
|
function fillPixelData(dst, color, _x, _y, _w, _h) {
|
|
2203
3060
|
let x;
|
|
2204
3061
|
let y;
|
|
@@ -2220,34 +3077,57 @@ function fillPixelData(dst, color, _x, _y, _w, _h) {
|
|
|
2220
3077
|
w = dst.width;
|
|
2221
3078
|
h = dst.height;
|
|
2222
3079
|
}
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
}
|
|
2231
|
-
const actualW = Math.min(w, dst.width - x);
|
|
2232
|
-
const actualH = Math.min(h, dst.height - y);
|
|
2233
|
-
if (actualW <= 0 || actualH <= 0) {
|
|
2234
|
-
return;
|
|
2235
|
-
}
|
|
3080
|
+
const clip = resolveRectClipping(x, y, w, h, dst.width, dst.height, SCRATCH_RECT);
|
|
3081
|
+
if (!clip.inBounds) return;
|
|
3082
|
+
const {
|
|
3083
|
+
x: finalX,
|
|
3084
|
+
y: finalY,
|
|
3085
|
+
w: actualW,
|
|
3086
|
+
h: actualH
|
|
3087
|
+
} = clip;
|
|
2236
3088
|
const dst32 = dst.data32;
|
|
2237
3089
|
const dw = dst.width;
|
|
2238
|
-
if (actualW === dw && actualH === dst.height &&
|
|
3090
|
+
if (actualW === dw && actualH === dst.height && finalX === 0 && finalY === 0) {
|
|
2239
3091
|
dst32.fill(color);
|
|
2240
3092
|
return;
|
|
2241
3093
|
}
|
|
2242
3094
|
for (let iy = 0; iy < actualH; iy++) {
|
|
2243
|
-
const start = (
|
|
3095
|
+
const start = (finalY + iy) * dw + finalX;
|
|
2244
3096
|
const end = start + actualW;
|
|
2245
3097
|
dst32.fill(color, start, end);
|
|
2246
3098
|
}
|
|
2247
3099
|
}
|
|
2248
3100
|
|
|
2249
|
-
// src/History/PixelMutator/
|
|
2250
|
-
|
|
3101
|
+
// src/History/PixelMutator/mutatorClear.ts
|
|
3102
|
+
var defaults12 = {
|
|
3103
|
+
fillPixelData
|
|
3104
|
+
};
|
|
3105
|
+
var mutatorClear = ((writer, deps = defaults12) => {
|
|
3106
|
+
const {
|
|
3107
|
+
fillPixelData: fillPixelData2 = defaults12.fillPixelData
|
|
3108
|
+
} = deps;
|
|
3109
|
+
return {
|
|
3110
|
+
clear(rect = {}) {
|
|
3111
|
+
const {
|
|
3112
|
+
x = 0,
|
|
3113
|
+
y = 0,
|
|
3114
|
+
w = writer.target.width,
|
|
3115
|
+
h = writer.target.height
|
|
3116
|
+
} = rect;
|
|
3117
|
+
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3118
|
+
fillPixelData2(writer.target, 0, x, y, w, h);
|
|
3119
|
+
}
|
|
3120
|
+
};
|
|
3121
|
+
});
|
|
3122
|
+
|
|
3123
|
+
// src/History/PixelMutator/mutatorFill.ts
|
|
3124
|
+
var defaults13 = {
|
|
3125
|
+
fillPixelData
|
|
3126
|
+
};
|
|
3127
|
+
var mutatorFill = ((writer, deps = defaults13) => {
|
|
3128
|
+
const {
|
|
3129
|
+
fillPixelData: fillPixelData2 = defaults13.fillPixelData
|
|
3130
|
+
} = deps;
|
|
2251
3131
|
return {
|
|
2252
3132
|
fill(color, rect = {}) {
|
|
2253
3133
|
const {
|
|
@@ -2257,12 +3137,13 @@ function mutatorFill(writer) {
|
|
|
2257
3137
|
h = writer.target.height
|
|
2258
3138
|
} = rect;
|
|
2259
3139
|
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2260
|
-
|
|
3140
|
+
fillPixelData2(writer.target, color, x, y, w, h);
|
|
2261
3141
|
}
|
|
2262
3142
|
};
|
|
2263
|
-
}
|
|
3143
|
+
});
|
|
2264
3144
|
|
|
2265
3145
|
// src/PixelData/invertPixelData.ts
|
|
3146
|
+
var SCRATCH_RECT2 = makeClippedRect();
|
|
2266
3147
|
function invertPixelData(pixelData, opts = {}) {
|
|
2267
3148
|
const dst = pixelData;
|
|
2268
3149
|
const {
|
|
@@ -2276,21 +3157,14 @@ function invertPixelData(pixelData, opts = {}) {
|
|
|
2276
3157
|
my = 0,
|
|
2277
3158
|
invertMask = false
|
|
2278
3159
|
} = opts;
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
w
|
|
2285
|
-
|
|
2286
|
-
}
|
|
2287
|
-
if (y < 0) {
|
|
2288
|
-
h += y;
|
|
2289
|
-
y = 0;
|
|
2290
|
-
}
|
|
2291
|
-
const actualW = Math.min(w, dst.width - x);
|
|
2292
|
-
const actualH = Math.min(h, dst.height - y);
|
|
2293
|
-
if (actualW <= 0 || actualH <= 0) return;
|
|
3160
|
+
const clip = resolveRectClipping(targetX, targetY, width, height, dst.width, dst.height, SCRATCH_RECT2);
|
|
3161
|
+
if (!clip.inBounds) return;
|
|
3162
|
+
const {
|
|
3163
|
+
x,
|
|
3164
|
+
y,
|
|
3165
|
+
w: actualW,
|
|
3166
|
+
h: actualH
|
|
3167
|
+
} = clip;
|
|
2294
3168
|
const dst32 = dst.data32;
|
|
2295
3169
|
const dw = dst.width;
|
|
2296
3170
|
const mPitch = mw ?? width;
|
|
@@ -2326,7 +3200,13 @@ function invertPixelData(pixelData, opts = {}) {
|
|
|
2326
3200
|
}
|
|
2327
3201
|
|
|
2328
3202
|
// src/History/PixelMutator/mutatorInvert.ts
|
|
2329
|
-
|
|
3203
|
+
var defaults14 = {
|
|
3204
|
+
invertPixelData
|
|
3205
|
+
};
|
|
3206
|
+
var mutatorInvert = ((writer, deps = defaults14) => {
|
|
3207
|
+
const {
|
|
3208
|
+
invertPixelData: invertPixelData2 = defaults14.invertPixelData
|
|
3209
|
+
} = deps;
|
|
2330
3210
|
return {
|
|
2331
3211
|
invert(opts = {}) {
|
|
2332
3212
|
const {
|
|
@@ -2336,44 +3216,121 @@ function mutatorInvert(writer) {
|
|
|
2336
3216
|
h = writer.target.height
|
|
2337
3217
|
} = opts;
|
|
2338
3218
|
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2339
|
-
|
|
3219
|
+
invertPixelData2(writer.target, opts);
|
|
2340
3220
|
}
|
|
2341
3221
|
};
|
|
2342
|
-
}
|
|
3222
|
+
});
|
|
2343
3223
|
|
|
2344
3224
|
// src/History/PixelMutator.ts
|
|
2345
3225
|
function makeFullPixelMutator(writer) {
|
|
2346
3226
|
return {
|
|
2347
|
-
...
|
|
3227
|
+
...mutatorApplyAlphaMask(writer),
|
|
3228
|
+
...mutatorApplyBinaryMask(writer),
|
|
2348
3229
|
...mutatorBlendPixelData(writer),
|
|
2349
3230
|
...mutatorBlendColor(writer),
|
|
2350
3231
|
...mutatorBlendPixel(writer),
|
|
2351
3232
|
...mutatorFill(writer),
|
|
2352
|
-
...mutatorInvert(writer)
|
|
3233
|
+
...mutatorInvert(writer),
|
|
3234
|
+
...mutatorApplyCircleBrush(writer),
|
|
3235
|
+
...mutatorApplyCircleBrushStroke(writer),
|
|
3236
|
+
...mutatorApplyCirclePencilStroke(writer),
|
|
3237
|
+
...mutatorApplyRectBrush(writer),
|
|
3238
|
+
...mutatorApplyRectBrushStroke(writer),
|
|
3239
|
+
...mutatorApplyRectPencil(writer),
|
|
3240
|
+
...mutatorApplyRectPencilStroke(writer),
|
|
3241
|
+
...mutatorClear(writer)
|
|
2353
3242
|
};
|
|
2354
3243
|
}
|
|
2355
3244
|
|
|
2356
|
-
// src/
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
3245
|
+
// src/History/PixelWriter.ts
|
|
3246
|
+
var PixelWriter = class {
|
|
3247
|
+
target;
|
|
3248
|
+
historyManager;
|
|
3249
|
+
accumulator;
|
|
3250
|
+
config;
|
|
3251
|
+
mutator;
|
|
3252
|
+
constructor(target, mutatorFactory, {
|
|
3253
|
+
tileSize = 256,
|
|
3254
|
+
maxHistorySteps = 50,
|
|
3255
|
+
historyManager = new HistoryManager(maxHistorySteps)
|
|
3256
|
+
} = {}) {
|
|
3257
|
+
this.target = target;
|
|
3258
|
+
this.config = new PixelEngineConfig(tileSize);
|
|
3259
|
+
this.historyManager = historyManager;
|
|
3260
|
+
this.accumulator = new PixelAccumulator(target, this.config);
|
|
3261
|
+
this.mutator = mutatorFactory(this);
|
|
3262
|
+
}
|
|
3263
|
+
withHistory(cb) {
|
|
3264
|
+
cb(this.mutator);
|
|
3265
|
+
this.captureHistory();
|
|
3266
|
+
}
|
|
3267
|
+
captureHistory() {
|
|
3268
|
+
const beforeTiles = this.accumulator.beforeTiles;
|
|
3269
|
+
if (beforeTiles.length === 0) return;
|
|
3270
|
+
const afterTiles = this.accumulator.extractAfterTiles();
|
|
3271
|
+
const patch = {
|
|
3272
|
+
beforeTiles,
|
|
3273
|
+
afterTiles
|
|
3274
|
+
};
|
|
3275
|
+
const target = this.target;
|
|
3276
|
+
const tileSize = this.config.tileSize;
|
|
3277
|
+
const accumulator = this.accumulator;
|
|
3278
|
+
const action = {
|
|
3279
|
+
undo: () => applyPatchTiles(target, patch.beforeTiles, tileSize),
|
|
3280
|
+
redo: () => applyPatchTiles(target, patch.afterTiles, tileSize),
|
|
3281
|
+
dispose: () => accumulator.recyclePatch(patch)
|
|
3282
|
+
};
|
|
3283
|
+
this.historyManager.commit(action);
|
|
3284
|
+
this.accumulator.reset();
|
|
3285
|
+
}
|
|
3286
|
+
};
|
|
3287
|
+
|
|
3288
|
+
// src/History/PixelMutator/mutatorApplyCirclePencil.ts
|
|
3289
|
+
var defaults15 = {
|
|
3290
|
+
applyCircleBrushToPixelData,
|
|
3291
|
+
getCircleBrushOrPencilBounds,
|
|
3292
|
+
fallOff: () => 1
|
|
3293
|
+
};
|
|
3294
|
+
var mutatorApplyCirclePencil = ((writer, deps = defaults15) => {
|
|
3295
|
+
const {
|
|
3296
|
+
applyCircleBrushToPixelData: applyCircleBrushToPixelData2 = defaults15.applyCircleBrushToPixelData,
|
|
3297
|
+
getCircleBrushOrPencilBounds: getCircleBrushOrPencilBounds2 = defaults15.getCircleBrushOrPencilBounds,
|
|
3298
|
+
fallOff = defaults15.fallOff
|
|
3299
|
+
} = deps;
|
|
3300
|
+
const boundsOut = {
|
|
3301
|
+
x: 0,
|
|
3302
|
+
y: 0,
|
|
3303
|
+
w: 0,
|
|
3304
|
+
h: 0
|
|
3305
|
+
};
|
|
3306
|
+
return {
|
|
3307
|
+
applyCirclePencil(color, centerX, centerY, brushSize, alpha = 255, blendFn) {
|
|
3308
|
+
const bounds = getCircleBrushOrPencilBounds2(centerX, centerY, brushSize, writer.target.width, writer.target.height, boundsOut);
|
|
3309
|
+
const {
|
|
3310
|
+
x,
|
|
3311
|
+
y,
|
|
3312
|
+
w,
|
|
3313
|
+
h
|
|
3314
|
+
} = bounds;
|
|
3315
|
+
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
3316
|
+
applyCircleBrushToPixelData2(writer.target, color, centerX, centerY, brushSize, alpha, fallOff, blendFn, bounds);
|
|
2367
3317
|
}
|
|
2368
|
-
return imageData;
|
|
2369
3318
|
};
|
|
2370
|
-
}
|
|
3319
|
+
});
|
|
2371
3320
|
|
|
2372
3321
|
// src/ImageData/copyImageData.ts
|
|
2373
|
-
function copyImageData({
|
|
3322
|
+
function copyImageData({
|
|
3323
|
+
data,
|
|
3324
|
+
width,
|
|
3325
|
+
height
|
|
3326
|
+
}) {
|
|
2374
3327
|
return new ImageData(data.slice(), width, height);
|
|
2375
3328
|
}
|
|
2376
|
-
function copyImageDataLike({
|
|
3329
|
+
function copyImageDataLike({
|
|
3330
|
+
data,
|
|
3331
|
+
width,
|
|
3332
|
+
height
|
|
3333
|
+
}) {
|
|
2377
3334
|
return {
|
|
2378
3335
|
data: data.slice(),
|
|
2379
3336
|
width,
|
|
@@ -2381,20 +3338,15 @@ function copyImageDataLike({ data, width, height }) {
|
|
|
2381
3338
|
};
|
|
2382
3339
|
}
|
|
2383
3340
|
|
|
2384
|
-
// src/
|
|
2385
|
-
function
|
|
2386
|
-
const
|
|
2387
|
-
|
|
3341
|
+
// src/ImageData/ImageDataLike.ts
|
|
3342
|
+
function makeImageDataLike(width, height, data) {
|
|
3343
|
+
const size = width * height * 4;
|
|
3344
|
+
const buffer = data ? new Uint8ClampedArray(data.buffer, data.byteOffset, size) : new Uint8ClampedArray(size);
|
|
3345
|
+
return {
|
|
2388
3346
|
width,
|
|
2389
|
-
height
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
const mask = new Uint8Array(width * height);
|
|
2393
|
-
for (let i = 0; i < len; i++) {
|
|
2394
|
-
const val = data32[i];
|
|
2395
|
-
mask[i] = val >>> 24 & 255;
|
|
2396
|
-
}
|
|
2397
|
-
return mask;
|
|
3347
|
+
height,
|
|
3348
|
+
data: buffer
|
|
3349
|
+
};
|
|
2398
3350
|
}
|
|
2399
3351
|
|
|
2400
3352
|
// src/ImageData/imageDataToAlphaMask.ts
|
|
@@ -2404,11 +3356,7 @@ function imageDataToAlphaMask(imageData) {
|
|
|
2404
3356
|
height,
|
|
2405
3357
|
data
|
|
2406
3358
|
} = imageData;
|
|
2407
|
-
const data32 = new Uint32Array(
|
|
2408
|
-
data.buffer,
|
|
2409
|
-
data.byteOffset,
|
|
2410
|
-
data.byteLength >> 2
|
|
2411
|
-
);
|
|
3359
|
+
const data32 = new Uint32Array(data.buffer, data.byteOffset, data.byteLength >> 2);
|
|
2412
3360
|
const len = data32.length;
|
|
2413
3361
|
const mask = new Uint8Array(width * height);
|
|
2414
3362
|
for (let i = 0; i < len; i++) {
|
|
@@ -2421,7 +3369,10 @@ function imageDataToAlphaMask(imageData) {
|
|
|
2421
3369
|
// src/ImageData/imageDataToDataUrl.ts
|
|
2422
3370
|
var get = makeReusableCanvas();
|
|
2423
3371
|
function imageDataToDataUrl(imageData) {
|
|
2424
|
-
const {
|
|
3372
|
+
const {
|
|
3373
|
+
canvas,
|
|
3374
|
+
ctx
|
|
3375
|
+
} = get(imageData.width, imageData.height);
|
|
2425
3376
|
ctx.putImageData(imageData, 0, 0);
|
|
2426
3377
|
return canvas.toDataURL();
|
|
2427
3378
|
}
|
|
@@ -2479,7 +3430,11 @@ function resample32(srcData32, srcW, srcH, factor) {
|
|
|
2479
3430
|
// src/ImageData/resampleImageData.ts
|
|
2480
3431
|
function resampleImageData(source, factor) {
|
|
2481
3432
|
const src32 = new Uint32Array(source.data.buffer);
|
|
2482
|
-
const {
|
|
3433
|
+
const {
|
|
3434
|
+
data,
|
|
3435
|
+
width,
|
|
3436
|
+
height
|
|
3437
|
+
} = resample32(src32, source.width, source.height, factor);
|
|
2483
3438
|
const uint8ClampedArray = new Uint8ClampedArray(data.buffer);
|
|
2484
3439
|
return new ImageData(uint8ClampedArray, width, height);
|
|
2485
3440
|
}
|
|
@@ -2508,14 +3463,25 @@ function resizeImageData(current, newWidth, newHeight, offsetX = 0, offsetY = 0)
|
|
|
2508
3463
|
const srcX = x0 - offsetX;
|
|
2509
3464
|
const dstStart = (dstY * newWidth + x0) * 4;
|
|
2510
3465
|
const srcStart = (srcY * oldW + srcX) * 4;
|
|
2511
|
-
newData.set(
|
|
2512
|
-
oldData.subarray(srcStart, srcStart + rowLen),
|
|
2513
|
-
dstStart
|
|
2514
|
-
);
|
|
3466
|
+
newData.set(oldData.subarray(srcStart, srcStart + rowLen), dstStart);
|
|
2515
3467
|
}
|
|
2516
3468
|
return result;
|
|
2517
3469
|
}
|
|
2518
3470
|
|
|
3471
|
+
// src/ImageData/ReusableImageData.ts
|
|
3472
|
+
function makeReusableImageData() {
|
|
3473
|
+
let imageData = null;
|
|
3474
|
+
return function getReusableImageData(width, height) {
|
|
3475
|
+
const hasInstance = !!imageData;
|
|
3476
|
+
const widthMatches = hasInstance && imageData.width === width;
|
|
3477
|
+
const heightMatches = hasInstance && imageData.height === height;
|
|
3478
|
+
if (!widthMatches || !heightMatches) {
|
|
3479
|
+
imageData = new ImageData(width, height);
|
|
3480
|
+
}
|
|
3481
|
+
return imageData;
|
|
3482
|
+
};
|
|
3483
|
+
}
|
|
3484
|
+
|
|
2519
3485
|
// src/ImageData/serialization.ts
|
|
2520
3486
|
function base64EncodeArrayBuffer(buffer) {
|
|
2521
3487
|
const uint8 = new Uint8Array(buffer);
|
|
@@ -2558,32 +3524,53 @@ function deserializeNullableImageData(serialized) {
|
|
|
2558
3524
|
return deserializeImageData(serialized);
|
|
2559
3525
|
}
|
|
2560
3526
|
|
|
3527
|
+
// src/ImageData/uInt32ArrayToImageData.ts
|
|
3528
|
+
function uInt32ArrayToImageData(data, width, height) {
|
|
3529
|
+
const buffer = data.buffer;
|
|
3530
|
+
const byteOffset = data.byteOffset;
|
|
3531
|
+
const byteLength = data.byteLength;
|
|
3532
|
+
const clampedArray = new Uint8ClampedArray(buffer, byteOffset, byteLength);
|
|
3533
|
+
return new ImageData(clampedArray, width, height);
|
|
3534
|
+
}
|
|
3535
|
+
function uInt32ArrayToImageDataLike(data, width, height) {
|
|
3536
|
+
const buffer = data.buffer;
|
|
3537
|
+
const byteOffset = data.byteOffset;
|
|
3538
|
+
const byteLength = data.byteLength;
|
|
3539
|
+
const clampedArray = new Uint8ClampedArray(buffer, byteOffset, byteLength);
|
|
3540
|
+
return {
|
|
3541
|
+
width,
|
|
3542
|
+
height,
|
|
3543
|
+
data: clampedArray
|
|
3544
|
+
};
|
|
3545
|
+
}
|
|
3546
|
+
|
|
2561
3547
|
// src/ImageData/writeImageData.ts
|
|
3548
|
+
var SCRATCH_BLIT2 = makeClippedBlit();
|
|
2562
3549
|
function writeImageData(target, source, x, y, sx = 0, sy = 0, sw = source.width, sh = source.height, mask = null, maskType = 1 /* BINARY */) {
|
|
2563
3550
|
const dstW = target.width;
|
|
2564
3551
|
const dstH = target.height;
|
|
2565
3552
|
const dstData = target.data;
|
|
2566
3553
|
const srcW = source.width;
|
|
2567
3554
|
const srcData = source.data;
|
|
2568
|
-
const
|
|
2569
|
-
|
|
2570
|
-
const
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
3555
|
+
const clip = resolveBlitClipping(x, y, sx, sy, sw, sh, dstW, dstH, srcW, source.height, SCRATCH_BLIT2);
|
|
3556
|
+
if (!clip.inBounds) return;
|
|
3557
|
+
const {
|
|
3558
|
+
x: dstX,
|
|
3559
|
+
y: dstY,
|
|
3560
|
+
sx: srcX,
|
|
3561
|
+
sy: srcY,
|
|
3562
|
+
w: copyW,
|
|
3563
|
+
h: copyH
|
|
3564
|
+
} = clip;
|
|
2575
3565
|
const useMask = !!mask;
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
const
|
|
2580
|
-
const
|
|
2581
|
-
const srcXBase = sx + (x0 - x);
|
|
2582
|
-
const dstStart = (dstY * dstW + x0) * 4;
|
|
2583
|
-
const srcStart = (srcY * srcW + srcXBase) * 4;
|
|
3566
|
+
for (let row = 0; row < copyH; row++) {
|
|
3567
|
+
const currentDstY = dstY + row;
|
|
3568
|
+
const currentSrcY = srcY + row;
|
|
3569
|
+
const dstStart = (currentDstY * dstW + dstX) * 4;
|
|
3570
|
+
const srcStart = (currentSrcY * srcW + srcX) * 4;
|
|
2584
3571
|
if (useMask && mask) {
|
|
2585
|
-
for (let ix = 0; ix <
|
|
2586
|
-
const mi =
|
|
3572
|
+
for (let ix = 0; ix < copyW; ix++) {
|
|
3573
|
+
const mi = currentSrcY * srcW + (srcX + ix);
|
|
2587
3574
|
const alpha = mask[mi];
|
|
2588
3575
|
if (alpha === 0) {
|
|
2589
3576
|
continue;
|
|
@@ -2605,7 +3592,7 @@ function writeImageData(target, source, x, y, sx = 0, sy = 0, sw = source.width,
|
|
|
2605
3592
|
}
|
|
2606
3593
|
}
|
|
2607
3594
|
} else {
|
|
2608
|
-
const byteLen =
|
|
3595
|
+
const byteLen = copyW * 4;
|
|
2609
3596
|
const sub = srcData.subarray(srcStart, srcStart + byteLen);
|
|
2610
3597
|
dstData.set(sub, dstStart);
|
|
2611
3598
|
}
|
|
@@ -2613,24 +3600,52 @@ function writeImageData(target, source, x, y, sx = 0, sy = 0, sw = source.width,
|
|
|
2613
3600
|
}
|
|
2614
3601
|
|
|
2615
3602
|
// src/ImageData/writeImageDataBuffer.ts
|
|
3603
|
+
var SCRATCH_BLIT3 = makeClippedBlit();
|
|
2616
3604
|
function writeImageDataBuffer(imageData, data, _x, _y, _w, _h) {
|
|
2617
|
-
const {
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
3605
|
+
const {
|
|
3606
|
+
x,
|
|
3607
|
+
y,
|
|
3608
|
+
w,
|
|
3609
|
+
h
|
|
3610
|
+
} = typeof _x === "object" ? _x : {
|
|
3611
|
+
x: _x,
|
|
3612
|
+
y: _y,
|
|
3613
|
+
w: _w,
|
|
3614
|
+
h: _h
|
|
3615
|
+
};
|
|
3616
|
+
const {
|
|
3617
|
+
width: dstW,
|
|
3618
|
+
height: dstH,
|
|
3619
|
+
data: dst
|
|
3620
|
+
} = imageData;
|
|
3621
|
+
const clip = resolveBlitClipping(x, y, 0, 0, w, h, dstW, dstH, w, h, SCRATCH_BLIT3);
|
|
3622
|
+
if (!clip.inBounds) return;
|
|
3623
|
+
const {
|
|
3624
|
+
x: dstX,
|
|
3625
|
+
y: dstY,
|
|
3626
|
+
sx: srcX,
|
|
3627
|
+
sy: srcY,
|
|
3628
|
+
w: copyW,
|
|
3629
|
+
h: copyH
|
|
3630
|
+
} = clip;
|
|
3631
|
+
const rowLen = copyW * 4;
|
|
3632
|
+
for (let row = 0; row < copyH; row++) {
|
|
3633
|
+
const dstStart = ((dstY + row) * dstW + dstX) * 4;
|
|
3634
|
+
const srcStart = ((srcY + row) * w + srcX) * 4;
|
|
3635
|
+
dst.set(data.subarray(srcStart, srcStart + rowLen), dstStart);
|
|
3636
|
+
}
|
|
3637
|
+
}
|
|
3638
|
+
|
|
3639
|
+
// src/IndexedImage/getIndexedImageColorCounts.ts
|
|
3640
|
+
function getIndexedImageColorCounts(indexedImage) {
|
|
3641
|
+
const data = indexedImage.data;
|
|
3642
|
+
const palette = indexedImage.palette;
|
|
3643
|
+
const frequencies = new Int32Array(palette.length);
|
|
3644
|
+
for (let i = 0; i < data.length; i++) {
|
|
3645
|
+
const colorIndex = data[i];
|
|
3646
|
+
frequencies[colorIndex]++;
|
|
2633
3647
|
}
|
|
3648
|
+
return frequencies;
|
|
2634
3649
|
}
|
|
2635
3650
|
|
|
2636
3651
|
// src/IndexedImage/IndexedImage.ts
|
|
@@ -2696,13 +3711,7 @@ var IndexedImage = class _IndexedImage {
|
|
|
2696
3711
|
indexedData[i] = id;
|
|
2697
3712
|
}
|
|
2698
3713
|
const palette = Uint32Array.from(colorMap.keys());
|
|
2699
|
-
return new _IndexedImage(
|
|
2700
|
-
width,
|
|
2701
|
-
height,
|
|
2702
|
-
indexedData,
|
|
2703
|
-
palette,
|
|
2704
|
-
transparentPalletIndex
|
|
2705
|
-
);
|
|
3714
|
+
return new _IndexedImage(width, height, indexedData, palette, transparentPalletIndex);
|
|
2706
3715
|
}
|
|
2707
3716
|
/**
|
|
2708
3717
|
* Retrieves the 32-bit packed color value at the given coordinates.
|
|
@@ -2717,21 +3726,13 @@ var IndexedImage = class _IndexedImage {
|
|
|
2717
3726
|
}
|
|
2718
3727
|
};
|
|
2719
3728
|
|
|
2720
|
-
// src/IndexedImage/getIndexedImageColorCounts.ts
|
|
2721
|
-
function getIndexedImageColorCounts(indexedImage) {
|
|
2722
|
-
const data = indexedImage.data;
|
|
2723
|
-
const palette = indexedImage.palette;
|
|
2724
|
-
const frequencies = new Int32Array(palette.length);
|
|
2725
|
-
for (let i = 0; i < data.length; i++) {
|
|
2726
|
-
const colorIndex = data[i];
|
|
2727
|
-
frequencies[colorIndex]++;
|
|
2728
|
-
}
|
|
2729
|
-
return frequencies;
|
|
2730
|
-
}
|
|
2731
|
-
|
|
2732
3729
|
// src/IndexedImage/indexedImageToAverageColor.ts
|
|
2733
3730
|
function indexedImageToAverageColor(indexedImage, includeTransparent = false) {
|
|
2734
|
-
const {
|
|
3731
|
+
const {
|
|
3732
|
+
data,
|
|
3733
|
+
palette,
|
|
3734
|
+
transparentPalletIndex
|
|
3735
|
+
} = indexedImage;
|
|
2735
3736
|
const counts = new Uint32Array(palette.length);
|
|
2736
3737
|
for (let i = 0; i < data.length; i++) {
|
|
2737
3738
|
const id = data[i];
|
|
@@ -2771,26 +3772,14 @@ function indexedImageToAverageColor(indexedImage, includeTransparent = false) {
|
|
|
2771
3772
|
return packColor(r, g, b, a);
|
|
2772
3773
|
}
|
|
2773
3774
|
|
|
2774
|
-
// src/IndexedImage/
|
|
2775
|
-
function
|
|
2776
|
-
const {
|
|
2777
|
-
source.data,
|
|
2778
|
-
source.width,
|
|
2779
|
-
source.height,
|
|
2780
|
-
factor
|
|
2781
|
-
);
|
|
2782
|
-
return new IndexedImage(
|
|
3775
|
+
// src/IndexedImage/indexedImageToImageData.ts
|
|
3776
|
+
function indexedImageToImageData(indexedImage) {
|
|
3777
|
+
const {
|
|
2783
3778
|
width,
|
|
2784
3779
|
height,
|
|
2785
3780
|
data,
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
);
|
|
2789
|
-
}
|
|
2790
|
-
|
|
2791
|
-
// src/IndexedImage/indexedImageToImageData.ts
|
|
2792
|
-
function indexedImageToImageData(indexedImage) {
|
|
2793
|
-
const { width, height, data, palette } = indexedImage;
|
|
3781
|
+
palette
|
|
3782
|
+
} = indexedImage;
|
|
2794
3783
|
const result = new ImageData(width, height);
|
|
2795
3784
|
const data32 = new Uint32Array(result.data.buffer);
|
|
2796
3785
|
for (let i = 0; i < data.length; i++) {
|
|
@@ -2801,6 +3790,16 @@ function indexedImageToImageData(indexedImage) {
|
|
|
2801
3790
|
return result;
|
|
2802
3791
|
}
|
|
2803
3792
|
|
|
3793
|
+
// src/IndexedImage/resampleIndexedImage.ts
|
|
3794
|
+
function resampleIndexedImage(source, factor) {
|
|
3795
|
+
const {
|
|
3796
|
+
data,
|
|
3797
|
+
width,
|
|
3798
|
+
height
|
|
3799
|
+
} = resample32(source.data, source.width, source.height, factor);
|
|
3800
|
+
return new IndexedImage(width, height, data, source.palette, source.transparentPalletIndex);
|
|
3801
|
+
}
|
|
3802
|
+
|
|
2804
3803
|
// src/Input/fileInputChangeToImageData.ts
|
|
2805
3804
|
async function fileInputChangeToImageData(event) {
|
|
2806
3805
|
const target = event.target;
|
|
@@ -2824,23 +3823,11 @@ async function fileToImageData(file) {
|
|
|
2824
3823
|
let bitmap = null;
|
|
2825
3824
|
try {
|
|
2826
3825
|
bitmap = await createImageBitmap(file);
|
|
2827
|
-
const canvas = new OffscreenCanvas(
|
|
2828
|
-
bitmap.width,
|
|
2829
|
-
bitmap.height
|
|
2830
|
-
);
|
|
3826
|
+
const canvas = new OffscreenCanvas(bitmap.width, bitmap.height);
|
|
2831
3827
|
const ctx = canvas.getContext("2d");
|
|
2832
3828
|
if (!ctx) throw new Error(OFFSCREEN_CANVAS_CTX_FAILED);
|
|
2833
|
-
ctx.drawImage(
|
|
2834
|
-
|
|
2835
|
-
0,
|
|
2836
|
-
0
|
|
2837
|
-
);
|
|
2838
|
-
return ctx.getImageData(
|
|
2839
|
-
0,
|
|
2840
|
-
0,
|
|
2841
|
-
bitmap.width,
|
|
2842
|
-
bitmap.height
|
|
2843
|
-
);
|
|
3829
|
+
ctx.drawImage(bitmap, 0, 0);
|
|
3830
|
+
return ctx.getImageData(0, 0, bitmap.width, bitmap.height);
|
|
2844
3831
|
} finally {
|
|
2845
3832
|
bitmap?.close();
|
|
2846
3833
|
}
|
|
@@ -2848,32 +3835,23 @@ async function fileToImageData(file) {
|
|
|
2848
3835
|
|
|
2849
3836
|
// src/Input/getSupportedRasterFormats.ts
|
|
2850
3837
|
var formatsPromise = null;
|
|
2851
|
-
var defaultRasterMimes = [
|
|
2852
|
-
"image/png",
|
|
2853
|
-
"image/jpeg",
|
|
2854
|
-
"image/webp",
|
|
2855
|
-
"image/avif",
|
|
2856
|
-
"image/gif",
|
|
2857
|
-
"image/bmp"
|
|
2858
|
-
];
|
|
3838
|
+
var defaultRasterMimes = ["image/png", "image/jpeg", "image/webp", "image/avif", "image/gif", "image/bmp"];
|
|
2859
3839
|
async function getSupportedPixelFormats(rasterMimes = defaultRasterMimes) {
|
|
2860
3840
|
if (formatsPromise) {
|
|
2861
3841
|
return formatsPromise;
|
|
2862
3842
|
}
|
|
2863
3843
|
const probeCanvas = async () => {
|
|
2864
3844
|
const canvas = new OffscreenCanvas(1, 1);
|
|
2865
|
-
const results = await Promise.all(
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
})
|
|
2876
|
-
);
|
|
3845
|
+
const results = await Promise.all(rasterMimes.map(async (mime) => {
|
|
3846
|
+
try {
|
|
3847
|
+
const blob = await canvas.convertToBlob({
|
|
3848
|
+
type: mime
|
|
3849
|
+
});
|
|
3850
|
+
return blob.type === mime ? mime : null;
|
|
3851
|
+
} catch {
|
|
3852
|
+
return null;
|
|
3853
|
+
}
|
|
3854
|
+
}));
|
|
2877
3855
|
return results.filter((type) => {
|
|
2878
3856
|
return type !== null;
|
|
2879
3857
|
});
|
|
@@ -2885,6 +3863,73 @@ async function getSupportedPixelFormats(rasterMimes = defaultRasterMimes) {
|
|
|
2885
3863
|
return formatsPromise;
|
|
2886
3864
|
}
|
|
2887
3865
|
|
|
3866
|
+
// src/Mask/applyBinaryMaskToAlphaMask.ts
|
|
3867
|
+
function applyBinaryMaskToAlphaMask(alphaMaskDst, dstWidth, binaryMaskSrc, srcWidth, opts = {}) {
|
|
3868
|
+
const {
|
|
3869
|
+
x: targetX = 0,
|
|
3870
|
+
y: targetY = 0,
|
|
3871
|
+
w: reqWidth = 0,
|
|
3872
|
+
h: reqHeight = 0,
|
|
3873
|
+
mx = 0,
|
|
3874
|
+
my = 0,
|
|
3875
|
+
invertMask = false
|
|
3876
|
+
} = opts;
|
|
3877
|
+
if (dstWidth <= 0) return;
|
|
3878
|
+
if (binaryMaskSrc.length === 0) return;
|
|
3879
|
+
if (srcWidth <= 0) return;
|
|
3880
|
+
const dstHeight = alphaMaskDst.length / dstWidth | 0;
|
|
3881
|
+
const srcHeight = binaryMaskSrc.length / srcWidth | 0;
|
|
3882
|
+
if (dstHeight <= 0) return;
|
|
3883
|
+
if (srcHeight <= 0) return;
|
|
3884
|
+
const dstX0 = Math.max(0, targetX);
|
|
3885
|
+
const dstY0 = Math.max(0, targetY);
|
|
3886
|
+
const dstX1 = reqWidth > 0 ? Math.min(dstWidth, targetX + reqWidth) : dstWidth;
|
|
3887
|
+
const dstY1 = reqHeight > 0 ? Math.min(dstHeight, targetY + reqHeight) : dstHeight;
|
|
3888
|
+
if (dstX0 >= dstX1) return;
|
|
3889
|
+
if (dstY0 >= dstY1) return;
|
|
3890
|
+
const srcX0 = mx + (dstX0 - targetX);
|
|
3891
|
+
const srcY0 = my + (dstY0 - targetY);
|
|
3892
|
+
if (srcX0 >= srcWidth) return;
|
|
3893
|
+
if (srcY0 >= srcHeight) return;
|
|
3894
|
+
if (srcX0 + (dstX1 - dstX0) <= 0) return;
|
|
3895
|
+
if (srcY0 + (dstY1 - dstY0) <= 0) return;
|
|
3896
|
+
const iterW = Math.min(dstX1 - dstX0, srcWidth - srcX0);
|
|
3897
|
+
const iterH = Math.min(dstY1 - dstY0, srcHeight - srcY0);
|
|
3898
|
+
let dstIdx = dstY0 * dstWidth + dstX0;
|
|
3899
|
+
let srcIdx = srcY0 * srcWidth + srcX0;
|
|
3900
|
+
if (invertMask) {
|
|
3901
|
+
for (let row = 0; row < iterH; row++) {
|
|
3902
|
+
const dstEnd = dstIdx + iterW;
|
|
3903
|
+
let d = dstIdx;
|
|
3904
|
+
let s = srcIdx;
|
|
3905
|
+
while (d < dstEnd) {
|
|
3906
|
+
if (binaryMaskSrc[s] !== 0) {
|
|
3907
|
+
alphaMaskDst[d] = 0;
|
|
3908
|
+
}
|
|
3909
|
+
d++;
|
|
3910
|
+
s++;
|
|
3911
|
+
}
|
|
3912
|
+
dstIdx += dstWidth;
|
|
3913
|
+
srcIdx += srcWidth;
|
|
3914
|
+
}
|
|
3915
|
+
} else {
|
|
3916
|
+
for (let row = 0; row < iterH; row++) {
|
|
3917
|
+
const dstEnd = dstIdx + iterW;
|
|
3918
|
+
let d = dstIdx;
|
|
3919
|
+
let s = srcIdx;
|
|
3920
|
+
while (d < dstEnd) {
|
|
3921
|
+
if (binaryMaskSrc[s] === 0) {
|
|
3922
|
+
alphaMaskDst[d] = 0;
|
|
3923
|
+
}
|
|
3924
|
+
d++;
|
|
3925
|
+
s++;
|
|
3926
|
+
}
|
|
3927
|
+
dstIdx += dstWidth;
|
|
3928
|
+
srcIdx += srcWidth;
|
|
3929
|
+
}
|
|
3930
|
+
}
|
|
3931
|
+
}
|
|
3932
|
+
|
|
2888
3933
|
// src/Mask/copyMask.ts
|
|
2889
3934
|
function copyMask(src) {
|
|
2890
3935
|
return src.slice();
|
|
@@ -2904,69 +3949,124 @@ function invertAlphaMask(dst) {
|
|
|
2904
3949
|
}
|
|
2905
3950
|
}
|
|
2906
3951
|
|
|
2907
|
-
// src/Mask/
|
|
2908
|
-
function
|
|
3952
|
+
// src/Mask/mergeAlphaMasks.ts
|
|
3953
|
+
function mergeAlphaMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
2909
3954
|
const {
|
|
2910
3955
|
x: targetX = 0,
|
|
2911
3956
|
y: targetY = 0,
|
|
2912
3957
|
w: width = 0,
|
|
2913
3958
|
h: height = 0,
|
|
2914
3959
|
alpha: globalAlpha = 255,
|
|
2915
|
-
maskType = 0 /* ALPHA */,
|
|
2916
|
-
mw,
|
|
2917
3960
|
mx = 0,
|
|
2918
3961
|
my = 0,
|
|
2919
3962
|
invertMask = false
|
|
2920
3963
|
} = opts;
|
|
2921
|
-
|
|
2922
|
-
|
|
3964
|
+
const dstHeight = dst.length / dstWidth | 0;
|
|
3965
|
+
const srcHeight = src.length / srcWidth | 0;
|
|
3966
|
+
if (width <= 0) return;
|
|
3967
|
+
if (height <= 0) return;
|
|
3968
|
+
if (globalAlpha === 0) return;
|
|
3969
|
+
const startX = Math.max(0, -targetX, -mx);
|
|
3970
|
+
const startY = Math.max(0, -targetY, -my);
|
|
3971
|
+
const endX = Math.min(width, dstWidth - targetX, srcWidth - mx);
|
|
3972
|
+
const endY = Math.min(height, dstHeight - targetY, srcHeight - my);
|
|
3973
|
+
if (startX >= endX) return;
|
|
3974
|
+
if (startY >= endY) return;
|
|
3975
|
+
for (let iy = startY; iy < endY; iy++) {
|
|
3976
|
+
const dy = targetY + iy;
|
|
3977
|
+
const sy = my + iy;
|
|
3978
|
+
let dIdx = dy * dstWidth + targetX + startX;
|
|
3979
|
+
let sIdx = sy * srcWidth + mx + startX;
|
|
3980
|
+
for (let ix = startX; ix < endX; ix++) {
|
|
3981
|
+
const rawM = src[sIdx];
|
|
3982
|
+
const effectiveM = invertMask ? 255 - rawM : rawM;
|
|
3983
|
+
let weight = 0;
|
|
3984
|
+
if (effectiveM === 0) {
|
|
3985
|
+
weight = 0;
|
|
3986
|
+
} else if (effectiveM === 255) {
|
|
3987
|
+
weight = globalAlpha;
|
|
3988
|
+
} else if (globalAlpha === 255) {
|
|
3989
|
+
weight = effectiveM;
|
|
3990
|
+
} else {
|
|
3991
|
+
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
3992
|
+
}
|
|
3993
|
+
if (weight !== 255) {
|
|
3994
|
+
if (weight === 0) {
|
|
3995
|
+
dst[dIdx] = 0;
|
|
3996
|
+
} else {
|
|
3997
|
+
const da = dst[dIdx];
|
|
3998
|
+
if (da === 255) {
|
|
3999
|
+
dst[dIdx] = weight;
|
|
4000
|
+
} else if (da !== 0) {
|
|
4001
|
+
dst[dIdx] = da * weight + 128 >> 8;
|
|
4002
|
+
}
|
|
4003
|
+
}
|
|
4004
|
+
}
|
|
4005
|
+
sIdx++;
|
|
4006
|
+
dIdx++;
|
|
4007
|
+
}
|
|
4008
|
+
}
|
|
4009
|
+
}
|
|
4010
|
+
|
|
4011
|
+
// src/Mask/mergeBinaryMasks.ts
|
|
4012
|
+
function mergeBinaryMasks(dst, dstWidth, src, srcWidth, opts) {
|
|
4013
|
+
const {
|
|
4014
|
+
x: targetX = 0,
|
|
4015
|
+
y: targetY = 0,
|
|
4016
|
+
w: width = 0,
|
|
4017
|
+
h: height = 0,
|
|
4018
|
+
mx = 0,
|
|
4019
|
+
my = 0,
|
|
4020
|
+
invertMask = false
|
|
4021
|
+
} = opts;
|
|
4022
|
+
if (dstWidth <= 0) return;
|
|
4023
|
+
if (srcWidth <= 0) return;
|
|
4024
|
+
const dstHeight = dst.length / dstWidth | 0;
|
|
4025
|
+
const srcHeight = src.length / srcWidth | 0;
|
|
4026
|
+
let x = targetX;
|
|
4027
|
+
let y = targetY;
|
|
4028
|
+
let w = width;
|
|
4029
|
+
let h = height;
|
|
4030
|
+
if (x < 0) {
|
|
4031
|
+
w += x;
|
|
4032
|
+
x = 0;
|
|
4033
|
+
}
|
|
4034
|
+
if (y < 0) {
|
|
4035
|
+
h += y;
|
|
4036
|
+
y = 0;
|
|
2923
4037
|
}
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
4038
|
+
w = Math.min(w, dstWidth - x);
|
|
4039
|
+
h = Math.min(h, dstHeight - y);
|
|
4040
|
+
if (w <= 0) return;
|
|
4041
|
+
if (h <= 0) return;
|
|
4042
|
+
const startX = mx + (x - targetX);
|
|
4043
|
+
const startY = my + (y - targetY);
|
|
4044
|
+
const sX0 = Math.max(0, startX);
|
|
4045
|
+
const sY0 = Math.max(0, startY);
|
|
4046
|
+
const sX1 = Math.min(srcWidth, startX + w);
|
|
4047
|
+
const sY1 = Math.min(srcHeight, startY + h);
|
|
4048
|
+
const finalW = sX1 - sX0;
|
|
4049
|
+
const finalH = sY1 - sY0;
|
|
4050
|
+
if (finalW <= 0) return;
|
|
4051
|
+
if (finalH <= 0) return;
|
|
4052
|
+
const xShift = sX0 - startX;
|
|
4053
|
+
const yShift = sY0 - startY;
|
|
4054
|
+
const dStride = dstWidth - finalW;
|
|
4055
|
+
const sStride = srcWidth - finalW;
|
|
4056
|
+
let dIdx = (y + yShift) * dstWidth + (x + xShift);
|
|
4057
|
+
let sIdx = sY0 * srcWidth + sX0;
|
|
4058
|
+
for (let iy = 0; iy < finalH; iy++) {
|
|
4059
|
+
for (let ix = 0; ix < finalW; ix++) {
|
|
2940
4060
|
const mVal = src[sIdx];
|
|
2941
|
-
|
|
2942
|
-
if (
|
|
2943
|
-
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
2944
|
-
if (effectiveM === 0) {
|
|
2945
|
-
dst[dIdx] = 0;
|
|
2946
|
-
continue;
|
|
2947
|
-
}
|
|
2948
|
-
weight = globalAlpha === 255 ? effectiveM : effectiveM * globalAlpha + 128 >> 8;
|
|
2949
|
-
} else {
|
|
2950
|
-
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
2951
|
-
if (!isHit) {
|
|
2952
|
-
dst[dIdx] = 0;
|
|
2953
|
-
continue;
|
|
2954
|
-
}
|
|
2955
|
-
weight = globalAlpha;
|
|
2956
|
-
}
|
|
2957
|
-
if (weight === 0) {
|
|
4061
|
+
const isMaskedOut = invertMask ? mVal !== 0 : mVal === 0;
|
|
4062
|
+
if (isMaskedOut) {
|
|
2958
4063
|
dst[dIdx] = 0;
|
|
2959
|
-
continue;
|
|
2960
|
-
}
|
|
2961
|
-
const da = dst[dIdx];
|
|
2962
|
-
if (da === 0) {
|
|
2963
|
-
} else if (weight === 255) {
|
|
2964
|
-
} else if (da === 255) {
|
|
2965
|
-
dst[dIdx] = weight;
|
|
2966
|
-
} else {
|
|
2967
|
-
dst[dIdx] = da * weight + 128 >> 8;
|
|
2968
4064
|
}
|
|
4065
|
+
dIdx++;
|
|
4066
|
+
sIdx++;
|
|
2969
4067
|
}
|
|
4068
|
+
dIdx += dStride;
|
|
4069
|
+
sIdx += sStride;
|
|
2970
4070
|
}
|
|
2971
4071
|
}
|
|
2972
4072
|
|
|
@@ -2974,118 +4074,258 @@ function mergeMasks(dst, dstWidth, src, opts) {
|
|
|
2974
4074
|
var PixelData = class _PixelData {
|
|
2975
4075
|
data32;
|
|
2976
4076
|
imageData;
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
}
|
|
2980
|
-
get height() {
|
|
2981
|
-
return this.imageData.height;
|
|
2982
|
-
}
|
|
4077
|
+
width;
|
|
4078
|
+
height;
|
|
2983
4079
|
constructor(imageData) {
|
|
2984
4080
|
this.data32 = imageDataToUInt32Array(imageData);
|
|
2985
4081
|
this.imageData = imageData;
|
|
4082
|
+
this.width = imageData.width;
|
|
4083
|
+
this.height = imageData.height;
|
|
2986
4084
|
}
|
|
2987
4085
|
set(imageData) {
|
|
4086
|
+
;
|
|
2988
4087
|
this.imageData = imageData;
|
|
2989
4088
|
this.data32 = imageDataToUInt32Array(imageData);
|
|
4089
|
+
this.width = imageData.width;
|
|
4090
|
+
this.height = imageData.height;
|
|
2990
4091
|
}
|
|
2991
|
-
|
|
2992
|
-
* Creates a deep copy of the PixelData using the environment's ImageData constructor.
|
|
2993
|
-
*/
|
|
4092
|
+
// should only be used for debug and testing
|
|
2994
4093
|
copy() {
|
|
2995
|
-
const
|
|
2996
|
-
const
|
|
2997
|
-
const
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
4094
|
+
const data = this.imageData.data;
|
|
4095
|
+
const buffer = new Uint8ClampedArray(data);
|
|
4096
|
+
const Ctor = this.imageData.constructor;
|
|
4097
|
+
const isCtorValid = typeof Ctor === "function";
|
|
4098
|
+
let newImageData;
|
|
4099
|
+
if (isCtorValid && Ctor !== Object) {
|
|
4100
|
+
const ImageConstructor = Ctor;
|
|
4101
|
+
newImageData = new ImageConstructor(buffer, this.width, this.height);
|
|
4102
|
+
} else {
|
|
4103
|
+
newImageData = {
|
|
4104
|
+
width: this.width,
|
|
4105
|
+
height: this.height,
|
|
4106
|
+
data: buffer
|
|
4107
|
+
};
|
|
4108
|
+
}
|
|
3002
4109
|
return new _PixelData(newImageData);
|
|
3003
4110
|
}
|
|
3004
4111
|
};
|
|
3005
4112
|
|
|
3006
|
-
// src/PixelData/
|
|
3007
|
-
function
|
|
3008
|
-
const
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
4113
|
+
// src/PixelData/blendPixelDataAlphaMask.ts
|
|
4114
|
+
function blendPixelDataAlphaMask(dst, src, alphaMask, opts = {}) {
|
|
4115
|
+
const {
|
|
4116
|
+
x: targetX = 0,
|
|
4117
|
+
y: targetY = 0,
|
|
4118
|
+
sx: sourceX = 0,
|
|
4119
|
+
sy: sourceY = 0,
|
|
4120
|
+
w: width = src.width,
|
|
4121
|
+
h: height = src.height,
|
|
4122
|
+
alpha: globalAlpha = 255,
|
|
4123
|
+
blendFn = sourceOverPerfect,
|
|
4124
|
+
mw = src.width,
|
|
4125
|
+
mx = 0,
|
|
4126
|
+
my = 0,
|
|
4127
|
+
invertMask = false
|
|
4128
|
+
} = opts;
|
|
4129
|
+
if (globalAlpha === 0) return;
|
|
4130
|
+
let x = targetX;
|
|
4131
|
+
let y = targetY;
|
|
4132
|
+
let sx = sourceX;
|
|
4133
|
+
let sy = sourceY;
|
|
4134
|
+
let w = width;
|
|
4135
|
+
let h = height;
|
|
4136
|
+
if (sx < 0) {
|
|
4137
|
+
x -= sx;
|
|
4138
|
+
w += sx;
|
|
4139
|
+
sx = 0;
|
|
4140
|
+
}
|
|
4141
|
+
if (sy < 0) {
|
|
4142
|
+
y -= sy;
|
|
4143
|
+
h += sy;
|
|
4144
|
+
sy = 0;
|
|
4145
|
+
}
|
|
4146
|
+
w = Math.min(w, src.width - sx);
|
|
4147
|
+
h = Math.min(h, src.height - sy);
|
|
4148
|
+
if (x < 0) {
|
|
4149
|
+
sx -= x;
|
|
4150
|
+
w += x;
|
|
4151
|
+
x = 0;
|
|
4152
|
+
}
|
|
4153
|
+
if (y < 0) {
|
|
4154
|
+
sy -= y;
|
|
4155
|
+
h += y;
|
|
4156
|
+
y = 0;
|
|
4157
|
+
}
|
|
4158
|
+
const actualW = Math.min(w, dst.width - x);
|
|
4159
|
+
const actualH = Math.min(h, dst.height - y);
|
|
4160
|
+
if (actualW <= 0 || actualH <= 0) return;
|
|
4161
|
+
const dw = dst.width;
|
|
4162
|
+
const sw = src.width;
|
|
4163
|
+
const mPitch = mw;
|
|
4164
|
+
const dx = x - targetX | 0;
|
|
4165
|
+
const dy = y - targetY | 0;
|
|
4166
|
+
const dst32 = dst.data32;
|
|
4167
|
+
const src32 = src.data32;
|
|
4168
|
+
let dIdx = y * dw + x | 0;
|
|
4169
|
+
let sIdx = sy * sw + sx | 0;
|
|
4170
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
4171
|
+
const dStride = dw - actualW | 0;
|
|
4172
|
+
const sStride = sw - actualW | 0;
|
|
4173
|
+
const mStride = mPitch - actualW | 0;
|
|
4174
|
+
const isOpaque = globalAlpha === 255;
|
|
4175
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
4176
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
4177
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
4178
|
+
const mVal = alphaMask[mIdx];
|
|
4179
|
+
const effM = invertMask ? 255 - mVal : mVal;
|
|
4180
|
+
if (effM === 0) {
|
|
4181
|
+
dIdx++;
|
|
4182
|
+
sIdx++;
|
|
4183
|
+
mIdx++;
|
|
4184
|
+
continue;
|
|
4185
|
+
}
|
|
4186
|
+
const srcCol = src32[sIdx];
|
|
4187
|
+
const srcAlpha = srcCol >>> 24;
|
|
4188
|
+
if (srcAlpha === 0 && !isOverwrite) {
|
|
4189
|
+
dIdx++;
|
|
4190
|
+
sIdx++;
|
|
4191
|
+
mIdx++;
|
|
4192
|
+
continue;
|
|
4193
|
+
}
|
|
4194
|
+
let weight = globalAlpha;
|
|
4195
|
+
if (isOpaque) {
|
|
4196
|
+
weight = effM;
|
|
4197
|
+
} else if (effM !== 255) {
|
|
4198
|
+
weight = effM * globalAlpha + 128 >> 8;
|
|
4199
|
+
}
|
|
4200
|
+
if (weight === 0) {
|
|
4201
|
+
dIdx++;
|
|
4202
|
+
sIdx++;
|
|
4203
|
+
mIdx++;
|
|
4204
|
+
continue;
|
|
4205
|
+
}
|
|
4206
|
+
let finalCol = srcCol;
|
|
4207
|
+
if (weight < 255) {
|
|
4208
|
+
const a = srcAlpha * weight + 128 >> 8;
|
|
4209
|
+
if (a === 0 && !isOverwrite) {
|
|
4210
|
+
dIdx++;
|
|
4211
|
+
sIdx++;
|
|
4212
|
+
mIdx++;
|
|
4213
|
+
continue;
|
|
3036
4214
|
}
|
|
4215
|
+
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
3037
4216
|
}
|
|
4217
|
+
dst32[dIdx] = blendFn(finalCol, dst32[dIdx]);
|
|
4218
|
+
dIdx++;
|
|
4219
|
+
sIdx++;
|
|
4220
|
+
mIdx++;
|
|
3038
4221
|
}
|
|
4222
|
+
dIdx += dStride;
|
|
4223
|
+
sIdx += sStride;
|
|
4224
|
+
mIdx += mStride;
|
|
3039
4225
|
}
|
|
3040
4226
|
}
|
|
3041
4227
|
|
|
3042
|
-
// src/PixelData/
|
|
3043
|
-
function
|
|
3044
|
-
const
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
4228
|
+
// src/PixelData/blendPixelDataBinaryMask.ts
|
|
4229
|
+
function blendPixelDataBinaryMask(dst, src, binaryMask, opts) {
|
|
4230
|
+
const {
|
|
4231
|
+
x: targetX = 0,
|
|
4232
|
+
y: targetY = 0,
|
|
4233
|
+
sx: sourceX = 0,
|
|
4234
|
+
sy: sourceY = 0,
|
|
4235
|
+
w: width = src.width,
|
|
4236
|
+
h: height = src.height,
|
|
4237
|
+
alpha: globalAlpha = 255,
|
|
4238
|
+
blendFn = sourceOverPerfect,
|
|
4239
|
+
mw = src.width,
|
|
4240
|
+
mx = 0,
|
|
4241
|
+
my = 0,
|
|
4242
|
+
invertMask = false
|
|
4243
|
+
} = opts;
|
|
4244
|
+
if (globalAlpha === 0) return;
|
|
4245
|
+
let x = targetX;
|
|
4246
|
+
let y = targetY;
|
|
4247
|
+
let sx = sourceX;
|
|
4248
|
+
let sy = sourceY;
|
|
4249
|
+
let w = width;
|
|
4250
|
+
let h = height;
|
|
4251
|
+
if (sx < 0) {
|
|
4252
|
+
x -= sx;
|
|
4253
|
+
w += sx;
|
|
4254
|
+
sx = 0;
|
|
4255
|
+
}
|
|
4256
|
+
if (sy < 0) {
|
|
4257
|
+
y -= sy;
|
|
4258
|
+
h += sy;
|
|
4259
|
+
sy = 0;
|
|
4260
|
+
}
|
|
4261
|
+
w = Math.min(w, src.width - sx);
|
|
4262
|
+
h = Math.min(h, src.height - sy);
|
|
4263
|
+
if (x < 0) {
|
|
4264
|
+
sx -= x;
|
|
4265
|
+
w += x;
|
|
4266
|
+
x = 0;
|
|
4267
|
+
}
|
|
4268
|
+
if (y < 0) {
|
|
4269
|
+
sy -= y;
|
|
4270
|
+
h += y;
|
|
4271
|
+
y = 0;
|
|
4272
|
+
}
|
|
4273
|
+
const actualW = Math.min(w, dst.width - x);
|
|
4274
|
+
const actualH = Math.min(h, dst.height - y);
|
|
4275
|
+
if (actualW <= 0 || actualH <= 0) return;
|
|
4276
|
+
const dx = x - targetX | 0;
|
|
4277
|
+
const dy = y - targetY | 0;
|
|
4278
|
+
const dst32 = dst.data32;
|
|
4279
|
+
const src32 = src.data32;
|
|
4280
|
+
const dw = dst.width;
|
|
4281
|
+
const sw = src.width;
|
|
4282
|
+
const mPitch = mw;
|
|
4283
|
+
let dIdx = y * dw + x | 0;
|
|
4284
|
+
let sIdx = sy * sw + sx | 0;
|
|
4285
|
+
let mIdx = (my + dy) * mPitch + (mx + dx) | 0;
|
|
4286
|
+
const dStride = dw - actualW | 0;
|
|
4287
|
+
const sStride = sw - actualW | 0;
|
|
4288
|
+
const mStride = mPitch - actualW | 0;
|
|
4289
|
+
const skipVal = invertMask ? 1 : 0;
|
|
4290
|
+
const isOpaque = globalAlpha === 255;
|
|
4291
|
+
const isOverwrite = blendFn.isOverwrite || false;
|
|
4292
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
4293
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
4294
|
+
if (binaryMask[mIdx] === skipVal) {
|
|
4295
|
+
dIdx++;
|
|
4296
|
+
sIdx++;
|
|
4297
|
+
mIdx++;
|
|
4298
|
+
continue;
|
|
4299
|
+
}
|
|
4300
|
+
const srcCol = src32[sIdx];
|
|
4301
|
+
const srcAlpha = srcCol >>> 24;
|
|
4302
|
+
if (srcAlpha === 0 && !isOverwrite) {
|
|
4303
|
+
dIdx++;
|
|
4304
|
+
sIdx++;
|
|
4305
|
+
mIdx++;
|
|
4306
|
+
continue;
|
|
3069
4307
|
}
|
|
4308
|
+
let finalCol = srcCol;
|
|
4309
|
+
if (!isOpaque) {
|
|
4310
|
+
const a = srcAlpha * globalAlpha + 128 >> 8;
|
|
4311
|
+
if (a === 0 && !isOverwrite) {
|
|
4312
|
+
dIdx++;
|
|
4313
|
+
sIdx++;
|
|
4314
|
+
mIdx++;
|
|
4315
|
+
continue;
|
|
4316
|
+
}
|
|
4317
|
+
finalCol = (srcCol & 16777215 | a << 24) >>> 0;
|
|
4318
|
+
}
|
|
4319
|
+
dst32[dIdx] = blendFn(finalCol, dst32[dIdx]);
|
|
4320
|
+
dIdx++;
|
|
4321
|
+
sIdx++;
|
|
4322
|
+
mIdx++;
|
|
3070
4323
|
}
|
|
4324
|
+
dIdx += dStride;
|
|
4325
|
+
sIdx += sStride;
|
|
4326
|
+
mIdx += mStride;
|
|
3071
4327
|
}
|
|
3072
4328
|
}
|
|
3073
|
-
function getRectBrushBounds(centerX, centerY, brushWidth, brushHeight, targetWidth, targetHeight) {
|
|
3074
|
-
const rawStartX = Math.floor(centerX - brushWidth / 2);
|
|
3075
|
-
const rawStartY = Math.floor(centerY - brushHeight / 2);
|
|
3076
|
-
const rawEndX = rawStartX + brushWidth;
|
|
3077
|
-
const rawEndY = rawStartY + brushHeight;
|
|
3078
|
-
const startX = targetWidth !== void 0 ? Math.max(0, rawStartX) : rawStartX;
|
|
3079
|
-
const startY = targetHeight !== void 0 ? Math.max(0, rawStartY) : rawStartY;
|
|
3080
|
-
const endX = targetWidth !== void 0 ? Math.min(targetWidth, rawEndX) : rawEndX;
|
|
3081
|
-
const endY = targetHeight !== void 0 ? Math.min(targetHeight, rawEndY) : rawEndY;
|
|
3082
|
-
return {
|
|
3083
|
-
x: startX,
|
|
3084
|
-
y: startY,
|
|
3085
|
-
w: endX - startX,
|
|
3086
|
-
h: endY - startY
|
|
3087
|
-
};
|
|
3088
|
-
}
|
|
3089
4329
|
|
|
3090
4330
|
// src/PixelData/clearPixelData.ts
|
|
3091
4331
|
function clearPixelData(dst, rect) {
|
|
@@ -3093,32 +4333,40 @@ function clearPixelData(dst, rect) {
|
|
|
3093
4333
|
}
|
|
3094
4334
|
|
|
3095
4335
|
// src/PixelData/extractPixelDataBuffer.ts
|
|
4336
|
+
var SCRATCH_BLIT4 = makeClippedBlit();
|
|
3096
4337
|
function extractPixelDataBuffer(source, _x, _y, _w, _h) {
|
|
3097
|
-
const {
|
|
4338
|
+
const {
|
|
4339
|
+
x,
|
|
4340
|
+
y,
|
|
4341
|
+
w,
|
|
4342
|
+
h
|
|
4343
|
+
} = typeof _x === "object" ? _x : {
|
|
4344
|
+
x: _x,
|
|
4345
|
+
y: _y,
|
|
4346
|
+
w: _w,
|
|
4347
|
+
h: _h
|
|
4348
|
+
};
|
|
3098
4349
|
const srcW = source.width;
|
|
3099
4350
|
const srcH = source.height;
|
|
3100
4351
|
const srcData = source.data32;
|
|
3101
4352
|
if (w <= 0 || h <= 0) {
|
|
3102
4353
|
return new Uint32Array(0);
|
|
3103
4354
|
}
|
|
3104
|
-
const
|
|
3105
|
-
const
|
|
3106
|
-
|
|
3107
|
-
const
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
for (let row = 0; row <
|
|
3116
|
-
const
|
|
3117
|
-
const
|
|
3118
|
-
const
|
|
3119
|
-
const dstCol = x0 - x;
|
|
3120
|
-
const dstStart = dstRow * w + dstCol;
|
|
3121
|
-
const chunk = srcData.subarray(srcStart, srcStart + copyWidth);
|
|
4355
|
+
const dstData = new Uint32Array(w * h);
|
|
4356
|
+
const clip = resolveBlitClipping(0, 0, x, y, w, h, w, h, srcW, srcH, SCRATCH_BLIT4);
|
|
4357
|
+
if (!clip.inBounds) return dstData;
|
|
4358
|
+
const {
|
|
4359
|
+
x: dstX,
|
|
4360
|
+
y: dstY,
|
|
4361
|
+
sx: srcX,
|
|
4362
|
+
sy: srcY,
|
|
4363
|
+
w: copyW,
|
|
4364
|
+
h: copyH
|
|
4365
|
+
} = clip;
|
|
4366
|
+
for (let row = 0; row < copyH; row++) {
|
|
4367
|
+
const srcStart = (srcY + row) * srcW + srcX;
|
|
4368
|
+
const dstStart = (dstY + row) * w + dstX;
|
|
4369
|
+
const chunk = srcData.subarray(srcStart, srcStart + copyW);
|
|
3122
4370
|
dstData.set(chunk, dstStart);
|
|
3123
4371
|
}
|
|
3124
4372
|
return dstData;
|
|
@@ -3126,13 +4374,59 @@ function extractPixelDataBuffer(source, _x, _y, _w, _h) {
|
|
|
3126
4374
|
|
|
3127
4375
|
// src/PixelData/extractPixelData.ts
|
|
3128
4376
|
function extractPixelData(source, _x, _y, _w, _h) {
|
|
3129
|
-
const {
|
|
4377
|
+
const {
|
|
4378
|
+
x,
|
|
4379
|
+
y,
|
|
4380
|
+
w,
|
|
4381
|
+
h
|
|
4382
|
+
} = typeof _x === "object" ? _x : {
|
|
4383
|
+
x: _x,
|
|
4384
|
+
y: _y,
|
|
4385
|
+
w: _w,
|
|
4386
|
+
h: _h
|
|
4387
|
+
};
|
|
3130
4388
|
const result = new PixelData(new ImageData(w, h));
|
|
3131
4389
|
const buffer = extractPixelDataBuffer(source, x, y, w, h);
|
|
3132
4390
|
result.data32.set(buffer);
|
|
3133
4391
|
return result;
|
|
3134
4392
|
}
|
|
3135
4393
|
|
|
4394
|
+
// src/PixelData/PixelBuffer32.ts
|
|
4395
|
+
var PixelBuffer32 = class _PixelBuffer32 {
|
|
4396
|
+
constructor(width, height, data32) {
|
|
4397
|
+
this.width = width;
|
|
4398
|
+
this.height = height;
|
|
4399
|
+
this.data32 = data32 ?? new Uint32Array(width * height);
|
|
4400
|
+
}
|
|
4401
|
+
data32;
|
|
4402
|
+
set(width, height, data32) {
|
|
4403
|
+
;
|
|
4404
|
+
this.data32 = data32 ?? new Uint32Array(width * height);
|
|
4405
|
+
this.width = width;
|
|
4406
|
+
this.height = height;
|
|
4407
|
+
}
|
|
4408
|
+
copy() {
|
|
4409
|
+
const newData32 = new Uint32Array(this.data32);
|
|
4410
|
+
return new _PixelBuffer32(this.width, this.height, newData32);
|
|
4411
|
+
}
|
|
4412
|
+
};
|
|
4413
|
+
|
|
4414
|
+
// src/PixelData/pixelDataToAlphaMask.ts
|
|
4415
|
+
function pixelDataToAlphaMask(pixelData) {
|
|
4416
|
+
const {
|
|
4417
|
+
data32,
|
|
4418
|
+
width,
|
|
4419
|
+
height
|
|
4420
|
+
} = pixelData;
|
|
4421
|
+
const len = data32.length;
|
|
4422
|
+
const mask = new Uint8Array(width * height);
|
|
4423
|
+
for (let i = 0; i < len; i++) {
|
|
4424
|
+
const val = data32[i];
|
|
4425
|
+
mask[i] = val >>> 24 & 255;
|
|
4426
|
+
}
|
|
4427
|
+
return mask;
|
|
4428
|
+
}
|
|
4429
|
+
|
|
3136
4430
|
// src/PixelData/reflectPixelData.ts
|
|
3137
4431
|
function reflectPixelDataHorizontal(pixelData) {
|
|
3138
4432
|
const width = pixelData.width;
|
|
@@ -3170,12 +4464,12 @@ function reflectPixelDataVertical(pixelData) {
|
|
|
3170
4464
|
|
|
3171
4465
|
// src/PixelData/resamplePixelData.ts
|
|
3172
4466
|
function resamplePixelData(pixelData, factor) {
|
|
3173
|
-
const {
|
|
3174
|
-
|
|
3175
|
-
new Uint8ClampedArray(data.buffer),
|
|
4467
|
+
const {
|
|
4468
|
+
data,
|
|
3176
4469
|
width,
|
|
3177
4470
|
height
|
|
3178
|
-
)
|
|
4471
|
+
} = resample32(pixelData.data32, pixelData.width, pixelData.height, factor);
|
|
4472
|
+
return new PixelData(new ImageData(new Uint8ClampedArray(data.buffer), width, height));
|
|
3179
4473
|
}
|
|
3180
4474
|
|
|
3181
4475
|
// src/PixelData/rotatePixelData.ts
|
|
@@ -3199,11 +4493,7 @@ function rotatePixelData(pixelData) {
|
|
|
3199
4493
|
newData32[newIdx] = data[oldIdx];
|
|
3200
4494
|
}
|
|
3201
4495
|
}
|
|
3202
|
-
const newImageData = new ImageData(
|
|
3203
|
-
new Uint8ClampedArray(newData32.buffer),
|
|
3204
|
-
newWidth,
|
|
3205
|
-
newHeight
|
|
3206
|
-
);
|
|
4496
|
+
const newImageData = new ImageData(new Uint8ClampedArray(newData32.buffer), newWidth, newHeight);
|
|
3207
4497
|
pixelData.set(newImageData);
|
|
3208
4498
|
}
|
|
3209
4499
|
function rotateSquareInPlace(pixelData) {
|
|
@@ -3225,8 +4515,14 @@ function rotateSquareInPlace(pixelData) {
|
|
|
3225
4515
|
}
|
|
3226
4516
|
|
|
3227
4517
|
// src/PixelData/writePixelDataBuffer.ts
|
|
4518
|
+
var SCRATCH_BLIT5 = makeClippedBlit();
|
|
3228
4519
|
function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
3229
|
-
const {
|
|
4520
|
+
const {
|
|
4521
|
+
x,
|
|
4522
|
+
y,
|
|
4523
|
+
w,
|
|
4524
|
+
h
|
|
4525
|
+
} = typeof _x === "object" ? _x : {
|
|
3230
4526
|
x: _x,
|
|
3231
4527
|
y: _y,
|
|
3232
4528
|
w: _w,
|
|
@@ -3235,45 +4531,52 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
3235
4531
|
const dstW = target.width;
|
|
3236
4532
|
const dstH = target.height;
|
|
3237
4533
|
const dstData = target.data32;
|
|
3238
|
-
const
|
|
3239
|
-
|
|
3240
|
-
const
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
const
|
|
3251
|
-
|
|
3252
|
-
const srcStart = srcRow * w + srcCol;
|
|
3253
|
-
dstData.set(data.subarray(srcStart, srcStart + rowLen), dstStart);
|
|
4534
|
+
const clip = resolveBlitClipping(x, y, 0, 0, w, h, dstW, dstH, w, h, SCRATCH_BLIT5);
|
|
4535
|
+
if (!clip.inBounds) return;
|
|
4536
|
+
const {
|
|
4537
|
+
x: dstX,
|
|
4538
|
+
y: dstY,
|
|
4539
|
+
sx: srcX,
|
|
4540
|
+
sy: srcY,
|
|
4541
|
+
w: copyW,
|
|
4542
|
+
h: copyH
|
|
4543
|
+
} = clip;
|
|
4544
|
+
for (let row = 0; row < copyH; row++) {
|
|
4545
|
+
const dstStart = (dstY + row) * dstW + dstX;
|
|
4546
|
+
const srcStart = (srcY + row) * w + srcX;
|
|
4547
|
+
dstData.set(data.subarray(srcStart, srcStart + copyW), dstStart);
|
|
3254
4548
|
}
|
|
3255
4549
|
}
|
|
3256
4550
|
export {
|
|
3257
4551
|
BASE_FAST_BLEND_MODE_FUNCTIONS,
|
|
3258
4552
|
BASE_PERFECT_BLEND_MODE_FUNCTIONS,
|
|
3259
4553
|
BaseBlendMode,
|
|
4554
|
+
CANVAS_CTX_FAILED,
|
|
3260
4555
|
HistoryManager,
|
|
3261
4556
|
IndexedImage,
|
|
3262
4557
|
MaskType,
|
|
4558
|
+
OFFSCREEN_CANVAS_CTX_FAILED,
|
|
3263
4559
|
PixelAccumulator,
|
|
4560
|
+
PixelBuffer32,
|
|
3264
4561
|
PixelData,
|
|
3265
4562
|
PixelEngineConfig,
|
|
3266
4563
|
PixelTile,
|
|
3267
4564
|
PixelWriter,
|
|
3268
4565
|
UnsupportedFormatError,
|
|
4566
|
+
applyAlphaMaskToPixelData,
|
|
4567
|
+
applyBinaryMaskToAlphaMask,
|
|
4568
|
+
applyBinaryMaskToPixelData,
|
|
3269
4569
|
applyCircleBrushToPixelData,
|
|
3270
|
-
applyMaskToPixelData,
|
|
3271
4570
|
applyPatchTiles,
|
|
3272
4571
|
applyRectBrushToPixelData,
|
|
3273
4572
|
base64DecodeArrayBuffer,
|
|
3274
4573
|
base64EncodeArrayBuffer,
|
|
3275
4574
|
blendColorPixelData,
|
|
4575
|
+
blendColorPixelDataAlphaMask,
|
|
4576
|
+
blendColorPixelDataBinaryMask,
|
|
3276
4577
|
blendPixelData,
|
|
4578
|
+
blendPixelDataAlphaMask,
|
|
4579
|
+
blendPixelDataBinaryMask,
|
|
3277
4580
|
clearPixelData,
|
|
3278
4581
|
color32ToCssRGBA,
|
|
3279
4582
|
color32ToHex,
|
|
@@ -3306,9 +4609,13 @@ export {
|
|
|
3306
4609
|
fileToImageData,
|
|
3307
4610
|
fillPixelData,
|
|
3308
4611
|
floodFillSelection,
|
|
4612
|
+
forEachLinePoint,
|
|
4613
|
+
getCircleBrushOrPencilBounds,
|
|
4614
|
+
getCircleBrushOrPencilStrokeBounds,
|
|
3309
4615
|
getImageDataFromClipboard,
|
|
3310
4616
|
getIndexedImageColorCounts,
|
|
3311
|
-
|
|
4617
|
+
getRectBrushOrPencilBounds,
|
|
4618
|
+
getRectBrushOrPencilStrokeBounds,
|
|
3312
4619
|
getSupportedPixelFormats,
|
|
3313
4620
|
hardLightFast,
|
|
3314
4621
|
hardLightPerfect,
|
|
@@ -3340,17 +4647,29 @@ export {
|
|
|
3340
4647
|
makeBlendModeRegistry,
|
|
3341
4648
|
makeFastBlendModeRegistry,
|
|
3342
4649
|
makeFullPixelMutator,
|
|
4650
|
+
makeImageDataLike,
|
|
3343
4651
|
makePerfectBlendModeRegistry,
|
|
3344
4652
|
makePixelCanvas,
|
|
3345
4653
|
makeReusableCanvas,
|
|
3346
4654
|
makeReusableImageData,
|
|
3347
|
-
|
|
4655
|
+
mergeAlphaMasks,
|
|
4656
|
+
mergeBinaryMasks,
|
|
3348
4657
|
multiplyFast,
|
|
3349
4658
|
multiplyPerfect,
|
|
3350
|
-
|
|
4659
|
+
mutatorApplyAlphaMask,
|
|
4660
|
+
mutatorApplyBinaryMask,
|
|
4661
|
+
mutatorApplyCircleBrush,
|
|
4662
|
+
mutatorApplyCircleBrushStroke,
|
|
4663
|
+
mutatorApplyCirclePencil,
|
|
4664
|
+
mutatorApplyCirclePencilStroke,
|
|
4665
|
+
mutatorApplyRectBrush,
|
|
4666
|
+
mutatorApplyRectBrushStroke,
|
|
4667
|
+
mutatorApplyRectPencil,
|
|
4668
|
+
mutatorApplyRectPencilStroke,
|
|
3351
4669
|
mutatorBlendColor,
|
|
3352
4670
|
mutatorBlendPixel,
|
|
3353
4671
|
mutatorBlendPixelData,
|
|
4672
|
+
mutatorClear,
|
|
3354
4673
|
mutatorFill,
|
|
3355
4674
|
mutatorInvert,
|
|
3356
4675
|
overlayFast,
|
|
@@ -3380,7 +4699,10 @@ export {
|
|
|
3380
4699
|
sourceOverPerfect,
|
|
3381
4700
|
subtractFast,
|
|
3382
4701
|
subtractPerfect,
|
|
4702
|
+
toBlendModeIndexAndName,
|
|
3383
4703
|
trimRectBounds,
|
|
4704
|
+
uInt32ArrayToImageData,
|
|
4705
|
+
uInt32ArrayToImageDataLike,
|
|
3384
4706
|
unpackAlpha,
|
|
3385
4707
|
unpackBlue,
|
|
3386
4708
|
unpackColor,
|