Files
lightcraft/crates/inpaint/src/lib.rs
T
Andrew FrahnandClaude Opus 5.5 fe6d7b0192 Content-aware Remove: inpaint crate (PatchMatch completion) and a Fill spot mode
New `inpaint` crate (L1): multi-scale patch-based completion with a PatchMatch
nearest-neighbour field, seeded by a membrane fill. Deterministic, no panics on
hostile sizes, cancellable. Ported from PhotoCraft (MIT OR Apache-2.0).

Remove tool: a fourth spot mode, `fill` ("Content-Aware"), rebuilds the spot
from patches of its surroundings instead of one source; coarse-to-fine, so the
structure is chosen at a scale set by the spot size and preview and export agree
(tested). spot.add leaves its source unset.

Sources: C. Barnes et al., PatchMatch (SIGGRAPH 2009); Y. Wexler, E. Shechtman,
M. Irani, Space-Time Completion of Video (TPAMI 2007); P. Perez et al., Poisson
Image Editing (SIGGRAPH 2003) for the membrane fill; code ported from PhotoCraft
crates/algo/src/inpaint.rs + poisson.rs (a680ed22).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 19:30:42 +11:00

62 lines
2.7 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Content-aware hole filling (inpainting) for the Remove tool.
//!
//! * [`complete`]: multi-scale patch-based completion (Wexler, Shechtman, Irani 2007) with the
//! nearest-neighbour field found by PatchMatch (Barnes et al. 2009). See [`patchmatch`].
//! * [`membrane_fill`]: smooth harmonic fill, used to seed the coarsest level and as a fallback.
//!
//! Buffers are interleaved `w × h × ch` floats in any colour model plus a `w × h` hole mask.
//! Everything is deterministic (fixed-seed RNG, results independent of the thread count) and never
//! panics on mismatched sizes: such calls return `None` or the input unchanged.
//!
//! Sources: C. Barnes, E. Shechtman, A. Finkelstein, D. B. Goldman, *PatchMatch: A Randomized
//! Correspondence Algorithm for Structural Image Editing*, SIGGRAPH 2009; Y. Wexler, E. Shechtman,
//! M. Irani, *Space-Time Completion of Video*, PAMI 2007.
//!
//! Ported from PhotoCraft (`crates/algo/src/inpaint.rs`, `poisson.rs`, MIT OR Apache-2.0, same
//! organisation; see `NOTICE`).
#![forbid(unsafe_code)]
#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)]
pub mod membrane;
pub mod patchmatch;
pub use membrane::membrane_fill;
pub use patchmatch::{CompleteParams, complete, complete_with};
/// A cancelled [`complete_with`].
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Cancelled;
impl std::fmt::Display for Cancelled {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("cancelled")
}
}
impl std::error::Error for Cancelled {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn hostile_sizes_do_not_panic() {
assert_eq!(complete(4, 4, 3, &[0.0; 5], &[true; 16], &CompleteParams::default()), None);
assert_eq!(complete(4, 4, 0, &[], &[true; 16], &CompleteParams::default()), None);
assert_eq!(complete(usize::MAX, 2, 3, &[0.0; 6], &[true; 2], &CompleteParams::default()), None);
assert_eq!(membrane_fill(4, 4, 1, &[0.5; 3], &[true; 16]), vec![0.5; 3]);
// A hole covering everything: nothing to copy from.
assert_eq!(complete(16, 16, 1, &[0.5; 256], &[true; 256], &CompleteParams::default()), None);
// A tiny image smaller than a patch.
let _ = complete(2, 2, 1, &[0.5; 4], &[true, false, false, false], &CompleteParams::default());
}
#[test]
fn cancellation_stops() {
let img = vec![0.5f32; 64 * 64];
let hole: Vec<bool> = (0..64 * 64usize).map(|i| (i % 64).abs_diff(32) < 4 && (i / 64).abs_diff(32) < 4).collect();
assert_eq!(complete_with(64, 64, 1, &img, &hole, &CompleteParams::default(), &|| true), Err(Cancelled));
}
}