fix(raw): resolve RAW green-yellow color cast via cam_xyz prioritization, daylight WB fallback, and fitMatch sanity checks

This commit is contained in:
2026-10-05 20:16:53 +07:00
parent c486397388
commit 8021529657
2 changed files with 16 additions and 12 deletions
+12 -12
View File
@@ -145,7 +145,7 @@ half4 main(float2 pos) {
// The matrix was fitted luma-preserving, so mx is the value to hold.
float hi = max(max(n.r, n.g), n.b);
hi = max(hi, max(max(lin.r, lin.g), lin.b));
rgb = mix(rgb, float3(mx), smoothstep(0.92, 1.0, hi));
rgb = mix(rgb, float3(mx), smoothstep(0.99, 1.02, hi));
// The overflow used to fade towards white — mix(rgb / mx, 1, 1 - 1 / mx) —
// which put every pixel of a blown sky on exactly 1.0 and threw the two stops
// the sensor held above white away with it: LIGHT's HIGHLIGHT row then had a
@@ -440,14 +440,6 @@ function invert3x3(m: number[][]): number[][] | null {
}
function getCamToSrgbMatrix(cd: any): number[][] {
if (cd?.rgb_cam && Array.isArray(cd.rgb_cam) && cd.rgb_cam.length >= 3) {
return [
[cd.rgb_cam[0][0] || 0, cd.rgb_cam[0][1] || 0, cd.rgb_cam[0][2] || 0],
[cd.rgb_cam[1][0] || 0, cd.rgb_cam[1][1] || 0, cd.rgb_cam[1][2] || 0],
[cd.rgb_cam[2][0] || 0, cd.rgb_cam[2][1] || 0, cd.rgb_cam[2][2] || 0],
];
}
if (cd?.cam_xyz && Array.isArray(cd.cam_xyz) && cd.cam_xyz.length >= 3) {
const cx = cd.cam_xyz;
const scale = (Math.abs(cx[0][0]) > 100) ? 10000.0 : 1.0;
@@ -470,6 +462,14 @@ function getCamToSrgbMatrix(cd: any): number[][] {
return [[m00, m01, m02], [m10, m11, m12], [m20, m21, m22]];
}
if (cd?.rgb_cam && Array.isArray(cd.rgb_cam) && cd.rgb_cam.length >= 3) {
return [
[cd.rgb_cam[0][0] || 0, cd.rgb_cam[0][1] || 0, cd.rgb_cam[0][2] || 0],
[cd.rgb_cam[1][0] || 0, cd.rgb_cam[1][1] || 0, cd.rgb_cam[1][2] || 0],
[cd.rgb_cam[2][0] || 0, cd.rgb_cam[2][1] || 0, cd.rgb_cam[2][2] || 0],
];
}
return [[1, 0, 0], [0, 1, 0], [0, 0, 1]];
}
@@ -483,7 +483,7 @@ export async function developRaw(bytes: Uint8Array): Promise<Uint8Array> {
const meta = await raw.metadata(true);
const img = await raw.imageData();
const cd = meta?.color_data;
if (!img || !cd?.cam_mul || (!cd.rgb_cam && !cd.cam_xyz)) throw new Error('RAW has no colour data');
if (!img || (!cd?.cam_mul && !cd?.pre_mul) || (!cd.rgb_cam && !cd.cam_xyz)) throw new Error('RAW has no colour data');
const { width: w, height: h } = img;
const data = img.data as Uint16Array;
@@ -494,9 +494,9 @@ export async function developRaw(bytes: Uint8Array): Promise<Uint8Array> {
const rawMul = (cd?.cam_mul && cd.cam_mul.some((v: number) => v > 0 && v !== 1))
? cd.cam_mul
: (cd?.pre_mul && cd.pre_mul.some((v: number) => v > 0))
: (cd?.pre_mul && cd.pre_mul.some((v: number) => v > 0 && v !== 1))
? cd.pre_mul
: [1, 1, 1, 1];
: [2.0, 1.0, 1.5, 1.0];
const green = rawMul[1] || rawMul[3] || 1;
const mul = rawMul.map((v: number) => v / green);
const [r0, r1, r2] = getCamToSrgbMatrix(cd);