Manipulating pixels in the canvas

I'm trying to write a simple 2D top-down game with a map based grid and I have a problem manipulating pixels in a specific area of ​​the canvas. I have the following function:

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

      

where context is the canvas 2d context:

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

      

and an Img tag that has a src link to a set of elements:

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

      

However, when I try to use the above function, I get SecurityError: The operation is insecure.

. As I understand it, this is due to CORS restrictions, so I try to add crossOrigin="anonymous"

attribute Img

:

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

      

But now I am getting NS_ERROR_NOT_AVAILABLE:

. I'm guessing this is happening because the image hasn't loaded yet when the rest of the script started executing. How to fix it? I've tried this:

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

      

But it doesn't work - when I set console.log(tileSet)

at the end of the function onload

, nothing gets written to the console. It seems that the onload function was not firing. Why is this happening and how can I fix it?

+3


source to share


2 answers


This is a much easier way to add value to the pixels on the canvas.

Your function

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

      

Adds r, g, b to each x, y pixel on the tile

can be done with



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
 }

      

The above function is identical to your function, but without the need to access pixel data. This means you don't have to worry about the unsafe image and load it without the cross-origin header.

As you might guess, if you are working with a hard drive (i.e. ../assets/tiles.png

located on your hard drive), you will not get the CORS image, as it requires a server.

You can set up a server on your machine (there are many options) and then use the localhost domain, in which case the image is not cross domain and doesn't need headers. Or, you can find your browser security keys and disable cross-origin protection, which will also give you access to image data.

+1


source


In your question, there is no connection between changeCellBackground()

and tileset

, so I'm not sure if there is still a problem, but to wait for the image to load, you actually need to take the src part out of the function:

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

      



Currently the onload event is not firing because there was no src to load.

0


source







All Articles