1use std::iter::Iterator;
5use std::marker::PhantomData;
6use std::ops::Deref;
7use std::slice::ChunksExact;
8
9use num::{FromPrimitive, ToPrimitive};
10
11use crate::error::PineappleError;
12use crate::im::{MaskingStyle, PineappleMaskView, PineappleViewBuffer};
13
14#[derive(Debug, Clone)]
50pub struct PineappleBuffer<T, Container> {
51 w: u32, h: u32, c: u32, pub buffer: Container, _phantom: PhantomData<T>, }
57
58impl<T, Container> PineappleBuffer<T, Container>
59where
60 T: ToPrimitive + FromPrimitive,
61 Container: Deref<Target = [T]>,
62{
63 pub fn new(
80 width: u32,
81 height: u32,
82 channels: u32,
83 buffer: Container,
84 ) -> Result<PineappleBuffer<T, Container>, PineappleError> {
85 if width * height * channels == buffer.len() as u32 {
86 Ok(PineappleBuffer {
87 w: width,
88 h: height,
89 c: channels,
90 buffer,
91 _phantom: PhantomData,
92 })
93 } else {
94 Err(PineappleError::BufferSizeError)
95 }
96 }
97}
98
99impl<T, Container> PineappleBuffer<T, Container>
102where
103 T: ToPrimitive + FromPrimitive,
104 Container: Deref<Target = [T]>,
105{
106 pub fn width(&self) -> u32 {
108 self.w
109 }
110
111 pub fn height(&self) -> u32 {
113 self.h
114 }
115
116 pub fn channels(&self) -> u32 {
118 self.c
119 }
120
121 pub fn shape(&self) -> (u32, u32, u32) {
123 (self.h, self.w, self.c)
124 }
125
126 pub fn len(&self) -> usize {
128 (self.w * self.h * self.c) as usize
129 }
130
131 pub fn is_empty(&self) -> bool {
133 self.len() == 0
134 }
135}
136
137impl<T, Container> PineappleBuffer<T, Container>
142where
143 T: ToPrimitive + FromPrimitive,
144 Container: Deref<Target = [T]>,
145{
146 pub fn into_raw(self) -> Container {
148 self.buffer
149 }
150
151 pub fn as_raw(&self) -> &Container {
153 &self.buffer
154 }
155
156 pub fn to_u8(&self) -> Vec<u8> {
158 self.buffer
159 .iter()
160 .map(|x| x.to_u8().unwrap_or(0u8))
161 .collect()
162 }
163
164 pub fn to_u16(&self) -> Vec<u16> {
166 self.buffer
167 .iter()
168 .map(|x| x.to_u16().unwrap_or(0u16))
169 .collect()
170 }
171
172 pub fn to_u32(&self) -> Vec<u32> {
174 self.buffer
175 .iter()
176 .map(|x| x.to_u32().unwrap_or(0u32))
177 .collect()
178 }
179
180 pub fn to_f32(&self) -> Vec<f32> {
182 self.buffer
183 .iter()
184 .map(|x| x.to_f32().unwrap_or(0f32))
185 .collect()
186 }
187
188 pub fn to_f64(&self) -> Vec<f64> {
190 self.buffer
191 .iter()
192 .map(|x| x.to_f64().unwrap_or(0f64))
193 .collect()
194 }
195
196 pub fn iter(&self) -> impl Iterator<Item = &T> {
198 self.buffer.iter()
199 }
200
201 pub fn iter_channel(&self, channel: u32) -> Result<impl Iterator<Item = &T>, PineappleError>
203 where
204 Container: Deref<Target = [T]>,
205 {
206 if channel >= self.channels() {
207 return Err(PineappleError::ChannelBoundsError);
208 }
209
210 Ok(self
211 .iter()
212 .skip(channel as usize)
213 .step_by(self.channels() as usize))
214 }
215
216 pub fn iter_pixels(&self) -> ChunksExact<'_, T> {
218 self.buffer.chunks_exact(self.channels() as usize)
219 }
220}
221
222impl<T, Container> PineappleBuffer<T, Container>
227where
228 Container: Deref<Target = [T]> + FromIterator<T>,
229 T: Clone + ToPrimitive + FromPrimitive,
230{
231 pub fn crop_view(&self, x: u32, y: u32, w: u32, h: u32) -> PineappleViewBuffer<'_, T, Container> {
240 PineappleViewBuffer::new(x, y, w, h, self)
241 }
242
243 pub fn crop(
252 &self,
253 x: u32,
254 y: u32,
255 w: u32,
256 h: u32,
257 ) -> Result<PineappleBuffer<T, Container>, PineappleError> {
258 if x + w > self.w || y + h > self.h {
259 return Err(PineappleError::ImageError("Cropping coordinates out of bounds"));
260 }
261
262 let c = self.c as usize;
263 let orig_w = self.w as usize;
264 let orig_buffer = self.buffer.as_ref();
265
266 let mut new_buffer = Vec::with_capacity((w * h * self.c) as usize);
267
268 for row in y..y + h {
269 let start = ((row as usize) * orig_w + (x as usize)) * c;
270 let end = start + (w as usize) * c;
271 new_buffer.extend_from_slice(&orig_buffer[start..end]);
272 }
273
274 Ok(PineappleBuffer {
275 w,
276 h,
277 c: self.c,
278 buffer: Container::from_iter(new_buffer),
279 _phantom: PhantomData,
280 })
281 }
282
283 pub fn crop_masked(
294 &self,
295 x: u32,
296 y: u32,
297 w: u32,
298 h: u32,
299 mask: &PineappleMaskView,
300 mask_style: MaskingStyle,
301 ) -> Result<PineappleBuffer<T, Container>, PineappleError> {
302 let crop = self.crop_view(x, y, w, h);
303 let mut masked = Vec::with_capacity(crop.len());
304
305 match mask_style {
306 MaskingStyle::Foreground => {
307 for (m, b) in mask.iter().zip(crop.iter_pixels()) {
308 if m == &0u32 {
309 for _ in 0..self.c {
310 masked.push(T::from_u32(0u32).unwrap());
311 }
312 } else {
313 masked.extend_from_slice(b);
314 }
315 }
316 }
317 MaskingStyle::Background => {
318 for (m, b) in mask.iter().zip(crop.iter_pixels()) {
319 if m != &0u32 {
320 for _ in 0..self.c {
321 masked.push(T::from_u32(0u32).unwrap());
322 }
323 } else {
324 masked.extend_from_slice(b);
325 }
326 }
327 }
328 }
329
330 Ok(PineappleBuffer {
331 w,
332 h,
333 c: self.c,
334 buffer: Container::from_iter(masked),
335 _phantom: PhantomData,
336 })
337 }
338}
339
340#[cfg(test)]
343mod test {
344
345 use super::*;
346
347 #[test]
348 fn test_buffer_new_success() {
349 let buffer = PineappleBuffer::new(1, 3, 2, [1, 2, 3, 4, 5, 6].as_slice());
350 assert!(buffer.is_ok());
351 }
352
353 #[test]
354 fn test_buffer_new_error() {
355 let buffer = PineappleBuffer::new(2, 3, 2, [1, 2, 3, 4, 5, 6].as_slice());
356 assert!(buffer.is_err());
357 }
358
359 #[test]
360 fn test_buffer_width() {
361 let buffer = PineappleBuffer::new(1, 3, 2, [1, 2, 3, 4, 5, 6].as_slice());
362 assert_eq!(buffer.unwrap().width(), 1);
363 }
364
365 #[test]
366 fn test_buffer_height() {
367 let buffer = PineappleBuffer::new(1, 3, 2, [1, 2, 3, 4, 5, 6].as_slice());
368 assert_eq!(buffer.unwrap().height(), 3);
369 }
370
371 #[test]
372 fn test_buffer_channels() {
373 let buffer = PineappleBuffer::new(1, 3, 2, [1, 2, 3, 4, 5, 6].as_slice());
374 assert_eq!(buffer.unwrap().channels(), 2);
375 }
376
377 #[test]
378 fn test_buffer_shape() {
379 let buffer = PineappleBuffer::new(1, 3, 2, [1, 2, 3, 4, 5, 6].as_slice());
380 assert_eq!(buffer.unwrap().shape(), (3, 1, 2));
381 }
382
383 #[test]
384 fn test_buffer_len() {
385 let buffer = PineappleBuffer::new(1, 3, 2, [1, 2, 3, 4, 5, 6].as_slice());
386 assert_eq!(buffer.unwrap().len(), 6);
387 }
388
389 #[test]
390 fn test_buffer_into_raw() {
391 let buffer = PineappleBuffer::new(1, 3, 2, [1, 2, 3, 4, 5, 6].as_slice());
392 assert_eq!(buffer.unwrap().into_raw(), [1, 2, 3, 4, 5, 6]);
393 }
394
395 #[test]
396 fn test_buffer_as_raw() {
397 let buffer = PineappleBuffer::new(1, 3, 2, [1, 2, 3, 4, 5, 6].as_slice());
398 assert_eq!(buffer.unwrap().as_raw(), &[1, 2, 3, 4, 5, 6]);
399 }
400
401 #[test]
402 fn test_buffer_to_u8() {
403 let buffer = PineappleBuffer::new(1, 2, 2, [2.5, 3.9, 4.8, 2.2].as_slice()).unwrap();
404
405 let u8_vec = buffer.to_u8();
406 assert_eq!(u8_vec, [2, 3, 4, 2]);
407 }
408
409 #[test]
410 fn test_buffer_to_u16() {
411 let buffer = PineappleBuffer::new(1, 2, 2, [2.5, 3.9, 4.8, 2.2].as_slice()).unwrap();
412
413 let u16_vec = buffer.to_u16();
414 assert_eq!(u16_vec, [2, 3, 4, 2]);
415 }
416
417 #[test]
418 fn test_iter() {
419 let buffer = PineappleBuffer::new(1, 3, 2, [1, 2, 3, 4, 5, 6].as_slice()).unwrap();
420
421 for (a, b) in buffer.iter().zip([1, 2, 3, 4, 5, 6]) {
422 assert_eq!(a, &b);
423 }
424 }
425
426 #[test]
427 fn test_iter_channel() {
428 let buffer = PineappleBuffer::new(1, 3, 2, [1, 2, 3, 4, 5, 6].as_slice()).unwrap();
429
430 for (a, b) in buffer.iter_channel(0).unwrap().zip([1, 3, 5]) {
431 assert_eq!(a, &b)
432 }
433
434 for (a, b) in buffer.iter_channel(1).unwrap().zip([2, 4, 6]) {
435 assert_eq!(a, &b)
436 }
437
438 let buffer = PineappleBuffer::new(2, 1, 3, [1, 2, 3, 4, 5, 6].as_slice()).unwrap();
439
440 for (a, b) in buffer.iter_channel(0).unwrap().zip([1, 4]) {
441 assert_eq!(a, &b)
442 }
443
444 for (a, b) in buffer.iter_channel(1).unwrap().zip([2, 5]) {
445 assert_eq!(a, &b)
446 }
447
448 for (a, b) in buffer.iter_channel(2).unwrap().zip([3, 6]) {
449 assert_eq!(a, &b)
450 }
451 }
452
453 #[test]
454 fn test_iter_pixels() {
455 let buffer = PineappleBuffer::new(1, 4, 2, [1, 2, 3, 4, 5, 6, 7, 8].as_slice()).unwrap();
456
457 for (a, b) in buffer.iter_pixels().zip([[1, 2], [3, 4], [5, 6], [7, 8]]) {
458 assert_eq!(a[0], b[0]);
459 assert_eq!(a[1], b[1]);
460 }
461 }
462}