wonfy-tools 0.2.0

Collection of tools for personal use, provides library and CLI.
Documentation
// Converts a region of RGBA8 pixels into per-pixel match values (0..255):
// mode 0 = mean of RGB, mode 1 = Sobel L1 edge magnitude of the srgb luma.
// Transparent pixels (alpha 0, e.g. unfilled composite padding) additionally
// carry the 0x100 invalid flag so scoring won't treat them as real content.
// Output is written in "match space": rows become columns when transpose == 1,
// so downstream scoring is direction-agnostic.

struct Params {
    in_width: u32,
    in_height: u32,
    out_width: u32,
    out_height: u32,
    halo_x: u32,
    halo_y: u32,
    mode: u32,
    transpose: u32,
}

@group(0) @binding(0) var<uniform> params: Params;
@group(0) @binding(1) var<storage, read> input: array<u32>;
@group(0) @binding(2) var<storage, read_write> output: array<u32>;

fn luma_at(x: i32, y: i32) -> i32 {
    let cx = u32(clamp(x, 0, i32(params.in_width) - 1));
    let cy = u32(clamp(y, 0, i32(params.in_height) - 1));
    let word = input[cy * params.in_width + cx];
    let r = word & 0xffu;
    let g = (word >> 8u) & 0xffu;
    let b = (word >> 16u) & 0xffu;
    return i32((2126u * r + 7152u * g + 722u * b) / 10000u);
}

@compute @workgroup_size(16, 16)
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
    let ox = gid.x;
    let oy = gid.y;

    if ox >= params.out_width || oy >= params.out_height {
        return;
    }

    let ix = i32(ox + params.halo_x);
    let iy = i32(oy + params.halo_y);

    let own_word = input[u32(iy) * params.in_width + u32(ix)];
    var value: u32;

    if params.mode == 0u {
        let r = own_word & 0xffu;
        let g = (own_word >> 8u) & 0xffu;
        let b = (own_word >> 16u) & 0xffu;
        value = (r + g + b) / 3u;
    } else {
        let tl = luma_at(ix - 1, iy - 1);
        let tc = luma_at(ix, iy - 1);
        let tr = luma_at(ix + 1, iy - 1);
        let ml = luma_at(ix - 1, iy);
        let mr = luma_at(ix + 1, iy);
        let bl = luma_at(ix - 1, iy + 1);
        let bc = luma_at(ix, iy + 1);
        let br = luma_at(ix + 1, iy + 1);

        let gx = (tr + 2 * mr + br) - (tl + 2 * ml + bl);
        let gy = (bl + 2 * bc + br) - (tl + 2 * tc + tr);

        value = u32(abs(gx) + abs(gy)) / 8u;
    }

    if ((own_word >> 24u) & 0xffu) == 0u {
        value |= 0x100u;
    }

    if params.transpose == 0u {
        output[oy * params.out_width + ox] = value;
    } else {
        output[ox * params.out_height + oy] = value;
    }
}