mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-10 18:40:27 -06:00
Print color: Knockout Group and Isolate Blending as group attributes
Groups are pushed with Surface::push_group, so Knockout Group writes /K true and Isolate Blending /I true, each on its own. File > Export PDF no longer rasterizes knockout groups.
This commit is contained in:
+1
-1
@@ -127,7 +127,7 @@ DesignCraft aims at full Adobe InDesign parity — and to be better: faster, ope
|
||||
- Object Layer Options for placed PDFs (`object.pdfLayers`, `object.layerOptions`, Object ▸ Object Layer Options…): the file's optional-content layers listed and shown or hidden per frame on screen; in exported PDFs such graphics go out as 300 ppi images of their visible layers.
|
||||
- Effects: Inner Glow (edge or centre), Bevel and Emboss (inner bevel lit from the light angle), Satin (`object.innerGlow`, `object.bevel`, `object.satin`); PDF export now keeps soft effects: objects with shadows, glows, feathers, bevels or satin go out as 300 ppi transparent images of their appearance (threaded text frames excepted).
|
||||
- Directional Feather (`object.directionalFeather {widths: [top, left, bottom, right]}`): each side fades over its own width.
|
||||
- View ▸ Flattener Preview (`view.flattenerPreview`): objects involving transparency highlighted in red; knockout groups export as images (PDF output has no knockout groups).
|
||||
- View ▸ Flattener Preview (`view.flattenerPreview`): objects involving transparency highlighted in red; PDF export writes Knockout Group as a knockout transparency group (`/K true`) and Isolate Blending as `/I true`.
|
||||
- Live captions (`object.caption {live: true}`, Object ▸ Captions ▸ Generate Live Caption): the caption text is re-filled from the source object's metadata after every edit (same undo step).
|
||||
- Style Export Tagging (`style.exportTag`, Paragraph Style Options ▸ Export Tagging): paragraph and character styles choose their HTML element and class in EPUB/HTML.
|
||||
- Tagged Text: export (`file.exportText {format: "tagged"}`) and place (detected by its header; ASCII, UTF-8 or UTF-16) with paragraph and character styles, font, typeface and size, and `<0x…>` characters.
|
||||
|
||||
@@ -513,9 +513,7 @@ fn threaded(d: &designcraft_doc::Document, it: &designcraft_doc::Item) -> bool {
|
||||
/// Soft effects other than the gradient feather (which PDF export draws itself).
|
||||
fn raster_effects(it: &designcraft_doc::Item) -> bool {
|
||||
let e = &it.effects;
|
||||
// Knockout groups too: PDF output here has no knockout transparency groups.
|
||||
it.knockout
|
||||
|| e.drop_shadow.on
|
||||
e.drop_shadow.on
|
||||
|| e.feather > 0.0
|
||||
|| e.inner_shadow.on
|
||||
|| e.outer_glow.on
|
||||
@@ -795,7 +793,7 @@ fn export_pdf(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
}
|
||||
}
|
||||
if fx_count > 0 {
|
||||
r.warnings.push(format!("{fx_count} object(s) with soft effects (shadows, glows, feathers, bevels) or knockout groups exported as images"));
|
||||
r.warnings.push(format!("{fx_count} object(s) with soft effects (shadows, glows, feathers, bevels) exported as images"));
|
||||
}
|
||||
if layer_count > 0 {
|
||||
r.warnings.push(format!("{layer_count} placed PDF(s) with hidden layers exported as images"));
|
||||
|
||||
@@ -4195,13 +4195,14 @@ mod fitting_tests {
|
||||
let df = shot(&s);
|
||||
assert!(df.pixel(102, 200)[0] > 200, "left edge faded to paper: {:?}", df.pixel(102, 200));
|
||||
assert_eq!(df.pixel(298, 200), plain.pixel(298, 200), "right edge untouched");
|
||||
// A knockout group exports as an image too.
|
||||
// A knockout group stays vector, as a knockout transparency group.
|
||||
let other = s.execute("frame.create", &json!({"rect": [400, 100, 450, 150]})).unwrap()["id"].clone();
|
||||
let other2 = s.execute("frame.create", &json!({"rect": [420, 120, 470, 170]})).unwrap()["id"].clone();
|
||||
let g = s.execute("object.group", &json!({"ids": [other, other2]})).unwrap()["id"].clone();
|
||||
s.execute("object.transparencyGroup", &json!({"ids": [g], "knockout": true})).unwrap();
|
||||
let r = s.execute("file.exportPdf", &json!({})).unwrap();
|
||||
assert!(r["warnings"].as_array().unwrap().iter().any(|w| w.as_str().unwrap().contains("2 object(s)")), "{r}");
|
||||
assert!(r["warnings"].as_array().unwrap().iter().any(|w| w.as_str().unwrap().contains("1 object(s)")), "{r}");
|
||||
assert!(String::from_utf8_lossy(&super::super::file::base64_decode(r["base64"].as_str().unwrap())).contains("/K true"));
|
||||
// PDF export carries effects (as an image of the object).
|
||||
let r = s.execute("file.exportPdf", &json!({})).unwrap();
|
||||
assert!(r["warnings"].as_array().unwrap().iter().any(|w| w.as_str().unwrap().contains("soft effects")), "{r}");
|
||||
|
||||
@@ -749,11 +749,10 @@ impl Exporter<'_> {
|
||||
n
|
||||
}
|
||||
|
||||
/// Isolate Blending / Knockout groups: an isolated transparency group (knockout is drawn
|
||||
/// isolated too).
|
||||
/// Isolate Blending / Knockout Group: a transparency group with `/I` and `/K` as set.
|
||||
fn push_isolation(s: &mut Surface, it: &Item) -> usize {
|
||||
if it.isolate || it.knockout {
|
||||
s.push_isolated();
|
||||
s.push_group(krilla::blend::GroupOptions { isolated: it.isolate, knockout: it.knockout });
|
||||
1
|
||||
} else {
|
||||
0
|
||||
|
||||
@@ -240,3 +240,38 @@ fn ruby_overprint_fill_is_written() {
|
||||
assert_eq!(overprint_states(&r.bytes), [(true, false, 1)]);
|
||||
assert!(!r.warnings.iter().any(|w| w.contains("overprint")), "{:?}", r.warnings);
|
||||
}
|
||||
|
||||
/// Knockout Group writes `/K true` and Isolate Blending `/I true`, each on its own.
|
||||
#[test]
|
||||
fn knockout_and_isolation_are_group_attributes() {
|
||||
let grouped = |knockout: bool, isolate: bool| {
|
||||
let mut d = Document::new(&NewDocument::default());
|
||||
let lid = d.default_layer();
|
||||
let child = |d: &mut Document, r: Rect, swatch: &str| {
|
||||
let mut b = Item::new(ItemId(d.alloc()), lid, designcraft_doc::Shape::Rectangle, designcraft_geom::shapes::rectangle(r));
|
||||
b.fill = Fill::swatch(swatch);
|
||||
std::sync::Arc::new(b)
|
||||
};
|
||||
let items = vec![
|
||||
child(&mut d, Rect::new(36.0, 36.0, 136.0, 136.0), "C=100 M=0 Y=0 K=0"),
|
||||
child(&mut d, Rect::new(86.0, 86.0, 186.0, 186.0), "C=0 M=100 Y=0 K=0"),
|
||||
];
|
||||
let mut g = Item::new(
|
||||
ItemId(d.alloc()),
|
||||
lid,
|
||||
designcraft_doc::Shape::Group,
|
||||
designcraft_geom::shapes::rectangle(Rect::new(36.0, 36.0, 186.0, 186.0)),
|
||||
);
|
||||
g.content = designcraft_doc::Content::Group { items };
|
||||
g.knockout = knockout;
|
||||
g.isolate = isolate;
|
||||
d.insert_item(SpreadRef::Doc(0), g, None).unwrap();
|
||||
form_groups(&exported(&d))
|
||||
};
|
||||
let attributes =
|
||||
|groups: Vec<(Option<String>, bool, bool)>| groups.into_iter().map(|(_, i, k)| (i, k)).filter(|ik| *ik != (false, false)).collect::<Vec<_>>();
|
||||
assert_eq!(attributes(grouped(true, false)), [(false, true)]);
|
||||
assert_eq!(attributes(grouped(false, true)), [(true, false)]);
|
||||
assert_eq!(attributes(grouped(true, true)), [(true, true)]);
|
||||
assert_eq!(attributes(grouped(false, false)), []);
|
||||
}
|
||||
|
||||
@@ -389,7 +389,7 @@ It is evidence of breadth: each item exists. It is not a claim of InDesign-level
|
||||
- Object Layer Options for placed PDFs (`object.pdfLayers`, `object.layerOptions`, Object ▸ Object Layer Options…): the file's optional-content layers listed and shown or hidden per frame on screen; in exported PDFs such graphics go out as 300 ppi images of their visible layers.
|
||||
- Effects: Inner Glow (edge or centre), Bevel and Emboss (inner bevel lit from the light angle), Satin (`object.innerGlow`, `object.bevel`, `object.satin`); PDF export now keeps soft effects: objects with shadows, glows, feathers, bevels or satin go out as 300 ppi transparent images of their appearance (threaded text frames excepted).
|
||||
- Directional Feather (`object.directionalFeather {widths: [top, left, bottom, right]}`): each side fades over its own width.
|
||||
- View ▸ Flattener Preview (`view.flattenerPreview`): objects involving transparency highlighted in red; knockout groups export as images (PDF output has no knockout groups).
|
||||
- View ▸ Flattener Preview (`view.flattenerPreview`): objects involving transparency highlighted in red; PDF export writes Knockout Group as a knockout transparency group (`/K true`) and Isolate Blending as `/I true`.
|
||||
- Live captions (`object.caption {live: true}`, Object ▸ Captions ▸ Generate Live Caption): the caption text is re-filled from the source object's metadata after every edit (same undo step).
|
||||
- Style Export Tagging (`style.exportTag`, Paragraph Style Options ▸ Export Tagging): paragraph and character styles choose their HTML element and class in EPUB/HTML.
|
||||
- Tagged Text: export (`file.exportText {format: "tagged"}`) and place (detected by its header; ASCII, UTF-8 or UTF-16) with paragraph and character styles, font, typeface and size, and `<0x…>` characters.
|
||||
|
||||
Reference in New Issue
Block a user