在画布中操纵像素

时间:2017-05-01 16:10:41

标签: javascript html5 image image-processing canvas

我正在尝试使用基于网格的地图编写简单的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 context:

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

和Img标签有src链接到tileset:

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

然而,当我尝试使用上述功能时,我得到了SecurityError: The operation is insecure.。据我所知,这是因为CORS限制,所以我尝试add crossOrigin="anonymous"属性Img

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);
    };

但它也不起作用 - 当我在console.log(tileSet)函数结束时设置onload时,控制台上没有记录任何内容。似乎没有触发onload函数。为什么会发生这种情况?我该如何解决这个问题?

2 个答案:

答案 0 :(得分:1)

这是一种向画布上的像素添加值的更简单方法。

你的功能

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

将r,g,b添加到拼贴上x,y

处的每个像素

可以用

完成
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映像,因为这需要服务器。

您可以在计算机上设置服务器(有很多选项),然后使用域localhost,在这种情况下,图像不是跨域的,不需要标头。或者您可以查看浏览器安全开关并关闭跨源安全性,这样您也可以访问图像数据。

答案 1 :(得分: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事件,因为没有要加载的src。