mirror of
https://github.com/storytold/craft-libs.git
synced 2026-10-31 07:39:23 +00:00
hayro: port PdfCraft's page transparency group (#2972)
The page group composites over a transparent backdrop and is then put on the background, so a blend mode over an empty part of the page keeps its color. With a color replacement, and on a plate render, the background stays inside the group as its backdrop, so plate films are as before. Ledger hayro (18); the PdfCraft raster test is adapted in upstream_raster.rs.
This commit is contained in:
1 parent
7c7ec9c8ca
commit
30ee2f832f
4 files changed
+67
-13
No files matched your search
@@ -618,3 +618,37 @@ fn visibility_expressions_decide_what_a_membership_dictionary_shows() {
|
||||
let deep = format!("<< /Type /OCMD /OCGs [5 0 R] /VE {}5 0 R{} >>", "[/Not ".repeat(41), "]".repeat(41));
|
||||
assert!(!render(&deep, &[5]), "too deep: /OCGs decides");
|
||||
}
|
||||
|
||||
/// PdfCraft ledger hayro (18) (#2972): a page's objects composite with a transparent backdrop
|
||||
/// and the page group is then put on the paper, so a blend mode only blends where something
|
||||
/// was drawn. A green fill with `/BM /Screen` (or Lighten, Difference…) half over a red square
|
||||
/// takes the mode's color over the red and stays plain green over the empty page.
|
||||
#[cfg_attr(not(target_arch = "wasm32"), test)]
|
||||
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
|
||||
fn blend_modes_over_an_empty_part_of_the_page_keep_their_color() {
|
||||
for (mode, over_red) in [
|
||||
("Normal", Some([0, 255, 0])),
|
||||
("Multiply", Some([0, 0, 0])),
|
||||
("Screen", Some([255, 255, 0])),
|
||||
("Lighten", Some([255, 255, 0])),
|
||||
("Difference", Some([255, 255, 0])),
|
||||
("Exclusion", Some([255, 255, 0])),
|
||||
("ColorDodge", Some([255, 0, 0])),
|
||||
("Overlay", Some([255, 0, 0])),
|
||||
// The non-separable modes mix hue, saturation and luminosity; over an empty part of
|
||||
// the page they too keep the source color.
|
||||
("Hue", None),
|
||||
("Saturation", None),
|
||||
("Color", None),
|
||||
("Luminosity", None),
|
||||
] {
|
||||
let page = format!("/MediaBox [0 0 300 200] /Resources << /ExtGState << /G1 << /Type /ExtGState /BM /{mode} >> >> >>");
|
||||
let p = render(&one_page(&page, b"1 0 0 rg 20 20 150 150 re f /G1 gs 0 1 0 rg 100 50 150 120 re f", b""));
|
||||
// Pixel rows run top down: PDF (210, 100) and (130, 100) are rows 100 from the top.
|
||||
assert_eq!(pixel(&p, 210, 100), [0, 255, 0, 255], "{mode} over the empty page");
|
||||
if let Some(over_red) = over_red {
|
||||
assert_eq!(pixel(&p, 130, 100)[..3], over_red, "{mode} over the red square");
|
||||
}
|
||||
assert_eq!(pixel(&p, 280, 10), [255, 255, 255, 255], "{mode}: the paper stays white");
|
||||
}
|
||||
}
|
||||
Vendored
+7
-2
@@ -210,8 +210,13 @@ each marked `PdfCraft patch` in the source: hayro-interpret (40) (PdfCraft #2987
|
||||
content membership dictionary with a visibility expression (`/VE`: `/And`, `/Or` and `/Not`
|
||||
over groups the document lists in `/OCProperties /OCGs`) shows its content when the
|
||||
expression is true, ahead of `/OCGs` and `/P`; a malformed expression, or one nested deeper
|
||||
than 32 levels, is ignored and `/OCGs` and `/P` decide. Its PdfCraft raster test is adapted in
|
||||
`tests/upstream_raster.rs`.
|
||||
than 32 levels, is ignored and `/OCGs` and `/P` decide; and hayro (18) (PdfCraft #2972), the
|
||||
page renders as one transparency group over a transparent backdrop that is then put on the
|
||||
background, so a blend mode over an empty part of the page keeps its color; with a color
|
||||
replacement (reading colors) the background stays inside the group as its backdrop. A plate
|
||||
render (`InterpreterSettings::plate`) also keeps the background inside, marked `Craft patch`,
|
||||
so blend modes on a separation's film blend with the paper. The PdfCraft raster tests of both
|
||||
are adapted in `tests/upstream_raster.rs`.
|
||||
|
||||
This remains the patched 0.7 backend. It retains the existing Bradford Lab conversion,
|
||||
floating component precision and codec versions, rather than claiming full 0.8
|
||||
|
||||
Vendored
+1
-1
@@ -62,7 +62,7 @@
|
||||
"path": "src/lib.rs",
|
||||
"source_sha256": "682db2a32fbf4d875c0e9dd7ac5dc875a6b09ade375efbce6f104de9197de078",
|
||||
"source_git_blob": "6333ed5808ae0cf9cf158e4730e973c1d7089bab",
|
||||
"sha256": "682db2a32fbf4d875c0e9dd7ac5dc875a6b09ade375efbce6f104de9197de078"
|
||||
"sha256": "8396b90516603079bb43012621e8089621fec58fdd3d9c9aa9a8d2aa840265da"
|
||||
},
|
||||
{
|
||||
"path": "src/renderer.rs",
|
||||
|
||||
Vendored
+25
-10
@@ -254,15 +254,22 @@ pub fn render_into<'a>(
|
||||
interpreter_settings.preview,
|
||||
);
|
||||
|
||||
// PdfCraft patch (18): the page renders as one transparency group with the background
|
||||
// painted *inside* it, as the initial backdrop. A group isolates what it wraps from what
|
||||
// was painted before it, so with the background outside, a Multiply highlight blended
|
||||
// only with the group's transparent backdrop and stayed its own colour — over a dark
|
||||
// reading-colours background the whole quad became one flat bar and the words under it
|
||||
// vanished. Inside the group the highlight multiplies with the background too: the words
|
||||
// keep the highlight's colour and the band between them takes the background (white
|
||||
// backgrounds are unaffected — multiplying with white is the identity).
|
||||
device.push_transparency_group(1.0, None, BlendMode::Normal);
|
||||
// PdfCraft patch (18): the page renders as one transparency group (the page group). Its
|
||||
// objects composite with an initially transparent backdrop, and the group is then put on
|
||||
// the paper (ISO 32000-2, page group), so a blend mode only blends where something was
|
||||
// drawn: a /BM /Screen fill over an empty part of the page keeps its color (#2970).
|
||||
// Under reading colors the background is painted *inside* the group instead, as its
|
||||
// initial backdrop, so a Multiply highlight blends with the dark background: outside it,
|
||||
// the highlight kept its own flat color and the words under it vanished into the band
|
||||
// (#1548). Reading colors replace the page's colors anyway; for document colors the
|
||||
// background stays outside, or every separable mode but Normal, Multiply, Darken and
|
||||
// HardLight would blend with the white paper. Craft patch: a plate render keeps the
|
||||
// background inside as well, so blend modes on a separation's film blend with the paper.
|
||||
let backdrop_inside =
|
||||
render_settings.color_replacement.is_some() || interpreter_settings.plate.is_some();
|
||||
if backdrop_inside {
|
||||
device.push_transparency_group(1.0, None, BlendMode::Normal);
|
||||
}
|
||||
|
||||
device.ctx.set_paint(render_settings.bg_color);
|
||||
device
|
||||
@@ -274,11 +281,19 @@ pub fn render_into<'a>(
|
||||
path: clip_path,
|
||||
fill: FillRule::NonZero,
|
||||
});
|
||||
if !backdrop_inside {
|
||||
device.push_transparency_group(1.0, None, BlendMode::Normal);
|
||||
}
|
||||
|
||||
interpret_page(page, &mut state, &mut device);
|
||||
|
||||
if !backdrop_inside {
|
||||
device.pop_transparency_group();
|
||||
}
|
||||
device.pop_clip_path();
|
||||
device.pop_transparency_group();
|
||||
if backdrop_inside {
|
||||
device.pop_transparency_group();
|
||||
}
|
||||
|
||||
let mut resources = vello_cpu::Resources::default();
|
||||
device.ctx.render_to_buffer(
|
||||
|
||||
Reference in new issue
Block a user