Skip to main content

panorama_tiler/
config.rs

1use serde::{Deserialize, Serialize};
2
3/// Input projection format of the source image.
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5pub enum Projection {
6    #[default]
7    Equirectangular,
8    Cylindrical,
9}
10
11/// Output image formats supported by the tiler.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
13#[serde(rename_all = "lowercase")]
14pub enum OutputFormat {
15    #[default]
16    Jpeg,
17    Png,
18    #[cfg(feature = "webp")]
19    Webp,
20}
21
22impl OutputFormat {
23    #[must_use]
24    pub const fn to_extension(&self) -> &'static str {
25        match self {
26            Self::Jpeg => "jpg",
27            Self::Png => "png",
28            #[cfg(feature = "webp")]
29            Self::Webp => "webp",
30        }
31    }
32}
33
34/// Interpolation mode for pixel sampling.
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
36#[serde(rename_all = "lowercase")]
37pub enum InterpolationMode {
38    Bilinear,
39    #[default]
40    Bicubic,
41}
42
43/// Downscaling method used for lower-resolution pyramid levels.
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
45#[serde(rename_all = "lowercase")]
46pub enum DownscalingMethod {
47    /// Recursively downscale from the previous level. Faster but can accumulate interpolation errors.
48    #[default]
49    Recursive,
50    /// Downscale directly from the full-resolution cube face for each level. Slower but preserves maximum sharpness.
51    Direct,
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct PanoAngles {
56    /// Horizontal Angle of View (degrees, 0.0 to 360.0).
57    pub haov: f64,
58    /// Vertical Angle of View (degrees, 0.0 to 180.0).
59    pub vaov: f64,
60    /// Vertical pitch offset of the center (degrees).
61    pub v_offset: f64,
62    /// Offset of the horizon in pixels (can be negative).
63    pub horizon_pixels: i32,
64    pub projection: Projection,
65    /// Compass heading offset of the center (degrees).
66    pub north_offset: Option<f64>,
67}
68
69impl Default for PanoAngles {
70    fn default() -> Self {
71        Self {
72            haov: 360.0,
73            vaov: 180.0,
74            v_offset: 0.0,
75            horizon_pixels: 0,
76            projection: Projection::default(),
77            north_offset: None,
78        }
79    }
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize)]
83pub struct OutputConfig {
84    pub tile_size: u32,
85    pub fallback_size: u32,
86    pub cube_size: u32,
87    pub format: OutputFormat,
88    pub quality: u8,
89    pub interpolation_mode: InterpolationMode,
90    pub yaw_padding: f64,
91    pub pitch_padding: f64,
92    /// Background color used beyond boundaries (RGB, 0-255).
93    pub background_color: [u8; 3],
94    /// Method used to downscale cube faces to generate lower resolution pyramid levels.
95    pub downscaling_method: DownscalingMethod,
96}
97
98impl Default for OutputConfig {
99    fn default() -> Self {
100        Self {
101            tile_size: 512,
102            fallback_size: 1024,
103            cube_size: 0, // 0 defaults to retaining full detail automatically
104            format: OutputFormat::default(),
105            quality: 75,
106            interpolation_mode: InterpolationMode::default(),
107            background_color: [0, 0, 0],
108            yaw_padding: 0.0,
109            pitch_padding: 0.0,
110            downscaling_method: DownscalingMethod::default(),
111        }
112    }
113}
114
115/// Global tiler options.
116#[derive(Debug, Clone, Serialize, Deserialize, Default)]
117pub struct TilerConfig {
118    pub angles: PanoAngles,
119    pub output: OutputConfig,
120}
121
122// --- Serialization structures for the final output config.json ---
123#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
124#[serde(rename_all = "camelCase")]
125pub struct PannellumConfig {
126    #[serde(skip_serializing_if = "Option::is_none")]
127    pub haov: Option<f64>,
128    #[serde(skip_serializing_if = "Option::is_none")]
129    pub min_yaw: Option<f64>,
130    #[serde(skip_serializing_if = "Option::is_none")]
131    pub max_yaw: Option<f64>,
132    #[serde(skip_serializing_if = "Option::is_none")]
133    pub vaov: Option<f64>,
134    #[serde(skip_serializing_if = "Option::is_none")]
135    pub v_offset: Option<f64>,
136    #[serde(skip_serializing_if = "Option::is_none")]
137    pub min_pitch: Option<f64>,
138    #[serde(skip_serializing_if = "Option::is_none")]
139    pub max_pitch: Option<f64>,
140    #[serde(skip_serializing_if = "Option::is_none")]
141    pub background_color: Option<Vec<f64>>,
142    #[serde(skip_serializing_if = "Option::is_none")]
143    pub north_offset: Option<f64>,
144    #[serde(rename = "type")]
145    pub pano_type: String, // Always "multires"
146    pub multi_res: MultiResConfig,
147}
148
149#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
150#[serde(rename_all = "camelCase")]
151pub struct MultiResConfig {
152    #[serde(skip_serializing_if = "Option::is_none")]
153    pub missing_tiles: Option<String>,
154    pub path: String,
155    #[serde(skip_serializing_if = "Option::is_none")]
156    pub fallback_path: Option<String>,
157    pub extension: String,
158    pub tile_resolution: u32,
159    pub max_level: u32,
160    pub cube_resolution: u32,
161}