First commit.

It filters the colours by doing matrix multiplication in JS on the pixel array. It could almost definitely be made faster using a WebGL shader.
This commit is contained in:
Christian Lawson-Perfect 2025-04-04 08:21:57 +00:00
commit e4ea0b0b99
6 changed files with 183 additions and 0 deletions

98
script.js Normal file
View file

@ -0,0 +1,98 @@
const img = document.querySelector('img');
function matmul(m,v) {
return m.map(r => r[0]*v[0] + r[1]*v[1] + r[2]*v[2]);
}
/* From https://www.inf.ufrgs.br/~oliveira/pubs_files/CVD_Simulation/CVD_Simulation.html#Tutorial
*/
const protan = [
[0.152286 , 1.052583 , -0.204868],
[0.114503 , 0.786281 , 0.099216],
[-0.003882 , -0.048116 , 1.051998],
];
const deuteran = [
[0.367322 , 0.860646 , -0.227968],
[0.280085 , 0.672501 , 0.047413],
[-0.011820 , 0.042940 , 0.968881],
]
const tritan = [
[1.255528 , -0.076749 , -0.178779],
[-0.078411 , 0.930809 , 0.147602],
[0.004733 , 0.691367 , 0.303900],
];
async function filter(canvas, matrix) {
const {naturalWidth, naturalHeight} = img;
const width = Math.min(2*img.width, naturalWidth);
const height = naturalHeight/naturalWidth * width;
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img,0,0,width,height);
const {data} = ctx.getImageData(0,0,width,height);
for(let i=0;i<data.length;i+=4) {
const v = data.slice(i,i+3);
const [r,g,b] = matmul(matrix, v);
data[i] = r;
data[i+1] = g;
data[i+2] = b;
}
const nimagedata = new ImageData(data,width,height);
ctx.putImageData(nimagedata,0,0);
}
async function go() {
console.log('loaded');
const sims = {
protan, deuteran, tritan
}
console.log(img.width, img.height);
Object.entries(sims).forEach(async ([k,m]) => {
const canvas = document.getElementById(k).querySelector('canvas');
const blob = await filter(canvas, m);
sim_img.src = URL.createObjectURL(blob);
})
}
if(img.complete) {
go();
} else {
img.addEventListener('load', go, {once:true});
}
document.body.addEventListener('dragover', e => {
e.preventDefault();
e.stopPropagation();
})
function load_file(file) {
img.src = URL.createObjectURL(file);
img.addEventListener('load', go, {once:true});
}
document.body.addEventListener('drop', e => {
e.preventDefault();
e.stopPropagation();
const [file] = e.dataTransfer.files;
if(!file) {
return;
}
load_file(file);
})
document.getElementById('file').addEventListener('change', ({target}) => {
const [file] = target.files;
console.log(file);
if(!file) {
return;
}
load_file(file);
})