📜 ⬆️ ⬇️

Web Workers work with Canvas

main idea


In the process of studying the methods of multi-threaded image processing in the browser, many face the problem of displaying the result of Web Workers on canvas. This is mainly due to the fact that DOM elements cannot be passed to the web worker. The solution might be to use getImageData () . This article describes a specific example of the use of this technology on the example of processing the blur filter in a separate stream.

For this we need 2 files: index.html and filter_worker.js

Page layout


In index.html, you need to place one canvas element, a form for specifying the blur radius and a span in which we will record the current process of filter operation in percent.
HTML
<!DOCTYPE html> <html> <head> <title>Web Worker</title> <style> #my_canvas { border: #00ff00 solid 1px; } </style> </head> <body> <form> <input type="text" id="radius" value="5" /> <input type="button" onclick="draw('my_canvas')" value="Draw" /> </form><br> <canvas id="my_canvas" width="200" height="200"></canvas><br> <span id="load_info"></span> </body> </html> 



Javascript


Add a javascript function in which we set up the canvas and call the web worker.
Javascript
 //   var img = new Image(); img.src = "Malevich.jpg"; function draw(canvas_name) { //    Web Workers? if(!window.Worker) { return alert('    Web Workers!'); } //   var canvas = document.getElementById(canvas_name); var ctx = canvas.getContext("2d"); //   ctx.clearRect(0,0,canvas.width,canvas.height); ctx.drawImage(img,0,0,img.width,img.height,0,0,img.width,img.height); var worker = new Worker('filter_worker.js'); //   worker worker.postMessage({ //  ImageData  worker imagedata: ctx.getImageData(0, 0, canvas.width, canvas.height), width: canvas.width, height: canvas.height, radius: document.getElementById("radius").value }); worker.onmessage = function (event) { if (event.data.status === 'complite') { //   Image Data   canvas ctx.putImageData(event.data.imagedata,0,0); } else { //     ,     document.getElementById("load_info").innerHTML = event.data.progress + "%"; } } } 


')

Webworker


The algorithm of the blur filter works as follows: find the arithmetic average of the sum of the colors of all pixels falling within a certain radius from the current pixel and record the outgoing color in it.
Webworker
 onmessage = function (event) { var imagedata = event.data.imagedata; var width = event.data.width; var height = event.data.height; var radius = event.data.radius; var sum_r, sum_g, sum_b, sum_a; //  ,     var scale = (radius * 2 + 1) * (radius * 2 + 1) var num_pixels = width * height; function getPixel(x, y) { if (x < 0) { x = 0; } if (y < 0) { y = 0; } if (x >= width) { x = width - 1; } if (y >= height) { y = height - 1; } var index = (y * width + x) * 4; return [ imagedata.data[index + 0], imagedata.data[index + 1], imagedata.data[index + 2], imagedata.data[index + 3], ]; } function setPixel(x, y, r, g, b, a) { var index = (y * width + x) * 4; imagedata.data[index + 0] = r; imagedata.data[index + 1] = g; imagedata.data[index + 2] = b; imagedata.data[index + 3] = a; } var lastprogress = 0; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { var progress = Math.round((((y * width) + height) / num_pixels) * 100); if (progress > lastprogress) { lastprogress = progress; postMessage({status: 'progress', progress: progress}); } sum_r = 0; sum_g = 0; sum_b = 0; sum_a = 0; for (var dy = -radius; dy <= radius; dy++) { for (var dx = -radius; dx <= radius; dx++) { var pixeldata = getPixel(x + dx, y + dy); sum_r += pixeldata[0]; sum_g += pixeldata[1]; sum_b += pixeldata[2]; sum_a += pixeldata[3]; } } //    (     //     setPixel( x, y, Math.round(sum_r / scale), Math.round(sum_g / scale), Math.round(sum_b / scale), Math.round(sum_a / scale) ); } } postMessage({status: 'complite', imagedata: imagedata}); } 



Conclusion:


Based on this example, you can create your own image processing scripts that do not cause the web page to freeze.

Source: https://habr.com/ru/post/151722/


All Articles