use std::mem::size_of;
use std::slice::from_raw_parts;
#[cfg(feature = "image")]
use image::{ImageBuffer, Pixel};
use xiapi_sys::XI_IMG;
pub struct Image<'a, T> {
pub(crate) xi_img: XI_IMG,
pub(crate) pix_type: std::marker::PhantomData<&'a T>,
}
impl<'a, T> Image<'a, T> {
pub fn pixel(&self, x: usize, y: usize) -> Option<&T> {
let buffer = self.xi_img.bp as *const u8;
if buffer.is_null() {
return None;
}
if x >= self.xi_img.width as usize || y >= self.xi_img.height as usize {
return None;
}
let nb_channels = self.nb_channels();
let stride = self.xi_img.width as usize * size_of::<T>() * nb_channels
+ self.xi_img.padding_x as usize;
let offset = (stride * y) + (x * size_of::<T>() * nb_channels);
unsafe {
let pixel_pointer = buffer.add(offset) as *const T;
pixel_pointer.as_ref()
}
}
pub fn width(&self) -> u32 {
self.xi_img.width
}
pub fn height(&self) -> u32 {
self.xi_img.height
}
pub fn format(&self) -> xiapi_sys::XI_IMG_FORMAT::Type {
self.xi_img.frm
}
pub fn nframe(&self) -> u32 {
self.xi_img.nframe
}
pub fn black_level(&self) -> u32 {
self.xi_img.black_level
}
pub fn padding_x(&self) -> u32 {
self.xi_img.padding_x
}
pub fn absolute_offset_x(&self) -> u32 {
self.xi_img.AbsoluteOffsetX
}
pub fn absolute_offset_y(&self) -> u32 {
self.xi_img.AbsoluteOffsetY
}
pub fn transport_format(&self) -> xiapi_sys::XI_IMG_FORMAT::Type {
self.xi_img.transport_frm
}
pub fn downsampling_x(&self) -> u32 {
self.xi_img.DownsamplingX
}
pub fn downsampling_y(&self) -> u32 {
self.xi_img.DownsamplingY
}
pub fn exposure_time_us(&self) -> u32 {
self.xi_img.exposure_time_us
}
pub fn acq_nframe(&self) -> u32 {
self.xi_img.acq_nframe
}
pub fn image_user_data(&self) -> u32 {
self.xi_img.image_user_data
}
pub fn timestamp_raw(&self) -> u64 {
let high = self.xi_img.tsSec as u64;
let low = self.xi_img.tsUSec as u64;
(high << 32) | low
}
pub fn data(&'a self) -> &'a [T] {
unsafe {
if self.xi_img.bp_size != 0 {
let length = self.xi_img.bp_size as usize / size_of::<T>();
from_raw_parts(self.xi_img.bp as *const T, length)
}
else {
let length = self.xi_img.width as usize * self.xi_img.height as usize * self.nb_channels();
from_raw_parts(self.xi_img.bp as *const T, length)
}
}
}
fn nb_channels(&self) -> usize
{
match self.xi_img.frm {
xiapi_sys::XI_IMG_FORMAT::XI_MONO8 => 1,
xiapi_sys::XI_IMG_FORMAT::XI_MONO16 => 1,
xiapi_sys::XI_IMG_FORMAT::XI_RAW8 => 1,
xiapi_sys::XI_IMG_FORMAT::XI_RAW16 => 1,
xiapi_sys::XI_IMG_FORMAT::XI_RGB24 => 3,
xiapi_sys::XI_IMG_FORMAT::XI_RGB32 => 4,
_ => 0,
}
}
}
unsafe impl<'a,T> Send for Image<'a, T>{
}
#[cfg(feature = "image")]
impl<P> From<Image<'_, P::Subpixel>> for ImageBuffer<P, Vec<P::Subpixel>>
where
P: Pixel,
{
fn from(image: Image<P::Subpixel>) -> Self {
let data = Vec::from(image.data());
match Self::from_raw(image.width(), image.height(), data) {
None => panic!("Failed to create image from raw pointer"),
Some(buffer) => buffer,
}
}
}