HTML Canvas'ı gif / jpg / png / pdf olarak yakalansın mı?


719

Bir html tuvalinde görüntülenenleri resim veya pdf olarak yakalamak veya yazdırmak mümkün mü?

Tuval üzerinden bir görüntü oluşturmak ve bu görüntüden bir png oluşturmak istiyorum.





1
Canvas2image kütüphanesini bunun için yararlı bulabilirsiniz: github.com/hongru/canvas2image
noego

Yanıtlar:


737

Hata. Orijinal cevap benzer bir soruya özgüdür. Bu revize edildi:

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

IMG'deki değerle, bunu aşağıdaki gibi yeni bir Resim olarak yazabilirsiniz:

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

15
bir soru daha, bu etiketteki görüntüyü sunucuya nasıl kaydedebilirim. Herhangi Bir tahmin??
Surya

7
Ama var img = canvas.toDataURL ("image / jpeg") kullanırsam; arka planı tam siyah olarak alıyorum. Bunu nasıl
düzeltebilirim

181
Ah, hadi ama. Bunu 2009 yılında yanıtladım. Ne bekliyorsunuz?
donohoe

35
@donohoe aslında Ağustos 2010'da cevapladınız :)
nick

13
Gibi bir şey yapmak için çok daha az bellek kullanır var img = new Image(); img.src = canvas.toDataURL(); document.body.appendChild(img);. document.writeBunların kodunu sonra DOM bu dizinin bir kopyasını koyarak, bir HTML dize yapım veri URL'yi yapıyor, tarayıcı daha sonra, görüntü elemanı üzerine başka bir kopyasını koymak, HTML dizesini ayrıştırmak açmak için tekrar ayrıştırması gerekir veri URL'sini resim verilerine ekledikten sonra resmi gösterebilir. Büyük miktarda bellek / kopyalama / ayrıştırma olan bir ekran boyutu görüntüsü için. Sadece bir öneri
gman

116

HTML5, Opera, Firefox ve Safari 4 beta sürümlerinde uygulanan Canvas.toDataURL (mimetype) işlevini sağlar. Bununla birlikte, bir dizi güvenlik kısıtlaması vardır (çoğunlukla başka bir kaynaktan gelen içeriği tuval üzerine çizmekle ilgilidir).

Yani ek bir kütüphaneye ihtiyacınız yok.

Örneğin

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

Teorik olarak bu, ortasında yeşil bir kare olan bir görüntü oluşturmalı ve bu görüntüye gitmelidir, ancak test etmedim.


2
Görüntünün nereye kaydedileceği. Yerel konum?
chinna_82

5
resim tarayıcınızda bir resim olarak görüntülenir. Daha sonra diske veya her neyse kaydedebilirsiniz. İşte sayfadaki ilk tuvali PNG'ye dönüştüren ve tarayıcıda yeni bir pencerede görüntüleyen hızlı ve kirli bir genel "Canvas2PNG" yer işareti:javascript:void(window.open().location = document.getElementsByTagName("canvas")[0].toDataURL("image/png"))
Kai Carver

