extern crate png;
extern crate sdl2;
use sdl2::pixels::{Color, PixelFormatEnum};
use sdl2::render::{BlendMode, Canvas};
use sdl2::video::Window;
use self::png::{ColorType, Decoder, DecodingError};
use std::io::Read;
use drawable::{DrawSettings, Drawable, KnownSize, Position, State};
#[derive(Clone)]
pub struct PngImage {
pub width: usize,
pub height: usize,
pub data: Vec<u8>,
}
impl PngImage {
pub fn load_from_path<R: Read>(r: R) -> Result<Self, DecodingError> {
PngImage::load_from_path_transform(r, |x| x)
}
pub fn load_from_path_transform<R: Read, F: Fn(Color) -> Color>(
r: R,
transform: F,
) -> Result<Self, DecodingError> {
let (info, mut reader) = Decoder::new(r).read_info()?;
let (width, height) = (info.width as usize, info.height as usize);
let mut data = vec![0; width * height * 4];
for y in 0..height {
if let Some(row) = reader.next_row()? {
assert_eq!(row.len(), width * info.color_type.samples());
for (x, col) in row.chunks(info.color_type.samples()).enumerate() {
let sdl_col = match info.color_type {
ColorType::RGB => Color::RGB(col[0], col[1], col[2]),
ColorType::RGBA => Color::RGBA(col[0], col[1], col[2], col[3]),
_ => unimplemented!(),
};
let sdl_col = transform(sdl_col);
data[(y * width + x) * 4] = sdl_col.r;
data[(y * width + x) * 4 + 1] = sdl_col.g;
data[(y * width + x) * 4 + 2] = sdl_col.b;
data[(y * width + x) * 4 + 3] = sdl_col.a;
}
}
}
Ok(PngImage {
width,
height,
data,
})
}
}
impl Drawable for PngImage {
fn content(&self) -> Vec<&dyn Drawable> {
vec![]
}
fn content_mut(&mut self) -> Vec<&mut dyn Drawable> {
vec![]
}
fn draw(&self, canvas: &mut Canvas<Window>, pos: &Position, _settings: DrawSettings) {
let creator = canvas.texture_creator();
let mut texture = creator
.create_texture_target(
Some(PixelFormatEnum::ABGR8888),
self.width as u32,
self.height as u32,
)
.expect("Can't make texture");
texture.set_blend_mode(BlendMode::Blend);
texture
.update(None, self.data.as_slice(), 4 * self.width)
.expect("Can't update");
let rect = pos.into_rect_with_size_unbounded(self.width as u32, self.height as u32);
canvas.copy(&texture, None, rect).expect("Can't copy");
}
fn step(&mut self) {}
fn state(&self) -> State {
State::Final
}
}
pub trait ImageContainer: KnownSize + Sized {
fn get_data(&self) -> &Vec<u8>;
fn get_data_mut(&mut self) -> &mut Vec<u8>;
fn into_data(self) -> Vec<u8>;
fn as_knownsize(&self) -> &dyn KnownSize {
self
}
}
impl KnownSize for PngImage {
fn width(&self) -> usize {
self.width
}
fn height(&self) -> usize {
self.height
}
}
impl ImageContainer for PngImage {
fn get_data(&self) -> &Vec<u8> {
&self.data
}
fn get_data_mut(&mut self) -> &mut Vec<u8> {
&mut self.data
}
fn into_data(self) -> Vec<u8> {
self.data
}
}