// ZPHOTO — PHOTOSHOP + ILLUSTRATOR PORT REPORT

One Rust engine (zphoto-core) · raster editor (Photoshop/GIMP port) + vector mode (Illustrator port) · vectors render into the same raster layer stack · source-derived at 793a73fed4

>_EXECUTIVE SUMMARY

zphoto is a single Rust engine that ports two Adobe products into one command surface. The raster side is a Photoshop / GIMP port — layers, masks, blend modes, smart objects, 444 commands across 19 groups, with an 8/16/32-bit (f32 working-space) pixel pipeline. The vector side is an Adobe Illustrator port — Bézier paths, gradients, meshes, patterns, Pathfinder, symbols, type, masks and SVG/PDF/AI/EPS round-trip, exposed through 114 vec.* commands — that rasterizes into the raster layer stack, so layer opacity, blend modes, masks, filters and PSD save all apply to vector artwork for free. Every number below is grepped from source, not estimated.

444
Raster Commands
114
Vector Commands
680 / 681
Engine Tests Passing
8 / 16 / 32
Bit Depth (f32 core)
342
Photoshop Features ✅
119
Illustrator Features ✅
12,521
Vector Engine LOC
19
Raster Command Groups

Photoshop port — PORT_CHECKLIST.md (347 rows, 346 in scope)

342 ✅ · 2 🚧 · 2 ⬜ · 1 N/A — 98.8% done / 99.4% incl. partial

Illustrator port — VECTOR_CHECKLIST.md (120 rows, 119 in scope)

119 ✅ · 0 🚧 · 0 ⬜ · 1 N/A — 100%

One engine test is currently red: pick_and_histogram_read_the_render (tests/engine.rs:646) still asserts that an out-of-bounds image.pick is an error, but the command was deliberately changed to return {"color": null} instead. The assertion is stale, not the engine.


01RASTER ENGINE — PHOTOSHOP / GIMP PORT

Unique group.verb dispatch arms grepped from zphoto-core/src/lib.rs. The feature matrix in PORT_CHECKLIST.md stands at 342 ✅ / 2 🚧 / 2 ⬜ / 1 N/A.

GroupCmdsArea
filter.*138Blur / sharpen / noise / distort / stylize neighbourhood + gallery filters
op.*80Point ops — curves, levels, hue/sat, exposure, adjustments, perceptual audits
layer.*65Layers, masks, blend modes, smart objects, groups, layer styles
image.*36New/open/save, mode & bit-depth convert, resize, crop, transform, colour table
select.*31Marquee, lasso, magic wand, refine, feather, grow/shrink, texture
paint.*24Brush, pencil, eraser, clone, smudge, dodge/burn, gradient
fill.*15Bucket, pattern, gradient, content-aware, fill layers, generative render
edit.*8Undo / redo / copy / paste / fade / history
action.*7Actions panel — record / replay macros
path.*6Pen paths, path ↔ selection, stroke path
comp / sampler10Layer comps + perceptual edit attribution; Info-panel colour samplers and their solve targets
program.*4Edit-program compiler (analyze / optimize / apply) and Constraint Solve
brush / channel / note / pattern / text / project20Brush presets, spot channels, notes, define pattern, type, native save/load
19 groups444Raster command surface (excludes the 114 vec.* below)

Precision: pixels carry an 8/16/32-bit depth over an f32 working space; image.convert changes depth; 16-bit PSD encode/decode round-trips. Remaining: a few advanced filters / niche adjustments (🚧/⬜); 32-bit PSD currently folds to 16-bit on save; native-project pixels persist at 8-bit (depth tag preserved).


02VECTOR ENGINE — ILLUSTRATOR PORT

114 vec.* commands · src/vector.rs 12,521 LOC · f64 geometry, anti-aliased rasterizer (4× vertical SSAA + analytic horizontal span coverage), non-zero & even-odd fill rules.

AreaStatusWhat's implemented
Document / artboardsNew, layers, multiple artboards + per-artboard render (vec.artboard.add), guides
DrawingRect/round-rect, ellipse, polygon, star, line, arc, spiral, grid, flare, pen (Bézier), pencil, blob brush, compound paths
FillSolid, non-zero/even-odd, linear/radial gradients, gradient mesh, freeform gradient, pattern swatches, Live Paint
StrokeWidth/colour, caps, real miter/bevel/round joins, dashes, gradient stroke, arrowheads, variable-width profiles
Transform / arrangeMove/scale/rotate/shear/matrix, reflect, transform-each, 3D rotate / Extrude / Revolve, group/ungroup, z-order, align/distribute, radial / grid / mirror Repeat
PathfinderUnite / Intersect / Minus / Exclude, Divide / Trim / Merge / Crop / Outline, Outline Stroke, Offset Path, Shape Builder
TypePoint type, type-on-path, area type (word-wrap), threaded text, text wrap, change-case, Create Outlines
Masks / blend / effectsClipping mask, opacity mask, 29 per-object blend modes (the shared LayerMode set), Warp envelopes, mesh envelopes, Liquify, Free Distort, glow / scribble
SymbolsSymbol registry + placed instances, Symbol Sprayer, Symbolism Shifter/Sizer/Spinner/Screener
File I/OSVG import + export (full round-trip), PDF / AI / EPS import + export, raster export, Image Trace, trim marks
120 rows119 ✅0 🚧 · 0 ⬜ · 1 N/A (Shape Builder's interactive region-pick is editor UI)

03REMAINING

The ⬜ / 🚧 items left in the two checklists, plus the deliberate scope limits recorded in PRECISION_REFACTOR.md. VECTOR_CHECKLIST.md has none left — the Illustrator roadmap is closed.

Single-Channel Buffers (🚧)

BaseType GRAY desaturates and INDEXED carries a real editable colormap, but pixels stay RGBA-backed — there is no single-channel or index buffer behind either mode.

Tiled Buffer (⬜)

Layer pixels are a flat Vec<RgbaF>; GEGL-style tiling is an optimization left for later.

Progress Streaming (⬜)

Long-running ops complete atomically — no event sink emitting progress, as the sibling engines have.

GUI Polish Gate (🚧)

Terminal, hooks editor, file browser and the 27-locale catalogue are wired; the 18 i18n proof tests, shared-component tables and the rest of the haxor script surface are not.

32-bit PSD

32-bit documents fold to 16-bit channels on PSD save; 32-bit channel I/O is a follow-up.

High-Bit Project Persistence

The native .zpo format stores the document's depth but persists pixels at 8-bit, so older projects load unchanged.

16-bit PNG Export

PNG export still routes through the 8-bit image-crate path even for 16/32-bit documents.

Float Composite

Image::render() returns the 8-bit display composite; per-layer float precision lives in the layer buffers where the operations run.


?KEY DESIGN DECISIONS

Why the two ports share one engine.

Vectors Render Into Raster Layers

vec.render rasterizes each vector layer into a raster Layer, so the existing compositor — opacity, the 29 LayerMode blend modes, masks, filters, PSD/project save — applies to vector artwork with zero new code.

One Command Surface

Both engines dispatch through Engine::invoke(cmd, args). Raster is image.* / layer.* / op.* / filter.* / …; vector is vec.*. Hosts (Tauri, JUCE WebView, headless tests) talk to one transport.

f64 Geometry, f32 Pixels

Vector geometry is resolution-independent f64; the raster pipeline computes in an f32 working space and quantizes to the document's 8/16/32-bit grid per command.

Region-Trace Operators

Pathfinder, Offset Path, Outline Stroke, Create Outlines and Image Trace all reuse one mask → boundary-trace pipeline — exact for axis-aligned shapes, supersampled for curves.

SVG as Interchange

SVG export and import round-trip paths, shapes, gradients and text. AI files (PDF containers) route through zpdf-core.

Reused Glyph Rasterizer

Vector type renders through the same bundled-font text module the raster engine uses — no duplicate glyph code, and Create Outlines just traces its output.