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.

Parand
fonte
Aqui está uma solução pitônica: stackoverflow.com/questions/19395649/… , além de responder stackoverflow.com/a/3514404/529442
Eugene Gr. Philippov 23/05
Exemplo aqui freakyjolly.com/…
Código Spy
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+'"/>');
donohoe
fonte
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.

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

meiamsome
fonte
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);
}
david.barkhuizen
fonte
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

lepe
fonte
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
@khaledDehia check: stackoverflow.com/questions/10287386/…
lepe
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);
Comunidade
fonte
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
Cybermaxs
fonte
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+'"/>');
Pattle
fonte
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

ferralucho
fonte
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

cancerbero
fonte
-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
Pedro
fonte