use anyhow::{Context, Result};
use crate::cli::args::WatermarkArgs;
use crate::cli::utils::{PageSelection, parse_color_hex, parse_page_selection};
pub fn watermark(args: WatermarkArgs) -> Result<()> {
use printwell::watermark::{Color, Layer, Watermark, add_watermark};
if args.text.is_none() && args.image.is_none() {
anyhow::bail!("Either --text or --image must be specified");
}
if args.text.is_some() && args.image.is_some() {
anyhow::bail!("Cannot specify both --text and --image");
}
let pdf_data = std::fs::read(&args.input)
.with_context(|| format!("Failed to read input file: {}", args.input))?;
let position = parse_position(&args.position)
.with_context(|| format!("Invalid position: {}", args.position))?;
let (r, g, b) =
parse_color_hex(&args.color).with_context(|| format!("Invalid color: {}", args.color))?;
let color = Color::rgb(r, g, b);
let layer = if args.foreground {
Layer::Foreground
} else {
Layer::Background
};
let page_selection =
parse_page_selection(args.pages.as_deref()).context("Invalid page selection")?;
let pages = convert_page_selection(page_selection);
let image_data = if let Some(ref image_path) = args.image {
Some(
std::fs::read(image_path)
.with_context(|| format!("Failed to read image file: {image_path}"))?,
)
} else {
None
};
let watermark = Watermark {
text: args.text,
image: image_data,
position,
rotation: args.rotation,
opacity: args.opacity,
font_size: args.font_size,
font_name: String::from("Helvetica"),
color,
layer,
pages,
scale: args.scale,
};
let result = add_watermark(&pdf_data, &watermark).context("Failed to add watermark to PDF")?;
std::fs::write(&args.output, &result)
.with_context(|| format!("Failed to write watermarked PDF to: {}", args.output))?;
eprintln!("Watermarked PDF written to: {}", args.output);
Ok(())
}
fn parse_position(s: &str) -> Result<printwell::watermark::Position> {
use printwell::watermark::Position;
match s.to_lowercase().as_str() {
"center" => Ok(Position::Center),
"top-left" | "topleft" => Ok(Position::TopLeft),
"top-center" | "topcenter" => Ok(Position::TopCenter),
"top-right" | "topright" => Ok(Position::TopRight),
"middle-left" | "middleleft" => Ok(Position::MiddleLeft),
"middle-right" | "middleright" => Ok(Position::MiddleRight),
"bottom-left" | "bottomleft" => Ok(Position::BottomLeft),
"bottom-center" | "bottomcenter" => Ok(Position::BottomCenter),
"bottom-right" | "bottomright" => Ok(Position::BottomRight),
custom => {
if let Some((x_str, y_str)) = custom.split_once(',') {
let x: f32 = x_str.trim().parse().context("Invalid X coordinate")?;
let y: f32 = y_str.trim().parse().context("Invalid Y coordinate")?;
Ok(Position::Custom(x, y))
} else {
anyhow::bail!(
"Unknown position. Use: center, top-left, top-center, top-right, \
middle-left, middle-right, bottom-left, bottom-center, bottom-right, or x,y"
);
}
}
}
}
fn convert_page_selection(sel: PageSelection) -> printwell::watermark::PageSelection {
use printwell::watermark::PageSelection as WmPageSelection;
match sel {
PageSelection::All => WmPageSelection::All,
PageSelection::Pages(p) => WmPageSelection::Pages(p),
PageSelection::Range(s, e) => WmPageSelection::Range(s, e),
PageSelection::Odd => WmPageSelection::Odd,
PageSelection::Even => WmPageSelection::Even,
PageSelection::First => WmPageSelection::First,
PageSelection::Last => WmPageSelection::Last,
}
}