Алгоритм Flood Fill canvas - PullRequest
       51

Алгоритм Flood Fill canvas

0 голосов
/ 25 января 2020

Я использую алгоритм floodFill, но он очень медленно. Например, у меня есть холст (512px x 512px), и для заполнения всего холста мне нужно 6 секунд. Можете ли вы помочь мне улучшить мою реализацию? Я использую алгоритм из http://www.williammalone.com/articles/html5-canvas-javascript-paint-bucket-tool/

И вот ссылка, где я пытался улучшить свой алгоритм: https://labs.eleks.com/2012/11/html5-canvas-performance-and.html

function flood(context, canvas, color, target) {

      function floodFill(startX, startY, color) {

        function isStartColor(position, startColor, imageData) {
          if ((imageData[position + 0]) != ((startColor >> 24) & 0xFF)
                  || (imageData[position + 1]) != ((startColor >> 16) & 0xFF)
                  || (imageData[position + 2]) != ((startColor >> 8) & 0xFF)) {  
                    return false;     
                } 
                return true;
        }

        function drawPixel(position, imageData) {
          imageData[position] = color.r;
          imageData[position + 1] = color.g;
          imageData[position + 2] = color.b;
          imageData[position + 3] = 255;
        }

        let stack = [[startX, startY]];

        while (stack.length) {
          const image = context.getImageData(0, 0, canvas.width, canvas.height);
          const imageData = image.data;
          const newPosition = stack.pop();
          const x = Math.round(newPosition[0]);
          const y = Math.round(newPosition[1]);

          const pixelPosition = (y * canvas.width + x) * 4;

          const startColor = {
            r: imageData[pixelPosition + 0] << 24,
            g: imageData[pixelPosition + 1] << 16,
            b: imageData[pixelPosition + 2] << 8
          }

          while (y-- >= 0 && isStartColor(pixelPosition, startColor, imageData)) {
            pixelPosition = pixelPosition - canvas.width * 4;
          }

          y++;
          pixelPosition = pixelPosition + canvas.width * 4;
          let reachLeft = false;
          let reachRight = false;

          while (y++ < canvas.height - 1 && isStartColor(pixelPosition, startColor, imageData)) {
            drawPixel(pixelPosition, imageData);

            if (x > 0) {
              if (isStartColor(pixelPosition - 4, startColor, imageData)) {
                if (!reachLeft) {
                  stack.push([x - 1, y]);
                  reachLeft = true;
                }
              } else {
                if (reachLeft) {
                  reachLeft = false;
                }
              }
            }

          if (x < canvas.width - 1) {
              if (isStartColor(pixelPosition + 4, startColor, imageData)) {
                if (!reachRight) {
                  stack.push([x + 1, y]);
                  reachRight = true;
                }
              } else {
                if (reachRight) {
                  reachRight = false;
                }
              }
            }
            pixelPosition = pixelPosition + canvas.width * 4;
          }

          context.putImageData(image, 0, 0);
        }
      }


      const canvasHTMLWidth = document.querySelector('.main-canvas').offsetWidth;
      const canvasHTMLHeight = document.querySelector('.main-canvas').offsetHeight;
      let xCoordinateScale;
      let yCoordinateScale;

      function getCoodinateScale() {
          xCoordinateScale = (canvasHTMLWidth / canvas.width);
          yCoordinateScale = (canvasHTMLHeight / canvas.height);
        }

        function hexToRgb(hex) {
            var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
            return result ? {
              r: parseInt(result[1], 16),
              g: parseInt(result[2], 16),
              b: parseInt(result[3], 16),
              a: 255
            } : null;
          }

        getCoodinateScale();
        const floodColor = hexToRgb(color.value);
        canvas.addEventListener('mousedown', (event) => {
          if (!target.classList.contains('active-tool')) {
            return
          }
          floodFill(event.offsetX / xCoordinateScale, event.offsetY / yCoordinateScale, floodColor);
        });
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...