brightness adjustment; find closest palette colour; tests

This commit is contained in:
Max Bradbury 2020-11-06 12:35:37 +00:00
parent 03588c4c55
commit 4bd896f05a
2 changed files with 137 additions and 15 deletions

View File

@ -6,6 +6,7 @@ import init, {
load_game,
load_default_game,
output,
set_brightness,
set_dither,
set_room_name,
} from './pkg/pixsy.js';
@ -70,6 +71,7 @@ async function run() {
const buttonNewGame = el("new");
const buttonReset = el("reset");
const checkboxDither = el("dither");
const inputBrightness = el("brightness");
const inputRoomName = el("room-name");
const selectPalette = el("palette");
const textareaGameDataInput = el("game-data");
@ -171,12 +173,18 @@ async function run() {
checkboxDither.addEventListener("change", () => {
set_dither(checkboxDither.checked);
loadPreview();
});
inputRoomName.addEventListener("change", () => {
set_room_name(inputRoomName.value);
});
inputBrightness.addEventListener("input", () => {
set_brightness(inputBrightness.value);
loadPreview();
});
function addRoom() {
console.log(add_room());
textareaGameDataOutput.value = output();

View File

@ -1,3 +1,5 @@
#![feature(clamp)]
use bitsy_parser::game::Game;
use bitsy_parser::image::Image;
use bitsy_parser::tile::Tile;
@ -15,6 +17,7 @@ struct State {
room_name: Option<String>,
palette: Option<String>,
dither: bool,
brightness: i32,
}
lazy_static! {
@ -25,6 +28,7 @@ lazy_static! {
room_name: None,
palette: None,
dither: true,
brightness: 0,
}
);
}
@ -117,6 +121,12 @@ pub fn set_room_name(room_name: String) {
}
}
#[wasm_bindgen]
pub fn set_brightness(brightness: i32) {
let mut state = STATE.lock().unwrap();
state.brightness = brightness;
}
#[wasm_bindgen]
pub fn get_palettes() -> String {
let state = STATE.lock().unwrap();
@ -146,15 +156,54 @@ fn image_to_base64(image: &DynamicImage) -> String {
format!("data:image/png;base64,{}", base64::encode(&bytes))
}
fn render_preview(image: &DynamicImage) -> DynamicImage {
let image = image.clone();
let image = image.grayscale();
fn colour_difference(compare: image::Rgba<u8>, other: &bitsy_parser::Colour) -> u32 {
let diff_red = (compare[0] as i16 - other.red as i16).abs();
let diff_green= (compare[1] as i16 - other.green as i16).abs();
let diff_blue = (compare[2] as i16 - other.blue as i16).abs();
(diff_red + diff_green + diff_blue) as u32
}
fn closest_colour(compare: image::Rgba<u8>, colours: &[bitsy_parser::Colour]) -> image::Rgba<u8> {
let diff_background = colour_difference(compare, &colours[0]);
let diff_foreground = colour_difference(compare, &colours[1]);
if diff_foreground <= diff_background {
image::Rgba::from([colours[1].red, colours[1].green, colours[1].blue, 255])
} else {
image::Rgba::from([colours[0].red, colours[0].green, colours[0].blue, 255])
}
}
fn adjust_brightness(pixel: &mut image::Rgba<u8>, state: &State) -> image::Rgba<u8> {
pixel[0] = (pixel[0] as i32 + state.brightness).clamp(0, 255) as u8;
pixel[1] = (pixel[1] as i32 + state.brightness).clamp(0, 255) as u8;
pixel[2] = (pixel[2] as i32 + state.brightness).clamp(0, 255) as u8;
*pixel
}
fn render_preview(state: &State) -> DynamicImage {
let image = state.image.as_ref().unwrap().clone();
let mut preview = image.clone();
// todo dither
// todo convert to palette colours
image
// get background and foreground colours from palette
let colours = &state.game.as_ref().unwrap().palettes
.iter()
.find(|palette| &palette.id == state.palette.as_ref().unwrap())
.unwrap()
.colours[0..2];
for (x, y, mut pixel) in image.pixels() {
// is pixel closer to background or foreground?
preview.put_pixel(x, y, closest_colour(adjust_brightness(&mut pixel, &state), colours));
}
preview
}
#[wasm_bindgen]
@ -162,7 +211,7 @@ pub fn get_preview() -> String {
let state = STATE.lock().unwrap();
match &state.image.is_some() {
true => image_to_base64(&render_preview(state.image.as_ref().unwrap())),
true => image_to_base64(&render_preview(&state)),
false => "".to_string(),
}
}
@ -238,6 +287,7 @@ pub fn output() -> String {
#[cfg(test)]
mod test {
use crate::{add_room, load_image, load_default_game, output, get_preview};
use image::Rgba;
#[test]
fn image_to_base64() {
@ -247,6 +297,70 @@ mod test {
assert_eq!(output, expected);
}
#[test]
fn colour_difference_none() {
let output = crate::colour_difference(
Rgba::from([255; 4]),
&bitsy_parser::Colour {
red: 255,
green: 255,
blue: 255
}
);
assert_eq!(output, 0);
}
#[test]
fn colour_difference_some() {
let output = crate::colour_difference(
Rgba::from([255; 4]),
&bitsy_parser::Colour {
red: 254,
green: 255,
blue: 255
}
);
assert_eq!(output, 1);
}
#[test]
fn colour_difference_some_2() {
let output = crate::colour_difference(
Rgba::from([254; 4]),
&bitsy_parser::Colour {
red: 254,
green: 255,
blue: 254
}
);
assert_eq!(output, 1);
}
#[test]
fn colour_difference_max() {
let expected = 255 * 3;
let output = crate::colour_difference(
Rgba::from([0; 4]),
&bitsy_parser::Colour {
red: 255,
green: 255,
blue: 255
}
);
assert_eq!(output, expected);
let output = crate::colour_difference(
Rgba::from([255; 4]),
&bitsy_parser::Colour {
red: 0,
green: 0,
blue: 0
}
);
assert_eq!(output, expected);
}
#[test]
fn get_palettes() {
load_default_game();