Double-clicking the MSI now opens WixUI_InstallDir without the licence page:
Welcome, install folder (remembered for upgrades in
HKLM\Software\PhotoCraft\InstallDir), Ready, progress, and a Finish page with
a ticked "Launch PhotoCraft" box (WixShellExec, unelevated). The pages name
the full version, pre-release tag included (photocraft.en-us.wxl).
package.ps1 draws the banner and side bitmaps from the app icon, so no WiX
stock art ships. msiexec /qn still installs silently. The release and ARM64
workflows install the WiX UI and Util extensions; packaging-lint checks the
.wxl. Ported from VectorCraft (storytold/vectorcraft@aa548d2).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AP7ThRN3kpNmjsuJUerJui
Filter and gallery parameter names and choices, command, tool and menu names, hints, preferences, metadata fields and colour spaces, using Photoshop's Japanese terms (浅浮き彫り, チョーク・木炭, アンシャープマスク …).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The MCP server follows the crafts' shared conventions (FilmCraft #28): core tools
incl. render_preview, titles and annotation hints, strict argument keys (-32602),
live photocraft://document and photocraft://commands resources, and -32700
recovery from malformed JSON lines. Headless Render Video writes through the
granted write root, reports progress, stays ping-responsive and can be cancelled,
removing only the files it created. docs/mcp.md describes it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PNG tEXt/zTXt/iTXt entries (and TIFF ASCII tags) were dropped on open with a warning. The
document now keeps them in Metadata.text, the .pcraft manifest saves them (older files still
load), and PNG/TIFF saves write them back; Metadata: None and embed_metadata=false strip them,
and PSD/PSB and palette PNG exports warn that they are dropped. XMP in a tEXt or zTXt chunk is
read as XMP too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ui.inspect now has brushPicker: null while closed, {pos, list} while the Brush
Preset picker is open (list is its collapsed/filter/view/renaming state), so
agents can see what a right-click with a painting tool opened. Fixes#1558.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A control-channel menu click could run an edit behind an open dialog (a rotation
under Image Size), which the native menu bar already refuses (#1354). The modal
gate moves to menus::modal_allows and ui.menu.invoke checks it; view navigation
stays live, engine.execute is unaffected. Fixes#1556.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Choosing Save in the close prompt for a layered TIFF only parked the save behind TIFF Options,
yet the prompt went on to close the document. The prompt now waits for TIFF Options and
advances only once the write succeeded and the document is clean; the save stays bound to the
document that asked even if the active tab changes, and Discard Layers and Save a Copy leaves
the original's path and unsaved changes alone, as in Photoshop. Fixes#1098.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sync_all on Apple platforms asks for F_FULLFSYNC, which SMB shares (ENOTSUP) and some virtual
file systems (ENOTTY) refuse, so every save there failed. atomic::sync_file falls back to a
plain fsync for exactly those errors, as Apple's removefile does; the automation workspace
writes use it too. rustix is already in the lock on Apple targets. Fixes#1336.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The eyes on a layer's Effects row and on each effect's row did nothing. As in Photoshop, the
Effects eye now hides or shows all of the layer's effects and an effect's eye just that one, each
one history step that keeps the settings, via the new layer.setEffectsVisible command. Fixes#1622.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
Clicking the gradient swatch in the options bar did nothing; as in Photoshop it now opens a
popup with the Gradients preset browser, so a preset is picked without opening Window › Gradients.
Fixes#1651.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On Windows and Linux the System title bar checkbox now carries the existing "Applies at next
launch." note, since saving it does not change the current window. Fixes#1661.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
As in Photoshop, a secondary click on the Layers footer's Add a layer style and Create new fill or
adjustment layer buttons opens their menus too (a primary click still toggles them), and a small
arrow marks them as menu buttons. Fixes#1579.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Follow-up to #1494: Alt captured at stroke-down records the reversed tool, a
later stroke records the selected one, and the field rebuilt from the strokes
matches after undo and redo.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When one band failed, its siblings stopped with a generic "another band failed"
error, which could win the collection order and hide the real cause. The abort
flag now carries the first error, so every band reports it; tests cover traps,
error codes and the instruction budget across parallel bands.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The live brush, pencil, retouch and dab previews fed pointer batches to the
stroke renderer unchecked, so a NaN or huge coordinate could hang the path
walker. Every push now runs the shared check_coords first and rejects the whole
batch without touching the preview; tests cover 8/16/32-bit and every live tool.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The portal and zenity match rfd's *.ext globs case-sensitively, so IMG_0001.JPG or DSC_0001.NEF didn't show. On Linux and the BSDs each letter of an Open filter extension becomes a [jJ] class; Windows and macOS keep plain extensions.
Duplicate #1682 by @switch87 took the same approach.
Co-authored-by: switch87 <switch87@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Gradient Map preset picker lists the session's gradient library by group with a swatch per preset, in the Properties panel and the dialog, as Photoshop's gradient picker does. Picking one writes its colour stops as one undoable edit.
Fixes#1588.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A command dialog's preview is never shown in another tab, and the preview is computed even without a GPU texture, so headless tests can check it (90° Arbitrary rotation, Preview off, document untouched).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Target Path (and Extras) now gate the work path, shape and vector-mask outlines and Direct Selection's paths; the Pen's path in progress stays visible.
Part of #1119.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
These four ran through map_pixels, which always rewrote the active layer, so with an alpha
channel, the Quick Mask or a layer mask targeted they changed the layer and left the channel
alone. They now rewrite the targeted grayscale surface, as the core filters do. Fixes#935.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A long filter could occupy every worker in Rayon's global pool, and the marching-ants trace on
the UI thread then waited for those workers, so the job's Cancel control froze. While jobs run
the outline is traced serially; a test checks it matches the parallel trace. Fixes#1554.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Esc while drawing with the Pen ended the path by throwing it away. As in Photoshop, it now ends
the path where it is, left open, and keeps it as the Work Path, the same as Return. Fixes#1769.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A segment to a far-off point walked one dab per spacing step along its whole length (about
3e14 for a point at 1e15). Only the steps whose dab can reach a field node are walked now; a
test checks the result is bit-identical to the full walk for every tool. Fixes#937.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The org has 5 macOS slots in total (GitHub Team), shared by every repo's CI and
release builds, and PR CI kept them full, so release builds queued behind it.
macOS now runs only in release.yml; a release that fails on macOS is fixed and
rebuilt.
Co-authored-by: Brandon Thomas <shared2@storyteller.ai>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The painting and retouch tools now share one check_coords helper for the ±1e6 point bound,
and a regression test sends far-off points to all eleven retouch commands at every depth.
Fixes#976.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Screen is Negativ multiplizieren, Perceptual is Perzeptiv, Blend If is Farbbereich, Oldstyle is Mediävalziffern and Protect Tones is Tonwerte schützen, as in Photoshop's German UI; the font weight Black no longer reads as a colour.
Tool names keep the catalog's -Werkzeug form, Black Point Compensation is Tiefenkompensierung, and Float in Window is In Fenster schweben lassen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Document the MSVC toolchain and C++ build tools workload, and how to diagnose
Smart App Control blocking Cargo or build outputs (os error 4551), with a
pointer to the packaged release. Fixes#1585.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The PHOTOCRAFT_AUTOMATION_*_ROOT variables are read only by the desktop app, so
headless photocraft-cli mcp/serve need the --automation-*-root flags. Say so,
and pass explicit roots in the .mcp.json and claude mcp add examples.
Fixes#1551.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ui.set gains rotation, gradientBlendMode and gradientClassic in its signature
and the stale duplicate ui.set line goes; ui.menu.invoke documents params,
ui.pointer tool, app.save an optional path, and serve's doc.save tiffLayers.
Fixes#1550.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Preferences entry said ui.dialog.apply/confirm save the dialog, but the
automation policy refuses whole-preferences updates (SECURITY.md). Document the
refusal, what happens to the dialog, and prefs.set for single safe preferences.
Fixes#1555.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
muda is maintained by the tauri-apps org but is standalone: AppKit menus,
no webview or JS, so it fits the no-Tauri rule. Reword the comments that
called it "Tauri's menu crate".
Claude-Session: https://claude.ai/code/session_01UHgFEHEsefoQoBParH47JA
Co-authored-by: Claude <noreply@anthropic.com>
* CR2: read ColorData's as-shot white balance as words
CANON_COLOR_DATA is an UNDEFINED entry: uints() hands its bytes back one
by one, but the WB_RGGBLevelsAsShot offsets count 16-bit words. Reading
word i at entry offset i*2 (file byte order, bounds-checked) finds the
quadruple at 0x47 in the corpus PowerShot SX50 HS: [1613, 951, 951, 1605]
-> [1.70, 1.0, 1.69], matching the white balance its own DNG conversion
neutralises (AsShotNeutral -> [1.58, 0.955, 1.666] through the color
matrix). With this the file's balance is used instead of the grey-world
estimate; the regression test pins the words and the missing estimate
warning. (The remaining brightness gap between the CR2 and the DNG of
the same camera is the CR2 path's exposure normalisation, to be looked
at next; the estimate was never what brightened the file.)
* cr2: drop the unused glob import in the corpus test
* CR2 WB: synthetic word-offset oracle, entry bounds, corpus test behind the feature
testgen writes ColorData as Canon does, UNDEFINED bytes that are 16-bit words
with the PowerShot's WB_RGGBLevelsAsShot at word offset 0x47, and the new
color_data_wb_as_words test checks the decoded balance in every CI run (the
corpus oracle stays behind the corpus feature and now panics when its file is
missing instead of silently skipping). word() reads stay inside the entry's
own byte count, and the shared inspect example moves back to the corpus PR.
Photoshop writes the per-channel blend-if ranges byte for byte in either byte
order (an II TIFF holds the defaults as 00 00 ff ff). The transcoder swapped
them as u32s, turning every range into ff ff 00 00, which hides every pixel of
the layer: a Photoshop layered TIFF opened with an empty canvas.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- Linear Dodge (Add) and Divide keep values above 1 in 32-bit float documents, clipped only at f32::MAX. Integer depths still clip at 1.
- CPU: add psblend::HDR and generic::blend_rgb_hdr / blend_channel_hdr; render sets the flag per document depth.
- GPU: add the F_HDR pass flag, and compose.wgsl uses it for the same clip bound.
- Non-separable modes are unchanged.
- Tests: colour unit tests, compose depth tests, and the GPU parity test float_documents_blend_past_white.
Co-authored-by: hideoneric <hideoneric@users.noreply.github.com>