| Crates.io | sarpro |
| lib.rs | sarpro |
| version | 0.3.2 |
| created_at | 2025-08-09 00:47:31.263196+00 |
| updated_at | 2025-09-01 01:55:41.938114+00 |
| description | A high-performance Sentinel-1 Synthetic Aperture Radar (SAR) GRD product to image processor. |
| homepage | https://github.com/bogwi/sarpro |
| repository | https://github.com/bogwi/sarpro |
| max_upload_size | |
| id | 1787460 |
| size | 5,280,246 |
A high-performance Sentinel-1 Synthetic Aperture Radar (SAR) GRD product to image processor written in Rust. SARPRO is designed for users and organizations who need fast, hassle-free processing of Sentinel-1 GRD products into GeoTIFF or JPEG formats, delivering excellent grayscale GeoTIFFs and grayscale or synthetic RGB JPEGs with minimal setup time.
See ROADMAP.md for the high‑level phases and upcoming features. See ROADMAP_explained.md for the detailed technical explanation. This highlights what’s coming (COG/STAC, masking, speckle filters, DEM‑based RTC, tiling, time‑series) and expected release groupings.
Note 1: The ROADMAP and its technical explanation might change at any moment prioritizing some features over others or adding new ones and slicing some out. Yet it was created to be a minimal-refactor plan and as organic as possible, though not a contract.
Note 2: The ROADMAP and its technical explanation can have mistakes and knowledge gaps which as our understanding of the project deepens will be eliminated or treated as opinionated.
Visit CHANGELOG.md to track the changes.
CLI: Download CDSE (dataspace.copernicus.eu) and ASF (asf.alaska.edu) SAFE ZIPs: Get and process SAFE ZIPs from remote CDSE/ASF sources with full authentication flow and materialize them into cache.
--safe-zip-url <URL>, --remote-cache-dir <PATH/TO/CACHE>, --output <PATH/TO/OUTPUT/NAME.jpg|tiff>, --output-dir <PATH/TO/OUTPUT/>CDSE_ZIP_URL="https://download.dataspace.copernicus.eu/odata/v1/Products(e1499d5b-6e3f-40c1-9c09-d6afe4fdcfeb)/$value"
cargo run --bin sarpro -- --safe-zip-url "$CDSE_ZIP_URL" \
--remote-cache-dir /tmp/sarpro_cache \
--output /tmp/ --format tiff --polarization vv \
--size 1024 --log --target-crs auto
ASF_ZIP_URL="https://datapool.asf.alaska.edu/GRD_HD/SA/S1A_IW_GRDH_1SDV_20250827T225857_20250827T225922_060728_078ECD_5BCB.zip"
cargo run --bin sarpro -- --safe-zip-url "$ASF_ZIP_URL" \
--remote-cache-dir /tmp/sarpro_cache \
--output /tmp/asf_ok.jpg --format jpeg --polarization multiband \
--size 1024 --log --target-crs auto
--output /path/to/output/name.jpg|tiff to set the output filename directory and the name of the file. If the name is not set, like in the CDSE example, the default is the canonical filename of the .SAFE file.CDSE_CLIENT_ID and CDSE_CLIENT_SECRET or SARPRO_NETRC.--input <PATH_OR_URL> and --input-dir <PATH_OR_URL>--input http://127.0.0.1:8999/GRD/...F07D.SAFE
...
--input-dir http://127.0.0.1:8999/GRD/
...
--input-dir /path/to/GRD
...
GRD is a placeholder for a directory containing unpacked SAFE files served by a server or on your local filesystem.https://datapool.asf.alaska.edu/GRD_HD/SA/S1A_IW_GRDH_1SDV_20240516T225933_20240516T225958_053903_068D39_BA0C.zip
https://datapool.asf.alaska.edu/GRD_HD/SA/S1A_IW_GRDH_1SDV_20240528T225908_20240528T225933_054078_069350_95E2.zip
https://datapool.asf.alaska.edu/GRD_HD/SA/S1A_IW_GRDH_1SDV_20250411T110554_20250411T110623_058708_07455A_3328.zip
https://download.dataspace.copernicus.eu/odata/v1/Products(82fcf068-c4df-4735-87d1-7eb9aad4b231)/$value
Support for a native flag --input-list <PATH/TO/LIST/OF/URLS> is coming soon. In the meantime, see sarpro_intake_cdse_asf_urls.sh (Bash, Linux/macOS) and sarpro_intake_cdse_asf_urls.py (Python, cross-platform) for robust, parallel batch processing from a list of URLs.
chmod +x sarpro_intake_cdse_asf_urls.sh
./sarpro_intake_cdse_asf_urls.sh
python sarpro_intake_cdse_asf_urls.py
EPSG:4326, EPSG:32633) with --target-crs and resampling (--resample-alg nearest|bilinear|cubic|lanczos)..json metadata, .jgw/.wld worldfile, and .prj projection. Great for catalogs and reports.sum, diff, ratio, n-diff, and log-ratio on available pairs (VV/VH or HH/HV) to emphasize scattering differences.--batch and --input-dir/--output-dir, continue on errors, and get per‑run summaries.--size), minimizing I/O and memory. Choose resampling quality; Lanczos and Average are used appropriately when shrinking (v0.2.3+).--pad to square for CNN‑friendly datasets.--target-crs none to avoid any resampling (better for quantitative pixel comparisons and downstream co‑registration pipelines).CLI: Ideal for server environments and remote processing. Perfect for batch processing large datasets ready for machine learning workflows. Connect remotely and process images in bulk with consistent, automated results.
GUI: Best for local work and interactive processing. Use when you need visual feedback, parameter experimentation, or one-off processing tasks on your local machine.
Library: For experimentation and when you need direct access to core processing functions. Integrate SARPRO capabilities into your own Rust applications.
CDSE_CLIENT_ID, CDSE_CLIENT_SECRET (OAuth2 client_credentials).../openid-connect/token and injects Authorization: Bearer <token> into HTTP requests.GDAL_HTTP_HEADERS) when needed.SARPRO_NETRC (absolute path you provide)sarpro/.netrc~/.netrcmachine urs.earthdata.nasa.gov login <username> password <password>; file must be chmod 600.~/.sarpro/asf_cookies.txt and applied to both curl and GDAL (GDAL_HTTP_COOKIEFILE/JAR).--remote-cache-dir is set)
Content‑Disposition or OData ?$select=Name and cached.curl using --netrc-file and cookie jar; resume enabled with -C -, retries and backoff configured; canonical filename comes from the URL tail./vsizip//vsicurl/...); CDSE headers/cookies and ASF cookies are applied via GDAL config so range requests and auth flow through GDAL.HEAD (via curl for ASF, reqwest for CDSE) → parse Content‑Length and Content‑Disposition.Range: bytes=0-0 → parse Content‑Range total.?$select=Name,ContentLength.content_length drives a determinate progress bar; if unavailable, progress is shown as indeterminate..netrc is chmod 600; otherwise servers may ignore it and GDAL/curl may refuse to use it.$value endpoints may not support HTTP Range; resume is therefore best‑effort. ASF datapool supports Range and robust resume..netrc host is exactly urs.earthdata.nasa.gov and permissions are 600; remove stale cookies if needed.CDSE_CLIENT_ID/SECRET; re‑try after token refresh; confirm the product UUID is accessible.Content‑Length; the Range preflight or OData fallback should populate it when possible.# Point SARPRO to a custom netrc file for ASF
export SARPRO_NETRC=/secure/path/earthdata.netrc
chmod 600 "$SARPRO_NETRC"
# CDSE OAuth2
export CDSE_CLIENT_ID=...
export CDSE_CLIENT_SECRET=...
That's it!
SARPRO is optimized for bulk processing with exceptional performance:
none will reduce the time to ~348.21 ms. And you might as well expect N x performance improvement in the cloud. Warping to the native resolution same dual-band 400MP SAR GRD product and into synthetic RGB JPEG takes x 12-14 or around 55 seconds. Non warping on the same product peaks around 40 seconds.Name: S1A_IW_GRDH_1SDV_20250706T204346_20250706T204411_059968_07730F_F70D.SAFE
Size: 1893MB
Sensing time: 2025-07-06T20:39:57.839576
Platform short name: SENTINEL-1
Instrument short name: SAR

