use std::io;
use std::path::Path;
use std::fs::File;
use std::io::{BufWriter, BufReader};
use crate::pcolorvalue::PColorMap;
pub struct PImage{
width: usize,
height: usize,
vec_rgba: Vec<u8>,
}
impl PImage {
pub fn new(width: usize, height: usize) -> Self{
PImage {
width: width,
height: height,
vec_rgba: vec![0; width*height*4]
}
}
pub fn from(filename: &Path) -> Self{
let mut image: PImage = PImage { width: 0, height: 0, vec_rgba: vec![] };
image.read(filename).unwrap();
return image;
}
pub fn get_width(&self) -> usize{
self.width
}
pub fn get_height(&self) -> usize{
self.height
}
pub fn set_color(&mut self, vec_data: &Vec<f32>, colormap: &PColorMap){
assert_eq!(self.width*self.height, vec_data.len());
for i in 0..self.height{
for j in 0..self.width{
let index: usize = i*self.width + j;
let color = colormap.interpolate(*vec_data.get(index).unwrap());
self.set_component(index*4, color.0);
self.set_component(index*4 + 1, color.1);
self.set_component(index*4 + 2, color.2);
self.set_component(index*4 + 3, color.3);
}
}
}
pub fn set_rgba(&mut self, windex: usize, hindex: usize, r: u8, g: u8, b: u8, a: u8){
if windex > self.width {
panic!("PImage::set_rgba : index on width = {} greater than image width = {}", windex, self.width);
}
if hindex > self.height {
panic!("PImage::set_rgba : index on height = {} greater than image height = {}", hindex, self.height);
}
let index = (hindex*self.width + windex)*4;
self.set_component(index, r);
self.set_component(index + 1, g);
self.set_component(index + 2, b);
self.set_component(index + 3, a);
}
fn set_component(&mut self, index: usize, value: u8){
match self.vec_rgba.get_mut(index) {
Some(pixel) => *pixel = value,
None => {}
}
}
pub fn write(&self, filename: &Path) -> io::Result<()>{
let file = File::create(filename)?;
let ref mut w = BufWriter::new(file);
let mut encoder = png::Encoder::new(w, self.width as u32, self.height as u32);
encoder.set_color(png::ColorType::Rgba);
encoder.set_depth(png::BitDepth::Eight);
encoder.set_source_gamma(png::ScaledFloat::from_scaled(45455)); let source_chromaticities = png::SourceChromaticities::new( (0.31270, 0.32900),
(0.64000, 0.33000),
(0.30000, 0.60000),
(0.15000, 0.06000)
);
encoder.set_source_chromaticities(source_chromaticities);
let mut writer = encoder.write_header().unwrap();
writer.write_image_data(&self.vec_rgba)?; Ok(())
}
pub fn read(&mut self, filename: &Path) -> io::Result<()>{
let decoder = png::Decoder::new(BufReader::new(File::open(filename).unwrap()));
let mut reader = decoder.read_info().unwrap();
let mut buf = vec![0; reader.output_buffer_size().unwrap()];
let info = reader.next_frame(&mut buf).unwrap();
*self = PImage::new(info.width as usize, info.height as usize);
let bytes = &buf[..info.buffer_size()];
self.vec_rgba = bytes.to_vec();
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
use std::path::PathBuf;
#[test]
fn test_pimage_write() {
fs::create_dir_all("generated").unwrap();
let filename = PathBuf::from("generated/image.png");
let image: PImage = PImage::new(100, 50);
image.write(&filename).unwrap();
let other: PImage = PImage::from(&filename);
assert_eq!(other.get_width(), 100);
assert_eq!(other.get_height(), 50);
}
#[test]
fn test_pimage_set_pixel(){
fs::create_dir_all("generated").unwrap();
let filename = PathBuf::from("generated/set_pixel.png");
let mut image: PImage = PImage::new(250, 200);
for j in 0..image.get_height() {
for i in 0..image.get_width() {
let g: u8 = (i % 255) as u8;
let b: u8 = (j % 255) as u8;
image.set_rgba(i, j, 12, g, b, 255);
}
}
image.write(&filename).unwrap();
}
#[test]
fn test_set_color(){
fs::create_dir_all("generated").unwrap();
let filename = PathBuf::from("generated/set_color.png");
let vec_data: Vec<f32> = (0..250*200).into_iter().map(|index| ((index as f32)*0.025).cos().powf(2.0)*0.6).collect::<Vec<_>>();
let mut image: PImage = PImage::new(250, 200);
let colormap: PColorMap = PColorMap::gray_scott();
image.set_color(&vec_data, &colormap);
image.write(&filename).unwrap();
}
}