Files
photocraft/docs/embedded-vector-editing.md
T
1acb1f464b Integration: SVG contents open and render as on main; AI originals for other editors (#8571)
- Smart-object contents (Replace Contents, Convert to Layers, Stack Mode,
  internal Edit Contents) refused any SVG whose canvas area times its
  node count passed 24 MP, e.g. a 1920x1080 layout with 12 shapes.
  decode_source now uses the bounded image parse with File > Open's
  layered import (import_svg_bounded_images). Convert to Layers' shape
  cache cap is 1 GiB in the document's format, the import's own budget,
  not 24 MP (four full-canvas shapes in a 4K document failed).
- The bounded resolver failed the whole drawing on an embedded image it
  can't read (an unknown MIME type, a corrupt PNG); it now leaves it out
  as usvg does, so such SVGs place and render again. Byte and decode
  overruns stay errors.
- resvg gives each embedded SVG image a scratch pixmap the size of its
  target and frees it after, so the scratch budget counts the deepest
  chain of nested SVG images, not every sibling: 12 SVG icons on a 2 MP
  canvas, or one at a 12 MP render, no longer fail.
- Main's shared nesting budget (#9397) now covers the bounded path too:
  511 + 511 levels across a drawing and its embedded SVG overflowed a
  1 MB stack.
- An AI working copy is regenerated through VectorCraft only when
  VectorCraft is the editor; Illustrator or another program gets the
  original bytes. VectorCraft is recognised by bundle id, a known
  install, or its name (vectorcraft[.exe], vectorcraft-<version> AppImage,
  ai.storyteller.vectorcraft).
- updateSvg refuses an AI/PDF/EPS source (updateVectorSource saves it
  back in its own format); the doc no longer calls updateSvg "existing".
- Edit Contents on contents already open in the internal editor switches
  to that document, as main does, instead of an error.
- Stack Mode on an SVG refuses up front when one float frame per layer
  would pass 1 GiB (the layered import no longer refuses for it).
- A stored display preview still fails on an embedded image it can't
  read (strict budget, its own import_svg_preview_with_work; external-
  editor saves and conversions leave the image out as placement does); skipped embedded SVGs still use up the XML byte
  budget; an image under an unknown MIME type or with no pixels is left
  out uncharged.
- Merge: the PSD import reads a preview's native source from the
  document's global blocks; main's owned open moves them out of the
  file, so every stored preview was dropped.
- Main's strict Clippy rules on the PR's app code (explicit import, a
  Unix-only test helper, one long opt-in test).

Co-authored-by: Mocky Digital <282319807+mockydevs@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 18:13:23 +01:00

9.9 KiB

Embedded vector smart-object editing

Layer > Smart Objects > Edit Contents offers VectorCraft editing for embedded SVG, PDF-compatible AI, PDF and EPS, including payloads retained in PSD linked-layer tables. Choose VectorCraft or a local executable. PhotoCraft creates a private working copy in the original format; saving that file updates the original smart object when its parent is active and ready. Each accepted save is one undo step, including all shared instances. Placement, masks, filters and Undo/Redo remain in the existing smart-object transaction.

For a vector inside a nested PSB smart object, save the edited PSB contents back to its parent as well. Raster/PSD/PSB internal editing retains its existing behavior.

Format and platform limits

AI, PDF and EPS save-back retains the native file name and saved native bytes. A separate, source-hash-bound SVG is a display preview, never a replacement for the embedded native file. It is retained in .pcraft and a private PSD pcVP layer block; other PSD readers may ignore that block and use the layer's cached pixels. Undo restores both the original source and preview. No original file on disk is edited. Test on a PSD copy.

Format preservation is not a claim of lossless Illustrator editing: the editor regenerates its supported AI/PDF/EPS content, and unsupported features or missing fonts can change appearance. Native Adobe Photoshop/Illustrator Edit Contents acceptance remains unverified. The chooser keeps that warning explicit. updateSvg only replaces SVG contents: it refuses an AI, PDF or EPS source, which only updateVectorSource saves back, in its own format.

Native editing requires VectorCraft and its adjacent vectorcraft-cli for bounded previews, even when another interactive editor is selected. The CLI runs headless in the background, restricted to a fresh private temporary read/write root per snapshot, separate from the interactive working directory. Open and export must both succeed, with cancellation and a 60-second timeout. Each stable native save is validated before PhotoCraft accepts it.

Foreign AI files ordinarily require Save As in VectorCraft to protect the source. When VectorCraft is the editor, PhotoCraft regenerates only the private AI working copy with VectorCraft editing data before launching it, so ordinary Save can be used without changing that general protection. Illustrator and other editors get the original AI bytes. Merely opening the editor never updates the embedded original. Ordinary EPS Save needs the companion VectorCraft EPS-save support; older editors may require exporting EPS to the opened private file.

The PSD source-pixel frame is retained when PDF points differ from stored dimensions. The native file retains its own geometry; the display preview fits the original placed frame. Unsupported or oversized frames fail without changing the smart object.

Desktop integration supports an explicitly selected executable. Linux discovery checks standard native locations and a user Flatpak deployment. On Linux, choosing VectorCraft uses the desktop's Open With chooser to launch the regular application; select VectorCraft there. The writable document portal shares only the private working file. Working copies live in PhotoCraft's private cache because its isolated /tmp cannot be exported. Ordinary VectorCraft launches retain preferences and existing-window handoff instead of running a second payload inside PhotoCraft's sandbox. Reusing tabs requires the installed VectorCraft build's Linux single-instance support.

Native AI/PDF/EPS previews still need vectorcraft-cli alongside the discovered executable. The local Flatpak runtime test granted read-only access to the test VectorCraft build for that invocation. A sandboxed distribution must arrange access to its compatible converter; this source change adds no broad filesystem or host-process permissions and does not establish default Flatpak packaging acceptance. SVG editing through the portal does not require access to the VectorCraft deployment. Explicit Other application executables retain their direct-launch behavior.

On macOS, VectorCraft discovery also checks /Applications/VectorCraft.app and ~/Applications/VectorCraft.app and runs the bundle's executable directly. Other application accepts an application bundle (.app): its Info.plist CFBundleExecutable must name an executable inside the bundle's Contents/MacOS. Bundles with the application identifier ai.storyteller.vectorcraft run directly with the working file as an argument, matching automatic discovery; other bundles use /usr/bin/open -a for open-document events. Adobe Illustrator is offered when an Adobe Illustrator*.app is found in /Applications (at most one folder deep). AI/PDF/EPS previews look for vectorcraft-cli in the same bundle's Contents/MacOS, then in the other known locations; current VectorCraft macOS packages ship the CLI as a separate download, so it must be placed there or installed beside a discovered executable. These paths are unit-tested on Linux with synthetic bundles. Windows and macOS runtime acceptance has not been performed. Browser and automation paths do not launch editors; browser internal editing remains available.

This PR does not add clipboard discovery or Paste As. It stands alone on main, without requiring the clipboard or Shape Tools work in #3409/#3446. Its source-watching and bounded SVG rendering build on credited open-source work from #3409; the embedded AI/PDF/EPS extension was first submitted in Skyfuller1303/photocraft#1.

Safety

Artwork never supplies a program, command line or output pathname. Editor selection is explicit, without a shell. The interactive editor runs with its normal desktop permissions; the restricted MCP roots apply to preview generation, not to that editor process. Working copies reject links and nonregular files; Unix opens are no-follow and nonblocking. Unix save settling includes device/inode identity, including equal-time atomic replacement. Reads remain byte-bounded even if another process grows the file. A save that changes while it is being read is not reported as an error; the watcher waits for it to settle again and reads it.

Source input/output is limited to 16 MiB. Bounded SVG parsing permits one size-checked gzip layer; nested gzip is rejected both at the top level and inside embedded SVG data URLs. PSD preview validation caches shared sources and uses a 96 million pixel-work budget across distinct previews; previews beyond that budget fall back to the PSD cached appearance without changing the native source. The charge includes raster decoding, eager layer caches and embedded-SVG intermediate surfaces. Raster-bearing repeatable paint/effect resources reserve conservative repaint work; ordinary vector paths, artboard clips and blur without image references do not multiply unrelated image decoding. Decoded images and each canvas/cache component keep their independent 24 million pixel limits, with separate bounds on SVG nesting. A new saved preview also has a 96 million pixel-work validation limit. External file and URL images are not fetched. Missing system generic fonts fall back to installed families; matching typography still requires the authored fonts.

Memory-only layer.smartObjects.exportSvg, layer.smartObjects.updateSvg and layer.smartObjects.updateVectorSource validate parent document, layer, shared-content identity and source fingerprint. They never follow a linked disk pathname or launch processes. The native update command is unavailable to untrusted automation because a caller-supplied preview is not evidence of native appearance. Automation authorization also checks visible stored smart filters on every shared instance before replay, so a desktop LUT file parameter cannot inherit filesystem access. Malformed saves, locked targets and conflicting edits retain existing content. Saved updates wait through masks, gradients, other active previews and dialogs instead of interrupting an edit.

Frame recovery does not rasterize old previews or decode their embedded images just to read their dimensions. It checks the actual native-source digest, memoizes shared immutable preview identities and caps distinct old-preview XML at 64 MiB per update. Exhaustion rejects the whole update without changing any instance. PSD preview import/export keeps its separate 96 million pixel validation budget. Native and SVG source updates do not append full artwork to the replay journal; document Undo/Redo remains available.

Validation evidence

Eight contributor-owned logo PSDs were tested through their visible nested AI vectors. A real VectorCraft edit/save reached PhotoCraft's native watcher and engine; child and parent Undo/Redo and PSD export/reopen preserved the changed vector. Original SHA256 hashes were unchanged. This combines runtime editor/engine acceptance and separate UI wiring tests; it is not a claim of manual full PhotoCraft GUI acceptance. Private artwork, and private screenshots are excluded from this repository. The opt-in acceptance harness accepts local paths through environment variables; it contains no private artwork.

Embedded-vector editor chooser

Earlier SVG-only Linux Flatpak GUI acceptance verified an editor save through the writable document portal reached PhotoCraft's watcher, with an ordinary document opening as a second tab in the same VectorCraft window. Both launch orders were checked.

Regular and PhotoCraft vector documents in one VectorCraft window

Separate isolated VectorCraft GUI tests saved AI, PDF and EPS back to the same paths and opened a second document as another tab. The native-format watcher/engine test also passed inside PhotoCraft's Flatpak runtime. These tests do not establish lossless Adobe compatibility or Windows/macOS acceptance.

D-Bus tests cover chooser success/cancellation/failure and reject symlinks and FIFOs before sharing.

Offscreen dialog capture with authored bytes and mock services; no private artwork.