#[cfg(feature = "image")]
use crate::error::{Error, Result};
#[cfg(feature = "image")]
use crate::image_data::{ImageData, PixelData};
#[cfg(feature = "image")]
use image::{DynamicImage, GrayImage, ImageBuffer, Luma};
type Gray16Image = ImageBuffer<Luma<u16>, Vec<u16>>;
#[cfg(feature = "image")]
impl ImageData {
pub fn to_dynamic_image(&self, bscale: f64, bzero: f64) -> Result<DynamicImage> {
let width = self
.width()
.ok_or_else(|| Error::InvalidFormat("need at least 1 axis".into()))?
as u32;
let height = self.height().unwrap_or(1) as u32;
match &self.pixels {
PixelData::U8(data) => {
let img = GrayImage::from_raw(width, height, data.clone())
.ok_or_else(|| Error::InvalidFormat("image dimensions mismatch".into()))?;
Ok(DynamicImage::ImageLuma8(img))
}
PixelData::I16(data) => {
let pixels: Vec<u16> =
if (bzero - 32768.0).abs() < 0.5 && (bscale - 1.0).abs() < 1e-10 {
data.iter().map(|&v| (v as i32 + 32768) as u16).collect()
} else {
data.iter()
.map(|&v| (bzero + bscale * v as f64).clamp(0.0, 65535.0) as u16)
.collect()
};
let img = Gray16Image::from_raw(width, height, pixels)
.ok_or_else(|| Error::InvalidFormat("image dimensions mismatch".into()))?;
Ok(DynamicImage::ImageLuma16(img))
}
_ => {
let scaled = self.scaled_values(bscale, bzero);
let (min, max) = scaled
.iter()
.fold((f64::MAX, f64::MIN), |(mn, mx), &v| (mn.min(v), mx.max(v)));
let range = if (max - min).abs() < 1e-30 {
1.0
} else {
max - min
};
let pixels: Vec<u16> = scaled
.iter()
.map(|&v| ((v - min) / range * 65535.0) as u16)
.collect();
let img = Gray16Image::from_raw(width, height, pixels)
.ok_or_else(|| Error::InvalidFormat("image dimensions mismatch".into()))?;
Ok(DynamicImage::ImageLuma16(img))
}
}
}
pub fn from_dynamic_image(img: &DynamicImage) -> Result<(Self, f64, f64)> {
match img {
DynamicImage::ImageLuma8(gray) => {
let (w, h) = gray.dimensions();
let data = gray.as_raw().clone();
Ok((
ImageData::new(vec![w as usize, h as usize], PixelData::U8(data)),
1.0,
0.0,
))
}
DynamicImage::ImageLuma16(gray16) => {
let (w, h) = gray16.dimensions();
let pixels: Vec<i16> = gray16
.as_raw()
.iter()
.map(|&v| (v as i32 - 32768) as i16)
.collect();
Ok((
ImageData::new(vec![w as usize, h as usize], PixelData::I16(pixels)),
1.0,
32768.0,
))
}
other => {
let gray16 = other.to_luma16();
let (w, h) = gray16.dimensions();
let pixels: Vec<i16> = gray16
.as_raw()
.iter()
.map(|&v| (v as i32 - 32768) as i16)
.collect();
Ok((
ImageData::new(vec![w as usize, h as usize], PixelData::I16(pixels)),
1.0,
32768.0,
))
}
}
}
}