pixel-data-js 0.16.0 → 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.
Files changed (33) hide show
  1. package/dist/index.dev.cjs +1648 -908
  2. package/dist/index.dev.cjs.map +1 -1
  3. package/dist/index.dev.js +1629 -906
  4. package/dist/index.dev.js.map +1 -1
  5. package/dist/index.prod.cjs +1648 -908
  6. package/dist/index.prod.cjs.map +1 -1
  7. package/dist/index.prod.d.ts +287 -67
  8. package/dist/index.prod.js +1629 -906
  9. package/dist/index.prod.js.map +1 -1
  10. package/package.json +1 -1
  11. package/src/BlendModes/BlendModeRegistry.ts +34 -50
  12. package/src/BlendModes/blend-modes-perfect.ts +313 -136
  13. package/src/BlendModes/blend-modes.ts +6 -0
  14. package/src/History/HistoryManager.ts +83 -0
  15. package/src/History/PixelAccumulator.ts +191 -0
  16. package/src/History/PixelEngineConfig.ts +18 -0
  17. package/src/History/PixelMutator/mutatorApplyMask.ts +20 -0
  18. package/src/History/PixelMutator/mutatorBlendColor.ts +22 -0
  19. package/src/History/PixelMutator/mutatorBlendPixel.ts +37 -0
  20. package/src/History/PixelMutator/mutatorBlendPixelData.ts +24 -0
  21. package/src/History/PixelMutator/mutatorFillPixelData.ts +21 -0
  22. package/src/History/PixelMutator/mutatorInvert.ts +18 -0
  23. package/src/History/PixelMutator.ts +18 -0
  24. package/src/History/PixelPatchTiles.ts +52 -0
  25. package/src/History/PixelWriter.ts +79 -0
  26. package/src/ImageData/{writeImageDataPixels.ts → writeImageDataBuffer.ts} +3 -3
  27. package/src/PixelData/applyCircleBrushToPixelData.ts +69 -0
  28. package/src/PixelData/applyMaskToPixelData.ts +1 -1
  29. package/src/PixelData/applyRectBrushToPixelData.ts +102 -0
  30. package/src/PixelData/invertPixelData.ts +74 -7
  31. package/src/PixelData/writePixelDataBuffer.ts +65 -0
  32. package/src/_types.ts +31 -11
  33. package/src/index.ts +18 -1
package/dist/index.dev.js CHANGED
@@ -29,33 +29,37 @@ overwriteBase.isOverwrite = true;
29
29
 
30
30
  // src/BlendModes/BlendModeRegistry.ts
