mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-28 03:58:45 -06:00
refactor(engine): move the Fill & Sign geometry helpers to fill_sign.rs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
94b6110819
commit
fc6072154d
@@ -0,0 +1,47 @@
|
||||
//! Fill & Sign geometry: typed signatures, and boxes placed as a turned page displays them.
|
||||
|
||||
use crate::{Shape, script_outline, signature_image};
|
||||
|
||||
/// Fill & Sign: `text` in the script font as a typed signature, its left edge at `at` (user
|
||||
/// space, vertically centred) and `height` points tall. `None` for text with no outlines.
|
||||
///
|
||||
/// Left, centred and upright are as displayed on a page turned by `rotation` (its `/Rotate`):
|
||||
/// the box runs along the displayed axes, like an image signature's
|
||||
/// ([`SignatureImage::rect`]), and the outlines are turned back so the name reads across.
|
||||
pub fn typed_signature_shape(at: [f64; 2], text: &str, height: f64, rotation: i64) -> Option<Shape> {
|
||||
let o = script_outline(text);
|
||||
let [left, bottom, right, top] = o.bounds();
|
||||
let span = (top - bottom).max(0.1);
|
||||
let width = right - left;
|
||||
if o.contours.is_empty() || o.width <= 0.0 || !(width > 0.0 && height > 0.0) {
|
||||
return None;
|
||||
}
|
||||
let k = height / span;
|
||||
let rect = signature_image::upright_box(rotation, at, width * k, height)?;
|
||||
// Displayed right and up as user-space unit vectors: a point at (nx, ny) of the displayed box
|
||||
// is at this fraction of the user-space box. Exact for an unturned page.
|
||||
let [a, b, c, d, ..] = pdfcraft_model::view_matrix_for(rotation, [0.0; 4]);
|
||||
let to_user = |nx: f64, ny: f64| [a * nx + c * ny + (-a).max(0.0) + (-c).max(0.0), b * nx + d * ny + (-b).max(0.0) + (-d).max(0.0)];
|
||||
let contours = o.contours.iter().map(|c| c.iter().map(|p| to_user((p[0] - left) / width, (p[1] - bottom) / span)).collect()).collect();
|
||||
Some(Shape::TypedSignature { rect, contours })
|
||||
}
|
||||
|
||||
/// `at` moved `right` and `up` points as displayed on a page turned by `rotation` (its `/Rotate`).
|
||||
pub fn displayed_offset(rotation: i64, at: [f64; 2], right: f64, up: f64) -> [f64; 2] {
|
||||
let [a, b, c, d, ..] = pdfcraft_model::view_matrix_for(rotation, [0.0; 4]);
|
||||
[at[0] + a * right + c * up, at[1] + b * right + d * up]
|
||||
}
|
||||
|
||||
/// The user-space box `width` x `height` points as displayed on a page turned by `rotation`,
|
||||
/// with its displayed top-left corner at `at`: where typed text and text boxes go. `None` for a
|
||||
/// non-finite point.
|
||||
pub fn text_box_at(rotation: i64, at: [f64; 2], width: f64, height: f64) -> Option<[f64; 4]> {
|
||||
signature_image::upright_box(rotation, displayed_offset(rotation, at, 0.0, -height / 2.0), width, height)
|
||||
}
|
||||
|
||||
/// `text` in the script font as the graphic of a visible digital signature, as Fill & Sign types
|
||||
/// it. `None` for text with no outlines.
|
||||
pub fn typed_signature_graphic(text: &str) -> Option<pdfcraft_sign::Graphic> {
|
||||
let o = script_outline(text);
|
||||
o.contours.iter().any(|c| c.len() > 2).then_some(pdfcraft_sign::Graphic::Outlines(o.contours))
|
||||
}
|
||||
@@ -30,6 +30,7 @@ mod edit;
|
||||
mod error;
|
||||
pub mod export;
|
||||
pub mod field_table;
|
||||
mod fill_sign;
|
||||
mod history;
|
||||
pub mod js;
|
||||
mod layers;
|
||||
@@ -84,49 +85,6 @@ pub enum ImageEdit {
|
||||
Delete,
|
||||
}
|
||||
|
||||
/// Fill & Sign: `text` in the script font as a typed signature, its left edge at `at` (user
|
||||
/// space, vertically centred) and `height` points tall. `None` for text with no outlines.
|
||||
///
|
||||
/// Left, centred and upright are as displayed on a page turned by `rotation` (its `/Rotate`):
|
||||
/// the box runs along the displayed axes, like an image signature's
|
||||
/// ([`SignatureImage::rect`]), and the outlines are turned back so the name reads across.
|
||||
pub fn typed_signature_shape(at: [f64; 2], text: &str, height: f64, rotation: i64) -> Option<Shape> {
|
||||
let o = script_outline(text);
|
||||
let [left, bottom, right, top] = o.bounds();
|
||||
let span = (top - bottom).max(0.1);
|
||||
let width = right - left;
|
||||
if o.contours.is_empty() || o.width <= 0.0 || !(width > 0.0 && height > 0.0) {
|
||||
return None;
|
||||
}
|
||||
let k = height / span;
|
||||
let rect = signature_image::upright_box(rotation, at, width * k, height)?;
|
||||
// Displayed right and up as user-space unit vectors: a point at (nx, ny) of the displayed box
|
||||
// is at this fraction of the user-space box. Exact for an unturned page.
|
||||
let [a, b, c, d, ..] = pdfcraft_model::view_matrix_for(rotation, [0.0; 4]);
|
||||
let to_user = |nx: f64, ny: f64| [a * nx + c * ny + (-a).max(0.0) + (-c).max(0.0), b * nx + d * ny + (-b).max(0.0) + (-d).max(0.0)];
|
||||
let contours = o.contours.iter().map(|c| c.iter().map(|p| to_user((p[0] - left) / width, (p[1] - bottom) / span)).collect()).collect();
|
||||
Some(Shape::TypedSignature { rect, contours })
|
||||
}
|
||||
/// `at` moved `right` and `up` points as displayed on a page turned by `rotation` (its `/Rotate`).
|
||||
pub fn displayed_offset(rotation: i64, at: [f64; 2], right: f64, up: f64) -> [f64; 2] {
|
||||
let [a, b, c, d, ..] = pdfcraft_model::view_matrix_for(rotation, [0.0; 4]);
|
||||
[at[0] + a * right + c * up, at[1] + b * right + d * up]
|
||||
}
|
||||
|
||||
/// The user-space box `width` x `height` points as displayed on a page turned by `rotation`,
|
||||
/// with its displayed top-left corner at `at`: where typed text and text boxes go. `None` for a
|
||||
/// non-finite point.
|
||||
pub fn text_box_at(rotation: i64, at: [f64; 2], width: f64, height: f64) -> Option<[f64; 4]> {
|
||||
signature_image::upright_box(rotation, displayed_offset(rotation, at, 0.0, -height / 2.0), width, height)
|
||||
}
|
||||
|
||||
/// `text` in the script font as the graphic of a visible digital signature, as Fill & Sign types
|
||||
/// it. `None` for text with no outlines.
|
||||
pub fn typed_signature_graphic(text: &str) -> Option<pdfcraft_sign::Graphic> {
|
||||
let o = script_outline(text);
|
||||
o.contours.iter().any(|c| c.len() > 2).then_some(pdfcraft_sign::Graphic::Outlines(o.contours))
|
||||
}
|
||||
|
||||
pub use links::{
|
||||
MAX_REMOTE_DOCUMENT_BYTES, RemoteDocumentPathError, read_remote_document, remote_document_path_is_absolute, resolve_remote_document_path,
|
||||
};
|
||||
@@ -200,6 +158,7 @@ pub use document::{Document, TextNotice, display_bytes_for, render_password_for}
|
||||
use document::{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};
|
||||
|
||||
Reference in New Issue
Block a user