1use std::ops::{Index, IndexMut};
28
29use log::debug;
30
31use crate::color::{Color, ColorSpace};
32use crate::error::Error;
33use crate::geometry::{self, get_index_from_point_and_shape, Point, Shape};
34use crate::traits::*;
35use crate::types::*;
36
37#[derive(Debug, Clone)]
38pub struct Image {
39 shape: Shape,
40 data: Vec<u8>,
41 colorspace: ColorSpace,
42}
43
44impl Image {
45 pub fn new(shape: Shape, colorspace: ColorSpace) -> Self {
46 let data = vec![0; shape.size()];
47 assert_eq!(data.len(), shape.size());
48 debug!("Creating Image of size {}", data.len());
49 dbg!(data.len());
50 Image {
51 shape,
52 data,
53 colorspace,
54 }
55 }
56
57 pub fn from_data(data: Vec<u8>, shape: Shape, colorspace: ColorSpace) -> Self {
58 assert_eq!(data.len(), shape.size());
59 Image {
60 shape,
61 data,
62 colorspace,
63 }
64 }
65
66 pub fn swap(&mut self, idx_a: usize, idx_b: usize) {
67 self.data.swap(idx_a, idx_b);
68 }
69
70 pub fn slice(&self, start: usize, end: usize) -> &[u8] {
71 &self.data[start..end]
72 }
73
74 pub fn mut_slice(&mut self, start: usize, end: usize) -> &mut [u8] {
75 &mut self.data[start..end]
76 }
77
78 pub fn width(&self) -> usize {
79 self.shape.width
80 }
81
82 pub fn height(&self) -> usize {
83 self.shape.height
84 }
85
86 pub fn size(&self) -> usize {
87 self.shape.size()
88 }
89
90 pub fn crop(&self, topleft: Point, shape: Shape) -> Self {
91 let bottomright = topleft + shape;
92
93 let mut data = Vec::new();
94 for hindex in topleft.x..bottomright.x {
95 for vindex in topleft.y..bottomright.y {
96 for cindex in 0..self.shape.ndim {
97 data.push(self[(hindex, vindex, cindex)]);
98 }
99 }
100 }
101
102 dbg!(data.len());
103
104 let image_shape = Shape::new(shape.width, shape.height, Some(self.colorspace.channels()));
105 Self::from_data(data, image_shape, self.colorspace)
106 }
107
108 pub fn get_index(&self, point: &Point) -> Result<usize, Error> {
121 self.get_index_from_xy(point.x, point.y)
122 }
123
124 pub fn get_index_from_xy(&self, x: usize, y: usize) -> Result<usize, Error> {
138 geometry::get_index_from_xywh(
139 x,
140 y,
141 self.width(),
142 self.height(),
143 self.colorspace.channels(),
144 )
145 }
146
147 pub fn get_pixel(&self, point: &Point) -> &[u8] {
160 let channels = self.colorspace.channels();
161 let index = self.get_index(point).unwrap();
162 &self.data[index..index + channels]
163 }
164
165 pub fn get_mut_pixel(&mut self, point: &Point) -> &mut [u8] {
167 let channels = self.colorspace.channels();
168 let index = self.get_index(point).unwrap();
169 &mut self.data[index..index + channels]
170 }
171
172 pub fn set_pixel(&mut self, point: &Point, color: &Color) -> Result<(), Error> {
173 let channels = self.colorspace.channels();
174 let pixel = self.get_mut_pixel(point);
175 for i in 0..channels {
176 pixel[i] = color[i];
177 }
178 Ok(())
179 }
180}
181
182impl Index<usize> for Image {
189 type Output = u8;
190
191 fn index(&self, index: usize) -> &Self::Output {
192 &self.data[index]
193 }
194}
195
196impl IndexMut<usize> for Image {
203 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
204 &mut self.data[index]
205 }
206}
207
208impl Index<Index2D> for Image {
215 type Output = [u8];
216
217 fn index(&self, (x, y): Index2D) -> &Self::Output {
218 let point = Point::new(x, y);
219 self.get_pixel(&point)
220 }
221}
222
223impl IndexMut<Index2D> for Image {
224 fn index_mut(&mut self, (x, y): Index2D) -> &mut Self::Output {
225 let point = Point::new(x, y);
226 self.get_mut_pixel(&point)
227 }
228}
229
230impl Index<Index3D> for Image {
240 type Output = u8;
241
242 fn index(&self, (x, y, c): Index3D) -> &Self::Output {
243 let point = Point::new(x, y);
244 let pixel = self.get_pixel(&point);
245 &pixel[c]
246 }
247}
248
249impl IndexMut<Index3D> for Image {
250 fn index_mut(&mut self, (x, y, c): Index3D) -> &mut Self::Output {
251 let point = Point::new(x, y);
252 let pixel = self.get_mut_pixel(&point);
253 &mut pixel[c]
254 }
255}
256
257impl Drawable<RectParams> for Image {
259 fn draw(&mut self, params: &RectParams) -> Result<(), Error> {
263 let border_width = params.border_width.unwrap_or_default();
264
265 match params.fill_color {
266 Some(color) => {
267 let top_left = params.topleft;
268 let bottom_right = params.topleft + params.shape;
269
270 for i in top_left.x..bottom_right.x + 1 {
271 for j in top_left.y..bottom_right.y + 1 {
272 let point = Point::new(i, j);
273 self.set_pixel(&point, &color)?;
274 }
275 }
276 }
277 None => {
278 dbg!("Fill not enabled");
279 }
280 };
281
282 for i in 0..params.shape.width + border_width {
283 let range = match params.border_width {
284 Some(value) => (-((value / 2) as i32), ((value / 2) + 1) as i32),
285 None => (0, 1),
286 };
287
288 dbg!(range);
289 for k in range.0..range.1 {
290 let x_top_left = params.topleft.x;
291 let y_top_left = params.topleft.y;
292
293 let top = Point::new(
295 x_top_left + i - (border_width / 2),
296 (y_top_left as i32 + k) as usize,
297 );
298 dbg!(top);
299 self.set_pixel(&top, ¶ms.color)?;
300
301 let left = Point::new(
303 (x_top_left as i32 + k) as usize,
304 y_top_left + i - (border_width / 2),
305 );
306 dbg!(left);
307 self.set_pixel(&left, ¶ms.color)?;
308
309 let right = Point::new(
311 ((x_top_left + params.shape.width) as i32 - k) as usize,
312 y_top_left + i - (border_width / 2),
313 );
314 dbg!(right);
315 self.set_pixel(&right, ¶ms.color)?;
316
317 let bottom = Point::new(
319 x_top_left + i - (border_width / 2),
320 ((y_top_left + params.shape.height) as i32 - k) as usize,
321 );
322 dbg!(bottom);
323 self.set_pixel(&bottom, ¶ms.color)?;
324 }
325 }
326
327 Ok(())
328 }
329}
330
331impl Drawable<CircleParams> for Image {
332 fn draw(&mut self, params: &CircleParams) -> Result<(), Error> {
336 println!("Drawing circle {params:?}");
337
338 let mut x = params.radius;
339 let mut y = 0;
340
341 let mut p: f32 = 1.0 - params.radius as f32;
342
343 while x >= y {
344 dbg!(x, y, p);
345
346 let symmetric = [
347 [
348 Point::new(params.center.x - x, params.center.y + y),
349 Point::new(params.center.x + x, params.center.y + y),
350 ],
351 [
352 Point::new(params.center.x - x, params.center.y - y),
353 Point::new(params.center.x + x, params.center.y - y),
354 ],
355 [
356 Point::new(params.center.x - y, params.center.y + x),
357 Point::new(params.center.x + y, params.center.y + x),
358 ],
359 [
360 Point::new(params.center.x - y, params.center.y - x),
361 Point::new(params.center.x + y, params.center.y - x),
362 ],
363 ];
364
365 for pair in symmetric {
366 if let Some(color) = params.fill_color {
367 let mut start = pair[0].clone();
368 let end = pair[1].clone();
369 while start.x < end.x - 1 {
370 start.x += 1;
371 dbg!(start);
372 self.set_pixel(&start, &color)?;
373 }
374 }
375
376 self.set_pixel(&pair[0], ¶ms.color)?;
377 self.set_pixel(&pair[1], ¶ms.color)?;
378 }
379
380 y += 1;
381
382 if p <= 0.0 {
383 p = p + 2.0 * y as f32 + 1.0;
384 } else {
385 x -= 1;
386 p = p + 2.0 * y as f32 - 2.0 * x as f32 + 1.0;
387 }
388 }
389
390 Ok(())
391 }
392}
393impl Resizable<NearestNeighborParams> for Image {
397 fn resize(&mut self, shape: Shape) -> Result<(), Error> {
398 todo!()
399 }
400}
401
402impl Resizable<BiCubicParams> for Image {
403 fn resize(&mut self, shape: Shape) -> Result<(), Error> {
404 todo!()
405 }
406}
407
408impl Resizable<BiLinearParams> for Image {
409 fn resize(&mut self, shape: Shape) -> Result<(), Error> {
410 todo!()
411 }
412}
413impl Rotatable<i32> for Image {
418 fn rotate(&mut self, value: i32) -> Result<(), Error> {
419 todo!()
421 }
422}
423
424impl Rotatable<RotationType> for Image {
425 fn rotate(&mut self, value: RotationType) -> Result<(), Error> {
429 let new_shape = match value {
430 RotationType::Clockwise90
431 | RotationType::Anticlockwise270
432 | RotationType::Clockwise270
433 | RotationType::Anticlockwise90 => Shape {
434 width: self.height(),
435 height: self.width(),
436 ndim: self.shape.ndim,
437 },
438 RotationType::Clockwise180 | RotationType::Anticlockwise180 => self.shape,
439 RotationType::Custom(_) => todo!(),
440 };
441
442 if new_shape == self.shape {
443 for x in 0..self.width() / 2 {
444 for y in 0..self.height() {
445 let p1 = Point::new(x, y);
446 let p2 = p1.relocate(&self.shape, value.degree());
447
448 let idx_a = self.get_index(&p1).unwrap();
449 let idx_b = get_index_from_point_and_shape(p2, &new_shape).unwrap();
450
451 for c in 0..self.colorspace.channels() {
452 self.swap(idx_a + c, idx_b + c);
453 }
454 }
455 }
456 } else {
457 let mut rotated = vec![0; self.size()];
459 let ndim = self.shape.ndim;
460 for x in 0..self.width() {
461 for y in 0..self.height() {
462 let p1 = Point::new(x, y);
463 let p2 = p1.relocate(&self.shape, value.degree());
464
465 let idx_a = self.get_index(&p1).unwrap();
466 let idx_b = get_index_from_point_and_shape(p2, &new_shape).unwrap();
467
468 rotated[idx_b..ndim + idx_b].copy_from_slice(&self.data[idx_a..ndim + idx_a]);
469 }
470 }
471
472 self.data = rotated;
473 self.shape = new_shape;
474 }
475
476 Ok(())
477 }
478}
479