superbook_pdf/margin/
types.rs1use std::path::{Path, PathBuf};
6use thiserror::Error;
7
8#[derive(Debug, Error)]
14pub enum MarginError {
15 #[error("Image not found: {0}")]
16 ImageNotFound(PathBuf),
17
18 #[error("Invalid image: {0}")]
19 InvalidImage(String),
20
21 #[error("No content detected in image")]
22 NoContentDetected,
23
24 #[error("IO error: {0}")]
25 IoError(#[from] std::io::Error),
26}
27
28pub type Result<T> = std::result::Result<T, MarginError>;
29
30#[derive(Debug, Clone, Copy, Default)]
36pub struct Margins {
37 pub top: u32,
38 pub bottom: u32,
39 pub left: u32,
40 pub right: u32,
41}
42
43impl Margins {
44 pub fn uniform(value: u32) -> Self {
46 Self {
47 top: value,
48 bottom: value,
49 left: value,
50 right: value,
51 }
52 }
53
54 pub fn total_horizontal(&self) -> u32 {
56 self.left + self.right
57 }
58
59 pub fn total_vertical(&self) -> u32 {
61 self.top + self.bottom
62 }
63}
64
65#[derive(Debug, Clone, Copy)]
67pub struct ContentRect {
68 pub x: u32,
69 pub y: u32,
70 pub width: u32,
71 pub height: u32,
72}
73
74#[derive(Debug, Clone)]
76pub struct MarginDetection {
77 pub margins: Margins,
79 pub image_size: (u32, u32),
81 pub content_rect: ContentRect,
83 pub confidence: f64,
85}
86
87#[derive(Debug, Clone)]
89pub struct UnifiedMargins {
90 pub margins: Margins,
92 pub page_detections: Vec<MarginDetection>,
94 pub unified_size: (u32, u32),
96}
97
98#[derive(Debug)]
100pub struct TrimResult {
101 pub input_path: PathBuf,
102 pub output_path: PathBuf,
103 pub original_size: (u32, u32),
104 pub trimmed_size: (u32, u32),
105 pub margins_applied: Margins,
106}
107
108use super::MarginOptions;
113
114pub trait MarginDetector {
116 fn detect(image_path: &Path, options: &MarginOptions) -> Result<MarginDetection>;
118
119 fn detect_unified(images: &[PathBuf], options: &MarginOptions) -> Result<UnifiedMargins>;
121
122 fn trim(input_path: &Path, output_path: &Path, margins: &Margins) -> Result<TrimResult>;
124
125 fn pad_to_size(
127 input_path: &Path,
128 output_path: &Path,
129 target_size: (u32, u32),
130 background: [u8; 3],
131 ) -> Result<TrimResult>;
132
133 fn process_batch(
135 images: &[(PathBuf, PathBuf)],
136 options: &MarginOptions,
137 ) -> Result<Vec<TrimResult>>;
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143
144 #[test]
145 fn test_margins_uniform() {
146 let margins = Margins::uniform(10);
147 assert_eq!(margins.top, 10);
148 assert_eq!(margins.bottom, 10);
149 assert_eq!(margins.left, 10);
150 assert_eq!(margins.right, 10);
151 }
152
153 #[test]
154 fn test_margins_total() {
155 let margins = Margins {
156 top: 10,
157 bottom: 20,
158 left: 15,
159 right: 25,
160 };
161 assert_eq!(margins.total_horizontal(), 40);
162 assert_eq!(margins.total_vertical(), 30);
163 }
164
165 #[test]
166 fn test_margins_default() {
167 let margins = Margins::default();
168 assert_eq!(margins.top, 0);
169 assert_eq!(margins.bottom, 0);
170 assert_eq!(margins.left, 0);
171 assert_eq!(margins.right, 0);
172 }
173}