@pixerate/editor 0.214.0 → 0.215.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-UOGKSVRQ.cjs → chunk-B46UQUDC.cjs} +770 -733
- package/dist/{chunk-W3TOZTL7.js → chunk-F7Z2MKY2.js} +115 -4
- package/dist/{chunk-YBJXCQTR.js → chunk-QXY4YTRI.js} +738 -701
- package/dist/{chunk-H65IBXFI.cjs → chunk-S55JFWDA.cjs} +350 -239
- package/dist/{chunk-QYLWG22N.cjs → chunk-SS53NNZO.cjs} +304 -1
- package/dist/{chunk-LQ5SALHK.js → chunk-U7C655AM.js} +5 -311
- package/dist/{chunk-L52VMQZS.cjs → chunk-UC3PWFM3.cjs} +68 -374
- package/dist/{chunk-L3G23N5Y.js → chunk-ZNA3IQZF.js} +304 -1
- package/dist/image-editor/controller.d.cts +29 -0
- package/dist/image-editor/controller.d.ts +29 -0
- package/dist/image-editor/index.cjs +1224 -1074
- package/dist/image-editor/index.d.cts +1 -0
- package/dist/image-editor/index.d.ts +1 -0
- package/dist/image-editor/index.js +166 -16
- package/dist/image-editor/layers/edge-color.d.cts +27 -0
- package/dist/image-editor/layers/edge-color.d.ts +27 -0
- package/dist/image-editor/layers/serialize.d.cts +13 -0
- package/dist/image-editor/layers/serialize.d.ts +13 -0
- package/dist/image-editor/selection-worker.cjs +4 -4
- package/dist/image-editor/selection-worker.js +2 -2
- package/dist/paint-editor/index.cjs +79 -79
- package/dist/paint-editor/index.js +3 -3
- package/dist/raster/compositor.d.cts +10 -1
- package/dist/raster/compositor.d.ts +10 -1
- package/dist/raster/deep-compositor.d.cts +1 -1
- package/dist/raster/deep-compositor.d.ts +1 -1
- package/dist/raster/index.cjs +4 -2
- package/dist/raster/index.js +3 -1
- package/dist/raster/layers.d.cts +16 -0
- package/dist/raster/layers.d.ts +16 -0
- package/package.json +1 -1
- package/skills/pixerate-image-editor/SKILL.md +8 -6
- package/skills/pixerate-image-editor/references/paths.md +12 -0
- package/skills/pixerate-image-selection-masking/SKILL.md +8 -8
|
@@ -724,6 +724,298 @@ function modifySelection(mask, op, radius) {
|
|
|
724
724
|
}
|
|
725
725
|
}
|
|
726
726
|
|
|
727
|
+
// src/image-editor/selection/refine.ts
|
|
728
|
+
var DEFAULT_REFINE_EDGE_PARAMS = {
|
|
729
|
+
radius: 0,
|
|
730
|
+
smartRadius: false,
|
|
731
|
+
smooth: 0,
|
|
732
|
+
feather: 0,
|
|
733
|
+
contrast: 0,
|
|
734
|
+
shiftEdge: 0
|
|
735
|
+
};
|
|
736
|
+
var GUIDED_FILTER_EPS = 1e-4;
|
|
737
|
+
var fin = (v, d) => typeof v === "number" && Number.isFinite(v) ? v : d;
|
|
738
|
+
function normalizeRefineEdgeParams(p = {}) {
|
|
739
|
+
return {
|
|
740
|
+
radius: Math.min(250, Math.max(0, fin(p.radius, 0))),
|
|
741
|
+
smartRadius: p.smartRadius === true,
|
|
742
|
+
smooth: Math.min(100, Math.max(0, fin(p.smooth, 0))),
|
|
743
|
+
feather: Math.min(1e3, Math.max(0, fin(p.feather, 0))),
|
|
744
|
+
contrast: Math.min(100, Math.max(0, fin(p.contrast, 0))),
|
|
745
|
+
shiftEdge: Math.min(100, Math.max(-100, fin(p.shiftEdge, 0)))
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
var gfRadius = (p) => Math.min(64, Math.max(1, Math.ceil(p.radius)));
|
|
749
|
+
var smoothSigma = (p) => p.smooth / 100 * 4;
|
|
750
|
+
var featherSigma = (p) => p.feather / 2;
|
|
751
|
+
function shiftAmount(p) {
|
|
752
|
+
const px = p.shiftEdge / 100 * Math.max(p.radius, 4);
|
|
753
|
+
return Number.isFinite(px) ? Math.min(64, Math.max(-64, px)) : 0;
|
|
754
|
+
}
|
|
755
|
+
function refineEdgeHalo(params = {}) {
|
|
756
|
+
const p = normalizeRefineEdgeParams(params);
|
|
757
|
+
const g = gfRadius(p);
|
|
758
|
+
const edge = p.radius > 0 ? Math.max(Math.ceil(p.radius), 2 * g + (p.smartRadius ? g + 1 : 0)) : 0;
|
|
759
|
+
return edge + Math.ceil(3 * smoothSigma(p)) + Math.ceil(3 * featherSigma(p)) + Math.ceil(Math.abs(shiftAmount(p))) + 2;
|
|
760
|
+
}
|
|
761
|
+
function boxMean(src, w, h, r) {
|
|
762
|
+
const tmp = new Float32Array(w * h);
|
|
763
|
+
const pre = new Float64Array(Math.max(w, h) + 1);
|
|
764
|
+
for (let y = 0; y < h; y++) {
|
|
765
|
+
const row = y * w;
|
|
766
|
+
for (let x = 0; x < w; x++) pre[x + 1] = pre[x] + src[row + x];
|
|
767
|
+
for (let x = 0; x < w; x++) {
|
|
768
|
+
const lo = Math.max(0, x - r);
|
|
769
|
+
const hi = Math.min(w, x + r + 1);
|
|
770
|
+
tmp[row + x] = (pre[hi] - pre[lo]) / (hi - lo);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
const out = new Float32Array(w * h);
|
|
774
|
+
for (let x = 0; x < w; x++) {
|
|
775
|
+
for (let y = 0; y < h; y++) pre[y + 1] = pre[y] + tmp[y * w + x];
|
|
776
|
+
for (let y = 0; y < h; y++) {
|
|
777
|
+
const lo = Math.max(0, y - r);
|
|
778
|
+
const hi = Math.min(h, y + r + 1);
|
|
779
|
+
out[y * w + x] = (pre[hi] - pre[lo]) / (hi - lo);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
return out;
|
|
783
|
+
}
|
|
784
|
+
function guidedFilterColor(guide, p, w, h, r, eps = GUIDED_FILTER_EPS) {
|
|
785
|
+
const n = w * h;
|
|
786
|
+
const [c0, c1, c2] = guide;
|
|
787
|
+
const prod = (a, b2) => {
|
|
788
|
+
const o = new Float32Array(n);
|
|
789
|
+
for (let i = 0; i < n; i++) o[i] = a[i] * b2[i];
|
|
790
|
+
return o;
|
|
791
|
+
};
|
|
792
|
+
const m0 = boxMean(c0, w, h, r);
|
|
793
|
+
const m1 = boxMean(c1, w, h, r);
|
|
794
|
+
const m2 = boxMean(c2, w, h, r);
|
|
795
|
+
const mp = boxMean(p, w, h, r);
|
|
796
|
+
const mip0 = boxMean(prod(c0, p), w, h, r);
|
|
797
|
+
const mip1 = boxMean(prod(c1, p), w, h, r);
|
|
798
|
+
const mip2 = boxMean(prod(c2, p), w, h, r);
|
|
799
|
+
const s00 = boxMean(prod(c0, c0), w, h, r);
|
|
800
|
+
const s01 = boxMean(prod(c0, c1), w, h, r);
|
|
801
|
+
const s02 = boxMean(prod(c0, c2), w, h, r);
|
|
802
|
+
const s11 = boxMean(prod(c1, c1), w, h, r);
|
|
803
|
+
const s12 = boxMean(prod(c1, c2), w, h, r);
|
|
804
|
+
const s22 = boxMean(prod(c2, c2), w, h, r);
|
|
805
|
+
const a0 = new Float32Array(n);
|
|
806
|
+
const a1 = new Float32Array(n);
|
|
807
|
+
const a2 = new Float32Array(n);
|
|
808
|
+
const b = new Float32Array(n);
|
|
809
|
+
for (let i = 0; i < n; i++) {
|
|
810
|
+
const u0 = m0[i], u1 = m1[i], u2 = m2[i], up = mp[i];
|
|
811
|
+
const rr = s00[i] - u0 * u0 + eps;
|
|
812
|
+
const rg = s01[i] - u0 * u1;
|
|
813
|
+
const rb = s02[i] - u0 * u2;
|
|
814
|
+
const gg = s11[i] - u1 * u1 + eps;
|
|
815
|
+
const gb = s12[i] - u1 * u2;
|
|
816
|
+
const bb = s22[i] - u2 * u2 + eps;
|
|
817
|
+
const v0 = mip0[i] - u0 * up;
|
|
818
|
+
const v1 = mip1[i] - u1 * up;
|
|
819
|
+
const v2 = mip2[i] - u2 * up;
|
|
820
|
+
const i00 = gg * bb - gb * gb;
|
|
821
|
+
const i01 = gb * rb - rg * bb;
|
|
822
|
+
const i02 = rg * gb - gg * rb;
|
|
823
|
+
const i11 = rr * bb - rb * rb;
|
|
824
|
+
const i12 = rb * rg - rr * gb;
|
|
825
|
+
const i22 = rr * gg - rg * rg;
|
|
826
|
+
const det = rr * i00 + rg * i01 + rb * i02;
|
|
827
|
+
let x0 = 0, x1 = 0, x2 = 0;
|
|
828
|
+
if (Math.abs(det) >= 1e-30) {
|
|
829
|
+
x0 = (i00 * v0 + i01 * v1 + i02 * v2) / det;
|
|
830
|
+
x1 = (i01 * v0 + i11 * v1 + i12 * v2) / det;
|
|
831
|
+
x2 = (i02 * v0 + i12 * v1 + i22 * v2) / det;
|
|
832
|
+
}
|
|
833
|
+
a0[i] = x0;
|
|
834
|
+
a1[i] = x1;
|
|
835
|
+
a2[i] = x2;
|
|
836
|
+
b[i] = up - x0 * u0 - x1 * u1 - x2 * u2;
|
|
837
|
+
}
|
|
838
|
+
const ma0 = boxMean(a0, w, h, r);
|
|
839
|
+
const ma1 = boxMean(a1, w, h, r);
|
|
840
|
+
const ma2 = boxMean(a2, w, h, r);
|
|
841
|
+
const mb = boxMean(b, w, h, r);
|
|
842
|
+
const out = new Float32Array(n);
|
|
843
|
+
for (let i = 0; i < n; i++) out[i] = ma0[i] * c0[i] + ma1[i] * c1[i] + ma2[i] * c2[i] + mb[i];
|
|
844
|
+
return out;
|
|
845
|
+
}
|
|
846
|
+
function edgeWidth(guide, w, h, r) {
|
|
847
|
+
const n = w * h;
|
|
848
|
+
const y = new Float32Array(n);
|
|
849
|
+
for (let i = 0; i < n; i++) y[i] = 0.299 * guide[0][i] + 0.587 * guide[1][i] + 0.114 * guide[2][i];
|
|
850
|
+
const g = new Float32Array(n);
|
|
851
|
+
for (let yy = 0; yy < h; yy++) {
|
|
852
|
+
for (let xx = 0; xx < w; xx++) {
|
|
853
|
+
const gx = (y[yy * w + Math.min(w - 1, xx + 1)] - y[yy * w + Math.max(0, xx - 1)]) / 2;
|
|
854
|
+
const gy = (y[Math.min(h - 1, yy + 1) * w + xx] - y[Math.max(0, yy - 1) * w + xx]) / 2;
|
|
855
|
+
g[yy * w + xx] = Math.sqrt(gx * gx + gy * gy);
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
const gm = greyMorphology(g, w, h, r, true);
|
|
859
|
+
const hi = greyMorphology(y, w, h, r, true);
|
|
860
|
+
const lo = greyMorphology(y, w, h, r, false);
|
|
861
|
+
const out = new Float32Array(n);
|
|
862
|
+
for (let i = 0; i < n; i++) out[i] = (hi[i] - lo[i]) / Math.max(gm[i], 1e-4);
|
|
863
|
+
return out;
|
|
864
|
+
}
|
|
865
|
+
function refineCoverage(guide, m, w, h, params = {}, band = null) {
|
|
866
|
+
const p = normalizeRefineEdgeParams(params);
|
|
867
|
+
let a = Float32Array.from(m);
|
|
868
|
+
if ((p.radius > 0 || band) && guide) {
|
|
869
|
+
const n = w * h;
|
|
870
|
+
const boundary = new Uint8Array(n);
|
|
871
|
+
let any = false;
|
|
872
|
+
for (let y = 0; y < h; y++) {
|
|
873
|
+
for (let x = 0; x < w; x++) {
|
|
874
|
+
const i = y * w + x;
|
|
875
|
+
const v = m[i] >= 0.5;
|
|
876
|
+
const diff = x > 0 && m[i - 1] >= 0.5 !== v || x + 1 < w && m[i + 1] >= 0.5 !== v || y > 0 && m[i - w] >= 0.5 !== v || y + 1 < h && m[i + w] >= 0.5 !== v;
|
|
877
|
+
if (diff) {
|
|
878
|
+
boundary[i] = 1;
|
|
879
|
+
any = true;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
if (any || band) {
|
|
884
|
+
const dist = distanceTransform(boundary, w, h);
|
|
885
|
+
const r = band ? Math.max(4, gfRadius(p)) : gfRadius(p);
|
|
886
|
+
const q = guidedFilterColor(guide, m, w, h, r);
|
|
887
|
+
const widths = p.smartRadius ? edgeWidth(guide, w, h, r) : null;
|
|
888
|
+
for (let i = 0; i < n; i++) {
|
|
889
|
+
const reff = widths ? Math.min(Math.max(p.radius, 1.5), Math.max(1.5, widths[i])) : p.radius;
|
|
890
|
+
const edge = p.radius > 0 ? Math.min(1, Math.max(0, reff + 1 - dist[i])) : 0;
|
|
891
|
+
const wgt = band ? Math.max(edge, Math.min(1, Math.max(0, band[i]))) : edge;
|
|
892
|
+
if (wgt > 0) {
|
|
893
|
+
const qi = Math.min(1, Math.max(0, q[i]));
|
|
894
|
+
a[i] = m[i] + (qi - m[i]) * wgt;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
const ss = smoothSigma(p);
|
|
900
|
+
if (ss >= 0.3) {
|
|
901
|
+
a = gaussianBlur(a, w, h, ss, "clamp");
|
|
902
|
+
const gain = 1 + ss;
|
|
903
|
+
for (let i = 0; i < a.length; i++) a[i] = Math.min(1, Math.max(0, (a[i] - 0.5) * gain + 0.5));
|
|
904
|
+
}
|
|
905
|
+
a = gaussianBlur(a, w, h, featherSigma(p), "clamp");
|
|
906
|
+
if (p.contrast > 0) {
|
|
907
|
+
const gain = 1 / (1 - 0.99 * p.contrast / 100);
|
|
908
|
+
for (let i = 0; i < a.length; i++) a[i] = Math.min(1, Math.max(0, (a[i] - 0.5) * gain + 0.5));
|
|
909
|
+
}
|
|
910
|
+
const amount = shiftAmount(p);
|
|
911
|
+
if (Math.abs(amount) >= 1e-4) a = shiftCoverage(a, w, h, amount);
|
|
912
|
+
return a;
|
|
913
|
+
}
|
|
914
|
+
function guidePlanes(pixels, win) {
|
|
915
|
+
const box = win ?? { x: 0, y: 0, width: pixels.width, height: pixels.height };
|
|
916
|
+
const n = box.width * box.height;
|
|
917
|
+
const r = new Float32Array(n);
|
|
918
|
+
const g = new Float32Array(n);
|
|
919
|
+
const b = new Float32Array(n);
|
|
920
|
+
const d = pixels.data;
|
|
921
|
+
for (let y = 0; y < box.height; y++) {
|
|
922
|
+
for (let x = 0; x < box.width; x++) {
|
|
923
|
+
const i = y * box.width + x;
|
|
924
|
+
const p = ((box.y + y) * pixels.width + box.x + x) * 4;
|
|
925
|
+
r[i] = d[p] / 255;
|
|
926
|
+
g[i] = d[p + 1] / 255;
|
|
927
|
+
b[i] = d[p + 2] / 255;
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
return [r, g, b];
|
|
931
|
+
}
|
|
932
|
+
function refineSelection(pixels, mask, params = {}, refineBrush = null) {
|
|
933
|
+
const p = normalizeRefineEdgeParams(params);
|
|
934
|
+
if (pixels && (pixels.width !== mask.width || pixels.height !== mask.height)) {
|
|
935
|
+
throw new Error("Refine Edge needs pixels the size of the selection");
|
|
936
|
+
}
|
|
937
|
+
if (!mask.bounds) return mask;
|
|
938
|
+
const brush = refineBrush?.bounds ? refineBrush : null;
|
|
939
|
+
const halo = refineEdgeHalo(p) + (brush ? 2 * Math.max(4, gfRadius(p)) : 0);
|
|
940
|
+
const b = brush ? {
|
|
941
|
+
x: Math.min(mask.bounds.x, brush.bounds.x),
|
|
942
|
+
y: Math.min(mask.bounds.y, brush.bounds.y),
|
|
943
|
+
r: Math.max(mask.bounds.x + mask.bounds.width, brush.bounds.x + brush.bounds.width),
|
|
944
|
+
btm: Math.max(mask.bounds.y + mask.bounds.height, brush.bounds.y + brush.bounds.height)
|
|
945
|
+
} : { x: mask.bounds.x, y: mask.bounds.y, r: mask.bounds.x + mask.bounds.width, btm: mask.bounds.y + mask.bounds.height };
|
|
946
|
+
const x0 = Math.max(0, b.x - halo);
|
|
947
|
+
const y0 = Math.max(0, b.y - halo);
|
|
948
|
+
const x1 = Math.min(mask.width, b.r + halo);
|
|
949
|
+
const y1 = Math.min(mask.height, b.btm + halo);
|
|
950
|
+
const ww = x1 - x0;
|
|
951
|
+
const wh = y1 - y0;
|
|
952
|
+
const m = new Float32Array(ww * wh);
|
|
953
|
+
for (let y = 0; y < wh; y++) {
|
|
954
|
+
const src = (y0 + y) * mask.width + x0;
|
|
955
|
+
for (let x = 0; x < ww; x++) m[y * ww + x] = mask.data[src + x] / 255;
|
|
956
|
+
}
|
|
957
|
+
const guide = pixels && (p.radius > 0 || brush) ? guidePlanes(pixels, { x: x0, y: y0, width: ww, height: wh }) : null;
|
|
958
|
+
let band = null;
|
|
959
|
+
if (brush) {
|
|
960
|
+
band = new Float32Array(ww * wh);
|
|
961
|
+
const bd = brush.data;
|
|
962
|
+
for (let y = 0; y < wh; y++) {
|
|
963
|
+
const src = (y0 + y) * mask.width + x0;
|
|
964
|
+
for (let x = 0; x < ww; x++) band[y * ww + x] = bd[src + x] / 255;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
const refined = refineCoverage(guide, m, ww, wh, p, band);
|
|
968
|
+
const out = new Uint8Array(mask.width * mask.height);
|
|
969
|
+
for (let y = 0; y < wh; y++) {
|
|
970
|
+
const dst = (y0 + y) * mask.width + x0;
|
|
971
|
+
for (let x = 0; x < ww; x++) out[dst + x] = coverageToByte(refined[y * ww + x]);
|
|
972
|
+
}
|
|
973
|
+
return createSelectionMask(mask.width, mask.height, out);
|
|
974
|
+
}
|
|
975
|
+
function decontaminateColors(rgba, coverage, w, h, amount, radius = 8) {
|
|
976
|
+
const out = Uint8ClampedArray.from(rgba);
|
|
977
|
+
const n = w * h;
|
|
978
|
+
const k = Math.min(1, Math.max(0, amount));
|
|
979
|
+
if (k === 0) return out;
|
|
980
|
+
const r = Math.max(2, Math.round(radius));
|
|
981
|
+
const fgW = new Float32Array(n);
|
|
982
|
+
const bgW = new Float32Array(n);
|
|
983
|
+
for (let i = 0; i < n; i++) {
|
|
984
|
+
fgW[i] = coverage[i] >= 250 ? 1 : 0;
|
|
985
|
+
bgW[i] = coverage[i] <= 5 ? 1 : 0;
|
|
986
|
+
}
|
|
987
|
+
const meanOf = (weights, radiusPx) => {
|
|
988
|
+
const wm = boxMean(weights, w, h, radiusPx);
|
|
989
|
+
const planes = [0, 1, 2].map((c) => {
|
|
990
|
+
const v = new Float32Array(n);
|
|
991
|
+
for (let i = 0; i < n; i++) v[i] = rgba[i * 4 + c] * weights[i];
|
|
992
|
+
const m = boxMean(v, w, h, radiusPx);
|
|
993
|
+
for (let i = 0; i < n; i++) m[i] = wm[i] > 1e-6 ? m[i] / wm[i] : NaN;
|
|
994
|
+
return m;
|
|
995
|
+
});
|
|
996
|
+
return { weight: wm, planes };
|
|
997
|
+
};
|
|
998
|
+
const fg = meanOf(fgW, r);
|
|
999
|
+
const fgWide = meanOf(fgW, r * 3);
|
|
1000
|
+
const bg = meanOf(bgW, r);
|
|
1001
|
+
for (let i = 0; i < n; i++) {
|
|
1002
|
+
const c = coverage[i];
|
|
1003
|
+
if (c <= 5 || c >= 250) continue;
|
|
1004
|
+
const a = c / 255;
|
|
1005
|
+
for (let ch = 0; ch < 3; ch++) {
|
|
1006
|
+
const C = rgba[i * 4 + ch];
|
|
1007
|
+
const B = bg.planes[ch][i];
|
|
1008
|
+
const Fm = Number.isNaN(fg.planes[ch][i]) ? fgWide.planes[ch][i] : fg.planes[ch][i];
|
|
1009
|
+
let F;
|
|
1010
|
+
if (a >= 0.5 && !Number.isNaN(B)) F = (C - (1 - a) * B) / a;
|
|
1011
|
+
else if (!Number.isNaN(Fm)) F = Fm;
|
|
1012
|
+
else F = C;
|
|
1013
|
+
out[i * 4 + ch] = Math.round(C + k * (Math.min(255, Math.max(0, F)) - C));
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
return out;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
727
1019
|
export {
|
|
728
1020
|
SELECTION_MODES,
|
|
729
1021
|
isSelectionMode,
|
|
@@ -759,5 +1051,16 @@ export {
|
|
|
759
1051
|
greyMorphology,
|
|
760
1052
|
shiftCoverage,
|
|
761
1053
|
SELECTION_MODIFY_OPS,
|
|
762
|
-
modifySelection
|
|
1054
|
+
modifySelection,
|
|
1055
|
+
DEFAULT_REFINE_EDGE_PARAMS,
|
|
1056
|
+
GUIDED_FILTER_EPS,
|
|
1057
|
+
normalizeRefineEdgeParams,
|
|
1058
|
+
refineEdgeHalo,
|
|
1059
|
+
boxMean,
|
|
1060
|
+
guidedFilterColor,
|
|
1061
|
+
edgeWidth,
|
|
1062
|
+
refineCoverage,
|
|
1063
|
+
guidePlanes,
|
|
1064
|
+
refineSelection,
|
|
1065
|
+
decontaminateColors
|
|
763
1066
|
};
|
|
@@ -283,6 +283,15 @@ export interface CloneSource {
|
|
|
283
283
|
/** A vector mask's path: several `components`, or one `shape` / `subpaths` (with `op`). */
|
|
284
284
|
/** What `inspectMaskEdge` reads: the selection, a layer's painted mask or its vector mask. */
|
|
285
285
|
export type MaskEdgeTarget = 'selection' | 'layer-mask' | 'vector-mask';
|
|
286
|
+
/** A layer's edge colour as `getEdgeColor` describes it (percentages). */
|
|
287
|
+
export interface EdgeColorInfo {
|
|
288
|
+
layerId: string;
|
|
289
|
+
decontaminate: number;
|
|
290
|
+
despill: number;
|
|
291
|
+
ambient: number;
|
|
292
|
+
/** `auto` (what is behind the layer, live) or `#rrggbb`. */
|
|
293
|
+
ambientSource: string;
|
|
294
|
+
}
|
|
286
295
|
export interface VectorMaskPathInput extends ShapeGeometryInput {
|
|
287
296
|
components?: ShapeGeometryInput[];
|
|
288
297
|
fillRule?: ShapeFillRule;
|
|
@@ -1025,6 +1034,26 @@ export declare class ImageEditorController {
|
|
|
1025
1034
|
parentId: string | null;
|
|
1026
1035
|
index: number;
|
|
1027
1036
|
};
|
|
1037
|
+
/** A layer's edge colour as percentages (see `setEdgeColor`). */
|
|
1038
|
+
getEdgeColor(id: string): EdgeColorInfo;
|
|
1039
|
+
private requireEdgeLayer;
|
|
1040
|
+
/** Whether the layer's mask (painted and vector, with feather) has a soft band. */
|
|
1041
|
+
private maskHasSoftBand;
|
|
1042
|
+
/**
|
|
1043
|
+
* Edge colour on a layer's soft edge, applied when compositing (nothing is baked); amounts in
|
|
1044
|
+
* percent, 0 turns one off. `decontaminate` unmixes the old background (the pixels the mask
|
|
1045
|
+
* hides) from the edge and `despill` limits its hue there: both need a pixel layer whose mask
|
|
1046
|
+
* (painted or vector) has a soft band. `ambient` pulls the edge toward what is behind the layer
|
|
1047
|
+
* (`ambientColor` null: sampled live) or a fixed `#rrggbb`; it needs a soft mask or soft
|
|
1048
|
+
* pixels at the edge. Validates everything before changing anything; one undo step (none with
|
|
1049
|
+
* `commitToHistory` false, for the later moves of a slider drag). Returns the effective settings.
|
|
1050
|
+
*/
|
|
1051
|
+
setEdgeColor(id: string, change: {
|
|
1052
|
+
decontaminate?: number;
|
|
1053
|
+
despill?: number;
|
|
1054
|
+
ambient?: number;
|
|
1055
|
+
ambientColor?: string | null;
|
|
1056
|
+
}, commitToHistory?: boolean): EdgeColorInfo;
|
|
1028
1057
|
/**
|
|
1029
1058
|
* Changes name, visibility, opacity, fill, blend, clipping, locks or (groups) collapsed state, as
|
|
1030
1059
|
* one undo step (`commitToHistory = false` for the moves of a slider drag). Returns the layer.
|
|
@@ -283,6 +283,15 @@ export interface CloneSource {
|
|
|
283
283
|
/** A vector mask's path: several `components`, or one `shape` / `subpaths` (with `op`). */
|
|
284
284
|
/** What `inspectMaskEdge` reads: the selection, a layer's painted mask or its vector mask. */
|
|
285
285
|
export type MaskEdgeTarget = 'selection' | 'layer-mask' | 'vector-mask';
|
|
286
|
+
/** A layer's edge colour as `getEdgeColor` describes it (percentages). */
|
|
287
|
+
export interface EdgeColorInfo {
|
|
288
|
+
layerId: string;
|
|
289
|
+
decontaminate: number;
|
|
290
|
+
despill: number;
|
|
291
|
+
ambient: number;
|
|
292
|
+
/** `auto` (what is behind the layer, live) or `#rrggbb`. */
|
|
293
|
+
ambientSource: string;
|
|
294
|
+
}
|
|
286
295
|
export interface VectorMaskPathInput extends ShapeGeometryInput {
|
|
287
296
|
components?: ShapeGeometryInput[];
|
|
288
297
|
fillRule?: ShapeFillRule;
|
|
@@ -1025,6 +1034,26 @@ export declare class ImageEditorController {
|
|
|
1025
1034
|
parentId: string | null;
|
|
1026
1035
|
index: number;
|
|
1027
1036
|
};
|
|
1037
|
+
/** A layer's edge colour as percentages (see `setEdgeColor`). */
|
|
1038
|
+
getEdgeColor(id: string): EdgeColorInfo;
|
|
1039
|
+
private requireEdgeLayer;
|
|
1040
|
+
/** Whether the layer's mask (painted and vector, with feather) has a soft band. */
|
|
1041
|
+
private maskHasSoftBand;
|
|
1042
|
+
/**
|
|
1043
|
+
* Edge colour on a layer's soft edge, applied when compositing (nothing is baked); amounts in
|
|
1044
|
+
* percent, 0 turns one off. `decontaminate` unmixes the old background (the pixels the mask
|
|
1045
|
+
* hides) from the edge and `despill` limits its hue there: both need a pixel layer whose mask
|
|
1046
|
+
* (painted or vector) has a soft band. `ambient` pulls the edge toward what is behind the layer
|
|
1047
|
+
* (`ambientColor` null: sampled live) or a fixed `#rrggbb`; it needs a soft mask or soft
|
|
1048
|
+
* pixels at the edge. Validates everything before changing anything; one undo step (none with
|
|
1049
|
+
* `commitToHistory` false, for the later moves of a slider drag). Returns the effective settings.
|
|
1050
|
+
*/
|
|
1051
|
+
setEdgeColor(id: string, change: {
|
|
1052
|
+
decontaminate?: number;
|
|
1053
|
+
despill?: number;
|
|
1054
|
+
ambient?: number;
|
|
1055
|
+
ambientColor?: string | null;
|
|
1056
|
+
}, commitToHistory?: boolean): EdgeColorInfo;
|
|
1028
1057
|
/**
|
|
1029
1058
|
* Changes name, visibility, opacity, fill, blend, clipping, locks or (groups) collapsed state, as
|
|
1030
1059
|
* one undo step (`commitToHistory = false` for the moves of a slider drag). Returns the layer.
|