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:
commit
e4ea0b0b99
6 changed files with 183 additions and 0 deletions
98
script.js
Normal file
98
script.js
Normal 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);
|
||||
})
|
Loading…
Add table
Add a link
Reference in a new issue