SARPRO delivers excellent layer separation in synthetic RGB JPEGs, even in highly complex scenes and at extreme zoom levels. The example shown uses the handcrafted Default preset with the new CLAHE autoscale strategy. Speckle is minimal and unobtrusive, despite no speckle filtering being applied. Speckle filtering will be introduced as an optional feature in v0.3.x to further enhance synthetic RGB quality and leverage workstation performance as needed.

Setting reprojection to --target-crs none or omitting it preserves native geometry just as it is packed in the SAFE product.
SARPRO depends on GDAL (Geospatial Data Abstraction Library) for reading and processing geospatial data. This is the only critical dependency to install correctly.
# Install GDAL via Homebrew
brew install gdal
# Verify installation
gdalinfo --version
Environment Variables Setup:
After installing GDAL with Homebrew, you need to set up environment variables for the Rust build process:
# Add to your ~/.zshrc or ~/.bashrc
export GDAL_HOME=$(brew --prefix gdal)
export GDAL_INCLUDE_DIR=$GDAL_HOME/include
export GDAL_LIB_DIR=$GDAL_HOME/lib
export PKG_CONFIG_PATH=$GDAL_HOME/lib/pkgconfig:$PKG_CONFIG_PATH
# For Apple Silicon Macs, you might also need:
export LIBRARY_PATH=$GDAL_HOME/lib:$LIBRARY_PATH
export CPATH=$GDAL_HOME/include:$CPATH
# Install GDAL development packages
sudo apt update
sudo apt install libgdal-dev gdal-bin pkg-config
# Verify installation
gdalinfo --version
For other platforms or custom installations, ensure:
pkg-config can find GDALGDAL_HOME, GDAL_LIB_DIR, and GDAL_INCLUDE_DIR environment variables if neededSARPRO requires Rust 2024 edition. Install Rust using rustup:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Clone the repository
git clone https://github.com/bogwi/sarpro.git
cd sarpro
# Build the project
cargo build --release --features full
# The CLI binary will be available at target/release/sarpro
# The GUI binary will be available at target/release/sarproUI
# Install CLI only (default features)
cargo install sarpro
# Install GUI binary (requires GDAL and GUI deps)
cargo install sarpro --features gui --bin sarproUI
Note: Installing the GUI requires the GDAL runtime and GUI dependencies to be available on your system.
debug=1) and panic=abort for useful backtraces. Fast to compile; suitable for cargo install and typical Linux/Windows source installs.release-lto profile enables fat LTO and codegen-units=1. It produces smaller binaries on many platforms at the cost of significantly longer compile times.Build examples:
# Fast build (default release)
cargo build --release --features full
# Opt-in fat LTO build
cargo build --profile release-lto --features full
Notes:
The CLI provides powerful batch processing capabilities for SAR imagery, optimized for cloud environments and ML pipeline preparation. Perfect for remote processing and bulk operations.
# Batch process a directory
cargo run --release --bin sarpro -- --input-dir /path/to/safe/directories --output-dir /path/to/output --batch --log --format jpeg --polarization multiband --size 1024 --autoscale tamed --target-crs auto --resample-alg lanczos --synrgb-mode default
# Process a .SAFE file with specific parameters
cargo run --release --bin sarpro -- -i data.SAFE -o output.tiff \
--polarization multiband \
--format tiff \
--bit-depth u16 \
--size 1024 \
--autoscale tamed \
--target-crs auto \
--resample-alg lanczos \
--log
--input, -i: Input SAFE local path or remote non-authenticated HTTP(S) URL (single file mode)
--input-dir: Input local path or remote non-authenticated HTTP(S) URL directory containing SAFE files (batch mode)
--output, -o: Output filename (single file mode)
--output-dir: Output directory for batch processing
--format, -f: Output format (tiff or jpeg)
--bit-depth: Output bit depth (8 or 16)
--polarization: Polarization mode (vv, vh, hh, hv, multiband, sum, diff, ratio, n-diff, log-ratio)
--autoscale: Autoscaling strategy (standard, robust, adaptive, equalized, tamed, default, clahe)
--synrgb-mode: Synthetic RGB mode, for JPEG outputs (default, rgb-ratio, sar-urban, enhanced)
--size: Output image size (predefined: 512, 1024, 2048, or custom number, or original)
--pad: Add padding to make square images
--batch: Enable batch mode with error resilience
--log: Enable detailed logging
--target-crs: Optional target CRS for map reprojection (e.g., EPSG:4326, EPSG:32633). Special values: auto (detect UTM zone from metadata), none (disable reprojection)
--resample-alg: Resampling algorithm for reprojection (nearest, bilinear, cubic, lanczos) — default: lanczos
--safe-zip-url: Optional remote CDSE(dataspace.copernicus.eu) or ASF(asf.alaska.edu) SAFE ZIP URL to download and process with full authentication flow.
--remote-cache-dir: Remote cache directory to materialize the SAFE ZIP (mandatory for remote ZIPs).
Launch the GUI application for interactive local processing and experimentation:
cargo run --release --bin sarproUI --features gui
or double click the executable here: target/release/sarproUI if you have built the project with the full feature.
The GUI is ideal for local work and provides:
The GUI is the easiest way to get started with SARPRO locally.

