@pixerate/editor 0.219.1 → 0.220.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.
@@ -810,54 +810,62 @@ function selectObjectIn(pixels, target, options = {}) {
810
810
  let half = Math.max(24, Math.round(0.3 * Math.max(w, h)));
811
811
  let seed = null;
812
812
  let reseeds = 0;
813
+ let small;
813
814
  for (; ; ) {
814
815
  const rx = Math.max(0, px - half);
815
816
  const ry = Math.max(0, py - half);
816
817
  const roi = { x: rx, y: ry, width: Math.min(w, px + half + 1) - rx, height: Math.min(h, py + half + 1) - ry };
817
818
  const whole = roi.width === w && roi.height === h;
818
819
  const band = Math.max(4, Math.round(0.15 * half));
819
- const radius = seed ?? 0.3 * half;
820
820
  const n = roi.width * roi.height;
821
- const initial = new Uint8Array(n);
822
821
  const hardBg = new Uint8Array(n);
823
822
  const hardFg = new Uint8Array(n);
824
823
  const inBand = (x, y) => rx > 0 && x < band || ry > 0 && y < band || rx + roi.width < w && x >= roi.width - band || ry + roi.height < h && y >= roi.height - band;
825
824
  for (let y = 0; y < roi.height; y++) {
826
825
  for (let x = 0; x < roi.width; x++) {
827
826
  const p = y * roi.width + x;
828
- const d = Math.hypot(rx + x - px, ry + y - py);
829
827
  if (inBand(x, y)) hardBg[p] = 1;
830
- else if (d <= radius) initial[p] = 1;
831
- if (d <= 1.5) hardFg[p] = 1;
828
+ if (Math.hypot(rx + x - px, ry + y - py) <= 1.5) hardFg[p] = 1;
832
829
  }
833
830
  }
834
- const label = grabCutLabels(work, { roi, initial, hardBg, hardFg }, iterations, round);
835
- keepMainPieces(label, roi.width, roi.height, (py - ry) * roi.width + (px - rx));
836
- let touches = false;
837
- for (let y = 0; y < roi.height && !touches; y++) {
838
- for (let x = 0; x < roi.width; x++) {
839
- if (label[y * roi.width + x] && (inBand(x - 1, y) || inBand(x + 1, y) || inBand(x, y - 1) || inBand(x, y + 1))) {
840
- touches = true;
841
- break;
831
+ const cut = (radius) => {
832
+ const initial = new Uint8Array(n);
833
+ let seeded2 = 0;
834
+ for (let y = 0; y < roi.height; y++) {
835
+ for (let x = 0; x < roi.width; x++) {
836
+ const p = y * roi.width + x;
837
+ if (!hardBg[p] && Math.hypot(rx + x - px, ry + y - py) <= radius) {
838
+ initial[p] = 1;
839
+ seeded2++;
840
+ }
842
841
  }
843
842
  }
844
- }
845
- if (!touches && reseeds < 2) {
846
- let found = 0;
847
- let seeded = 0;
848
- for (let p = 0; p < n; p++) {
849
- found += label[p];
850
- seeded += initial[p];
851
- }
852
- if (found * 2 < seeded) {
853
- reseeds++;
854
- seed = Math.max(2, 0.7 * Math.sqrt(found / Math.PI));
855
- continue;
843
+ const label2 = grabCutLabels(work, { roi, initial, hardBg, hardFg }, iterations, round);
844
+ keepMainPieces(label2, roi.width, roi.height, (py - ry) * roi.width + (px - rx));
845
+ let found2 = 0;
846
+ let touches2 = false;
847
+ for (let y = 0; y < roi.height; y++) {
848
+ for (let x = 0; x < roi.width; x++) {
849
+ if (!label2[y * roi.width + x]) continue;
850
+ found2++;
851
+ if (inBand(x - 1, y) || inBand(x + 1, y) || inBand(x, y - 1) || inBand(x, y + 1)) touches2 = true;
852
+ }
856
853
  }
854
+ return { label: label2, seeded: seeded2, found: found2, touches: touches2 };
855
+ };
856
+ const { label, seeded, found, touches } = cut(seed ?? 0.3 * half);
857
+ if (!touches && reseeds < 2 && found * 2 < seeded) {
858
+ reseeds++;
859
+ seed = Math.max(2, 0.7 * Math.sqrt(found / Math.PI));
860
+ continue;
861
+ }
862
+ if (touches && small === void 0) {
863
+ const s = cut(Math.max(2, 0.05 * half));
864
+ small = !s.touches && s.found > 1.5 * s.seeded ? { roi, label: s.label } : null;
857
865
  }
858
866
  if (!touches || whole) {
859
867
  report?.(0.9, "Scaling up");
860
- const out = upscaleRegion(work, pixels, roi, label, enhance);
868
+ const out = small && edgesReached(label, roi, w, h) >= 3 ? upscaleRegion(work, pixels, small.roi, small.label, enhance) : upscaleRegion(work, pixels, roi, label, enhance);
861
869
  report?.(1, "Done");
862
870
  return out;
863
871
  }
@@ -865,6 +873,15 @@ function selectObjectIn(pixels, target, options = {}) {
865
873
  seed = null;
866
874
  }
867
875
  }
876
+ function edgesReached(label, roi, w, h) {
877
+ const { x: rx, y: ry, width: rw, height: rh } = roi;
878
+ const row = (y) => label.subarray(y * rw, (y + 1) * rw).includes(1);
879
+ const col = (x) => {
880
+ for (let y = 0; y < rh; y++) if (label[y * rw + x]) return true;
881
+ return false;
882
+ };
883
+ return +(rx === 0 && col(0)) + +(ry === 0 && row(0)) + +(rx + rw === w && col(rw - 1)) + +(ry + rh === h && row(rh - 1));
884
+ }
868
885
 
869
886
  // src/image-editor/selection/segment/quick.ts
870
887
  var BINS = 16;
@@ -810,54 +810,62 @@ function selectObjectIn(pixels, target, options = {}) {
810
810
  let half = Math.max(24, Math.round(0.3 * Math.max(w, h)));
811
811
  let seed = null;
812
812
  let reseeds = 0;
813
+ let small;
813
814
  for (; ; ) {
814
815
  const rx = Math.max(0, px - half);
815
816
  const ry = Math.max(0, py - half);
816
817
  const roi = { x: rx, y: ry, width: Math.min(w, px + half + 1) - rx, height: Math.min(h, py + half + 1) - ry };
817
818
  const whole = roi.width === w && roi.height === h;
818
819
  const band = Math.max(4, Math.round(0.15 * half));
819
- const radius = _nullishCoalesce(seed, () => ( 0.3 * half));
820
820
  const n = roi.width * roi.height;
821
- const initial = new Uint8Array(n);
822
821
  const hardBg = new Uint8Array(n);
823
822
  const hardFg = new Uint8Array(n);
824
823
  const inBand = (x, y) => rx > 0 && x < band || ry > 0 && y < band || rx + roi.width < w && x >= roi.width - band || ry + roi.height < h && y >= roi.height - band;
825
824
  for (let y = 0; y < roi.height; y++) {
826
825
  for (let x = 0; x < roi.width; x++) {
827
826
  const p = y * roi.width + x;
828
- const d = Math.hypot(rx + x - px, ry + y - py);
829
827
  if (inBand(x, y)) hardBg[p] = 1;
830
- else if (d <= radius) initial[p] = 1;
831
- if (d <= 1.5) hardFg[p] = 1;
828
+ if (Math.hypot(rx + x - px, ry + y - py) <= 1.5) hardFg[p] = 1;
832
829
  }
833
830
  }
834
- const label = grabCutLabels(work, { roi, initial, hardBg, hardFg }, iterations, round);
835
- keepMainPieces(label, roi.width, roi.height, (py - ry) * roi.width + (px - rx));
836
- let touches = false;
837
- for (let y = 0; y < roi.height && !touches; y++) {
838
- for (let x = 0; x < roi.width; x++) {
839
- if (label[y * roi.width + x] && (inBand(x - 1, y) || inBand(x + 1, y) || inBand(x, y - 1) || inBand(x, y + 1))) {
840
- touches = true;
841
- break;
831
+ const cut = (radius) => {
832
+ const initial = new Uint8Array(n);
833
+ let seeded2 = 0;
834
+ for (let y = 0; y < roi.height; y++) {
835
+ for (let x = 0; x < roi.width; x++) {
836
+ const p = y * roi.width + x;
837
+ if (!hardBg[p] && Math.hypot(rx + x - px, ry + y - py) <= radius) {
838
+ initial[p] = 1;
839
+ seeded2++;
840
+ }
842
841
  }
843
842
  }
844
- }
845
- if (!touches && reseeds < 2) {
846
- let found = 0;
847
- let seeded = 0;
848
- for (let p = 0; p < n; p++) {
849
- found += label[p];
850
- seeded += initial[p];
851
- }
852
- if (found * 2 < seeded) {
853
- reseeds++;
854
- seed = Math.max(2, 0.7 * Math.sqrt(found / Math.PI));
855
- continue;
843
+ const label2 = grabCutLabels(work, { roi, initial, hardBg, hardFg }, iterations, round);
844
+ keepMainPieces(label2, roi.width, roi.height, (py - ry) * roi.width + (px - rx));
845
+ let found2 = 0;
846
+ let touches2 = false;
847
+ for (let y = 0; y < roi.height; y++) {
848
+ for (let x = 0; x < roi.width; x++) {
849
+ if (!label2[y * roi.width + x]) continue;
850
+ found2++;
851
+ if (inBand(x - 1, y) || inBand(x + 1, y) || inBand(x, y - 1) || inBand(x, y + 1)) touches2 = true;
852
+ }
856
853
  }
854
+ return { label: label2, seeded: seeded2, found: found2, touches: touches2 };
855
+ };
856
+ const { label, seeded, found, touches } = cut(_nullishCoalesce(seed, () => ( 0.3 * half)));
857
+ if (!touches && reseeds < 2 && found * 2 < seeded) {
858
+ reseeds++;
859
+ seed = Math.max(2, 0.7 * Math.sqrt(found / Math.PI));
860
+ continue;
861
+ }
862
+ if (touches && small === void 0) {
863
+ const s = cut(Math.max(2, 0.05 * half));
864
+ small = !s.touches && s.found > 1.5 * s.seeded ? { roi, label: s.label } : null;
857
865
  }
858
866
  if (!touches || whole) {
859
867
  _optionalChain([report, 'optionalCall', _10 => _10(0.9, "Scaling up")]);
860
- const out = upscaleRegion(work, pixels, roi, label, enhance);
868
+ const out = small && edgesReached(label, roi, w, h) >= 3 ? upscaleRegion(work, pixels, small.roi, small.label, enhance) : upscaleRegion(work, pixels, roi, label, enhance);
861
869
  _optionalChain([report, 'optionalCall', _11 => _11(1, "Done")]);
862
870
  return out;
863
871
  }
@@ -865,6 +873,15 @@ function selectObjectIn(pixels, target, options = {}) {
865
873
  seed = null;
866
874
  }
867
875
  }
876
+ function edgesReached(label, roi, w, h) {
877
+ const { x: rx, y: ry, width: rw, height: rh } = roi;
878
+ const row = (y) => label.subarray(y * rw, (y + 1) * rw).includes(1);
879
+ const col = (x) => {
880
+ for (let y = 0; y < rh; y++) if (label[y * rw + x]) return true;
881
+ return false;
882
+ };
883
+ return +(rx === 0 && col(0)) + +(ry === 0 && row(0)) + +(rx + rw === w && col(rw - 1)) + +(ry + rh === h && row(rh - 1));
884
+ }
868
885
 
869
886
  // src/image-editor/selection/segment/quick.ts
870
887
  var BINS = 16;