use std::error::FromError;
use std::mem;
use std::io;
use std::slice;
use std::iter::repeat;
use color;
use color::ColorType;
use buffer::{ImageBuffer, Pixel};
use traits::Primitive;
use animation::{Frame, Frames};
use dynimage::decoder_to_image;
#[derive(Show, PartialEq, Eq)]
pub enum ImageError {
FormatError(String),
DimensionError,
UnsupportedError(String),
UnsupportedColor(ColorType),
NotEnoughData,
IoError(io::IoError),
ImageEnd
}
impl FromError<io::IoError> for ImageError {
fn from_error(err: io::IoError) -> ImageError {
ImageError::IoError(err)
}
}
pub type ImageResult<T> = Result<T, ImageError>;
pub enum DecodingResult {
U8(Vec<u8>),
U16(Vec<u16>)
}
pub enum DecodingBuffer<'a> {
U8(&'a mut [u8]),
U16(&'a mut [u16])
}
#[derive(Copy, PartialEq, Eq, Show)]
pub enum ImageFormat {
PNG,
JPEG,
GIF,
WEBP,
PPM,
TIFF,
TGA
}
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 is_animated(&mut self) -> ImageResult<bool> {
return Ok(false)
}
fn into_frames(self) -> ImageResult<Frames> {
Ok(Frames::new(vec![
Frame::new(try!(decoder_to_image(self)).to_rgba())
]))
}
fn read_scanline(&mut self, buf: &mut [u8]) -> ImageResult<u32>;
fn read_image(&mut self) -> ImageResult<DecodingResult>;
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 = repeat(0u8).take(length as usize * width as usize * bpp).collect::<Vec<u8>>();
let mut tmp = repeat(0u8).take(rowlen).collect::<Vec<u8>>();
loop {
let row = try!(self.read_scanline(tmp.as_mut_slice()));
if row - 1 == y {
break
}
}
for i in range(0, length as usize) {
{
let from = tmp.slice_from(x as usize * bpp)
.slice_to(width as usize * bpp);
let to = buf.slice_from_mut(i * width as usize * bpp)
.slice_to_mut(width as usize * bpp);
slice::bytes::copy_memory(to, from);
}
let _ = try!(self.read_scanline(tmp.as_mut_slice()));
}
Ok(buf)
}
}
pub struct Pixels<'a, I:'a> {
image: &'a I,
x: u32,
y: u32,
width: u32,
height: u32
}
#[old_impl_check]
impl<'a, T: Primitive, P: Pixel<T>, I: GenericImage<P>> Iterator for Pixels<'a, I> {
type Item = (u32, u32, P);
fn next(&mut self) -> Option<(u32, u32, P)> {
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)
}
}
}
#[deprecated = "It is currently not possible to create a safe iterator for this in Rust. You have to use an iterator over the image buffer instead."]
pub struct MutPixels<'a, I:'a> {
image: &'a mut I,
x: u32,
y: u32,
width: u32,
height: u32
}
#[old_impl_check]
impl<'a, T: Primitive, P: Pixel<T>, I: GenericImage<P>> Iterator for MutPixels<'a, I> {
type Item = (u32, u32, &'a mut P);
fn next(&mut self) -> Option<(u32, u32, &'a mut P)> {
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<P>: Sized {
fn dimensions(&self) -> (u32, u32);
fn bounds(&self) -> (u32, u32, u32, u32);
fn get_pixel(&self, x: u32, y: u32) -> P;
fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut P;
fn put_pixel(&mut self, x: u32, y: u32, pixel: P);
#[deprecated = "This method will be removed. Blend the pixel directly instead."]
fn blend_pixel(&mut self, x: u32, y: u32, pixel: P);
fn pixels(&self) -> Pixels<Self> {
let (width, height) = self.dimensions();
Pixels {
image: self,
x: 0,
y: 0,
width: width,
height: height,
}
}
#[allow(deprecated)]
#[deprecated = "This cannot be implemented safely Rust. Please use the image buffer directly."]
fn pixels_mut(&mut self) -> MutPixels<Self> {
let (width, height) = self.dimensions();
MutPixels {
image: self,
x: 0,
y: 0,
width: width,
height: height,
}
}
}
pub struct SubImage <'a, I:'a> {
image: &'a mut I,
xoffset: u32,
yoffset: u32,
xstride: u32,
ystride: u32,
}
#[old_impl_check]
impl<'a, T: Primitive + 'static, P: Pixel<T> + 'static, I: GenericImage<P>> SubImage<'a, I> {
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<Vec<T>, T, P> {
let mut out = ImageBuffer::new(self.xstride, self.ystride);
for y in range(0, self.ystride) {
for x in range(0, self.xstride) {
let p = self.get_pixel(x, y);
out.put_pixel(x, y, p);
}
}
out
}
}
#[allow(deprecated)]
#[old_impl_check]
impl<'a, T: Primitive, P: Pixel<T>, I: GenericImage<P>> GenericImage<P> for SubImage<'a, I> {
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) -> P {
self.image.get_pixel(x + self.xoffset, y + self.yoffset)
}
fn put_pixel(&mut self, x: u32, y: u32, pixel: P) {
self.image.put_pixel(x + self.xoffset, y + self.yoffset, pixel)
}
#[deprecated = "This method will be removed. Blend the pixel directly instead."]
fn blend_pixel(&mut self, x: u32, y: u32, pixel: P) {
self.image.blend_pixel(x + self.xoffset, y + self.yoffset, pixel)
}
fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut P {
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]
#[allow(deprecated)]
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]));
}
}