pixel-data-js 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.dev.cjs +285 -171
- package/dist/index.dev.cjs.map +1 -1
- package/dist/index.dev.js +284 -171
- package/dist/index.dev.js.map +1 -1
- package/dist/index.prod.cjs +285 -171
- package/dist/index.prod.cjs.map +1 -1
- package/dist/index.prod.d.ts +11 -5
- package/dist/index.prod.js +284 -171
- package/dist/index.prod.js.map +1 -1
- package/package.json +1 -1
- package/src/History/PixelMutator/mutatorApplyCircleBrush.ts +45 -0
- package/src/History/PixelMutator/mutatorApplyRectBrush.ts +48 -0
- package/src/History/PixelMutator.ts +4 -0
- package/src/History/PixelWriter.ts +5 -1
- package/src/ImageData/ReusableImageData.ts +1 -4
- package/src/PixelData/applyCircleBrushToPixelData.ts +72 -17
- package/src/PixelData/applyRectBrushToPixelData.ts +52 -37
package/dist/index.dev.cjs
CHANGED
|
@@ -72,6 +72,7 @@ __export(src_exports, {
|
|
|
72
72
|
fileToImageData: () => fileToImageData,
|
|
73
73
|
fillPixelData: () => fillPixelData,
|
|
74
74
|
floodFillSelection: () => floodFillSelection,
|
|
75
|
+
getCircleBrushBounds: () => getCircleBrushBounds,
|
|
75
76
|
getImageDataFromClipboard: () => getImageDataFromClipboard,
|
|
76
77
|
getIndexedImageColorCounts: () => getIndexedImageColorCounts,
|
|
77
78
|
getRectBrushBounds: () => getRectBrushBounds,
|
|
@@ -1925,6 +1926,148 @@ var PixelEngineConfig = class {
|
|
|
1925
1926
|
}
|
|
1926
1927
|
};
|
|
1927
1928
|
|
|
1929
|
+
// src/PixelData/applyCircleBrushToPixelData.ts
|
|
1930
|
+
function applyCircleBrushToPixelData(target, color, centerX, centerY, brushSize, alpha = 255, fallOff, blendFn = sourceOverPerfect, bounds) {
|
|
1931
|
+
const targetWidth = target.width;
|
|
1932
|
+
const targetHeight = target.height;
|
|
1933
|
+
const b = bounds ?? getCircleBrushBounds(
|
|
1934
|
+
centerX,
|
|
1935
|
+
centerY,
|
|
1936
|
+
brushSize,
|
|
1937
|
+
targetWidth,
|
|
1938
|
+
targetHeight
|
|
1939
|
+
);
|
|
1940
|
+
if (b.w <= 0 || b.h <= 0) return;
|
|
1941
|
+
const data32 = target.data32;
|
|
1942
|
+
const r = brushSize / 2;
|
|
1943
|
+
const rSqr = r * r;
|
|
1944
|
+
const invR = 1 / r;
|
|
1945
|
+
const centerOffset = brushSize % 2 === 0 ? 0.5 : 0;
|
|
1946
|
+
const baseColor = color & 16777215;
|
|
1947
|
+
const constantSrc = (alpha << 24 | baseColor) >>> 0;
|
|
1948
|
+
const endX = b.x + b.w;
|
|
1949
|
+
const endY = b.y + b.h;
|
|
1950
|
+
const fCenterX = Math.floor(centerX);
|
|
1951
|
+
const fCenterY = Math.floor(centerY);
|
|
1952
|
+
for (let cy = b.y; cy < endY; cy++) {
|
|
1953
|
+
const relY = cy - fCenterY + centerOffset;
|
|
1954
|
+
const dySqr = relY * relY;
|
|
1955
|
+
const rowOffset = cy * targetWidth;
|
|
1956
|
+
for (let cx = b.x; cx < endX; cx++) {
|
|
1957
|
+
const relX = cx - fCenterX + centerOffset;
|
|
1958
|
+
const dSqr = relX * relX + dySqr;
|
|
1959
|
+
if (dSqr <= rSqr) {
|
|
1960
|
+
const idx = rowOffset + cx;
|
|
1961
|
+
if (fallOff) {
|
|
1962
|
+
const strength = fallOff(Math.sqrt(dSqr) * invR);
|
|
1963
|
+
const fAlpha = alpha * strength & 255;
|
|
1964
|
+
const src = (fAlpha << 24 | baseColor) >>> 0;
|
|
1965
|
+
data32[idx] = blendFn(src, data32[idx]);
|
|
1966
|
+
} else {
|
|
1967
|
+
data32[idx] = blendFn(constantSrc, data32[idx]);
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
function getCircleBrushBounds(centerX, centerY, brushSize, targetWidth, targetHeight, out) {
|
|
1974
|
+
const r = brushSize / 2;
|
|
1975
|
+
const minOffset = -Math.ceil(r - 0.5);
|
|
1976
|
+
const maxOffset = Math.floor(r - 0.5);
|
|
1977
|
+
const startX = Math.floor(centerX + minOffset);
|
|
1978
|
+
const startY = Math.floor(centerY + minOffset);
|
|
1979
|
+
const endX = Math.floor(centerX + maxOffset) + 1;
|
|
1980
|
+
const endY = Math.floor(centerY + maxOffset) + 1;
|
|
1981
|
+
const res = out ?? {
|
|
1982
|
+
x: 0,
|
|
1983
|
+
y: 0,
|
|
1984
|
+
w: 0,
|
|
1985
|
+
h: 0
|
|
1986
|
+
};
|
|
1987
|
+
const cStartX = targetWidth !== void 0 ? Math.max(0, startX) : startX;
|
|
1988
|
+
const cStartY = targetHeight !== void 0 ? Math.max(0, startY) : startY;
|
|
1989
|
+
const cEndX = targetWidth !== void 0 ? Math.min(targetWidth, endX) : endX;
|
|
1990
|
+
const cEndY = targetHeight !== void 0 ? Math.min(targetHeight, endY) : endY;
|
|
1991
|
+
res.x = cStartX;
|
|
1992
|
+
res.y = cStartY;
|
|
1993
|
+
res.w = Math.max(0, cEndX - cStartX);
|
|
1994
|
+
res.h = Math.max(0, cEndY - cStartY);
|
|
1995
|
+
return res;
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
// src/History/PixelWriter.ts
|
|
1999
|
+
var PixelWriter = class {
|
|
2000
|
+
target;
|
|
2001
|
+
historyManager;
|
|
2002
|
+
accumulator;
|
|
2003
|
+
config;
|
|
2004
|
+
mutator;
|
|
2005
|
+
constructor(target, mutatorFactory, {
|
|
2006
|
+
tileSize = 256,
|
|
2007
|
+
maxHistorySteps = 50,
|
|
2008
|
+
historyManager = new HistoryManager(maxHistorySteps)
|
|
2009
|
+
} = {}) {
|
|
2010
|
+
this.target = target;
|
|
2011
|
+
this.config = new PixelEngineConfig(tileSize);
|
|
2012
|
+
this.historyManager = historyManager;
|
|
2013
|
+
this.accumulator = new PixelAccumulator(target, this.config);
|
|
2014
|
+
this.mutator = mutatorFactory(this);
|
|
2015
|
+
}
|
|
2016
|
+
withHistory(cb) {
|
|
2017
|
+
cb(this.mutator);
|
|
2018
|
+
this.captureHistory();
|
|
2019
|
+
}
|
|
2020
|
+
captureHistory() {
|
|
2021
|
+
const beforeTiles = this.accumulator.beforeTiles;
|
|
2022
|
+
if (beforeTiles.length === 0) return;
|
|
2023
|
+
const afterTiles = this.accumulator.extractAfterTiles();
|
|
2024
|
+
const patch = {
|
|
2025
|
+
beforeTiles,
|
|
2026
|
+
afterTiles
|
|
2027
|
+
};
|
|
2028
|
+
const target = this.target;
|
|
2029
|
+
const tileSize = this.config.tileSize;
|
|
2030
|
+
const accumulator = this.accumulator;
|
|
2031
|
+
const action = {
|
|
2032
|
+
undo: () => applyPatchTiles(target, patch.beforeTiles, tileSize),
|
|
2033
|
+
redo: () => applyPatchTiles(target, patch.afterTiles, tileSize),
|
|
2034
|
+
dispose: () => accumulator.recyclePatch(patch)
|
|
2035
|
+
};
|
|
2036
|
+
this.historyManager.commit(action);
|
|
2037
|
+
this.accumulator.reset();
|
|
2038
|
+
}
|
|
2039
|
+
};
|
|
2040
|
+
|
|
2041
|
+
// src/History/PixelMutator/mutatorApplyCircleBrush.ts
|
|
2042
|
+
var boundsOut = { x: 0, y: 0, w: 0, h: 0 };
|
|
2043
|
+
function mutatorApplyCircleBrush(writer) {
|
|
2044
|
+
return {
|
|
2045
|
+
applyCircleBrush(color, centerX, centerY, brushSize, alpha = 255, fallOff, blendFn) {
|
|
2046
|
+
const circleBounds = getCircleBrushBounds(
|
|
2047
|
+
centerX,
|
|
2048
|
+
centerY,
|
|
2049
|
+
brushSize,
|
|
2050
|
+
writer.target.width,
|
|
2051
|
+
writer.target.height,
|
|
2052
|
+
boundsOut
|
|
2053
|
+
);
|
|
2054
|
+
const { x, y, w, h } = circleBounds;
|
|
2055
|
+
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2056
|
+
applyCircleBrushToPixelData(
|
|
2057
|
+
writer.target,
|
|
2058
|
+
color,
|
|
2059
|
+
centerX,
|
|
2060
|
+
centerY,
|
|
2061
|
+
brushSize,
|
|
2062
|
+
alpha,
|
|
2063
|
+
fallOff,
|
|
2064
|
+
blendFn,
|
|
2065
|
+
circleBounds
|
|
2066
|
+
);
|
|
2067
|
+
}
|
|
2068
|
+
};
|
|
2069
|
+
}
|
|
2070
|
+
|
|
1928
2071
|
// src/PixelData/applyMaskToPixelData.ts
|
|
1929
2072
|
function applyMaskToPixelData(dst, mask, opts = {}) {
|
|
1930
2073
|
const {
|
|
@@ -2012,46 +2155,6 @@ function applyMaskToPixelData(dst, mask, opts = {}) {
|
|
|
2012
2155
|
}
|
|
2013
2156
|
}
|
|
2014
2157
|
|
|
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();
|
|
2052
|
-
}
|
|
2053
|
-
};
|
|
2054
|
-
|
|
2055
2158
|
// src/History/PixelMutator/mutatorApplyMask.ts
|
|
2056
2159
|
function mutatorApplyMask(writer) {
|
|
2057
2160
|
return {
|
|
@@ -2069,6 +2172,143 @@ function mutatorApplyMask(writer) {
|
|
|
2069
2172
|
};
|
|
2070
2173
|
}
|
|
2071
2174
|
|
|
2175
|
+
// src/ImageData/imageDataToUInt32Array.ts
|
|
2176
|
+
function imageDataToUInt32Array(imageData) {
|
|
2177
|
+
return new Uint32Array(
|
|
2178
|
+
imageData.data.buffer,
|
|
2179
|
+
imageData.data.byteOffset,
|
|
2180
|
+
// Shift right by 2 is a fast bitwise division by 4.
|
|
2181
|
+
imageData.data.byteLength >> 2
|
|
2182
|
+
);
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2185
|
+
// src/PixelData/PixelData.ts
|
|
2186
|
+
var PixelData = class _PixelData {
|
|
2187
|
+
data32;
|
|
2188
|
+
imageData;
|
|
2189
|
+
get width() {
|
|
2190
|
+
return this.imageData.width;
|
|
2191
|
+
}
|
|
2192
|
+
get height() {
|
|
2193
|
+
return this.imageData.height;
|
|
2194
|
+
}
|
|
2195
|
+
constructor(imageData) {
|
|
2196
|
+
this.data32 = imageDataToUInt32Array(imageData);
|
|
2197
|
+
this.imageData = imageData;
|
|
2198
|
+
}
|
|
2199
|
+
set(imageData) {
|
|
2200
|
+
this.imageData = imageData;
|
|
2201
|
+
this.data32 = imageDataToUInt32Array(imageData);
|
|
2202
|
+
}
|
|
2203
|
+
/**
|
|
2204
|
+
* Creates a deep copy of the PixelData using the environment's ImageData constructor.
|
|
2205
|
+
*/
|
|
2206
|
+
copy() {
|
|
2207
|
+
const buffer = new Uint8ClampedArray(this.imageData.data);
|
|
2208
|
+
const ImageConstructor = typeof ImageData !== "undefined" ? ImageData : this.imageData.constructor;
|
|
2209
|
+
const newImageData = new ImageConstructor(
|
|
2210
|
+
buffer,
|
|
2211
|
+
this.width,
|
|
2212
|
+
this.height
|
|
2213
|
+
);
|
|
2214
|
+
return new _PixelData(newImageData);
|
|
2215
|
+
}
|
|
2216
|
+
};
|
|
2217
|
+
|
|
2218
|
+
// src/PixelData/applyRectBrushToPixelData.ts
|
|
2219
|
+
function applyRectBrushToPixelData(target, color, centerX, centerY, brushWidth, brushHeight, alpha = 255, fallOff, blendFn = sourceOverPerfect, bounds) {
|
|
2220
|
+
const targetWidth = target.width;
|
|
2221
|
+
const targetHeight = target.height;
|
|
2222
|
+
const b = bounds ?? getRectBrushBounds(
|
|
2223
|
+
centerX,
|
|
2224
|
+
centerY,
|
|
2225
|
+
brushWidth,
|
|
2226
|
+
brushHeight,
|
|
2227
|
+
targetWidth,
|
|
2228
|
+
targetHeight
|
|
2229
|
+
);
|
|
2230
|
+
if (b.w <= 0 || b.h <= 0) return;
|
|
2231
|
+
const data32 = target.data32;
|
|
2232
|
+
const baseColor = color & 16777215;
|
|
2233
|
+
const constantSrc = (alpha << 24 | baseColor) >>> 0;
|
|
2234
|
+
const invHalfW = 1 / (brushWidth / 2);
|
|
2235
|
+
const invHalfH = 1 / (brushHeight / 2);
|
|
2236
|
+
const endX = b.x + b.w;
|
|
2237
|
+
const endY = b.y + b.h;
|
|
2238
|
+
for (let py = b.y; py < endY; py++) {
|
|
2239
|
+
const rowOffset = py * targetWidth;
|
|
2240
|
+
const dy = fallOff ? Math.abs(py + 0.5 - centerY) * invHalfH : 0;
|
|
2241
|
+
for (let px = b.x; px < endX; px++) {
|
|
2242
|
+
const idx = rowOffset + px;
|
|
2243
|
+
if (fallOff) {
|
|
2244
|
+
const dx = Math.abs(px + 0.5 - centerX) * invHalfW;
|
|
2245
|
+
const dist = dx > dy ? dx : dy;
|
|
2246
|
+
const strength = fallOff(dist);
|
|
2247
|
+
const fAlpha = alpha * strength | 0;
|
|
2248
|
+
const src = (fAlpha << 24 | baseColor) >>> 0;
|
|
2249
|
+
data32[idx] = blendFn(src, data32[idx]);
|
|
2250
|
+
} else {
|
|
2251
|
+
data32[idx] = blendFn(constantSrc, data32[idx]);
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
function getRectBrushBounds(centerX, centerY, brushWidth, brushHeight, targetWidth, targetHeight, out) {
|
|
2257
|
+
const startX = Math.floor(centerX - brushWidth / 2);
|
|
2258
|
+
const startY = Math.floor(centerY - brushHeight / 2);
|
|
2259
|
+
const endX = startX + brushWidth;
|
|
2260
|
+
const endY = startY + brushHeight;
|
|
2261
|
+
const res = out ?? {
|
|
2262
|
+
x: 0,
|
|
2263
|
+
y: 0,
|
|
2264
|
+
w: 0,
|
|
2265
|
+
h: 0
|
|
2266
|
+
};
|
|
2267
|
+
const cStartX = targetWidth !== void 0 ? Math.max(0, startX) : startX;
|
|
2268
|
+
const cStartY = targetHeight !== void 0 ? Math.max(0, startY) : startY;
|
|
2269
|
+
const cEndX = targetWidth !== void 0 ? Math.min(targetWidth, endX) : endX;
|
|
2270
|
+
const cEndY = targetHeight !== void 0 ? Math.min(targetHeight, endY) : endY;
|
|
2271
|
+
const w = cEndX - cStartX;
|
|
2272
|
+
const h = cEndY - cStartY;
|
|
2273
|
+
res.x = cStartX;
|
|
2274
|
+
res.y = cStartY;
|
|
2275
|
+
res.w = w < 0 ? 0 : w;
|
|
2276
|
+
res.h = h < 0 ? 0 : h;
|
|
2277
|
+
return res;
|
|
2278
|
+
}
|
|
2279
|
+
|
|
2280
|
+
// src/History/PixelMutator/mutatorApplyRectBrush.ts
|
|
2281
|
+
var boundsOut2 = { x: 0, y: 0, w: 0, h: 0 };
|
|
2282
|
+
function mutatorApplyRectBrush(writer) {
|
|
2283
|
+
return {
|
|
2284
|
+
applyRectBrush(color, centerX, centerY, brushWidth, brushHeight, alpha = 255, fallOff, blendFn) {
|
|
2285
|
+
const bounds = getRectBrushBounds(
|
|
2286
|
+
centerX,
|
|
2287
|
+
centerY,
|
|
2288
|
+
brushWidth,
|
|
2289
|
+
brushHeight,
|
|
2290
|
+
writer.target.width,
|
|
2291
|
+
writer.target.height,
|
|
2292
|
+
boundsOut2
|
|
2293
|
+
);
|
|
2294
|
+
const { x, y, w, h } = bounds;
|
|
2295
|
+
writer.accumulator.storeRegionBeforeState(x, y, w, h);
|
|
2296
|
+
applyRectBrushToPixelData(
|
|
2297
|
+
writer.target,
|
|
2298
|
+
color,
|
|
2299
|
+
centerX,
|
|
2300
|
+
centerY,
|
|
2301
|
+
brushWidth,
|
|
2302
|
+
brushHeight,
|
|
2303
|
+
alpha,
|
|
2304
|
+
fallOff,
|
|
2305
|
+
blendFn,
|
|
2306
|
+
bounds
|
|
2307
|
+
);
|
|
2308
|
+
}
|
|
2309
|
+
};
|
|
2310
|
+
}
|
|
2311
|
+
|
|
2072
2312
|
// src/PixelData/blendColorPixelData.ts
|
|
2073
2313
|
function blendColorPixelData(dst, color, opts = {}) {
|
|
2074
2314
|
const {
|
|
@@ -2514,21 +2754,21 @@ function makeFullPixelMutator(writer) {
|
|
|
2514
2754
|
...mutatorBlendColor(writer),
|
|
2515
2755
|
...mutatorBlendPixel(writer),
|
|
2516
2756
|
...mutatorFill(writer),
|
|
2517
|
-
...mutatorInvert(writer)
|
|
2757
|
+
...mutatorInvert(writer),
|
|
2758
|
+
...mutatorApplyCircleBrush(writer),
|
|
2759
|
+
...mutatorApplyRectBrush(writer)
|
|
2518
2760
|
};
|
|
2519
2761
|
}
|
|
2520
2762
|
|
|
2521
2763
|
// src/ImageData/ReusableImageData.ts
|
|
2522
2764
|
function makeReusableImageData() {
|
|
2523
2765
|
let imageData = null;
|
|
2524
|
-
let buffer = null;
|
|
2525
2766
|
return function getReusableImageData(width, height) {
|
|
2526
2767
|
const hasInstance = !!imageData;
|
|
2527
2768
|
const widthMatches = hasInstance && imageData.width === width;
|
|
2528
2769
|
const heightMatches = hasInstance && imageData.height === height;
|
|
2529
2770
|
if (!widthMatches || !heightMatches) {
|
|
2530
|
-
|
|
2531
|
-
imageData = new ImageData(buffer2, width, height);
|
|
2771
|
+
imageData = new ImageData(width, height);
|
|
2532
2772
|
}
|
|
2533
2773
|
return imageData;
|
|
2534
2774
|
};
|
|
@@ -2592,16 +2832,6 @@ function imageDataToDataUrl(imageData) {
|
|
|
2592
2832
|
}
|
|
2593
2833
|
imageDataToDataUrl.reset = get.reset;
|
|
2594
2834
|
|
|
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
2835
|
// src/ImageData/invertImageData.ts
|
|
2606
2836
|
function invertImageData(imageData) {
|
|
2607
2837
|
const data = imageData.data;
|
|
@@ -3135,123 +3365,6 @@ function mergeMasks(dst, dstWidth, src, opts) {
|
|
|
3135
3365
|
}
|
|
3136
3366
|
}
|
|
3137
3367
|
|
|
3138
|
-
// src/PixelData/PixelData.ts
|
|
3139
|
-
var PixelData = class _PixelData {
|
|
3140
|
-
data32;
|
|
3141
|
-
imageData;
|
|
3142
|
-
get width() {
|
|
3143
|
-
return this.imageData.width;
|
|
3144
|
-
}
|
|
3145
|
-
get height() {
|
|
3146
|
-
return this.imageData.height;
|
|
3147
|
-
}
|
|
3148
|
-
constructor(imageData) {
|
|
3149
|
-
this.data32 = imageDataToUInt32Array(imageData);
|
|
3150
|
-
this.imageData = imageData;
|
|
3151
|
-
}
|
|
3152
|
-
set(imageData) {
|
|
3153
|
-
this.imageData = imageData;
|
|
3154
|
-
this.data32 = imageDataToUInt32Array(imageData);
|
|
3155
|
-
}
|
|
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);
|
|
3168
|
-
}
|
|
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
|
-
}
|
|
3236
|
-
}
|
|
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
|
-
}
|
|
3254
|
-
|
|
3255
3368
|
// src/PixelData/clearPixelData.ts
|
|
3256
3369
|
function clearPixelData(dst, rect) {
|
|
3257
3370
|
fillPixelData(dst, 0, rect);
|
|
@@ -3472,6 +3585,7 @@ function writePixelDataBuffer(target, data, _x, _y, _w, _h) {
|
|
|
3472
3585
|
fileToImageData,
|
|
3473
3586
|
fillPixelData,
|
|
3474
3587
|
floodFillSelection,
|
|
3588
|
+
getCircleBrushBounds,
|
|
3475
3589
|
getImageDataFromClipboard,
|
|
3476
3590
|
getIndexedImageColorCounts,
|
|
3477
3591
|
getRectBrushBounds,
|