use crate::ConversionResult;
use bigcolor::BigColor;
use duc::types::{DucPath, ElementBackground, ElementContentBase};
use hipdf::lopdf::{content::Operation, Object};
use std::collections::BTreeSet;
pub struct PdfBackgroundRenderer;
impl PdfBackgroundRenderer {
pub fn parse_color(content: &ElementContentBase) -> Option<(f32, f32, f32, f32)> {
if !content.visible {
return None;
}
let mut color = BigColor::new(&content.src);
let alpha = content.opacity as f32;
color.set_alpha(alpha);
let rgb = color.to_rgb();
Some((
rgb.r as f32 / 255.0,
rgb.g as f32 / 255.0,
rgb.b as f32 / 255.0,
alpha,
))
}
pub fn apply_background_color(
background: &ElementBackground,
) -> ConversionResult<Vec<Operation>> {
let mut ops = Vec::new();
if !background.content.visible {
return Ok(ops);
}
if let Some((r, g, b, _alpha)) = Self::parse_color(&background.content) {
ops.push(Operation::new(
"rg",
vec![Object::Real(r), Object::Real(g), Object::Real(b)],
));
}
Ok(ops)
}
pub fn render_linear_element_backgrounds(
default_backgrounds: &[ElementBackground],
paths_with_indices: &[(Vec<Operation>, Vec<usize>)], path_overrides: &[DucPath],
) -> ConversionResult<Vec<Operation>> {
let mut ops = Vec::new();
if paths_with_indices.is_empty() || default_backgrounds.is_empty() {
return Ok(ops);
}
let primary_background = &default_backgrounds[0];
let override_map: std::collections::HashMap<BTreeSet<usize>, &ElementBackground> =
path_overrides
.iter()
.filter_map(|p| {
p.background
.as_ref()
.map(|bg| (p.line_indices.iter().map(|&i| i as usize).collect(), bg))
})
.collect();
let mut fills_to_render: std::collections::HashMap<String, Vec<Operation>> =
std::collections::HashMap::new();
let mut hole_paths: Vec<Operation> = Vec::new();
for (path_ops, line_indices) in paths_with_indices {
let indices_set: BTreeSet<usize> = line_indices.iter().cloned().collect();
let background = override_map
.get(&indices_set)
.copied()
.unwrap_or(primary_background);
if !background.content.visible {
hole_paths.extend(path_ops.clone());
} else {
fills_to_render
.entry(background.content.src.clone())
.or_insert_with(Vec::new)
.extend(path_ops.clone());
}
}
for (color_src, mut fill_path_ops) in fills_to_render {
fill_path_ops.extend(hole_paths.clone());
let temp_content = ElementContentBase {
src: color_src,
visible: true,
opacity: primary_background.content.opacity,
preference: primary_background.content.preference,
tiling: primary_background.content.tiling.clone(),
hatch: None,
image_filter: None,
};
if let Some((r, g, b, _alpha)) = Self::parse_color(&temp_content) {
ops.push(Operation::new(
"rg",
vec![Object::Real(r), Object::Real(g), Object::Real(b)],
));
ops.extend(fill_path_ops);
ops.push(Operation::new("f*", vec![]));
}
}
Ok(ops)
}
}