#[derive(Debug, Clone)]
pub struct Watermark {
pub text: Option<String>,
pub image: Option<Vec<u8>>,
pub position: (f64, f64),
pub font_size: f64,
pub font: String,
pub color: u32,
pub opacity: f64,
pub rotation: f64,
pub page: Option<usize>,
}
impl Default for Watermark {
fn default() -> Self {
Self {
text: None,
image: None,
position: (0.0, 0.0),
font_size: 24.0,
font: "SimSun".into(),
color: 0xCC_CC_CC,
opacity: 0.3,
rotation: 45.0,
page: None,
}
}
}
impl Watermark {
#[must_use]
pub fn text(content: impl Into<String>) -> Self {
Self {
text: Some(content.into()),
..Self::default()
}
}
#[must_use]
pub fn position(mut self, x: f64, y: f64) -> Self {
self.position = (x, y);
self
}
#[must_use]
pub fn font_size(mut self, size: f64) -> Self {
self.font_size = size;
self
}
#[must_use]
pub fn opacity(mut self, opacity: f64) -> Self {
self.opacity = opacity;
self
}
#[must_use]
pub fn rotation(mut self, degrees: f64) -> Self {
self.rotation = degrees;
self
}
#[must_use]
pub fn page(mut self, page: usize) -> Self {
self.page = Some(page);
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_watermark_default() {
let wm = Watermark::default();
assert!((wm.font_size - 24.0).abs() < f64::EPSILON);
assert!((wm.opacity - 0.3).abs() < f64::EPSILON);
assert!((wm.rotation - 45.0).abs() < f64::EPSILON);
assert!(wm.text.is_none());
assert!(wm.page.is_none());
}
#[test]
fn test_watermark_text_builder() {
let wm = Watermark::text("CONFIDENTIAL")
.position(50.0, 100.0)
.font_size(36.0)
.opacity(0.5)
.rotation(30.0)
.page(1);
assert_eq!(wm.text.as_deref(), Some("CONFIDENTIAL"));
assert_eq!(wm.position, (50.0, 100.0));
assert!((wm.font_size - 36.0).abs() < f64::EPSILON);
assert!((wm.opacity - 0.5).abs() < f64::EPSILON);
assert!((wm.rotation - 30.0).abs() < f64::EPSILON);
assert_eq!(wm.page, Some(1));
}
#[test]
fn test_watermark_clone_debug() {
let wm = Watermark::text("test");
let wm2 = wm.clone();
assert_eq!(wm2.text, wm.text);
assert!(format!("{wm:?}").contains("Watermark"));
}
}