@pixerate/editor 0.96.0 → 0.97.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/{chunk-T422YCHR.cjs → chunk-4AB5BHYK.cjs} +237 -63
- package/dist/chunk-4AB5BHYK.cjs.map +1 -0
- package/dist/{chunk-KFTQ2PKP.js → chunk-OEVSVA6V.js} +214 -40
- package/dist/chunk-OEVSVA6V.js.map +1 -0
- package/dist/image-editor/index.cjs +413 -235
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +75 -1
- package/dist/image-editor/index.d.ts +75 -1
- package/dist/image-editor/index.js +254 -76
- package/dist/image-editor/index.js.map +1 -1
- package/dist/raster/index.cjs +4 -2
- package/dist/raster/index.cjs.map +1 -1
- package/dist/raster/index.d.cts +46 -3
- package/dist/raster/index.d.ts +46 -3
- package/dist/raster/index.js +3 -1
- package/package.json +1 -1
- package/dist/chunk-KFTQ2PKP.js.map +0 -1
- package/dist/chunk-T422YCHR.cjs.map +0 -1
|
@@ -1080,11 +1080,18 @@ function boxLine(src, x0, dst, bw) {
|
|
|
1080
1080
|
}
|
|
1081
1081
|
}
|
|
1082
1082
|
var BLUR_EPS = 1e-7;
|
|
1083
|
+
var BLUR_FIX = 2 ** 32;
|
|
1083
1084
|
function tentLine(src, dst, bw, mid) {
|
|
1084
1085
|
const [r] = boxGeom(bw);
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1086
|
+
const m = mid.subarray(0, src.length + 2 * r);
|
|
1087
|
+
for (let i = 0; i < src.length; i++) src[i] = Math.round(src[i] * BLUR_FIX);
|
|
1088
|
+
boxLine(src, -r, m, bw);
|
|
1089
|
+
for (let i = 0; i < m.length; i++) m[i] = Math.round(m[i]);
|
|
1090
|
+
boxLine(m, r, dst, bw);
|
|
1091
|
+
for (let i = 0; i < dst.length; i++) {
|
|
1092
|
+
const v = dst[i] / BLUR_FIX;
|
|
1093
|
+
dst[i] = Math.abs(v) < BLUR_EPS ? 0 : v;
|
|
1094
|
+
}
|
|
1088
1095
|
}
|
|
1089
1096
|
function tent(m, w) {
|
|
1090
1097
|
if (!Number.isFinite(w) || m.v.length === 0) return;
|
|
@@ -1386,25 +1393,41 @@ function effectsAreLocal(items) {
|
|
|
1386
1393
|
}
|
|
1387
1394
|
});
|
|
1388
1395
|
}
|
|
1396
|
+
function shapeBounds(shape, rect) {
|
|
1397
|
+
const { width: w, height: h } = rect;
|
|
1398
|
+
const rowHit = (y) => {
|
|
1399
|
+
for (let x = 0, i = y * w; x < w; x++, i++) if (shape[i] > INSIDE_EPS) return true;
|
|
1400
|
+
return false;
|
|
1401
|
+
};
|
|
1402
|
+
let y0 = 0;
|
|
1403
|
+
while (y0 < h && !rowHit(y0)) y0++;
|
|
1404
|
+
if (y0 === h) return null;
|
|
1405
|
+
let y1 = h - 1;
|
|
1406
|
+
while (!rowHit(y1)) y1--;
|
|
1407
|
+
let x0 = w;
|
|
1408
|
+
let x1 = -1;
|
|
1409
|
+
for (let y = y0; y <= y1; y++) {
|
|
1410
|
+
const o = y * w;
|
|
1411
|
+
for (let x = 0; x < x0; x++) {
|
|
1412
|
+
if (shape[o + x] > INSIDE_EPS) {
|
|
1413
|
+
x0 = x;
|
|
1414
|
+
break;
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
for (let x = w - 1; x > x1; x--) {
|
|
1418
|
+
if (shape[o + x] > INSIDE_EPS) {
|
|
1419
|
+
x1 = x;
|
|
1420
|
+
break;
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
return { x: rect.x + x0, y: rect.y + y0, width: x1 - x0 + 1, height: y1 - y0 + 1 };
|
|
1425
|
+
}
|
|
1389
1426
|
function buildEffectMaps(items, shape, rect, ctx) {
|
|
1390
1427
|
const w = rect.width;
|
|
1391
1428
|
const h = rect.height;
|
|
1392
1429
|
const s = { w, h, v: shape };
|
|
1393
|
-
|
|
1394
|
-
let y0 = Infinity;
|
|
1395
|
-
let x1 = -Infinity;
|
|
1396
|
-
let y1 = -Infinity;
|
|
1397
|
-
for (let y = 0; y < h; y++) {
|
|
1398
|
-
for (let x = 0; x < w; x++) {
|
|
1399
|
-
if (shape[y * w + x] > INSIDE_EPS) {
|
|
1400
|
-
if (x < x0) x0 = x;
|
|
1401
|
-
if (x > x1) x1 = x;
|
|
1402
|
-
if (y < y0) y0 = y;
|
|
1403
|
-
if (y > y1) y1 = y;
|
|
1404
|
-
}
|
|
1405
|
-
}
|
|
1406
|
-
}
|
|
1407
|
-
const bounds = x0 === Infinity ? null : { x: rect.x + x0, y: rect.y + y0, width: x1 - x0 + 1, height: y1 - y0 + 1 };
|
|
1430
|
+
const bounds = shapeBounds(shape, rect);
|
|
1408
1431
|
const anchor = bounds ? { x: bounds.x, y: bounds.y } : { x: rect.x, y: rect.y };
|
|
1409
1432
|
const per = [];
|
|
1410
1433
|
const bevelPaint = [];
|
|
@@ -1452,6 +1475,81 @@ function buildEffectMaps(items, shape, rect, ctx) {
|
|
|
1452
1475
|
for (const d of [din, dout, doutExact]) if (d) bytes += d.byteLength;
|
|
1453
1476
|
return { rect, items, bounds, shape, per, bevelPaint, din, dout, doutExact, frames, bytes };
|
|
1454
1477
|
}
|
|
1478
|
+
var rectArea = (r) => r.width * r.height;
|
|
1479
|
+
function clipRect(a, b) {
|
|
1480
|
+
const x0 = Math.max(a.x, b.x);
|
|
1481
|
+
const y0 = Math.max(a.y, b.y);
|
|
1482
|
+
const x1 = Math.min(a.x + a.width, b.x + b.width);
|
|
1483
|
+
const y1 = Math.min(a.y + a.height, b.y + b.height);
|
|
1484
|
+
return x1 > x0 && y1 > y0 ? { x: x0, y: y0, width: x1 - x0, height: y1 - y0 } : null;
|
|
1485
|
+
}
|
|
1486
|
+
var growRect = (r, m) => ({ x: r.x - m, y: r.y - m, width: r.width + 2 * m, height: r.height + 2 * m });
|
|
1487
|
+
function unionRect(a, b) {
|
|
1488
|
+
const x0 = Math.min(a.x, b.x);
|
|
1489
|
+
const y0 = Math.min(a.y, b.y);
|
|
1490
|
+
return { x: x0, y: y0, width: Math.max(a.x + a.width, b.x + b.width) - x0, height: Math.max(a.y + a.height, b.y + b.height) - y0 };
|
|
1491
|
+
}
|
|
1492
|
+
function rectMinus(r, cut) {
|
|
1493
|
+
const i = clipRect(r, cut);
|
|
1494
|
+
if (!i) return [r];
|
|
1495
|
+
const parts = [
|
|
1496
|
+
{ x: r.x, y: r.y, width: r.width, height: i.y - r.y },
|
|
1497
|
+
{ x: r.x, y: i.y + i.height, width: r.width, height: r.y + r.height - (i.y + i.height) },
|
|
1498
|
+
{ x: r.x, y: i.y, width: i.x - r.x, height: i.height },
|
|
1499
|
+
{ x: i.x + i.width, y: i.y, width: r.x + r.width - (i.x + i.width), height: i.height }
|
|
1500
|
+
];
|
|
1501
|
+
return parts.filter((p) => p.width > 0 && p.height > 0);
|
|
1502
|
+
}
|
|
1503
|
+
function pasteMap(dst, to, src, from, a) {
|
|
1504
|
+
for (let y = a.y; y < a.y + a.height; y++) {
|
|
1505
|
+
const s = (y - from.y) * from.width + (a.x - from.x);
|
|
1506
|
+
dst.set(src.subarray(s, s + a.width), (y - to.y) * to.width + (a.x - to.x));
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
function patchEffectMaps(prev, items, rect, changed, margin, shapeOver, ctx) {
|
|
1510
|
+
if (!effectsAreLocal(items) || rectArea(rect) <= 0) return null;
|
|
1511
|
+
let areas = [];
|
|
1512
|
+
for (const c of changed) {
|
|
1513
|
+
const a = clipRect(growRect(c, margin), rect);
|
|
1514
|
+
if (a) areas.push(a);
|
|
1515
|
+
}
|
|
1516
|
+
areas.push(...rectMinus(rect, prev.rect));
|
|
1517
|
+
for (let merged = true; merged; ) {
|
|
1518
|
+
merged = false;
|
|
1519
|
+
for (let i = 0; i < areas.length && !merged; i++) {
|
|
1520
|
+
for (let j = i + 1; j < areas.length; j++) {
|
|
1521
|
+
if (clipRect(growRect(areas[i], 2 * margin), areas[j])) {
|
|
1522
|
+
areas[i] = unionRect(areas[i], areas[j]);
|
|
1523
|
+
areas.splice(j, 1);
|
|
1524
|
+
merged = true;
|
|
1525
|
+
break;
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
const windows = areas.map((a) => clipRect(growRect(a, margin), rect));
|
|
1531
|
+
if (windows.reduce((n, w) => n + rectArea(w), 0) > rectArea(rect) / 2) return null;
|
|
1532
|
+
const same = rect.x === prev.rect.x && rect.y === prev.rect.y && rect.width === prev.rect.width && rect.height === prev.rect.height;
|
|
1533
|
+
const take = (v) => same ? v : crop(v, prev.rect, rect, 0);
|
|
1534
|
+
const shape = take(prev.shape);
|
|
1535
|
+
const per = prev.per.map((maps) => maps.map(take));
|
|
1536
|
+
const din = prev.din && take(prev.din);
|
|
1537
|
+
const dout = prev.dout && take(prev.dout);
|
|
1538
|
+
const doutExact = prev.doutExact && take(prev.doutExact);
|
|
1539
|
+
areas.forEach((a, k) => {
|
|
1540
|
+
const w = windows[k];
|
|
1541
|
+
const part = buildEffectMaps(items, shapeOver(w), w, ctx);
|
|
1542
|
+
pasteMap(shape, rect, part.shape, w, a);
|
|
1543
|
+
per.forEach((maps, i) => maps.forEach((m, j) => pasteMap(m, rect, part.per[i][j], w, a)));
|
|
1544
|
+
if (din) pasteMap(din, rect, part.din, w, a);
|
|
1545
|
+
if (dout) pasteMap(dout, rect, part.dout, w, a);
|
|
1546
|
+
if (doutExact) pasteMap(doutExact, rect, part.doutExact, w, a);
|
|
1547
|
+
});
|
|
1548
|
+
let bytes = shape.byteLength;
|
|
1549
|
+
for (const maps of per) for (const m of maps) bytes += m.byteLength;
|
|
1550
|
+
for (const d of [din, dout, doutExact]) if (d) bytes += d.byteLength;
|
|
1551
|
+
return { rect, items, bounds: shapeBounds(shape, rect), shape, per, bevelPaint: prev.bevelPaint, din, dout, doutExact, frames: /* @__PURE__ */ new Map(), bytes };
|
|
1552
|
+
}
|
|
1455
1553
|
var rgbScratchB = [0, 0, 0];
|
|
1456
1554
|
var rgbScratchS = [0, 0, 0];
|
|
1457
1555
|
var rgbScratchM = [0, 0, 0];
|
|
@@ -2084,8 +2182,11 @@ var RasterCompositor = class {
|
|
|
2084
2182
|
patternTiles = /* @__PURE__ */ new WeakMap();
|
|
2085
2183
|
reachCache = /* @__PURE__ */ new WeakMap();
|
|
2086
2184
|
fxContext = null;
|
|
2087
|
-
lastStats = { tiles: 0, cached: 0, stepsRun: 0 };
|
|
2185
|
+
lastStats = { tiles: 0, cached: 0, stepsRun: 0, effectsBuilt: 0, effectsPatched: 0 };
|
|
2088
2186
|
hint = -1;
|
|
2187
|
+
/** The `dirty` rectangles of the current call, as passed. */
|
|
2188
|
+
callDirty = null;
|
|
2189
|
+
callStats = this.lastStats;
|
|
2089
2190
|
/** Drops every cached tile and plane. */
|
|
2090
2191
|
clear() {
|
|
2091
2192
|
this.tiles.clear();
|
|
@@ -2133,7 +2234,9 @@ var RasterCompositor = class {
|
|
|
2133
2234
|
const steps = this.buildSteps(layers);
|
|
2134
2235
|
this.hint = options.checkpointLayerId ? this.stepIndexOf(steps, options.checkpointLayerId) : -1;
|
|
2135
2236
|
this.stamp++;
|
|
2136
|
-
|
|
2237
|
+
this.callDirty = options.dirty ?? null;
|
|
2238
|
+
const stats = { tiles: 0, cached: 0, stepsRun: 0, effectsBuilt: 0, effectsPatched: 0 };
|
|
2239
|
+
this.callStats = stats;
|
|
2137
2240
|
const grow = options.dirty ? this.effectsReach(layers) : 0;
|
|
2138
2241
|
const dirty = grow > 0 ? options.dirty.map((d) => inflateRect(d, grow)) : options.dirty;
|
|
2139
2242
|
for (const { tx, ty } of tilesInRect(rect)) {
|
|
@@ -2149,8 +2252,10 @@ var RasterCompositor = class {
|
|
|
2149
2252
|
tile(layers, tx, ty, sources) {
|
|
2150
2253
|
this.setSources(sources);
|
|
2151
2254
|
this.stamp++;
|
|
2152
|
-
const stats = { tiles: 1, cached: 0, stepsRun: 0 };
|
|
2255
|
+
const stats = { tiles: 1, cached: 0, stepsRun: 0, effectsBuilt: 0, effectsPatched: 0 };
|
|
2256
|
+
this.callStats = stats;
|
|
2153
2257
|
this.hint = -1;
|
|
2258
|
+
this.callDirty = null;
|
|
2154
2259
|
const data = this.compositeTile(layers, this.buildSteps(layers), tx, ty, stats);
|
|
2155
2260
|
this.lastStats = stats;
|
|
2156
2261
|
this.evict();
|
|
@@ -2220,7 +2325,8 @@ var RasterCompositor = class {
|
|
|
2220
2325
|
let first = 0;
|
|
2221
2326
|
if (entry) {
|
|
2222
2327
|
while (first < sigs.length && first < entry.sigs.length && sameSig(entry.sigs[first], sigs[first])) first++;
|
|
2223
|
-
if (first === sigs.length && first === entry.sigs.length) {
|
|
2328
|
+
if (first === sigs.length && first === entry.sigs.length || this.changedOnlyNearby(steps, sigs, entry, dirty)) {
|
|
2329
|
+
entry.sigs = sigs;
|
|
2224
2330
|
entry.stamp = this.stamp;
|
|
2225
2331
|
stats.cached++;
|
|
2226
2332
|
return entry.result;
|
|
@@ -2285,6 +2391,20 @@ var RasterCompositor = class {
|
|
|
2285
2391
|
this.cacheBytes += this.entryBytes(next) - prevBytes;
|
|
2286
2392
|
return result;
|
|
2287
2393
|
}
|
|
2394
|
+
/**
|
|
2395
|
+
* Whether a tile with no part in this call's (grown) `dirty` rectangles changed only in what local
|
|
2396
|
+
* effects read beyond it: every changed step is a pixel layer with local effects whose changes stay
|
|
2397
|
+
* inside `dirty` (and so are farther than its margin), which leaves the tile's pixels as they were.
|
|
2398
|
+
*/
|
|
2399
|
+
changedOnlyNearby(steps, sigs, entry, dirty) {
|
|
2400
|
+
if (this.callDirty === null || dirty || entry.stamp !== this.stamp - 1 || sigs.length !== entry.sigs.length) return false;
|
|
2401
|
+
return steps.every((step, i) => {
|
|
2402
|
+
if (sameSig(entry.sigs[i], sigs[i])) return true;
|
|
2403
|
+
if (step.kind !== "content" || entry.sigs[i].key !== sigs[i].key) return false;
|
|
2404
|
+
const { layer, clipped } = step;
|
|
2405
|
+
return this.hasEffects(layer) && effectsAreLocal(activeEffectItems(layer.effects)) && this.dirtyCoversShape(layer) && clipped.every((c) => this.dirtyCoversShape(c));
|
|
2406
|
+
});
|
|
2407
|
+
}
|
|
2288
2408
|
entryBytes(e) {
|
|
2289
2409
|
let n = e.result === ZERO_TILE ? 0 : TILE_BYTES;
|
|
2290
2410
|
for (const cp of e.checkpoints.values()) n += cp.data.byteLength;
|
|
@@ -2415,14 +2535,20 @@ var RasterCompositor = class {
|
|
|
2415
2535
|
if (!b) return { x: 0, y: 0, width: 0, height: 0 };
|
|
2416
2536
|
return intersectRect({ x: b.x + dx - m, y: b.y + dy - m, width: b.width + 2 * m, height: b.height + 2 * m }, canvas);
|
|
2417
2537
|
}
|
|
2538
|
+
/** The signature of a layer's shape (its surface tiles and mask refs) per tile of `region`. */
|
|
2539
|
+
shapeSigs(layer, region) {
|
|
2540
|
+
const sigs = /* @__PURE__ */ new Map();
|
|
2541
|
+
if (region.width <= 0 || region.height <= 0) return sigs;
|
|
2542
|
+
const steps = isGroup(layer) ? this.buildSteps(layer.children ?? []) : null;
|
|
2543
|
+
for (const t of tilesInRect(region)) {
|
|
2544
|
+
sigs.set(tileKey(t.tx, t.ty), steps ? this.plainGroupSig(layer, steps, t.tx, t.ty) : this.plainContentSig(layer, t.tx, t.ty));
|
|
2545
|
+
}
|
|
2546
|
+
return sigs;
|
|
2547
|
+
}
|
|
2418
2548
|
/** The surface tiles (and mask refs) a layer's shape reads over `region`. */
|
|
2419
2549
|
shapeRefs(layer, region) {
|
|
2420
2550
|
const refs = [];
|
|
2421
|
-
|
|
2422
|
-
for (const t of tilesInRect(region)) {
|
|
2423
|
-
const sig = isGroup(layer) ? this.plainGroupSig(layer, this.buildSteps(layer.children ?? []), t.tx, t.ty) : this.plainContentSig(layer, t.tx, t.ty);
|
|
2424
|
-
for (const r of sig.refs) refs.push(r);
|
|
2425
|
-
}
|
|
2551
|
+
for (const sig of this.shapeSigs(layer, region).values()) for (const r of sig.refs) refs.push(r);
|
|
2426
2552
|
return refs;
|
|
2427
2553
|
}
|
|
2428
2554
|
lightKey() {
|
|
@@ -2448,18 +2574,28 @@ var RasterCompositor = class {
|
|
|
2448
2574
|
const memo = this.effectMemo.get(layer);
|
|
2449
2575
|
if (memo && memo.stamp === this.stamp) return memo.maps;
|
|
2450
2576
|
const region = this.effectRegion(layer);
|
|
2451
|
-
const key =
|
|
2452
|
-
const
|
|
2577
|
+
const key = this.propsKey(layer) + this.lightKey();
|
|
2578
|
+
const tiles = this.shapeSigs(layer, region);
|
|
2453
2579
|
const hit = this.effectCache.get(layer.id);
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
maps = hit.maps;
|
|
2580
|
+
this.effectCache.delete(layer.id);
|
|
2581
|
+
let entry;
|
|
2582
|
+
if (hit && hit.key === key && sameRect(hit.region, region) && [...tiles].every(([k, sig]) => sameSig(hit.tiles.get(k), sig))) {
|
|
2583
|
+
entry = hit;
|
|
2459
2584
|
} else {
|
|
2460
|
-
|
|
2461
|
-
this.
|
|
2462
|
-
|
|
2585
|
+
const items = activeEffectItems(layer.effects);
|
|
2586
|
+
const ctx = this.effectContext();
|
|
2587
|
+
let maps = null;
|
|
2588
|
+
if (hit && hit.key === key && items.every((e) => effectReach(e) <= MAX_EFFECT_REACH)) {
|
|
2589
|
+
const changed = this.shapeChanges(layer, hit, tiles, region);
|
|
2590
|
+
maps = patchEffectMaps(hit.maps, items, region, changed, effectsMargin(layer.effects), (r) => this.layerShape(layer, r), ctx);
|
|
2591
|
+
}
|
|
2592
|
+
if (maps) this.callStats.effectsPatched++;
|
|
2593
|
+
else this.callStats.effectsBuilt++;
|
|
2594
|
+
entry = { key, region, tiles, maps: maps ?? buildEffectMaps(items, this.layerShape(layer, region), region, ctx), stamp: 0 };
|
|
2595
|
+
}
|
|
2596
|
+
entry.stamp = this.stamp;
|
|
2597
|
+
this.effectCache.set(layer.id, entry);
|
|
2598
|
+
if (entry !== hit) {
|
|
2463
2599
|
let bytes = 0;
|
|
2464
2600
|
for (const e of this.effectCache.values()) bytes += e.maps.bytes;
|
|
2465
2601
|
while (this.effectCache.size > 1 && (this.effectCache.size > 32 || bytes > this.maxCacheBytes / 2)) {
|
|
@@ -2468,8 +2604,42 @@ var RasterCompositor = class {
|
|
|
2468
2604
|
this.effectCache.delete(oldest);
|
|
2469
2605
|
}
|
|
2470
2606
|
}
|
|
2471
|
-
this.effectMemo.set(layer, { stamp: this.stamp, maps });
|
|
2472
|
-
return maps;
|
|
2607
|
+
this.effectMemo.set(layer, { stamp: this.stamp, maps: entry.maps });
|
|
2608
|
+
return entry.maps;
|
|
2609
|
+
}
|
|
2610
|
+
/**
|
|
2611
|
+
* Where a layer's shape may differ from the one `prev` was built from: the tiles whose signature
|
|
2612
|
+
* changed (a tile new to the region that reads nothing did not), narrowed to this call's `dirty`
|
|
2613
|
+
* rectangles when `prev` is from the previous call and they cover every change of the shape.
|
|
2614
|
+
*/
|
|
2615
|
+
shapeChanges(layer, prev, tiles, region) {
|
|
2616
|
+
const out = [];
|
|
2617
|
+
for (const { tx, ty } of tilesInRect(region)) {
|
|
2618
|
+
const sig = tiles.get(tileKey(tx, ty));
|
|
2619
|
+
const old = prev.tiles.get(tileKey(tx, ty));
|
|
2620
|
+
if (old ? sameSig(old, sig) : sig.refs.every((r2) => r2 === null || r2 === 0)) continue;
|
|
2621
|
+
const r = intersectRect({ x: tx * TILE, y: ty * TILE, width: TILE, height: TILE }, region);
|
|
2622
|
+
if (r.width > 0 && r.height > 0) out.push(r);
|
|
2623
|
+
}
|
|
2624
|
+
const dirty = this.callDirty;
|
|
2625
|
+
if (!dirty || prev.stamp !== this.stamp - 1 || !this.dirtyCoversShape(layer)) return out;
|
|
2626
|
+
const narrowed = [];
|
|
2627
|
+
for (const r of out) {
|
|
2628
|
+
for (const d of dirty) {
|
|
2629
|
+
const a = intersectRect(r, { x: Math.floor(d.x), y: Math.floor(d.y), width: Math.ceil(d.x + d.width) - Math.floor(d.x), height: Math.ceil(d.y + d.height) - Math.floor(d.y) });
|
|
2630
|
+
if (a.width > 0 && a.height > 0) narrowed.push(a);
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2633
|
+
return narrowed;
|
|
2634
|
+
}
|
|
2635
|
+
/**
|
|
2636
|
+
* Whether a change to a layer stays inside the `dirty` rectangles that name it: a pixel layer
|
|
2637
|
+
* without filters or a feathered or parametric mask (those spread a change beyond it).
|
|
2638
|
+
*/
|
|
2639
|
+
dirtyCoversShape(layer) {
|
|
2640
|
+
if (!isPixel(layer) || this.profile.pixelFilters?.(layer)) return false;
|
|
2641
|
+
const mask = layer.mask;
|
|
2642
|
+
return !mask || mask.enabled === false || !mask.source && !((mask.feather ?? 0) > 0);
|
|
2473
2643
|
}
|
|
2474
2644
|
/** A layer's alpha over `r` after its mask (0..1, quantised to bytes as tiles see it). */
|
|
2475
2645
|
layerShape(layer, r) {
|
|
@@ -2796,6 +2966,9 @@ function copyRect(data, r, a) {
|
|
|
2796
2966
|
function pasteRect(data, r, part, a) {
|
|
2797
2967
|
for (let y = 0; y < a.height; y++) data.set(part.subarray(y * a.width * 4, (y + 1) * a.width * 4), ((a.y - r.y + y) * r.width + (a.x - r.x)) * 4);
|
|
2798
2968
|
}
|
|
2969
|
+
function sameRect(a, b) {
|
|
2970
|
+
return a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;
|
|
2971
|
+
}
|
|
2799
2972
|
function inflateRect(r, m) {
|
|
2800
2973
|
return { x: r.x - m, y: r.y - m, width: r.width + 2 * m, height: r.height + 2 * m };
|
|
2801
2974
|
}
|
|
@@ -3689,6 +3862,7 @@ export {
|
|
|
3689
3862
|
activeEffectItems,
|
|
3690
3863
|
effectsAreLocal,
|
|
3691
3864
|
buildEffectMaps,
|
|
3865
|
+
patchEffectMaps,
|
|
3692
3866
|
gradientT,
|
|
3693
3867
|
compositeLayerEffects,
|
|
3694
3868
|
renderLayerEffects,
|
|
@@ -3709,4 +3883,4 @@ export {
|
|
|
3709
3883
|
parseDataUrl,
|
|
3710
3884
|
pngDataUrl
|
|
3711
3885
|
};
|
|
3712
|
-
//# sourceMappingURL=chunk-
|
|
3886
|
+
//# sourceMappingURL=chunk-OEVSVA6V.js.map
|