31
31
  function makeBlendModeRegistry(blendModes, initialEntries) {
32
- const modes = [];
33
- const toIndex = /* @__PURE__ */ new Map();
34
- const fromIndex = /* @__PURE__ */ new Map();
35
- const byName = {};
32
+ const blendToName = /* @__PURE__ */ new Map();
33
+ const blendToIndex = /* @__PURE__ */ new Map();
34
+ const indexToName = [];
35
+ const indexToBlend = [];
36
+ const nameToBlend = {};
37
+ const nameToIndex = {};
36
38
  const add = (name, index, blendFn) => {
37
- if (modes[index]) {
38
- throw new Error(`Blend Mode index: ${index} is already used`);
39
+ if (!Number.isFinite(index)) {
40
+ throw new Error(`Index "${index}" is not a number. Attempting to add name: "${name}", index: "${index}"`);
39
41
  }
40
- if (byName[name]) {
41
- throw new Error(`Blend Mode name: "${name}" is already used`);
42
+ if (indexToBlend[index]) {
43
+ throw new Error(`Blend Mode index: ${index} is already used. Attempting to add name: "${name}", index: "${index}"`);
42
44
  }
43
- const idx = index;
44
- modes[idx] = blendFn;
45
- toIndex.set(blendFn, idx);
46
- fromIndex.set(idx, blendFn);
47
- byName[name] = blendFn;
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;
48
51
  };
49
52
  for (const [name, index] of Object.entries(blendModes)) {
50
53
  const blend = initialEntries[index];
51
54
  add(name, index, blend);
52
55
  }
53
56
  return {
54
- modes,
55
- byName,
56
- toIndex,
57
- fromIndex,
58
- add,
57
+ nameToBlend,
58
+ nameToIndex,
59
+ blendToIndex,
60
+ blendToName,
61
+ indexToBlend,
62
+ indexToName,
59
63
  indexType: null,
60
64
  nameType: null
61
65
  };
@@ -840,14 +844,18 @@ var sourceOverPerfect = (src, dst) => {
840
844
  const sa = src >>> 24 & 255;
841
845
  if (sa === 255) return src;
842
846
  if (sa === 0) return dst;
847
+ const invA = 255 - sa;
843
848
  const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
844
849
  const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
845
850
  const da = dst >>> 24 & 255;
846
- const invA = 255 - sa;
847
- const r = (sr * sa + dr * invA) / 255 | 0;
848
- const g = (sg * sa + dg * invA) / 255 | 0;
849
- const b = (sb * sa + db * invA) / 255 | 0;
850
- const a = (255 * sa + da * invA) / 255 | 0;
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;
851
859
  return (a << 24 | b << 16 | g << 8 | r) >>> 0;
852
860
  };
853
861
  var darkenPerfect = (src, dst) => {
@@ -860,44 +868,71 @@ var darkenPerfect = (src, dst) => {
860
868
  const bb = sb < db ? sb : db;
861
869
  if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
862
870
  const invA = 255 - sa;
863
- const r = (br * sa + dr * invA) / 255 | 0;
864
- const g = (bg * sa + dg * invA) / 255 | 0;
865
- const b = (bb * sa + db * invA) / 255 | 0;
866
- const a = (255 * sa + (dst >>> 24 & 255) * invA) / 255 | 0;
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;
867
880
  return (a << 24 | b << 16 | g << 8 | r) >>> 0;
868
881
  };
869
882
  var multiplyPerfect = (src, dst) => {
870
883
  const sa = src >>> 24 & 255;
871
884
  if (sa === 0) return dst;
872
- const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
873
- const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
874
- const br = sr * dr / 255 | 0;
875
- const bg = sg * dg / 255 | 0;
876
- const bb = sb * db / 255 | 0;
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;
877
898
  if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
878
899
  const invA = 255 - sa;
879
- const da = dst >>> 24 & 255;
880
- const r = (br * sa + dr * invA) / 255 | 0;
881
- const g = (bg * sa + dg * invA) / 255 | 0;
882
- const b = (bb * sa + db * invA) / 255 | 0;
883
- const a = (255 * sa + da * invA) / 255 | 0;
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;
884
908
  return (a << 24 | b << 16 | g << 8 | r) >>> 0;
885
909
  };
886
910
  var colorBurnPerfect = (src, dst) => {
887
911
  const sa = src >>> 24 & 255;
888
912
  if (sa === 0) return dst;
889
- const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
890
- const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
891
- const br = dr === 255 ? 255 : sr === 0 ? 0 : Math.max(0, 255 - ((255 - dr) * 255 / sr | 0));
892
- const bg = dg === 255 ? 255 : sg === 0 ? 0 : Math.max(0, 255 - ((255 - dg) * 255 / sg | 0));
893
- const bb = db === 255 ? 255 : sb === 0 ? 0 : Math.max(0, 255 - ((255 - db) * 255 / sb | 0));
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;
894
925
  if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
895
926
  const invA = 255 - sa;
896
927
  const da = dst >>> 24 & 255;
897
- const r = (br * sa + dr * invA) / 255 | 0;
898
- const g = (bg * sa + dg * invA) / 255 | 0;
899
- const b = (bb * sa + db * invA) / 255 | 0;
900
- const a = (255 * sa + da * invA) / 255 | 0;
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;
901
936
  return (a << 24 | b << 16 | g << 8 | r) >>> 0;
902
937
  };
903
938
  var linearBurnPerfect = (src, dst) => {
@@ -913,10 +948,15 @@ var linearBurnPerfect = (src, dst) => {
913
948
  const bb = bbU < 0 ? 0 : bbU;
914
949
  if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
915
950
  const invA = 255 - sa;
916
- const r = (br * sa + dr * invA) / 255 | 0;
917
- const g = (bg * sa + dg * invA) / 255 | 0;
918
- const b = (bb * sa + db * invA) / 255 | 0;
919
- const a = (255 * sa + (dst >>> 24 & 255) * invA) / 255 | 0;
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;
920
960
  return (a << 24 | b << 16 | g << 8 | r) >>> 0;
921
961
  };
922
962
  var darkerPerfect = (src, dst) => {
@@ -938,10 +978,15 @@ var darkerPerfect = (src, dst) => {
938
978
  }
939
979
  if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
940
980
  const invA = 255 - sa;
941
- const r = (br * sa + dr * invA) / 255 | 0;
942
- const g = (bg * sa + dg * invA) / 255 | 0;
943
- const b = (bb * sa + db * invA) / 255 | 0;
944
- const a = (255 * sa + (dst >>> 24 & 255) * invA) / 255 | 0;
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;
945
990
  return (a << 24 | b << 16 | g << 8 | r) >>> 0;
946
991
  };
947
992
  var lightenPerfect = (src, dst) => {
@@ -953,10 +998,15 @@ var lightenPerfect = (src, dst) => {
953
998
  const bb = (src >>> 16 & 255) > db ? src >>> 16 & 255 : db;
954
999
  if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
955
1000
  const invA = 255 - sa;
956
- const r = (br * sa + dr * invA) / 255 | 0;
957
- const g = (bg * sa + dg * invA) / 255 | 0;
958
- const b = (bb * sa + db * invA) / 255 | 0;
959
- const a = (255 * sa + (dst >>> 24 & 255) * invA) / 255 | 0;
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;
960
1010
  return (a << 24 | b << 16 | g << 8 | r) >>> 0;
961
1011
  };
962
1012
  var screenPerfect = (src, dst) => {
@@ -968,26 +1018,43 @@ var screenPerfect = (src, dst) => {
968
1018
  const bb = 255 - ((255 - (src >>> 16 & 255)) * (255 - db) / 255 | 0);
969
1019
  if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
970
1020
  const invA = 255 - sa;
971
- const r = (br * sa + dr * invA) / 255 | 0;
972
- const g = (bg * sa + dg * invA) / 255 | 0;
973
- const b = (bb * sa + db * invA) / 255 | 0;
974
- const a = (255 * sa + (dst >>> 24 & 255) * invA) / 255 | 0;
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;
975
1030
  return (a << 24 | b << 16 | g << 8 | r) >>> 0;
976
1031
  };
977
1032
  var colorDodgePerfect = (src, dst) => {
978
1033
  const sa = src >>> 24 & 255;
979
1034
  if (sa === 0) return dst;
980
- const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
981
- const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
982
- const br = sr === 255 ? 255 : Math.min(255, dr * 255 / (255 - sr) | 0);
983
- const bg = sg === 255 ? 255 : Math.min(255, dg * 255 / (255 - sg) | 0);
984
- const bb = sb === 255 ? 255 : Math.min(255, db * 255 / (255 - sb) | 0);
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;
985
1047
  if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
986
1048
  const invA = 255 - sa;
987
- const r = (br * sa + dr * invA) / 255 | 0;
988
- const g = (bg * sa + dg * invA) / 255 | 0;
989
- const b = (bb * sa + db * invA) / 255 | 0;
990
- const a = (255 * sa + (dst >>> 24 & 255) * invA) / 255 | 0;
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;
991
1058
  return (a << 24 | b << 16 | g << 8 | r) >>> 0;
992
1059
  };
993
1060
  var linearDodgePerfect = (src, dst) => {
@@ -1002,10 +1069,15 @@ var linearDodgePerfect = (src, dst) => {
1002
1069
  const bb = bbU > 255 ? 255 : bbU;
1003
1070
  if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
1004
1071
  const invA = 255 - sa;
1005
- const r = (br * sa + dr * invA) / 255 | 0;
1006
- const g = (bg * sa + dg * invA) / 255 | 0;
1007
- const b = (bb * sa + db * invA) / 255 | 0;
1008
- const a = (255 * sa + (dst >>> 24 & 255) * invA) / 255 | 0;
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;
1009
1081
  return (a << 24 | b << 16 | g << 8 | r) >>> 0;
1010
1082
  };
1011
1083
  var lighterPerfect = (src, dst) => {
@@ -1027,10 +1099,15 @@ var lighterPerfect = (src, dst) => {
1027
1099
  }
1028
1100
  if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
1029
1101
  const invA = 255 - sa;
1030
- const r = (br * sa + dr * invA) / 255 | 0;
1031
- const g = (bg * sa + dg * invA) / 255 | 0;
1032
- const b = (bb * sa + db * invA) / 255 | 0;
1033
- const a = (255 * sa + (dst >>> 24 & 255) * invA) / 255 | 0;
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;
1034
1111
  return (a << 24 | b << 16 | g << 8 | r) >>> 0;
1035
1112
  };
1036
1113
  var overlayPerfect = (src, dst) => {
@@ -1043,10 +1120,15 @@ var overlayPerfect = (src, dst) => {
1043
1120
  const bb = db < 128 ? 2 * sb * db / 255 | 0 : 255 - (2 * (255 - sb) * (255 - db) / 255 | 0);
1044
1121
  if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
1045
1122
  const invA = 255 - sa;
1046
- const r = (br * sa + dr * invA) / 255 | 0;
1047
- const g = (bg * sa + dg * invA) / 255 | 0;
1048
- const b = (bb * sa + db * invA) / 255 | 0;
1049
- const a = (255 * sa + (dst >>> 24 & 255) * invA) / 255 | 0;
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;
1050
1132
  return (a << 24 | b << 16 | g << 8 | r) >>> 0;
1051
1133
  };
1052
1134
  var softLightPerfect = (src, dst) => {
@@ -1054,15 +1136,26 @@ var softLightPerfect = (src, dst) => {
1054
1136
  if (sa === 0) return dst;
1055
1137
  const dr = dst & 255, dg = dst >>> 8 & 255, db = dst >>> 16 & 255;
1056
1138
  const sr = src & 255, sg = src >>> 8 & 255, sb = src >>> 16 & 255;
1057
- const br = ((255 - dr) * (sr * dr / 255 | 0) + dr * (255 - ((255 - sr) * (255 - dr) / 255 | 0))) / 255 | 0;
1058
- const bg = ((255 - dg) * (sg * dg / 255 | 0) + dg * (255 - ((255 - sg) * (255 - dg) / 255 | 0))) / 255 | 0;
1059
- const bb = ((255 - db) * (sb * db / 255 | 0) + db * (255 - ((255 - sb) * (255 - db) / 255 | 0))) / 255 | 0;
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;
1060
1148
  if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
1061
1149
  const invA = 255 - sa;
1062
- const r = (br * sa + dr * invA) / 255 | 0;
1063
- const g = (bg * sa + dg * invA) / 255 | 0;
1064
- const b = (bb * sa + db * invA) / 255 | 0;
1065
- const a = (255 * sa + (dst >>> 24 & 255) * invA) / 255 | 0;
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;
1066
1159
  return (a << 24 | b << 16 | g << 8 | r) >>> 0;
1067
1160
  };
1068
1161
  var hardLightPerfect = (src, dst) => {
@@ -1075,10 +1168,15 @@ var hardLightPerfect = (src, dst) => {
1075
1168
  const bb = sb < 128 ? 2 * sb * db / 255 | 0 : 255 - (2 * (255 - sb) * (255 - db) / 255 | 0);
1076
1169
  if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
1077
1170
  const invA = 255 - sa;
1078
- const r = (br * sa + dr * invA) / 255 | 0;
1079
- const g = (bg * sa + dg * invA) / 255 | 0;
1080
- const b = (bb * sa + db * invA) / 255 | 0;
1081
- const a = (255 * sa + (dst >>> 24 & 255) * invA) / 255 | 0;
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;
1082
1180
  return (a << 24 | b << 16 | g << 8 | r) >>> 0;
1083
1181
  };
1084
1182
  var vividLightPerfect = (src, dst) => {
@@ -1091,10 +1189,15 @@ var vividLightPerfect = (src, dst) => {
1091
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);
1092
1190
  if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
1093
1191
  const invA = 255 - sa;
1094
- const r = (br * sa + dr * invA) / 255 | 0;
1095
- const g = (bg * sa + dg * invA) / 255 | 0;
1096
- const b = (bb * sa + db * invA) / 255 | 0;
1097
- const a = (255 * sa + (dst >>> 24 & 255) * invA) / 255 | 0;
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;
1098
1201
  return (a << 24 | b << 16 | g << 8 | r) >>> 0;
1099
1202
  };
1100
1203
  var linearLightPerfect = (src, dst) => {
@@ -1110,10 +1213,15 @@ var linearLightPerfect = (src, dst) => {
1110
1213
  const bb = bbU < 0 ? 0 : bbU > 255 ? 255 : bbU;
1111
1214
  if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
1112
1215
  const invA = 255 - sa;
1113
- const r = (br * sa + dr * invA) / 255 | 0;
1114
- const g = (bg * sa + dg * invA) / 255 | 0;
1115
- const b = (bb * sa + db * invA) / 255 | 0;
1116
- const a = (255 * sa + (dst >>> 24 & 255) * invA) / 255 | 0;
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;
1117
1225
  return (a << 24 | b << 16 | g << 8 | r) >>> 0;
1118
1226
  };
1119
1227
  var pinLightPerfect = (src, dst) => {
@@ -1131,10 +1239,14 @@ var pinLightPerfect = (src, dst) => {
1131
1239
  if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
1132
1240
  const invA = 255 - sa;
1133
1241
  const da = dst >>> 24 & 255;
1134
- const r = (br * sa + dr * invA + 128) / 255 | 0;
1135
- const g = (bg * sa + dg * invA + 128) / 255 | 0;
1136
- const b = (bb * sa + db * invA + 128) / 255 | 0;
1137
- const a = (255 * sa + da * invA + 128) / 255 | 0;
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;
1138
1250
  return (a << 24 | b << 16 | g << 8 | r) >>> 0;
1139
1251
  };
1140
1252
  var hardMixPerfect = (src, dst) => {
@@ -1147,33 +1259,36 @@ var hardMixPerfect = (src, dst) => {
1147
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;
1148
1260
  if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
1149
1261
  const invA = 255 - sa;
1150
- const r = (br * sa + dr * invA) / 255 | 0;
1151
- const g = (bg * sa + dg * invA) / 255 | 0;
1152
- const b = (bb * sa + db * invA) / 255 | 0;
1153
- const a = (255 * sa + (dst >>> 24 & 255) * invA) / 255 | 0;
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;
1154
1271
  return (a << 24 | b << 16 | g << 8 | r) >>> 0;
1155
1272
  };
1156
1273
  var differencePerfect = (src, dst) => {
1157
1274
  const sa = src >>> 24 & 255;
1158
1275
  if (sa === 0) return dst;
1159
- const dr = dst & 255;
1160
- const dg = dst >>> 8 & 255;
1161
- const db = dst >>> 16 & 255;
1162
- const sr = src & 255;
1163
- const sg = src >>> 8 & 255;
1164
- const sb = src >>> 16 & 255;
1165
- const br = Math.abs(dr - sr);
1166
- const bg = Math.abs(dg - sg);
1167
- const bb = Math.abs(db - sb);
1168
- if (sa === 255) {
1169
- return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
1170
- }
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;
1171
1282
  const invA = 255 - sa;
1172
1283
  const da = dst >>> 24 & 255;
1173
- const r = (br * sa + dr * invA + 128) / 255 | 0;
1174
- const g = (bg * sa + dg * invA + 128) / 255 | 0;
1175
- const b = (bb * sa + db * invA + 128) / 255 | 0;
1176
- const a = (255 * sa + da * invA + 128) / 255 | 0;
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;
1177
1292
  return (a << 24 | b << 16 | g << 8 | r) >>> 0;
1178
1293
  };
1179
1294
  var exclusionPerfect = (src, dst) => {
@@ -1185,18 +1300,23 @@ var exclusionPerfect = (src, dst) => {
1185
1300
  const sr = src & 255;
1186
1301
  const sg = src >>> 8 & 255;
1187
1302
  const sb = src >>> 16 & 255;
1188
- const br = dr + sr - (dr * sr >> 7);
1189
- const bg = dg + sg - (dg * sg >> 7);
1190
- const bb = db + sb - (db * sb >> 7);
1191
- if (sa === 255) {
1192
- return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
1193
- }
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;
1194
1310
  const invA = 255 - sa;
1195
1311
  const da = dst >>> 24 & 255;
1196
- const r = (br * sa + dr * invA) / 255 | 0;
1197
- const g = (bg * sa + dg * invA) / 255 | 0;
1198
- const b = (bb * sa + db * invA) / 255 | 0;
1199
- const a = (255 * sa + da * invA) / 255 | 0;
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;
1200
1320
  return (a << 24 | b << 16 | g << 8 | r) >>> 0;
1201
1321
  };
1202
1322
  var subtractPerfect = (src, dst) => {
@@ -1212,10 +1332,15 @@ var subtractPerfect = (src, dst) => {
1212
1332
  const bb = bbU < 0 ? 0 : bbU;
1213
1333
  if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
1214
1334
  const invA = 255 - sa;
1215
- const r = (br * sa + dr * invA) / 255 | 0;
1216
- const g = (bg * sa + dg * invA) / 255 | 0;
1217
- const b = (bb * sa + db * invA) / 255 | 0;
1218
- const a = (255 * sa + (dst >>> 24 & 255) * invA) / 255 | 0;
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;
1219
1344
  return (a << 24 | b << 16 | g << 8 | r) >>> 0;
1220
1345
  };
1221
1346
  var dividePerfect = (src, dst) => {
@@ -1228,10 +1353,15 @@ var dividePerfect = (src, dst) => {
1228
1353
  const bb = sb === 0 ? 255 : Math.min(255, db * 255 / sb | 0);
1229
1354
  if (sa === 255) return (4278190080 | bb << 16 | bg << 8 | br) >>> 0;
1230
1355
  const invA = 255 - sa;
1231
- const r = (br * sa + dr * invA) / 255 | 0;
1232
- const g = (bg * sa + dg * invA) / 255 | 0;
1233
- const b = (bb * sa + db * invA) / 255 | 0;
1234
- const a = (255 * sa + (dst >>> 24 & 255) * invA) / 255 | 0;
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;
1235
1365
  return (a << 24 | b << 16 | g << 8 | r) >>> 0;
1236
1366
  };
1237
1367
  var BASE_PERFECT_BLEND_MODE_FUNCTIONS = {
@@ -1376,279 +1506,1126 @@ async function writeImageDataToClipboard(imageData) {
1376
1506
  return writeImgBlobToClipboard(blob);
1377
1507
  }
1378
1508
 
1379
- // src/ImageData/ReusableImageData.ts
1380
- function makeReusableImageData() {
1381
- let imageData = null;
1382
- let buffer = null;
1383
- return function getReusableImageData(width, height) {
1384
- const hasInstance = !!imageData;
1385
- const widthMatches = hasInstance && imageData.width === width;
1386
- const heightMatches = hasInstance && imageData.height === height;
1387
- if (!widthMatches || !heightMatches) {
1388
- const buffer2 = new Uint8ClampedArray(width * height * 4);
1389
- imageData = new ImageData(buffer2, width, height);
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);
1390
1538
  }
1391
- return imageData;
1392
- };
1393
- }
1394
-
1395
- // src/ImageData/copyImageData.ts
1396
- function copyImageData({ data, width, height }) {
1397
- return new ImageData(data.slice(), width, height);
1398
- }
1399
- function copyImageDataLike({ data, width, height }) {
1400
- return {
1401
- data: data.slice(),
1402
- width,
1403
- height
1404
- };
1405
- }
1406
-
1407
- // src/PixelData/pixelDataToAlphaMask.ts
1408
- function pixelDataToAlphaMask(pixelData) {
1409
- const {
1410
- data32,
1411
- width,
1412
- height
1413
- } = pixelData;
1414
- const len = data32.length;
1415
- const mask = new Uint8Array(width * height);
1416
- for (let i = 0; i < len; i++) {
1417
- const val = data32[i];
1418
- mask[i] = val >>> 24 & 255;
1419
1539
  }
1420
- return mask;
1421
1540
  }
1422
1541
 
1423
- // src/ImageData/imageDataToAlphaMask.ts
1424
- function imageDataToAlphaMask(imageData) {
1425
- const {
1426
- width,
1427
- height,
1428
- data
1429
- } = imageData;
1430
- const data32 = new Uint32Array(
1431
- data.buffer,
1432
- data.byteOffset,
1433
- data.byteLength >> 2
1434
- );
1435
- const len = data32.length;
1436
- const mask = new Uint8Array(width * height);
1437
- for (let i = 0; i < len; i++) {
1438
- const val = data32[i];
1439
- mask[i] = val >>> 24 & 255;
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
+ );
1440
1568
  }
1441
- return mask;
1442
- }
1443
-
1444
- // src/ImageData/imageDataToDataUrl.ts
1445
- var get = makeReusableCanvas();
1446
- function imageDataToDataUrl(imageData) {
1447
- const { canvas, ctx } = get(imageData.width, imageData.height);
1448
- ctx.putImageData(imageData, 0, 0);
1449
- return canvas.toDataURL();
1450
- }
1451
- imageDataToDataUrl.reset = get.reset;
1452
-
1453
- // src/ImageData/imageDataToUInt32Array.ts
1454
- function imageDataToUInt32Array(imageData) {
1455
- return new Uint32Array(
1456
- imageData.data.buffer,
1457
- imageData.data.byteOffset,
1458
- // Shift right by 2 is a fast bitwise division by 4.
1459
- imageData.data.byteLength >> 2
1460
- );
1461
- }
1462
-
1463
- // src/ImageData/invertImageData.ts
1464
- function invertImageData(imageData) {
1465
- const data = imageData.data;
1466
- let length = data.length;
1467
- for (let i = 0; i < length; i += 4) {
1468
- data[i] = 255 - data[i];
1469
- data[i + 1] = 255 - data[i + 1];
1470
- data[i + 2] = 255 - data[i + 2];
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 = [];
1471
1685
  }
1472
- return imageData;
1473
- }
1474
-
1475
- // src/Internal/resample32.ts
1476
- var resample32Scratch = {
1477
- data: null,
1478
- width: 0,
1479
- height: 0
1480
1686
  };
1481
- function resample32(srcData32, srcW, srcH, factor) {
1482
- const dstW = Math.max(1, srcW * factor | 0);
1483
- const dstH = Math.max(1, srcH * factor | 0);
1484
- const dstData = new Int32Array(dstW * dstH);
1485
- const scaleX = srcW / dstW;
1486
- const scaleY = srcH / dstH;
1487
- for (let y = 0; y < dstH; y++) {
1488
- const srcY = Math.min(srcH - 1, y * scaleY | 0);
1489
- const srcRowOffset = srcY * srcW;
1490
- const dstRowOffset = y * dstW;
1491
- for (let x = 0; x < dstW; x++) {
1492
- const srcX = Math.min(srcW - 1, x * scaleX | 0);
1493
- dstData[dstRowOffset + x] = srcData32[srcRowOffset + srcX];
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
+ }
1494
1741
  }
1742
+ this.redoStack.length = 0;
1495
1743
  }
1496
- resample32Scratch.data = dstData;
1497
- resample32Scratch.width = dstW;
1498
- resample32Scratch.height = dstH;
1499
- return resample32Scratch;
1500
- }
1744
+ };
1501
1745
 
1502
- // src/ImageData/resampleImageData.ts
1503
- function resampleImageData(source, factor) {
1504
- const src32 = new Uint32Array(source.data.buffer);
1505
- const { data, width, height } = resample32(src32, source.width, source.height, factor);
1506
- const uint8ClampedArray = new Uint8ClampedArray(data.buffer);
1507
- return new ImageData(uint8ClampedArray, width, height);
1508
- }
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
+ };
1509
1762
 
1510
- // src/ImageData/resizeImageData.ts
1511
- function resizeImageData(current, newWidth, newHeight, offsetX = 0, offsetY = 0) {
1512
- const result = new ImageData(newWidth, newHeight);
1763
+ // src/PixelData/applyMaskToPixelData.ts
1764
+ function applyMaskToPixelData(dst, mask, opts = {}) {
1513
1765
  const {
1514
- width: oldW,
1515
- height: oldH,
1516
- data: oldData
1517
- } = current;
1518
- const newData = result.data;
1519
- const x0 = Math.max(0, offsetX);
1520
- const y0 = Math.max(0, offsetY);
1521
- const x1 = Math.min(newWidth, offsetX + oldW);
1522
- const y1 = Math.min(newHeight, offsetY + oldH);
1523
- if (x1 <= x0 || y1 <= y0) {
1524
- return result;
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;
1525
1784
  }
1526
- const rowCount = y1 - y0;
1527
- const rowLen = (x1 - x0) * 4;
1528
- for (let row = 0; row < rowCount; row++) {
1529
- const dstY = y0 + row;
1530
- const srcY = dstY - offsetY;
1531
- const srcX = x0 - offsetX;
1532
- const dstStart = (dstY * newWidth + x0) * 4;
1533
- const srcStart = (srcY * oldW + srcX) * 4;
1534
- newData.set(
1535
- oldData.subarray(srcStart, srcStart + rowLen),
1536
- dstStart
1537
- );
1785
+ if (y < 0) {
1786
+ h += y;
1787
+ y = 0;
1788
+ }
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) {
1792
+ return;
1793
+ }
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++;
1814
+ continue;
1815
+ }
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;
1837
+ } else {
1838
+ finalAlpha = da * weight + 128 >> 8;
1839
+ }
1840
+ dst32[dIdx] = (d & 16777215 | finalAlpha << 24) >>> 0;
1841
+ }
1842
+ dIdx++;
1843
+ mIdx++;
1844
+ }
1845
+ dIdx += dStride;
1846
+ mIdx += mStride;
1538
1847
  }
1539
- return result;
1540
1848
  }
1541
1849
 
1542
- // src/ImageData/serialization.ts
1543
- function base64EncodeArrayBuffer(buffer) {
1544
- const uint8 = new Uint8Array(buffer);
1545
- const decoder = new TextDecoder("latin1");
1546
- const binary = decoder.decode(uint8);
1547
- return btoa(binary);
1548
- }
1549
- function base64DecodeArrayBuffer(encoded) {
1550
- const binary = atob(encoded);
1551
- const bytes = new Uint8ClampedArray(binary.length);
1552
- for (let i = 0; i < binary.length; i++) {
1553
- bytes[i] = binary.charCodeAt(i);
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();
1554
1887
  }
1555
- return bytes;
1556
- }
1557
- function serializeImageData(imageData) {
1558
- return {
1559
- width: imageData.width,
1560
- height: imageData.height,
1561
- data: base64EncodeArrayBuffer(imageData.data.buffer)
1562
- };
1563
- }
1564
- function serializeNullableImageData(imageData) {
1565
- if (!imageData) return null;
1566
- return serializeImageData(imageData);
1567
- }
1568
- function deserializeRawImageData(serialized) {
1888
+ };
1889
+
1890
+ // src/History/PixelMutator/mutatorApplyMask.ts
1891
+ function mutatorApplyMask(writer) {
1569
1892
  return {
1570
- width: serialized.width,
1571
- height: serialized.height,
1572
- data: base64DecodeArrayBuffer(serialized.data)
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
+ }
1573
1904
  };
1574
1905
  }
1575
- function deserializeImageData(serialized) {
1576
- const data = base64DecodeArrayBuffer(serialized.data);
1577
- return new ImageData(data, serialized.width, serialized.height);
1578
- }
1579
- function deserializeNullableImageData(serialized) {
1580
- if (!serialized) return null;
1581
- return deserializeImageData(serialized);
1582
- }
1583
1906
 
1584
- // src/ImageData/writeImageData.ts
1585
- function writeImageData(target, source, x, y, sx = 0, sy = 0, sw = source.width, sh = source.height, mask = null, maskType = 1 /* BINARY */) {
1586
- const dstW = target.width;
1587
- const dstH = target.height;
1588
- const dstData = target.data;
1589
- const srcW = source.width;
1590
- const srcData = source.data;
1591
- const x0 = Math.max(0, x);
1592
- const y0 = Math.max(0, y);
1593
- const x1 = Math.min(dstW, x + sw);
1594
- const y1 = Math.min(dstH, y + sh);
1595
- if (x1 <= x0 || y1 <= y0) {
1596
- return;
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;
1597
1934
  }
1598
- const useMask = !!mask;
1599
- const rowCount = y1 - y0;
1600
- const rowLenPixels = x1 - x0;
1601
- for (let row = 0; row < rowCount; row++) {
1602
- const dstY = y0 + row;
1603
- const srcY = sy + (dstY - y);
1604
- const srcXBase = sx + (x0 - x);
1605
- const dstStart = (dstY * dstW + x0) * 4;
1606
- const srcStart = (srcY * srcW + srcXBase) * 4;
1607
- if (useMask && mask) {
1608
- for (let ix = 0; ix < rowLenPixels; ix++) {
1609
- const mi = srcY * srcW + (srcXBase + ix);
1610
- const alpha = mask[mi];
1611
- if (alpha === 0) {
1935
+ if (y < 0) {
1936
+ h += y;
1937
+ y = 0;
1938
+ }
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++;
1612
1983
  continue;
1613
1984
  }
1614
- const di = dstStart + ix * 4;
1615
- const si = srcStart + ix * 4;
1616
- if (maskType === 1 /* BINARY */ || alpha === 255) {
1617
- dstData[di] = srcData[si];
1618
- dstData[di + 1] = srcData[si + 1];
1619
- dstData[di + 2] = srcData[si + 2];
1620
- dstData[di + 3] = srcData[si + 3];
1985
+ }
1986
+ let currentSrcColor = color;
1987
+ if (weight < 255) {
1988
+ let currentSrcAlpha = baseSrcAlpha;
1989
+ if (baseSrcAlpha === 255) {
1990
+ currentSrcAlpha = weight;
1621
1991
  } else {
1622
- const a = alpha / 255;
1623
- const invA = 1 - a;
1624
- dstData[di] = srcData[si] * a + dstData[di] * invA;
1625
- dstData[di + 1] = srcData[si + 1] * a + dstData[di + 1] * invA;
1626
- dstData[di + 2] = srcData[si + 2] * a + dstData[di + 2] * invA;
1627
- dstData[di + 3] = srcData[si + 3] * a + dstData[di + 3] * invA;
1992
+ currentSrcAlpha = baseSrcAlpha * weight + 128 >> 8;
1993
+ }
1994
+ if (!isOverwrite && currentSrcAlpha === 0) {
1995
+ dIdx++;
1996
+ mIdx++;
1997
+ continue;
1628
1998
  }
1999
+ currentSrcColor = (color & 16777215 | currentSrcAlpha << 24) >>> 0;
1629
2000
  }
1630
- } else {
1631
- const byteLen = rowLenPixels * 4;
1632
- const sub = srcData.subarray(srcStart, srcStart + byteLen);
1633
- dstData.set(sub, dstStart);
2001
+ dst32[dIdx] = blendFn(currentSrcColor, dst32[dIdx]);
2002
+ dIdx++;
2003
+ mIdx++;
1634
2004
  }
2005
+ dIdx += dStride;
2006
+ mIdx += mStride;
1635
2007
  }
1636
2008
  }
1637
2009
 
1638
- // src/ImageData/writeImageDataPixels.ts
1639
- function writeImageDataPixels(imageData, data, _x, _y, _w, _h) {
1640
- const { x, y, w, h } = typeof _x === "object" ? _x : { x: _x, y: _y, w: _w, h: _h };
1641
- const { width: dstW, height: dstH, data: dst } = imageData;
1642
- const x0 = Math.max(0, x);
1643
- const y0 = Math.max(0, y);
1644
- const x1 = Math.min(dstW, x + w);
1645
- const y1 = Math.min(dstH, y + h);
1646
- if (x1 <= x0 || y1 <= y0) return;
1647
- const rowLen = (x1 - x0) * 4;
1648
- const srcCol = x0 - x;
1649
- const srcYOffset = y0 - y;
1650
- const actualH = y1 - y0;
1651
- for (let row = 0; row < actualH; row++) {
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);
2022
+ }
2023
+ };
2024
+ }
2025
+
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
+ };
2046
+ }
2047
+
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;
2077
+ }
2078
+ if (sy < 0) {
2079
+ y -= sy;
2080
+ h += sy;
2081
+ sy = 0;
2082
+ }
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;
2089
+ }
2090
+ if (y < 0) {
2091
+ sy -= y;
2092
+ h += y;
2093
+ y = 0;
2094
+ }
2095
+ const actualW = Math.min(w, dst.width - x);
2096
+ const actualH = Math.min(h, dst.height - y);
2097
+ if (actualW <= 0 || actualH <= 0) return;
2098
+ const dst32 = dst.data32;
2099
+ const src32 = src.data32;
2100
+ const dw = dst.width;
2101
+ const sw = src.width;
2102
+ const mPitch = mw ?? width;
2103
+ const isAlphaMask = maskType === 0 /* ALPHA */;
2104
+ const dx = x - targetX;
2105
+ const dy = y - targetY;
2106
+ let dIdx = y * dw + x;
2107
+ let sIdx = sy * sw + sx;
2108
+ let mIdx = (my + dy) * mPitch + (mx + dx);
2109
+ const dStride = dw - actualW;
2110
+ const sStride = sw - actualW;
2111
+ const mStride = mPitch - actualW;
2112
+ const isOverwrite = blendFn.isOverwrite;
2113
+ for (let iy = 0; iy < actualH; iy++) {
2114
+ for (let ix = 0; ix < actualW; ix++) {
2115
+ const baseSrcColor = src32[sIdx];
2116
+ const baseSrcAlpha = baseSrcColor >>> 24;
2117
+ if (baseSrcAlpha === 0 && !isOverwrite) {
2118
+ dIdx++;
2119
+ sIdx++;
2120
+ mIdx++;
2121
+ continue;
2122
+ }
2123
+ let weight = globalAlpha;
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) {
2152
+ dIdx++;
2153
+ sIdx++;
2154
+ mIdx++;
2155
+ continue;
2156
+ }
2157
+ }
2158
+ let currentSrcColor = baseSrcColor;
2159
+ if (weight < 255) {
2160
+ let currentSrcAlpha = baseSrcAlpha;
2161
+ if (baseSrcAlpha === 255) {
2162
+ currentSrcAlpha = weight;
2163
+ } else {
2164
+ currentSrcAlpha = baseSrcAlpha * weight + 128 >> 8;
2165
+ }
2166
+ if (!isOverwrite && currentSrcAlpha === 0) {
2167
+ dIdx++;
2168
+ sIdx++;
2169
+ mIdx++;
2170
+ continue;
2171
+ }
2172
+ currentSrcColor = (baseSrcColor & 16777215 | currentSrcAlpha << 24) >>> 0;
2173
+ }
2174
+ dst32[dIdx] = blendFn(currentSrcColor, dst32[dIdx]);
2175
+ dIdx++;
2176
+ sIdx++;
2177
+ mIdx++;
2178
+ }
2179
+ dIdx += dStride;
2180
+ sIdx += sStride;
2181
+ mIdx += mStride;
2182
+ }
2183
+ }
2184
+
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;
2268
+ const {
2269
+ x: targetX = 0,
2270
+ y: targetY = 0,
2271
+ w: width = pixelData.width,
2272
+ h: height = pixelData.height,
2273
+ mask,
2274
+ mw,
2275
+ mx = 0,
2276
+ my = 0,
2277
+ invertMask = false
2278
+ } = opts;
2279
+ let x = targetX;
2280
+ let y = targetY;
2281
+ let w = width;
2282
+ let h = height;
2283
+ if (x < 0) {
2284
+ w += x;
2285
+ x = 0;
2286
+ }
2287
+ if (y < 0) {
2288
+ h += y;
2289
+ y = 0;
2290
+ }
2291
+ const actualW = Math.min(w, dst.width - x);
2292
+ const actualH = Math.min(h, dst.height - y);
2293
+ if (actualW <= 0 || actualH <= 0) return;
2294
+ const dst32 = dst.data32;
2295
+ const dw = dst.width;
2296
+ const mPitch = mw ?? width;
2297
+ const dx = x - targetX;
2298
+ const dy = y - targetY;
2299
+ let dIdx = y * dw + x;
2300
+ let mIdx = (my + dy) * mPitch + (mx + dx);
2301
+ const dStride = dw - actualW;
2302
+ const mStride = mPitch - actualW;
2303
+ if (mask) {
2304
+ for (let iy = 0; iy < actualH; iy++) {
2305
+ for (let ix = 0; ix < actualW; ix++) {
2306
+ const mVal = mask[mIdx];
2307
+ const isHit = invertMask ? mVal === 0 : mVal === 1;
2308
+ if (isHit) {
2309
+ dst32[dIdx] = dst32[dIdx] ^ 16777215;
2310
+ }
2311
+ dIdx++;
2312
+ mIdx++;
2313
+ }
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++;
2322
+ }
2323
+ dIdx += dStride;
2324
+ }
2325
+ }
2326
+ }
2327
+
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) {
2386
+ const {
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++) {
1652
2629
  const dstStart = ((y0 + row) * dstW + x0) * 4;
1653
2630
  const srcRow = srcYOffset + row;
1654
2631
  const o = (srcRow * w + srcCol) * 4;
@@ -1853,553 +2830,262 @@ async function fileToImageData(file) {
1853
2830
  );
1854
2831
  const ctx = canvas.getContext("2d");
1855
2832
  if (!ctx) throw new Error(OFFSCREEN_CANVAS_CTX_FAILED);
1856
- ctx.drawImage(
1857
- bitmap,
1858
- 0,
1859
- 0
1860
- );
1861
- return ctx.getImageData(
1862
- 0,
1863
- 0,
1864
- bitmap.width,
1865
- bitmap.height
1866
- );
1867
- } finally {
1868
- bitmap?.close();
1869
- }
1870
- }
1871
-
1872
- // src/Input/getSupportedRasterFormats.ts
1873
- var formatsPromise = null;
1874
- var defaultRasterMimes = [
1875
- "image/png",
1876
- "image/jpeg",
1877
- "image/webp",
1878
- "image/avif",
1879
- "image/gif",
1880
- "image/bmp"
1881
- ];
1882
- async function getSupportedPixelFormats(rasterMimes = defaultRasterMimes) {
1883
- if (formatsPromise) {
1884
- return formatsPromise;
1885
- }
1886
- const probeCanvas = async () => {
1887
- const canvas = new OffscreenCanvas(1, 1);
1888
- const results = await Promise.all(
1889
- rasterMimes.map(async (mime) => {
1890
- try {
1891
- const blob = await canvas.convertToBlob({
1892
- type: mime
1893
- });
1894
- return blob.type === mime ? mime : null;
1895
- } catch {
1896
- return null;
1897
- }
1898
- })
1899
- );
1900
- return results.filter((type) => {
1901
- return type !== null;
1902
- });
1903
- };
1904
- formatsPromise = probeCanvas().catch((error) => {
1905
- formatsPromise = null;
1906
- throw error;
1907
- });
1908
- return formatsPromise;
1909
- }
1910
-
1911
- // src/Mask/copyMask.ts
1912
- function copyMask(src) {
1913
- return src.slice();
1914
- }
1915
-
1916
- // src/Mask/invertMask.ts
1917
- function invertBinaryMask(dst) {
1918
- const len = dst.length;
1919
- for (let i = 0; i < len; i++) {
1920
- dst[i] = dst[i] === 0 ? 1 : 0;
1921
- }
1922
- }
1923
- function invertAlphaMask(dst) {
1924
- const len = dst.length;
1925
- for (let i = 0; i < len; i++) {
1926
- dst[i] = 255 - dst[i];
1927
- }
1928
- }
1929
-
1930
- // src/Mask/mergeMasks.ts
1931
- function mergeMasks(dst, dstWidth, src, opts) {
1932
- const {
1933
- x: targetX = 0,
1934
- y: targetY = 0,
1935
- w: width = 0,
1936
- h: height = 0,
1937
- alpha: globalAlpha = 255,
1938
- maskType = 0 /* ALPHA */,
1939
- mw,
1940
- mx = 0,
1941
- my = 0,
1942
- invertMask = false
1943
- } = opts;
1944
- if (width <= 0 || height <= 0 || globalAlpha === 0) {
1945
- return;
1946
- }
1947
- const sPitch = mw ?? width;
1948
- const isAlpha = maskType === 0 /* ALPHA */;
1949
- for (let iy = 0; iy < height; iy++) {
1950
- const dy = targetY + iy;
1951
- const sy = my + iy;
1952
- if (dy < 0 || sy < 0) {
1953
- continue;
1954
- }
1955
- for (let ix = 0; ix < width; ix++) {
1956
- const dx = targetX + ix;
1957
- const sx = mx + ix;
1958
- if (dx < 0 || dx >= dstWidth || sx < 0 || sx >= sPitch) {
1959
- continue;
1960
- }
1961
- const dIdx = dy * dstWidth + dx;
1962
- const sIdx = sy * sPitch + sx;
1963
- const mVal = src[sIdx];
1964
- let weight = globalAlpha;
1965
- if (isAlpha) {
1966
- const effectiveM = invertMask ? 255 - mVal : mVal;
1967
- if (effectiveM === 0) {
1968
- dst[dIdx] = 0;
1969
- continue;
1970
- }
1971
- weight = globalAlpha === 255 ? effectiveM : effectiveM * globalAlpha + 128 >> 8;
1972
- } else {
1973
- const isHit = invertMask ? mVal === 0 : mVal === 1;
1974
- if (!isHit) {
1975
- dst[dIdx] = 0;
1976
- continue;
1977
- }
1978
- weight = globalAlpha;
1979
- }
1980
- if (weight === 0) {
1981
- dst[dIdx] = 0;
1982
- continue;
1983
- }
1984
- const da = dst[dIdx];
1985
- if (da === 0) {
1986
- } else if (weight === 255) {
1987
- } else if (da === 255) {
1988
- dst[dIdx] = weight;
1989
- } else {
1990
- dst[dIdx] = da * weight + 128 >> 8;
1991
- }
1992
- }
1993
- }
1994
- }
1995
-
1996
- // src/PixelData/PixelData.ts
1997
- var PixelData = class _PixelData {
1998
- data32;
1999
- imageData;
2000
- get width() {
2001
- return this.imageData.width;
2002
- }
2003
- get height() {
2004
- return this.imageData.height;
2005
- }
2006
- constructor(imageData) {
2007
- this.data32 = imageDataToUInt32Array(imageData);
2008
- this.imageData = imageData;
2009
- }
2010
- set(imageData) {
2011
- this.imageData = imageData;
2012
- this.data32 = imageDataToUInt32Array(imageData);
2013
- }
2014
- /**
2015
- * Creates a deep copy of the PixelData using the environment's ImageData constructor.
2016
- */
2017
- copy() {
2018
- const buffer = new Uint8ClampedArray(this.imageData.data);
2019
- const ImageConstructor = typeof ImageData !== "undefined" ? ImageData : this.imageData.constructor;
2020
- const newImageData = new ImageConstructor(
2021
- buffer,
2022
- this.width,
2023
- this.height
2833
+ ctx.drawImage(
2834
+ bitmap,
2835
+ 0,
2836
+ 0
2024
2837
  );
2025
- return new _PixelData(newImageData);
2838
+ return ctx.getImageData(
2839
+ 0,
2840
+ 0,
2841
+ bitmap.width,
2842
+ bitmap.height
2843
+ );
2844
+ } finally {
2845
+ bitmap?.close();
2026
2846
  }
2027
- };
2847
+ }
2028
2848
 
