brush-parity.md, gaps.md and ui-parity.md had 2026-10-25 revision rows
under a 2026-10-23/24 "Last updated" header; the headers now carry the
latest row. gaps.md (24 of 171), ui-parity.md and target-app-parity.md
(46 of 149) quoted stale counts of preferences that do nothing; they now
quote the scorecard's 12 of 178. target-app-parity.md still listed the
Camera Raw Calibration panel as missing, which landed on 2026-10-13
(#5128); the row now names per-camera colour for non-DNG cameras, as
gaps.md G14 does.
Found by CodeRabbit on #9386.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Conflicts: the batch's wheel reads (#5547 Animated Zoom) keep their extra
argument with main's ids (`Id::unique`, `ui.scope_id()`); crop presets keep
#6620's `apply_choice` with main's accessible name; Bevel & Emboss keeps
#9370's per-mode id with main's name argument; the Stroke field keeps
#7203's gradients with main's name; tone.rs keeps #9139's move of the
Histogram panel to histogram_panel.rs (main only renamed ids there);
translation catalogs as unions.
Not flagged by git, the batch's new code follows egui 0.37 too: dropdowns
take an accessible name (Histogram Channel/Source #9139, tool Mode #5504,
Art History Style #1610, New Snapshot From #3567), MouseWheel events carry
`source`, `WidgetType` is `Role` (ColorButton is ColorWell, #7203),
`Id::new`/`Ui::id` are `Id::unique`/`Ui::scope_id`.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* egui037: name each control for what it sets, and order the eager fonts for the UI
CodeRabbit review follow-ups on the migration: the Artboard X/Y fields, the CAF
dropdowns, the channel Solidity field, the GPU backend/adapter dropdowns, the
corner radius fields and the canvas extension colour all had an accessible name
that named another control (or was shared by four). The eager craft-fonts
registration now puts the UI Japanese face first, as the lazy loader does, so
Japanese UI is not drawn in the manifest's Mincho face and shared Han characters
do not take Japanese forms.
Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
* egui037: rustfmt the eager craft-font order
---------
Co-authored-by: Dylan M. Taylor <dylan@dylanmtaylor.com>
Co-authored-by: Codebuff <noreply@codebuff.com>
Reconcile 39 upstream commits: keep main's off-menu gallery zoom, folder-field
picker and Transform edit tolerance while keeping the migration's accessible
names, and use Id::unique for the ids main added.
The Windows legs build with the suite's craft-fonts input: the runner has no
Japanese or Simplified Chinese system font, and egui 0.37 panics on a missing
glyph, which failed the localized UI tests. The background-redraw test now
holds the worker after its first batch, so an edit during a redraw cannot lose
the race on a fast machine.
Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
- The open scroll brings the marked row itself into view, keeping the recent
group's top in view when the row fits below it: with Font Preview Size Huge
and 10 recents, recent #8 opened below the fold.
- The open scroll is armed for the first laid-out pass only, whether or not a
row matched: with a missing font or a mixed selection the scrolled list
jumped later, once the font loaded or the selection settled.
Co-authored-by: hectorviov <1501713+hectorviov@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
sign.ps1 downloaded Microsoft.Trusted.Signing.Client from the unversioned
NuGet URL and loaded its dlib into signtool, next to the Azure signing
secrets, with no version or integrity check.
Download a pinned version (1.0.95, which the unversioned URL serves today)
and refuse it unless its SHA-256 matches, so upgrading the client is a
deliberate change in the repository. The release docs say where the pin
lives.
Merged with our fix-up branch pr-8885-fixup (8f6863f53) on the author's head 996b55eb4.
Conflicts resolved:
- crates/io/src/tiff_layers.rs: #9148's tiff_source (an empty LMsk gets Photoshop's 14 bytes)
gives way to #8885's tiff_image_source, which writes the same bytes for an empty or short
LMsk; #9148's test stays.
- crates/io/src/flat.rs: #8776's DDS alpha step and #8885's TIFF channel stamp both run.
- crates/io/Cargo.toml, Cargo.lock: #8402's zune dev-deps and #8885's tiff dev-dep.
- crates/io/tests/it/tiff_layers.rs, docs: unions; docs/scorecard.md kept as is, regenerated at
the batch gate.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Earlier PhotoCraft versions kept the 1053 of a Photoshop file they opened
and wrote it back unchanged, while storing spot channels added there
straight. A transparent Photoshop document carries 1053 = [0], so a white
plate added to it in 0.16.0 or earlier sat behind a 1053, and the rule
read that file in Photoshop's polarity: the added spot opened inverted.
A 1053 that lists fewer channels (non-zero ids; 0 is the transparency's)
than the file has after its transparency now counts as kept, with the
PhotoCraft 1057 and DisplayInfo spot conditions unchanged. Planes the
kept 1053 lists stay in Photoshop's polarity (they are the Photoshop
file's own); the ones after them are read straight. Photoshop and this
version write one id per extra channel, so their files are unaffected.
Known limit, as before: channels reordered there, or as many deleted as
added, can't be told apart from the Photoshop file's own.
The earlier versions are 0.1.0 to 0.16.0, not 0.11.1: every release
since writes the same 1057 and straight spot planes without a 1053.
Co-authored-by: jasallen <615848+jasallen@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Cache Levels 1 in Preferences turned off the 250 ms recount throttle,
because "forced" was derived from max_level == 1: only an Uncached
Refresh skips it now.
- The proxy factor became 2^(level-1) for every count, so the Levels,
Curves and Threshold dialogs counted a 6000x3000 image on an 8x proxy
instead of main's 7x (a 36 MP one 16x instead of 9x). Uncapped counts
use main's factor again; only a Cache Levels cap halves by powers of two.
- The panel opens in Compact View, as in Photoshop, and Compact View
counts the entire image whatever Source Expanded View was left at.
- The clipping corner marks are gone: Photoshop's Histogram panel has none.
- ui.inspect: "preview" counts only the active document's preview, and
"current" compares the source and cache level too, not only the
revision (a Source change left it true until the recount landed).
- ui-parity row lists two more differences (selection, Selected Layer
with a dialog preview); cargo fmt.
Co-authored-by: mathildalabs <347373177+mathildalabs@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
psd_import.rs keeps main's warning for an incomplete merged extra channel
next to the PR's Photoshop spot polarity. people.toml takes main's entries
plus jasallen's own. Docs take both sides' status lines and revision rows;
docs/scorecard.md is regenerated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The summary row still said 9/13/5 after an earlier batch PR moved FILE-215-11 to partial,
and #3297 moves FILE-215-3 to done: scorecard/file_compat.toml now counts 10 done,
14 partial, 3 missing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merged with our fix-up pr-3297-fixup (1de1e9eb58) on top of the author's head 053e1e0d03.
Conflicts resolved: channel_cmds.rs routed() keeps the PR's PAINT_IDS list plus the batch's
paint.artHistoryBrush; paint_cmds.rs Paint Bucket params keep the batch's "mode" and the PR's
"filterMask" target; docs/scorecard.md takes the batch's numbers with FILE-215-3 done.
* fix(ui): Properties Transform shows a shape's path, not its stroke
For a shape layer, Properties › Transform showed the pixel bounds, so a
400 × 300 rectangle with a 15 px stroke read W 416, H 316, X 192, Y 142,
and typing a width scaled those bounds rather than the path. As in
Photoshop, the fields now show and edit the path's geometry (W 400,
H 300, X 200, Y 150); pixel and other layers are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Properties: a shape's W/H takes edits under half a pixel
CodeRabbit finding on #9181 ("Apply fractional W/H edits below 0.5 px"): the
W/H field and transform_params ignored changes under 0.5 px, so a 400.25 px
path typed as 400 kept its old width, though the fields now show and scale
the path exactly. For a shape the threshold is half the field's last shown
decimal (focusing and leaving the field, which re-reads its rounded text,
still changes nothing); pixel layers keep half a pixel. New test:
a_shape_path_takes_a_width_edit_under_half_a_pixel (the edit is dropped
without the fix).
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>
Redone on the PR head 053e1e0d0 (the author's main merge); the earlier
fix-up f7af09d0f carried the first six points.
With a smart object's filter mask targeted, every routed command got
"target":"filterMask" and the filter-mask precondition instead of its own:
- Cmd+T and Edit > Transform > Flip/Rotate failed ("can't transform a
filter mask on its own"); now the smart object transforms, as in
Photoshop (lone_target -> Ok(None), and transforms get no target).
- Move (layer.translate) re-rendered the whole filter stack on every
nudge, and failed for contents that can't render.
- Convert for Smart Filters became enabled and nested the smart object;
Apply Image, Last Filter, Liquify, the lens filters, Vanishing Point,
the render filters and Desaturate ignore the target.
`follows_filter_mask` now leaves these out, in the shell, in
inject_target, in the precondition and in the re-render hook; Paste
keeps its own precondition.
- With the filter mask shown (Alt-click), clicking the layer, layer-mask
or vector-mask thumbnail (or ui.set maskTarget/vectorMaskTarget/
filterMaskTarget:false) left the view on (and ui.set maskTarget:false
left the filter mask targeted), so strokes kept landing in
the filter mask; those now end the view (CodeRabbit, panels.rs).
- ui.set filterMaskTarget:true on a layer without smart filters, or with
a single channel targeted, cleared the mask target and answered ok; it
is now refused before anything changes (CodeRabbit, control.rs).
- Curves on a targeted filter mask showed colour channels and the smart
object's histogram; it is now a gray plane with the mask's histogram
(GraySurface::FilterMask).
New on this head:
- Filters with a parameter schema (Gaussian Blur, High Pass, ...)
refused "target":"filterMask" ("`target` must be pixels, mask,
quickMask or {channel}"), so blurring the filter mask, the usual way to
feather it, failed from the menu, the dialog and agents. The filter
validation now accepts it (blurring_the_filter_mask_feathers_it).
- Delete with a selection and the filter mask targeted ran Edit > Clear
on the smart object ("not a pixel layer"); it now fills the filter mask
with the background colour there, as Photoshop does. With no selection
Photoshop deletes the layer, which Delete already did
(delete_with_the_filter_mask_targeted_edits_the_filter_mask).
- docs/control-protocol.md: the ui.set line lost its closing parenthesis
in the main merge.
Co-authored-by: Valentin Klein <271991477+vangel76@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Photoshop reads and writes IFF; PhotoCraft opened Amiga IFF/ILBM files
but had no writer. Saving as .iff now writes a FORM ILBM with a BMHD and
a ByteRun1-compressed BODY of 24 bitplanes (red, green and blue, least
significant bit first), one plane row at a time. An image with alpha
also gets a mask plane (masking 1): alpha of 128 or more is opaque, and
when any pixel is not fully opaque the export warns that alpha is
reduced to on/off transparency. Gray is expanded to RGB, 16-bit and
float images are reduced to 8 bits, and images wider or taller than
65535 pixels are refused.
The reader also opens 24-bitplane ILBMs, so a saved file reopens with
the same pixels. A transparent color index in a 24-bitplane file is
refused as unsupported.
IFF leaves ASYMMETRIC_EXCEPTIONS, Save As offers Amiga IFF, and the
codecs README, file-format parity and G10 are updated.
The dialog always opened on 2-Up. It now remembers the Original /
Optimized / 2-Up / 4-Up tab last chosen (in the UI state, so across
restarts too) and reopens on it; 2-Up stays the first-time default.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A swatch recoloured the selected type layers only with a Type tool, and
shape fills only with a shape or Pen tool. Photoshop 2025 recolours both
whatever the tool (measured with the Move and Brush tools); its Color
panel keeps to the tool-based rule, which is unchanged here.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A right-click while the left button still dragged a crop frame or a
Straighten line opened the crop menu over the live gesture (or, outside
the image, the pasteboard menu). The canvas now opens no menu with the
Crop tool while a crop drag or Straighten line is under way and the
primary button is still down. It needs both: egui ends the drag on the
right button's release without an Up, so the drag flag can stay stale,
and a lost release (Alt+Tab, a cancelled touch) leaves the button
"down". A finger held still (egui's press-and-hold right-click) is
excepted. The agent path (ui.pointer) opens no menu while its own crop
or Straighten drag is down, also the first one on the default frame.
Tests: no_crop_menu_while_the_left_button_drags_the_frame (real pointer
events), a_left_button_down_without_a_crop_drag_keeps_the_crop_menu,
no_crop_menu_while_the_left_button_draws_a_straighten_line,
a_finger_held_on_a_pending_crop_opens_the_crop_menu,
agent_right_click_during_its_crop_drag_opens_no_menu, and
enter_under_the_crop_menu_does_not_crop (only Esc was tested). The
parity row notes Photoshop's Reset Crop and Rotate Crop Box, both still
missing.
Co-authored-by: Marco Arnulfo <103679419+marcoarnulfo@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Folding #5236's performance notes into docs/seam-carving-performance.md
dropped main's "P28's recorded number is stale" section (the 2026-10-05
baseline commit at 266 s, the loaded machine behind the 954 s). None of
it depends on #8526's code, so it is back, dated and attributed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merged with our fix-up d5139d177 (pr-1199-fixup), which merged main as of 8f09d122d.
Conflicts with main since then and with batch 8:
- photocraft-cli: main split the CLI into clap modules (#7071); the model wiring
(local_headless, configure_cli_models, batch's shared backend, droplet) is re-applied there.
- Cargo.lock regenerated: crates/ml pins ureq =3.4.2, so the app's ureq goes 3.5.0 -> 3.4.2.
- cutout_cmds: main's subject area (#8235) kept for the classical path beside the model path.
- file_cmds batch: main's per-input closure takes `s` later, so the backend and
integrations prefs are read before the closure instead of inside it.
- prefs_ui: model-choice filter with #4573's pref_choice_label; Integrations stays visible
(#4097) with the model choices only where models run; the translation-coverage test main
deleted (c3aa3f9e5) stays deleted; old section_fields test calls take PreferenceFieldOptions.
- Semantic clashes git did not flag: #4097's Integrations test literals in
apps/photocraft take ..Default::default() for the new model fields; main's and #4573's
section_fields test calls pass PreferenceFieldOptions.
- engine lib.rs, prefs.rs, smartselect tests, snapshot example, jobs_ui_tests, people.toml,
docs and i18n catalogs merged as unions.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
panels.rs: the PR's snapshot rows next to main's History Brush source
and scroll-to-current; ui-parity.md: main's status line.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Main moved the shape options bar and paint swatch out of vector_ui.rs into
shape_options.rs and shape_paint_ui.rs (#5452). Carry the PR's gradient paint
over: PaintChange::Gradient, paint_param and the swatch's Gradient tab live in
shape_paint_ui.rs, the tool gradients and set_tool_paint in shape_options.rs,
and shape_gradient_ui.rs is its own module. Both sides' new tests are kept.
Co-authored-by: Denis <179751626+deniskhud@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#6923 develops the Camera Raw dialog's preview on the GPU whenever no spatial stage is set,
from `per_pixel`'s stages. #5128 adds Calibration (primaries and Shadows tint) to the CPU
develop between white balance and Dehaze, which those stages don't run, so with both merged
a Calibration-only change previewed unchanged on the GPU while Open applied it. `per_pixel`
now returns None when Calibration is set, so the dialog develops on the CPU then. The
white and black points stay as they were, so the dialog's points cache is still right once
Calibration goes back to neutral. The hardware parity doc and BUG-204-3's note now say so.
Co-authored-by: Fabio Lissi <3223836+FabioLissi@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>