mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-24 10:09:01 -06:00
Sony ARWs record shading, lateral chromatic aberration and distortion as a camera setting plus a radial table in the raw image IFD (0x7031-0x7037), with copies in the encrypted SR2SubIFD (0x797c-0x7982). They are now decoded for every body that records them and carried through RawInfo and RawImage as `lens_metadata.sony` (types in crates/raw/src/lens_metadata.rs, decoder in crates/raw/src/vendor/arw_lens.rs): - Raw-IFD fields are the ones the TIFF reader parsed, which is what the image itself uses. A scan of the directory adds diagnostics only: repeated tags, and why an entry the reader skipped was dropped (values outside the file, an unknown type, past the reader's limits). SR2SubIFD fields are read from their first entry. Only the exact layouts are accepted: SHORT[1] or non-negative SSHORT[1] settings, SSHORT[17] headed by 16 for shading and distortion, SSHORT[33] headed by 32 for CA. Nothing is allocated from a count in the file. - The raw IFD's copy wins. The SR2SubIFD copy fills in only for a tag the raw IFD lacks, never for a malformed one, and the two copies' agreement is recorded. - Settings keep their number and their documented meaning, Unknown(value) otherwise (never Off). - Framing evidence (stored frame, Sony and default crops, reference rectangle, coding, 3:2) and a per-component status. Only Applied components become opcodes. Applied corrections are unchanged: the ILCE-7RM4A distortion conversion receives exactly the table it received before, and no other body or component gains a correction. The ILCE-7CR distortion misses its camera JPEG at 24 mm, and shading and CA semantics are not validated on any body; see docs/sony-lens-corrections.md. Locating the SR2SubIFD, now done for every ARW that has one, selects the SR2Private offset, length and key with the TIFF reader's own rules, which lightcraft-tiff now exposes and builds its reader on (directory_entries, entry_span, ParseOptions::budget_for, decode_value). Only each field's first value is decoded, so the directory's other entries cost no memory sized by the file: a 16 MiB file whose SR2Private holds eight fields aliasing it peaks at 37 kB. DirectoryEntries keeps its layout private, and its positions() iterator uses checked arithmetic. Tests: synthetic decoder tests; a differential test of the SR2Private selection against the TIFF reader's in both byte orders (0 to 8,193 filler entries, unreadable and unusual first occurrences of each field, a used-up value budget); a dhat peak-heap test; public-corpus checks against the values ExifTool prints, with pinned and anchored SHA-256s (LIGHTCRAFT_CORPUS_REQUIRED=1 makes absent files fail); and an opt-in local inventory check (crates/raw/tests/sony_lens_inventory.rs). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
165 lines
6.4 KiB
TOML
165 lines
6.4 KiB
TOML
[workspace]
|
|
resolver = "3"
|
|
members = ["crates/*", "apps/*", "xtask"]
|
|
|
|
[workspace.package]
|
|
version = "0.7.1"
|
|
edition = "2024"
|
|
license = "MIT OR Apache-2.0"
|
|
rust-version = "1.90"
|
|
repository = "https://github.com/storytold/lightcraft"
|
|
|
|
[workspace.dependencies]
|
|
craft-ui = { git = "https://github.com/storytold/craft-libs", rev = "5c874d51eeb3de70e735c8ce87a59a7dedd47675", features = ["serde"] }
|
|
# internal
|
|
lightcraft-denoise-core = { path = "crates/denoise-core" }
|
|
lightcraft-denoise = { path = "crates/denoise", default-features = false }
|
|
lightcraft-geom = { path = "crates/geom" }
|
|
lightcraft-faces = { path = "crates/faces" }
|
|
lightcraft-sysmem = { path = "crates/sysmem" }
|
|
lightcraft-color = { path = "crates/color" }
|
|
lightcraft-raster = { path = "crates/raster" }
|
|
lightcraft-tiff = { path = "crates/tiff" }
|
|
lightcraft-raw = { path = "crates/raw" }
|
|
lightcraft-codecs = { path = "crates/codecs" }
|
|
lightcraft-meta = { path = "crates/meta" }
|
|
lightcraft-develop = { path = "crates/develop" }
|
|
lightcraft-lensdb = { path = "crates/lensdb" }
|
|
lightcraft-inpaint = { path = "crates/inpaint" }
|
|
lightcraft-scenes = { path = "crates/scenes" }
|
|
lightcraft-pipeline = { path = "crates/pipeline" }
|
|
lightcraft-gpu = { path = "crates/gpu" }
|
|
lightcraft-catalog = { path = "crates/catalog" }
|
|
lightcraft-preview = { path = "crates/preview" }
|
|
lightcraft-merge = { path = "crates/merge" }
|
|
lightcraft-engine = { path = "crates/engine" }
|
|
lightcraft-ui-egui = { path = "crates/ui-egui" }
|
|
lightcraft-mcp = { path = "crates/mcp" }
|
|
lightcraft-fetch = { path = "crates/fetch" }
|
|
lightcraft-heif = { path = "crates/heif" }
|
|
lightcraft-segment = { path = "crates/segment" }
|
|
lightcraft-geocode = { path = "crates/geocode" }
|
|
|
|
# foundation
|
|
thiserror = "2"
|
|
sha2 = "0.10"
|
|
serde = { version = "1", features = ["derive", "rc"] }
|
|
serde_json = { version = "1", features = ["float_roundtrip"] }
|
|
log = "0.4"
|
|
rayon = "1"
|
|
proptest = "1"
|
|
bytemuck = { version = "1", features = ["derive"] }
|
|
crc32fast = "1"
|
|
siphasher = "1"
|
|
libc = "0.2" # dev-only: process CPU time in benches
|
|
dhat = "0.3" # opt-in heap profiling (lightcraft-cli --features dhat-heap) and heap tests; never in product builds
|
|
|
|
# formats
|
|
quick-xml = "0.38"
|
|
miniz_oxide = "0.8"
|
|
|
|
# codecs
|
|
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "tiff", "webp"] }
|
|
zune-jpeg = { version = "0.5", default-features = false, features = ["std", "x86", "neon"] }
|
|
zune-core = { version = "0.5", default-features = false, features = ["std"] }
|
|
jpeg-decoder = { version = "0.3", default-features = false }
|
|
jpeg-encoder = { version = "0.7", default-features = false, features = ["std"] }
|
|
ab_glyph = { version = "0.2", default-features = false, features = ["std"] } # Apache-2.0, pure Rust glyph rasterizer (export watermarks)
|
|
png = "0.18"
|
|
tiff = "0.11"
|
|
image-webp = "0.2"
|
|
moxcms = { version = "0.9", default-features = false, features = ["lut"] }
|
|
jxl-oxide = { version = "0.12", default-features = false }
|
|
jixel = "=0.3.4" # BSD-3-Clause OR Apache-2.0, pure-Rust JPEG XL encoder (export; port of libjxl-tiny)
|
|
zune-jpegxl = { version = "0.5", default-features = false, features = ["std"] } # MIT/Apache-2.0/Zlib lossless JXL encoder (test fixtures only)
|
|
ravif = { version = "0.13", default-features = false, features = ["threading"] } # no "asm": it needs nasm (non-Rust)
|
|
# HDR AVIF (PQ): ravif fixes the sRGB transfer curve, so HDR files drive its rav1e + avif-serialize directly
|
|
rav1e = { version = "0.8.1", default-features = false, features = ["threading"] }
|
|
avif-serialize = "0.8.6"
|
|
|
|
# gpu (crates/gpu; native backends only, no GL: everything stays pure Rust)
|
|
# SAM 3 inference (lightcraft-segment). 0.9.2: later releases pull `tokenizers` with the
|
|
# Oniguruma C library into candle-core, and the product is pure Rust.
|
|
candle-core = { version = "=0.9.2", default-features = false }
|
|
candle-nn = { version = "=0.9.2", default-features = false }
|
|
wgpu = { version = "30", default-features = false, features = ["std", "parking_lot", "metal", "vulkan", "dx12", "wgsl"] }
|
|
pollster = "1"
|
|
|
|
# ui
|
|
egui = "0.36"
|
|
egui_extras = { version = "0.36", default-features = false }
|
|
eframe = { version = "0.36", default-features = false }
|
|
egui_kittest = "0.36"
|
|
rfd = "0.17"
|
|
muda = { version = "0.21", default-features = false } # native menu bar (macOS: objc2/AppKit, pure Rust; no GTK)
|
|
# macOS: the profile of the screen showing the window (safe AppKit bindings; muda and wgpu use the same)
|
|
objc2 = { version = "0.6", default-features = false, features = ["std"] }
|
|
objc2-app-kit = { version = "0.3", default-features = false, features = ["std", "NSApplication", "NSColorSpace", "NSResponder", "NSScreen", "NSWindow"] }
|
|
objc2-foundation = { version = "0.3", default-features = false, features = ["std", "NSArray", "NSData"] }
|
|
# Linux: the desktop's dark/light setting from the XDG settings portal (Settings ▸ Interface ▸
|
|
# Appearance Mode ▸ Auto). Pure Rust; the version accesskit already brings in, pinned to it.
|
|
zbus = "=5.19.0"
|
|
web-time = "1"
|
|
|
|
# web (apps/lightcraft-web)
|
|
wasm-bindgen = "0.2.129"
|
|
wasm-bindgen-futures = "0.4"
|
|
js-sys = "0.3"
|
|
web-sys = "0.3"
|
|
|
|
[workspace.lints.rust]
|
|
unsafe_code = "deny"
|
|
|
|
[workspace.lints.clippy]
|
|
dbg_macro = "warn"
|
|
todo = "warn"
|
|
too_many_arguments = "allow"
|
|
needless_range_loop = "allow"
|
|
type_complexity = "allow"
|
|
excessive_precision = "allow"
|
|
|
|
[profile.dev.package."*"]
|
|
opt-level = 2
|
|
|
|
[profile.dev]
|
|
opt-level = 1
|
|
|
|
[profile.release]
|
|
debug = "line-tables-only"
|
|
|
|
[profile.dist]
|
|
inherits = "release"
|
|
lto = "thin"
|
|
codegen-units = 1
|
|
debug = false
|
|
|
|
# `cargo xtask web`: the browser build. Size matters more than build time: fat LTO, one codegen
|
|
# unit, no symbols, abort on panic (wasm32 can't unwind anyway), size-optimized code — except the
|
|
# crates that do per-pixel work, which stay at opt-level 3 (opt-level "s"/"z" there costs ~50 %/
|
|
# ~130 % render time; measured in docs/web.md → Bundle size).
|
|
[profile.web]
|
|
inherits = "release"
|
|
debug = false
|
|
lto = "fat"
|
|
codegen-units = 1
|
|
strip = true
|
|
panic = "abort"
|
|
opt-level = "s"
|
|
|
|
[profile.web.package]
|
|
lightcraft-pipeline = { opt-level = 3 }
|
|
lightcraft-raster = { opt-level = 3 }
|
|
lightcraft-color = { opt-level = 3 }
|
|
lightcraft-develop = { opt-level = 3 }
|
|
lightcraft-geom = { opt-level = 3 }
|
|
lightcraft-raw = { opt-level = 3 }
|
|
lightcraft-codecs = { opt-level = 3 }
|
|
lightcraft-scenes = { opt-level = 3 }
|
|
lightcraft-preview = { opt-level = 3 }
|
|
zune-jpeg = { opt-level = 3 }
|
|
zune-core = { opt-level = 3 }
|
|
jpeg-decoder = { opt-level = 3 }
|
|
jpeg-encoder = { opt-level = 3 }
|
|
png = { opt-level = 3 }
|
|
miniz_oxide = { opt-level = 3 }
|