* 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>
* 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>
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>
* 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>
* M10: macOS print jobs name their title and owner (#5743)
lp sends no com.apple.print.JobInfo.* attributes, and Kyocera's macOS
filter crashes without PMJobName and PMJobOwner, so the job stops with
cups-filter-crashed and nothing prints. Both go to lp as job options, in
the form lp_args passes on: printable ASCII, up to 64 bytes.
* M10: keep macOS job metadata as the name CUPS should send (#5743)
Review of #5757, checked against this Mac's libcups in memory:
- `'` and `\` were consumed as quoting and `{` opened a collection, and a
bare true/false became a boolean, so a filter reading PMJobName got
nothing or the wrong type. They now become `_`, or the fallback.
- CUPS keeps the last of a repeated option, ignoring case, so the
defaults replaced a value a doc_print caller had set. They are now
added only for a key the job leaves out.
- Nothing proved the job info reached the spooler. A test now runs both
submit paths against a stand-in `lp` on PATH.
The pdfcraft-print unit-test executable imported windows.data.pdf.dll and
prntvpt.dll at load time (the windows crate binds them with raw-dylib), so
on a Windows installation without them it could not start, and the tests
of the missing-DLL guard never ran there. crates/print/build.rs now passes
/DELAYLOAD for both and delayimp.lib on MSVC, as the applications' build
scripts do. Link arguments from a build script reach only this package's
own executables, so dependents are unaffected.
dumpbin /imports: before, both DLLs under "the following imports"; after,
under "the following delay load imports". A copy of each test binary with
prntvpt.dll renamed to a DLL that doesn't exist: the old one exits with
0xC0000135 (STATUS_DLL_NOT_FOUND) before main, the new one starts and runs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCfwzyRXj4VfQAVVdv
The area Take a Snapshot copies stays outlined with a small menu under it:
Print area… and Save as image… (PNG). Print area… opens Print with
"Selected area (page N, size)" under Pages to Print; the area prints alone,
as a page of that size, with Fit, Actual size, Shrink or a custom scale,
clipped to the area. Multiple, Booklet, Poster and Label stay for pages.
- print: Settings.area (one page's rectangle in display space, y up),
placed with place_crop under a Size layout; other layouts are refused.
- ui: PrintDraft.area and Which::Area; only Size is offered while the area
is chosen. Another tool puts the area and its menu away.
- automation: doc_print takes area [x0, y0, x1, y1] from the top-left.
- Five new labels in all 22 catalogs (ATTRIBUTION.toml checksums
refreshed); parity print.selected-area; ROADMAP progress log.
Requested in #2051.
Carries the review fixes:
- Save as image: save this tab's area, not the last snapshot taken anywhere
- Web downloads: type the file by its extension; keep the snapshot area after Print area
- Clear the copied area of every tab when Snapshot is left
- i18n(ui): carry this PR's new wordings in the catalogues that must cover them
- style: rustfmt after the merge with main
- Use Id::unique for the snapshot area menu (Id::new is deprecated in egui 0.37)
- rustfmt
- print area: refuse an area that isn't finite, and a page out of range first
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review follow-up on #2701: the test no longer requires the DLLs in the
host's System32 (the trimmed installations this supports lack them).
Instead a test-only override points the lookup at an empty folder and
submit, submit_with_progress and printers are called through: printing
is refused naming the DLL and no printers are listed, before any call
into the delay-loaded DLLs. The job names a printer that doesn't exist
and the bytes aren't a PDF, so a missing guard can't reach a real one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pdfcraft.exe and pdfcraft-cli.exe imported windows.data.pdf.dll and
prntvpt.dll at load time (through craft-print's printing), so a trimmed
Windows installation without them refused to start the program at all.
The executables now delay-load the two DLLs, and the spool adapters
check that they exist before calling in: without them the printer list
is empty and a print job fails with a message pointing to Save as PDF.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keep the print module split and reapply the /Contents space join in
imposition::decoded_contents, matching the renderer and the organize pruner.
Co-authored-by: jonathanwxh-cell <jonathanwxh-cell@users.noreply.github.com>
Review follow-ups to the landscape fix rebased from #3068:
- Both submission paths add the orientation through
pdfcraft_print::add_cups_orientation, which never adds it over an
orientation the job already names (a driver choice in the Print
dialog, or a caller's doc_print options), so lp never gets it twice.
- doc_print adds it inside spool_job, next to the paper (#3752), so its
test checks the job it sends.
- The Print dialog takes a stand-in for the spooler in tests
(PdfCraftApp::spooler), like printer_source and options_source, and a
test follows a real Print click to the job.
- Doc comments for the tests beside the change.
Checked on macOS with cupsfilter (cgpdftoraster, AirPrint PPD): a landscape
sheet sent as before lands unrotated at 100% and cut off at the paper's
right edge (#3739); with the option it is turned inside the margins.
Co-authored-by: Zach <90340773+zdblazer@users.noreply.github.com>
On macOS and Linux the job sent no orientation, so CUPS left a landscape
sheet unrotated and shrank it into the portrait paper named by `media`
(Letter, A4, ...). Printing in Landscape therefore came out as a small
landscape page on a portrait sheet.
Add `pdfcraft_print::cups_orientation`, which gives
`orientation-requested=4` when every sheet is landscape, and attach it to
the job in two places:
- the Print dialog (`print_now`);
- the headless `doc_print` tool, which builds its own spooler job, so the
automation tool and MCP server print the same way. An
`orientation-requested` the caller already chose in `options` stands.
Neither applies on Windows, whose print ticket sets the orientation. A
job that mixes orientations gets nothing, since the option applies to the
whole job.
Record the new test as evidence on the `print.orientation` parity entry,
saying what is still only checked by hand, and mention the option in the
print crate README's CUPS paragraph.
Checked against Apple's CUPS filters with a generic PostScript queue: a
792x612 sheet sent to Letter without the option stays unrotated at about
77% scale; with it the page is turned 90 degrees to fill the sheet. The
new test fails with the fix stubbed out.
* Record successful PdfCraft web application check
* E21: bound startup requests and validate font and license inputs
* E21: separate pending control completion and gesture regression phases
* M-egui037: enforce control admission and per-family font notices
* M-egui037: qualify capture fixes and document migration behavior
* egui-037: identify current and historical qualification results
The print filter read /Subtype with a direct-only lookup, so a standard
annotation whose /Subtype is an indirect reference (ISO 32000-2 §7.3.10)
looked like an unknown type and an Invisible flag dropped it from print
(Table 167 applies only to non-standard types, Table 171). The subtype is now
resolved through the document first.
Also removes a stray cell separator in the hayro-interpret row of
vendor/README.md that pushed the test references for patches (44)-(56) out
of the table.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0175FWj4xFhMhSH3UpMU8DSC
An annotation whose Invisible flag (bit 1) is set and whose /Subtype is none
of the standard types of ISO 32000-2 Table 171 is no longer drawn (Table 167)
or printed (Table 167: "do not print it even if the Print flag is set"). A
/Popup annotation's /AP is no longer painted as page content: per §12.5.6.14 a
popup has no appearance stream of its own and is shown by the viewer as a
window for its parent. Printing already left popups out.
Link appearances are painted as before (§12.5.5).
hayro-interpret patch (56), recorded in vendor/README.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0175FWj4xFhMhSH3UpMU8DSC
dialog hides Two-sided while Booklet is chosen and prints the booklet two-sided itself
(Using Acrobat X Pro, Print dialog box options: "Acrobat automatically enables duplex
printing, if available, for booklet printing"; later manuals and the current help no
longer say so, and on a current Acrobat the Two-sided control is shown for Size and
hidden for Booklet with the same duplex-capable printer). print::booklet_duplex gives a
booklet's setting: both sides flip on the short edge, the fold of a 2-up sheet turned
sideways; front or back only is one pass of a manual duplex and prints one-sided. The
Print dialog hides Two-sided while Booklet is chosen and sends that setting, leaving the
Two-sided choice as it was for the other layouts (and as #2001 remembers it); doc_print
applies the same rule. This replaces the first version, which rewrote Two-sided to the
short edge when Booklet was chosen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>