Skip to main content

astroimage/
converter.rs

1use std::path::Path;
2use std::sync::Arc;
3
4use anyhow::{Context, Result};
5
6use crate::output;
7use crate::pipeline;
8use crate::types::{ProcessConfig, ProcessedImage};
9
10pub struct ImageConverter {
11    downscale: usize,
12    quality: u8,
13    apply_debayer: bool,
14    preview_mode: bool,
15    thread_pool: Option<Arc<rayon::ThreadPool>>,
16}
17
18impl ImageConverter {
19    pub fn new() -> Self {
20        ImageConverter {
21            downscale: 1,
22            quality: 95,
23            apply_debayer: true,
24            preview_mode: false,
25            thread_pool: None,
26        }
27    }
28
29    pub fn with_downscale(mut self, factor: usize) -> Self {
30        self.downscale = factor;
31        self
32    }
33
34    pub fn with_quality(mut self, quality: u8) -> Self {
35        self.quality = quality.clamp(1, 100);
36        self
37    }
38
39    pub fn without_debayer(mut self) -> Self {
40        self.apply_debayer = false;
41        self
42    }
43
44    pub fn with_preview_mode(mut self) -> Self {
45        self.preview_mode = true;
46        self
47    }
48
49    pub fn with_thread_pool(mut self, pool: Arc<rayon::ThreadPool>) -> Self {
50        self.thread_pool = Some(pool);
51        self
52    }
53
54    /// Process a FITS/XISF image and return raw pixel data without writing to disk.
55    ///
56    /// Returns a `ProcessedImage` containing interleaved RGB u8 bytes,
57    /// suitable for display in a GUI, web backend, or further processing.
58    pub fn process<P: AsRef<Path>>(&self, input_path: P) -> Result<ProcessedImage> {
59        let config = ProcessConfig {
60            downscale_factor: self.downscale,
61            jpeg_quality: self.quality,
62            apply_debayer: self.apply_debayer,
63            preview_mode: self.preview_mode,
64            auto_stretch: true,
65        };
66
67        let path = input_path.as_ref();
68        match &self.thread_pool {
69            Some(pool) => pool.install(|| pipeline::process_image(path, &config)),
70            None => pipeline::process_image(path, &config),
71        }
72        .context("Image processing failed")
73    }
74
75    /// Process a FITS/XISF image and save the result as JPEG or PNG.
76    pub fn convert<P: AsRef<Path>, Q: AsRef<Path>>(
77        &self,
78        input_path: P,
79        output_path: Q,
80    ) -> Result<()> {
81        let image = self.process(&input_path)?;
82
83        output::save_image(&image, output_path.as_ref(), self.quality)
84            .context("Image save failed")?;
85
86        Ok(())
87    }
88}
89
90impl Default for ImageConverter {
91    fn default() -> Self {
92        Self::new()
93    }
94}