use std::fmt;
use std::mem;
use std::io;
use std::error::Error;
use color;
use color::ColorType;
use buffer::{ImageBuffer, Pixel};
use animation::{Frame, Frames};
use dynimage::decoder_to_image;
#[derive(Debug)]
pub enum ImageError {
FormatError(String),
DimensionError,
UnsupportedError(String),
UnsupportedColor(ColorType),
NotEnoughData,
IoError(io::Error),
ImageEnd
}
impl fmt::Display for ImageError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
ImageError::FormatError(ref e) => write!(fmt, "Format error: {}", e),
ImageError::DimensionError => write!(fmt, "The Image's dimensions are either too \
small or too large"),
ImageError::UnsupportedError(ref f) => write!(fmt, "The Decoder does not support the \
image format `{}`", f),
ImageError::UnsupportedColor(ref c) => write!(fmt, "The decoder does not support \
the color type `{:?}`", c),
ImageError::NotEnoughData => write!(fmt, "Not enough data was provided to the \
Decoder to decode the image"),
ImageError::IoError(ref e) => e.fmt(fmt),
ImageError::ImageEnd => write!(fmt, "The end of the image has been reached")
}
}
}
impl Error for ImageError {
fn description (&self) -> &str {
match *self {
ImageError::FormatError(..) => "Format error",
ImageError::DimensionError => "Dimension error",
ImageError::UnsupportedError(..) => "Unsupported error",
ImageError::UnsupportedColor(..) => "Unsupported color",
ImageError::NotEnoughData => "Not enough data",
ImageError::IoError(..) => "IO error",
ImageError::ImageEnd => "Image end"
}
}
fn cause (&self) -> Option<&Error> {
match *self {
ImageError::IoError(ref e) => Some(e),
_ => None
}
}
}
impl From<io::Error> for ImageError {
fn from(err: io::Error) -> ImageError {
ImageError::IoError(err)
}
}
pub type ImageResult<T> = Result<T, ImageError>;
#[derive(Debug)]
pub enum DecodingResult {
U8(Vec<u8>),
U16(Vec<u16>)
}
pub enum DecodingBuffer<'a> {
U8(&'a mut [u8]),
U16(&'a mut [u16])
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum ImageFormat {
PNG,
JPEG,
GIF,
WEBP,
#[deprecated(since="0.17.0", note="Use the more general `PNM`")]
PPM,
PNM,
TIFF,
TGA,
BMP,
ICO,
HDR,
}
pub trait ImageDecoder: Sized {
fn dimensions(&mut self) -> ImageResult<(u32, u32)>;
fn colortype(&mut self) -> ImageResult<ColorType>;
fn row_len(&mut self) -> ImageResult<usize>;
fn read_scanline(&mut self, buf: &mut [u8]) -> ImageResult<u32>;
fn read_image(&mut self) -> ImageResult<DecodingResult>;
fn is_animated(&mut self) -> ImageResult<bool> {
Ok(false)
}
fn into_frames(self) -> ImageResult<Frames> {
Ok(Frames::new(vec![
Frame::new(try!(decoder_to_image(self)).to_rgba())
]))
}
fn load_rect(&mut self, x: u32, y: u32, length: u32, width: u32) -> ImageResult<Vec<u8>> {
let (w, h) = try!(self.dimensions());
if length > h || width > w || x > w || y > h {
return Err(ImageError::DimensionError)
}
let c = try!(self.colortype());
let bpp = color::bits_per_pixel(c) / 8;
let rowlen = try!(self.row_len());
let mut buf = vec![0u8; length as usize * width as usize * bpp];
let mut tmp = vec![0u8; rowlen];
loop {
let row = try!(self.read_scanline(&mut tmp));
if row - 1 == y {
break
}
}
for i in 0..length as usize {
{
let from = &tmp[x as usize * bpp..width as usize * bpp];
let to = &mut buf[i * width as usize * bpp..width as usize * bpp];
::copy_memory(from, to);
}
let _ = try!(self.read_scanline(&mut tmp));
}
Ok(buf)
}
}
pub struct Pixels<'a, I: 'a> {
image: &'a I,
x: u32,
y: u32,
width: u32,
height: u32
}
impl<'a, I: GenericImage> Iterator for Pixels<'a, I> {
type Item = (u32, u32, I::Pixel);
fn next(&mut self) -> Option<(u32, u32, I::Pixel)> {
if self.x >= self.width {
self.x = 0;
self.y += 1;
}
if self.y >= self.height {
None
} else {
let pixel = self.image.get_pixel(self.x, self.y);
let p = (self.x, self.y, pixel);
self.x += 1;
Some(p)
}
}
}
pub struct MutPixels<'a, I: 'a> {
image: &'a mut I,
x: u32,
y: u32,
width: u32,
height: u32
}
impl<'a, I: GenericImage + 'a> Iterator for MutPixels<'a, I>
where I::Pixel: 'a,
<I::Pixel as Pixel>::Subpixel: 'a {
type Item = (u32, u32, &'a mut I::Pixel);
fn next(&mut self) -> Option<(u32, u32, &'a mut I::Pixel)> {
if self.x >= self.width {
self.x = 0;
self.y += 1;
}
if self.y >= self.height {
None
} else {
let tmp = self.image.get_pixel_mut(self.x, self.y);
let ptr = unsafe {
mem::transmute(tmp)
};
let p = (self.x, self.y, ptr);
self.x += 1;
Some(p)
}
}
}
pub trait GenericImage: Sized {
type Pixel: Pixel;
fn dimensions(&self) -> (u32, u32);
fn width(&self) -> u32 {
let (w, _) = self.dimensions();
w
}
fn height(&self) -> u32 {
let (_, h) = self.dimensions();
h
}
fn bounds(&self) -> (u32, u32, u32, u32);
fn in_bounds(&self, x: u32, y: u32) -> bool {
let (ix, iy, iw, ih) = self.bounds();
x >= ix && x < ix + iw && y >= iy && y < iy + ih
}
fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel;
fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut Self::Pixel;
unsafe fn unsafe_get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
self.get_pixel(x, y)
}
fn put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel);
unsafe fn unsafe_put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
self.put_pixel(x, y, pixel);
}
fn blend_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel);
fn pixels(&self) -> Pixels<Self> {
let (width, height) = self.dimensions();
Pixels {
image: self,
x: 0,
y: 0,
width: width,
height: height,
}
}
fn pixels_mut(&mut self) -> MutPixels<Self> {
let (width, height) = self.dimensions();
MutPixels {
image: self,
x: 0,
y: 0,
width: width,
height: height,
}
}
fn copy_from<O>(&mut self, other: &O, x: u32, y:u32) -> bool
where O: GenericImage<Pixel=Self::Pixel> {
if self.width() < other.width() + x || self.height() < other.height() + y {
return false;
}
for i in 0 .. other.width() {
for k in 0 .. other.height() {
unsafe {
let p = other.unsafe_get_pixel(i, k);
self.unsafe_put_pixel(i + x, k + y, p);
}
}
}
true
}
fn sub_image(&mut self, x: u32, y: u32, width: u32, height: u32)
-> SubImage<Self>
where Self: 'static, <Self::Pixel as Pixel>::Subpixel: 'static,
Self::Pixel: 'static {
SubImage::new(self, x, y, width, height)
}
}
pub struct SubImage <'a, I: 'a> {
image: &'a mut I,
xoffset: u32,
yoffset: u32,
xstride: u32,
ystride: u32,
}
impl<'a, I: GenericImage + 'static> SubImage<'a, I>
where I::Pixel: 'static,
<I::Pixel as Pixel>::Subpixel: 'static {
pub fn new(image: &mut I, x: u32, y: u32, width: u32, height: u32) -> SubImage<I> {
SubImage {
image: image,
xoffset: x,
yoffset: y,
xstride: width,
ystride: height,
}
}
pub fn inner_mut(&mut self) -> &mut I {
&mut (*self.image)
}
pub fn change_bounds(&mut self, x: u32, y: u32, width: u32, height: u32) {
self.xoffset = x;
self.yoffset = y;
self.xstride = width;
self.ystride = height;
}
pub fn to_image(&self) -> ImageBuffer<I::Pixel, Vec<<I::Pixel as Pixel>::Subpixel>> {
let mut out = ImageBuffer::new(self.xstride, self.ystride);
for y in 0..self.ystride {
for x in 0..self.xstride {
let p = self.get_pixel(x, y);
out.put_pixel(x, y, p);
}
}
out
}
}
#[allow(deprecated)]
impl<'a, I: GenericImage + 'static> GenericImage for SubImage<'a, I>
where I::Pixel: 'static,
<I::Pixel as Pixel>::Subpixel: 'static {
type Pixel = I::Pixel;
fn dimensions(&self) -> (u32, u32) {
(self.xstride, self.ystride)
}
fn bounds(&self) -> (u32, u32, u32, u32) {
(self.xoffset, self.yoffset, self.xstride, self.ystride)
}
fn get_pixel(&self, x: u32, y: u32) -> I::Pixel {
self.image.get_pixel(x + self.xoffset, y + self.yoffset)
}
fn put_pixel(&mut self, x: u32, y: u32, pixel: I::Pixel) {
self.image.put_pixel(x + self.xoffset, y + self.yoffset, pixel)
}
fn blend_pixel(&mut self, x: u32, y: u32, pixel: I::Pixel) {
self.image.blend_pixel(x + self.xoffset, y + self.yoffset, pixel)
}
fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut I::Pixel {
self.image.get_pixel_mut(x + self.xoffset, y + self.yoffset)
}
}
#[cfg(test)]
mod tests {
use super::GenericImage;
use buffer::ImageBuffer;
use color::{Rgba};
#[test]
fn test_image_alpha_blending() {
let mut target = ImageBuffer::new(1, 1);
target.put_pixel(0, 0, Rgba([255u8, 0, 0, 255]));
assert!(*target.get_pixel(0, 0) == Rgba([255, 0, 0, 255]));
target.blend_pixel(0, 0, Rgba([0, 255, 0, 255]));
assert!(*target.get_pixel(0, 0) == Rgba([0, 255, 0, 255]));
target.blend_pixel(0, 0, Rgba([255, 0, 0, 127]));
assert!(*target.get_pixel(0, 0) == Rgba([127, 127, 0, 255]));
target.put_pixel(0, 0, Rgba([0, 255, 0, 127]));
target.blend_pixel(0, 0, Rgba([255, 0, 0, 127]));
assert!(*target.get_pixel(0, 0) == Rgba([169, 85, 0, 190]));
}
#[test]
fn test_in_bounds() {
let mut target = ImageBuffer::new(2, 2);
target.put_pixel(0, 0, Rgba([255u8, 0, 0, 255]));
assert!(target.in_bounds(0,0));
assert!(target.in_bounds(1,0));
assert!(target.in_bounds(0,1));
assert!(target.in_bounds(1,1));
assert!(!target.in_bounds(2,0));
assert!(!target.in_bounds(0,2));
assert!(!target.in_bounds(2,2));
}
}