Commit Graph
748 Commits
Author SHA1 Message Date
Combiler01 035183777a fix:implement 8 point non destructive crop, image resize and Arrange extraction bugs 2026-10-16 21:24:49 +05:30
aiongg 934a10740d Merge track r1-core (fredapps-r1)
ROADMAP.md, docs/roadmap.md: keep next's status line
2026-10-16 14:17:52 +00:00
aiongg 405ad489c2 Merge PR #2681: Replace Text: give the caret its own /NM (#2666) 2026-10-16 14:02:08 +00:00
aiongg eb403f84ec Merge PR #2702: Remove security also from files with /Encrypt inline in the trailer 2026-10-16 14:02:08 +00:00
mixlnwuu d5bbf60efe i18n: add Thai (th) interface language
A clean-room Thai catalog covering every key the bundled catalogs translate, its LANGUAGES row (one plural form) and Thai month and weekday names in DATE_LANGUAGES.
2026-10-16 19:22:00 +07:00
mtlcl410andClaude Opus 5.5 b97e59190f M5: year-first slash dates (yyyy/mm/dd, yyyy/m/d) for Fill & Sign and headers
Taiwan, Japan and China write dates year first with slashes (Windows'
zh-TW short date is yyyy/M/d), and neither the Fill & Sign presets nor
the header and footer date tokens offered it. Both now have yyyy/mm/dd
and yyyy/m/d. The header and footer list gains them at its end, since
its selection is an index.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz
2026-10-16 19:20:48 +08:00
boneylandandClaude Opus 5.5 bf2eb470ed M6: detected form fields get no border or fill
Prepare a form ▸ Detect form fields places each field on a line or box the
page already draws, but every new widget got a grey /MK /BC and an opaque
white /MK /BG, so the fill hid the printed form underneath. Detected fields
now clear both in the same undoable step; fields drawn by hand keep the
defaults.

