Model IDML graphic gradients and text paths

This commit is contained in:
Dylan M. Taylor committed 2026-11-13 09:05:19 -05:00
1 parent 49238094eb
commit fa159b3f36
2 files changed
+56 -1

No files matched your search

+9 -1
View File
@@ -23,7 +23,8 @@ pub use resources::{
SwatchKind, color_groups, inks, named, preference, stroke_styles, style_groups, swatches,
};
pub use spread::{
Graphic, GraphicChild, GraphicKind, Guide, ItemChild, ItemKind, Link, MarginPreference, Page, PageChild, PageItem, Spread, SpreadChild, spreads,
Graphic, GraphicChild, GraphicKind, Guide, ItemChild, ItemKind, Link, MarginPreference, Page, PageChild, PageItem, Spread, SpreadChild, TextPath,
spreads,
};
pub use story::{Ace, CONTAINERS, Cell, Container, ContentPart, Range, Story, Table, TableChild, TextNode, stories};
@@ -106,6 +107,13 @@ impl Values {
self.prop(key).and_then(|v| v.trim().parse::<f64>().ok()).filter(|v| v.is_finite())
}
/// A two-number value (for properties such as `GradientFillStart`), bounded to three tokens.
pub fn pair(&self, key: &str) -> Option<[f64; 2]> {
let source = self.prop(key)?;
let values: Vec<f64> = source.split_whitespace().take(3).filter_map(|v| v.parse::<f64>().ok()).collect();
<[f64; 2]>::try_from(values).ok().filter(|v| v.iter().all(|n| n.is_finite()))
}
/// `true` or `false`; anything else counts as absent.
pub fn boolean(&self, key: &str) -> Option<bool> {
match self.prop(key)?.trim() {
+47
View File
@@ -437,6 +437,29 @@ impl PageItem {
self.values.boolean("Nonprinting") == Some(true)
}
pub fn gradient_fill_angle(&self) -> Option<f64> {
self.values.num("GradientFillAngle")
}
pub fn gradient_fill_start(&self) -> Option<[f64; 2]> {
self.values.pair("GradientFillStart")
}
pub fn gradient_fill_length(&self) -> Option<f64> {
self.values.num("GradientFillLength")
}
pub fn gradient_stroke_angle(&self) -> Option<f64> {
self.values.num("GradientStrokeAngle")
}
pub fn gradient_stroke_start(&self) -> Option<[f64; 2]> {
self.values.pair("GradientStrokeStart")
}
pub fn gradient_stroke_length(&self) -> Option<f64> {
self.values.num("GradientStrokeLength")
}
pub fn text_path(&self) -> Option<TextPath> {
self.other("TextPath").map(|el| TextPath { values: Values::of(el) })
}
/// Replaces the outline.
pub fn set_geometry(&mut self, g: &PathGeometry) {
self.values.set_prop_el("PathGeometry", Some(g.to_el()));
@@ -486,6 +509,30 @@ impl PageItem {
}
}
/// Type-on-a-path settings.
#[derive(Clone, Debug, PartialEq)]
pub struct TextPath {
pub values: Values,
}
impl TextPath {
pub fn parent_story(&self) -> Option<&str> {
self.values.get("ParentStory").filter(|s| *s != "n")
}
pub fn start_bracket(&self) -> Option<f64> {
self.values.num("StartBracket")
}
pub fn end_bracket(&self) -> Option<f64> {
self.values.num("EndBracket")
}
pub fn flipped(&self) -> bool {
self.values.get("FlipPathEffect") == Some("Flipped")
}
pub fn alignment(&self) -> Option<&str> {
self.values.get("TextAlignment")
}
}
/// What a placed graphic is.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum GraphicKind {