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