pdf_redact/error.rs
1//! Error types for `pdf-redact` operations.
2
3// Copyright (c) 2026 Innovation Trigger B.V.
4//
5// PDFluent is available under two licences, at your option: the GNU AGPLv3, or
6// the PDFluent Commercial Licence. See the LICENSE file in this repository --
7// that file travels with the copy you received, which a URL does not.
8
9use thiserror::Error;
10
11/// Errors returned by the `pdf-redact` crate while marking or applying
12/// content redaction.
13///
14/// Redaction is high-stakes (compliance, legal disclosure) so each variant
15/// describes a *refusal to proceed* rather than a best-effort fallback. If
16/// you receive any variant, the input is left untouched.
17#[derive(Debug, Error)]
18pub enum RedactError {
19 /// The underlying PDF byte stream could not be parsed.
20 ///
21 /// Typically a malformed cross-reference table, a truncated stream, or
22 /// an encrypted PDF that was not opened with the right password.
23 #[error("PDF error: {0}")]
24 Pdf(#[from] lopdf::Error),
25
26 /// An I/O error occurred while reading the source PDF or writing the
27 /// redacted output.
28 #[error("IO error: {0}")]
29 Io(#[from] std::io::Error),
30
31 /// The caller asked to redact a page index that does not exist in the
32 /// document.
33 ///
34 /// Fields: `(requested_page, total_pages)`. Page numbers are 1-based.
35 #[error("page {0} out of range (document has {1} pages)")]
36 PageOutOfRange(u32, u32),
37
38 /// The redaction call had no regions and no search query — nothing to
39 /// remove. Returned eagerly so callers do not silently produce
40 /// no-op output.
41 #[error("no redaction areas specified")]
42 NoAreas,
43
44 /// An image embedded inside a redaction region uses a PDF stream filter
45 /// that the redactor cannot rewrite (for example JBIG2 or some JPEG2000
46 /// profiles). The redaction is aborted because partially-stripped
47 /// images would leak content. The caller can either rasterise the page
48 /// before redacting or skip the affected page.
49 #[error("unsupported image filter: {0}")]
50 UnsupportedImageFilter(String),
51
52 /// A page touched by the redaction has a `/ToUnicode` CMap whose shape
53 /// the conservative `pdf-redact` parser cannot rewrite safely.
54 ///
55 /// The redactor refuses to silently drop the CMap because that would
56 /// break text-extraction tools downstream. The caller's options are
57 /// to rasterise the page first or to redact a different page range
58 /// that does not include this font.
59 #[error(
60 "unsupported /ToUnicode CMap on redacted page (font {font_resource_name}): \
61 redaction strip refuses to silently drop /ToUnicode; CMap shape not understood by the \
62 conservative pdf-redact parser ({reason})"
63 )]
64 UnsupportedToUnicodeCMap {
65 /// The PDF resource name of the font whose CMap is unsupported,
66 /// e.g. `"F1"`.
67 font_resource_name: String,
68 /// A human-readable reason for the parser's refusal, e.g.
69 /// `"surrogate pair without continuation"`.
70 reason: String,
71 },
72
73 /// A non-categorised redaction failure. Reserved for cases the more
74 /// specific variants do not cover; the message describes the situation.
75 #[error("{0}")]
76 Other(String),
77}
78
79/// Convenience `Result` alias for fallible `pdf-redact` operations.
80pub type Result<T> = std::result::Result<T, RedactError>;