use crate::ConversionResult;
use duc::types::{ElementStroke, STROKE_CAP, STROKE_JOIN, STROKE_PLACEMENT};
use hipdf::lopdf::{content::Operation, Object};
pub struct PdfStrokeRenderer;
impl PdfStrokeRenderer {
pub fn apply_stroke_style(stroke: &ElementStroke) -> ConversionResult<Vec<Operation>> {
let mut ops = Vec::new();
if !stroke.content.visible {
return Ok(ops);
}
ops.push(Operation::new("w", vec![Object::Real(stroke.width as f32)]));
if let Some(cap) = stroke.style.cap {
let cap_style = match cap {
STROKE_CAP::BUTT => 0,
STROKE_CAP::ROUND => 1,
STROKE_CAP::SQUARE => 2,
};
ops.push(Operation::new("J", vec![Object::Integer(cap_style)]));
}
if let Some(join) = stroke.style.join {
let join_style = match join {
STROKE_JOIN::MITER => 0,
STROKE_JOIN::ROUND => 1,
STROKE_JOIN::BEVEL => 2,
};
ops.push(Operation::new("j", vec![Object::Integer(join_style)]));
}
if let Some(miter_limit) = stroke.style.miter_limit {
ops.push(Operation::new("M", vec![Object::Real(miter_limit as f32)]));
}
if let Some(dash) = &stroke.style.dash {
let dash_array: Vec<Object> = dash.iter().map(|&v| Object::Real(v as f32)).collect();
ops.push(Operation::new(
"d",
vec![
Object::Array(dash_array),
Object::Real(0.0), ],
));
}
Ok(ops)
}
pub fn get_stroke_offset(stroke: &ElementStroke) -> f64 {
match stroke.placement {
Some(STROKE_PLACEMENT::CENTER) => 0.0,
Some(STROKE_PLACEMENT::OUTSIDE) => stroke.width / 2.0,
Some(STROKE_PLACEMENT::INSIDE) => -stroke.width / 2.0,
_ => 0.0,
}
}
pub fn needs_stroke_offset(stroke: &ElementStroke) -> bool {
matches!(
stroke.placement,
Some(STROKE_PLACEMENT::INSIDE) | Some(STROKE_PLACEMENT::OUTSIDE)
)
}
pub fn get_max_width(strokes: &[ElementStroke]) -> f64 {
strokes
.iter()
.map(|s| s.width)
.max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
.unwrap_or(0.0)
}
}