A data line such as `nan 0 0` starts with a letter and was skipped as an
unknown keyword, so a file with enough other entries still parsed.
(CodeRabbit review on #2540.)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
UPDATE_APP (native builds; craft-update is a native-only dependency) carries our 128 px icon and accent (#f2a516, its colour in ArtCraft Launcher). The updater, the self-update
helper and craft-update's startup prompt all get them through crate::UPDATE_APP; the
prompt draws the icon, the accent and "by ArtCraft" (craft-update's default developer).
craft-update is pinned to storytold/craft-libs main at 1065653e7 (#434).
Clippy fixes for Rust 1.99 in untouched code (same logic):
- crates/engine/src/cmd/export.rs
- crates/ui-egui/src/dialogs/rules_editor/rules_move.rs
- crates/ui-egui/src/panels/detail.rs
AGENTS.md (and CLAUDE.md where present) gets a CI workflows section: workflows only call
craft-common-actions at @main, with no other jobs; feature and fix PRs don't touch CI and
link or open a craft-common-actions issue (a PR only for a small fix that is safe for
every app and does not increase CI time); legacy jobs
aren't added to and move only as their own task, staying until a shared workflow runs them.
windows-arm64.yml moves from its SHA pin to @main. The pinned revision is on
craft-common-actions main and the workflow (and the actions it calls) is identical
there, so nothing changes in behaviour.
The test's stored image and LightCraft's size of the photo were both 20 × 10, so
fitting radials to the photo's size instead of the stored image went unnoticed.
The photo is now already in the library at its shown 10 × 20, as a vertical shot
is.
The catalog's XMP is merged before the develop row, and its masks were taken as
they are, on the stored image: when the row has no masks of its own to replace
them, they stayed a quarter turn off on a vertical shot. They now go through the
same frame as the row's. A radial is fitted to the stored image before it is
turned, so its radii swap with the stored aspect and not the sidecar default.
Updating a photo already in the library keeps its Rotate Left / Right and Flip in
LightCraft, which LightCraft draws masks after, but the masks went through the
catalog's orientation only: an upright photo turned right in LightCraft got an
unturned gradient. They now go through the catalog's orientation and then the
photo's own.
A hostile segment now lays only its end point, so five of them no longer
fill the stroke budget. The test asserts the endpoint-only count directly
and proves that a stroke which has spent its count takes no more through
push_dabs_counted, which tracks the budget across buffers.
The gap 24 row, the change-log line and the two document headers now say only
that an extreme brush segment skips its intermediate dabs. They no longer claim
live preview, edge refinement or a mask test count, and the headers no longer
carry the unrelated gap 15 and print-page entries.
push_dabs clamped the number of intermediate dabs of one brush segment to 1,000,000, so a
finite but extreme segment (a point 10,000,000 px away) still allocated a million dabs. A
segment that would need more than that many now keeps only its endpoints; ordinary
spacing and the segment's end point are unchanged.
Adds oversized_brush_segments_skip_intermediate_dabs, which checks both the extreme case
(2 dabs) and an ordinary feathered-brush segment (21 dabs, end point kept, spacing kept).
The docs record the fix under gap 24 and LR-MASK-BRUSH; the parity status stays partial.
The old version's cached installer is missing, so Windows cannot remove it.
Re-caching it with msiexec /fv on the same-version MSI fixes both updating
and uninstalling (reproduced and verified on Windows 11, #3254).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Honor CARGO_BUILD_TARGET in FreeBSD packaging for aarch64 release builds
package.sh always built for the host and took the arch from uname -m, so a
cross build (aarch64 in an x86_64 FreeBSD VM) would read the wrong target
directory and name the archive after the VM. With CARGO_BUILD_TARGET set,
pass it to cargo, read target/<triple>/release, and take the arch from the
target. Unset keeps the old behavior.
* Reject unknown CARGO_BUILD_TARGET in FreeBSD packaging
Only the two FreeBSD triples are packaged. Any other target now fails before the
build instead of being labelled x86_64.
* Skip the --version smoke run for cross-built FreeBSD packages
A binary built for another target cannot run on the build host, so under set -e
the run would fail the release after the archive is written.
The existing synthetic lossy RGB fixture tiles are re-declared grey by a
header edit (colour space RGB to Grey, dropping the 6-bit primaries field
a grey encoding does not carry, per the ColourEncoding bundle). Their XYB
frame data is unchanged, so they decode as one grey plane whose rendered
channels differ. The test checks decode against the gradient's BT.2100
luminance in the linear and sRGB curves.
Refs #275
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014ti8KemZbjE2ZgHgV1q1BM
Lightroom Classic's HDR and panorama merges of monochrome raws store a
one-plane LinearRaw image as lossy (XYB) JPEG XL tiles whose codestream
declares a grey colour encoding (16-bit float with a linear curve, or
16-bit integer with the sRGB curve). Those were refused as "lossy JPEG XL
tile with a single colour plane", so the files opened preview-only.
A lossy grey tile is still coded as three XYB channels. It is now
restored like the RGB case: jxl-oxide renders linear sRGB (never the
declared encoding, which would clip), the single plane is the luminance
(CIE Y, D65) of that, then the declared transfer curve is applied.
One plane must be declared grey and three RGB; HDR curves, other white
points and intensity targets above 255 stay unsupported.
RENDER_CACHE_VERSION 70 -> 71: files that showed their embedded preview
before render from raw data now, under the same content key.
Refs #275
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014ti8KemZbjE2ZgHgV1q1BM