1use crate::error::Result;
10use crate::format::IffImage;
11use crate::texture::TextureSynthesizer;
12use crate::warp::BicubicSampler;
13use crate::wavelet::Cdf53Transform;
14use crate::color::{ycocg_to_rgb, upsample_420, YCoCgImage, Channel};
15use serde::{Deserialize, Serialize};
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct DecoderConfig {
20 pub enable_layer2: bool,
22 pub enable_layer3: bool,
24 pub enable_residual: bool,
26}
27
28impl Default for DecoderConfig {
29 fn default() -> Self {
30 DecoderConfig {
31 enable_layer2: true,
32 enable_layer3: true,
33 enable_residual: true,
34 }
35 }
36}
37
38pub struct Decoder {
40 config: DecoderConfig,
41}
42
43impl Decoder {
44 pub fn new(config: DecoderConfig) -> Self {
46 Decoder { config }
47 }
48
49 pub fn decode(&self, iff_image: &IffImage) -> Result<Vec<[u8; 3]>> {
51 let width = iff_image.header.width as usize;
52 let height = iff_image.header.height as usize;
53
54 let transform = Cdf53Transform::new(iff_image.header.wavelet_levels as usize);
56
57 let mut image = if iff_image.header.flags.ycocg_420 {
58 let y_coeffs = iff_image.layer1.y.to_dense()?;
60 let y_data = transform.inverse(&y_coeffs[0], width, height)?;
61
62 let co_width = iff_image.layer1.co.width as usize;
64 let co_height = iff_image.layer1.co.height as usize;
65 let co_coeffs = iff_image.layer1.co.to_dense()?;
66 let co_data = transform.inverse(&co_coeffs[0], co_width, co_height)?;
67
68 let cg_width = iff_image.layer1.cg.width as usize;
70 let cg_height = iff_image.layer1.cg.height as usize;
71 let cg_coeffs = iff_image.layer1.cg.to_dense()?;
72 let cg_data = transform.inverse(&cg_coeffs[0], cg_width, cg_height)?;
73
74 let co_channel = Channel { width: co_width, height: co_height, data: co_data };
76 let cg_channel = Channel { width: cg_width, height: cg_height, data: cg_data };
77
78 let co_up = upsample_420(&co_channel, width, height);
79 let cg_up = upsample_420(&cg_channel, width, height);
80
81 let ycocg = YCoCgImage {
83 width,
84 height,
85 y: Channel { width, height, data: y_data },
86 co: co_up,
87 cg: cg_up,
88 };
89
90 ycocg_to_rgb(&ycocg)?
91 } else {
92 let r_coeffs = iff_image.layer1.y.to_dense()?;
95 let g_coeffs = iff_image.layer1.co.to_dense()?;
96 let b_coeffs = iff_image.layer1.cg.to_dense()?;
97
98 let r_data = transform.inverse(&r_coeffs[0], width, height)?;
99 let g_data = transform.inverse(&g_coeffs[0], width, height)?;
100 let b_data = transform.inverse(&b_coeffs[0], width, height)?;
101
102 let mut pixels = Vec::with_capacity(width * height);
103 for i in 0..(width * height) {
104 pixels.push([
105 (r_data[i] + 128).clamp(0, 255) as u8,
106 (g_data[i] + 128).clamp(0, 255) as u8,
107 (b_data[i] + 128).clamp(0, 255) as u8,
108 ]);
109 }
110 pixels
111 };
112
113 if self.config.enable_layer2 && !iff_image.layer2.regions.is_empty() {
115 let synthesizer = TextureSynthesizer::new();
116 for region in &iff_image.layer2.regions {
117 for y in 0..region.h {
119 for x in 0..region.w {
120 let global_x = region.x + x;
121 let global_y = region.y + y;
122 let idx = (global_y as usize) * width + (global_x as usize);
123
124 if idx < image.len() {
125 let color = synthesizer.synthesize_region_pixel(region, x, y);
126 image[idx] = color;
127 }
128 }
129 }
130 }
131 }
132
133 if self.config.enable_layer3 && !iff_image.layer3.vortices.is_empty() {
135 let mut warped = image.clone();
137
138 for y in 0..height {
139 for x in 0..width {
140 let (src_x, src_y) = iff_image.layer3.warp_backwards(x as u16, y as u16);
141
142 let color = BicubicSampler::sample(&image, width, height, src_x, src_y);
144
145 let idx = y * width + x;
146 warped[idx] = color;
147 }
148 }
149
150 image = warped;
151 }
152
153 if self.config.enable_residual && !iff_image.residual.data.is_empty() {
155 let residual_pixels = iff_image.residual.to_dense()?;
156
157 if residual_pixels.len() != image.len() {
158 log::warn!("Residual size mismatch: expected {}, got {}", image.len(), residual_pixels.len());
159 }
160
161 for (i, rgb) in residual_pixels.iter().enumerate() {
162 if i < image.len() {
163 for c in 0..3 {
164 let corrected = (image[i][c] as i32 + rgb[c] as i32).clamp(0, 255);
165 image[i][c] = corrected as u8;
166 }
167 }
168 }
169 }
170
171 Ok(image)
172 }
173
174 #[cfg(feature = "decoder")]
176 pub fn decode_to_image(&self, iff_image: &IffImage) -> Result<image::DynamicImage> {
177 let buffer = self.decode(iff_image)?;
178 let width = iff_image.header.width;
179 let height = iff_image.header.height;
180
181 let mut img_buffer = image::RgbImage::new(width, height);
183
184 for (i, pixel) in buffer.iter().enumerate() {
185 let x = (i % width as usize) as u32;
186 let y = (i / width as usize) as u32;
187 img_buffer.put_pixel(x, y, image::Rgb(*pixel));
188 }
189
190 Ok(image::DynamicImage::ImageRgb8(img_buffer))
191 }
192}
193
194impl Default for Decoder {
196 fn default() -> Self {
197 Decoder::new(DecoderConfig::default())
198 }
199}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204
205 #[test]
206 fn test_decoder_config_default() {
207 let config = DecoderConfig::default();
208 assert!(config.enable_layer2);
209 assert!(config.enable_layer3);
210 assert!(config.enable_residual);
211 }
212
213 #[test]
214 fn test_decoder_creation() {
215 let config = DecoderConfig::default();
216 let decoder = Decoder::new(config);
217 assert!(decoder.config.enable_layer2);
218 }
219
220 #[test]
221 fn test_decode_empty_image() {
222 let decoder = Decoder::default();
223 let iff_image = IffImage::new(64, 64, 3);
224
225 let result = decoder.decode(&iff_image);
226 assert!(result.is_ok());
227
228 let buffer = result.unwrap();
229 assert_eq!(buffer.len(), 64 * 64);
230 }
231}