1use asefile::{AsepriteFile, AsepriteParseError};
2use image::{DynamicImage, ImageBuffer, Rgba};
3use ron::ser::{to_string_pretty, PrettyConfig};
4use serde::{Deserialize, Serialize};
5use std::{collections::HashMap, fs::File, path::Path};
6use std::{fs, io::Write, path::PathBuf};
7use texture_packer::{exporter::ImageExporter, TexturePacker, TexturePackerConfig};
8
9#[derive(Serialize, Deserialize, Debug)]
10pub struct AseTextureData {
11 pub width: u32,
12 pub height: u32,
13 pub basename: String,
14 pub frame: u32,
15 pub x: u32,
16 pub y: u32,
17}
18
19#[derive(Debug)]
20pub struct AsepritePackerConfig<'a> {
21 pub aseprite_file_names: &'a [&'a str],
22 pub path: &'a Path,
23 pub output_image_location: Option<&'a Path>,
24 pub output_ron_location: Option<&'a Path>,
25 pub trim: bool,
26}
27
28impl<'a> Default for AsepritePackerConfig<'a> {
29 fn default() -> Self {
30 AsepritePackerConfig {
31 aseprite_file_names: &[],
32 path: Path::new("."),
33 output_image_location: None,
34 output_ron_location: None,
35 trim: false,
36 }
37 }
38}
39
40struct AseFile {
41 path: PathBuf,
42 name: String,
43}
44
45pub struct AsepritePacker {
46 pub image: DynamicImage,
47 pub packed_texture_data: HashMap<String, AseTextureData>,
48}
49
50impl AsepritePacker {
51 pub fn new(config: AsepritePackerConfig) -> Self {
52 let AsepritePackerConfig {
53 aseprite_file_names,
54 path,
55 output_image_location,
56 output_ron_location,
57 trim,
58 } = config;
59
60 let texture_packer_config = TexturePackerConfig {
61 max_width: std::u32::MAX,
62 max_height: std::u32::MAX,
63 allow_rotation: false,
64 texture_outlines: false,
65 border_padding: 0,
66 texture_padding: 0,
67 trim,
68 ..Default::default()
69 };
70
71 let mut packer: TexturePacker<ImageBuffer<Rgba<u8>, Vec<u8>>, String> =
72 TexturePacker::new_skyline(texture_packer_config);
73
74 let mut packed_texture_data: HashMap<String, AseTextureData> = HashMap::default();
75
76 let ase_files: Vec<AseFile> = if !aseprite_file_names.is_empty() {
77 aseprite_file_names
78 .iter()
79 .map(|name| {
80 let resolved_name = format!("{}.aseprite", name);
81 AseFile {
82 path: path.clone().join(resolved_name.to_string()),
83 name: name.to_string(),
84 }
85 })
86 .collect()
87 } else {
88 println!("{}", path.display());
89 let paths = fs::read_dir(path).unwrap();
90 paths
91 .map(|p| {
92 let path_buff = p.unwrap();
93 let name = path_buff
94 .path()
95 .file_stem()
96 .unwrap()
97 .to_str()
98 .unwrap()
99 .to_string();
100 AseFile {
101 path: path_buff.path().as_path().to_owned(),
102 name,
103 }
104 })
105 .collect()
106 };
107
108 for file in ase_files {
109 let ase_file = load_ase(file.path.as_path());
111 match ase_file {
112 Err(e) => panic!("{}", e),
113 Ok(ase) => {
114 for frame_num in 0..ase.num_frames() {
115 ase.width();
116 let key: String = if ase.num_frames() > 1 {
117 format!("{}_{}", file.name.to_string(), frame_num)
118 } else {
119 file.name.to_string()
120 };
121 let _result = packer.pack_own(key.clone(), ase.frame(frame_num).image());
122 match _result {
123 Ok(_) => {}
124 Err(e) => panic!("Error packing file: {:?}", e),
125 }
126 let frame_data = packer.get_frame(&key).expect("Frame not found");
127 let source = frame_data.frame;
128 packed_texture_data.insert(
129 key.clone(),
130 AseTextureData {
131 width: source.w,
132 height: source.h,
133 x: source.x,
134 y: source.y,
135 basename: file.name.to_string(),
136 frame: frame_num,
137 },
138 );
139 }
140 }
141 }
142 }
143
144 let image = ImageExporter::export(&packer).unwrap();
145
146 if let Some(output) = output_image_location {
147 let mut file = std::fs::File::create(output).unwrap();
148 image.write_to(&mut file, image::ImageFormat::Png).unwrap();
149 }
150
151 if let Some(output) = output_ron_location {
152 let mut file = std::fs::File::create(output).unwrap();
153 let str = to_string_pretty(&packed_texture_data, PrettyConfig::default()).unwrap();
154 let _result = file.write_all(str.as_bytes());
155 match _result {
156 Ok(_) => {}
157 Err(e) => panic!("{}", e),
158 }
159 }
160
161 let ase_packer = AsepritePacker {
162 packed_texture_data,
163 image,
164 };
165
166 ase_packer
167 }
168}
169
170fn load_ase(file_path: &Path) -> Result<AsepriteFile, AsepriteParseError> {
171 let f = File::open(file_path).unwrap();
172 AsepriteFile::read(&f)
173}