use libc;
use std::{self, ffi, str};
use failure::Error;
pub enum OpenSlideT {}
#[link(name="openslide")]
extern {
fn openslide_detect_vendor(
filename: *const libc::c_char
) -> *const libc::c_char;
fn openslide_open(
filename: *const libc::c_char
) -> *const OpenSlideT;
fn openslide_close(
osr: *const OpenSlideT
) -> libc::c_void;
fn openslide_get_level_count(
osr: *const OpenSlideT
) -> libc::int32_t;
fn openslide_get_level0_dimensions(
osr: *const OpenSlideT,
w: *mut libc::int64_t,
h: *mut libc::int64_t
) -> libc::c_void;
fn openslide_get_level_dimensions(
osr: *const OpenSlideT,
level: libc::int32_t,
w: *mut libc::int64_t,
h: *mut libc::int64_t
) -> libc::c_void;
fn openslide_get_level_downsample(
osr: *const OpenSlideT,
level: libc::int32_t
) -> libc::c_double;
fn openslide_get_best_level_for_downsample(
slide: *const OpenSlideT,
downsample_factor: libc::c_double
) -> libc::int32_t;
fn openslide_read_region(
osr: *const OpenSlideT,
dest: *mut libc::uint32_t,
x: libc::int64_t,
y: libc::int64_t,
level: libc::int32_t,
w: libc::int64_t,
h: libc::int64_t
) -> libc::c_void;
fn openslide_get_property_names(
osr: *const OpenSlideT
) -> *const *const libc::c_char;
fn openslide_get_property_value(
osr: *const OpenSlideT,
name: *const libc::c_char
) -> *const libc::c_char;
}
pub fn detect_vendor(
filename: &str
) -> Result<String, Error> {
let c_filename = ffi::CString::new(filename)?;
let vendor = unsafe {
let c_vendor = openslide_detect_vendor(c_filename.as_ptr());
ffi::CStr::from_ptr(c_vendor).to_string_lossy().into_owned()
};
Ok(vendor)
}
pub fn open(
filename: &str
) -> Result<*const OpenSlideT, Error> {
let c_filename = ffi::CString::new(filename)?;
let slide = unsafe {
openslide_open(c_filename.as_ptr())
};
Ok(slide)
}
pub fn close(
osr: *const OpenSlideT
) {
unsafe {
openslide_close(osr);
}
}
pub fn get_level_count(
osr: *const OpenSlideT
) -> Result<i32, Error> {
let num_levels = unsafe {
openslide_get_level_count(osr)
};
Ok(num_levels)
}
pub fn get_level0_dimensions(
osr: *const OpenSlideT
) -> Result<(i64, i64), Error> {
let mut width: libc::int64_t = 0;
let mut height: libc::int64_t = 0;
unsafe {
openslide_get_level0_dimensions(osr, &mut width, &mut height);
}
Ok((width, height))
}
pub fn get_level_dimensions(
osr: *const OpenSlideT,
level: i32
) -> Result<(i64, i64), Error> {
let mut width: libc::int64_t = 0;
let mut height: libc::int64_t = 0;
unsafe {
openslide_get_level_dimensions(osr, level, &mut width, &mut height);
}
Ok((width, height))
}
pub fn get_level_downsample(
osr: *const OpenSlideT,
level: i32
) -> Result<f64, Error> {
let downsampling_factor = unsafe {
openslide_get_level_downsample(osr, level)
};
Ok(downsampling_factor)
}
pub fn get_best_level_for_downsample(
osr: *const OpenSlideT,
downsample: f64
) -> Result<i32, Error> {
let level = unsafe {
openslide_get_best_level_for_downsample(osr, downsample)
};
Ok(level)
}
pub fn read_region(
osr: *const OpenSlideT,
x: i64,
y: i64,
level: i32,
w: i64,
h: i64
) -> Result<Vec<u32>, Error> {
let mut buffer: Vec<libc::uint32_t> = Vec::with_capacity((h * w) as usize);
unsafe {
let p_buffer = buffer.as_mut_ptr();
openslide_read_region(osr, p_buffer, x, y, level, w, h);
buffer.set_len((h * w) as usize);
}
Ok(buffer)
}
pub fn get_property_names(
osr: *const OpenSlideT
) -> Result<Vec<String>, Error> {
let string_values = unsafe {
let null_terminated_array_ptr = openslide_get_property_names(osr);
let mut counter = 0;
let mut loc = null_terminated_array_ptr;
while *loc != std::ptr::null() {
counter += 1;
loc = loc.offset(1);
}
let values = std::slice::from_raw_parts(null_terminated_array_ptr, counter as usize);
values.iter()
.map(|&p| ffi::CStr::from_ptr(p) ) .map(|cs| cs.to_bytes()) .map(|bs| str::from_utf8(bs).unwrap()) .map(|ss| ss.to_owned())
.collect()
};
Ok(string_values)
}
pub fn get_property_value(
osr: *const OpenSlideT,
name: &str
) -> Result<String, Error> {
let c_name = ffi::CString::new(name)?;
let value = unsafe {
let c_value = openslide_get_property_value(osr, c_name.as_ptr());
ffi::CStr::from_ptr(c_value).to_string_lossy().into_owned()
};
Ok(value)
}