The Actions panel's Play button falls back to the first action when no row (or a stale row) is selected, as Photoshop does, and a failed playback request now shows in the status bar instead of being dropped (#1951).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A dialog's drag handle spans the full title row plus a few pixels of padding around the title, so grabs slightly beside, above or below the title text move the window (#1921). The title keeps its height.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Just outside a corner the pointer becomes a curved rotate arrow, and while rotating the angle is shown
next to it. Distort and Warp keep their cursors.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Proximity Match copied its translated patch within the buffer it was writing, so overlapping offsets
re-copied fresh output and left streaks. It now reads from the pre-heal pixels, with checked bounds.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Preferences > File Handling > Lowercase Extension is live: with it on (the default) a save path's extension is lowercased (CAT.PSD saves as CAT.psd); off keeps the user's spelling. Settings that do nothing: 51 of 141 (#204).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A flat image with transparency (alpha channel or tRNS) opens as a normal, unlocked Layer 0, as in
Photoshop; opaque images still open as the locked Background. A lone Layer 0 saves back to PNG natively.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Preferences > Type > Use Escape to Commit is live: on (the default) Escape commits the type session as before; off, Escape cancels it like the Cancel button, as in Photoshop. Settings that do nothing: 52 of 141 (#204).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Preferences > Type > Fill new type layers with placeholder text is live: with it off, a Type tool click starts an empty layer (removed again if committed without typing). Settings that do nothing: 53 of 141 (#204).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A literal tab in PSD text shaped as .notdef. Layout now shapes it as a space, keeping byte, style
and caret offsets intact. Tab stops are still to come. Part of #1881.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A release that egui reports as both a drag stop and a click no longer replays the click over a live
stroke (which painted a second full-pressure dab), and the click fallback now uses the pen's pressure.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A submenu header is enabled only while some item under it can run, so File > Export, Automate, Scripts and Import grey out while a crop is pending, as in Photoshop (#1976).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The embedded document built by layer_to_smart now carries the document's patterns, so pattern fills
and pattern effects keep rendering inside the smart object and after Edit Contents. Fixes#1867.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The refusal message Debug-quotes the path, which doubles backslashes on Windows, so
contains(path) never matched there. Matching the unique file name keeps the check.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
An adjustment layer kept verbatim as Unsupported rendered as nothing without telling anyone. Import
now warns, naming the layer, the adjustment and (for Color Lookup) the reason. Part of #1763.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
View > Print Size divides the document's ppi into Preferences > Units & Rulers > Screen Resolution (72 ppi by default) instead of a hard-coded 72, and the setting is no longer hidden. Settings that do nothing: 54 of 141 (#204).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
best_offset clamps the search radius and ring to the image extent and rejects zero or negative radii,
so hostile values no longer overflow i32 loops or search for billions of iterations.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A percentage grid now spaces vertical lines by the document width and horizontal lines by its height,
so rectangular canvases get proportional cells, and grid snapping uses the same per-axis steps.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The PSD (and layered TIFF) exporter rendered fill layers with no patterns, so pattern fills were
written as transparent pixels; in CMYK and Lab those tiles survive and the reopened layer drew empty.
Pattern fills now render from the document's patterns. Round-trip test over 4 modes x 3 depths.
Fixes#1907.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New Fill Layer (Solid Color, Gradient), the Gradient tool's live fill layers, gradient fill edits and Gradients panel presets store their colours in the document's mode (Color::in_mode / Fill::in_mode), so a fill layer in a Grayscale, CMYK or Lab document composites like the same colour painted with Edit › Fill, as Image › Mode already converted them. Fixes#1905; tests at 8, 16 and 32 bits.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The decimal 3.40282347e38 is just above f32::MAX; naga rounds it but browsers' Tint rejects it, so
the web app had no GPU compositor. Now a hex literal, with a test that every decimal float literal in
the shader fits f32.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On macOS the save prompt reads Save / Don't Save / Cancel without printed key letters, like the native alert; D, C, S, Return and Escape still answer it. Windows and Linux keep their mnemonics. Shortcut test from #1963 (arthurdeka).
Co-Authored-By: arthurdeka <arthurdeka@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When the OS clipboard no longer holds the image we mirrored or imported (text or a file was copied
since), the session clipboard drops it, so Paste reports nothing to paste instead of a stale image.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reading a deflated .pcraft entry with max = usize::MAX no longer overflows the take() limit, and a
forged size in the ZIP header no longer reserves gigabytes up front (preallocation is now capped).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ukrainian: clearer sampling terms (Sample, Sample Size), N × N averages, Color to Alpha and the web/print gamut warnings, plus the missing Transparency/Opacity Threshold rows.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The parallel PNG encoder now cuts deflate bands by a fixed byte budget instead of by thread count,
so the same image and options give identical files on any machine. Test covers 1, 2, 7 and 32 threads.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PSD export regenerates the document Txt2 block with one text object per TextIndex carrying each run's auto-kern mode (manual, metrics, optical), which EngineData's AutoKerning can't distinguish, so Optical no longer reopens as Metrics (#1348). A kept object with unchanged text keeps the file's extras (glyph pen positions); duplicate or out-of-range TextIndex values are renumbered and capped, so a crafted file can't size the save. io corpus tests stay at their floors.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Radial Blur prepares its sample transforms once per filter (blur::radial::Plan) and shares them across output tiles, reading each bilinear tap once with channels kept together. Output is identical to the previous sampler at Draft, Good and Best, across colour models and depths (tests compare against the unchanged reference path); a failed table allocation falls back to that sampler. Measured on 24 MP RGBA8, Good, amount 1: Spin 66.1 -> 16.4 s, Zoom 19.2 -> 5.4 s (bench_radial example, docs/radial-blur-performance.md).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
file.export.colorLookupTables takes scope all|selected or an explicit layers list and bakes only those top-level, visible adjustment layers, always in document stacking order; the dialog defaults to the selection when it is all exportable adjustments. Invalid selections and sizes are errors rather than silent fallbacks; LUT sizes outside 2-129 (the reader's limit) are now refused instead of clamped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mosaic sums each four-channel cell by reading whole rows once with channel sums kept in registers, in the original addition order, so the output is bit-identical (including HDR values, -0.0, zero alpha and partial source bounds); 24-38% faster on three of the four measured cell sizes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixes#1833. Control and MCP may run Edit Contents, Convert to Layers and Save Contents on smart objects whose source is in memory (embedded, or a Photoshop UUID backed by embedded liFD data). Before any disk read the engine re-checks the source's stored path through the session's authorize gate, including nested sources re-rendered while unpacking, so external linked files stay refused; explicit layer targets work with another layer selected, and interactive linked-file access is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The style menu now shows each face's actual OpenType subfamily (name 17, else 2) instead of a name guessed from its weight, so fonts whose faces share one weight (Yoon's numeric 20/30/40/50) list and render distinct faces: FontDb::select_named_face registers a runtime-only alias for the exact face, while the document keeps its public family and PostScript name. Variable faces still list the standard weights their wght axis covers.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Save for Web gets a platform-writer entry point (web_cmds::save_for_web_with_writer) so the browser build downloads every image, spacer and HTML file side by side; the export is authorized before any picker opens, a failed write stops it, and only a complete export remembers its settings. Each document now opens the dialog at its own size instead of the last export's width, height and percent.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RAF's header, metadata records and Fuji IFD give size, packing (16-bit, 12-bit LSB-first,
14-bit in 32-bit words), layout, black, WB, crop and exposure bias; X-Trans and other
periodic non-Bayer CFAs go through a new edge-directed demosaic. Compressed and early
SuperCCD RAF stay unsupported (preview fallback). Tests use synthetic files only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In the desktop app every filter's live preview now runs on the preview worker (not just Indexed Color), so a slow one like Gaussian Blur at 1000 px no longer freezes the window. The worker hands the filter a JobCtx (Session::set_inline_job_ctx) and cancels a preview for older values once the dialog's values have been unchanged for 150 ms; during a drag the running preview is left to finish.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sony cRAW files with no BlackLevel tag take the 512 their tone curve gives the black
code instead of 0 (the ILCE-7 no longer develops washed out; the RX0 corpus oracle moves
to 512 too). cameras.rs gains measured image areas without a full profile: the Nikon
D800E and Sony ILCE-7 crop like the camera's JPEG.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A pre-scan rejects element nesting past 512 levels before the XML parser recurses
(a 70 KB file of <g> aborted the process). .svgz is inflated by the importer with a
128 MB cap, so it can be scanned too and gzip bombs are refused; flate2 moves from a
dev-dependency to a dependency (already in the tree through usvg).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Photoshop's Vertical, Horizontal, Dual Axis and Diagonal paint symmetry presets beside the
path-based symmetry: axes start at the document centre, Transform Symmetry moves and rotates
them (Shift snaps to 15°, Enter applies, Esc cancels), and all copies merge into one coverage
pass so overlaps don't build opacity. New paint.setSymmetry command and preset icons. Fixes#1648.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The document tab's context menu gains Reveal in Finder (a new file.revealInFinder command that reuses the smart-object reveal helper and targets the clicked tab's document), and dragging a tab sideways reorders the open documents through document.move, with a drop line, in both tab strips. Flips UI-217-6 to done.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every tool's input schema is rewritten once at startup: $refs inlined (use-site
descriptions win), $defs dropped, boolean schemas turned into {}, with a depth cap
for recursive definitions. ui_pointer events get a concrete schema. Strict providers
no longer reject the whole tool list. Fixes#1782.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ui.inspect lists the open shell dialog (Workspace, Pixel Aspect Ratio, Show Extras,
32-bit Preview) with the id "shell", and ui.dialog.set/confirm/cancel accept it;
confirm goes through the automation authorizer and the dialog's shared OK. Fixes#1004.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Outside the crop frame the pointer is Photoshop's curved turn cursor and a drag turns the frame
about its centre (Shift: 15 degree steps) with an angle readout; handles resize along the turned
axes and a double-click inside commits. image.crop takes an optional angle: Image Rotation >
Arbitrary so the frame is upright, then the crop, in one undo step. Fixes#1792.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Edit > Stroke… from the menus opens a Photoshop-style dialog (Width, Color, Location, Blending:
Mode, Opacity, Preserve Transparency) remembering its last values; called with params it runs
directly. edit.stroke gains mode and preserveTransparency, blending through Fill's compositing
(blend_color_mask), and validates them. The Blending section is shared with Fill
(dialog_blend_ui.rs). Fixes#1463.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
menus::invoke records each successfully run command (deduplicated, newest first, last 8) and the palette lists them when its query is empty, falling back to the full list in a fresh session. Flips UI-217-7 to done.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Unknown keys, wrong types, out-of-range sizes or resolution and unsupported
mode/depth/background now fail naming the parameter, before a floating selection is
committed or a document added; omitted fields keep their defaults. The renderer tests
now pass numeric depths (strings had silently fallen back to 8-bit). Part of #507.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
While a Pen path is being drawn, Undo (its customisable shortcut or Edit > Undo) and Backspace/
Delete remove the last uncommitted anchor instead of undoing an earlier document step, as in
Photoshop; once the draft is empty, Undo works on the document again. Fixes#1466.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixes#1810. File > New remembers the size, resolution, mode, depth, background and display units its OK used (in the preferences' dialogs map, so they survive a restart) and starts from them next time, as Photoshop does; a clipboard image still sets the size, and corrupt remembered values are ignored.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A host lists fonts in fonts/manifest.txt beside index.html (craft-fonts' manifest format, paths
kept inside the site); the web shell lists those families in the font menus and fetches a family
when it is picked or a layout needs it, then re-renders the affected type layers without a history
step. No manifest changes nothing; package.sh copies one in with PHOTOCRAFT_WEB_FONTS_DIR. The
style menu also lists the weights of a variable font's wght axis.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
adjust_surface now takes the layer's tiles and adjusts each one on its own rayon task, so a large layer needs one tile's buffers per thread instead of four full-layer copies. The result is bit-identical to the single pass for every adjustment kind, colour model and depth, with and without a soft selection (tiled_adjustment_matches_one_pass_over_the_content). Adds an invert scenario to large_image_bench.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The CPU path drew the pixel grid over the whole view, including transparent areas, while the
GPU shader only lightens or darkens pixels with content. pixel_grid.rs applies the shader's
rule to the composite of the area in view, as merged segments cached per revision and padded
region (capped at 60k segments), sharing the zoom and strength constants with the shader.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Changed tiles are grouped by shared Arc and converted once each in parallel batches; a tile
shared by several coordinates (a solid fill, a cleared area, a non-zero default) is uploaded
once to a scratch tile and copied on the GPU, and new pages take the same path. 16-bit RGB and
gray tiles convert to RGBA16F through a lookup table. Select All + Fill on a 50 MP 16-bit page
refreshes in 15-19 ms instead of about 1.4 s. Fixes#1774.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>