@pixerate/editor 0.187.0 → 0.189.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-X2KQQZBT.cjs → chunk-ED4L4UD6.cjs} +389 -180
- package/dist/{chunk-FW7N64XK.js → chunk-ZEHTUR7Z.js} +229 -20
- package/dist/image-editor/controller.d.cts +20 -3
- package/dist/image-editor/controller.d.ts +20 -3
- package/dist/image-editor/index.cjs +1618 -1467
- package/dist/image-editor/index.js +623 -472
- package/dist/image-editor/layers/paint-ui.d.cts +2 -1
- package/dist/image-editor/layers/paint-ui.d.ts +2 -1
- package/dist/image-editor/layers/panel.d.cts +3 -2
- package/dist/image-editor/layers/panel.d.ts +3 -2
- package/dist/image-editor/renderer.d.cts +6 -0
- package/dist/image-editor/renderer.d.ts +6 -0
- package/dist/image-editor/selection/gesture.d.cts +10 -0
- package/dist/image-editor/selection/gesture.d.ts +10 -0
- package/dist/image-editor/selection/layer-mask.d.cts +6 -0
- package/dist/image-editor/selection/layer-mask.d.ts +6 -0
- package/dist/image-editor/selection/mask.d.cts +20 -1
- package/dist/image-editor/selection/mask.d.ts +20 -1
- package/dist/image-editor/selection/shapes.d.cts +8 -0
- package/dist/image-editor/selection/shapes.d.ts +8 -0
- package/dist/image-editor/selection/tool-options.d.cts +1 -1
- package/dist/image-editor/selection/tool-options.d.ts +1 -1
- package/dist/image-editor/types.d.cts +8 -0
- package/dist/image-editor/types.d.ts +8 -0
- package/dist/paint-editor/index.cjs +6 -6
- package/dist/paint-editor/index.js +1 -1
- package/package.json +1 -1
- package/skills/pixerate-image-editor/SKILL.md +1 -0
- package/skills/pixerate-image-selection-masking/SKILL.md +4 -1
|
@@ -114,15 +114,19 @@ import {
|
|
|
114
114
|
parseDataUrl,
|
|
115
115
|
pngDataUrl,
|
|
116
116
|
readDeepRegion,
|
|
117
|
+
readPixel,
|
|
117
118
|
readRegion,
|
|
118
119
|
setLum,
|
|
119
120
|
surfaceDepth,
|
|
120
121
|
surfaceFromDeepPixels,
|
|
121
122
|
surfaceFromPixels,
|
|
123
|
+
tileCoord,
|
|
122
124
|
tileKey,
|
|
123
125
|
tilesInRect,
|
|
124
126
|
translateSurface,
|
|
125
|
-
|
|
127
|
+
uniformTile,
|
|
128
|
+
writeDeepRegion,
|
|
129
|
+
writeRegion
|
|
126
130
|
} from "./chunk-H367YTXI.js";
|
|
127
131
|
import {
|
|
128
132
|
ZlibError,
|
|
@@ -750,15 +754,159 @@ function computeSelectionBounds(width, height, data) {
|
|
|
750
754
|
if (y0 < 0) return null;
|
|
751
755
|
return { x: x0, y: y0, width: x1 - x0 + 1, height: y1 - y0 + 1 };
|
|
752
756
|
}
|
|
757
|
+
var TILE_PIXELS = TILE * TILE;
|
|
758
|
+
var MATERIALIZED_LIMIT = 4;
|
|
759
|
+
var materialized = /* @__PURE__ */ new Map();
|
|
760
|
+
var lastRead = null;
|
|
761
|
+
var lastData = null;
|
|
762
|
+
var TiledSelectionMask = class {
|
|
763
|
+
constructor(width, height, surface, bounds, data) {
|
|
764
|
+
this.width = width;
|
|
765
|
+
this.height = height;
|
|
766
|
+
this.surface = surface;
|
|
767
|
+
this.cachedBounds = bounds;
|
|
768
|
+
if (data) this.remember(data);
|
|
769
|
+
}
|
|
770
|
+
width;
|
|
771
|
+
height;
|
|
772
|
+
surface;
|
|
773
|
+
cachedBounds;
|
|
774
|
+
weak = null;
|
|
775
|
+
get bounds() {
|
|
776
|
+
if (this.cachedBounds === void 0) this.cachedBounds = contentBounds(this.surface);
|
|
777
|
+
return this.cachedBounds;
|
|
778
|
+
}
|
|
779
|
+
get data() {
|
|
780
|
+
if (lastRead === this) return lastData;
|
|
781
|
+
let d = materialized.get(this);
|
|
782
|
+
if (d) {
|
|
783
|
+
materialized.delete(this);
|
|
784
|
+
materialized.set(this, d);
|
|
785
|
+
lastRead = this;
|
|
786
|
+
lastData = d;
|
|
787
|
+
return d;
|
|
788
|
+
}
|
|
789
|
+
d = this.weak?.deref();
|
|
790
|
+
if (!d) {
|
|
791
|
+
const all = readRegion(this.surface, { x: 0, y: 0, width: this.width, height: this.height });
|
|
792
|
+
d = new Uint8Array(all.buffer, all.byteOffset, all.length);
|
|
793
|
+
}
|
|
794
|
+
this.remember(d);
|
|
795
|
+
return d;
|
|
796
|
+
}
|
|
797
|
+
remember(d) {
|
|
798
|
+
lastRead = this;
|
|
799
|
+
lastData = d;
|
|
800
|
+
this.weak = typeof WeakRef === "function" ? new WeakRef(d) : null;
|
|
801
|
+
materialized.set(this, d);
|
|
802
|
+
while (materialized.size > MATERIALIZED_LIMIT) materialized.delete(materialized.keys().next().value);
|
|
803
|
+
}
|
|
804
|
+
};
|
|
805
|
+
function tileGrid(width, height) {
|
|
806
|
+
return { cols: Math.ceil(width / TILE), rows: Math.ceil(height / TILE) };
|
|
807
|
+
}
|
|
808
|
+
function insideTile(tx, ty, width, height) {
|
|
809
|
+
return (tx + 1) * TILE <= width && (ty + 1) * TILE <= height;
|
|
810
|
+
}
|
|
811
|
+
function surfaceFromCoverage(width, height, data) {
|
|
812
|
+
const tiles = /* @__PURE__ */ new Map();
|
|
813
|
+
const { cols, rows } = tileGrid(width, height);
|
|
814
|
+
for (let ty = 0; ty < rows; ty++) {
|
|
815
|
+
for (let tx = 0; tx < cols; tx++) {
|
|
816
|
+
const ox = tx * TILE;
|
|
817
|
+
const oy = ty * TILE;
|
|
818
|
+
const w = Math.min(TILE, width - ox);
|
|
819
|
+
const h = Math.min(TILE, height - oy);
|
|
820
|
+
let lo = 255;
|
|
821
|
+
let hi = 0;
|
|
822
|
+
for (let y = 0; y < h && !(hi > 0 && lo < hi); y++) {
|
|
823
|
+
const row = (oy + y) * width + ox;
|
|
824
|
+
for (let x = 0; x < w; x++) {
|
|
825
|
+
const v = data[row + x];
|
|
826
|
+
if (v < lo) lo = v;
|
|
827
|
+
if (v > hi) hi = v;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
if (hi === 0) continue;
|
|
831
|
+
if (lo === hi && w === TILE && h === TILE) {
|
|
832
|
+
tiles.set(tileKey(tx, ty), uniformTile(1, hi));
|
|
833
|
+
continue;
|
|
834
|
+
}
|
|
835
|
+
const t = new Uint8ClampedArray(TILE_PIXELS);
|
|
836
|
+
for (let y = 0; y < h; y++) {
|
|
837
|
+
const row = (oy + y) * width + ox;
|
|
838
|
+
for (let x = 0; x < w; x++) t[y * TILE + x] = data[row + x];
|
|
839
|
+
}
|
|
840
|
+
tiles.set(tileKey(tx, ty), { data: t, uniform: null });
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
return new TiledSurface(1, tiles, 0);
|
|
844
|
+
}
|
|
845
|
+
function clipTile(tile, w, h) {
|
|
846
|
+
const d = tile.data;
|
|
847
|
+
let outside = false;
|
|
848
|
+
for (let y = 0; y < TILE && !outside; y++) {
|
|
849
|
+
for (let x = y < h ? w : 0; x < TILE; x++) {
|
|
850
|
+
if (d[y * TILE + x] !== 0) {
|
|
851
|
+
outside = true;
|
|
852
|
+
break;
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
if (!outside) return tile;
|
|
857
|
+
const t = new Uint8ClampedArray(TILE_PIXELS);
|
|
858
|
+
for (let y = 0; y < h; y++) t.set(d.subarray(y * TILE, y * TILE + w), y * TILE);
|
|
859
|
+
return finishTile(t, 1, 0);
|
|
860
|
+
}
|
|
861
|
+
function selectionFromTiles(width, height, surface) {
|
|
862
|
+
checkSize(width, height);
|
|
863
|
+
if (surface.channels !== 1) throw new Error("A selection needs a 1-channel surface");
|
|
864
|
+
if (surface.defaultValue !== 0) {
|
|
865
|
+
const all = readRegion(surface, { x: 0, y: 0, width, height });
|
|
866
|
+
return createSelectionMask(width, height, new Uint8Array(all.buffer, all.byteOffset, all.length));
|
|
867
|
+
}
|
|
868
|
+
const { cols, rows } = tileGrid(width, height);
|
|
869
|
+
let tiles = null;
|
|
870
|
+
for (const [key, tile] of surface.tiles) {
|
|
871
|
+
const { tx, ty } = tileCoord(key);
|
|
872
|
+
let next = tile;
|
|
873
|
+
if (tx < 0 || ty < 0 || tx >= cols || ty >= rows) next = null;
|
|
874
|
+
else if (!insideTile(tx, ty, width, height)) next = clipTile(tile, Math.min(TILE, width - tx * TILE), Math.min(TILE, height - ty * TILE));
|
|
875
|
+
if (next === tile) continue;
|
|
876
|
+
tiles ??= new Map(surface.tiles);
|
|
877
|
+
if (next) tiles.set(key, next);
|
|
878
|
+
else tiles.delete(key);
|
|
879
|
+
}
|
|
880
|
+
return new TiledSelectionMask(width, height, tiles ? new TiledSurface(1, tiles, 0) : surface);
|
|
881
|
+
}
|
|
753
882
|
function createSelectionMask(width, height, data) {
|
|
754
883
|
checkSize(width, height);
|
|
755
|
-
|
|
756
|
-
if (
|
|
757
|
-
return
|
|
884
|
+
if (!data) return new TiledSelectionMask(width, height, new TiledSurface(1, /* @__PURE__ */ new Map(), 0), null);
|
|
885
|
+
if (data.length !== width * height) throw new Error("Selection data does not match its size");
|
|
886
|
+
return new TiledSelectionMask(width, height, surfaceFromCoverage(width, height, data), void 0, data);
|
|
887
|
+
}
|
|
888
|
+
function selectionFromRegion(width, height, rect, data) {
|
|
889
|
+
checkSize(width, height);
|
|
890
|
+
if (rect.x < 0 || rect.y < 0 || rect.x + rect.width > width || rect.y + rect.height > height) throw new Error("The region lies outside the selection");
|
|
891
|
+
return new TiledSelectionMask(width, height, writeRegion(new TiledSurface(1, /* @__PURE__ */ new Map(), 0), rect, data));
|
|
758
892
|
}
|
|
759
893
|
function fullSelection(width, height) {
|
|
760
894
|
checkSize(width, height);
|
|
761
|
-
|
|
895
|
+
const tiles = /* @__PURE__ */ new Map();
|
|
896
|
+
const { cols, rows } = tileGrid(width, height);
|
|
897
|
+
for (let ty = 0; ty < rows; ty++) {
|
|
898
|
+
for (let tx = 0; tx < cols; tx++) {
|
|
899
|
+
if (insideTile(tx, ty, width, height)) {
|
|
900
|
+
tiles.set(tileKey(tx, ty), uniformTile(1, 255));
|
|
901
|
+
continue;
|
|
902
|
+
}
|
|
903
|
+
const t = new Uint8ClampedArray(TILE_PIXELS);
|
|
904
|
+
const w = Math.min(TILE, width - tx * TILE);
|
|
905
|
+
for (let y = 0; y < Math.min(TILE, height - ty * TILE); y++) t.fill(255, y * TILE, y * TILE + w);
|
|
906
|
+
tiles.set(tileKey(tx, ty), { data: t, uniform: null });
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
return new TiledSelectionMask(width, height, new TiledSurface(1, tiles, 0), { x: 0, y: 0, width, height });
|
|
762
910
|
}
|
|
763
911
|
function isSelectionEmpty(mask) {
|
|
764
912
|
return !mask || mask.bounds === null;
|
|
@@ -767,7 +915,7 @@ function selectionValueAt(mask, x, y) {
|
|
|
767
915
|
const xi = Math.floor(x);
|
|
768
916
|
const yi = Math.floor(y);
|
|
769
917
|
if (xi < 0 || yi < 0 || xi >= mask.width || yi >= mask.height) return 0;
|
|
770
|
-
return mask.
|
|
918
|
+
return readPixel(mask.surface, xi, yi)[0] / 255;
|
|
771
919
|
}
|
|
772
920
|
function coverageToByte(v) {
|
|
773
921
|
if (!(v > 0)) return 0;
|
|
@@ -788,10 +936,13 @@ function selectionToCoverage(mask) {
|
|
|
788
936
|
function selectionArea(mask) {
|
|
789
937
|
if (!mask || !mask.bounds) return 0;
|
|
790
938
|
let sum = 0;
|
|
791
|
-
const
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
939
|
+
for (const tile of mask.surface.tiles.values()) {
|
|
940
|
+
if (tile.uniform !== null) {
|
|
941
|
+
sum += tile.uniform * TILE_PIXELS;
|
|
942
|
+
continue;
|
|
943
|
+
}
|
|
944
|
+
const d = tile.data;
|
|
945
|
+
for (let i = 0; i < d.length; i++) sum += d[i];
|
|
795
946
|
}
|
|
796
947
|
return sum / 255;
|
|
797
948
|
}
|
|
@@ -803,20 +954,68 @@ function combineSelections(prev, next, mode) {
|
|
|
803
954
|
return null;
|
|
804
955
|
} else {
|
|
805
956
|
if (prev.width !== next.width || prev.height !== next.height) throw new Error("Selections differ in size");
|
|
806
|
-
|
|
807
|
-
const b = next.data;
|
|
808
|
-
const out = new Uint8Array(a.length);
|
|
809
|
-
if (mode === "add") for (let i = 0; i < a.length; i++) out[i] = a[i] > b[i] ? a[i] : b[i];
|
|
810
|
-
else if (mode === "subtract") for (let i = 0; i < a.length; i++) out[i] = a[i] > b[i] ? a[i] - b[i] : 0;
|
|
811
|
-
else for (let i = 0; i < a.length; i++) out[i] = a[i] < b[i] ? a[i] : b[i];
|
|
812
|
-
result = createSelectionMask(prev.width, prev.height, out);
|
|
957
|
+
result = new TiledSelectionMask(prev.width, prev.height, combineSurfaces(prev.surface, next.surface, mode));
|
|
813
958
|
}
|
|
814
959
|
return result.bounds ? result : null;
|
|
815
960
|
}
|
|
961
|
+
var FULL = 255;
|
|
962
|
+
function combineTile(a, b, mode) {
|
|
963
|
+
if (mode === "add") {
|
|
964
|
+
if (!b || a?.uniform === FULL) return a;
|
|
965
|
+
if (!a || b.uniform === FULL) return b;
|
|
966
|
+
} else if (mode === "subtract") {
|
|
967
|
+
if (!a || !b) return a;
|
|
968
|
+
if (b.uniform === FULL) return void 0;
|
|
969
|
+
} else {
|
|
970
|
+
if (!a || !b) return void 0;
|
|
971
|
+
if (a.uniform === FULL) return b;
|
|
972
|
+
if (b.uniform === FULL) return a;
|
|
973
|
+
}
|
|
974
|
+
const x = a.data;
|
|
975
|
+
const y = b.data;
|
|
976
|
+
const out = new Uint8ClampedArray(TILE_PIXELS);
|
|
977
|
+
if (mode === "add") for (let i = 0; i < out.length; i++) out[i] = x[i] > y[i] ? x[i] : y[i];
|
|
978
|
+
else if (mode === "subtract") for (let i = 0; i < out.length; i++) out[i] = x[i] > y[i] ? x[i] - y[i] : 0;
|
|
979
|
+
else for (let i = 0; i < out.length; i++) out[i] = x[i] < y[i] ? x[i] : y[i];
|
|
980
|
+
return finishTile(out, 1, 0) ?? void 0;
|
|
981
|
+
}
|
|
982
|
+
function combineSurfaces(a, b, mode) {
|
|
983
|
+
const tiles = /* @__PURE__ */ new Map();
|
|
984
|
+
for (const key of /* @__PURE__ */ new Set([...a.tiles.keys(), ...b.tiles.keys()])) {
|
|
985
|
+
const tile = combineTile(a.tiles.get(key), b.tiles.get(key), mode);
|
|
986
|
+
if (tile) tiles.set(key, tile);
|
|
987
|
+
}
|
|
988
|
+
return new TiledSurface(1, tiles, 0);
|
|
989
|
+
}
|
|
816
990
|
function invertSelection(mask) {
|
|
817
|
-
const
|
|
818
|
-
|
|
819
|
-
|
|
991
|
+
const { width, height } = mask;
|
|
992
|
+
const tiles = /* @__PURE__ */ new Map();
|
|
993
|
+
const { cols, rows } = tileGrid(width, height);
|
|
994
|
+
for (let ty = 0; ty < rows; ty++) {
|
|
995
|
+
for (let tx = 0; tx < cols; tx++) {
|
|
996
|
+
const src = mask.surface.getTile(tx, ty);
|
|
997
|
+
const key = tileKey(tx, ty);
|
|
998
|
+
if (insideTile(tx, ty, width, height)) {
|
|
999
|
+
if (!src) tiles.set(key, uniformTile(1, FULL));
|
|
1000
|
+
else if (src.uniform !== null) {
|
|
1001
|
+
if (src.uniform !== FULL) tiles.set(key, uniformTile(1, FULL - src.uniform));
|
|
1002
|
+
} else {
|
|
1003
|
+
const out2 = new Uint8ClampedArray(TILE_PIXELS);
|
|
1004
|
+
for (let i = 0; i < out2.length; i++) out2[i] = FULL - src.data[i];
|
|
1005
|
+
const t2 = finishTile(out2, 1, 0);
|
|
1006
|
+
if (t2) tiles.set(key, t2);
|
|
1007
|
+
}
|
|
1008
|
+
continue;
|
|
1009
|
+
}
|
|
1010
|
+
const w = Math.min(TILE, width - tx * TILE);
|
|
1011
|
+
const h = Math.min(TILE, height - ty * TILE);
|
|
1012
|
+
const out = new Uint8ClampedArray(TILE_PIXELS);
|
|
1013
|
+
for (let y = 0; y < h; y++) for (let x = 0; x < w; x++) out[y * TILE + x] = FULL - (src ? src.data[y * TILE + x] : 0);
|
|
1014
|
+
const t = finishTile(out, 1, 0);
|
|
1015
|
+
if (t) tiles.set(key, t);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
return new TiledSelectionMask(width, height, new TiledSurface(1, tiles, 0));
|
|
820
1019
|
}
|
|
821
1020
|
function resizeSelection(mask, width, height) {
|
|
822
1021
|
if (mask.width === width && mask.height === height) return mask;
|
|
@@ -1222,6 +1421,13 @@ function modifySelection(mask, op, radius) {
|
|
|
1222
1421
|
}
|
|
1223
1422
|
|
|
1224
1423
|
// src/image-editor/selection/layer-mask.ts
|
|
1424
|
+
function layerMaskSelection(layer, width, height) {
|
|
1425
|
+
if (!layer.mask || layer.mask.source) return null;
|
|
1426
|
+
const ox = layer.type === "pixel" ? layer.offset.x : 0;
|
|
1427
|
+
const oy = layer.type === "pixel" ? layer.offset.y : 0;
|
|
1428
|
+
const data = readRegion(layer.mask.surface, { x: -ox, y: -oy, width, height });
|
|
1429
|
+
return createSelectionMask(width, height, new Uint8Array(data.buffer, data.byteOffset, data.length));
|
|
1430
|
+
}
|
|
1225
1431
|
var MAX_SIDE2 = 1 << 15;
|
|
1226
1432
|
function normalizeLayerMask(raw) {
|
|
1227
1433
|
if (!raw || typeof raw !== "object") return null;
|
|
@@ -11640,7 +11846,9 @@ export {
|
|
|
11640
11846
|
isSelectionMode,
|
|
11641
11847
|
parseSelectionMode,
|
|
11642
11848
|
computeSelectionBounds,
|
|
11849
|
+
selectionFromTiles,
|
|
11643
11850
|
createSelectionMask,
|
|
11851
|
+
selectionFromRegion,
|
|
11644
11852
|
fullSelection,
|
|
11645
11853
|
isSelectionEmpty,
|
|
11646
11854
|
selectionValueAt,
|
|
@@ -11669,6 +11877,7 @@ export {
|
|
|
11669
11877
|
shiftCoverage,
|
|
11670
11878
|
SELECTION_MODIFY_OPS,
|
|
11671
11879
|
modifySelection,
|
|
11880
|
+
layerMaskSelection,
|
|
11672
11881
|
normalizeLayerMask,
|
|
11673
11882
|
layerMaskFromSelection,
|
|
11674
11883
|
updateLayerMaskProps,
|
|
@@ -113,6 +113,8 @@ export interface SelectionCommandOptions {
|
|
|
113
113
|
}
|
|
114
114
|
/** How the canvas shows the selection: marching ants, a Quick Mask tint, or not at all. */
|
|
115
115
|
export type SelectionDisplay = 'ants' | 'quickMask' | 'none';
|
|
116
|
+
/** How a layer mask is shown on the canvas: alone in grey, or as a red tint over the image. */
|
|
117
|
+
export type MaskViewMode = 'gray' | 'overlay';
|
|
116
118
|
/** What `exportMaskImage` writes: the selection, an alpha channel or a layer's painted mask. */
|
|
117
119
|
export type MaskImageSource = 'selection' | {
|
|
118
120
|
channelId: string;
|
|
@@ -724,8 +726,8 @@ export declare class ImageEditorController {
|
|
|
724
726
|
private asOneStep;
|
|
725
727
|
private recordHistory;
|
|
726
728
|
/**
|
|
727
|
-
* Bytes of pixel tiles held only by undo / redo steps (not by the
|
|
728
|
-
* undo steps are dropped while it exceeds `maxHistoryBytes`.
|
|
729
|
+
* Bytes of pixel, selection and channel tiles held only by undo / redo steps (not by the
|
|
730
|
+
* current state). The oldest undo steps are dropped while it exceeds `maxHistoryBytes`.
|
|
729
731
|
*/
|
|
730
732
|
get historyBytes(): number;
|
|
731
733
|
private trimHistoryBytes;
|
|
@@ -1506,6 +1508,21 @@ export declare class ImageEditorController {
|
|
|
1506
1508
|
* it (the selection still applies). View state: no undo step, not saved.
|
|
1507
1509
|
*/
|
|
1508
1510
|
setSelectionDisplay(display: SelectionDisplay): void;
|
|
1511
|
+
/** The layer mask shown on the canvas, or `null` (see `setMaskView`). */
|
|
1512
|
+
getMaskView(): {
|
|
1513
|
+
layerId: string;
|
|
1514
|
+
mode: MaskViewMode;
|
|
1515
|
+
} | null;
|
|
1516
|
+
/**
|
|
1517
|
+
* Shows a layer's mask on the canvas: `gray` alone in grey (Alt-click the mask thumbnail),
|
|
1518
|
+
* `overlay` as a red tint over what it hides (the \ key), `off` back to the image. The layer
|
|
1519
|
+
* defaults to the active one. View state: no undo step, not saved. Throws when the layer has
|
|
1520
|
+
* no painted mask.
|
|
1521
|
+
*/
|
|
1522
|
+
setMaskView(mode: MaskViewMode | 'off', layerId?: string): {
|
|
1523
|
+
layerId: string;
|
|
1524
|
+
mode: MaskViewMode;
|
|
1525
|
+
} | null;
|
|
1509
1526
|
/** The alpha channels (saved selections), in panel order. */
|
|
1510
1527
|
getChannels(): readonly AlphaChannel[];
|
|
1511
1528
|
getChannel(id: string): AlphaChannel | null;
|
|
@@ -1559,7 +1576,7 @@ export declare class ImageEditorController {
|
|
|
1559
1576
|
setQuickMaskMode(on: boolean): void;
|
|
1560
1577
|
/** The selection as a 1-channel surface to paint in Quick Mask mode. */
|
|
1561
1578
|
private quickMaskSurface;
|
|
1562
|
-
/** The selection a painted Quick Mask surface stands for (
|
|
1579
|
+
/** The selection a painted Quick Mask surface stands for (it shares the surface's tiles). */
|
|
1563
1580
|
private selectionFromSurface;
|
|
1564
1581
|
private maskFromSelection;
|
|
1565
1582
|
/**
|
|
@@ -113,6 +113,8 @@ export interface SelectionCommandOptions {
|
|
|
113
113
|
}
|
|
114
114
|
/** How the canvas shows the selection: marching ants, a Quick Mask tint, or not at all. */
|
|
115
115
|
export type SelectionDisplay = 'ants' | 'quickMask' | 'none';
|
|
116
|
+
/** How a layer mask is shown on the canvas: alone in grey, or as a red tint over the image. */
|
|
117
|
+
export type MaskViewMode = 'gray' | 'overlay';
|
|
116
118
|
/** What `exportMaskImage` writes: the selection, an alpha channel or a layer's painted mask. */
|
|
117
119
|
export type MaskImageSource = 'selection' | {
|
|
118
120
|
channelId: string;
|
|
@@ -724,8 +726,8 @@ export declare class ImageEditorController {
|
|
|
724
726
|
private asOneStep;
|
|
725
727
|
private recordHistory;
|
|
726
728
|
/**
|
|
727
|
-
* Bytes of pixel tiles held only by undo / redo steps (not by the
|
|
728
|
-
* undo steps are dropped while it exceeds `maxHistoryBytes`.
|
|
729
|
+
* Bytes of pixel, selection and channel tiles held only by undo / redo steps (not by the
|
|
730
|
+
* current state). The oldest undo steps are dropped while it exceeds `maxHistoryBytes`.
|
|
729
731
|
*/
|
|
730
732
|
get historyBytes(): number;
|
|
731
733
|
private trimHistoryBytes;
|
|
@@ -1506,6 +1508,21 @@ export declare class ImageEditorController {
|
|
|
1506
1508
|
* it (the selection still applies). View state: no undo step, not saved.
|
|
1507
1509
|
*/
|
|
1508
1510
|
setSelectionDisplay(display: SelectionDisplay): void;
|
|
1511
|
+
/** The layer mask shown on the canvas, or `null` (see `setMaskView`). */
|
|
1512
|
+
getMaskView(): {
|
|
1513
|
+
layerId: string;
|
|
1514
|
+
mode: MaskViewMode;
|
|
1515
|
+
} | null;
|
|
1516
|
+
/**
|
|
1517
|
+
* Shows a layer's mask on the canvas: `gray` alone in grey (Alt-click the mask thumbnail),
|
|
1518
|
+
* `overlay` as a red tint over what it hides (the \ key), `off` back to the image. The layer
|
|
1519
|
+
* defaults to the active one. View state: no undo step, not saved. Throws when the layer has
|
|
1520
|
+
* no painted mask.
|
|
1521
|
+
*/
|
|
1522
|
+
setMaskView(mode: MaskViewMode | 'off', layerId?: string): {
|
|
1523
|
+
layerId: string;
|
|
1524
|
+
mode: MaskViewMode;
|
|
1525
|
+
} | null;
|
|
1509
1526
|
/** The alpha channels (saved selections), in panel order. */
|
|
1510
1527
|
getChannels(): readonly AlphaChannel[];
|
|
1511
1528
|
getChannel(id: string): AlphaChannel | null;
|
|
@@ -1559,7 +1576,7 @@ export declare class ImageEditorController {
|
|
|
1559
1576
|
setQuickMaskMode(on: boolean): void;
|
|
1560
1577
|
/** The selection as a 1-channel surface to paint in Quick Mask mode. */
|
|
1561
1578
|
private quickMaskSurface;
|
|
1562
|
-
/** The selection a painted Quick Mask surface stands for (
|
|
1579
|
+
/** The selection a painted Quick Mask surface stands for (it shares the surface's tiles). */
|
|
1563
1580
|
private selectionFromSurface;
|
|
1564
1581
|
private maskFromSelection;
|
|
1565
1582
|
/**
|