sarpro/api/
process_directory_to_path.rs

1//! Process all SAFE subdirectories from input_dir into output_dir
2
3use std::path::Path;
4use crate::core::params::ProcessingParams;
5use crate::error::{Error, Result};
6use crate::io::sentinel1::{SafeReader, TargetCrsArg};
7use super::batch_report::BatchReport;
8use super::iterate_safe_products::iterate_safe_products;
9use super::process_safe_to_path::process_safe_to_path;
10
11/// Process all SAFE subdirectories from `input_dir` into `output_dir` using `params`.
12/// If `continue_on_error` is true, errors are logged in the report and processing continues; otherwise, the first error is returned.
13pub fn process_directory_to_path(
14    input_dir: &Path,
15    output_dir: &Path,
16    params: &ProcessingParams,
17    continue_on_error: bool,
18) -> Result<BatchReport> {
19    std::fs::create_dir_all(output_dir).map_err(Error::from)?;
20
21    let mut report = BatchReport::default();
22
23    let mut iter = iterate_safe_products(input_dir)?;
24    while let Some(path) = iter.next() {
25        // Early viability check to allow skipping unsupported product types
26        // Map target CRS and resample algorithm similarly to single-file path
27        let target_arg: Option<TargetCrsArg> = match params.target_crs.as_deref() {
28            Some(t) if t.eq_ignore_ascii_case("none") => Some(TargetCrsArg::None),
29            Some(t) if t.eq_ignore_ascii_case("auto") => Some(TargetCrsArg::Auto),
30            Some(t) => Some(TargetCrsArg::Custom(t.to_string())),
31            None => None,
32        };
33        let resample_alg = match params.resample_alg.as_deref() {
34            Some("nearest") => Some(gdal::raster::ResampleAlg::NearestNeighbour),
35            Some("bilinear") => Some(gdal::raster::ResampleAlg::Bilinear),
36            Some("cubic") => Some(gdal::raster::ResampleAlg::Cubic),
37            Some("lanczos") | None => Some(gdal::raster::ResampleAlg::Lanczos),
38            Some(_) => Some(gdal::raster::ResampleAlg::Lanczos),
39        };
40
41        match SafeReader::open_with_warnings_with_options(
42            &path,
43            params.polarization,
44            target_arg,
45            resample_alg,
46            params.size,
47        )? {
48            Some(_) => {
49                // Determine output file name
50                let safe_name = path.file_name().unwrap().to_string_lossy();
51                let ext = match params.format {
52                    crate::types::OutputFormat::TIFF => "tiff",
53                    crate::types::OutputFormat::JPEG => "jpg",
54                };
55                let output_path = output_dir.join(format!("{}.{}", safe_name, ext));
56
57                match process_safe_to_path(&path, &output_path, params) {
58                    Ok(()) => report.processed += 1,
59                    Err(e) => {
60                        report.errors += 1;
61                        if !continue_on_error {
62                            return Err(e);
63                        }
64                    }
65                }
66            }
67            None => {
68                report.skipped += 1;
69                continue;
70            }
71        }
72    }
73
74    Ok(report)
75}