2029
- // src/PixelData/applyMaskToPixelData.ts
2030
- function applyMaskToPixelData(dst, mask, opts) {
2031
- const {
2032
- x: targetX = 0,
2033
- y: targetY = 0,
2034
- w: width = dst.width,
2035
- h: height = dst.height,
2036
- alpha: globalAlpha = 255,
2037
- maskType = 0 /* ALPHA */,
2038
- mw,
2039
- mx = 0,
2040
- my = 0,
2041
- invertMask = false
2042
- } = opts;
2043
- let x = targetX;
2044
- let y = targetY;
2045
- let w = width;
2046
- let h = height;
2047
- if (x < 0) {
2048
- w += x;
2049
- x = 0;
2050
- }
2051
- if (y < 0) {
2052
- h += y;
2053
- y = 0;
2054
- }
2055
- const actualW = Math.min(w, dst.width - x);
2056
- const actualH = Math.min(h, dst.height - y);
2057
- if (actualW <= 0 || actualH <= 0 || globalAlpha === 0) {
2058
- return;
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;
2059
2862
  }
2060
- const dst32 = dst.data32;
2061
- const dw = dst.width;
2062
- const mPitch = mw ?? width;
2063
- const isAlpha = maskType === 0 /* ALPHA */;
2064
- const dx = x - targetX;
2065
- const dy = y - targetY;
2066
- let dIdx = y * dw + x;
2067
- let mIdx = (my + dy) * mPitch + (mx + dx);
2068
- const dStride = dw - actualW;
2069
- const mStride = mPitch - actualW;
2070
- for (let iy = 0; iy < actualH; iy++) {
2071
- for (let ix = 0; ix < actualW; ix++) {
2072
- const mVal = mask[mIdx];
2073
- let weight = globalAlpha;
2074
- if (isAlpha) {
2075
- const effectiveM = invertMask ? 255 - mVal : mVal;
2076
- if (effectiveM === 0) {
2077
- dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
2078
- dIdx++;
2079
- mIdx++;
2080
- continue;
2081
- }
2082
- weight = globalAlpha === 255 ? effectiveM : effectiveM * globalAlpha + 128 >> 8;
2083
- } else {
2084
- const isHit = invertMask ? mVal === 0 : mVal === 1;
2085
- if (!isHit) {
2086
- dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
2087
- dIdx++;
2088
- mIdx++;
2089
- continue;
2090
- }
2091
- weight = globalAlpha;
2092
- }
2093
- if (weight === 0) {
2094
- dst32[dIdx] = (dst32[dIdx] & 16777215) >>> 0;
2095
- } else {
2096
- const d = dst32[dIdx];
2097
- const da = d >>> 24;
2098
- let finalAlpha = da;
2099
- if (da === 0) {
2100
- } else if (weight === 255) {
2101
- } else if (da === 255) {
2102
- finalAlpha = weight;
2103
- } else {
2104
- finalAlpha = da * weight + 128 >> 8;
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;
2105
2874
  }
2106
- dst32[dIdx] = (d & 16777215 | finalAlpha << 24) >>> 0;
2107
- }
2108
- dIdx++;
2109
- mIdx++;
2110
- }
2111
- dIdx += dStride;
2112
- mIdx += mStride;
2113
- }
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;
2114
2886
  }
