1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//! Module for the pixel data trait and implementations.
//!
//! **Note:** This module is deprecated and obsolete.
//! Please check out the [`dicom-pixeldata` crate][1] instead.
//!
//! [1]: https://docs.rs/dicom-pixeldata
use snafu::{Backtrace, Snafu};
use std::marker::PhantomData;

#[derive(Debug, Snafu)]
#[non_exhaustive]
pub enum Error {
    PixelIndexOutOfBounds { backtrace: Backtrace },
}

pub type Result<T> = std::result::Result<T, Error>;

/** Implemented by DICOM pixel data blocks retrieved from objects.
 *
 * Pixel data elements typically represent 2D images. This trait provides
 * access to Pixel Data (7FE0,0010), Overlay Data (60xx,3000), or Waveform Data (5400,1010)
 * in a similar fashion to a two-dimensional array.
 */
pub trait PixelData {
    /// The representation of an individual pixel.
    type Pixel;

    /// Get the number of rows (height) of the slice.
    fn rows(&self) -> u32;

    /// Get the number of columns (width) of the slice.
    fn columns(&self) -> u32;

    /// Get the number of bits used to represent each pixel.
    fn bits_per_pixel(&self) -> u32;

    /// Retrieve the number of samples (channels) per pixel.
    fn samples_per_pixel(&self) -> u16;

    /// Obtain the pixel value in the given position.
    /// Can return PixelDataOutOfBounds error when the given coordinates
    /// are out of the slice's boundaries.
    fn pixel_at(&self, width: u32, height: u32) -> Result<Self::Pixel>;
}

pub trait PixelDataMut: PixelData {
    /// Obtain a mutable reference to the pixel value in the given position.
    /// Can return PixelDataOutOfBounds error when the given coordinates
    /// are out of the slice's boundaries.
    fn pixel_at_mut(&mut self, width: u32, height: u32) -> Result<&mut Self::Pixel>;
}

/// A DICOM slice that is completely stored in memory, which may be
/// owned by this  and owned by a local
/// vector. Pixels are stored in row-major order with no padding.
#[derive(Debug, Clone, PartialEq)]
pub struct InMemoryPixelData<C, P> {
    phantom: PhantomData<P>,
    data: C,
    rows: u32,
    cols: u32,
    bpp: u32,
    samples: u16,
}

impl<C, P> InMemoryPixelData<C, P> {
    fn check_bounds(&self, w: u32, h: u32) -> Result<()> {
        if w >= self.cols || h >= self.rows {
            PixelIndexOutOfBoundsSnafu.fail()
        } else {
            Ok(())
        }
    }

    /// Fetch the internal data container, destroying the pixel data structure in the process.
    pub fn into_raw_data(self) -> C {
        self.data
    }

    /// Obtain a reference to the internal data container.
    pub fn raw_data(&self) -> &C {
        &self.data
    }

    /// Obtain a reference to the internal data container.
    pub fn raw_data_mut(&mut self) -> &mut C {
        &mut self.data
    }
}

impl<C, P> PixelData for InMemoryPixelData<C, P>
where
    P: Clone,
    C: std::ops::Deref<Target = [P]>,
{
    type Pixel = P;

    fn rows(&self) -> u32 {
        self.rows
    }

    fn columns(&self) -> u32 {
        self.cols
    }

    fn bits_per_pixel(&self) -> u32 {
        self.bpp
    }

    fn samples_per_pixel(&self) -> u16 {
        self.samples
    }

    fn pixel_at(&self, w: u32, h: u32) -> Result<P> {
        self.check_bounds(w, h).map(move |_| {
            let i = (h * self.cols + w) as usize;
            self.data[i].clone()
        })
    }
}

impl<C, P> PixelDataMut for InMemoryPixelData<C, P>
where
    P: Clone,
    C: std::ops::DerefMut<Target = [P]>,
{
    fn pixel_at_mut(&mut self, w: u32, h: u32) -> Result<&mut P> {
        self.check_bounds(w, h).map(move |_| {
            let i = (h * self.cols + w) as usize;
            &mut self.data[i]
        })
    }
}