svg2pdf/render/
pattern.rs

1use std::sync::Arc;
2
3use pdf_writer::types::{PaintType, TilingType};
4use pdf_writer::{Chunk, Content, Filter, Ref};
5use usvg::{Opacity, Pattern, Transform};
6
7use super::group;
8use crate::util::context::Context;
9use crate::util::helper::TransformExt;
10use crate::util::resources::ResourceContainer;
11use crate::Result;
12
13/// Turn a pattern into a PDF tiling pattern.
14pub fn create(
15    pattern: Arc<Pattern>,
16    chunk: &mut Chunk,
17    ctx: &mut Context,
18    matrix: Transform,
19    initial_opacity: Option<Opacity>,
20) -> Result<Ref> {
21    let pattern_ref = ctx.alloc_ref();
22    let mut rc = ResourceContainer::new();
23
24    let pattern_rect = pattern.rect();
25
26    let pattern_matrix = matrix.pre_concat(pattern.transform()).pre_concat(
27        Transform::from_row(1.0, 0.0, 0.0, 1.0, pattern_rect.x(), pattern_rect.y()),
28    );
29
30    let mut content = Content::new();
31    group::render(
32        pattern.root(),
33        chunk,
34        &mut content,
35        ctx,
36        Transform::default(),
37        initial_opacity,
38        &mut rc,
39    )?;
40
41    let content_stream = ctx.finish_content(content);
42
43    let mut tiling_pattern = chunk.tiling_pattern(pattern_ref, &content_stream);
44
45    if ctx.options.compress {
46        tiling_pattern.filter(Filter::FlateDecode);
47    }
48
49    rc.finish(&mut tiling_pattern.resources());
50
51    // We already account for the x/y of the pattern by appending it to the matrix above, so here we just need to take the height / width
52    // in consideration
53    let final_bbox =
54        pdf_writer::Rect::new(0.0, 0.0, pattern_rect.width(), pattern_rect.height());
55
56    tiling_pattern
57        .tiling_type(TilingType::ConstantSpacing)
58        .paint_type(PaintType::Colored)
59        .bbox(final_bbox)
60        .matrix(pattern_matrix.to_pdf_transform())
61        .x_step(final_bbox.x2 - final_bbox.x1)
62        .y_step(final_bbox.y2 - final_bbox.y1);
63
64    Ok(pattern_ref)
65}