Capturar tela HTML como gif / jpg / png / pdf?


719

É possível capturar ou imprimir o que é exibido em uma tela html como uma imagem ou pdf?

Gostaria de gerar uma imagem via tela e poder gerar um png a partir dessa imagem.





1
Você pode achar a biblioteca canvas2image útil para isso: github.com/hongru/canvas2image
— noego

Respostas:


737

Opa A resposta original foi específica para uma pergunta semelhante. Isso foi revisado:

var canvas = document.getElementById("mycanvas");
var img    = canvas.toDataURL("image/png");

com o valor em IMG, você pode escrevê-lo como uma nova imagem da seguinte forma:

document.write('<img src="'+img+'"/>');

15
mais uma pergunta, como posso salvar a imagem que obtive nesta tag no servidor. Algum palpite?
— Surya

7
Mas se eu usar var img = canvas.toDataURL ("image / jpeg"); estou obtendo o fundo como preto completo. Como corrigir isso
— gauti

181
Oh vamos lá. Eu respondi isso em 2009. O que você espera?
— donohoe

35
@donohoe, na verdade, você respondeu em agosto de 2010 :)
— nick

13
Usaria muito menos memória para fazer algo assim var img = new Image(); img.src = canvas.toDataURL(); document.body.appendChild(img);. O document.writecódigo está criando o URL dos dados, eles criando uma string HTML e, em seguida, colocando uma cópia dessa string no DOM, o navegador precisa analisar essa string HTML, colocar outra cópia no elemento de imagem e analisá-la novamente para ativar o URL de dados nos dados da imagem e, finalmente, ele pode mostrar a imagem. Para uma imagem em tamanho de tela, é uma quantidade enorme de memória / cópia / análise. Apenas uma sugestão
— gman

116

O HTML5 fornece Canvas.toDataURL (mimetype), implementado no Opera, Firefox e Safari 4 beta. Entretanto, existem várias restrições de segurança (principalmente relacionadas ao desenho de conteúdo de outra origem na tela).

Portanto, você não precisa de uma biblioteca adicional.

por exemplo

 <canvas id=canvas width=200 height=200></canvas>
 <script>
      window.onload = function() {
          var canvas = document.getElementById("canvas");
          var context = canvas.getContext("2d");
          context.fillStyle = "green";
          context.fillRect(50, 50, 100, 100);
          // no argument defaults to image/png; image/jpeg, etc also work on some
          // implementations -- image/png is the only one that must be supported per spec.
          window.location = canvas.toDataURL("image/png");
      }
 </script>

Teoricamente, isso deve criar e navegar para uma imagem com um quadrado verde no meio, mas não testei.


2
Onde a imagem será salva. Localização no meu local?
— chinna_82

5
a imagem será exibida como uma imagem no seu navegador. Você pode salvá-lo em disco ou o que for. Aqui está um bookmarklet rápida e suja genérica "Canvas2PNG" que converte a primeira tela na página para PNG e exibe no navegador em uma nova janela:javascript:void(window.open().location = document.getElementsByTagName("canvas")[0].toDataURL("image/png"))
— Kai Carver

Se a imagem tiver alguns MB, prepare-se para travar o navegador (fiz isso há algum tempo no FireFox).
— jahu

1
Como isso pode ser modificado para renderizar várias imagens?
— Mentalista

Os URIs de dados têm tamanho máximo, portanto, há um limite superior no tamanho de uma imagem que você pode colocar em um URL de dados.
— Juha Syrjälä

44

Pensei em ampliar um pouco o escopo dessa pergunta, com alguns boatos úteis sobre o assunto.

Para obter a tela como uma imagem, faça o seguinte:

var canvas = document.getElementById("mycanvas");
var image = canvas.toDataURL("image/png");

Você pode usar isso para escrever a imagem na página:

document.write('<img src="'+image+'"/>');

Onde "image / png" é do tipo mime (png é o único que deve ser suportado). Se você deseja uma matriz dos tipos suportados, pode fazer algo como:

var imageMimes = ['image/png', 'image/bmp', 'image/gif', 'image/jpeg', 'image/tiff']; //Extend as necessary 
var acceptedMimes = new Array();
for(i = 0; i < imageMimes.length; i++) {
    if(canvas.toDataURL(imageMimes[i]).search(imageMimes[i])>=0) {
        acceptedMimes[acceptedMimes.length] = imageMimes[i];
    }
}

