HTML5 Canvas泛洪填充(Flood Fill)异常:颜色偏差、黑色填充崩溃
Canvas泛洪填充问题修复方案
存在的问题
- 移除alpha通道后出现颜色偏差,仅红色、白色填充功能正常
- 使用黑色(0,0,0)填充时触发无限循环,导致页面崩溃
问题根源与修复步骤
alpha通道赋值错误
原代码中setPixel函数把alpha通道设为红色通道的值,导致非红色颜色因半透明显示异常。需将alpha设为255(完全不透明)。颜色格式不统一
getPixel返回带alpha的4元素数组,但传入的填充色是3元素RGB数组,导致颜色匹配逻辑因长度不匹配出错。修改getPixel仅返回RGB值。visited数组初始化错误
原代码创建的visited数组长度仅为画布宽度,无法覆盖所有像素,导致重复处理像素引发无限循环。需创建长度为画布宽×高的数组。可选优化:边界检查提前
在将像素加入待检查队列前先做边界判断,减少无效处理。
修复后的完整代码
<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
相关产品推荐
相关产品推荐

