Published
Edited
Jan 8, 2021
35 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
floydsteinberg = {
//*

function diffuseError(mydata, r, c, error, factor){
var idx = rowcol2index(r, c, w, h);
mydata[idx+0] = Math.max(Math.min(mydata[idx+0] + factor*error.r,255),0);
mydata[idx+1] = Math.max(Math.min(mydata[idx+1] + factor*error.g,255),0);
mydata[idx+2] = Math.max(Math.min(mydata[idx+2] + factor*error.b,255),0);
return(mydata)
}
var w = mywidth;
var h = Math.floor(image.height*mywidth/image.width);
var context = DOM.context2d(w, h);
var imgData = context.createImageData(w, h);
var dithered = [];
for (var ii=0; ii<raw_rgba.length; ii++){
imgData.data[ii] = raw_rgba[ii];
dithered.push(raw_rgba[ii]);
}

var paletteIDs = [];
for (var ii=0; ii<dithered.length; ii+=4){
var RC = index2rowcol(ii, w, h);
var myRow = RC.r;
var myCol = RC.c;
// oldpixel := pixel[x][y]
var thisRawColor = d3.rgb(dithered[ii+0],
dithered[ii+1],
dithered[ii+2]);
// newpixel := find_closest_palette_color(oldpixel)
var closeColorID = FindClosestColorIDFrom(colorPalette, thisRawColor);
var thisPalleteColor = d3.rgb(colorPalette[closeColorID]);
paletteIDs.push(closeColorID)
dithered[ii+0] = thisPalleteColor.r;
dithered[ii+1] = thisPalleteColor.g;
dithered[ii+2] = thisPalleteColor.b;
dithered[ii+3] = 255;
// quant_error := oldpixel - newpixel
var quant_error = {r:(thisRawColor.r-thisPalleteColor.r),
g:(thisRawColor.g-thisPalleteColor.g),
b:(thisRawColor.b-thisPalleteColor.b)}

if ((myRow<(h-2))&(myCol<(w-2))&(myCol>(1))){
dithered = diffuseError(dithered, myRow+0, myCol+1, quant_error, 7/48); // this is so f***ing cool
dithered = diffuseError(dithered, myRow+0, myCol+2, quant_error, 5/48); //
dithered = diffuseError(dithered, myRow+1, myCol-2, quant_error, 3/48); // basically we take the error
dithered = diffuseError(dithered, myRow+1, myCol-1, quant_error, 5/48); // in how close we came
dithered = diffuseError(dithered, myRow+1, myCol+0, quant_error, 7/48); // to approximating true color
dithered = diffuseError(dithered, myRow+1, myCol+1, quant_error, 5/48); // and we add
dithered = diffuseError(dithered, myRow+1, myCol+2, quant_error, 3/48); // (a portion of) that delta
dithered = diffuseError(dithered, myRow+2, myCol-2, quant_error, 1/48); // to the nearby pixels
dithered = diffuseError(dithered, myRow+2, myCol-1, quant_error, 3/48); //
dithered = diffuseError(dithered, myRow+2, myCol+0, quant_error, 5/48); // how cool is that
dithered = diffuseError(dithered, myRow+2, myCol+1, quant_error, 3/48); //
dithered = diffuseError(dithered, myRow+2, myCol+2, quant_error, 1/48); // and it works
}
} // end of pixel by pixel FOR loop
//
for (var ii=0; ii<dithered.length; ii++){
imgData.data[ii] = dithered[ii];
}
return({rgba: imgData.data, paletteData: paletteIDs})
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
GIF = {
const [gif, workerScript] = await Promise.all([
require("gif.js@0.2"),
require.resolve("gif.js@0.2/dist/gif.worker.js")
.then(fetch)
.then(response => response.blob())
.then(blob => URL.createObjectURL(blob, {type: "text/javascript"}))
]);
return class extends gif {
constructor(options) {
super({workerScript, ...options});
}
};
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more