БлогNot. Фильтрация изображений на Javascript

Фильтрация изображений на Javascript

Ниже показан пример обработки изображения фильтрами, описанными в Википедии. На серверной стороне средствами PHP нечто подобное делалось здесь.

Листинг может быть сохранён в файле типа .html, картинка для теста применялась стандартная.

Файл подключаемого к скрипту изображения должен быть локальным или загружаться через форму HTML, но не через внешний URL, иначе будет "Uncaught DOMException: The operation is insecure" на методе getImageData (или включите в своём домене CORS). Также скрипт должен выполняться на локалхосте, а не открываться кликом по локальному файлу (т.е., не выполняться по протоколу file://).

Конкретный фильтр в коде, конечно же, легко заменить:

Например, фильтру Gaussian blur 5 × 5 будет соответствовать матрица

[
 1/256, 4/256, 6/256, 4/256, 1/256,
 4/256, 16/256, 24/256, 16/256, 4/256,
 6/256, 24/256, 36/256, 24/256, 6/256,
 4/256, 16/256, 24/256, 16/256, 4/256,
 1/256, 4/256, 6/256, 4/256, 1/256
]

, переданная вторым аргументом функции convolve.

Вот исходник и результат тестового выполнения скрипта:

<p>Скрипт выполняется на локалхосте, а не по протоколу file://
<p>В текущей папке присутствует картинка Lenna.png
<script>
function convolve (imageIn, kernel, callback) { 
 //вернёт картинку, отсильтрованную с помощью kernel 
 //в callback-функцию function (Error error, Image imageOut)
let dim = Math.sqrt(kernel.length),
    pad = Math.floor(dim / 2);
 if (dim % 2 !== 1) { //Должна быть нечётная размерность
  return callback(new RangeError("Invalid kernel dimension"), null);
 }
 let w = imageIn.width,
     h = imageIn.height,
     can = document.createElement('canvas'),
     cw,
     ch,
     ctx,
     imgIn, imgOut,
     datIn, datOut;
 can.width = cw = w + pad * 2;
 can.height = ch = h + pad * 2; //добавлены отступы
 ctx = can.getContext('2d');
 ctx.fillStyle = '#000'; //начальное заполнение чёрным
 ctx.fillRect(0, 0, cw, ch);
 ctx.drawImage(imageIn, pad, pad);
 imgIn = ctx.getImageData(0, 0, cw, ch);
 datIn = imgIn.data;
 imgOut = ctx.createImageData(w, h);
 datOut = imgOut.data;
 let row, col, pix, i, dx, dy, r, g, b;
 for (row = pad; row <= h; row++) {
  for (col = pad; col <= w; col++) {
   r = g = b = 0;
   for (dx = -pad; dx <= pad; dx++) {
    for (dy = -pad; dy <= pad; dy++) {
     i = (dy + pad) * dim + (dx + pad); //индекс в фильтре
     pix = 4 * ((row + dy) * cw + (col + dx)); //индекс в картинке
     r += datIn[pix++] * kernel[i];
     g += datIn[pix++] * kernel[i];
     b += datIn[pix  ] * kernel[i];
    }
   }
   pix = 4 * ((row - pad) * w + (col - pad)); //индекс в целевой картинке
   datOut[pix++] = (r + .5) ^ 0;
   datOut[pix++] = (g + .5) ^ 0;
   datOut[pix++] = (b + .5) ^ 0;
   datOut[pix  ] = 255; //без прозрачности
  }
 }
 can.width = w;
 can.height = h; //ставим размеры канвы
 ctx.putImageData(imgOut, 0, 0);
 let imageOut = new Image();
 imageOut.addEventListener('load', function () {
  callback (null, imageOut);
 });
 imageOut.addEventListener('error', function (error) {
  callback(error, null);
 });
 imageOut.src = can.toDataURL('image/png');
}

//Как применять функцию, пример:
let image = new Image();

image.addEventListener ('load', function () { //Вызвать по загрузке картинки
 image.alt = 'Image is here!';
 document.body.appendChild(image);
 convolve (image, 
  [ 0, -1,  0,
   -1,  5, -1,
    0, -1,  0], // фильтр "Sharpen"
  function (error, result) {
   if (error !== null) console.error(error);
   else {
    result.alt = 'Filtered image';
    document.body.appendChild(result);
   }
  }
 );
});

image.src = './Lenna.png'; 
 //Файл Lenna.png должен находиться в текущей папке, 
 //см. http://blog.kislenko.net/show.php?id=2524
</script>
тестовое выполнение скрипта, скриншот автоматически сжат и утратил качество
тестовое выполнение скрипта, скриншот автоматически сжат и утратил качество

24.10.2021, 14:06 [751 просмотр]


теги: javascript графика

К этой статье пока нет комментариев, Ваш будет первым