rimg 0.1.1

RImg aims to be a Rust implementation of CImg, the C++ Image Template Image Processing Toolkit
Documentation
/// 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());
    }
}