Você só precisa executá-lo uma vez por página - nunca deve mudar no ciclo de vida de uma página.

Se você deseja fazer o usuário baixar o arquivo como ele é salvo, você pode fazer o seguinte:

var canvas = document.getElementById("mycanvas");
var image = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream"); //Convert image to 'octet-stream' (Just a download, really)
window.location.href = image;

Se você estiver usando isso com diferentes tipos de mímica, altere as duas instâncias de image / png, mas não a imagem / octet-stream. Também vale a pena mencionar que, se você usar algum recurso entre domínios na renderização de sua tela, encontrará um erro de segurança ao tentar usar o método toDataUrl.


1
Com a sua solução para baixar o arquivo, devo escolher o software que quero usar, é um pouco inconveniente ... Existe uma maneira de substituir o mime como png depois de baixado?
— So4ne

1
@ So4ne Acho que não, tem que ser um fluxo de imagem / octeto para solicitar ao usuário o download. Se você se livrar dessa linha, a página será redirecionada para a imagem. Eu adoraria saber se alguém sabe como fazer isso muito bem.
— meiamsome 26/12/13

2
usando target = "_ blank" no link <a> e .click (), também deve funcionar para acionar o download (testado com URLs de dados FF e download = "filename" para texto / csv e texto / sem formatação)
— Ax3l

Isso é ótimo. Obrigado! Mas e se eu quiser salvar no servidor e não no local? Uma entrada de arquivo de formulário aceitará o img src como algo que pode ser carregado?
— Chefe Alchemist

Opa Acabei de encontrar a resposta. Deixando a pergunta anterior no caso de alguém procurar também stackoverflow.com/questions/13198131/…
— Chief Alchemist

34
function exportCanvasAsPNG(id, fileName) {

    var canvasElement = document.getElementById(id);

    var MIME_TYPE = "image/png";

    var imgURL = canvasElement.toDataURL(MIME_TYPE);

    var dlLink = document.createElement('a');
    dlLink.download = fileName;
    dlLink.href = imgURL;
    dlLink.dataset.downloadurl = [MIME_TYPE, dlLink.download, dlLink.href].join(':');

    document.body.appendChild(dlLink);
    dlLink.click();
    document.body.removeChild(dlLink);
}

O arquivo salvo permanece no formato .svg. Como salvá-lo como png?
— Nulopointer

Esta é uma boa solução, exceto que ela pode não funcionar no IE. Recebendo erro "A área de dados passada para uma chamada de sistema é muito pequena"
— José Cherian

No Chrome, diz "Erro de rede", enquanto no Firefox funciona muito bem. (Linux)
— Ecker00

20

Eu usaria " wkhtmltopdf ". Apenas funciona muito bem. Ele usa o mecanismo de webkit (usado no Chrome, Safari etc.) e é muito fácil de usar:

wkhtmltopdf stackoverflow.com/questions/923885/ this_question.pdf

É isso aí!

Tente


1
Também estou no campo wkhtmltopdf. Temos usado para arquivamento e sua incrível.
— Daniel Szabo

Como usar o WKHTMLtoPDF na página que exigia informações de login? Eu estou usando Jsreport para converter em PDF, mas eu capturar o meu conteúdo com HTML2Canvas, eu tenho problema com o envio a tela como parâmetro para JSreport
— khaled Dehia


15

Aqui está uma ajuda se você fizer o download através de um servidor (desta forma, você pode nomear / converter / pós-processar / etc seu arquivo):

-Postar dados usando toDataURL

-Definir os cabeçalhos

$filename = "test.jpg"; //or png
header('Content-Description: File Transfer');
if($msie = !strstr($_SERVER["HTTP_USER_AGENT"],"MSIE")==false)      
  header("Content-type: application/force-download");else       
  header("Content-type: application/octet-stream"); 
header("Content-Disposition: attachment; filename=\"$filename\"");   
header("Content-Transfer-Encoding: binary"); 
header("Expires: 0"); header("Cache-Control: must-revalidate"); 
header("Pragma: public");

-criar imagem

$data = $_POST['data'];
$img = imagecreatefromstring(base64_decode(substr($data,strpos($data,',')+1)));

