Pad an open void's canvas to a tile: the merge page's preview is shorter than one, and filled nothing

This commit is contained in:
2026-09-20 20:19:01 +02:00
parent 8d72cabff5
commit 9c556364fa
+53 -9
View File
@@ -303,7 +303,7 @@ fn fill_once(
} }
// The padded canvas with mirrored context, and the hole within it. // The padded canvas with mirrored context, and the hole within it.
let ctx = MirroredContext::build(rgb, width, height, known, mirror_depth); let ctx = MirroredContext::build(rgb, width, height, known, mirror_depth, t);
let (pw, ph) = (ctx.width, ctx.height); let (pw, ph) = (ctx.width, ctx.height);
// Tiles that touch the hole, on a grid that reaches both far edges. // Tiles that touch the hole, on a grid that reaches both far edges.
@@ -499,16 +499,36 @@ struct MirroredContext {
} }
impl MirroredContext { impl MirroredContext {
fn build(rgb: &[f32], width: usize, height: usize, known: &[bool], depth: usize) -> Self { fn build(
rgb: &[f32],
width: usize,
height: usize,
known: &[bool],
depth: usize,
tile: usize,
) -> Self {
if depth == 0 { if depth == 0 {
// Open: the picture as it is, the hole as it is. What the hole // Open: the picture as it is, the hole as it is. What the hole
// holds does not matter — the model masks it out. // holds does not matter — the model masks it out. A picture
// smaller than a tile (the merge page's preview) sits at the
// origin of a tile-sized canvas whose rest is hole: still the
// void as it is, and the only way a tile fits at all.
let (pw, ph) = (width.max(tile), height.max(tile));
let mut canvas = vec![0.0f32; pw * ph * 3];
let mut hole = vec![true; pw * ph];
for y in 0..height {
canvas[y * pw * 3..(y * pw + width) * 3]
.copy_from_slice(&rgb[y * width * 3..(y + 1) * width * 3]);
for x in 0..width {
hole[y * pw + x] = !known[y * width + x];
}
}
return MirroredContext { return MirroredContext {
width, width: pw,
height, height: ph,
ring: 0, ring: 0,
rgb: rgb.to_vec(), rgb: canvas,
hole: known.iter().map(|&k| !k).collect(), hole,
}; };
} }
let fold = |d: usize| fold(d, depth); let fold = |d: usize| fold(d, depth);
@@ -715,6 +735,30 @@ mod tests {
} }
} }
#[test]
fn a_picture_smaller_than_the_tile_is_still_filled_when_the_void_is_open() {
// The merge page's preview is 1600 wide and a few hundred tall —
// shorter than a 512 tile. With no ring the canvas is padded to a
// tile, the padding hole, and the border is still filled.
let (mut rgb, known) = picture(300, 40, 8);
let mut model = Flat {
tile: 64,
seen: Vec::new(),
};
let tiles = fill_border(&mut rgb, 300, 40, &known, &mut model, test_params(0), &mut |_, _| {})
.unwrap();
assert!(tiles > 0, "no tile fitted a picture shorter than the tile");
for i in 0..300 * 40 {
if !known[i] {
assert!((rgb[i * 3] - 0.5).abs() < 1e-4, "pixel {i}");
}
}
// And the model saw the padding as hole, never as black content.
for (_, k) in &model.seen {
assert_eq!(k.len(), 64 * 64);
}
}
#[test] #[test]
fn the_fine_passes_run_in_bands_after_the_coarse_one() { fn the_fine_passes_run_in_bands_after_the_coarse_one() {
// A 150-tall hole above and below a picture: the coarse pass sees // A 150-tall hole above and below a picture: the coarse pass sees
@@ -824,7 +868,7 @@ mod tests {
#[test] #[test]
fn the_context_mirrors_the_top_rows_upward() { fn the_context_mirrors_the_top_rows_upward() {
let (rgb, known) = picture(40, 30, 5); let (rgb, known) = picture(40, 30, 5);
let ctx = MirroredContext::build(&rgb, 40, 30, &known, 48); let ctx = MirroredContext::build(&rgb, 40, 30, &known, 48, 64);
let x = RING + 10; let x = RING + 10;
let first = RING + 5; let first = RING + 5;
for k in 1..=4 { for k in 1..=4 {
@@ -846,7 +890,7 @@ mod tests {
for x in 0..40 { for x in 0..40 {
rgb[(ridge * 40 + x) * 3..(ridge * 40 + x) * 3 + 3].copy_from_slice(&[0.9, 0.1, 0.1]); rgb[(ridge * 40 + x) * 3..(ridge * 40 + x) * 3 + 3].copy_from_slice(&[0.9, 0.1, 0.1]);
} }
let ctx = MirroredContext::build(&rgb, 40, 400, &known, 48); let ctx = MirroredContext::build(&rgb, 40, 400, &known, 48, 64);
let x = RING + 10; let x = RING + 10;
for y in 0..RING + 5 { for y in 0..RING + 5 {
let p = (y * ctx.width + x) * 3; let p = (y * ctx.width + x) * 3;