@pixerate/editor 0.213.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 +44 -0
- package/dist/image-editor/controller.d.ts +44 -0
- package/dist/image-editor/index.cjs +1768 -1140
- package/dist/image-editor/index.d.cts +1 -0
- package/dist/image-editor/index.d.ts +1 -0
- package/dist/image-editor/index.js +660 -32
- 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/index.d.cts +1 -0
- package/dist/image-editor/selection/index.d.ts +1 -0
- package/dist/image-editor/selection/inspect.d.cts +70 -0
- package/dist/image-editor/selection/inspect.d.ts +70 -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 +9 -6
- package/skills/pixerate-image-editor/references/paths.md +12 -0
- package/skills/pixerate-image-selection-masking/SKILL.md +17 -17
|
@@ -724,6 +724,309 @@ 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 = _chunkK6PXS6DOcjs.gaussianBlur.call(void 0, 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 = _chunkK6PXS6DOcjs.gaussianBlur.call(void 0, 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 = _nullishCoalesce(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 = _optionalChain([refineBrush, 'optionalAccess', _5 => _5.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
|
+
|
|
1019
|
+
|
|
1020
|
+
|
|
1021
|
+
|
|
1022
|
+
|
|
1023
|
+
|
|
1024
|
+
|
|
1025
|
+
|
|
1026
|
+
|
|
1027
|
+
|
|
1028
|
+
|
|
1029
|
+
|
|
727
1030
|
|
|
728
1031
|
|
|
729
1032
|
|
|
@@ -760,4 +1063,4 @@ function modifySelection(mask, op, radius) {
|
|
|
760
1063
|
|
|
761
1064
|
|
|
762
1065
|
|
|
763
|
-
exports.SELECTION_MODES = SELECTION_MODES; exports.isSelectionMode = isSelectionMode; exports.parseSelectionMode = parseSelectionMode; exports.computeSelectionBounds = computeSelectionBounds; exports.selectionFromTiles = selectionFromTiles; exports.createSelectionMask = createSelectionMask; exports.selectionFromRegion = selectionFromRegion; exports.fullSelection = fullSelection; exports.isSelectionEmpty = isSelectionEmpty; exports.selectionValueAt = selectionValueAt; exports.coverageToByte = coverageToByte; exports.selectionFromCoverage = selectionFromCoverage; exports.selectionToCoverage = selectionToCoverage; exports.selectionArea = selectionArea; exports.combineSelections = combineSelections; exports.invertSelection = invertSelection; exports.resizeSelection = resizeSelection; exports.selectionFromPixels = selectionFromPixels; exports.selectionToPixels = selectionToPixels; exports.encodeSelectionRle = encodeSelectionRle; exports.decodeSelectionRle = decodeSelectionRle; exports.serializeSelection = serializeSelection; exports.deserializeSelection = deserializeSelection; exports.hashMaskContent = hashMaskContent; exports.EMPTY_DISTANCE = EMPTY_DISTANCE; exports.distanceTransform = distanceTransform; exports.expandCoverage = expandCoverage; exports.contractCoverage = contractCoverage; exports.borderCoverage = borderCoverage; exports.smoothCoverage = smoothCoverage; exports.featherCoverage = featherCoverage; exports.greyMorphology = greyMorphology; exports.shiftCoverage = shiftCoverage; exports.SELECTION_MODIFY_OPS = SELECTION_MODIFY_OPS; exports.modifySelection = modifySelection;
|
|
1066
|
+
exports.SELECTION_MODES = SELECTION_MODES; exports.isSelectionMode = isSelectionMode; exports.parseSelectionMode = parseSelectionMode; exports.computeSelectionBounds = computeSelectionBounds; exports.selectionFromTiles = selectionFromTiles; exports.createSelectionMask = createSelectionMask; exports.selectionFromRegion = selectionFromRegion; exports.fullSelection = fullSelection; exports.isSelectionEmpty = isSelectionEmpty; exports.selectionValueAt = selectionValueAt; exports.coverageToByte = coverageToByte; exports.selectionFromCoverage = selectionFromCoverage; exports.selectionToCoverage = selectionToCoverage; exports.selectionArea = selectionArea; exports.combineSelections = combineSelections; exports.invertSelection = invertSelection; exports.resizeSelection = resizeSelection; exports.selectionFromPixels = selectionFromPixels; exports.selectionToPixels = selectionToPixels; exports.encodeSelectionRle = encodeSelectionRle; exports.decodeSelectionRle = decodeSelectionRle; exports.serializeSelection = serializeSelection; exports.deserializeSelection = deserializeSelection; exports.hashMaskContent = hashMaskContent; exports.EMPTY_DISTANCE = EMPTY_DISTANCE; exports.distanceTransform = distanceTransform; exports.expandCoverage = expandCoverage; exports.contractCoverage = contractCoverage; exports.borderCoverage = borderCoverage; exports.smoothCoverage = smoothCoverage; exports.featherCoverage = featherCoverage; exports.greyMorphology = greyMorphology; exports.shiftCoverage = shiftCoverage; exports.SELECTION_MODIFY_OPS = SELECTION_MODIFY_OPS; exports.modifySelection = modifySelection; exports.DEFAULT_REFINE_EDGE_PARAMS = DEFAULT_REFINE_EDGE_PARAMS; exports.GUIDED_FILTER_EPS = GUIDED_FILTER_EPS; exports.normalizeRefineEdgeParams = normalizeRefineEdgeParams; exports.refineEdgeHalo = refineEdgeHalo; exports.boxMean = boxMean; exports.guidedFilterColor = guidedFilterColor; exports.edgeWidth = edgeWidth; exports.refineCoverage = refineCoverage; exports.guidePlanes = guidePlanes; exports.refineSelection = refineSelection; exports.decontaminateColors = decontaminateColors;
|
|
@@ -1,312 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
|
+
boxMean,
|
|
2
3
|
combineSelections,
|
|
3
4
|
coverageToByte,
|
|
4
5
|
createSelectionMask,
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
guidedFilterColor,
|
|
7
|
+
refineSelection,
|
|
7
8
|
selectionFromRegion,
|
|
8
|
-
selectionValueAt
|
|
9
|
-
|
|
10
|
-
} from "./chunk-L3G23N5Y.js";
|
|
11
|
-
import {
|
|
12
|
-
gaussianBlur
|
|
13
|
-
} from "./chunk-ZIF4UJJ6.js";
|
|
9
|
+
selectionValueAt
|
|
10
|
+
} from "./chunk-ZNA3IQZF.js";
|
|
14
11
|
import {
|
|
15
12
|
contentAwareFill
|
|
16
13
|
} from "./chunk-XI2NV5U7.js";
|
|
17
14
|
|
|
18
|
-
// src/image-editor/selection/refine.ts
|
|
19
|
-
var DEFAULT_REFINE_EDGE_PARAMS = {
|
|
20
|
-
radius: 0,
|
|
21
|
-
smartRadius: false,
|
|
22
|
-
smooth: 0,
|
|
23
|
-
feather: 0,
|
|
24
|
-
contrast: 0,
|
|
25
|
-
shiftEdge: 0
|
|
26
|
-
};
|
|
27
|
-
var GUIDED_FILTER_EPS = 1e-4;
|
|
28
|
-
var fin = (v, d) => typeof v === "number" && Number.isFinite(v) ? v : d;
|
|
29
|
-
function normalizeRefineEdgeParams(p = {}) {
|
|
30
|
-
return {
|
|
31
|
-
radius: Math.min(250, Math.max(0, fin(p.radius, 0))),
|
|
32
|
-
smartRadius: p.smartRadius === true,
|
|
33
|
-
smooth: Math.min(100, Math.max(0, fin(p.smooth, 0))),
|
|
34
|
-
feather: Math.min(1e3, Math.max(0, fin(p.feather, 0))),
|
|
35
|
-
contrast: Math.min(100, Math.max(0, fin(p.contrast, 0))),
|
|
36
|
-
shiftEdge: Math.min(100, Math.max(-100, fin(p.shiftEdge, 0)))
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
var gfRadius = (p) => Math.min(64, Math.max(1, Math.ceil(p.radius)));
|
|
40
|
-
var smoothSigma = (p) => p.smooth / 100 * 4;
|
|
41
|
-
var featherSigma = (p) => p.feather / 2;
|
|
42
|
-
function shiftAmount(p) {
|
|
43
|
-
const px = p.shiftEdge / 100 * Math.max(p.radius, 4);
|
|
44
|
-
return Number.isFinite(px) ? Math.min(64, Math.max(-64, px)) : 0;
|
|
45
|
-
}
|
|
46
|
-
function refineEdgeHalo(params = {}) {
|
|
47
|
-
const p = normalizeRefineEdgeParams(params);
|
|
48
|
-
const g = gfRadius(p);
|
|
49
|
-
const edge = p.radius > 0 ? Math.max(Math.ceil(p.radius), 2 * g + (p.smartRadius ? g + 1 : 0)) : 0;
|
|
50
|
-
return edge + Math.ceil(3 * smoothSigma(p)) + Math.ceil(3 * featherSigma(p)) + Math.ceil(Math.abs(shiftAmount(p))) + 2;
|
|
51
|
-
}
|
|
52
|
-
function boxMean(src, w, h, r) {
|
|
53
|
-
const tmp = new Float32Array(w * h);
|
|
54
|
-
const pre = new Float64Array(Math.max(w, h) + 1);
|
|
55
|
-
for (let y = 0; y < h; y++) {
|
|
56
|
-
const row = y * w;
|
|
57
|
-
for (let x = 0; x < w; x++) pre[x + 1] = pre[x] + src[row + x];
|
|
58
|
-
for (let x = 0; x < w; x++) {
|
|
59
|
-
const lo = Math.max(0, x - r);
|
|
60
|
-
const hi = Math.min(w, x + r + 1);
|
|
61
|
-
tmp[row + x] = (pre[hi] - pre[lo]) / (hi - lo);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
const out = new Float32Array(w * h);
|
|
65
|
-
for (let x = 0; x < w; x++) {
|
|
66
|
-
for (let y = 0; y < h; y++) pre[y + 1] = pre[y] + tmp[y * w + x];
|
|
67
|
-
for (let y = 0; y < h; y++) {
|
|
68
|
-
const lo = Math.max(0, y - r);
|
|
69
|
-
const hi = Math.min(h, y + r + 1);
|
|
70
|
-
out[y * w + x] = (pre[hi] - pre[lo]) / (hi - lo);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
return out;
|
|
74
|
-
}
|
|
75
|
-
function guidedFilterColor(guide, p, w, h, r, eps = GUIDED_FILTER_EPS) {
|
|
76
|
-
const n = w * h;
|
|
77
|
-
const [c0, c1, c2] = guide;
|
|
78
|
-
const prod = (a, b2) => {
|
|
79
|
-
const o = new Float32Array(n);
|
|
80
|
-
for (let i = 0; i < n; i++) o[i] = a[i] * b2[i];
|
|
81
|
-
return o;
|
|
82
|
-
};
|
|
83
|
-
const m0 = boxMean(c0, w, h, r);
|
|
84
|
-
const m1 = boxMean(c1, w, h, r);
|
|
85
|
-
const m2 = boxMean(c2, w, h, r);
|
|
86
|
-
const mp = boxMean(p, w, h, r);
|
|
87
|
-
const mip0 = boxMean(prod(c0, p), w, h, r);
|
|
88
|
-
const mip1 = boxMean(prod(c1, p), w, h, r);
|
|
89
|
-
const mip2 = boxMean(prod(c2, p), w, h, r);
|
|
90
|
-
const s00 = boxMean(prod(c0, c0), w, h, r);
|
|
91
|
-
const s01 = boxMean(prod(c0, c1), w, h, r);
|
|
92
|
-
const s02 = boxMean(prod(c0, c2), w, h, r);
|
|
93
|
-
const s11 = boxMean(prod(c1, c1), w, h, r);
|
|
94
|
-
const s12 = boxMean(prod(c1, c2), w, h, r);
|
|
95
|
-
const s22 = boxMean(prod(c2, c2), w, h, r);
|
|
96
|
-
const a0 = new Float32Array(n);
|
|
97
|
-
const a1 = new Float32Array(n);
|
|
98
|
-
const a2 = new Float32Array(n);
|
|
99
|
-
const b = new Float32Array(n);
|
|
100
|
-
for (let i = 0; i < n; i++) {
|
|
101
|
-
const u0 = m0[i], u1 = m1[i], u2 = m2[i], up = mp[i];
|
|
102
|
-
const rr = s00[i] - u0 * u0 + eps;
|
|
103
|
-
const rg = s01[i] - u0 * u1;
|
|
104
|
-
const rb = s02[i] - u0 * u2;
|
|
105
|
-
const gg = s11[i] - u1 * u1 + eps;
|
|
106
|
-
const gb = s12[i] - u1 * u2;
|
|
107
|
-
const bb = s22[i] - u2 * u2 + eps;
|
|
108
|
-
const v0 = mip0[i] - u0 * up;
|
|
109
|
-
const v1 = mip1[i] - u1 * up;
|
|
110
|
-
const v2 = mip2[i] - u2 * up;
|
|
111
|
-
const i00 = gg * bb - gb * gb;
|
|
112
|
-
const i01 = gb * rb - rg * bb;
|
|
113
|
-
const i02 = rg * gb - gg * rb;
|
|
114
|
-
const i11 = rr * bb - rb * rb;
|
|
115
|
-
const i12 = rb * rg - rr * gb;
|
|
116
|
-
const i22 = rr * gg - rg * rg;
|
|
117
|
-
const det = rr * i00 + rg * i01 + rb * i02;
|
|
118
|
-
let x0 = 0, x1 = 0, x2 = 0;
|
|
119
|
-
if (Math.abs(det) >= 1e-30) {
|
|
120
|
-
x0 = (i00 * v0 + i01 * v1 + i02 * v2) / det;
|
|
121
|
-
x1 = (i01 * v0 + i11 * v1 + i12 * v2) / det;
|
|
122
|
-
x2 = (i02 * v0 + i12 * v1 + i22 * v2) / det;
|
|
123
|
-
}
|
|
124
|
-
a0[i] = x0;
|
|
125
|
-
a1[i] = x1;
|
|
126
|
-
a2[i] = x2;
|
|
127
|
-
b[i] = up - x0 * u0 - x1 * u1 - x2 * u2;
|
|
128
|
-
}
|
|
129
|
-
const ma0 = boxMean(a0, w, h, r);
|
|
130
|
-
const ma1 = boxMean(a1, w, h, r);
|
|
131
|
-
const ma2 = boxMean(a2, w, h, r);
|
|
132
|
-
const mb = boxMean(b, w, h, r);
|
|
133
|
-
const out = new Float32Array(n);
|
|
134
|
-
for (let i = 0; i < n; i++) out[i] = ma0[i] * c0[i] + ma1[i] * c1[i] + ma2[i] * c2[i] + mb[i];
|
|
135
|
-
return out;
|
|
136
|
-
}
|
|
137
|
-
function edgeWidth(guide, w, h, r) {
|
|
138
|
-
const n = w * h;
|
|
139
|
-
const y = new Float32Array(n);
|
|
140
|
-
for (let i = 0; i < n; i++) y[i] = 0.299 * guide[0][i] + 0.587 * guide[1][i] + 0.114 * guide[2][i];
|
|
141
|
-
const g = new Float32Array(n);
|
|
142
|
-
for (let yy = 0; yy < h; yy++) {
|
|
143
|
-
for (let xx = 0; xx < w; xx++) {
|
|
144
|
-
const gx = (y[yy * w + Math.min(w - 1, xx + 1)] - y[yy * w + Math.max(0, xx - 1)]) / 2;
|
|
145
|
-
const gy = (y[Math.min(h - 1, yy + 1) * w + xx] - y[Math.max(0, yy - 1) * w + xx]) / 2;
|
|
146
|
-
g[yy * w + xx] = Math.sqrt(gx * gx + gy * gy);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
const gm = greyMorphology(g, w, h, r, true);
|
|
150
|
-
const hi = greyMorphology(y, w, h, r, true);
|
|
151
|
-
const lo = greyMorphology(y, w, h, r, false);
|
|
152
|
-
const out = new Float32Array(n);
|
|
153
|
-
for (let i = 0; i < n; i++) out[i] = (hi[i] - lo[i]) / Math.max(gm[i], 1e-4);
|
|
154
|
-
return out;
|
|
155
|
-
}
|
|
156
|
-
function refineCoverage(guide, m, w, h, params = {}, band = null) {
|
|
157
|
-
const p = normalizeRefineEdgeParams(params);
|
|
158
|
-
let a = Float32Array.from(m);
|
|
159
|
-
if ((p.radius > 0 || band) && guide) {
|
|
160
|
-
const n = w * h;
|
|
161
|
-
const boundary = new Uint8Array(n);
|
|
162
|
-
let any = false;
|
|
163
|
-
for (let y = 0; y < h; y++) {
|
|
164
|
-
for (let x = 0; x < w; x++) {
|
|
165
|
-
const i = y * w + x;
|
|
166
|
-
const v = m[i] >= 0.5;
|
|
167
|
-
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;
|
|
168
|
-
if (diff) {
|
|
169
|
-
boundary[i] = 1;
|
|
170
|
-
any = true;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
if (any || band) {
|
|
175
|
-
const dist = distanceTransform(boundary, w, h);
|
|
176
|
-
const r = band ? Math.max(4, gfRadius(p)) : gfRadius(p);
|
|
177
|
-
const q = guidedFilterColor(guide, m, w, h, r);
|
|
178
|
-
const widths = p.smartRadius ? edgeWidth(guide, w, h, r) : null;
|
|
179
|
-
for (let i = 0; i < n; i++) {
|
|
180
|
-
const reff = widths ? Math.min(Math.max(p.radius, 1.5), Math.max(1.5, widths[i])) : p.radius;
|
|
181
|
-
const edge = p.radius > 0 ? Math.min(1, Math.max(0, reff + 1 - dist[i])) : 0;
|
|
182
|
-
const wgt = band ? Math.max(edge, Math.min(1, Math.max(0, band[i]))) : edge;
|
|
183
|
-
if (wgt > 0) {
|
|
184
|
-
const qi = Math.min(1, Math.max(0, q[i]));
|
|
185
|
-
a[i] = m[i] + (qi - m[i]) * wgt;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
const ss = smoothSigma(p);
|
|
191
|
-
if (ss >= 0.3) {
|
|
192
|
-
a = gaussianBlur(a, w, h, ss, "clamp");
|
|
193
|
-
const gain = 1 + ss;
|
|
194
|
-
for (let i = 0; i < a.length; i++) a[i] = Math.min(1, Math.max(0, (a[i] - 0.5) * gain + 0.5));
|
|
195
|
-
}
|
|
196
|
-
a = gaussianBlur(a, w, h, featherSigma(p), "clamp");
|
|
197
|
-
if (p.contrast > 0) {
|
|
198
|
-
const gain = 1 / (1 - 0.99 * p.contrast / 100);
|
|
199
|
-
for (let i = 0; i < a.length; i++) a[i] = Math.min(1, Math.max(0, (a[i] - 0.5) * gain + 0.5));
|
|
200
|
-
}
|
|
201
|
-
const amount = shiftAmount(p);
|
|
202
|
-
if (Math.abs(amount) >= 1e-4) a = shiftCoverage(a, w, h, amount);
|
|
203
|
-
return a;
|
|
204
|
-
}
|
|
205
|
-
function guidePlanes(pixels, win) {
|
|
206
|
-
const box = win ?? { x: 0, y: 0, width: pixels.width, height: pixels.height };
|
|
207
|
-
const n = box.width * box.height;
|
|
208
|
-
const r = new Float32Array(n);
|
|
209
|
-
const g = new Float32Array(n);
|
|
210
|
-
const b = new Float32Array(n);
|
|
211
|
-
const d = pixels.data;
|
|
212
|
-
for (let y = 0; y < box.height; y++) {
|
|
213
|
-
for (let x = 0; x < box.width; x++) {
|
|
214
|
-
const i = y * box.width + x;
|
|
215
|
-
const p = ((box.y + y) * pixels.width + box.x + x) * 4;
|
|
216
|
-
r[i] = d[p] / 255;
|
|
217
|
-
g[i] = d[p + 1] / 255;
|
|
218
|
-
b[i] = d[p + 2] / 255;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
return [r, g, b];
|
|
222
|
-
}
|
|
223
|
-
function refineSelection(pixels, mask, params = {}, refineBrush = null) {
|
|
224
|
-
const p = normalizeRefineEdgeParams(params);
|
|
225
|
-
if (pixels && (pixels.width !== mask.width || pixels.height !== mask.height)) {
|
|
226
|
-
throw new Error("Refine Edge needs pixels the size of the selection");
|
|
227
|
-
}
|
|
228
|
-
if (!mask.bounds) return mask;
|
|
229
|
-
const brush = refineBrush?.bounds ? refineBrush : null;
|
|
230
|
-
const halo = refineEdgeHalo(p) + (brush ? 2 * Math.max(4, gfRadius(p)) : 0);
|
|
231
|
-
const b = brush ? {
|
|
232
|
-
x: Math.min(mask.bounds.x, brush.bounds.x),
|
|
233
|
-
y: Math.min(mask.bounds.y, brush.bounds.y),
|
|
234
|
-
r: Math.max(mask.bounds.x + mask.bounds.width, brush.bounds.x + brush.bounds.width),
|
|
235
|
-
btm: Math.max(mask.bounds.y + mask.bounds.height, brush.bounds.y + brush.bounds.height)
|
|
236
|
-
} : { x: mask.bounds.x, y: mask.bounds.y, r: mask.bounds.x + mask.bounds.width, btm: mask.bounds.y + mask.bounds.height };
|
|
237
|
-
const x0 = Math.max(0, b.x - halo);
|
|
238
|
-
const y0 = Math.max(0, b.y - halo);
|
|
239
|
-
const x1 = Math.min(mask.width, b.r + halo);
|
|
240
|
-
const y1 = Math.min(mask.height, b.btm + halo);
|
|
241
|
-
const ww = x1 - x0;
|
|
242
|
-
const wh = y1 - y0;
|
|
243
|
-
const m = new Float32Array(ww * wh);
|
|
244
|
-
for (let y = 0; y < wh; y++) {
|
|
245
|
-
const src = (y0 + y) * mask.width + x0;
|
|
246
|
-
for (let x = 0; x < ww; x++) m[y * ww + x] = mask.data[src + x] / 255;
|
|
247
|
-
}
|
|
248
|
-
const guide = pixels && (p.radius > 0 || brush) ? guidePlanes(pixels, { x: x0, y: y0, width: ww, height: wh }) : null;
|
|
249
|
-
let band = null;
|
|
250
|
-
if (brush) {
|
|
251
|
-
band = new Float32Array(ww * wh);
|
|
252
|
-
const bd = brush.data;
|
|
253
|
-
for (let y = 0; y < wh; y++) {
|
|
254
|
-
const src = (y0 + y) * mask.width + x0;
|
|
255
|
-
for (let x = 0; x < ww; x++) band[y * ww + x] = bd[src + x] / 255;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
const refined = refineCoverage(guide, m, ww, wh, p, band);
|
|
259
|
-
const out = new Uint8Array(mask.width * mask.height);
|
|
260
|
-
for (let y = 0; y < wh; y++) {
|
|
261
|
-
const dst = (y0 + y) * mask.width + x0;
|
|
262
|
-
for (let x = 0; x < ww; x++) out[dst + x] = coverageToByte(refined[y * ww + x]);
|
|
263
|
-
}
|
|
264
|
-
return createSelectionMask(mask.width, mask.height, out);
|
|
265
|
-
}
|
|
266
|
-
function decontaminateColors(rgba, coverage, w, h, amount, radius = 8) {
|
|
267
|
-
const out = Uint8ClampedArray.from(rgba);
|
|
268
|
-
const n = w * h;
|
|
269
|
-
const k = Math.min(1, Math.max(0, amount));
|
|
270
|
-
if (k === 0) return out;
|
|
271
|
-
const r = Math.max(2, Math.round(radius));
|
|
272
|
-
const fgW = new Float32Array(n);
|
|
273
|
-
const bgW = new Float32Array(n);
|
|
274
|
-
for (let i = 0; i < n; i++) {
|
|
275
|
-
fgW[i] = coverage[i] >= 250 ? 1 : 0;
|
|
276
|
-
bgW[i] = coverage[i] <= 5 ? 1 : 0;
|
|
277
|
-
}
|
|
278
|
-
const meanOf = (weights, radiusPx) => {
|
|
279
|
-
const wm = boxMean(weights, w, h, radiusPx);
|
|
280
|
-
const planes = [0, 1, 2].map((c) => {
|
|
281
|
-
const v = new Float32Array(n);
|
|
282
|
-
for (let i = 0; i < n; i++) v[i] = rgba[i * 4 + c] * weights[i];
|
|
283
|
-
const m = boxMean(v, w, h, radiusPx);
|
|
284
|
-
for (let i = 0; i < n; i++) m[i] = wm[i] > 1e-6 ? m[i] / wm[i] : NaN;
|
|
285
|
-
return m;
|
|
286
|
-
});
|
|
287
|
-
return { weight: wm, planes };
|
|
288
|
-
};
|
|
289
|
-
const fg = meanOf(fgW, r);
|
|
290
|
-
const fgWide = meanOf(fgW, r * 3);
|
|
291
|
-
const bg = meanOf(bgW, r);
|
|
292
|
-
for (let i = 0; i < n; i++) {
|
|
293
|
-
const c = coverage[i];
|
|
294
|
-
if (c <= 5 || c >= 250) continue;
|
|
295
|
-
const a = c / 255;
|
|
296
|
-
for (let ch = 0; ch < 3; ch++) {
|
|
297
|
-
const C = rgba[i * 4 + ch];
|
|
298
|
-
const B = bg.planes[ch][i];
|
|
299
|
-
const Fm = Number.isNaN(fg.planes[ch][i]) ? fgWide.planes[ch][i] : fg.planes[ch][i];
|
|
300
|
-
let F;
|
|
301
|
-
if (a >= 0.5 && !Number.isNaN(B)) F = (C - (1 - a) * B) / a;
|
|
302
|
-
else if (!Number.isNaN(Fm)) F = Fm;
|
|
303
|
-
else F = C;
|
|
304
|
-
out[i * 4 + ch] = Math.round(C + k * (Math.min(255, Math.max(0, F)) - C));
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
return out;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
15
|
// src/image-editor/selection/shapes.ts
|
|
311
16
|
function polygonCoverage(points, width, height, antiAlias = true) {
|
|
312
17
|
const { box, coverage } = polygonCoverageBox(points, width, height, antiAlias);
|
|
@@ -1970,17 +1675,6 @@ var SelectionWorkerClient = class {
|
|
|
1970
1675
|
};
|
|
1971
1676
|
|
|
1972
1677
|
export {
|
|
1973
|
-
DEFAULT_REFINE_EDGE_PARAMS,
|
|
1974
|
-
GUIDED_FILTER_EPS,
|
|
1975
|
-
normalizeRefineEdgeParams,
|
|
1976
|
-
refineEdgeHalo,
|
|
1977
|
-
boxMean,
|
|
1978
|
-
guidedFilterColor,
|
|
1979
|
-
edgeWidth,
|
|
1980
|
-
refineCoverage,
|
|
1981
|
-
guidePlanes,
|
|
1982
|
-
refineSelection,
|
|
1983
|
-
decontaminateColors,
|
|
1984
1678
|
polygonCoverage,
|
|
1985
1679
|
polygonCoverageBox,
|
|
1986
1680
|
polygonSelection,
|