Commit Graph
7 Commits
Author SHA1 Message Date
Marco Arnulfo 79d726f856 LRC-PRINT-PAGE: Page Options print page numbers, page info and crop marks (gap 15)
The Print dialog's Page section gets Lightroom's Page Options for Single Image
and Contact Sheet: the page number at the bottom right, the print settings line
(sharpening, profile, resolution) at the bottom left, and crop marks at the
corners of each photo. They are `print.set {page: {pageNumbers, pageInfo,
cropMarks}}`, saved with templates, drawn in the preview and composed into the
PDF; marks and text turn white on a dark page.
2026-10-15 15:38:03 +02:00
Brandon Thomas b29a1a8cc2 Merge PR #1215
# Conflicts:
#	crates/engine/src/lib.rs
#	crates/engine/src/pdf.rs
#	crates/ui-egui/src/lib.rs
#	crates/ui-egui/src/menus.rs
#	crates/ui-egui/src/panels/dialogs.rs
#	crates/ui-egui/src/state.rs
#	docs/gaps.md
#	docs/parity-checklist.md
2026-10-15 00:22:08 -04:00
Atmik Shetty 65775b4716 LRC-PRINT-JOB: colour-managed print PDFs (printer profiles, intent, black point compensation, print adjustment, print sharpening)
print.exportPdf now converts each composed page to the job's colour target and writes it into a
print-ready PDF:

- PrintJob gains `color` (PrintColorSettings): Managed by Printer (sRGB / Adobe RGB, profile
  embedded, no output intent) or a printer / paper .icc / .icm converted here and named as the
  document's output intent; perceptual or relative colorimetric with black point compensation;
  Print Adjustment brightness / contrast; print sharpening Low / Standard / High for Matte or
  Glossy; 16 or 8 bits per component. print.set / print.get and print templates carry it;
  out-of-range values are refused when set.
- Each photo is sharpened for the paper right after it renders at its print size.
- print/output.rs converts and Flate-compresses one page at a time (memory holds one page's device
  samples) into ICC-tagged images through engine::pdf; the PDF is 1.6. The 256 MiB cap counts the
  compressed pages.
- A printer profile that can't be used (missing, too large, not a profile) fails the print before
  anything renders, naming the file.
- contact_sheet's PDF writer goes back to private: only the contact sheet uses it.

Tests: a printer profile reaches the PDF as ICCBased images plus an output intent, a junk profile
fails naming the file, colour settings validate with the job, sharpening and media round-trip
through print.set / print.get, a missing profile fails before rendering with no activity row;
the existing print and CLI tests follow the PDF 1.6 output. Docs: LRC-PRINT-JOB and gap 15.
2026-10-12 15:16:32 +05:30
Atmik Shetty 32b5aefc5b LRC-PRINT-GUIDES: the Print dialog (File → Print…) with page preview, rulers, guides and cell editing
File → Print… (⌘P) opens the Print module as a dialog: settings on the left,
the page drawn to scale on the right with the photos as they will print (fit
or Zoom to Fill, turned by Rotate to Fit, Photo Border, Inner Stroke, page
background).

Settings column: templates (save, apply, delete), layout style, image
settings, grid / package cell controls (standard and custom cell sizes, Auto
Layout, New Page, Clear Layout), rulers and guides (units in/cm/mm/pt, snap
off/cells/grid, grid size, margins, bleed, page grid, image cells,
dimensions), page setup (paper, orientation, margins), page background and
the print job.

Preview: rulers in the chosen unit, dashed margins and bleed, page grid,
dimension labels, page navigation. In the package styles cells are selected,
dragged (print.cell.move) and resized from a corner handle
(print.cell.resize) with the guides' snapping, arranged from the inspector
row or a context menu, and given a photo (Custom Package). Every change is a
print.* command; the drag is measured from where the pointer went down so
the click-versus-drag slop is not lost.

Print to PDF… picks a file and renders on a background thread with an
activity-stack row, cancellation and original protection, like the contact
sheet, which keeps working unchanged.

