use std::path::PathBuf;
use gdal::raster::ResampleAlg;
use tracing::info;
use sarpro::core::processing::save::{
save_processed_image, save_processed_multiband_image_sequential,
};
use sarpro::io::sentinel1::TargetCrsArg;
use sarpro::io::SafeReader;
use sarpro::types::{BitDepth, OutputFormat, ProcessingOperation, SyntheticRgbMode};
use sarpro::{AutoscaleStrategy, BitDepthArg, InputFormat, Polarization, PolarizationOperation};
use sarpro::core::params::ProcessingOptions;
use crate::cli::errors::AppError;
pub fn process_single_file(
input: &PathBuf,
output: &PathBuf,
format: OutputFormat,
bit_depth: BitDepthArg,
input_format: InputFormat,
polarization: Polarization,
autoscale: AutoscaleStrategy,
size: &str,
batch_mode: bool,
pad: bool,
target_crs: Option<&str>,
resample_alg: Option<&str>,
synrgb_mode: SyntheticRgbMode,
_proc_opts: &ProcessingOptions,
) -> Result<(), Box<dyn std::error::Error>> {
let target_size = if size == "original" {
None
} else {
let parsed_size = size.parse::<usize>().map_err(|_| AppError::InvalidSize {
size: size.to_string(),
})?;
if parsed_size == 0 {
return Err(AppError::ZeroSize { size: parsed_size }.into());
}
Some(parsed_size)
};
let reader = if batch_mode {
match input_format {
InputFormat::Safe => {
let resample = match resample_alg {
Some("nearest") => Some(ResampleAlg::NearestNeighbour),
Some("bilinear") => Some(ResampleAlg::Bilinear),
Some("cubic") => Some(ResampleAlg::Cubic),
Some("lanczos") => Some(ResampleAlg::Lanczos),
_ => None,
};
let target_arg: Option<TargetCrsArg> = match target_crs {
Some(t) if t.eq_ignore_ascii_case("none") => Some(TargetCrsArg::None),
Some(t) if t.eq_ignore_ascii_case("auto") => Some(TargetCrsArg::Auto),
Some(t) => Some(TargetCrsArg::Custom(t.to_string())),
None => None,
};
match SafeReader::open_with_warnings_with_options(
input,
polarization,
target_arg,
resample,
target_size,
)? {
Some(reader) => reader,
None => {
tracing::warn!("Skipping unsupported product type: {:?}", input);
return Ok(());
}
}
}
}
} else {
match input_format {
InputFormat::Safe => {
let resample_alg = match resample_alg {
Some("nearest") => Some(ResampleAlg::NearestNeighbour),
Some("bilinear") => Some(ResampleAlg::Bilinear),
Some("cubic") => Some(ResampleAlg::Cubic),
Some("lanczos") => Some(ResampleAlg::Lanczos),
_ => None,
};
let target_arg: Option<TargetCrsArg> = match target_crs {
Some(t) if t.eq_ignore_ascii_case("none") => Some(TargetCrsArg::None),
Some(t) if t.eq_ignore_ascii_case("auto") => Some(TargetCrsArg::Auto),
Some(t) => Some(TargetCrsArg::Custom(t.to_string())),
None => None,
};
SafeReader::open_with_options(
input,
polarization,
target_arg,
resample_alg,
target_size,
)?
}
}
};
let bit_depth_enum = match bit_depth {
BitDepthArg::U8 => BitDepth::U8,
BitDepthArg::U16 => BitDepth::U16,
};
match polarization {
Polarization::Vv | Polarization::Vh | Polarization::Hh | Polarization::Hv => {
let processed = match polarization {
Polarization::Vv => reader.vv_data()?,
Polarization::Vh => reader.vh_data()?,
Polarization::Hh => reader.hh_data()?,
Polarization::Hv => reader.hv_data()?,
_ => unreachable!(),
};
let bytes = processed.len() * std::mem::size_of::<f32>();
info!(
"Memory usage (approx): {:.2} MB",
bytes as f64 / 1024.0 / 1024.0
);
save_processed_image(
&processed,
output.as_path(),
format,
bit_depth_enum,
target_size,
Some(reader.metadata()),
pad,
autoscale,
ProcessingOperation::SingleBand,
)
}
Polarization::Multiband => {
if reader.vv_data().is_ok() && reader.vh_data().is_ok() {
let vv_processed = reader.vv_data()?;
let vh_processed = reader.vh_data()?;
let total_bytes =
(vv_processed.len() + vh_processed.len()) * std::mem::size_of::<f32>();
info!(
"Memory usage (Multiband VV/VH): {:.2} MB",
total_bytes as f64 / 1024.0 / 1024.0
);
save_processed_multiband_image_sequential(
&vv_processed,
&vh_processed,
output.as_path(),
format,
bit_depth_enum,
target_size,
Some(reader.metadata()),
pad,
autoscale,
ProcessingOperation::MultibandVvVh,
synrgb_mode,
)
} else if reader.hh_data().is_ok() && reader.hv_data().is_ok() {
let hh_processed = reader.hh_data()?;
let hv_processed = reader.hv_data()?;
let total_bytes =
(hh_processed.len() + hv_processed.len()) * std::mem::size_of::<f32>();
info!(
"Memory usage (Multiband HH/HV): {:.2} MB",
total_bytes as f64 / 1024.0 / 1024.0
);
save_processed_multiband_image_sequential(
&hh_processed,
&hv_processed,
output.as_path(),
format,
bit_depth_enum,
target_size,
Some(reader.metadata()),
pad,
autoscale,
ProcessingOperation::MultibandHhHv,
synrgb_mode,
)
} else {
let available = reader.get_available_polarizations();
return Err(AppError::IncompleDataPair {
operation: "multiband".to_string(),
available,
}
.into());
}
}
Polarization::OP(_) => {
let processed = if reader.vv_data().is_ok() && reader.vh_data().is_ok() {
match polarization {
Polarization::OP(PolarizationOperation::Sum) => reader.sum_data()?,
Polarization::OP(PolarizationOperation::Diff) => reader.difference_data()?,
Polarization::OP(PolarizationOperation::Ratio) => reader.ratio_data()?,
Polarization::OP(PolarizationOperation::NDiff) => {
reader.normalized_diff_data()?
}
Polarization::OP(PolarizationOperation::LogRatio) => reader.log_ratio_data()?,
_ => unreachable!(),
}
} else if reader.hh_data().is_ok() && reader.hv_data().is_ok() {
match polarization {
Polarization::OP(PolarizationOperation::Sum) => reader.sum_hh_hv_data()?,
Polarization::OP(PolarizationOperation::Diff) => {
reader.difference_hh_hv_data()?
}
Polarization::OP(PolarizationOperation::Ratio) => reader.ratio_hh_hv_data()?,
Polarization::OP(PolarizationOperation::NDiff) => {
reader.normalized_diff_hh_hv_data()?
}
Polarization::OP(PolarizationOperation::LogRatio) => {
reader.log_ratio_hh_hv_data()?
}
_ => unreachable!(),
}
} else {
let available = reader.get_available_polarizations();
return Err(AppError::IncompleDataPair {
operation: polarization.to_string(),
available,
}
.into());
};
let bytes = processed.len() * std::mem::size_of::<f32>();
info!(
"Memory usage (approx): {:.2} MB",
bytes as f64 / 1024.0 / 1024.0
);
save_processed_image(
&processed,
output.as_path(),
format,
bit_depth_enum,
target_size,
Some(reader.metadata()),
pad,
autoscale,
ProcessingOperation::PolarOp(match polarization {
Polarization::OP(op) => op,
_ => unreachable!(),
}),
)
}
}
}