I'm trying to implement Floyd-Steinberg dithering in a P5.js sketch by pre-dithering a bunch of circles in a graphics object (in setup) and then drawing them later.
However, I keep running into the issue where only part of the circle is dithered, and the rest looks normal. Any suggestions are welcome as I'm really stumped as to what is going on.
setup()
:
let circs;
function setup() {
//...
createCanvas(1000,1000);
let size = 200;
circs = [];
circs.push({
gfx: createGraphics(size, size),
size: size,
color: color(random(255))
});
for (let i = 0; i < circs.length; i++)
dither(circs[i]);
// ...
}
draw()
:
function draw() {
if (!paused) {
background(bg);
drawShadow(4); // just a call to the drawingContext shadow
for (let i = 0; i < circs.length; i++) {
push();
translate(width / 2, height / 2);
imageMode(CENTER);
image(circs[i].gfx, 0, 0);
pop();
}
}
}
floyd-steinberg - based on https://openprocessing.org/sketch/1192123
function index(x, y, g) {
return (x + y * g.width) * 4;
}
function dither(g) {
g.loadPixels();
for (let y = 0; y < g.height - 1; y++) {
for (let x = 1; x < g.width - 1; x++) {
let oldr = g.pixels[index(x, y, g)];
let oldg = g.pixels[index(x, y, g) + 1];
let oldb = g.pixels[index(x, y, g) + 2];
let factor = 1.0;
let newr = round((factor * oldr) / 255) * (255 / factor);
let newg = round((factor * oldg) / 255) * (255 / factor);
let newb = round((factor * oldb) / 255) * (255 / factor);
g.pixels[index(x, y, g)] = newr;
g.pixels[index(x, y, g) + 1] = newg;
g.pixels[index(x, y, g) + 2] = newb;
g.pixels[index(x + 1, y, g)] += ((oldr - newr) * 7) / 16.0;
g.pixels[index(x + 1, y, g) + 1] += ((oldr - newr) * 7) / 16.0;
g.pixels[index(x + 1, y, g) + 2] += ((oldr - newr) * 7) / 16.0;
g.pixels[index(x - 1, y + 1, g)] += ((oldr - newr) * 3) / 16.0;
g.pixels[index(x - 1, y + 1, g) + 1] += ((oldr - newr) * 3) / 16.0;
g.pixels[index(x - 1, y + 1, g) + 2] += ((oldr - newr) * 3) / 16.0;
g.pixels[index(x, y + 1, g)] += ((oldr - newr) * 5) / 16.0;
g.pixels[index(x, y + 1, g) + 1] += ((oldr - newr) * 5) / 16.0;
g.pixels[index(x, y + 1, g) + 2] += ((oldr - newr) * 5) / 16.0;
g.pixels[index(x + 1, y + 1, g)] += ((oldr - newr) * 1) / 16.0;
g.pixels[index(x + 1, y + 1, g) + 1] += ((oldr - newr) * 1) / 16.0;
g.pixels[index(x + 1, y + 1, g) + 2] += ((oldr - newr) * 1) / 16.0;
}
}
g.updatePixels();
}
I'm not sure what I'm missing as the dithering algorithm loops over the height and width and then should be updating, but I think I'm missing something.