@@ -216,9 +216,11 @@ static inline void illuminant_CCT_to_RGB(const float t, dt_aligned_pixel_t RGB)
216216 illuminant_xy_to_RGB (x , y , RGB );
217217}
218218
219+ static inline gboolean find_temperature_from_wb_coeffs (const dt_image_t * img , const dt_aligned_pixel_t wb_coeffs ,
220+ float * chroma_x , float * chroma_y );
219221
220222// Fetch image from pipeline and read EXIF for camera RAW WB coeffs
221- static inline gboolean find_temperature_from_raw_coeffs (const dt_image_t * img , const dt_aligned_pixel_t custom_wb ,
223+ static inline gboolean find_temperature_from_as_shot_coeffs (const dt_image_t * img , const dt_aligned_pixel_t custom_wb ,
222224 float * chroma_x , float * chroma_y );
223225
224226
@@ -301,13 +303,13 @@ static inline int illuminant_to_xy(const dt_illuminant_t illuminant, // primary
301303 {
302304 // Detect WB from RAW EXIF
303305 if (img )
304- if (find_temperature_from_raw_coeffs (img , custom_wb , & x , & y )) break ;
306+ if (find_temperature_from_as_shot_coeffs (img , custom_wb , & x , & y )) break ;
305307 }
306308 case DT_ILLUMINANT_FROM_WB :
307309 { // FIXME copy-paste
308310 // Detect WB from RAW EXIF
309311 if (img )
310- if (find_temperature_from_raw_coeffs (img , custom_wb , & x , & y )) break ;
312+ if (find_temperature_from_as_shot_coeffs (img , custom_wb , & x , & y )) break ;
311313 }
312314 case DT_ILLUMINANT_CUSTOM : // leave x and y as-is
313315 case DT_ILLUMINANT_DETECT_EDGES :
@@ -392,31 +394,11 @@ static inline void matrice_pseudoinverse(float (*in)[3], float (*out)[3], int si
392394 }
393395}
394396
395-
396- static gboolean find_temperature_from_raw_coeffs (const dt_image_t * img , const dt_aligned_pixel_t custom_wb ,
397- float * chroma_x , float * chroma_y )
397+ // returns TRUE is OK, FALSE if failed
398+ static gboolean get_CAM_to_XYZ (const dt_image_t * img , float (* CAM_to_XYZ )[3 ])
398399{
399- if (img == NULL ) return FALSE;
400- if (!dt_image_is_matrix_correction_supported (img )) return FALSE;
401-
402- gboolean has_valid_coeffs = TRUE;
403- const int num_coeffs = (img -> flags & DT_IMAGE_4BAYER ) ? 4 : 3 ;
404-
405- // Check coeffs
406- for (int k = 0 ; has_valid_coeffs && k < num_coeffs ; k ++ )
407- if (!dt_isnormal (img -> wb_coeffs [k ]) || img -> wb_coeffs [k ] == 0.0f ) has_valid_coeffs = FALSE;
408-
409- if (!has_valid_coeffs ) return FALSE;
410-
411- // Get white balance camera factors
412- dt_aligned_pixel_t WB = { img -> wb_coeffs [0 ], img -> wb_coeffs [1 ], img -> wb_coeffs [2 ], img -> wb_coeffs [3 ] };
413-
414- // Adapt the camera coeffs with custom white balance if provided
415- // this can deal with WB coeffs that don't use the input matrix reference
416- if (custom_wb )
417- for (size_t k = 0 ; k < 4 ; k ++ ) WB [k ] *= custom_wb [k ];
418-
419- // Get the camera input profile (matrice of primaries)
400+ if (img == NULL || CAM_to_XYZ == NULL ) return FALSE;
401+ // Get the camera input profile (matrice of primaries) - embedded or raw library DB
420402 float XYZ_to_CAM [4 ][3 ];
421403 dt_mark_colormatrix_invalid (& XYZ_to_CAM [0 ][0 ]);
422404
@@ -445,21 +427,61 @@ static gboolean find_temperature_from_raw_coeffs(const dt_image_t *img, const dt
445427
446428 if (!dt_is_valid_colormatrix (XYZ_to_CAM [0 ][0 ])) return FALSE;
447429
448- // Bloody input matrices define XYZ -> CAM transform, as if we often needed camera profiles to output
449- // So we need to invert them. Here go your CPU cycles again.
450- float CAM_to_XYZ [4 ][3 ];
451430 dt_mark_colormatrix_invalid (& CAM_to_XYZ [0 ][0 ]);
452431 matrice_pseudoinverse (XYZ_to_CAM , CAM_to_XYZ , 3 );
453- if (!dt_is_valid_colormatrix (CAM_to_XYZ [0 ][0 ])) return FALSE;
432+ return dt_is_valid_colormatrix (CAM_to_XYZ [0 ][0 ]);
433+ }
434+
435+ // returns FALSE if failed; TRUE if successful
436+ static gboolean find_temperature_from_wb_coeffs (const dt_image_t * img , const dt_aligned_pixel_t wb_coeffs ,
437+ float * chroma_x , float * chroma_y )
438+ {
439+ if (img == NULL || wb_coeffs == NULL ) return FALSE;
440+ if (!dt_image_is_matrix_correction_supported (img )) return FALSE;
441+
442+ float CAM_to_XYZ [4 ][3 ];
443+ if (!get_CAM_to_XYZ (img , CAM_to_XYZ )) {
444+ return FALSE;
445+ }
454446
455447 float x , y ;
456- WB_coeffs_to_illuminant_xy (CAM_to_XYZ , WB , & x , & y );
448+ WB_coeffs_to_illuminant_xy (CAM_to_XYZ , wb_coeffs , & x , & y );
457449 * chroma_x = x ;
458450 * chroma_y = y ;
459451
460452 return TRUE;
461453}
462454
455+ // returns FALSE if failed; TRUE if successful
456+ static gboolean find_temperature_from_as_shot_coeffs (const dt_image_t * img , const dt_aligned_pixel_t custom_wb ,
457+ float * chroma_x , float * chroma_y )
458+ {
459+ if (img == NULL ) return FALSE;
460+
461+ gboolean has_valid_coeffs = TRUE;
462+ const int num_coeffs = (img -> flags & DT_IMAGE_4BAYER ) ? 4 : 3 ;
463+
464+ // Check coeffs
465+ for (int k = 0 ; has_valid_coeffs && k < num_coeffs ; k ++ )
466+ if (!dt_isnormal (img -> wb_coeffs [k ]) || img -> wb_coeffs [k ] == 0.0f ) has_valid_coeffs = FALSE;
467+
468+ if (!has_valid_coeffs ) return FALSE;
469+
470+ // Get as-shot white balance camera factors (from raw)
471+ // component wise raw-RGB * wb_coeffs should provide R=G=B for a neutral patch under
472+ // the scene illuminant
473+ dt_aligned_pixel_t WB = { img -> wb_coeffs [0 ], img -> wb_coeffs [1 ], img -> wb_coeffs [2 ], img -> wb_coeffs [3 ] };
474+
475+ // Adapt the camera coeffs with custom D65 coefficients if provided ('caveats' workaround)
476+ // this can deal with WB coeffs that don't use the input matrix reference
477+ // adaptation_ratios[k] = chr->D65coeffs[k] / chr->wb_coeffs[k]
478+ if (custom_wb )
479+ for (size_t k = 0 ; k < 4 ; k ++ ) WB [k ] *= custom_wb [k ];
480+ // for a neutral surface, raw RGB * img->wb_coeffs would produce neutral R=G=B
481+
482+ return find_temperature_from_wb_coeffs (img , WB , chroma_x , chroma_y );
483+ }
484+
463485
464486DT_OMP_DECLARE_SIMD ()
465487static inline float planckian_normal (const float x , const float t )
0 commit comments