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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
/// Struct representing an image (up to 4 dimensions wide), each pixel being of type T.
///
/// This is the main class of the CImg Library. It declares and constructs an image,
/// allows access to its pixel values, and is able to perform various image operations.
///
/// ## Image representation
///
/// A RImg image is defined as an instance of the container RImg<T>, which contains a
/// regular grid of pixels, each pixel value being of type T. The image grid can have
/// up to 4 dimensions: width, height, depth and number of channels. Usually, the three
/// first dimensions are used to describe spatial coordinates (x,y,z), while the number
/// of channels is rather used as a vector-valued dimension (it may describe the R,G,B
/// color channels for instance).
///
/// Thus, the RImg<T> struct is able to represent volumetric images of vector-valued
/// pixels, as well as images with less dimensions (1D scalar signal, 2D color images, ...).
/// Most member functions of the struct RImg<T> are designed to handle this maximum case
/// of (3+1) dimensions.
///
/// Concerning the pixel value type T: fully supported template types are Rust primitive
/// number types:
///
///   * Integers: `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`,
///     `isize`, `usize`
///   * Floats: `f32`, `f64`
///
/// Typically, fast image display can be done using CImg<u8> images, while
/// complex image processing algorithms may be rather coded using RImg<f32> or RImg<f54>
/// images that have floating-point pixel values. The default value for the template T is
/// f32. Using your own template types may be possible.
///
/// ## Image structure
///
/// The RImg<T> structure contains five fields:
///
///   * `width` defines the number of columns of the image (size along the X-axis).
///   * `height` defines the number of rows of the image (size along the Y-axis).
///   * `depth` defines the number of slices of the image (size along the Z-axis).
///   * `spectrum` defines the number of channels of the image (size along the C-axis).
///   * `data` defines a pointer to the pixel data (of type T).
///
/// You can access these fields the dedicated functions `width()`, `height()`, `depth()`,
/// `spectrum()` and `vec()` to do so. Image dimensions are not limited to a specific range
/// (as long as you got enough available memory). A value of 1 usually means that the
/// corresponding dimension is *flat*. If one of the dimensions is 0, or if the data pointer is null,
/// the image is considered as empty. Empty images should not contain any pixel data and thus,
/// will not be processed by RImg member functions (an Error Status will be returned instead).
/// Pixel data are stored in memory, in a non interlaced mode.
pub struct RImg<T = f32> {
    pub width: usize,
    pub height: usize,
    pub depth: usize,
    pub spectrum: usize,
    pub data: Vec<T>,
}

impl<T: Copy> RImg<T> {
    /// Creates a new RImg instance
    ///
    /// ## Examples
    ///
    /// ```
    /// # use rimg::RImg;
    /// // creates a 256x256 sized with 3 channels image filled with 0
    /// let img = RImg::new(256, 256, 1, 3, 0);
    /// # img.size();
    /// ```
    pub fn new(width: usize, height: usize, depth: usize, spectrum: usize, value: T) -> RImg<T> {
        let data_size = width * height * depth * spectrum;
        let mut data: Vec<T> = Vec::new();
        for _i in 0..data_size {
            data.push(value);
        }
        RImg::<T> {
            width,
            height,
            depth,
            spectrum,
            data,
        }
    }

    /// Return the number of image rows.
    ///
    /// Return the image height, i.e. the image dimension along the Y-axis.
    ///
    /// ## Note
    ///
    ///  * The height() of an empty image is equal to 0.
    ///  * height() returns an `isize`, although the image height is internally stored as 
    ///    a `usize`. Using an `isize` is safer and prevents arithmetic traps (and subsequent 
    ///    compilation errors) possibly encountered when doing calculations involving
    ///    usize variables. Access to the initial `usize` is possible (though not
    ///    recommended) by `self.height`
    ///
    /// ## Examples
    ///
    /// ```
    /// # use rimg::RImg;
    /// # let img = RImg::new(256, 256, 1, 3, 0);
    /// assert_eq!(256, img.height());
    /// ```
    pub fn height(&self) -> isize {
        self.height as isize
    }

