Commit Graph
1001 Commits
Author SHA1 Message Date
FredApps 79f1da3a93 Merge main and Hand menu test compatibility fix 2026-11-08 17:30:30 +01:00
FredApps 5ae31d3de2 fix(pdf): preserve editable import fidelity and bound caches 2026-11-08 16:58:06 +01:00
David Mann 32ce08364b Merge pull request #9991 from ljkx/feat/raw-xmp-crop
Camera Raw sidecars: apply the crop, stop reporting RawFileName (#9985)
2026-11-08 16:55:43 +01:00
Triwarr 51174ad04e PDF: review fixes for shape caches and font registration
- Render each shape cache clipped to its own bounds instead of the full
  page clip.
- Copy embedded font bytes before locking the shared text engine and take
  the lock per font, not for the whole registration loop.
- Track seen font content keys in a HashSet instead of scanning the font
  list for every glyph; hash glyph text for fake-bold pairing instead of
  cloning strings.
- Update the module and `pdf-editable` feature docs to describe text and
  accepted no-op clips.
- Poll the cancellation watcher every 20 ms; Device callbacks only cover
  paints, so a single long path still needs the watcher.
2026-11-08 14:34:23 +01:00
Triwarr d39fc3f9cd PDF: fifth review round on editable import
- Accept explicitly closed page-sized clip rectangles (m l l l l h).
- Pair fake-bold strokes through a text/font/order index instead of a
  full scan, keeping the comparison cap and cancellation checks.
- Tests: solid zero-length stroke stays editable, explicit clip
  rectangle.
2026-11-08 11:29:05 +01:00
Triwarr bf21e370f4 PDF: fourth review round on editable import
- Count actual fake-bold comparisons toward the cap instead of the
  product of glyph and stroke counts.
- Fall back for any dashed zero-length subpath (open or closed); test
  covers a stroked line followed by a closed point.
- Handle invisible glyphs before the soft-mask check so hidden text
  does not rasterise the page.
2026-11-08 09:54:52 +01:00
Triwarr 0692a3cf47 PDF: third review round on editable import
- Bound fake-bold glyph/stroke pairing by comparison count and check
  cancellation during the scan.
- Keep both knots when a closing curve returns to its start; fall back
  for a dashed single-point subpath.
- Skip inkless runs (zero-width/format characters) instead of treating
  an empty cache as a render failure.
- Track soft masks and reject the page only when paint happens while one
  is active.
- Tests: fake-bold mismatch across a path, closing curve loop.
2026-11-08 08:21:19 +01:00
Triwarr b17c98f595 PDF: second review round on editable import
- A text cache that renders empty now falls back the page instead of
  leaving blank text.
- Fake-bold strokes pair only with fill glyphs at the same paint order.
- Retain single-point closed subpaths (round-cap dots) without emitting
  duplicate phantom points; test added.
- Device methods documented; paint-order test covers text on both sides
  of a path.
2026-11-08 07:17:09 +01:00
Triwarr a3778b4476 PDF: address editable-import review findings
- Colours: AlphaColor components are straight, not premultiplied; use
  them directly instead of dividing by alpha (the opacity test now
  checks RGB, not just alpha).
- Text: key families by font content key, not PostScript name, so two
  faces with one name cannot share a family. Keep text layers at the
  path index where their glyphs were painted instead of appending them
  after all paths.
- Correctness: reject bow-tie clip paths, start a new subpath after
  close, fall back on unparseable/unsupported glyph mappings, truncated
  content, failed font registration, and shape-cache budget exhaustion.
- Cancellation: check between text-cache renders as well as between
  objects.
- Include Bezier control points in the cache-size estimate; cache the
  content hash per Hayro font identity.
- Docs: ImportOptions/CLI help now describe editable text and the
  embedded-font caveat. Tests: text cache is not blank, paint order,
  bow-tie clip, line after close, cancellation between objects.
2026-11-08 06:14:24 +01:00
Triwarr d91ea1911e PDF: content-key embedded font aliases
- Always suffix an embedded face's alias with a hash of its bytes, so the
  same PostScript name from different documents cannot collide in the
  process-wide shared engine; a face imported twice reuses its entry.
  Registration is skipped when the alias or an installed full family is
  already present.
- Release the shared text engine lock between layers so a text-heavy
  import does not block the UI's layout for the whole cache loop.
- Test: two documents with one font name but different bytes get
  distinct aliases and both families are present in the shared engine.
2026-11-08 05:02:23 +01:00
Triwarr d1e95f57a8 PDF: share embedded fonts and tighten text checks
- Register imported fonts in photocraft_text::shared() so the app can
  re-lay text after edits or DPI changes. Prefer an installed full
  family, and register an embedded face under its PostScript name
  (key-suffixed when two faces share it) so a subset cannot shadow it.
- Warn that text using PDF-embedded fonts may change font when edited or
  reopened; the document format does not carry the bytes yet.
- Reject mirrored text and b == -c matrices; scale the tolerance by the
  em size so 90-degree text stays editable. Tests for rotated and
  mirrored text.
- Use pdfcer's 0.30 em line tolerance.
2026-11-08 05:02:23 +01:00
Triwarr a18268d0d3 PDF: editable text pass and review fixes
- Text: build one TextLayer per line/style run from the Device's glyph
  draws. Derive the family from the PostScript name (subset tag, style
  suffix, MT/PS, camel spacing); italic from the font flags/attributes
  or name; bold from the weight or name; pair fill+stroke glyphs as fake
  bold (Tr 2/6) instead of a second run.
- Require an embedded font with a PostScript name; standard-14/Type 1
  substitutes and Type 3 text fall back to the raster page.
- Register embedded font bytes in the text engine, use the family the
  font reports, and render text caches on import. Tests compare the
  text composite with the raster page.
- Review fixes: accept a page-sized no-op clip; draw zero-width strokes
  as 1 px hairlines and use 1 px as the dash base; reject non-uniform
  stroke transforms; repeat odd dash arrays and keep zero dashes;
  ExtGState ca/CA already reach the colour alpha (tested); note that
  catch_unwind only guards unwinding profiles.
2026-11-08 05:02:23 +01:00
Triwarr 80a254050b PDF: editable import step 1 - paths as shape layers
Add an experimental, opt-in PDF path importer on craft-pdf's interpret
Device. Fills and strokes become ShapeLayers in document pixels with
their real colours, widths and dash patterns; text, images, clipping
paths, transparency groups, patterns, soft masks and annotations keep
the raster page with a warning, so a page is never half imported.

- ImportOptions::pdf_editable (off by default) and --pdf-editable.
- pdf-editable Cargo feature in photocraft-io; the CLI enables it.
- Shape caches are rendered within a 256 MiB page budget.
- Cancellation is forwarded through a 5 ms watcher; hostile pages are
  caught and fall back instead of panicking.

Tests cover fill/stroke colours and dashes, composite parity with the
raster page, text fallback and cancellation.
2026-11-08 05:02:23 +01:00
Triwarr 3ef91ec45a PDF: widen the dense-page cancellation margin
Raise the synthetic page to a million strokes so the 45 ms watcher
threshold keeps a wide margin on an optimised test build, and record why
the importer keeps one RenderCache per page.
2026-11-08 02:41:37 +01:00
Triwarr 1df674997b PDF: cancel dense pages, complete page labels, isolate artboards
- render_page: forward Interrupt to craft-pdf through an owned flag and a
  scoped 5 ms watcher, so dense vector pages stop mid-render.
- Warn when craft-pdf reports a substituted font (the backend does not emit
  the flag yet).
- /PageLabels: emit an entry for every page, start at 0, and write no tree
  when every artboard name is empty.
- Export budget: charge retained page data plus the largest page's two f32
  buffers instead of the whole document canvas, saturating on overflow.
- Render each artboard from a document holding only its group, so
  overlapping boards no longer paint on each other's pages. One document
  shell is cloned and reused.
- Tests: dense-page cancellation, labels with an empty middle name and all
  empty, overlapping artboard pixels, sparse 9000x9000 canvas, seven US
  Letter pages.
2026-11-08 02:34:58 +01:00
David Mann 100997baaa Merge origin/main into feat/raw-xmp-crop
# Conflicts:
#	crates/ui-egui/src/dialogs/camera_raw_ui/open.rs
#	crates/ui-egui/src/dialogs/camera_raw_ui/sidecar.rs
#	docs/file-format-parity.md
2026-11-08 01:36:16 +01:00
Triwarr 0525197133 Merge remote-tracking branch 'origin/main' into pdf
# Conflicts:
#	docs/scorecard.md
2026-11-08 01:09:29 +01:00
David Mann be26364ebc Merge pull request #12093 from yoriswind/codex/count-psd-resource-11759
Preserve Count groups in PSD resource 1080
2026-11-08 00:28:20 +01:00
5de6aa4e04 Merge origin/main into feat/psd-puppet-warp-2 (PR #8140)
Conflicts: psd_import.rs (main's vector_preview field kept, the SmartObject
still built as a binding so pin_puppet_meshes runs), smart_cmds/rendering.rs
(main's JobCtx argument kept next to the PR's placed_puppet_params).

Co-Authored-By: Tungtono <Tungtono@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 20:18:37 +01:00
Triwarr d297dd3a2d PDF: validate --pdf-dpi, band the raster conversion, complete the notices
- --pdf-dpi now rejects zero, negative, NaN and infinite values at parse time (unit-tested) instead of silently falling back to 300 DPI.
- The RGBA8 raster is converted and written in 256-row bands with a cancellation check per band, so the f32 buffer no longer duplicates a whole page; the pixel-memory estimate charges the retained raster instead of that buffer.
- docs/file-format-parity.md: the 2026-11-07 revision row is inside the revision table.
- NOTICE now reproduces the Hayro MIT notice, the Foxit/PDFium BSD-3-Clause text, Adobe's CMaps BSD-3-Clause text and the CC0 statement for the ICC profile; package.ps1 ships NOTICE and ATTRIBUTION.md in both installers.
2026-11-07 20:12:46 +01:00
Triwarr c5a9288c4b PDF: keep the craft-pdf imports off the wasm build
The module compiles for wasm (only its import entry point is stubbed), so the renderer imports and the native document types are gated; the web build no longer sees a dependency it does not have.
2026-11-07 19:52:35 +01:00
Triwarr 060d35265a PDF: keep the raster importer clippy-clean and refresh the scorecard
- Iterate the page sizes with their index instead of indexing the vector (clippy::needless_range_loop).
- Fix the .ai dispatch test's module path.
- Regenerate docs/scorecard.md after the merge (10 of 197 settings).
2026-11-07 19:46:18 +01:00
Triwarr ca92d936c0 PDF: import raster pages through craft-pdf instead of PDFium
- craft-pdf (the shared Rust/Hayro reader in craft-libs, rev c5a1cbf) renders each page; no shared library is loaded or shipped, and every desktop platform works.
- Raster pages only: editable text/vector import and the pdf_text/pdf_vectors options are removed (they can return later through craft-pdf's interpret device). Page geometry, artboards, page range, budgets, cancellation and warnings are kept; the effective DPI now respects craft-pdf's 8192 px side and 64M px page limits.
- Drops pdfium-render, the PDFium download in CI, the build-script copy and the packaging/licence staging; records the Hayro/fonts/CMaps/ICC assets in ATTRIBUTION.md and NOTICE.
- \.ai\ files starting with %PDF- now take the PDF importer, matching the comment.
- Attribution, architecture and file-format-parity docs updated.
2026-11-07 19:41:22 +01:00
yoriswind 57d346b0c4 Warn when PSD export omits nonfinite Count points 2026-11-07 09:51:42 -08:00
yoriswind 2bd2ced6e6 Write and verify Count groups in the shared layerless PSD exporter 2026-11-07 09:36:19 -08:00
yoriswind 9452f31733 Accept all eight fields in PSD Count group descriptors 2026-11-07 08:05:28 -08:00
yoriswind 08563f0f18 Format PSD Count resource import 2026-11-07 08:02:36 -08:00
yoriswind aa470b0f8e Round-trip Count groups in PSD resource 1080 2026-11-07 03:41:37 -08:00
Triwarr f7dfe7a017 PDF: test last-object cancellation and raster fidelity
- A complete import makes a fixed number of cancellation checks; cancelling on the last per-object check and on the public boundary check must both return Cancelled and never a document.
- Six page variants (plain, CropBox offset, rotations 90/180/270, oversized CropBox) compare each stored page raster with a direct PDFium render at 72, 150 and 300 DPI: 18/18 byte-identical, and the sizes prove the crop intersection (190x80) and oversized CropBox (200x100) cases.
- Both tests skip without PDFium and fail under PHOTOCRAFT_REQUIRE_PDFIUM, like the existing end-to-end test.
2026-11-07 02:34:55 +01:00
Triwarr b57603708e PDF: drop the unused image dependency from photocraft-io
The PDF export codec goes through photocraft-codecs; nothing in the crate used the image crate, so the dependency and its lockfile edge are removed. pdfium-render stays pinned exactly.
2026-11-06 23:47:23 +01:00
Triwarr 7e1de84bce PDF: document the added test functions
Every function this PR adds now has a doc comment, including the test functions in the importer, PDF export and layers_to_files suites. No behaviour change.
2026-11-06 23:44:59 +01:00
Triwarr 2f95eac75b PDF: document the importer's known limits
Module docs now state that pdfium-render 0.9.5 exposes path fill/stroke presence but not paint, width or dash (black paints, 1 pt stroke); that text colour is sampled and fonts are matched by family/name; and that only package.ps1 provisions PDFium, not the shared release workflow. The text and path extraction comments say the same where the code relies on it.
2026-11-06 23:41:53 +01:00
Triwarr eda8759d11 PDF: document the import test helpers
Raise docstring coverage on the functions this PR adds: the fixture/assertion helpers in the end-to-end test and the importer's test frame builders now have doc comments. No behaviour change.
2026-11-06 23:35:28 +01:00
Triwarr 00a1b1cd3e PDF: use PDFium's page bounding box; bound editable objects
- Map editable objects through the page's effective bounding box (media box clipped to the crop box) rather than the raw CropBox: an oversized CropBox no longer offsets text or paths from the rendered page. Covered by a fourth fixture page with CropBox (-50, -50, 250, 150) around a 200 x 100 MediaBox.
- Add a document-wide editable-object budget (20,000 layers, 1,000,000 path knots). A page that exceeds it keeps its raster, warns that its editable objects were omitted, and the unit test covers the accounting.
2026-11-06 23:12:14 +01:00
Triwarr 4f585f704b PDF: rotate/offset-aware objects, cancellation, licences, CI PDFium
- Map editable text and paths through the page's crop box and /Rotate, matching the rendered raster: box offsets, 90/180/270 rotation, rotated text transforms and rotation-aware colour sampling.
- Check cancellation while traversing page objects and before returning the import; cap text colour samples at 4096.
- The cached PDFium failure now says to restart the application after fixing the library path.
- package.ps1 stages PDFium's LICENSE and bundled licence files flat for the MSI and the portable ZIP, tags the cache with the pinned release, and verifies freshly extracted DLLs.
- ci.yml provisions the pinned PDFium for the Windows integration leg and requires it there; local runs still skip explicitly.
2026-11-06 22:48:30 +01:00
Triwarr 95908e2b92 Pin pdfium-render exactly to the verified wrapper
Same reasoning as the wintab-sys pin in #11331: PDFium is FFI-loaded at run time, so a lockfile refresh must not move the wrapper under the pinned DLL release. Bump deliberately and re-check both the wrapper and the DLL release pin in packaging/windows/package.ps1.
2026-11-06 22:16:32 +01:00
Triwarr fabfbb5d5a PDF: fix segment closing, admission, glyph colour and PDFium reuse
- Process a closing segment's own geometry before marking the subpath closed, so a closing Bezier endpoint cannot leak control points into the next curve.
- Estimate retained memory from tile-aligned page bounds (including the page's X offset) instead of raw pixels: a 1 x 10,000 px page admits its 40 tiles, not 10,000 pixels.
- Sample text colour from the glyph ink (the pixel farthest from the box's dominant colour) instead of the bounds' top-left corner, which was usually background or antialiasing.
- Cache the PDFium bind: pdfium-render binds once per process, so a second PDF import in one session failed with PdfiumLibraryBindingsAlreadyInitialized.
- Add a PDFium-backed two-page end-to-end test with a transformed path on page 2 and non-origin red/green text at 72 and 300 dpi; it prints an explicit SKIPPED line when PDFium is unavailable.
- package.ps1: pin pdfium-binaries chromium/8138, verify the archive and any cached DLL against SHA-256, drop a stale bin/pdfium.dll before extraction and check tar's exit status.
2026-11-06 22:15:50 +01:00
Triwarr 192b075bfa PDF: map editable objects through one page-to-document transform
- Paths on page 2+ were placed without the page's document X offset; text and paths now share PageFrame::to_doc, which applies the DPI scale, the Y flip and the page offset in one place.
- Flip Y in pixels and round once, so text placement, text colour sampling and path points all stay in the same coordinate system.
- Add unit tests for 72/300 dpi, the page-2 offset and the sampled colour; they need no PDFium.
2026-11-06 21:29:06 +01:00
Triwarr 36e7c50178 PDF: transform imported paths by their object matrix
- Apply PdfPageObject::matrix() to path segments: PDFium returns raw object-space points, so scaled or rotated paths landed in the wrong place.
- Flip path y with the page height in pixels, not points; paths were off-canvas at any DPI other than 72.
- Take fill and stroke presence from the path's draw mode: stroke-only paths no longer get a black fill, and paths that are neither filled nor stroked are skipped.
- Estimate import pixel memory as retained tiles (4 B/px over all pages) plus the converting page's peak (24 B/px), defaulting to a 2 GiB budget when the caller sets none. Reuse the RGBA copy and reserve the f32 buffer fallibly.
2026-11-06 20:34:01 +01:00
Triwarr adbe906eaf PDF: fix CI packaging and CodeRabbit findings
- Stage pdfium.dll for the MSI fixtures (install-policy payload) and for the real package
  stage/portable zip; the package script downloads it before cargo.
- Regenerate docs/scorecard.md for the new Preferences fields.
- Text y positions convert the page height to pixels; invisible PDF text stays hidden.
- Page ranges that start past the PDF are refused; zero first/last bounds are independent.
2026-11-06 20:11:03 +01:00
Triwarr fb66c11df6 PDF: CodeRabbit SVG signature fix, sampled text colour, Preferences page fields
- A PDF named .svg now keeps the PDF importer; other signatures beat the .svg suffix fallback (regression test).
- Text layers sample their fill colour from the rendered page and use the PDF font family/name.
- File Handling preferences expose pdf_dpi, pdf_first_page and pdf_last_page; the page range maps to ImportOptions.pdf_pages.
2026-11-06 19:35:02 +01:00
Triwarr 244a6287ab PDF: import options (page range, DPI, editable text/vector) and DLL packaging
- ImportOptions gains pdf_pages (1-based inclusive), pdf_text and pdf_vectors;
  the importer maps PDF text objects to editable text layers and vector paths to
  shape layers through the effective DPI.
- photocraft-cli convert gains --pdf-dpi and --pdf-pages.
- Preferences gain pdf_dpi/pdf_pages, wired through jobs::import_options.
- apps/photocraft/build.rs copies PDFIUM_DLL beside the exe; the MSI installs it.
2026-11-06 19:15:09 +01:00
Triwarr 06a6442076 PDF: SVG precedence, hidden artboards, export budget, writer cancellation 2026-11-06 19:15:08 +01:00
Triwarr ef7699ae9a PDF: render each artboard rect instead of a whole-document crop 2026-11-06 19:15:08 +01:00
Triwarr b1870f1950 PDF: second CodeRabbit round (render size, buffer estimate, label tree) 2026-11-06 19:15:08 +01:00
Triwarr 94a4998208 PDF: address CodeRabbit review (cancellation, budgets, labels, export edges)
- Cancellation: the importer and the PDF writer take the Interrupt and check between pages.
- Physical size: the effective DPI keeps each page print size when budgets cap the raster.
- Oversized pages: final dimensions are checked before rendering.
- Memory: pages go straight into layer surfaces; the aggregate pixel estimate is admitted.
- Labels: /PageLabels (UTF-16BE) carry artboard names; no label is drawn outside the media box.
- Metadata: the artboard export warns when free-form text metadata is dropped.
- Export: hidden groups report their children; non-string modes are rejected; case-insensitive
  filename collisions are suffixed.
- Dispatch: a recognised raster renamed .pdf goes to the flat importer; .ai keeps its path.
- Platform: the PDFium recovery message names the actual library.
2026-11-06 19:15:08 +01:00
Triwarr 3a1b41f0c6 PDF: bound the import canvas
The importer budgets the per-page raster (100 M px) and the artboard strip (200 M px): an
oversized page is scaled down, and pages that would exceed the strip budget are skipped with
a warning, instead of allocating a multi-gigabyte union canvas. The page-count cap stays 16.

Also applies cargo fmt to the new PDF code and the export-recursion test.
2026-11-06 19:15:08 +01:00
Triwarr 399cd6ea4d PDF: import every page as an artboard; export a page per artboard
The PDF importer renders each page with PDFium at the import DPI (default 300), lays the
pages out side by side and wraps each in an artboard, so a 2-page PDF opens as 2 artboards
and saves back as a 2-page PDF (one page per artboard, page-sized, labelled). The import
caps at 16 pages for now.

The PDF writer now takes a list of pages: shared font/ICC/selection objects, one image per
page, and the existing one-page export is the single-page case. Artboards with vector/text
layers are rasterised in this path.

Tested: artboards_export_as_one_page_each; convert sample.pdf app-multi.pdf (2 pages),
rendered back with the probe.
2026-11-06 19:15:08 +01:00
Triwarr 95c9d3c9eb PDF import: open the first page with PDFium
File > Open, drag-and-drop and photocraft-cli now accept PDF files. The first page is
rendered with PDFium at 300 dpi (ImportOptions.pdf_dpi), built through the flat
importer, and the document resolution keeps the page's print size. The page count is
reported; multi-page import is the next step (#2541 / FILE-215-10).

- crates/io: pdf_import module, native-only pdfium-render + image deps, import and
  preflight dispatch (.ai keeps its existing path).
- PDFium loads from the executable's folder or PDFIUM_DIR.
2026-11-06 19:15:07 +01:00
FredApps d2ce418bb3 Merge pull request #11641 from wanikhawar/claude/agitated-jones-8e1a8e
A little free memory no longer refuses every PSD; the refusal says what to do
2026-11-06 18:36:17 +01:00