mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-14 19:27:04 -04:00
* M10.5: Restore architectural paper presets and PDF scale controls Port the missing paper catalog and scale controls from PR #599 onto the merged Windows printing implementation. Keep the spooler and background discovery from #847/#1007. Document the feature-by-feature audit and verification limits. Assisted-by: OpenAI Codex * Drop the provenance write-up and the screenshot example (the kittest covers the dialog) * Refresh catalog hashes --------- Co-authored-by: Brandon Thomas <[email protected]>
This commit is contained in:
1 parent
a3753c52f9
commit
f036d3841b
23 files changed
+293
-22
No files matched your search
+11
-11
@@ -19,7 +19,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Simplified Chinese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "7936028709844d28d14489d608810480a1af5a707e883032161bc2fe95ff5d67"
|
||||
sha256 = "fd1660ea192c41ec38d11344035a5d2a5f453479c43a1f0bb56b65919fa5073d"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/zh-hant.tsv"
|
||||
@@ -52,7 +52,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Brazilian Portuguese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "781ac07860770313bc2a74cb1e7b312a5e027f3299d137c84d799829345f1eee"
|
||||
sha256 = "7d9b83a8f699b37e191849d79e0f116dff45486d8fccef50bd4b20c8172f95b0"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/es.tsv"
|
||||
@@ -74,7 +74,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "French UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "cec6518ba35fdd26669c200283b3a46e908f2ba940f6917b414bf1f68bcb19ce"
|
||||
sha256 = "111430ed0180b24a65f6d2b76e6bbc51b88d11c81f0da0e6d0975744584f7ad4"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/de.tsv"
|
||||
@@ -85,7 +85,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "German UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "6bb45afb959816bc6c69a1b262d568d49fe8c9a3dcec8a321231196b0831251f"
|
||||
sha256 = "cf5866438a696013303886a4a60de3348f5acb5acc4f97ec6889f5759c785a04"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/te.tsv"
|
||||
@@ -107,7 +107,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Italian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "771b72fbed8f7ef9a5689fd84322b2feb27e36295f7f0228f755fee678c34774"
|
||||
sha256 = "5564af1f42d201c1d2e2d14a77c50eff19c254f5ef9e03165552c16f6806a35b"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/pl.tsv"
|
||||
@@ -129,7 +129,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Russian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "3b37271fc6aed595b01ab42fd39cefe3dfd0e5e0e25905620590d9be5bc29c02"
|
||||
sha256 = "f1d9178f5c73fff154c7408c01ee26a12cb0c76b614a4e16e0dd6a27b6bacb4e"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/hu.tsv"
|
||||
@@ -140,7 +140,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Hungarian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "8e6549bb81c37757822776e3f8f46b3479688bd950508c9c311a3723a1a7b173"
|
||||
sha256 = "00473565c3545c1fe86aff596c57e004eb25ae914d831f628b57ec08113f03d8"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/bg.tsv"
|
||||
@@ -151,7 +151,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Bulgarian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "8d8ec98406f3d8b44766c3daad04af5beac39a5e69cceedfb1b881bd20457023"
|
||||
sha256 = "a38c9276670bfd292358d021ef55d12b17f944f9236180a068d55f59d454957d"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/ja.tsv"
|
||||
@@ -162,7 +162,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Japanese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "b995a67d0fdac2b2d567e2f37d2688a31e5a6222ffca59a95c304c7f331e18ad"
|
||||
sha256 = "c6391eb0e85439a8473eb152ab58e817831e8ad48ec6c4a54315126cf4a46ba2"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/uk.tsv"
|
||||
@@ -173,7 +173,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Ukrainian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "32f471f14b9f3cff21d57a3f69336717c697f8cd6bf502c7aa01591d69c42e90"
|
||||
sha256 = "1d2f66915cde08456309a2ca726257e6b025e56bcc49377d7cd3fc095d294a2f"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/ar.tsv"
|
||||
@@ -184,7 +184,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Arabic UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "d46933f539a253fce67e81c06b6bf9d295cc7805cd36842c9d189fcc57b17950"
|
||||
sha256 = "7551eba21c7bfdba960684711e1580c32059f5620a02903898441058d1b93ed3"
|
||||
|
||||
[[asset]]
|
||||
path = "assets/icons/accessibility.svg"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
**Stage: alpha** · next: beta, ~26% (ready for real work 49% → 75%) and ~400–700 h away
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (architectural paper controls from #599; localized shortcut labels, #496; readiness table with hours per audience; full number as weighted sum 49%; earlier: second look: ready 40% → 47%, mainstream 55% added; core-workflow gate applied → alpha) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** M14 #307 Plan 3 uses one marker traversal on open and full refresh, and the combined scanner borrows metadata instead of cloning scan-only containers; includes a behavior-preserving `organize` binding for the workspace Clippy gate · earlier: minor (localized shortcut labels, #496; readiness table with hours per audience; full number as weighted sum 49%; second look: ready 40% → 47%, mainstream 55% added; core-workflow gate applied → alpha) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (closed issues synced: #774, #756 and the #799–#821 batch; earlier: localized shortcut labels, #496; readiness table with hours per audience; full number as weighted sum 49%; earlier: second look: ready 40% → 47%, mainstream 55% added; core-workflow gate applied → alpha) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
|
||||
|
||||
@@ -134,6 +135,8 @@ Ranked; detail and the full milestone table in [docs/roadmap.md](docs/roadmap.md
|
||||
|
||||
## Progress log
|
||||
|
||||
- **2026-10-11 (M10.5, focused follow-up to #599):** Carry the architectural/ANSI/large ISO paper presets, current-page matching at 100%, and previewed PDF scale into the current print dialog and `doc_print`. Retains the #847/#1007 spooler and background discovery. Driver substitution, physical calibration, vector Windows printing and managed-endpoint restrictions remain separate gaps. Overall estimates unchanged.
|
||||
|
||||
Newest first: the date, what moved, and the new overall estimate.
|
||||
|
||||
- **2026-10-11 (M14, #307 Plan 3):** Engine open and full refresh use one page/content traversal to populate marks and added content. The independent public scans remain available; the combined scanner borrows direct objects and holds referenced objects through `Arc<Object>` instead of cloning scan-only `/Contents` arrays or `/PCAdded` dictionaries. Differential tests cover an indirect `/PCAdded` dictionary as well as ordering, malformed/direct/indirect/repeated entries and `/UserUnit`. Exact `bbbe600`→final release CLI measurements used 10 alternating pairs: wall-time medians were 183.645→174.440 ms on 10,000 marker-free pages (10/10 wins), 33.587→32.752 ms on 1,500 mixed pages (8/10), and 24.331→20.133 ms on the 100,000-entry array stress fixture (10/10). The stress fixture's maximum-RSS median fell 28,655,616→19,038,208 B; peak-footprint medians were 14,747,136→14,673,408 B. From P0, the follow-up stress run was 20.886→20.201 ms (10/10), with RSS 23,953,408→19,087,360 B and peak footprint 14,706,144→14,697,952 B. `doc_open` stdout hashes matched every pair. The ancillary `organize` binding preserves the prior `prune_legacy` update condition. Estimates unchanged.
|
||||
|
||||
@@ -105,9 +105,15 @@ impl Automation {
|
||||
None => PAPERS[0].1,
|
||||
Some(p) => PAPERS
|
||||
.iter()
|
||||
.find(|(n, _)| n.eq_ignore_ascii_case(p) || n.replace("US ", "").eq_ignore_ascii_case(p))
|
||||
.find(|(n, _)| {
|
||||
n.eq_ignore_ascii_case(p)
|
||||
|| n.replace("US ", "").eq_ignore_ascii_case(p)
|
||||
|| n.split(" (").next().is_some_and(|name| name.eq_ignore_ascii_case(p))
|
||||
})
|
||||
.map(|x| x.1)
|
||||
.ok_or_else(|| bad(format!("unknown paper {p:?} (Letter, Legal, Tabloid, A3, A4, A5)")))?,
|
||||
.ok_or_else(|| {
|
||||
bad(format!("unknown paper {p:?}; choose one of {}", PAPERS.iter().map(|(name, _)| *name).collect::<Vec<_>>().join(", ")))
|
||||
})?,
|
||||
};
|
||||
let settings = print::Settings { pages, paper, orientation, layout, content };
|
||||
let sizes: Vec<(f64, f64)> = self.doc(a)?.info.pages.iter().map(|p| (p.width as f64, p.height as f64)).collect();
|
||||
|
||||
@@ -461,7 +461,7 @@ pub fn tools() -> Vec<ToolDef> {
|
||||
t(
|
||||
"doc_print",
|
||||
"Print",
|
||||
"Print with Acrobat's Print dialog options, or save the print-ready PDF. pages: a range such as \"1-3, 6, 9-\" (page labels allowed; default all); subset odd/even; reverse. layout: fit (default), actual, shrink, custom (scale %), multiple (per_sheet 2/4/6/9/16, order, border, auto_rotate; cut-stack order arranges single-sided sheets for cutting into piles and stacking left to right, top to bottom, keeping sheet order within each pile; duplex must be off), booklet (booklet_subset both/front/back, binding left/right), poster (scale %, overlap pt, cut_marks). orientation auto/portrait/landscape; comments_forms document / document-and-markups (default) / document-and-stamps / form-fields-only; paper Letter/Legal/Tabloid/A3/A4/A5. Then path (save) or printer (a name or \"default\") with copies, collate, duplex off/long-edge/short-edge, grayscale, and options (driver options from printer_options, CUPS).",
|
||||
"Print with Acrobat's Print dialog options, or save the print-ready PDF. pages: a range such as \"1-3, 6, 9-\" (page labels allowed; default all); subset odd/even; reverse. layout: fit (default), actual, shrink, custom (scale %), multiple (per_sheet 2/4/6/9/16, order, border, auto_rotate; cut-stack order arranges single-sided sheets for cutting into piles and stacking left to right, top to bottom, keeping sheet order within each pile; duplex must be off), booklet (booklet_subset both/front/back, binding left/right), poster (scale %, overlap pt, cut_marks). orientation auto/portrait/landscape; comments_forms document / document-and-markups (default) / document-and-stamps / form-fields-only; paper Letter/Legal/Tabloid, ARCH A/B/C/D/E1/E, ANSI C/D/E, or A0/A1/A2/A3/A4/A5 (short names or full preset labels); use layout actual for 100% in the print-ready PDF; printer drivers may still substitute paper or scale. Then path (save) or printer (a name or \"default\") with copies, collate, duplex off/long-edge/short-edge, grayscale, and options (driver options from printer_options, CUPS).",
|
||||
)
|
||||
.with(schema(
|
||||
json!({
|
||||
|
||||
@@ -4197,3 +4197,51 @@ fn text_extract_with_a_rect_takes_one_column() {
|
||||
assert!(matches!(e, ToolError::InvalidArgs(_)), "{bad}: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Independent inch/mm dimensions, checked in the saved file through the tool path.
|
||||
#[test]
|
||||
fn architectural_and_iso_papers_through_tools() {
|
||||
let dir = workdir("plotter-papers");
|
||||
let mut a = auto(&dir);
|
||||
let doc = ok(&mut a, "doc_open", json!({ "path": "a.pdf" }))["doc"].as_u64().unwrap();
|
||||
let mm = 72.0 / 25.4;
|
||||
for (name, w, h) in [
|
||||
("ARCH A", 9.0 * 72.0, 12.0 * 72.0),
|
||||
("arch b", 12.0 * 72.0, 18.0 * 72.0),
|
||||
("ARCH C", 18.0 * 72.0, 24.0 * 72.0),
|
||||
("ARCH D", 24.0 * 72.0, 36.0 * 72.0),
|
||||
("ARCH E1", 30.0 * 72.0, 42.0 * 72.0),
|
||||
("ARCH E (36 x 48 in)", 36.0 * 72.0, 48.0 * 72.0),
|
||||
("ANSI C", 17.0 * 72.0, 22.0 * 72.0),
|
||||
("ANSI D", 22.0 * 72.0, 34.0 * 72.0),
|
||||
("ANSI E", 34.0 * 72.0, 44.0 * 72.0),
|
||||
("A2", 420.0 * mm, 594.0 * mm),
|
||||
("A1", 594.0 * mm, 841.0 * mm),
|
||||
("A0", 841.0 * mm, 1189.0 * mm),
|
||||
("Letter", 612.0, 792.0),
|
||||
("US Legal", 612.0, 1008.0),
|
||||
("Tabloid", 792.0, 1224.0),
|
||||
] {
|
||||
for orientation in ["portrait", "landscape"] {
|
||||
let out = ok(
|
||||
&mut a,
|
||||
"doc_print",
|
||||
json!({"doc": doc, "pages": "1", "paper": name,
|
||||
"layout": "actual", "orientation": orientation, "path": "plot.pdf"}),
|
||||
);
|
||||
assert_eq!(out["sheets"], 1);
|
||||
let bytes = std::fs::read(dir.join("plot.pdf")).unwrap();
|
||||
let saved = pdfcraft_cos::Document::open(std::sync::Arc::new(bytes)).unwrap();
|
||||
let pages = pdfcraft_model::pages(&saved);
|
||||
assert_eq!(pages.len(), 1);
|
||||
let (ew, eh) = if orientation == "landscape" { (h, w) } else { (w, h) };
|
||||
let (aw, ah) = pages[0].display_size(&saved);
|
||||
assert!((aw - ew).abs() < 0.02 && (ah - eh).abs() < 0.02, "{name} {orientation}: {aw} x {ah}");
|
||||
}
|
||||
}
|
||||
let before = std::fs::read(dir.join("plot.pdf")).unwrap();
|
||||
let bad = a.call("doc_print", &json!({"doc": doc, "paper": "ARCH Z", "path": "plot.pdf"}));
|
||||
assert!(matches!(bad, Err(ToolError::InvalidArgs(m)) if m.contains("ARCH E1") && m.contains("A0")));
|
||||
assert_eq!(std::fs::read(dir.join("plot.pdf")).unwrap(), before);
|
||||
assert!(a.call("doc_print", &json!({"doc": doc, "paper": "ARCH D", "path": "../escape.pdf"})).is_err());
|
||||
}
|
||||
@@ -46,3 +46,25 @@ printer isn't available yet; the print-ready PDF can always be saved.
|
||||
|
||||
Not yet: the web spooler, print as image, poster labels, PostScript output, colour conversion for
|
||||
grayscale.
|
||||
|
||||
## Architectural sheets and scale
|
||||
|
||||
The Paper menu and `doc_print` share Letter, Legal, Tabloid, A3/A4/A5 plus
|
||||
ARCH A/B/C/D/E1/E, ANSI C/D/E and ISO A0/A1/A2. ARCH D is 24 × 36 inches;
|
||||
ANSI D is 22 × 34 inches. Dimensions follow the [HP DesignJet paper-size table](https://support.hp.com/hr-en/document/bpp01676).
|
||||
Automation accepts short names such as `"ARCH D"` (case-insensitive) or the full menu label.
|
||||
For example, `doc_print` with `paper: "ARCH D"`, `layout: "actual"`,
|
||||
`orientation: "auto"` and `path: "plan.pdf"` writes a print-ready PDF at 100%.
|
||||
|
||||
**Match page at 100%** uses the currently viewed document page to choose a standard
|
||||
sheet (either orientation, within 0.5 pt for rounded metric dimensions), Actual size
|
||||
and Auto orientation. It leaves the selected page range intact. It is disabled
|
||||
for a custom page size with no matching preset. One preset applies to the whole job;
|
||||
this is not per-page paper-source selection.
|
||||
|
||||
**PDF scale** describes the source-to-sheet transform in the previewed print-ready
|
||||
PDF, not measured physical output. Fit reserves an 18 pt margin and can reduce even
|
||||
a matching page. The current Windows backend still rasterises and can substitute
|
||||
paper/shrink a job if its driver lacks the requested size. These controls do not
|
||||
add #599's strict PrintTicket validation or vector spooler. Verify the driver's
|
||||
paper/scaling settings and physical calibration before relying on drawing scale.
|
||||
+23
-1
@@ -161,15 +161,37 @@ impl Default for Settings {
|
||||
}
|
||||
|
||||
/// Common paper sizes (points, portrait).
|
||||
pub const PAPERS: [(&str, (f64, f64)); 6] = [
|
||||
pub const PAPERS: [(&str, (f64, f64)); 18] = [
|
||||
("US Letter", (612.0, 792.0)),
|
||||
("US Legal", (612.0, 1008.0)),
|
||||
("Tabloid", (792.0, 1224.0)),
|
||||
("A3", (841.89, 1190.55)),
|
||||
("A4", (595.28, 841.89)),
|
||||
("A5", (419.53, 595.28)),
|
||||
("ARCH A (9 x 12 in)", (648.0, 864.0)),
|
||||
("ARCH B (12 x 18 in)", (864.0, 1296.0)),
|
||||
("ARCH C (18 x 24 in)", (1296.0, 1728.0)),
|
||||
("ARCH D (24 x 36 in)", (1728.0, 2592.0)),
|
||||
("ARCH E1 (30 x 42 in)", (2160.0, 3024.0)),
|
||||
("ARCH E (36 x 48 in)", (2592.0, 3456.0)),
|
||||
("ANSI C (17 x 22 in)", (1224.0, 1584.0)),
|
||||
("ANSI D (22 x 34 in)", (1584.0, 2448.0)),
|
||||
("ANSI E (34 x 44 in)", (2448.0, 3168.0)),
|
||||
("A2", (1190.55, 1683.78)),
|
||||
("A1", (1683.78, 2383.94)),
|
||||
("A0", (2383.94, 3370.39)),
|
||||
];
|
||||
|
||||
/// Match a displayed PDF page to a standard sheet, independent of orientation.
|
||||
/// Half a point allows rounded metric PDF dimensions without confusing distinct sizes.
|
||||
pub fn matching_paper(size: (f64, f64)) -> Option<usize> {
|
||||
if !size.0.is_finite() || !size.1.is_finite() {
|
||||
return None;
|
||||
}
|
||||
let size = (size.0.min(size.1), size.0.max(size.1));
|
||||
PAPERS.iter().position(|(_, p)| (p.0 - size.0).abs() <= 0.5 && (p.1 - size.1).abs() <= 0.5)
|
||||
}
|
||||
|
||||
/// The unprintable margin assumed around the sheet for Fit, Multiple and Booklet.
|
||||
pub const MARGIN: f64 = 18.0;
|
||||
|
||||
|
||||
@@ -631,3 +631,30 @@ fn a_scaled_appearance_is_not_scaled_twice() {
|
||||
assert!(close(m.0[0], 2.0) && close(m.0[3], 2.0), "{:?}", m.0);
|
||||
assert!(close(m.0[4], 10.0) && close(m.0[5], 10.0), "{:?}", m.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn architectural_sheets_preserve_full_scale() {
|
||||
let index = matching_paper((2592.0, 1728.0)).unwrap();
|
||||
assert_eq!(PAPERS[index].0, "ARCH D (24 x 36 in)");
|
||||
assert_eq!(matching_paper((1728.0, 2592.0)), Some(index));
|
||||
assert_eq!(matching_paper((f64::NAN, 2592.0)), None);
|
||||
let s = Settings { pages: vec![0], paper: PAPERS[index].1, layout: Layout::Size(SizeMode::Actual), ..Settings::default() };
|
||||
let sheets = layout(&[(2592.0, 1728.0)], &s).unwrap();
|
||||
assert_eq!(sheets[0].size, (2592.0, 1728.0));
|
||||
assert_eq!(sheets[0].placed[0].matrix.0, [1.0, 0.0, 0.0, 1.0, 0.0, 0.0]);
|
||||
let fit = layout(&[(2592.0, 1728.0)], &Settings { layout: Layout::Size(SizeMode::Fit), ..s }).unwrap();
|
||||
assert!(fit[0].placed[0].matrix.0[0] < 1.0, "Fit adds margins and must not masquerade as full scale");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn paper_matching_accepts_rounded_metric_sizes_but_not_custom_or_invalid_sizes() {
|
||||
for (i, (_, (w, h))) in PAPERS.iter().enumerate() {
|
||||
assert_eq!(matching_paper((*w, *h)), Some(i));
|
||||
assert_eq!(matching_paper((*h, *w)), Some(i));
|
||||
assert_eq!(matching_paper((w.round(), h.round())), Some(i));
|
||||
assert_eq!(matching_paper((w + 0.51, *h)), None);
|
||||
}
|
||||
for size in [(0.0, 0.0), (-1728.0, 2592.0), (f64::INFINITY, 2592.0), (1728.0, f64::NAN), (1000.0, 1000.0)] {
|
||||
assert_eq!(matching_paper(size), None);
|
||||
}
|
||||
}
|
||||
@@ -2232,6 +2232,13 @@ key Space مسافة
|
||||
Panels اللوحات
|
||||
Resize panels تغيير حجم اللوحات
|
||||
Resize panel window تغيير حجم نافذة اللوحة
|
||||
|
||||
# Architectural print controls (follow-up to #599).
|
||||
PDF page: {w} × {h} in صفحة PDF: {w} × {h} بوصة
|
||||
Match page at 100% مطابقة الورق للصفحة بنسبة 100%
|
||||
PDF scale: {scale}% مقياس PDF: {scale}%
|
||||
Printer paper and scaling may differ. Check driver settings. قد يختلف ورق الطابعة ومقياس الطباعة. تحقق من إعدادات برنامج التشغيل.
|
||||
Drawing scale changes. Use Actual size for full-scale plans. يتغير مقياس الرسم. استخدم الحجم الفعلي لطباعة المخططات بمقياسها الأصلي.
|
||||
Reload documents when their files change on disk إعادة تحميل المستندات عند تغيّر ملفاتها على القرص
|
||||
This file changed on disk. Reload it to see the new version; your unsaved changes will be lost. تغيّر هذا الملف على القرص. أعد تحميله لعرض النسخة الجديدة؛ ستفقد تغييراتك غير المحفوظة.
|
||||
Reload إعادة تحميل
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -2174,6 +2174,13 @@ key Space Интервал
|
||||
Resize panel window Преоразмери прозореца на панела
|
||||
Tools Инструменти
|
||||
Inspector Инспектор
|
||||
|
||||
# Architectural print controls (follow-up to #599).
|
||||
PDF page: {w} × {h} in PDF страница: {w} × {h} инча
|
||||
Match page at 100% Хартия по страницата, мащаб 100%
|
||||
PDF scale: {scale}% Мащаб на PDF: {scale}%
|
||||
Printer paper and scaling may differ. Check driver settings. Хартията и мащабът на принтера може да се различават. Проверете настройките на драйвера.
|
||||
Drawing scale changes. Use Actual size for full-scale plans. Мащабът на чертежа се променя. Използвайте Действителен размер за планове в оригинален мащаб.
|
||||
Reload documents when their files change on disk Презареждай документите, когато файловете им се променят на диска
|
||||
This file changed on disk. Reload it to see the new version; your unsaved changes will be lost. Този файл е променен на диска. Презаредете го, за да видите новата версия; незаписаните ви промени ще бъдат загубени.
|
||||
Reload Презареди
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 8 and column 16.
|
@@ -2216,6 +2216,13 @@ key Space Leertaste
|
||||
Resize panel window Größe des Bereichsfensters ändern
|
||||
Tools Werkzeuge
|
||||
Inspector Inspektor
|
||||
|
||||
# Architectural print controls (follow-up to #599).
|
||||
PDF page: {w} × {h} in PDF-Seite: {w} × {h} Zoll
|
||||
Match page at 100% Papier an Seite anpassen, 100%
|
||||
PDF scale: {scale}% PDF-Maßstab: {scale}%
|
||||
Printer paper and scaling may differ. Check driver settings. Druckerpapier und Skalierung können abweichen. Treibereinstellungen prüfen.
|
||||
Drawing scale changes. Use Actual size for full-scale plans. Der Zeichnungsmaßstab ändert sich. Für maßstabsgetreue Pläne Tatsächliche Größe verwenden.
|
||||
Reload documents when their files change on disk Dokumente neu laden, wenn sich ihre Dateien auf dem Datenträger ändern
|
||||
This file changed on disk. Reload it to see the new version; your unsaved changes will be lost. Diese Datei wurde auf dem Datenträger geändert. Lade sie neu, um die neue Version zu sehen; deine nicht gespeicherten Änderungen gehen dabei verloren.
|
||||
Reload Neu laden
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 51.
|
@@ -2216,6 +2216,13 @@ key Space Espace
|
||||
Resize panel window Redimensionner la fenêtre du panneau
|
||||
Tools Outils
|
||||
Inspector Inspecteur
|
||||
|
||||
# Architectural print controls (follow-up to #599).
|
||||
PDF page: {w} × {h} in Page PDF : {w} × {h} po
|
||||
Match page at 100% Adapter le papier à la page à 100 %
|
||||
PDF scale: {scale}% Échelle PDF : {scale}%
|
||||
Printer paper and scaling may differ. Check driver settings. Le papier et l’échelle de l’imprimante peuvent différer. Vérifiez les réglages du pilote.
|
||||
Drawing scale changes. Use Actual size for full-scale plans. L’échelle du dessin change. Utilisez Taille réelle pour les plans à l’échelle.
|
||||
Select page {label} Sélectionner la page {label}
|
||||
Rotate page {label} counterclockwise Faire pivoter la page {label} dans le sens antihoraire
|
||||
Rotate page {label} clockwise Faire pivoter la page {label} dans le sens horaire
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 39.
|
@@ -2210,6 +2210,13 @@ key Space Szóköz
|
||||
Resize panel window Panelablak átméretezése
|
||||
Tools Eszközök
|
||||
Inspector Tulajdonságvizsgáló
|
||||
|
||||
# Architectural print controls (follow-up to #599).
|
||||
PDF page: {w} × {h} in PDF-oldal: {w} × {h} hüvelyk
|
||||
Match page at 100% Papír illesztése az oldalhoz, 100%
|
||||
PDF scale: {scale}% PDF-méretarány: {scale}%
|
||||
Printer paper and scaling may differ. Check driver settings. A nyomtató papírja és méretezése eltérhet. Ellenőrizze az illesztőprogram beállításait.
|
||||
Drawing scale changes. Use Actual size for full-scale plans. A rajz méretaránya változik. Méretarányos tervekhez használja a Tényleges méret beállítást.
|
||||
Reload documents when their files change on disk Dokumentumok újratöltése, ha a fájljuk megváltozik a lemezen
|
||||
This file changed on disk. Reload it to see the new version; your unsaved changes will be lost. Ez a fájl megváltozott a lemezen. Töltsd újra az új változat megtekintéséhez; a nem mentett módosításaid elvesznek.
|
||||
Reload Újratöltés
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 7 and column 44.
|
@@ -2219,6 +2219,13 @@ key Space Spazio
|
||||
Panels Pannelli
|
||||
Resize panels Ridimensiona pannelli
|
||||
Resize panel window Ridimensiona finestra pannello
|
||||
|
||||
# Architectural print controls (follow-up to #599).
|
||||
PDF page: {w} × {h} in Pagina PDF: {w} × {h} pollici
|
||||
Match page at 100% Adatta il foglio alla pagina al 100%
|
||||
PDF scale: {scale}% Scala PDF: {scale}%
|
||||
Printer paper and scaling may differ. Check driver settings. Carta e scala della stampante possono differire. Controlla le impostazioni del driver.
|
||||
Drawing scale changes. Use Actual size for full-scale plans. La scala del disegno cambia. Usa Dimensioni effettive per le planimetrie in scala.
|
||||
Reload documents when their files change on disk Ricarica i documenti quando i loro file cambiano sul disco
|
||||
This file changed on disk. Reload it to see the new version; your unsaved changes will be lost. Questo file è cambiato sul disco. Ricaricalo per vedere la nuova versione; le modifiche non salvate andranno perse.
|
||||
Reload Ricarica
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -2212,6 +2212,13 @@ key Space スペース
|
||||
Resize panel window パネルウィンドウのサイズを変更
|
||||
Tools ツール
|
||||
Inspector インスペクター
|
||||
|
||||
# Architectural print controls (follow-up to #599).
|
||||
PDF page: {w} × {h} in PDFページ: {w} × {h} インチ
|
||||
Match page at 100% ページに合わせて100%に設定
|
||||
PDF scale: {scale}% PDFの倍率: {scale}%
|
||||
Printer paper and scaling may differ. Check driver settings. プリンターの用紙や倍率は異なる場合があります。ドライバーの設定を確認してください。
|
||||
Drawing scale changes. Use Actual size for full-scale plans. 図面の縮尺が変わります。原寸で印刷するには「実際のサイズ」を使用してください。
|
||||
Reload documents when their files change on disk ディスク上のファイルが変更されたら文書を再読み込みする
|
||||
This file changed on disk. Reload it to see the new version; your unsaved changes will be lost. このファイルはディスク上で変更されました。再読み込みすると新しいバージョンが表示されますが、未保存の変更は失われます。
|
||||
Reload 再読み込み
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -2213,6 +2213,13 @@ key Space Espaço
|
||||
Resize panel window Redimensionar janela do painel
|
||||
Tools Ferramentas
|
||||
Inspector Inspetor
|
||||
|
||||
# Architectural print controls (follow-up to #599).
|
||||
PDF page: {w} × {h} in Página PDF: {w} × {h} pol.
|
||||
Match page at 100% Ajustar papel à página a 100%
|
||||
PDF scale: {scale}% Escala do PDF: {scale}%
|
||||
Printer paper and scaling may differ. Check driver settings. O papel e a escala da impressora podem variar. Confira as configurações do driver.
|
||||
Drawing scale changes. Use Actual size for full-scale plans. A escala do desenho muda. Use Tamanho real para plantas em escala.
|
||||
Reload documents when their files change on disk Recarregar documentos quando os arquivos mudarem no disco
|
||||
This file changed on disk. Reload it to see the new version; your unsaved changes will be lost. Este arquivo foi alterado no disco. Recarregue-o para ver a nova versão; suas alterações não salvas serão perdidas.
|
||||
Reload Recarregar
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 9 and column 16.
|
@@ -2129,6 +2129,13 @@ key Space Пробел
|
||||
Resize panel window Изменить размер окна панели
|
||||
Tools Инструменты
|
||||
Inspector Инспектор
|
||||
|
||||
# Architectural print controls (follow-up to #599).
|
||||
PDF page: {w} × {h} in Страница PDF: {w} × {h} дюйм.
|
||||
Match page at 100% Подобрать бумагу, масштаб 100%
|
||||
PDF scale: {scale}% Масштаб PDF: {scale}%
|
||||
Printer paper and scaling may differ. Check driver settings. Бумага и масштаб принтера могут отличаться. Проверьте настройки драйвера.
|
||||
Drawing scale changes. Use Actual size for full-scale plans. Масштаб чертежа изменяется. Для печати в исходном масштабе выберите Фактический размер.
|
||||
Select page {label} Выбрать страницу {label}
|
||||
Rotate page {label} counterclockwise Повернуть страницу {label} против часовой стрелки
|
||||
Rotate page {label} clockwise Повернуть страницу {label} по часовой стрелке
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 9 and column 16.
|
@@ -2233,6 +2233,13 @@ key Space Пробіл
|
||||
Panels Панелі
|
||||
Resize panels Змінити розмір панелей
|
||||
Resize panel window Змінити розмір вікна панелі
|
||||
|
||||
# Architectural print controls (follow-up to #599).
|
||||
PDF page: {w} × {h} in Сторінка PDF: {w} × {h} дюйм.
|
||||
Match page at 100% Підібрати папір, масштаб 100%
|
||||
PDF scale: {scale}% Масштаб PDF: {scale}%
|
||||
Printer paper and scaling may differ. Check driver settings. Папір і масштаб принтера можуть відрізнятися. Перевірте налаштування драйвера.
|
||||
Drawing scale changes. Use Actual size for full-scale plans. Масштаб креслення змінюється. Для друку в початковому масштабі виберіть Фактичний розмір.
|
||||
Reload documents when their files change on disk Перезавантажувати документи, коли їхні файли змінюються на диску
|
||||
This file changed on disk. Reload it to see the new version; your unsaved changes will be lost. Цей файл змінено на диску. Перезавантажте його, щоб побачити нову версію; незбережені зміни буде втрачено.
|
||||
Reload Перезавантажити
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -2180,6 +2180,13 @@ key Space 空格
|
||||
Resize panel window 调整面板窗口大小
|
||||
Tools 工具
|
||||
Inspector 检查器
|
||||
|
||||
# Architectural print controls (follow-up to #599).
|
||||
PDF page: {w} × {h} in PDF 页面:{w} × {h} 英寸
|
||||
Match page at 100% 匹配页面并设为 100%
|
||||
PDF scale: {scale}% PDF 缩放:{scale}%
|
||||
Printer paper and scaling may differ. Check driver settings. 打印机纸张和缩放可能不同。请检查驱动程序设置。
|
||||
Drawing scale changes. Use Actual size for full-scale plans. 图纸比例发生变化。按原比例打印图纸时请使用实际大小。
|
||||
Select page {label} 选择页面 {label}
|
||||
Rotate page {label} counterclockwise 逆时针旋转页面 {label}
|
||||
Rotate page {label} clockwise 顺时针旋转页面 {label}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 9 and column 16.
|
@@ -603,7 +603,8 @@ pub(crate) fn body(
|
||||
);
|
||||
ui.end_row();
|
||||
ui.label(tl!("Paper:"));
|
||||
egui::ComboBox::from_id_salt("paper").selected_text(PAPERS[d.paper].0).width(160.0).show_ui(ui, |ui| {
|
||||
let paper_name = PAPERS.get(d.paper).map_or("US Letter", |p| p.0);
|
||||
egui::ComboBox::from_id_salt("paper").selected_text(paper_name).width(260.0).show_ui(ui, |ui| {
|
||||
for (i, (name, _)) in PAPERS.iter().enumerate() {
|
||||
ui.selectable_value(&mut d.paper, i, *name);
|
||||
}
|
||||
@@ -616,6 +617,21 @@ pub(crate) fn body(
|
||||
if d.show_driver_options {
|
||||
driver_options_panel(ui, d, t);
|
||||
}
|
||||
if let Some(&source) = sizes.get(d.current_page) {
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
ui.label(crate::i18n::fmt(tl!("PDF page: {w} × {h} in"), &[("w", &format!("{:.2}", source.0 / 72.0)), ("h", &format!("{:.2}", source.1 / 72.0))]));
|
||||
let matched = print::matching_paper(source);
|
||||
if ui.add_enabled(matched.is_some(), egui::Button::new(tl!("Match page at 100%"))).clicked()
|
||||
&& let Some(paper) = matched
|
||||
{
|
||||
d.paper = paper;
|
||||
d.handling = Handling::Size;
|
||||
d.size = SizeMode::Actual;
|
||||
d.orientation = Orientation::Auto;
|
||||
d.sheet = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
ui.add_space(6.0);
|
||||
widgets::section_title(ui, tl!("Pages to Print"));
|
||||
ui.horizontal(|ui| {
|
||||
@@ -841,9 +857,19 @@ pub(crate) fn body(
|
||||
d.sheet += 1;
|
||||
}
|
||||
});
|
||||
if let Some(s) = sheets.first() {
|
||||
if let Some(s) = sheets.get(d.sheet) {
|
||||
let (w, h) = (s.size.0 / 72.0, s.size.1 / 72.0);
|
||||
ui.label(egui::RichText::new(format!("{w:.2} × {h:.2} in")).small().color(t.text_muted));
|
||||
if d.handling == Handling::Size
|
||||
&& let Some(p) = s.placed.first()
|
||||
{
|
||||
let scale = p.matrix.0[0].hypot(p.matrix.0[1]) * 100.0;
|
||||
ui.label(crate::i18n::fmt(tl!("PDF scale: {scale}%"), &[("scale", &format!("{scale:.2}"))]));
|
||||
ui.label(egui::RichText::new(tl!("Printer paper and scaling may differ. Check driver settings.")).small().color(t.text_muted));
|
||||
if (scale - 100.0).abs() > 0.01 {
|
||||
ui.label(egui::RichText::new(tl!("Drawing scale changes. Use Actual size for full-scale plans.")).small().color(t.text_muted));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! The Print dialog in the real shell (egui_kittest): settings, preview sheets, Save as PDF.
|
||||
|
||||
use egui_kittest::Harness;
|
||||
use egui_kittest::kittest::Queryable;
|
||||
use egui_kittest::kittest::{NodeT, Queryable};
|
||||
use pdfcraft_ui_egui::{Dialog, PdfCraftApp};
|
||||
|
||||
fn harness() -> Harness<'static, PdfCraftApp> {
|
||||
@@ -243,3 +243,42 @@ fn printers_listed_in_the_background_preselect_the_default_unless_one_was_picked
|
||||
assert!(!h.state().print_draft.printers_loading);
|
||||
assert_eq!(h.state().print_draft.printer, None, "Save as PDF, as picked");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn architectural_page_can_be_matched_at_100_percent() {
|
||||
let mut h = Harness::builder().with_size(egui::vec2(1400.0, 1000.0)).build_eframe(|_cc| {
|
||||
let mut app = PdfCraftApp::new();
|
||||
app.set_option("language", "en").unwrap();
|
||||
let bytes = app.session.create_blank(2592.0, 1728.0, 1).unwrap();
|
||||
app.open_bytes("architectural.pdf", None, bytes.as_ref().clone()).unwrap();
|
||||
app
|
||||
});
|
||||
h.run_steps(4);
|
||||
assert!(h.state_mut().execute("print.dialog"));
|
||||
h.run_steps(3);
|
||||
h.get_by_label("PDF page: 36.00 × 24.00 in");
|
||||
h.get_by_label("Match page at 100%").click();
|
||||
h.run_steps(3);
|
||||
h.get_by_value("ARCH D (24 x 36 in)");
|
||||
h.get_by_label("PDF scale: 100.00%");
|
||||
h.get_by_label("36.00 × 24.00 in");
|
||||
h.get_by_label("Printer paper and scaling may differ. Check driver settings.");
|
||||
let settings = h.state().print_draft.settings(1, &[]).unwrap();
|
||||
assert_eq!(settings.paper, (1728.0, 2592.0));
|
||||
assert_eq!(settings.layout, pdfcraft_engine::print::Layout::Size(pdfcraft_engine::print::SizeMode::Actual));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn custom_page_cannot_silently_match_a_standard_paper() {
|
||||
let mut h = harness();
|
||||
assert!(h.state_mut().execute("print.dialog"));
|
||||
h.run_steps(3);
|
||||
// The 300 x 400 pt fixture is not a standard sheet.
|
||||
assert!(pdfcraft_engine::print::matching_paper((300.0, 400.0)).is_none());
|
||||
let before = h.state().print_draft.clone();
|
||||
assert!(h.get_by_label("Match page at 100%").accesskit_node().is_disabled());
|
||||
h.get_by_label("Match page at 100%").click();
|
||||
h.run_steps(3);
|
||||
assert_eq!(h.state().print_draft.paper, before.paper);
|
||||
assert_eq!(h.state().print_draft.size, before.size);
|
||||
}
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
# PdfCraft roadmap: milestones and what's next
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (architectural paper controls from #599; M6: respect existing form-font encodings; retain source fonts on appearance fallback; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (direct Organize overview and page actions; localized shortcut labels, #496; alpha gate added; convert-and-share re-judged with the cross-app rule → alpha) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (closed issues synced: #774, #756, #817–#821, #809, #819, #816, #844; earlier: localized shortcut labels, #496; alpha gate added; convert-and-share re-judged with the cross-app rule → alpha) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (M6: respect existing form-font encodings; retain source fonts on appearance fallback; estimates unchanged) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS)
|
||||
@@ -84,7 +85,7 @@ total matches the parity estimate.
|
||||
| M7 | Content editing (text, images, header/footer, watermark) | 250–500 | 20% | 100–180 | Done: header & footer, watermarks, backgrounds, Bates; added text and images that stay editable (move, resize, format, rotate, flip, crop, replace); links (Link tool, Link Properties, create from URLs, remove all). Missing: editing existing text and images in place (the longest pole), image/PDF watermarks |
|
||||
| M8 | Security + redaction | 100–180 | 68% | 15–30 | Done: opening protected documents, permissions, Protect Using Password, Remove security; redaction (mark text/areas/pages, Search & Redact with patterns, apply removing glyphs, image pixels, vectors, XObject content, annotations and fields, verification, full rewrite on save); Remove hidden information and Sanitize.<br>Done since: redaction codes (U.S. FOIA and Privacy Act sets as overlay text, in Redaction properties and `redact_mark`). Missing: certificate security, custom redaction code sets and pattern locales, DCT re-encoding |
|
||||
| M9 | Signatures (PAdES, validation) | 160–280 | 60% | 40–70 | Done: new `sign` crate (DER, X.509, CMS, PKCS #12 on RustCrypto; aws-lc-rs for RSA private keys); PAdES B-B signing (visible, invisible, existing fields, certification with DocMDP); validation with trust store and changes-after-signing classification; self-signed digital IDs; Signatures panel, message bar, sign dialogs; agent tools. Checked with pdfsig and OpenSSL.<br>Done since: macOS Keychain and Windows Current User Personal store signing (software-backed CNG keys), certificate viewer, signed documents protected from rewrites. Missing: timestamps (B-T), LTV (DSS, OCSP, CRL), FieldMDP, smart cards, PKCS #11 |
|
||||
| M10 | OCR, create, export, print | 200–350 | 33% | 120–215 | Done: create from blank/text/PNG/JPEG/TIFF (multi-page)/GIF/BMP; export PNG/JPEG/TIFF and text; Print (Acrobat's sizing, n-up, booklet, poster, comments & forms, preview, the CUPS and Windows spoolers, print-ready PDF).<br>Done since: embedded/72/custom DPI choices for image imports; export all images; OCR (searchable image for pages, ranges and multiple files); single-sided cut-and-stack imposition with cut marks, through Print and doc_print; Create PDF from multiple files (PDFs, images and text, edited as pages in the grid). Missing: OCR languages beyond Latin, editable-text OCR output, Office export/import, web printing |
|
||||
| M10 | OCR, create, export, print | 200–350 | 33% | 120–215 | Done: create from blank/text/PNG/JPEG/TIFF (multi-page)/GIF/BMP; export PNG/JPEG/TIFF and text; Print (Acrobat's sizing, n-up, booklet, poster, comments & forms, preview, the CUPS and Windows spoolers, print-ready PDF).<br>Done since: embedded/72/custom DPI choices for image imports; export all images; OCR (searchable image for pages, ranges and multiple files); single-sided cut-and-stack imposition with cut marks, through Print and doc_print; architectural/ANSI/large ISO sheet presets, Match page at 100% and PDF-scale preview (#599 follow-up); Create PDF from multiple files (PDFs, images and text, edited as pages in the grid). Missing: OCR languages beyond Latin, editable-text OCR output, Office export/import, web printing |
|
||||
| M11 | Optimize, preflight, PDF/A/X/UA, print production | 200–350 | 18% | 80–140 | Done: new `optimize` crate: Reduce File Size and the PDF Optimizer (images measured where drawn, bicubic downsampling, JPEG/ZIP recompression only when smaller, discard objects and user data, Flate clean-up, resource merging, object streams). Missing: fonts and transparency panels, space audit, preflight, PDF/A/X/UA |
|
||||
| M12 | Accessibility, compare, measure, search, XFA | 200–380 | 30% | 90–160 | Done: new `a11y` crate with the Accessibility Checker (all 32 rules, report, Fix/Skip/Explain, options dialog and results panel, agent tools).<br>Done since: 2D distance, perimeter and area measurements with persistent viewport calibration, snapping, live information and CSV export. Missing: autotag, Tags/Order/Content panels, Reading Order tool, alt-text workflow, compare, geospatial/3D measurement, search index, XFA |
|
||||
| M13 | Automation (MCP, Action Wizard, CLI) + AI providers | 60–120 | 45% | 25–45 | Done: MCP resources (document info, text, page images); headless tool table (123 tools incl. signing, optimizing, initial view, links, stamps, data exchange, comment review, forms authoring and scripts, redaction, sanitize, print, add content), opt-in MCP server over stdio, CLI `run`/`tools` (closed stdout pipes exit cleanly), UI control channel with drag. Missing: Action Wizard, AI providers<br>Done since: CLI run and MCP reject missing, empty, repeated and option-valued --root arguments before any tool/script execution or MCP initialization. A single-hyphen directory name remains valid; synthetic CLI regressions preserve a would-be overwritten file. |
|
||||
|
||||
@@ -7938,8 +7938,8 @@ milestone = "M10"
|
||||
status = "shipped"
|
||||
commands = ["print.dialog"]
|
||||
tools = ["doc_print"]
|
||||
evidence = ["crates/print/src/tests.rs::size_modes"]
|
||||
notes = "fit, actual size, shrink oversized, custom %"
|
||||
evidence = ["crates/print/src/tests.rs::size_modes", "crates/print/src/tests.rs::architectural_sheets_preserve_full_scale", "crates/automation/tests/automation.rs::architectural_and_iso_papers_through_tools", "crates/ui-egui/tests/print.rs::architectural_page_can_be_matched_at_100_percent"]
|
||||
notes = "fit, actual size, shrink oversized, custom %; ARCH A/B/C/D/E1/E, ANSI C/D/E, ISO A0/A1/A2 presets; Match page at 100% matches the current page to a standard sheet. PDF scale shows the previewed source-to-sheet transform, not calibrated physical output; driver substitution/scaling remains possible"
|
||||
|
||||
[[feature]]
|
||||
id = "print.paper-source-by-size"
|
||||
@@ -8010,7 +8010,7 @@ milestone = "M10"
|
||||
status = "shipped"
|
||||
commands = ["print.dialog"]
|
||||
tools = ["doc_print"]
|
||||
evidence = ["crates/print/src/tests.rs::size_modes"]
|
||||
evidence = ["crates/print/src/tests.rs::size_modes", "crates/print/src/tests.rs::architectural_sheets_preserve_full_scale", "crates/automation/tests/automation.rs::architectural_and_iso_papers_through_tools", "crates/ui-egui/tests/print.rs::architectural_page_can_be_matched_at_100_percent"]
|
||||
notes = "auto portrait/landscape"
|
||||
|
||||
[[feature]]
|
||||
|
||||
Reference in new issue
Block a user