Skip to main content

pdf_engine/
api.rs

1//! The ideal top-level API facade for the PDFluent SDK.
2//!
3//! This module defines the intended public surface of the PDFluent library,
4//! following the "Zero-Config First Success", "Pit of Success", and "Progressive Disclosure"
5//! design principles.
6
7// Copyright (c) 2026 Innovation Trigger B.V.
8//
9// PDFluent is available under two licences, at your option: the GNU AGPLv3, or
10// the PDFluent Commercial Licence. See the LICENSE file in this repository --
11// that file travels with the copy you received, which a URL does not.
12
13use std::path::Path;
14
15pub use crate::api_error::Error;
16
17/// Input source for a PDF document — accepts either a filesystem path or
18/// in-memory bytes.
19pub enum PdfSource<'a> {
20    /// Read the PDF from a filesystem path.
21    Path(&'a Path),
22    /// Read the PDF from an in-memory byte slice.
23    Bytes(&'a [u8]),
24}
25
26impl<'a> From<&'a str> for PdfSource<'a> {
27    fn from(s: &'a str) -> Self {
28        PdfSource::Path(Path::new(s))
29    }
30}
31
32impl<'a> From<&'a Path> for PdfSource<'a> {
33    fn from(p: &'a Path) -> Self {
34        PdfSource::Path(p)
35    }
36}
37
38impl<'a> From<&'a [u8]> for PdfSource<'a> {
39    fn from(b: &'a [u8]) -> Self {
40        PdfSource::Bytes(b)
41    }
42}
43
44/// Options for reading a PDF.
45#[derive(Default, Debug, Clone)]
46pub struct ReadOptions {
47    pub(crate) password: Option<String>,
48    pub(crate) repair: bool,
49}
50
51impl ReadOptions {
52    /// Construct default `ReadOptions` (no password, no repair).
53    pub fn new() -> Self {
54        Self::default()
55    }
56
57    /// Set a password to attempt when the PDF is encrypted (user or owner
58    /// password). Ignored on unencrypted documents.
59    pub fn password(&mut self, pw: impl Into<String>) -> &mut Self {
60        self.password = Some(pw.into());
61        self
62    }
63
64    /// Enable best-effort recovery of malformed PDFs (broken xref,
65    /// truncated streams). Slower but loads more inputs.
66    pub fn repair(&mut self, repair: bool) -> &mut Self {
67        self.repair = repair;
68        self
69    }
70}
71
72/// Options for saving a PDF.
73#[derive(Default, Debug, Clone)]
74pub struct SaveOptions {
75    pub(crate) format: Option<PdfFormat>,
76    pub(crate) linearize: bool,
77}
78
79impl SaveOptions {
80    /// Construct default `SaveOptions` (preserve input format, no
81    /// linearization).
82    pub fn new() -> Self {
83        Self::default()
84    }
85
86    /// Force the saver to emit a specific PDF or PDF/A version. When unset,
87    /// the input document's version is preserved.
88    pub fn format(&mut self, format: PdfFormat) -> &mut Self {
89        self.format = Some(format);
90        self
91    }
92
93    /// Linearize the output for "fast web view" — the saver reorders
94    /// objects so a viewer can render the first page before the full file
95    /// has downloaded.
96    pub fn linearize(&mut self, linearize: bool) -> &mut Self {
97        self.linearize = linearize;
98        self
99    }
100}
101
102/// PDF or PDF/A target version that the saver should emit. Used by
103/// [`SaveOptions::format`].
104#[derive(Debug, Clone, Copy, PartialEq, Eq)]
105pub enum PdfFormat {
106    /// PDF 1.4 — broadest reader compatibility, no AES-256.
107    Pdf1_4,
108    /// PDF 1.7 (ISO 32000-1) — modern baseline.
109    Pdf1_7,
110    /// PDF 2.0 (ISO 32000-2) — required for AES-256 (`V=5, R=6`).
111    Pdf2_0,
112    /// PDF/A-1b (ISO 19005-1, level B) — basic archival.
113    PdfA1b,
114    /// PDF/A-2b (ISO 19005-2, level B) — adds JPEG 2000, transparency.
115    PdfA2b,
116    /// PDF/A-3b (ISO 19005-3, level B) — adds arbitrary file attachments
117    /// (used for ZUGFeRD/Factur-X).
118    PdfA3b,
119}
120
121/// Options for [`Document::add_watermark`]. Defaults: opaque, unrotated.
122#[derive(Default, Debug, Clone)]
123pub struct WatermarkOptions {
124    /// Opacity, 0.0 (transparent) to 1.0 (opaque). Out-of-range values
125    /// clamp at 0.0/1.0.
126    pub opacity: f64,
127    /// Rotation in degrees around the page center. Positive =
128    /// counter-clockwise.
129    pub rotation: f64,
130}
131
132/// Output format selector for [`Document::to_images`]. PNG for line art /
133/// text, JPEG for photographic content.
134#[derive(Debug, Clone, Copy, PartialEq, Eq)]
135pub enum ImageFormat {
136    /// Lossless PNG — preserves text edges and line art.
137    Png,
138    /// Lossy JPEG — smaller output for photographic pages.
139    Jpeg,
140}
141
142/// A structured block of text from a PDF, with its bounding box on the
143/// page. Returned by [`Document::structured_text`].
144pub struct TextBlock {
145    /// Block text content in reading order.
146    pub text: String,
147    /// Bounding box `[llx, lly, urx, ury]` in PDF user-space points
148    /// (1/72 inch). Origin is the bottom-left of the page.
149    pub bbox: [f64; 4],
150}
151
152/// Document-level metadata read from the `/Info` dictionary or XMP. All
153/// fields are `None` if absent. Returned by [`Document::metadata`].
154pub struct Metadata {
155    /// `/Title`. `None` if not set.
156    pub title: Option<String>,
157    /// `/Author`. `None` if not set.
158    pub author: Option<String>,
159    /// `/CreationDate` as a PDF date string
160    /// (`D:YYYYMMDDHHmmSSOHH'mm'`). May be malformed in legacy
161    /// documents — parse defensively.
162    pub creation_date: Option<String>,
163}
164
165/// An interactive form field as seen by the form-fill API. One entry per
166/// terminal field; group fields are flattened. Returned by
167/// [`Document::form_fields`].
168pub struct FormField {
169    /// Fully-qualified field name (`parent.child` notation).
170    pub name: String,
171    /// Current field value as a string. For checkboxes this is the
172    /// "on"-state name (e.g. `"Yes"`, `"Off"`); for choice fields, the
173    /// selected option.
174    pub value: String,
175    /// Field-type discriminator: `"Tx"` (text), `"Btn"` (button),
176    /// `"Ch"` (choice), `"Sig"` (signature).
177    pub field_type: String,
178}
179
180/// A digital signature widget found in the document. Returned by
181/// [`Document::signatures`]; cryptographic verification is performed
182/// separately by [`Document::verify_signatures`].
183pub struct Signature {
184    /// Display name from the signature dictionary's `/Name` entry, or
185    /// from the certificate's subject if `/Name` is absent.
186    pub signer_name: String,
187    /// Signing time as a PDF date string. May be the signer's local
188    /// time (untrusted) or a TSA timestamp (trusted) depending on the
189    /// PAdES profile.
190    pub date: String,
191    /// `true` if the signature digest matches and the certificate chain
192    /// validates. For full validation reports, see
193    /// [`Document::verify_signatures`].
194    pub is_valid: bool,
195}
196
197/// The main entry point for a PDF Document.
198pub struct Document {
199    // Internal handle to actual implementation would go here
200}
201
202impl Document {
203    // === TEKST ===
204
205    /// Extracts plain text from all pages.
206    pub fn text(&self) -> String {
207        unimplemented!("facade")
208    }
209
210    /// Accesses a specific page for text extraction and other operations (1-based index).
211    pub fn page(&self, page_number: usize) -> Page {
212        let _ = page_number;
213        unimplemented!("facade")
214    }
215
216    /// Extracts structured text blocks with coordinates.
217    pub fn structured_text(&self) -> Vec<TextBlock> {
218        unimplemented!("facade")
219    }
220
221    // === METADATA ===
222
223    /// Returns the total number of pages in the document.
224    pub fn page_count(&self) -> usize {
225        unimplemented!("facade")
226    }
227
228    /// Returns the document's metadata.
229    pub fn metadata(&self) -> Metadata {
230        unimplemented!("facade")
231    }
232
233    // === OPSLAAN ===
234
235    /// Saves the document to a file.
236    pub fn save(&self, path: impl AsRef<Path>) -> Result<(), Error> {
237        let _ = path;
238        unimplemented!("facade")
239    }
240
241    /// Saves the document with specific options.
242    pub fn save_with<F>(&self, path: impl AsRef<Path>, build_opts: F) -> Result<(), Error>
243    where
244        F: FnOnce(&mut SaveOptions) -> &mut SaveOptions,
245    {
246        let _ = path;
247        let _ = build_opts;
248        unimplemented!("facade")
249    }
250
251    // === FORMULIEREN ===
252
253    /// Gets all form fields in the document.
254    pub fn form_fields(&self) -> Vec<FormField> {
255        unimplemented!("facade")
256    }
257
258    /// Fills form fields matching the provided name-value pairs.
259    pub fn fill_form(&self, fields: &[(&str, &str)]) -> Result<(), Error> {
260        let _ = fields;
261        unimplemented!("facade")
262    }
263
264    /// Flattens all forms, converting them to static content.
265    pub fn flatten_forms(&self) -> Result<(), Error> {
266        unimplemented!("facade")
267    }
268
269    // === HANDTEKENINGEN ===
270
271    /// Signs the document using the provided certificate and private key.
272    pub fn sign(&self, certificate: &[u8], private_key: &[u8]) -> Result<(), Error> {
273        let _ = certificate;
274        let _ = private_key;
275        unimplemented!("facade")
276    }
277
278    /// Retrieves all signatures from the document.
279    pub fn signatures(&self) -> Vec<Signature> {
280        unimplemented!("facade")
281    }
282
283    /// Verifies the cryptographic validity of all signatures.
284    pub fn verify_signatures(&self) -> Result<bool, Error> {
285        unimplemented!("facade")
286    }
287
288    // === REDACTIE ===
289
290    /// Redacts all occurrences of the specified text.
291    pub fn redact(&self, text: &str) -> Result<(), Error> {
292        let _ = text;
293        unimplemented!("facade")
294    }
295
296    /// Redacts a specific rectangular region on the specified page.
297    pub fn redact_region(&self, page: usize, rect: [f64; 4]) -> Result<(), Error> {
298        let _ = page;
299        let _ = rect;
300        unimplemented!("facade")
301    }
302
303    // === CONVERSIE ===
304
305    /// Converts the document to a DOCX file.
306    pub fn to_docx(&self, path: impl AsRef<Path>) -> Result<(), Error> {
307        let _ = path;
308        unimplemented!("facade")
309    }
310
311    /// Renders the document's pages to images based on a filename pattern.
312    pub fn to_images(&self, pattern: &str, format: ImageFormat) -> Result<(), Error> {
313        let _ = pattern;
314        let _ = format;
315        unimplemented!("facade")
316    }
317
318    /// Checks if the document is PDF/A compliant.
319    pub fn is_pdfa_compliant(&self) -> Result<bool, Error> {
320        unimplemented!("facade")
321    }
322
323    // === MANIPULATIE ===
324
325    /// Merges another document into this one.
326    pub fn merge(&self, other_doc: &Document) -> Result<(), Error> {
327        let _ = other_doc;
328        unimplemented!("facade")
329    }
330
331    /// Splits the document into individual 1-page documents.
332    pub fn split_pages(&self) -> Result<Vec<Document>, Error> {
333        unimplemented!("facade")
334    }
335
336    /// Rotates a specific page by the given angle (in degrees).
337    pub fn rotate_page(&self, page: usize, angle: i32) -> Result<(), Error> {
338        let _ = page;
339        let _ = angle;
340        unimplemented!("facade")
341    }
342
343    /// Adds a watermark to all pages of the document.
344    pub fn add_watermark(&self, text: &str, options: WatermarkOptions) -> Result<(), Error> {
345        let _ = text;
346        let _ = options;
347        unimplemented!("facade")
348    }
349}
350
351/// Represents a single page within a Document.
352pub struct Page {
353    // Internal handle to the specific page
354}
355
356impl Page {
357    /// Extracts plain text from this page only.
358    pub fn text(&self) -> String {
359        unimplemented!("facade")
360    }
361}
362
363// === LEZEN (Top-level functions) ===
364
365/// Reads a PDF document from a file path or bytes, using default options.
366pub fn read<'a, S: Into<PdfSource<'a>>>(input: S) -> Result<Document, Error> {
367    let _ = input;
368    unimplemented!("facade")
369}
370
371/// Reads a PDF document with custom options (e.g., providing a password).
372pub fn read_with<'a, S, F>(input: S, build_opts: F) -> Result<Document, Error>
373where
374    S: Into<PdfSource<'a>>,
375    F: FnOnce(&mut ReadOptions) -> &mut ReadOptions,
376{
377    let _ = input;
378    let _ = build_opts;
379    unimplemented!("facade")
380}