mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-11 08:51:27 +00:00
* M9: redraw named-layer signature status layers - /N drawing one Form that holds n1 and n3: n1, n3 and n4 redrawn for the state - copies made once per original and state; originals never edited - Lucide icons; captions in Helvetica, embedded Inter, or craft-fonts outlines Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: draw signature states in the display copy, exports and print - marks follow the bytes shown; a changed verdict redraws after a metadata edit - background opens pick up the trust and captions current at commit Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: status captions in the interface language - the three captions in all 22 catalogues - Signatures panel colours from sign::status_rgb Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: signature badge in the widget's corner - a quarter of the shorter side, 48pt cap; outline only under 32pt - dropped for a drawn valid state; bottom-right where the appearance draws one - sign_list reports verdict_shown; parity and roadmap Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: keep Arabic signature captions in logical order Pass raw RTL catalogue text to the signature appearance shaper so UAX #9 is applied exactly once. This keeps the rendered word order and exported /ActualText consistent. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M2: read /ActualText over painted paths and pictures - A replacement that marks no glyph reads where it paints, cut to what is visible and along the way it is drawn. - A span the page content leaves open ends before the annotations. - OCR and scan field detection still count such a page as having no text of its own. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M8: redaction strips /ActualText around paint it clips - A path or shading written again under a clip counts as changed, so a partly redacted word drawn as outlines leaves no name in the file. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: recognise only layer forms that draw n1 and n3 - Settle on the one form holding both first, then read its content once per call. - Skip an /N that is its own layer form; copies keep the layer's /OC. - A verdict counts as drawn when any visible widget shows it. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: keep the signature badge and redraw wherever a state changes - The badge stays for every state; its mark sits bottom-right as the widget lies on the page. - An edit that changes a verdict redraws every page; captions apply before startup files open. - Print, the CLI's render and the repair log follow the display copy. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: restore the attribution usage the rebase dropped - Usage lines for the three icons, Inter and the craft-fonts input; ATTRIBUTION.md rebuilt from them. - Roadmap and localization notes for this round. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: pin signature field names on a nested form Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: bound the signature field walk - kids share their parent's name and type instead of each copying them - a widget stays listed under every field that claims it, as one shared copy - a field written in place in a shared /Kids array is walked once - caps of 20,000 fields, 100,000 entries and 4096-byte names; no states drawn past them Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: keep a document signed when the field walk stops early - list_cached adds a signed row of unknown validity for the fields the walk didn't read - Save As and actions then append, and Optimize, Sanitize and full rewrites are refused, as for any signed file Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M8: removing hidden content no longer strips the names of shadings - With no regions to clip, a shading is left alone instead of wrapped and marked clipped - clean_replacements skips scopes already marked, so deep nesting stays linear Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M2: read a picture's /ActualText over the whole picture - draw_image's transform maps pixels, not a unit square, so the text sat on one pixel in the corner; the test now draws a 2x2 picture - Painted grows in place instead of being copied through an Option Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: cap the bytes of names the signature field walk keeps - A kid's name repeats its parent's, so one long name over 20,000 kids came to 80 MB; the walk now stops at 4 MiB of names and counts the rest as unread - Cover the widget written into a shared /Kids array and the field cap among kids, which no test caught - sig_fields is private again, and the cap docs say what happens past each cap Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: skip status-layer work that changes nothing; fix tests that could not fail - show_status_layers and has_status_layers return before reading the form when nothing is signed, so an unsigned form no longer walks every field on each edit - revalidate and draw_captions leave documents with no drawn state alone, and no longer copy the signature list to update it - Scan form detection reads the page's text once; comment and badge tips share one hover rule - Tests: drop a table row that repeated another, stop taking an expectation from the code under test, stop comparing an Arc with itself, give bare asserts messages Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: test the signature field name cap at the engine boundary - A 4,096-byte name is read and blocks a full rewrite; at 4,097 bytes the list holds the unread-fields row and a full rewrite is still refused Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: test signature states beside fields the viewer draws - One display copy holds both a field's drawn appearance and the signature's state. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: draw Thai and Devanagari status captions in their own script - script_of names Thai and Devanagari, so a craft-fonts face meant for either draws the caption as outlines; without one it stays English. - Localization, parity and the craft-fonts usage line list the new scripts. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M2: paint left out by an exclusion mixes its /ActualText replacement - A replacement placed by outlines or pictures, some of them excluded, fails filtered extraction as one with excluded glyphs does. - Glyphs still place a replacement that has them. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: a long-named field that can't hold a signature leaves the walk whole - A leaf of another type passed over for its name is no signature field and has none below it, so an unsigned form stays unsigned. - A signature field, or any field with kids, still counts as unread. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: status captions use document faces only - Each script takes the face PdfCraft writes it into documents with, so Chinese stays English although the pinned craft-fonts' interface-only Chinese face is meant for Hani. - The craft-fonts usage line names Devanagari: the pinned revision has a face for it, and Hindi captions are drawn in it. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: refuse a new signature field the field walk can't read back - Signing adds a field only when the walk reads the whole form with it: past a cap the signature would be listed as unread fields, and its name could repeat an unread field's. - A field the walk already reads is signed as before. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: refuse a new signature field with a blank name - The walk lists no field without a name, so signing now also requires the walk to list the new field: one named only with spaces or NULs would be a signature nothing shows. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: an unnamed signed field or an unreadable form counts as unread - A signed field with no usable /T, or an /AcroForm or /Fields of the wrong type, cuts the field walk short: the document keeps its unread-fields row and stays signed. - Signing refuses a blank new field name before it adds the field, so the refusal still says why. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: no display copy when no signature state is drawn - display_bytes_for makes a copy only when it added an appearance or drew a state, as the app does. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: the verdict mark stays on the page - A widget past the crop box takes its mark in the part on the page, or none when too little of it is there. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: typed values stay drawn while a signature redraws every page - A form edit that changes a signature's state puts its values back in unbaked after the pages are invalidated. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: the action, Save As and shading tests check their effects - The signed action and Save As tests reopen the output for the title and the comment; the shading test checks its clip. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: values typed earlier stay drawn while a signature redraws every page - A form edit that changes a signature's state keeps every value still waiting on its page, not only its own. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: comment and content edits keep typed values drawn too - An edit to one page's comments or content that changes a signature's state moves no page, so the values still waiting on their pages stay pending, as after a form edit. - The pending-value test runs a field deletion and a comment after a fill, under a certification that allows the fill; its messages say what it checks. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: the language-change test skips without catalogs - Like the other language tests, it returns early when the build has no craft-i18n catalogs. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M9: signed fields behind kids without a name count - A kid with no /T but kids of its own is walked as a field node, so a signed field under it is listed by its full name. - An unnamed kid claiming a signature its field doesn't have cuts the walk short, so the document stays signed and keeps its unread-fields row. Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> --------- Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com>
185 lines
8.1 KiB
Rust
185 lines
8.1 KiB
Rust
//! pdfcraft-engine — the façade every frontend talks to (architecture §4).
|
|
//!
|
|
//! Holds open documents, their edit history and the tool catalogue. Frontends never touch the
|
|
//! parsing, rendering or editing crates directly.
|
|
//!
|
|
//! **Editing model.** Each document keeps a `pdfcraft_cos::Document` (the object graph with a
|
|
//! copy-on-write overlay of edits). An edit runs on a clone, and on success the previous state is
|
|
//! pushed onto the undo stack (clones share all unchanged data, so this is cheap). After every
|
|
//! edit the *working file* is produced by an incremental write — original bytes plus one
|
|
//! appended revision — and the view is refreshed from it, so what you see is exactly what Save
|
|
//! will write. Saving rebases onto the written bytes, so the next save appends only new edits.
|
|
|
|
#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)]
|
|
|
|
pub mod actions;
|
|
pub mod autotag;
|
|
mod bookmarks;
|
|
pub mod build_info;
|
|
pub mod camera;
|
|
pub mod camera_clean;
|
|
pub mod camera_edges;
|
|
pub mod catalog;
|
|
pub mod commands;
|
|
mod comments;
|
|
pub mod compare;
|
|
mod copy_image;
|
|
pub mod dates;
|
|
mod document;
|
|
mod edit;
|
|
mod error;
|
|
pub mod export;
|
|
pub mod field_table;
|
|
mod fill_sign;
|
|
mod history;
|
|
pub mod js;
|
|
mod layers;
|
|
pub mod links;
|
|
pub mod model3d;
|
|
pub mod ocr;
|
|
mod open;
|
|
pub mod optimizer;
|
|
mod page_filter;
|
|
mod pictures;
|
|
pub mod print_raster;
|
|
pub mod printcheck;
|
|
mod protection;
|
|
mod rich_copy;
|
|
pub mod scan_clean;
|
|
mod scan_colours;
|
|
mod scan_fields;
|
|
mod session;
|
|
pub mod signature_image;
|
|
pub mod signature_scan;
|
|
mod sources;
|
|
mod stamp_preview;
|
|
#[cfg(test)]
|
|
mod test_hooks;
|
|
pub mod text_fonts;
|
|
mod text_preview;
|
|
pub mod text_script;
|
|
pub mod text_style_bookmarks;
|
|
pub mod word_count;
|
|
pub mod xfa;
|
|
mod xfa_form;
|
|
|
|
use std::sync::Arc;
|
|
|
|
pub use links::{
|
|
MAX_REMOTE_DOCUMENT_BYTES, RemoteDocumentPathError, read_remote_document, remote_document_path_is_absolute, resolve_remote_document_path,
|
|
};
|
|
pub use pdfcraft_edit::strip_subset_tag;
|
|
pub use rich_copy::RichCopy;
|
|
pub use signature_image::{ImageSignaturePreview, SignatureImage};
|
|
pub use signature_scan::{PhotoRect, ScanError, SignaturePhoto, Turn};
|
|
pub use stamp_preview::{CommentLayer, StampPreview};
|
|
pub use text_preview::{TextEditPreview, UnmarkedPages};
|
|
|
|
pub use pdfcraft_organize::{
|
|
BoxSpec, FieldConflicts, MAX_IMPORT_BOOKMARKS, OutlineNode, OutlineTree, PageBox, SplitBy, Transition, TransitionSpec, mime_for_name,
|
|
split_ranges, unmapped as outline_unmapped, view_arity as outline_view_arity,
|
|
};
|
|
|
|
pub use pdfcraft_organize::LabelStyle;
|
|
pub use pdfcraft_organize::Standard;
|
|
pub use pdfcraft_organize::check_custom_key;
|
|
pub use pdfcraft_organize::view::{InitialView, Layout as InitialLayout, Magnification, Navigation};
|
|
|
|
pub use pdfcraft_cos::Algorithm;
|
|
pub use pdfcraft_create::{CONVERTIBLE, CreateError, ImageResolution, SourceKind, decode_text, source_kind};
|
|
pub use pdfcraft_edit::added::{
|
|
CHAR_SPACING_LIMIT as ADDED_CHAR_SPACING_LIMIT, paste_place as added_paste_place, paste_rect as added_paste_rect, text_rect as added_text_rect,
|
|
text_width as added_text_width,
|
|
};
|
|
pub use pdfcraft_edit::paragraph_align;
|
|
pub use pdfcraft_edit::{
|
|
Added, AddedImage, AddedText, Align as TextAlign, Background, Content as AddedContent, Family as FontFamily, HeaderFooter, Ink as TextInk,
|
|
MarkKind, Watermark,
|
|
};
|
|
pub use pdfcraft_forms::{
|
|
BorderStyle, CalculatedField, CalculationIssue, CalculationOrder, CheckStyle, Field as FormField, FieldAction, FieldChange, FieldFont,
|
|
FieldKind as FormFieldKind, FieldProps, FieldValue, Look as FieldLook, LookPatch as FieldLookPatch, NewField, TabOrder, Trigger as FieldTrigger,
|
|
Widget as FormWidget, af as form_scripts, appearance as form_appearance, appearance::auto_text_size_by as field_auto_text_size_by,
|
|
appearance::comb_auto_text_size as field_comb_auto_text_size, calculations_changed as form_calculations_changed, flags as field_flags,
|
|
};
|
|
|
|
pub use pdfcraft_a11y as a11y;
|
|
pub use pdfcraft_edit::{Backdrop, BlockKey, BlockStyle, PageImage, RangeStyle, TextBlock, TextLine, block_overlapping, first_undrawable};
|
|
pub use pdfcraft_measure as measure;
|
|
pub use pdfcraft_xfa::Report as XfaLayout;
|
|
|
|
pub use pdfcraft_edit::{EditableObject, MAX_MOVE_OBJECTS, ObjectKind, ObjectTarget};
|
|
|
|
pub use pdfcraft_fonts::{MAX_SIGNATURE_CHARS, ScriptOutline, script_missing, script_outline, undrawable_message};
|
|
|
|
/// Comment geometry helpers (text-box line breaking) for frontends.
|
|
pub use pdfcraft_annot::appearance as annot_text;
|
|
pub use pdfcraft_annot::links::{Highlight as LinkHighlight, LinkAction, LinkItem, LinkStyle};
|
|
pub use pdfcraft_annot::{
|
|
Activation3d, AppearanceCache, AttachIcon, BorderShape, FillMark, LineEnding, Markup, NOTE_SIZE, NewAnnotation, NoteIcon, OverlayFont,
|
|
OverlayLook, Props as CommentProps, ReviewState, Rgb, Shape, StampGroup, StampKind, Style, rect_quad,
|
|
};
|
|
pub use pdfcraft_annot::{MAX_MODEL_BYTES as MAX_3D_MODEL_BYTES, ModelFormat as Model3dFormat};
|
|
pub use pdfcraft_forms::detect;
|
|
pub use pdfcraft_optimize as optimize;
|
|
pub use pdfcraft_preflight as pdfa;
|
|
pub use pdfcraft_print as print;
|
|
pub use pdfcraft_redact::codes::{CODE_SETS as REDACTION_CODE_SETS, CodeSet as RedactionCodeSet};
|
|
pub use pdfcraft_redact::patterns::{
|
|
MAX_WORDS as REDACT_MAX_WORDS, PATTERNS as REDACT_PATTERNS, Pattern as RedactPattern, find as find_pattern, word_list as redact_word_list,
|
|
};
|
|
pub use pdfcraft_redact::sanitize::{HIDDEN, Hidden};
|
|
pub use pdfcraft_sign as sign;
|
|
pub use pdfcraft_sign::{SignOptions, SignatureInfo, Status as SignatureStatus, StatusCaptions, TrustStore};
|
|
pub use pdfcraft_xfdf::Format as DataFormat;
|
|
pub use pdfcraft_xfdf::{Outline as CommentOutline, comment_count, comment_outlines, comments_bounds, is_xfdf_comments};
|
|
|
|
use bookmarks::outline_rows;
|
|
pub use bookmarks::{BookmarkPage, BookmarkRow};
|
|
use comments::comment_list;
|
|
pub use comments::{SummarySort, comment_kind, comment_summary, comment_type_name};
|
|
#[cfg(test)]
|
|
use document::page_runs;
|
|
pub use document::{Document, EditNotice, TextNotice, display_bytes_for, render_password_for};
|
|
use document::{carry_verdict_marks, display_bytes, info_fields, recovered_render_password, same_pages, shown_under_redactions, undrawn_notices};
|
|
pub use edit::{BATCH_LABELS, EDIT_LABELS, Edit};
|
|
pub use error::{EditError, SourceProblem};
|
|
pub use fill_sign::{displayed_offset, text_box_at, typed_signature_graphic, typed_signature_shape};
|
|
pub use history::Label;
|
|
use layers::{apply_layer_state, set_default_layer_state, use_layer_choices};
|
|
pub use open::{OpenContext, PreparedDocument};
|
|
pub use page_filter::{PageOrientation, PageParity, filter_pages};
|
|
pub use pictures::{MarkFile, image_dimensions};
|
|
use pictures::{embed_image, fit_picture, mark_source, model_poster};
|
|
use protection::unrestricted;
|
|
pub use protection::{Changes, Printing, Protection, SecuritySummary};
|
|
pub use session::Session;
|
|
pub use sources::{CombineSource, Combined, combine_source_check, source_page_count};
|
|
use sources::{open_source, open_source_with};
|
|
#[cfg(test)]
|
|
use test_hooks::{check_refresh_panic, panic_on_refresh, record_link_scan, record_marker_scan, reset_secondary_scan_counts, secondary_scan_counts};
|
|
use xfa_form::{
|
|
XFA_REMOVED_PREFIX, XFA_SCRIPTS_OFF, decode_data_file, image_content_type, is_xfa_data_file, note_warnings, strip_xfa, sync_xfa_state,
|
|
undrawn_field_warnings, xfa_after_data_change, xfa_layout, xfa_redraw, xfa_sync_datasets, xfa_values_from_datasets,
|
|
};
|
|
|
|
mod clock;
|
|
mod doc_state;
|
|
|
|
pub use pdfcraft_edit::ArrangeOrder;
|
|
|
|
use clock::{local_utc_offset, parse_ymd};
|
|
pub use doc_state::{DocId, ImageEdit, OptimizeReport, RecoverySnapshot, SplitPart, guard, merge_data_files};
|
|
use doc_state::{LOW_RESOLUTION_PRINT_DPI, render_threads, renderer_password, signatures_of, writable};
|
|
|
|
/// The configuration of the pool that draws the viewer: the document's own, plus installed CJK
|
|
/// fonts for fonts a PDF does not embed (`pdfcraft_render::RenderConfig::system_fonts`). Exports,
|
|
/// printing, OCR and automation use the document configuration itself, so nothing drawn with an
|
|
/// installed font is saved or printed (AGENTS.md §1.2, §1.4).
|
|
fn display_config(config: &pdfcraft_render::RenderConfig) -> pdfcraft_render::RenderConfig {
|
|
config.clone().on_screen()
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests;
|