2115
2887
 
2116
- // src/PixelData/blendColorPixelData.ts
2117
- function blendColorPixelData(dst, color, opts = {}) {
2118
- const {
2119
- x: targetX = 0,
2120
- y: targetY = 0,
2121
- w: width = dst.width,
2122
- h: height = dst.height,
2123
- alpha: globalAlpha = 255,
2124
- blendFn = sourceOverFast,
2125
- mask,
2126
- maskType = 0 /* ALPHA */,
2127
- mw,
2128
- mx = 0,
2129
- my = 0,
2130
- invertMask = false
2131
- } = opts;
2132
- if (globalAlpha === 0) return;
2133
- const baseSrcAlpha = color >>> 24;
2134
- const isOverwrite = blendFn.isOverwrite;
2135
- if (baseSrcAlpha === 0 && !isOverwrite) return;
2136
- let x = targetX;
2137
- let y = targetY;
2138
- let w = width;
2139
- let h = height;
2140
- if (x < 0) {
2141
- w += x;
2142
- x = 0;
2143
- }
2144
- if (y < 0) {
2145
- h += y;
2146
- y = 0;
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;
2147
2898
  }
2148
- const actualW = Math.min(w, dst.width - x);
2149
- const actualH = Math.min(h, dst.height - y);
2150
- if (actualW <= 0 || actualH <= 0) return;
2151
- const dst32 = dst.data32;
2152
- const dw = dst.width;
2153
- const mPitch = mw ?? width;
2154
- const isAlphaMask = maskType === 0 /* ALPHA */;
2155
- const dx = x - targetX;
2156
- const dy = y - targetY;
2157
- let dIdx = y * dw + x;
2158
- let mIdx = (my + dy) * mPitch + (mx + dx);
2159
- const dStride = dw - actualW;
2160
- const mStride = mPitch - actualW;
2161
- for (let iy = 0; iy < actualH; iy++) {
2162
- for (let ix = 0; ix < actualW; ix++) {
2163
- let weight = globalAlpha;
2164
- if (mask) {
2165
- const mVal = mask[mIdx];
2166
- if (isAlphaMask) {
2167
- const effectiveM = invertMask ? 255 - mVal : mVal;
2168
- if (effectiveM === 0) {
2169
- dIdx++;
2170
- mIdx++;
2171
- continue;
2172
- }
2173
- if (globalAlpha === 255) {
2174
- weight = effectiveM;
2175
- } else if (effectiveM === 255) {
2176
- weight = globalAlpha;
2177
- } else {
2178
- weight = effectiveM * globalAlpha + 128 >> 8;
2179
- }
2180
- } else {
2181
- const isHit = invertMask ? mVal === 0 : mVal === 1;
2182
- if (!isHit) {
2183
- dIdx++;
2184
- mIdx++;
2185
- continue;
2186
- }
2187
- weight = globalAlpha;
2188
- }
2189
- if (weight === 0) {
2190
- dIdx++;
2191
- mIdx++;
2192
- continue;
2193
- }
2194
- }
2195
- let currentSrcColor = color;
2196
- if (weight < 255) {
2197
- let currentSrcAlpha = baseSrcAlpha;
2198
- if (baseSrcAlpha === 255) {
2199
- currentSrcAlpha = weight;
2200
- } else {
2201
- currentSrcAlpha = baseSrcAlpha * weight + 128 >> 8;
2202
- }
2203
- if (!isOverwrite && currentSrcAlpha === 0) {
2204
- dIdx++;
2205
- mIdx++;
2206
- continue;
2207
- }
2208
- currentSrcColor = (color & 16777215 | currentSrcAlpha << 24) >>> 0;
2209
- }
2210
- dst32[dIdx] = blendFn(currentSrcColor, dst32[dIdx]);
2211
- dIdx++;
2212
- mIdx++;
2213
- }
2214
- dIdx += dStride;
2215
- mIdx += mStride;
2899
+ }
2900
+ function invertAlphaMask(dst) {
2901
+ const len = dst.length;
2902
+ for (let i = 0; i < len; i++) {
2903
+ dst[i] = 255 - dst[i];
2216
2904
  }
2217
2905
  }
2218
2906
 
2219
- // src/PixelData/blendPixelData.ts
2220
- function blendPixelData(dst, src, opts) {
2907
+ // src/Mask/mergeMasks.ts
2908
+ function mergeMasks(dst, dstWidth, src, opts) {
2221
2909
  const {
2222
- x: targetX = 0,
2223
- y: targetY = 0,
2224
- sx: sourceX = 0,
2225
- sy: sourceY = 0,
2226
- w: width = src.width,
2227
- h: height = src.height,
2910
+ x: targetX = 0,
2911
+ y: targetY = 0,
2912
+ w: width = 0,
2913
+ h: height = 0,
2228
2914
  alpha: globalAlpha = 255,
2229
- blendFn = sourceOverFast,
2230
- mask,
2231
2915
  maskType = 0 /* ALPHA */,
2232
2916
  mw,
2233
2917
  mx = 0,
2234
2918
  my = 0,
2235
2919
  invertMask = false
2236
2920
  } = opts;
2237
- if (globalAlpha === 0) return;
2238
- let x = targetX;
2239
- let y = targetY;
2240
- let sx = sourceX;
2241
- let sy = sourceY;
2242
- let w = width;
2243
- let h = height;
2244
- if (sx < 0) {
2245
- x -= sx;
2246
- w += sx;
2247
- sx = 0;
2248
- }
2249
- if (sy < 0) {
2250
- y -= sy;
2251
- h += sy;
2252
- sy = 0;
2253
- }
2254
- w = Math.min(w, src.width - sx);
2255
- h = Math.min(h, src.height - sy);
2256
- if (x < 0) {
2257
- sx -= x;
2258
- w += x;
2259
- x = 0;
2260
- }
2261
- if (y < 0) {
2262
- sy -= y;
2263
- h += y;
2264
- y = 0;
2921
+ if (width <= 0 || height <= 0 || globalAlpha === 0) {
2922
+ return;
2265
2923
  }
2266
- const actualW = Math.min(w, dst.width - x);
2267
- const actualH = Math.min(h, dst.height - y);
2268
- if (actualW <= 0 || actualH <= 0) return;
2269
- const dst32 = dst.data32;
2270
- const src32 = src.data32;
2271
- const dw = dst.width;
2272
- const sw = src.width;
2273
- const mPitch = mw ?? width;
2274
- const isAlphaMask = maskType === 0 /* ALPHA */;
2275
- const dx = x - targetX;
2276
- const dy = y - targetY;
2277
- let dIdx = y * dw + x;
2278
- let sIdx = sy * sw + sx;
2279
- let mIdx = (my + dy) * mPitch + (mx + dx);
2280
- const dStride = dw - actualW;
2281
- const sStride = sw - actualW;
2282
- const mStride = mPitch - actualW;
2283
- const isOverwrite = blendFn.isOverwrite;
2284
- for (let iy = 0; iy < actualH; iy++) {
2285
- for (let ix = 0; ix < actualW; ix++) {
2286
- const baseSrcColor = src32[sIdx];
2287
- const baseSrcAlpha = baseSrcColor >>> 24;
2288
- if (baseSrcAlpha === 0 && !isOverwrite) {
2289
- dIdx++;
2290
- sIdx++;
2291
- 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) {
2292
2936
  continue;
2293
2937
  }
2938
+ const dIdx = dy * dstWidth + dx;
2939
+ const sIdx = sy * sPitch + sx;
2940
+ const mVal = src[sIdx];
2294
2941
  let weight = globalAlpha;
2295
- if (mask) {
2296
- const mVal = mask[mIdx];
2297
- if (isAlphaMask) {
2298
- const effectiveM = invertMask ? 255 - mVal : mVal;
2299
- if (effectiveM === 0) {
2300
- dIdx++;
2301
- sIdx++;
2302
- mIdx++;
2303
- continue;
2304
- }
2305
- if (globalAlpha === 255) {
2306
- weight = effectiveM;
2307
- } else if (effectiveM === 255) {
2308
- weight = globalAlpha;
2309
- } else {
2310
- weight = effectiveM * globalAlpha + 128 >> 8;
2311
- }
2312
- } else {
2313
- const isHit = invertMask ? mVal === 0 : mVal === 1;
2314
- if (!isHit) {
2315
- dIdx++;
2316
- sIdx++;
2317
- mIdx++;
2318
- continue;
2319
- }
2320
- weight = globalAlpha;
2321
- }
2322
- if (weight === 0) {
2323
- dIdx++;
2324
- sIdx++;
2325
- mIdx++;
2942
+ if (isAlpha) {
2943
+ const effectiveM = invertMask ? 255 - mVal : mVal;
2944
+ if (effectiveM === 0) {
2945
+ dst[dIdx] = 0;
2326
2946
  continue;
2327
2947
  }
2328
- }
2329
- let currentSrcColor = baseSrcColor;
2330
- if (weight < 255) {
2331
- let currentSrcAlpha = baseSrcAlpha;
2332
- if (baseSrcAlpha === 255) {
2333
- currentSrcAlpha = weight;
2334
- } else {
2335
- currentSrcAlpha = baseSrcAlpha * weight + 128 >> 8;
2336
- }
2337
- if (!isOverwrite && currentSrcAlpha === 0) {
2338
- dIdx++;
2339
- sIdx++;
2340
- 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;
2341
2953
  continue;
2342
2954
  }
2343
- currentSrcColor = (baseSrcColor & 16777215 | currentSrcAlpha << 24) >>> 0;
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;
2344
2968
  }
2345
- dst32[dIdx] = blendFn(currentSrcColor, dst32[dIdx]);
2346
- dIdx++;
2347
- sIdx++;
2348
- mIdx++;
2349
2969
  }
2350
- dIdx += dStride;
2351
- sIdx += sStride;
2352
- mIdx += mStride;
2353
2970
  }
2354
2971
  }
2355
2972
 
2356
- // src/PixelData/fillPixelData.ts
2357
- function fillPixelData(dst, color, _x, _y, _w, _h) {
2358
- let x;
2359
- let y;
2360
- let w;
2361
- let h;
2362
- if (typeof _x === "object") {
2363
- x = _x.x ?? 0;
2364
- y = _x.y ?? 0;
2365
- w = _x.w ?? dst.width;
2366
- h = _x.h ?? dst.height;
2367
- } else if (typeof _x === "number") {
2368
- x = _x;
2369
- y = _y;
2370
- w = _w;
2371
- h = _h;
2372
- } else {
2373
- x = 0;
2374
- y = 0;
2375
- w = dst.width;
2376
- 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;
2377
2979
  }
2378
- if (x < 0) {
2379
- w += x;
2380
- x = 0;
2980
+ get height() {
2981
+ return this.imageData.height;
2381
2982
  }
2382
- if (y < 0) {
2383
- h += y;
2384
- y = 0;
2983
+ constructor(imageData) {
2984
+ this.data32 = imageDataToUInt32Array(imageData);
2985
+ this.imageData = imageData;
2385
2986
  }
2386
- const actualW = Math.min(w, dst.width - x);
2387
- const actualH = Math.min(h, dst.height - y);
2388
- if (actualW <= 0 || actualH <= 0) {
2389
- return;
2987
+ set(imageData) {
2988
+ this.imageData = imageData;
2989
+ this.data32 = imageDataToUInt32Array(imageData);
2390
2990
  }
2391
- const dst32 = dst.data32;
2392
- const dw = dst.width;
2393
- if (actualW === dw && actualH === dst.height && x === 0 && y === 0) {
2394
- dst32.fill(color);
2395
- return;
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);
2396
3003
  }
2397
- for (let iy = 0; iy < actualH; iy++) {
2398
- const start = (y + iy) * dw + x;
2399
- const end = start + actualW;
2400
- dst32.fill(color, start, end);
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
+ }
2401
3071
  }
2402
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
+ }
2403
3089
 
2404
3090
  // src/PixelData/clearPixelData.ts
2405
3091
  function clearPixelData(dst, rect) {
@@ -2447,16 +3133,6 @@ function extractPixelData(source, _x, _y, _w, _h) {
2447
3133
  return result;
2448
3134
  }
2449
3135
 
2450
- // src/PixelData/invertPixelData.ts
2451
- function invertPixelData(pixelData) {
2452
- const data32 = pixelData.data32;
2453
- const len = data32.length;
2454
- for (let i = 0; i < len; i++) {
2455
- data32[i] = data32[i] ^ 16777215;
2456
- }
2457
- return pixelData;
2458
- }
2459
-
2460
3136
  // src/PixelData/reflectPixelData.ts
2461
3137
  function reflectPixelDataHorizontal(pixelData) {
2462
3138
  const width = pixelData.width;
@@ -2547,15 +3223,53 @@ function rotateSquareInPlace(pixelData) {
2547
3223
  }
2548
3224
  }
2549
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
+ }
2550
3256
  export {
2551
3257
  BASE_FAST_BLEND_MODE_FUNCTIONS,
2552
3258
  BASE_PERFECT_BLEND_MODE_FUNCTIONS,
2553
3259
  BaseBlendMode,
3260
+ HistoryManager,
2554
3261
  IndexedImage,
2555
3262
  MaskType,
3263
+ PixelAccumulator,
2556
3264
  PixelData,
3265
+ PixelEngineConfig,
3266
+ PixelTile,
3267
+ PixelWriter,
2557
3268
  UnsupportedFormatError,
3269
+ applyCircleBrushToPixelData,
2558
3270
  applyMaskToPixelData,
3271
+ applyPatchTiles,
3272
+ applyRectBrushToPixelData,
2559
3273
  base64DecodeArrayBuffer,
2560
3274
  base64EncodeArrayBuffer,
2561
3275
  blendColorPixelData,
@@ -2594,6 +3308,7 @@ export {
2594
3308
  floodFillSelection,
2595
3309
  getImageDataFromClipboard,
2596
3310
  getIndexedImageColorCounts,
3311
+ getRectBrushBounds,
2597
3312
  getSupportedPixelFormats,
2598
3313
  hardLightFast,
2599
3314
  hardLightPerfect,
@@ -2624,6 +3339,7 @@ export {
2624
3339
  linearLightPerfect,
2625
3340
  makeBlendModeRegistry,
2626
3341
  makeFastBlendModeRegistry,
3342
+ makeFullPixelMutator,
2627
3343
  makePerfectBlendModeRegistry,
2628
3344
  makePixelCanvas,
2629
3345
  makeReusableCanvas,
@@ -2631,6 +3347,12 @@ export {
2631
3347
  mergeMasks,
2632
3348
  multiplyFast,
2633
3349
  multiplyPerfect,
3350
+ mutatorApplyMask,
3351
+ mutatorBlendColor,
3352
+ mutatorBlendPixel,
3353
+ mutatorBlendPixelData,
3354
+ mutatorFill,
3355
+ mutatorInvert,
2634
3356
  overlayFast,
2635
3357
  overlayPerfect,
2636
3358
  overwriteBase,
@@ -2668,8 +3390,9 @@ export {
2668
3390
  vividLightFast,
2669
3391
  vividLightPerfect,
2670
3392
  writeImageData,
2671
- writeImageDataPixels,
3393
+ writeImageDataBuffer,
2672
3394
  writeImageDataToClipboard,
2673
- writeImgBlobToClipboard
3395
+ writeImgBlobToClipboard,
3396
+ writePixelDataBuffer
2674
3397
  };
2675
3398
  //# sourceMappingURL=index.dev.js.map