Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 132 additions & 2 deletions src-tauri/src/raw_processing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ use crate::white_balance::WhiteBalance;
use anyhow::{Result, anyhow};
use image::{DynamicImage, ImageBuffer, Rgba};
use rawler::{
decoders::{Decoder, Orientation, RawDecodeParams},
decoders::{Decoder, FormatHint, Orientation, RawDecodeParams, WellKnownIFD},
formats::tiff::Value,
imgop::{
develop::{DemosaicAlgorithm, Intermediate, ProcessingStep, RawDevelop},
xyz::Illuminant,
},
rawimage::{RawImage, RawPhotometricInterpretation},
rawimage::{RawImage, RawImageData, RawPhotometricInterpretation},
rawsource::RawSource,
tags::DngTag,
};
use std::sync::{
Arc,
Expand Down Expand Up @@ -60,6 +62,129 @@ fn is_linear_raw_format(raw_image: &RawImage) -> bool {
)
}

fn apply_black_level_delta_v_to_data(
data: &mut RawImageData,
width: usize,
height: usize,
cpp: usize,
delta_start_row: usize,
deltas: &[f32],
) -> bool {
let Some(row_width) = width.checked_mul(cpp) else {
return false;
};
let Some(expected_len) = row_width.checked_mul(height) else {
return false;
};
if row_width == 0
|| deltas.is_empty()
|| deltas.iter().any(|delta| !delta.is_finite())
{
return false;
}
let Some(delta_end_row) = delta_start_row.checked_add(deltas.len()) else {
return false;
};
if deltas.len() != 1 && delta_end_row > height {
return false;
}

match data {
RawImageData::Integer(pixels) if pixels.len() == expected_len => {
for (row, row_pixels) in pixels.chunks_exact_mut(row_width).enumerate() {
let delta = if deltas.len() == 1 {
deltas[0]
} else if (delta_start_row..delta_end_row).contains(&row) {
deltas[row - delta_start_row]
} else {
continue;
};
for pixel in row_pixels {
*pixel = (*pixel as f32 - delta)
.round()
.clamp(0.0, u16::MAX as f32) as u16;
}
}
}
RawImageData::Float(pixels) if pixels.len() == expected_len => {
for (row, row_pixels) in pixels.chunks_exact_mut(row_width).enumerate() {
let delta = if deltas.len() == 1 {
deltas[0]
} else if (delta_start_row..delta_end_row).contains(&row) {
deltas[row - delta_start_row]
} else {
continue;
};
for pixel in row_pixels {
*pixel = (*pixel - delta).max(0.0);
}
}
}
_ => return false,
}

true
}

fn apply_dng_black_level_delta_v(raw_image: &mut RawImage, decoder: &dyn Decoder) -> bool {
if decoder.format_hint() != FormatHint::DNG
|| !matches!(
&raw_image.photometric,
RawPhotometricInterpretation::Cfa(_)
)
{
return false;
}

let Ok(Some(raw_ifd)) = decoder.ifd(WellKnownIFD::Raw) else {
return false;
};
let Some(entry) = raw_ifd.get_entry(DngTag::BlackLevelDeltaV) else {
return false;
};
let value = &entry.value;
if !matches!(
value,
Value::Rational(_) | Value::SRational(_) | Value::Float(_) | Value::Double(_)
) {
return false;
}

let mut deltas = Vec::with_capacity(value.count());
for index in 0..value.count() {
let Ok(Some(delta)) = value.get_f32(index) else {
return false;
};
deltas.push(delta);
}

let delta_start_row = if deltas.len() == 1 || deltas.len() == raw_image.height {
0
} else {
let Some(active_area) = raw_ifd.get_entry(DngTag::ActiveArea) else {
return false;
};
if active_area.value.count() < 4 {
return false;
}
let top = active_area.value.force_usize(0);
let bottom = active_area.value.force_usize(2);
if bottom.checked_sub(top) != Some(deltas.len()) {
return false;
}
top
};

apply_black_level_delta_v_to_data(
&mut raw_image.data,
raw_image.width,
raw_image.height,
raw_image.cpp,
delta_start_row,
&deltas,
)
}

#[inline]
fn srgb_to_linear(value: f32) -> f32 {
if value <= 0.04045 {
Expand Down Expand Up @@ -155,6 +280,10 @@ fn develop_internal(
check_cancel()?;
let mut raw_image: RawImage = decoder.raw_image(&source, &RawDecodeParams::default(), false)?;

if apply_dng_black_level_delta_v(&mut raw_image, decoder.as_ref()) {
log::debug!("Applied DNG BlackLevelDeltaV correction");
}

let orientation = metadata_orientation(decoder.as_ref(), &source)?;

let is_linear_format = is_linear_raw_format(&raw_image);
Expand Down Expand Up @@ -345,3 +474,4 @@ pub fn get_fast_demosaic_scale_factor(
}
1.0
}