1 //! MMX image filters
2 
3 use std::mem;
4 use libc::{self,size_t, c_void, c_uint, c_int};
5 use ::get_error;
6 use c_vec::CVec;
7 use sys::gfx::imagefilter;
8 
9 /// MMX detection routine (with override flag).
mmx_detect() -> bool10 pub fn mmx_detect() -> bool {
11     unsafe { imagefilter::SDL_imageFilterMMXdetect() == 1 }
12 }
13 
14 /// Disable MMX check for filter functions and and force to use non-MMX C based code.
mmx_off()15 pub fn mmx_off() {
16     unsafe { imagefilter::SDL_imageFilterMMXoff() }
17 }
18 
19 /// Enable MMX check for filter functions and use MMX code if available.
mmx_on()20 pub fn mmx_on() {
21     unsafe { imagefilter::SDL_imageFilterMMXon() }
22 }
23 
24 #[inline]
cvec_with_size(sz: usize) -> CVec<u8>25 fn cvec_with_size(sz: usize) -> CVec<u8> {
26     unsafe {
27         let p = libc::malloc(sz as size_t) as *mut u8;
28         CVec::new_with_dtor(p, sz, move |p| {
29             libc::free(p as *mut c_void)
30         })
31     }
32 }
33 
34 /// Filter using Add: D = saturation255(S1 + S2).
add(src1: CVec<u8>, src2: CVec<u8>) -> Result<CVec<u8>, String>35 pub fn add(src1: CVec<u8>, src2: CVec<u8>) -> Result<CVec<u8>, String> {
36     assert_eq!(src1.len(), src2.len());
37     let size = src1.len();
38     let dest = cvec_with_size(size);
39     let ret = unsafe { imagefilter::SDL_imageFilterAdd(mem::transmute(src1.get(0)),
40                                               mem::transmute(src2.get(0)),
41                                               mem::transmute(dest.get(0)),
42                                               size as c_uint) };
43     if ret == 0 { Ok(dest) }
44     else { Err(get_error()) }
45 }
46 
47 /// Filter using Mean: D = S1/2 + S2/2.
mean(src1: CVec<u8>, src2: CVec<u8>) -> Result<CVec<u8>, String>48 pub fn mean(src1: CVec<u8>, src2: CVec<u8>) -> Result<CVec<u8>, String> {
49     assert_eq!(src1.len(), src2.len());
50     let size = src1.len();
51     let dest = cvec_with_size(size);
52     let ret = unsafe { imagefilter::SDL_imageFilterMean(mem::transmute(src1.get(0)),
53                                                mem::transmute(src2.get(0)),
54                                                mem::transmute(dest.get(0)),
55                                                size as c_uint) };
56     if ret == 0 { Ok(dest) }
57     else { Err(get_error()) }
58 }
59 
60 /// Filter using Sub: D = saturation0(S1 - S2).
sub(src1: CVec<u8>, src2: CVec<u8>) -> Result<CVec<u8>, String>61 pub fn sub(src1: CVec<u8>, src2: CVec<u8>) -> Result<CVec<u8>, String> {
62     assert_eq!(src1.len(), src2.len());
63     let size = src1.len();
64     let dest = cvec_with_size(size);
65     let ret = unsafe { imagefilter::SDL_imageFilterSub(mem::transmute(src1.get(0)),
66                                               mem::transmute(src2.get(0)),
67                                               mem::transmute(dest.get(0)),
68                                               size as c_uint) };
69     if ret == 0 { Ok(dest) }
70     else { Err(get_error()) }
71 }
72 
73 /// Filter using `AbsDiff`: D = | S1 - S2 |.
abs_diff(src1: CVec<u8>, src2: CVec<u8>) -> Result<CVec<u8>, String>74 pub fn abs_diff(src1: CVec<u8>, src2: CVec<u8>) -> Result<CVec<u8>, String> {
75     assert_eq!(src1.len(), src2.len());
76     let size = src1.len();
77     let dest = cvec_with_size(size);
78     let ret = unsafe { imagefilter::SDL_imageFilterAbsDiff(mem::transmute(src1.get(0)),
79                                                   mem::transmute(src2.get(0)),
80                                                   mem::transmute(dest.get(0)),
81                                                   size as c_uint) };
82     if ret == 0 { Ok(dest) }
83     else { Err(get_error()) }
84 }
85 
86 /// Filter using Mult: D = saturation255(S1 * S2).
mult(src1: CVec<u8>, src2: CVec<u8>) -> Result<CVec<u8>, String>87 pub fn mult(src1: CVec<u8>, src2: CVec<u8>) -> Result<CVec<u8>, String> {
88     assert_eq!(src1.len(), src2.len());
89     let size = src1.len();
90     let dest = cvec_with_size(size);
91     let ret = unsafe { imagefilter::SDL_imageFilterMult(mem::transmute(src1.get(0)),
92                                                mem::transmute(src2.get(0)),
93                                                mem::transmute(dest.get(0)),
94                                                size as c_uint) };
95     if ret == 0 { Ok(dest) }
96     else { Err(get_error()) }
97 }
98 
99 /// Filter using `MultNor`: D = S1 * S2.
mult_nor(src1: CVec<u8>, src2: CVec<u8>) -> Result<CVec<u8>, String>100 pub fn mult_nor(src1: CVec<u8>, src2: CVec<u8>) -> Result<CVec<u8>, String> {
101     assert_eq!(src1.len(), src2.len());
102     let size = src1.len();
103     let dest = cvec_with_size(size);
104     let ret = unsafe { imagefilter::SDL_imageFilterMultNor(mem::transmute(src1.get(0)),
105                                                   mem::transmute(src2.get(0)),
106                                                   mem::transmute(dest.get(0)),
107                                                   size as c_uint) };
108     if ret == 0 { Ok(dest) }
109     else { Err(get_error()) }
110 }
111 
112 /// Filter using `MultDivby2`: D = saturation255(S1/2 * S2).
mult_div_by2(src1: CVec<u8>, src2: CVec<u8>) -> Result<CVec<u8>, String>113 pub fn mult_div_by2(src1: CVec<u8>, src2: CVec<u8>) -> Result<CVec<u8>, String> {
114     assert_eq!(src1.len(), src2.len());
115     let size = src1.len();
116     let dest = cvec_with_size(size);
117     let ret = unsafe { imagefilter::SDL_imageFilterMultDivby2(mem::transmute(src1.get(0)),
118                                                      mem::transmute(src2.get(0)),
119                                                      mem::transmute(dest.get(0)),
120                                                      size as c_uint) };
121     if ret == 0 { Ok(dest) }
122     else { Err(get_error()) }
123 }
124 
125 /// Filter using `MultDivby4`: D = saturation255(S1/2 * S2/2).
mult_div_by4(src1: CVec<u8>, src2: CVec<u8>) -> Result<CVec<u8>, String>126 pub fn mult_div_by4(src1: CVec<u8>, src2: CVec<u8>) -> Result<CVec<u8>, String> {
127     assert_eq!(src1.len(), src2.len());
128     let size = src1.len();
129     let dest = cvec_with_size(size);
130     let ret = unsafe { imagefilter::SDL_imageFilterMultDivby4(mem::transmute(src1.get(0)),
131                                                      mem::transmute(src2.get(0)),
132                                                      mem::transmute(dest.get(0)),
133                                                      size as c_uint) };
134     if ret == 0 { Ok(dest) }
135     else { Err(get_error()) }
136 }
137 
138 /// Filter using `BitAnd`: D = S1 & S2.
bit_and(src1: CVec<u8>, src2: CVec<u8>) -> Result<CVec<u8>, String>139 pub fn bit_and(src1: CVec<u8>, src2: CVec<u8>) -> Result<CVec<u8>, String> {
140     assert_eq!(src1.len(), src2.len());
141     let size = src1.len();
142     let dest = cvec_with_size(size);
143     let ret = unsafe { imagefilter::SDL_imageFilterBitAnd(mem::transmute(src1.get(0)),
144                                                  mem::transmute(src2.get(0)),
145                                                  mem::transmute(dest.get(0)),
146                                                  size as c_uint) };
147     if ret == 0 { Ok(dest) }
148     else { Err(get_error()) }
149 }
150 
151 /// Filter using `BitOr`: D = S1 | S2.
bit_or(src1: CVec<u8>, src2: CVec<u8>) -> Result<CVec<u8>, String>152 pub fn bit_or(src1: CVec<u8>, src2: CVec<u8>) -> Result<CVec<u8>, String> {
153     assert_eq!(src1.len(), src2.len());
154     let size = src1.len();
155     let dest = cvec_with_size(size);
156     let ret = unsafe { imagefilter::SDL_imageFilterBitOr(mem::transmute(src1.get(0)),
157                                                 mem::transmute(src2.get(0)),
158                                                 mem::transmute(dest.get(0)),
159                                                 size as c_uint) };
160     if ret == 0 { Ok(dest) }
161     else { Err(get_error()) }
162 }
163 
164 /// Filter using Div: D = S1 / S2.
div(src1: CVec<u8>, src2: CVec<u8>) -> Result<CVec<u8>, String>165 pub fn div(src1: CVec<u8>, src2: CVec<u8>) -> Result<CVec<u8>, String> {
166     assert_eq!(src1.len(), src2.len());
167     let size = src1.len();
168     let dest = cvec_with_size(size);
169     let ret = unsafe { imagefilter::SDL_imageFilterDiv(mem::transmute(src1.get(0)),
170                                               mem::transmute(src2.get(0)),
171                                               mem::transmute(dest.get(0)),
172                                               size as c_uint) };
173     if ret == 0 { Ok(dest) }
174     else { Err(get_error()) }
175 }
176 
177 /// Filter using `BitNegation`: D = !S.
bit_negation(src1: CVec<u8>) -> Result<CVec<u8>, String>178 pub fn bit_negation(src1: CVec<u8>) -> Result<CVec<u8>, String> {
179     let size = src1.len();
180     let dest = cvec_with_size(size);
181     let ret = unsafe { imagefilter::SDL_imageFilterBitNegation(mem::transmute(src1.get(0)),
182                                                       mem::transmute(dest.get(0)),
183                                                       size as c_uint) };
184     if ret == 0 { Ok(dest) }
185     else { Err(get_error()) }
186 }
187 
188 /// Filter using `AddByte`: D = saturation255(S + C).
add_byte(src1: CVec<u8>, c: u8) -> Result<CVec<u8>, String>189 pub fn add_byte(src1: CVec<u8>, c: u8) -> Result<CVec<u8>, String> {
190     let size = src1.len();
191     let dest = cvec_with_size(size);
192     let ret = unsafe { imagefilter::SDL_imageFilterAddByte(mem::transmute(src1.get(0)),
193                                                   mem::transmute(dest.get(0)),
194                                                   size as c_uint, c) };
195     if ret == 0 { Ok(dest) }
196     else { Err(get_error()) }
197 }
198 
199 /// Filter using `AddUint`: D = saturation255((S[i] + Cs[i % 4]), Cs=Swap32((uint)C).
add_uint(src1: CVec<u8>, c: u32) -> Result<CVec<u8>, String>200 pub fn add_uint(src1: CVec<u8>, c: u32) -> Result<CVec<u8>, String> {
201     let size = src1.len();
202     let dest = cvec_with_size(size);
203     let ret = unsafe { imagefilter::SDL_imageFilterAddUint(mem::transmute(src1.get(0)),
204                                                   mem::transmute(dest.get(0)),
205                                                   size as c_uint, c) };
206     if ret == 0 { Ok(dest) }
207     else { Err(get_error()) }
208 }
209 
210 /// Filter using `AddByteToHalf`: D = saturation255(S/2 + C).
add_byte_to_half(src1: CVec<u8>, c: u8) -> Result<CVec<u8>, String>211 pub fn add_byte_to_half(src1: CVec<u8>, c: u8) -> Result<CVec<u8>, String> {
212     let size = src1.len();
213     let dest = cvec_with_size(size);
214     let ret = unsafe { imagefilter::SDL_imageFilterAddByteToHalf(mem::transmute(src1.get(0)),
215                                                         mem::transmute(dest.get(0)),
216                                                         size as c_uint, c) };
217     if ret == 0 { Ok(dest) }
218     else { Err(get_error()) }
219 }
220 
221 /// Filter using `SubByte`: D = saturation0(S - C).
sub_byte(src1: CVec<u8>, c: u8) -> Result<CVec<u8>, String>222 pub fn sub_byte(src1: CVec<u8>, c: u8) -> Result<CVec<u8>, String> {
223     let size = src1.len();
224     let dest = cvec_with_size(size);
225     let ret = unsafe { imagefilter::SDL_imageFilterSubByte(mem::transmute(src1.get(0)),
226                                                   mem::transmute(dest.get(0)),
227                                                   size as c_uint, c) };
228     if ret == 0 { Ok(dest) }
229     else { Err(get_error()) }
230 }
231 
232 /// Filter using `SubUint`: D = saturation0(S[i] - Cs[i % 4]), Cs=Swap32((uint)C).
sub_uint(src1: CVec<u8>, c: u32) -> Result<CVec<u8>, String>233 pub fn sub_uint(src1: CVec<u8>, c: u32) -> Result<CVec<u8>, String> {
234     let size = src1.len();
235     let dest = cvec_with_size(size);
236     let ret = unsafe { imagefilter::SDL_imageFilterSubUint(mem::transmute(src1.get(0)),
237                                                   mem::transmute(dest.get(0)),
238                                                   size as c_uint, c) };
239     if ret == 0 { Ok(dest) }
240     else { Err(get_error()) }
241 }
242 
243 /// Filter using `ShiftRight`: D = saturation0(S >> N).
shift_right(src1: CVec<u8>, n: u8) -> Result<CVec<u8>, String>244 pub fn shift_right(src1: CVec<u8>, n: u8) -> Result<CVec<u8>, String> {
245     let size = src1.len();
246     let dest = cvec_with_size(size);
247     let ret = unsafe { imagefilter::SDL_imageFilterShiftRight(mem::transmute(src1.get(0)),
248                                                      mem::transmute(dest.get(0)),
249                                                      size as c_uint, n) };
250     if ret == 0 { Ok(dest) }
251     else { Err(get_error()) }
252 }
253 
254 /// Filter using `ShiftRightUint`: D = saturation0((uint)S[i] >> N).
shift_right_uint(src1: CVec<u8>, n: u8) -> Result<CVec<u8>, String>255 pub fn shift_right_uint(src1: CVec<u8>, n: u8) -> Result<CVec<u8>, String> {
256     let size = src1.len();
257     let dest = cvec_with_size(size);
258     let ret = unsafe { imagefilter::SDL_imageFilterShiftRightUint(mem::transmute(src1.get(0)),
259                                                          mem::transmute(dest.get(0)),
260                                                          size as c_uint, n) };
261     if ret == 0 { Ok(dest) }
262     else { Err(get_error()) }
263 }
264 
265 /// Filter using `MultByByte`: D = saturation255(S * C).
mult_by_byte(src1: CVec<u8>, c: u8) -> Result<CVec<u8>, String>266 pub fn mult_by_byte(src1: CVec<u8>, c: u8) -> Result<CVec<u8>, String> {
267     let size = src1.len();
268     let dest = cvec_with_size(size);
269     let ret = unsafe { imagefilter::SDL_imageFilterMultByByte(mem::transmute(src1.get(0)),
270                                                      mem::transmute(dest.get(0)),
271                                                      size as c_uint, c) };
272     if ret == 0 { Ok(dest) }
273     else { Err(get_error()) }
274 }
275 
276 /// Filter using `ShiftRightAndMultByByte`: D = saturation255((S >> N) * C).
shift_right_and_mult_by_byte(src1: CVec<u8>, n: u8, c: u8) -> Result<CVec<u8>, String>277 pub fn shift_right_and_mult_by_byte(src1: CVec<u8>, n: u8, c: u8) -> Result<CVec<u8>, String> {
278     let size = src1.len();
279     let dest = cvec_with_size(size);
280     let ret = unsafe { imagefilter::SDL_imageFilterShiftRightAndMultByByte(mem::transmute(src1.get(0)),
281                                                                   mem::transmute(dest.get(0)),
282                                                                   size as c_uint, n, c) };
283     if ret == 0 { Ok(dest) }
284     else { Err(get_error()) }
285 }
286 
287 /// Filter using `ShiftLeftByte`: D = (S << N).
shift_left_byte(src1: CVec<u8>, n: u8) -> Result<CVec<u8>, String>288 pub fn shift_left_byte(src1: CVec<u8>, n: u8) -> Result<CVec<u8>, String> {
289     let size = src1.len();
290     let dest = cvec_with_size(size);
291     let ret = unsafe { imagefilter::SDL_imageFilterShiftLeftByte(mem::transmute(src1.get(0)),
292                                                         mem::transmute(dest.get(0)),
293                                                         size as c_uint, n) };
294     if ret == 0 { Ok(dest) }
295     else { Err(get_error()) }
296 }
297 
298 /// Filter using `ShiftLeftUint`: D = ((uint)S << N).
shift_left_uint(src1: CVec<u8>, n: u8) -> Result<CVec<u8>, String>299 pub fn shift_left_uint(src1: CVec<u8>, n: u8) -> Result<CVec<u8>, String> {
300     let size = src1.len();
301     let dest = cvec_with_size(size);
302     let ret = unsafe { imagefilter::SDL_imageFilterShiftLeftUint(mem::transmute(src1.get(0)),
303                                                         mem::transmute(dest.get(0)),
304                                                         size as c_uint, n) };
305     if ret == 0 { Ok(dest) }
306     else { Err(get_error()) }
307 }
308 
309 /// Filter `ShiftLeft`: D = saturation255(S << N).
shift_left(src1: CVec<u8>, n: u8) -> Result<CVec<u8>, String>310 pub fn shift_left(src1: CVec<u8>, n: u8) -> Result<CVec<u8>, String> {
311     let size = src1.len();
312     let dest = cvec_with_size(size);
313     let ret = unsafe { imagefilter::SDL_imageFilterShiftLeft(mem::transmute(src1.get(0)),
314                                                     mem::transmute(dest.get(0)),
315                                                     size as c_uint, n) };
316     if ret == 0 { Ok(dest) }
317     else { Err(get_error()) }
318 }
319 
320 /// Filter using `BinarizeUsingThreshold`: D = (S >= T) ? 255:0.
binarize_using_threshold(src1: CVec<u8>, t: u8) -> Result<CVec<u8>, String>321 pub fn binarize_using_threshold(src1: CVec<u8>, t: u8) -> Result<CVec<u8>, String> {
322     let size = src1.len();
323     let dest = cvec_with_size(size);
324     let ret = unsafe { imagefilter::SDL_imageFilterBinarizeUsingThreshold(mem::transmute(src1.get(0)),
325                                                                  mem::transmute(dest.get(0)),
326                                                                  size as c_uint, t) };
327     if ret == 0 { Ok(dest) }
328     else { Err(get_error()) }
329 }
330 
331 /// Filter using `ClipToRange`: D = (S >= Tmin) & (S <= Tmax) S:Tmin | Tmax.
clip_to_range(src1: CVec<u8>, tmin: u8, tmax: u8) -> Result<CVec<u8>, String>332 pub fn clip_to_range(src1: CVec<u8>, tmin: u8, tmax: u8) -> Result<CVec<u8>, String> {
333     let size = src1.len();
334     let dest = cvec_with_size(size);
335     let ret = unsafe { imagefilter::SDL_imageFilterClipToRange(mem::transmute(src1.get(0)),
336                                                       mem::transmute(dest.get(0)),
337                                                       size as c_uint, tmin, tmax) };
338     if ret == 0 { Ok(dest) }
339     else { Err(get_error()) }
340 }
341 
342 /// Filter using `NormalizeLinear`: D = saturation255((Nmax - Nmin)/(Cmax - Cmin)*(S - Cmin) + Nmin).
normalize_linear(src1: CVec<u8>, cmin: i32, cmax: i32, nmin: i32, nmax: i32) -> Result<CVec<u8>, String>343 pub fn normalize_linear(src1: CVec<u8>, cmin: i32, cmax: i32, nmin: i32, nmax: i32) -> Result<CVec<u8>, String> {
344     let size = src1.len();
345     let dest = cvec_with_size(size);
346     let ret = unsafe { imagefilter::SDL_imageFilterNormalizeLinear(mem::transmute(src1.get(0)),
347                                                           mem::transmute(dest.get(0)),
348                                                           size as c_uint,
349                                                           cmin as c_int, cmax as c_int,
350                                                           nmin as c_int, nmax as c_int) };
351     if ret == 0 { Ok(dest) }
352     else { Err(get_error()) }
353 }
354