Chụp Canvas HTML dưới dạng gif / jpg / png / pdf?


719

Có thể chụp hoặc in những gì được hiển thị trong một khung vải html dưới dạng hình ảnh hoặc pdf không?

Tôi muốn tạo một hình ảnh thông qua canvas và có thể tạo png từ hình ảnh đó.


Đây là một giải pháp pythonic: stackoverflow.com/questions/19395649/ trên ngoài việc trả lời stackoverflow.com/a35314404/529442
Eugene Gr. Philippov


Ví dụ ở đây freakyjolly.com/ từ
Code Spy

1
Bạn có thể thấy thư viện
canvas2image

Câu trả lời:


737

Giáo sư. Câu trả lời ban đầu là cụ thể cho một câu hỏi tương tự. Điều này đã được sửa đổi:

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

với giá trị trong IMG bạn có thể viết nó thành một hình ảnh mới như vậy:

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

15
một câu hỏi nữa, làm thế nào tôi có thể lưu hình ảnh tôi có trong thẻ này vào máy chủ. Có đoán được không ??
Surya

7
Nhưng nếu tôi sử dụng var img = canvas.toDataURL ("image / jpeg"); đang nhận được nền là màu đen hoàn toàn. Làm thế nào để khắc phục điều đó
gauti 23/12/13

181
Thôi nào. Tôi đã trả lời điều này vào năm 2009. Bạn mong đợi điều gì?
donohoe

35
@donohoe thực sự bạn đã trả lời nó vào tháng 8 năm 2010 :)
nick

13
Nó sẽ sử dụng ít bộ nhớ hơn để làm một cái gì đó như thế var img = new Image(); img.src = canvas.toDataURL(); document.body.appendChild(img);. Các document.writecode được làm URL dữ liệu, họ thực hiện một chuỗi HTML, sau đó đặt một bản sao của chuỗi mà trong DOM, trình duyệt sau đó đã phân tích rằng chuỗi HTML, đặt một bản sao trên các yếu tố hình ảnh, sau đó phân tích nó một lần nữa để biến URL dữ liệu vào dữ liệu hình ảnh, sau đó cuối cùng nó có thể hiển thị hình ảnh. Đối với hình ảnh kích thước màn hình đó là một lượng lớn bộ nhớ / sao chép / phân tích cú pháp. Chỉ là một gợi ý
gman

116

HTML5 cung cấp Canvas.toDataURL (mimetype) được triển khai trong Opera, Firefox và Safari 4 beta. Tuy nhiên, có một số hạn chế về bảo mật (chủ yếu là để vẽ nội dung từ nguồn gốc khác lên khung vẽ).

Vì vậy, bạn không cần một thư viện bổ sung.

ví dụ

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

Về mặt lý thuyết, điều này sẽ tạo và sau đó điều hướng đến một hình ảnh có hình vuông màu xanh lá cây ở giữa nó, nhưng tôi chưa thử nghiệm.


2
Nơi hình ảnh sẽ được lưu. Địa điểm tại địa phương của tôi?
chinna_82

5
hình ảnh sẽ được hiển thị dưới dạng hình ảnh trong trình duyệt của bạn. Sau đó bạn có thể lưu nó vào đĩa hoặc bất cứ điều gì. Đây là một bookmarklet "Canvas2PNG" chung chung nhanh và bẩn, chuyển đổi khung vẽ đầu tiên trong trang thành PNG và hiển thị nó trong trình duyệt trong một cửa sổ mới:javascript:void(window.open().location = document.getElementsByTagName("canvas")[0].toDataURL("image/png"))
Kai Carver

Nếu hình ảnh có kích thước vài MB, hãy chuẩn bị đánh sập trình duyệt của bạn (tôi đã làm điều đó một thời gian trước trong FireFox).
14:00

1
Làm thế nào điều này có thể được sửa đổi để kết xuất nhiều hình ảnh?
Mentalist

URI dữ liệu có độ dài tối đa, do đó, có giới hạn trên về kích thước của hình ảnh mà bạn có thể đặt vào url dữ liệu.
Juha Syrjälä

44

Tôi nghĩ rằng tôi sẽ mở rộng phạm vi của câu hỏi này một chút, với một số thông tin hữu ích về vấn đề này.

Để có được khung vẽ dưới dạng hình ảnh, bạn nên làm như sau:

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

Bạn có thể sử dụng điều này để viết hình ảnh lên trang:

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

Trong đó "image / png" là loại mime (png là loại duy nhất phải được hỗ trợ). Nếu bạn muốn một mảng các loại được hỗ trợ, bạn có thể làm gì đó dọc theo dòng này:

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

Bạn chỉ cần chạy cái này một lần trên mỗi trang - nó sẽ không bao giờ thay đổi qua vòng đời của trang.

Nếu bạn muốn làm cho người dùng tải xuống tệp khi nó được lưu, bạn có thể làm như sau:

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;

Nếu bạn đang sử dụng loại đó với các loại mime khác nhau, hãy đảm bảo thay đổi cả hai trường hợp của hình ảnh / png, nhưng không phải là hình ảnh / octet-stream. Một điều đáng nói nữa là nếu bạn sử dụng bất kỳ tài nguyên tên miền chéo nào trong kết xuất canvas của mình, bạn sẽ gặp phải lỗi bảo mật khi bạn cố gắng sử dụng phương thức toDataUrl.


1
Với giải pháp của bạn để tải xuống tệp, tôi phải chọn phần mềm tôi muốn sử dụng, điều đó hơi bất tiện ... Có cách nào để thay thế mime như png đã tải xuống không?
So4ne

