unity_asset_decode/texture/decoders/
basic.rs1use super::{Decoder, create_rgba_image, validate_dimensions};
6use crate::error::{BinaryError, Result};
7use crate::texture::formats::TextureFormat;
8use crate::texture::types::Texture2D;
9use image::RgbaImage;
10
11pub struct BasicDecoder;
13
14impl BasicDecoder {
15 pub fn new() -> Self {
17 Self
18 }
19
20 fn decode_rgba32(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
22 validate_dimensions(width, height)?;
23
24 let expected_size = (width * height * 4) as usize;
25 if data.len() < expected_size {
26 return Err(BinaryError::invalid_data(format!(
27 "Insufficient data for RGBA32: expected {}, got {}",
28 expected_size,
29 data.len()
30 )));
31 }
32
33 create_rgba_image(data[..expected_size].to_vec(), width, height)
35 }
36
37 fn decode_rgb24(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
39 validate_dimensions(width, height)?;
40
41 let expected_size = (width * height * 3) as usize;
42 if data.len() < expected_size {
43 return Err(BinaryError::invalid_data(format!(
44 "Insufficient data for RGB24: expected {}, got {}",
45 expected_size,
46 data.len()
47 )));
48 }
49
50 let mut rgba_data = Vec::with_capacity((width * height * 4) as usize);
52 for chunk in data[..expected_size].chunks_exact(3) {
53 rgba_data.push(chunk[0]); rgba_data.push(chunk[1]); rgba_data.push(chunk[2]); rgba_data.push(255); }
58
59 create_rgba_image(rgba_data, width, height)
60 }
61
62 fn decode_argb32(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
64 validate_dimensions(width, height)?;
65
66 let expected_size = (width * height * 4) as usize;
67 if data.len() < expected_size {
68 return Err(BinaryError::invalid_data(format!(
69 "Insufficient data for ARGB32: expected {}, got {}",
70 expected_size,
71 data.len()
72 )));
73 }
74
75 let mut rgba_data = Vec::with_capacity(expected_size);
77 for chunk in data[..expected_size].chunks_exact(4) {
78 rgba_data.push(chunk[1]); rgba_data.push(chunk[2]); rgba_data.push(chunk[3]); rgba_data.push(chunk[0]); }
83
84 create_rgba_image(rgba_data, width, height)
85 }
86
87 fn decode_bgra32(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
89 validate_dimensions(width, height)?;
90
91 let expected_size = (width * height * 4) as usize;
92 if data.len() < expected_size {
93 return Err(BinaryError::invalid_data(format!(
94 "Insufficient data for BGRA32: expected {}, got {}",
95 expected_size,
96 data.len()
97 )));
98 }
99
100 let mut rgba_data = Vec::with_capacity(expected_size);
102 for chunk in data[..expected_size].chunks_exact(4) {
103 rgba_data.push(chunk[2]); rgba_data.push(chunk[1]); rgba_data.push(chunk[0]); rgba_data.push(chunk[3]); }
108
109 create_rgba_image(rgba_data, width, height)
110 }
111
112 fn decode_alpha8(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
114 validate_dimensions(width, height)?;
115
116 let expected_size = (width * height) as usize;
117 if data.len() < expected_size {
118 return Err(BinaryError::invalid_data(format!(
119 "Insufficient data for Alpha8: expected {}, got {}",
120 expected_size,
121 data.len()
122 )));
123 }
124
125 let mut rgba_data = Vec::with_capacity((width * height * 4) as usize);
127 for &alpha in &data[..expected_size] {
128 rgba_data.push(255); rgba_data.push(255); rgba_data.push(255); rgba_data.push(alpha); }
133
134 create_rgba_image(rgba_data, width, height)
135 }
136
137 fn decode_rgba4444(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
139 validate_dimensions(width, height)?;
140
141 let expected_size = (width * height * 2) as usize; if data.len() < expected_size {
143 return Err(BinaryError::invalid_data(format!(
144 "Insufficient data for RGBA4444: expected {}, got {}",
145 expected_size,
146 data.len()
147 )));
148 }
149
150 let mut rgba_data = Vec::with_capacity((width * height * 4) as usize);
152 for chunk in data[..expected_size].chunks_exact(2) {
153 let pixel = u16::from_le_bytes([chunk[0], chunk[1]]);
154
155 let r = ((pixel >> 12) & 0xF) as u8;
157 let g = ((pixel >> 8) & 0xF) as u8;
158 let b = ((pixel >> 4) & 0xF) as u8;
159 let a = (pixel & 0xF) as u8;
160
161 rgba_data.push(r << 4 | r);
163 rgba_data.push(g << 4 | g);
164 rgba_data.push(b << 4 | b);
165 rgba_data.push(a << 4 | a);
166 }
167
168 create_rgba_image(rgba_data, width, height)
169 }
170
171 fn decode_argb4444(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
173 validate_dimensions(width, height)?;
174
175 let expected_size = (width * height * 2) as usize; if data.len() < expected_size {
177 return Err(BinaryError::invalid_data(format!(
178 "Insufficient data for ARGB4444: expected {}, got {}",
179 expected_size,
180 data.len()
181 )));
182 }
183
184 let mut rgba_data = Vec::with_capacity((width * height * 4) as usize);
186 for chunk in data[..expected_size].chunks_exact(2) {
187 let pixel = u16::from_le_bytes([chunk[0], chunk[1]]);
188
189 let a = ((pixel >> 12) & 0xF) as u8;
191 let r = ((pixel >> 8) & 0xF) as u8;
192 let g = ((pixel >> 4) & 0xF) as u8;
193 let b = (pixel & 0xF) as u8;
194
195 rgba_data.push(r << 4 | r); rgba_data.push(g << 4 | g); rgba_data.push(b << 4 | b); rgba_data.push(a << 4 | a); }
201
202 create_rgba_image(rgba_data, width, height)
203 }
204
205 fn decode_rgb565(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
207 validate_dimensions(width, height)?;
208
209 let expected_size = (width * height * 2) as usize; if data.len() < expected_size {
211 return Err(BinaryError::invalid_data(format!(
212 "Insufficient data for RGB565: expected {}, got {}",
213 expected_size,
214 data.len()
215 )));
216 }
217
218 let mut rgba_data = Vec::with_capacity((width * height * 4) as usize);
220 for chunk in data[..expected_size].chunks_exact(2) {
221 let pixel = u16::from_le_bytes([chunk[0], chunk[1]]);
222
223 let r = ((pixel >> 11) & 0x1F) as u8;
225 let g = ((pixel >> 5) & 0x3F) as u8;
226 let b = (pixel & 0x1F) as u8;
227
228 rgba_data.push((r << 3) | (r >> 2)); rgba_data.push((g << 2) | (g >> 4)); rgba_data.push((b << 3) | (b >> 2)); rgba_data.push(255); }
234
235 create_rgba_image(rgba_data, width, height)
236 }
237}
238
239impl Decoder for BasicDecoder {
240 fn decode(&self, texture: &Texture2D) -> Result<RgbaImage> {
241 let width = texture.width as u32;
242 let height = texture.height as u32;
243 let data = &texture.image_data;
244
245 match texture.format {
246 TextureFormat::RGBA32 => self.decode_rgba32(data, width, height),
247 TextureFormat::RGB24 => self.decode_rgb24(data, width, height),
248 TextureFormat::ARGB32 => self.decode_argb32(data, width, height),
249 TextureFormat::BGRA32 => self.decode_bgra32(data, width, height),
250 TextureFormat::Alpha8 => self.decode_alpha8(data, width, height),
251 TextureFormat::RGBA4444 => self.decode_rgba4444(data, width, height),
252 TextureFormat::ARGB4444 => self.decode_argb4444(data, width, height),
253 TextureFormat::RGB565 => self.decode_rgb565(data, width, height),
254 _ => Err(BinaryError::unsupported(format!(
255 "Format {:?} is not a basic format",
256 texture.format
257 ))),
258 }
259 }
260
261 fn can_decode(&self, format: TextureFormat) -> bool {
262 format.is_basic_format()
263 }
264
265 fn supported_formats(&self) -> Vec<TextureFormat> {
266 vec![
267 TextureFormat::Alpha8,
268 TextureFormat::RGB24,
269 TextureFormat::RGBA32,
270 TextureFormat::ARGB32,
271 TextureFormat::BGRA32,
272 TextureFormat::RGBA4444,
273 TextureFormat::ARGB4444,
274 TextureFormat::RGB565,
275 ]
276 }
277}
278
279impl Default for BasicDecoder {
280 fn default() -> Self {
281 Self::new()
282 }
283}