Índice do conteúdo

  1. Obtendo imagens para serem desenhadas
    1. Usando imagens da mesma página
    2. Usando imagens de outros domínios
    3. Usando outros elementos canvas
    4. Criando uma imagem do zero
    5. Embutindo uma imagem através de data:URL
    6. Usando quadros de um vídeo
  2. Desenhando imagens
    1. Exemplo: Um gráfico de linha simples
  3. Escalonamento
    1. Exemplo: Imagem lado a lado
  4. Fatiamento
    1. Exemplo: Enquadrando uma imagem
  5. Exemplo de uma galeria de imagens
  6. Controlando o comportamento do escalonamento da imagem

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.

  • Desenhar a imagem no canvas através da função 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.

    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:

    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ê contaminacanvas. 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ê 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

    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.

    Embutindo uma imagem através de data:URL

    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.

    var img_src = 'data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw==';

    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.
    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

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

    Isso irá retornar o objeto HTMLVideoElement para o vídeo, que, como mencionado anteriormente, pode ser usado como um CanvasImageSource.

    Desenhando imagens

    Uma vez que você tenha uma referência para sua fonte de imagem, podemos usar o  método 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)
    Desenha o CanvasImageSource especificado pelo parâmetro image nas coordenadas (x, y).

    Exemplo: um gráfico de linha simples

    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 drawImage() posiciona os backdrops na coordenada (0, 0), que é o canto superior esquerdo do canvas.

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

    O gráfico resultante deve se parecer com isso:

    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 e height, 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.

    Nota: Imagens podem ficar borradas quando escalonada para um tamanho maior do que o original ou granuladas se escalonadas para tamanhos menores. Escalonamento provavelmente não é a melhor solução se você tiver algum texto que precisa ficar legível.
    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ão sWidth e sHeight e desenha essa imagem no canvas, posicionando ela em (dx, dy) e escalonando-a para o tamanho especificado por dWidth e dHeight.

    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().

    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;