6290 Commits
Author SHA1 Message Date
4bff30cf62 M10: Windows prints a large image whole: drawn as tiles under Windows.Data.Pdf's cap (#5131) (#5897)
* M10: Windows prints a large image whole: drawn as tiles under Windows.Data.Pdf's cap (#5131)

Windows prints each page through Windows.Data.Pdf, which draws any image
of more than 2^22 pixels from a copy shrunk to that size. With the page
at the printer's resolution (craft-libs#396, #5023), a 6000 x 6000 scan
still printed as 2048 x 2048, its one-pixel detail gone.

pdfcraft_optimize::tile_large_images replaces each such image XObject
with a form XObject of the same object number that draws it as tiles of
at most 2000 pixels a side, so whatever drew the image draws the tiles.
Samples are copied as stored (any bit depth and colour space, decode
array, interpolation, colour key); a grey or RGB JPEG is decoded and
stored with Flate; a soft or stencil mask of the image's size is cut
into the same tiles. Tiles overlap by a pixel against drivers that
soften image edges, except under a soft mask, where the overlap would
blend see-through pixels twice. JPEG 2000, CMYK or ambiguous JPEGs,
masks of another size, more than 80 million pixels, short data and
images past the decode allowance are left whole.

pdfcraft_engine::spooler::spooler_copy applies it to the copy that goes
to the spooler on Windows, from the Print dialog's worker and doc_print;
elsewhere, or when the copy can't be read or written, the bytes go as
they are. The saved print-ready PDF is unchanged.

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