Görüntü birkaç MB boyutundaysa, tarayıcınızı kilitlemeye hazırlanın (FireFox'ta bir süre yaptım).
jahu

1
Bu, birden fazla görüntü oluşturmak için nasıl değiştirilebilir?
Mentalist

Veri URI'lerinin maksimum uzunluğu vardır, bu nedenle bir veri URL'sine koyabileceğiniz bir görüntünün boyutu için üst sınır vardır.
Juha Syrjälä

44

Bu sorunun kapsamını biraz genişleteceğimi, konuyla ilgili bazı yararlı bilgilerle düşündüm.

Tuvali bir görüntü olarak almak için aşağıdakileri yapmanız gerekir:

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

Görüntüyü sayfaya yazmak için bunu kullanabilirsiniz:

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

"Resim / png" bir mime türüdür (png, desteklenmesi gereken tek biçimdir). Desteklenen türlerden bir dizi istiyorsanız, bunun satırları boyunca bir şeyler yapabilirsiniz:

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

Bunu sayfa başına yalnızca bir kez çalıştırmanız yeterlidir; hiçbir zaman sayfanın yaşam döngüsü boyunca değişmemelidir.

Kullanıcının dosyayı kaydedildiği gibi indirmesini istiyorsanız, aşağıdakileri yapabilirsiniz:

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;

Bunu farklı mime türleriyle kullanıyorsanız, görüntü / png öğelerinin her ikisini de değiştirdiğinizden emin olun, ancak görüntü / sekizli akışını değiştirmeyin. Tuvalinizi oluştururken herhangi bir etki alanları arası kaynak kullanırsanız, toDataUrl yöntemini kullanmaya çalıştığınızda bir güvenlik hatasıyla karşılaşacağınızı belirtmek gerekir.


1
Dosyayı indirmek için çözümünüzle, kullanmak istediğim yazılımı seçmeliyim, biraz rahatsız edici ... Mime'i indirdikten sonra png'yi değiştirmenin bir yolu var mı?
So4ne

1
@ So4ne Ben öyle düşünmüyorum, kullanıcı bir indirme için istemek için bir görüntü / octet-akışı olması gerekir. Bu satırdan kurtulursanız, görüntüye yönlendiren sayfayla sonuçlanırsınız. Yine de, başka birinin bunu güzel yapmanın bir yolunu biliyor olup olmadığını bilmek isterim.
meiamsome

2
<a> bağlantısında ve .click () hedef = "_ blank" kullanarak, indirme işlemini tetiklemek için de çalışmalıdır (FF data-urls ile test edildi ve text / csv ve text / plain için download = "dosyaadı")
Ax3l

Bu harika. Teşekkürler! Peki yerel olarak değil sunucuya kaydetmek istersem ne olur? Bir form dosyası girişi img src'yi yüklenebilir bir şey olarak kabul eder mi?
Şef Simyacı

Hata. Sadece cevabı buldum. Başkasının iyi görünmesi durumunda önceki soruyu terk stackoverflow.com/questions/13198131/…
Şef Simyacı

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

Kaydedilen dosya .svg biçiminde kalır. PNG olarak nasıl kaydedilir?
nullpointer

Bu IE üzerinde çalışmayabilir dışında güzel bir çözümdür. "Bir sistem çağrısına aktarılan veri alanı çok küçük" hatası alma
Jose Cherian

Chrome'da "Ağ hatası" yazıyor, Firefox'ta harika çalışıyor. (Linux'ta)
Ecker00

20

" Wkhtmltopdf " kullanırdım. Sadece harika çalışıyor. Webkit motoru kullanır (Chrome, Safari, vb. Kullanılır) ve kullanımı çok kolaydır:

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

Bu kadar!

Dene


1
Ben de wkhtmltopdf kampındayım. Arşivleme ve İNANILMAZ için kullanıyoruz.
Daniel Szabo

Giriş bilgileri gerektiren sayfada WKHTMLtoPDF nasıl kullanılır? PDF'ye dönüştürmek için Jsreport kullanıyorum ama HTML2Canvas ile içeriğimi yakaladım, Tuval'i parametre olarak JSreport'a göndermekle ilgili sorunum var
khaled Dehia


15

İndirmeyi bir sunucu üzerinden yaparsanız (yardımınızı bu şekilde adlandırabilir / dönüştürebilirsiniz / işlem sonrası / vb. Yapabilirsiniz):

-Verisini kullanarak verileri yayınlayın toDataURL

Başlıkları ayarlama

$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");

-görüntü yarat

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

-Görüntüyü JPEG olarak dışa aktarma

$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();

-veya şeffaf PNG olarak

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

9

Bir başka ilginç çözüm PhantomJS . JavaScript veya CoffeeScript ile yazılabilen başsız bir WebKit.

Kullanım durumlarından biri ekran görüntüsüdür: SVG ve Canvas dahil web içeriğini programlanabilir şekilde yakalayabilir ve / veya küçük resim önizlemesiyle web sitesi ekran görüntüleri oluşturabilirsiniz.

En iyi giriş noktası, ekran yakalama wiki sayfasıdır.

İşte kutup saati için iyi bir örnek (RaphaelJS'den):

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

PDF'ye sayfa oluşturmak ister misiniz?

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

2
+1: PhantomJS, bu iş için mükemmel olan basit, iyi belgelenmiş ve iyi düşünülmüş bir sistemdir. Tuvali kapmaktan çok daha fazlasını sağlar - örneğin, kapmadan önce sayfayı veya bir kısmını (JS aracılığıyla) değiştirebilirsiniz, böylece tam istediğiniz gibi görünmesini sağlayın. Mükemmel!
johndodo

1
PhantomJs artık kullanılmıyor
Merc

3

Birçok insanın yaptığı jQuery kullanıyorsanız, kabul edilen cevabı şu şekilde uygularsınız:

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

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

12
Burada jQuery'nin tek kullanımının tuval seçimi olduğunu unutmayın . .toDataURLyerel JS'dir.
j6m8 9:14

Bazıları bu bağlantıyı görmeme yardımcı olabilir tasarruf sorunu var: stackoverflow.com/questions/25131763/…
Ramesh S

2
Saf (% 100) jQuery çözümü şudur: $('<img>').attr('src',$('#mycanvas')[0].toDataURL('image/png')).appendTo($('#element-to-write-to').empty());Tam olarak bir satır.
Naeel Maqsudov

1

Bir tuvali bir görüntüye veya pdf'ye böyle yakalamak için jspdf kullanabilirsiniz:

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

Daha fazla bilgi: https://github.com/MrRio/jsPDF


1

Bu daha hızlı olup olmadığını bilmesem de, dizeler olmadan başka bir yol. ToDataURL yerine (buradaki tüm sorular önerdiği gibi). Benim durumumda bir dizi arabellek veya görünüm gerektiğinden dataUrl / base64 önlemek istiyorum. Yani HTMLCanvasElement içindeki diğer yöntem toBlob. (TypeScript işlevi):

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

Blob'ların bir başka avantajı da HTMLInputFile'ın 'files' üyesine benzer şekilde verileri dosya olarak temsil etmek için ObjectUrls oluşturabilmenizdir. Daha fazla bilgi:

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


-1

Chrome'un bazı sürümlerinde şunları yapabilirsiniz:

  1. Resim çiz fonksiyonunu kullanma ctx.drawImage(image1, 0, 0, w, h);
  2. Tuval üzerine sağ tıklayın
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.