    /// Return the number of image columns.
    ///
    /// Return the image width, i.e. the image dimension along the X-axis.
    ///
    /// ## Note
    ///
    ///  * The width() of an empty image is equal to 0.
    ///  * width() is typically equal to 1 when considering images as vectors for
    ///    matrix calculations.
    ///  * width() returns an `isize`, although the image width is internally stored as
    ///    a `usize`. Using an `isize` is safer and prevents arithmetic traps (and subsequent
    ///    compilation errors) possibly encountered when doing calculations involving `usize`
    ///    variables. Access to the initial `usize` variable is possible (though not recommended)
    ///    by `self.width`. 
    ///
    /// ## Examples
    ///
    /// ```
    /// # use rimg::RImg;
    /// # let img = RImg::new(256, 256, 1, 3, 0);
    /// assert_eq!(256, img.width());
    /// ```
    pub fn width(&self) -> isize {
        self.width as isize
    }

    

    /// Return the number of image slices.
    ///
    /// Return the image depth, i.e. the image dimension along the Z-axis.
    ///
    /// ## Note
    ///
    ///  * The depth() of an empty image is equal to 0.
    ///  * depth() is typically equal to 1 when considering usual 2D images. When depth() > 1,
    ///    the image is said to be volumetric.
    ///  * depth() returns an `isize`, although the image depth is internally stored as a `usize`.
    ///    Using an `isize` is safer and prevents arithmetic traps (and subsequent compilation errors)
    ///    possibly encountered when doing calculations involving `usize` variables. Access to the
    ///    initial `usize` variable is possible (though not recommended) by `self.depth`.
    ///
    /// ## Examples
    ///
    /// ```
    /// # use rimg::RImg;
    /// # let img = RImg::new(256, 256, 1, 3, 0);
    /// assert_eq!(1, img.depth());
    /// ```
    pub fn depth(&self) -> isize {
        self.depth as isize
    }

    /// Return the number of image channels.
    ///
    /// Return the number of image channels, i.e. the image dimension along the C-axis.
    ///
    /// ## Note
    ///
    ///  * The spectrum() of an empty image is equal to 0.
    ///  * spectrum() is typically equal to 1 when considering scalar-valued images, to 3
    ///    for RGB-coded color images, and to 4 for RGBA-coded color images (with alpha-channel).
    ///    The number of channels of an image instance is not limited. The meaning of the pixel
    ///    values is not linked up to the number of channels (e.g. a 4-channel image may
    ///    indifferently stands for a RGBA or CMYK color image).
    ///  * spectrum() returns an `isize`, although the image spectrum is internally stored as
    ///    a `usize`. Using an `isize` is safer and prevents arithmetic traps (and subsequent
    ///    compilation errors) possibly encountered when doing calculations involving `usize`
    ///    variables. Access to the initial `usize` variable is possible (though not recommended)
    ///    by `self.spectrum`.
    /// 
    /// ## Examples
    ///
    /// ```
    /// # use rimg::RImg;
    /// # let img = RImg::new(256, 256, 1, 3, 0);
    /// assert_eq!(3, img.spectrum());
    /// ```
    pub fn spectrum(&self) -> isize {
        self.spectrum as isize
    }

    /// Returns the image number of pixel total values.
    /// 
    /// Return `width * height * depth * spectrum`, i.e. the total number of values of type T
    /// in the pixel buffer of the image instance.
    /// 
    /// ## Note
    ///
    ///  * The size() of an empty image is equal to 0.
    ///  * The allocated memory size for a pixel buffer of a RImg<T> instance is equal to `size() * size_of<T>()`.
    /// 
    /// ## Examples
    ///
    /// ```
    /// # use rimg::RImg;
    /// # let img = RImg::new(256, 256, 1, 3, 0);
    /// assert_eq!(196608, img.size());
    /// ```
    pub fn size(&self) -> usize {
        self.width * self.height * self.depth * self.spectrum
    }
}

#[cfg(test)]
mod tests {
    use crate::RImg;

    fn create_img() -> RImg<u16> {
        RImg::new(128, 256, 1, 3, 0u16)
    }

    #[test]
    fn test_width() {
        let img = create_img();
        assert_eq!(128, img.width());
    }

    #[test]
    fn test_height() {
        let img = create_img();
        assert_eq!(256, img.height());
    }

    #[test]
    fn test_depth() {
        let img = create_img();
        assert_eq!(1, img.depth());
    }

    #[test]
    fn test_spectrum() {
        let img = create_img();
        assert_eq!(3, img.spectrum());
    }

    #[test]
    fn test_size() {
        let img = create_img();
        assert_eq!(98304, img.size());
    }
}