* Camera Raw: Whites, Blacks, Shadows and Highlights closer to Photoshop's
Measured as a black box on Photoshop 25.4's Camera Raw Filter.
Whites and Blacks are global curves of the grey level: the measured rows
per slider value, Whites first, after Shadows and Highlights. The
clipping directions adapt to the image's black and white points
(Whites up to 2.7 times stronger on a dark image, Blacks at least 1.2).
On ten public-domain photos the mean error against Photoshop drops from
4.2-36.8 to 0.9-8.9 levels of 255.
Shadows and Highlights are a local Laplacian filter (Paris et al. 2011,
fast form of Aubry et al. 2014) on the log luminance, the method Adobe
credits for process version 2012. Shadows raises pixels darker than
their surroundings by an amount set by their own and their
surroundings' tone, so big edges keep no halo, and keeps the 99th
percentile; Highlights pulls pixels brighter than their surroundings
toward them and keeps the 1st. The strengths are fitted to the photos
(mean error 2.8-9.4 levels, was 3.7-14.3); Photoshop's exact operator
was not recovered.
The tone stages decode light with the document's curve: filter.cameraRaw
stores encodingGamma (1.8 for ProPhoto, where raws open).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Camera Raw Shadows/Highlights: no contour lines on smooth gradients
Twelve reference values over a raw's whole range left more than a stop
between them, and the remapping changes within half a stop: coefficients
interpolated across that gap drew contour lines in out-of-focus areas
(Shadows +100 on a Nikon D4 raw). References are now an eighth of a stop
apart over the image's tones (the deepest 0.1 % share the lowest), on a
copy at most 1600 px across whose change comes back to full size by a
guided upsampling, so a 16-megapixel image takes about 2 s per slider and
the preview matches the result.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Camera Raw on raw opens: Shadows/Highlights in linear light, D4 look and black point as Photoshop
Measured black-box on 29 Nikon D4 NEFs opened through Camera Raw in Photoshop 25.4 (sliders at
+-100 and +50, exposure +-1) against our own linear development of the same files.
- Shadows and Highlights of the open-time dialog now act while developing, in linear light before
the tone curve, as Camera Raw does for raw files (exposure -1 gives the same gains). The log2
gain is slider/100 * C(B - anchor): B is a guided-filter base of the log2 luminance on a copy
1232 px on its long side, the anchor is image-adaptive (Shadows: log2 power mean p=1.5 of the
linear luminance; Highlights: mean log2 luminance). New module photocraft_raw::tone; the
preview undoes the camera curve to show the same (photocraft_raw::retone).
- The D4 profile copies Camera Raw's default rendering: look matrix folded into the
ForwardMatrix, per-channel curve, and an adaptive black point (0.33 x the 0.1th percentile of
the luminance, Sensor::black_point).
Against Photoshop on the 29 frames (1/4 size, log2 Y): default rendering median difference
0.29 -> 0.04 stop; correlation of the slider's effect Shadows +100 0.96, -100 0.91, Highlights
-100 0.87, +100 0.85 (the previous filter model: 0.68 and 0.55 on DSG_3464).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* docs: the open-time Camera Raw re-develop covers Shadows and Highlights
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Camera Raw raw-stage Shadows: keep shadow contrast as Photoshop does
The user saw Photoshop's shadows sink deeper with more contrast. Measured on the 29 D4 NEFs:
with Shadows +100 our shadow detail had 0.79 of Photoshop's local contrast and shadows sat 0.38
stop lighter. Two causes:
- The black point now comes before the Shadows / Highlights gain, as in Camera Raw (lifting
first let the lift wash out the black point's deep-shadow contrast).
- The guided upsampling's epsilon goes from 0.01 to 1 stop^2: the change follows strong edges
but stays smooth inside texture (with 0.01 it followed every detail and flattened it). Near
strong edges the effect still matches Photoshop as well as elsewhere.
Shadows +100: shadow detail 0.79 -> 0.91, shadow bias +0.38 -> +0.16 stop; effect correlation
Shadows -100 0.906 -> 0.946, Highlights -100 0.870 -> 0.886, others unchanged.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Camera Raw on raw opens: Clarity, Texture and Dehaze in linear light, as Photoshop
Measured black-box from Photoshop 25.4 opening 29 Nikon D4 NEFs through Camera Raw (descriptor
keys Cl12, CrTx, Dhze; each at ±100 and +50, and +100 at exposure −1, 348 opens). All three act
before the tone curve: the change at exposure −1 equals the one at 0 (correlation 0.98–0.99).
- Clarity: log2 luminance split into bands between guided-filter bases (radii 2, 8, 32, 128 on
the 1232 px work copy), each band scaled by a measured gain that follows its base's tone, plus
a tone term; carried to full size with the Shadows / Highlights change.
- Texture: Gaussian bands σ 0.5…16 on a half-size copy, each through its measured response
(small detail raised more than strong edges, flat areas unchanged), guided-upsampled.
- Dehaze: He, Sun and Tang's dark channel prior on linear ProPhoto (dark channel in Display P3,
airlight from the brightest 0.1 % of it, guided-smoothed transmission), w 0.8 at +100;
−100 a uniform veil. The black point stays the default rendering's.
Against Photoshop, PhotoCraft's develop vs Photoshop's open on all 29 frames (median effect
correlation, log2 luminance at 1/4 size, Texture at 1/2): Clarity +100 0.81, −100 0.85;
Texture +100 0.85, −100 0.88; Dehaze +100 0.61 (0.78 in gamma 2.2: the crushed shadows
differ), −100 0.96. Shadows / Highlights unchanged (0.964 / 0.886).
The open-time Camera Raw dialog re-develops for them and its preview shows them (retone).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
The per-file colour fit (`fit_preview_look`) converted the embedded JPEG to sRGB only when the JPEG
carried an ICC profile, and otherwise read it as sRGB. A Sony body set to Adobe RGB writes no profile
into its previews; it states the colour space only in the raw's EXIF (ColorSpace Uncalibrated with
InteropIndex "R03", the DCF option file for Adobe RGB). The fit then targeted a desaturated,
hue-shifted reference, and the developed raw came out that way.
`photocraft_raw::embedded_preview_color_space` reads that EXIF (sRGB, Adobe RGB or unstated; never for a
DNG, whose previews are the converter's), and `preview_profile` uses it when the preview has no ICC
profile of its own. A preview's own profile still wins. LightCraft reads the same tags for the same
reason (storytold/lightcraft#778).
Measured on 19 private Sony ILCE-1M2 ARWs, all shot in Adobe RGB, against the camera's JPEG read as
Adobe RGB (median CIE76 ΔE at 240 px): full-frame 400 mm shots against blue sky 5.6-7.0 → 1.5-2.4,
their mean a* offset +4.3…+4.9 → +0.7…+1.1; every file improved, mean of the medians 4.9 → 2.2.
Tests: `exif_colour_space_of_the_previews` (sRGB, Adobe RGB; R98, a missing interop IFD, other values,
a DNG and junk are unstated) and `a_preview_without_a_profile_takes_the_raws_exif_colour_space` (fails
without the EXIF fallback; the preview's own ICC profile wins). The hostile-input harness calls the new
function.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A one-sample LinearRaw DNG (VueScan film scans, Leica Monochrom) was
rejected as "LinearRaw data with 1 samples per pixel". The DNG decoder
now accepts it and develop renders it as neutral grey: the one sample
fills all three channels, white balance, colour matrices and camera
looks do not apply, and the output is R = G = B in 16-bit ProPhoto.
io skips the preview colour fit for such files.
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* raw: fit non-DNG colour to the camera's embedded JPEG
* raw look: clippy (as_chunks) and rustfmt after merging main
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Open camera raws in Camera Raw first (Open / Cancel)
Photoshop opens a raw file in Adobe Camera Raw before it becomes a
document; PhotoCraft developed it with the defaults straight away and
said so in a warning. An interactive open (File › Open, Open Recent,
drag and drop, the command line) of a raw developed from its sensor data
now shows the Camera Raw dialog first, titled "Camera Raw (name)", with
Open and Cancel.
- Open re-develops the raw when Temperature, Tint or Exposure changed:
as-shot white-balance multipliers times the filter's gains, and the
develop exposure (photocraft_io::raw::import_raw_tuned). The other
settings are one filter.cameraRaw step; the document starts
unmodified. Without an as-shot white balance or without the file's
bytes, Temperature / Tint stay RGB adjustments as in the filter.
- Cancel closes the document again.
- The "developed with default settings" note is no longer shown when
the dialog is.
- Preference rawDefaults.openInCameraRaw (default on), the first
visible Camera Raw Defaults setting. Automation opens (app.open, MCP,
CLI) never show the dialog.
- "NIKON CORPORATION" + "NIKON D3200" now reads "NIKON D3200" in the
import note.
Tests: open → set → Open re-develops (brighter, still 16-bit, one
document, unmodified); Cancel closes; unchanged settings add no step;
preference off skips the dialog; a closed document is an error.
Translations for the two new strings in every catalog.
* Camera Raw open: re-develop in the background, keep tab and view
Open re-read and re-developed the whole raw on the UI thread. In the desktop
app it now runs as a job (cameraRaw.redevelop, document locked) like the
open itself; the reply is {job, pending} and the shell finishes when it
lands. The final Camera Raw step goes through app.run (a job too) and the
document is marked unmodified once it lands. Tests and the web still run
inline.
The re-developed document replaces the old one at the same tab position
and path, and its view (zoom, scroll) carries over. New test covers the
background path with documents on both sides.
wb_gains now uses camera_raw::white_balance_gains, shared with the Camera
Raw filter and documented as an observed approximation. 'Developing {name}'
translated in every catalog.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* raw: clean-room camera raw decoder and developer (photocraft-raw)
A new standalone crate (no workspace deps, wasm-safe, no unsafe) written
from TIFF 6.0, TIFF/EP, the DNG 1.7 spec, ITU-T T.81 Annex H and published
demosaicing papers:
- Lossless JPEG (LJ92) decoder: predictors 1-7, point transform, restart
intervals, combined Huffman+extra-bits fast table.
- DNG: uncompressed (8-16 bit, packed) and LJ92, strips and tiles, CFA and
LinearRaw, linearization, black level (repeat, deltas), white level,
active area, default crop, ColorMatrix/CameraCalibration/ForwardMatrix
interpolation by CCT, AnalogBalance, AsShotNeutral/WhiteXY,
BaselineExposure, orientation.
- CR2 (LJ92 slices, SensorInfo borders, ColorData as-shot WB, measured
black) and TIFF/EP raws (NEF/ARW/PEF uncompressed or LJ92, incl. Sony
lossless ARW tiles, Nikon/Sony documented black and WB tags).
- Develop: black/white scaling, WB with highlight clipping, bilinear /
Malvar-He-Cutler / AHD demosaic (rayon bands, sequential on wasm),
camera -> XYZ D50 -> ProPhoto, exposure, gamma 1.8, 16-bit, orientation.
- Embedded JPEG preview finder; clear Unsupported errors for CR3, RAF,
ORF, RW2, vendor-compressed NEF/ARW/PEF, lossy/JXL/float DNG, X-Trans.
- Limits checked before every allocation; testgen feature with an LJ92
encoder and DNG/CR2/TIFF-EP writers; round-trip, colour-reference,
truncation and corruption tests.
Registered as a standalone crate in xtask layers.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* io: open camera raws through photocraft-raw (16-bit ProPhoto), preview fallback
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* raw: DNG GainMap opcode, fuzz targets, stress tools; open raws from the apps
- Apply DNG OpcodeList2 GainMap (lens shading, e.g. phone DNGs); report other opcodes.
- cargo-fuzz targets (develop, ljpeg) and a mutation stress example.
- Raw extensions in the desktop/web open dialogs and the batch folder list.
- file.open returns the import notes (how a raw was developed, preview fallback).
- codecs: the camera raw refusal points at photocraft-raw.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* raw: clippy 1.99 (is_multiple_of, clamp)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>