Headless tests drive the dialog with real pointer input through the control
channel (print:cell:N, print:resize:N, button:print*): styles and checkboxes,
add / drag / resize / arrange / delete, snapping to a neighbour, Auto Layout
and pages, templates, the PDF, the activity row, and that the dialog and its
buttons fit the window.
2026-10-12 15:15:33 +05:30
Atmik Shetty 3b32f82e9e LRC-PRINT-LAYOUTSTYLE: print.* commands for the layout styles, cells, templates and PDF
The Print module's state lives in the session (Session::print), so the app,
CLI, control channel and MCP share one print: layout style (Single Image,
Contact Sheet, Picture Package, Custom Package), page setup, grid, image
settings, page background, guides and job. 18 commands, none journaled
(nothing here touches the catalog):

  print.get / set / reset      set merges a partial patch, validates the whole
                               result and changes nothing on error; a new
                               paper or margin pulls cells back inside
  print.cell.add|move|resize|delete|stack|photo|page
  print.layout.autoLayout|newPage|clear
  print.exportPdf {path, ids?} composes and writes the PDF with an activity
                               row, refuses to replace an original
  print.template.list|save|apply|delete

Templates keep layout, image settings, page and job (not the photos assigned
to cells, not the guides) and are saved in the library's prefs.json next to
the export presets. They are stored as JSON and checked when applied, so a
template from another version or a hostile one is an error on use and never
makes the preferences file unreadable.

Tests drive every command through the dispatcher (hostile numbers, unknown
keys, caps, persistence across reopening a library) and a CLI end-to-end test
chains set / add cells / Auto Layout / PDF in one run.
2026-10-12 14:35:03 +05:30
Atmik Shetty 8336f06d28 LRC-PRINT-IMAGESETTINGS: compose print pages (fit / Zoom to Fill, Rotate to Fit, border, stroke, background)
print/compose.rs turns a layout and its photos into PageRasters: 16-bit
interleaved RGB encoded in Rec. 2020 at the job's pixel density. Each cell's
photo is rendered with the export pipeline at exactly the size the cell needs,
then fitted (whole photo, centred) or zoomed to fill (centre crop), turned a
quarter clockwise when Rotate to Fit makes it print larger (or crop less),
framed by the Photo Border (package styles only) and finished with the Inner
Stroke drawn inside the photo edge. The page background, border and stroke
colours are given in sRGB and converted to the page encoding.

Photos go to cells by layout style: Single Image and Contact Sheet paginate
the selection, Picture Package repeats the first photo, Custom Package prints
each cell's own photo. The job is prepared on the session and run off it with
progress and cancellation, like the contact sheet; page and job pixel counts
and page counts are capped so a hostile resolution or paper cannot exhaust
memory.

print/output.rs holds the interim PDF writer (Rec. 2020 to 8-bit sRGB JPEG
pages sized to the paper in points) through the contact sheet's Pdf, now
pub(crate). PrintJob carries the print resolution (72 to 720 ppi, 240 default).

Tests draw on synthetic images for exact pixels (borders, strokes, crop,
rotation direction, resampling) and on the demo library for whole pages.
2026-10-12 14:28:40 +05:30
Atmik Shetty 4f1ed6df65 LRC-PRINT-LAYOUT: the print layout model (paper, margins, grid, package cells, packer, snapping)
crates/engine/src/print/layout.rs is the pure page model the Print module
builds on: ten named papers plus custom, orientation, margins and the
printable area; Single Image, Contact Sheet (grid with spacing and square
cells), Picture Package and Custom Package styles; package cells with a
stacking order (send to back / backward / forward / bring to front); a
deterministic MaxRects packer behind Auto Layout (largest first, earlier
pages filled before a new one opens, a cell turned a quarter only when it
fits nowhere as given); snap-to-cells and snap-to-grid helpers; ruler units
and guide options.

All lengths are inches in page space, after orientation. Every number from
outside is checked (NaN, infinity, negative, oversized, cell and page caps)
and Layout::validate guards saved layouts.

No command or UI reaches it yet, so the parity rows keep their status.
2026-10-12 14:21:42 +05:30