use {
Result,
backend::{Backend, BackendImpl, ImageData},
error::QuicksilverError,
file::load_file,
futures::{Future, future},
geom::{Rectangle, Transform, Vector},
image,
std::{
error::Error,
fmt,
io::Error as IOError,
path::Path,
rc::Rc
}
};
#[derive(Debug, Eq, PartialEq, Hash)]
pub enum PixelFormat {
RGB,
RGBA
}
#[derive(Clone, Debug)]
pub struct Image {
source: Rc<ImageData>,
region: Rectangle,
}
impl Image {
pub(crate) fn new(data: ImageData) -> Image {
let region = Rectangle::new_sized((data.width, data.height));
Image {
source: Rc::new(data),
region
}
}
pub fn load<P: AsRef<Path>>(path: P) -> impl Future<Item = Image, Error = QuicksilverError> {
load_file(path)
.map(|data| Image::from_bytes(data.as_slice()))
.and_then(future::result)
}
pub(crate) fn new_null(width: u32, height: u32, format: PixelFormat) -> Result<Image> {
Image::from_raw(&[], width, height, format)
}
pub fn from_raw(data: &[u8], width: u32, height: u32, format: PixelFormat) -> Result<Image> {
Ok(unsafe {
Image::new(BackendImpl::create_texture(data, width, height, format)?)
})
}
pub fn from_bytes(raw: &[u8]) -> Result<Image> {
let img = image::load_from_memory(raw)?.to_rgba();
let width = img.width();
let height = img.height();
Image::from_raw(img.into_raw().as_slice(), width, height, PixelFormat::RGBA)
}
#[cfg(target_arch="wasm32")]
pub(crate) fn data(&self) -> &ImageData {
&self.source
}
pub(crate) fn get_id(&self) -> u32 {
self.source.id
}
pub(crate) fn source_width(&self) -> u32 {
self.source.width
}
pub(crate) fn source_height(&self) -> u32 {
self.source.height
}
pub fn area(&self) -> Rectangle {
self.region
}
pub fn subimage(&self, rect: Rectangle) -> Image {
Image {
source: self.source.clone(),
region: Rectangle::new(
(
self.region.pos.x + rect.pos.x,
self.region.pos.y + rect.pos.y
),
(
rect.width(),
rect.height()
)
)
}
}
pub fn projection(&self, region: Rectangle) -> Transform {
let source_size: Vector = (self.source_width(), self.source_height()).into();
let recip_size = source_size.recip();
let normalized_pos = self.region.top_left().times(recip_size);
let normalized_size = self.region.size().times(recip_size);
Transform::translate(normalized_pos)
* Transform::scale(normalized_size)
* Transform::scale(region.size().recip())
* Transform::translate(-region.top_left())
}
}
#[derive(Debug)]
pub enum ImageError {
DecodingError(image::ImageError),
IOError(IOError)
}
#[doc(hidden)]
impl From<IOError> for ImageError {
fn from(err: IOError) -> ImageError {
ImageError::IOError(err)
}
}
#[doc(hidden)]
impl From<image::ImageError> for ImageError {
fn from(img: image::ImageError) -> ImageError {
ImageError::DecodingError(img)
}
}
impl fmt::Display for ImageError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.description())
}
}
impl Error for ImageError {
fn description(&self) -> &str {
match self {
&ImageError::DecodingError(ref err) => err.description(),
&ImageError::IOError(ref err) => err.description(),
}
}
fn cause(&self) -> Option<&dyn Error> {
match self {
&ImageError::DecodingError(ref err) => Some(err),
&ImageError::IOError(ref err) => Some(err),
}
}
}