Este é o terceiro artigo de uma série que irá apresentar os recursos disponibilizados pela nova tag <canvas> do HTML5. Nesse artigo, veremos
Um dos recursos mais excitantes do elements.” href=”/en-US/docs/Web/API/HTMLImageElement”>HTMLImageElement
ou para algum outro elemento canvas que será usado com fonte. Não é possível usar imagens apenas pelo fornecimento de uma URL ou caminho para ela.
drawImage()
.Vamos dar uma olhada em como isso é feito.
Obtendo imagens para serem desenhadas
A API do canvas é capaz de usar qualquer um dos seguintes tipos de dados como fonte de uma imagem:
- Element (or HTML Image Element) represents an image of the document.” href=”/en-US/docs/Web/HTML/Element/img”>
<img>
.HTMLVideoElement
- Ao usar o elemento
HTMLCanvasElement
- Você pode usar outro elemento
ImageBitmap
- Este é um bitmap de alta performance que pode ser renderizado com baixa latência; ele pode ser criado tanto de qualquer uma das fontes acima quanto de muitas outras.
- Você pode usar outro elemento
Essas fontes são referenciadas coletivamente pelo tipo CanvasImageSource
.
Existem diversas maneiras para obter imagens para uso em um canvas.
Usando imagens da mesma página
Podemos obter uma referência para imagens na mesma página onde está o canvas através de um das opções a seguir:
- A coleção
document.images
- O método
document.getElementsByTagName()
- Se você souver o ID da imagem especifica que quer usar, pode usar o método
document.getElementById()
para recuperar a imagem específica
Usando imagens de outro domínios
Usando o atributo crossOrigin
de um contaminar o canvas.
O que é um canvas “contaminado”?
Apesar de você poder usar imagens sem aprovação de acesso em seu canvas, fazendo isso você contamina o canvas. Uma vez que o canvas seja contaminado, você não será capaz de puxar dados dele. Por exemplo, não poderá usar os métodos toBlob()
, toDataURL()
, ougetImageData()
; fazer isso irá disparar um erro de segurança.
Isso protege os usuários de ter dados privativos expostos pelo uso de imagens para puxar informações de sites remotos sem permissão.
Usando outros elementos do canvas
De forma análoga ao uso de imagens normais, podemos acessar outros elementos canvas apenas pelo uso dos métodos document.getElementsByTagName()
ou document.getElementById()
. Certifique-se de ter desenhado algo no canvas antes de usa-lo no destino.
Um dos usos mais práticos desse método seria usar um segundo elemento canvas como miniatura de outros canvas maiores.
Criando uma imagem do zero
Uma outra opção é criar um novo objeto var img = new Image(); // Create new img element
img.src = 'myImage.png'; // Set source path
Quando o script é executado, a imagem começa a ser carregada. Se você estiver usando apenas uma imagem externa, essa é uma boa abordagem, mas uma vez que tenha que rastrear mais de uma, precisaremos recorrer a um recurso mais esperto. Isso vai além do escopo desse artigo, mas você pode dar uma olhada em JavaScript Image Preloader para uma solução mais completa. Uma outra forma possível para incluir imagens é através de data: url. Data URLs permitem que você defina complemente uma imagem como uma String Base64 diretamente em seu código. Uma vantagem de Data URLs é que a imagem resultante estará disponível imediatamente sem necessidade de um novo acesso ao servidor. Uma outra vantagem em potencial é que é possível encapsular todos os seus códigos CSS, JavaScript, HTML, e imagens, tornando a página mais portátil. Você pode usar quadros de um vídeo que está sendo apresentado por um elemento element is used to embed video content in an HTML or XHTML document.” href=”/en-US/docs/Web/HTML/Element/video”> Isso irá retornar o objeto Uma vez que você tenha uma referência para sua fonte de imagem, podemos usar o método No exemplo a seguir, usaremos uma imagem externa como backdrop para um pequeno gráfico de linha. O uso de backdrops pode tornar o seu script consideravelmente menor porque evita a necessidade de código para gerar o fundo. Nesse exemplo, usamos apenas uma imagem, assim foi usado o manipulador de imagem load do objeto image para executar as sentenças de desenho. O método O gráfico resultante deve se parecer com isso:
Se você tentar chamar drawImage()
antes da imagem ter terminado seu carregamento, nada irá acontecer (ou, em navegadores antigos, um erro pode ser disparado). Dessa forma, certifique-se de usar o evento load de forma que você não tente usar esse método antes do término do carregamento da imagem:var img = new Image(); // Create new img element
img.addEventListener("load", function() {
// execute drawImage statements here
}, false);
img.src = 'myImage.png'; // Set source path
Embutindo uma imagem através de data:URL
var img_src = 'data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw==';
Algumas desvantagens desse método são que sua imagem não será salva em cache, e para imagens grandes a URL codificada será bem longa.Usando quadros de um vídeo
<video>
com o ID “myvideo“, pode fazer isso:function getMyVideo() {
var canvas = document.getElementById('canvas');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
return document.getElementById('myvideo');
}
}
HTMLVideoElement
para o vídeo, que, como mencionado anteriormente, pode ser usado como um CanvasImageSource
.Desenhando imagens
drawImage()
para renderiza-la no canvas. Como veremos mais tarde o método drawImage()
é sobrecarregado e tem diversas variações. Em sua forma mais básica, ele se parece com o seguinte:
drawImage(image, x, y)
CanvasImageSource
especificado pelo parâmetro image
nas coordenadas (x
, y
).Exemplo: um gráfico de linha simples
drawImage()
posiciona os backdrops na coordenada (0, 0), que é o canto superior esquerdo do canvas.<html>
<body onload="draw();">
<canvas id="canvas" width="180" height="150"></canvas>
</body>
</html>
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
var img = new Image();
img.onload = function(){
ctx.drawImage(img,0,0);
ctx.beginPath();
ctx.moveTo(30,96);
ctx.lineTo(70,66);
ctx.lineTo(103,76);
ctx.lineTo(170,15);
ctx.stroke();
};
img.src = 'https://mdn.mozillademos.org/files/5395/backdrop.png';
}
Screenshot | Live sample |
---|---|
![]() |
Escalonamento
A segunda variação do método drawImage()
adiciona dois novos parâmetros e permite que posicionemos imagens escalonadas no canvas.
drawImage(image, x, y, width, height)
- Essa variação acrescenta os parâmetros
width
eheight
, que indicam o tamanho que a imagem terá ao ser desenhada no canvas.
Exemplo: Imagem lado a lado
Nesse exemplo, usaremos uma imagem como papel de parede e repetiremos ela diversas vezes no canvas. Isso é feito simplesmente pelo posicionamento em loop da imagem em diversas posições. No código abaixo, o primeiro loop for
itera as linhas. O segundo for
itera as colunas. A imagem é escalonada para 1/3 de seu tamanho original, que é 50×38 pixels.
<html> <body onload="draw();"> <canvas id="canvas" width="150" height="150"></canvas> </body> </html>
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); var img = new Image(); img.onload = function(){ for (var i=0;i<4;i++){ for (var j=0;j<3;j++){ ctx.drawImage(img,j*50,i*38,50,38); } } }; img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg'; }
O canvas resultante ficará assim:
Screenshot | Live sample |
---|---|
![]() |
Fatiamento
A terceira e última variação do método drawImage()
possui oito parâmetros. Essa variação recorta uma seção da imagem, escalona essa seção e a desenha no canvas.
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
- Dada uma
image
, essa função obtém a área da imagem especifica pelo retângulo cujo canto superior esquerdo é (sx
,sy
) e cuja largura e altura sãosWidth
esHeight
e desenha essa imagem no canvas, posicionando ela em (dx
,dy
) e escalonando-a para o tamanho especificado pordWidth
edHeight
.
Para realmente entender o que esse método faz, pode ajudar dar uma olhada na imagem à direita. Os primeiros quatro parâmetros definem a localização e o tamanho da fatia da imagem fonte. Os últimos quatro definem o retângulo no qual será desenhado a imagem no canvas destino.
O fatiamento pode ser útil quando se quer fazer composições. Você pode ter todos os elementos em um único arquivo de imagem e usar esse método para compor um desenho completo. Por exemplo, se quiser criar um mapa pode ter uma imagem PNG que contenha todo o texto necessário em um único arquivo e dependendo de seus dados poderia alterar a escala de seu mapa de forma bem fácil. Uma outra vantagem é que você não precisa carregar cada imagem individualmente, o que pode melhorar a performance do carregamento.
Exemplo: Enquadrando uma imagem
Nesse exemplo, usaremos a mesma foto usada no exemplo anterior, mas recortaremos sua cabeça e colocaremos ela em um quadro. A imagem do quadro é um PNG de 24 bits que inclui uma sombra. Como um PNG de 24 bits inclui um canal alfa de 8 bits, ele pode ser posicionado em qualquer fundo sem ter que se preocupar com um cor fosca.
<html> <body onload="draw();"> <canvas id="canvas" width="150" height="150"></canvas> <div style="display:none;"> <img id="source" src="http://www.klebermota.eti.br/wp-content/rhino.jpg" width="300" height="227"> <img id="frame" src="http://www.klebermota.eti.br/wp-content/Canvas_picture_frame.png" width="132" height="150"> </div> </body> </html>
function draw() { var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); // Draw slice ctx.drawImage(document.getElementById('source'), 33, 71, 104, 124, 21, 20, 87, 104); // Draw frame ctx.drawImage(document.getElementById('frame'),0,0); }
Usamos uma abordagem diferente para carregar a imagem dessa vez. Ao invés de carrega-las pela criação de um novo objeto Element (or HTML Image Element) represents an image of the document.” href=”/en-US/docs/Web/HTML/Element/img”><img>
diretamente em nosso HTML e recuperamos as imagens a partir dela. As imagens ficam ocultas na saída pela configuração da propriedade display
do CSS para none para essas imagens.
Screenshot | Live sample |
---|---|
![]() |
O script em si é bastante simples. Para cada document.getElementById()
. Em seguida, simplesmente usamos drawImage()
para fatiar a imagem do rinoceronte e escalona-la no canvas, e em seguida desenhar a moldura sobre ela usando uma segunda chamada àdrawImage()
.
Exemplo de uma galeria de imagens
No exemplo final desse artigo, construiremos uma pequena galeria de imagens. Quando a página é carregada, um elemento document.images
e adicionamos novos elementos canvas de acordo. Provavelmente a única coisa digna de nota, para aqueles que não estejam familiarizados com o DOM, é o uso do métodoNode.insertBefore
. insertBefore()
é um método do nó pai (uma célula da tabela) do elemento (a imagem) antes que nós inserimos nosso novo nó (o elemento canvas).
<html> <body onload="draw();"> <table> <tr> <td><img src="https://mdn.mozillademos.org/files/5399/gallery_1.jpg"></td> <td><img src="https://mdn.mozillademos.org/files/5401/gallery_2.jpg"></td> <td><img src="https://mdn.mozillademos.org/files/5403/gallery_3.jpg"></td> <td><img src="https://mdn.mozillademos.org/files/5405/gallery_4.jpg"></td> </tr> <tr> <td><img src="https://mdn.mozillademos.org/files/5407/gallery_5.jpg"></td> <td><img src="https://mdn.mozillademos.org/files/5409/gallery_6.jpg"></td> <td><img src="https://mdn.mozillademos.org/files/5411/gallery_7.jpg"></td> <td><img src="https://mdn.mozillademos.org/files/5413/gallery_8.jpg"></td> </tr> </table> <img id="frame" src="https://mdn.mozillademos.org/files/242/Canvas_picture_frame.png" width="132" height="150"> </body> </html>
E a seguir algum código CSS para tornar as coisas melhores:
body { background: 0 -100px repeat-x url(https://mdn.mozillademos.org/files/5415/bg_gallery.png) #4F191A; margin: 10px; } img { display: none; } table { margin: 0 auto; } td { padding: 15px; }
Agora segue o código JavaScript que põe tudo junto para desenhar as imagens emolduradas:
function draw() { // Loop through all images for (var i=0;i<document.images.length;i++){ // Don't add a canvas for the frame image if (document.images[i].getAttribute('id')!='frame'){ // Create canvas element canvas = document.createElement('canvas'); canvas.setAttribute('width',132); canvas.setAttribute('height',150); // Insert before the image document.images[i].parentNode.insertBefore(canvas,document.images[i]); ctx = canvas.getContext('2d'); // Draw image to canvas ctx.drawImage(document.images[i],15,20); // Add frame ctx.drawImage(document.getElementById('frame'),0,0); } } }
Screenshot | Live sample |
---|---|
![]() |
Controlando o comportamento do escalonamento da imagem
Como mencionado anteriormente, escalonar imagens pode resultar em artefatos difusos ou quadriculados, devido ao processo de escalonamento. Você pode usar a propriedade imageSmoothingEnabled do contexto de desenho para controlar o uso dos algoritmos de suavização da imagem quando escalonar imagens em seu contexto. Por padrão, isso é true
, o que significa que as imagens serão suavizadas quando escalonadas. Você pode desativar esse recurso dessa forma:
ctx.mozImageSmoothingEnabled = false;