pixel-data-js 0.15.1 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.dev.cjs +1884 -1203
- package/dist/index.dev.cjs.map +1 -1
- package/dist/index.dev.js +1858 -1190
- package/dist/index.dev.js.map +1 -1
- package/dist/index.prod.cjs +1884 -1203
- package/dist/index.prod.cjs.map +1 -1
- package/dist/index.prod.d.ts +320 -66
- package/dist/index.prod.js +1858 -1190
- package/dist/index.prod.js.map +1 -1
- package/package.json +1 -1
- package/src/BlendModes/BlendModeRegistry.ts +62 -0
- package/src/BlendModes/blend-modes-fast.ts +31 -84
- package/src/BlendModes/blend-modes-perfect.ts +343 -215
- package/src/BlendModes/blend-modes.ts +28 -30
- package/src/History/HistoryManager.ts +83 -0
- package/src/History/PixelAccumulator.ts +191 -0
- package/src/History/PixelEngineConfig.ts +18 -0
- package/src/History/PixelMutator/mutatorApplyMask.ts +20 -0
- package/src/History/PixelMutator/mutatorBlendColor.ts +22 -0
- package/src/History/PixelMutator/mutatorBlendPixel.ts +37 -0
- package/src/History/PixelMutator/mutatorBlendPixelData.ts +24 -0
- package/src/History/PixelMutator/mutatorFillPixelData.ts +21 -0
- package/src/History/PixelMutator/mutatorInvert.ts +18 -0
- package/src/History/PixelMutator.ts +18 -0
- package/src/History/PixelPatchTiles.ts +52 -0
- package/src/History/PixelWriter.ts +79 -0
- package/src/ImageData/{writeImageDataPixels.ts → writeImageDataBuffer.ts} +3 -3
- package/src/PixelData/applyCircleBrushToPixelData.ts +69 -0
- package/src/PixelData/applyMaskToPixelData.ts +1 -1
- package/src/PixelData/applyRectBrushToPixelData.ts +102 -0
- package/src/PixelData/blendPixelData.ts +2 -3
- package/src/PixelData/invertPixelData.ts +74 -7
- package/src/PixelData/writePixelDataBuffer.ts +65 -0
- package/src/_types.ts +31 -11
- package/src/index.ts +20 -10
- package/src/BlendModes/blend-mode-getters.ts +0 -14
package/dist/index.dev.cjs
CHANGED
|
@@ -20,22 +20,22 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var src_exports = {};
|
|
22
22
|
__export(src_exports, {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
FAST_BLEND_TO_INDEX: () => FAST_BLEND_TO_INDEX,
|
|
28
|
-
INDEX_TO_FAST_BLEND: () => INDEX_TO_FAST_BLEND,
|
|
29
|
-
INDEX_TO_PERFECT_BLEND: () => INDEX_TO_PERFECT_BLEND,
|
|
23
|
+
BASE_FAST_BLEND_MODE_FUNCTIONS: () => BASE_FAST_BLEND_MODE_FUNCTIONS,
|
|
24
|
+
BASE_PERFECT_BLEND_MODE_FUNCTIONS: () => BASE_PERFECT_BLEND_MODE_FUNCTIONS,
|
|
25
|
+
BaseBlendMode: () => BaseBlendMode,
|
|
26
|
+
HistoryManager: () => HistoryManager,
|
|
30
27
|
IndexedImage: () => IndexedImage,
|
|
31
28
|
MaskType: () => MaskType,
|
|
32
|
-
|
|
33
|
-
PERFECT_BLEND_MODES: () => PERFECT_BLEND_MODES,
|
|
34
|
-
PERFECT_BLEND_MODE_BY_NAME: () => PERFECT_BLEND_MODE_BY_NAME,
|
|
35
|
-
PERFECT_BLEND_TO_INDEX: () => PERFECT_BLEND_TO_INDEX,
|
|
29
|
+
PixelAccumulator: () => PixelAccumulator,
|
|
36
30
|
PixelData: () => PixelData,
|
|
31
|
+
PixelEngineConfig: () => PixelEngineConfig,
|
|
32
|
+
PixelTile: () => PixelTile,
|
|
33
|
+
PixelWriter: () => PixelWriter,
|
|
37
34
|
UnsupportedFormatError: () => UnsupportedFormatError,
|
|
35
|
+
applyCircleBrushToPixelData: () => applyCircleBrushToPixelData,
|
|
38
36
|
applyMaskToPixelData: () => applyMaskToPixelData,
|
|
37
|
+
applyPatchTiles: () => applyPatchTiles,
|
|
38
|
+
applyRectBrushToPixelData: () => applyRectBrushToPixelData,
|
|
39
39
|
base64DecodeArrayBuffer: () => base64DecodeArrayBuffer,
|
|
40
40
|
base64EncodeArrayBuffer: () => base64EncodeArrayBuffer,
|
|
41
41
|
blendColorPixelData: () => blendColorPixelData,
|
|
@@ -74,6 +74,7 @@ __export(src_exports, {
|
|
|
74
74
|
floodFillSelection: () => floodFillSelection,
|
|
75
75
|
getImageDataFromClipboard: () => getImageDataFromClipboard,
|
|
76
76
|
getIndexedImageColorCounts: () => getIndexedImageColorCounts,
|
|
77
|
+
getRectBrushBounds: () => getRectBrushBounds,
|
|
77
78
|
getSupportedPixelFormats: () => getSupportedPixelFormats,
|
|
78
79
|
hardLightFast: () => hardLightFast,
|
|
79
80
|
hardLightPerfect: () => hardLightPerfect,
|
|
@@ -102,14 +103,25 @@ __export(src_exports, {
|
|
|
102
103
|
linearDodgePerfect: () => linearDodgePerfect,
|
|
103
104
|
linearLightFast: () => linearLightFast,
|
|
104
105
|
linearLightPerfect: () => linearLightPerfect,
|
|
106
|
+
makeBlendModeRegistry: () => makeBlendModeRegistry,
|
|
107
|
+
makeFastBlendModeRegistry: () => makeFastBlendModeRegistry,
|
|
108
|
+
makeFullPixelMutator: () => makeFullPixelMutator,
|
|
109
|
+
makePerfectBlendModeRegistry: () => makePerfectBlendModeRegistry,
|
|
105
110
|
makePixelCanvas: () => makePixelCanvas,
|
|
106
111
|
makeReusableCanvas: () => makeReusableCanvas,
|
|
107
112
|
makeReusableImageData: () => makeReusableImageData,
|
|
108
113
|
mergeMasks: () => mergeMasks,
|
|
109
114
|
multiplyFast: () => multiplyFast,
|
|
110
115
|
multiplyPerfect: () => multiplyPerfect,
|
|
116
|
+
mutatorApplyMask: () => mutatorApplyMask,
|
|
117
|
+
mutatorBlendColor: () => mutatorBlendColor,
|
|
118
|
+
mutatorBlendPixel: () => mutatorBlendPixel,
|
|
119
|
+
mutatorBlendPixelData: () => mutatorBlendPixelData,
|
|
120
|
+
mutatorFill: () => mutatorFill,
|
|
121
|
+
mutatorInvert: () => mutatorInvert,
|
|
111
122
|
overlayFast: () => overlayFast,
|
|
112
123
|
overlayPerfect: () => overlayPerfect,
|
|
124
|
+
overwriteBase: () => overwriteBase,
|
|
113
125
|
overwriteFast: () => overwriteFast,
|
|
114
126
|
overwritePerfect: () => overwritePerfect,
|
|
115
127
|
packColor: () => packColor,
|
|
@@ -144,42 +156,80 @@ __export(src_exports, {
|
|
|
144
156
|
vividLightFast: () => vividLightFast,
|
|
145
157
|
vividLightPerfect: () => vividLightPerfect,
|
|
146
158
|
writeImageData: () => writeImageData,
|
|
147
|
-
|
|
159
|
+
writeImageDataBuffer: () => writeImageDataBuffer,
|
|
148
160
|
writeImageDataToClipboard: () => writeImageDataToClipboard,
|
|
149
|
-
writeImgBlobToClipboard: () => writeImgBlobToClipboard
|
|
161
|
+
writeImgBlobToClipboard: () => writeImgBlobToClipboard,
|
|
162
|
+
writePixelDataBuffer: () => writePixelDataBuffer
|
|
150
163
|
});
|
|
151
164
|
module.exports = __toCommonJS(src_exports);
|
|
152
165
|
|
|
153
166
|
// src/BlendModes/blend-modes.ts
|
|
154
|
-
var
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
})(BlendMode || {});
|
|
167
|
+
var BaseBlendMode = {
|
|
168
|
+
overwrite: 0,
|
|
169
|
+
sourceOver: 1,
|
|
170
|
+
darken: 2,
|
|
171
|
+
multiply: 3,
|
|
172
|
+
colorBurn: 4,
|
|
173
|
+
linearBurn: 5,
|
|
174
|
+
darkerColor: 6,
|
|
175
|
+
lighten: 7,
|
|
176
|
+
screen: 8,
|
|
177
|
+
colorDodge: 9,
|
|
178
|
+
linearDodge: 10,
|
|
179
|
+
lighterColor: 11,
|
|
180
|
+
overlay: 12,
|
|
181
|
+
softLight: 13,
|
|
182
|
+
hardLight: 14,
|
|
183
|
+
vividLight: 15,
|
|
184
|
+
linearLight: 16,
|
|
185
|
+
pinLight: 17,
|
|
186
|
+
hardMix: 18,
|
|
187
|
+
difference: 19,
|
|
188
|
+
exclusion: 20,
|
|
189
|
+
subtract: 21,
|
|
190
|
+
divide: 22
|
|
191
|
+
};
|
|
180
192
|
var overwriteBase = (src, _dst) => src;
|
|
181
193
|
overwriteBase.isOverwrite = true;
|
|
182
194
|
|
|
195
|
+
// src/BlendModes/BlendModeRegistry.ts
|
|
196
|
+
function makeBlendModeRegistry(blendModes, initialEntries) {
|
|
197
|
+
const blendToName = /* @__PURE__ */ new Map();
|
|
198
|
+
const blendToIndex = /* @__PURE__ */ new Map();
|
|
199
|
+
const indexToName = [];
|
|
200
|
+
const indexToBlend = [];
|
|
201
|
+
const nameToBlend = {};
|
|
202
|
+
const nameToIndex = {};
|
|
203
|
+
const add = (name, index, blendFn) => {
|
|
204
|
+
if (!Number.isFinite(index)) {
|
|
205
|
+
throw new Error(`Index "${index}" is not a number. Attempting to add name: "${name}", index: "${index}"`);
|
|
206
|
+
}
|
|
207
|
+
if (indexToBlend[index]) {
|
|
208
|
+
throw new Error(`Blend Mode index: ${index} is already used. Attempting to add name: "${name}", index: "${index}"`);
|
|
209
|
+
}
|
|
210
|
+
indexToName[index] = name;
|
|
211
|
+
indexToBlend[index] = blendFn;
|
|
212
|
+
blendToIndex.set(blendFn, index);
|
|
213
|
+
blendToName.set(blendFn, name);
|
|
214
|
+
nameToBlend[name] = blendFn;
|
|
215
|
+
nameToIndex[name] = index;
|
|
216
|
+
};
|
|
217
|
+
for (const [name, index] of Object.entries(blendModes)) {
|
|
218
|
+
const blend = initialEntries[index];
|
|
219
|
+
add(name, index, blend);
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
nameToBlend,
|
|
223
|
+
nameToIndex,
|
|
224
|
+
blendToIndex,
|
|
225
|
+
blendToName,
|
|
226
|
+
indexToBlend,
|
|
227
|
+
indexToName,
|
|
228
|
+
indexType: null,
|
|
229
|
+
nameType: null
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
183
233
|
// src/BlendModes/blend-modes-fast.ts
|
|
184
234
|
var overwriteFast = overwriteBase;
|
|
185
235
|
var sourceOverFast = (src, dst) => {
|
|
@@ -565,76 +615,34 @@ var divideFast = (src, dst) => {
|
|
|
565
615
|
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
566
616
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
567
617
|
};
|
|
568
|
-
var
|
|
569
|
-
[
|
|
570
|
-
[
|
|
571
|
-
[
|
|
572
|
-
[
|
|
573
|
-
[
|
|
574
|
-
[
|
|
575
|
-
[
|
|
576
|
-
[
|
|
577
|
-
[
|
|
578
|
-
[
|
|
579
|
-
[
|
|
580
|
-
[
|
|
581
|
-
[
|
|
582
|
-
[
|
|
583
|
-
[
|
|
584
|
-
[
|
|
585
|
-
[
|
|
586
|
-
[
|
|
587
|
-
[
|
|
588
|
-
[
|
|
589
|
-
[
|
|
590
|
-
[
|
|
591
|
-
[
|
|
592
|
-
];
|
|
593
|
-
var FAST_BLEND_MODES = [];
|
|
594
|
-
for (const [index, blend] of FAST_BLENDER_REGISTRY) {
|
|
595
|
-
FAST_BLEND_MODES[index] = blend;
|
|
596
|
-
}
|
|
597
|
-
var FAST_BLEND_TO_INDEX = new Map(
|
|
598
|
-
FAST_BLENDER_REGISTRY.map((entry, index) => {
|
|
599
|
-
return [
|
|
600
|
-
entry[1],
|
|
601
|
-
index
|
|
602
|
-
];
|
|
603
|
-
})
|
|
604
|
-
);
|
|
605
|
-
var INDEX_TO_FAST_BLEND = new Map(
|
|
606
|
-
FAST_BLENDER_REGISTRY.map((entry, index) => {
|
|
607
|
-
return [
|
|
608
|
-
index,
|
|
609
|
-
entry[1]
|
|
610
|
-
];
|
|
611
|
-
})
|
|
612
|
-
);
|
|
613
|
-
var FAST_BLEND_MODE_BY_NAME = {
|
|
614
|
-
overwrite: overwriteFast,
|
|
615
|
-
sourceOver: sourceOverFast,
|
|
616
|
-
darken: darkenFast,
|
|
617
|
-
multiply: multiplyFast,
|
|
618
|
-
colorBurn: colorBurnFast,
|
|
619
|
-
linearBurn: linearBurnFast,
|
|
620
|
-
darkerColor: darkerFast,
|
|
621
|
-
lighten: lightenFast,
|
|
622
|
-
screen: screenFast,
|
|
623
|
-
colorDodge: colorDodgeFast,
|
|
624
|
-
linearDodge: linearDodgeFast,
|
|
625
|
-
lighterColor: lighterFast,
|
|
626
|
-
overlay: overlayFast,
|
|
627
|
-
softLight: softLightFast,
|
|
628
|
-
hardLight: hardLightFast,
|
|
629
|
-
vividLight: vividLightFast,
|
|
630
|
-
linearLight: linearLightFast,
|
|
631
|
-
pinLight: pinLightFast,
|
|
632
|
-
hardMix: hardMixFast,
|
|
633
|
-
difference: differenceFast,
|
|
634
|
-
exclusion: exclusionFast,
|
|
635
|
-
subtract: subtractFast,
|
|
636
|
-
divide: divideFast
|
|
618
|
+
var BASE_FAST_BLEND_MODE_FUNCTIONS = {
|
|
619
|
+
[BaseBlendMode.overwrite]: overwriteFast,
|
|
620
|
+
[BaseBlendMode.sourceOver]: sourceOverFast,
|
|
621
|
+
[BaseBlendMode.darken]: darkenFast,
|
|
622
|
+
[BaseBlendMode.multiply]: multiplyFast,
|
|
623
|
+
[BaseBlendMode.colorBurn]: colorBurnFast,
|
|
624
|
+
[BaseBlendMode.linearBurn]: linearBurnFast,
|
|
625
|
+
[BaseBlendMode.darkerColor]: darkerFast,
|
|
626
|
+
[BaseBlendMode.lighten]: lightenFast,
|
|
627
|
+
[BaseBlendMode.screen]: screenFast,
|
|
628
|
+
[BaseBlendMode.colorDodge]: colorDodgeFast,
|
|
629
|
+
[BaseBlendMode.linearDodge]: linearDodgeFast,
|
|
630
|
+
[BaseBlendMode.lighterColor]: lighterFast,
|
|
631
|
+
[BaseBlendMode.overlay]: overlayFast,
|
|
632
|
+
[BaseBlendMode.softLight]: softLightFast,
|
|
633
|
+
[BaseBlendMode.hardLight]: hardLightFast,
|
|
634
|
+
[BaseBlendMode.vividLight]: vividLightFast,
|
|
635
|
+
[BaseBlendMode.linearLight]: linearLightFast,
|
|
636
|
+
[BaseBlendMode.pinLight]: pinLightFast,
|
|
637
|
+
[BaseBlendMode.hardMix]: hardMixFast,
|
|
638
|
+
[BaseBlendMode.difference]: differenceFast,
|
|
639
|
+
[BaseBlendMode.exclusion]: exclusionFast,
|
|
640
|
+
[BaseBlendMode.subtract]: subtractFast,
|
|
641
|
+
[BaseBlendMode.divide]: divideFast
|
|
637
642
|
};
|
|
643
|
+
function makeFastBlendModeRegistry() {
|
|
644
|
+
return makeBlendModeRegistry(BaseBlendMode, BASE_FAST_BLEND_MODE_FUNCTIONS);
|
|
645
|
+
}
|
|
638
646
|
|
|
639
647
|
// src/_types.ts
|
|
640
648
|
var MaskType = /* @__PURE__ */ ((MaskType2) => {
|
|
@@ -1001,14 +1009,18 @@ var sourceOverPerfect = (src, dst) => {
|
|
|
1001
1009
|
const sa = src >>> 24 & 255;
|
|
1002
1010
|
if (sa === 255) return src;
|
|
1003
1011
|
if (sa === 0) return dst;
|
|
1012
|
+
const invA = 255 - sa;
|
|
1004
1013
|
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
1005
1014
|
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
1006
1015
|
const da = dst >>> 24 & 255;
|
|
1007
|
-
const
|
|
1008
|
-
const r =
|
|
1009
|
-
const
|
|
1010
|
-
const
|
|
1011
|
-
const
|
|
1016
|
+
const tR = sr * sa + dr * invA;
|
|
1017
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1018
|
+
const tG = sg * sa + dg * invA;
|
|
1019
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1020
|
+
const tB = sb * sa + db * invA;
|
|
1021
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1022
|
+
const tA = 255 * sa + da * invA;
|
|
1023
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1012
1024
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1013
1025
|
};
|
|
1014
1026
|
var darkenPerfect = (src, dst) => {
|
|
@@ -1021,44 +1033,71 @@ var darkenPerfect = (src, dst) => {
|
|
|
1021
1033
|
const bb = sb < db ? sb : db;
|
|
1022
1034
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1023
1035
|
const invA = 255 - sa;
|
|
1024
|
-
const
|
|
1025
|
-
const
|
|
1026
|
-
const
|
|
1027
|
-
const
|
|
1036
|
+
const da = dst >>> 24 & 255;
|
|
1037
|
+
const tR = br * sa + dr * invA;
|
|
1038
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1039
|
+
const tG = bg * sa + dg * invA;
|
|
1040
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1041
|
+
const tB = bb * sa + db * invA;
|
|
1042
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1043
|
+
const tA = 255 * sa + da * invA;
|
|
1044
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1028
1045
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1029
1046
|
};
|
|
1030
1047
|
var multiplyPerfect = (src, dst) => {
|
|
1031
1048
|
const sa = src >>> 24 & 255;
|
|
1032
1049
|
if (sa === 0) return dst;
|
|
1033
|
-
const
|
|
1034
|
-
const
|
|
1035
|
-
const
|
|
1036
|
-
const
|
|
1037
|
-
const
|
|
1050
|
+
const dr = dst & 255;
|
|
1051
|
+
const dg = dst >>> 8 & 255;
|
|
1052
|
+
const db = dst >>> 16 & 255;
|
|
1053
|
+
const da = dst >>> 24 & 255;
|
|
1054
|
+
const sr = src & 255;
|
|
1055
|
+
const sg = src >>> 8 & 255;
|
|
1056
|
+
const sb = src >>> 16 & 255;
|
|
1057
|
+
const mR = sr * dr;
|
|
1058
|
+
const br = mR + 1 + (mR >> 8) >> 8;
|
|
1059
|
+
const mG = sg * dg;
|
|
1060
|
+
const bg = mG + 1 + (mG >> 8) >> 8;
|
|
1061
|
+
const mB = sb * db;
|
|
1062
|
+
const bb = mB + 1 + (mB >> 8) >> 8;
|
|
1038
1063
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1039
1064
|
const invA = 255 - sa;
|
|
1040
|
-
const
|
|
1041
|
-
const r =
|
|
1042
|
-
const
|
|
1043
|
-
const
|
|
1044
|
-
const
|
|
1065
|
+
const tR = br * sa + dr * invA;
|
|
1066
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1067
|
+
const tG = bg * sa + dg * invA;
|
|
1068
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1069
|
+
const tB = bb * sa + db * invA;
|
|
1070
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1071
|
+
const tA = 255 * sa + da * invA;
|
|
1072
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1045
1073
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1046
1074
|
};
|
|
1047
1075
|
var colorBurnPerfect = (src, dst) => {
|
|
1048
1076
|
const sa = src >>> 24 & 255;
|
|
1049
1077
|
if (sa === 0) return dst;
|
|
1050
|
-
const
|
|
1051
|
-
const
|
|
1052
|
-
const
|
|
1053
|
-
const
|
|
1054
|
-
const
|
|
1078
|
+
const dr = dst & 255;
|
|
1079
|
+
const dg = dst >>> 8 & 255;
|
|
1080
|
+
const db = dst >>> 16 & 255;
|
|
1081
|
+
const sr = src & 255;
|
|
1082
|
+
const sg = src >>> 8 & 255;
|
|
1083
|
+
const sb = src >>> 16 & 255;
|
|
1084
|
+
const resR = dr === 255 ? 255 : sr === 0 ? 0 : 255 - ((255 - dr) * 255 / sr | 0);
|
|
1085
|
+
const br = resR < 0 ? 0 : resR;
|
|
1086
|
+
const resG = dg === 255 ? 255 : sg === 0 ? 0 : 255 - ((255 - dg) * 255 / sg | 0);
|
|
1087
|
+
const bg = resG < 0 ? 0 : resG;
|
|
1088
|
+
const resB = db === 255 ? 255 : sb === 0 ? 0 : 255 - ((255 - db) * 255 / sb | 0);
|
|
1089
|
+
const bb = resB < 0 ? 0 : resB;
|
|
1055
1090
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1056
1091
|
const invA = 255 - sa;
|
|
1057
1092
|
const da = dst >>> 24 & 255;
|
|
1058
|
-
const
|
|
1059
|
-
const
|
|
1060
|
-
const
|
|
1061
|
-
const
|
|
1093
|
+
const tR = br * sa + dr * invA;
|
|
1094
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1095
|
+
const tG = bg * sa + dg * invA;
|
|
1096
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1097
|
+
const tB = bb * sa + db * invA;
|
|
1098
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1099
|
+
const tA = 255 * sa + da * invA;
|
|
1100
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1062
1101
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1063
1102
|
};
|
|
1064
1103
|
var linearBurnPerfect = (src, dst) => {
|
|
@@ -1074,10 +1113,15 @@ var linearBurnPerfect = (src, dst) => {
|
|
|
1074
1113
|
const bb = bbU < 0 ? 0 : bbU;
|
|
1075
1114
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1076
1115
|
const invA = 255 - sa;
|
|
1077
|
-
const
|
|
1078
|
-
const
|
|
1079
|
-
const
|
|
1080
|
-
const
|
|
1116
|
+
const da = dst >>> 24 & 255;
|
|
1117
|
+
const tR = br * sa + dr * invA;
|
|
1118
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1119
|
+
const tG = bg * sa + dg * invA;
|
|
1120
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1121
|
+
const tB = bb * sa + db * invA;
|
|
1122
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1123
|
+
const tA = 255 * sa + da * invA;
|
|
1124
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1081
1125
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1082
1126
|
};
|
|
1083
1127
|
var darkerPerfect = (src, dst) => {
|
|
@@ -1099,10 +1143,15 @@ var darkerPerfect = (src, dst) => {
|
|
|
1099
1143
|
}
|
|
1100
1144
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1101
1145
|
const invA = 255 - sa;
|
|
1102
|
-
const
|
|
1103
|
-
const
|
|
1104
|
-
const
|
|
1105
|
-
const
|
|
1146
|
+
const da = dst >>> 24 & 255;
|
|
1147
|
+
const tR = br * sa + dr * invA;
|
|
1148
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1149
|
+
const tG = bg * sa + dg * invA;
|
|
1150
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1151
|
+
const tB = bb * sa + db * invA;
|
|
1152
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1153
|
+
const tA = 255 * sa + da * invA;
|
|
1154
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1106
1155
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1107
1156
|
};
|
|
1108
1157
|
var lightenPerfect = (src, dst) => {
|
|
@@ -1114,10 +1163,15 @@ var lightenPerfect = (src, dst) => {
|
|
|
1114
1163
|
const bb = (src >>> 16 & 255) > db ? src >>> 16 & 255 : db;
|
|
1115
1164
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1116
1165
|
const invA = 255 - sa;
|
|
1117
|
-
const
|
|
1118
|
-
const
|
|
1119
|
-
const
|
|
1120
|
-
const
|
|
1166
|
+
const da = dst >>> 24 & 255;
|
|
1167
|
+
const tR = br * sa + dr * invA;
|
|
1168
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1169
|
+
const tG = bg * sa + dg * invA;
|
|
1170
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1171
|
+
const tB = bb * sa + db * invA;
|
|
1172
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1173
|
+
const tA = 255 * sa + da * invA;
|
|
1174
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1121
1175
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1122
1176
|
};
|
|
1123
1177
|
var screenPerfect = (src, dst) => {
|
|
@@ -1129,26 +1183,43 @@ var screenPerfect = (src, dst) => {
|
|
|
1129
1183
|
const bb = 255 - ((255 - (src >>> 16 & 255)) * (255 - db) / 255 | 0);
|
|
1130
1184
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1131
1185
|
const invA = 255 - sa;
|
|
1132
|
-
const
|
|
1133
|
-
const
|
|
1134
|
-
const
|
|
1135
|
-
const
|
|
1186
|
+
const da = dst >>> 24 & 255;
|
|
1187
|
+
const tR = br * sa + dr * invA;
|
|
1188
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1189
|
+
const tG = bg * sa + dg * invA;
|
|
1190
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1191
|
+
const tB = bb * sa + db * invA;
|
|
1192
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1193
|
+
const tA = 255 * sa + da * invA;
|
|
1194
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1136
1195
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1137
1196
|
};
|
|
1138
1197
|
var colorDodgePerfect = (src, dst) => {
|
|
1139
1198
|
const sa = src >>> 24 & 255;
|
|
1140
1199
|
if (sa === 0) return dst;
|
|
1141
|
-
const dr = dst & 255
|
|
1142
|
-
const
|
|
1143
|
-
const
|
|
1144
|
-
const
|
|
1145
|
-
const
|
|
1200
|
+
const dr = dst & 255;
|
|
1201
|
+
const dg = dst >>> 8 & 255;
|
|
1202
|
+
const db = dst >>> 16 & 255;
|
|
1203
|
+
const sr = src & 255;
|
|
1204
|
+
const sg = src >>> 8 & 255;
|
|
1205
|
+
const sb = src >>> 16 & 255;
|
|
1206
|
+
const resR = sr === 255 ? 255 : dr * 255 / (255 - sr) | 0;
|
|
1207
|
+
const br = resR > 255 ? 255 : resR;
|
|
1208
|
+
const resG = sg === 255 ? 255 : dg * 255 / (255 - sg) | 0;
|
|
1209
|
+
const bg = resG > 255 ? 255 : resG;
|
|
1210
|
+
const resB = sb === 255 ? 255 : db * 255 / (255 - sb) | 0;
|
|
1211
|
+
const bb = resB > 255 ? 255 : resB;
|
|
1146
1212
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1147
1213
|
const invA = 255 - sa;
|
|
1148
|
-
const
|
|
1149
|
-
const
|
|
1150
|
-
const
|
|
1151
|
-
const
|
|
1214
|
+
const da = dst >>> 24 & 255;
|
|
1215
|
+
const tR = br * sa + dr * invA;
|
|
1216
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1217
|
+
const tG = bg * sa + dg * invA;
|
|
1218
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1219
|
+
const tB = bb * sa + db * invA;
|
|
1220
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1221
|
+
const tA = 255 * sa + da * invA;
|
|
1222
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1152
1223
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1153
1224
|
};
|
|
1154
1225
|
var linearDodgePerfect = (src, dst) => {
|
|
@@ -1163,10 +1234,15 @@ var linearDodgePerfect = (src, dst) => {
|
|
|
1163
1234
|
const bb = bbU > 255 ? 255 : bbU;
|
|
1164
1235
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1165
1236
|
const invA = 255 - sa;
|
|
1166
|
-
const
|
|
1167
|
-
const
|
|
1168
|
-
const
|
|
1169
|
-
const
|
|
1237
|
+
const da = dst >>> 24 & 255;
|
|
1238
|
+
const tR = br * sa + dr * invA;
|
|
1239
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1240
|
+
const tG = bg * sa + dg * invA;
|
|
1241
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1242
|
+
const tB = bb * sa + db * invA;
|
|
1243
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1244
|
+
const tA = 255 * sa + da * invA;
|
|
1245
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1170
1246
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1171
1247
|
};
|
|
1172
1248
|
var lighterPerfect = (src, dst) => {
|
|
@@ -1188,10 +1264,15 @@ var lighterPerfect = (src, dst) => {
|
|
|
1188
1264
|
}
|
|
1189
1265
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1190
1266
|
const invA = 255 - sa;
|
|
1191
|
-
const
|
|
1192
|
-
const
|
|
1193
|
-
const
|
|
1194
|
-
const
|
|
1267
|
+
const da = dst >>> 24 & 255;
|
|
1268
|
+
const tR = br * sa + dr * invA;
|
|
1269
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1270
|
+
const tG = bg * sa + dg * invA;
|
|
1271
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1272
|
+
const tB = bb * sa + db * invA;
|
|
1273
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1274
|
+
const tA = 255 * sa + da * invA;
|
|
1275
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1195
1276
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1196
1277
|
};
|
|
1197
1278
|
var overlayPerfect = (src, dst) => {
|
|
@@ -1204,10 +1285,15 @@ var overlayPerfect = (src, dst) => {
|
|
|
1204
1285
|
const bb = db < 128 ? 2 * sb * db / 255 | 0 : 255 - (2 * (255 - sb) * (255 - db) / 255 | 0);
|
|
1205
1286
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1206
1287
|
const invA = 255 - sa;
|
|
1207
|
-
const
|
|
1208
|
-
const
|
|
1209
|
-
const
|
|
1210
|
-
const
|
|
1288
|
+
const da = dst >>> 24 & 255;
|
|
1289
|
+
const tR = br * sa + dr * invA;
|
|
1290
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1291
|
+
const tG = bg * sa + dg * invA;
|
|
1292
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1293
|
+
const tB = bb * sa + db * invA;
|
|
1294
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1295
|
+
const tA = 255 * sa + da * invA;
|
|
1296
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1211
1297
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1212
1298
|
};
|
|
1213
1299
|
var softLightPerfect = (src, dst) => {
|
|
@@ -1215,15 +1301,26 @@ var softLightPerfect = (src, dst) => {
|
|
|
1215
1301
|
if (sa === 0) return dst;
|
|
1216
1302
|
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
1217
1303
|
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
1218
|
-
const
|
|
1219
|
-
const
|
|
1220
|
-
const
|
|
1304
|
+
const mR = sr * dr;
|
|
1305
|
+
const scR = (255 - sr) * (255 - dr);
|
|
1306
|
+
const br = (255 - dr) * (mR + 1 + (mR >> 8) >> 8) + dr * (255 - (scR + 1 + (scR >> 8) >> 8)) + 1 + ((255 - dr) * (mR + 1 + (mR >> 8) >> 8) + dr * (255 - (scR + 1 + (scR >> 8) >> 8)) >> 8) >> 8;
|
|
1307
|
+
const mG = sg * dg;
|
|
1308
|
+
const scG = (255 - sg) * (255 - dg);
|
|
1309
|
+
const bg = (255 - dg) * (mG + 1 + (mG >> 8) >> 8) + dg * (255 - (scG + 1 + (scG >> 8) >> 8)) + 1 + ((255 - dg) * (mG + 1 + (mG >> 8) >> 8) + dg * (255 - (scG + 1 + (scG >> 8) >> 8)) >> 8) >> 8;
|
|
1310
|
+
const mB = sb * db;
|
|
1311
|
+
const scB = (255 - sb) * (255 - db);
|
|
1312
|
+
const bb = (255 - db) * (mB + 1 + (mB >> 8) >> 8) + db * (255 - (scB + 1 + (scB >> 8) >> 8)) + 1 + ((255 - db) * (mB + 1 + (mB >> 8) >> 8) + db * (255 - (scB + 1 + (scB >> 8) >> 8)) >> 8) >> 8;
|
|
1221
1313
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1222
1314
|
const invA = 255 - sa;
|
|
1223
|
-
const
|
|
1224
|
-
const
|
|
1225
|
-
const
|
|
1226
|
-
const
|
|
1315
|
+
const da = dst >>> 24 & 255;
|
|
1316
|
+
const tR = br * sa + dr * invA;
|
|
1317
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1318
|
+
const tG = bg * sa + dg * invA;
|
|
1319
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1320
|
+
const tB = bb * sa + db * invA;
|
|
1321
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1322
|
+
const tA = 255 * sa + da * invA;
|
|
1323
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1227
1324
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1228
1325
|
};
|
|
1229
1326
|
var hardLightPerfect = (src, dst) => {
|
|
@@ -1236,10 +1333,15 @@ var hardLightPerfect = (src, dst) => {
|
|
|
1236
1333
|
const bb = sb < 128 ? 2 * sb * db / 255 | 0 : 255 - (2 * (255 - sb) * (255 - db) / 255 | 0);
|
|
1237
1334
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1238
1335
|
const invA = 255 - sa;
|
|
1239
|
-
const
|
|
1240
|
-
const
|
|
1241
|
-
const
|
|
1242
|
-
const
|
|
1336
|
+
const da = dst >>> 24 & 255;
|
|
1337
|
+
const tR = br * sa + dr * invA;
|
|
1338
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1339
|
+
const tG = bg * sa + dg * invA;
|
|
1340
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1341
|
+
const tB = bb * sa + db * invA;
|
|
1342
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1343
|
+
const tA = 255 * sa + da * invA;
|
|
1344
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1243
1345
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1244
1346
|
};
|
|
1245
1347
|
var vividLightPerfect = (src, dst) => {
|
|
@@ -1252,10 +1354,15 @@ var vividLightPerfect = (src, dst) => {
|
|
|
1252
1354
|
const bb = sb < 128 ? sb === 0 ? 0 : Math.max(0, 255 - ((255 - db) * 255 / (2 * sb) | 0)) : sb === 255 ? 255 : Math.min(255, db * 255 / (2 * (255 - sb)) | 0);
|
|
1253
1355
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1254
1356
|
const invA = 255 - sa;
|
|
1255
|
-
const
|
|
1256
|
-
const
|
|
1257
|
-
const
|
|
1258
|
-
const
|
|
1357
|
+
const da = dst >>> 24 & 255;
|
|
1358
|
+
const tR = br * sa + dr * invA;
|
|
1359
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1360
|
+
const tG = bg * sa + dg * invA;
|
|
1361
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1362
|
+
const tB = bb * sa + db * invA;
|
|
1363
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1364
|
+
const tA = 255 * sa + da * invA;
|
|
1365
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1259
1366
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1260
1367
|
};
|
|
1261
1368
|
var linearLightPerfect = (src, dst) => {
|
|
@@ -1271,10 +1378,15 @@ var linearLightPerfect = (src, dst) => {
|
|
|
1271
1378
|
const bb = bbU < 0 ? 0 : bbU > 255 ? 255 : bbU;
|
|
1272
1379
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1273
1380
|
const invA = 255 - sa;
|
|
1274
|
-
const
|
|
1275
|
-
const
|
|
1276
|
-
const
|
|
1277
|
-
const
|
|
1381
|
+
const da = dst >>> 24 & 255;
|
|
1382
|
+
const tR = br * sa + dr * invA;
|
|
1383
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1384
|
+
const tG = bg * sa + dg * invA;
|
|
1385
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1386
|
+
const tB = bb * sa + db * invA;
|
|
1387
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1388
|
+
const tA = 255 * sa + da * invA;
|
|
1389
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1278
1390
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1279
1391
|
};
|
|
1280
1392
|
var pinLightPerfect = (src, dst) => {
|
|
@@ -1292,10 +1404,14 @@ var pinLightPerfect = (src, dst) => {
|
|
|
1292
1404
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1293
1405
|
const invA = 255 - sa;
|
|
1294
1406
|
const da = dst >>> 24 & 255;
|
|
1295
|
-
const
|
|
1296
|
-
const
|
|
1297
|
-
const
|
|
1298
|
-
const
|
|
1407
|
+
const tR = br * sa + dr * invA;
|
|
1408
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1409
|
+
const tG = bg * sa + dg * invA;
|
|
1410
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1411
|
+
const tB = bb * sa + db * invA;
|
|
1412
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1413
|
+
const tA = 255 * sa + da * invA;
|
|
1414
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1299
1415
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1300
1416
|
};
|
|
1301
1417
|
var hardMixPerfect = (src, dst) => {
|
|
@@ -1308,33 +1424,36 @@ var hardMixPerfect = (src, dst) => {
|
|
|
1308
1424
|
const bb = (sb < 128 ? sb === 0 ? 0 : Math.max(0, 255 - ((255 - db) * 255 / (2 * sb) | 0)) : sb === 255 ? 255 : Math.min(255, db * 255 / (2 * (255 - sb)) | 0)) < 128 ? 0 : 255;
|
|
1309
1425
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1310
1426
|
const invA = 255 - sa;
|
|
1311
|
-
const
|
|
1312
|
-
const
|
|
1313
|
-
const
|
|
1314
|
-
const
|
|
1427
|
+
const da = dst >>> 24 & 255;
|
|
1428
|
+
const tR = br * sa + dr * invA;
|
|
1429
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1430
|
+
const tG = bg * sa + dg * invA;
|
|
1431
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1432
|
+
const tB = bb * sa + db * invA;
|
|
1433
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1434
|
+
const tA = 255 * sa + da * invA;
|
|
1435
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1315
1436
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1316
1437
|
};
|
|
1317
1438
|
var differencePerfect = (src, dst) => {
|
|
1318
1439
|
const sa = src >>> 24 & 255;
|
|
1319
1440
|
if (sa === 0) return dst;
|
|
1320
|
-
const dr = dst & 255;
|
|
1321
|
-
const
|
|
1322
|
-
const
|
|
1323
|
-
const
|
|
1324
|
-
const
|
|
1325
|
-
|
|
1326
|
-
const br = Math.abs(dr - sr);
|
|
1327
|
-
const bg = Math.abs(dg - sg);
|
|
1328
|
-
const bb = Math.abs(db - sb);
|
|
1329
|
-
if (sa === 255) {
|
|
1330
|
-
return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1331
|
-
}
|
|
1441
|
+
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
1442
|
+
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
1443
|
+
const br = dr > sr ? dr - sr : sr - dr;
|
|
1444
|
+
const bg = dg > sg ? dg - sg : sg - dg;
|
|
1445
|
+
const bb = db > sb ? db - sb : sb - db;
|
|
1446
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1332
1447
|
const invA = 255 - sa;
|
|
1333
1448
|
const da = dst >>> 24 & 255;
|
|
1334
|
-
const
|
|
1335
|
-
const
|
|
1336
|
-
const
|
|
1337
|
-
const
|
|
1449
|
+
const tR = br * sa + dr * invA;
|
|
1450
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1451
|
+
const tG = bg * sa + dg * invA;
|
|
1452
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1453
|
+
const tB = bb * sa + db * invA;
|
|
1454
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1455
|
+
const tA = 255 * sa + da * invA;
|
|
1456
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1338
1457
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1339
1458
|
};
|
|
1340
1459
|
var exclusionPerfect = (src, dst) => {
|
|
@@ -1346,18 +1465,23 @@ var exclusionPerfect = (src, dst) => {
|
|
|
1346
1465
|
const sr = src & 255;
|
|
1347
1466
|
const sg = src >>> 8 & 255;
|
|
1348
1467
|
const sb = src >>> 16 & 255;
|
|
1349
|
-
const
|
|
1350
|
-
const
|
|
1351
|
-
const
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1468
|
+
const r2 = dr * sr;
|
|
1469
|
+
const br = dr + sr - (r2 + r2 + 1 + (r2 + r2 >> 8) >> 8);
|
|
1470
|
+
const g2 = dg * sg;
|
|
1471
|
+
const bg = dg + sg - (g2 + g2 + 1 + (g2 + g2 >> 8) >> 8);
|
|
1472
|
+
const b2 = db * sb;
|
|
1473
|
+
const bb = db + sb - (b2 + b2 + 1 + (b2 + b2 >> 8) >> 8);
|
|
1474
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1355
1475
|
const invA = 255 - sa;
|
|
1356
1476
|
const da = dst >>> 24 & 255;
|
|
1357
|
-
const
|
|
1358
|
-
const
|
|
1359
|
-
const
|
|
1360
|
-
const
|
|
1477
|
+
const tR = br * sa + dr * invA;
|
|
1478
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1479
|
+
const tG = bg * sa + dg * invA;
|
|
1480
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1481
|
+
const tB = bb * sa + db * invA;
|
|
1482
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1483
|
+
const tA = 255 * sa + da * invA;
|
|
1484
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1361
1485
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1362
1486
|
};
|
|
1363
1487
|
var subtractPerfect = (src, dst) => {
|
|
@@ -1373,10 +1497,15 @@ var subtractPerfect = (src, dst) => {
|
|
|
1373
1497
|
const bb = bbU < 0 ? 0 : bbU;
|
|
1374
1498
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1375
1499
|
const invA = 255 - sa;
|
|
1376
|
-
const
|
|
1377
|
-
const
|
|
1378
|
-
const
|
|
1379
|
-
const
|
|
1500
|
+
const da = dst >>> 24 & 255;
|
|
1501
|
+
const tR = br * sa + dr * invA;
|
|
1502
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1503
|
+
const tG = bg * sa + dg * invA;
|
|
1504
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1505
|
+
const tB = bb * sa + db * invA;
|
|
1506
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1507
|
+
const tA = 255 * sa + da * invA;
|
|
1508
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1380
1509
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1381
1510
|
};
|
|
1382
1511
|
var dividePerfect = (src, dst) => {
|
|
@@ -1389,82 +1518,45 @@ var dividePerfect = (src, dst) => {
|
|
|
1389
1518
|
const bb = sb === 0 ? 255 : Math.min(255, db * 255 / sb | 0);
|
|
1390
1519
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1391
1520
|
const invA = 255 - sa;
|
|
1392
|
-
const
|
|
1393
|
-
const
|
|
1394
|
-
const
|
|
1395
|
-
const
|
|
1521
|
+
const da = dst >>> 24 & 255;
|
|
1522
|
+
const tR = br * sa + dr * invA;
|
|
1523
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1524
|
+
const tG = bg * sa + dg * invA;
|
|
1525
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1526
|
+
const tB = bb * sa + db * invA;
|
|
1527
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1528
|
+
const tA = 255 * sa + da * invA;
|
|
1529
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1396
1530
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1397
1531
|
};
|
|
1398
|
-
var
|
|
1399
|
-
[
|
|
1400
|
-
[
|
|
1401
|
-
[
|
|
1402
|
-
[
|
|
1403
|
-
[
|
|
1404
|
-
[
|
|
1405
|
-
[
|
|
1406
|
-
[
|
|
1407
|
-
[
|
|
1408
|
-
[
|
|
1409
|
-
[
|
|
1410
|
-
[
|
|
1411
|
-
[
|
|
1412
|
-
[
|
|
1413
|
-
[
|
|
1414
|
-
[
|
|
1415
|
-
[
|
|
1416
|
-
[
|
|
1417
|
-
[
|
|
1418
|
-
[
|
|
1419
|
-
[
|
|
1420
|
-
[
|
|
1421
|
-
[
|
|
1422
|
-
];
|
|
1423
|
-
var PERFECT_BLEND_MODES = [];
|
|
1424
|
-
for (const [index, blend] of PERFECT_BLENDER_REGISTRY) {
|
|
1425
|
-
PERFECT_BLEND_MODES[index] = blend;
|
|
1426
|
-
}
|
|
1427
|
-
var PERFECT_BLEND_TO_INDEX = new Map(
|
|
1428
|
-
PERFECT_BLENDER_REGISTRY.map((entry, index) => {
|
|
1429
|
-
return [
|
|
1430
|
-
entry[1],
|
|
1431
|
-
index
|
|
1432
|
-
];
|
|
1433
|
-
})
|
|
1434
|
-
);
|
|
1435
|
-
var INDEX_TO_PERFECT_BLEND = new Map(
|
|
1436
|
-
PERFECT_BLENDER_REGISTRY.map((entry, index) => {
|
|
1437
|
-
return [
|
|
1438
|
-
index,
|
|
1439
|
-
entry[1]
|
|
1440
|
-
];
|
|
1441
|
-
})
|
|
1442
|
-
);
|
|
1443
|
-
var PERFECT_BLEND_MODE_BY_NAME = {
|
|
1444
|
-
overwrite: overwritePerfect,
|
|
1445
|
-
sourceOver: sourceOverPerfect,
|
|
1446
|
-
darken: darkenPerfect,
|
|
1447
|
-
multiply: multiplyPerfect,
|
|
1448
|
-
colorBurn: colorBurnPerfect,
|
|
1449
|
-
linearBurn: linearBurnPerfect,
|
|
1450
|
-
darkerColor: darkerPerfect,
|
|
1451
|
-
lighten: lightenPerfect,
|
|
1452
|
-
screen: screenPerfect,
|
|
1453
|
-
colorDodge: colorDodgePerfect,
|
|
1454
|
-
linearDodge: linearDodgePerfect,
|
|
1455
|
-
lighterColor: lighterPerfect,
|
|
1456
|
-
overlay: overlayPerfect,
|
|
1457
|
-
softLight: softLightPerfect,
|
|
1458
|
-
hardLight: hardLightPerfect,
|
|
1459
|
-
vividLight: vividLightPerfect,
|
|
1460
|
-
linearLight: linearLightPerfect,
|
|
1461
|
-
pinLight: pinLightPerfect,
|
|
1462
|
-
hardMix: hardMixPerfect,
|
|
1463
|
-
difference: differencePerfect,
|
|
1464
|
-
exclusion: exclusionPerfect,
|
|
1465
|
-
subtract: subtractPerfect,
|
|
1466
|
-
divide: dividePerfect
|
|
1532
|
+
var BASE_PERFECT_BLEND_MODE_FUNCTIONS = {
|
|
1533
|
+
[BaseBlendMode.overwrite]: overwritePerfect,
|
|
1534
|
+
[BaseBlendMode.sourceOver]: sourceOverPerfect,
|
|
1535
|
+
[BaseBlendMode.darken]: darkenPerfect,
|
|
1536
|
+
[BaseBlendMode.multiply]: multiplyPerfect,
|
|
1537
|
+
[BaseBlendMode.colorBurn]: colorBurnPerfect,
|
|
1538
|
+
[BaseBlendMode.linearBurn]: linearBurnPerfect,
|
|
1539
|
+
[BaseBlendMode.darkerColor]: darkerPerfect,
|
|
1540
|
+
[BaseBlendMode.lighten]: lightenPerfect,
|
|
1541
|
+
[BaseBlendMode.screen]: screenPerfect,
|
|
1542
|
+
[BaseBlendMode.colorDodge]: colorDodgePerfect,
|
|
1543
|
+
[BaseBlendMode.linearDodge]: linearDodgePerfect,
|
|
1544
|
+
[BaseBlendMode.lighterColor]: lighterPerfect,
|
|
1545
|
+
[BaseBlendMode.overlay]: overlayPerfect,
|
|
1546
|
+
[BaseBlendMode.softLight]: softLightPerfect,
|
|
1547
|
+
[BaseBlendMode.hardLight]: hardLightPerfect,
|
|
1548
|
+
[BaseBlendMode.vividLight]: vividLightPerfect,
|
|
1549
|
+
[BaseBlendMode.linearLight]: linearLightPerfect,
|
|
1550
|
+
[BaseBlendMode.pinLight]: pinLightPerfect,
|
|
1551
|
+
[BaseBlendMode.hardMix]: hardMixPerfect,
|
|
1552
|
+
[BaseBlendMode.difference]: differencePerfect,
|
|
1553
|
+
[BaseBlendMode.exclusion]: exclusionPerfect,
|
|
1554
|
+
[BaseBlendMode.subtract]: subtractPerfect,
|
|
1555
|
+
[BaseBlendMode.divide]: dividePerfect
|
|
1467
1556
|
};
|
|
1557
|
+
function makePerfectBlendModeRegistry() {
|
|
1558
|
+
return makeBlendModeRegistry(BaseBlendMode, BASE_PERFECT_BLEND_MODE_FUNCTIONS);
|
|
1559
|
+
}
|
|
1468
1560
|
|
|
1469
1561
|
// src/Canvas/_constants.ts
|
|
1470
1562
|
var OFFSCREEN_CANVAS_CTX_FAILED = "Failed to create OffscreenCanvas context";
|
|
@@ -1579,763 +1671,776 @@ async function writeImageDataToClipboard(imageData) {
|
|
|
1579
1671
|
return writeImgBlobToClipboard(blob);
|
|
1580
1672
|
}
|
|
1581
1673
|
|
|
1582
|
-
// src/
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1674
|
+
// src/History/PixelPatchTiles.ts
|
|
1675
|
+
var PixelTile = class {
|
|
1676
|
+
constructor(id, tx, ty, tileArea) {
|
|
1677
|
+
this.id = id;
|
|
1678
|
+
this.tx = tx;
|
|
1679
|
+
this.ty = ty;
|
|
1680
|
+
this.data32 = new Uint32Array(tileArea);
|
|
1681
|
+
}
|
|
1682
|
+
data32;
|
|
1683
|
+
};
|
|
1684
|
+
function applyPatchTiles(target, tiles, tileSize = 256) {
|
|
1685
|
+
for (let i = 0; i < tiles.length; i++) {
|
|
1686
|
+
const tile = tiles[i];
|
|
1687
|
+
if (!tile) continue;
|
|
1688
|
+
const dst = target.data32;
|
|
1689
|
+
const src = tile.data32;
|
|
1690
|
+
const dstWidth = target.width;
|
|
1691
|
+
const dstHeight = target.height;
|
|
1692
|
+
const startX = tile.tx * tileSize;
|
|
1693
|
+
const startY = tile.ty * tileSize;
|
|
1694
|
+
const copyWidth = Math.max(0, Math.min(tileSize, dstWidth - startX));
|
|
1695
|
+
if (copyWidth <= 0) return;
|
|
1696
|
+
for (let ly = 0; ly < tileSize; ly++) {
|
|
1697
|
+
const globalY = startY + ly;
|
|
1698
|
+
if (globalY >= dstHeight) break;
|
|
1699
|
+
const dstIndex = globalY * dstWidth + startX;
|
|
1700
|
+
const srcIndex = ly * tileSize;
|
|
1701
|
+
const rowData = src.subarray(srcIndex, srcIndex + copyWidth);
|
|
1702
|
+
dst.set(rowData, dstIndex);
|
|
1593
1703
|
}
|
|
1594
|
-
return imageData;
|
|
1595
|
-
};
|
|
1596
|
-
}
|
|
1597
|
-
|
|
1598
|
-
// src/ImageData/copyImageData.ts
|
|
1599
|
-
function copyImageData({ data, width, height }) {
|
|
1600
|
-
return new ImageData(data.slice(), width, height);
|
|
1601
|
-
}
|
|
1602
|
-
function copyImageDataLike({ data, width, height }) {
|
|
1603
|
-
return {
|
|
1604
|
-
data: data.slice(),
|
|
1605
|
-
width,
|
|
1606
|
-
height
|
|
1607
|
-
};
|
|
1608
|
-
}
|
|
1609
|
-
|
|
1610
|
-
// src/PixelData/pixelDataToAlphaMask.ts
|
|
1611
|
-
function pixelDataToAlphaMask(pixelData) {
|
|
1612
|
-
const {
|
|
1613
|
-
data32,
|
|
1614
|
-
width,
|
|
1615
|
-
height
|
|
1616
|
-
} = pixelData;
|
|
1617
|
-
const len = data32.length;
|
|
1618
|
-
const mask = new Uint8Array(width * height);
|
|
1619
|
-
for (let i = 0; i < len; i++) {
|
|
1620
|
-
const val = data32[i];
|
|
1621
|
-
mask[i] = val >>> 24 & 255;
|
|
1622
1704
|
}
|
|
1623
|
-
return mask;
|
|
1624
1705
|
}
|
|
1625
1706
|
|
|
1626
|
-
// src/
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1707
|
+
// src/History/PixelAccumulator.ts
|
|
1708
|
+
var PixelAccumulator = class {
|
|
1709
|
+
constructor(target, config) {
|
|
1710
|
+
this.target = target;
|
|
1711
|
+
this.config = config;
|
|
1712
|
+
this.lookup = [];
|
|
1713
|
+
this.beforeTiles = [];
|
|
1714
|
+
this.pool = [];
|
|
1715
|
+
}
|
|
1716
|
+
lookup;
|
|
1717
|
+
beforeTiles;
|
|
1718
|
+
pool;
|
|
1719
|
+
getTile(id, tx, ty) {
|
|
1720
|
+
let tile = this.pool.pop();
|
|
1721
|
+
if (tile) {
|
|
1722
|
+
tile.id = id;
|
|
1723
|
+
tile.tx = tx;
|
|
1724
|
+
tile.ty = ty;
|
|
1725
|
+
return tile;
|
|
1726
|
+
}
|
|
1727
|
+
return new PixelTile(
|
|
1728
|
+
id,
|
|
1729
|
+
tx,
|
|
1730
|
+
ty,
|
|
1731
|
+
this.config.tileArea
|
|
1732
|
+
);
|
|
1643
1733
|
}
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1734
|
+
recyclePatch(patch) {
|
|
1735
|
+
const before = patch.beforeTiles;
|
|
1736
|
+
for (let i = 0; i < before.length; i++) {
|
|
1737
|
+
let tile = before[i];
|
|
1738
|
+
if (tile) {
|
|
1739
|
+
this.pool.push(tile);
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
const after = patch.afterTiles;
|
|
1743
|
+
for (let i = 0; i < after.length; i++) {
|
|
1744
|
+
let tile = after[i];
|
|
1745
|
+
if (tile) {
|
|
1746
|
+
this.pool.push(tile);
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
/**
|
|
1751
|
+
* @param x pixel x coordinate
|
|
1752
|
+
* @param y pixel y coordinate
|
|
1753
|
+
*/
|
|
1754
|
+
storeTileBeforeState(x, y) {
|
|
1755
|
+
let target = this.target;
|
|
1756
|
+
let shift = this.config.tileShift;
|
|
1757
|
+
let columns = target.width + this.config.tileMask >> shift;
|
|
1758
|
+
let tx = x >> shift;
|
|
1759
|
+
let ty = y >> shift;
|
|
1760
|
+
let id = ty * columns + tx;
|
|
1761
|
+
let tile = this.lookup[id];
|
|
1762
|
+
if (!tile) {
|
|
1763
|
+
tile = this.getTile(
|
|
1764
|
+
id,
|
|
1765
|
+
tx,
|
|
1766
|
+
ty
|
|
1767
|
+
);
|
|
1768
|
+
this.extractState(tile);
|
|
1769
|
+
this.lookup[id] = tile;
|
|
1770
|
+
this.beforeTiles.push(tile);
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
/**
|
|
1774
|
+
*
|
|
1775
|
+
* @param x pixel x coordinate
|
|
1776
|
+
* @param y pixel y coordinate
|
|
1777
|
+
* @param w pixel width
|
|
1778
|
+
* @param h pixel height
|
|
1779
|
+
*/
|
|
1780
|
+
storeRegionBeforeState(x, y, w, h) {
|
|
1781
|
+
let target = this.target;
|
|
1782
|
+
let shift = this.config.tileShift;
|
|
1783
|
+
let columns = target.width + this.config.tileMask >> shift;
|
|
1784
|
+
let startX = x >> shift;
|
|
1785
|
+
let startY = y >> shift;
|
|
1786
|
+
let endX = x + w - 1 >> shift;
|
|
1787
|
+
let endY = y + h - 1 >> shift;
|
|
1788
|
+
for (let ty = startY; ty <= endY; ty++) {
|
|
1789
|
+
for (let tx = startX; tx <= endX; tx++) {
|
|
1790
|
+
let id = ty * columns + tx;
|
|
1791
|
+
let tile = this.lookup[id];
|
|
1792
|
+
if (!tile) {
|
|
1793
|
+
tile = this.getTile(
|
|
1794
|
+
id,
|
|
1795
|
+
tx,
|
|
1796
|
+
ty
|
|
1797
|
+
);
|
|
1798
|
+
this.extractState(tile);
|
|
1799
|
+
this.lookup[id] = tile;
|
|
1800
|
+
this.beforeTiles.push(tile);
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
extractState(tile) {
|
|
1806
|
+
let target = this.target;
|
|
1807
|
+
let TILE_SIZE = this.config.tileSize;
|
|
1808
|
+
let dst = tile.data32;
|
|
1809
|
+
let src = target.data32;
|
|
1810
|
+
let startX = tile.tx * TILE_SIZE;
|
|
1811
|
+
let startY = tile.ty * TILE_SIZE;
|
|
1812
|
+
let targetWidth = target.width;
|
|
1813
|
+
let targetHeight = target.height;
|
|
1814
|
+
let copyWidth = Math.max(0, Math.min(TILE_SIZE, targetWidth - startX));
|
|
1815
|
+
for (let ly = 0; ly < TILE_SIZE; ly++) {
|
|
1816
|
+
let globalY = startY + ly;
|
|
1817
|
+
let dstIndex = ly * TILE_SIZE;
|
|
1818
|
+
if (globalY < 0 || globalY >= targetHeight || copyWidth === 0) {
|
|
1819
|
+
dst.fill(0, dstIndex, dstIndex + TILE_SIZE);
|
|
1820
|
+
continue;
|
|
1821
|
+
}
|
|
1822
|
+
let srcIndex = globalY * targetWidth + startX;
|
|
1823
|
+
let rowData = src.subarray(srcIndex, srcIndex + copyWidth);
|
|
1824
|
+
dst.set(rowData, dstIndex);
|
|
1825
|
+
if (copyWidth < TILE_SIZE) {
|
|
1826
|
+
dst.fill(0, dstIndex + copyWidth, dstIndex + TILE_SIZE);
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
extractAfterTiles() {
|
|
1831
|
+
let afterTiles = [];
|
|
1832
|
+
let length = this.beforeTiles.length;
|
|
1833
|
+
for (let i = 0; i < length; i++) {
|
|
1834
|
+
let beforeTile = this.beforeTiles[i];
|
|
1835
|
+
if (beforeTile) {
|
|
1836
|
+
let afterTile = this.getTile(
|
|
1837
|
+
beforeTile.id,
|
|
1838
|
+
beforeTile.tx,
|
|
1839
|
+
beforeTile.ty
|
|
1840
|
+
);
|
|
1841
|
+
this.extractState(afterTile);
|
|
1842
|
+
afterTiles.push(afterTile);
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
return afterTiles;
|
|
1846
|
+
}
|
|
1847
|
+
reset() {
|
|
1848
|
+
this.lookup = [];
|
|
1849
|
+
this.beforeTiles = [];
|
|
1674
1850
|
}
|
|
1675
|
-
return imageData;
|
|
1676
|
-
}
|
|
1677
|
-
|
|
1678
|
-
// src/Internal/resample32.ts
|
|
1679
|
-
var resample32Scratch = {
|
|
1680
|
-
data: null,
|
|
1681
|
-
width: 0,
|
|
1682
|
-
height: 0
|
|
1683
1851
|
};
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1852
|
+
|
|
1853
|
+
// src/History/HistoryManager.ts
|
|
1854
|
+
var HistoryManager = class {
|
|
1855
|
+
constructor(maxSteps = 50) {
|
|
1856
|
+
this.maxSteps = maxSteps;
|
|
1857
|
+
this.undoStack = [];
|
|
1858
|
+
this.redoStack = [];
|
|
1859
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
1860
|
+
}
|
|
1861
|
+
undoStack;
|
|
1862
|
+
redoStack;
|
|
1863
|
+
listeners;
|
|
1864
|
+
get canUndo() {
|
|
1865
|
+
return this.undoStack.length > 0;
|
|
1866
|
+
}
|
|
1867
|
+
get canRedo() {
|
|
1868
|
+
return this.redoStack.length > 0;
|
|
1869
|
+
}
|
|
1870
|
+
subscribe(fn) {
|
|
1871
|
+
this.listeners.add(fn);
|
|
1872
|
+
return () => this.listeners.delete(fn);
|
|
1873
|
+
}
|
|
1874
|
+
notify() {
|
|
1875
|
+
this.listeners.forEach((fn) => fn());
|
|
1876
|
+
}
|
|
1877
|
+
commit(action) {
|
|
1878
|
+
this.undoStack.push(action);
|
|
1879
|
+
this.clearRedoStack();
|
|
1880
|
+
if (this.undoStack.length > this.maxSteps) {
|
|
1881
|
+
this.undoStack.shift()?.dispose?.();
|
|
1882
|
+
}
|
|
1883
|
+
this.notify();
|
|
1884
|
+
}
|
|
1885
|
+
undo() {
|
|
1886
|
+
let action = this.undoStack.pop();
|
|
1887
|
+
if (!action) return;
|
|
1888
|
+
this.redoStack.push(action);
|
|
1889
|
+
action.undo();
|
|
1890
|
+
this.notify();
|
|
1891
|
+
}
|
|
1892
|
+
redo() {
|
|
1893
|
+
let action = this.redoStack.pop();
|
|
1894
|
+
if (!action) return;
|
|
1895
|
+
this.undoStack.push(action);
|
|
1896
|
+
action.redo();
|
|
1897
|
+
this.notify();
|
|
1898
|
+
}
|
|
1899
|
+
clearRedoStack() {
|
|
1900
|
+
let length = this.redoStack.length;
|
|
1901
|
+
for (let i = 0; i < length; i++) {
|
|
1902
|
+
let action = this.redoStack[i];
|
|
1903
|
+
if (action) {
|
|
1904
|
+
action.dispose?.();
|
|
1905
|
+
}
|
|
1697
1906
|
}
|
|
1907
|
+
this.redoStack.length = 0;
|
|
1698
1908
|
}
|
|
1699
|
-
|
|
1700
|
-
resample32Scratch.width = dstW;
|
|
1701
|
-
resample32Scratch.height = dstH;
|
|
1702
|
-
return resample32Scratch;
|
|
1703
|
-
}
|
|
1909
|
+
};
|
|
1704
1910
|
|
|
1705
|
-
// src/
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1911
|
+
// src/History/PixelEngineConfig.ts
|
|
1912
|
+
var PixelEngineConfig = class {
|
|
1913
|
+
tileSize;
|
|
1914
|
+
tileShift;
|
|
1915
|
+
tileMask;
|
|
1916
|
+
tileArea;
|
|
1917
|
+
constructor(tileSize = 256) {
|
|
1918
|
+
if ((tileSize & tileSize - 1) !== 0) {
|
|
1919
|
+
throw new Error("tileSize must be a power of 2");
|
|
1920
|
+
}
|
|
1921
|
+
this.tileSize = tileSize;
|
|
1922
|
+
this.tileShift = Math.log2(tileSize);
|
|
1923
|
+
this.tileMask = tileSize - 1;
|
|
1924
|
+
this.tileArea = tileSize * tileSize;
|
|
1925
|
+
}
|
|
1926
|
+
};
|
|
1712
1927
|
|
|
1713
|
-
// src/
|
|
1714
|
-
function
|
|
1715
|
-
const result = new ImageData(newWidth, newHeight);
|
|
1928
|
+
// src/PixelData/applyMaskToPixelData.ts
|
|
1929
|
+
function applyMaskToPixelData(dst, mask, opts = {}) {
|
|
1716
1930
|
const {
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
const dstStart = (dstY * newWidth + x0) * 4;
|
|
1736
|
-
const srcStart = (srcY * oldW + srcX) * 4;
|
|
1737
|
-
newData.set(
|
|
1738
|
-
oldData.subarray(srcStart, srcStart + rowLen),
|
|
1739
|
-
dstStart
|
|
1740
|
-
);
|
|
1931
|
+
x: targetX = 0,
|
|
1932
|
+
y: targetY = 0,
|
|
1933
|
+
w: width = dst.width,
|
|
1934
|
+
h: height = dst.height,
|
|
1935
|
+
alpha: globalAlpha = 255,
|
|
1936
|
+
maskType = 0 /* ALPHA */,
|
|
1937
|
+
mw,
|
|
1938
|
+
mx = 0,
|
|
1939
|
+
my = 0,
|
|
1940
|
+
invertMask = false
|
|
1941
|
+
} = opts;
|
|
1942
|
+
let x = targetX;
|
|
1943
|
+
let y = targetY;
|
|
1944
|
+
let w = width;
|
|
1945
|
+
let h = height;
|
|
1946
|
+
if (x < 0) {
|
|
1947
|
+
w += x;
|
|
1948
|
+
x = 0;
|
|
1741
1949
|
}
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
// src/ImageData/serialization.ts
|
|
1746
|
-
function base64EncodeArrayBuffer(buffer) {
|
|
1747
|
-
const uint8 = new Uint8Array(buffer);
|
|
1748
|
-
const decoder = new TextDecoder("latin1");
|
|
1749
|
-
const binary = decoder.decode(uint8);
|
|
1750
|
-
return btoa(binary);
|
|
1751
|
-
}
|
|
1752
|
-
function base64DecodeArrayBuffer(encoded) {
|
|
1753
|
-
const binary = atob(encoded);
|
|
1754
|
-
const bytes = new Uint8ClampedArray(binary.length);
|
|
1755
|
-
for (let i = 0; i < binary.length; i++) {
|
|
1756
|
-
bytes[i] = binary.charCodeAt(i);
|
|
1950
|
+
if (y < 0) {
|
|
1951
|
+
h += y;
|
|
1952
|
+
y = 0;
|
|
1757
1953
|
}
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
return {
|
|
1762
|
-
width: imageData.width,
|
|
1763
|
-
height: imageData.height,
|
|
1764
|
-
data: base64EncodeArrayBuffer(imageData.data.buffer)
|
|
1765
|
-
};
|
|
1766
|
-
}
|
|
1767
|
-
function serializeNullableImageData(imageData) {
|
|
1768
|
-
if (!imageData) return null;
|
|
1769
|
-
return serializeImageData(imageData);
|
|
1770
|
-
}
|
|
1771
|
-
function deserializeRawImageData(serialized) {
|
|
1772
|
-
return {
|
|
1773
|
-
width: serialized.width,
|
|
1774
|
-
height: serialized.height,
|
|
1775
|
-
data: base64DecodeArrayBuffer(serialized.data)
|
|
1776
|
-
};
|
|
1777
|
-
}
|
|
1778
|
-
function deserializeImageData(serialized) {
|
|
1779
|
-
const data = base64DecodeArrayBuffer(serialized.data);
|
|
1780
|
-
return new ImageData(data, serialized.width, serialized.height);
|
|
1781
|
-
}
|
|
1782
|
-
function deserializeNullableImageData(serialized) {
|
|
1783
|
-
if (!serialized) return null;
|
|
1784
|
-
return deserializeImageData(serialized);
|
|
1785
|
-
}
|
|
1786
|
-
|
|
1787
|
-
// src/ImageData/writeImageData.ts
|
|
1788
|
-
function writeImageData(target, source, x, y, sx = 0, sy = 0, sw = source.width, sh = source.height, mask = null, maskType = 1 /* BINARY */) {
|
|
1789
|
-
const dstW = target.width;
|
|
1790
|
-
const dstH = target.height;
|
|
1791
|
-
const dstData = target.data;
|
|
1792
|
-
const srcW = source.width;
|
|
1793
|
-
const srcData = source.data;
|
|
1794
|
-
const x0 = Math.max(0, x);
|
|
1795
|
-
const y0 = Math.max(0, y);
|
|
1796
|
-
const x1 = Math.min(dstW, x + sw);
|
|
1797
|
-
const y1 = Math.min(dstH, y + sh);
|
|
1798
|
-
if (x1 <= x0 || y1 <= y0) {
|
|
1954
|
+
const actualW = Math.min(w, dst.width - x);
|
|
1955
|
+
const actualH = Math.min(h, dst.height - y);
|
|
1956
|
+
if (actualW <= 0 || actualH <= 0 || globalAlpha === 0) {
|
|
1799
1957
|
return;
|
|
1800
1958
|
}
|
|
1801
|
-
const
|
|
1802
|
-
const
|
|
1803
|
-
const
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1959
|
+
const dst32 = dst.data32;
|
|
1960
|
+
const dw = dst.width;
|
|
1961
|
+
const mPitch = mw ?? width;
|
|
1962
|
+
const isAlpha = maskType === 0 /* ALPHA */;
|
|
1963
|
+
const dx = x - targetX;
|
|
1964
|
+
const dy = y - targetY;
|
|
1965
|
+
let dIdx = y * dw + x;
|
|
1966
|
+
let mIdx = (my + dy) * mPitch + (mx + dx);
|
|
1967
|
+
const dStride = dw - actualW;
|
|
1968
|
+
const mStride = mPitch - actualW;
|
|
1969
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
1970
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
1971
|
+
const mVal = mask[mIdx];
|
|
1972
|
+
let weight = globalAlpha;
|
|
1973
|
+
if (isAlpha) {
|
|
1974
|
+
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
1975
|
+
if (effectiveM === 0) {
|
|
1976
|
+
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
1977
|
+
dIdx++;
|
|
1978
|
+
mIdx++;
|
|
1815
1979
|
continue;
|
|
1816
1980
|
}
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1981
|
+
weight = globalAlpha === 255 ? effectiveM : effectiveM * globalAlpha + 128 >> 8;
|
|
1982
|
+
} else {
|
|
1983
|
+
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
1984
|
+
if (!isHit) {
|
|
1985
|
+
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
1986
|
+
dIdx++;
|
|
1987
|
+
mIdx++;
|
|
1988
|
+
continue;
|
|
1989
|
+
}
|
|
1990
|
+
weight = globalAlpha;
|
|
1991
|
+
}
|
|
1992
|
+
if (weight === 0) {
|
|
1993
|
+
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
1994
|
+
} else {
|
|
1995
|
+
const d = dst32[dIdx];
|
|
1996
|
+
const da = d >>> 24;
|
|
1997
|
+
let finalAlpha = da;
|
|
1998
|
+
if (da === 0) {
|
|
1999
|
+
} else if (weight === 255) {
|
|
2000
|
+
} else if (da === 255) {
|
|
2001
|
+
finalAlpha = weight;
|
|
1824
2002
|
} else {
|
|
1825
|
-
|
|
1826
|
-
const invA = 1 - a;
|
|
1827
|
-
dstData[di] = srcData[si] * a + dstData[di] * invA;
|
|
1828
|
-
dstData[di + 1] = srcData[si + 1] * a + dstData[di + 1] * invA;
|
|
1829
|
-
dstData[di + 2] = srcData[si + 2] * a + dstData[di + 2] * invA;
|
|
1830
|
-
dstData[di + 3] = srcData[si + 3] * a + dstData[di + 3] * invA;
|
|
2003
|
+
finalAlpha = da * weight + 128 >> 8;
|
|
1831
2004
|
}
|
|
2005
|
+
dst32[dIdx] = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
1832
2006
|
}
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
const sub = srcData.subarray(srcStart, srcStart + byteLen);
|
|
1836
|
-
dstData.set(sub, dstStart);
|
|
2007
|
+
dIdx++;
|
|
2008
|
+
mIdx++;
|
|
1837
2009
|
}
|
|
2010
|
+
dIdx += dStride;
|
|
2011
|
+
mIdx += mStride;
|
|
1838
2012
|
}
|
|
1839
2013
|
}
|
|
1840
2014
|
|
|
1841
|
-
// src/
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
2015
|
+
// src/History/PixelWriter.ts
|
|
2016
|
+
var PixelWriter = class {
|
|
2017
|
+
target;
|
|
2018
|
+
historyManager;
|
|
2019
|
+
accumulator;
|
|
2020
|
+
config;
|
|
2021
|
+
mutator;
|
|
2022
|
+
constructor(target, mutatorFactory, {
|
|
2023
|
+
tileSize = 256,
|
|
2024
|
+
maxHistorySteps = 50,
|
|
2025
|
+
historyManager = new HistoryManager(maxHistorySteps)
|
|
2026
|
+
} = {}) {
|
|
2027
|
+
this.target = target;
|
|
2028
|
+
this.config = new PixelEngineConfig(tileSize);
|
|
2029
|
+
this.historyManager = historyManager;
|
|
2030
|
+
this.accumulator = new PixelAccumulator(target, this.config);
|
|
2031
|
+
this.mutator = mutatorFactory(this);
|
|
2032
|
+
}
|
|
2033
|
+
withHistory(cb) {
|
|
2034
|
+
cb(this.mutator);
|
|
2035
|
+
const beforeTiles = this.accumulator.beforeTiles;
|
|
2036
|
+
if (beforeTiles.length === 0) return;
|
|
2037
|
+
const afterTiles = this.accumulator.extractAfterTiles();
|
|
2038
|
+
const patch = {
|
|
2039
|
+
beforeTiles,
|
|
2040
|
+
afterTiles
|
|
2041
|
+
};
|
|
2042
|
+
const target = this.target;
|
|
2043
|
+
const tileSize = this.config.tileSize;
|
|
2044
|
+
const accumulator = this.accumulator;
|
|
2045
|
+
const action = {
|
|
2046
|
+
undo: () => applyPatchTiles(target, patch.beforeTiles, tileSize),
|
|
2047
|
+
redo: () => applyPatchTiles(target, patch.afterTiles, tileSize),
|
|
2048
|
+
dispose: () => accumulator.recyclePatch(patch)
|
|
2049
|
+
};
|
|
2050
|
+
this.historyManager.commit(action);
|
|
2051
|
+
this.accumulator.reset();
|
|
1859
2052
|
}
|
|
2053
|
+
};
|
|
2054
|
+
|
|
2055
|
+
// src/History/PixelMutator/mutatorApplyMask.ts
|
|
2056
|
+
function mutatorApplyMask(writer) {
|
|
2057
|
+
return {
|
|
2058
|
+
applyMask: (mask, opts = {}) => {
|
|
2059
|
+
let target = writer.target;
|
|
2060
|
+
const {
|
|
2061
|
+
x = 0,
|
|
2062
|
+
y = 0,
|
|
2063
|
+
w = writer.target.width,
|
|
2064
|
+
h = writer.target.height
|
|
2065
|
+
} = opts;
|
|
2066
|
+
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2067
|
+
applyMaskToPixelData(target, mask, opts);
|
|
2068
|
+
}
|
|
2069
|
+
};
|
|
1860
2070
|
}
|
|
1861
2071
|
|
|
1862
|
-
// src/
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
2072
|
+
// src/PixelData/blendColorPixelData.ts
|
|
2073
|
+
function blendColorPixelData(dst, color, opts = {}) {
|
|
2074
|
+
const {
|
|
2075
|
+
x: targetX = 0,
|
|
2076
|
+
y: targetY = 0,
|
|
2077
|
+
w: width = dst.width,
|
|
2078
|
+
h: height = dst.height,
|
|
2079
|
+
alpha: globalAlpha = 255,
|
|
2080
|
+
blendFn = sourceOverFast,
|
|
2081
|
+
mask,
|
|
2082
|
+
maskType = 0 /* ALPHA */,
|
|
2083
|
+
mw,
|
|
2084
|
+
mx = 0,
|
|
2085
|
+
my = 0,
|
|
2086
|
+
invertMask = false
|
|
2087
|
+
} = opts;
|
|
2088
|
+
if (globalAlpha === 0) return;
|
|
2089
|
+
const baseSrcAlpha = color >>> 24;
|
|
2090
|
+
const isOverwrite = blendFn.isOverwrite;
|
|
2091
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return;
|
|
2092
|
+
let x = targetX;
|
|
2093
|
+
let y = targetY;
|
|
2094
|
+
let w = width;
|
|
2095
|
+
let h = height;
|
|
2096
|
+
if (x < 0) {
|
|
2097
|
+
w += x;
|
|
2098
|
+
x = 0;
|
|
1887
2099
|
}
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
* @returns A new IndexedImage instance.
|
|
1892
|
-
*/
|
|
1893
|
-
static fromImageData(imageData) {
|
|
1894
|
-
return _IndexedImage.fromRaw(imageData.data, imageData.width, imageData.height);
|
|
2100
|
+
if (y < 0) {
|
|
2101
|
+
h += y;
|
|
2102
|
+
y = 0;
|
|
1895
2103
|
}
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
2104
|
+
const actualW = Math.min(w, dst.width - x);
|
|
2105
|
+
const actualH = Math.min(h, dst.height - y);
|
|
2106
|
+
if (actualW <= 0 || actualH <= 0) return;
|
|
2107
|
+
const dst32 = dst.data32;
|
|
2108
|
+
const dw = dst.width;
|
|
2109
|
+
const mPitch = mw ?? width;
|
|
2110
|
+
const isAlphaMask = maskType === 0 /* ALPHA */;
|
|
2111
|
+
const dx = x - targetX;
|
|
2112
|
+
const dy = y - targetY;
|
|
2113
|
+
let dIdx = y * dw + x;
|
|
2114
|
+
let mIdx = (my + dy) * mPitch + (mx + dx);
|
|
2115
|
+
const dStride = dw - actualW;
|
|
2116
|
+
const mStride = mPitch - actualW;
|
|
2117
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2118
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2119
|
+
let weight = globalAlpha;
|
|
2120
|
+
if (mask) {
|
|
2121
|
+
const mVal = mask[mIdx];
|
|
2122
|
+
if (isAlphaMask) {
|
|
2123
|
+
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
2124
|
+
if (effectiveM === 0) {
|
|
2125
|
+
dIdx++;
|
|
2126
|
+
mIdx++;
|
|
2127
|
+
continue;
|
|
2128
|
+
}
|
|
2129
|
+
if (globalAlpha === 255) {
|
|
2130
|
+
weight = effectiveM;
|
|
2131
|
+
} else if (effectiveM === 255) {
|
|
2132
|
+
weight = globalAlpha;
|
|
2133
|
+
} else {
|
|
2134
|
+
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
2135
|
+
}
|
|
2136
|
+
} else {
|
|
2137
|
+
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
2138
|
+
if (!isHit) {
|
|
2139
|
+
dIdx++;
|
|
2140
|
+
mIdx++;
|
|
2141
|
+
continue;
|
|
2142
|
+
}
|
|
2143
|
+
weight = globalAlpha;
|
|
2144
|
+
}
|
|
2145
|
+
if (weight === 0) {
|
|
2146
|
+
dIdx++;
|
|
2147
|
+
mIdx++;
|
|
2148
|
+
continue;
|
|
2149
|
+
}
|
|
1921
2150
|
}
|
|
1922
|
-
|
|
2151
|
+
let currentSrcColor = color;
|
|
2152
|
+
if (weight < 255) {
|
|
2153
|
+
let currentSrcAlpha = baseSrcAlpha;
|
|
2154
|
+
if (baseSrcAlpha === 255) {
|
|
2155
|
+
currentSrcAlpha = weight;
|
|
2156
|
+
} else {
|
|
2157
|
+
currentSrcAlpha = baseSrcAlpha * weight + 128 >> 8;
|
|
2158
|
+
}
|
|
2159
|
+
if (!isOverwrite && currentSrcAlpha === 0) {
|
|
2160
|
+
dIdx++;
|
|
2161
|
+
mIdx++;
|
|
2162
|
+
continue;
|
|
2163
|
+
}
|
|
2164
|
+
currentSrcColor = (color & 16777215 | currentSrcAlpha << 24) >>> 0;
|
|
2165
|
+
}
|
|
2166
|
+
dst32[dIdx] = blendFn(currentSrcColor, dst32[dIdx]);
|
|
2167
|
+
dIdx++;
|
|
2168
|
+
mIdx++;
|
|
1923
2169
|
}
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
width,
|
|
1927
|
-
height,
|
|
1928
|
-
indexedData,
|
|
1929
|
-
palette,
|
|
1930
|
-
transparentPalletIndex
|
|
1931
|
-
);
|
|
1932
|
-
}
|
|
1933
|
-
/**
|
|
1934
|
-
* Retrieves the 32-bit packed color value at the given coordinates.
|
|
1935
|
-
* @param x - X coordinate.
|
|
1936
|
-
* @param y - Y coordinate.
|
|
1937
|
-
* @returns The packed color from the palette.
|
|
1938
|
-
*/
|
|
1939
|
-
getColorAt(x, y) {
|
|
1940
|
-
const index = x + y * this.width;
|
|
1941
|
-
const paletteIndex = this.data[index];
|
|
1942
|
-
return this.palette[paletteIndex];
|
|
1943
|
-
}
|
|
1944
|
-
};
|
|
1945
|
-
|
|
1946
|
-
// src/IndexedImage/getIndexedImageColorCounts.ts
|
|
1947
|
-
function getIndexedImageColorCounts(indexedImage) {
|
|
1948
|
-
const data = indexedImage.data;
|
|
1949
|
-
const palette = indexedImage.palette;
|
|
1950
|
-
const frequencies = new Int32Array(palette.length);
|
|
1951
|
-
for (let i = 0; i < data.length; i++) {
|
|
1952
|
-
const colorIndex = data[i];
|
|
1953
|
-
frequencies[colorIndex]++;
|
|
2170
|
+
dIdx += dStride;
|
|
2171
|
+
mIdx += mStride;
|
|
1954
2172
|
}
|
|
1955
|
-
return frequencies;
|
|
1956
2173
|
}
|
|
1957
2174
|
|
|
1958
|
-
// src/
|
|
1959
|
-
function
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
let totalWeight = 0;
|
|
1971
|
-
for (let id = 0; id < counts.length; id++) {
|
|
1972
|
-
const weight = counts[id];
|
|
1973
|
-
if (weight === 0) {
|
|
1974
|
-
continue;
|
|
1975
|
-
}
|
|
1976
|
-
if (!includeTransparent && id === transparentPalletIndex) {
|
|
1977
|
-
continue;
|
|
2175
|
+
// src/History/PixelMutator/mutatorBlendColor.ts
|
|
2176
|
+
function mutatorBlendColor(writer) {
|
|
2177
|
+
return {
|
|
2178
|
+
blendColor(color, opts = {}) {
|
|
2179
|
+
const {
|
|
2180
|
+
x = 0,
|
|
2181
|
+
y = 0,
|
|
2182
|
+
w = writer.target.width,
|
|
2183
|
+
h = writer.target.height
|
|
2184
|
+
} = opts;
|
|
2185
|
+
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2186
|
+
blendColorPixelData(writer.target, color, opts);
|
|
1978
2187
|
}
|
|
1979
|
-
|
|
1980
|
-
const r2 = color & 255;
|
|
1981
|
-
const g2 = color >> 8 & 255;
|
|
1982
|
-
const b2 = color >> 16 & 255;
|
|
1983
|
-
const a2 = color >> 24 & 255;
|
|
1984
|
-
rSum += r2 * weight;
|
|
1985
|
-
gSum += g2 * weight;
|
|
1986
|
-
bSum += b2 * weight;
|
|
1987
|
-
aSum += a2 * weight;
|
|
1988
|
-
totalWeight += weight;
|
|
1989
|
-
}
|
|
1990
|
-
if (totalWeight === 0) {
|
|
1991
|
-
return packColor(0, 0, 0, 0);
|
|
1992
|
-
}
|
|
1993
|
-
const r = rSum / totalWeight | 0;
|
|
1994
|
-
const g = gSum / totalWeight | 0;
|
|
1995
|
-
const b = bSum / totalWeight | 0;
|
|
1996
|
-
const a = aSum / totalWeight | 0;
|
|
1997
|
-
return packColor(r, g, b, a);
|
|
2188
|
+
};
|
|
1998
2189
|
}
|
|
1999
2190
|
|
|
2000
|
-
// src/
|
|
2001
|
-
function
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2191
|
+
// src/History/PixelMutator/mutatorBlendPixel.ts
|
|
2192
|
+
function mutatorBlendPixel(writer) {
|
|
2193
|
+
return {
|
|
2194
|
+
blendPixel(x, y, color, alpha = 255, blendFn = overwriteFast) {
|
|
2195
|
+
let target = writer.target;
|
|
2196
|
+
let width = target.width;
|
|
2197
|
+
let height = target.height;
|
|
2198
|
+
if (x < 0 || x >= width || y < 0 || y >= height) return;
|
|
2199
|
+
writer.accumulator.storeTileBeforeState(x, y);
|
|
2200
|
+
let index = y * width + x;
|
|
2201
|
+
let bg = target.data32[index];
|
|
2202
|
+
let finalColor = color;
|
|
2203
|
+
if (alpha < 255) {
|
|
2204
|
+
let baseSrcAlpha = color >>> 24;
|
|
2205
|
+
let finalAlpha = baseSrcAlpha * alpha + 128 >> 8;
|
|
2206
|
+
finalColor = (color & 16777215 | finalAlpha << 24) >>> 0;
|
|
2207
|
+
}
|
|
2208
|
+
target.data32[index] = blendFn(finalColor, bg);
|
|
2209
|
+
}
|
|
2210
|
+
};
|
|
2015
2211
|
}
|
|
2016
2212
|
|
|
2017
|
-
// src/
|
|
2018
|
-
function
|
|
2019
|
-
const {
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2213
|
+
// src/PixelData/blendPixelData.ts
|
|
2214
|
+
function blendPixelData(dst, src, opts) {
|
|
2215
|
+
const {
|
|
2216
|
+
x: targetX = 0,
|
|
2217
|
+
y: targetY = 0,
|
|
2218
|
+
sx: sourceX = 0,
|
|
2219
|
+
sy: sourceY = 0,
|
|
2220
|
+
w: width = src.width,
|
|
2221
|
+
h: height = src.height,
|
|
2222
|
+
alpha: globalAlpha = 255,
|
|
2223
|
+
blendFn = sourceOverFast,
|
|
2224
|
+
mask,
|
|
2225
|
+
maskType = 0 /* ALPHA */,
|
|
2226
|
+
mw,
|
|
2227
|
+
mx = 0,
|
|
2228
|
+
my = 0,
|
|
2229
|
+
invertMask = false
|
|
2230
|
+
} = opts;
|
|
2231
|
+
if (globalAlpha === 0) return;
|
|
2232
|
+
let x = targetX;
|
|
2233
|
+
let y = targetY;
|
|
2234
|
+
let sx = sourceX;
|
|
2235
|
+
let sy = sourceY;
|
|
2236
|
+
let w = width;
|
|
2237
|
+
let h = height;
|
|
2238
|
+
if (sx < 0) {
|
|
2239
|
+
x -= sx;
|
|
2240
|
+
w += sx;
|
|
2241
|
+
sx = 0;
|
|
2026
2242
|
}
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
async function fileInputChangeToImageData(event) {
|
|
2032
|
-
const target = event.target;
|
|
2033
|
-
const file = target.files?.[0];
|
|
2034
|
-
if (!file) return null;
|
|
2035
|
-
return await fileToImageData(file);
|
|
2036
|
-
}
|
|
2037
|
-
|
|
2038
|
-
// src/Input/fileToImageData.ts
|
|
2039
|
-
var UnsupportedFormatError = class extends Error {
|
|
2040
|
-
constructor(mimeType) {
|
|
2041
|
-
super(`File type ${mimeType} is not a supported image format.`);
|
|
2042
|
-
this.name = "UnsupportedFormatError";
|
|
2243
|
+
if (sy < 0) {
|
|
2244
|
+
y -= sy;
|
|
2245
|
+
h += sy;
|
|
2246
|
+
sy = 0;
|
|
2043
2247
|
}
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
if (
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
let bitmap = null;
|
|
2051
|
-
try {
|
|
2052
|
-
bitmap = await createImageBitmap(file);
|
|
2053
|
-
const canvas = new OffscreenCanvas(
|
|
2054
|
-
bitmap.width,
|
|
2055
|
-
bitmap.height
|
|
2056
|
-
);
|
|
2057
|
-
const ctx = canvas.getContext("2d");
|
|
2058
|
-
if (!ctx) throw new Error(OFFSCREEN_CANVAS_CTX_FAILED);
|
|
2059
|
-
ctx.drawImage(
|
|
2060
|
-
bitmap,
|
|
2061
|
-
0,
|
|
2062
|
-
0
|
|
2063
|
-
);
|
|
2064
|
-
return ctx.getImageData(
|
|
2065
|
-
0,
|
|
2066
|
-
0,
|
|
2067
|
-
bitmap.width,
|
|
2068
|
-
bitmap.height
|
|
2069
|
-
);
|
|
2070
|
-
} finally {
|
|
2071
|
-
bitmap?.close();
|
|
2072
|
-
}
|
|
2073
|
-
}
|
|
2074
|
-
|
|
2075
|
-
// src/Input/getSupportedRasterFormats.ts
|
|
2076
|
-
var formatsPromise = null;
|
|
2077
|
-
var defaultRasterMimes = [
|
|
2078
|
-
"image/png",
|
|
2079
|
-
"image/jpeg",
|
|
2080
|
-
"image/webp",
|
|
2081
|
-
"image/avif",
|
|
2082
|
-
"image/gif",
|
|
2083
|
-
"image/bmp"
|
|
2084
|
-
];
|
|
2085
|
-
async function getSupportedPixelFormats(rasterMimes = defaultRasterMimes) {
|
|
2086
|
-
if (formatsPromise) {
|
|
2087
|
-
return formatsPromise;
|
|
2088
|
-
}
|
|
2089
|
-
const probeCanvas = async () => {
|
|
2090
|
-
const canvas = new OffscreenCanvas(1, 1);
|
|
2091
|
-
const results = await Promise.all(
|
|
2092
|
-
rasterMimes.map(async (mime) => {
|
|
2093
|
-
try {
|
|
2094
|
-
const blob = await canvas.convertToBlob({
|
|
2095
|
-
type: mime
|
|
2096
|
-
});
|
|
2097
|
-
return blob.type === mime ? mime : null;
|
|
2098
|
-
} catch {
|
|
2099
|
-
return null;
|
|
2100
|
-
}
|
|
2101
|
-
})
|
|
2102
|
-
);
|
|
2103
|
-
return results.filter((type) => {
|
|
2104
|
-
return type !== null;
|
|
2105
|
-
});
|
|
2106
|
-
};
|
|
2107
|
-
formatsPromise = probeCanvas().catch((error) => {
|
|
2108
|
-
formatsPromise = null;
|
|
2109
|
-
throw error;
|
|
2110
|
-
});
|
|
2111
|
-
return formatsPromise;
|
|
2112
|
-
}
|
|
2113
|
-
|
|
2114
|
-
// src/Mask/copyMask.ts
|
|
2115
|
-
function copyMask(src) {
|
|
2116
|
-
return src.slice();
|
|
2117
|
-
}
|
|
2118
|
-
|
|
2119
|
-
// src/Mask/invertMask.ts
|
|
2120
|
-
function invertBinaryMask(dst) {
|
|
2121
|
-
const len = dst.length;
|
|
2122
|
-
for (let i = 0; i < len; i++) {
|
|
2123
|
-
dst[i] = dst[i] === 0 ? 1 : 0;
|
|
2124
|
-
}
|
|
2125
|
-
}
|
|
2126
|
-
function invertAlphaMask(dst) {
|
|
2127
|
-
const len = dst.length;
|
|
2128
|
-
for (let i = 0; i < len; i++) {
|
|
2129
|
-
dst[i] = 255 - dst[i];
|
|
2130
|
-
}
|
|
2131
|
-
}
|
|
2132
|
-
|
|
2133
|
-
// src/Mask/mergeMasks.ts
|
|
2134
|
-
function mergeMasks(dst, dstWidth, src, opts) {
|
|
2135
|
-
const {
|
|
2136
|
-
x: targetX = 0,
|
|
2137
|
-
y: targetY = 0,
|
|
2138
|
-
w: width = 0,
|
|
2139
|
-
h: height = 0,
|
|
2140
|
-
alpha: globalAlpha = 255,
|
|
2141
|
-
maskType = 0 /* ALPHA */,
|
|
2142
|
-
mw,
|
|
2143
|
-
mx = 0,
|
|
2144
|
-
my = 0,
|
|
2145
|
-
invertMask = false
|
|
2146
|
-
} = opts;
|
|
2147
|
-
if (width <= 0 || height <= 0 || globalAlpha === 0) {
|
|
2148
|
-
return;
|
|
2149
|
-
}
|
|
2150
|
-
const sPitch = mw ?? width;
|
|
2151
|
-
const isAlpha = maskType === 0 /* ALPHA */;
|
|
2152
|
-
for (let iy = 0; iy < height; iy++) {
|
|
2153
|
-
const dy = targetY + iy;
|
|
2154
|
-
const sy = my + iy;
|
|
2155
|
-
if (dy < 0 || sy < 0) {
|
|
2156
|
-
continue;
|
|
2157
|
-
}
|
|
2158
|
-
for (let ix = 0; ix < width; ix++) {
|
|
2159
|
-
const dx = targetX + ix;
|
|
2160
|
-
const sx = mx + ix;
|
|
2161
|
-
if (dx < 0 || dx >= dstWidth || sx < 0 || sx >= sPitch) {
|
|
2162
|
-
continue;
|
|
2163
|
-
}
|
|
2164
|
-
const dIdx = dy * dstWidth + dx;
|
|
2165
|
-
const sIdx = sy * sPitch + sx;
|
|
2166
|
-
const mVal = src[sIdx];
|
|
2167
|
-
let weight = globalAlpha;
|
|
2168
|
-
if (isAlpha) {
|
|
2169
|
-
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
2170
|
-
if (effectiveM === 0) {
|
|
2171
|
-
dst[dIdx] = 0;
|
|
2172
|
-
continue;
|
|
2173
|
-
}
|
|
2174
|
-
weight = globalAlpha === 255 ? effectiveM : effectiveM * globalAlpha + 128 >> 8;
|
|
2175
|
-
} else {
|
|
2176
|
-
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
2177
|
-
if (!isHit) {
|
|
2178
|
-
dst[dIdx] = 0;
|
|
2179
|
-
continue;
|
|
2180
|
-
}
|
|
2181
|
-
weight = globalAlpha;
|
|
2182
|
-
}
|
|
2183
|
-
if (weight === 0) {
|
|
2184
|
-
dst[dIdx] = 0;
|
|
2185
|
-
continue;
|
|
2186
|
-
}
|
|
2187
|
-
const da = dst[dIdx];
|
|
2188
|
-
if (da === 0) {
|
|
2189
|
-
} else if (weight === 255) {
|
|
2190
|
-
} else if (da === 255) {
|
|
2191
|
-
dst[dIdx] = weight;
|
|
2192
|
-
} else {
|
|
2193
|
-
dst[dIdx] = da * weight + 128 >> 8;
|
|
2194
|
-
}
|
|
2195
|
-
}
|
|
2196
|
-
}
|
|
2197
|
-
}
|
|
2198
|
-
|
|
2199
|
-
// src/PixelData/PixelData.ts
|
|
2200
|
-
var PixelData = class _PixelData {
|
|
2201
|
-
data32;
|
|
2202
|
-
imageData;
|
|
2203
|
-
get width() {
|
|
2204
|
-
return this.imageData.width;
|
|
2205
|
-
}
|
|
2206
|
-
get height() {
|
|
2207
|
-
return this.imageData.height;
|
|
2208
|
-
}
|
|
2209
|
-
constructor(imageData) {
|
|
2210
|
-
this.data32 = imageDataToUInt32Array(imageData);
|
|
2211
|
-
this.imageData = imageData;
|
|
2212
|
-
}
|
|
2213
|
-
set(imageData) {
|
|
2214
|
-
this.imageData = imageData;
|
|
2215
|
-
this.data32 = imageDataToUInt32Array(imageData);
|
|
2216
|
-
}
|
|
2217
|
-
/**
|
|
2218
|
-
* Creates a deep copy of the PixelData using the environment's ImageData constructor.
|
|
2219
|
-
*/
|
|
2220
|
-
copy() {
|
|
2221
|
-
const buffer = new Uint8ClampedArray(this.imageData.data);
|
|
2222
|
-
const ImageConstructor = typeof ImageData !== "undefined" ? ImageData : this.imageData.constructor;
|
|
2223
|
-
const newImageData = new ImageConstructor(
|
|
2224
|
-
buffer,
|
|
2225
|
-
this.width,
|
|
2226
|
-
this.height
|
|
2227
|
-
);
|
|
2228
|
-
return new _PixelData(newImageData);
|
|
2229
|
-
}
|
|
2230
|
-
};
|
|
2231
|
-
|
|
2232
|
-
// src/PixelData/applyMaskToPixelData.ts
|
|
2233
|
-
function applyMaskToPixelData(dst, mask, opts) {
|
|
2234
|
-
const {
|
|
2235
|
-
x: targetX = 0,
|
|
2236
|
-
y: targetY = 0,
|
|
2237
|
-
w: width = dst.width,
|
|
2238
|
-
h: height = dst.height,
|
|
2239
|
-
alpha: globalAlpha = 255,
|
|
2240
|
-
maskType = 0 /* ALPHA */,
|
|
2241
|
-
mw,
|
|
2242
|
-
mx = 0,
|
|
2243
|
-
my = 0,
|
|
2244
|
-
invertMask = false
|
|
2245
|
-
} = opts;
|
|
2246
|
-
let x = targetX;
|
|
2247
|
-
let y = targetY;
|
|
2248
|
-
let w = width;
|
|
2249
|
-
let h = height;
|
|
2250
|
-
if (x < 0) {
|
|
2251
|
-
w += x;
|
|
2252
|
-
x = 0;
|
|
2248
|
+
w = Math.min(w, src.width - sx);
|
|
2249
|
+
h = Math.min(h, src.height - sy);
|
|
2250
|
+
if (x < 0) {
|
|
2251
|
+
sx -= x;
|
|
2252
|
+
w += x;
|
|
2253
|
+
x = 0;
|
|
2253
2254
|
}
|
|
2254
2255
|
if (y < 0) {
|
|
2256
|
+
sy -= y;
|
|
2255
2257
|
h += y;
|
|
2256
2258
|
y = 0;
|
|
2257
2259
|
}
|
|
2258
2260
|
const actualW = Math.min(w, dst.width - x);
|
|
2259
2261
|
const actualH = Math.min(h, dst.height - y);
|
|
2260
|
-
if (actualW <= 0 || actualH <= 0
|
|
2261
|
-
return;
|
|
2262
|
-
}
|
|
2262
|
+
if (actualW <= 0 || actualH <= 0) return;
|
|
2263
2263
|
const dst32 = dst.data32;
|
|
2264
|
+
const src32 = src.data32;
|
|
2264
2265
|
const dw = dst.width;
|
|
2266
|
+
const sw = src.width;
|
|
2265
2267
|
const mPitch = mw ?? width;
|
|
2266
|
-
const
|
|
2268
|
+
const isAlphaMask = maskType === 0 /* ALPHA */;
|
|
2267
2269
|
const dx = x - targetX;
|
|
2268
2270
|
const dy = y - targetY;
|
|
2269
2271
|
let dIdx = y * dw + x;
|
|
2272
|
+
let sIdx = sy * sw + sx;
|
|
2270
2273
|
let mIdx = (my + dy) * mPitch + (mx + dx);
|
|
2271
2274
|
const dStride = dw - actualW;
|
|
2275
|
+
const sStride = sw - actualW;
|
|
2272
2276
|
const mStride = mPitch - actualW;
|
|
2277
|
+
const isOverwrite = blendFn.isOverwrite;
|
|
2273
2278
|
for (let iy = 0; iy < actualH; iy++) {
|
|
2274
2279
|
for (let ix = 0; ix < actualW; ix++) {
|
|
2275
|
-
const
|
|
2280
|
+
const baseSrcColor = src32[sIdx];
|
|
2281
|
+
const baseSrcAlpha = baseSrcColor >>> 24;
|
|
2282
|
+
if (baseSrcAlpha === 0 && !isOverwrite) {
|
|
2283
|
+
dIdx++;
|
|
2284
|
+
sIdx++;
|
|
2285
|
+
mIdx++;
|
|
2286
|
+
continue;
|
|
2287
|
+
}
|
|
2276
2288
|
let weight = globalAlpha;
|
|
2277
|
-
if (
|
|
2278
|
-
const
|
|
2279
|
-
if (
|
|
2280
|
-
|
|
2289
|
+
if (mask) {
|
|
2290
|
+
const mVal = mask[mIdx];
|
|
2291
|
+
if (isAlphaMask) {
|
|
2292
|
+
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
2293
|
+
if (effectiveM === 0) {
|
|
2294
|
+
dIdx++;
|
|
2295
|
+
sIdx++;
|
|
2296
|
+
mIdx++;
|
|
2297
|
+
continue;
|
|
2298
|
+
}
|
|
2299
|
+
if (globalAlpha === 255) {
|
|
2300
|
+
weight = effectiveM;
|
|
2301
|
+
} else if (effectiveM === 255) {
|
|
2302
|
+
weight = globalAlpha;
|
|
2303
|
+
} else {
|
|
2304
|
+
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
2305
|
+
}
|
|
2306
|
+
} else {
|
|
2307
|
+
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
2308
|
+
if (!isHit) {
|
|
2309
|
+
dIdx++;
|
|
2310
|
+
sIdx++;
|
|
2311
|
+
mIdx++;
|
|
2312
|
+
continue;
|
|
2313
|
+
}
|
|
2314
|
+
weight = globalAlpha;
|
|
2315
|
+
}
|
|
2316
|
+
if (weight === 0) {
|
|
2281
2317
|
dIdx++;
|
|
2318
|
+
sIdx++;
|
|
2282
2319
|
mIdx++;
|
|
2283
2320
|
continue;
|
|
2284
2321
|
}
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2322
|
+
}
|
|
2323
|
+
let currentSrcColor = baseSrcColor;
|
|
2324
|
+
if (weight < 255) {
|
|
2325
|
+
let currentSrcAlpha = baseSrcAlpha;
|
|
2326
|
+
if (baseSrcAlpha === 255) {
|
|
2327
|
+
currentSrcAlpha = weight;
|
|
2328
|
+
} else {
|
|
2329
|
+
currentSrcAlpha = baseSrcAlpha * weight + 128 >> 8;
|
|
2330
|
+
}
|
|
2331
|
+
if (!isOverwrite && currentSrcAlpha === 0) {
|
|
2290
2332
|
dIdx++;
|
|
2333
|
+
sIdx++;
|
|
2291
2334
|
mIdx++;
|
|
2292
2335
|
continue;
|
|
2293
2336
|
}
|
|
2294
|
-
|
|
2295
|
-
}
|
|
2296
|
-
if (weight === 0) {
|
|
2297
|
-
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
2298
|
-
} else {
|
|
2299
|
-
const d = dst32[dIdx];
|
|
2300
|
-
const da = d >>> 24;
|
|
2301
|
-
let finalAlpha = da;
|
|
2302
|
-
if (da === 0) {
|
|
2303
|
-
} else if (weight === 255) {
|
|
2304
|
-
} else if (da === 255) {
|
|
2305
|
-
finalAlpha = weight;
|
|
2306
|
-
} else {
|
|
2307
|
-
finalAlpha = da * weight + 128 >> 8;
|
|
2308
|
-
}
|
|
2309
|
-
dst32[dIdx] = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
2337
|
+
currentSrcColor = (baseSrcColor & 16777215 | currentSrcAlpha << 24) >>> 0;
|
|
2310
2338
|
}
|
|
2339
|
+
dst32[dIdx] = blendFn(currentSrcColor, dst32[dIdx]);
|
|
2311
2340
|
dIdx++;
|
|
2341
|
+
sIdx++;
|
|
2312
2342
|
mIdx++;
|
|
2313
2343
|
}
|
|
2314
2344
|
dIdx += dStride;
|
|
2345
|
+
sIdx += sStride;
|
|
2315
2346
|
mIdx += mStride;
|
|
2316
2347
|
}
|
|
2317
2348
|
}
|
|
2318
2349
|
|
|
2319
|
-
// src/
|
|
2320
|
-
function
|
|
2350
|
+
// src/History/PixelMutator/mutatorBlendPixelData.ts
|
|
2351
|
+
function mutatorBlendPixelData(writer) {
|
|
2352
|
+
return {
|
|
2353
|
+
blendPixelData(src, opts) {
|
|
2354
|
+
const {
|
|
2355
|
+
x = 0,
|
|
2356
|
+
y = 0,
|
|
2357
|
+
w = src.width,
|
|
2358
|
+
h = src.height
|
|
2359
|
+
} = opts;
|
|
2360
|
+
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2361
|
+
blendPixelData(writer.target, src, opts);
|
|
2362
|
+
}
|
|
2363
|
+
};
|
|
2364
|
+
}
|
|
2365
|
+
|
|
2366
|
+
// src/PixelData/fillPixelData.ts
|
|
2367
|
+
function fillPixelData(dst, color, _x, _y, _w, _h) {
|
|
2368
|
+
let x;
|
|
2369
|
+
let y;
|
|
2370
|
+
let w;
|
|
2371
|
+
let h;
|
|
2372
|
+
if (typeof _x === "object") {
|
|
2373
|
+
x = _x.x ?? 0;
|
|
2374
|
+
y = _x.y ?? 0;
|
|
2375
|
+
w = _x.w ?? dst.width;
|
|
2376
|
+
h = _x.h ?? dst.height;
|
|
2377
|
+
} else if (typeof _x === "number") {
|
|
2378
|
+
x = _x;
|
|
2379
|
+
y = _y;
|
|
2380
|
+
w = _w;
|
|
2381
|
+
h = _h;
|
|
2382
|
+
} else {
|
|
2383
|
+
x = 0;
|
|
2384
|
+
y = 0;
|
|
2385
|
+
w = dst.width;
|
|
2386
|
+
h = dst.height;
|
|
2387
|
+
}
|
|
2388
|
+
if (x < 0) {
|
|
2389
|
+
w += x;
|
|
2390
|
+
x = 0;
|
|
2391
|
+
}
|
|
2392
|
+
if (y < 0) {
|
|
2393
|
+
h += y;
|
|
2394
|
+
y = 0;
|
|
2395
|
+
}
|
|
2396
|
+
const actualW = Math.min(w, dst.width - x);
|
|
2397
|
+
const actualH = Math.min(h, dst.height - y);
|
|
2398
|
+
if (actualW <= 0 || actualH <= 0) {
|
|
2399
|
+
return;
|
|
2400
|
+
}
|
|
2401
|
+
const dst32 = dst.data32;
|
|
2402
|
+
const dw = dst.width;
|
|
2403
|
+
if (actualW === dw && actualH === dst.height && x === 0 && y === 0) {
|
|
2404
|
+
dst32.fill(color);
|
|
2405
|
+
return;
|
|
2406
|
+
}
|
|
2407
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2408
|
+
const start = (y + iy) * dw + x;
|
|
2409
|
+
const end = start + actualW;
|
|
2410
|
+
dst32.fill(color, start, end);
|
|
2411
|
+
}
|
|
2412
|
+
}
|
|
2413
|
+
|
|
2414
|
+
// src/History/PixelMutator/mutatorFillPixelData.ts
|
|
2415
|
+
function mutatorFill(writer) {
|
|
2416
|
+
return {
|
|
2417
|
+
fill(color, rect = {}) {
|
|
2418
|
+
const {
|
|
2419
|
+
x = 0,
|
|
2420
|
+
y = 0,
|
|
2421
|
+
w = writer.target.width,
|
|
2422
|
+
h = writer.target.height
|
|
2423
|
+
} = rect;
|
|
2424
|
+
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2425
|
+
fillPixelData(writer.target, color, x, y, w, h);
|
|
2426
|
+
}
|
|
2427
|
+
};
|
|
2428
|
+
}
|
|
2429
|
+
|
|
2430
|
+
// src/PixelData/invertPixelData.ts
|
|
2431
|
+
function invertPixelData(pixelData, opts = {}) {
|
|
2432
|
+
const dst = pixelData;
|
|
2321
2433
|
const {
|
|
2322
2434
|
x: targetX = 0,
|
|
2323
2435
|
y: targetY = 0,
|
|
2324
|
-
w: width =
|
|
2325
|
-
h: height =
|
|
2326
|
-
alpha: globalAlpha = 255,
|
|
2327
|
-
blendFn = sourceOverFast,
|
|
2436
|
+
w: width = pixelData.width,
|
|
2437
|
+
h: height = pixelData.height,
|
|
2328
2438
|
mask,
|
|
2329
|
-
maskType = 0 /* ALPHA */,
|
|
2330
2439
|
mw,
|
|
2331
2440
|
mx = 0,
|
|
2332
2441
|
my = 0,
|
|
2333
2442
|
invertMask = false
|
|
2334
2443
|
} = opts;
|
|
2335
|
-
if (globalAlpha === 0) return;
|
|
2336
|
-
const baseSrcAlpha = color >>> 24;
|
|
2337
|
-
const isOverwrite = blendFn.isOverwrite;
|
|
2338
|
-
if (baseSrcAlpha === 0 && !isOverwrite) return;
|
|
2339
2444
|
let x = targetX;
|
|
2340
2445
|
let y = targetY;
|
|
2341
2446
|
let w = width;
|
|
@@ -2354,255 +2459,798 @@ function blendColorPixelData(dst, color, opts = {}) {
|
|
|
2354
2459
|
const dst32 = dst.data32;
|
|
2355
2460
|
const dw = dst.width;
|
|
2356
2461
|
const mPitch = mw ?? width;
|
|
2357
|
-
const isAlphaMask = maskType === 0 /* ALPHA */;
|
|
2358
2462
|
const dx = x - targetX;
|
|
2359
2463
|
const dy = y - targetY;
|
|
2360
2464
|
let dIdx = y * dw + x;
|
|
2361
2465
|
let mIdx = (my + dy) * mPitch + (mx + dx);
|
|
2362
2466
|
const dStride = dw - actualW;
|
|
2363
2467
|
const mStride = mPitch - actualW;
|
|
2364
|
-
|
|
2365
|
-
for (let
|
|
2366
|
-
let
|
|
2367
|
-
if (mask) {
|
|
2468
|
+
if (mask) {
|
|
2469
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2470
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2368
2471
|
const mVal = mask[mIdx];
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
dIdx++;
|
|
2373
|
-
mIdx++;
|
|
2374
|
-
continue;
|
|
2375
|
-
}
|
|
2376
|
-
if (globalAlpha === 255) {
|
|
2377
|
-
weight = effectiveM;
|
|
2378
|
-
} else if (effectiveM === 255) {
|
|
2379
|
-
weight = globalAlpha;
|
|
2380
|
-
} else {
|
|
2381
|
-
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
2382
|
-
}
|
|
2383
|
-
} else {
|
|
2384
|
-
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
2385
|
-
if (!isHit) {
|
|
2386
|
-
dIdx++;
|
|
2387
|
-
mIdx++;
|
|
2388
|
-
continue;
|
|
2389
|
-
}
|
|
2390
|
-
weight = globalAlpha;
|
|
2391
|
-
}
|
|
2392
|
-
if (weight === 0) {
|
|
2393
|
-
dIdx++;
|
|
2394
|
-
mIdx++;
|
|
2395
|
-
continue;
|
|
2472
|
+
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
2473
|
+
if (isHit) {
|
|
2474
|
+
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
2396
2475
|
}
|
|
2476
|
+
dIdx++;
|
|
2477
|
+
mIdx++;
|
|
2397
2478
|
}
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
if (!isOverwrite && currentSrcAlpha === 0) {
|
|
2407
|
-
dIdx++;
|
|
2408
|
-
mIdx++;
|
|
2409
|
-
continue;
|
|
2410
|
-
}
|
|
2411
|
-
currentSrcColor = (color & 16777215 | currentSrcAlpha << 24) >>> 0;
|
|
2479
|
+
dIdx += dStride;
|
|
2480
|
+
mIdx += mStride;
|
|
2481
|
+
}
|
|
2482
|
+
} else {
|
|
2483
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2484
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2485
|
+
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
2486
|
+
dIdx++;
|
|
2412
2487
|
}
|
|
2413
|
-
|
|
2414
|
-
dIdx++;
|
|
2415
|
-
mIdx++;
|
|
2488
|
+
dIdx += dStride;
|
|
2416
2489
|
}
|
|
2417
|
-
dIdx += dStride;
|
|
2418
|
-
mIdx += mStride;
|
|
2419
2490
|
}
|
|
2420
2491
|
}
|
|
2421
2492
|
|
|
2422
|
-
// src/
|
|
2423
|
-
function
|
|
2493
|
+
// src/History/PixelMutator/mutatorInvert.ts
|
|
2494
|
+
function mutatorInvert(writer) {
|
|
2495
|
+
return {
|
|
2496
|
+
invert(opts = {}) {
|
|
2497
|
+
const {
|
|
2498
|
+
x = 0,
|
|
2499
|
+
y = 0,
|
|
2500
|
+
w = writer.target.width,
|
|
2501
|
+
h = writer.target.height
|
|
2502
|
+
} = opts;
|
|
2503
|
+
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2504
|
+
invertPixelData(writer.target, opts);
|
|
2505
|
+
}
|
|
2506
|
+
};
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2509
|
+
// src/History/PixelMutator.ts
|
|
2510
|
+
function makeFullPixelMutator(writer) {
|
|
2511
|
+
return {
|
|
2512
|
+
...mutatorApplyMask(writer),
|
|
2513
|
+
...mutatorBlendPixelData(writer),
|
|
2514
|
+
...mutatorBlendColor(writer),
|
|
2515
|
+
...mutatorBlendPixel(writer),
|
|
2516
|
+
...mutatorFill(writer),
|
|
2517
|
+
...mutatorInvert(writer)
|
|
2518
|
+
};
|
|
2519
|
+
}
|
|
2520
|
+
|
|
2521
|
+
// src/ImageData/ReusableImageData.ts
|
|
2522
|
+
function makeReusableImageData() {
|
|
2523
|
+
let imageData = null;
|
|
2524
|
+
let buffer = null;
|
|
2525
|
+
return function getReusableImageData(width, height) {
|
|
2526
|
+
const hasInstance = !!imageData;
|
|
2527
|
+
const widthMatches = hasInstance && imageData.width === width;
|
|
2528
|
+
const heightMatches = hasInstance && imageData.height === height;
|
|
2529
|
+
if (!widthMatches || !heightMatches) {
|
|
2530
|
+
const buffer2 = new Uint8ClampedArray(width * height * 4);
|
|
2531
|
+
imageData = new ImageData(buffer2, width, height);
|
|
2532
|
+
}
|
|
2533
|
+
return imageData;
|
|
2534
|
+
};
|
|
2535
|
+
}
|
|
2536
|
+
|
|
2537
|
+
// src/ImageData/copyImageData.ts
|
|
2538
|
+
function copyImageData({ data, width, height }) {
|
|
2539
|
+
return new ImageData(data.slice(), width, height);
|
|
2540
|
+
}
|
|
2541
|
+
function copyImageDataLike({ data, width, height }) {
|
|
2542
|
+
return {
|
|
2543
|
+
data: data.slice(),
|
|
2544
|
+
width,
|
|
2545
|
+
height
|
|
2546
|
+
};
|
|
2547
|
+
}
|
|
2548
|
+
|
|
2549
|
+
// src/PixelData/pixelDataToAlphaMask.ts
|
|
2550
|
+
function pixelDataToAlphaMask(pixelData) {
|
|
2424
2551
|
const {
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2552
|
+
data32,
|
|
2553
|
+
width,
|
|
2554
|
+
height
|
|
2555
|
+
} = pixelData;
|
|
2556
|
+
const len = data32.length;
|
|
2557
|
+
const mask = new Uint8Array(width * height);
|
|
2558
|
+
for (let i = 0; i < len; i++) {
|
|
2559
|
+
const val = data32[i];
|
|
2560
|
+
mask[i] = val >>> 24 & 255;
|
|
2561
|
+
}
|
|
2562
|
+
return mask;
|
|
2563
|
+
}
|
|
2564
|
+
|
|
2565
|
+
// src/ImageData/imageDataToAlphaMask.ts
|
|
2566
|
+
function imageDataToAlphaMask(imageData) {
|
|
2567
|
+
const {
|
|
2568
|
+
width,
|
|
2569
|
+
height,
|
|
2570
|
+
data
|
|
2571
|
+
} = imageData;
|
|
2572
|
+
const data32 = new Uint32Array(
|
|
2573
|
+
data.buffer,
|
|
2574
|
+
data.byteOffset,
|
|
2575
|
+
data.byteLength >> 2
|
|
2576
|
+
);
|
|
2577
|
+
const len = data32.length;
|
|
2578
|
+
const mask = new Uint8Array(width * height);
|
|
2579
|
+
for (let i = 0; i < len; i++) {
|
|
2580
|
+
const val = data32[i];
|
|
2581
|
+
mask[i] = val >>> 24 & 255;
|
|
2582
|
+
}
|
|
2583
|
+
return mask;
|
|
2584
|
+
}
|
|
2585
|
+
|
|
2586
|
+
// src/ImageData/imageDataToDataUrl.ts
|
|
2587
|
+
var get = makeReusableCanvas();
|
|
2588
|
+
function imageDataToDataUrl(imageData) {
|
|
2589
|
+
const { canvas, ctx } = get(imageData.width, imageData.height);
|
|
2590
|
+
ctx.putImageData(imageData, 0, 0);
|
|
2591
|
+
return canvas.toDataURL();
|
|
2592
|
+
}
|
|
2593
|
+
imageDataToDataUrl.reset = get.reset;
|
|
2594
|
+
|
|
2595
|
+
// src/ImageData/imageDataToUInt32Array.ts
|
|
2596
|
+
function imageDataToUInt32Array(imageData) {
|
|
2597
|
+
return new Uint32Array(
|
|
2598
|
+
imageData.data.buffer,
|
|
2599
|
+
imageData.data.byteOffset,
|
|
2600
|
+
// Shift right by 2 is a fast bitwise division by 4.
|
|
2601
|
+
imageData.data.byteLength >> 2
|
|
2602
|
+
);
|
|
2603
|
+
}
|
|
2604
|
+
|
|
2605
|
+
// src/ImageData/invertImageData.ts
|
|
2606
|
+
function invertImageData(imageData) {
|
|
2607
|
+
const data = imageData.data;
|
|
2608
|
+
let length = data.length;
|
|
2609
|
+
for (let i = 0; i < length; i += 4) {
|
|
2610
|
+
data[i] = 255 - data[i];
|
|
2611
|
+
data[i + 1] = 255 - data[i + 1];
|
|
2612
|
+
data[i + 2] = 255 - data[i + 2];
|
|
2613
|
+
}
|
|
2614
|
+
return imageData;
|
|
2615
|
+
}
|
|
2616
|
+
|
|
2617
|
+
// src/Internal/resample32.ts
|
|
2618
|
+
var resample32Scratch = {
|
|
2619
|
+
data: null,
|
|
2620
|
+
width: 0,
|
|
2621
|
+
height: 0
|
|
2622
|
+
};
|
|
2623
|
+
function resample32(srcData32, srcW, srcH, factor) {
|
|
2624
|
+
const dstW = Math.max(1, srcW * factor | 0);
|
|
2625
|
+
const dstH = Math.max(1, srcH * factor | 0);
|
|
2626
|
+
const dstData = new Int32Array(dstW * dstH);
|
|
2627
|
+
const scaleX = srcW / dstW;
|
|
2628
|
+
const scaleY = srcH / dstH;
|
|
2629
|
+
for (let y = 0; y < dstH; y++) {
|
|
2630
|
+
const srcY = Math.min(srcH - 1, y * scaleY | 0);
|
|
2631
|
+
const srcRowOffset = srcY * srcW;
|
|
2632
|
+
const dstRowOffset = y * dstW;
|
|
2633
|
+
for (let x = 0; x < dstW; x++) {
|
|
2634
|
+
const srcX = Math.min(srcW - 1, x * scaleX | 0);
|
|
2635
|
+
dstData[dstRowOffset + x] = srcData32[srcRowOffset + srcX];
|
|
2636
|
+
}
|
|
2637
|
+
}
|
|
2638
|
+
resample32Scratch.data = dstData;
|
|
2639
|
+
resample32Scratch.width = dstW;
|
|
2640
|
+
resample32Scratch.height = dstH;
|
|
2641
|
+
return resample32Scratch;
|
|
2642
|
+
}
|
|
2643
|
+
|
|
2644
|
+
// src/ImageData/resampleImageData.ts
|
|
2645
|
+
function resampleImageData(source, factor) {
|
|
2646
|
+
const src32 = new Uint32Array(source.data.buffer);
|
|
2647
|
+
const { data, width, height } = resample32(src32, source.width, source.height, factor);
|
|
2648
|
+
const uint8ClampedArray = new Uint8ClampedArray(data.buffer);
|
|
2649
|
+
return new ImageData(uint8ClampedArray, width, height);
|
|
2650
|
+
}
|
|
2651
|
+
|
|
2652
|
+
// src/ImageData/resizeImageData.ts
|
|
2653
|
+
function resizeImageData(current, newWidth, newHeight, offsetX = 0, offsetY = 0) {
|
|
2654
|
+
const result = new ImageData(newWidth, newHeight);
|
|
2655
|
+
const {
|
|
2656
|
+
width: oldW,
|
|
2657
|
+
height: oldH,
|
|
2658
|
+
data: oldData
|
|
2659
|
+
} = current;
|
|
2660
|
+
const newData = result.data;
|
|
2661
|
+
const x0 = Math.max(0, offsetX);
|
|
2662
|
+
const y0 = Math.max(0, offsetY);
|
|
2663
|
+
const x1 = Math.min(newWidth, offsetX + oldW);
|
|
2664
|
+
const y1 = Math.min(newHeight, offsetY + oldH);
|
|
2665
|
+
if (x1 <= x0 || y1 <= y0) {
|
|
2666
|
+
return result;
|
|
2667
|
+
}
|
|
2668
|
+
const rowCount = y1 - y0;
|
|
2669
|
+
const rowLen = (x1 - x0) * 4;
|
|
2670
|
+
for (let row = 0; row < rowCount; row++) {
|
|
2671
|
+
const dstY = y0 + row;
|
|
2672
|
+
const srcY = dstY - offsetY;
|
|
2673
|
+
const srcX = x0 - offsetX;
|
|
2674
|
+
const dstStart = (dstY * newWidth + x0) * 4;
|
|
2675
|
+
const srcStart = (srcY * oldW + srcX) * 4;
|
|
2676
|
+
newData.set(
|
|
2677
|
+
oldData.subarray(srcStart, srcStart + rowLen),
|
|
2678
|
+
dstStart
|
|
2679
|
+
);
|
|
2680
|
+
}
|
|
2681
|
+
return result;
|
|
2682
|
+
}
|
|
2683
|
+
|
|
2684
|
+
// src/ImageData/serialization.ts
|
|
2685
|
+
function base64EncodeArrayBuffer(buffer) {
|
|
2686
|
+
const uint8 = new Uint8Array(buffer);
|
|
2687
|
+
const decoder = new TextDecoder("latin1");
|
|
2688
|
+
const binary = decoder.decode(uint8);
|
|
2689
|
+
return btoa(binary);
|
|
2690
|
+
}
|
|
2691
|
+
function base64DecodeArrayBuffer(encoded) {
|
|
2692
|
+
const binary = atob(encoded);
|
|
2693
|
+
const bytes = new Uint8ClampedArray(binary.length);
|
|
2694
|
+
for (let i = 0; i < binary.length; i++) {
|
|
2695
|
+
bytes[i] = binary.charCodeAt(i);
|
|
2696
|
+
}
|
|
2697
|
+
return bytes;
|
|
2698
|
+
}
|
|
2699
|
+
function serializeImageData(imageData) {
|
|
2700
|
+
return {
|
|
2701
|
+
width: imageData.width,
|
|
2702
|
+
height: imageData.height,
|
|
2703
|
+
data: base64EncodeArrayBuffer(imageData.data.buffer)
|
|
2704
|
+
};
|
|
2705
|
+
}
|
|
2706
|
+
function serializeNullableImageData(imageData) {
|
|
2707
|
+
if (!imageData) return null;
|
|
2708
|
+
return serializeImageData(imageData);
|
|
2709
|
+
}
|
|
2710
|
+
function deserializeRawImageData(serialized) {
|
|
2711
|
+
return {
|
|
2712
|
+
width: serialized.width,
|
|
2713
|
+
height: serialized.height,
|
|
2714
|
+
data: base64DecodeArrayBuffer(serialized.data)
|
|
2715
|
+
};
|
|
2716
|
+
}
|
|
2717
|
+
function deserializeImageData(serialized) {
|
|
2718
|
+
const data = base64DecodeArrayBuffer(serialized.data);
|
|
2719
|
+
return new ImageData(data, serialized.width, serialized.height);
|
|
2720
|
+
}
|
|
2721
|
+
function deserializeNullableImageData(serialized) {
|
|
2722
|
+
if (!serialized) return null;
|
|
2723
|
+
return deserializeImageData(serialized);
|
|
2724
|
+
}
|
|
2725
|
+
|
|
2726
|
+
// src/ImageData/writeImageData.ts
|
|
2727
|
+
function writeImageData(target, source, x, y, sx = 0, sy = 0, sw = source.width, sh = source.height, mask = null, maskType = 1 /* BINARY */) {
|
|
2728
|
+
const dstW = target.width;
|
|
2729
|
+
const dstH = target.height;
|
|
2730
|
+
const dstData = target.data;
|
|
2731
|
+
const srcW = source.width;
|
|
2732
|
+
const srcData = source.data;
|
|
2733
|
+
const x0 = Math.max(0, x);
|
|
2734
|
+
const y0 = Math.max(0, y);
|
|
2735
|
+
const x1 = Math.min(dstW, x + sw);
|
|
2736
|
+
const y1 = Math.min(dstH, y + sh);
|
|
2737
|
+
if (x1 <= x0 || y1 <= y0) {
|
|
2738
|
+
return;
|
|
2739
|
+
}
|
|
2740
|
+
const useMask = !!mask;
|
|
2741
|
+
const rowCount = y1 - y0;
|
|
2742
|
+
const rowLenPixels = x1 - x0;
|
|
2743
|
+
for (let row = 0; row < rowCount; row++) {
|
|
2744
|
+
const dstY = y0 + row;
|
|
2745
|
+
const srcY = sy + (dstY - y);
|
|
2746
|
+
const srcXBase = sx + (x0 - x);
|
|
2747
|
+
const dstStart = (dstY * dstW + x0) * 4;
|
|
2748
|
+
const srcStart = (srcY * srcW + srcXBase) * 4;
|
|
2749
|
+
if (useMask && mask) {
|
|
2750
|
+
for (let ix = 0; ix < rowLenPixels; ix++) {
|
|
2751
|
+
const mi = srcY * srcW + (srcXBase + ix);
|
|
2752
|
+
const alpha = mask[mi];
|
|
2753
|
+
if (alpha === 0) {
|
|
2754
|
+
continue;
|
|
2755
|
+
}
|
|
2756
|
+
const di = dstStart + ix * 4;
|
|
2757
|
+
const si = srcStart + ix * 4;
|
|
2758
|
+
if (maskType === 1 /* BINARY */ || alpha === 255) {
|
|
2759
|
+
dstData[di] = srcData[si];
|
|
2760
|
+
dstData[di + 1] = srcData[si + 1];
|
|
2761
|
+
dstData[di + 2] = srcData[si + 2];
|
|
2762
|
+
dstData[di + 3] = srcData[si + 3];
|
|
2763
|
+
} else {
|
|
2764
|
+
const a = alpha / 255;
|
|
2765
|
+
const invA = 1 - a;
|
|
2766
|
+
dstData[di] = srcData[si] * a + dstData[di] * invA;
|
|
2767
|
+
dstData[di + 1] = srcData[si + 1] * a + dstData[di + 1] * invA;
|
|
2768
|
+
dstData[di + 2] = srcData[si + 2] * a + dstData[di + 2] * invA;
|
|
2769
|
+
dstData[di + 3] = srcData[si + 3] * a + dstData[di + 3] * invA;
|
|
2770
|
+
}
|
|
2771
|
+
}
|
|
2772
|
+
} else {
|
|
2773
|
+
const byteLen = rowLenPixels * 4;
|
|
2774
|
+
const sub = srcData.subarray(srcStart, srcStart + byteLen);
|
|
2775
|
+
dstData.set(sub, dstStart);
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2778
|
+
}
|
|
2779
|
+
|
|
2780
|
+
// src/ImageData/writeImageDataBuffer.ts
|
|
2781
|
+
function writeImageDataBuffer(imageData, data, _x, _y, _w, _h) {
|
|
2782
|
+
const { x, y, w, h } = typeof _x === "object" ? _x : { x: _x, y: _y, w: _w, h: _h };
|
|
2783
|
+
const { width: dstW, height: dstH, data: dst } = imageData;
|
|
2784
|
+
const x0 = Math.max(0, x);
|
|
2785
|
+
const y0 = Math.max(0, y);
|
|
2786
|
+
const x1 = Math.min(dstW, x + w);
|
|
2787
|
+
const y1 = Math.min(dstH, y + h);
|
|
2788
|
+
if (x1 <= x0 || y1 <= y0) return;
|
|
2789
|
+
const rowLen = (x1 - x0) * 4;
|
|
2790
|
+
const srcCol = x0 - x;
|
|
2791
|
+
const srcYOffset = y0 - y;
|
|
2792
|
+
const actualH = y1 - y0;
|
|
2793
|
+
for (let row = 0; row < actualH; row++) {
|
|
2794
|
+
const dstStart = ((y0 + row) * dstW + x0) * 4;
|
|
2795
|
+
const srcRow = srcYOffset + row;
|
|
2796
|
+
const o = (srcRow * w + srcCol) * 4;
|
|
2797
|
+
dst.set(data.subarray(o, o + rowLen), dstStart);
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
|
|
2801
|
+
// src/IndexedImage/IndexedImage.ts
|
|
2802
|
+
var IndexedImage = class _IndexedImage {
|
|
2803
|
+
/** The width of the image in pixels. */
|
|
2804
|
+
width;
|
|
2805
|
+
/** The height of the image in pixels. */
|
|
2806
|
+
height;
|
|
2807
|
+
/** Flat array of palette indices. Index = x + (y * width). */
|
|
2808
|
+
data;
|
|
2809
|
+
/** The palette of unique 32-bit colors (ABGR/RGBA packed) found in the image. */
|
|
2810
|
+
palette;
|
|
2811
|
+
/** The specific index in the palette reserved for fully transparent pixels. */
|
|
2812
|
+
transparentPalletIndex;
|
|
2813
|
+
/**
|
|
2814
|
+
* @param width - Image width.
|
|
2815
|
+
* @param height - Image height.
|
|
2816
|
+
* @param data - The indexed pixel data.
|
|
2817
|
+
* @param palette - The array of packed colors.
|
|
2818
|
+
* @param transparentPalletIndex - The index representing alpha 0.
|
|
2819
|
+
*/
|
|
2820
|
+
constructor(width, height, data, palette, transparentPalletIndex) {
|
|
2821
|
+
this.width = width;
|
|
2822
|
+
this.height = height;
|
|
2823
|
+
this.data = data;
|
|
2824
|
+
this.palette = palette;
|
|
2825
|
+
this.transparentPalletIndex = transparentPalletIndex;
|
|
2826
|
+
}
|
|
2827
|
+
/**
|
|
2828
|
+
* Creates an IndexedImage from standard browser ImageData.
|
|
2829
|
+
* @param imageData - The source ImageData to convert.
|
|
2830
|
+
* @returns A new IndexedImage instance.
|
|
2831
|
+
*/
|
|
2832
|
+
static fromImageData(imageData) {
|
|
2833
|
+
return _IndexedImage.fromRaw(imageData.data, imageData.width, imageData.height);
|
|
2834
|
+
}
|
|
2835
|
+
/**
|
|
2836
|
+
* Creates an IndexedImage from a raw byte buffer and dimensions.
|
|
2837
|
+
* Any pixel with an alpha channel of 0 is normalized to the transparent palette index.
|
|
2838
|
+
* @param data - Raw RGBA byte data.
|
|
2839
|
+
* @param width - Image width.
|
|
2840
|
+
* @param height - Image height.
|
|
2841
|
+
* @returns A new IndexedImage instance.
|
|
2842
|
+
*/
|
|
2843
|
+
static fromRaw(data, width, height) {
|
|
2844
|
+
const buffer = data.buffer;
|
|
2845
|
+
const rawData = new Uint32Array(buffer);
|
|
2846
|
+
const indexedData = new Int32Array(rawData.length);
|
|
2847
|
+
const colorMap = /* @__PURE__ */ new Map();
|
|
2848
|
+
const transparentColor = 0;
|
|
2849
|
+
const transparentPalletIndex = 0;
|
|
2850
|
+
colorMap.set(transparentColor, transparentPalletIndex);
|
|
2851
|
+
for (let i = 0; i < rawData.length; i++) {
|
|
2852
|
+
const pixel = rawData[i];
|
|
2853
|
+
const alpha = pixel >>> 24 & 255;
|
|
2854
|
+
const isTransparent = alpha === 0;
|
|
2855
|
+
const colorKey = isTransparent ? transparentColor : pixel >>> 0;
|
|
2856
|
+
let id = colorMap.get(colorKey);
|
|
2857
|
+
if (id === void 0) {
|
|
2858
|
+
id = colorMap.size;
|
|
2859
|
+
colorMap.set(colorKey, id);
|
|
2860
|
+
}
|
|
2861
|
+
indexedData[i] = id;
|
|
2862
|
+
}
|
|
2863
|
+
const palette = Uint32Array.from(colorMap.keys());
|
|
2864
|
+
return new _IndexedImage(
|
|
2865
|
+
width,
|
|
2866
|
+
height,
|
|
2867
|
+
indexedData,
|
|
2868
|
+
palette,
|
|
2869
|
+
transparentPalletIndex
|
|
2870
|
+
);
|
|
2871
|
+
}
|
|
2872
|
+
/**
|
|
2873
|
+
* Retrieves the 32-bit packed color value at the given coordinates.
|
|
2874
|
+
* @param x - X coordinate.
|
|
2875
|
+
* @param y - Y coordinate.
|
|
2876
|
+
* @returns The packed color from the palette.
|
|
2877
|
+
*/
|
|
2878
|
+
getColorAt(x, y) {
|
|
2879
|
+
const index = x + y * this.width;
|
|
2880
|
+
const paletteIndex = this.data[index];
|
|
2881
|
+
return this.palette[paletteIndex];
|
|
2882
|
+
}
|
|
2883
|
+
};
|
|
2884
|
+
|
|
2885
|
+
// src/IndexedImage/getIndexedImageColorCounts.ts
|
|
2886
|
+
function getIndexedImageColorCounts(indexedImage) {
|
|
2887
|
+
const data = indexedImage.data;
|
|
2888
|
+
const palette = indexedImage.palette;
|
|
2889
|
+
const frequencies = new Int32Array(palette.length);
|
|
2890
|
+
for (let i = 0; i < data.length; i++) {
|
|
2891
|
+
const colorIndex = data[i];
|
|
2892
|
+
frequencies[colorIndex]++;
|
|
2893
|
+
}
|
|
2894
|
+
return frequencies;
|
|
2895
|
+
}
|
|
2896
|
+
|
|
2897
|
+
// src/IndexedImage/indexedImageToAverageColor.ts
|
|
2898
|
+
function indexedImageToAverageColor(indexedImage, includeTransparent = false) {
|
|
2899
|
+
const { data, palette, transparentPalletIndex } = indexedImage;
|
|
2900
|
+
const counts = new Uint32Array(palette.length);
|
|
2901
|
+
for (let i = 0; i < data.length; i++) {
|
|
2902
|
+
const id = data[i];
|
|
2903
|
+
counts[id]++;
|
|
2904
|
+
}
|
|
2905
|
+
let rSum = 0;
|
|
2906
|
+
let gSum = 0;
|
|
2907
|
+
let bSum = 0;
|
|
2908
|
+
let aSum = 0;
|
|
2909
|
+
let totalWeight = 0;
|
|
2910
|
+
for (let id = 0; id < counts.length; id++) {
|
|
2911
|
+
const weight = counts[id];
|
|
2912
|
+
if (weight === 0) {
|
|
2913
|
+
continue;
|
|
2914
|
+
}
|
|
2915
|
+
if (!includeTransparent && id === transparentPalletIndex) {
|
|
2916
|
+
continue;
|
|
2917
|
+
}
|
|
2918
|
+
const color = palette[id] >>> 0;
|
|
2919
|
+
const r2 = color & 255;
|
|
2920
|
+
const g2 = color >> 8 & 255;
|
|
2921
|
+
const b2 = color >> 16 & 255;
|
|
2922
|
+
const a2 = color >> 24 & 255;
|
|
2923
|
+
rSum += r2 * weight;
|
|
2924
|
+
gSum += g2 * weight;
|
|
2925
|
+
bSum += b2 * weight;
|
|
2926
|
+
aSum += a2 * weight;
|
|
2927
|
+
totalWeight += weight;
|
|
2928
|
+
}
|
|
2929
|
+
if (totalWeight === 0) {
|
|
2930
|
+
return packColor(0, 0, 0, 0);
|
|
2931
|
+
}
|
|
2932
|
+
const r = rSum / totalWeight | 0;
|
|
2933
|
+
const g = gSum / totalWeight | 0;
|
|
2934
|
+
const b = bSum / totalWeight | 0;
|
|
2935
|
+
const a = aSum / totalWeight | 0;
|
|
2936
|
+
return packColor(r, g, b, a);
|
|
2937
|
+
}
|
|
2938
|
+
|
|
2939
|
+
// src/IndexedImage/resampleIndexedImage.ts
|
|
2940
|
+
function resampleIndexedImage(source, factor) {
|
|
2941
|
+
const { data, width, height } = resample32(
|
|
2942
|
+
source.data,
|
|
2943
|
+
source.width,
|
|
2944
|
+
source.height,
|
|
2945
|
+
factor
|
|
2946
|
+
);
|
|
2947
|
+
return new IndexedImage(
|
|
2948
|
+
width,
|
|
2949
|
+
height,
|
|
2950
|
+
data,
|
|
2951
|
+
source.palette,
|
|
2952
|
+
source.transparentPalletIndex
|
|
2953
|
+
);
|
|
2954
|
+
}
|
|
2955
|
+
|
|
2956
|
+
// src/IndexedImage/indexedImageToImageData.ts
|
|
2957
|
+
function indexedImageToImageData(indexedImage) {
|
|
2958
|
+
const { width, height, data, palette } = indexedImage;
|
|
2959
|
+
const result = new ImageData(width, height);
|
|
2960
|
+
const data32 = new Uint32Array(result.data.buffer);
|
|
2961
|
+
for (let i = 0; i < data.length; i++) {
|
|
2962
|
+
const paletteIndex = data[i];
|
|
2963
|
+
const color = palette[paletteIndex];
|
|
2964
|
+
data32[i] = color;
|
|
2965
|
+
}
|
|
2966
|
+
return result;
|
|
2967
|
+
}
|
|
2968
|
+
|
|
2969
|
+
// src/Input/fileInputChangeToImageData.ts
|
|
2970
|
+
async function fileInputChangeToImageData(event) {
|
|
2971
|
+
const target = event.target;
|
|
2972
|
+
const file = target.files?.[0];
|
|
2973
|
+
if (!file) return null;
|
|
2974
|
+
return await fileToImageData(file);
|
|
2975
|
+
}
|
|
2976
|
+
|
|
2977
|
+
// src/Input/fileToImageData.ts
|
|
2978
|
+
var UnsupportedFormatError = class extends Error {
|
|
2979
|
+
constructor(mimeType) {
|
|
2980
|
+
super(`File type ${mimeType} is not a supported image format.`);
|
|
2981
|
+
this.name = "UnsupportedFormatError";
|
|
2982
|
+
}
|
|
2983
|
+
};
|
|
2984
|
+
async function fileToImageData(file) {
|
|
2985
|
+
if (!file) return null;
|
|
2986
|
+
if (!file.type.startsWith("image/")) {
|
|
2987
|
+
throw new UnsupportedFormatError(file.type);
|
|
2988
|
+
}
|
|
2989
|
+
let bitmap = null;
|
|
2990
|
+
try {
|
|
2991
|
+
bitmap = await createImageBitmap(file);
|
|
2992
|
+
const canvas = new OffscreenCanvas(
|
|
2993
|
+
bitmap.width,
|
|
2994
|
+
bitmap.height
|
|
2995
|
+
);
|
|
2996
|
+
const ctx = canvas.getContext("2d");
|
|
2997
|
+
if (!ctx) throw new Error(OFFSCREEN_CANVAS_CTX_FAILED);
|
|
2998
|
+
ctx.drawImage(
|
|
2999
|
+
bitmap,
|
|
3000
|
+
0,
|
|
3001
|
+
0
|
|
3002
|
+
);
|
|
3003
|
+
return ctx.getImageData(
|
|
3004
|
+
0,
|
|
3005
|
+
0,
|
|
3006
|
+
bitmap.width,
|
|
3007
|
+
bitmap.height
|
|
3008
|
+
);
|
|
3009
|
+
} finally {
|
|
3010
|
+
bitmap?.close();
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
|
|
3014
|
+
// src/Input/getSupportedRasterFormats.ts
|
|
3015
|
+
var formatsPromise = null;
|
|
3016
|
+
var defaultRasterMimes = [
|
|
3017
|
+
"image/png",
|
|
3018
|
+
"image/jpeg",
|
|
3019
|
+
"image/webp",
|
|
3020
|
+
"image/avif",
|
|
3021
|
+
"image/gif",
|
|
3022
|
+
"image/bmp"
|
|
3023
|
+
];
|
|
3024
|
+
async function getSupportedPixelFormats(rasterMimes = defaultRasterMimes) {
|
|
3025
|
+
if (formatsPromise) {
|
|
3026
|
+
return formatsPromise;
|
|
3027
|
+
}
|
|
3028
|
+
const probeCanvas = async () => {
|
|
3029
|
+
const canvas = new OffscreenCanvas(1, 1);
|
|
3030
|
+
const results = await Promise.all(
|
|
3031
|
+
rasterMimes.map(async (mime) => {
|
|
3032
|
+
try {
|
|
3033
|
+
const blob = await canvas.convertToBlob({
|
|
3034
|
+
type: mime
|
|
3035
|
+
});
|
|
3036
|
+
return blob.type === mime ? mime : null;
|
|
3037
|
+
} catch {
|
|
3038
|
+
return null;
|
|
3039
|
+
}
|
|
3040
|
+
})
|
|
3041
|
+
);
|
|
3042
|
+
return results.filter((type) => {
|
|
3043
|
+
return type !== null;
|
|
3044
|
+
});
|
|
3045
|
+
};
|
|
3046
|
+
formatsPromise = probeCanvas().catch((error) => {
|
|
3047
|
+
formatsPromise = null;
|
|
3048
|
+
throw error;
|
|
3049
|
+
});
|
|
3050
|
+
return formatsPromise;
|
|
3051
|
+
}
|
|
3052
|
+
|
|
3053
|
+
// src/Mask/copyMask.ts
|
|
3054
|
+
function copyMask(src) {
|
|
3055
|
+
return src.slice();
|
|
3056
|
+
}
|
|
3057
|
+
|
|
3058
|
+
// src/Mask/invertMask.ts
|
|
3059
|
+
function invertBinaryMask(dst) {
|
|
3060
|
+
const len = dst.length;
|
|
3061
|
+
for (let i = 0; i < len; i++) {
|
|
3062
|
+
dst[i] = dst[i] === 0 ? 1 : 0;
|
|
3063
|
+
}
|
|
3064
|
+
}
|
|
3065
|
+
function invertAlphaMask(dst) {
|
|
3066
|
+
const len = dst.length;
|
|
3067
|
+
for (let i = 0; i < len; i++) {
|
|
3068
|
+
dst[i] = 255 - dst[i];
|
|
3069
|
+
}
|
|
3070
|
+
}
|
|
3071
|
+
|
|
3072
|
+
// src/Mask/mergeMasks.ts
|
|
3073
|
+
function mergeMasks(dst, dstWidth, src, opts) {
|
|
3074
|
+
const {
|
|
3075
|
+
x: targetX = 0,
|
|
3076
|
+
y: targetY = 0,
|
|
3077
|
+
w: width = 0,
|
|
3078
|
+
h: height = 0,
|
|
2431
3079
|
alpha: globalAlpha = 255,
|
|
2432
|
-
blendFn = FAST_BLEND_MODES[1 /* sourceOver */],
|
|
2433
|
-
mask,
|
|
2434
3080
|
maskType = 0 /* ALPHA */,
|
|
2435
3081
|
mw,
|
|
2436
3082
|
mx = 0,
|
|
2437
3083
|
my = 0,
|
|
2438
3084
|
invertMask = false
|
|
2439
3085
|
} = opts;
|
|
2440
|
-
if (globalAlpha === 0)
|
|
2441
|
-
|
|
2442
|
-
let y = targetY;
|
|
2443
|
-
let sx = sourceX;
|
|
2444
|
-
let sy = sourceY;
|
|
2445
|
-
let w = width;
|
|
2446
|
-
let h = height;
|
|
2447
|
-
if (sx < 0) {
|
|
2448
|
-
x -= sx;
|
|
2449
|
-
w += sx;
|
|
2450
|
-
sx = 0;
|
|
2451
|
-
}
|
|
2452
|
-
if (sy < 0) {
|
|
2453
|
-
y -= sy;
|
|
2454
|
-
h += sy;
|
|
2455
|
-
sy = 0;
|
|
2456
|
-
}
|
|
2457
|
-
w = Math.min(w, src.width - sx);
|
|
2458
|
-
h = Math.min(h, src.height - sy);
|
|
2459
|
-
if (x < 0) {
|
|
2460
|
-
sx -= x;
|
|
2461
|
-
w += x;
|
|
2462
|
-
x = 0;
|
|
2463
|
-
}
|
|
2464
|
-
if (y < 0) {
|
|
2465
|
-
sy -= y;
|
|
2466
|
-
h += y;
|
|
2467
|
-
y = 0;
|
|
3086
|
+
if (width <= 0 || height <= 0 || globalAlpha === 0) {
|
|
3087
|
+
return;
|
|
2468
3088
|
}
|
|
2469
|
-
const
|
|
2470
|
-
const
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
let sIdx = sy * sw + sx;
|
|
2482
|
-
let mIdx = (my + dy) * mPitch + (mx + dx);
|
|
2483
|
-
const dStride = dw - actualW;
|
|
2484
|
-
const sStride = sw - actualW;
|
|
2485
|
-
const mStride = mPitch - actualW;
|
|
2486
|
-
const isOverwrite = blendFn.isOverwrite;
|
|
2487
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
2488
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
2489
|
-
const baseSrcColor = src32[sIdx];
|
|
2490
|
-
const baseSrcAlpha = baseSrcColor >>> 24;
|
|
2491
|
-
if (baseSrcAlpha === 0 && !isOverwrite) {
|
|
2492
|
-
dIdx++;
|
|
2493
|
-
sIdx++;
|
|
2494
|
-
mIdx++;
|
|
3089
|
+
const sPitch = mw ?? width;
|
|
3090
|
+
const isAlpha = maskType === 0 /* ALPHA */;
|
|
3091
|
+
for (let iy = 0; iy < height; iy++) {
|
|
3092
|
+
const dy = targetY + iy;
|
|
3093
|
+
const sy = my + iy;
|
|
3094
|
+
if (dy < 0 || sy < 0) {
|
|
3095
|
+
continue;
|
|
3096
|
+
}
|
|
3097
|
+
for (let ix = 0; ix < width; ix++) {
|
|
3098
|
+
const dx = targetX + ix;
|
|
3099
|
+
const sx = mx + ix;
|
|
3100
|
+
if (dx < 0 || dx >= dstWidth || sx < 0 || sx >= sPitch) {
|
|
2495
3101
|
continue;
|
|
2496
3102
|
}
|
|
3103
|
+
const dIdx = dy * dstWidth + dx;
|
|
3104
|
+
const sIdx = sy * sPitch + sx;
|
|
3105
|
+
const mVal = src[sIdx];
|
|
2497
3106
|
let weight = globalAlpha;
|
|
2498
|
-
if (
|
|
2499
|
-
const
|
|
2500
|
-
if (
|
|
2501
|
-
|
|
2502
|
-
if (effectiveM === 0) {
|
|
2503
|
-
dIdx++;
|
|
2504
|
-
sIdx++;
|
|
2505
|
-
mIdx++;
|
|
2506
|
-
continue;
|
|
2507
|
-
}
|
|
2508
|
-
if (globalAlpha === 255) {
|
|
2509
|
-
weight = effectiveM;
|
|
2510
|
-
} else if (effectiveM === 255) {
|
|
2511
|
-
weight = globalAlpha;
|
|
2512
|
-
} else {
|
|
2513
|
-
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
2514
|
-
}
|
|
2515
|
-
} else {
|
|
2516
|
-
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
2517
|
-
if (!isHit) {
|
|
2518
|
-
dIdx++;
|
|
2519
|
-
sIdx++;
|
|
2520
|
-
mIdx++;
|
|
2521
|
-
continue;
|
|
2522
|
-
}
|
|
2523
|
-
weight = globalAlpha;
|
|
2524
|
-
}
|
|
2525
|
-
if (weight === 0) {
|
|
2526
|
-
dIdx++;
|
|
2527
|
-
sIdx++;
|
|
2528
|
-
mIdx++;
|
|
3107
|
+
if (isAlpha) {
|
|
3108
|
+
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
3109
|
+
if (effectiveM === 0) {
|
|
3110
|
+
dst[dIdx] = 0;
|
|
2529
3111
|
continue;
|
|
2530
3112
|
}
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
currentSrcAlpha = weight;
|
|
2537
|
-
} else {
|
|
2538
|
-
currentSrcAlpha = baseSrcAlpha * weight + 128 >> 8;
|
|
2539
|
-
}
|
|
2540
|
-
if (!isOverwrite && currentSrcAlpha === 0) {
|
|
2541
|
-
dIdx++;
|
|
2542
|
-
sIdx++;
|
|
2543
|
-
mIdx++;
|
|
3113
|
+
weight = globalAlpha === 255 ? effectiveM : effectiveM * globalAlpha + 128 >> 8;
|
|
3114
|
+
} else {
|
|
3115
|
+
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
3116
|
+
if (!isHit) {
|
|
3117
|
+
dst[dIdx] = 0;
|
|
2544
3118
|
continue;
|
|
2545
3119
|
}
|
|
2546
|
-
|
|
3120
|
+
weight = globalAlpha;
|
|
3121
|
+
}
|
|
3122
|
+
if (weight === 0) {
|
|
3123
|
+
dst[dIdx] = 0;
|
|
3124
|
+
continue;
|
|
3125
|
+
}
|
|
3126
|
+
const da = dst[dIdx];
|
|
3127
|
+
if (da === 0) {
|
|
3128
|
+
} else if (weight === 255) {
|
|
3129
|
+
} else if (da === 255) {
|
|
3130
|
+
dst[dIdx] = weight;
|
|
3131
|
+
} else {
|
|
3132
|
+
dst[dIdx] = da * weight + 128 >> 8;
|
|
2547
3133
|
}
|
|
2548
|
-
dst32[dIdx] = blendFn(currentSrcColor, dst32[dIdx]);
|
|
2549
|
-
dIdx++;
|
|
2550
|
-
sIdx++;
|
|
2551
|
-
mIdx++;
|
|
2552
3134
|
}
|
|
2553
|
-
dIdx += dStride;
|
|
2554
|
-
sIdx += sStride;
|
|
2555
|
-
mIdx += mStride;
|
|
2556
3135
|
}
|
|
2557
3136
|
}
|
|
2558
3137
|
|
|
2559
|
-
// src/PixelData/
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
if (typeof _x === "object") {
|
|
2566
|
-
x = _x.x ?? 0;
|
|
2567
|
-
y = _x.y ?? 0;
|
|
2568
|
-
w = _x.w ?? dst.width;
|
|
2569
|
-
h = _x.h ?? dst.height;
|
|
2570
|
-
} else if (typeof _x === "number") {
|
|
2571
|
-
x = _x;
|
|
2572
|
-
y = _y;
|
|
2573
|
-
w = _w;
|
|
2574
|
-
h = _h;
|
|
2575
|
-
} else {
|
|
2576
|
-
x = 0;
|
|
2577
|
-
y = 0;
|
|
2578
|
-
w = dst.width;
|
|
2579
|
-
h = dst.height;
|
|
3138
|
+
// src/PixelData/PixelData.ts
|
|
3139
|
+
var PixelData = class _PixelData {
|
|
3140
|
+
data32;
|
|
3141
|
+
imageData;
|
|
3142
|
+
get width() {
|
|
3143
|
+
return this.imageData.width;
|
|
2580
3144
|
}
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
x = 0;
|
|
3145
|
+
get height() {
|
|
3146
|
+
return this.imageData.height;
|
|
2584
3147
|
}
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
3148
|
+
constructor(imageData) {
|
|
3149
|
+
this.data32 = imageDataToUInt32Array(imageData);
|
|
3150
|
+
this.imageData = imageData;
|
|
2588
3151
|
}
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
return;
|
|
3152
|
+
set(imageData) {
|
|
3153
|
+
this.imageData = imageData;
|
|
3154
|
+
this.data32 = imageDataToUInt32Array(imageData);
|
|
2593
3155
|
}
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
3156
|
+
/**
|
|
3157
|
+
* Creates a deep copy of the PixelData using the environment's ImageData constructor.
|
|
3158
|
+
*/
|
|
3159
|
+
copy() {
|
|
3160
|
+
const buffer = new Uint8ClampedArray(this.imageData.data);
|
|
3161
|
+
const ImageConstructor = typeof ImageData !== "undefined" ? ImageData : this.imageData.constructor;
|
|
3162
|
+
const newImageData = new ImageConstructor(
|
|
3163
|
+
buffer,
|
|
3164
|
+
this.width,
|
|
3165
|
+
this.height
|
|
3166
|
+
);
|
|
3167
|
+
return new _PixelData(newImageData);
|
|
2599
3168
|
}
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
3169
|
+
};
|
|
3170
|
+
|
|
3171
|
+
// src/PixelData/applyCircleBrushToPixelData.ts
|
|
3172
|
+
function applyCircleBrushToPixelData(target, color, centerX, centerY, brushSize, alpha = 255, fallOff, blendFn = sourceOverPerfect) {
|
|
3173
|
+
const r = brushSize / 2;
|
|
3174
|
+
const rSqr = r * r;
|
|
3175
|
+
const centerOffset = brushSize % 2 === 0 ? 0.5 : 0;
|
|
3176
|
+
const xStart = Math.max(0, Math.ceil(centerX - r));
|
|
3177
|
+
const xEnd = Math.min(target.width - 1, Math.floor(centerX + r));
|
|
3178
|
+
const yStart = Math.max(0, Math.ceil(centerY - r));
|
|
3179
|
+
const yEnd = Math.min(target.height - 1, Math.floor(centerY + r));
|
|
3180
|
+
const data32 = target.data32;
|
|
3181
|
+
const targetWidth = target.width;
|
|
3182
|
+
const baseColor = color & 16777215;
|
|
3183
|
+
const invR = 1 / r;
|
|
3184
|
+
const constantSrc = (alpha << 24 | baseColor) >>> 0;
|
|
3185
|
+
for (let cy = yStart; cy <= yEnd; cy++) {
|
|
3186
|
+
const dy = cy - centerY + centerOffset;
|
|
3187
|
+
const dySqr = dy * dy;
|
|
3188
|
+
const rowOffset = cy * targetWidth;
|
|
3189
|
+
for (let cx = xStart; cx <= xEnd; cx++) {
|
|
3190
|
+
const dx = cx - centerX + centerOffset;
|
|
3191
|
+
const dSqr = dx * dx + dySqr;
|
|
3192
|
+
if (dSqr <= rSqr) {
|
|
3193
|
+
const idx = rowOffset + cx;
|
|
3194
|
+
if (fallOff) {
|
|
3195
|
+
const strength = fallOff(Math.sqrt(dSqr) * invR);
|
|
3196
|
+
const fAlpha = alpha * strength & 255;
|
|
3197
|
+
const src = (fAlpha << 24 | baseColor) >>> 0;
|
|
3198
|
+
data32[idx] = blendFn(src, data32[idx]);
|
|
3199
|
+
} else {
|
|
3200
|
+
data32[idx] = blendFn(constantSrc, data32[idx]);
|
|
3201
|
+
}
|
|
3202
|
+
}
|
|
3203
|
+
}
|
|
3204
|
+
}
|
|
3205
|
+
}
|
|
3206
|
+
|
|
3207
|
+
// src/PixelData/applyRectBrushToPixelData.ts
|
|
3208
|
+
function applyRectBrushToPixelData(target, color, centerX, centerY, brushWidth, brushHeight, alpha = 255, fallOff, blendFn = sourceOverPerfect) {
|
|
3209
|
+
const targetWidth = target.width;
|
|
3210
|
+
const targetHeight = target.height;
|
|
3211
|
+
const data32 = target.data32;
|
|
3212
|
+
const rawStartX = Math.floor(centerX - brushWidth / 2);
|
|
3213
|
+
const rawStartY = Math.floor(centerY - brushHeight / 2);
|
|
3214
|
+
const endX = Math.min(targetWidth, rawStartX + brushWidth);
|
|
3215
|
+
const endY = Math.min(targetHeight, rawStartY + brushHeight);
|
|
3216
|
+
const startX = Math.max(0, rawStartX);
|
|
3217
|
+
const startY = Math.max(0, rawStartY);
|
|
3218
|
+
const baseColor = color & 16777215;
|
|
3219
|
+
const constantSrc = (alpha << 24 | baseColor) >>> 0;
|
|
3220
|
+
const invHalfW = 1 / (brushWidth / 2);
|
|
3221
|
+
const invHalfH = 1 / (brushHeight / 2);
|
|
3222
|
+
for (let py = startY; py < endY; py++) {
|
|
3223
|
+
const rowOffset = py * targetWidth;
|
|
3224
|
+
const dy = Math.abs(py + 0.5 - centerY) * invHalfH;
|
|
3225
|
+
for (let px = startX; px < endX; px++) {
|
|
3226
|
+
if (fallOff) {
|
|
3227
|
+
const dx = Math.abs(px + 0.5 - centerX) * invHalfW;
|
|
3228
|
+
const dist = dx > dy ? dx : dy;
|
|
3229
|
+
const fAlpha = alpha * fallOff(dist) | 0;
|
|
3230
|
+
const src = (fAlpha << 24 | baseColor) >>> 0;
|
|
3231
|
+
data32[rowOffset + px] = blendFn(src, data32[rowOffset + px]);
|
|
3232
|
+
} else {
|
|
3233
|
+
data32[rowOffset + px] = blendFn(constantSrc, data32[rowOffset + px]);
|
|
3234
|
+
}
|
|
3235
|
+
}
|
|
2604
3236
|
}
|
|
2605
3237
|
}
|
|
3238
|
+
function getRectBrushBounds(centerX, centerY, brushWidth, brushHeight, targetWidth, targetHeight) {
|
|
3239
|
+
const rawStartX = Math.floor(centerX - brushWidth / 2);
|
|
3240
|
+
const rawStartY = Math.floor(centerY - brushHeight / 2);
|
|
3241
|
+
const rawEndX = rawStartX + brushWidth;
|
|
3242
|
+
const rawEndY = rawStartY + brushHeight;
|
|
3243
|
+
const startX = targetWidth !== void 0 ? Math.max(0, rawStartX) : rawStartX;
|
|
3244
|
+
const startY = targetHeight !== void 0 ? Math.max(0, rawStartY) : rawStartY;
|
|
3245
|
+
const endX = targetWidth !== void 0 ? Math.min(targetWidth, rawEndX) : rawEndX;
|
|
3246
|
+
const endY = targetHeight !== void 0 ? Math.min(targetHeight, rawEndY) : rawEndY;
|
|
3247
|
+
return {
|
|
3248
|
+
x: startX,
|
|
3249
|
+
y: startY,
|
|
3250
|
+
w: endX - startX,
|
|
3251
|
+
h: endY - startY
|
|
3252
|
+
};
|
|
3253
|
+
}
|
|
2606
3254
|
|
|
2607
3255
|
// src/PixelData/clearPixelData.ts
|
|
2608
3256
|
function clearPixelData(dst, rect) {
|
|
@@ -2650,16 +3298,6 @@ function extractPixelData(source, _x, _y, _w, _h) {
|
|
|
2650
3298
|
return result;
|
|
2651
3299
|
}
|
|
2652
3300
|
|
|
2653
|
-
// src/PixelData/invertPixelData.ts
|
|
2654
|
-
function invertPixelData(pixelData) {
|
|
2655
|
-
const data32 = pixelData.data32;
|
|
2656
|
-
const len = data32.length;
|
|
2657
|
-
for (let i = 0; i < len; i++) {
|
|
2658
|
-
data32[i] = data32[i] ^ 16777215;
|
|
2659
|
-
}
|
|
2660
|
-
return pixelData;
|
|
2661
|
-
}
|
|
2662
|
-
|
|
2663
3301
|
// src/PixelData/reflectPixelData.ts
|
|
2664
3302
|
function reflectPixelDataHorizontal(pixelData) {
|
|
2665
3303
|
const width = pixelData.width;
|
|
@@ -2750,24 +3388,54 @@ function rotateSquareInPlace(pixelData) {
|
|
|
2750
3388
|
}
|
|
2751
3389
|
}
|
|
2752
3390
|
}
|
|
3391
|
+
|
|
3392
|
+
// src/PixelData/writePixelDataBuffer.ts
|
|
3393
|
+
function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
3394
|
+
const { x, y, w, h } = typeof _x === "object" ? _x : {
|
|
3395
|
+
x: _x,
|
|
3396
|
+
y: _y,
|
|
3397
|
+
w: _w,
|
|
3398
|
+
h: _h
|
|
3399
|
+
};
|
|
3400
|
+
const dstW = target.width;
|
|
3401
|
+
const dstH = target.height;
|
|
3402
|
+
const dstData = target.data32;
|
|
3403
|
+
const x0 = Math.max(0, x);
|
|
3404
|
+
const y0 = Math.max(0, y);
|
|
3405
|
+
const x1 = Math.min(dstW, x + w);
|
|
3406
|
+
const y1 = Math.min(dstH, y + h);
|
|
3407
|
+
if (x1 <= x0 || y1 <= y0) {
|
|
3408
|
+
return;
|
|
3409
|
+
}
|
|
3410
|
+
const rowLen = x1 - x0;
|
|
3411
|
+
const srcCol = x0 - x;
|
|
3412
|
+
const srcYOffset = y0 - y;
|
|
3413
|
+
const actualH = y1 - y0;
|
|
3414
|
+
for (let row = 0; row < actualH; row++) {
|
|
3415
|
+
const dstStart = (y0 + row) * dstW + x0;
|
|
3416
|
+
const srcRow = srcYOffset + row;
|
|
3417
|
+
const srcStart = srcRow * w + srcCol;
|
|
3418
|
+
dstData.set(data.subarray(srcStart, srcStart + rowLen), dstStart);
|
|
3419
|
+
}
|
|
3420
|
+
}
|
|
2753
3421
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2754
3422
|
0 && (module.exports = {
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
FAST_BLEND_TO_INDEX,
|
|
2760
|
-
INDEX_TO_FAST_BLEND,
|
|
2761
|
-
INDEX_TO_PERFECT_BLEND,
|
|
3423
|
+
BASE_FAST_BLEND_MODE_FUNCTIONS,
|
|
3424
|
+
BASE_PERFECT_BLEND_MODE_FUNCTIONS,
|
|
3425
|
+
BaseBlendMode,
|
|
3426
|
+
HistoryManager,
|
|
2762
3427
|
IndexedImage,
|
|
2763
3428
|
MaskType,
|
|
2764
|
-
|
|
2765
|
-
PERFECT_BLEND_MODES,
|
|
2766
|
-
PERFECT_BLEND_MODE_BY_NAME,
|
|
2767
|
-
PERFECT_BLEND_TO_INDEX,
|
|
3429
|
+
PixelAccumulator,
|
|
2768
3430
|
PixelData,
|
|
3431
|
+
PixelEngineConfig,
|
|
3432
|
+
PixelTile,
|
|
3433
|
+
PixelWriter,
|
|
2769
3434
|
UnsupportedFormatError,
|
|
3435
|
+
applyCircleBrushToPixelData,
|
|
2770
3436
|
applyMaskToPixelData,
|
|
3437
|
+
applyPatchTiles,
|
|
3438
|
+
applyRectBrushToPixelData,
|
|
2771
3439
|
base64DecodeArrayBuffer,
|
|
2772
3440
|
base64EncodeArrayBuffer,
|
|
2773
3441
|
blendColorPixelData,
|
|
@@ -2806,6 +3474,7 @@ function rotateSquareInPlace(pixelData) {
|
|
|
2806
3474
|
floodFillSelection,
|
|
2807
3475
|
getImageDataFromClipboard,
|
|
2808
3476
|
getIndexedImageColorCounts,
|
|
3477
|
+
getRectBrushBounds,
|
|
2809
3478
|
getSupportedPixelFormats,
|
|
2810
3479
|
hardLightFast,
|
|
2811
3480
|
hardLightPerfect,
|
|
@@ -2834,14 +3503,25 @@ function rotateSquareInPlace(pixelData) {
|
|
|
2834
3503
|
linearDodgePerfect,
|
|
2835
3504
|
linearLightFast,
|
|
2836
3505
|
linearLightPerfect,
|
|
3506
|
+
makeBlendModeRegistry,
|
|
3507
|
+
makeFastBlendModeRegistry,
|
|
3508
|
+
makeFullPixelMutator,
|
|
3509
|
+
makePerfectBlendModeRegistry,
|
|
2837
3510
|
makePixelCanvas,
|
|
2838
3511
|
makeReusableCanvas,
|
|
2839
3512
|
makeReusableImageData,
|
|
2840
3513
|
mergeMasks,
|
|
2841
3514
|
multiplyFast,
|
|
2842
3515
|
multiplyPerfect,
|
|
3516
|
+
mutatorApplyMask,
|
|
3517
|
+
mutatorBlendColor,
|
|
3518
|
+
mutatorBlendPixel,
|
|
3519
|
+
mutatorBlendPixelData,
|
|
3520
|
+
mutatorFill,
|
|
3521
|
+
mutatorInvert,
|
|
2843
3522
|
overlayFast,
|
|
2844
3523
|
overlayPerfect,
|
|
3524
|
+
overwriteBase,
|
|
2845
3525
|
overwriteFast,
|
|
2846
3526
|
overwritePerfect,
|
|
2847
3527
|
packColor,
|
|
@@ -2876,8 +3556,9 @@ function rotateSquareInPlace(pixelData) {
|
|
|
2876
3556
|
vividLightFast,
|
|
2877
3557
|
vividLightPerfect,
|
|
2878
3558
|
writeImageData,
|
|
2879
|
-
|
|
3559
|
+
writeImageDataBuffer,
|
|
2880
3560
|
writeImageDataToClipboard,
|
|
2881
|
-
writeImgBlobToClipboard
|
|
3561
|
+
writeImgBlobToClipboard,
|
|
3562
|
+
writePixelDataBuffer
|
|
2882
3563
|
});
|
|
2883
3564
|
//# sourceMappingURL=index.dev.cjs.map
|