Skip to main content

bitmapfont_creator/
output.rs

1//! Output handling module
2
3use std::path::{Path, PathBuf};
4use serde::{Deserialize, Serialize};
5
6use crate::error::{BitmapFontError, Result};
7use crate::packer::AtlasResult;
8use crate::xml_generator::CharMetrics;
9
10/// Output result containing generated file paths
11#[derive(Debug, Serialize, Deserialize)]
12pub struct OutputResult {
13    /// Whether the operation succeeded
14    pub success: bool,
15    /// Path to the generated atlas PNG
16    #[serde(skip_serializing_if = "Option::is_none")]
17    pub atlas_path: Option<String>,
18    /// Path to the generated XML file
19    #[serde(skip_serializing_if = "Option::is_none")]
20    pub xml_path: Option<String>,
21    /// Number of characters processed
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub char_count: Option<usize>,
24    /// Atlas dimensions
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub atlas_size: Option<AtlasSize>,
27    /// Character map with positions
28    #[serde(skip_serializing_if = "Option::is_none")]
29    pub char_map: Option<serde_json::Value>,
30    /// Error type (if failed)
31    #[serde(skip_serializing_if = "Option::is_none")]
32    pub error_type: Option<String>,
33    /// Error message (if failed)
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub error_message: Option<String>,
36    /// Suggestion for fixing the error
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub suggestion: Option<String>,
39}
40
41/// Atlas size information
42#[derive(Debug, Serialize, Deserialize)]
43pub struct AtlasSize {
44    pub width: u32,
45    pub height: u32,
46}
47
48impl OutputResult {
49    /// Create a successful result
50    pub fn success(
51        atlas_path: PathBuf,
52        xml_path: PathBuf,
53        char_count: usize,
54        atlas_width: u32,
55        atlas_height: u32,
56        chars: &[CharMetrics],
57    ) -> Self {
58        let char_map = chars.iter().map(|c| {
59            (c.char.clone(), serde_json::json!({
60                "x": c.x,
61                "y": c.y,
62                "width": c.width,
63                "height": c.height,
64                "xoffset": c.xoffset,
65                "yoffset": c.yoffset,
66                "xadvance": c.xadvance,
67                "padding": c.padding
68            }))
69        }).collect::<serde_json::Map<String, serde_json::Value>>();
70
71        OutputResult {
72            success: true,
73            atlas_path: Some(atlas_path.to_string_lossy().to_string()),
74            xml_path: Some(xml_path.to_string_lossy().to_string()),
75            char_count: Some(char_count),
76            atlas_size: Some(AtlasSize {
77                width: atlas_width,
78                height: atlas_height,
79            }),
80            char_map: Some(serde_json::Value::Object(char_map)),
81            error_type: None,
82            error_message: None,
83            suggestion: None,
84        }
85    }
86
87    /// Create an error result
88    pub fn error(error_type: &str, message: &str, suggestion: &str) -> Self {
89        OutputResult {
90            success: false,
91            atlas_path: None,
92            xml_path: None,
93            char_count: None,
94            atlas_size: None,
95            char_map: None,
96            error_type: Some(error_type.to_string()),
97            error_message: Some(message.to_string()),
98            suggestion: Some(suggestion.to_string()),
99        }
100    }
101
102    /// Convert to JSON string
103    pub fn to_json(&self) -> Result<String> {
104        serde_json::to_string_pretty(self)
105            .map_err(|e| BitmapFontError::XmlGeneration(format!("Failed to serialize JSON: {}", e)))
106    }
107}
108
109/// Save output files
110pub fn save_outputs(
111    atlas: &AtlasResult,
112    xml_content: &str,
113    output_dir: &Path,
114    font_name: &str,
115) -> Result<(PathBuf, PathBuf)> {
116    // Create output directory if it doesn't exist
117    std::fs::create_dir_all(output_dir)?;
118
119    // Save atlas PNG
120    let atlas_path = output_dir.join(format!("{}.png", font_name));
121    atlas.image.save(&atlas_path)
122        .map_err(|e| BitmapFontError::Io(std::io::Error::new(
123            std::io::ErrorKind::Other,
124            format!("Failed to save atlas: {}", e)
125        )))?;
126
127    // Save XML file
128    let xml_path = output_dir.join(format!("{}.xml", font_name));
129    std::fs::write(&xml_path, xml_content)?;
130
131    Ok((atlas_path, xml_path))
132}