use std::cmp;
use error::{RasterError, RasterResult};
use Image;
use Color;
#[derive(Debug)]
pub enum BlurMode {
Box,
Gaussian
}
pub fn blur(mut src: &mut Image, mode: BlurMode) -> RasterResult<()>{
match mode {
BlurMode::Box => blur_box(src),
BlurMode::Gaussian => blur_gaussian(src)
}
}
pub fn brightness(mut src: &mut Image, factor: f32) -> RasterResult<()>{
let w: i32 = src.width;
let h: i32 = src.height;
for y in 0..h {
for x in 0..w {
let p = try!(src.get_pixel(x, y));
let r = cmp::max(0, cmp::min(255, (p.r as f32 * factor) as i32));
let g = cmp::max(0, cmp::min(255, (p.g as f32 * factor) as i32));
let b = cmp::max(0, cmp::min(255, (p.b as f32 * factor) as i32));
let a = cmp::max(0, cmp::min(255, (p.a as f32 * factor) as i32));
try!(src.set_pixel(x, y, Color::rgba(r as u8, g as u8, b as u8, a as u8)));
}
}
Ok(())
}
pub fn convolve(src: &mut Image, matrix: [[i32; 3]; 3], divisor: i32) -> RasterResult<()> {
let w: i32 = src.width;
let h: i32 = src.height;
let m_size = 3;
let copy = src.clone();
for y in 0..h {
for x in 0..w {
let mstarty = y - 1;
let mstartx = x - 1;
let mut accum_red: i32 = 0;
let mut accum_green: i32 = 0;
let mut accum_blue: i32 = 0;
let mut accum_alpha: i32 = 0;
for (m_index_y, mut src_y) in (0..).zip(mstarty..mstarty + m_size) {
if src_y < 0 {
src_y = 0;
} else if src_y > h - 1 {
src_y = h - 1;
}
for (m_index_x, mut src_x) in (0..).zip(mstartx..mstartx + m_size) {
if src_x < 0 {
src_x = 0;
} else if src_x > w - 1 {
src_x = w - 1;
}
let pixel = try!(copy.get_pixel(src_x, src_y));
accum_red += pixel.r as i32 * matrix[m_index_y][m_index_x];
accum_green += pixel.g as i32 * matrix[m_index_y][m_index_x];
accum_blue += pixel.b as i32 * matrix[m_index_y][m_index_x];
accum_alpha += pixel.a as i32 * matrix[m_index_y][m_index_x];
}
}
if divisor != 1 {
accum_red /= divisor;
accum_green /= divisor;
accum_blue /= divisor;
accum_alpha /= divisor;
}
if accum_red < 0 {
accum_red = 0;
}
if accum_green < 0 {
accum_green = 0;
}
if accum_blue < 0 {
accum_blue = 0;
}
if accum_alpha < 0 {
accum_alpha = 0;
}
if accum_red > 255 {
accum_red = 255;
}
if accum_green > 255 {
accum_green = 255;
}
if accum_blue > 255 {
accum_blue = 255;
}
if accum_alpha > 255 {
accum_alpha = 255;
}
try!(src.set_pixel(x, y, Color::rgba(accum_red as u8, accum_green as u8, accum_blue as u8, accum_alpha as u8)));
}
}
Ok(())
}
pub fn emboss(mut src: &mut Image) -> RasterResult<()>{
let matrix: [[i32; 3]; 3] = [
[-2, -1, 0],
[-1, 1, 1],
[0, 1, 2]
];
convolve(src, matrix, 1)
}
pub fn gamma(mut src: &mut Image, gamma: f32) -> RasterResult<()>{
let w: i32 = src.width;
let h: i32 = src.height;
if gamma < 0.01 || gamma > 9.99 {
return Err(RasterError::InvalidGamma(gamma));
}
let gamma = 1.0 / gamma;
for y in 0..h {
for x in 0..w {
let p = try!(src.get_pixel(x, y));
let r = (p.r as f32 / 255.0).powf(gamma) * 255.0;
let g = (p.g as f32 / 255.0).powf(gamma) * 255.0;
let b = (p.b as f32 / 255.0).powf(gamma) * 255.0;
let a = (p.a as f32 / 255.0).powf(gamma) * 255.0;
try!(src.set_pixel(x, y, Color::rgba(r as u8, g as u8, b as u8, a as u8)));
}
}
Ok(())
}
pub fn grayscale(mut src: &mut Image) -> RasterResult<()>{
let w: i32 = src.width;
let h: i32 = src.height;
for y in 0..h {
for x in 0..w {
let p = try!(src.get_pixel(x, y));
let gray = (p.r as f32 * 0.3) + (p.g as f32 * 0.59) + (p.b as f32 * 0.11);
try!(src.set_pixel(x, y, Color::rgba(gray as u8, gray as u8, gray as u8, gray as u8)));
}
}
Ok(())
}
pub fn saturation(mut src: &mut Image, sat: f32) -> RasterResult<()>{
let w: i32 = src.width;
let h: i32 = src.height;
for y in 0..h {
for x in 0..w {
let p = try!(src.get_pixel(x, y));
let hsv = Color::to_hsv(p.r, p.g, p.b);
let s = hsv.1;
let factor = (100.0 - s) * sat; let mut new_s = s + factor;
if new_s > 100.0 {
new_s = 100.0;
} else if new_s < 0.0 {
new_s = 0.0;
}
let rgb = Color::to_rgb(hsv.0, new_s, hsv.2);
try!(src.set_pixel(x, y, Color::rgb(rgb.0, rgb.1, rgb.2)));
}
}
Ok(())
}
pub fn sharpen(mut src: &mut Image) -> RasterResult<()>{
let matrix: [[i32; 3]; 3] = [
[0, -1, 0],
[-1, 5,-1],
[0, -1, 0]
];
convolve(src, matrix, 1)
}
fn blur_box(mut src: &mut Image) -> RasterResult<()>{
let matrix: [[i32; 3]; 3] = [
[1,1,1],
[1,1,1],
[1,1,1]
];
convolve(src, matrix, 9)
}
fn blur_gaussian(mut src: &mut Image) -> RasterResult<()>{
let matrix: [[i32; 3]; 3] = [
[1,2,1],
[2,4,2],
[1,2,1]
];
convolve(src, matrix, 16)
}