1
@ So4ne Tôi không nghĩ vậy, nó phải là một hình ảnh / octet-stream để nhắc người dùng tải xuống. Nếu bạn thoát khỏi dòng đó, bạn sẽ kết thúc với trang chuyển hướng đến hình ảnh. Tôi rất muốn biết nếu người khác biết một cách để làm điều này độc đáo, mặc dù.
meiamsome

2
sử dụng target = "_ blank" trên <a> link và .click () cũng sẽ hoạt động để kích hoạt tải xuống (được thử nghiệm với FF data-url và download = "filename" cho text / csv và text / plain)
Ax3l

Điều đó thật tuyệt. Cảm ơn! Nhưng nếu tôi muốn lưu vào máy chủ và không cục bộ thì sao? Đầu vào tệp biểu mẫu có chấp nhận img src dưới dạng nội dung có thể tải lên không?
Nhà giả kim trưởng

Giáo sư. Chỉ cần tìm thấy câu trả lời. Để lại câu hỏi trước đó trong trường hợp người khác cũng đang tìm kiếm stackoverflow.com/questions/13198131/iêu
Nhà giả kim trưởng

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

Tệp đã lưu vẫn ở định dạng .svg. Làm thế nào để lưu nó như png?
nullpulum

Đây là một giải pháp tốt ngoại trừ việc nó có thể không hoạt động trên IE. Gặp lỗi "Vùng dữ liệu được truyền cho một cuộc gọi hệ thống quá nhỏ"
Jose Cherian

Trong Chrome, nó báo "Lỗi mạng", trong khi ở Firefox, nó hoạt động rất tốt. (Trên Linux)
Ecker00

20

Tôi sẽ sử dụng " wkhtmltopdf ". Nó chỉ hoạt động tuyệt vời. Nó sử dụng công cụ webkit (được sử dụng trong Chrome, Safari, v.v.) và rất dễ sử dụng:

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

Đó là nó!

Thử nó


1
Tôi cũng ở trong trại wkhtmltopdf. Chúng tôi đã sử dụng nó để lưu trữ và TUYỆT VỜI của nó.
Daniel Szabo

Làm cách nào để sử dụng WKHTMLtoPDF trong trang yêu cầu thông tin đăng nhập? Tôi đang sử dụng Jsreport để chuyển đổi sang PDF nhưng tôi chụp nội dung của mình bằng HTML2Canvas, tôi gặp vấn đề với việc gửi Canvas dưới dạng tham số tới JSreport
khaled Dehia


15

Dưới đây là một số trợ giúp nếu bạn thực hiện tải xuống thông qua một máy chủ (theo cách này bạn có thể đặt tên / chuyển đổi / hậu xử lý / vv tập tin của bạn):

Dữ liệu -Post sử dụng toDataURL

-Thiết lập các tiêu đề

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

hình ảnh -tạo

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

-xuất hình ảnh dưới dạng 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();

-Hoặc như PNG trong suốt

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

9

Một giải pháp thú vị khác là PhantomJS . Đó là một kịch bản WebKit không đầu với JavaScript hoặc CoffeeScript.

Một trong những trường hợp sử dụng là chụp màn hình: bạn có thể lập trình chụp nội dung web, bao gồm SVG và Canvas và / hoặc Tạo ảnh chụp màn hình trang web với xem trước hình thu nhỏ.

Điểm vào tốt nhất là trang wiki chụp màn hình .

Dưới đây là một ví dụ tốt cho đồng hồ cực (từ RaphaelJS):

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

Bạn có muốn kết xuất một trang thành PDF?

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

2
+1: PhantomJS là hệ thống đơn giản, được ghi chép tốt và chu đáo, hoàn hảo cho công việc này. Nó cũng cho phép nhiều hơn là chỉ lấy một khung vẽ - ví dụ, bạn có thể sửa đổi trang hoặc một phần của nó (thông qua JS) trước khi lấy để làm cho nó trông giống như bạn muốn. Hoàn hảo!
johndodo

1
PhantomJs đã lỗi thời
Merc

3

Nếu bạn đang sử dụng jQuery, điều mà khá nhiều người làm, thì bạn sẽ thực hiện câu trả lời được chấp nhận như vậy:

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

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

12
Xin lưu ý rằng cách sử dụng duy nhất của jQuery ở đây là lựa chọn canvas. .toDataURLlà bản địa của JS.
j6m8

Tôi đã lưu vấn đề mà ai đó có thể giúp tôi xem liên kết này: stackoverflow.com/questions/25131763/NH
Ramesh S

2
Giải pháp jQuery thuần túy (100%) là như sau: $('<img>').attr('src',$('#mycanvas')[0].toDataURL('image/png')).appendTo($('#element-to-write-to').empty());Chính xác là một dòng.
Naeel Maqsudov

1

Bạn có thể sử dụng jspdf để chụp canvas vào hình ảnh hoặc pdf như thế này:

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

Thông tin thêm: https://github.com/MrRio/jsPDF


1

Đây là một cách khác, không có chuỗi mặc dù tôi không thực sự biết nó có nhanh hơn hay không. Thay vì toDataURL (như tất cả các câu hỏi ở đây đề xuất). Trong trường hợp của tôi, tôi muốn ngăn dataUrl / base64 vì tôi cần một bộ đệm Array hoặc dạng xem. Vì vậy, phương pháp khác trong HTMLCanvasEuity là toBlob. (Hàm 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));
}

Một ưu điểm khác của các đốm màu là bạn có thể tạo ObjectUrl để biểu thị dữ liệu dưới dạng tệp, tương tự như thành viên 'tệp' của HTMLInputFile. Thêm thông tin:

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


-1

Trên một số phiên bản Chrome, bạn có thể:

  1. Sử dụng chức năng vẽ hình ảnh ctx.drawImage(image1, 0, 0, w, h);
  2. Nhấp chuột phải vào khung vẽ
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.