mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-09 10:46:38 +00:00
* Fill & Sign: a Border control for typed text, and a border colour of its own Rebased onto main as one commit: main's Fill & Sign text colour (#2444) runs through the same places as the border (the open box, typed(), the page input, the toolbar and the preferences), so every step of the branch met it again. Text colour and border now travel together as TypedLook (typed_with), which keeps typed() and the new function under Clippy's argument limit; a border without its own colour takes the text's. Make Current Properties Default on typed text also keeps its colour for new text now. The branch's commits, in order: - Typewriter text: a border change grows its box on every side, so the text keeps its place - Fill & Sign: a Border control for typed text and dates - Parity: the typewriter border's evidence - i18n: the Border label in every catalog, recorded in ATTRIBUTION.toml - Text boxes, typewriter text and callouts: a border colour of their own - Fill & Sign: the toolbar follows the selected text; a Border colour button - fill_sign_add and comment_edit take `border_color` - Parity: the border colour and the toolbar following the selection - i18n: Border colour and Same as text in every catalog, recorded in ATTRIBUTION.toml - Typed text's border: /Border's width is read, a non-finite border colour refused, a saved Same as text restored - Fill & Sign: the toolbar changes only the selected text; Make Current Properties Default keeps new text's border - Review: Make Properties Default gives a text box's or callout's tool its border colour - i18n: the new labels in the Persian catalog, recorded in ATTRIBUTION.toml - Review: a test that dragging the Font size control resizes the selected text to where the drag ends - Rebase: the typed text's border in main's annot and comments modules (Style's border colour, exports), and craft_ui's ComboBox Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * M5: text boxes and typed text take an oval or a circle for their border Rebased onto #4146's new head as one commit (see there: main's Fill & Sign text colour runs through the same places). The border shape goes into TypedLook's border with the width and colour; a circle around typed text still takes the snug box. The branch's commits, in order: - Text boxes and typed text take an oval or a circle for their border - A circle goes snug around its text - Review: fill_sign_add takes an oval or a circle only with a border - Review: a circle made on a quarter-turned page is sized from the text as shown - Review: Border ▸ None takes an oval or a circle away with the line - Review: the Border colour button shows the selected text box's own colour - i18n: Border shape in the Persian catalog, recorded in ATTRIBUTION.toml - Review: Border ▸ None on a circled text is one undo step - Rebase: the border shape in main's annot, engine and comments modules; craft_ui's ComboBox; Fill & Sign's border controls in a function of their own (main's complexity limit) - Review: Thickness 0 in Comment Properties takes an oval or a circle away, as Border ▸ None does Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Open the Font size popup first in the drag test: main moved the size into a popup * Border shape per selected comment, and split the oval/circle border out of draw_free_text (clippy cognitive complexity) * Re-run CI (the push of the main merge did not start it) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: FredApps <FredApps@users.noreply.github.com>
626 lines
22 KiB
Rust
626 lines
22 KiB
Rust
//! The edits a document takes: what each is called, whether its permissions allow it, and running it.
|
||
|
||
use std::sync::Arc;
|
||
|
||
use crate::{
|
||
AddedContent, AddedText, Background, BorderShape, BoxSpec, EditError, FieldProps, FieldValue, FillMark, HeaderFooter, Hidden, ImageEdit,
|
||
InitialView, Label, LineEnding, LinkAction, LinkStyle, MarkFile, MarkKind, Markup, NewAnnotation, NewField, NoteIcon, ObjectTarget, PageBox,
|
||
Protection, ReviewState, Rgb, Shape, Standard, Style, TabOrder, TransitionSpec, Watermark, a11y, copy_image, decode_data_file, embed_image,
|
||
field_table, fit_picture, image_content_type, is_xfa_data_file, js, mark_source, measure, model_poster, open_source, strip_xfa, unrestricted,
|
||
xfa, xfa_after_data_change,
|
||
};
|
||
|
||
mod labels;
|
||
mod run;
|
||
|
||
pub use labels::{BATCH_LABELS, EDIT_LABELS};
|
||
pub(crate) use run::{EditCtx, check_permission, run_edit};
|
||
|
||
/// Edits that can be applied to a document. Page indices are 0-based.
|
||
#[derive(Clone, Debug, PartialEq)]
|
||
pub enum Edit {
|
||
RotatePages {
|
||
pages: Vec<usize>,
|
||
degrees: i64,
|
||
},
|
||
DeletePages {
|
||
pages: Vec<usize>,
|
||
},
|
||
MovePages {
|
||
pages: Vec<usize>,
|
||
to: usize,
|
||
},
|
||
/// `pages` reversed among the positions they occupy.
|
||
ReversePages {
|
||
pages: Vec<usize>,
|
||
},
|
||
InsertBlankPage {
|
||
at: usize,
|
||
width: f64,
|
||
height: f64,
|
||
},
|
||
/// Copies of `pages` inserted at `at` (an index in the page order as it is now), or after
|
||
/// the last of them when `at` is `None`.
|
||
DuplicatePages {
|
||
pages: Vec<usize>,
|
||
at: Option<usize>,
|
||
},
|
||
/// Replace Pages: the content of `pages` is replaced by `src_pages` of another PDF; the
|
||
/// pages' links, comments and bookmarks stay.
|
||
ReplacePages {
|
||
pages: Vec<usize>,
|
||
name: String,
|
||
bytes: Arc<Vec<u8>>,
|
||
src_pages: Vec<usize>,
|
||
},
|
||
/// Set Page Boxes / Crop: set (or reset) one box on `pages`.
|
||
SetPageBox {
|
||
pages: Vec<usize>,
|
||
which: PageBox,
|
||
spec: BoxSpec,
|
||
},
|
||
/// Set or remove the page transition and display time of pages (ISO 32000-2 §12.4.4),
|
||
/// Organize ▸ Page Transitions.
|
||
SetTransition {
|
||
pages: Vec<usize>,
|
||
spec: TransitionSpec,
|
||
},
|
||
SetInfo {
|
||
key: String,
|
||
value: String,
|
||
},
|
||
/// Insert pages from another PDF (all pages when `pages` is `None`) at position `at`.
|
||
InsertPagesFrom {
|
||
name: String,
|
||
bytes: Arc<Vec<u8>>,
|
||
pages: Option<Vec<usize>>,
|
||
at: usize,
|
||
/// How a form field whose name the document already uses is kept separate.
|
||
field_conflicts: pdfcraft_organize::FieldConflicts,
|
||
},
|
||
/// Add a bookmark to `page` as child `index` of the bookmark at `parent` (`[]` = top level).
|
||
/// It goes to the user-space point (`left`, `top`) of the page at the reader's zoom, and
|
||
/// either may be `None` to keep the reader's position that way (both `None` is the page top).
|
||
/// A coordinate that is not finite fails the edit.
|
||
AddBookmark {
|
||
parent: Vec<usize>,
|
||
index: usize,
|
||
title: String,
|
||
page: usize,
|
||
left: Option<f64>,
|
||
top: Option<f64>,
|
||
},
|
||
RenameBookmark {
|
||
path: Vec<usize>,
|
||
title: String,
|
||
},
|
||
/// Delete a bookmark and the bookmarks under it.
|
||
DeleteBookmark {
|
||
path: Vec<usize>,
|
||
},
|
||
/// Move a bookmark to child `index` of `to_parent` (indices after removing it).
|
||
MoveBookmark {
|
||
from: Vec<usize>,
|
||
to_parent: Vec<usize>,
|
||
index: usize,
|
||
},
|
||
/// Point a bookmark at another page.
|
||
SetBookmarkPage {
|
||
path: Vec<usize>,
|
||
page: usize,
|
||
},
|
||
/// Colour a bookmark's title (`/C`); `None` or black is the default black.
|
||
SetBookmarkColor {
|
||
path: Vec<usize>,
|
||
color: Option<[f64; 3]>,
|
||
},
|
||
/// Make a bookmark's title bold or italic or not (`/F`); `None` keeps that one.
|
||
SetBookmarkStyle {
|
||
path: Vec<usize>,
|
||
bold: Option<bool>,
|
||
italic: Option<bool>,
|
||
},
|
||
/// Write `bookmarks` as children of `parent` from child `index` on, or with `replace` in
|
||
/// place of the whole outline (`parent` must then be `[]`). A bookmark whose page this
|
||
/// document lacks is kept without a destination (see [`pdfcraft_organize::import_outline`]).
|
||
ImportBookmarks {
|
||
parent: Vec<usize>,
|
||
index: usize,
|
||
bookmarks: Vec<pdfcraft_organize::OutlineNode>,
|
||
replace: bool,
|
||
},
|
||
/// Bookmarks for the tagged headings (H, H1–H6), nested by level under a new first
|
||
/// "Untitled" bookmark (New Bookmarks from Structure).
|
||
BookmarksFromStructure,
|
||
/// Bookmarks for the lines set in `levels`' styles (the first is level 1, the next nests
|
||
/// under it, …), under a new first "Untitled" bookmark (#1693; see [`crate::text_style_bookmarks`]).
|
||
BookmarksFromTextStyles {
|
||
levels: Vec<crate::text_style_bookmarks::TextStyle>,
|
||
},
|
||
/// Label pages `from..=to` (0-based) as Acrobat's "Number pages" does; later pages keep their labels.
|
||
NumberPages {
|
||
from: usize,
|
||
to: usize,
|
||
style: pdfcraft_organize::LabelStyle,
|
||
prefix: String,
|
||
first: u32,
|
||
},
|
||
/// Add a calibrated distance, perimeter or area annotation.
|
||
AddMeasurement(measure::NewMeasurement),
|
||
/// Store a drawing scale for a rectangular viewport (PDF user space).
|
||
SetMeasurementScale {
|
||
page: usize,
|
||
bbox: [f64; 4],
|
||
name: String,
|
||
scale: measure::Scale,
|
||
},
|
||
/// Add a comment (sticky note, highlight, shape, drawing, text box…).
|
||
AddAnnotation(NewAnnotation),
|
||
/// A custom stamp from a picture file (a PDF page or an image) on `page`. A zero-size
|
||
/// `rect` is a point: the stamp is centred there at its natural size (at most 200 pt).
|
||
/// Any other `rect` is a box: the picture is scaled to fit inside it, keeping its shape,
|
||
/// and centred in it (#4077).
|
||
AddCustomStamp {
|
||
page: usize,
|
||
rect: [f64; 4],
|
||
name: String,
|
||
file: MarkFile,
|
||
author: String,
|
||
},
|
||
/// Rich Media ▸ Add 3D: a U3D or PRC `model` as a 3D annotation in `rect` on `page`, named
|
||
/// `name` (its alternate description). Its poster is the picture in `poster` (a PDF page or an
|
||
/// image) fitted inside `rect`, keeping its shape and centred, or a labelled frame without one.
|
||
AddModel3d {
|
||
page: usize,
|
||
rect: [f64; 4],
|
||
model: Arc<Vec<u8>>,
|
||
poster: Option<MarkFile>,
|
||
activation: pdfcraft_annot::Activation3d,
|
||
name: String,
|
||
},
|
||
/// Delete the comment at `index` in the page's `/Annots`, with its pop-up and replies.
|
||
DeleteAnnotation {
|
||
page: usize,
|
||
index: usize,
|
||
},
|
||
SetAnnotationContents {
|
||
page: usize,
|
||
index: usize,
|
||
text: String,
|
||
},
|
||
ReplyToAnnotation {
|
||
page: usize,
|
||
index: usize,
|
||
text: String,
|
||
author: String,
|
||
},
|
||
/// Acrobat's "Set status" (a state reply by `author`).
|
||
SetAnnotationStatus {
|
||
page: usize,
|
||
index: usize,
|
||
state: ReviewState,
|
||
author: String,
|
||
},
|
||
/// The Eraser: rub out the parts of drawing `(page, index)` near `path` (user space).
|
||
EraseInk {
|
||
page: usize,
|
||
index: usize,
|
||
path: Vec<[f64; 2]>,
|
||
radius: f64,
|
||
},
|
||
/// Replace Text: strike out `quads` and add a grouped caret holding `text`.
|
||
ReplaceText {
|
||
page: usize,
|
||
quads: Vec<[f64; 8]>,
|
||
text: String,
|
||
author: String,
|
||
strike: Style,
|
||
caret: Style,
|
||
},
|
||
/// Acrobat's "Mark with checkmark" (a hidden `/StateModel /Marked` reply by `author`).
|
||
MarkAnnotation {
|
||
page: usize,
|
||
index: usize,
|
||
marked: bool,
|
||
author: String,
|
||
},
|
||
/// Properties ▸ Locked.
|
||
LockAnnotation {
|
||
page: usize,
|
||
index: usize,
|
||
locked: bool,
|
||
},
|
||
MoveAnnotation {
|
||
page: usize,
|
||
index: usize,
|
||
dx: f64,
|
||
dy: f64,
|
||
},
|
||
/// Reshape a line, connected lines, a polygon or a cloud: its points in user space (a line's
|
||
/// two ends, the others' corners).
|
||
ReshapeAnnotation {
|
||
page: usize,
|
||
index: usize,
|
||
points: Vec<[f64; 2]>,
|
||
},
|
||
/// Resize a rectangle, oval or text box.
|
||
ResizeAnnotation {
|
||
page: usize,
|
||
index: usize,
|
||
rect: [f64; 4],
|
||
},
|
||
StyleAnnotation {
|
||
page: usize,
|
||
index: usize,
|
||
color: Option<Rgb>,
|
||
opacity: Option<f64>,
|
||
width: Option<f64>,
|
||
/// Line or polyline: two endings. Callout: one. `None` leaves `/LE` unchanged.
|
||
endings: Option<Vec<pdfcraft_annot::LineEnding>>,
|
||
},
|
||
/// Fill a rectangle, oval or polygon comment, or remove its fill (`None`).
|
||
FillAnnotation {
|
||
page: usize,
|
||
index: usize,
|
||
fill: Option<Rgb>,
|
||
},
|
||
/// Draw a rectangle's, oval's, polygon's or text box's fill, or a text box's text, at an
|
||
/// opacity of its own (0–1), the line or border keeping the comment's; `None` leaves that
|
||
/// part as it is. `StyleAnnotation`'s opacity sets the whole comment's.
|
||
PartOpacity {
|
||
page: usize,
|
||
index: usize,
|
||
fill: Option<f64>,
|
||
text: Option<f64>,
|
||
},
|
||
/// Change the font size (pt) of a text box, typewriter text or callout.
|
||
FontSizeAnnotation {
|
||
page: usize,
|
||
index: usize,
|
||
size: f64,
|
||
},
|
||
/// Give a text box, typewriter text or callout a border colour of its own (`None`: the
|
||
/// text's again).
|
||
BorderColorAnnotation {
|
||
page: usize,
|
||
index: usize,
|
||
color: Option<Rgb>,
|
||
},
|
||
/// Give a text box or typewriter text an oval, a circle or a rectangle for its border: the
|
||
/// text box keeps its place, the oval or circle goes around it.
|
||
BorderShapeAnnotation {
|
||
page: usize,
|
||
index: usize,
|
||
shape: BorderShape,
|
||
},
|
||
/// Comment properties ▸ General / note icon.
|
||
SetAnnotationInfo {
|
||
page: usize,
|
||
index: usize,
|
||
author: Option<String>,
|
||
subject: Option<String>,
|
||
icon: Option<NoteIcon>,
|
||
},
|
||
/// Fill in a form field.
|
||
SetFieldValue {
|
||
name: String,
|
||
value: FieldValue,
|
||
},
|
||
/// Clear form: the named fields (all when `None`) back to their defaults.
|
||
ResetForm {
|
||
names: Option<Vec<String>>,
|
||
},
|
||
/// Prepare a form: add a field on a page (`rect` in PDF user space); `name` defaults to
|
||
/// Acrobat's next free name ("Text1", "Check Box2", …).
|
||
AddField {
|
||
page: usize,
|
||
rect: [f64; 4],
|
||
kind: NewField,
|
||
name: Option<String>,
|
||
},
|
||
/// Field Properties ▸ General / Options.
|
||
SetFieldProps {
|
||
name: String,
|
||
props: Box<FieldProps>,
|
||
},
|
||
/// An image field (or any button): show this image file (PNG, JPEG, TIFF, GIF, BMP).
|
||
SetFieldImage {
|
||
name: String,
|
||
image: Arc<Vec<u8>>,
|
||
},
|
||
/// Duplicate a field onto other pages (same field, shared value).
|
||
DuplicateField {
|
||
name: String,
|
||
pages: Vec<usize>,
|
||
},
|
||
DeleteField {
|
||
name: String,
|
||
},
|
||
/// Delete one widget of a field (`widget`, 0-based in the field's widgets): one radio button
|
||
/// of a group, or one copy of a duplicated field. The last widget takes the field with it.
|
||
DeleteWidget {
|
||
name: String,
|
||
widget: usize,
|
||
},
|
||
/// Page properties ▸ Tab order, for pages (0-based).
|
||
SetTabOrder {
|
||
pages: Vec<usize>,
|
||
order: TabOrder,
|
||
},
|
||
/// Document Properties ▸ Initial View (and the language and binding).
|
||
SetInitialView(Box<InitialView>),
|
||
/// Edit ▸ Attach a file: a document-level attachment (`/Names /EmbeddedFiles`) under
|
||
/// `name`, made unique; `mime` is the embedded file's `/Subtype` when known.
|
||
AddAttachment {
|
||
name: String,
|
||
bytes: Vec<u8>,
|
||
description: Option<String>,
|
||
mime: Option<String>,
|
||
},
|
||
/// Remove the document-level attachment whose name-tree key is `key`.
|
||
DeleteAttachment {
|
||
key: String,
|
||
},
|
||
/// Build a tagged structure tree for an untagged, text-only document.
|
||
AutoTagText,
|
||
/// Add alternate text: set (or clear, with `None`) a figure's alternate text. `figure` is
|
||
/// the figure element's object number (from `Document::figures`).
|
||
SetAltText {
|
||
figure: u32,
|
||
alt: Option<String>,
|
||
},
|
||
/// Add `/Form` tags and object references for all widgets in an untagged AcroForm.
|
||
AutoTagFormFields,
|
||
/// Change one property on a reachable indirect structure tag.
|
||
SetTagProperty {
|
||
object: pdfcraft_cos::ObjRef,
|
||
property: a11y::TagProperty,
|
||
value: Option<String>,
|
||
},
|
||
/// Move a structure tag before or after a direct sibling in reading order.
|
||
MoveTag {
|
||
object: pdfcraft_cos::ObjRef,
|
||
anchor: pdfcraft_cos::ObjRef,
|
||
placement: a11y::TagPlacement,
|
||
},
|
||
/// Add alternate text ▸ Decorative figure: the figure's content becomes an artifact.
|
||
MarkDecorative {
|
||
figure: u32,
|
||
},
|
||
/// Tags panel ▸ Mark as artifact: retire a leaf tag and mark its content as an artifact.
|
||
MarkTagArtifact {
|
||
object: pdfcraft_cos::ObjRef,
|
||
},
|
||
/// Document JavaScripts: add, replace (`script`) or remove (`None`) the document-level
|
||
/// script `name`.
|
||
SetDocumentScript {
|
||
name: String,
|
||
script: Option<String>,
|
||
},
|
||
/// Field Properties ▸ a custom script: set or remove field `name`'s JavaScript for `event`
|
||
/// (keystroke, format, validate, calculate or mouse_up).
|
||
SetFieldScript {
|
||
name: String,
|
||
event: String,
|
||
script: Option<String>,
|
||
},
|
||
/// Standards ▸ Save as PDF/A: fix what can be fixed for `level` (metadata, output intent,
|
||
/// forbidden actions, annotation flags, …).
|
||
ConvertPdfA {
|
||
level: pdfcraft_preflight::Level,
|
||
},
|
||
/// Remove what identifies the document as meeting `standard` (PDF/A or PDF/X).
|
||
RemoveStandardId {
|
||
standard: Standard,
|
||
},
|
||
/// What a script (button or console) changed in form fields: values, read-only, required
|
||
/// and visibility.
|
||
ApplyScriptChanges {
|
||
changes: Vec<pdfcraft_forms::FieldChange>,
|
||
},
|
||
/// An XFA form's scripted event (a button's `click`, say) on the object at `som`: what the
|
||
/// script changes (values, rows, visibility) is applied and the form laid out again.
|
||
XfaEvent {
|
||
som: String,
|
||
activity: String,
|
||
},
|
||
/// Scan & OCR ▸ Recognize text: put recognised words on `page` as invisible text over the
|
||
/// image (from [`ocr::OcrJob::run`](crate::ocr::OcrJob::run)).
|
||
AddOcrText {
|
||
page: usize,
|
||
words: Vec<pdfcraft_ocr::PlacedWord>,
|
||
},
|
||
/// Scan & OCR ▸ Enhance ▸ Scanned document: put the scan images
|
||
/// [`ScanCleanJob::run`](crate::scan_clean::ScanCleanJob::run) cleaned in place of the old
|
||
/// ones (each object must still be an image). Built by
|
||
/// [`Session::apply_scan_clean`](crate::Session::apply_scan_clean).
|
||
EnhanceScan {
|
||
images: Vec<(pdfcraft_cos::ObjRef, pdfcraft_cos::Stream)>,
|
||
},
|
||
/// Edit a PDF ▸ Edit text: replace the text of line `line` (from `Document::text_lines`) on
|
||
/// `page`, in its own font when it can show it, else in Helvetica.
|
||
EditTextLine {
|
||
page: usize,
|
||
line: usize,
|
||
text: String,
|
||
},
|
||
/// Edit a PDF ▸ an existing image on `page` (index from `Document::page_images`).
|
||
EditPageImage {
|
||
page: usize,
|
||
index: usize,
|
||
change: ImageEdit,
|
||
},
|
||
/// Move mixed existing and added objects together. References resolve before any change;
|
||
/// offset is a user-space vector. No retyping, reflow or font substitution is involved.
|
||
MoveObjects {
|
||
page: usize,
|
||
objects: Vec<ObjectTarget>,
|
||
offset: [f64; 2],
|
||
},
|
||
/// Edit text in a paragraph box: replace paragraph `block` (from `Document::text_blocks`),
|
||
/// rewrapped to the box's width.
|
||
EditTextBlock {
|
||
page: usize,
|
||
block: usize,
|
||
text: String,
|
||
/// Formatting changes (font, size, colour, alignment); default keeps the paragraph's.
|
||
style: pdfcraft_edit::BlockStyle,
|
||
},
|
||
/// An explicit open-licensed full font program, completing subsets or selected by a user.
|
||
RegisterTextFont {
|
||
page: usize,
|
||
bytes: Arc<Vec<u8>>,
|
||
},
|
||
/// Order tabs manually: move a field one place earlier or later on its page.
|
||
MoveInTabOrder {
|
||
name: String,
|
||
earlier: bool,
|
||
},
|
||
/// Set the calculation order: these calculated fields first, in this order, then the others
|
||
/// in their current order (see [`Document::calculation_order`](crate::Document::calculation_order)). The form recalculates.
|
||
SetCalculationOrder {
|
||
names: Vec<String>,
|
||
},
|
||
/// Add a header and footer (with `replace`, existing ones on those pages go first).
|
||
AddHeaderFooter {
|
||
pages: Vec<usize>,
|
||
settings: HeaderFooter,
|
||
replace: bool,
|
||
},
|
||
/// `file`: a picture from a file (an image, or a page of a PDF) instead of text.
|
||
AddWatermark {
|
||
pages: Vec<usize>,
|
||
settings: Watermark,
|
||
replace: bool,
|
||
file: Option<MarkFile>,
|
||
},
|
||
/// `file`: a picture from a file instead of a colour.
|
||
AddBackground {
|
||
pages: Vec<usize>,
|
||
settings: Background,
|
||
replace: bool,
|
||
file: Option<MarkFile>,
|
||
},
|
||
/// Remove every mark of a kind from every page.
|
||
RemoveMarks {
|
||
kind: MarkKind,
|
||
},
|
||
/// Edit a PDF ▸ Add content ▸ Text (`text.rect` in display space).
|
||
AddText {
|
||
page: usize,
|
||
text: AddedText,
|
||
},
|
||
/// Edit a PDF ▸ Add content ▸ Image: an image file placed at `rect` (display space), or at
|
||
/// its natural size centred on the page (shrunk to fit).
|
||
AddImage {
|
||
page: usize,
|
||
rect: Option<[f64; 4]>,
|
||
name: String,
|
||
bytes: Arc<Vec<u8>>,
|
||
},
|
||
/// Move, resize, retype or reformat an added item (`index` among the page's added items).
|
||
UpdateContent {
|
||
page: usize,
|
||
index: usize,
|
||
content: AddedContent,
|
||
},
|
||
DeleteContent {
|
||
page: usize,
|
||
index: usize,
|
||
},
|
||
/// Replace an added image with another file (keeping its box and transforms).
|
||
ReplaceImage {
|
||
page: usize,
|
||
index: usize,
|
||
name: String,
|
||
bytes: Arc<Vec<u8>>,
|
||
},
|
||
/// Edit ▸ Paste: an added item copied in this document or another, as it was: text with its
|
||
/// style, an image in its box (display space) with its turns, flips and crop. An image's
|
||
/// picture is `file` (from [`Document::added_image_file`](crate::Document::added_image_file)): the copied image object is reused
|
||
/// while it is still that picture in this document, else one an added image here already draws
|
||
/// it from, else the file is embedded.
|
||
PasteContent {
|
||
page: usize,
|
||
content: AddedContent,
|
||
file: Option<(String, Arc<Vec<u8>>)>,
|
||
},
|
||
/// Apply redaction marks (all, or those on `pages`): remove what they cover for good.
|
||
ApplyRedactions {
|
||
pages: Option<Vec<usize>>,
|
||
},
|
||
/// Remove redaction marks without applying them.
|
||
ClearRedactions,
|
||
/// Edit a PDF ▸ Link: a new link over `rect` (user space).
|
||
AddLink {
|
||
page: usize,
|
||
rect: [f64; 4],
|
||
action: LinkAction,
|
||
style: LinkStyle,
|
||
},
|
||
/// Link Properties (`index` in the page's `/Annots`).
|
||
SetLink {
|
||
page: usize,
|
||
index: usize,
|
||
rect: Option<[f64; 4]>,
|
||
action: Option<LinkAction>,
|
||
style: Option<LinkStyle>,
|
||
},
|
||
DeleteLink {
|
||
page: usize,
|
||
index: usize,
|
||
},
|
||
/// Remove all links (on `pages`, or everywhere).
|
||
RemoveLinks {
|
||
pages: Option<Vec<usize>>,
|
||
},
|
||
/// Create links from URLs in the text: (page, line rects in user space, URI).
|
||
AddLinks {
|
||
links: Vec<(usize, Vec<[f64; 4]>, String)>,
|
||
style: LinkStyle,
|
||
},
|
||
/// Import comments and/or form data (XFDF, FDF, XML, CSV, tab-delimited text), or the
|
||
/// comments of another PDF onto the pages with the same numbers.
|
||
ImportData {
|
||
name: String,
|
||
bytes: Arc<Vec<u8>>,
|
||
},
|
||
/// Paste copied comments (XFDF from [`Session::export_comments`]) onto `page` as new
|
||
/// comments: copies under names of their own, so nothing is replaced and pasting twice
|
||
/// gives two sets; replies keep their copied parent.
|
||
PasteComments {
|
||
xfdf: String,
|
||
page: usize,
|
||
/// Where the copies go: moved by (dx, dy) in user space, or at their own positions.
|
||
offset: Option<[f64; 2]>,
|
||
},
|
||
/// Remove Hidden Information: the chosen categories.
|
||
RemoveHidden {
|
||
which: Vec<Hidden>,
|
||
},
|
||
/// Sanitize Document: every category, then a full rewrite on save.
|
||
Sanitize,
|
||
/// An XFA form made an ordinary (static) PDF form: the XFA packets, `/NeedsRendering` and
|
||
/// PdfCraft's private keys go, the pages as laid out and the fields with their values
|
||
/// stay, so every viewer shows the same form and none lays it out again. Its scripts no
|
||
/// longer run.
|
||
XfaToStatic,
|
||
/// Flatten comments and/or form fields on every page into page content.
|
||
Flatten {
|
||
comments: bool,
|
||
fields: bool,
|
||
},
|
||
/// Bake Fill & Sign text, marks and signatures into the page. Other comments and fields stay.
|
||
/// A no-op (no undo step) when the document has none.
|
||
FlattenFillSign,
|
||
/// Protect with passwords and permissions (written by the next save, which is a full rewrite).
|
||
Protect(Protection),
|
||
/// Remove password security (needs the owner password).
|
||
RemoveProtection,
|
||
/// Several edits applied as one undoable step (all or nothing).
|
||
Batch {
|
||
label: String,
|
||
edits: Vec<Edit>,
|
||
},
|
||
}
|