Last active
November 6, 2020 02:51
-
-
Save 74togo/6443667 to your computer and use it in GitHub Desktop.
An example of the Floyd–Steinberg applied to images in Javascript.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<title>Dithering Test</title> | |
</head> | |
<body> | |
<canvas></canvas> | |
<script> | |
var canvas = document.getElementsByTagName("canvas")[0]; | |
var ctx = canvas.getContext('2d'); | |
var id = ctx.getImageData(0, 0, 1, 1); | |
var img; | |
var image_data; | |
id.data[3] = 255; | |
function clip(x) { | |
return x < 0 ? 0 : (x > 255 ? 255 : x) | |
} | |
function setPixel(x, y, color) { | |
var index = (x + y * image_data.width) * 4; | |
image_data.data[index+0] = parseInt(color[0]+0.5); | |
image_data.data[index+1] = parseInt(color[1]+0.5); | |
image_data.data[index+2] = parseInt(color[2]+0.5); | |
image_data.data[index+3] = 255; | |
} | |
function color_diff(one, two) { | |
return [(one[0] - two[0]), (one[1] - two[1]), (one[2] - two[2])]; | |
} | |
function color_add_err(x, y, err_red, err_green, err_blue) { | |
var index = (x + y * image_data.width) * 4; | |
image_data.data[index+0] = clip(image_data.data[index+0]+err_red) | |
image_data.data[index+1] = clip(image_data.data[index+1]+err_green) | |
image_data.data[index+2] = clip(image_data.data[index+2]+err_blue) | |
image_data.data[index+3] = 255; | |
} | |
function find_closest_palette_color(pixel) { | |
return (0.2126*pixel[0] + 0.7152*pixel[1] + 0.0722*pixel[2]) > 128 ? [255,255,255] : [0,0,0]; | |
} | |
function get_pixel(x, y) { | |
var index = (x + y * image_data.width) * 4; | |
return [ image_data.data[index+0], image_data.data[index+1], image_data.data[index+2] ]; | |
} | |
function rgb2bin(img_name) { | |
img = new Image(); | |
img.src = img_name; | |
img.onload = function(){ | |
canvas.height = img.height; | |
canvas.width = img.width; | |
ctx.drawImage(img, 0, 0, img.width, img.height); | |
image_data = ctx.getImageData(0, 0, img.width, img.height); | |
var oldpixel; | |
var newpixel; | |
var quant_error; | |
var err_red, err_green, err_blue; | |
for (var y = 0; y < img.height; y++) { | |
for (var x = 0; x < img.width; x++) { | |
oldpixel = get_pixel(x, y); | |
newpixel = find_closest_palette_color(oldpixel); | |
setPixel(x, y, newpixel); | |
quant_error = color_diff(oldpixel, newpixel); | |
err_red = quant_error[0]; | |
err_green = quant_error[1]; | |
err_blue = quant_error[2]; | |
if (x+1 < img.width) | |
color_add_err(x+1, y, (7/16) * err_red, (7/16) * err_green, (7/16) * err_blue); | |
if (x-1 > 0 && y+1 < img.height) | |
color_add_err(x-1, y+1, (3/16) * err_red, (3/16) * err_green, (3/16) * err_blue); | |
if (y+1 < img.height) | |
color_add_err(x, y+1, (5/16) * err_red, (5/16) * err_green, (5/16) * err_blue); | |
if (x+1 < img.width) | |
color_add_err(x+1, y+1, (1/16) * err_red, (1/16) * err_green, (1/16) * err_blue); | |
} | |
} | |
ctx.putImageData(image_data, 0, 0); | |
} | |
} | |
document.body.onload = function(){rgb2bin(prompt("Enter image location"));} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note, sharpening an image before doing this makes it look better.