Maceo, 2005

Maceo, 2005

Comecei a programar muito cedo. E quando criança, mas já com meu super TK3000 2e, a experiência de manipular cada pixel da tela foi revolucionária. No meu raciocínio infantil, se eu tinha o IF, o GOTO e o ‘poder’ sobre qualquer pixel da tela, então eu poderia fazer qualquer coisa com o computador. Hoje, mesmo sabendo que meu pensamento era no mínimo inocente, não posso deixar de reconhecer alguma lógica nele. E ainda afirmo: a possibilidade de manipular qualquer pixel é libertadora! ;) .
Porém quem começa a trabalhar com o elemento Canvas do HTML5 percebe que parece faltar funções do gênero setPixel e getPixel.
Mas existe salvação. Por sorte é possível obter e registrar um array de cores que representa cada pixel do canvas. Na realidade, esta técnica já foi até utilizada aqui no post: Como compactar Código Javascript em um PNG.
A seguir veremos, passo a passo, como obter, modificar e registrar o array de pixels do canvas. Ao final mostrarei o código do bitMapCanvas, que criei contendo as úteis e inexistentes funções setPixel e getPixel.

Como havia dito, o segredo é saber como obter do canvas e registrar no canvas o array representando a imagem e seus pixels. Segue abaixo o código exemplificando como obter tal array:

   //obtem objeto canvas
   cnv = document.getElementById(psIdCanvas);

   //obtem o contexto 2d
   ctx = cnv.getContext('2d');

   //pega os valores de altura e largura do canvas
   w=parseInt(cnv.width);
   h=parseInt(cnv.height);

//cria ou obtem o array de pixels
if (ctx.createImageData) {
   img = ctx.createImageData(w, h);
} else if (ctx.getImageData) {
   img = ctx.getImageData(0, 0, w, h);
} else {
   img = {'width' : w, 'height' :h, 'data' : new Array(w*h*4)};
}

//a variavel arrPix é o seu array de pixels
arrPix = img.data

Do exemplo acima temos um array de dimensão w*h*4, onde w*h é a quantidade de pixels e o 4 vem do fato de que cada pixel é composto de 4 canais: red, green, blue e alpha – transparência.
Tentando exemplificar um pouco, a estrutura do array é:

[componente red do pixel 1,
componente green do pixel 1,
componente blue do pixel 1,
componente alpha do pixel 1,
componente red do pixel 2,
componente green do pixel 2,
componente blue do pixel 2,
componente alpha do pixel 2,
componente red do pixel 3,
componente green do pixel 3,
...]

Onde o valor de cada componente varia de 0 à 255.

Ou seja, se, e somente se, seu canvas tiver 300px de largura, sua primeira linha será representada pelos pixels de 0 -red do 1o pixel – até 1200 – alpha do 300o pixel.
Então para colocar o pixel do meio da 2a linha como verde o código seria: arrPix[1801]=255;arrPix[1803]=255; .
Onde arrPix[1801] é a componente verde do pixel que se inicia em 1800; e
arrPix[1803] é a transparência do mesmo onde o 255 é o sólido sem transparência.

Depois de tudo devemos utilizar a instrução abaixo para atualizar o canvas:

context.putImageData(imgd, 0,0); //cria a imagem na posição 0,0 do canvas.

Convenhamos: É possível trabalhar assim. Mas não é nada prático.
Então criei a classe abaixo chamada bitMapCanvas para facilitar a nossa vida:

function bitMapCanvas(psIdCanvas)
{
   this.cnv; //canvas
   this.ctx; //context
   this.img; //imagem
   this.w;
   this.h;

   //obtem objeto canvas
   this.cnv = document.getElementById(psIdCanvas);

   //obtem o contexto 2d
   this.ctx = this.cnv.getContext('2d');

   //pega os valores de altura e largura do canvas
   this.w=parseInt(this.cnv.width);
   this.h=parseInt(this.cnv.height);

//cria ou obtem o array de pixels
if (this.ctx.createImageData) {
   this.img = this.ctx.createImageData(this.w, this.h);
} else if (this.ctx.getImageData) {
   this.img = this.ctx.getImageData(0, 0, this.w, this.h);
} else {
   this.img = {'width' : this.w,
                  'height' :this.h,
                  'data' : new Array(this.w*this.h*4)};
}

this.setPixel=function(piLeft, piTop, piRed, piGreen, piBlue, piAlpha)
{
   iPixel=piTop*this.w*4+(piLeft*4);
   this.img.data[iPixel]=piRed;
   this.img.data[iPixel+1]=piGreen;
   this.img.data[iPixel+2]=piBlue;
   this.img.data[iPixel+3]=piAlpha;
   this.ctx.putImageData(this.img, 0,0);
}

this.getPixel=function(piLeft, piTop)
{
   iPixel=piTop*this.w*4+(piLeft*4);
   return [this.img.data[iPixel],
             this.img.data[iPixel+1],
             this.img.data[iPixel+2],
             this.img.data[iPixel+3]];
}

this.clear=function()
{
   this.img = {'width' : this.w,
                  'height' :this.h,
                  'data' : new Array(this.w*this.h*4)};
   this.ctx.putImageData(this.img, 0,0);
}

this.getContext=function()
{
   return this.ctx;
}

}

Dado um elemento html canvas de id=arena de width=”300px” e height=”300px”, segue a demonstração de como utilizar o bitMapCanvas:

//obtem um novo bitMapCanvas ligado ao canvas arena.
 G_bcvArena = new bitMapCanvas('arena');  

//desenha o famigerado pixel verde no centro do canvas
G_bcvArena.setPixel(150,150,0,255,0,255);

//Querendo desenhar outras formas basta obter o contexto e utiliza-lo normalmente.
ctx = G_bcvArena.getContext();

//Como nem sempre é simples encontrar um pixel isolado na tela,
//desenharemos um círculo em volta do mesmo
ctx.beginPath();
ctx.arc(150, 150, 10, 0, Math.PI*2, true);
ctx.closePath();
ctx.stroke();

E é isso! Abraços e até a próxima!

Uma Resposta para “Canvas: Manipulação Pixel a Pixel “Pixel Based” em Javascript”
  1. Tron: O jogo das Light Cycles em Javascript | Blog do Renato, o Louro diz:

    [...] desta moto e que elas viram sempre num ângulo de 90o. Aproveitando a biblioteca criada no post Canvas: Manipulação Pixel a Pixel “Pixel Based” em Javascript, criei este pequeno jogo que ilustra o funcionamento da biblioteca. Então este jogo é para você [...]

Deixe um Comentário

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>