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

use super::core::{CMat, Mat};
use std::ffi::CString;
use std::os::raw::{c_char, c_int};
use std::path::Path;

// =============================================================================
//  Imgproc
// =============================================================================
/// ImreadModes
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum ImreadModes {
    /// If set, return the loaded image as is (with alpha channel, otherwise it
    /// gets cropped
    ImreadUnchanged = -1,
    /// If set, always convert image to the single channel grayscale image.
    ImreadGrayscale = 0,
    /// If set, always convert image to the 3 channel BGR color image.
    ImreadColor = 1,
    /// If set, return 16-bit/32-bit image when the input has the corresponding
    /// depth, otherwise convert it to 8-bit.
    ImreadAnydepth = 2,
    /// If set, the image is read in any possible color format.
    ImreadAnycolor = 4,
    /// If set, use the gdal driver for loading the image.
    ImreadLoadGdal = 8,
    /// If set, always convert image to the single channel grayscale image and
    /// the image size reduced 1/2.
    ImreadReducedGrayscale2 = 16,
    /// If set, always convert image to the 3 channel BGR color image and the
    /// image size reduced 1/2.
    ImreadReducedColor2 = 17,
    /// If set, always convert image to the single channel grayscale image and
    /// the image size reduced 1/4.
    ImreadReducedGrayscale4 = 32,
    /// If set, always convert image to the 3 channel BGR color image and the
    /// image size reduced 1/4.
    ImreadReducedColor4 = 33,
    /// If set, always convert image to the single channel grayscale image and
    /// the image size reduced 1/8.
    ImreadReducedGrayscale8 = 64,
    /// If set, always convert image to the 3 channel BGR color image and the
    /// image size reduced 1/8.
    ImreadReducedColor8 = 65,
}

/// Imwrite flags
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum ImwriteFlags {
    /// For JPEG, it can be a quality from 0 to 100 (the higher is the
    /// better). Default value is 95.
    ImwriteJpegQuality = 1,
    /// Enable JPEG features, 0 or 1, default is False.
    ImwriteJpegProgressive = 2,
    /// Enable JPEG features, 0 or 1, default is False.
    ImwriteJpegOptimize = 3,
    /// JPEG restart interval, 0 - 65535, default is 0 - no restart.
    ImwriteJpegRstInterval = 4,
    /// Separate luma quality level, 0 - 100, default is 0 - don't use.
    ImwriteJpegLumaQuality = 5,
    /// Separate chroma quality level, 0 - 100, default is 0 - don't use.
    ImwriteJpegChromaQuality = 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).
    ImwritePngCompression = 16,
    /// One of cv::ImwritePNGFlags, default is IMWRITE_PNG_STRATEGY_DEFAULT.
    ImwritePngStrategy = 17,
    /// Binary level PNG, 0 or 1, default is 0.
    ImwritePngBilevel = 18,
    /// For PPM, PGM, or PBM, it can be a binary format flag, 0 or 1. Default
    /// value is 1.
    ImwritePxmBinary = 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.
    ImwriteWebpQuality = 64,
    /// For PAM, sets the TUPLETYPE field to the corresponding string value that
    /// is defined for the format
    ImwritePamTupletype = 128,
}

/// Imwrite PNG flag
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum ImwritePngFlags {
    /// Use this value for normal data.
    ImwritePngStrategyDefault = 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.
    ImwritePngStrategyFiltered = 1,
    /// Use this value to force Huffman encoding only (no string match).
    ImwritePngStrategyHuffmanOnly = 2,
    /// Use this value to limit match distances to one (run-length encoding).
    ImwritePngStrategyRle = 3,
    /// Using this value prevents the use of dynamic Huffman codes, allowing for
    /// a simpler decoder for special applications.
    ImwritePngStrategyFixed = 4,
}

extern "C" {
    fn cv_imread(input: *const c_char, flags: c_int) -> *mut CMat;
    fn cv_imdecode(buf: *const u8, l: usize, m: c_int) -> *mut CMat;
    fn cv_imencode(ext: *const c_char, inner: *const CMat, flag_ptr: *const c_int, flag_size: usize) -> ImencodeResult;

}

#[repr(C)]
struct ImencodeResult {
    status: bool,
    buf: *mut u8,
    size: usize,
}

impl Mat {
    /// Creates a `Mat` from reading the image specified by the path.
    pub fn from_path<P: AsRef<Path>>(path: P, flags: ImreadModes) -> Option<Mat> {
        if let Some(unicode_path) = path.as_ref().as_os_str().to_str() {
            let s = CString::new(unicode_path).unwrap();
            let m = unsafe { cv_imread((&s).as_ptr(), flags as c_int) };
            Some(Mat::from_raw(m))
        } else {
            None
        }
    }

    /// Decodes an image from `buf` according to the specified mode.
    pub fn imdecode(buf: &[u8], mode: ImreadModes) -> Mat {
        let inner = unsafe { cv_imdecode(buf.as_ptr(), buf.len(), mode as i32) };
        Mat::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 imencode(&self, ext: &str, f: Vec<ImwriteFlags>) -> Option<Vec<u8>> {
        let ext = CString::new(ext).expect("invalid extension string");
        let flags = f.into_iter().map(|f| f as i32).collect::<Vec<_>>();
        let r = unsafe { cv_imencode(ext.into_raw(), self.inner, flags.as_ptr(), flags.len()) };
        if r.status {
            unsafe { Some(::std::slice::from_raw_parts(r.buf, r.size).to_vec()) }
        } else {
            None
        }
    }
}