fix(raw): open Olympus ORF at the colour of its own preview via rgb_cam
The develop preferred cam_xyz, whose rows are the XYZ of each camera channel and which nothing normalised: on the ORF this was reported on it left the frame green and blue (R/G 0.921, B/G 0.886) where the file's own preview sits at 1.013 / 0.841, and saturated reds came back as the dark purple the frame was reported for — a red pixel's green ran negative through a row that carries -2.64, so it clipped to 0 while the knee pulled red down with it. LibRaw hands back dcraw's own rgb_cam, already the camera -> sRGB transform with rows summing to one, and it is now applied as handed back: R/G 1.020 B/G 0.920, and the fit against the embedded preview follows to mean 167.5,164.8,138.5 against the preview's 167.0,164.8,138.6 and the camera's own JPEG's 165,162,133. Dividing rgb_cam by pre_mul — which carries that row normalisation — is what the frame before this one did instead, and it undoes it. The cam_xyz chain stays as the fallback for a file with no rgb_cam, with its rows normalised so a neutral frame opens neutral. invert3x3, unused since the frame stopped going through the chain, is dropped.
This commit is contained in:
@@ -119,4 +119,48 @@ assert.match(src, /^ *uniforms\[21\] = f\[0\]; uniforms\[22\] = f\[1\]; uniforms
|
||||
// 6020x4024, and every one of the eight bodies checked doubled its frame.
|
||||
assert.match(src, /^ *halfSize: false,$/m, 'the develop is half-size again');
|
||||
|
||||
// The matrix the develop applies is the camera->sRGB one LibRaw already hands
|
||||
// back, not one derived from `cam_xyz` beside it. They disagree on the Olympus
|
||||
// ORF this was reported on: rgb_cam x cam_mul lands on R/G 1.021 B/G 0.920
|
||||
// against the file's own preview's 1.013 / 0.841, the cam_xyz chain on
|
||||
// 0.921 / 0.886 — green, and blue for a scene the camera left neutral, which is
|
||||
// the cast the frame opened with. And the matrix must not be divided by `pre_mul`
|
||||
// again: that undoes the row-sum-to-one normalisation dcraw built into rgb_cam.
|
||||
{
|
||||
const body = src.match(/const XYZ_TO_SRGB = \[[\s\S]*?\n\}\n/)?.[0];
|
||||
assert.ok(body, 'getCamToSrgbMatrix not found');
|
||||
// The file is TypeScript; the two annotations in this block are all that stop
|
||||
// `new Function` from reading it.
|
||||
const js = body.replace(/: any/g, '').replace(/: number\[\]\[\]/g, '');
|
||||
const getCamToSrgbMatrix = new Function(`${js}; return getCamToSrgbMatrix;`)();
|
||||
const rgb_cam = [
|
||||
[1.631760597229004, -0.39896339178085327, -0.23279713094234467],
|
||||
[-0.298429936170578, 1.7056032419204712, -0.4071732759475708],
|
||||
[0.02502557262778282, -0.45518237352371216, 1.4301568269729614],
|
||||
];
|
||||
const cam_xyz = [
|
||||
[0.9422, -0.3258, -0.0711],
|
||||
[-0.2655, 1.0898, 0.2015],
|
||||
[-0.0512, 0.1354, 0.5512],
|
||||
];
|
||||
const pre_mul = [2.0312116146087646, 0.9462084174156189, 1.4558180570602417];
|
||||
assert.deepEqual(
|
||||
getCamToSrgbMatrix({ rgb_cam, cam_xyz, pre_mul }),
|
||||
rgb_cam.map((row) => row.slice(0, 3)),
|
||||
'rgb_cam is no longer applied as LibRaw handed it back'
|
||||
);
|
||||
// A neutral camera triple stays neutral through what is left: every row of the
|
||||
// matrix has to sum to one, or the frame opens with a cast of its own.
|
||||
for (const [name, cd] of [
|
||||
['rgb_cam', { rgb_cam }],
|
||||
['cam_xyz', { cam_xyz }],
|
||||
['nothing', {}],
|
||||
]) {
|
||||
const rows = getCamToSrgbMatrix(cd);
|
||||
for (const row of rows) {
|
||||
assert.ok(Math.abs(row[0] + row[1] + row[2] - 1) < 1e-6, `${name}: row sums to what white is not`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('raw-develop-check ok');
|
||||
|
||||
Reference in New Issue
Block a user