在画布中操作像素

3

我正在尝试编写简单的2D俯视格子地图游戏,但在对特定画布区域中的像素进行操作时遇到了问题。我有以下函数:

changeCellBackground(x, y, r, g, b){

    let cell = this.context.getImageData(x * this.TILE_SIZE, y * this.TILE_SIZE, this.TILE_SIZE, this.TILE_SIZE);

    for(let i=0; i<cell.data.length; i+=4){

        cell.data[i] += r;
        cell.data[i+1] += g;
        cell.data[i+2] += b;
    }

    this.context.putImageData(cell, x * this.TILE_SIZE, y * this.TILE_SIZE);
}

其中 context 是 canvas 2d 上下文:

this.screen = $('#game');
this.context = this.screen[0].getContext('2d');

一个带有指向图块集的链接的Img标签:

let tileSet = $('<img></img>').attr('src', '../assets/tiles.png');

然而,当我尝试使用上述函数时,我遇到了SecurityError: The operation is insecure.的错误。据我了解,这是由于CORS限制造成的,所以我尝试在Img中添加crossOrigin="anonymous"属性:

let tileSet = $('<img></img>').attr('crossOrigin', 'anonymous').attr('src', '../assets/tiles.png');

但是现在我收到了NS_ERROR_NOT_AVAILABLE:的错误信息。我猜测这是因为当脚本开始执行时,图片还没有加载完成。我该如何解决这个问题?我尝试了以下方法:

let tileSet = $('<img></img>');

    tileSet.onload = function(){

        tileSet.attr('crossOrigin', 'anonymous').attr('src', '../assets/tiles.png');

        gameScreen.drawAnimatedImage(0, 0, 'waterfall');
        gameScreen.drawAnimatedImage(2, 2, 'fountain');
        gameScreen.drawAnimatedImage(11, 5, 'street_lamp');
        gameScreen.drawAnimatedImage(10, 5, 'street_lamp');
        gameScreen.changeCellBackground(10, 15, -30, -30, -30);
    };

但它也不起作用——当我在onload函数末尾设置console.log(tileSet)时,控制台上没有输出任何内容。看起来onload函数没有被触发。为什么会出现这种情况,我该如何修复它?


你正在设置src属性你的加载事件处理程序中,但这需要src被设置以便于某一天触发...将这行代码移到这个处理程序之外。我的看法是这个问题应该作为打字错误而关闭... - Kaiido
2个回答

1
这里有一种更简单的方法来向画布上的像素添加值。
你的函数:
changeCellBackground(x, y, r, g, b){

在坐标为x,y的瓦片上,将r、g、b添加到每个像素中。
可以通过以下方式完成。
function changeCellBackground(x, y, r, g, b){
     this.context.fillStyle = "rgb(" + Math.floor(r) + ","  + Math.floor(g) + "," + Math.floor(b) + ")";
     this.context.globalCompositeOperation = "lighter"; // adds the fill color to existing pixels
     this.context.fillRect(x * this.TILE_SIZE, y * this.TILE_SIZE, this.TILE_SIZE, this.TILE_SIZE);
     this.context.globalCompositeOperation = "source-over"; // restore default composite operation
 }

上述函数与您的函数相同,但无需访问像素数据。这意味着您不必担心不安全的图像,可以在没有跨域头的情况下加载它。
猜测一下,如果您是在硬盘上工作(即../assets/tiles.png在您的硬盘上),那么您将无法获得CORS图像,因为这需要服务器。
您可以在计算机上设置服务器(有很多选项),然后使用本地主机名,这样图像就不是跨域的,也不需要头文件。或者您可以查找浏览器安全开关并关闭跨域安全性,这样也可以访问图像数据。

0

在你的问题中,changeCellBackground()tileset 之间没有联系,所以我不确定是否会有更多的问题,但是要等待图像加载,实际上需要将 src 部分放到函数外面:

let tileSet = $('<img></img>');

tileSet.onload = function(){
    gameScreen.drawAnimatedImage(0, 0, 'waterfall');
    gameScreen.drawAnimatedImage(2, 2, 'fountain');
    gameScreen.drawAnimatedImage(11, 5, 'street_lamp');
    gameScreen.drawAnimatedImage(10, 5, 'street_lamp');
    gameScreen.changeCellBackground(10, 15, -30, -30, -30);
};

tileSet.attr('crossOrigin', 'anonymous').attr('src', '../assets/tiles.png');

目前情况是,由于没有要加载的源,因此不会触发onload事件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接