mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-25 18:59:48 +00:00
sonar-fix/enforce-https
35 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
0831d911b4 |
M6: a date typed without separators fills a yyyymmdd field (#3388)
* M6: a date typed without separators fills a yyyymmdd field
parse_date read each run of digits as one number, so 20261018 in a
yyyymmdd field was a single number with nothing left for the month and
the day, and the keystroke check refused it. Every date field on forms
that use the YYYYMMDD date format (US Army forms such as DA Form 31 among
them) refused every valid date.
order() now records each field's fixed width (4 for yyyy; 2 for yy, mm,
dd, HH, MM and ss) and whether the next field follows with nothing in
between. parse_date keeps runs of digits as text and splits a run between
such joined fields by those widths. Formats with separators, month names,
literal digits (dd.mm.26) and two-digit years behave as before.
A run of digits too long for a u32 used to be dropped silently, which let
"2026 99999999999" pass for yyyy; it is now read like any other number and
refused when it is left over or does not fit.
* chore(contributors): credit Eric Kaden by real name
* M6: separated runs of digits stay whole in a joined date format
With separators each run of digits is one field's number, as before this
branch: "2026-10-18" in a yymmdd field reads the year 2026, where the
first commit split the run into 20 and 26 and refused the date. A run is
now split between joined fields only when fewer runs were typed than the
fields still to fill, so "2610" and "261018" still split.
* M6: what is left of a split run of digits fills its field exactly
"202610018" in a yyyymmdd field split off 2026 and 10 and read the rest,
018, as day 18, so a nine-digit date passed. The rest of a split run now
has to be its field's width; a number typed on its own ("2026 10 018")
keeps its leeway.
* M6: a number typed on its own is split only when its rest fills the next field
The optional time fields of a format like yyyymmddHHMM counted as fields
still to fill, so "2026 10 018" split the day 018 into 01 and 8 and was
refused; on main the time defaults to 00:00. A run typed on its own is
now split only when what is left can fill the next field; the rest of a
run that was already split is split as before.
* M6: describe the undelimited-date tests without naming one form
The tests and their comments now say what they check (fields written side by side, such as yyyymmdd) instead of naming the form that showed the problem, and use a generic field label.
* M6: count date and time fields apart when deciding to split a run
Optional time fields counted towards the fields still to fill, so
"2026-10-18" in a yymmddHHMM field split the year into 20 and 26 and was
refused, where main reads it with the time left out. A run typed on its
own is now matched against the fields of its own kind: date runs against
date fields, time runs against time fields. What is left of a split run
goes on being split along the fields written side by side, so
"20261018143005" still fills yyyymmddHHMMss. A mix such as
"2026 1018 1430" (year apart, month and day joined, then a time) is still
refused, as on main.
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
|
||
|
|
f280ca8e6d |
M10: exported TIFF and JPEG pages record the resolution they were drawn at (#3332)
* M10: exported TIFF and JPEG pages record the resolution they were drawn at A page exported as TIFF said 1 x 1 with no unit, whatever the dpi, and a JPEG export said nothing, so other programs showed and printed them at a default (a 300-dpi page shown at 72 dpi is four times too big). encode_image now takes the dpi: TIFF X/YResolution in inches, the JFIF density in dots per inch. PNG stays without pHYs. It counts pixels per metre, so 72 dpi would read back as 72.009, and a page made from an exported PNG (doc_create from images, as enhance_camera_image_through_tools does) would come out 0.01% small. Exporter records the resolution a page was actually drawn at (dpi_used), so a page too large for the renderer says the lower one. render records --dpi, since it refuses oversized pages. The TIFF is written with the tiff crate, already in the graph, because image's TiffEncoder can't set a resolution. * M10: TIFF page exports are LZW-compressed, as documented encode_tiff's comment said "LZW-compressed by the encoder's default", but the TIFF was written uncompressed: a Letter page at 300 dpi came to 25 MB. It is now LZW without a predictor, the compression TIFF readers support most widely after none. * Contributors: add my name for the About window |
||
|
|
ab45a1855f |
Keep annotations readable under reading colours (#1548) (#1557)
* fix(render): keep annotations readable under reading colours (#1548) Reading colours remapped annotation paints as line art: the yellow highlight fill is luminance-light, so it was mapped toward the dark background, and Multiply then darkened the remapped-white words under it into invisibility. Two changes in hayro: - The /Annots loop in interpret_page is bracketed by a new begin_annotations/end_annotations Device signal (patch 26), and the renderer's reading-colours mapping leaves annotation paints alone. Reading colours replace document colours, never the colours a comment was given — the Acrobat model. - The page background is painted inside the page transparency group (patch 27), as the initial backdrop, so a Multiply highlight blends with the background too. With the background outside the group the band kept its own flat colour and the words vanished into it. White pages are unaffected: multiplying with white is the identity. Regression test reading_colors_keep_highlight_annotations_readable covers both annotation paths (/AP and the no-/AP /QuadPoints fallback) under WHITE_ON_BLACK; parity entry a11y.replace-page-colors updated with the behaviour and evidence. Co-Authored-By: GLM <noreply@z.ai> * contributors: credit @edurbs as Eduardo Soares The contributor's own entry, chosen by them (real and display name). Co-Authored-By: GLM <noreply@z.ai> * #1557: record the vendored hayro patches in vendor/README.md Main already uses hayro-interpret patches (26)-(28), so the annotation hooks become hayro-interpret (29) and the renderer's parts hayro (17) and (18). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: GLM <noreply@z.ai> Co-authored-by: Brandon Thomas <echelon@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
2a130abf82 |
Refuse header/footer Bates numbers that would overflow u64 (#2253)
Found while testing crates/edit/src/lib.rs:445 Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
f00a84121b |
chore(contributors): credit mtlcl410 by display name (#2065)
* chore(contributors): credit hpcgrid as mtlcl410 My own people.toml entry: display name only, no real name, no GitHub profile sync. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz * chore(contributors): the entry's key follows the renamed account The GitHub account was renamed from hpcgrid to mtlcl410 after the first commit, and people.toml keys are GitHub usernames. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> 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> |
||
|
|
00957b9f21 |
M5: Fill & Sign text reads across on rotated pages (#1710)
* M5: Fill & Sign text reads across on rotated pages Typed text, dates and text boxes ignored the page's /Rotate, so on a page stored sideways (common for scanned forms) the text came out sideways. The box now follows the displayed axes, the annotation records the turn in /PCTextRotate and its appearance is turned back with a form /Matrix, as stamps and image signatures already do. Callouts keep user-space axes. The headless fill_sign_add tool gets the same layout. generated with Claude Code * chore: credit alexanderalber in the About window generated with Claude Code |
||
|
|
a9745dd22d |
fix(organize): normalize rotations before adding so large quarter turns cannot overflow (#1512)
* Contributors: credit webdevtodayjason as Jason Brashear * fix(organize): normalize rotations before adding so large quarter turns cannot overflow |
||
|
|
186c1dc767 |
M7: preserve Arabic text order in copy, search and editing (#1369)
* M7: preserve Arabic text order when copying and editing Record per-line ActualText for shaped added text and preserve its logical order in Edit text. Cover mixed scripts, marks, copy/search, retyping and save/reopen; retain the drawing golden. Assisted-by: Codex * Edit text: keep only right-to-left ActualText out of line joining and bidi recovery Word and Chrome wrap Latin ligatures in /ActualText spans mid-word; splitting lines at every span broke such words into pieces in Edit Text. Only spans whose ActualText has strong right-to-left characters keep their own line and typing order now. Regression: a Latin fi ligature span stays on its line. 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> |
||
|
|
8cacb44728 |
M3: follow Windows' Animation effects setting; add an Animation effects preference (#1235)
* M3: follow Windows' Animation effects setting; Smooth scrolling preference With Settings > Accessibility > Visual effects > Animation effects turned off, the wheel still eased: egui spreads a coarse wheel step over about a quarter of a second, for scrolling and for Ctrl-wheel zooming, and has no switch for it. - crates/ui-egui/src/motion.rs reads each frame's wheel input the way egui does, minus the easing, and hands it to the scroll areas and the views (zoom_delta). A test sums what egui eases and compares it with what is read at once, and fails if egui stops easing. - With the system asking for no animations, egui's own animations take no time and the progress card's bar steps without its sweep. - The desktop app asks WinRT's UISettings.AnimationsEnabled at launch and every two seconds of use, so a change applies without a restart. - Preferences has Smooth scrolling: Use system setting (default), On, Off. On or Off decides the wheel's scrolling and zooming, and scrolling to a place, whatever the system says. Saved, settable as smooth_scrolling on the control channel, translated in all 20 catalogs. How far a notch scrolls or zooms is unchanged. macOS, Linux and the browser aren't asked for their setting yet; Off works everywhere. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Credit Jeremy Yao by name in About (contributors/people.toml) My own entry: real name and display name "Jeremy Yao". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * M3: rename Smooth scrolling to Animation effects; it decides every animation The preference also governs Ctrl-wheel zooming, so "Smooth scrolling" described only part of it. As "Animation effects" (Use system setting, On, Off) it now decides every animation in the window, the way the Windows setting of the same name does: - the wheel's scrolling and zooming, and scrolling to a place (as before); - egui's own animations, the progress card's sweep, and the chrome's hover and press washes (new on main, with durations of their own), which used to follow the system alone or not at all. Saved and set on the control channel as animation_effects (system, on, off); the unreleased smooth_scrolling name is gone. The three labels are retranslated in all 20 catalogs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Tests: the app's two real-GPU tests take turns (FreeBSD SIGSEGV) FreeBSD CI died with SIGSEGV in the pdfcraft binary's tests on this branch ( |
||
|
|
7caaa35a81 |
Fix Word invoice layout and pagination (#773) (#1126)
* M10: keep invoice overlays out of Word body flow (#773) Export inferred tables without visible borders. Keep text and images positioned on pages with artwork, rotated or large text, and retain each source page's size, crop rotation and units. Cover invoice conversion through the automation tools, and handle unavailable Windows symlink setup in the confinement test. Co-authored-by: Codex <noreply@openai.com> * M10: add @lollinoo's chosen contributor credit (#773) The contributor requested their public GitHub profile name while preparing the #773 PR. Co-authored-by: Codex <noreply@openai.com> * Word export: float a page only when text overlaps an image or watermark positioned() turned every page with any image, or with text twice the body size, into absolutely positioned VML text boxes, so a page with a logo or a big title lost its flowing paragraphs, headings and tables. Now a page floats only when it has rotated text, or when an image or a watermark-sized text block actually overlaps other text (bounded pairwise test). Other pages flow with images inline. Adds a regression test for a page whose image and title sit clear of the text, and updates the docs and parity notes. --------- Co-authored-by: Codex <noreply@openai.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
0824f44daf |
docs: sync Earl Co contributor name from GitHub (#1199)
Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
634f3d1144 |
Issue #1028: OCR can read pictures on pages that already have text (#1184)
* Issue #1028: OCR can read pictures on pages that already have text Recognize Text skipped every page with text, so a picture of text on a page that also has real text never became searchable. The engine and the ocr_recognize tool already had skip_text_pages, but the desktop dialog never offered it, and turning it off read the page's own text again and added it a second time, so search found every word twice. - Engine: always collect the page's own glyph boxes; with skip_text_pages false, a recognised word at least half covered by them (an earlier OCR layer included) is left out. OcrPage counts those words as already_on_page. The default still skips pages with text. - Dialog: "Also recognize pages that already have text", kept with the other choices and used by Recognize text in multiple files too. - Tools: ocr_recognize reports already_on_page; ocr_recognize_files accepts skip_text_pages. - The two new labels in the 15 catalogs that translate the OCR dialog. - Synthetic tests (a picture of a sentence plus real text) for the engine, the tool and the dialog; the engine test fails with the filter turned off. Unit tests for the coverage check, including NaN, infinite, inverted and overlapping boxes. - parity, docs/roadmap.md M10 row and the ROADMAP.md progress log. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqiZ658tGndQaHao5Q6mdm * Issue #1028: Czech labels for the OCR text-pages option The Czech catalog was completed (#1066) while #1028 was in review, and czech_covers_ui_literals requires every tl! literal: the two new Recognize Text labels were missing, so the test failed after the merge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqiZ658tGndQaHao5Q6mdm * Contributors: credit rp6186030 as Raj Patel in the About window Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JqiZ658tGndQaHao5Q6mdm --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: rp6186030 <25706807+rp6186030@users.noreply.github.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
826941dcfc | docs(contributors): add Ufuk Efe to people.toml (#1177) | ||
|
|
de8e0176ed |
M14: complete the Czech (cs) interface catalog (#1066)
* M14: complete the Czech (cs) interface catalog
Czech covered the menus and a few later additions (167 keys). The catalog
now has every key the code uses (2,194): Home, All tools, panels, dialogs,
notices, diagnostics and history labels. Translated clean-room from the
meaning of the English labels; the 167 existing entries are unchanged.
- The @plural messages use the three Czech forms (one | few | other);
other counted messages use count-neutral wording ("Vybráno stránek: {n}").
- "calendar date" months are genitive ("9. října 2026"); "Undo {action}"
and "Redo {action}" are whole phrases ("Zpět: {action}").
- Labels the code joins with a leading or trailing space keep it.
- The key-name entries (context "key") are kept as they were.
Tests that relied on the incomplete catalog:
- czech_covers_every_menu_label keeps a short list of strings spelled the
same in Czech (product and format names, Text, Index, Metadata, Model,
templates such as "{0}: {1}"), compares leading and trailing spaces with
the source instead of forbidding them, and requires a catalog without
parse errors.
- date_format.rs expected the English fallback "Same as interface
(Čeština)" under the Czech interface; that label is now translated.
ATTRIBUTION.toml: new SHA-256 of cs.tsv.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* M14: check the Czech catalog like the other complete catalogs
Czech now has the same coverage gates as the complete catalogs:
- czech_covers_commands_and_catalogue: every registered command, menu
title and All tools group, section and item;
- czech_covers_ui_literals: every tl!("…") literal in the UI source;
- czech_plurals_dates_and_history_labels: 1/3/5 pages and 0 fields, the
genitive date ("9. října 2026"), and Undo/Redo/Change history labels
that keep captured names.
cs also joins the lists in missing_ocr_models_messages_are_translated and
bulk_field_properties_labels_are_in_every_full_catalog.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* i18n (cs): terminology review fixes
An independent review of the Czech catalog found 5 entries with a wrong
or misleading meaning and 44 that read unnaturally or inconsistently.
Meaning:
- US formats say so: "Čísla sociálního zabezpečení (USA)" (not the Czech
birth number) and "Telefonní číslo (USA)" for the field format.
- Mouse Exit/Enter triggers: "Odjetí kurzoru" / "Najetí kurzoru".
- Rich text in form fields is not RTF; Form XObjects are not forms.
Wording and consistency:
- Home: pinning folders refers to "úvodní obrazovka" (also in the existing
"Pin folder to Home…"); "úvodní stránka" reads as the first page.
- Callout is "Popisek se šipkou"; Self-signed is "Samopodepsaný" (fixes
the agreement in "Samopodepsaná ID").
- Reset (forms), Apply redactions, guided actions, the radio button and
checkbox styles, line endings (also the existing arrow entries), border
styles, "Omezit na … znaků", "Rozlišovat velikost písmen", grammar in
several messages, and the About window wording shared with the other
Crafting Apps.
History labels for the Creator and Producer document information keys
use the Document Properties wording: "Aplikace" and "Producent PDF".
ATTRIBUTION.toml: new SHA-256 of cs.tsv.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* contributors: add my own people.toml entry
Own entry only, as AGENTS.md describes: credited by the name on my public
GitHub profile (sync_github_name), otherwise by @username.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* i18n (cs): translate "Offset from centre" (watermark offset, #1076)
New upstream string added after the catalog was last synced.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* i18n (cs): follow the reworded Combine files strings (#1032)
Upstream generalised the Combine files dialog (images and text files, a
prompt for files that can't be read) and replaced six strings. The old
Czech entries are dropped and the ten new ones translated.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* i18n (cs): translate the new Enhance page / camera image strings (#1027)
Four strings added upstream after the catalog was last synced.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* i18n (cs): margin labels Top/Bottom read Nahoře/Dole
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* i18n: translate the Digital ID errors, the Signatures panel and key usages
The digital-ID dialog printed its validation errors, the Signatures panel
headings ("Rev. n: Signed by ...", "Unsigned signature field"), the
certificate issuer line of the signed-document bar and the nine key-usage
names in English. Translate them at the point where they are drawn, the way
title() and notify_fmt() already do, so engine and OS error texts that
share those paths pass through unchanged. Czech catalog entries added; other
languages fall back to English.
The signature appearance preview is left alone on purpose: it mirrors the
Helvetica text the engine bakes into the PDF ("Digitally signed by", "Reason:"),
which is document content, not interface.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* i18n: translate form action, print, panel layout, rendering and OCR language texts
Route the remaining plain-English messages through the translation lookup
where they are drawn: the Add-action validation hints, the Cut and stack
print error (preview and notice), the two panel-layout notices, the
"Rendering..." placeholders on unrendered pages, the page number under the
Page Boxes preview (reuses "Page {label}") and the OCR language name.
The messages of the docking validator and the engine and OS errors stay
English: they report internal invariants or text this code does not own.
"My stamps" stays too: it is stored as the category of the user's stamps, so
translating it would split a library when the language changes. The dynamic
stamp chip text mirrors the English text baked into the stamp and is left as is.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* i18n (cs): translate the Appearance preferences and the wheel scroll speed
The strings added upstream with the Appearance section and the mouse wheel
scroll speed setting were missing from the Czech catalog, so
czech_covers_ui_literals failed after the merge.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* i18n: use plural forms for counts built in code
The saved notice after Optimize ("3 images optimized", "2 items discarded"),
the pixel sizes in Export all images, the exact size in bytes (human_size and
the document properties) and the history label of a multi-field delete were
assembled from English words and a trailing "s". Use trn() for them, with
@plural entries in the Czech catalog (1 | 2-4 | 5+), and translate the
"Delete N fields" history label in action_label(). English output is unchanged;
other languages without a plural entry keep the English wording.
The Czech plural test now also checks bytes, optimized images and the
Delete N fields label.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* i18n: translate the text-box and organize toolbar tooltips
"Done adding text" and "Discard this text (Esc)" (the buttons under a new
text box) and the Rotate tooltips of the organize toolbar were passed to
icons::button as plain English. Translate them at the call site, as the
other icon buttons do.
The two text-box tooltips are tl!() literals, so every complete catalog
(ar, bg, cs, de, fr, hu, it, ja, pt-br, ru, uk, zh-hans) has to carry them;
the entries for the languages other than Czech are AI drafts that want a
native speaker's look. The Rotate tooltips already had translations.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Losminek <301412321+Losminek@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
|
||
|
|
0f7ff1ce30 |
Improve PDF Navigation with Cursor-Anchored Zoom and Mouse Panning (#504)
* M3: add cursor zoom and temporary mouse-button navigation on Windows Anchor Ctrl-wheel zoom to the cursor; share bounded, immediate ScrollArea pan between the middle button and Space + primary drag. Preserve ordinary scrolling and editing, cancel capture on focus/document changes, and initialize numeric zoom before the viewport exists. Validation on Windows x64: formatting, application check and workspace Clippy pass; full workspace tests pass (928 passed, 4 ignored), including 53 UI unit tests and 27 control integration tests. No branding changes, new dependencies, machine-specific build configuration or local development notes. * M3: add contributor display name for mhadidi06 --------- Co-authored-by: Brandon Thomas <echelon@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
d576fe2b06 |
Forms: keep tiles and render unbaked field values during page re-render (#636)
* Forms: keep tiles and render unbaked field values during page re-render In complex interactive forms, switching focus away from an edited field caused its text to disappear for several seconds while background tiles re-rendered. - In DocView, retain existing tiles as stale rather than immediately purging them on page_changed so the canvas remains sharp without flashing. - Prioritize visible tiles over backdrops in the render queue. - Track unbaked form fields and paint an immediate egui widget preview for committed text, checkbox, and radio inputs until fresh raster tiles arrive. - Scope page invalidation on form edits to pages containing the edited or calculated fields. - Hoist fields lookup in recalculate_with and apply_changes to eliminate repeated parsing. - Run JavaScript scripts via catch_unwind on the current thread instead of spawning a new thread per script invocation. - Add contributor entry for Piohrun in contributors/people.toml. - Add test switching_fields_keeps_committed_text_visible_immediately. * Forms: address review feedback on tile stale tracking, hoist, and diff invalidation - Revert crates/js to preserve dedicated 1 GiB stack thread for boa scripts. - In DocView::page_changed, purge non-current-tag tiles and mark only current-tag tiles stale. - Restore demand queue order in prepare_render_queue. - Add unbaked overlay entries only on successful edit apply and only for fields whose values changed; fix font zoom calculation on 90°/270° pages. - Re-read fields(doc) in recalculate_with only when script returns changes. - Diff form before and after edit in apply_edit, invalidating pages with changed fields, falling back to document_changed for XFA or page-count changes. - Add tests covering script recalculation side effects across pages, unbaked overlay cleanup on tile delivery/zoom/rejection, and checkbox recalc chaining. --------- Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
e4c9cc1a19 |
Open dialog: allow selecting several files at once (#1086)
* Open dialog: allow selecting several files at once * add contribution in people.toml * people.toml: restore arcanii and atoslins (lost in a merge); key the new entry by GitHub login --------- Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
b90875466e |
Select tool: trigger multi-click text selection on pointer press (#1024) (#1040)
* Select tool: trigger multi-click text selection on pointer press (#1024) - Detect consecutive primary pointer presses on page text using press timing and distance thresholds, highlighting words, lines, or the whole page immediately on the down-stroke rather than waiting for pointer release. - Keep selection intact on release for multi-clicks while allowing single clicks to clear or shift-extend. - Add regression test `multiclick_selects_on_pointer_press_before_release` in `crates/ui-egui/tests/text_select.rs`. - Credit krinry in contributors/people.toml. * Count presses with egui's own double-click delay and distance --------- Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
ea1df6e1cb |
Linux: StartupWMClass is the window's app id (#1087)
* Linux: StartupWMClass is the window's app id The desktop entry said StartupWMClass=pdfcraft, but the window carries the app id ai.storyteller.pdfcraft (APP_ID) on Wayland and under X11 alike, so nothing that matches a window to its launcher by that key ever matched it: on X11 the launch's startup notification can't end when the window maps. VectorCraft, GridCraft and WordCraft already use the app id. A test reads the entry and compares it with APP_ID. * Contributors: add atoslins (Atos Lins) --------- Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
a7e24b9512 |
M12: XFA script time limits start when the engine is ready (#1081)
* M12: XFA script time limits start when the engine is ready An XFA script's wall-clock limit (1 s for scripts that run unasked, such as initialize and calculate) also counted the engine's start-up: the script thread, a new boa Context, and for the first script in a process the engine's own one-time set-up (~60-170 ms when idle, shared by every script starting at the same moment). On a busy machine a trivial initialize script could pass 1 s, be abandoned, and so turn all of the form's scripts off, with the error only in the JavaScript console. That made two ui-egui xfa.rs tests flaky (xfa_buttons_run_their_scripts_in_the_app, messages_from_scripts_run_on_open_show_right_away): under full CPU load 25 of 40 runs of the test binary failed, and none of 40 with this change. - run_within: the script calls `started` once the engine is ready, and the time limit runs from then. Start-up has a cap of its own (10 s), so a caller still never waits forever. - run_here: a once-per-process warm-up script takes the engine's first use, so the first form script's timed part drops from ~52 ms to under ~11 ms. - FormCalc (no engine to start) signals at once, as before. - Tests: a slow start doesn't abandon a script; the script's own time, and start-up, are still capped. The UI tests print the script console when they fail. Runaway scripts are still abandoned at the same limits (runaway_xfa_calculations_at_open_end_quickly_with_a_report). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add arcanii to the contributor names Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
f45fd7507e |
Issue #870: keys leave the document under a dialog alone (#898)
* Issue #870: keys leave the document under a dialog alone With Preferences (or any other dialog) open, the registered shortcuts still ran on the document underneath it: ⌘W / Ctrl+W closed the file, ⌘Z undid an edit, ⌘F opened Find. In Organize Pages the grid's own keys did too, so Delete or Backspace deleted the selected pages behind the dialog, and the grid took the Escape meant to close it. Every modal now owns the keyboard, as "Save changes?" already did: PdfCraftApp::modal_open covers the dialog, the save, password and link prompts and the update check. Shortcuts stop there, and the organize grid's keys and autoscroll wait until the page is unobstructed. * Contributors: credit jay-tau by their GitHub profile name |
||
|
|
627d822709 |
create: lift TIFF decoding buffer limit to allow print-sized images (#665) (#681)
* create: lift TIFF decoding buffer limit to allow print-sized images (#665) By default, the tiff crate limits decoded buffer size to 256 MiB. Set Decoder::with_limits(Limits::unlimited()) to match PNG decoding behavior and prevent 'decoder limits exceeded' on large images. * create: cap the TIFF decode buffer at 2 GiB instead of lifting it entirely (#665) A few bytes claiming enormous dimensions must still be refused, not allocated. 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> |
||
|
|
80e6bc9d98 |
M14: complete the French (fr) catalog (#579)
Add the 47 labels and messages that had no French translation (redaction marks, undo/redo labels, file-dialog and script warnings, SHA digests, contextual Start/Subject/Edit/Type, ...). Written from the plain meaning of the English text, clean-room, following the existing fr.tsv vocabulary (vouvoiement, "biffer" for redact). Update the fr.tsv SHA-256 in ATTRIBUTION.toml and add a credit entry for the contributor in contributors/people.toml. Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
5f570eab01 |
M2.6: non-embedded Mincho fonts draw half-width katakana (#484)
Since #368, a non-embedded Adobe-Japan1 font with a Mincho name (HeiseiMin-W3, MS-Mincho, ...) is drawn in document_japanese_font(), i.e. Shippori Mincho. Shippori Mincho has none of the 63 half-width katakana (U+FF61-U+FF9F), which are common in Japanese documents. hayro maps the CID through Adobe-Japan1-UCS2 to Unicode, finds no glyph in the face's cmap, and falls back to drawing the CID as a glyph index: half-width katakana came out as unrelated glyphs (ligatures such as fi and fl). The Mincho substitute is now BIZ UDMincho Regular, which covers half-width katakana (and was designed as a metric-compatible replacement for MS Mincho), falling back to document_japanese_font() when it isn't built in. The face used for Japanese text written into PDFs is unchanged. Without craft-fonts nothing changes. Tests: raster::tests::mincho_substitute_covers_half_width_katakana (with CRAFT_FONTS_DIR: the Mincho substitute's cmap maps U+FF61-U+FF9F and 日本; it lacked all 63 half-width katakana before; skips without craft-fonts). skrifa 0.44 is a dev-dependency of pdfcraft-render for it, the version pdfcraft-fonts already uses. The parity entry view.render-cid-fonts cites the test. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
31f3631868 |
Home: pin folders and list their newest PDFs (#383)
* Home: pin folders and list their newest PDFs
File > Pin folder to Home... (or "Pin a folder..." on Home) pins up to 8
folders. Each lists its newest PDFs with how long ago and size, opens one
with a click, and can be unpinned. Folders are read on a worker thread and
listed again every few seconds while Home shows, so new scans appear by
themselves; an unreadable folder (moved, offline synced drive) stays pinned
and says so. A folder is described by where it is ("iCloud Drive",
"OneDrive - Contoso", "Documents > Work") instead of its full path.
Cloud drives work through their local synced folder; nothing goes through a
provider API. Settings keep absolute paths only, deduplicated and capped.
Tests: crates/ui-egui/tests/folders.rs (8) and folders_ui unit tests (4).
Command label translated in every catalog; Home strings in fr, es, ja,
zh-hans and zh-hant; catalog hashes updated in ATTRIBUTION.toml.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Add my contributor name (amitabhthakur)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Home pinned folders: Russian strings; regenerate ATTRIBUTION.md
The Russian catalog (#375) landed while this branch was open: its coverage
tests need the new command label and Home strings. ATTRIBUTION.md is
regenerated (cargo xtask assets --write), which also adds the ru.tsv row
that #375 left out.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
|
||
|
|
620e8a2d7b |
Add my contributor name (cyfung1031) (#364)
Adds my own entry to contributors/people.toml, as described in
docs/contributors.md ("Credit yourself").
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
05c8ab3b3e |
M14: Telugu (తెలుగు) interface language (#349)
* M14: Telugu interface font - The interface takes `Telu` faces from craft-fonts after the CJK and Arabic ones, on the web too - Test: Telugu text has glyphs in every family and its conjuncts are shaped Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M14: Telugu interface language - Complete te catalog: 1,984 entries plus whole-phrase Undo/Redo; te and te_IN locales use it - Undo and Redo labels use a catalog phrase when the language has one (Telugu puts the verb last) - Tests, docs, attribution, parity and ROADMAP Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * Add my contributor name (chiranjeevi-max) Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M14: catalog contexts for labels with two meanings - tl_ctx! gives the signature pad's Type, the Action Wizard's Start and the comment menu's Edit their own context; Telugu translates them, other languages keep their current translation - Preferences' All tools goes through the catalog in every language Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M14: Telugu for the look-alike web address warnings Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * M14: Telugu for the image signature notices Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> * Telugu for Open Recent (#323) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Signed-off-by: Chiranjeevi U <244287281+chiranjeevi-max@users.noreply.github.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
130b7ea06c |
Security: print jobs, new digital IDs and the --control file no longer write through planted links (#338)
* Security: pipe print jobs to lp instead of a shared temp folder On macOS, Linux and FreeBSD, Print wrote each job to <temp>/pdfcraft-print-<pid>/job-<time>.pdf and passed that name to lp. The folder name is predictable and was made with create_dir_all, which accepts a folder another local user created first in a shared /tmp and follows a symlink planted there; the job was then written with fs::write. That user could read every printed document, or swap the file before lp read it. The folder was also never removed. The job now goes to lp on stdin, so nothing is written to disk. lp_args no longer takes a file. The job is fed on its own thread while lp's output is collected, so neither side can block on a full pipe; if that thread can't be started, lp is stopped and an error returned rather than a panic. When lp refuses a job before reading it (an unknown printer) the user sees lp's message rather than a broken pipe. CUPS ends its reply for a job read from stdin with "(0 file(s))", which reads as if nothing was sent, so that is dropped from the message shown. submit_via takes the spooler command so tests can run this test binary as a stand-in lp on every platform; the new test failed on the old code (it received the temp file as an argument and nothing on stdin). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Security: create a new digital ID file fresh, owner-only Configure New Digital ID > Create picked the first free name with `!p.exists()` and then wrote the .p12 with fs::write. That is check-then-write: a file or link planted at the name between the two is written through. exists() also follows links, so a dangling symlink looked free and the private key was created wherever it pointed. The file got default permissions, readable by other local users on most Unix systems. save_new_id_file now creates the file with create_new, never opening anything already at the name, and with mode 0o600 on Unix. A taken name moves on to the next ("<name> 2.p12", ...), including a folder, which Windows reports as access denied rather than already exists. A failed write removes the partial file. The dangling-link test failed on the old code (the key was written through the link); the hard-link and folder test guards the retry loop, and a Unix-only test checks the 0o600 mode. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Security: never write the --control token through a planted link write_control_file opened the --control path with create + truncate. A symlink or hard link already at that path was followed: its target was truncated and overwritten with the control token before set_permissions ran, so the token could land in a file another user can read, and any file the link pointed at was destroyed. The JSON now goes to a fresh file next to the path, with a random name (create_new, 0o600 on Unix, another name if one is taken, including a folder on Windows), which is then renamed over the path. The rename replaces a link instead of following it, a control file left by an earlier run is still replaced as before, and a reader polling for the file never sees it half-written. A failed write or rename removes the temporary file. The hard-link and symlink tests failed on the old code (the token was written into the linked file); a third test covers replacing a previous run's file, and the owner-only mode on Unix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Contributors: credit jcl-bit as James Locke My own entry in contributors/people.toml (AGENTS.md, Contributor credits), added in my PR as asked there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
9140b44792 |
M4: Combine files in its own tab, with a sortable table and unlocking of protected files (#321)
* M4: Combine files in its own tab, with a sortable table and unlocking of protected files Combine files was a modal dialog with a cramped list and up/down buttons on every row. It is now a tab next to Home and the documents, showing a table of the files: File name | Pages | Size | Modified | Warnings. - Columns sort when their heading is clicked (anywhere in the cell; again to reverse; names in natural order), resize from their edges and move by dragging the heading. Order and widths are kept in the settings; a right-click on a heading resets them. - Rows select like a file manager (click, Ctrl/Cmd+click, Shift+click, Shift+arrows, Ctrl/Cmd+A). One toolbar moves, removes and unlocks the selection; Alt+arrows and dragging move it too. Every change to the list undoes and redoes with Cmd/Ctrl+Z (also toolbar buttons). - Add files, Add folder, Add folder and subfolders (a split button), Add open documents, or drop files and folders on the tab. - Problems show before Combine: password-protected files, security settings that withhold page assembly, page ranges (checked as typed, with the pages they take), duplicates. Files that open but are protected say that the combined file won't keep their security; the result is never encrypted. - Unlock... asks for a file's open or permissions password (one password can be tried on several files). Passwords stay in memory, are never printed, and reach the engine through combine_unlocked; doc_combine takes them as `passwords`. The engine decides whether a password works, since the inspector rejects some it accepts (RC4 owner passwords). organize.combine-sort is shipped and organize.combine-options partial (include open files). Strings are translated for es, fr, ja, zh-hans, zh-hant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Credit Marlon Konrad (mlkonrad) in the About window Adds my own entry to contributors/people.toml, as docs/contributors.md asks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
9f2188bf7e |
Issue #166: Save, Print and Export include the text still being typed in a form field (#278)
* Issue #166: Save, Print and Export include the text still being typed in a form field A field's editor kept its text in a draft until Enter, Tab or clicking away, and ⌘S (which runs while a field has focus) saved the document first. Typing also didn't count as unsaved, so closing or quitting didn't ask. - commit_form_typing(): apply the tab's queued edit, then commit the open field's draft; if the field refuses the value, keep the editor and text and stop. Called where the document is read: Save, Save As (and its later callback), Print, Export, Reduce/Optimize, Sign, Extract, Split, Copy pages, Flatten, button scripts. - Uncommitted typing counts as unsaved work for Close, Close All and Quit; saving from the prompt brings that tab forward first. - Shortcuts pressed while a form field's editor is open run one frame later, for that document only, so the field takes the frame's typing and Escape. - A value refused on Enter/Tab/blur reopens the field with the text. - Notices show in full screen too. Co-authored-by: Hal Goff <hal@hg.studio> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add my contributor name (AutoHenry) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
79ac5e68f8 |
Add my contributor name (viator1969) (#264)
* Add my contributor name (viator1969) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A3kqJC1D3PAgT3dHxnqYNy * Use my real name in my contributor entry Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A3kqJC1D3PAgT3dHxnqYNy --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
eb46a993bf |
README: install on Gentoo from the ::snakebyte overlay (#237)
* README: install on Gentoo from the ::snakebyte overlay * Contributors: credit switch87 as Gert Pellin |
||
|
|
932967a30d |
Restore #196, #202, #203 and the macOS release-runner change, reverted by the i18n chain (#229)
* Release CI: macOS job on macos-15-xlarge Custom macOS larger runners in a runner group do not pick up jobs; the built-in M2 Pro label does. Only release.yml uses it, and the actions_macos_xl budget caps the monthly spend. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit |
||
|
|
41734376be |
i18n: add Brazilian Portuguese (pt-br) UI translation (#165)
* M14: translation catalogs, same system as PhotoCraft Move the interface translations to PhotoCraft's i18n system: one TSV catalog per language (crates/ui-egui/src/i18n/ja.tsv), the tl! macro, entries keyed by command id, context or plural forms, and catalog tests (format, duplicates, placeholders, command ids). The 49 existing Japanese strings move over unchanged, plus "Auto". The language preference now defaults to "auto" and follows the system language (English when it has no catalog); "en" and "ja" still persist and unknown values are rejected. Update docs/localization.md, ROADMAP.md and the misc.prefs-language parity entry. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * i18n: add Brazilian Portuguese (pt-br) UI translation Adds Language::PtBr (code pt-br, endonym Português (Brasil)) with serde rename so it persists as "pt-br", registers it in Language::ALL (Preferences ▸ Interface language and ui.set/ui.state) and translates the same 49 menu/command keys as the Japanese table. Extends the i18n tests (table parity, codes, persistence) and updates docs/localization.md. * M14: strict catalog validation, one-pass fmt, translation assets Fold in the infrastructure parts of #175: - `fmt` fills placeholders in one pass, so inserted values (a file name containing `{n}`) are never substituted again. - Catalog validation rejects unknown escapes, unknown `@` contexts, placeholder, ellipsis and plural-form mismatches and duplicates. The bundled catalogs must have no errors (tests); at run time a bad line is still only skipped and logged, so the rest of the catalog loads. - `.tsv` files count as assets in `cargo xtask assets`, with a `translation` kind that may never come from Adobe; ja.tsv gets its ATTRIBUTION.toml entry. - Control-channel test: switching the language keeps documents, their dirty state and command ids. Also make the drawing language thread-local, as in PhotoCraft, so parallel kittest harnesses can't change each other's language. Co-Authored-By: 才倾梦华V <185041488+CQMHV@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * M14: Brazilian Portuguese as a TSV catalog Move #165's Portuguese table into crates/ui-egui/src/i18n/pt-br.tsv (same 49 strings, plus Auto) and register it in LANGUAGES with PhotoCraft's Portuguese plural rule (0 and 1 singular). Any Portuguese locale (pt_BR, pt_PT, pt) follows the Brazilian catalog, as in PhotoCraft. The catalog is an attributed asset (ATTRIBUTION.toml), and the docs and parity notes list the new code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Simon Leblanc <contact@leblanc-simon.eu> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> Co-authored-by: 才倾梦华V <185041488+CQMHV@users.noreply.github.com> |
||
|
|
41e214c318 |
About: contributor and model credits compiled in (grab bag + table, self-submitted names) (#196)
* About: contributors compiled in from contributors.json (grab bag + table, sortable, name toggle) Adds About ▸ Contributors and About ▸ Models tabs per the craftrules standard (standards/contributors.md): contributors/contributors.json is generated by craftrules/scripts/contributors.py and baked into the binary by crates/ui-egui/build.rs as static tables; nothing is read at run time. Each contributor line: @username, opt-in display/real name, PRs, commits, lines +/−/Δ, binary assets +/−, first/last commit. Sortable by every column; alphabetical ignores case and the leading @. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Contributors: self-submitted names in contributors/people.toml; AGENTS.md credit-yourself section build.rs reads contributors/people.toml next to the generated contributors.json and shows a name only for entries the generator verified as written by that person (craftrules standards/contributors.md). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Contributors: regenerate (verified people.toml entries) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |