High-bit image pipeline, WYSIWYG editor, and editor UX #47

Merged
parkerhdavis merged 4 commits from high-bit-image-pipeline into main 2026-06-02 00:09:41 -06:00
parkerhdavis commented 2026-06-02 00:08:59 -06:00 (Migrated from github.com)

Reworks Garnet's image stack to preserve precision, fixes the editor's saved-output-vs-preview mismatch, makes dev-build saves fast, and adds editor input shortcuts + a save lock.

32-bit float pipeline (high-bit workflows)

The shared image stack was 8-bit internally — every editor adjust op and texturing op called to_rgba8(), so a 16-bit source truncated at the first step and the existing png16 export just re-inflated 8-bit data. The pipeline now works in a normalized Rgba32FImage end-to-end and quantizes only on save:

  • Editor (editor/{adjust,transform,pipeline}.rs) and the 3D Texturing plugin (texturing/{channel_pack,normal_map}.rs) + Automations FlipGreen/Normalize steps all process in f32; png16 export is now real.
  • image_io: load_exr/save_exr carry true f32 (EXR was tone-mapped to 8-bit on load); save_image gains a real tiff16.
  • Editor save UI gains an explicit format + bit-depth selector (PNG 8/16-bit, TIFF 16-bit, TGA, OpenEXR) since the extension can't express png8 vs png16.

WYSIWYG color fix

Saved files didn't match the editor preview (pre-existing on main) — hue/saturation edits especially could come out magenta/cyan. The preview is a CSS/SVG filter: chain but the commit used different math (HSL hue/saturation, additive brightness) in a different order. The commit now replicates the W3C Filter Effects math the browser uses (hue/saturation color matrices, brightness multiply) and canonicalizes op order to color → curve → white-balance → geometry. What you see is what you save.

Dev-build save perf

A 30 MP JPEG save hung the editor ~10s in make dev (vs ~1.3s release) — purely unoptimized debug codegen of the image codecs. Two Cargo.toml profile fixes: optimize every dependency in dev (catch-all package."*", fixing decode), and bump our own crate to opt-level 1 (the JPEG encoder + f32→u8 conversions are generic, so their hot loops monomorphize into our crate and weren't covered). ~12s → ~1.5s in dev, near release.

Editor UX

  • Modal save overlay that dims the app and locks input while a commit is in flight.
  • Shortcuts: Ctrl/Cmd+E open editor from the asset view, Ctrl/Cmd+S save, Ctrl/Cmd+R revert (confirm), Esc exit (confirm when unsaved). The \ original-image peek already existed.

Notes

  • Garnet's adjust math now diverges from standalone Packi (still 8-bit/HSL); the eventual shared processing crate should adopt this f32 + filter-math version.
  • An ignored bench_commit / repro_commit_real harness lives in editor/pipeline.rs for profiling.

Verification

make lint typecheck test green (130 Rust tests, 13 frontend tests, clippy, tsc). Precision round-trip and EXR f32 round-trip covered by tests; WYSIWYG output verified by rendering a hue+warm edit on a real 30 MP photo.

Reworks Garnet's image stack to preserve precision, fixes the editor's saved-output-vs-preview mismatch, makes dev-build saves fast, and adds editor input shortcuts + a save lock. ## 32-bit float pipeline (high-bit workflows) The shared image stack was 8-bit internally — every editor adjust op and texturing op called `to_rgba8()`, so a 16-bit source truncated at the first step and the existing `png16` export just re-inflated 8-bit data. The pipeline now works in a normalized `Rgba32FImage` end-to-end and quantizes only on save: - Editor (`editor/{adjust,transform,pipeline}.rs`) and the 3D Texturing plugin (`texturing/{channel_pack,normal_map}.rs`) + Automations FlipGreen/Normalize steps all process in f32; `png16` export is now real. - `image_io`: `load_exr`/`save_exr` carry true f32 (EXR was tone-mapped to 8-bit on load); `save_image` gains a real `tiff16`. - Editor save UI gains an explicit **format + bit-depth selector** (PNG 8/16-bit, TIFF 16-bit, TGA, OpenEXR) since the extension can't express png8 vs png16. ## WYSIWYG color fix Saved files didn't match the editor preview (pre-existing on main) — hue/saturation edits especially could come out magenta/cyan. The preview is a CSS/SVG `filter:` chain but the commit used different math (HSL hue/saturation, additive brightness) in a different order. The commit now replicates the **W3C Filter Effects** math the browser uses (hue/saturation color matrices, `brightness` multiply) and canonicalizes op order to color → curve → white-balance → geometry. What you see is what you save. ## Dev-build save perf A 30 MP JPEG save hung the editor ~10s in `make dev` (vs ~1.3s release) — purely unoptimized debug codegen of the image codecs. Two `Cargo.toml` profile fixes: optimize every dependency in dev (catch-all `package."*"`, fixing decode), and bump our own crate to opt-level 1 (the JPEG encoder + f32→u8 conversions are generic, so their hot loops monomorphize into our crate and weren't covered). ~12s → ~1.5s in dev, near release. ## Editor UX - Modal **save overlay** that dims the app and locks input while a commit is in flight. - Shortcuts: **Ctrl/Cmd+E** open editor from the asset view, **Ctrl/Cmd+S** save, **Ctrl/Cmd+R** revert (confirm), **Esc** exit (confirm when unsaved). The `\` original-image peek already existed. ## Notes - Garnet's adjust math now diverges from standalone Packi (still 8-bit/HSL); the eventual shared processing crate should adopt this f32 + filter-math version. - An ignored `bench_commit` / `repro_commit_real` harness lives in `editor/pipeline.rs` for profiling. ## Verification `make lint typecheck test` green (130 Rust tests, 13 frontend tests, clippy, tsc). Precision round-trip and EXR f32 round-trip covered by tests; WYSIWYG output verified by rendering a hue+warm edit on a real 30 MP photo.
Sign in to join this conversation.
No reviewers
No labels
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
parker/garnet!47
No description provided.