You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

HTML5 Canvas泛洪填充(Flood Fill)异常:颜色偏差、黑色填充崩溃

Canvas泛洪填充问题修复方案

存在的问题

  • 移除alpha通道后出现颜色偏差,仅红色、白色填充功能正常
  • 使用黑色(0,0,0)填充时触发无限循环,导致页面崩溃

问题根源与修复步骤

  1. alpha通道赋值错误
    原代码中setPixel函数把alpha通道设为红色通道的值,导致非红色颜色因半透明显示异常。需将alpha设为255(完全不透明)。

  2. 颜色格式不统一
    getPixel返回带alpha的4元素数组,但传入的填充色是3元素RGB数组,导致颜色匹配逻辑因长度不匹配出错。修改getPixel仅返回RGB值。

  3. visited数组初始化错误
    原代码创建的visited数组长度仅为画布宽度,无法覆盖所有像素,导致重复处理像素引发无限循环。需创建长度为画布宽×高的数组。

  4. 可选优化:边界检查提前
    在将像素加入待检查队列前先做边界判断,减少无效处理。


修复后的完整代码

<canvas id="myCanvas" width="300" height="150" style="border:1px solid grey"></canvas>

<script>
const c = document.getElementById("myCanvas");
const ctx = c.getContext("2d");

ctx.strokeStyle = "rgb(252, 53, 3)";
ctx.strokeRect(10, 10, 50, 50);
var red = [252, 53, 3];
floodFill(ctx, 15, 15, red);

ctx.strokeStyle = "rgb(3, 252, 3)";
ctx.strokeRect(75, 10, 50, 50);
var green = [3, 252, 3];
floodFill(ctx, 80, 15, green);

ctx.strokeStyle = "rgb(3, 119, 252)";
ctx.strokeRect(150, 10, 50, 50);
var blue = [3, 119, 252];
floodFill(ctx, 155, 15, blue);

ctx.strokeStyle = "rgb(0, 0, 0)";
ctx.strokeRect(225, 10, 50, 50);
var black = [0, 0, 0];
floodFill(ctx, 230, 15, black); // 现在可正常运行


function getPixel(imageData, x, y) {
  if (x < 0 || y < 0 || x >= imageData.width || y >= imageData.height) {
    return [-1, -1, -1];  // 返回RGB格式无效颜色
  } else {
    const offset = (y * imageData.width + x) * 4;
    // 仅返回RGB通道,忽略alpha
    return [
      imageData.data[offset],
      imageData.data[offset + 1],
      imageData.data[offset + 2]
    ];
  }
}

function setPixel(imageData, x, y, color) {
  const offset = (y * imageData.width + x) * 4;
  imageData.data[offset + 0] = color[0];
  imageData.data[offset + 1] = color[1];
  imageData.data[offset + 2] = color[2];
  imageData.data[offset + 3] = 255; // 设为完全不透明
}

function colorsMatch(a, b) {
  if (!a || !b || a.length !== 3 || b.length !== 3) return false;
  return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
}

function floodFill(ctx, x, y, fillColor) {
  const imageData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
  // 创建覆盖所有像素的visited数组
  const visited = new Uint8Array(imageData.width * imageData.height);
  const targetColor = getPixel(imageData, x, y);

  if (!colorsMatch(targetColor, fillColor)) {
    const pixelsToCheck = [x, y];
    while (pixelsToCheck.length > 0) {
      const y = pixelsToCheck.pop();
      const x = pixelsToCheck.pop();
      
      const currentColor = getPixel(imageData, x, y);
      const index = y * imageData.width + x;

      if (!visited[index] && colorsMatch(currentColor, targetColor)) {
        setPixel(imageData, x, y, fillColor);
        visited[index] = 1;
        // 提前做边界检查,减少无效操作
        if (x + 1 < imageData.width) pixelsToCheck.push(x + 1, y);
        if (x - 1 >= 0) pixelsToCheck.push(x - 1, y);
        if (y + 1 < imageData.height) pixelsToCheck.push(x, y + 1);
        if (y - 1 >= 0) pixelsToCheck.push(x, y - 1);
      }
    }
    ctx.putImageData(imageData, 0, 0);
  }
}
</script>

内容的提问来源于stack exchange,提问作者CleverCookie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 14:24:55