admin管理员组文章数量:1125929
Is it possible to capture or print what's displayed in an HTML canvas as an image or PDF?
I'd like to generate an image via canvas and be able to generate a PNG from that image.
Is it possible to capture or print what's displayed in an HTML canvas as an image or PDF?
I'd like to generate an image via canvas and be able to generate a PNG from that image.
Share Improve this question edited Feb 11, 2023 at 20:18 Matthias Braun 34.2k27 gold badges152 silver badges176 bronze badges asked May 29, 2009 at 0:28 ParandParand 106k49 gold badges154 silver badges188 bronze badges 6- Here's a pythonic solution: stackoverflow.com/questions/19395649/… in addition to answer stackoverflow.com/a/3514404/529442 – Eugene Gr. Philippov Commented May 23, 2016 at 16:20
- 1 HTMLCanvasElement/toDataURL#Examples – sam Commented Oct 8, 2016 at 22:10
- Example here freakyjolly.com/… – Code Spy Commented Jun 8, 2018 at 9:45
- 2 You might find canvas2image library useful for this: github.com/hongru/canvas2image – koders Commented Dec 29, 2018 at 1:17
- 2 If someone is looking for an answer related to React, I wrote two tutorials about it yesterday: React Component to Image and React Component to PDF. – Robin Wieruch Commented Sep 30, 2021 at 15:35
16 Answers
Reset to default 856Original answer was specific to a similar question. This has been revised:
const canvas = document.getElementById('mycanvas')
const img = canvas.toDataURL('image/png')
With the value in img
you can write it out as a new image like so:
document.getElementById('existing-image-id').src = img
or
document.write('<img src="'+img+'"/>');
HTML5 provides Canvas.toDataURL(mimetype) which is implemented in Opera, Firefox, and Safari 4 beta. There are a number of security restrictions, however (mostly to do with drawing content from another origin onto the canvas).
So you don't need an additional library.
e.g.
<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>
Theoretically this should create and then navigate to an image with a green square in the middle of it, but I haven't tested.
I thought I'd extend the scope of this question a bit, with some useful tidbits on the matter.
In order to get the canvas as an image, you should do the following:
var canvas = document.getElementById("mycanvas");
var image = canvas.toDataURL("image/png");
You can use this to write the image to the page:
document.write('<img src="'+image+'"/>');
Where "image/png" is a mime type (png is the only one that must be supported). If you would like an array of the supported types you can do something along the lines of this:
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];
}
}
You only need to run this once per page - it should never change through a page's lifecycle.
If you wish to make the user download the file as it is saved you can do the following:
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;
If you're using that with different mime types, be sure to change both instances of image/png, but not the image/octet-stream. It is also worth mentioning that if you use any cross-domain resources in rendering your canvas, you will encounter a security error when you try to use the toDataUrl method.
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);
}
I would use "wkhtmltopdf". It just work great. It uses webkit engine (used in Chrome, Safari, etc.), and it is very easy to use:
wkhtmltopdf stackoverflow.com/questions/923885/ this_question.pdf
That's it!
Try it
Here is some help if you do the download through a server (this way you can name/convert/post-process/etc your file):
-Post data using toDataURL
-Set the headers
$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");
-create image
$data = $_POST['data'];
$img = imagecreatefromstring(base64_decode(substr($data,strpos($data,',')+1)));
-export image as 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();
-or as transparent PNG
imagesavealpha($img, true);
imagepng($img);
die($img);
This is the other way, without strings although I don't really know if it's faster or not. Instead of toDataURL (as all questions here propose). In my case want to prevent dataUrl/base64 since I need a Array buffer or view. So the other method in HTMLCanvasElement is toBlob
. (TypeScript function):
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));
}
Another advantage of blobs is you can create ObjectUrls to represent data as files, similar to HTMLInputFile's 'files' member. More info:
https://developer.mozilla.org/en/docs/Web/API/HTMLCanvasElement/toBlob
Another interesting solution is PhantomJS. It's a headless WebKit scriptable with JavaScript or CoffeeScript.
One of the use case is screen capture : you can programmatically capture web contents, including SVG and Canvas and/or Create web site screenshots with thumbnail preview.
The best entry point is the screen capture wiki page.
Here is a good example for polar clock (from RaphaelJS):
>phantomjs rasterize.js http://raphaeljs.com/polar-clock.html clock.png
Do you want to render a page to a PDF ?
> phantomjs rasterize.js 'http://en.wikipedia.org/w/index.php?title=Jakarta&printable=yes' jakarta.pdf
If you are using jQuery, which quite a lot of people do, then you would implement the accepted answer like so:
var canvas = $("#mycanvas")[0];
var img = canvas.toDataURL("image/png");
$("#elememt-to-write-to").html('<img src="'+img+'"/>');
The key point is
canvas.toDataURL(type, quality)
And I want to provide an example for someone like me who wants to save SVG to PNG(also can add some text if you wish), which may be from an Online source or font-awesome icon, etc.
Example
100% javascript and no other 3-rd library.
<script>
(() => {
window.onload = () => {
// Test 1: SVG from Online
const canvas = new Canvas(650, 500)
// canvas.DrawGrid() // If you want to show grid, you can use it.
const svg2img = new SVG2IMG(canvas.canvas, "https://upload.wikimedia.org/wikipedia/commons/b/bd/Test.svg")
svg2img.AddText("Hello", 100, 250, {mode: "fill", color: "yellow", alpha: 0.8})
svg2img.AddText("world", 200, 250, {mode: "stroke", color: "red"})
svg2img.AddText("!", 280, 250, {color: "#f700ff", size: "72px"})
svg2img.Build("Test.png")
// Test 2: URI.data
const canvas2 = new Canvas(180, 180)
const uriData = "data:image/svg+xml;base64,PHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtc21pbGUtd2luayBmYS13LTE2IiBhcmlhLWhpZGRlbj0idHJ1ZSIgZm9jdXNhYmxlPSJmYWxzZSIgZGF0YS1wcmVmaXg9ImZhciIgZGF0YS1pY29uPSJzbWlsZS13aW5rIiByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDQ5NiA1MTIiIGRhdGEtZmEtaTJzdmc9IiI+PHBhdGggZmlsbD0iY3VycmVudENvbG9yIiBkPSJNMjQ4IDhDMTExIDggMCAxMTkgMCAyNTZzMTExIDI0OCAyNDggMjQ4IDI0OC0xMTEgMjQ4LTI0OFMzODUgOCAyNDggOHptMCA0NDhjLTExMC4zIDAtMjAwLTg5LjctMjAwLTIwMFMxMzcuNyA1NiAyNDggNTZzMjAwIDg5LjcgMjAwIDIwMC04OS43IDIwMC0yMDAgMjAwem0xMTcuOC0xNDYuNGMtMTAuMi04LjUtMjUuMy03LjEtMzMuOCAzLjEtMjAuOCAyNS01MS41IDM5LjQtODQgMzkuNHMtNjMuMi0xNC4zLTg0LTM5LjRjLTguNS0xMC4yLTIzLjctMTEuNS0zMy44LTMuMS0xMC4yIDguNS0xMS41IDIzLjYtMy4xIDMzLjggMzAgMzYgNzQuMSA1Ni42IDEyMC45IDU2LjZzOTAuOS0yMC42IDEyMC45LTU2LjZjOC41LTEwLjIgNy4xLTI1LjMtMy4xLTMzLjh6TTE2OCAyNDBjMTcuNyAwIDMyLTE0LjMgMzItMzJzLTE0LjMtMzItMzItMzItMzIgMTQuMy0zMiAzMiAxNC4zIDMyIDMyIDMyem0xNjAtNjBjLTI1LjcgMC01NS45IDE2LjktNTkuOSA0Mi4xLTEuNyAxMS4yIDExLjUgMTguMiAxOS44IDEwLjhsOS41LTguNWMxNC44LTEzLjIgNDYuMi0xMy4yIDYxIDBsOS41IDguNWM4LjUgNy40IDIxLjYuMyAxOS44LTEwLjgtMy44LTI1LjItMzQtNDIuMS01OS43LTQyLjF6Ij48L3BhdGg+PC9zdmc+"
const svg2img2 = new SVG2IMG(canvas2.canvas, uriData)
svg2img2.Build("SmileWink.png")
// Test 3: Exists SVG
ImportFontAwesome()
const range = document.createRange()
const fragSmile = range.createContextualFragment(`<i class="far fa-smile" style="background-color:black;color:yellow"></i>`)
document.querySelector(`body`).append(fragSmile)
// use MutationObserver wait the fontawesome convert ``<i class="far fa-smile"></i>`` to SVG. If you write the element in the HTML, then you can skip this hassle way.
const observer = new MutationObserver((mutationRecordList, observer) => {
for (const mutation of mutationRecordList) {
switch (mutation.type) {
case "childList":
const targetSVG = mutation.target.querySelector(`svg`)
if (targetSVG !== null) {
const canvas3 = new Canvas(64, 64) //
本文标签:
javascriptCapture HTML canvas as GIFJPGPNGPDFStack Overflow
版权声明:本文标题:javascript - Capture HTML canvas as GIFJPGPNGPDF? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人,
转载请联系作者并注明出处:http://www.betaflare.com/web/1736676996a1947233.html,
本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论