Refs #294, #2831.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 18:59:09 +08:00
alehelandClaude Opus 5.5 a9b0db12c6 fix(edit): show backgrounds on pages that paint their own white backdrop
Add Background draws behind the page content, so on a page that first
fills itself with opaque white (browsers' Save as PDF, print drivers) the
background was hidden completely and the tool looked broken.

- pdfcraft-edit: new `backdrop` module. A strictly detected backdrop (one
  axis-aligned `re`, opaque white in a device colour space, painted before
  anything else and covering the crop box) is replaced by turning that one
  fill into `n` in a per-page copy of its stream; the original stream is
  left untouched for other pages. Remove background restores it, unless
  the copy was edited since. Page-sized pictures (scans) are reported only.
- Background gains `replace_backdrop` (default on); the default colour is
  a visible light yellow instead of near-white.
- Dialog: offers to replace the backdrop, warns about scanned pages,
  checks pages a few per frame, preview draws text over the colour.
- Automation: `doc_background` takes `replace_backdrop`; new read-only
  `doc_backdrops` lists pages with a backdrop.

Acrobat's behaviour on such pages is unobserved; recorded as our choice
in parity/.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 10:46:02 +02:00
Enrico SitaandClaude Opus 5.5 26051871d0 M11: remove PDF/A or PDF/X identification (optimize.remove-standards-id)
A file edited after it was made PDF/A or PDF/X can keep claiming a
standard it no longer meets. organize::remove_standard_id removes the
claim: the pdfaid: XMP properties for PDF/A, or GTS_PDFXVersion and
GTS_PDFXConformance in the document information and as pdfxid: XMP
properties for PDF/X. Output intents and other claims (PDF/UA) stay.

The XMP is edited with the packet editor Document Properties already
uses (sync_info and the new remove_properties share its read and write),
so the rest of the packet stays byte for byte and unsafe packets are left
alone. It is one undoable edit, in Standards ▸ PDF/A as a button worded
like its undo label, and the standards_remove_id tool (pdfa or pdfx).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 09:45:31 +02:00
PerchAnton f79ab9ae2d M12: update viewer-warning PR against main (#2589) 2026-10-16 07:48:00 +03:00
PerchAnton d78df1f163 M12: update growable-field PR against main (#2569) 2026-10-16 07:44:37 +03:00
PerchAnton 4d0f2e4dde M12: update print-button PR against main (#2572) 2026-10-16 07:41:57 +03:00
Osvaldo DuranandClaude Opus 5.5 e5c2ea2bff Merge upstream main 5fdd820b into pr/attachments
Conflicts: ATTRIBUTION.toml, crates/ui-egui/src/i18n/es.tsv, crates/ui-egui/src/i18n/vi.tsv. Catalogs keep upstream's rows, then this branch's rows upstream lacks; ATTRIBUTION.toml is upstream's with every sha256 recomputed; progress lines keep both sides, upstream's first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 21:31:50 -04:00
alehel 8f0b36d66e Merge remote-tracking branch 'origin/main' into feat/all-tools-expand-view
# Conflicts:
#	ATTRIBUTION.toml
#	crates/ui-egui/src/i18n/es.tsv
2026-10-16 03:25:54 +02:00
Chiranjeevi Uandskylar taylor-barrick 5fdd820bdb fix(ui): validated signature display, snapshot tab reuse (#1895)
* fix(ui): validated signature display, snapshot tab reuse

Signature widgets with layered appearances baked the unverified state
into the page, so a valid signature kept reading 'Signature Not Verified'
while the banner and panel said valid. Validated verdicts are now drawn
into the icon and caption layers in the display copy only: the signed
bytes are untouched, saving keeps the original appearance, and files
without those layers or without a valid verdict render exactly as before.

Other valid signatures still get the verdict mark over their widget,
sharing one style with the Signatures panel, and hide it again once the
appearance itself shows the verdict.

View signed version and View revision opened a new tab on every click,
and every tab showed the document title, so repeats piled up identical
tabs. Repeats now reuse the snapshot tab, snapshot tabs read like their
source plus the suffix in the tab strip, window title and Combine picker,
and carry a notice bar naming the revision with a Close that asks about
saving first.

Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com>

* Address review comments on validated appearances and trust refresh

Count every field when checking shared appearance streams, so a
caption shared with an unvalidated field is never rewritten for the
valid one alone.

Pick the icon slot by drawing instead of length, and only when a
single layer qualifies. Bare rectangles never count as the icon, and
ambiguous or missing slots fall back to the overlay badge.

Revalidate and invalidate together through one helper, so trusting a
certificate always drops rendered pages. Trust alone still marks
nothing dirty.

Tests: mixed-verdict sharing, longer decorative borders, competing
and doubled layers, capture-before preservation, trust invalidation
without zooming, and signed Session round trips with rendering,
saving and passwords.

Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com>

* Prove the icon slot geometrically and cover real layered signatures

A lone line drawing is still not the icon: frames and borders span the
box while the status mark lives in a corner of it. The icon now has to
sit strictly inside the appearance frame and cover at most half of it;
anything else falls back to the overlay badge. Widgets without a
measurable frame veto the rewrite the same way.

Tests: parsed extents and inhabitant checks as units, both reported
border repros plus a frameless widget, and real layered signatures
built with cms::sign_detached through Session open, trust, rendering,
save and reopen, plain and password-protected.

Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com>

* Identify the icon by shape instead of geometry

A lone line drawing is still not the icon, but size and position were
the wrong signals: the real status mark is large, and geometry blocked
it. Frames, borders and panels are rectangles by nature while the mark
is not, so a drawing made only of axis-aligned rectangles is decoration
however it is stroked. Singularity, shared-stream and template checks
are unchanged; anything ambiguous still falls back to the overlay badge.

Tests: rectangularity as a unit, nested line-drawn frames, and a
triangular fixture mark in place of the rectangular one.

Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com>

* Budget the appearance walk and keep the marks with the bytes

The walk that finds a signature's icon and caption capped depth,
layers and fields, but not the work: a dictionary whose entries all
point at the next one is visited once per entry per level, so a small
hostile file never finishes opening. The walk now counts its visits
and gives up, and a field whose tree cannot be read to the end stops
the whole pass, because a layer we never read may be the one two
fields share and a rewritten shared layer puts one field's verdict on
another field's page. The sharing count is exact again with that: two
widgets of one field pointing at the same appearance claim it once,
or the field vetoes its own rewrite.

A mark used to outlive the bytes it described. A failed display write
left the page showing the file's own caption while the verdict still
claimed its state was drawn; a metadata edit dropped the mark while
the page kept drawing the state, so the badge landed on top of it. The
write fallback now drops the marks and logs the loss, and metadata
carries them over.

Tests: a self-referential appearance tree, which never finished before
the budget, two widgets sharing one appearance, a metadata edit that
keeps its mark, a save that goes through the writer instead of
short-circuiting on the opened file, and the snapshot bar's Close
button pressed for real.

Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com>

* Cite the new regressions in parity, restore main's installer note

The appearance entry now cites the bounded walk and the save through
the writer, and says what a tree that cannot be read to the end does.
The installer entry carried main's older text, which still claims
signed installers are planned; main's newer note is taken verbatim.

Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com>

* M9: preserve rounded decoration beside raster status glyphs

* M9: place appearance progress beside signature history

* M9: retain appearances with ambiguous curved layers

* M9: keep signature verdicts in viewer overlays

Defer generic appearance rewriting: caption text and a unique drawing do not establish an icon role. Preserve original artwork for saves, image and text exports, and both print modes while retaining snapshot reuse and trust refresh. Cover chamfered borders and mixed signer/caption streams through signed Session round trips.

---------

Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com>
Co-authored-by: skylar taylor-barrick <hi@skylar.cc>
2026-10-15 19:16:48 -06:00
FredApps a5ef6b76e8 Wake idle windows for pending recovery snapshots (#2663) 2026-10-16 02:17:12 +02:00
Marco Arnulfo bb651792a9 Remove security also from files with /Encrypt inline in the trailer (fixes #2661) 2026-10-16 00:33:39 +02:00
vangel76andClaude Sonnet 5.5 0871543fd8 M7: rotate an existing page image by any angle (#1940)
A selected image gets a rotate knob (Shift: 15 degree steps); image_edit
gains rotate_by (degrees). The turn is one extra cm about the visible centre.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 23:14:59 +02:00
Muhammad Saad c9956bf77f Replace Text: give the caret its own /NM (#2666)
add_text_replacement built the StrikeOut and the Caret from one Meta, and
add_annotation stamps /NM from meta.id, so the pair shared a single name. XFDF
names a reply by the /NM of what it replies to, so the exporter wrote the
caret's inreplyto as the caret's own name. Importing that file found a comment
replying to itself, and the Replace Text comment did not arrive: the reporter's
second document listed none. FDF was unaffected because it keeps the pair by
object structure rather than by name.

Take a second Meta for the caret. The ids stay supplied by the caller, as the
rest of the crate does so edits remain deterministic, and the one production
caller already has a generator and calls it twice. /IRT still points at the
strikeout, so the group still moves, lists and deletes as one.

Tests: the annotation test now asserts the two carry different names and that
the caret's /IRT resolves to the strikeout's. A new XFDF test exports a Replace
Text pair and imports it into another document, asserting both comments arrive
with their thread intact; it fails if the two are given one id again.
2026-10-16 00:34:21 +04:00
PerchAnton ff62683ff8 M12: skip PDF container scripts during active XFA layout (#2589) 2026-10-15 22:18:58 +03:00
PerchAnton 97d286b2b9 M12: reflow growable XFA text after form edits (#2569) 2026-10-15 20:33:03 +03:00
PerchAnton f06bebd520 M12: dispatch repeated XFA print buttons by their own field (#2572) 2026-10-15 20:08:05 +03:00
Guillem VelaandClaude Sonnet 5.5 aad803caae M14: add Catalan interface and date localization
Register Catalan (`ca`) as an interface and date language with a
2,592-entry contributor-original catalog written from the meaning of the
English labels. Plurals use the one/other rule; every `ca-*` locale,
including Valencian (`ca_ES@valencia`), resolves to this catalog.

Tests cover registration and persistence, every command, menu, tool group
and section, every `tl!` literal in the UI source, and every key in the
other bundled catalogs. The Latin-script glyph test in tests/fonts.rs now
includes Catalan (the interpunct of l·l is covered by the bundled faces).

Catalan dates elide the preposition before a vowel (7 de març, 7 d'abril,
8 d'octubre), so the date language sets months_with_day, as Czech and Russian
do; a unit test pins it.

Update localization docs, the parity table and the roadmap log, and add the
ATTRIBUTION.toml entry (ATTRIBUTION.md regenerated). The contributor, a
native Catalan speaker, has reviewed the translation.

Validation: cargo fmt --check; clippy -D warnings and tests on
pdfcraft-ui-egui (i18n, fonts); pdfcraft-engine dates tests;
cargo xtask assets; cargo xtask layers.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 16:51:02 +02:00
Combiler01 b31e6b49db merge: reconcile upstream/main with local changes 2026-10-15 19:36:23 +05:30
Osvaldo Duran e46cc70d73 Merge main (afa8e184) into pr/attachments 2026-10-15 07:59:50 -04:00
Philip 0c06186486 Merge remote-tracking branch 'origin/main' into feat/edit-scanned-page-offers-ocr
# Conflicts:
#	ROADMAP.md
2026-10-15 10:31:33 +01:00
alehelandClaude Opus 5.5 3ec7ce8aae M3: All tools expands to a full, searchable view
An expand button at the top-left of the All tools sidebar opens a view that
fills the workspace, like Acrobat's tools page: every tool as a tile, filed
under five categories (Create & Edit, Review & Compare, Forms & Signatures,
Protect & Standardize, Customize & Automate), with a search field that matches
tool names and the items inside each tool, in English or the UI language.
Choosing a tile opens that tool's panel; Collapse, Esc or another workspace
puts the view away. `--tools full` opens it from the command line and the
control channel.

The categories live in the engine catalogue (TOOL_CATEGORIES), with a test
that every tool group is in exactly one. Six new strings are translated in
all 22 catalogues.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 10:41:14 +02:00
cccd55fab2 M1: edit finds the pages a damaged file's readers find (#1664)
* M1: edit finds the pages a damaged file's readers find (fixes #1656)

* M1: rebuild a lost page tree only when the reader shows the same pages, and refuse edits to signed rebuilt files (#1656)

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 04:01:45 -04:00
fcd72747cd M6: make list boxes directly selectable and scroll to selection (#1524) (#1543)
* M6: make list boxes directly selectable and scroll to selection (#1524)

- In-place selection: List boxes are rendered directly on the page and
  selectable in place. Clicking an option row selects it immediately;
  Ctrl/Cmd-clicking toggles items in multi-select lists, and Shift-clicking
  selects ranges, without opening a popup menu.
- Appearance and scroll (/TI): When options are selected, /TI (top index)
  is automatically adjusted so the selected items are scrolled into view
  within the widget's visible rows, and option rows and selection highlights
  are drawn into the appearance stream.
- Unit and UI tests: Added tests in pdfcraft-forms verifying /TI scrolling
  and appearance generation for multi-select lists, and UI tests in
  pdfcraft-ui-egui covering in-place click and Ctrl-click toggling.
  Also ensured test harness in reload.rs explicitly sets language to en.

Fixes #1524

* List boxes: keep the engine's page appearance, consume arrow keys

Drop the overpaint of every fillable list box with an egui mock (it ignored the
PDF's fonts, colours and /MK /R; the engine redraws the appearance with the new
/TI), and consume ArrowUp/ArrowDown in the list overlay so they don't also
scroll the page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 03:52:55 -04:00
d1bc200115 M7: grow text boxes and edit existing text (#1539)
* M7: grow text boxes and edit existing text

Text boxes now grow to the page edge and vertically as needed, retaining their size when saved. Clicking native or added text in either text tool edits the existing item instead of layering a duplicate over it.\n\nCo-authored-by: OpenAI gpt-6.1-sol <noreply@openai.com>

* #1539: build against main's Document::added() accessor and draft-aware prepare

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 03:52:33 -04:00
b7976ef40e M12: show structure tag content (#1496)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 03:38:35 -04:00
980bd90087 Print: 4 x 6 in label paper and a Label layout for shipping labels (#1583)
* Print: 4 x 6 in label paper and a Label layout for shipping labels

Thermal label printers (e.g. VEVOR Y486) could not be used for eBay/carrier
labels: the paper list had no 4 x 6 in size, the chosen paper was never sent
to CUPS (the queue's default was used), and labels laid out sideways on a
Letter/A4 sheet printed small or rotated.

- PAPERS gains "4 x 6 in label (101.6 x 152.4 mm)"; cups_media() sends the
  chosen sheet to the spooler as `-o media=` (Letter, Legal, Tabloid, A3-A5
  and w288h432 for the label), so the driver feeds the size the PDF was
  laid out on.
- New Layout::Label: each page is cut to its printed area (a low-resolution
  render, as Fit Visible does), turned a quarter turn when it is sideways in
  the direction that makes its text upright (text_reads_up reads the text
  and form matrices), and fitted uniformly with a small margin. Vector
  content is kept, so barcodes stay sharp and undistorted. "Turn upside
  down" flips it 180 degrees. One label per sheet.
- Choosing the label paper selects the Label layout, and vice versa.
- Strings translated in every bundled catalog.

Tests: label geometry (crop, quarter turns, no stretching, margins),
cups_media, text direction; print, ui-egui and automation unit tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GFXSksdMaJ3YnheY7Q6sTx

* Refresh catalog hashes after merging main

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Alessio Boschi <alessio.boschi@dinova.one>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-15 03:38:06 -04:00
a6124bcdfe M12: find untagged accessibility content (#1463)
* M12: find untagged accessibility content

* i18n: translate untagged content checker (rebased)

* fix(i18n): refresh untagged content translation hashes

* fix(tests): restore full test modules for find-untagged content

* fix(i18n): preserve existing translations after rebase

* ci: rerun shared timeout test

* chore(deps): refresh rust for the advisory gate

Use the current lockfile, including the rustls security update, so the dependency check can run on this branch.

* Refresh catalog hashes after merging main

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 03:33:19 -04:00
afa50999ef M12: tag unstructured AcroForm widgets (#1451)
* M12: tag unstructured AcroForm widgets

* i18n: translate form tag command

* i18n: repair form-field label merges

* fix(i18n): refresh translation catalog hashes

* fix(i18n): preserve main translations after rebase

* Merge main; tag a widget listed on several pages once, docs say existing trees are extended

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Merge main; add the Vietnamese catalog entry for Tag form fields

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 03:24:55 -04:00
Osvaldo Duran 77d9f7509f Merge main (7461c297) into pr/attachments
Conflicts: the language catalogs (both sides' rows kept), ATTRIBUTION.toml's checksums
(recomputed from the merged files), and tests both sides appended at the same place.
Upstream's new Vietnamese catalog gets this change's labels.
2026-10-15 03:20:43 -04:00
416c85579b Perf: defer marker and link index scans until first use (#1434)
* Defer secondary PDF indexes until first use

* Merge main into #1434; read Document::added through the new method in content_ui

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 03:20:32 -04:00
02a4d81a22 Keep selected form values and page content through later edits (#1319, #1305, #1324, #1306) (#1452)
* Keep selected form values and page content through later edits (#1319, #1305, #1324, #1306)

An XFA radio item whose text contains a space was written back as an appearance-state name, so the next layout selected nothing. Replace Pages filled the gap between a split selection. Marking a figure decorative replaced every content stream on the page. Control clicks and drags accepted coordinates that overflow to infinity.

* Move the decorative-figure regression out of pdfcraft-edit

edit and a11y are both layer 4, so a dev-dependency from edit to a11y fails the layer check. The same regression now runs in the engine, which already depends on both.

* Drop pdfcraft-a11y from the edit crate's lockfile entry

* Run a tool after a background open of the file it asked for

A tool chosen with no document opened the picked file on the worker, but only ran when that open finished inside the picker callback. Remember the command on the pending open, and let the command test wait for the worker.

* Wait for background opens in the command tests

Opening a picked file or a recent file finishes on the worker, so a fixed handful of frames can assert before the tab exists.

* Compare batch copies to the PDF that was written

A new text PDF stamps the current second, so a later pdf() call is a different file. The numbered copy and the source must match the bytes that were saved.

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 03:05:21 -04:00
6b185cdc5b Add permission-aware selected-text Copy to Edit and context menus (#1244)
* M3: add selected-text Copy to page and Edit menus (#1225)

Register selected page-text Copy with the existing document permission gate and expose it in Edit and the ordinary page context menu. Route floating Copy through the same gate while preserving focused-input and Organize clipboard ownership.

Four regressions fail behaviorally on the exact base; five candidate regressions pass. All eight cargo xtask ci stages pass: 2575 tests passed, 12 ignored, and 31 WASM crate checks. Native synthetic checks verify Unicode clipboard output, disabled no-selection/restricted actions, and permissions-password unlock using presented Xvfb/Vulkan software-rendered frames. Physical display and hardware GPU coverage are not claimed; the optional cargo-deny audit was unavailable.

Generated with Codex for FredApps.

* Tests: scope GoToR case mutation to Unix for Windows Clippy

Keep the common directory/non-PDF cases immutable. Shadow them in the Unix-only block so FIFO coverage can append its case without an unused-mut warning on Windows. No assertion or platform coverage is removed.

This repairs the exact hosted Windows Clippy failure inherited from upstream. Source review and whitespace checks passed; no local build, test or formatter was run during the pause. Automatically triggered hosted CI will validate this head separately.

Generated with Codex for FredApps.

* Tests: scope document link target mutation to Unix for Windows Clippy

Preserve directory coverage on all native platforms and device coverage on Unix. Static diff, whitespace and conflict checks passed; no local build, test or formatter was run during the pause.

Generated with Codex for FredApps.

* Tests: escape GoToR fixture file paths as PDF literal strings

Windows absolute paths were interpreted as PDF escape sequences, introducing control characters and failing the hosted local GoToR root test. Escape backslashes and parentheses in the fixture helper without changing product behavior or assertions. Static diff and whitespace checks passed; hosted CI will validate the repair. No local builds, tests or formatters ran.

Generated with Codex for FredApps.

* Tests: use ordinary absolute paths in the GoToR fixture

Build the absolute target from the original sandbox base rather than its canonicalized Windows verbatim path. Assert absolute-path form and canonical identity with the sandbox target. Preserve production UNC/device/verbatim rejection and existing containment and destination assertions. Static diff and whitespace checks passed; no local build, test or formatter ran.

Generated with Codex for FredApps.

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 03:00:45 -04:00
Earl Co ad6728bf6c fix(cli): render comments the app renders when /AP is missing (#2371) (#2382) 2026-10-15 02:58:04 -04:00
AlexandBrandon Thomas c4d8c5bb55 feat(automation): bookmarks and links say where on the page they go (#2344)
bookmark_list and link_list add a destination: its type (XYZ, Fit, FitH,
FitV, FitR) and its position in the same top-left points as every rect.
A link through a named destination now gives its page (to_page, named)
instead of only the name.

Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-15 02:56:48 -04:00
6a78a9ce99 fix(engine): give a host with no clock or time zone a real one (Session::with_wall_clock) (#2317)
On wasm32-unknown-unknown the engine has neither a clock (`now()` is empty) nor a time zone
(`local_utc_offset()` is 0), so in a browser Fill & Sign stamps 1 Jan 1970 and `/ModDate` is never
written. The one way to inject a clock, `with_clock`, is a test shortcut: it takes the injected
instant AS local time and zeroes the zone, so a host that injects only that gets either the local
dates or the UTC ones wrong by its offset (21:30 in São Paulo, UTC-3, is already the next day
in UTC).

`Session::with_wall_clock(clock, utc_offset)` keeps the two separate: `clock` is the UTC instant
(what the file records) and `utc_offset` is asked on every use, because the zone changes with
daylight saving. `Automation::with_wall_clock` forwards it. Nothing changes for a native build, or
for `with_clock`.

The test pins the contrast: at 21:30 in São Paulo the stamped day is the 14th, `signing_date`
carries `-03'00'`, the file's instant stays 00:30Z on the 15th, and the plain test clock still
answers the 15th.

Co-authored-by: Paulo Junior <195025778+bonfim6P@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 02:53:57 -04:00
snipeTR 5288946b54 export: zero-pad the page number in Export All Images file names (#2208) (#2295) 2026-10-15 02:53:23 -04:00
3f9cd3b87d M1: every PDF leaves the engine checked, and every writer uses one staging-file writer (#2166) (#2182)
New files from Combine, Extract, Split and Create, signed, timestamped and
LTV-embedded files and the OCR batch output reopen with their pages before
anyone writes them, as saves already did. The desktop app, the automation
tools (with or without --root) and the CLI's edit, combine, extract and
split write through pdfcraft_platform::staging::write_atomically, so a
failed write or --out naming the input never leaves a half-written file.
Special files such as /dev/stdout are still written as given.


Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-15 02:48:09 -04:00
c1146d0d8d feat(ui): improve back and forward page navigation (#2080) (#2151)
Co-authored-by: srt8hellcat2-ui <225485253+srt8hellcat2-ui@users.noreply.github.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-15 02:47:33 -04:00
1af7a38bd0 Fix multi-select choice index ordering (#2144)
* M6: sort multi-select choice indices

Write ascending /I option indices without reordering /V selections.
Add forms and engine regressions for reverse selection and save/reopen.

Co-authored-by: Codex <codex@openai.com>

* M0: update rustls to 0.23.46

Update only the resolved rustls version and registry checksum.
Keep the existing choice-index feature changes and advisory policy.

Co-authored-by: Codex <codex@openai.com>

---------

Co-authored-by: sanyamsingh001 <314051937+sanyamsingh001@users.noreply.github.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-15 02:47:08 -04:00
Marco Arnulfo b008c52291 OCR: Downsample to shrinks a page box given in pixels (fixes #1848) (#2135) 2026-10-15 02:46:44 -04:00
c0f76fc73a M4: set page transitions and display times (/Trans, /Dur) through the engine and the tools (#2083)
* M4: set page transitions and display times (/Trans, /Dur) through the engine and the tools

organize::set_transition writes or removes a page's /Trans dictionary
(only the entries the style reads and that differ from the defaults) and
/Dur, with every value checked before any page changes; Edit::SetTransition
is one undo step ("Set page transitions", translated in every catalogue);
page_transition_set is the tool. The counterpart of reading them (#2074);
playing them and the Organize dialog stay planned.

Refs #379.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz

* Refresh catalog hashes after merging main

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-15 02:42:28 -04:00
Benno Evers d8f32e767c M7: list Edit text & images first under Modify page (#2028)
Edit text & images changes what is already on the page rather than
adding content, so it belongs under Modify page, the first section.
2026-10-15 02:39:27 -04:00
6c22c78a72 Edit: crop an existing page image with its handles (#2002)
* Edit: crop an existing page image with its handles

ImageChange::Crop(rect) keeps the part of a page image inside rect (user space)
with a clipping path placed just inside the scope that holds the image (or a
new q … Q around its Do); a clipping path already at the scope's start, the
picture's earlier crop, is replaced, so a crop can grow back. The pixels are
never scaled, and a later move or resize wraps the scope, so the crop moves
with the picture. ImageEdit::Crop (undo label "Crop image"), image_edit
action crop. In the window, right-click ▸ Crop Image puts the selected
picture in crop mode: eight handles trim (the inside pans), the part that goes
is dimmed, Enter or Done applies, Esc or Cancel leaves; Remove Crop shows the
whole picture again. Rows in every language, their checksums in
ATTRIBUTION.toml, parity edit.image-crop shipped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Image crop: Bulgarian hint without a character the monospace UI font lacks

JetBrains Mono has no 'ѝ', so primary_ui_fonts_cover_latin_and_cyrillic_catalogs
failed; the hint is reworded ("with its handles" -> "with the handles").

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Refresh catalog hashes after merging main

---------

Co-authored-by: Osvaldo Duran <338149330+regendorf-ux@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-15 02:37:56 -04:00
75c9a9c27b Comments: font size for text boxes in Comment Properties (#1908) (#1984)
* Comments: font size for text boxes in Comment Properties (#1908)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Refresh catalog hashes after merging main

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-15 02:36:35 -04:00