1use crate::error::{Error, Result};
11
12#[derive(Debug, Clone)]
19pub struct Channel {
20 data: Vec<i32>,
22 width: usize,
24 height: usize,
26 pub hshift: u32,
28 pub vshift: u32,
30}
31
32impl Channel {
33 pub fn new(width: usize, height: usize) -> Result<Self> {
35 if width == 0 || height == 0 {
36 return Err(Error::InvalidImageDimensions(width, height));
37 }
38
39 let size = width
40 .checked_mul(height)
41 .ok_or(Error::InvalidImageDimensions(width, height))?;
42
43 let mut data = Vec::new();
44 data.try_reserve_exact(size)?;
45 data.resize(size, 0);
46
47 Ok(Self {
48 data,
49 width,
50 height,
51 hshift: 0,
52 vshift: 0,
53 })
54 }
55
56 pub fn from_vec(data: Vec<i32>, width: usize, height: usize) -> Result<Self> {
58 if width == 0 || height == 0 {
59 return Err(Error::InvalidImageDimensions(width, height));
60 }
61 if data.len() != width * height {
62 return Err(Error::InvalidImageDimensions(width, height));
63 }
64 Ok(Self {
65 data,
66 width,
67 height,
68 hshift: 0,
69 vshift: 0,
70 })
71 }
72
73 #[inline]
75 pub fn width(&self) -> usize {
76 self.width
77 }
78
79 #[inline]
81 pub fn height(&self) -> usize {
82 self.height
83 }
84
85 #[inline]
87 pub fn len(&self) -> usize {
88 self.data.len()
89 }
90
91 #[inline]
93 pub fn is_empty(&self) -> bool {
94 self.data.is_empty()
95 }
96
97 #[inline]
99 pub fn get(&self, x: usize, y: usize) -> i32 {
100 debug_assert!(x < self.width && y < self.height);
101 self.data[y * self.width + x]
102 }
103
104 #[inline]
106 pub fn set(&mut self, x: usize, y: usize, value: i32) {
107 debug_assert!(x < self.width && y < self.height);
108 self.data[y * self.width + x] = value;
109 }
110
111 #[inline]
113 pub fn row(&self, y: usize) -> &[i32] {
114 debug_assert!(y < self.height);
115 let start = y * self.width;
116 &self.data[start..start + self.width]
117 }
118
119 #[inline]
121 pub fn row_mut(&mut self, y: usize) -> &mut [i32] {
122 debug_assert!(y < self.height);
123 let start = y * self.width;
124 &mut self.data[start..start + self.width]
125 }
126
127 #[inline]
129 pub fn data(&self) -> &[i32] {
130 &self.data
131 }
132
133 #[inline]
135 pub fn data_mut(&mut self) -> &mut [i32] {
136 &mut self.data
137 }
138
139 #[inline]
141 pub fn get_clamped(&self, x: isize, y: isize) -> i32 {
142 if x < 0 || y < 0 || x >= self.width as isize || y >= self.height as isize {
143 0
144 } else {
145 self.data[y as usize * self.width + x as usize]
146 }
147 }
148
149 #[inline]
151 pub fn get_clamped_to_edge(&self, x: isize, y: isize) -> i32 {
152 let x = x.clamp(0, self.width as isize - 1) as usize;
153 let y = y.clamp(0, self.height as isize - 1) as usize;
154 self.data[y * self.width + x]
155 }
156}
157
158#[derive(Debug, Clone)]
163pub struct ModularImage {
164 pub channels: Vec<Channel>,
166 pub bit_depth: u32,
168 pub is_grayscale: bool,
170 pub has_alpha: bool,
172}
173
174impl ModularImage {
175 pub fn from_rgb8(data: &[u8], width: usize, height: usize) -> Result<Self> {
177 if data.len() != width * height * 3 {
178 return Err(Error::InvalidImageDimensions(width, height));
179 }
180
181 let mut channels = Vec::with_capacity(3);
182 for c in 0..3 {
183 let mut channel = Channel::new(width, height)?;
184 for y in 0..height {
185 for x in 0..width {
186 let idx = (y * width + x) * 3 + c;
187 channel.set(x, y, data[idx] as i32);
188 }
189 }
190 channels.push(channel);
191 }
192
193 Ok(Self {
194 channels,
195 bit_depth: 8,
196 is_grayscale: false,
197 has_alpha: false,
198 })
199 }
200
201 pub fn from_rgba8(data: &[u8], width: usize, height: usize) -> Result<Self> {
203 if data.len() != width * height * 4 {
204 return Err(Error::InvalidImageDimensions(width, height));
205 }
206
207 let mut channels = Vec::with_capacity(4);
208 for c in 0..4 {
209 let mut channel = Channel::new(width, height)?;
210 for y in 0..height {
211 for x in 0..width {
212 let idx = (y * width + x) * 4 + c;
213 channel.set(x, y, data[idx] as i32);
214 }
215 }
216 channels.push(channel);
217 }
218
219 Ok(Self {
220 channels,
221 bit_depth: 8,
222 is_grayscale: false,
223 has_alpha: true,
224 })
225 }
226
227 pub fn from_gray8(data: &[u8], width: usize, height: usize) -> Result<Self> {
229 if data.len() != width * height {
230 return Err(Error::InvalidImageDimensions(width, height));
231 }
232
233 let mut channel = Channel::new(width, height)?;
234 for (i, &val) in data.iter().enumerate() {
235 let x = i % width;
236 let y = i / width;
237 channel.set(x, y, val as i32);
238 }
239
240 Ok(Self {
241 channels: vec![channel],
242 bit_depth: 8,
243 is_grayscale: true,
244 has_alpha: false,
245 })
246 }
247
248 pub fn from_rgb16(data: &[u8], width: usize, height: usize) -> Result<Self> {
250 if data.len() != width * height * 6 {
251 return Err(Error::InvalidImageDimensions(width, height));
252 }
253
254 let mut channels = Vec::with_capacity(3);
255 for c in 0..3 {
256 let mut channel = Channel::new(width, height)?;
257 for y in 0..height {
258 for x in 0..width {
259 let idx = (y * width + x) * 6 + c * 2;
260 let val = u16::from_be_bytes([data[idx], data[idx + 1]]);
261 channel.set(x, y, val as i32);
262 }
263 }
264 channels.push(channel);
265 }
266
267 Ok(Self {
268 channels,
269 bit_depth: 16,
270 is_grayscale: false,
271 has_alpha: false,
272 })
273 }
274
275 pub fn from_rgb16_native(data: &[u8], width: usize, height: usize) -> Result<Self> {
280 if data.len() != width * height * 6 {
281 return Err(Error::InvalidImageDimensions(width, height));
282 }
283 let pixels: &[u16] = bytemuck::cast_slice(data);
284 let mut channels = Vec::with_capacity(3);
285 for c in 0..3 {
286 let mut channel = Channel::new(width, height)?;
287 for y in 0..height {
288 for x in 0..width {
289 let idx = (y * width + x) * 3 + c;
290 channel.set(x, y, pixels[idx] as i32);
291 }
292 }
293 channels.push(channel);
294 }
295 Ok(Self {
296 channels,
297 bit_depth: 16,
298 is_grayscale: false,
299 has_alpha: false,
300 })
301 }
302
303 pub fn from_rgba16_native(data: &[u8], width: usize, height: usize) -> Result<Self> {
307 if data.len() != width * height * 8 {
308 return Err(Error::InvalidImageDimensions(width, height));
309 }
310 let pixels: &[u16] = bytemuck::cast_slice(data);
311 let mut channels = Vec::with_capacity(4);
312 for c in 0..4 {
313 let mut channel = Channel::new(width, height)?;
314 for y in 0..height {
315 for x in 0..width {
316 let idx = (y * width + x) * 4 + c;
317 channel.set(x, y, pixels[idx] as i32);
318 }
319 }
320 channels.push(channel);
321 }
322 Ok(Self {
323 channels,
324 bit_depth: 16,
325 is_grayscale: false,
326 has_alpha: true,
327 })
328 }
329
330 pub fn from_gray16_native(data: &[u8], width: usize, height: usize) -> Result<Self> {
334 if data.len() != width * height * 2 {
335 return Err(Error::InvalidImageDimensions(width, height));
336 }
337 let pixels: &[u16] = bytemuck::cast_slice(data);
338 let mut channel = Channel::new(width, height)?;
339 for (i, &val) in pixels.iter().enumerate() {
340 let x = i % width;
341 let y = i / width;
342 channel.set(x, y, val as i32);
343 }
344 Ok(Self {
345 channels: vec![channel],
346 bit_depth: 16,
347 is_grayscale: true,
348 has_alpha: false,
349 })
350 }
351
352 pub fn width(&self) -> usize {
354 self.channels.first().map_or(0, |c| c.width())
355 }
356
357 pub fn height(&self) -> usize {
359 self.channels.first().map_or(0, |c| c.height())
360 }
361
362 pub fn num_channels(&self) -> usize {
364 self.channels.len()
365 }
366
367 pub fn channel(&self, idx: usize) -> &Channel {
369 &self.channels[idx]
370 }
371
372 pub fn channel_mut(&mut self, idx: usize) -> &mut Channel {
374 &mut self.channels[idx]
375 }
376
377 pub fn extract_region(
382 &self,
383 x_start: usize,
384 y_start: usize,
385 x_end: usize,
386 y_end: usize,
387 ) -> Result<Self> {
388 let region_width = x_end.saturating_sub(x_start);
389 let region_height = y_end.saturating_sub(y_start);
390
391 if region_width == 0 || region_height == 0 {
392 return Err(Error::InvalidImageDimensions(region_width, region_height));
393 }
394
395 let mut channels = Vec::with_capacity(self.channels.len());
396 for src_channel in &self.channels {
397 let mut dst_channel = Channel::new(region_width, region_height)?;
398
399 for dy in 0..region_height {
400 let sy = y_start + dy;
401 if sy >= src_channel.height() {
402 continue;
403 }
404
405 for dx in 0..region_width {
406 let sx = x_start + dx;
407 if sx >= src_channel.width() {
408 continue;
409 }
410
411 dst_channel.set(dx, dy, src_channel.get(sx, sy));
412 }
413 }
414
415 channels.push(dst_channel);
416 }
417
418 Ok(Self {
419 channels,
420 bit_depth: self.bit_depth,
421 is_grayscale: self.is_grayscale,
422 has_alpha: self.has_alpha,
423 })
424 }
425}
426
427#[cfg(test)]
428mod tests {
429 use super::*;
430
431 #[test]
432 fn test_channel_creation() {
433 let channel = Channel::new(100, 100).unwrap();
434 assert_eq!(channel.width(), 100);
435 assert_eq!(channel.height(), 100);
436 assert_eq!(channel.len(), 10000);
437 }
438
439 #[test]
440 fn test_channel_access() {
441 let mut channel = Channel::new(10, 10).unwrap();
442 channel.set(5, 5, 42);
443 assert_eq!(channel.get(5, 5), 42);
444 }
445
446 #[test]
447 fn test_channel_clamped() {
448 let mut channel = Channel::new(10, 10).unwrap();
449 channel.set(0, 0, 100);
450 assert_eq!(channel.get_clamped(-1, -1), 0);
451 assert_eq!(channel.get_clamped(0, 0), 100);
452 assert_eq!(channel.get_clamped(100, 100), 0);
453 }
454
455 #[test]
456 fn test_modular_image_rgb8() {
457 let data = vec![
458 255, 0, 0, 0, 255, 0, 0, 0, 255, 255, 255, 0, ];
463 let img = ModularImage::from_rgb8(&data, 2, 2).unwrap();
464
465 assert_eq!(img.num_channels(), 3);
466 assert_eq!(img.width(), 2);
467 assert_eq!(img.height(), 2);
468
469 assert_eq!(img.channel(0).get(0, 0), 255);
471 assert_eq!(img.channel(0).get(1, 0), 0);
472
473 assert_eq!(img.channel(1).get(0, 0), 0);
475 assert_eq!(img.channel(1).get(1, 0), 255);
476
477 assert_eq!(img.channel(2).get(0, 0), 0);
479 assert_eq!(img.channel(2).get(0, 1), 255);
480 }
481}