Imagens Matriciais
Nas atividades realizadas até o momento, temos manipulado desenhos vetoriais, ou seja, desenhos compostos de elementos como retângulos, círculos, segmentos de reta e curvas. O p5.js também é capaz de manipular imagens matriciais. Nesse caso, a informação visual é codificada como uma grade (ou matriz) de cores (e outros atributos, como transparência). Desse modelo de representação visual surge o termo "pixel" (picture element), correspondente a um elemento da matriz de imagem.
Da mesma forma que ocorre com os desenhos vetoriais, o p5.js também é capaz de ler e exibir imagens matriciais a partir de um arquivo, usando a função loadImage() dentro de preload() — exatamente como fizemos com arquivos SVG. O exemplo a seguir demonstra como isso pode ser feito.
let figura;
function preload() {
figura = loadImage('minha_imagem.jpg');
}
function setup() {
createCanvas(400, 500);
background(220, 220, 240);
// Apresenta a imagem na janela do programa
image(figura, 0, 0);
}
Assim como no caso dos desenhos vetoriais, para que o carregamento de um arquivo real funcione corretamente, ele deve estar acessível dentro da pasta do seu projeto (em geral em uma subpasta como assets), com o caminho referenciado em loadImage().
O p5.js é capaz de ler imagens nos formatos JPG, PNG e GIF. No caso dos formatos PNG e GIF, a informação de transparência é preservada. Se um GIF animado for carregado com loadImage(), ele é exibido já animado automaticamente ao ser desenhado repetidamente dentro de draw().
Na forma apresentada no exemplo anterior, a função image() recebeu três parâmetros: a variável com a informação da imagem matricial a ser apresentada e dois valores numéricos correspondentes à posição do canto superior esquerdo do desenho na janela (da mesma forma que retângulos são especificados na função rect()). Nesse caso, a imagem é apresentada em seu tamanho original.
Também é possível especificar mais dois parâmetros para a função image(), de forma similar ao que ocorre com a função usada para desenhos vetoriais, indicando a largura e altura da imagem. Por exemplo, se modificarmos a última linha do programa anterior para:
let figura;
function preload() {
figura = loadImage('minha_imagem.jpg');
}
function setup() {
createCanvas(400, 500);
figura = createImage(200, 200);
background(220, 220, 240);
image(figura, 0, 0, 200, 100);
}
a imagem será apresentada com pixels de largura e pixels de altura. Observe que, como essas dimensões não seguem a proporção original da figura, o desenho é distorcido. Outro ponto importante é que a ampliação e redução de uma imagem matricial podem causar outras distorções visuais à medida que parte dos pixels precisa ser ampliada ou suprimida para que a imagem ocupe o novo tamanho.
Atividade 1
Modifique o Código 5.1 para desenhar a imagem várias vezes na janela, como mostrado a seguir, utilizando comandos de repetição.
Manipulando informações de cor
Em diversas funções do p5.js, como background(), fill() e stroke(), utilizamos valores numéricos para representar cores. Na configuração padrão, o p5.js representa cores como um ou três números entre 0 e 255. Quando são utilizados três valores, eles representam quantidades de vermelho, verde e azul (do formato RGB, red / green / blue). Esse é um sistema aditivo de formação de cores, em que raios de luz dessas três cores componentes se misturam para produzir novas cores. Assim, a cor preta é representada pelos valores (0, 0, 0) e a cor branca por (255, 255, 255). Quando somente um valor é utilizado, ele é copiado para os três componentes, ou seja background(255) corresponde a background(255, 255, 255). Assim, obteremos tonalidades de cinza.
É importante notar que cada pixel de uma imagem matricial armazena informações de cor e transparência em p5.js. Assim, quando desenhamos uma imagem na tela usando a função image(), efetivamente copiamos essas informações de cor para a janela do programa.
É possível alterar as configurações de representação de cor do p5.js através da função colorMode(). O primeiro parâmetro dessa função é RGB ou HSB, indicando o modelo de representação de cores. O modelo RGB já foi explicado; o modelo HSB também usa três componentes, mas elas correspondem à tonalidade (hue), saturação e brilho (brightness) da cor. Os parâmetros seguintes são usados para indicar os limites numéricos para cada parâmetro. Por exemplo:
// usar representação RGB sendo que cada componente de cor tem um valor variando entre 0 e 100
colorMode(RGB, 100);
// usar representação HSB sendo que a tonalidade varia entre 0 e 360 e a saturação e o brilho variam
// entre 0 e 100
colorMode(HSB, 360, 100, 100);
Por fim, a função tint() permite definir uma cor que será multiplicada pelas cores das imagens desenhadas pela função image(). A função noTint() pode ser utilizada para cancelar chamadas anteriores da função tint(). O programa a seguir mostra como essa função pode ser usada para aplicar um efeito de transparência a uma imagem, variando de acordo com a posição horizontal do mouse (passe o mouse sobre o canvas para testar).
let figura;
function preload() {
// em um projeto real:
// figura = loadImage('minha_imagem.jpg');
}
function setup() {
createCanvas(500, 500);
figura = createImage(200, 200);
figura.loadPixels();
for (let x = 0; x < figura.width; x++) {
for (let y = 0; y < figura.height; y++) {
figura.set(x, y, color(x, y, 150));
}
}
figura.updatePixels();
}
function draw() {
background(220, 220, 240);
// Calcula um valor de transparência proporcional à
// posição horizontal do cursor do mouse, usando para
// isso a função map()
let alpha = map(mouseX, 0, width, 0, 255);
tint(255, alpha);
image(figura, 0, 0, width, height);
}
Atividade 2
Modifique o Código 5.3 para tingir a imagem com uma coloração avermelhada dependendo da posição horizontal do cursor do mouse, sem alterar a transparência. Consulte a referência da função tint() para mais informações.
Combinando transformações e imagens
Da mesma forma que os desenhos vetoriais, as imagens matriciais também podem ser manipuladas por transformações geométricas em p5.js.
A função imageMode() funciona de maneira análoga ao ponto de referência usado por outras formas geométricas, determinando a partir de qual ponto a imagem é posicionada. Dessa forma, imageMode(CORNER) (comportamento padrão) faz com que as coordenadas passadas para a função image() sejam interpretadas como a posição do canto superior esquerdo, e imageMode(CENTER) faz com que sejam interpretadas como a posição do centro da imagem. Essa função pode ser combinada com translate() e rotate(), exatamente como vimos no capítulo de translação e rotação, para girar ou posicionar imagens de forma mais flexível.
Atividade 3
Usando imageMode(), translate() e rotate() combinados com as variáveis mouseX/mouseY, modifique o Código 5.3 para gerar uma interação semelhante à mostrada na animação a seguir.

