use super::*;
#[cfg(test)]
mod tests;
#[derive(Clone, Debug)]
pub struct Image<T> {
pub width: i32,
pub height: i32,
pub data: Vec<T>,
}
impl<T: Copy> Image<T> {
#[inline]
pub fn len(&self) -> usize {
(self.width as i64 * self.height as i64) as usize
}
#[inline]
pub fn new(width: i32, height: i32, fill: T) -> Image<T> {
let len = (width as i64 * height as i64) as usize;
Image {
width,
height,
data: vec![fill; len],
}
}
#[inline]
pub fn from_raw(width: i32, height: i32, data: Vec<T>) -> Image<T> {
let len = (width as i64 * height as i64) as usize;
assert_eq!(data.len(), len);
Image { width, height, data }
}
#[inline]
pub fn map_colors<U, F: FnMut(T) -> U>(self, f: F) -> Image<U> {
let data = self.data.into_iter().map(f).collect();
Image {
width: self.width,
height: self.height,
data,
}
}
#[inline]
pub fn transmute<U: dataview::Pod>(self) -> Image<U> where T: dataview::Pod {
assert_eq!(mem::size_of::<T>(), mem::size_of::<U>());
assert_eq!(mem::align_of::<T>(), mem::align_of::<U>());
Image {
width: self.width,
height: self.height,
data: unsafe { mem::transmute(self.data) },
}
}
#[inline]
pub fn as_bytes(&self) -> &[u8] where T: dataview::Pod {
dataview::bytes(&*self.data)
}
#[inline]
pub fn row(&self, y: i32) -> Option<&[T]> {
self.row_span(y, 0, self.width)
}
#[inline]
pub fn row_span(&self, y: i32, x_start: i32, x_end: i32) -> Option<&[T]> {
if y < 0 || y >= self.height {
return None;
}
if !(x_start >= 0 && x_end <= self.width && x_start <= x_end) {
return None;
}
let start = (y as i64 * self.width as i64 + x_start as i64) as usize;
let end = start + (x_end - x_start) as usize;
self.data.get(start..end)
}
#[inline]
pub fn row_mut(&mut self, y: i32) -> Option<&mut [T]> {
let width = self.width;
self.row_span_mut(y, 0, width)
}
#[inline]
pub fn row_span_mut(&mut self, y: i32, x_start: i32, x_end: i32) -> Option<&mut [T]> {
if y < 0 || y >= self.height {
return None;
}
if !(x_start >= 0 && x_end <= self.width && x_start <= x_end) {
return None;
}
let start = (y as i64 * self.width as i64 + x_start as i64) as usize;
let end = start + (x_end - x_start) as usize;
self.data.get_mut(start..end)
}
#[inline]
pub fn sub_image(&self, x: i32, y: i32, width: i32, height: i32) -> Option<Image<T>> {
if width < 0 || height < 0 {
return None;
}
if x < 0 || y < 0 || x + width > self.width || y + height > self.height {
return None;
}
let mut data = Vec::with_capacity((width as i64 * height as i64) as usize);
for row in 0..height {
let src_row = self.row_span(y + row, x, x + width).unwrap();
data.extend_from_slice(src_row);
}
Some(Image { width, height, data })
}
#[inline]
pub fn index(&self, x: i32, y: i32) -> Option<usize> {
if x < 0 || x >= self.width || y < 0 || y >= self.height {
return None;
}
Some((y as i64 * self.width as i64 + x as i64) as usize)
}
#[inline]
pub fn read(&self, x: i32, y: i32) -> Option<T> {
let index = self.index(x, y)?;
self.data.get(index).copied()
}
#[inline]
pub fn write(&mut self, x: i32, y: i32, value: T) {
if let Some(index) = self.index(x, y) {
if let Some(p) = self.data.get_mut(index) {
*p = value;
}
}
}
}
fn load_file<T>(path: &path::Path) -> Result<Image<T>, LoadImageError> where Image<T>: From<DecodedImage> {
#![allow(unused_variables)]
let ext = path.extension().and_then(|s| s.to_str());
#[cfg(feature = "png")]
if ext == Some("png") {
return Image::load_file_png(path).map_err(Into::into);
}
#[cfg(feature = "gif")]
if ext == Some("gif") {
return Image::load_file_gif(path).map_err(Into::into);
}
#[cfg(feature = "jpeg")]
if ext == Some("jpg") || ext == Some("jpeg") {
return Image::load_file_jpeg(path).map_err(Into::into);
}
Err(LoadImageError::UnsupportedFormat)
}
fn load_memory<T>(data: &[u8]) -> Result<Image<T>, LoadImageError> where Image<T>: From<DecodedImage> {
#![allow(unused_variables)]
#[cfg(feature = "png")]
if data.starts_with(io::png::PNG_SIGNATURE) {
return Image::load_memory_png(data).map_err(Into::into);
}
#[cfg(feature = "gif")]
if data.starts_with(io::gif::GIF_SIGNATURE_87A) || data.starts_with(io::gif::GIF_SIGNATURE_89A) {
return Image::load_memory_gif(data).map_err(Into::into);
}
#[cfg(feature = "jpeg")]
if data.starts_with(io::jpeg::JPEG_SIGNATURE) {
return Image::load_memory_jpeg(data).map_err(Into::into);
}
Err(LoadImageError::UnsupportedFormat)
}
impl<T> Image<T> where Image<T>: From<DecodedImage> {
#[inline]
pub fn load_file(path: impl AsRef<path::Path>) -> Result<Self, LoadImageError> {
load_file(path.as_ref())
}
#[inline]
pub fn load_memory(data: &[u8]) -> Result<Self, LoadImageError> {
load_memory(data)
}
}
pub type ImageRGB = Image<[u8; 3]>;
pub type ImageRGBA = Image<[u8; 4]>;