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
//! Image file reading and writing, see [OpenCV
//! imgcodecs](http://docs.opencv.org/3.1.0/d4/da8/group__imgcodecs.html).

use errors::*;
use failure::Error;
use mat::*;
use std::ffi::CString;
use std::os::raw::c_char;
use std::path::Path;
use *;

extern "C" {
    fn cv_imread(input: *const c_char, flags: ImageReadMode) -> *mut CMat;
    fn cv_imdecode(buf: *const u8, l: usize, m: ImageReadMode) -> *mut CMat;
    fn cv_imencode(
        ext: *const c_char,
        inner: *const CMat,
        flag_ptr: *const ImageWriteMode,
        flag_size: usize,
        result: *mut COption<CVec<u8>>,
    );
}

// =============================================================================
//  Imgproc
// =============================================================================
/// ImreadModes. [See documentation](https://docs.opencv.org/trunk/d4/da8/group__imgcodecs.html#ga61d9b0126a3e57d9277ac48327799c80) for detauls
#[repr(C)]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum ImageReadMode {
    /// If set, return the loaded image as is (with alpha channel, otherwise it
    /// gets cropped
    Unchanged = -1,
    /// If set, always convert image to the single channel grayscale image.
    Grayscale = 0,
    /// If set, always convert image to the 3 channel BGR color image.
    Color = 1,
    /// If set, return 16-bit/32-bit image when the input has the corresponding
    /// depth, otherwise convert it to 8-bit.
    AnyDepth = 2,
    /// If set, the image is read in any possible color format.
    AnyColor = 4,
    /// If set, use the gdal driver for loading the image.
    LoadGdal = 8,
    /// If set, always convert image to the single channel grayscale image and
    /// the image size reduced 1/2.
    ReducedGrayscale2 = 16,
    /// If set, always convert image to the 3 channel BGR color image and the
    /// image size reduced 1/2.
    ReducedColor2 = 17,
    /// If set, always convert image to the single channel grayscale image and
    /// the image size reduced 1/4.
    ReducedGrayscale4 = 32,
    /// If set, always convert image to the 3 channel BGR color image and the
    /// image size reduced 1/4.
    ReducedColor4 = 33,
    /// If set, always convert image to the single channel grayscale image and
    /// the image size reduced 1/8.
    ReducedGrayscale8 = 64,
    /// If set, always convert image to the 3 channel BGR color image and the
    /// image size reduced 1/8.
    ReducedColor8 = 65,
}

/// Imwrite flags. [See documentation](https://docs.opencv.org/trunk/d4/da8/group__imgcodecs.html#ga292d81be8d76901bff7988d18d2b42ac) for detauls
#[repr(C)]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum ImageWriteMode {
    /// For JPEG, it can be a quality from 0 to 100 (the higher is the
    /// better). Default value is 95.
    JpegQuality = 1,
    /// Enable JPEG features, 0 or 1, default is False.
    JpegProgressive = 2,
    /// Enable JPEG features, 0 or 1, default is False.
    JpegOptimize = 3,
    /// JPEG restart interval, 0 - 65535, default is 0 - no restart.
    JpegRstInterval = 4,
    /// Separate luma quality level, 0 - 100, default is 0 - don't use.
    JpegLumaQuality = 5,
    /// Separate chroma quality level, 0 - 100, default is 0 - don't use.
    JpegChromaQuality = 6,
    /// For PNG, it can be the compression level from 0 to 9. A higher value
    /// means a smaller size and longer compression time. Default value is 3.
    /// Also strategy is changed to IMWRITE_PNG_STRATEGY_DEFAULT
    /// (Z_DEFAULT_STRATEGY).
    PngCompression = 16,
    /// One of cv::ImwritePNGFlags, default is IMWRITE_PNG_STRATEGY_DEFAULT.
    PngStrategy = 17,
    /// Binary level PNG, 0 or 1, default is 0.
    PngBilevel = 18,
    /// For PPM, PGM, or PBM, it can be a binary format flag, 0 or 1. Default
    /// value is 1.
    PxmBinary = 32,
    /// For WEBP, it can be a quality from 1 to 100 (the higher is the
    /// better). By default (without any parameter) and for quality above 100
    /// the lossless compression is used.
    WebpQuality = 64,
    /// For PAM, sets the TUPLETYPE field to the corresponding string value that
    /// is defined for the format
    PamTupletype = 128,
}

/// Imwrite PNG flag. [See documentation](https://docs.opencv.org/3.3.0/d4/da8/group__imgcodecs.html#gaa60044d347ffd187161b5ec9ea2ef2f9) for detauls
#[repr(C)]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum ImageWritePngStrategy {
    /// Use this value for normal data.
    Default = 0,
    ///  Use this value for data produced by a filter (or predictor).Filtered
    ///  data consists mostly of small values with a somewhat random
    ///  distribution. In this case, the compression algorithm is tuned to
    ///  compress them better.
    Filtered = 1,
    /// Use this value to force Huffman encoding only (no string match).
    HuffmanOnly = 2,
    /// Use this value to limit match distances to one (run-length encoding).
    RLE = 3,
    /// Using this value prevents the use of dynamic Huffman codes, allowing for
    /// a simpler decoder for special applications.
    Fixed = 4,
}

impl Mat {
    /// Decodes an image from `buf` according to the specified mode.
    pub fn image_decode(buf: &[u8], mode: ImageReadMode) -> Mat {
        let inner = unsafe { cv_imdecode(buf.as_ptr(), buf.len(), mode) };
        Self::from_raw(inner)
    }

    /// Encodes an image; the encoding scheme depends on the extension provided;
    /// additional write flags can be passed in using a vector. If successful,
    /// returns an owned vector of the encoded image.
    pub fn image_encode(&self, ext: &str, flags: Vec<ImageWriteMode>) -> Result<Vec<u8>, Error> {
        let ext = CString::new(ext)?;
        unsafe {
            let mut result: COption<CVec<u8>> = mem::zeroed();
            cv_imencode(ext.into_raw(), self.inner, flags.as_ptr(), flags.len(), &mut result);
            if result.has_value {
                Ok(result.value.unpack())
            } else {
                Err(CvError::UnknownError("Unable to convert this image to bytes".into()).into())
            }
        }
    }

    /// Creates a `Mat` from reading the image specified by the path.
    pub fn from_path<P: AsRef<Path>>(path: P, flags: ImageReadMode) -> Result<Mat, Error> {
        let path = path_to_cstring(path)?;
        let path = path.as_ptr();
        let result = unsafe { cv_imread(path, flags) };
        Ok(Mat::from_raw(result))
    }
}