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.js
CHANGED
|
@@ -1,33 +1,70 @@
|
|
|
1
1
|
// src/BlendModes/blend-modes.ts
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
})(BlendMode || {});
|
|
2
|
+
var BaseBlendMode = {
|
|
3
|
+
overwrite: 0,
|
|
4
|
+
sourceOver: 1,
|
|
5
|
+
darken: 2,
|
|
6
|
+
multiply: 3,
|
|
7
|
+
colorBurn: 4,
|
|
8
|
+
linearBurn: 5,
|
|
9
|
+
darkerColor: 6,
|
|
10
|
+
lighten: 7,
|
|
11
|
+
screen: 8,
|
|
12
|
+
colorDodge: 9,
|
|
13
|
+
linearDodge: 10,
|
|
14
|
+
lighterColor: 11,
|
|
15
|
+
overlay: 12,
|
|
16
|
+
softLight: 13,
|
|
17
|
+
hardLight: 14,
|
|
18
|
+
vividLight: 15,
|
|
19
|
+
linearLight: 16,
|
|
20
|
+
pinLight: 17,
|
|
21
|
+
hardMix: 18,
|
|
22
|
+
difference: 19,
|
|
23
|
+
exclusion: 20,
|
|
24
|
+
subtract: 21,
|
|
25
|
+
divide: 22
|
|
26
|
+
};
|
|
28
27
|
var overwriteBase = (src, _dst) => src;
|
|
29
28
|
overwriteBase.isOverwrite = true;
|
|
30
29
|
|
|
30
|
+
// src/BlendModes/BlendModeRegistry.ts
|
|
31
|
+
function makeBlendModeRegistry(blendModes, initialEntries) {
|
|
32
|
+
const blendToName = /* @__PURE__ */ new Map();
|
|
33
|
+
const blendToIndex = /* @__PURE__ */ new Map();
|
|
34
|
+
const indexToName = [];
|
|
35
|
+
const indexToBlend = [];
|
|
36
|
+
const nameToBlend = {};
|
|
37
|
+
const nameToIndex = {};
|
|
38
|
+
const add = (name, index, blendFn) => {
|
|
39
|
+
if (!Number.isFinite(index)) {
|
|
40
|
+
throw new Error(`Index "${index}" is not a number. Attempting to add name: "${name}", index: "${index}"`);
|
|
41
|
+
}
|
|
42
|
+
if (indexToBlend[index]) {
|
|
43
|
+
throw new Error(`Blend Mode index: ${index} is already used. Attempting to add name: "${name}", index: "${index}"`);
|
|
44
|
+
}
|
|
45
|
+
indexToName[index] = name;
|
|
46
|
+
indexToBlend[index] = blendFn;
|
|
47
|
+
blendToIndex.set(blendFn, index);
|
|
48
|
+
blendToName.set(blendFn, name);
|
|
49
|
+
nameToBlend[name] = blendFn;
|
|
50
|
+
nameToIndex[name] = index;
|
|
51
|
+
};
|
|
52
|
+
for (const [name, index] of Object.entries(blendModes)) {
|
|
53
|
+
const blend = initialEntries[index];
|
|
54
|
+
add(name, index, blend);
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
nameToBlend,
|
|
58
|
+
nameToIndex,
|
|
59
|
+
blendToIndex,
|
|
60
|
+
blendToName,
|
|
61
|
+
indexToBlend,
|
|
62
|
+
indexToName,
|
|
63
|
+
indexType: null,
|
|
64
|
+
nameType: null
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
31
68
|
// src/BlendModes/blend-modes-fast.ts
|
|
32
69
|
var overwriteFast = overwriteBase;
|
|
33
70
|
var sourceOverFast = (src, dst) => {
|
|
@@ -413,76 +450,34 @@ var divideFast = (src, dst) => {
|
|
|
413
450
|
const a = 255 * sa + (dst >>> 24 & 255) * invA >> 8;
|
|
414
451
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
415
452
|
};
|
|
416
|
-
var
|
|
417
|
-
[
|
|
418
|
-
[
|
|
419
|
-
[
|
|
420
|
-
[
|
|
421
|
-
[
|
|
422
|
-
[
|
|
423
|
-
[
|
|
424
|
-
[
|
|
425
|
-
[
|
|
426
|
-
[
|
|
427
|
-
[
|
|
428
|
-
[
|
|
429
|
-
[
|
|
430
|
-
[
|
|
431
|
-
[
|
|
432
|
-
[
|
|
433
|
-
[
|
|
434
|
-
[
|
|
435
|
-
[
|
|
436
|
-
[
|
|
437
|
-
[
|
|
438
|
-
[
|
|
439
|
-
[
|
|
440
|
-
];
|
|
441
|
-
var FAST_BLEND_MODES = [];
|
|
442
|
-
for (const [index, blend] of FAST_BLENDER_REGISTRY) {
|
|
443
|
-
FAST_BLEND_MODES[index] = blend;
|
|
444
|
-
}
|
|
445
|
-
var FAST_BLEND_TO_INDEX = new Map(
|
|
446
|
-
FAST_BLENDER_REGISTRY.map((entry, index) => {
|
|
447
|
-
return [
|
|
448
|
-
entry[1],
|
|
449
|
-
index
|
|
450
|
-
];
|
|
451
|
-
})
|
|
452
|
-
);
|
|
453
|
-
var INDEX_TO_FAST_BLEND = new Map(
|
|
454
|
-
FAST_BLENDER_REGISTRY.map((entry, index) => {
|
|
455
|
-
return [
|
|
456
|
-
index,
|
|
457
|
-
entry[1]
|
|
458
|
-
];
|
|
459
|
-
})
|
|
460
|
-
);
|
|
461
|
-
var FAST_BLEND_MODE_BY_NAME = {
|
|
462
|
-
overwrite: overwriteFast,
|
|
463
|
-
sourceOver: sourceOverFast,
|
|
464
|
-
darken: darkenFast,
|
|
465
|
-
multiply: multiplyFast,
|
|
466
|
-
colorBurn: colorBurnFast,
|
|
467
|
-
linearBurn: linearBurnFast,
|
|
468
|
-
darkerColor: darkerFast,
|
|
469
|
-
lighten: lightenFast,
|
|
470
|
-
screen: screenFast,
|
|
471
|
-
colorDodge: colorDodgeFast,
|
|
472
|
-
linearDodge: linearDodgeFast,
|
|
473
|
-
lighterColor: lighterFast,
|
|
474
|
-
overlay: overlayFast,
|
|
475
|
-
softLight: softLightFast,
|
|
476
|
-
hardLight: hardLightFast,
|
|
477
|
-
vividLight: vividLightFast,
|
|
478
|
-
linearLight: linearLightFast,
|
|
479
|
-
pinLight: pinLightFast,
|
|
480
|
-
hardMix: hardMixFast,
|
|
481
|
-
difference: differenceFast,
|
|
482
|
-
exclusion: exclusionFast,
|
|
483
|
-
subtract: subtractFast,
|
|
484
|
-
divide: divideFast
|
|
453
|
+
var BASE_FAST_BLEND_MODE_FUNCTIONS = {
|
|
454
|
+
[BaseBlendMode.overwrite]: overwriteFast,
|
|
455
|
+
[BaseBlendMode.sourceOver]: sourceOverFast,
|
|
456
|
+
[BaseBlendMode.darken]: darkenFast,
|
|
457
|
+
[BaseBlendMode.multiply]: multiplyFast,
|
|
458
|
+
[BaseBlendMode.colorBurn]: colorBurnFast,
|
|
459
|
+
[BaseBlendMode.linearBurn]: linearBurnFast,
|
|
460
|
+
[BaseBlendMode.darkerColor]: darkerFast,
|
|
461
|
+
[BaseBlendMode.lighten]: lightenFast,
|
|
462
|
+
[BaseBlendMode.screen]: screenFast,
|
|
463
|
+
[BaseBlendMode.colorDodge]: colorDodgeFast,
|
|
464
|
+
[BaseBlendMode.linearDodge]: linearDodgeFast,
|
|
465
|
+
[BaseBlendMode.lighterColor]: lighterFast,
|
|
466
|
+
[BaseBlendMode.overlay]: overlayFast,
|
|
467
|
+
[BaseBlendMode.softLight]: softLightFast,
|
|
468
|
+
[BaseBlendMode.hardLight]: hardLightFast,
|
|
469
|
+
[BaseBlendMode.vividLight]: vividLightFast,
|
|
470
|
+
[BaseBlendMode.linearLight]: linearLightFast,
|
|
471
|
+
[BaseBlendMode.pinLight]: pinLightFast,
|
|
472
|
+
[BaseBlendMode.hardMix]: hardMixFast,
|
|
473
|
+
[BaseBlendMode.difference]: differenceFast,
|
|
474
|
+
[BaseBlendMode.exclusion]: exclusionFast,
|
|
475
|
+
[BaseBlendMode.subtract]: subtractFast,
|
|
476
|
+
[BaseBlendMode.divide]: divideFast
|
|
485
477
|
};
|
|
478
|
+
function makeFastBlendModeRegistry() {
|
|
479
|
+
return makeBlendModeRegistry(BaseBlendMode, BASE_FAST_BLEND_MODE_FUNCTIONS);
|
|
480
|
+
}
|
|
486
481
|
|
|
487
482
|
// src/_types.ts
|
|
488
483
|
var MaskType = /* @__PURE__ */ ((MaskType2) => {
|
|
@@ -849,14 +844,18 @@ var sourceOverPerfect = (src, dst) => {
|
|
|
849
844
|
const sa = src >>> 24 & 255;
|
|
850
845
|
if (sa === 255) return src;
|
|
851
846
|
if (sa === 0) return dst;
|
|
847
|
+
const invA = 255 - sa;
|
|
852
848
|
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
853
849
|
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
854
850
|
const da = dst >>> 24 & 255;
|
|
855
|
-
const
|
|
856
|
-
const r =
|
|
857
|
-
const
|
|
858
|
-
const
|
|
859
|
-
const
|
|
851
|
+
const tR = sr * sa + dr * invA;
|
|
852
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
853
|
+
const tG = sg * sa + dg * invA;
|
|
854
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
855
|
+
const tB = sb * sa + db * invA;
|
|
856
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
857
|
+
const tA = 255 * sa + da * invA;
|
|
858
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
860
859
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
861
860
|
};
|
|
862
861
|
var darkenPerfect = (src, dst) => {
|
|
@@ -869,44 +868,71 @@ var darkenPerfect = (src, dst) => {
|
|
|
869
868
|
const bb = sb < db ? sb : db;
|
|
870
869
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
871
870
|
const invA = 255 - sa;
|
|
872
|
-
const
|
|
873
|
-
const
|
|
874
|
-
const
|
|
875
|
-
const
|
|
871
|
+
const da = dst >>> 24 & 255;
|
|
872
|
+
const tR = br * sa + dr * invA;
|
|
873
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
874
|
+
const tG = bg * sa + dg * invA;
|
|
875
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
876
|
+
const tB = bb * sa + db * invA;
|
|
877
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
878
|
+
const tA = 255 * sa + da * invA;
|
|
879
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
876
880
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
877
881
|
};
|
|
878
882
|
var multiplyPerfect = (src, dst) => {
|
|
879
883
|
const sa = src >>> 24 & 255;
|
|
880
884
|
if (sa === 0) return dst;
|
|
881
|
-
const
|
|
882
|
-
const
|
|
883
|
-
const
|
|
884
|
-
const
|
|
885
|
-
const
|
|
885
|
+
const dr = dst & 255;
|
|
886
|
+
const dg = dst >>> 8 & 255;
|
|
887
|
+
const db = dst >>> 16 & 255;
|
|
888
|
+
const da = dst >>> 24 & 255;
|
|
889
|
+
const sr = src & 255;
|
|
890
|
+
const sg = src >>> 8 & 255;
|
|
891
|
+
const sb = src >>> 16 & 255;
|
|
892
|
+
const mR = sr * dr;
|
|
893
|
+
const br = mR + 1 + (mR >> 8) >> 8;
|
|
894
|
+
const mG = sg * dg;
|
|
895
|
+
const bg = mG + 1 + (mG >> 8) >> 8;
|
|
896
|
+
const mB = sb * db;
|
|
897
|
+
const bb = mB + 1 + (mB >> 8) >> 8;
|
|
886
898
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
887
899
|
const invA = 255 - sa;
|
|
888
|
-
const
|
|
889
|
-
const r =
|
|
890
|
-
const
|
|
891
|
-
const
|
|
892
|
-
const
|
|
900
|
+
const tR = br * sa + dr * invA;
|
|
901
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
902
|
+
const tG = bg * sa + dg * invA;
|
|
903
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
904
|
+
const tB = bb * sa + db * invA;
|
|
905
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
906
|
+
const tA = 255 * sa + da * invA;
|
|
907
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
893
908
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
894
909
|
};
|
|
895
910
|
var colorBurnPerfect = (src, dst) => {
|
|
896
911
|
const sa = src >>> 24 & 255;
|
|
897
912
|
if (sa === 0) return dst;
|
|
898
|
-
const
|
|
899
|
-
const
|
|
900
|
-
const
|
|
901
|
-
const
|
|
902
|
-
const
|
|
913
|
+
const dr = dst & 255;
|
|
914
|
+
const dg = dst >>> 8 & 255;
|
|
915
|
+
const db = dst >>> 16 & 255;
|
|
916
|
+
const sr = src & 255;
|
|
917
|
+
const sg = src >>> 8 & 255;
|
|
918
|
+
const sb = src >>> 16 & 255;
|
|
919
|
+
const resR = dr === 255 ? 255 : sr === 0 ? 0 : 255 - ((255 - dr) * 255 / sr | 0);
|
|
920
|
+
const br = resR < 0 ? 0 : resR;
|
|
921
|
+
const resG = dg === 255 ? 255 : sg === 0 ? 0 : 255 - ((255 - dg) * 255 / sg | 0);
|
|
922
|
+
const bg = resG < 0 ? 0 : resG;
|
|
923
|
+
const resB = db === 255 ? 255 : sb === 0 ? 0 : 255 - ((255 - db) * 255 / sb | 0);
|
|
924
|
+
const bb = resB < 0 ? 0 : resB;
|
|
903
925
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
904
926
|
const invA = 255 - sa;
|
|
905
927
|
const da = dst >>> 24 & 255;
|
|
906
|
-
const
|
|
907
|
-
const
|
|
908
|
-
const
|
|
909
|
-
const
|
|
928
|
+
const tR = br * sa + dr * invA;
|
|
929
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
930
|
+
const tG = bg * sa + dg * invA;
|
|
931
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
932
|
+
const tB = bb * sa + db * invA;
|
|
933
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
934
|
+
const tA = 255 * sa + da * invA;
|
|
935
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
910
936
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
911
937
|
};
|
|
912
938
|
var linearBurnPerfect = (src, dst) => {
|
|
@@ -922,10 +948,15 @@ var linearBurnPerfect = (src, dst) => {
|
|
|
922
948
|
const bb = bbU < 0 ? 0 : bbU;
|
|
923
949
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
924
950
|
const invA = 255 - sa;
|
|
925
|
-
const
|
|
926
|
-
const
|
|
927
|
-
const
|
|
928
|
-
const
|
|
951
|
+
const da = dst >>> 24 & 255;
|
|
952
|
+
const tR = br * sa + dr * invA;
|
|
953
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
954
|
+
const tG = bg * sa + dg * invA;
|
|
955
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
956
|
+
const tB = bb * sa + db * invA;
|
|
957
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
958
|
+
const tA = 255 * sa + da * invA;
|
|
959
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
929
960
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
930
961
|
};
|
|
931
962
|
var darkerPerfect = (src, dst) => {
|
|
@@ -947,10 +978,15 @@ var darkerPerfect = (src, dst) => {
|
|
|
947
978
|
}
|
|
948
979
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
949
980
|
const invA = 255 - sa;
|
|
950
|
-
const
|
|
951
|
-
const
|
|
952
|
-
const
|
|
953
|
-
const
|
|
981
|
+
const da = dst >>> 24 & 255;
|
|
982
|
+
const tR = br * sa + dr * invA;
|
|
983
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
984
|
+
const tG = bg * sa + dg * invA;
|
|
985
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
986
|
+
const tB = bb * sa + db * invA;
|
|
987
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
988
|
+
const tA = 255 * sa + da * invA;
|
|
989
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
954
990
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
955
991
|
};
|
|
956
992
|
var lightenPerfect = (src, dst) => {
|
|
@@ -962,10 +998,15 @@ var lightenPerfect = (src, dst) => {
|
|
|
962
998
|
const bb = (src >>> 16 & 255) > db ? src >>> 16 & 255 : db;
|
|
963
999
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
964
1000
|
const invA = 255 - sa;
|
|
965
|
-
const
|
|
966
|
-
const
|
|
967
|
-
const
|
|
968
|
-
const
|
|
1001
|
+
const da = dst >>> 24 & 255;
|
|
1002
|
+
const tR = br * sa + dr * invA;
|
|
1003
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1004
|
+
const tG = bg * sa + dg * invA;
|
|
1005
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1006
|
+
const tB = bb * sa + db * invA;
|
|
1007
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1008
|
+
const tA = 255 * sa + da * invA;
|
|
1009
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
969
1010
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
970
1011
|
};
|
|
971
1012
|
var screenPerfect = (src, dst) => {
|
|
@@ -977,26 +1018,43 @@ var screenPerfect = (src, dst) => {
|
|
|
977
1018
|
const bb = 255 - ((255 - (src >>> 16 & 255)) * (255 - db) / 255 | 0);
|
|
978
1019
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
979
1020
|
const invA = 255 - sa;
|
|
980
|
-
const
|
|
981
|
-
const
|
|
982
|
-
const
|
|
983
|
-
const
|
|
1021
|
+
const da = dst >>> 24 & 255;
|
|
1022
|
+
const tR = br * sa + dr * invA;
|
|
1023
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1024
|
+
const tG = bg * sa + dg * invA;
|
|
1025
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1026
|
+
const tB = bb * sa + db * invA;
|
|
1027
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1028
|
+
const tA = 255 * sa + da * invA;
|
|
1029
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
984
1030
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
985
1031
|
};
|
|
986
1032
|
var colorDodgePerfect = (src, dst) => {
|
|
987
1033
|
const sa = src >>> 24 & 255;
|
|
988
1034
|
if (sa === 0) return dst;
|
|
989
|
-
const dr = dst & 255
|
|
990
|
-
const
|
|
991
|
-
const
|
|
992
|
-
const
|
|
993
|
-
const
|
|
1035
|
+
const dr = dst & 255;
|
|
1036
|
+
const dg = dst >>> 8 & 255;
|
|
1037
|
+
const db = dst >>> 16 & 255;
|
|
1038
|
+
const sr = src & 255;
|
|
1039
|
+
const sg = src >>> 8 & 255;
|
|
1040
|
+
const sb = src >>> 16 & 255;
|
|
1041
|
+
const resR = sr === 255 ? 255 : dr * 255 / (255 - sr) | 0;
|
|
1042
|
+
const br = resR > 255 ? 255 : resR;
|
|
1043
|
+
const resG = sg === 255 ? 255 : dg * 255 / (255 - sg) | 0;
|
|
1044
|
+
const bg = resG > 255 ? 255 : resG;
|
|
1045
|
+
const resB = sb === 255 ? 255 : db * 255 / (255 - sb) | 0;
|
|
1046
|
+
const bb = resB > 255 ? 255 : resB;
|
|
994
1047
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
995
1048
|
const invA = 255 - sa;
|
|
996
|
-
const
|
|
997
|
-
const
|
|
998
|
-
const
|
|
999
|
-
const
|
|
1049
|
+
const da = dst >>> 24 & 255;
|
|
1050
|
+
const tR = br * sa + dr * invA;
|
|
1051
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1052
|
+
const tG = bg * sa + dg * invA;
|
|
1053
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1054
|
+
const tB = bb * sa + db * invA;
|
|
1055
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1056
|
+
const tA = 255 * sa + da * invA;
|
|
1057
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1000
1058
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1001
1059
|
};
|
|
1002
1060
|
var linearDodgePerfect = (src, dst) => {
|
|
@@ -1011,10 +1069,15 @@ var linearDodgePerfect = (src, dst) => {
|
|
|
1011
1069
|
const bb = bbU > 255 ? 255 : bbU;
|
|
1012
1070
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1013
1071
|
const invA = 255 - sa;
|
|
1014
|
-
const
|
|
1015
|
-
const
|
|
1016
|
-
const
|
|
1017
|
-
const
|
|
1072
|
+
const da = dst >>> 24 & 255;
|
|
1073
|
+
const tR = br * sa + dr * invA;
|
|
1074
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1075
|
+
const tG = bg * sa + dg * invA;
|
|
1076
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1077
|
+
const tB = bb * sa + db * invA;
|
|
1078
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1079
|
+
const tA = 255 * sa + da * invA;
|
|
1080
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1018
1081
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1019
1082
|
};
|
|
1020
1083
|
var lighterPerfect = (src, dst) => {
|
|
@@ -1036,10 +1099,15 @@ var lighterPerfect = (src, dst) => {
|
|
|
1036
1099
|
}
|
|
1037
1100
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1038
1101
|
const invA = 255 - sa;
|
|
1039
|
-
const
|
|
1040
|
-
const
|
|
1041
|
-
const
|
|
1042
|
-
const
|
|
1102
|
+
const da = dst >>> 24 & 255;
|
|
1103
|
+
const tR = br * sa + dr * invA;
|
|
1104
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1105
|
+
const tG = bg * sa + dg * invA;
|
|
1106
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1107
|
+
const tB = bb * sa + db * invA;
|
|
1108
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1109
|
+
const tA = 255 * sa + da * invA;
|
|
1110
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1043
1111
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1044
1112
|
};
|
|
1045
1113
|
var overlayPerfect = (src, dst) => {
|
|
@@ -1052,10 +1120,15 @@ var overlayPerfect = (src, dst) => {
|
|
|
1052
1120
|
const bb = db < 128 ? 2 * sb * db / 255 | 0 : 255 - (2 * (255 - sb) * (255 - db) / 255 | 0);
|
|
1053
1121
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1054
1122
|
const invA = 255 - sa;
|
|
1055
|
-
const
|
|
1056
|
-
const
|
|
1057
|
-
const
|
|
1058
|
-
const
|
|
1123
|
+
const da = dst >>> 24 & 255;
|
|
1124
|
+
const tR = br * sa + dr * invA;
|
|
1125
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1126
|
+
const tG = bg * sa + dg * invA;
|
|
1127
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1128
|
+
const tB = bb * sa + db * invA;
|
|
1129
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1130
|
+
const tA = 255 * sa + da * invA;
|
|
1131
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1059
1132
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1060
1133
|
};
|
|
1061
1134
|
var softLightPerfect = (src, dst) => {
|
|
@@ -1063,15 +1136,26 @@ var softLightPerfect = (src, dst) => {
|
|
|
1063
1136
|
if (sa === 0) return dst;
|
|
1064
1137
|
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
1065
1138
|
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
1066
|
-
const
|
|
1067
|
-
const
|
|
1068
|
-
const
|
|
1139
|
+
const mR = sr * dr;
|
|
1140
|
+
const scR = (255 - sr) * (255 - dr);
|
|
1141
|
+
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;
|
|
1142
|
+
const mG = sg * dg;
|
|
1143
|
+
const scG = (255 - sg) * (255 - dg);
|
|
1144
|
+
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;
|
|
1145
|
+
const mB = sb * db;
|
|
1146
|
+
const scB = (255 - sb) * (255 - db);
|
|
1147
|
+
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;
|
|
1069
1148
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1070
1149
|
const invA = 255 - sa;
|
|
1071
|
-
const
|
|
1072
|
-
const
|
|
1073
|
-
const
|
|
1074
|
-
const
|
|
1150
|
+
const da = dst >>> 24 & 255;
|
|
1151
|
+
const tR = br * sa + dr * invA;
|
|
1152
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1153
|
+
const tG = bg * sa + dg * invA;
|
|
1154
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1155
|
+
const tB = bb * sa + db * invA;
|
|
1156
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1157
|
+
const tA = 255 * sa + da * invA;
|
|
1158
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1075
1159
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1076
1160
|
};
|
|
1077
1161
|
var hardLightPerfect = (src, dst) => {
|
|
@@ -1084,10 +1168,15 @@ var hardLightPerfect = (src, dst) => {
|
|
|
1084
1168
|
const bb = sb < 128 ? 2 * sb * db / 255 | 0 : 255 - (2 * (255 - sb) * (255 - db) / 255 | 0);
|
|
1085
1169
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1086
1170
|
const invA = 255 - sa;
|
|
1087
|
-
const
|
|
1088
|
-
const
|
|
1089
|
-
const
|
|
1090
|
-
const
|
|
1171
|
+
const da = dst >>> 24 & 255;
|
|
1172
|
+
const tR = br * sa + dr * invA;
|
|
1173
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1174
|
+
const tG = bg * sa + dg * invA;
|
|
1175
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1176
|
+
const tB = bb * sa + db * invA;
|
|
1177
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1178
|
+
const tA = 255 * sa + da * invA;
|
|
1179
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1091
1180
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1092
1181
|
};
|
|
1093
1182
|
var vividLightPerfect = (src, dst) => {
|
|
@@ -1100,10 +1189,15 @@ var vividLightPerfect = (src, dst) => {
|
|
|
1100
1189
|
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);
|
|
1101
1190
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1102
1191
|
const invA = 255 - sa;
|
|
1103
|
-
const
|
|
1104
|
-
const
|
|
1105
|
-
const
|
|
1106
|
-
const
|
|
1192
|
+
const da = dst >>> 24 & 255;
|
|
1193
|
+
const tR = br * sa + dr * invA;
|
|
1194
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1195
|
+
const tG = bg * sa + dg * invA;
|
|
1196
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1197
|
+
const tB = bb * sa + db * invA;
|
|
1198
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1199
|
+
const tA = 255 * sa + da * invA;
|
|
1200
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1107
1201
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1108
1202
|
};
|
|
1109
1203
|
var linearLightPerfect = (src, dst) => {
|
|
@@ -1119,10 +1213,15 @@ var linearLightPerfect = (src, dst) => {
|
|
|
1119
1213
|
const bb = bbU < 0 ? 0 : bbU > 255 ? 255 : bbU;
|
|
1120
1214
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1121
1215
|
const invA = 255 - sa;
|
|
1122
|
-
const
|
|
1123
|
-
const
|
|
1124
|
-
const
|
|
1125
|
-
const
|
|
1216
|
+
const da = dst >>> 24 & 255;
|
|
1217
|
+
const tR = br * sa + dr * invA;
|
|
1218
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1219
|
+
const tG = bg * sa + dg * invA;
|
|
1220
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1221
|
+
const tB = bb * sa + db * invA;
|
|
1222
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1223
|
+
const tA = 255 * sa + da * invA;
|
|
1224
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1126
1225
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1127
1226
|
};
|
|
1128
1227
|
var pinLightPerfect = (src, dst) => {
|
|
@@ -1140,10 +1239,14 @@ var pinLightPerfect = (src, dst) => {
|
|
|
1140
1239
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1141
1240
|
const invA = 255 - sa;
|
|
1142
1241
|
const da = dst >>> 24 & 255;
|
|
1143
|
-
const
|
|
1144
|
-
const
|
|
1145
|
-
const
|
|
1146
|
-
const
|
|
1242
|
+
const tR = br * sa + dr * invA;
|
|
1243
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1244
|
+
const tG = bg * sa + dg * invA;
|
|
1245
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1246
|
+
const tB = bb * sa + db * invA;
|
|
1247
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1248
|
+
const tA = 255 * sa + da * invA;
|
|
1249
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1147
1250
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1148
1251
|
};
|
|
1149
1252
|
var hardMixPerfect = (src, dst) => {
|
|
@@ -1156,33 +1259,36 @@ var hardMixPerfect = (src, dst) => {
|
|
|
1156
1259
|
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;
|
|
1157
1260
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1158
1261
|
const invA = 255 - sa;
|
|
1159
|
-
const
|
|
1160
|
-
const
|
|
1161
|
-
const
|
|
1162
|
-
const
|
|
1262
|
+
const da = dst >>> 24 & 255;
|
|
1263
|
+
const tR = br * sa + dr * invA;
|
|
1264
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1265
|
+
const tG = bg * sa + dg * invA;
|
|
1266
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1267
|
+
const tB = bb * sa + db * invA;
|
|
1268
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1269
|
+
const tA = 255 * sa + da * invA;
|
|
1270
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1163
1271
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1164
1272
|
};
|
|
1165
1273
|
var differencePerfect = (src, dst) => {
|
|
1166
1274
|
const sa = src >>> 24 & 255;
|
|
1167
1275
|
if (sa === 0) return dst;
|
|
1168
|
-
const dr = dst & 255;
|
|
1169
|
-
const
|
|
1170
|
-
const
|
|
1171
|
-
const
|
|
1172
|
-
const
|
|
1173
|
-
|
|
1174
|
-
const br = Math.abs(dr - sr);
|
|
1175
|
-
const bg = Math.abs(dg - sg);
|
|
1176
|
-
const bb = Math.abs(db - sb);
|
|
1177
|
-
if (sa === 255) {
|
|
1178
|
-
return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1179
|
-
}
|
|
1276
|
+
const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
|
|
1277
|
+
const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
|
|
1278
|
+
const br = dr > sr ? dr - sr : sr - dr;
|
|
1279
|
+
const bg = dg > sg ? dg - sg : sg - dg;
|
|
1280
|
+
const bb = db > sb ? db - sb : sb - db;
|
|
1281
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1180
1282
|
const invA = 255 - sa;
|
|
1181
1283
|
const da = dst >>> 24 & 255;
|
|
1182
|
-
const
|
|
1183
|
-
const
|
|
1184
|
-
const
|
|
1185
|
-
const
|
|
1284
|
+
const tR = br * sa + dr * invA;
|
|
1285
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1286
|
+
const tG = bg * sa + dg * invA;
|
|
1287
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1288
|
+
const tB = bb * sa + db * invA;
|
|
1289
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1290
|
+
const tA = 255 * sa + da * invA;
|
|
1291
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1186
1292
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1187
1293
|
};
|
|
1188
1294
|
var exclusionPerfect = (src, dst) => {
|
|
@@ -1194,18 +1300,23 @@ var exclusionPerfect = (src, dst) => {
|
|
|
1194
1300
|
const sr = src & 255;
|
|
1195
1301
|
const sg = src >>> 8 & 255;
|
|
1196
1302
|
const sb = src >>> 16 & 255;
|
|
1197
|
-
const
|
|
1198
|
-
const
|
|
1199
|
-
const
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1303
|
+
const r2 = dr * sr;
|
|
1304
|
+
const br = dr + sr - (r2 + r2 + 1 + (r2 + r2 >> 8) >> 8);
|
|
1305
|
+
const g2 = dg * sg;
|
|
1306
|
+
const bg = dg + sg - (g2 + g2 + 1 + (g2 + g2 >> 8) >> 8);
|
|
1307
|
+
const b2 = db * sb;
|
|
1308
|
+
const bb = db + sb - (b2 + b2 + 1 + (b2 + b2 >> 8) >> 8);
|
|
1309
|
+
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1203
1310
|
const invA = 255 - sa;
|
|
1204
1311
|
const da = dst >>> 24 & 255;
|
|
1205
|
-
const
|
|
1206
|
-
const
|
|
1207
|
-
const
|
|
1208
|
-
const
|
|
1312
|
+
const tR = br * sa + dr * invA;
|
|
1313
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1314
|
+
const tG = bg * sa + dg * invA;
|
|
1315
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1316
|
+
const tB = bb * sa + db * invA;
|
|
1317
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1318
|
+
const tA = 255 * sa + da * invA;
|
|
1319
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1209
1320
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1210
1321
|
};
|
|
1211
1322
|
var subtractPerfect = (src, dst) => {
|
|
@@ -1221,10 +1332,15 @@ var subtractPerfect = (src, dst) => {
|
|
|
1221
1332
|
const bb = bbU < 0 ? 0 : bbU;
|
|
1222
1333
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1223
1334
|
const invA = 255 - sa;
|
|
1224
|
-
const
|
|
1225
|
-
const
|
|
1226
|
-
const
|
|
1227
|
-
const
|
|
1335
|
+
const da = dst >>> 24 & 255;
|
|
1336
|
+
const tR = br * sa + dr * invA;
|
|
1337
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1338
|
+
const tG = bg * sa + dg * invA;
|
|
1339
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1340
|
+
const tB = bb * sa + db * invA;
|
|
1341
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1342
|
+
const tA = 255 * sa + da * invA;
|
|
1343
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1228
1344
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1229
1345
|
};
|
|
1230
1346
|
var dividePerfect = (src, dst) => {
|
|
@@ -1237,82 +1353,45 @@ var dividePerfect = (src, dst) => {
|
|
|
1237
1353
|
const bb = sb === 0 ? 255 : Math.min(255, db * 255 / sb | 0);
|
|
1238
1354
|
if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
|
|
1239
1355
|
const invA = 255 - sa;
|
|
1240
|
-
const
|
|
1241
|
-
const
|
|
1242
|
-
const
|
|
1243
|
-
const
|
|
1356
|
+
const da = dst >>> 24 & 255;
|
|
1357
|
+
const tR = br * sa + dr * invA;
|
|
1358
|
+
const r = tR + 1 + (tR >> 8) >> 8;
|
|
1359
|
+
const tG = bg * sa + dg * invA;
|
|
1360
|
+
const g = tG + 1 + (tG >> 8) >> 8;
|
|
1361
|
+
const tB = bb * sa + db * invA;
|
|
1362
|
+
const b = tB + 1 + (tB >> 8) >> 8;
|
|
1363
|
+
const tA = 255 * sa + da * invA;
|
|
1364
|
+
const a = tA + 1 + (tA >> 8) >> 8;
|
|
1244
1365
|
return (a << 24 | b << 16 | g << 8 | r) >>> 0;
|
|
1245
1366
|
};
|
|
1246
|
-
var
|
|
1247
|
-
[
|
|
1248
|
-
[
|
|
1249
|
-
[
|
|
1250
|
-
[
|
|
1251
|
-
[
|
|
1252
|
-
[
|
|
1253
|
-
[
|
|
1254
|
-
[
|
|
1255
|
-
[
|
|
1256
|
-
[
|
|
1257
|
-
[
|
|
1258
|
-
[
|
|
1259
|
-
[
|
|
1260
|
-
[
|
|
1261
|
-
[
|
|
1262
|
-
[
|
|
1263
|
-
[
|
|
1264
|
-
[
|
|
1265
|
-
[
|
|
1266
|
-
[
|
|
1267
|
-
[
|
|
1268
|
-
[
|
|
1269
|
-
[
|
|
1270
|
-
];
|
|
1271
|
-
var PERFECT_BLEND_MODES = [];
|
|
1272
|
-
for (const [index, blend] of PERFECT_BLENDER_REGISTRY) {
|
|
1273
|
-
PERFECT_BLEND_MODES[index] = blend;
|
|
1274
|
-
}
|
|
1275
|
-
var PERFECT_BLEND_TO_INDEX = new Map(
|
|
1276
|
-
PERFECT_BLENDER_REGISTRY.map((entry, index) => {
|
|
1277
|
-
return [
|
|
1278
|
-
entry[1],
|
|
1279
|
-
index
|
|
1280
|
-
];
|
|
1281
|
-
})
|
|
1282
|
-
);
|
|
1283
|
-
var INDEX_TO_PERFECT_BLEND = new Map(
|
|
1284
|
-
PERFECT_BLENDER_REGISTRY.map((entry, index) => {
|
|
1285
|
-
return [
|
|
1286
|
-
index,
|
|
1287
|
-
entry[1]
|
|
1288
|
-
];
|
|
1289
|
-
})
|
|
1290
|
-
);
|
|
1291
|
-
var PERFECT_BLEND_MODE_BY_NAME = {
|
|
1292
|
-
overwrite: overwritePerfect,
|
|
1293
|
-
sourceOver: sourceOverPerfect,
|
|
1294
|
-
darken: darkenPerfect,
|
|
1295
|
-
multiply: multiplyPerfect,
|
|
1296
|
-
colorBurn: colorBurnPerfect,
|
|
1297
|
-
linearBurn: linearBurnPerfect,
|
|
1298
|
-
darkerColor: darkerPerfect,
|
|
1299
|
-
lighten: lightenPerfect,
|
|
1300
|
-
screen: screenPerfect,
|
|
1301
|
-
colorDodge: colorDodgePerfect,
|
|
1302
|
-
linearDodge: linearDodgePerfect,
|
|
1303
|
-
lighterColor: lighterPerfect,
|
|
1304
|
-
overlay: overlayPerfect,
|
|
1305
|
-
softLight: softLightPerfect,
|
|
1306
|
-
hardLight: hardLightPerfect,
|
|
1307
|
-
vividLight: vividLightPerfect,
|
|
1308
|
-
linearLight: linearLightPerfect,
|
|
1309
|
-
pinLight: pinLightPerfect,
|
|
1310
|
-
hardMix: hardMixPerfect,
|
|
1311
|
-
difference: differencePerfect,
|
|
1312
|
-
exclusion: exclusionPerfect,
|
|
1313
|
-
subtract: subtractPerfect,
|
|
1314
|
-
divide: dividePerfect
|
|
1367
|
+
var BASE_PERFECT_BLEND_MODE_FUNCTIONS = {
|
|
1368
|
+
[BaseBlendMode.overwrite]: overwritePerfect,
|
|
1369
|
+
[BaseBlendMode.sourceOver]: sourceOverPerfect,
|
|
1370
|
+
[BaseBlendMode.darken]: darkenPerfect,
|
|
1371
|
+
[BaseBlendMode.multiply]: multiplyPerfect,
|
|
1372
|
+
[BaseBlendMode.colorBurn]: colorBurnPerfect,
|
|
1373
|
+
[BaseBlendMode.linearBurn]: linearBurnPerfect,
|
|
1374
|
+
[BaseBlendMode.darkerColor]: darkerPerfect,
|
|
1375
|
+
[BaseBlendMode.lighten]: lightenPerfect,
|
|
1376
|
+
[BaseBlendMode.screen]: screenPerfect,
|
|
1377
|
+
[BaseBlendMode.colorDodge]: colorDodgePerfect,
|
|
1378
|
+
[BaseBlendMode.linearDodge]: linearDodgePerfect,
|
|
1379
|
+
[BaseBlendMode.lighterColor]: lighterPerfect,
|
|
1380
|
+
[BaseBlendMode.overlay]: overlayPerfect,
|
|
1381
|
+
[BaseBlendMode.softLight]: softLightPerfect,
|
|
1382
|
+
[BaseBlendMode.hardLight]: hardLightPerfect,
|
|
1383
|
+
[BaseBlendMode.vividLight]: vividLightPerfect,
|
|
1384
|
+
[BaseBlendMode.linearLight]: linearLightPerfect,
|
|
1385
|
+
[BaseBlendMode.pinLight]: pinLightPerfect,
|
|
1386
|
+
[BaseBlendMode.hardMix]: hardMixPerfect,
|
|
1387
|
+
[BaseBlendMode.difference]: differencePerfect,
|
|
1388
|
+
[BaseBlendMode.exclusion]: exclusionPerfect,
|
|
1389
|
+
[BaseBlendMode.subtract]: subtractPerfect,
|
|
1390
|
+
[BaseBlendMode.divide]: dividePerfect
|
|
1315
1391
|
};
|
|
1392
|
+
function makePerfectBlendModeRegistry() {
|
|
1393
|
+
return makeBlendModeRegistry(BaseBlendMode, BASE_PERFECT_BLEND_MODE_FUNCTIONS);
|
|
1394
|
+
}
|
|
1316
1395
|
|
|
1317
1396
|
// src/Canvas/_constants.ts
|
|
1318
1397
|
var OFFSCREEN_CANVAS_CTX_FAILED = "Failed to create OffscreenCanvas context";
|
|
@@ -1427,763 +1506,776 @@ async function writeImageDataToClipboard(imageData) {
|
|
|
1427
1506
|
return writeImgBlobToClipboard(blob);
|
|
1428
1507
|
}
|
|
1429
1508
|
|
|
1430
|
-
// src/
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1509
|
+
// src/History/PixelPatchTiles.ts
|
|
1510
|
+
var PixelTile = class {
|
|
1511
|
+
constructor(id, tx, ty, tileArea) {
|
|
1512
|
+
this.id = id;
|
|
1513
|
+
this.tx = tx;
|
|
1514
|
+
this.ty = ty;
|
|
1515
|
+
this.data32 = new Uint32Array(tileArea);
|
|
1516
|
+
}
|
|
1517
|
+
data32;
|
|
1518
|
+
};
|
|
1519
|
+
function applyPatchTiles(target, tiles, tileSize = 256) {
|
|
1520
|
+
for (let i = 0; i < tiles.length; i++) {
|
|
1521
|
+
const tile = tiles[i];
|
|
1522
|
+
if (!tile) continue;
|
|
1523
|
+
const dst = target.data32;
|
|
1524
|
+
const src = tile.data32;
|
|
1525
|
+
const dstWidth = target.width;
|
|
1526
|
+
const dstHeight = target.height;
|
|
1527
|
+
const startX = tile.tx * tileSize;
|
|
1528
|
+
const startY = tile.ty * tileSize;
|
|
1529
|
+
const copyWidth = Math.max(0, Math.min(tileSize, dstWidth - startX));
|
|
1530
|
+
if (copyWidth <= 0) return;
|
|
1531
|
+
for (let ly = 0; ly < tileSize; ly++) {
|
|
1532
|
+
const globalY = startY + ly;
|
|
1533
|
+
if (globalY >= dstHeight) break;
|
|
1534
|
+
const dstIndex = globalY * dstWidth + startX;
|
|
1535
|
+
const srcIndex = ly * tileSize;
|
|
1536
|
+
const rowData = src.subarray(srcIndex, srcIndex + copyWidth);
|
|
1537
|
+
dst.set(rowData, dstIndex);
|
|
1441
1538
|
}
|
|
1442
|
-
return imageData;
|
|
1443
|
-
};
|
|
1444
|
-
}
|
|
1445
|
-
|
|
1446
|
-
// src/ImageData/copyImageData.ts
|
|
1447
|
-
function copyImageData({ data, width, height }) {
|
|
1448
|
-
return new ImageData(data.slice(), width, height);
|
|
1449
|
-
}
|
|
1450
|
-
function copyImageDataLike({ data, width, height }) {
|
|
1451
|
-
return {
|
|
1452
|
-
data: data.slice(),
|
|
1453
|
-
width,
|
|
1454
|
-
height
|
|
1455
|
-
};
|
|
1456
|
-
}
|
|
1457
|
-
|
|
1458
|
-
// src/PixelData/pixelDataToAlphaMask.ts
|
|
1459
|
-
function pixelDataToAlphaMask(pixelData) {
|
|
1460
|
-
const {
|
|
1461
|
-
data32,
|
|
1462
|
-
width,
|
|
1463
|
-
height
|
|
1464
|
-
} = pixelData;
|
|
1465
|
-
const len = data32.length;
|
|
1466
|
-
const mask = new Uint8Array(width * height);
|
|
1467
|
-
for (let i = 0; i < len; i++) {
|
|
1468
|
-
const val = data32[i];
|
|
1469
|
-
mask[i] = val >>> 24 & 255;
|
|
1470
1539
|
}
|
|
1471
|
-
return mask;
|
|
1472
1540
|
}
|
|
1473
1541
|
|
|
1474
|
-
// src/
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1542
|
+
// src/History/PixelAccumulator.ts
|
|
1543
|
+
var PixelAccumulator = class {
|
|
1544
|
+
constructor(target, config) {
|
|
1545
|
+
this.target = target;
|
|
1546
|
+
this.config = config;
|
|
1547
|
+
this.lookup = [];
|
|
1548
|
+
this.beforeTiles = [];
|
|
1549
|
+
this.pool = [];
|
|
1550
|
+
}
|
|
1551
|
+
lookup;
|
|
1552
|
+
beforeTiles;
|
|
1553
|
+
pool;
|
|
1554
|
+
getTile(id, tx, ty) {
|
|
1555
|
+
let tile = this.pool.pop();
|
|
1556
|
+
if (tile) {
|
|
1557
|
+
tile.id = id;
|
|
1558
|
+
tile.tx = tx;
|
|
1559
|
+
tile.ty = ty;
|
|
1560
|
+
return tile;
|
|
1561
|
+
}
|
|
1562
|
+
return new PixelTile(
|
|
1563
|
+
id,
|
|
1564
|
+
tx,
|
|
1565
|
+
ty,
|
|
1566
|
+
this.config.tileArea
|
|
1567
|
+
);
|
|
1491
1568
|
}
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1569
|
+
recyclePatch(patch) {
|
|
1570
|
+
const before = patch.beforeTiles;
|
|
1571
|
+
for (let i = 0; i < before.length; i++) {
|
|
1572
|
+
let tile = before[i];
|
|
1573
|
+
if (tile) {
|
|
1574
|
+
this.pool.push(tile);
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
const after = patch.afterTiles;
|
|
1578
|
+
for (let i = 0; i < after.length; i++) {
|
|
1579
|
+
let tile = after[i];
|
|
1580
|
+
if (tile) {
|
|
1581
|
+
this.pool.push(tile);
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
/**
|
|
1586
|
+
* @param x pixel x coordinate
|
|
1587
|
+
* @param y pixel y coordinate
|
|
1588
|
+
*/
|
|
1589
|
+
storeTileBeforeState(x, y) {
|
|
1590
|
+
let target = this.target;
|
|
1591
|
+
let shift = this.config.tileShift;
|
|
1592
|
+
let columns = target.width + this.config.tileMask >> shift;
|
|
1593
|
+
let tx = x >> shift;
|
|
1594
|
+
let ty = y >> shift;
|
|
1595
|
+
let id = ty * columns + tx;
|
|
1596
|
+
let tile = this.lookup[id];
|
|
1597
|
+
if (!tile) {
|
|
1598
|
+
tile = this.getTile(
|
|
1599
|
+
id,
|
|
1600
|
+
tx,
|
|
1601
|
+
ty
|
|
1602
|
+
);
|
|
1603
|
+
this.extractState(tile);
|
|
1604
|
+
this.lookup[id] = tile;
|
|
1605
|
+
this.beforeTiles.push(tile);
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
/**
|
|
1609
|
+
*
|
|
1610
|
+
* @param x pixel x coordinate
|
|
1611
|
+
* @param y pixel y coordinate
|
|
1612
|
+
* @param w pixel width
|
|
1613
|
+
* @param h pixel height
|
|
1614
|
+
*/
|
|
1615
|
+
storeRegionBeforeState(x, y, w, h) {
|
|
1616
|
+
let target = this.target;
|
|
1617
|
+
let shift = this.config.tileShift;
|
|
1618
|
+
let columns = target.width + this.config.tileMask >> shift;
|
|
1619
|
+
let startX = x >> shift;
|
|
1620
|
+
let startY = y >> shift;
|
|
1621
|
+
let endX = x + w - 1 >> shift;
|
|
1622
|
+
let endY = y + h - 1 >> shift;
|
|
1623
|
+
for (let ty = startY; ty <= endY; ty++) {
|
|
1624
|
+
for (let tx = startX; tx <= endX; tx++) {
|
|
1625
|
+
let id = ty * columns + tx;
|
|
1626
|
+
let tile = this.lookup[id];
|
|
1627
|
+
if (!tile) {
|
|
1628
|
+
tile = this.getTile(
|
|
1629
|
+
id,
|
|
1630
|
+
tx,
|
|
1631
|
+
ty
|
|
1632
|
+
);
|
|
1633
|
+
this.extractState(tile);
|
|
1634
|
+
this.lookup[id] = tile;
|
|
1635
|
+
this.beforeTiles.push(tile);
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
extractState(tile) {
|
|
1641
|
+
let target = this.target;
|
|
1642
|
+
let TILE_SIZE = this.config.tileSize;
|
|
1643
|
+
let dst = tile.data32;
|
|
1644
|
+
let src = target.data32;
|
|
1645
|
+
let startX = tile.tx * TILE_SIZE;
|
|
1646
|
+
let startY = tile.ty * TILE_SIZE;
|
|
1647
|
+
let targetWidth = target.width;
|
|
1648
|
+
let targetHeight = target.height;
|
|
1649
|
+
let copyWidth = Math.max(0, Math.min(TILE_SIZE, targetWidth - startX));
|
|
1650
|
+
for (let ly = 0; ly < TILE_SIZE; ly++) {
|
|
1651
|
+
let globalY = startY + ly;
|
|
1652
|
+
let dstIndex = ly * TILE_SIZE;
|
|
1653
|
+
if (globalY < 0 || globalY >= targetHeight || copyWidth === 0) {
|
|
1654
|
+
dst.fill(0, dstIndex, dstIndex + TILE_SIZE);
|
|
1655
|
+
continue;
|
|
1656
|
+
}
|
|
1657
|
+
let srcIndex = globalY * targetWidth + startX;
|
|
1658
|
+
let rowData = src.subarray(srcIndex, srcIndex + copyWidth);
|
|
1659
|
+
dst.set(rowData, dstIndex);
|
|
1660
|
+
if (copyWidth < TILE_SIZE) {
|
|
1661
|
+
dst.fill(0, dstIndex + copyWidth, dstIndex + TILE_SIZE);
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
extractAfterTiles() {
|
|
1666
|
+
let afterTiles = [];
|
|
1667
|
+
let length = this.beforeTiles.length;
|
|
1668
|
+
for (let i = 0; i < length; i++) {
|
|
1669
|
+
let beforeTile = this.beforeTiles[i];
|
|
1670
|
+
if (beforeTile) {
|
|
1671
|
+
let afterTile = this.getTile(
|
|
1672
|
+
beforeTile.id,
|
|
1673
|
+
beforeTile.tx,
|
|
1674
|
+
beforeTile.ty
|
|
1675
|
+
);
|
|
1676
|
+
this.extractState(afterTile);
|
|
1677
|
+
afterTiles.push(afterTile);
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
return afterTiles;
|
|
1681
|
+
}
|
|
1682
|
+
reset() {
|
|
1683
|
+
this.lookup = [];
|
|
1684
|
+
this.beforeTiles = [];
|
|
1522
1685
|
}
|
|
1523
|
-
return imageData;
|
|
1524
|
-
}
|
|
1525
|
-
|
|
1526
|
-
// src/Internal/resample32.ts
|
|
1527
|
-
var resample32Scratch = {
|
|
1528
|
-
data: null,
|
|
1529
|
-
width: 0,
|
|
1530
|
-
height: 0
|
|
1531
1686
|
};
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1687
|
+
|
|
1688
|
+
// src/History/HistoryManager.ts
|
|
1689
|
+
var HistoryManager = class {
|
|
1690
|
+
constructor(maxSteps = 50) {
|
|
1691
|
+
this.maxSteps = maxSteps;
|
|
1692
|
+
this.undoStack = [];
|
|
1693
|
+
this.redoStack = [];
|
|
1694
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
1695
|
+
}
|
|
1696
|
+
undoStack;
|
|
1697
|
+
redoStack;
|
|
1698
|
+
listeners;
|
|
1699
|
+
get canUndo() {
|
|
1700
|
+
return this.undoStack.length > 0;
|
|
1701
|
+
}
|
|
1702
|
+
get canRedo() {
|
|
1703
|
+
return this.redoStack.length > 0;
|
|
1704
|
+
}
|
|
1705
|
+
subscribe(fn) {
|
|
1706
|
+
this.listeners.add(fn);
|
|
1707
|
+
return () => this.listeners.delete(fn);
|
|
1708
|
+
}
|
|
1709
|
+
notify() {
|
|
1710
|
+
this.listeners.forEach((fn) => fn());
|
|
1711
|
+
}
|
|
1712
|
+
commit(action) {
|
|
1713
|
+
this.undoStack.push(action);
|
|
1714
|
+
this.clearRedoStack();
|
|
1715
|
+
if (this.undoStack.length > this.maxSteps) {
|
|
1716
|
+
this.undoStack.shift()?.dispose?.();
|
|
1717
|
+
}
|
|
1718
|
+
this.notify();
|
|
1719
|
+
}
|
|
1720
|
+
undo() {
|
|
1721
|
+
let action = this.undoStack.pop();
|
|
1722
|
+
if (!action) return;
|
|
1723
|
+
this.redoStack.push(action);
|
|
1724
|
+
action.undo();
|
|
1725
|
+
this.notify();
|
|
1726
|
+
}
|
|
1727
|
+
redo() {
|
|
1728
|
+
let action = this.redoStack.pop();
|
|
1729
|
+
if (!action) return;
|
|
1730
|
+
this.undoStack.push(action);
|
|
1731
|
+
action.redo();
|
|
1732
|
+
this.notify();
|
|
1733
|
+
}
|
|
1734
|
+
clearRedoStack() {
|
|
1735
|
+
let length = this.redoStack.length;
|
|
1736
|
+
for (let i = 0; i < length; i++) {
|
|
1737
|
+
let action = this.redoStack[i];
|
|
1738
|
+
if (action) {
|
|
1739
|
+
action.dispose?.();
|
|
1740
|
+
}
|
|
1545
1741
|
}
|
|
1742
|
+
this.redoStack.length = 0;
|
|
1546
1743
|
}
|
|
1547
|
-
|
|
1548
|
-
resample32Scratch.width = dstW;
|
|
1549
|
-
resample32Scratch.height = dstH;
|
|
1550
|
-
return resample32Scratch;
|
|
1551
|
-
}
|
|
1744
|
+
};
|
|
1552
1745
|
|
|
1553
|
-
// src/
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1746
|
+
// src/History/PixelEngineConfig.ts
|
|
1747
|
+
var PixelEngineConfig = class {
|
|
1748
|
+
tileSize;
|
|
1749
|
+
tileShift;
|
|
1750
|
+
tileMask;
|
|
1751
|
+
tileArea;
|
|
1752
|
+
constructor(tileSize = 256) {
|
|
1753
|
+
if ((tileSize & tileSize - 1) !== 0) {
|
|
1754
|
+
throw new Error("tileSize must be a power of 2");
|
|
1755
|
+
}
|
|
1756
|
+
this.tileSize = tileSize;
|
|
1757
|
+
this.tileShift = Math.log2(tileSize);
|
|
1758
|
+
this.tileMask = tileSize - 1;
|
|
1759
|
+
this.tileArea = tileSize * tileSize;
|
|
1760
|
+
}
|
|
1761
|
+
};
|
|
1560
1762
|
|
|
1561
|
-
// src/
|
|
1562
|
-
function
|
|
1563
|
-
const result = new ImageData(newWidth, newHeight);
|
|
1763
|
+
// src/PixelData/applyMaskToPixelData.ts
|
|
1764
|
+
function applyMaskToPixelData(dst, mask, opts = {}) {
|
|
1564
1765
|
const {
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
const dstStart = (dstY * newWidth + x0) * 4;
|
|
1584
|
-
const srcStart = (srcY * oldW + srcX) * 4;
|
|
1585
|
-
newData.set(
|
|
1586
|
-
oldData.subarray(srcStart, srcStart + rowLen),
|
|
1587
|
-
dstStart
|
|
1588
|
-
);
|
|
1766
|
+
x: targetX = 0,
|
|
1767
|
+
y: targetY = 0,
|
|
1768
|
+
w: width = dst.width,
|
|
1769
|
+
h: height = dst.height,
|
|
1770
|
+
alpha: globalAlpha = 255,
|
|
1771
|
+
maskType = 0 /* ALPHA */,
|
|
1772
|
+
mw,
|
|
1773
|
+
mx = 0,
|
|
1774
|
+
my = 0,
|
|
1775
|
+
invertMask = false
|
|
1776
|
+
} = opts;
|
|
1777
|
+
let x = targetX;
|
|
1778
|
+
let y = targetY;
|
|
1779
|
+
let w = width;
|
|
1780
|
+
let h = height;
|
|
1781
|
+
if (x < 0) {
|
|
1782
|
+
w += x;
|
|
1783
|
+
x = 0;
|
|
1589
1784
|
}
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
// src/ImageData/serialization.ts
|
|
1594
|
-
function base64EncodeArrayBuffer(buffer) {
|
|
1595
|
-
const uint8 = new Uint8Array(buffer);
|
|
1596
|
-
const decoder = new TextDecoder("latin1");
|
|
1597
|
-
const binary = decoder.decode(uint8);
|
|
1598
|
-
return btoa(binary);
|
|
1599
|
-
}
|
|
1600
|
-
function base64DecodeArrayBuffer(encoded) {
|
|
1601
|
-
const binary = atob(encoded);
|
|
1602
|
-
const bytes = new Uint8ClampedArray(binary.length);
|
|
1603
|
-
for (let i = 0; i < binary.length; i++) {
|
|
1604
|
-
bytes[i] = binary.charCodeAt(i);
|
|
1785
|
+
if (y < 0) {
|
|
1786
|
+
h += y;
|
|
1787
|
+
y = 0;
|
|
1605
1788
|
}
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
return {
|
|
1610
|
-
width: imageData.width,
|
|
1611
|
-
height: imageData.height,
|
|
1612
|
-
data: base64EncodeArrayBuffer(imageData.data.buffer)
|
|
1613
|
-
};
|
|
1614
|
-
}
|
|
1615
|
-
function serializeNullableImageData(imageData) {
|
|
1616
|
-
if (!imageData) return null;
|
|
1617
|
-
return serializeImageData(imageData);
|
|
1618
|
-
}
|
|
1619
|
-
function deserializeRawImageData(serialized) {
|
|
1620
|
-
return {
|
|
1621
|
-
width: serialized.width,
|
|
1622
|
-
height: serialized.height,
|
|
1623
|
-
data: base64DecodeArrayBuffer(serialized.data)
|
|
1624
|
-
};
|
|
1625
|
-
}
|
|
1626
|
-
function deserializeImageData(serialized) {
|
|
1627
|
-
const data = base64DecodeArrayBuffer(serialized.data);
|
|
1628
|
-
return new ImageData(data, serialized.width, serialized.height);
|
|
1629
|
-
}
|
|
1630
|
-
function deserializeNullableImageData(serialized) {
|
|
1631
|
-
if (!serialized) return null;
|
|
1632
|
-
return deserializeImageData(serialized);
|
|
1633
|
-
}
|
|
1634
|
-
|
|
1635
|
-
// src/ImageData/writeImageData.ts
|
|
1636
|
-
function writeImageData(target, source, x, y, sx = 0, sy = 0, sw = source.width, sh = source.height, mask = null, maskType = 1 /* BINARY */) {
|
|
1637
|
-
const dstW = target.width;
|
|
1638
|
-
const dstH = target.height;
|
|
1639
|
-
const dstData = target.data;
|
|
1640
|
-
const srcW = source.width;
|
|
1641
|
-
const srcData = source.data;
|
|
1642
|
-
const x0 = Math.max(0, x);
|
|
1643
|
-
const y0 = Math.max(0, y);
|
|
1644
|
-
const x1 = Math.min(dstW, x + sw);
|
|
1645
|
-
const y1 = Math.min(dstH, y + sh);
|
|
1646
|
-
if (x1 <= x0 || y1 <= y0) {
|
|
1789
|
+
const actualW = Math.min(w, dst.width - x);
|
|
1790
|
+
const actualH = Math.min(h, dst.height - y);
|
|
1791
|
+
if (actualW <= 0 || actualH <= 0 || globalAlpha === 0) {
|
|
1647
1792
|
return;
|
|
1648
1793
|
}
|
|
1649
|
-
const
|
|
1650
|
-
const
|
|
1651
|
-
const
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1794
|
+
const dst32 = dst.data32;
|
|
1795
|
+
const dw = dst.width;
|
|
1796
|
+
const mPitch = mw ?? width;
|
|
1797
|
+
const isAlpha = maskType === 0 /* ALPHA */;
|
|
1798
|
+
const dx = x - targetX;
|
|
1799
|
+
const dy = y - targetY;
|
|
1800
|
+
let dIdx = y * dw + x;
|
|
1801
|
+
let mIdx = (my + dy) * mPitch + (mx + dx);
|
|
1802
|
+
const dStride = dw - actualW;
|
|
1803
|
+
const mStride = mPitch - actualW;
|
|
1804
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
1805
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
1806
|
+
const mVal = mask[mIdx];
|
|
1807
|
+
let weight = globalAlpha;
|
|
1808
|
+
if (isAlpha) {
|
|
1809
|
+
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
1810
|
+
if (effectiveM === 0) {
|
|
1811
|
+
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
1812
|
+
dIdx++;
|
|
1813
|
+
mIdx++;
|
|
1663
1814
|
continue;
|
|
1664
1815
|
}
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1816
|
+
weight = globalAlpha === 255 ? effectiveM : effectiveM * globalAlpha + 128 >> 8;
|
|
1817
|
+
} else {
|
|
1818
|
+
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
1819
|
+
if (!isHit) {
|
|
1820
|
+
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
1821
|
+
dIdx++;
|
|
1822
|
+
mIdx++;
|
|
1823
|
+
continue;
|
|
1824
|
+
}
|
|
1825
|
+
weight = globalAlpha;
|
|
1826
|
+
}
|
|
1827
|
+
if (weight === 0) {
|
|
1828
|
+
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
1829
|
+
} else {
|
|
1830
|
+
const d = dst32[dIdx];
|
|
1831
|
+
const da = d >>> 24;
|
|
1832
|
+
let finalAlpha = da;
|
|
1833
|
+
if (da === 0) {
|
|
1834
|
+
} else if (weight === 255) {
|
|
1835
|
+
} else if (da === 255) {
|
|
1836
|
+
finalAlpha = weight;
|
|
1672
1837
|
} else {
|
|
1673
|
-
|
|
1674
|
-
const invA = 1 - a;
|
|
1675
|
-
dstData[di] = srcData[si] * a + dstData[di] * invA;
|
|
1676
|
-
dstData[di + 1] = srcData[si + 1] * a + dstData[di + 1] * invA;
|
|
1677
|
-
dstData[di + 2] = srcData[si + 2] * a + dstData[di + 2] * invA;
|
|
1678
|
-
dstData[di + 3] = srcData[si + 3] * a + dstData[di + 3] * invA;
|
|
1838
|
+
finalAlpha = da * weight + 128 >> 8;
|
|
1679
1839
|
}
|
|
1840
|
+
dst32[dIdx] = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
1680
1841
|
}
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
const sub = srcData.subarray(srcStart, srcStart + byteLen);
|
|
1684
|
-
dstData.set(sub, dstStart);
|
|
1842
|
+
dIdx++;
|
|
1843
|
+
mIdx++;
|
|
1685
1844
|
}
|
|
1845
|
+
dIdx += dStride;
|
|
1846
|
+
mIdx += mStride;
|
|
1686
1847
|
}
|
|
1687
1848
|
}
|
|
1688
1849
|
|
|
1689
|
-
// src/
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1850
|
+
// src/History/PixelWriter.ts
|
|
1851
|
+
var PixelWriter = class {
|
|
1852
|
+
target;
|
|
1853
|
+
historyManager;
|
|
1854
|
+
accumulator;
|
|
1855
|
+
config;
|
|
1856
|
+
mutator;
|
|
1857
|
+
constructor(target, mutatorFactory, {
|
|
1858
|
+
tileSize = 256,
|
|
1859
|
+
maxHistorySteps = 50,
|
|
1860
|
+
historyManager = new HistoryManager(maxHistorySteps)
|
|
1861
|
+
} = {}) {
|
|
1862
|
+
this.target = target;
|
|
1863
|
+
this.config = new PixelEngineConfig(tileSize);
|
|
1864
|
+
this.historyManager = historyManager;
|
|
1865
|
+
this.accumulator = new PixelAccumulator(target, this.config);
|
|
1866
|
+
this.mutator = mutatorFactory(this);
|
|
1867
|
+
}
|
|
1868
|
+
withHistory(cb) {
|
|
1869
|
+
cb(this.mutator);
|
|
1870
|
+
const beforeTiles = this.accumulator.beforeTiles;
|
|
1871
|
+
if (beforeTiles.length === 0) return;
|
|
1872
|
+
const afterTiles = this.accumulator.extractAfterTiles();
|
|
1873
|
+
const patch = {
|
|
1874
|
+
beforeTiles,
|
|
1875
|
+
afterTiles
|
|
1876
|
+
};
|
|
1877
|
+
const target = this.target;
|
|
1878
|
+
const tileSize = this.config.tileSize;
|
|
1879
|
+
const accumulator = this.accumulator;
|
|
1880
|
+
const action = {
|
|
1881
|
+
undo: () => applyPatchTiles(target, patch.beforeTiles, tileSize),
|
|
1882
|
+
redo: () => applyPatchTiles(target, patch.afterTiles, tileSize),
|
|
1883
|
+
dispose: () => accumulator.recyclePatch(patch)
|
|
1884
|
+
};
|
|
1885
|
+
this.historyManager.commit(action);
|
|
1886
|
+
this.accumulator.reset();
|
|
1707
1887
|
}
|
|
1888
|
+
};
|
|
1889
|
+
|
|
1890
|
+
// src/History/PixelMutator/mutatorApplyMask.ts
|
|
1891
|
+
function mutatorApplyMask(writer) {
|
|
1892
|
+
return {
|
|
1893
|
+
applyMask: (mask, opts = {}) => {
|
|
1894
|
+
let target = writer.target;
|
|
1895
|
+
const {
|
|
1896
|
+
x = 0,
|
|
1897
|
+
y = 0,
|
|
1898
|
+
w = writer.target.width,
|
|
1899
|
+
h = writer.target.height
|
|
1900
|
+
} = opts;
|
|
1901
|
+
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
1902
|
+
applyMaskToPixelData(target, mask, opts);
|
|
1903
|
+
}
|
|
1904
|
+
};
|
|
1708
1905
|
}
|
|
1709
1906
|
|
|
1710
|
-
// src/
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1907
|
+
// src/PixelData/blendColorPixelData.ts
|
|
1908
|
+
function blendColorPixelData(dst, color, opts = {}) {
|
|
1909
|
+
const {
|
|
1910
|
+
x: targetX = 0,
|
|
1911
|
+
y: targetY = 0,
|
|
1912
|
+
w: width = dst.width,
|
|
1913
|
+
h: height = dst.height,
|
|
1914
|
+
alpha: globalAlpha = 255,
|
|
1915
|
+
blendFn = sourceOverFast,
|
|
1916
|
+
mask,
|
|
1917
|
+
maskType = 0 /* ALPHA */,
|
|
1918
|
+
mw,
|
|
1919
|
+
mx = 0,
|
|
1920
|
+
my = 0,
|
|
1921
|
+
invertMask = false
|
|
1922
|
+
} = opts;
|
|
1923
|
+
if (globalAlpha === 0) return;
|
|
1924
|
+
const baseSrcAlpha = color >>> 24;
|
|
1925
|
+
const isOverwrite = blendFn.isOverwrite;
|
|
1926
|
+
if (baseSrcAlpha === 0 && !isOverwrite) return;
|
|
1927
|
+
let x = targetX;
|
|
1928
|
+
let y = targetY;
|
|
1929
|
+
let w = width;
|
|
1930
|
+
let h = height;
|
|
1931
|
+
if (x < 0) {
|
|
1932
|
+
w += x;
|
|
1933
|
+
x = 0;
|
|
1735
1934
|
}
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
* @returns A new IndexedImage instance.
|
|
1740
|
-
*/
|
|
1741
|
-
static fromImageData(imageData) {
|
|
1742
|
-
return _IndexedImage.fromRaw(imageData.data, imageData.width, imageData.height);
|
|
1935
|
+
if (y < 0) {
|
|
1936
|
+
h += y;
|
|
1937
|
+
y = 0;
|
|
1743
1938
|
}
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1939
|
+
const actualW = Math.min(w, dst.width - x);
|
|
1940
|
+
const actualH = Math.min(h, dst.height - y);
|
|
1941
|
+
if (actualW <= 0 || actualH <= 0) return;
|
|
1942
|
+
const dst32 = dst.data32;
|
|
1943
|
+
const dw = dst.width;
|
|
1944
|
+
const mPitch = mw ?? width;
|
|
1945
|
+
const isAlphaMask = maskType === 0 /* ALPHA */;
|
|
1946
|
+
const dx = x - targetX;
|
|
1947
|
+
const dy = y - targetY;
|
|
1948
|
+
let dIdx = y * dw + x;
|
|
1949
|
+
let mIdx = (my + dy) * mPitch + (mx + dx);
|
|
1950
|
+
const dStride = dw - actualW;
|
|
1951
|
+
const mStride = mPitch - actualW;
|
|
1952
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
1953
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
1954
|
+
let weight = globalAlpha;
|
|
1955
|
+
if (mask) {
|
|
1956
|
+
const mVal = mask[mIdx];
|
|
1957
|
+
if (isAlphaMask) {
|
|
1958
|
+
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
1959
|
+
if (effectiveM === 0) {
|
|
1960
|
+
dIdx++;
|
|
1961
|
+
mIdx++;
|
|
1962
|
+
continue;
|
|
1963
|
+
}
|
|
1964
|
+
if (globalAlpha === 255) {
|
|
1965
|
+
weight = effectiveM;
|
|
1966
|
+
} else if (effectiveM === 255) {
|
|
1967
|
+
weight = globalAlpha;
|
|
1968
|
+
} else {
|
|
1969
|
+
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
1970
|
+
}
|
|
1971
|
+
} else {
|
|
1972
|
+
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
1973
|
+
if (!isHit) {
|
|
1974
|
+
dIdx++;
|
|
1975
|
+
mIdx++;
|
|
1976
|
+
continue;
|
|
1977
|
+
}
|
|
1978
|
+
weight = globalAlpha;
|
|
1979
|
+
}
|
|
1980
|
+
if (weight === 0) {
|
|
1981
|
+
dIdx++;
|
|
1982
|
+
mIdx++;
|
|
1983
|
+
continue;
|
|
1984
|
+
}
|
|
1769
1985
|
}
|
|
1770
|
-
|
|
1986
|
+
let currentSrcColor = color;
|
|
1987
|
+
if (weight < 255) {
|
|
1988
|
+
let currentSrcAlpha = baseSrcAlpha;
|
|
1989
|
+
if (baseSrcAlpha === 255) {
|
|
1990
|
+
currentSrcAlpha = weight;
|
|
1991
|
+
} else {
|
|
1992
|
+
currentSrcAlpha = baseSrcAlpha * weight + 128 >> 8;
|
|
1993
|
+
}
|
|
1994
|
+
if (!isOverwrite && currentSrcAlpha === 0) {
|
|
1995
|
+
dIdx++;
|
|
1996
|
+
mIdx++;
|
|
1997
|
+
continue;
|
|
1998
|
+
}
|
|
1999
|
+
currentSrcColor = (color & 16777215 | currentSrcAlpha << 24) >>> 0;
|
|
2000
|
+
}
|
|
2001
|
+
dst32[dIdx] = blendFn(currentSrcColor, dst32[dIdx]);
|
|
2002
|
+
dIdx++;
|
|
2003
|
+
mIdx++;
|
|
1771
2004
|
}
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
width,
|
|
1775
|
-
height,
|
|
1776
|
-
indexedData,
|
|
1777
|
-
palette,
|
|
1778
|
-
transparentPalletIndex
|
|
1779
|
-
);
|
|
1780
|
-
}
|
|
1781
|
-
/**
|
|
1782
|
-
* Retrieves the 32-bit packed color value at the given coordinates.
|
|
1783
|
-
* @param x - X coordinate.
|
|
1784
|
-
* @param y - Y coordinate.
|
|
1785
|
-
* @returns The packed color from the palette.
|
|
1786
|
-
*/
|
|
1787
|
-
getColorAt(x, y) {
|
|
1788
|
-
const index = x + y * this.width;
|
|
1789
|
-
const paletteIndex = this.data[index];
|
|
1790
|
-
return this.palette[paletteIndex];
|
|
1791
|
-
}
|
|
1792
|
-
};
|
|
1793
|
-
|
|
1794
|
-
// src/IndexedImage/getIndexedImageColorCounts.ts
|
|
1795
|
-
function getIndexedImageColorCounts(indexedImage) {
|
|
1796
|
-
const data = indexedImage.data;
|
|
1797
|
-
const palette = indexedImage.palette;
|
|
1798
|
-
const frequencies = new Int32Array(palette.length);
|
|
1799
|
-
for (let i = 0; i < data.length; i++) {
|
|
1800
|
-
const colorIndex = data[i];
|
|
1801
|
-
frequencies[colorIndex]++;
|
|
2005
|
+
dIdx += dStride;
|
|
2006
|
+
mIdx += mStride;
|
|
1802
2007
|
}
|
|
1803
|
-
return frequencies;
|
|
1804
2008
|
}
|
|
1805
2009
|
|
|
1806
|
-
// src/
|
|
1807
|
-
function
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
let totalWeight = 0;
|
|
1819
|
-
for (let id = 0; id < counts.length; id++) {
|
|
1820
|
-
const weight = counts[id];
|
|
1821
|
-
if (weight === 0) {
|
|
1822
|
-
continue;
|
|
1823
|
-
}
|
|
1824
|
-
if (!includeTransparent && id === transparentPalletIndex) {
|
|
1825
|
-
continue;
|
|
2010
|
+
// src/History/PixelMutator/mutatorBlendColor.ts
|
|
2011
|
+
function mutatorBlendColor(writer) {
|
|
2012
|
+
return {
|
|
2013
|
+
blendColor(color, opts = {}) {
|
|
2014
|
+
const {
|
|
2015
|
+
x = 0,
|
|
2016
|
+
y = 0,
|
|
2017
|
+
w = writer.target.width,
|
|
2018
|
+
h = writer.target.height
|
|
2019
|
+
} = opts;
|
|
2020
|
+
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2021
|
+
blendColorPixelData(writer.target, color, opts);
|
|
1826
2022
|
}
|
|
1827
|
-
|
|
1828
|
-
const r2 = color & 255;
|
|
1829
|
-
const g2 = color >> 8 & 255;
|
|
1830
|
-
const b2 = color >> 16 & 255;
|
|
1831
|
-
const a2 = color >> 24 & 255;
|
|
1832
|
-
rSum += r2 * weight;
|
|
1833
|
-
gSum += g2 * weight;
|
|
1834
|
-
bSum += b2 * weight;
|
|
1835
|
-
aSum += a2 * weight;
|
|
1836
|
-
totalWeight += weight;
|
|
1837
|
-
}
|
|
1838
|
-
if (totalWeight === 0) {
|
|
1839
|
-
return packColor(0, 0, 0, 0);
|
|
1840
|
-
}
|
|
1841
|
-
const r = rSum / totalWeight | 0;
|
|
1842
|
-
const g = gSum / totalWeight | 0;
|
|
1843
|
-
const b = bSum / totalWeight | 0;
|
|
1844
|
-
const a = aSum / totalWeight | 0;
|
|
1845
|
-
return packColor(r, g, b, a);
|
|
2023
|
+
};
|
|
1846
2024
|
}
|
|
1847
2025
|
|
|
1848
|
-
// src/
|
|
1849
|
-
function
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
2026
|
+
// src/History/PixelMutator/mutatorBlendPixel.ts
|
|
2027
|
+
function mutatorBlendPixel(writer) {
|
|
2028
|
+
return {
|
|
2029
|
+
blendPixel(x, y, color, alpha = 255, blendFn = overwriteFast) {
|
|
2030
|
+
let target = writer.target;
|
|
2031
|
+
let width = target.width;
|
|
2032
|
+
let height = target.height;
|
|
2033
|
+
if (x < 0 || x >= width || y < 0 || y >= height) return;
|
|
2034
|
+
writer.accumulator.storeTileBeforeState(x, y);
|
|
2035
|
+
let index = y * width + x;
|
|
2036
|
+
let bg = target.data32[index];
|
|
2037
|
+
let finalColor = color;
|
|
2038
|
+
if (alpha < 255) {
|
|
2039
|
+
let baseSrcAlpha = color >>> 24;
|
|
2040
|
+
let finalAlpha = baseSrcAlpha * alpha + 128 >> 8;
|
|
2041
|
+
finalColor = (color & 16777215 | finalAlpha << 24) >>> 0;
|
|
2042
|
+
}
|
|
2043
|
+
target.data32[index] = blendFn(finalColor, bg);
|
|
2044
|
+
}
|
|
2045
|
+
};
|
|
1863
2046
|
}
|
|
1864
2047
|
|
|
1865
|
-
// src/
|
|
1866
|
-
function
|
|
1867
|
-
const {
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
2048
|
+
// src/PixelData/blendPixelData.ts
|
|
2049
|
+
function blendPixelData(dst, src, opts) {
|
|
2050
|
+
const {
|
|
2051
|
+
x: targetX = 0,
|
|
2052
|
+
y: targetY = 0,
|
|
2053
|
+
sx: sourceX = 0,
|
|
2054
|
+
sy: sourceY = 0,
|
|
2055
|
+
w: width = src.width,
|
|
2056
|
+
h: height = src.height,
|
|
2057
|
+
alpha: globalAlpha = 255,
|
|
2058
|
+
blendFn = sourceOverFast,
|
|
2059
|
+
mask,
|
|
2060
|
+
maskType = 0 /* ALPHA */,
|
|
2061
|
+
mw,
|
|
2062
|
+
mx = 0,
|
|
2063
|
+
my = 0,
|
|
2064
|
+
invertMask = false
|
|
2065
|
+
} = opts;
|
|
2066
|
+
if (globalAlpha === 0) return;
|
|
2067
|
+
let x = targetX;
|
|
2068
|
+
let y = targetY;
|
|
2069
|
+
let sx = sourceX;
|
|
2070
|
+
let sy = sourceY;
|
|
2071
|
+
let w = width;
|
|
2072
|
+
let h = height;
|
|
2073
|
+
if (sx < 0) {
|
|
2074
|
+
x -= sx;
|
|
2075
|
+
w += sx;
|
|
2076
|
+
sx = 0;
|
|
1874
2077
|
}
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
async function fileInputChangeToImageData(event) {
|
|
1880
|
-
const target = event.target;
|
|
1881
|
-
const file = target.files?.[0];
|
|
1882
|
-
if (!file) return null;
|
|
1883
|
-
return await fileToImageData(file);
|
|
1884
|
-
}
|
|
1885
|
-
|
|
1886
|
-
// src/Input/fileToImageData.ts
|
|
1887
|
-
var UnsupportedFormatError = class extends Error {
|
|
1888
|
-
constructor(mimeType) {
|
|
1889
|
-
super(`File type ${mimeType} is not a supported image format.`);
|
|
1890
|
-
this.name = "UnsupportedFormatError";
|
|
2078
|
+
if (sy < 0) {
|
|
2079
|
+
y -= sy;
|
|
2080
|
+
h += sy;
|
|
2081
|
+
sy = 0;
|
|
1891
2082
|
}
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
if (
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
let bitmap = null;
|
|
1899
|
-
try {
|
|
1900
|
-
bitmap = await createImageBitmap(file);
|
|
1901
|
-
const canvas = new OffscreenCanvas(
|
|
1902
|
-
bitmap.width,
|
|
1903
|
-
bitmap.height
|
|
1904
|
-
);
|
|
1905
|
-
const ctx = canvas.getContext("2d");
|
|
1906
|
-
if (!ctx) throw new Error(OFFSCREEN_CANVAS_CTX_FAILED);
|
|
1907
|
-
ctx.drawImage(
|
|
1908
|
-
bitmap,
|
|
1909
|
-
0,
|
|
1910
|
-
0
|
|
1911
|
-
);
|
|
1912
|
-
return ctx.getImageData(
|
|
1913
|
-
0,
|
|
1914
|
-
0,
|
|
1915
|
-
bitmap.width,
|
|
1916
|
-
bitmap.height
|
|
1917
|
-
);
|
|
1918
|
-
} finally {
|
|
1919
|
-
bitmap?.close();
|
|
1920
|
-
}
|
|
1921
|
-
}
|
|
1922
|
-
|
|
1923
|
-
// src/Input/getSupportedRasterFormats.ts
|
|
1924
|
-
var formatsPromise = null;
|
|
1925
|
-
var defaultRasterMimes = [
|
|
1926
|
-
"image/png",
|
|
1927
|
-
"image/jpeg",
|
|
1928
|
-
"image/webp",
|
|
1929
|
-
"image/avif",
|
|
1930
|
-
"image/gif",
|
|
1931
|
-
"image/bmp"
|
|
1932
|
-
];
|
|
1933
|
-
async function getSupportedPixelFormats(rasterMimes = defaultRasterMimes) {
|
|
1934
|
-
if (formatsPromise) {
|
|
1935
|
-
return formatsPromise;
|
|
1936
|
-
}
|
|
1937
|
-
const probeCanvas = async () => {
|
|
1938
|
-
const canvas = new OffscreenCanvas(1, 1);
|
|
1939
|
-
const results = await Promise.all(
|
|
1940
|
-
rasterMimes.map(async (mime) => {
|
|
1941
|
-
try {
|
|
1942
|
-
const blob = await canvas.convertToBlob({
|
|
1943
|
-
type: mime
|
|
1944
|
-
});
|
|
1945
|
-
return blob.type === mime ? mime : null;
|
|
1946
|
-
} catch {
|
|
1947
|
-
return null;
|
|
1948
|
-
}
|
|
1949
|
-
})
|
|
1950
|
-
);
|
|
1951
|
-
return results.filter((type) => {
|
|
1952
|
-
return type !== null;
|
|
1953
|
-
});
|
|
1954
|
-
};
|
|
1955
|
-
formatsPromise = probeCanvas().catch((error) => {
|
|
1956
|
-
formatsPromise = null;
|
|
1957
|
-
throw error;
|
|
1958
|
-
});
|
|
1959
|
-
return formatsPromise;
|
|
1960
|
-
}
|
|
1961
|
-
|
|
1962
|
-
// src/Mask/copyMask.ts
|
|
1963
|
-
function copyMask(src) {
|
|
1964
|
-
return src.slice();
|
|
1965
|
-
}
|
|
1966
|
-
|
|
1967
|
-
// src/Mask/invertMask.ts
|
|
1968
|
-
function invertBinaryMask(dst) {
|
|
1969
|
-
const len = dst.length;
|
|
1970
|
-
for (let i = 0; i < len; i++) {
|
|
1971
|
-
dst[i] = dst[i] === 0 ? 1 : 0;
|
|
1972
|
-
}
|
|
1973
|
-
}
|
|
1974
|
-
function invertAlphaMask(dst) {
|
|
1975
|
-
const len = dst.length;
|
|
1976
|
-
for (let i = 0; i < len; i++) {
|
|
1977
|
-
dst[i] = 255 - dst[i];
|
|
1978
|
-
}
|
|
1979
|
-
}
|
|
1980
|
-
|
|
1981
|
-
// src/Mask/mergeMasks.ts
|
|
1982
|
-
function mergeMasks(dst, dstWidth, src, opts) {
|
|
1983
|
-
const {
|
|
1984
|
-
x: targetX = 0,
|
|
1985
|
-
y: targetY = 0,
|
|
1986
|
-
w: width = 0,
|
|
1987
|
-
h: height = 0,
|
|
1988
|
-
alpha: globalAlpha = 255,
|
|
1989
|
-
maskType = 0 /* ALPHA */,
|
|
1990
|
-
mw,
|
|
1991
|
-
mx = 0,
|
|
1992
|
-
my = 0,
|
|
1993
|
-
invertMask = false
|
|
1994
|
-
} = opts;
|
|
1995
|
-
if (width <= 0 || height <= 0 || globalAlpha === 0) {
|
|
1996
|
-
return;
|
|
1997
|
-
}
|
|
1998
|
-
const sPitch = mw ?? width;
|
|
1999
|
-
const isAlpha = maskType === 0 /* ALPHA */;
|
|
2000
|
-
for (let iy = 0; iy < height; iy++) {
|
|
2001
|
-
const dy = targetY + iy;
|
|
2002
|
-
const sy = my + iy;
|
|
2003
|
-
if (dy < 0 || sy < 0) {
|
|
2004
|
-
continue;
|
|
2005
|
-
}
|
|
2006
|
-
for (let ix = 0; ix < width; ix++) {
|
|
2007
|
-
const dx = targetX + ix;
|
|
2008
|
-
const sx = mx + ix;
|
|
2009
|
-
if (dx < 0 || dx >= dstWidth || sx < 0 || sx >= sPitch) {
|
|
2010
|
-
continue;
|
|
2011
|
-
}
|
|
2012
|
-
const dIdx = dy * dstWidth + dx;
|
|
2013
|
-
const sIdx = sy * sPitch + sx;
|
|
2014
|
-
const mVal = src[sIdx];
|
|
2015
|
-
let weight = globalAlpha;
|
|
2016
|
-
if (isAlpha) {
|
|
2017
|
-
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
2018
|
-
if (effectiveM === 0) {
|
|
2019
|
-
dst[dIdx] = 0;
|
|
2020
|
-
continue;
|
|
2021
|
-
}
|
|
2022
|
-
weight = globalAlpha === 255 ? effectiveM : effectiveM * globalAlpha + 128 >> 8;
|
|
2023
|
-
} else {
|
|
2024
|
-
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
2025
|
-
if (!isHit) {
|
|
2026
|
-
dst[dIdx] = 0;
|
|
2027
|
-
continue;
|
|
2028
|
-
}
|
|
2029
|
-
weight = globalAlpha;
|
|
2030
|
-
}
|
|
2031
|
-
if (weight === 0) {
|
|
2032
|
-
dst[dIdx] = 0;
|
|
2033
|
-
continue;
|
|
2034
|
-
}
|
|
2035
|
-
const da = dst[dIdx];
|
|
2036
|
-
if (da === 0) {
|
|
2037
|
-
} else if (weight === 255) {
|
|
2038
|
-
} else if (da === 255) {
|
|
2039
|
-
dst[dIdx] = weight;
|
|
2040
|
-
} else {
|
|
2041
|
-
dst[dIdx] = da * weight + 128 >> 8;
|
|
2042
|
-
}
|
|
2043
|
-
}
|
|
2044
|
-
}
|
|
2045
|
-
}
|
|
2046
|
-
|
|
2047
|
-
// src/PixelData/PixelData.ts
|
|
2048
|
-
var PixelData = class _PixelData {
|
|
2049
|
-
data32;
|
|
2050
|
-
imageData;
|
|
2051
|
-
get width() {
|
|
2052
|
-
return this.imageData.width;
|
|
2053
|
-
}
|
|
2054
|
-
get height() {
|
|
2055
|
-
return this.imageData.height;
|
|
2056
|
-
}
|
|
2057
|
-
constructor(imageData) {
|
|
2058
|
-
this.data32 = imageDataToUInt32Array(imageData);
|
|
2059
|
-
this.imageData = imageData;
|
|
2060
|
-
}
|
|
2061
|
-
set(imageData) {
|
|
2062
|
-
this.imageData = imageData;
|
|
2063
|
-
this.data32 = imageDataToUInt32Array(imageData);
|
|
2064
|
-
}
|
|
2065
|
-
/**
|
|
2066
|
-
* Creates a deep copy of the PixelData using the environment's ImageData constructor.
|
|
2067
|
-
*/
|
|
2068
|
-
copy() {
|
|
2069
|
-
const buffer = new Uint8ClampedArray(this.imageData.data);
|
|
2070
|
-
const ImageConstructor = typeof ImageData !== "undefined" ? ImageData : this.imageData.constructor;
|
|
2071
|
-
const newImageData = new ImageConstructor(
|
|
2072
|
-
buffer,
|
|
2073
|
-
this.width,
|
|
2074
|
-
this.height
|
|
2075
|
-
);
|
|
2076
|
-
return new _PixelData(newImageData);
|
|
2077
|
-
}
|
|
2078
|
-
};
|
|
2079
|
-
|
|
2080
|
-
// src/PixelData/applyMaskToPixelData.ts
|
|
2081
|
-
function applyMaskToPixelData(dst, mask, opts) {
|
|
2082
|
-
const {
|
|
2083
|
-
x: targetX = 0,
|
|
2084
|
-
y: targetY = 0,
|
|
2085
|
-
w: width = dst.width,
|
|
2086
|
-
h: height = dst.height,
|
|
2087
|
-
alpha: globalAlpha = 255,
|
|
2088
|
-
maskType = 0 /* ALPHA */,
|
|
2089
|
-
mw,
|
|
2090
|
-
mx = 0,
|
|
2091
|
-
my = 0,
|
|
2092
|
-
invertMask = false
|
|
2093
|
-
} = opts;
|
|
2094
|
-
let x = targetX;
|
|
2095
|
-
let y = targetY;
|
|
2096
|
-
let w = width;
|
|
2097
|
-
let h = height;
|
|
2098
|
-
if (x < 0) {
|
|
2099
|
-
w += x;
|
|
2100
|
-
x = 0;
|
|
2083
|
+
w = Math.min(w, src.width - sx);
|
|
2084
|
+
h = Math.min(h, src.height - sy);
|
|
2085
|
+
if (x < 0) {
|
|
2086
|
+
sx -= x;
|
|
2087
|
+
w += x;
|
|
2088
|
+
x = 0;
|
|
2101
2089
|
}
|
|
2102
2090
|
if (y < 0) {
|
|
2091
|
+
sy -= y;
|
|
2103
2092
|
h += y;
|
|
2104
2093
|
y = 0;
|
|
2105
2094
|
}
|
|
2106
2095
|
const actualW = Math.min(w, dst.width - x);
|
|
2107
2096
|
const actualH = Math.min(h, dst.height - y);
|
|
2108
|
-
if (actualW <= 0 || actualH <= 0
|
|
2109
|
-
return;
|
|
2110
|
-
}
|
|
2097
|
+
if (actualW <= 0 || actualH <= 0) return;
|
|
2111
2098
|
const dst32 = dst.data32;
|
|
2099
|
+
const src32 = src.data32;
|
|
2112
2100
|
const dw = dst.width;
|
|
2101
|
+
const sw = src.width;
|
|
2113
2102
|
const mPitch = mw ?? width;
|
|
2114
|
-
const
|
|
2103
|
+
const isAlphaMask = maskType === 0 /* ALPHA */;
|
|
2115
2104
|
const dx = x - targetX;
|
|
2116
2105
|
const dy = y - targetY;
|
|
2117
2106
|
let dIdx = y * dw + x;
|
|
2107
|
+
let sIdx = sy * sw + sx;
|
|
2118
2108
|
let mIdx = (my + dy) * mPitch + (mx + dx);
|
|
2119
2109
|
const dStride = dw - actualW;
|
|
2110
|
+
const sStride = sw - actualW;
|
|
2120
2111
|
const mStride = mPitch - actualW;
|
|
2112
|
+
const isOverwrite = blendFn.isOverwrite;
|
|
2121
2113
|
for (let iy = 0; iy < actualH; iy++) {
|
|
2122
2114
|
for (let ix = 0; ix < actualW; ix++) {
|
|
2123
|
-
const
|
|
2115
|
+
const baseSrcColor = src32[sIdx];
|
|
2116
|
+
const baseSrcAlpha = baseSrcColor >>> 24;
|
|
2117
|
+
if (baseSrcAlpha === 0 && !isOverwrite) {
|
|
2118
|
+
dIdx++;
|
|
2119
|
+
sIdx++;
|
|
2120
|
+
mIdx++;
|
|
2121
|
+
continue;
|
|
2122
|
+
}
|
|
2124
2123
|
let weight = globalAlpha;
|
|
2125
|
-
if (
|
|
2126
|
-
const
|
|
2127
|
-
if (
|
|
2128
|
-
|
|
2124
|
+
if (mask) {
|
|
2125
|
+
const mVal = mask[mIdx];
|
|
2126
|
+
if (isAlphaMask) {
|
|
2127
|
+
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
2128
|
+
if (effectiveM === 0) {
|
|
2129
|
+
dIdx++;
|
|
2130
|
+
sIdx++;
|
|
2131
|
+
mIdx++;
|
|
2132
|
+
continue;
|
|
2133
|
+
}
|
|
2134
|
+
if (globalAlpha === 255) {
|
|
2135
|
+
weight = effectiveM;
|
|
2136
|
+
} else if (effectiveM === 255) {
|
|
2137
|
+
weight = globalAlpha;
|
|
2138
|
+
} else {
|
|
2139
|
+
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
2140
|
+
}
|
|
2141
|
+
} else {
|
|
2142
|
+
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
2143
|
+
if (!isHit) {
|
|
2144
|
+
dIdx++;
|
|
2145
|
+
sIdx++;
|
|
2146
|
+
mIdx++;
|
|
2147
|
+
continue;
|
|
2148
|
+
}
|
|
2149
|
+
weight = globalAlpha;
|
|
2150
|
+
}
|
|
2151
|
+
if (weight === 0) {
|
|
2129
2152
|
dIdx++;
|
|
2153
|
+
sIdx++;
|
|
2130
2154
|
mIdx++;
|
|
2131
2155
|
continue;
|
|
2132
2156
|
}
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2157
|
+
}
|
|
2158
|
+
let currentSrcColor = baseSrcColor;
|
|
2159
|
+
if (weight < 255) {
|
|
2160
|
+
let currentSrcAlpha = baseSrcAlpha;
|
|
2161
|
+
if (baseSrcAlpha === 255) {
|
|
2162
|
+
currentSrcAlpha = weight;
|
|
2163
|
+
} else {
|
|
2164
|
+
currentSrcAlpha = baseSrcAlpha * weight + 128 >> 8;
|
|
2165
|
+
}
|
|
2166
|
+
if (!isOverwrite && currentSrcAlpha === 0) {
|
|
2138
2167
|
dIdx++;
|
|
2168
|
+
sIdx++;
|
|
2139
2169
|
mIdx++;
|
|
2140
2170
|
continue;
|
|
2141
2171
|
}
|
|
2142
|
-
|
|
2143
|
-
}
|
|
2144
|
-
if (weight === 0) {
|
|
2145
|
-
dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
|
|
2146
|
-
} else {
|
|
2147
|
-
const d = dst32[dIdx];
|
|
2148
|
-
const da = d >>> 24;
|
|
2149
|
-
let finalAlpha = da;
|
|
2150
|
-
if (da === 0) {
|
|
2151
|
-
} else if (weight === 255) {
|
|
2152
|
-
} else if (da === 255) {
|
|
2153
|
-
finalAlpha = weight;
|
|
2154
|
-
} else {
|
|
2155
|
-
finalAlpha = da * weight + 128 >> 8;
|
|
2156
|
-
}
|
|
2157
|
-
dst32[dIdx] = (d & 16777215 | finalAlpha << 24) >>> 0;
|
|
2172
|
+
currentSrcColor = (baseSrcColor & 16777215 | currentSrcAlpha << 24) >>> 0;
|
|
2158
2173
|
}
|
|
2174
|
+
dst32[dIdx] = blendFn(currentSrcColor, dst32[dIdx]);
|
|
2159
2175
|
dIdx++;
|
|
2176
|
+
sIdx++;
|
|
2160
2177
|
mIdx++;
|
|
2161
2178
|
}
|
|
2162
2179
|
dIdx += dStride;
|
|
2180
|
+
sIdx += sStride;
|
|
2163
2181
|
mIdx += mStride;
|
|
2164
2182
|
}
|
|
2165
2183
|
}
|
|
2166
2184
|
|
|
2167
|
-
// src/
|
|
2168
|
-
function
|
|
2185
|
+
// src/History/PixelMutator/mutatorBlendPixelData.ts
|
|
2186
|
+
function mutatorBlendPixelData(writer) {
|
|
2187
|
+
return {
|
|
2188
|
+
blendPixelData(src, opts) {
|
|
2189
|
+
const {
|
|
2190
|
+
x = 0,
|
|
2191
|
+
y = 0,
|
|
2192
|
+
w = src.width,
|
|
2193
|
+
h = src.height
|
|
2194
|
+
} = opts;
|
|
2195
|
+
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2196
|
+
blendPixelData(writer.target, src, opts);
|
|
2197
|
+
}
|
|
2198
|
+
};
|
|
2199
|
+
}
|
|
2200
|
+
|
|
2201
|
+
// src/PixelData/fillPixelData.ts
|
|
2202
|
+
function fillPixelData(dst, color, _x, _y, _w, _h) {
|
|
2203
|
+
let x;
|
|
2204
|
+
let y;
|
|
2205
|
+
let w;
|
|
2206
|
+
let h;
|
|
2207
|
+
if (typeof _x === "object") {
|
|
2208
|
+
x = _x.x ?? 0;
|
|
2209
|
+
y = _x.y ?? 0;
|
|
2210
|
+
w = _x.w ?? dst.width;
|
|
2211
|
+
h = _x.h ?? dst.height;
|
|
2212
|
+
} else if (typeof _x === "number") {
|
|
2213
|
+
x = _x;
|
|
2214
|
+
y = _y;
|
|
2215
|
+
w = _w;
|
|
2216
|
+
h = _h;
|
|
2217
|
+
} else {
|
|
2218
|
+
x = 0;
|
|
2219
|
+
y = 0;
|
|
2220
|
+
w = dst.width;
|
|
2221
|
+
h = dst.height;
|
|
2222
|
+
}
|
|
2223
|
+
if (x < 0) {
|
|
2224
|
+
w += x;
|
|
2225
|
+
x = 0;
|
|
2226
|
+
}
|
|
2227
|
+
if (y < 0) {
|
|
2228
|
+
h += y;
|
|
2229
|
+
y = 0;
|
|
2230
|
+
}
|
|
2231
|
+
const actualW = Math.min(w, dst.width - x);
|
|
2232
|
+
const actualH = Math.min(h, dst.height - y);
|
|
2233
|
+
if (actualW <= 0 || actualH <= 0) {
|
|
2234
|
+
return;
|
|
2235
|
+
}
|
|
2236
|
+
const dst32 = dst.data32;
|
|
2237
|
+
const dw = dst.width;
|
|
2238
|
+
if (actualW === dw && actualH === dst.height && x === 0 && y === 0) {
|
|
2239
|
+
dst32.fill(color);
|
|
2240
|
+
return;
|
|
2241
|
+
}
|
|
2242
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2243
|
+
const start = (y + iy) * dw + x;
|
|
2244
|
+
const end = start + actualW;
|
|
2245
|
+
dst32.fill(color, start, end);
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
|
|
2249
|
+
// src/History/PixelMutator/mutatorFillPixelData.ts
|
|
2250
|
+
function mutatorFill(writer) {
|
|
2251
|
+
return {
|
|
2252
|
+
fill(color, rect = {}) {
|
|
2253
|
+
const {
|
|
2254
|
+
x = 0,
|
|
2255
|
+
y = 0,
|
|
2256
|
+
w = writer.target.width,
|
|
2257
|
+
h = writer.target.height
|
|
2258
|
+
} = rect;
|
|
2259
|
+
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2260
|
+
fillPixelData(writer.target, color, x, y, w, h);
|
|
2261
|
+
}
|
|
2262
|
+
};
|
|
2263
|
+
}
|
|
2264
|
+
|
|
2265
|
+
// src/PixelData/invertPixelData.ts
|
|
2266
|
+
function invertPixelData(pixelData, opts = {}) {
|
|
2267
|
+
const dst = pixelData;
|
|
2169
2268
|
const {
|
|
2170
2269
|
x: targetX = 0,
|
|
2171
2270
|
y: targetY = 0,
|
|
2172
|
-
w: width =
|
|
2173
|
-
h: height =
|
|
2174
|
-
alpha: globalAlpha = 255,
|
|
2175
|
-
blendFn = sourceOverFast,
|
|
2271
|
+
w: width = pixelData.width,
|
|
2272
|
+
h: height = pixelData.height,
|
|
2176
2273
|
mask,
|
|
2177
|
-
maskType = 0 /* ALPHA */,
|
|
2178
2274
|
mw,
|
|
2179
2275
|
mx = 0,
|
|
2180
2276
|
my = 0,
|
|
2181
2277
|
invertMask = false
|
|
2182
2278
|
} = opts;
|
|
2183
|
-
if (globalAlpha === 0) return;
|
|
2184
|
-
const baseSrcAlpha = color >>> 24;
|
|
2185
|
-
const isOverwrite = blendFn.isOverwrite;
|
|
2186
|
-
if (baseSrcAlpha === 0 && !isOverwrite) return;
|
|
2187
2279
|
let x = targetX;
|
|
2188
2280
|
let y = targetY;
|
|
2189
2281
|
let w = width;
|
|
@@ -2202,255 +2294,798 @@ function blendColorPixelData(dst, color, opts = {}) {
|
|
|
2202
2294
|
const dst32 = dst.data32;
|
|
2203
2295
|
const dw = dst.width;
|
|
2204
2296
|
const mPitch = mw ?? width;
|
|
2205
|
-
const isAlphaMask = maskType === 0 /* ALPHA */;
|
|
2206
2297
|
const dx = x - targetX;
|
|
2207
2298
|
const dy = y - targetY;
|
|
2208
2299
|
let dIdx = y * dw + x;
|
|
2209
2300
|
let mIdx = (my + dy) * mPitch + (mx + dx);
|
|
2210
2301
|
const dStride = dw - actualW;
|
|
2211
2302
|
const mStride = mPitch - actualW;
|
|
2212
|
-
|
|
2213
|
-
for (let
|
|
2214
|
-
let
|
|
2215
|
-
if (mask) {
|
|
2303
|
+
if (mask) {
|
|
2304
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2305
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2216
2306
|
const mVal = mask[mIdx];
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
dIdx++;
|
|
2221
|
-
mIdx++;
|
|
2222
|
-
continue;
|
|
2223
|
-
}
|
|
2224
|
-
if (globalAlpha === 255) {
|
|
2225
|
-
weight = effectiveM;
|
|
2226
|
-
} else if (effectiveM === 255) {
|
|
2227
|
-
weight = globalAlpha;
|
|
2228
|
-
} else {
|
|
2229
|
-
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
2230
|
-
}
|
|
2231
|
-
} else {
|
|
2232
|
-
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
2233
|
-
if (!isHit) {
|
|
2234
|
-
dIdx++;
|
|
2235
|
-
mIdx++;
|
|
2236
|
-
continue;
|
|
2237
|
-
}
|
|
2238
|
-
weight = globalAlpha;
|
|
2239
|
-
}
|
|
2240
|
-
if (weight === 0) {
|
|
2241
|
-
dIdx++;
|
|
2242
|
-
mIdx++;
|
|
2243
|
-
continue;
|
|
2307
|
+
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
2308
|
+
if (isHit) {
|
|
2309
|
+
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
2244
2310
|
}
|
|
2311
|
+
dIdx++;
|
|
2312
|
+
mIdx++;
|
|
2245
2313
|
}
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
if (!isOverwrite && currentSrcAlpha === 0) {
|
|
2255
|
-
dIdx++;
|
|
2256
|
-
mIdx++;
|
|
2257
|
-
continue;
|
|
2258
|
-
}
|
|
2259
|
-
currentSrcColor = (color & 16777215 | currentSrcAlpha << 24) >>> 0;
|
|
2314
|
+
dIdx += dStride;
|
|
2315
|
+
mIdx += mStride;
|
|
2316
|
+
}
|
|
2317
|
+
} else {
|
|
2318
|
+
for (let iy = 0; iy < actualH; iy++) {
|
|
2319
|
+
for (let ix = 0; ix < actualW; ix++) {
|
|
2320
|
+
dst32[dIdx] = dst32[dIdx] ^ 16777215;
|
|
2321
|
+
dIdx++;
|
|
2260
2322
|
}
|
|
2261
|
-
|
|
2262
|
-
dIdx++;
|
|
2263
|
-
mIdx++;
|
|
2323
|
+
dIdx += dStride;
|
|
2264
2324
|
}
|
|
2265
|
-
dIdx += dStride;
|
|
2266
|
-
mIdx += mStride;
|
|
2267
2325
|
}
|
|
2268
2326
|
}
|
|
2269
2327
|
|
|
2270
|
-
// src/
|
|
2271
|
-
function
|
|
2328
|
+
// src/History/PixelMutator/mutatorInvert.ts
|
|
2329
|
+
function mutatorInvert(writer) {
|
|
2330
|
+
return {
|
|
2331
|
+
invert(opts = {}) {
|
|
2332
|
+
const {
|
|
2333
|
+
x = 0,
|
|
2334
|
+
y = 0,
|
|
2335
|
+
w = writer.target.width,
|
|
2336
|
+
h = writer.target.height
|
|
2337
|
+
} = opts;
|
|
2338
|
+
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2339
|
+
invertPixelData(writer.target, opts);
|
|
2340
|
+
}
|
|
2341
|
+
};
|
|
2342
|
+
}
|
|
2343
|
+
|
|
2344
|
+
// src/History/PixelMutator.ts
|
|
2345
|
+
function makeFullPixelMutator(writer) {
|
|
2346
|
+
return {
|
|
2347
|
+
...mutatorApplyMask(writer),
|
|
2348
|
+
...mutatorBlendPixelData(writer),
|
|
2349
|
+
...mutatorBlendColor(writer),
|
|
2350
|
+
...mutatorBlendPixel(writer),
|
|
2351
|
+
...mutatorFill(writer),
|
|
2352
|
+
...mutatorInvert(writer)
|
|
2353
|
+
};
|
|
2354
|
+
}
|
|
2355
|
+
|
|
2356
|
+
// src/ImageData/ReusableImageData.ts
|
|
2357
|
+
function makeReusableImageData() {
|
|
2358
|
+
let imageData = null;
|
|
2359
|
+
let buffer = null;
|
|
2360
|
+
return function getReusableImageData(width, height) {
|
|
2361
|
+
const hasInstance = !!imageData;
|
|
2362
|
+
const widthMatches = hasInstance && imageData.width === width;
|
|
2363
|
+
const heightMatches = hasInstance && imageData.height === height;
|
|
2364
|
+
if (!widthMatches || !heightMatches) {
|
|
2365
|
+
const buffer2 = new Uint8ClampedArray(width * height * 4);
|
|
2366
|
+
imageData = new ImageData(buffer2, width, height);
|
|
2367
|
+
}
|
|
2368
|
+
return imageData;
|
|
2369
|
+
};
|
|
2370
|
+
}
|
|
2371
|
+
|
|
2372
|
+
// src/ImageData/copyImageData.ts
|
|
2373
|
+
function copyImageData({ data, width, height }) {
|
|
2374
|
+
return new ImageData(data.slice(), width, height);
|
|
2375
|
+
}
|
|
2376
|
+
function copyImageDataLike({ data, width, height }) {
|
|
2377
|
+
return {
|
|
2378
|
+
data: data.slice(),
|
|
2379
|
+
width,
|
|
2380
|
+
height
|
|
2381
|
+
};
|
|
2382
|
+
}
|
|
2383
|
+
|
|
2384
|
+
// src/PixelData/pixelDataToAlphaMask.ts
|
|
2385
|
+
function pixelDataToAlphaMask(pixelData) {
|
|
2272
2386
|
const {
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2387
|
+
data32,
|
|
2388
|
+
width,
|
|
2389
|
+
height
|
|
2390
|
+
} = pixelData;
|
|
2391
|
+
const len = data32.length;
|
|
2392
|
+
const mask = new Uint8Array(width * height);
|
|
2393
|
+
for (let i = 0; i < len; i++) {
|
|
2394
|
+
const val = data32[i];
|
|
2395
|
+
mask[i] = val >>> 24 & 255;
|
|
2396
|
+
}
|
|
2397
|
+
return mask;
|
|
2398
|
+
}
|
|
2399
|
+
|
|
2400
|
+
// src/ImageData/imageDataToAlphaMask.ts
|
|
2401
|
+
function imageDataToAlphaMask(imageData) {
|
|
2402
|
+
const {
|
|
2403
|
+
width,
|
|
2404
|
+
height,
|
|
2405
|
+
data
|
|
2406
|
+
} = imageData;
|
|
2407
|
+
const data32 = new Uint32Array(
|
|
2408
|
+
data.buffer,
|
|
2409
|
+
data.byteOffset,
|
|
2410
|
+
data.byteLength >> 2
|
|
2411
|
+
);
|
|
2412
|
+
const len = data32.length;
|
|
2413
|
+
const mask = new Uint8Array(width * height);
|
|
2414
|
+
for (let i = 0; i < len; i++) {
|
|
2415
|
+
const val = data32[i];
|
|
2416
|
+
mask[i] = val >>> 24 & 255;
|
|
2417
|
+
}
|
|
2418
|
+
return mask;
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
// src/ImageData/imageDataToDataUrl.ts
|
|
2422
|
+
var get = makeReusableCanvas();
|
|
2423
|
+
function imageDataToDataUrl(imageData) {
|
|
2424
|
+
const { canvas, ctx } = get(imageData.width, imageData.height);
|
|
2425
|
+
ctx.putImageData(imageData, 0, 0);
|
|
2426
|
+
return canvas.toDataURL();
|
|
2427
|
+
}
|
|
2428
|
+
imageDataToDataUrl.reset = get.reset;
|
|
2429
|
+
|
|
2430
|
+
// src/ImageData/imageDataToUInt32Array.ts
|
|
2431
|
+
function imageDataToUInt32Array(imageData) {
|
|
2432
|
+
return new Uint32Array(
|
|
2433
|
+
imageData.data.buffer,
|
|
2434
|
+
imageData.data.byteOffset,
|
|
2435
|
+
// Shift right by 2 is a fast bitwise division by 4.
|
|
2436
|
+
imageData.data.byteLength >> 2
|
|
2437
|
+
);
|
|
2438
|
+
}
|
|
2439
|
+
|
|
2440
|
+
// src/ImageData/invertImageData.ts
|
|
2441
|
+
function invertImageData(imageData) {
|
|
2442
|
+
const data = imageData.data;
|
|
2443
|
+
let length = data.length;
|
|
2444
|
+
for (let i = 0; i < length; i += 4) {
|
|
2445
|
+
data[i] = 255 - data[i];
|
|
2446
|
+
data[i + 1] = 255 - data[i + 1];
|
|
2447
|
+
data[i + 2] = 255 - data[i + 2];
|
|
2448
|
+
}
|
|
2449
|
+
return imageData;
|
|
2450
|
+
}
|
|
2451
|
+
|
|
2452
|
+
// src/Internal/resample32.ts
|
|
2453
|
+
var resample32Scratch = {
|
|
2454
|
+
data: null,
|
|
2455
|
+
width: 0,
|
|
2456
|
+
height: 0
|
|
2457
|
+
};
|
|
2458
|
+
function resample32(srcData32, srcW, srcH, factor) {
|
|
2459
|
+
const dstW = Math.max(1, srcW * factor | 0);
|
|
2460
|
+
const dstH = Math.max(1, srcH * factor | 0);
|
|
2461
|
+
const dstData = new Int32Array(dstW * dstH);
|
|
2462
|
+
const scaleX = srcW / dstW;
|
|
2463
|
+
const scaleY = srcH / dstH;
|
|
2464
|
+
for (let y = 0; y < dstH; y++) {
|
|
2465
|
+
const srcY = Math.min(srcH - 1, y * scaleY | 0);
|
|
2466
|
+
const srcRowOffset = srcY * srcW;
|
|
2467
|
+
const dstRowOffset = y * dstW;
|
|
2468
|
+
for (let x = 0; x < dstW; x++) {
|
|
2469
|
+
const srcX = Math.min(srcW - 1, x * scaleX | 0);
|
|
2470
|
+
dstData[dstRowOffset + x] = srcData32[srcRowOffset + srcX];
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
resample32Scratch.data = dstData;
|
|
2474
|
+
resample32Scratch.width = dstW;
|
|
2475
|
+
resample32Scratch.height = dstH;
|
|
2476
|
+
return resample32Scratch;
|
|
2477
|
+
}
|
|
2478
|
+
|
|
2479
|
+
// src/ImageData/resampleImageData.ts
|
|
2480
|
+
function resampleImageData(source, factor) {
|
|
2481
|
+
const src32 = new Uint32Array(source.data.buffer);
|
|
2482
|
+
const { data, width, height } = resample32(src32, source.width, source.height, factor);
|
|
2483
|
+
const uint8ClampedArray = new Uint8ClampedArray(data.buffer);
|
|
2484
|
+
return new ImageData(uint8ClampedArray, width, height);
|
|
2485
|
+
}
|
|
2486
|
+
|
|
2487
|
+
// src/ImageData/resizeImageData.ts
|
|
2488
|
+
function resizeImageData(current, newWidth, newHeight, offsetX = 0, offsetY = 0) {
|
|
2489
|
+
const result = new ImageData(newWidth, newHeight);
|
|
2490
|
+
const {
|
|
2491
|
+
width: oldW,
|
|
2492
|
+
height: oldH,
|
|
2493
|
+
data: oldData
|
|
2494
|
+
} = current;
|
|
2495
|
+
const newData = result.data;
|
|
2496
|
+
const x0 = Math.max(0, offsetX);
|
|
2497
|
+
const y0 = Math.max(0, offsetY);
|
|
2498
|
+
const x1 = Math.min(newWidth, offsetX + oldW);
|
|
2499
|
+
const y1 = Math.min(newHeight, offsetY + oldH);
|
|
2500
|
+
if (x1 <= x0 || y1 <= y0) {
|
|
2501
|
+
return result;
|
|
2502
|
+
}
|
|
2503
|
+
const rowCount = y1 - y0;
|
|
2504
|
+
const rowLen = (x1 - x0) * 4;
|
|
2505
|
+
for (let row = 0; row < rowCount; row++) {
|
|
2506
|
+
const dstY = y0 + row;
|
|
2507
|
+
const srcY = dstY - offsetY;
|
|
2508
|
+
const srcX = x0 - offsetX;
|
|
2509
|
+
const dstStart = (dstY * newWidth + x0) * 4;
|
|
2510
|
+
const srcStart = (srcY * oldW + srcX) * 4;
|
|
2511
|
+
newData.set(
|
|
2512
|
+
oldData.subarray(srcStart, srcStart + rowLen),
|
|
2513
|
+
dstStart
|
|
2514
|
+
);
|
|
2515
|
+
}
|
|
2516
|
+
return result;
|
|
2517
|
+
}
|
|
2518
|
+
|
|
2519
|
+
// src/ImageData/serialization.ts
|
|
2520
|
+
function base64EncodeArrayBuffer(buffer) {
|
|
2521
|
+
const uint8 = new Uint8Array(buffer);
|
|
2522
|
+
const decoder = new TextDecoder("latin1");
|
|
2523
|
+
const binary = decoder.decode(uint8);
|
|
2524
|
+
return btoa(binary);
|
|
2525
|
+
}
|
|
2526
|
+
function base64DecodeArrayBuffer(encoded) {
|
|
2527
|
+
const binary = atob(encoded);
|
|
2528
|
+
const bytes = new Uint8ClampedArray(binary.length);
|
|
2529
|
+
for (let i = 0; i < binary.length; i++) {
|
|
2530
|
+
bytes[i] = binary.charCodeAt(i);
|
|
2531
|
+
}
|
|
2532
|
+
return bytes;
|
|
2533
|
+
}
|
|
2534
|
+
function serializeImageData(imageData) {
|
|
2535
|
+
return {
|
|
2536
|
+
width: imageData.width,
|
|
2537
|
+
height: imageData.height,
|
|
2538
|
+
data: base64EncodeArrayBuffer(imageData.data.buffer)
|
|
2539
|
+
};
|
|
2540
|
+
}
|
|
2541
|
+
function serializeNullableImageData(imageData) {
|
|
2542
|
+
if (!imageData) return null;
|
|
2543
|
+
return serializeImageData(imageData);
|
|
2544
|
+
}
|
|
2545
|
+
function deserializeRawImageData(serialized) {
|
|
2546
|
+
return {
|
|
2547
|
+
width: serialized.width,
|
|
2548
|
+
height: serialized.height,
|
|
2549
|
+
data: base64DecodeArrayBuffer(serialized.data)
|
|
2550
|
+
};
|
|
2551
|
+
}
|
|
2552
|
+
function deserializeImageData(serialized) {
|
|
2553
|
+
const data = base64DecodeArrayBuffer(serialized.data);
|
|
2554
|
+
return new ImageData(data, serialized.width, serialized.height);
|
|
2555
|
+
}
|
|
2556
|
+
function deserializeNullableImageData(serialized) {
|
|
2557
|
+
if (!serialized) return null;
|
|
2558
|
+
return deserializeImageData(serialized);
|
|
2559
|
+
}
|
|
2560
|
+
|
|
2561
|
+
// src/ImageData/writeImageData.ts
|
|
2562
|
+
function writeImageData(target, source, x, y, sx = 0, sy = 0, sw = source.width, sh = source.height, mask = null, maskType = 1 /* BINARY */) {
|
|
2563
|
+
const dstW = target.width;
|
|
2564
|
+
const dstH = target.height;
|
|
2565
|
+
const dstData = target.data;
|
|
2566
|
+
const srcW = source.width;
|
|
2567
|
+
const srcData = source.data;
|
|
2568
|
+
const x0 = Math.max(0, x);
|
|
2569
|
+
const y0 = Math.max(0, y);
|
|
2570
|
+
const x1 = Math.min(dstW, x + sw);
|
|
2571
|
+
const y1 = Math.min(dstH, y + sh);
|
|
2572
|
+
if (x1 <= x0 || y1 <= y0) {
|
|
2573
|
+
return;
|
|
2574
|
+
}
|
|
2575
|
+
const useMask = !!mask;
|
|
2576
|
+
const rowCount = y1 - y0;
|
|
2577
|
+
const rowLenPixels = x1 - x0;
|
|
2578
|
+
for (let row = 0; row < rowCount; row++) {
|
|
2579
|
+
const dstY = y0 + row;
|
|
2580
|
+
const srcY = sy + (dstY - y);
|
|
2581
|
+
const srcXBase = sx + (x0 - x);
|
|
2582
|
+
const dstStart = (dstY * dstW + x0) * 4;
|
|
2583
|
+
const srcStart = (srcY * srcW + srcXBase) * 4;
|
|
2584
|
+
if (useMask && mask) {
|
|
2585
|
+
for (let ix = 0; ix < rowLenPixels; ix++) {
|
|
2586
|
+
const mi = srcY * srcW + (srcXBase + ix);
|
|
2587
|
+
const alpha = mask[mi];
|
|
2588
|
+
if (alpha === 0) {
|
|
2589
|
+
continue;
|
|
2590
|
+
}
|
|
2591
|
+
const di = dstStart + ix * 4;
|
|
2592
|
+
const si = srcStart + ix * 4;
|
|
2593
|
+
if (maskType === 1 /* BINARY */ || alpha === 255) {
|
|
2594
|
+
dstData[di] = srcData[si];
|
|
2595
|
+
dstData[di + 1] = srcData[si + 1];
|
|
2596
|
+
dstData[di + 2] = srcData[si + 2];
|
|
2597
|
+
dstData[di + 3] = srcData[si + 3];
|
|
2598
|
+
} else {
|
|
2599
|
+
const a = alpha / 255;
|
|
2600
|
+
const invA = 1 - a;
|
|
2601
|
+
dstData[di] = srcData[si] * a + dstData[di] * invA;
|
|
2602
|
+
dstData[di + 1] = srcData[si + 1] * a + dstData[di + 1] * invA;
|
|
2603
|
+
dstData[di + 2] = srcData[si + 2] * a + dstData[di + 2] * invA;
|
|
2604
|
+
dstData[di + 3] = srcData[si + 3] * a + dstData[di + 3] * invA;
|
|
2605
|
+
}
|
|
2606
|
+
}
|
|
2607
|
+
} else {
|
|
2608
|
+
const byteLen = rowLenPixels * 4;
|
|
2609
|
+
const sub = srcData.subarray(srcStart, srcStart + byteLen);
|
|
2610
|
+
dstData.set(sub, dstStart);
|
|
2611
|
+
}
|
|
2612
|
+
}
|
|
2613
|
+
}
|
|
2614
|
+
|
|
2615
|
+
// src/ImageData/writeImageDataBuffer.ts
|
|
2616
|
+
function writeImageDataBuffer(imageData, data, _x, _y, _w, _h) {
|
|
2617
|
+
const { x, y, w, h } = typeof _x === "object" ? _x : { x: _x, y: _y, w: _w, h: _h };
|
|
2618
|
+
const { width: dstW, height: dstH, data: dst } = imageData;
|
|
2619
|
+
const x0 = Math.max(0, x);
|
|
2620
|
+
const y0 = Math.max(0, y);
|
|
2621
|
+
const x1 = Math.min(dstW, x + w);
|
|
2622
|
+
const y1 = Math.min(dstH, y + h);
|
|
2623
|
+
if (x1 <= x0 || y1 <= y0) return;
|
|
2624
|
+
const rowLen = (x1 - x0) * 4;
|
|
2625
|
+
const srcCol = x0 - x;
|
|
2626
|
+
const srcYOffset = y0 - y;
|
|
2627
|
+
const actualH = y1 - y0;
|
|
2628
|
+
for (let row = 0; row < actualH; row++) {
|
|
2629
|
+
const dstStart = ((y0 + row) * dstW + x0) * 4;
|
|
2630
|
+
const srcRow = srcYOffset + row;
|
|
2631
|
+
const o = (srcRow * w + srcCol) * 4;
|
|
2632
|
+
dst.set(data.subarray(o, o + rowLen), dstStart);
|
|
2633
|
+
}
|
|
2634
|
+
}
|
|
2635
|
+
|
|
2636
|
+
// src/IndexedImage/IndexedImage.ts
|
|
2637
|
+
var IndexedImage = class _IndexedImage {
|
|
2638
|
+
/** The width of the image in pixels. */
|
|
2639
|
+
width;
|
|
2640
|
+
/** The height of the image in pixels. */
|
|
2641
|
+
height;
|
|
2642
|
+
/** Flat array of palette indices. Index = x + (y * width). */
|
|
2643
|
+
data;
|
|
2644
|
+
/** The palette of unique 32-bit colors (ABGR/RGBA packed) found in the image. */
|
|
2645
|
+
palette;
|
|
2646
|
+
/** The specific index in the palette reserved for fully transparent pixels. */
|
|
2647
|
+
transparentPalletIndex;
|
|
2648
|
+
/**
|
|
2649
|
+
* @param width - Image width.
|
|
2650
|
+
* @param height - Image height.
|
|
2651
|
+
* @param data - The indexed pixel data.
|
|
2652
|
+
* @param palette - The array of packed colors.
|
|
2653
|
+
* @param transparentPalletIndex - The index representing alpha 0.
|
|
2654
|
+
*/
|
|
2655
|
+
constructor(width, height, data, palette, transparentPalletIndex) {
|
|
2656
|
+
this.width = width;
|
|
2657
|
+
this.height = height;
|
|
2658
|
+
this.data = data;
|
|
2659
|
+
this.palette = palette;
|
|
2660
|
+
this.transparentPalletIndex = transparentPalletIndex;
|
|
2661
|
+
}
|
|
2662
|
+
/**
|
|
2663
|
+
* Creates an IndexedImage from standard browser ImageData.
|
|
2664
|
+
* @param imageData - The source ImageData to convert.
|
|
2665
|
+
* @returns A new IndexedImage instance.
|
|
2666
|
+
*/
|
|
2667
|
+
static fromImageData(imageData) {
|
|
2668
|
+
return _IndexedImage.fromRaw(imageData.data, imageData.width, imageData.height);
|
|
2669
|
+
}
|
|
2670
|
+
/**
|
|
2671
|
+
* Creates an IndexedImage from a raw byte buffer and dimensions.
|
|
2672
|
+
* Any pixel with an alpha channel of 0 is normalized to the transparent palette index.
|
|
2673
|
+
* @param data - Raw RGBA byte data.
|
|
2674
|
+
* @param width - Image width.
|
|
2675
|
+
* @param height - Image height.
|
|
2676
|
+
* @returns A new IndexedImage instance.
|
|
2677
|
+
*/
|
|
2678
|
+
static fromRaw(data, width, height) {
|
|
2679
|
+
const buffer = data.buffer;
|
|
2680
|
+
const rawData = new Uint32Array(buffer);
|
|
2681
|
+
const indexedData = new Int32Array(rawData.length);
|
|
2682
|
+
const colorMap = /* @__PURE__ */ new Map();
|
|
2683
|
+
const transparentColor = 0;
|
|
2684
|
+
const transparentPalletIndex = 0;
|
|
2685
|
+
colorMap.set(transparentColor, transparentPalletIndex);
|
|
2686
|
+
for (let i = 0; i < rawData.length; i++) {
|
|
2687
|
+
const pixel = rawData[i];
|
|
2688
|
+
const alpha = pixel >>> 24 & 255;
|
|
2689
|
+
const isTransparent = alpha === 0;
|
|
2690
|
+
const colorKey = isTransparent ? transparentColor : pixel >>> 0;
|
|
2691
|
+
let id = colorMap.get(colorKey);
|
|
2692
|
+
if (id === void 0) {
|
|
2693
|
+
id = colorMap.size;
|
|
2694
|
+
colorMap.set(colorKey, id);
|
|
2695
|
+
}
|
|
2696
|
+
indexedData[i] = id;
|
|
2697
|
+
}
|
|
2698
|
+
const palette = Uint32Array.from(colorMap.keys());
|
|
2699
|
+
return new _IndexedImage(
|
|
2700
|
+
width,
|
|
2701
|
+
height,
|
|
2702
|
+
indexedData,
|
|
2703
|
+
palette,
|
|
2704
|
+
transparentPalletIndex
|
|
2705
|
+
);
|
|
2706
|
+
}
|
|
2707
|
+
/**
|
|
2708
|
+
* Retrieves the 32-bit packed color value at the given coordinates.
|
|
2709
|
+
* @param x - X coordinate.
|
|
2710
|
+
* @param y - Y coordinate.
|
|
2711
|
+
* @returns The packed color from the palette.
|
|
2712
|
+
*/
|
|
2713
|
+
getColorAt(x, y) {
|
|
2714
|
+
const index = x + y * this.width;
|
|
2715
|
+
const paletteIndex = this.data[index];
|
|
2716
|
+
return this.palette[paletteIndex];
|
|
2717
|
+
}
|
|
2718
|
+
};
|
|
2719
|
+
|
|
2720
|
+
// src/IndexedImage/getIndexedImageColorCounts.ts
|
|
2721
|
+
function getIndexedImageColorCounts(indexedImage) {
|
|
2722
|
+
const data = indexedImage.data;
|
|
2723
|
+
const palette = indexedImage.palette;
|
|
2724
|
+
const frequencies = new Int32Array(palette.length);
|
|
2725
|
+
for (let i = 0; i < data.length; i++) {
|
|
2726
|
+
const colorIndex = data[i];
|
|
2727
|
+
frequencies[colorIndex]++;
|
|
2728
|
+
}
|
|
2729
|
+
return frequencies;
|
|
2730
|
+
}
|
|
2731
|
+
|
|
2732
|
+
// src/IndexedImage/indexedImageToAverageColor.ts
|
|
2733
|
+
function indexedImageToAverageColor(indexedImage, includeTransparent = false) {
|
|
2734
|
+
const { data, palette, transparentPalletIndex } = indexedImage;
|
|
2735
|
+
const counts = new Uint32Array(palette.length);
|
|
2736
|
+
for (let i = 0; i < data.length; i++) {
|
|
2737
|
+
const id = data[i];
|
|
2738
|
+
counts[id]++;
|
|
2739
|
+
}
|
|
2740
|
+
let rSum = 0;
|
|
2741
|
+
let gSum = 0;
|
|
2742
|
+
let bSum = 0;
|
|
2743
|
+
let aSum = 0;
|
|
2744
|
+
let totalWeight = 0;
|
|
2745
|
+
for (let id = 0; id < counts.length; id++) {
|
|
2746
|
+
const weight = counts[id];
|
|
2747
|
+
if (weight === 0) {
|
|
2748
|
+
continue;
|
|
2749
|
+
}
|
|
2750
|
+
if (!includeTransparent && id === transparentPalletIndex) {
|
|
2751
|
+
continue;
|
|
2752
|
+
}
|
|
2753
|
+
const color = palette[id] >>> 0;
|
|
2754
|
+
const r2 = color & 255;
|
|
2755
|
+
const g2 = color >> 8 & 255;
|
|
2756
|
+
const b2 = color >> 16 & 255;
|
|
2757
|
+
const a2 = color >> 24 & 255;
|
|
2758
|
+
rSum += r2 * weight;
|
|
2759
|
+
gSum += g2 * weight;
|
|
2760
|
+
bSum += b2 * weight;
|
|
2761
|
+
aSum += a2 * weight;
|
|
2762
|
+
totalWeight += weight;
|
|
2763
|
+
}
|
|
2764
|
+
if (totalWeight === 0) {
|
|
2765
|
+
return packColor(0, 0, 0, 0);
|
|
2766
|
+
}
|
|
2767
|
+
const r = rSum / totalWeight | 0;
|
|
2768
|
+
const g = gSum / totalWeight | 0;
|
|
2769
|
+
const b = bSum / totalWeight | 0;
|
|
2770
|
+
const a = aSum / totalWeight | 0;
|
|
2771
|
+
return packColor(r, g, b, a);
|
|
2772
|
+
}
|
|
2773
|
+
|
|
2774
|
+
// src/IndexedImage/resampleIndexedImage.ts
|
|
2775
|
+
function resampleIndexedImage(source, factor) {
|
|
2776
|
+
const { data, width, height } = resample32(
|
|
2777
|
+
source.data,
|
|
2778
|
+
source.width,
|
|
2779
|
+
source.height,
|
|
2780
|
+
factor
|
|
2781
|
+
);
|
|
2782
|
+
return new IndexedImage(
|
|
2783
|
+
width,
|
|
2784
|
+
height,
|
|
2785
|
+
data,
|
|
2786
|
+
source.palette,
|
|
2787
|
+
source.transparentPalletIndex
|
|
2788
|
+
);
|
|
2789
|
+
}
|
|
2790
|
+
|
|
2791
|
+
// src/IndexedImage/indexedImageToImageData.ts
|
|
2792
|
+
function indexedImageToImageData(indexedImage) {
|
|
2793
|
+
const { width, height, data, palette } = indexedImage;
|
|
2794
|
+
const result = new ImageData(width, height);
|
|
2795
|
+
const data32 = new Uint32Array(result.data.buffer);
|
|
2796
|
+
for (let i = 0; i < data.length; i++) {
|
|
2797
|
+
const paletteIndex = data[i];
|
|
2798
|
+
const color = palette[paletteIndex];
|
|
2799
|
+
data32[i] = color;
|
|
2800
|
+
}
|
|
2801
|
+
return result;
|
|
2802
|
+
}
|
|
2803
|
+
|
|
2804
|
+
// src/Input/fileInputChangeToImageData.ts
|
|
2805
|
+
async function fileInputChangeToImageData(event) {
|
|
2806
|
+
const target = event.target;
|
|
2807
|
+
const file = target.files?.[0];
|
|
2808
|
+
if (!file) return null;
|
|
2809
|
+
return await fileToImageData(file);
|
|
2810
|
+
}
|
|
2811
|
+
|
|
2812
|
+
// src/Input/fileToImageData.ts
|
|
2813
|
+
var UnsupportedFormatError = class extends Error {
|
|
2814
|
+
constructor(mimeType) {
|
|
2815
|
+
super(`File type ${mimeType} is not a supported image format.`);
|
|
2816
|
+
this.name = "UnsupportedFormatError";
|
|
2817
|
+
}
|
|
2818
|
+
};
|
|
2819
|
+
async function fileToImageData(file) {
|
|
2820
|
+
if (!file) return null;
|
|
2821
|
+
if (!file.type.startsWith("image/")) {
|
|
2822
|
+
throw new UnsupportedFormatError(file.type);
|
|
2823
|
+
}
|
|
2824
|
+
let bitmap = null;
|
|
2825
|
+
try {
|
|
2826
|
+
bitmap = await createImageBitmap(file);
|
|
2827
|
+
const canvas = new OffscreenCanvas(
|
|
2828
|
+
bitmap.width,
|
|
2829
|
+
bitmap.height
|
|
2830
|
+
);
|
|
2831
|
+
const ctx = canvas.getContext("2d");
|
|
2832
|
+
if (!ctx) throw new Error(OFFSCREEN_CANVAS_CTX_FAILED);
|
|
2833
|
+
ctx.drawImage(
|
|
2834
|
+
bitmap,
|
|
2835
|
+
0,
|
|
2836
|
+
0
|
|
2837
|
+
);
|
|
2838
|
+
return ctx.getImageData(
|
|
2839
|
+
0,
|
|
2840
|
+
0,
|
|
2841
|
+
bitmap.width,
|
|
2842
|
+
bitmap.height
|
|
2843
|
+
);
|
|
2844
|
+
} finally {
|
|
2845
|
+
bitmap?.close();
|
|
2846
|
+
}
|
|
2847
|
+
}
|
|
2848
|
+
|
|
2849
|
+
// src/Input/getSupportedRasterFormats.ts
|
|
2850
|
+
var formatsPromise = null;
|
|
2851
|
+
var defaultRasterMimes = [
|
|
2852
|
+
"image/png",
|
|
2853
|
+
"image/jpeg",
|
|
2854
|
+
"image/webp",
|
|
2855
|
+
"image/avif",
|
|
2856
|
+
"image/gif",
|
|
2857
|
+
"image/bmp"
|
|
2858
|
+
];
|
|
2859
|
+
async function getSupportedPixelFormats(rasterMimes = defaultRasterMimes) {
|
|
2860
|
+
if (formatsPromise) {
|
|
2861
|
+
return formatsPromise;
|
|
2862
|
+
}
|
|
2863
|
+
const probeCanvas = async () => {
|
|
2864
|
+
const canvas = new OffscreenCanvas(1, 1);
|
|
2865
|
+
const results = await Promise.all(
|
|
2866
|
+
rasterMimes.map(async (mime) => {
|
|
2867
|
+
try {
|
|
2868
|
+
const blob = await canvas.convertToBlob({
|
|
2869
|
+
type: mime
|
|
2870
|
+
});
|
|
2871
|
+
return blob.type === mime ? mime : null;
|
|
2872
|
+
} catch {
|
|
2873
|
+
return null;
|
|
2874
|
+
}
|
|
2875
|
+
})
|
|
2876
|
+
);
|
|
2877
|
+
return results.filter((type) => {
|
|
2878
|
+
return type !== null;
|
|
2879
|
+
});
|
|
2880
|
+
};
|
|
2881
|
+
formatsPromise = probeCanvas().catch((error) => {
|
|
2882
|
+
formatsPromise = null;
|
|
2883
|
+
throw error;
|
|
2884
|
+
});
|
|
2885
|
+
return formatsPromise;
|
|
2886
|
+
}
|
|
2887
|
+
|
|
2888
|
+
// src/Mask/copyMask.ts
|
|
2889
|
+
function copyMask(src) {
|
|
2890
|
+
return src.slice();
|
|
2891
|
+
}
|
|
2892
|
+
|
|
2893
|
+
// src/Mask/invertMask.ts
|
|
2894
|
+
function invertBinaryMask(dst) {
|
|
2895
|
+
const len = dst.length;
|
|
2896
|
+
for (let i = 0; i < len; i++) {
|
|
2897
|
+
dst[i] = dst[i] === 0 ? 1 : 0;
|
|
2898
|
+
}
|
|
2899
|
+
}
|
|
2900
|
+
function invertAlphaMask(dst) {
|
|
2901
|
+
const len = dst.length;
|
|
2902
|
+
for (let i = 0; i < len; i++) {
|
|
2903
|
+
dst[i] = 255 - dst[i];
|
|
2904
|
+
}
|
|
2905
|
+
}
|
|
2906
|
+
|
|
2907
|
+
// src/Mask/mergeMasks.ts
|
|
2908
|
+
function mergeMasks(dst, dstWidth, src, opts) {
|
|
2909
|
+
const {
|
|
2910
|
+
x: targetX = 0,
|
|
2911
|
+
y: targetY = 0,
|
|
2912
|
+
w: width = 0,
|
|
2913
|
+
h: height = 0,
|
|
2279
2914
|
alpha: globalAlpha = 255,
|
|
2280
|
-
blendFn = FAST_BLEND_MODES[1 /* sourceOver */],
|
|
2281
|
-
mask,
|
|
2282
2915
|
maskType = 0 /* ALPHA */,
|
|
2283
2916
|
mw,
|
|
2284
2917
|
mx = 0,
|
|
2285
2918
|
my = 0,
|
|
2286
2919
|
invertMask = false
|
|
2287
2920
|
} = opts;
|
|
2288
|
-
if (globalAlpha === 0)
|
|
2289
|
-
|
|
2290
|
-
let y = targetY;
|
|
2291
|
-
let sx = sourceX;
|
|
2292
|
-
let sy = sourceY;
|
|
2293
|
-
let w = width;
|
|
2294
|
-
let h = height;
|
|
2295
|
-
if (sx < 0) {
|
|
2296
|
-
x -= sx;
|
|
2297
|
-
w += sx;
|
|
2298
|
-
sx = 0;
|
|
2299
|
-
}
|
|
2300
|
-
if (sy < 0) {
|
|
2301
|
-
y -= sy;
|
|
2302
|
-
h += sy;
|
|
2303
|
-
sy = 0;
|
|
2304
|
-
}
|
|
2305
|
-
w = Math.min(w, src.width - sx);
|
|
2306
|
-
h = Math.min(h, src.height - sy);
|
|
2307
|
-
if (x < 0) {
|
|
2308
|
-
sx -= x;
|
|
2309
|
-
w += x;
|
|
2310
|
-
x = 0;
|
|
2311
|
-
}
|
|
2312
|
-
if (y < 0) {
|
|
2313
|
-
sy -= y;
|
|
2314
|
-
h += y;
|
|
2315
|
-
y = 0;
|
|
2921
|
+
if (width <= 0 || height <= 0 || globalAlpha === 0) {
|
|
2922
|
+
return;
|
|
2316
2923
|
}
|
|
2317
|
-
const
|
|
2318
|
-
const
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
let sIdx = sy * sw + sx;
|
|
2330
|
-
let mIdx = (my + dy) * mPitch + (mx + dx);
|
|
2331
|
-
const dStride = dw - actualW;
|
|
2332
|
-
const sStride = sw - actualW;
|
|
2333
|
-
const mStride = mPitch - actualW;
|
|
2334
|
-
const isOverwrite = blendFn.isOverwrite;
|
|
2335
|
-
for (let iy = 0; iy < actualH; iy++) {
|
|
2336
|
-
for (let ix = 0; ix < actualW; ix++) {
|
|
2337
|
-
const baseSrcColor = src32[sIdx];
|
|
2338
|
-
const baseSrcAlpha = baseSrcColor >>> 24;
|
|
2339
|
-
if (baseSrcAlpha === 0 && !isOverwrite) {
|
|
2340
|
-
dIdx++;
|
|
2341
|
-
sIdx++;
|
|
2342
|
-
mIdx++;
|
|
2924
|
+
const sPitch = mw ?? width;
|
|
2925
|
+
const isAlpha = maskType === 0 /* ALPHA */;
|
|
2926
|
+
for (let iy = 0; iy < height; iy++) {
|
|
2927
|
+
const dy = targetY + iy;
|
|
2928
|
+
const sy = my + iy;
|
|
2929
|
+
if (dy < 0 || sy < 0) {
|
|
2930
|
+
continue;
|
|
2931
|
+
}
|
|
2932
|
+
for (let ix = 0; ix < width; ix++) {
|
|
2933
|
+
const dx = targetX + ix;
|
|
2934
|
+
const sx = mx + ix;
|
|
2935
|
+
if (dx < 0 || dx >= dstWidth || sx < 0 || sx >= sPitch) {
|
|
2343
2936
|
continue;
|
|
2344
2937
|
}
|
|
2938
|
+
const dIdx = dy * dstWidth + dx;
|
|
2939
|
+
const sIdx = sy * sPitch + sx;
|
|
2940
|
+
const mVal = src[sIdx];
|
|
2345
2941
|
let weight = globalAlpha;
|
|
2346
|
-
if (
|
|
2347
|
-
const
|
|
2348
|
-
if (
|
|
2349
|
-
|
|
2350
|
-
if (effectiveM === 0) {
|
|
2351
|
-
dIdx++;
|
|
2352
|
-
sIdx++;
|
|
2353
|
-
mIdx++;
|
|
2354
|
-
continue;
|
|
2355
|
-
}
|
|
2356
|
-
if (globalAlpha === 255) {
|
|
2357
|
-
weight = effectiveM;
|
|
2358
|
-
} else if (effectiveM === 255) {
|
|
2359
|
-
weight = globalAlpha;
|
|
2360
|
-
} else {
|
|
2361
|
-
weight = effectiveM * globalAlpha + 128 >> 8;
|
|
2362
|
-
}
|
|
2363
|
-
} else {
|
|
2364
|
-
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
2365
|
-
if (!isHit) {
|
|
2366
|
-
dIdx++;
|
|
2367
|
-
sIdx++;
|
|
2368
|
-
mIdx++;
|
|
2369
|
-
continue;
|
|
2370
|
-
}
|
|
2371
|
-
weight = globalAlpha;
|
|
2372
|
-
}
|
|
2373
|
-
if (weight === 0) {
|
|
2374
|
-
dIdx++;
|
|
2375
|
-
sIdx++;
|
|
2376
|
-
mIdx++;
|
|
2942
|
+
if (isAlpha) {
|
|
2943
|
+
const effectiveM = invertMask ? 255 - mVal : mVal;
|
|
2944
|
+
if (effectiveM === 0) {
|
|
2945
|
+
dst[dIdx] = 0;
|
|
2377
2946
|
continue;
|
|
2378
2947
|
}
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
currentSrcAlpha = weight;
|
|
2385
|
-
} else {
|
|
2386
|
-
currentSrcAlpha = baseSrcAlpha * weight + 128 >> 8;
|
|
2387
|
-
}
|
|
2388
|
-
if (!isOverwrite && currentSrcAlpha === 0) {
|
|
2389
|
-
dIdx++;
|
|
2390
|
-
sIdx++;
|
|
2391
|
-
mIdx++;
|
|
2948
|
+
weight = globalAlpha === 255 ? effectiveM : effectiveM * globalAlpha + 128 >> 8;
|
|
2949
|
+
} else {
|
|
2950
|
+
const isHit = invertMask ? mVal === 0 : mVal === 1;
|
|
2951
|
+
if (!isHit) {
|
|
2952
|
+
dst[dIdx] = 0;
|
|
2392
2953
|
continue;
|
|
2393
2954
|
}
|
|
2394
|
-
|
|
2955
|
+
weight = globalAlpha;
|
|
2956
|
+
}
|
|
2957
|
+
if (weight === 0) {
|
|
2958
|
+
dst[dIdx] = 0;
|
|
2959
|
+
continue;
|
|
2960
|
+
}
|
|
2961
|
+
const da = dst[dIdx];
|
|
2962
|
+
if (da === 0) {
|
|
2963
|
+
} else if (weight === 255) {
|
|
2964
|
+
} else if (da === 255) {
|
|
2965
|
+
dst[dIdx] = weight;
|
|
2966
|
+
} else {
|
|
2967
|
+
dst[dIdx] = da * weight + 128 >> 8;
|
|
2395
2968
|
}
|
|
2396
|
-
dst32[dIdx] = blendFn(currentSrcColor, dst32[dIdx]);
|
|
2397
|
-
dIdx++;
|
|
2398
|
-
sIdx++;
|
|
2399
|
-
mIdx++;
|
|
2400
2969
|
}
|
|
2401
|
-
dIdx += dStride;
|
|
2402
|
-
sIdx += sStride;
|
|
2403
|
-
mIdx += mStride;
|
|
2404
2970
|
}
|
|
2405
2971
|
}
|
|
2406
2972
|
|
|
2407
|
-
// src/PixelData/
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
if (typeof _x === "object") {
|
|
2414
|
-
x = _x.x ?? 0;
|
|
2415
|
-
y = _x.y ?? 0;
|
|
2416
|
-
w = _x.w ?? dst.width;
|
|
2417
|
-
h = _x.h ?? dst.height;
|
|
2418
|
-
} else if (typeof _x === "number") {
|
|
2419
|
-
x = _x;
|
|
2420
|
-
y = _y;
|
|
2421
|
-
w = _w;
|
|
2422
|
-
h = _h;
|
|
2423
|
-
} else {
|
|
2424
|
-
x = 0;
|
|
2425
|
-
y = 0;
|
|
2426
|
-
w = dst.width;
|
|
2427
|
-
h = dst.height;
|
|
2973
|
+
// src/PixelData/PixelData.ts
|
|
2974
|
+
var PixelData = class _PixelData {
|
|
2975
|
+
data32;
|
|
2976
|
+
imageData;
|
|
2977
|
+
get width() {
|
|
2978
|
+
return this.imageData.width;
|
|
2428
2979
|
}
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
x = 0;
|
|
2980
|
+
get height() {
|
|
2981
|
+
return this.imageData.height;
|
|
2432
2982
|
}
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2983
|
+
constructor(imageData) {
|
|
2984
|
+
this.data32 = imageDataToUInt32Array(imageData);
|
|
2985
|
+
this.imageData = imageData;
|
|
2436
2986
|
}
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
return;
|
|
2987
|
+
set(imageData) {
|
|
2988
|
+
this.imageData = imageData;
|
|
2989
|
+
this.data32 = imageDataToUInt32Array(imageData);
|
|
2441
2990
|
}
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2991
|
+
/**
|
|
2992
|
+
* Creates a deep copy of the PixelData using the environment's ImageData constructor.
|
|
2993
|
+
*/
|
|
2994
|
+
copy() {
|
|
2995
|
+
const buffer = new Uint8ClampedArray(this.imageData.data);
|
|
2996
|
+
const ImageConstructor = typeof ImageData !== "undefined" ? ImageData : this.imageData.constructor;
|
|
2997
|
+
const newImageData = new ImageConstructor(
|
|
2998
|
+
buffer,
|
|
2999
|
+
this.width,
|
|
3000
|
+
this.height
|
|
3001
|
+
);
|
|
3002
|
+
return new _PixelData(newImageData);
|
|
2447
3003
|
}
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
3004
|
+
};
|
|
3005
|
+
|
|
3006
|
+
// src/PixelData/applyCircleBrushToPixelData.ts
|
|
3007
|
+
function applyCircleBrushToPixelData(target, color, centerX, centerY, brushSize, alpha = 255, fallOff, blendFn = sourceOverPerfect) {
|
|
3008
|
+
const r = brushSize / 2;
|
|
3009
|
+
const rSqr = r * r;
|
|
3010
|
+
const centerOffset = brushSize % 2 === 0 ? 0.5 : 0;
|
|
3011
|
+
const xStart = Math.max(0, Math.ceil(centerX - r));
|
|
3012
|
+
const xEnd = Math.min(target.width - 1, Math.floor(centerX + r));
|
|
3013
|
+
const yStart = Math.max(0, Math.ceil(centerY - r));
|
|
3014
|
+
const yEnd = Math.min(target.height - 1, Math.floor(centerY + r));
|
|
3015
|
+
const data32 = target.data32;
|
|
3016
|
+
const targetWidth = target.width;
|
|
3017
|
+
const baseColor = color & 16777215;
|
|
3018
|
+
const invR = 1 / r;
|
|
3019
|
+
const constantSrc = (alpha << 24 | baseColor) >>> 0;
|
|
3020
|
+
for (let cy = yStart; cy <= yEnd; cy++) {
|
|
3021
|
+
const dy = cy - centerY + centerOffset;
|
|
3022
|
+
const dySqr = dy * dy;
|
|
3023
|
+
const rowOffset = cy * targetWidth;
|
|
3024
|
+
for (let cx = xStart; cx <= xEnd; cx++) {
|
|
3025
|
+
const dx = cx - centerX + centerOffset;
|
|
3026
|
+
const dSqr = dx * dx + dySqr;
|
|
3027
|
+
if (dSqr <= rSqr) {
|
|
3028
|
+
const idx = rowOffset + cx;
|
|
3029
|
+
if (fallOff) {
|
|
3030
|
+
const strength = fallOff(Math.sqrt(dSqr) * invR);
|
|
3031
|
+
const fAlpha = alpha * strength & 255;
|
|
3032
|
+
const src = (fAlpha << 24 | baseColor) >>> 0;
|
|
3033
|
+
data32[idx] = blendFn(src, data32[idx]);
|
|
3034
|
+
} else {
|
|
3035
|
+
data32[idx] = blendFn(constantSrc, data32[idx]);
|
|
3036
|
+
}
|
|
3037
|
+
}
|
|
3038
|
+
}
|
|
3039
|
+
}
|
|
3040
|
+
}
|
|
3041
|
+
|
|
3042
|
+
// src/PixelData/applyRectBrushToPixelData.ts
|
|
3043
|
+
function applyRectBrushToPixelData(target, color, centerX, centerY, brushWidth, brushHeight, alpha = 255, fallOff, blendFn = sourceOverPerfect) {
|
|
3044
|
+
const targetWidth = target.width;
|
|
3045
|
+
const targetHeight = target.height;
|
|
3046
|
+
const data32 = target.data32;
|
|
3047
|
+
const rawStartX = Math.floor(centerX - brushWidth / 2);
|
|
3048
|
+
const rawStartY = Math.floor(centerY - brushHeight / 2);
|
|
3049
|
+
const endX = Math.min(targetWidth, rawStartX + brushWidth);
|
|
3050
|
+
const endY = Math.min(targetHeight, rawStartY + brushHeight);
|
|
3051
|
+
const startX = Math.max(0, rawStartX);
|
|
3052
|
+
const startY = Math.max(0, rawStartY);
|
|
3053
|
+
const baseColor = color & 16777215;
|
|
3054
|
+
const constantSrc = (alpha << 24 | baseColor) >>> 0;
|
|
3055
|
+
const invHalfW = 1 / (brushWidth / 2);
|
|
3056
|
+
const invHalfH = 1 / (brushHeight / 2);
|
|
3057
|
+
for (let py = startY; py < endY; py++) {
|
|
3058
|
+
const rowOffset = py * targetWidth;
|
|
3059
|
+
const dy = Math.abs(py + 0.5 - centerY) * invHalfH;
|
|
3060
|
+
for (let px = startX; px < endX; px++) {
|
|
3061
|
+
if (fallOff) {
|
|
3062
|
+
const dx = Math.abs(px + 0.5 - centerX) * invHalfW;
|
|
3063
|
+
const dist = dx > dy ? dx : dy;
|
|
3064
|
+
const fAlpha = alpha * fallOff(dist) | 0;
|
|
3065
|
+
const src = (fAlpha << 24 | baseColor) >>> 0;
|
|
3066
|
+
data32[rowOffset + px] = blendFn(src, data32[rowOffset + px]);
|
|
3067
|
+
} else {
|
|
3068
|
+
data32[rowOffset + px] = blendFn(constantSrc, data32[rowOffset + px]);
|
|
3069
|
+
}
|
|
3070
|
+
}
|
|
2452
3071
|
}
|
|
2453
3072
|
}
|
|
3073
|
+
function getRectBrushBounds(centerX, centerY, brushWidth, brushHeight, targetWidth, targetHeight) {
|
|
3074
|
+
const rawStartX = Math.floor(centerX - brushWidth / 2);
|
|
3075
|
+
const rawStartY = Math.floor(centerY - brushHeight / 2);
|
|
3076
|
+
const rawEndX = rawStartX + brushWidth;
|
|
3077
|
+
const rawEndY = rawStartY + brushHeight;
|
|
3078
|
+
const startX = targetWidth !== void 0 ? Math.max(0, rawStartX) : rawStartX;
|
|
3079
|
+
const startY = targetHeight !== void 0 ? Math.max(0, rawStartY) : rawStartY;
|
|
3080
|
+
const endX = targetWidth !== void 0 ? Math.min(targetWidth, rawEndX) : rawEndX;
|
|
3081
|
+
const endY = targetHeight !== void 0 ? Math.min(targetHeight, rawEndY) : rawEndY;
|
|
3082
|
+
return {
|
|
3083
|
+
x: startX,
|
|
3084
|
+
y: startY,
|
|
3085
|
+
w: endX - startX,
|
|
3086
|
+
h: endY - startY
|
|
3087
|
+
};
|
|
3088
|
+
}
|
|
2454
3089
|
|
|
2455
3090
|
// src/PixelData/clearPixelData.ts
|
|
2456
3091
|
function clearPixelData(dst, rect) {
|
|
@@ -2498,16 +3133,6 @@ function extractPixelData(source, _x, _y, _w, _h) {
|
|
|
2498
3133
|
return result;
|
|
2499
3134
|
}
|
|
2500
3135
|
|
|
2501
|
-
// src/PixelData/invertPixelData.ts
|
|
2502
|
-
function invertPixelData(pixelData) {
|
|
2503
|
-
const data32 = pixelData.data32;
|
|
2504
|
-
const len = data32.length;
|
|
2505
|
-
for (let i = 0; i < len; i++) {
|
|
2506
|
-
data32[i] = data32[i] ^ 16777215;
|
|
2507
|
-
}
|
|
2508
|
-
return pixelData;
|
|
2509
|
-
}
|
|
2510
|
-
|
|
2511
3136
|
// src/PixelData/reflectPixelData.ts
|
|
2512
3137
|
function reflectPixelDataHorizontal(pixelData) {
|
|
2513
3138
|
const width = pixelData.width;
|
|
@@ -2598,23 +3223,53 @@ function rotateSquareInPlace(pixelData) {
|
|
|
2598
3223
|
}
|
|
2599
3224
|
}
|
|
2600
3225
|
}
|
|
3226
|
+
|
|
3227
|
+
// src/PixelData/writePixelDataBuffer.ts
|
|
3228
|
+
function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
3229
|
+
const { x, y, w, h } = typeof _x === "object" ? _x : {
|
|
3230
|
+
x: _x,
|
|
3231
|
+
y: _y,
|
|
3232
|
+
w: _w,
|
|
3233
|
+
h: _h
|
|
3234
|
+
};
|
|
3235
|
+
const dstW = target.width;
|
|
3236
|
+
const dstH = target.height;
|
|
3237
|
+
const dstData = target.data32;
|
|
3238
|
+
const x0 = Math.max(0, x);
|
|
3239
|
+
const y0 = Math.max(0, y);
|
|
3240
|
+
const x1 = Math.min(dstW, x + w);
|
|
3241
|
+
const y1 = Math.min(dstH, y + h);
|
|
3242
|
+
if (x1 <= x0 || y1 <= y0) {
|
|
3243
|
+
return;
|
|
3244
|
+
}
|
|
3245
|
+
const rowLen = x1 - x0;
|
|
3246
|
+
const srcCol = x0 - x;
|
|
3247
|
+
const srcYOffset = y0 - y;
|
|
3248
|
+
const actualH = y1 - y0;
|
|
3249
|
+
for (let row = 0; row < actualH; row++) {
|
|
3250
|
+
const dstStart = (y0 + row) * dstW + x0;
|
|
3251
|
+
const srcRow = srcYOffset + row;
|
|
3252
|
+
const srcStart = srcRow * w + srcCol;
|
|
3253
|
+
dstData.set(data.subarray(srcStart, srcStart + rowLen), dstStart);
|
|
3254
|
+
}
|
|
3255
|
+
}
|
|
2601
3256
|
export {
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
FAST_BLEND_TO_INDEX,
|
|
2607
|
-
INDEX_TO_FAST_BLEND,
|
|
2608
|
-
INDEX_TO_PERFECT_BLEND,
|
|
3257
|
+
BASE_FAST_BLEND_MODE_FUNCTIONS,
|
|
3258
|
+
BASE_PERFECT_BLEND_MODE_FUNCTIONS,
|
|
3259
|
+
BaseBlendMode,
|
|
3260
|
+
HistoryManager,
|
|
2609
3261
|
IndexedImage,
|
|
2610
3262
|
MaskType,
|
|
2611
|
-
|
|
2612
|
-
PERFECT_BLEND_MODES,
|
|
2613
|
-
PERFECT_BLEND_MODE_BY_NAME,
|
|
2614
|
-
PERFECT_BLEND_TO_INDEX,
|
|
3263
|
+
PixelAccumulator,
|
|
2615
3264
|
PixelData,
|
|
3265
|
+
PixelEngineConfig,
|
|
3266
|
+
PixelTile,
|
|
3267
|
+
PixelWriter,
|
|
2616
3268
|
UnsupportedFormatError,
|
|
3269
|
+
applyCircleBrushToPixelData,
|
|
2617
3270
|
applyMaskToPixelData,
|
|
3271
|
+
applyPatchTiles,
|
|
3272
|
+
applyRectBrushToPixelData,
|
|
2618
3273
|
base64DecodeArrayBuffer,
|
|
2619
3274
|
base64EncodeArrayBuffer,
|
|
2620
3275
|
blendColorPixelData,
|
|
@@ -2653,6 +3308,7 @@ export {
|
|
|
2653
3308
|
floodFillSelection,
|
|
2654
3309
|
getImageDataFromClipboard,
|
|
2655
3310
|
getIndexedImageColorCounts,
|
|
3311
|
+
getRectBrushBounds,
|
|
2656
3312
|
getSupportedPixelFormats,
|
|
2657
3313
|
hardLightFast,
|
|
2658
3314
|
hardLightPerfect,
|
|
@@ -2681,14 +3337,25 @@ export {
|
|
|
2681
3337
|
linearDodgePerfect,
|
|
2682
3338
|
linearLightFast,
|
|
2683
3339
|
linearLightPerfect,
|
|
3340
|
+
makeBlendModeRegistry,
|
|
3341
|
+
makeFastBlendModeRegistry,
|
|
3342
|
+
makeFullPixelMutator,
|
|
3343
|
+
makePerfectBlendModeRegistry,
|
|
2684
3344
|
makePixelCanvas,
|
|
2685
3345
|
makeReusableCanvas,
|
|
2686
3346
|
makeReusableImageData,
|
|
2687
3347
|
mergeMasks,
|
|
2688
3348
|
multiplyFast,
|
|
2689
3349
|
multiplyPerfect,
|
|
3350
|
+
mutatorApplyMask,
|
|
3351
|
+
mutatorBlendColor,
|
|
3352
|
+
mutatorBlendPixel,
|
|
3353
|
+
mutatorBlendPixelData,
|
|
3354
|
+
mutatorFill,
|
|
3355
|
+
mutatorInvert,
|
|
2690
3356
|
overlayFast,
|
|
2691
3357
|
overlayPerfect,
|
|
3358
|
+
overwriteBase,
|
|
2692
3359
|
overwriteFast,
|
|
2693
3360
|
overwritePerfect,
|
|
2694
3361
|
packColor,
|
|
@@ -2723,8 +3390,9 @@ export {
|
|
|
2723
3390
|
vividLightFast,
|
|
2724
3391
|
vividLightPerfect,
|
|
2725
3392
|
writeImageData,
|
|
2726
|
-
|
|
3393
|
+
writeImageDataBuffer,
|
|
2727
3394
|
writeImageDataToClipboard,
|
|
2728
|
-
writeImgBlobToClipboard
|
|
3395
|
+
writeImgBlobToClipboard,
|
|
3396
|
+
writePixelDataBuffer
|
|
2729
3397
|
};
|
|
2730
3398
|
//# sourceMappingURL=index.dev.js.map
|