Commit Graph
13 Commits
Author SHA1 Message Date
9a4d925b34 Brush: remember the last selected brush across restarts (split from #2516) (#3472)
* Brush: remember the last selected brush across restarts (split from #2516)

The persistence half of #2516 on its own, so it can merge and be maintained
apart from the brush-outline half. The tool's brush (settings, tip
references, and the name of the preset it was picked from) is saved once the
pointer is up and restored at launch: options bar, painting cursor and
Brushes panel highlight all start where the session left off.

Review fix from #2516 -- no per-frame work:
- `ToolState::brush_rev` is bumped by every brush/preset setter
  (`tools.setBrush`, preset save/delete/rename/setCurrent/deleteGroup,
  `brush.defineFromSelection`, `brush.presets.importAbr`, the store's tip
  re-linking, and the shell's tool-switch/reset paths); `remember_brush`
  serialises only when it moved since `brush_saved_rev`, so an unchanged
  brush costs a counter compare per frame, not a clone and a JSON dump of
  the whole brush (sampled tip previews included).
- Restoring counts as saved: the launch value is never rewritten.

Bitmaps stay out of the preferences document: remembered tips and patterns
are references (a loaded stored tile drops its full bitmap), and a sampled
bitmap too big to embed is skipped, keeping the previous value so a preview
never enters the prefs file. A malformed remembered brush falls back to the
default.

docs/scorecard.md regenerated with `cargo xtask scorecard` (34 of 154).

Tests: engine 1267 lib (5 new: revision gating, rejected changes, picked
preset, restore round trip, no embedded bitmaps), ui-egui 1982 lib; clippy,
layers, wasm green.

* rustfmt the StoredTile line and regenerate the scorecard after the main merge

* engine tests: destructive Levels keep the signed float overshoot at 32 bits (#2592)

* Scorecard: regenerate after merging upstream/main

* Export As: compare batch paths without the Windows separator

* font fix ?

* fix(ui): only Filter menu dialogs get the in-dialog preview window

#3877 drew the preview window in every schema dialog with a Preview
checkbox, including Image > Rotation > Arbitrary. Photoshop's Rotate
Canvas and adjustment dialogs have no preview window, and the taller
dialog covered the canvas, which broke
arbitrary_rotation_preview::size_changing_rotation_preview_is_visible_and_preserves_the_panned_center
on main. The window and its reserved height now apply to filter.*
commands only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* cargo    fmt --check max_width = 160 fix

---------

Co-authored-by: JJ <jj@dot.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 12:48:41 -04:00
Gert Pellin - GPE 0bdaf905cc Curves: points outside 0..255 are refused, as the message says (#4868)
A point outside 0..255 was moved onto the edge without a word, while the
error for bad points says they must be in 0..255; Photoshop refuses
them too. The error also named the command twice-quoted (`adjustment
`curves``); it is now `curves adjustment`.

Fixes #4867
2026-10-13 12:45:35 -04:00
skylar taylor-barrick 67ca74fe18 Align overlapping CI repairs with upstream while retaining regression coverage 2026-10-12 05:44:48 +02:00
skylar taylor-barrick 055e4fee1b Merge remote-tracking branch 'upstream/main' into codex/photocraft-craft-print-sync
# Conflicts:
#	crates/ui-egui/src/i18n/cs.tsv
#	crates/ui-egui/src/i18n/de.tsv
#	crates/ui-egui/src/i18n/el.tsv
#	crates/ui-egui/src/i18n/es.tsv
#	crates/ui-egui/src/i18n/fr.tsv
#	crates/ui-egui/src/i18n/id.tsv
#	crates/ui-egui/src/i18n/it.tsv
#	crates/ui-egui/src/i18n/ja.tsv
#	crates/ui-egui/src/i18n/ko.tsv
#	crates/ui-egui/src/i18n/nl.tsv
#	crates/ui-egui/src/i18n/pl.tsv
#	crates/ui-egui/src/i18n/pt-br.tsv
#	crates/ui-egui/src/i18n/ru.tsv
#	crates/ui-egui/src/i18n/uk.tsv
#	crates/ui-egui/src/i18n/zh-hans.tsv
#	crates/ui-egui/src/i18n/zh-hant.tsv
2026-10-12 04:10:55 +02:00
9a9d23d258 Levels: black, gray and white point eyedroppers (#3116) (#3128)
* Curves: pencil mode, Smooth and Edit points (#3088)

The Curves editor (Image > Adjustments dialog and the adjustment layer's
Properties panel) gains Photoshop's "Edit points to modify the curve" and
"Draw to modify the curve" buttons plus Smooth, with tooltips. A drawn
curve is a 256-level map per channel, evaluated piecewise-linearly.

- doc: Adjustment::Curves gains `pencil` (serde default), with
  curve_map / curve_map_outputs helpers.
- compose: curve_map_lut / curve_lut_mode for drawn curves.
- engine: curves params take `pencil` and `smooth`; channels accept
  256-level maps; switching modes draws the spline into maps or fits up to
  16 points to the drawing. Eyedroppers fit points first.
- io: the PSD `curv` map flag (first byte, psd-tools `is_map`) was read
  as padding, so pencil curves from Photoshop were misparsed; they are now
  read and written as 256-byte maps, and smart-filter Curves use `Mpng`.
- scorecard UI-217-15 note updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Properties: Curves adjustment layers get the black/gray/white eyedroppers (#3110)

The Set Black/Neutral Gray/White Point pickers existed only in the
Image > Adjustments > Curves dialog (#873). The Properties editor of a
Curves adjustment layer now has them too (layer_picker.rs): with one
armed, a click on the image runs one layer.setAdjustment with the new
`eyedropper` param, which samples the image below the layer (the layer
hidden, like its Properties histogram) at the Eyedropper's Sample Size,
so a repeated click keeps the curve and the edit is one undoable,
recordable step agents can send directly. Esc, another tool or another
layer disarms it; ui.pointer and ui.inspect (`layerPicker`) cover it.

Scorecard UI-217-15 is done.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Levels: black, gray and white point eyedroppers (#3116)

Image > Adjustments > Levels and a Levels adjustment layer's Properties
panel get Photoshop's Set Black/Neutral Gray/White Point eyedroppers.
Black/white move each channel's input black/white to the sample, gray
sets each channel's midtone gamma so the sample turns neutral at its
luma (Grayscale: composite input, no gray). The engine takes the same
`eyedropper` param as Curves on image.adjustments.levels,
layer.newAdjustmentLayer.levels and layer.setAdjustment.

On a smart object, image.adjustments.levels/curves with `eyedropper`
now record the resolved adjustment as the smart filter instead of the
raw sample, which re-rendered as an identity (#3127).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Merge upstream/main: Curves in new compose/gpu HDR tests gets the pencil field (#3088)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-11 21:27:08 -04:00
skylar taylor-barrick f65f7cc9eb Correct stale HDR Levels test endpoints 2026-10-12 03:24:40 +02:00
ee9c9ef159 Properties: Curves adjustment layers get the black/gray/white eyedroppers (#3110) (#3115)
* Curves: pencil mode, Smooth and Edit points (#3088)

The Curves editor (Image > Adjustments dialog and the adjustment layer's
Properties panel) gains Photoshop's "Edit points to modify the curve" and
"Draw to modify the curve" buttons plus Smooth, with tooltips. A drawn
curve is a 256-level map per channel, evaluated piecewise-linearly.

- doc: Adjustment::Curves gains `pencil` (serde default), with
  curve_map / curve_map_outputs helpers.
- compose: curve_map_lut / curve_lut_mode for drawn curves.
- engine: curves params take `pencil` and `smooth`; channels accept
  256-level maps; switching modes draws the spline into maps or fits up to
  16 points to the drawing. Eyedroppers fit points first.
- io: the PSD `curv` map flag (first byte, psd-tools `is_map`) was read
  as padding, so pencil curves from Photoshop were misparsed; they are now
  read and written as 256-byte maps, and smart-filter Curves use `Mpng`.
- scorecard UI-217-15 note updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Properties: Curves adjustment layers get the black/gray/white eyedroppers (#3110)

The Set Black/Neutral Gray/White Point pickers existed only in the
Image > Adjustments > Curves dialog (#873). The Properties editor of a
Curves adjustment layer now has them too (layer_picker.rs): with one
armed, a click on the image runs one layer.setAdjustment with the new
`eyedropper` param, which samples the image below the layer (the layer
hidden, like its Properties histogram) at the Eyedropper's Sample Size,
so a repeated click keeps the curve and the edit is one undoable,
recordable step agents can send directly. Esc, another tool or another
layer disarms it; ui.pointer and ui.inspect (`layerPicker`) cover it.

Scorecard UI-217-15 is done.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Merge upstream/main: Curves in new compose/gpu HDR tests gets the pencil field (#3088)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-11 21:16:28 -04:00
aba9b2b4ef Curves: pencil mode, Smooth and Edit points (#3088) (#3108)
* Curves: pencil mode, Smooth and Edit points (#3088)

The Curves editor (Image > Adjustments dialog and the adjustment layer's
Properties panel) gains Photoshop's "Edit points to modify the curve" and
"Draw to modify the curve" buttons plus Smooth, with tooltips. A drawn
curve is a 256-level map per channel, evaluated piecewise-linearly.

- doc: Adjustment::Curves gains `pencil` (serde default), with
  curve_map / curve_map_outputs helpers.
- compose: curve_map_lut / curve_lut_mode for drawn curves.
- engine: curves params take `pencil` and `smooth`; channels accept
  256-level maps; switching modes draws the spline into maps or fits up to
  16 points to the drawing. Eyedroppers fit points first.
- io: the PSD `curv` map flag (first byte, psd-tools `is_map`) was read
  as padding, so pencil curves from Photoshop were misparsed; they are now
  read and written as 256-byte maps, and smart-filter Curves use `Mpng`.
- scorecard UI-217-15 note updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Merge upstream/main: Curves in new compose/gpu HDR tests gets the pencil field (#3088)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-11 21:05:58 -04:00
d166450c77 Hue/Saturation: Colorize at 0% saturation gives grey, not a 25% tint (#2343)
Colorize floored saturation at 25% on both the CPU (compose::adjust::hue_saturation) and the
GPU shader, so dragging Saturation to 0 with Colorize ticked still tinted the image. Photoshop
leaves only the lightness at 0%. The floor is gone from both paths, so 1-24% now tint
progressively too.

The floor also stood in for Photoshop's 25% starting saturation when Colorize is switched on.
The dialog's checkbox already sets that; the hueSaturation params now do the same when a call
turns Colorize on without giving a saturation, so {"colorize": true, "hue": 30} still tints.

Fixes #2326.

Co-authored-by: lloyd <lloyd@stackworx.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 13:16:26 -04:00
kayrockscreenprintingandClaude Opus 5.5 1284e79d23 Selective Color and Color Lookup: a wrong-typed key is an error (#1790)
Selective Color and Color Lookup params with the wrong type (a string percentage, a short range
array, an unknown method, range or interpolation) were silently ignored, so layer.setAdjustment
kept the old values without saying so. They are now BadParams errors naming the key; null still
means not given. Fixes #936.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:23:34 -04:00
dde8fcddce Curves: add black, gray, and white point eyedroppers (#873)
* feat(curves): add black gray and white point eyedroppers

* fix(curves): preserve luminance with gray-point eyedropper

* Curves eyedroppers: drivable by the command's eyedropper param (rule 1)

image.adjustments.curves and layer.newAdjustmentLayer.curves accept
{"eyedropper":{"point":"black|gray|white","at":[x,y]}} (samples the merged composite) or
{"point",…,"color":[r,g,b]}, resolved by the same curves_eyedropper the dialog uses, so agents
and the CLI can set black/gray/white points without ui.pointer. Bad points, positions outside
the image, transparent samples and malformed values are errors. The picker swatches are the
tone each picker maps to (image data, like the Curves gradient bars), drawn as
Color32::from_gray(level) with a token ring.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* i18n(pl): translate the Curves eyedropper strings

The Polish catalog landed on main after this PR was written; the
translation-coverage tests need every language to carry new UI strings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 20:26:33 -04:00
7313e08141 32-bit documents: Levels don't clip the input and output ranges (#403)
* 32-bit documents: Levels don't clip the input and output ranges

Photoshop's float Levels keep the curve going past the black and white points
and use a plain power for the gamma. rgb32 and gray32 levels.psd now match
within 0.5/255 (was 10/255).

* Raise the Photoshop oracle floor to 132

* Levels: destructive Image › Adjustments › Levels doesn't clip in 32-bit either; neutral comment wording

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 06:53:56 -04:00
Brandon ThomasandClaude Opus 5.5 37c8f81032 Image › Adjustments overhaul: full params, one editor per kind, live-preview dialogs, Curves point deletion (#68)
* Adjustments: full parameter sets for every kind, Hue/Sat ranges, CMYK/Lab tone channels

- doc: Hue/Saturation gains six colour ranges (HueRange), Gradient Map a dither flag,
  Levels/Curves a ToneSpace (RGB, CMYK inks + black, Lab) for mode-native channels.
- engine: new adjust_params module (from_params over a base / to_params) used by
  image.adjustments.*, layer.newAdjustmentLayer.* and layer.setAdjustment. Curves,
  Color Balance, Channel Mixer, Black & White, Gradient Map and Photo Filter now honour
  their params; bad params are BadParams errors; setAdjustment merges (empty = reset).
- compose/gpu: hue-range tables, CMYK/Lab tone channels (CPU; GPU falls back), dithered
  Gradient Map, Black & White from grey/secondary/primary parts; GPU parity extended.
- io: hue2 ranges, grdm dither, CMYK/Lab Levels/Curves records round-trip.
- destructive adjustments use the document's tone transfer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Adjustments UI: one editor per kind for Properties and Image › Adjustments dialogs

- adjust_editors: Brightness/Contrast (legacy), Levels and Curves (per channel in RGB, Gray,
  CMYK and Lab, histogram behind), Exposure, Vibrance, Hue/Saturation (master + six ranges with
  draggable range sliders, colorize, before/after spectrum), Color Balance (tones, preserve
  luminosity), Black & White (six weights, tint colour), Photo Filter (presets or colour,
  density), Channel Mixer (outputs, constant, monochrome, total), Posterize, Threshold
  (histogram), Gradient Map (stops, presets, reverse, dither). Replaces the M7 placeholder.
- Properties previews live (GPU) while a control moves and commits one setAdjustment per gesture.
- adjust_dialog: Image › Adjustments opens the same editor modally; the canvas previews the
  real command on the proxy, Preview checkbox, OK = one history step, Cancel leaves the doc.
- Curves (#43): hit-test at the press origin, Delete/Backspace removes the selected point when
  the graph has focus, Cmd/Ctrl-click removes, dragging off removes (and back on restores),
  arrows nudge; endpoints and the last two points stay; pressing the gradient bars does nothing.
- tone: histograms per channel space, of the image below a layer or of the target layer alone.
- kittests: every adjustment layer kind edited through the Properties panel with real input at
  8/16/32-bit RGB, Gray, CMYK and Lab (#12); Curves point interactions; dialog preview/OK/Cancel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* io tests: adjustment round trip covers the new Levels/Curves/Hue-Sat/Gradient Map fields

#60's round-trip tests predate #68's doc-model additions (tone space and black channel,
Hue/Saturation ranges, Gradient Map dither); fill them with their defaults.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 16:08:40 -04:00