Name: S1C_IW_GRDH_1SDV_20250730T142348_20250730T142417_003451_006EEA_895D.SAFE
Size: 1893MB
Sensing time: 2025-07-30T14:23:48.452000Z
Platform short name: SENTINEL-1
Instrument short name: SAR
Create good lookers using synthetic RGB JPEGs in a few clicks.

Get what you need in classic multi-band Grayscale TIFFs, quickly.

SARPRO provides a typed, ergonomic Rust API for integrating Sentinel-1 GRD processing into your applications. The API is built on top of the working MVP used by the CLI/GUI and is robust, but still early and may evolve.
Note on stability: the public API is experimental in initial releases. Expect incremental improvements as the project stabilizes. Breaking changes may occur; consult the changelog and docs.
[dependencies]
sarpro = { version = "0.3", features = ["full"] }
use std::path::Path;
use sarpro::{
api::process_safe_to_path,
ProcessingParams,
AutoscaleStrategy, BitDepthArg, OutputFormat, Polarization,
InputFormat, SyntheticRgbMode
};
let params = ProcessingParams {
format: OutputFormat::TIFF,
input_format: InputFormat::Safe,
bit_depth: BitDepthArg::U16,
polarization: Polarization::Multiband,
autoscale: AutoscaleStrategy::Clahe,
target_crs: Some("auto".to_string()),
resample_alg: Some("lanczos".to_string()),
synrgb_mode: SyntheticRgbMode::Default,
size: Some(2048),
pad: true,
};
process_safe_to_path(
Path::new("/data/S1A_example.SAFE"),
Path::new("/out/product.tiff"),
¶ms,
)?;
use std::path::Path;
use sarpro::{
api::process_safe_to_buffer_with_mode,
AutoscaleStrategy, BitDepth, OutputFormat, Polarization, SyntheticRgbMode,
};
let img = process_safe_to_buffer_with_mode(
Path::new("/data/S1A_xxx.SAFE"),
Polarization::Multiband,
AutoscaleStrategy::Tamed,
BitDepth::U8, // Controls buffer bit depth for TIFF paths
Some(1024), // Resize target
true, // Pad to square
OutputFormat::JPEG, // JPEG for synthetic RGB; TIFF for grayscale/multiband
SyntheticRgbMode::Default,
)?;
match (img.format, img.bit_depth) {
(OutputFormat::JPEG, _) => {
// Synthetic RGB (interleaved RGB u8)
let rgb: &[u8] = img.rgb.as_ref().unwrap();
// Use in your pipeline...
}
(OutputFormat::TIFF, sarpro::BitDepth::U8) => {
// Single-band or multiband u8
let band1 = img.gray.as_ref();
let band2 = img.gray_band2.as_ref();
}
(OutputFormat::TIFF, sarpro::BitDepth::U16) => {
// Single-band or multiband u16
let band1 = img.gray16.as_ref();
let band2 = img.gray16_band2.as_ref();
}
}
use std::path::Path;
use ndarray::Array2;
use sarpro::{
api::{save_image, save_multiband_image},
AutoscaleStrategy, BitDepth, OutputFormat, ProcessingOperation,
};
fn save_single(processed: &Array2<f32>) -> sarpro::Result<()> {
save_image(
processed,
Path::new("/out/single.tiff"),
OutputFormat::TIFF,
BitDepth::U16,
Some(2048),
None, // Optional SAFE metadata if available
true,
AutoscaleStrategy::Tamed,
ProcessingOperation::SingleBand,
)
}
fn save_dual(vv: &Array2<f32>, vh: &Array2<f32>) -> sarpro::Result<()> {
save_multiband_image(
vv,
vh,
Path::new("/out/multiband.tiff"),
OutputFormat::TIFF,
BitDepth::U8,
Some(1024),
None,
true,
AutoscaleStrategy::Tamed,
ProcessingOperation::MultibandVvVh,
)
}
use std::path::Path;
use sarpro::{
api::process_directory_to_path,
ProcessingParams, AutoscaleStrategy, BitDepthArg, OutputFormat, Polarization, InputFormat, SyntheticRgbMode,
};
let params = ProcessingParams {
format: OutputFormat::JPEG,
input_format: InputFormat::Safe,
bit_depth: BitDepthArg::U8,
polarization: Polarization::Multiband,
autoscale: AutoscaleStrategy::Tamed,
synrgb_mode: SyntheticRgbMode::Default,
size: Some(1024),
pad: true,
target_crs: Some("auto".to_string()),
resample_alg: Some("lanczos".to_string()),
};
let report = process_directory_to_path(
Path::new("/data/safe_dir"),
Path::new("/out"),
¶ms,
true, // continue_on_error
)?;
println!("processed={}, skipped={}, errors={}", report.processed, report.skipped, report.errors);
--target-crs is set, SARPRO uses GDAL gdalwarp to reproject using the product’s georeferencing (and falls back to GCP + -tps if needed). This improves map alignment in many cases but is not a substitute for full RDTC.json, .jgw/.wld, and .prj sidecarsflowchart TB
A["Input: Sentinel-1 SAFE (GRD)"] --> B["Parse manifest.safe + annotation XMLs\nExtract product & georef metadata"]
A --> C["Identify polarization measurement TIFFs (VV/VH/HH/HV)"]
C --> D["Read TIFF via GDAL\narray + geotransform + projection/GCP"]
D --> E{"Target CRS"}
E -- "none" --> G["Use native georeferencing"]
E -- "auto" --> Ea["Resolve UTM/UPS from metadata/GCPs\n(e.g., EPSG:326xx/327xx)"] --> F["Warp with gdalwarp to target CRS\n-r nearest/bilinear/cubic/lanczos\nIf no SRS: use GCP + -tps"]
E -- "custom EPSG" --> F
F --> H["Optional polarization ops\nsum/diff/ratio/n-diff/log-ratio or pair for synRGB"]
G --> H
H --> I["Convert magnitude to dB\n10·log10(|x|) and mask invalid"]
I --> J["Autoscale to U8/U16 using strategy\nstandard/robust/adaptive/equalized/tamed/clahe"]
J --> K["Optional resize (long side)"]
K --> L["Optional pad to square"]
L --> M{"Output format"}
M -- "TIFF (u8/u16)" --> N["Write GeoTIFF bands"]
N --> O["Embed metadata (geotransform/projection + attributes)"]
M -- "JPEG (gray/synRGB)" --> P["Write JPEG (gray or synthetic RGB)\nmode: default/rgb-ratio/sar-urban/enhanced"]
P --> Q["Sidecars: .json (metadata), .jgw/.wld, .prj"]
pkg-config locates it (pkg-config --libs gdal) and the environment variables in this README are exported in your shell.brew --prefix gdal resolves and paths are set for both compile and runtime (DYLD_LIBRARY_PATH may also be needed when running outside Cargo).libgdal-dev and gdal-bin are installed and the GDAL version is supported by the crate.This project is dual-licensed under MIT OR Apache-2.0.
SARPRO is built with: