Canvas调用putImageData绘制全白 除alpha外还有哪些实现错误?
问题现象
- 基于二维数组在canvas上绘制图形,预期初始渲染全画布#808080灰色,实际始终显示纯白色
- 参考同类问题的解决方案将像素alpha值设为255后,问题仍然存在
原有实现代码:
<!-- HTML部分 --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div id="container"></div>
// 原有问题JS代码 (function() { var context = null; var grid = []; var height = null; var image_data = null; var width = null; var draw = function() { var data = image_data.data; for (var index = 0; index < data.length; index += 4) { var x = Math.floor(Math.floor(index / 4) / width); var y = Math.floor(Math.floor(index / 4) * width); data[index] = grid[x][y][0]; data[index + 1] = grid[x][y][1]; data[index + 2] = grid[x][y][2]; data[index + 3] = 255; } image_data.data = data; context.putImageData(image_data, 0, 0); }; var init = function() { height = jQuery(window).height(); width = jQuery(window).width(); jQuery('#container').html('<canvas id="map" height="' + height + '" width="' + width + '"></canvas>') context = document.getElementById('map').getContext('2d'); image_data = context.getImageData(0, 0, width, height); for (var outer = 0; outer < width; outer += 1) { grid[outer] = []; for (var inner = 0; inner < height; inner += 1) { grid[outer][inner] = [128, 128, 128]; } } } var start_drawing = function() { draw(); setTimeout(start_drawing, 1); }; init(); start_drawing(); })();
错误原因
- 核心错误为像素坐标计算逻辑完全错误:ImageData的像素数据按行优先顺序存储(从上到下逐行、每行从左到右排列),原有代码计算x、y的公式不符合存储规则,坐标值严重超出二维数组
grid的索引范围,触发类型错误导致draw函数直接中断执行,canvas始终保持初始透明状态,在页面默认白色背景下看起来就是全白。 - 存在冗余无效代码:
image_data.data是只读的Uint8ClampedArray引用,直接修改该数组的元素就会同步作用到ImageData上,不需要也不能手动给image_data.data重新赋值,该操作在严格模式下会直接抛出错误。
修正后代码
(function() { var context = null; var grid = []; var height = null; var image_data = null; var width = null; var draw = function() { var data = image_data.data; // 遍历每个像素(每4个值对应1个像素的R/G/B/A通道) for (var index = 0; index < data.length; index += 4) { // 计算当前像素的序号 var pixelIndex = index / 4; // 按行优先规则正确计算坐标:y为像素序号除以画布宽度取整(行号),x为像素序号对画布宽度取模(列号) var y = Math.floor(pixelIndex / width); var x = pixelIndex % width; // 写入颜色值 data[index] = grid[x][y][0]; data[index + 1] = grid[x][y][1]; data[index + 2] = grid[x][y][2]; data[index + 3] = 255; } // 移除无效的data重新赋值操作,直接渲染 context.putImageData(image_data, 0, 0); }; var init = function() { height = jQuery(window).height(); width = jQuery(window).width(); jQuery('#container').html('<canvas id="map" height="' + height + '" width="' + width + '"></canvas>') var canvas = document.getElementById('map'); context = canvas.getContext('2d'); // 增加灰色填充兜底,避免首次渲染加载时的白屏闪烁 context.fillStyle = '#808080'; context.fillRect(0,0,width,height); image_data = context.getImageData(0, 0, width, height); // 初始化二维网格 for (var x = 0; x < width; x += 1) { grid[x] = []; for (var y = 0; y < height; y += 1) { grid[x][y] = [128, 128, 128]; } } } var start_drawing = function() { draw(); setTimeout(start_drawing, 1); }; init(); start_drawing(); })();
内容的提问来源于stack exchange,提问作者Christos Hayward
相关产品推荐
相关产品推荐

