use pdfrum_page::{SoftMask, SoftMaskKind};
use crate::pixmap::{AlphaMask, Pixmap};
#[must_use]
pub fn backdrop(mask: &SoftMask) -> peniko::Color {
match mask.kind {
SoftMaskKind::Luminosity => {
let [r, g, b] = mask.backdrop.to_bytes();
peniko::Color::from_rgba8(r, g, b, 255)
}
SoftMaskKind::Alpha => peniko::Color::TRANSPARENT,
}
}
#[must_use]
pub fn readback(mask: &SoftMask, rendered: &Pixmap) -> AlphaMask {
let mut out = match mask.kind {
SoftMaskKind::Luminosity => rendered.luminosity_mask(),
SoftMaskKind::Alpha => rendered.alpha_mask(),
};
if let Some(table) = &mask.transfer {
out.apply_transfer(table);
}
out
}
#[cfg(test)]
mod tests {
use kurbo::Affine;
use pdfrum_object::{ByteSpan, Dict, Stream};
use pdfrum_page::Rgb;
use super::*;
fn soft_mask(kind: SoftMaskKind, backdrop_rgb: Rgb) -> SoftMask {
SoftMask {
group: Stream {
dict: Dict::default(),
data: ByteSpan::empty(),
},
kind,
backdrop: backdrop_rgb,
transfer: None,
matrix: Affine::IDENTITY,
objects: Vec::new(),
}
}
#[test]
fn luminosity_defaults_to_an_opaque_black_backdrop() {
let m = soft_mask(SoftMaskKind::Luminosity, Rgb::BLACK);
assert_eq!(backdrop(&m), peniko::Color::from_rgba8(0, 0, 0, 255));
}
#[test]
fn bc_clears_the_backdrop() {
let m = soft_mask(
SoftMaskKind::Luminosity,
Rgb {
r: 1.0,
g: 1.0,
b: 1.0,
},
);
assert_eq!(backdrop(&m), peniko::Color::from_rgba8(255, 255, 255, 255));
}
#[test]
fn an_alpha_mask_starts_from_nothing() {
let m = soft_mask(
SoftMaskKind::Alpha,
Rgb {
r: 1.0,
g: 1.0,
b: 1.0,
},
);
assert_eq!(
backdrop(&m),
peniko::Color::TRANSPARENT,
"/BC is ignored for an alpha mask"
);
}
#[test]
fn luminosity_readback_uses_ntsc_not_bt709() {
let m = soft_mask(SoftMaskKind::Luminosity, Rgb::BLACK);
let rendered = Pixmap::filled(1, 1, peniko::Color::from_rgba8(0, 255, 0, 255));
assert_eq!(readback(&m, &rendered).data(), &[150]);
}
#[test]
fn alpha_readback_is_the_alpha_channel() {
let m = soft_mask(SoftMaskKind::Alpha, Rgb::BLACK);
let rendered = Pixmap::filled(1, 1, peniko::Color::from_rgba8(255, 255, 255, 77));
assert_eq!(readback(&m, &rendered).data(), &[77]);
}
#[test]
fn a_transfer_function_maps_every_byte() {
let mut m = soft_mask(SoftMaskKind::Alpha, Rgb::BLACK);
m.transfer = Some(Box::new([0u8; 256]));
let rendered = Pixmap::filled(2, 1, peniko::Color::from_rgba8(255, 255, 255, 255));
assert_eq!(readback(&m, &rendered).data(), &[0, 0]);
}
#[test]
fn a_luminosity_mask_over_an_unpainted_area_reads_the_backdrop() {
let m = soft_mask(
SoftMaskKind::Luminosity,
Rgb {
r: 1.0,
g: 1.0,
b: 1.0,
},
);
let cleared = Pixmap::filled(1, 1, backdrop(&m));
assert_eq!(readback(&m, &cleared).data(), &[255]);
}
}