Commit Graph
4058 Commits
Author SHA1 Message Date
mmmaarian03-cryptoandClaude Opus 5.5 e9a5f9ca05 OCR: a recognizer panic or a dead worker ends the run (#3919)
Recognize text (one document) and Recognize text in multiple files ran
their worker unguarded. A panic in the recognizer (third-party inference)
or a worker that died holding the progress lock left the run in place: the
progress notice stayed, and every later run was refused with "Text
recognition is already running" until restart.

- Both workers run inside `pdfcraft_engine::guard`; a panic becomes the
  run's error ("Recognize text failed: …", in the UI's language).
- `poll_ocr` treats a poisoned progress lock as a failure: it clears the
  run or batch and says so.

The batch's loop moved unchanged into `recognize_files` so it can run
inside the guard. A thread that can't be spawned is #1871's (#1819), and
Export and the Action Wizard are #4043's; this leaves both alone.

Tests (crates/ui-egui/src/ocr_ui.rs): a panicking recognizer ends with
the error; a page run and a batch whose worker died holding the lock are
cleared with a notice. Both fail without the change. The OCR integration
tests pass with the real models (PDFCRAFT_MODELS).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 08:56:53 +03:00
Combiler01 1b31708e32 i18n(ui): add translations for image arrange and crop menu literals across all catalogs 2026-10-23 11:25:15 +05:30
Combiler01 3cc55a00a9 chore(assets): update translation catalogue sha256 hashes in ATTRIBUTION.toml 2026-10-23 11:14:04 +05:30
Combiler01 91c575b1df Merge remote-tracking branch 'upstream/main'
# Conflicts:
#	crates/edit/src/images.rs
#	crates/engine/src/tests.rs
#	crates/xfa/src/script.rs
2026-10-23 11:08:12 +05:30
RiceDee 950715da0d test(ui): the narrow-box tests check the text reaches the box's right edge 2026-10-23 16:23:53 +11:00
RiceDee 6c8fd74ca1 fix(ui): an unchanged added-text box closes without an edit
Finishing a box trimmed its text before comparing it with the item, so
an unchanged box whose text was saved with trailing spaces finished as
an edit. Before an Undo or Redo step that edit was applied, clearing
the document's Redo. A box matching its item is now no edit.
2026-10-23 16:14:01 +11:00
Combiler01 2a9f7eb862 Fixes suggested by Reviewers 2 2026-10-23 10:28:47 +05:30
RiceDee 188341c667 test(ui): the Redo test checks Undo restores the exact paragraph text 2026-10-23 15:55:09 +11:00
mtlcl410andClaude Opus 5.5 fa146bbecd fix(forms): filling a field also stores inline /DR fonts as objects (#3441)
Review follow-up (CodeRabbit on #3488): a form an earlier PdfCraft made
should work in Acrobat once it has been filled here too, not only once a
field is added or edited. set_value now runs the same conversion (shared
with ensure_form through inline_fonts_as_objects and store_form_fonts);
it adds nothing, only changes where the existing fonts are stored.

Not in a form a signature covers (a signature field with /V): there the
file stays as the signer saw it apart from the value. PdfCraft's own
change check counts a /DR change after a form-fill certification as form
fill, but another validator may not.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 12:38:36 +08:00
mtlcl410andClaude Opus 5.5 941077715a fix(forms): write each /DR font as its own object, so Acrobat keeps typed text (#3441)
A text field PdfCraft added showed its typed text in Acrobat only while
the field had focus: as soon as the user clicked elsewhere the text
vanished (it was still stored, and printed). PDF-XChange Editor and
PDFgear were fine, and the same field made by MuPDF was fine in Acrobat.

Bisected in Acrobat with one-change variants of the same file: only the
variants whose /DR fonts are objects (or that have no /DR) keep the text.
The appearance stream's own fonts, /P, the appearance layout and /DA 0
made no difference. PdfCraft wrote Helv, TiRo and Cour inline in /DR.

ensure_form now adds them as objects, and turns fonts an earlier save
wrote inline into objects too (same dictionaries). An indirect /DR or
/Font stays the object it is. The XFA-to-AcroForm writer does the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 12:38:36 +08:00
RiceDee b1795b9d7b fix(ui): a narrow added-text box keeps its text at its own edge
The editor is at least 60 points wide on screen, so a short box can be
clicked into. With the box's alignment applied, right-aligned or centred
text in a box narrower than that was placed against the wider editor's
edge, past the box's right edge. The editor now reaches past a narrow
box away from the edge its text keeps, so the text stays where the page
draws it.
2026-10-23 15:23:58 +11:00
RiceDee cac63cf3db fix(ui): Redo after Undo in a page text box puts the typing back
With typing undone in a paragraph or added text box, its text matches
the page again, so Undo and Redo went to the document. Redo then closed
the box and redid a document change (or nothing), instead of putting the
typing back as the box's own Redo did before. And Shift+Cmd+Z is also
Cmd+Z to the Undo shortcut, so even a Redo the box kept was taken as a
document Undo.

Redo stays with the box while its own history has typing to put back
(the test egui makes when it handles the key), and Shift+Cmd+Z is never
a document Undo.
2026-10-23 15:05:23 +11:00
Eric Kaden 8f82bfccec Merge remote-tracking branch 'upstream/main' into fix/exec-menu-attachments
# Conflicts:
#	crates/engine/src/tests.rs
2026-10-22 23:09:22 -04:00
RiceDee 663368b38d fix(ui): the added-text editor keeps the box's alignment
Opening a centred or right-aligned Add text box drew its text at the left
edge, a layout the box never had, and Ctrl+Z inside the box (which goes to
the text, not the document) left it showing that way. The editor now lays
the text out with the box's alignment. Justified text is still shown
left-aligned while editing (TextEdit can't justify).
2026-10-23 14:05:20 +11:00
RiceDee 2842eeaa71 fix(ui): Ctrl+Z in an open paragraph undoes the document, not stale text
Ctrl+Z is left to a focused text field, so in the paragraph editor it
went to the box's own Undo history. That history still held the
paragraph's text from before the last formatting change, so Ctrl+Z put
it back into a box laid out for the page after the change, a layout
the page never had, and the document kept the change. The box shared
its id across paragraphs too, so it could put back another paragraph's
text.

The history of the paragraph editor and the added-text box now starts
at what the page has. Undo and Redo keep the keys only while the box
holds typing the page doesn't have; then they reach the document. An
open box is applied (as clicking away applies it) and closed before an
Undo or Redo step, so it never shows a state the document has left;
text it can't apply keeps it open and stops the step.
2026-10-23 14:05:20 +11:00
Marco Arnulfo 5ee279290a M11: PDF Optimizer ▸ Clean Up stores LZW streams with Flate (optimize.flate-unencoded) 2026-10-23 05:03:16 +02:00
Eric Kaden cf2f4ec766 Merge remote-tracking branch 'upstream/main' into fix/xfa-edit-picture-alternatives
# Conflicts:
#	crates/engine/src/tests.rs
2026-10-22 22:55:12 -04:00
Dylan M. Taylor 0dc77fe4ed Merge pull request #4129 from aiongg/fix/coderabbit-c5-forms-misc
fix(xfdf, sign, preflight, engine, forms, measure, annot): bound repeated work in form exchange, preflight and export, and check what imports and time stamps claim
2026-10-22 22:50:29 -04:00
Dylan M. Taylor 5f7b9e241b Merge pull request #4109 from aiongg/fix/coderabbit-a1-audit
fix(audit): find covers the audit missed, bound its work and honour the copy permission
2026-10-22 22:50:24 -04:00
songzhihui addb876297 M2: continue CJK viewer fallback for Windows GBK PDFs 2026-10-23 10:49:08 +08:00
Dylan M. Taylor 7fa38de186 Merge pull request #4170 from dylanmtaylor/fix/sonar-shell-scripts
fix(packaging): use [[ tests and name positional parameters (SonarCloud shelldre:S7688, S7679, S7682, S131)
2026-10-22 22:48:47 -04:00
Dylan M. Taylor 1d29f0673c Merge pull request #4169 from dylanmtaylor/chore/sonar-scope-vendor-and-spec-hashes
chore(sonar): exclude vendored crates and the spec-mandated MD5/RIPEMD-160 (SonarCloud rust:S4790)
2026-10-22 22:48:42 -04:00
mtlcl410andClaude Opus 5.5 1f4b49ebd7 M6: a typed field name loses its ends but keeps spaces beside periods (#2696)
Review on #2957, point 1. Both entry points already trim the whole name
before splitting it, and a space beside a period stays in its part,
which matches black-box observation of Acrobat and ISO 32000-2 12.7.4.2
(only a period is barred from a partial name). The test pins that down;
three mutants (no trim in add_field, no trim in set_props, untrimmed
empty-part check) each fail it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 10:45:14 +08:00
mtlcl410andClaude Opus 5.5 5e4ca789b8 M6: note why a dotted move that fails half way never reaches the document; the parity note says the table tool still refuses periods (#2696)
Review on #2957 (benandez, points 2 and 3).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 10:45:14 +08:00
mtlcl410andClaude Opus 5.5 601d7afe60 M6: a dotted rename's calculations follow the field (#2696)
main now renames a field in the calculations that read it. After rebasing,
that runs for a dotted name too, which moves the field under new parents: the
sum and the script that read `a` read `Group.a`, and still compute after a
save and reopen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 10:45:14 +08:00
mtlcl410andClaude Opus 5.5 5f8e573e04 M6: a refused move doesn't copy inherited values onto the field first (#2696)
Review on #2957: own_inherited wrote what the field inherits onto it before
check_place could refuse the move, so a refused move still changed the field.
What it inherits is now read first, counted as its own by the check, and
written only once the move is allowed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 10:45:14 +08:00
mtlcl410andClaude Opus 5.5 a77c47bea3 M6: a move the destination refuses leaves the field in place (#2696)
Review on #2957: set_props took the field out of the tree before attach
checked the destination, so a refused move (a parent holding /MaxLen, say)
left it out of /Fields for a direct caller of the forms API. The read-only
check is now its own function, run before the field is detached.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 10:45:14 +08:00
mtlcl410andClaude Opus 5.5 224a64e3d0 M6: a dotted name checks the place it goes: an empty parent's name, a parent's value (#2696)
Review on #2957. The field list holds only terminal fields, so a parent
left empty by a move wasn't seen and a second field of its name could be
made beside it, by adding or by renaming. And a new field joining a parent
that holds /V, /DV or /MaxLen inherited them, with no neutral value of its
own to turn them off: such a parent now takes no field that doesn't hold
its own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 10:45:14 +08:00
mtlcl410andClaude Opus 5.5 f41abf921f M6: dotted field names make parent fields (#2696)
A field's own (partial) name can't contain a period (ISO 32000-2
§12.7.4.2), so Prepare a form refused MASTER.first. Acrobat reads such a
name as a full name: the field `first` under a parent field `MASTER`.

- add_field: a dotted name makes or joins the parent fields it names.
- set_props: a dotted name is the full name and moves the field there,
  copying what it inherited onto it first; a plain name still renames
  the field within its parent. Either way the new full name may not be
  taken by, or hold or sit inside, another field.
- A field joining an existing parent doesn't take its Ff or Q.
- Field Properties and the Prepare a form name tags show the full name
  instead of the last part.
- Names are capped at 32 parts; empty parts are refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 10:45:13 +08:00
Dylan M. Taylor e93f11e81e fix(packaging): use [[ tests and name positional parameters in the scripts (SonarCloud shelldre:S7688, S7679, S7682, S131)
Every packaging script runs under bash, so [[ ]] is available. Name the positional
parameters of sha256, render and has, end env.sh's functions with an explicit return
(bare, so the exit status is unchanged), and give the build-label case a default arm.
2026-10-22 22:40:05 -04:00
Dylan M. Taylor bd9030b271 chore(sonar): exclude vendored crates and the spec-mandated MD5/RIPEMD-160 (SonarCloud rust:S4790)
vendor/ is third-party code kept close to upstream (vendor/README.md), so SonarCloud's
186 findings there are not ours to restyle. MD5 in crates/crypt is what ISO 32000's
standard security handler mandates, and RIPEMD-160 in crates/sign is a digest existing
signatures can name; both S4790 findings are scoped to those two files.
2026-10-22 22:36:03 -04:00
Dylan M. Taylor 7345e5f5de Merge main into fix/coderabbit-a1-audit
Keep this branch's budgeted audit() and read lines with main's
glyph_text_lines, so /ActualText cannot hide text under a cover.
2026-10-22 22:20:45 -04:00
Eric Kaden dd6d7feadb M12: a date is tried in the field's first pattern again only when its format refused it 2026-10-22 22:18:11 -04:00
Dylan M. Taylor 07a9109fed Merge remote-tracking branch 'origin/main' into HEAD 2026-10-22 22:07:20 -04:00
Dylan M. Taylor 93b25f67a6 Merge main into fix/coderabbit-c5-forms-misc
Keep the Ops iterator from this branch and carry main's long-number skip
(MAX_RETRIED_TOKEN) into its operand error path.
2026-10-22 22:07:19 -04:00
Dylan M. Taylor de91632934 Merge pull request #4151 from aiongg/fix/coderabbit-c2-edit-organize
fix(edit,organize,create): bound the work hostile files cause in editing, page organizing and image import
2026-10-22 21:57:13 -04:00
Eric Kaden 91df3c01a8 Merge remote-tracking branch 'upstream/main' into fix/xfa-edit-picture-alternatives
# Conflicts:
#	crates/xfa/src/tests.rs
2026-10-22 21:54:56 -04:00
Dylan M. Taylor 684226713a Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	crates/audit/src/tests.rs
2026-10-22 21:42:41 -04:00
Dylan M. Taylor d31a96f46f Merge pull request #4121 from aiongg/fix/coderabbit-c1-js-xfa
fix(js, xfa): bound the text and work that form scripts and XFA data can multiply
2026-10-22 21:39:08 -04:00
Dylan M. Taylor 8ee1ac0c58 Merge pull request #4117 from aiongg/fix/coderabbit-b-caps
fix(limits): bound the decoding and listing work that repeated references and small inputs multiply
2026-10-22 21:38:59 -04:00
Dylan M. Taylor 3cee9f338f Merge pull request #4128 from aiongg/fix/coderabbit-c4-core
fix(cos, content, filters, crypt, model, render, print, a11y): bound the work that repeated keys, streams and page values multiply
2026-10-22 21:38:37 -04:00
Dylan M. Taylor f7a3a52fad Merge pull request #4114 from aiongg/fix/coderabbit-b-shared
fix(cos): one decode budget per page walk, so repeated stream references cannot multiply decoding
2026-10-22 21:38:15 -04:00
Juan Jurado 635b42d989 M10: ARCH E1 goes out as PWG 5101.1's na_wide-format_30x42in (#3752)
30 x 42 in is `na_wide-format_30x42in` in PWG 5101.1-2023 and the IANA
IPP registry (checked against both). `na_arch-e1_30x42in` was asked for
on the IPP list in 2021 but never registered. CUPS maps the new name to
the PPD's 30 x 42 in size (cupsfilter, synthetic PPD), and the paper
test pins it and fails on the old name.

Doc comments for bad, printers and two paper tests, for the review's
docstring check.

Review: storytold/pdfcraft#4161 (CodeRabbit).
2026-10-22 18:42:49 -06:00
Juan Jurado 7594713937 M10: spell the ARCH media names as PWG 5101.1 does (#3752)
ARCH A-E went out as arch_a_9x12in .. arch_e_36x48in; PWG 5101.1 names
them na_arch-a_9x12in .. na_arch-e_36x48in (ARCH E1's IANA-registered
na_arch-e1_30x42in already had the prefix). CUPS parses either from the
dimensions, which is why the cupsfilter check passed, but a driverless
printer may accept only the names it advertises. Re-checked the corrected
names with cupsfilter against the synthetic PPD.

The paper test now pins every size's exact name, and fails on the old
spelling. Doc comments for doc_print and PrintDraft::job.

Review: storytold/pdfcraft#4161 (CodeRabbit).
2026-10-22 18:24:54 -06:00
Juan Jurado 5f042c691f M10: every paper size reaches the printer, from the dialog and doc_print (#3752)
A CUPS job that names no paper gets the queue's PPD default (A4 on the
reporter's Xerox queue), whatever the sheets were laid out on. Two gaps
remained after #1583:

- cups_media had no name for 13 of the 21 PAPERS sizes (A6, ARCH A-E1,
  ANSI C-E, A0-A2), so the Print dialog sent no media for them. They now
  use PWG 5101.1 names (the IANA-registered na_arch-e1_30x42in for ARCH
  E1), which carry their dimensions: CUPS feeds the driver's size of those
  dimensions whatever the driver calls it, and driverless IPP printers use
  them natively. Checked with cupsfilter against a synthetic PPD whose
  sizes use vendor keywords (ARCHD, AnsiD, A0...): each name produced its
  size's bounding box. The 8 sizes that already worked keep their PPD
  keywords.
- doc_print to a printer (CLI run, MCP) sent no paper at all. It now
  resolves the paper to its PAPERS index and sends the same media option
  as the dialog, after the driver options. The job is built in spool_job
  so it can be tested without printing.

print::media_option is the one place both get the option from. Both new
tests were seen failing without the fix. The macOS tray half of #3752
(Auto Select instead of the PPD's default tray) is a craft-print change.
2026-10-22 18:06:49 -06:00
Brandon ThomasandClaude Opus 5.5 53199fb4fa Release 0.13.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v0.13.0
2026-10-22 20:06:13 -04:00
aiongg ba024eb0dd fix(edit): flatten on a copy so a page refused part way changes nothing 2026-10-23 00:02:33 +00:00
SBaksa e37fd27619 Merge remote-tracking branch 'origin/main' into select-all-document
# Conflicts:
#	parity/acrobat-features.toml
2026-10-23 10:52:08 +11:00
aiongg 0d216199b9 fix(redact): apply redactions on a copy so a failure leaves the document as it was 2026-10-22 23:40:55 +00:00
aiongg 2430d53f9e fix(print): read the text after a form the budget refuses 2026-10-22 23:37:07 +00:00