M8.4: Remove Hidden Information and Sanitize Document: scan with per-category counts (metadata, attachments, comments, form fields, hidden text in render modes 3/7 or off the page, hidden layers' content and groups, bookmarks, links/actions/JavaScript, private data); remove chosen categories (fields flattened so values stay visible) or all; full rewrite on save. Dialogs with checkboxes and counts, Sanitize confirmation; doc_hidden_info/doc_remove_hidden tools (59 tools)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Thomas
2026-10-02 00:30:18 -04:00
co-authored by Claude Opus 5.5
parent f8175fb97e
commit d2926538bd
18 changed files with 866 additions and 22 deletions
+2 -2
View File
@@ -259,7 +259,7 @@ pub static TOOL_GROUPS: &[ToolGroup] = &[
title: "Protect",
items: &[
item("Protect with password", "lock", "protect.password", Ready),
item("Remove hidden information", "eye-off", "protect.sanitize", Planned("M8")),
item("Remove hidden information", "eye-off", "protect.remove_hidden", Ready),
],
},
ToolSection {
@@ -286,7 +286,7 @@ pub static TOOL_GROUPS: &[ToolGroup] = &[
item("Redact pages", "file-x", "redact.pages", Ready),
item("Find text and redact", "file-search", "redact.search", Ready),
item("Set properties", "settings-2", "redact.properties", Ready),
item("Sanitize document", "sparkles", "redact.sanitize", Planned("M8")),
item("Sanitize document", "sparkles", "redact.sanitize", Ready),
],
}],
},
+2
View File
@@ -183,6 +183,8 @@ pub const COMMANDS: &[CommandSpec] = &[
c("redact.properties", "Redaction properties…", None, None, Document, "settings-2"),
c("redact.apply", "Apply redactions…", None, None, HasRedactions, "check"),
c("redact.clear", "Clear redaction marks", None, None, HasRedactions, "eraser"),
c("protect.remove_hidden", "Remove hidden information…", None, None, Modification, "eye-off"),
c("redact.sanitize", "Sanitize document…", None, None, Modification, "sparkles"),
c("form.field.properties", "Field properties…", None, None, HasFields, "settings-2"),
c("form.add.text", "Add a text field", None, None, Modification, "text-cursor-input"),
c("form.add.checkbox", "Add a checkbox", None, None, Modification, "check-circle-2"),
+22
View File
@@ -30,6 +30,7 @@ pub use printcraft_forms::{
pub use printcraft_annot::appearance as annot_text;
pub use printcraft_annot::{FillMark, Markup, NewAnnotation, NoteIcon, Props as CommentProps, ReviewState, Rgb, Shape, Style, rect_quad};
pub use printcraft_redact::patterns::{PATTERNS as REDACT_PATTERNS, Pattern as RedactPattern, find as find_pattern};
pub use printcraft_redact::sanitize::{HIDDEN, Hidden};
pub type SplitPart = (usize, usize, Arc<Vec<u8>>);
@@ -197,6 +198,11 @@ impl Document {
self.editor.as_ref().and_then(|e| printcraft_annot::props(&e.cos, page, index))
}
/// Remove Hidden Information: what each category would remove.
pub fn hidden_info(&self) -> Vec<(Hidden, usize)> {
self.editor.as_ref().map(|e| printcraft_redact::sanitize::scan(&e.cos)).unwrap_or_default()
}
/// Every page's media, crop, bleed, trim and art boxes (user space), for Set Page Boxes.
pub fn page_boxes(&self) -> Vec<[[f64; 4]; 5]> {
self.editor.as_ref().and_then(|e| printcraft_organize::page_boxes(&e.cos).ok()).unwrap_or_default()
@@ -549,6 +555,12 @@ pub enum Edit {
},
/// Remove redaction marks without applying them.
ClearRedactions,
/// Remove Hidden Information: the chosen categories.
RemoveHidden {
which: Vec<Hidden>,
},
/// Sanitize Document: every category, then a full rewrite on save.
Sanitize,
/// Flatten comments and/or form fields on every page into page content.
Flatten {
comments: bool,
@@ -609,6 +621,8 @@ impl Edit {
Edit::RemoveMarks { kind: MarkKind::Background } => "Remove background".into(),
Edit::ApplyRedactions { .. } => "Apply redactions".into(),
Edit::ClearRedactions => "Remove redaction marks".into(),
Edit::RemoveHidden { .. } => "Remove hidden information".into(),
Edit::Sanitize => "Sanitize document".into(),
Edit::Flatten { comments: true, fields: false } => "Flatten comments".into(),
Edit::Flatten { comments: false, fields: true } => "Flatten form fields".into(),
Edit::Flatten { .. } => "Flatten".into(),
@@ -711,6 +725,8 @@ fn check_permission(edit: &Edit, p: &printcraft_cos::Permissions) -> Result<(),
| Edit::AddField { .. }
| Edit::ApplyRedactions { .. }
| Edit::ClearRedactions
| Edit::RemoveHidden { .. }
| Edit::Sanitize
| Edit::SetFieldProps { .. }
| Edit::DeleteField { .. }
| Edit::Flatten { .. } => {
@@ -866,6 +882,12 @@ fn run_edit(doc: &mut printcraft_cos::Document, edit: &Edit, cx: &mut EditCtx) -
Edit::ClearRedactions => {
printcraft_redact::clear_marks(doc, None)?;
}
Edit::RemoveHidden { which } => {
printcraft_redact::sanitize::remove_hidden(doc, which)?;
}
Edit::Sanitize => {
printcraft_redact::sanitize::sanitize(doc)?;
}
Edit::Flatten { comments, fields } => {
let n = printcraft_model::pages(doc).len();
printcraft_edit::flatten(doc, &(0..n).collect::<Vec<_>>(), *comments, *fields)?;