Skip to main content

lightweight_pdf_core/
watermark.rs

1//! `Watermark` (Phase 6, `plan/phases/phase-6-business-polish.md` step 2):
2//! a rotated diagonal stamp ("ENTWURF", "STORNIERT"). Deliberately **not**
3//! a normal flow `Element` — it's a document-level, independent layer,
4//! always drawn first (bottom) and clipped to the body content box, per
5//! `05-overflow-and-robustness.md`'s explicit requirement that it must
6//! never make normal content unreadable or bleed into the header/footer
7//! bands. No general rotation/transform API is introduced for other
8//! elements (ADR/plan: "kein allgemeine Transform-API").
9
10use crate::style::{Color, FontKey};
11
12#[derive(Clone, Debug)]
13pub struct Watermark {
14    pub text: String,
15    /// Counter-clockwise rotation in degrees, applied around the body
16    /// box's center. 45° (bottom-left to top-right diagonal) matches the
17    /// conventional "ENTWURF"/"DRAFT" stamp look.
18    pub rotation_deg: f32,
19    pub size: f32,
20    pub color: Color,
21    pub font: FontKey,
22}
23
24impl Watermark {
25    pub fn new(text: impl Into<String>) -> Self {
26        Watermark {
27            text: text.into(),
28            rotation_deg: 45.0,
29            size: 72.0,
30            // Light gray: legible-by-construction since normal content
31            // always draws *after* (on top of) the watermark, but a light
32            // color keeps the page from looking visually "shouted at".
33            color: Color::rgb(210, 210, 210),
34            font: FontKey::SANS_BOLD,
35        }
36    }
37
38    pub fn rotation(mut self, degrees: f32) -> Self {
39        self.rotation_deg = degrees;
40        self
41    }
42
43    pub fn size(mut self, size: f32) -> Self {
44        self.size = size;
45        self
46    }
47
48    pub fn color(mut self, color: Color) -> Self {
49        self.color = color;
50        self
51    }
52}