-exportar imagem como JPEG

$width = imagesx($img);
$height = imagesy($img);
$output = imagecreatetruecolor($width, $height);
$white = imagecolorallocate($output,  255, 255, 255);
imagefilledrectangle($output, 0, 0, $width, $height, $white);
imagecopy($output, $img, 0, 0, 0, 0, $width, $height);
imagejpeg($output);
exit();

-ou como PNG transparente

imagesavealpha($img, true);
imagepng($img);
die($img);

9

Outra solução interessante é o PhantomJS . É um WebKit decapitado com script em JavaScript ou CoffeeScript.

Um dos casos de uso é a captura de tela: você pode capturar programaticamente o conteúdo da Web, incluindo SVG e Canvas e / ou Criar capturas de tela de sites com visualização em miniatura.

O melhor ponto de entrada é a página wiki de captura de tela .

Aqui está um bom exemplo para o relógio polar (de RaphaelJS):

>phantomjs rasterize.js http://raphaeljs.com/polar-clock.html clock.png

Deseja renderizar uma página em PDF?

> phantomjs rasterize.js 'http://en.wikipedia.org/w/index.php?title=Jakarta&printable=yes' jakarta.pdf

2
+1: O PhantomJS é um sistema simples, bem documentado e bem pensado, perfeito para este trabalho. Ele permite muito mais do que apenas pegar uma tela também - por exemplo, você pode modificar a página ou parte dela (através do JS) antes de pegar, para que ela pareça do jeito que você deseja. Perfeito!
— Johndodo 18/09/2013

1
O PhantomJs agora está obsoleto #
— Merc

3

Se você estiver usando jQuery, o que muitas pessoas fazem, você implementaria a resposta aceita da seguinte maneira:

var canvas = $("#mycanvas")[0];
var img = canvas.toDataURL("image/png");

$("#elememt-to-write-to").html('<img src="'+img+'"/>');

12
Observe que o único uso do jQuery aqui é a seleção da tela. .toDataURLé JS nativo.
— J6m8

Eu tenho o problema de salvar que alguém pode me ajudar a ver este link: stackoverflow.com/questions/25131763/…
— Ramesh S

2
A solução pura (100%) do jQuery é a seguinte: $('<img>').attr('src',$('#mycanvas')[0].toDataURL('image/png')).appendTo($('#element-to-write-to').empty());Exatamente uma linha.
— Naeel Maqsudov

1

Você pode usar o jspdf para capturar uma tela em uma imagem ou pdf como este:

var imgData = canvas.toDataURL('image/png');              
var doc = new jsPDF('p', 'mm');
doc.addImage(imgData, 'PNG', 10, 10);
doc.save('sample-file.pdf');

Mais informações: https://github.com/MrRio/jsPDF


1

Essa é a outra maneira, sem strings, embora eu realmente não saiba se é mais rápido ou não. Em vez de toDataURL (como todas as perguntas aqui propõem). No meu caso, quero impedir o dataUrl / base64, pois preciso de um buffer ou exibição de matriz. Portanto, o outro método em HTMLCanvasElement é toBlob. (Função TypeScript):

    export function canvasToArrayBuffer(canvas: HTMLCanvasElement, mime: string): Promise<ArrayBuffer> {
  return new Promise((resolve, reject) => canvas.toBlob(async (d) => {
    if (d) {
      const r = new FileReader();
      r.addEventListener('loadend', e => {
        const ab = r.result;
        if (ab) {
          resolve(ab as ArrayBuffer);
        }
        else {
           reject(new Error('Expected FileReader result'));
        }
      }); r.addEventListener('error', e => {
        reject(e)
      });
      r.readAsArrayBuffer(d);
    }
    else {
      reject(new Error('Expected toBlob() to be defined'));
    }
  }, mime));
}

Outra vantagem dos blobs é que você pode criar ObjectUrls para representar dados como arquivos, semelhante ao membro 'files' do HTMLInputFile. Mais informações:

https://developer.mozilla.org/es/docs/Web/API/HTMLCanvasElement/toBlob


-1

Em algumas versões do Chrome, você pode:

  1. Use a função desenhar imagem ctx.drawImage(image1, 0, 0, w, h);
  2. Clique com o botão direito na tela
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.