3

Можно ли создать на canvas библиотеке Konva.js (или на каком-то другом) blur эффект на фото при mousemove?

Читал документацию к Konva js, но ничего подходящего не нашел. Искал примеры, достойных примеров не нашел.

Вот пример с встроенным фильтром в canvas ctx.filter = 'blur(5px)';.

1 Answers1

4

Конечно можно было бы взять библиотеку, но и вручную можно добится неплохих результатов, а заодно и познакомится поближе с обработкой изображений.

Это решение использунт прямые манипуляции с пикселями.

Применяем ко всем пикселям области, которую необходимо заблюрить, так называемое "ядро свертки" (convolution kernel) - основа основ в обработке изображений.

Вот тут подробно про это написано а так же визуализировано

Запустите сниппет заново, если картинка не показательная (они псевдослучайные), в сниппете реализовано рисование блюром, как Вы просили в комментариях...

let s = 44; // size of area to be blurred
let kernel =[[0,0,1,0,0],
             [0,1,2,1,0],
             [1,2,3,2,1],
             [0,1,2,1,0],
             [0,0,1,0,0]];

let ctx = canvas.getContext('2d'); let total = kernel.flatMap(i => i).reduce((a, i) => a + Math.abs(i)), ks = (kernel.length-1)/2, // half of kernel size - 1 (pixels around center) s2 = s/2, // half size of area to be blurred sks2 = s+ks*2; // size of area of pixels needed to be processed

img.onload = e => ctx.drawImage(img, 0, 0); addEventListener('mousedown', e => draw = true) addEventListener('mouseup', e => draw = false) addEventListener('mousemove', e => { if (!window.draw) return; var input = ctx.getImageData(e.layerX-s2-ks, e.layerY-s2-ks, sks2, sks2); var output = ctx.createImageData(s, s); for (var x = 0; x < s; x++) for (var y = 0; y < s; y++) handlePixel(input, output, x, y) ctx.putImageData(output, e.layerX - s2, e.layerY - s2) })

function handlePixel(i, o, x, y) { let offset = (y * s + x) * 4; // offset in output data (4=rgba) for (var kx = -ks; kx <= ks; kx++) for (var ky = -ks; ky <= ks; ky++) { let off = ((y+ks) * sks2 + (x+ks) + kx + ky * sks2) * 4; //offset in input for (var n = 0; n < 3; n++) o.data[offset + n] += kernel[kx+ks][ky+ks] * i.data[off+n] / total; } o.data[offset + 3] = 255; // always opaque }

<canvas id="canvas" width="500" height="500"></canvas>
<img id="img" src="https://picsum.photos/500/500" crossOrigin="anonymous">
<style>body{margin:0}img {display:none;}</style>

PS: от бага по краям надо подумать как избавиться...