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
//! Foreign function interface.

use std::io::{Cursor,Read};
use std::mem;
use std::ptr;
use std::slice;
use libc::{c_uchar,c_uint,size_t};

use ::{BayerDepth,BayerError,BayerResult,CFA,RasterDepth,RasterMut};
use demosaic;

/// Dummy opaque structure, equivalent to RasterMut<'a>.
pub struct CRasterMut;

// Print with "file:line - " prefix, for more informative error messages.
macro_rules! printerrorln {
    ($e:expr) => {{
        println!("{}:{} - {}", file!(), line!(), $e);
    }};
    ($fmt:expr, $arg:tt) => {{
        print!("{}:{} - ", file!(), line!());
        println!($fmt, $arg);
    }};
}

unsafe fn transmute_raster_mut<'a>(dst: *mut CRasterMut)
        -> &'a mut RasterMut<'a> {
    let ptr: *mut RasterMut = mem::transmute(dst);
    &mut *ptr
}

fn run_demosaic<F>(file: &'static str, line: u32,
        run: F,
        src: *const c_uchar, src_len: size_t,
        depth: c_uint, be: c_uint, cfa: c_uint,
        dst: *mut CRasterMut)
        -> c_uint
        where F: FnOnce(&mut Read, BayerDepth, CFA, &mut RasterMut) -> BayerResult<()> {
    if src.is_null() || dst.is_null() {
        println!("{} {} - bad input parameters", file, line);
        return 1;
    }

    let depth = match (depth, be) {
        (8, _) => BayerDepth::Depth8,
        (16, 0) => BayerDepth::Depth16LE,
        (16, _) => BayerDepth::Depth16BE,
        _ => {
            println!("{} {} - invalid depth", file, line);
            return 2;
        }
    };

    let cfa = match cfa {
        0 => CFA::BGGR,
        1 => CFA::GBRG,
        2 => CFA::GRBG,
        3 => CFA::RGGB,
        _ => {
            println!("{} {} - invalid cfa", file, line);
            return 1;
        }
    };

    let src_slice = unsafe{ slice::from_raw_parts(src, src_len) };
    let dst_raster = unsafe{ transmute_raster_mut(dst) };

    match run(&mut Cursor::new(&src_slice[..]), depth, cfa, dst_raster) {
        Ok(_) => 0,
        Err(BayerError::WrongResolution) => 2,
        Err(BayerError::WrongDepth) => 3,
        Err(_) => 1,
    }
}

/*--------------------------------------------------------------*/
/* Demosaicing algorithms                                       */
/*--------------------------------------------------------------*/

/// Demosaicing without any interpolation.
#[no_mangle]
pub extern "C" fn bayerrs_demosaic_none(
        src: *const c_uchar, src_len: size_t,
        depth: c_uint, be: c_uint, cfa: c_uint,
        dst: *mut CRasterMut)
        -> c_uint {
    run_demosaic(file!(), line!(),
            demosaic::none::run,
            src, src_len, depth, be, cfa, dst)
}

/// Demosaicing using nearest neighbour interpolation.
#[no_mangle]
pub extern "C" fn bayerrs_demosaic_nearest_neighbour(
        src: *const c_uchar, src_len: size_t,
        depth: c_uint, be: c_uint, cfa: c_uint,
        dst: *mut CRasterMut)
        -> c_uint {
    run_demosaic(file!(), line!(),
            demosaic::nearestneighbour::run,
            src, src_len, depth, be, cfa, dst)
}

/// Demosaicing using linear interpolation.
#[no_mangle]
pub extern "C" fn bayerrs_demosaic_linear(
        src: *const c_uchar, src_len: size_t,
        depth: c_uint, be: c_uint, cfa: c_uint,
        dst: *mut CRasterMut)
        -> c_uint {
    run_demosaic(file!(), line!(),
            demosaic::linear::run,
            src, src_len, depth, be, cfa, dst)
}

/// Demosaicing using cubic interpolation.
#[no_mangle]
pub extern "C" fn bayerrs_demosaic_cubic(
        src: *const c_uchar, src_len: size_t,
        depth: c_uint, be: c_uint, cfa: c_uint,
        dst: *mut CRasterMut)
        -> c_uint {
    run_demosaic(file!(), line!(),
            demosaic::cubic::run,
            src, src_len, depth, be, cfa, dst)
}

/*--------------------------------------------------------------*/
/* Raster                                                       */
/*--------------------------------------------------------------*/

/// Allocate a new raster.
#[no_mangle]
pub extern "C" fn bayerrs_raster_mut_alloc(
        x: size_t, y: size_t, w: size_t, h: size_t, stride: size_t, depth: c_uint,
        buf: *mut c_uchar, buf_len: size_t)
        -> *mut CRasterMut {
    if buf.is_null() {
        printerrorln!("bad input parameters");
        return ptr::null_mut();
    }

    let depth = match depth {
        8 => RasterDepth::Depth8,
        16 => RasterDepth::Depth16,
        _ => {
            printerrorln!("bad input parameters");
            return ptr::null_mut();
        }
    };

    let buf_slice = unsafe{ slice::from_raw_parts_mut(buf, buf_len) };
    let raster = RasterMut::with_offset(x, y, w, h, stride, depth, buf_slice);
    let rptr = Box::into_raw(Box::new(raster));
    let cptr: *mut CRasterMut = unsafe{ mem::transmute(rptr) };
    cptr
}

/// Free a previously allocated raster.
#[no_mangle]
pub extern "C" fn bayerrs_raster_mut_free(raster: *mut CRasterMut) {
    if raster.is_null() {
        return;
    }

    let rptr: *mut RasterMut = unsafe{ mem::transmute(raster) };
    let _raster = unsafe{ Box::from_raw(rptr) };
}