open-standards/wai/wai-vector/src/paint.rs
Transaction Science 82aee67cde
Some checks failed
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Has been cancelled
no-vanity-metrics / WAI public text names no comparison (pull_request) Has been cancelled
no-vanity-metrics / WAI public text names no company or product (pull_request) Has been cancelled
standards workspaces build + test / jouleclaw-rs (pull_request) Has been cancelled
standards workspaces build + test / aac-rs (pull_request) Has been cancelled
standards workspaces build + test / arl-rs (pull_request) Has been cancelled
standards workspaces build + test / eoc-rs (pull_request) Has been cancelled
standards workspaces build + test / jcp-rs (pull_request) Has been cancelled
standards workspaces build + test / joule-code-rs (pull_request) Has been cancelled
standards workspaces build + test / joule-ui-rs (pull_request) Has been cancelled
standards workspaces build + test / joulecontract-rs (pull_request) Has been cancelled
standards workspaces build + test / jouledesk-rs (pull_request) Has been cancelled
standards workspaces build + test / joulehook-rs (pull_request) Has been cancelled
standards workspaces build + test / map-rs (pull_request) Has been cancelled
standards workspaces build + test / mesh-rs (pull_request) Has been cancelled
standards workspaces build + test / openpay (pull_request) Has been cancelled
standards workspaces build + test / proof-rs (pull_request) Has been cancelled
standards workspaces build + test / sandbox-rs (pull_request) Has been cancelled
standards workspaces build + test / sense-rs (pull_request) Has been cancelled
standards workspaces build + test / smart-byte-rs (pull_request) Has been cancelled
standards workspaces build + test / macOS energy backends (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · macos (pull_request) Has been cancelled
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Has been cancelled
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Has been cancelled
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Has been cancelled
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · macos (pull_request) Has been cancelled
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Has been cancelled
WAI energy receipts / energy receipts · linux (pull_request) Has been cancelled
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Has been cancelled
WAI energy receipts / energy receipts · macos (pull_request) Has been cancelled
WAI section references / cited sections exist (pull_request) Has been cancelled
wai-vector vector graphics / linux-aarch64 (pull_request) Has been cancelled
wai-vector vector graphics / linux-x86_64 (pull_request) Has been cancelled
wai-vector vector graphics / macos-arm64 (pull_request) Has been cancelled
wai-vector vector graphics / wasm32-wasip2 (wasmtime) (pull_request) Has been cancelled
wai-vector vector graphics / wasm32 under Node (pull_request) Has been cancelled
wai-vector vector graphics / fuzz, peak allocation, comparison count (pull_request) Has been cancelled
workflow hygiene / every workflow supersedes its own queue (pull_request) Has been cancelled
Merge wai/d7-2-vector-formats into wai/d7-3-vector-raster; clippy-clean raster
The D7-2 cleanup (no generated byte changes), with the fuzz seed
conflict resolved to D7-2's literal; the raster's chunked loops on
as_chunks, collapsed conditionals, and no placeholder bindings.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-11 04:31:54 -04:00

90 lines
3 KiB
Rust
Raw Permalink 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.

//! RS7 `vec_composite`, RS8 `vec_group` and RS9 `vec_unpremul` (§3.9, §2.9).
//!
//! A fill: `p′ = div255(p·o)` once per item per frame; `s = div255(p′·α)` at each pixel;
//! then source-over, `T ← s + div255(T·(255 − s_A))`. A group's pop:
//! `k = div255(m·o_g)`, `s = div255(G·k)`, then source-over into the parent. The order
//! is part of the definition. Every value stays below 2^24, and `c ≤ a ≤ 255` holds
//! throughout with no clamp.
use alloc::vec;
use alloc::vec::Vec;
use crate::arith::{div255, unpremul};
/// A premultiplied RGBA8 target of `w × h` pixels, row-major.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Target {
pub w: usize,
pub h: usize,
pub px: Vec<u8>,
}
impl Target {
/// A target cleared to `(0, 0, 0, 0)`.
pub fn clear(w: usize, h: usize) -> Target {
Target { w, h, px: vec![0; 4 * w * h] }
}
}
/// A fill's paint after its opacity: `p′_ch = div255(p_ch·o)`.
#[inline]
pub fn paint_opacity(p: [u8; 4], o: u8) -> [u32; 4] {
p.map(|c| div255(u32::from(c) * u32::from(o)))
}
/// Source-over of `s` into the pixel `t`.
#[inline]
pub fn src_over(t: &mut [u8], s: [u32; 4]) {
let inv = 255 - s[3];
for ch in 0..4 {
t[ch] = (s[ch] + div255(u32::from(t[ch]) * inv)) as u8;
}
}
/// RS7: composite a paint `p′` at each pixel of a box, with the coverage `alpha(c, r)`
/// at canvas pixel `(c, r)`.
pub fn composite(t: &mut Target, p: [u32; 4], c0: i64, r0: i64, bw: usize, bh: usize, alpha: impl Fn(usize, usize) -> u8) {
for r in 0..bh {
let y = r0 as usize + r;
for c in 0..bw {
let a = u32::from(alpha(c, r));
if a == 0 {
continue;
}
let s = p.map(|ch| div255(ch * a));
let i = 4 * (y * t.w + c0 as usize + c);
src_over(&mut t.px[i..i + 4], s);
}
}
}
/// RS8: pop a group's target `g` into its parent, with its clip's coverage `mask(x, y)`
/// (255 where it has no clip) and its opacity `o_g`.
pub fn group_pop(parent: &mut Target, g: &Target, o_g: u8, mask: impl Fn(usize, usize) -> u8) {
for y in 0..g.h {
for x in 0..g.w {
let i = 4 * (y * g.w + x);
if g.px[i + 3] == 0 {
// G = (0, 0, 0, 0): s = 0, and source-over of 0 leaves the parent.
continue;
}
let k = div255(u32::from(mask(x, y)) * u32::from(o_g));
let s = [0, 1, 2, 3].map(|ch| div255(u32::from(g.px[i + ch]) * k));
src_over(&mut parent.px[i..i + 4], s);
}
}
}
/// RS9: `RGBA8S`, the straight-alpha view of an `RGBA8P` buffer (§2.9).
pub fn unpremul_buffer(p: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(p.len());
for px in p.as_chunks::<4>().0 {
let a = px[3];
if a == 0 {
out.extend_from_slice(&[0, 0, 0, 0]);
} else {
out.extend_from_slice(&[unpremul(px[0], a), unpremul(px[1], a), unpremul(px[2], a), a]);
}
}
out
}