* M10: a test that the spooler gets the tiles on Windows; tiles are up to 2001 px (#5131)

spooler_copy was only tested with prints that pass through unchanged, so
one that skipped tiling on Windows would have passed. A test now checks
that on Windows it sends the tiled copy and elsewhere the bytes as they
are. The optimize README said tiles have at most 2000 pixels a side;
with the overlap they have 2001.

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

* M10: the tiles' samples are StoredSamples, apart from the crate's Samples (#5131)

main has since added a public `Samples` (8-bit grey or RGB, for tools
that repaint an image), so two different things in one crate shared a
name. The tiles keep an image's samples as stored, in its own colour
space and depth, so each tile redraws exactly what it replaces; the
type now says so in its name and doc comment.

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

---------

Co-authored-by: austin62jake <340374338+austin62jake@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-10 10:25:54 +01:00
Combiler01 4ba51acbc5 Merge remote-tracking branch 'upstream/main' into fix/paper-size-driver-5861
# Conflicts:
#	crates/automation/src/printing.rs
#	crates/print/src/lib.rs
#	crates/print/src/tests.rs
#	crates/ui-egui/src/app.rs
#	crates/ui-egui/src/app/files.rs
#	crates/ui-egui/src/app/prefs.rs
#	crates/ui-egui/src/lib.rs
#	crates/ui-egui/src/platform/open_worker/tests.rs
#	crates/ui-egui/src/workflows/print_ui.rs
#	crates/ui-egui/src/workflows/print_ui/body.rs
#	crates/ui-egui/src/workflows/print_ui/draft.rs
#	crates/ui-egui/tests/it/print.rs
2026-11-10 14:18:01 +05:30
bflatastic e987f46fb6 Snapshot tab tests share one harness on the shared page fixture 2026-11-10 15:26:39 +07:00
bflatastic 3b23494513 Merge remote-tracking branch 'origin/main' into merge/egui-725a39fc-6699 2026-11-10 15:24:11 +07:00
regendorf-ux b7cfbd3980 Find and replace text in Edit text mode: a Replace row in the Find box, Replace all as one undo step (#2467) 2026-11-10 15:19:55 +07:00
bflatastic 51a87eb3d9 Give the snapshot-area booklet test main's creep field 2026-11-10 14:27:17 +07:00
bflatastic 1726d9aca3 Merge remote-tracking branch 'origin/main' into merge/print-snapshot-area-2491 2026-11-10 14:27:02 +07:00
BFlat 2b46f8bf8c Merge pull request #5698 from Piohrun/fix/jbig2-dictionary-any-route
fix(redact): a shared JBIG2 dictionary leaves with whatever used it, by any route
2026-11-10 14:24:09 +07:00
Hazel Granados 45d51d8c46 M3: a file named with open parameters opens at their destination (#3425) (#5049) 2026-11-10 14:23:54 +07:00
ljkx dec9f3600b Windows: Tesseract and the --control tools start without a console window (#6735) 2026-11-10 14:23:38 +07:00
BFlat 06572d57df Merge pull request #6805 from storytold/merge/redact-forms-6341
M8: redaction keeps an image a form without resources still draws (#6341, merged with main)
2026-11-10 14:22:51 +07:00
BFlat f48cf6eeba Merge pull request #6806 from storytold/merge/mixed-script-2778
fix(edit): preserve source fonts in mixed-script paragraphs (#2778, merged with main)
2026-11-10 14:22:36 +07:00
Aleksander Helgaker a1769246bd fix(ui): keys under a dialog or a menu leave the pages alone (keyboard routing, part 1) (#6608) 2026-11-10 14:22:20 +07:00
Eric Kaden ea2e13370c M12: dynamic XFA forms tab in their template's traversal order (#4149) 2026-11-10 14:22:02 +07:00
mtlcl410 67cd69050e M7: paragraph edits keep the advance of the text they drop (edit.text-edit) (#2968) 2026-11-10 14:21:29 +07:00
Combiler01 6df356b63d fix(open): submit password retries with priority when worker queue is full 2026-11-10 11:06:56 +05:30
bflatastic c6740a16d8 Merge remote-tracking branch 'origin/main' into merge/redact-forms-6341
# Conflicts:
#	crates/edit/src/tests.rs
2026-11-10 10:46:07 +07:00
bflatastic 10755a9da9 Merge remote-tracking branch 'origin/main' into merge/mixed-script-2778
# Conflicts:
#	parity/acrobat-features.toml
2026-11-10 10:45:45 +07:00
BFlat 274b7a0424 Merge pull request #6800 from storytold/merge/fonts-budget-6239
M7: a font's metrics can be read within a caller's decode allowance (#6239, merged with main)
2026-11-10 10:43:29 +07:00
Piohrun e2464e1440 M2: a JBIG2 mask with a large symbol dictionary draws, and one a decoder limit refuses takes its picture with it (#6722) (#6784) 2026-11-10 10:43:13 +07:00
mtlcl410 d9ec80243b M12: XFA forms with many repeated rows lay out in linear time (form.xfa-dynamic) (#6776) 2026-11-10 10:42:57 +07:00
BFlat 85e2ebfac8 Updates test: answer the startup prompt before clicking in Preferences (#6799) 2026-11-10 10:42:41 +07:00
Osvaldo Duran MelendezandClaude Sonnet 5.5 6034de11bf Print a selected area: the automation test reads the printed PDF (sheet size, the area's clip rectangle, the page drawn through it)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-09 22:22:43 -05:00
bflatastic f6fd408419 Merge remote-tracking branch 'origin/main' into merge/fonts-budget-6239
# Conflicts:
#	crates/edit/src/tests.rs
2026-11-10 10:09:08 +07:00
jonathanwxh-cell ccda1b0a1e fix(export): skip empty HTML runs and clamp heading levels to h6 (#6136) 2026-11-10 10:02:47 +07:00
Hitesh ba8beb12b9 fix(ui): All tools ▸ Edit a PDF turns on Edit text & images at once (#4605) 2026-11-10 10:02:30 +07:00
Eric Kaden 5af40c5515 M6: form buttons open the files attached to their document (exportDataObject) (#3575) 2026-11-10 10:02:13 +07:00
robertobulltech 851d6ceca5 M10 #5022: preserve printable Link appearances (#5028) 2026-11-10 10:01:52 +07:00
jonathanwxh-cell 466e1971d6 fix(annot,ui-egui): guard comment edits against non-comments and stale state (#3916) (#4673) 2026-11-10 10:01:09 +07:00
ljkx 0d853dace7 M6: the Calculate tab shows and edits a field's custom calculation script (#6630) (#6717) 2026-11-10 10:00:52 +07:00
Ken Mantle 5b67f8d021 Booklet printing: creep compensation (#6790) 2026-11-10 10:00:36 +07:00
jonathanwxh-cell c6d9c13002 fix(ui): keep added image corner resize responsive and clip out-of-bounds drag preview (#4477, #3938) (#4625) 2026-11-10 10:00:18 +07:00
jonathanwxh-cell 8e6db09459 Zeroize key material, KDF buffers, and UI password drafts (#3928) (#4427) 2026-11-10 10:00:01 +07:00
.CooCoo 709f5fb80f Updates: Restart to Update with unsaved changes opens the save prompt (#6726) 2026-11-10 09:59:45 +07:00
jonathanwxh-cell 9ccd6964ee fix(preflight): handle typeless annotations, indexed colour, and indirect filters (#5279) 2026-11-10 09:59:28 +07:00
FredApps 5e114c716f Windows printing: craft-print 0e4943cb (winprint 3c978dfc): pages at the printer's resolution, QName tickets, padded integers (#4941) (#6793)
storytold/craft-libs#761 moves winprint to 3c978dfc: winprint.rs#19 draws each page at the
job's resolution instead of ~96 dpi (#4941, #2676), #12 writes QName ticket values as
prefix:local (#3823), #3 accepts whitespace around integer capabilities (#2430). Only the
craft-print and winprint lock entries move, plus winprint's windows-numerics dependency.
2026-11-10 03:22:11 +01:00
a71b5124bc M10 #5130: resolve Windows printer-default duplex before spooling (#5180)
* M10 #5130: resolve Windows printer-default duplex before spooling

* M10 #5130: document printer duplex resolution

* M10 #5130: adopt DocumentDuplex driver fix from craft-print

* M10 #5130: adopt two-sided capability selection fix

* M10 #5130: update documented craft-print revision

* M10 #5130: fall back when Windows duplex defaults cannot be read

* fix(print): satisfy duplex review formatting and refresh shared pin

* Repin craft-print to craft-libs main (#411 and #133 merged); ask only the picked printer's driver for two-sided support

craft-libs b6b8a55b has #411 (DocumentDuplex) and #133 (two_sided(name)). The
Printer default support check now reads that one driver instead of listing
every printer's capabilities at submit time (#2192).

---------

Co-authored-by: robertobulltech <341520377+robertobulltech@users.noreply.github.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-10 02:38:14 +01:00
art804andFredApps dff02827fd Print: list printers without asking drivers; ask only about the one picked (#2192) (#3554)
* Print: list printers without asking drivers; ask only about the one picked (#2192)

On Windows, craft-print's printers() reads every driver's capabilities to
report two-sided support. Windows takes about 48 s to give up on a printer
it can't reach, such as a WSD printer on another network, so the Print
dialog waited for each one before it listed anything (#2192).

The dialog now lists printers from craft-print's printer_queues(), which
asks no driver, and asks two_sided() about the printer the user picks, on
a background thread (PdfCraftApp::two_sided_source, set by the desktop app
like printer_source). Each answer is kept for the session, so a printer is
asked about at most once, and one nobody picks is never waited on. The
"doesn't take two-sided settings" note shows once the answer arrives.

The automation printers tool still uses printers(), so it keeps reporting
two_sided.

Needs the craft-libs change that adds craft_print::two_sided.

* Build: take craft-print from storytold/craft-libs#133

Pins craft-print to the head of storytold/craft-libs#133 (b6a3b87), which
adds craft_print::two_sided as one commit on craft-libs main at 5ee809f.
craft-print is otherwise unchanged from 7ee35a9, the rev main pins now; the
other craft-libs crates stay where they are. Fetched through the
storytold/craft-libs URL, so cargo-deny's allow-git is unchanged. To be
replaced by the merge commit once #133 lands.

* Print: run at most four two-sided reads at once

A driver Windows can't reach holds its two-sided read for about 48 s, so
picking printer after printer started a thread for each. At most four now
run at once; past that, the printer picked is asked once a read finishes.

Tests: hanging reads are capped and the picked printer is asked after one
finishes; a list that already says whether a driver takes two-sided
settings is used as it is, with no driver asked.

* Repin craft-print to craft-libs main, where #133 merged (b6b8a55b)

---------

Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-10 02:17:00 +01:00
MandrakeElMagoandFredApps ca66667f33 fix: cap print dialog height to the screen so it can't overflow top/b… (#6223)
* fix: cap print dialog height to the screen so it can't overflow top/bottom

The Print dialog modal had no height constraint, so on screens where the settings+preview content (especially with the driver's Properties... panel expanded) exceeds available screen height, the dialog overflowed equally off the top and bottom, making Print/Cancel unreachable. Wrap the settings+preview area in a ScrollArea capped to the viewport's available height (read through viewport_rect(), which holds steady across frames unlike raw screen_rect), keeping the title and button row outside so they stay reachable. Includes a kittest regression test.

* Print dialog: size the scroll area from its cap, not from what the modal offers this frame

Opened after a taller dialog, the shared modal remeasures from a height of zero (#5118) and
offers less, so the settings area took the previous dialog's leftover height: Print was 408 pt
after Preferences against 674 pt fresh (dialog_chrome::a_dialog_keeps_its_own_height_after_a_taller_one).
min_scrolled_height(max_h) makes the viewport the cap; auto_shrink still fits shorter contents.
Comments cite #4252 and #5317.

---------

Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-10 01:56:21 +01:00
Joaquin ArellanoandClaude Opus 5.5 6914607f17 fix(print): M10 — Windows ya no cambia las letras de las fuentes TrueType incrustadas (#3132) (#4098)
* fix(print): M10 — Windows ya no cambia las letras de las fuentes TrueType incrustadas (#3132)

Un subconjunto TrueType incrustado numera sus glifos de nuevo (en el
subconjunto de Arial de ReportLab el espacio es el glifo 11; en la Arial
instalada, el 3). Al imprimir en Windows, Windows.Data.Pdf → Direct2D →
XPS conservaba esos números de glifo pero los dibujaba con la fuente
instalada del mismo nombre: «Revisión» salía como «Wj{nxn» y la «z» en
negrita como «Ä», tanto en las colas Brother como en la impresora Adobe PDF.

La copia que va a la cola de Windows renombra ahora cada programa
TrueType/OpenType incrustado como PdfCraftPrint<n>, en su tabla name
y en el PDF (/BaseFont, /FontName; el subconjunto conserva su etiqueta),
para que ninguna fuente instalada responda a ese nombre. Glifos,
codificaciones y /ToUnicode no cambian. CUPS y Guardar como PDF reciben
el PDF tal cual.

Tests: extremo a extremo con impose (la página se renderiza idéntica
antes y después, y el test falla sin el arreglo), fuentes que comparten
programa, Type 0, reescritura por plataforma de la tabla name y programas
dañados sin pánico. Falta comprobarlo en una impresora física con Windows.

Fixes #3132

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

* fix(print): M10 — solo se renombran en el PDF las fuentes cuyo programa se reescribe (#3132)

Si PdfCraft no puede leer o reescribir un programa incrustado (no es un
sfnt, está dañado o pasa de 64 MiB), ahora conserva también su /BaseFont
y su /FontName. Un visor que tampoco pueda cargarlo seguirá eligiendo el
sustituto por el nombre original («Arial») en vez de por PdfCraftPrint<n>.
Si no queda ningún programa reescrito, el PDF va a la cola tal cual.

Lo señaló CodeRabbit en el PR #4098. Test nuevo:
a_program_that_cannot_be_rewritten_keeps_its_name_in_the_pdf_too (falla
con el comportamiento anterior).

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

* fix(print): M10 — el renombrado de fuentes para Windows decodifica contra un presupuesto total (#3132)

Cada programa ya tenía un tope de 64 MiB, pero un PDF con muchos
programas distintos podía sumar mucho trabajo de descompresión al
imprimir. Ahora todo el renombrado comparte un DecodeBudget de 512 MiB,
el mecanismo que main acaba de introducir en print. Agotado el
presupuesto, los programas que faltan conservan su nombre, igual que uno
ilegible.

Test nuevo: programs_past_the_shared_decode_budget_keep_their_names
(falla si se decodifica sin presupuesto).

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

* fix(print): M10 — también se renombran los CIDFont escritos dentro de su fuente Type 0 (#3132)

Si /DescendantFonts lleva el CIDFont como diccionario en línea (en el
propio Type 0 o en un objeto array aparte), el recorrido no llegaba a
él. Cuando compartía programa con otra fuente, el programa se renombraba,
pero el Type 0, el CIDFont y su descriptor seguían diciendo «Arial», y
Windows podía volver a cruzarlos con la Arial instalada. Ahora el Type 0
se trata en el mismo recorrido, sin el segundo que hacía type0_names: un
CIDFont en línea apunta su programa, y al renombrar se cambian el Type 0,
el CIDFont y su descriptor en línea.

Lo señaló CodeRabbit en el PR #4098. Test nuevo:
a_cidfont_written_inside_its_type0_font_is_renamed_with_it (falla sin el
arreglo).

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

* fix(print): M10 — renamed_table ya no copia cada cadena de la tabla name (#3132)

renamed_table copiaba el texto de cada registro antes de comprobar el
tamaño del resultado: una tabla name de menos de 1 MB con 65.535
registros apuntando a una misma cadena de 65.535 bytes reservaba unos
4 GiB, y un fallo de reserva cierra el proceso al imprimir en Windows.

Ahora la tabla se lee entera sin copiar ningún texto (cada registro
guarda el offset y la longitud de origen) y después cada cadena distinta
se guarda una sola vez: los registros que compartían cadena la siguen
compartiendo y el almacén nunca pasa de lo que alcanzan los offsets de
16 bits. Una tabla que declara más registros de los que caben antes de
sus cadenas se rechaza de entrada.

Lo encontró RomanLis91 en el PR #4098. Tests nuevos:
records_that_share_one_string_keep_sharing_it (falla con el código
anterior) y a_name_table_claiming_more_records_than_fit_before_its_strings_is_refused.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 01:33:32 +01:00
FredAppsandFredApps 72e0bec32a FormCalc: a script its own clock stops is abandoned, as when the wait runs out first (#6783)
A FormCalc script under a time limit is watched twice: the caller waits
`timeout` for it, and the interpreter reads its own deadline, set to the
same `timeout`, every 256 steps. Which one notices first is down to the
scheduler, and the two reported different things: the caller's outcome is
abandoned with no changes (the form's scripts go off), while the
interpreter's kept every change the script made before the deadline.

For a click script that loops on addInstance, that difference is 1000 rows
(the most one run may add). Since repeating subforms lay out up to 1000
rows instead of 50 (#4608, landed with #6716), keeping them means laying
out a 1000-row form again, twice, which takes most of a minute in the test
build. The engine test hostile_formcalc_scripts_cannot_hang_or_bloat_the_document
took 3.0 s when the caller noticed first and 46-61 s when the script did,
so it failed its 60 s bound at random.

Now a run stopped by its own clock reports what an abandoned run does: the
same error, no changes, abandoned. XfaSession treats that outcome like a
wait that ran out (the session is dead after it). Limits other than time
(steps, loops, depth) keep their changes as before.

Co-authored-by: FredApps <FredApps@users.noreply.github.com>
2026-11-10 01:21:02 +01:00
FredApps 821636fbeb Print: each printer keeps its paper, sizing and two-sided choice across restarts (#2001) (#6779)
After a print to a printer, its paper, page sizing (Fit, Actual size,
Shrink, Custom %) and two-sided choice are remembered for that printer and
brought back when it is chosen. The printer printed to last is preselected
after a restart while it is listed, else the system default. Saved as
print_printers, most recent first, at most 32; malformed entries are skipped.
2026-11-10 00:57:33 +01:00
Osvaldo Duran MelendezandClaude Sonnet 5.5 b00a4be12a Merge upstream/main into pr/print-area
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-09 18:53:16 -05:00
0c0f0b6b56 M10: grayscale with Print as image prints on a driver that keeps no grayscale (#5806) (#5882)
* M10: grayscale with Print as image prints on a driver that keeps no grayscale (#5806)

With Print as image and grayscale, PdfCraft renders the pages as grey
pictures itself, yet the job still asked the driver for grayscale. A
driver that keeps no grayscale setting, Microsoft Print to PDF among
them, made craft-print refuse the job ("the printer's driver did not
retain the requested grayscale; nothing was sent"), so even the grey
pictures never printed. The job now asks the driver for grayscale only
when the pages aren't grey pictures already
(print::driver_needs_grayscale), in the dialog and in doc_print.

The print.grayscale parity note and the doc_print as_image description
say so, and the note names what is still missing: vector pages to such
a driver are refused rather than printed in colour.

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

* M10: the grey-pictures test checks that the pictures are grey too (#5806)

The test checked that grey pictures don't ask the driver for grayscale,
but not that the pictures are grey. A change that dropped grayscale from
the dialog's raster settings, while the job still skipped the driver,
would have printed in colour with the test passing. It now asserts both.

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

---------

Co-authored-by: austin62jake <340374338+austin62jake@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-10 00:43:00 +01:00
Osvaldo Duran MelendezandClaude Sonnet 5.5 3613779a01 Snapshot: a document change puts the copied area away
Its page index would name another page after pages were deleted or moved.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-09 18:28:36 -05:00
efd7c9fc24 fix(print): fall back to the lpoptions listing when the PPD is unreadable (#4699) (#4703)
* fix(print): fall back to the lpoptions listing when the PPD is unreadable

cupsd keeps /etc/cups/ppd/<queue>.ppd at 0640 root:cups on Arch and
similar setups, so an ordinary desktop user cannot open it. The option
reader treated that permission error as "no options", and Print ▸
Properties… said "This printer offers no settings of its own" for a
queue whose driver options cupsd was serving all along through
lpoptions.

When the PPD is missing, unreadable, or parses to no options, the list is
now built from `lpoptions -p <queue> -l`. The options Craft handles
itself are skipped, as the PPD parser does, and the starred choice is the
fallback default.

Fixes #4699

* fix(print): skip CUPS custom-value templates in the lpoptions fallback

`lpoptions -l` prints `Custom`, `Custom.<TYPE>` (`Custom.PASSCODE`,
`Custom.STRING`, …) or `Custom.WIDTHxHEIGHT` in place of the choices of an
option whose value the user has to type. Nothing in the dialog collects that
value, so offering the template sent its literal text to the driver. Those
entries are now dropped, and a starred template never becomes the default.

The choice cap is also tested before the duplicate scan, so a listing past
`MAX_LPOPTIONS_CHOICES` no longer walks the stored choices on every token.

Refs #4699

* fix(print): refuse a destination that starts with a dash

`lpoptions` parses its argv with getopt, so `-p -E -l` reads `-E` as an
option rather than as the destination; `--` cannot help, because it ends
option parsing before the `-p` that names the queue. Reject a leading
`-` on the queue and on the instance component beside the existing name
checks, before the PPD is opened or the command is spawned.

* fix(print): read the listing by its last colon, and stop inventing a default

`list_group()` prints the option as `"%s/%s:"` from the PPD's keyword and
translated text and each choice as a bare `" %s"`, so a colon can sit in
the text but not in a choice keyword. Splitting at the first colon turned
the rest of the text ("Supporto: Tipo") into invented choices; split at
the last one instead.

When the choice CUPS marks is a custom-value template, the parser dropped
it and stood the first retained choice in as the default. The UI then
showed a value the job does not use, because only options changed away
from the default are submitted. Leave the default empty in that case:
there is nothing the dialog could collect, and an invented choice is
worse than no selection.

---------

Co-authored-by: Jarvis (Hermes) <jarvis@localhost>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-10 00:24:22 +01:00
PerchAnton 8dfa52c9b5 Merge main into PR #2778 preserving feature behavior 2026-11-10 01:16:46 +02:00
Yusuf MANTAMandFredApps dc9d120fc8 feat(print): add Folio and F4 paper presets (#4777) (#4953)
Add Folio (8.5 x 13 in / 612 x 936 pt) and F4 (210 x 330 mm / 595.28 x 935.43 pt)
to the PAPERS preset table and map them to standard PWG 5101.1 media names
(na_foolscap_8.5x13in and om_folio_210x330mm) in cups_media.

Closes #4777.

Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-10 00:08:47 +01:00
abb06c70f8 M10: the Print dialog remembers two-sided, grayscale, collate, sizing, comments & forms and Print as image (#2001, #6392) (#2103)
* M10: the Print dialog remembers two-sided, grayscale, collate, sizing and comments & forms (#2001)

Persist the choices that describe how this computer prints and restore
them on the next launch, under the names doc_print takes; copies, pages,
layout, orientation and the printer still start fresh for each job.
Those names now live in one place, pdfcraft_print::names, used by the
tool and the settings file. Settings are untrusted: an unknown name or a
custom scale outside the dialog's 1..=1000 % keeps the default.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* M10: the Print dialog also remembers a booklet's binding side (#2707)

Acrobat keeps the booklet binding (left or right) between prints;
PdfCraft started at Left every time. It is now kept with the other
remembered print choices, named as doc_print names it, and an unknown
saved value keeps the default.

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

* M10: Print starts each job's copies, pages, layout and orientation afresh (#2001)

CodeRabbit on #2103: the README promised that copies, pages, layout and orientation
start fresh, but open_print carried them over through `..keep` within a session.
ISO 32000-2 Table 147 initialises these per document when the print dialog opens
(NumCopies "typically 1", PrintPageRange), so each opening now resets them to the
defaults (Selected pages still win when thumbnails are picked); two-sided,
grayscale, collate, sizing, Comments & forms, binding, the paper and the printer
picked last carry over as before. Two-sided names now include "printer" (leave it to
the printer, main's default since #2422), so that choice is remembered too.
main's paper-persistence test expected grayscale not to persist; it is one of the
remembered preferences.

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

* M10: a new print job also resets its layout's own options and leaves Label (#2001)

CodeRabbit on #2103: resetting the layout to Size kept pages per sheet, order, borders,
booklet subset and the poster options through `..keep`, so choosing Multiple again
brought back, say, a cut-and-stack order; and a job printed on Label went back to Size
without giving back the paper Label replaced. open_print now leaves Label through
set_handling (#3564) and resets the layout's own options with the rest of the job's
choices; the binding and sizing stay remembered. The README now says what resets on
each opening and what carries over.

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

* M10: the Print dialog also remembers Print as image and its resolution (#6392)

A printer that needs pictures keeps getting them after a restart: as_image and
dpi are saved with the other print preferences and restored, a resolution the
dialog doesn't offer keeping the default 300 dpi. The bad-settings checks move
to their own test.

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

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: mtlcl410 <chuanlin@niar.org.tw>
2026-11-09 23:09:03 +01:00
Grzegorz MartensandClaude Opus 5.5 4fca5783a7 M7: a Thai edit refuses only a read past its allowance, and reads its subsets' metrics within it
CodeRabbit's review of 674a20899:

- The Thai edit refused when nothing was left of its allowance, so an
  edit whose reads spent it to the byte was refused. It now refuses when
  a read was refused for want of it (`DecodeBudget::refused`).
- `LegacyThaiFont::from_pdf` read its metrics with `from_dict`, outside
  the edit's allowance, and so did the edit for each subset it measures.
  Both now read them within it (`from_dict_within`), and metrics read
  past it adapt nothing: `from_pdf` refuses the font before reading its
  program, and the edit leaves the subset unread and is refused. The
  edit's scan of every font on the page for its face name stays outside
  the allowance, as on `main`: charged, each alias of a font would pay
  again, and other faces would spend what the face's subsets need.
  `MAX_THAI_PROGRAMS` says what it pays for.
- When the `/CIDToGIDMap` a THSarabunPSK subset's Thai mappings are
  rebuilt from was left unread for want of the editor's allowance,
  `composite_glyph_maps` gave nothing, and a subset with a Latin-only
  cmap of its own was listed as it was, without its Thai mappings. The
  editor now lists no copy of it, as for metrics read past the
  allowance.

Tests: `a_thai_edit_that_spends_its_allowance_to_the_byte_goes_through`
(`pdfcraft-edit`: a subset costing exactly the 64 MiB is edited, and
one three bytes past it is refused),
`a_legacy_fonts_metrics_are_paid_for_from_the_edits_allowance` and
`a_map_left_unread_for_the_allowance_lists_no_copy` (`pdfcraft-fonts`).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
2026-11-09 21:45:29 +01:00