Javascript 将 HTML 渲染为图像
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10721884/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Render HTML to an image
提问by Martin Delille
Is there a way to render html to image like PNG? I know that it is possible with canvas but I would like to render standard html element like div for example.
有没有办法将html呈现为像PNG这样的图像?我知道使用画布是可能的,但我想呈现标准的 html 元素,例如 div。
采纳答案by yan
I know this is quite an old question which already has a lot of answers, yet I still spent hours trying to actually do what I wanted:
我知道这是一个很老的问题,已经有很多答案,但我仍然花了几个小时试图真正做我想做的事:
- given an html file, generate a (png) image with transparentbackground from the command line
- 给定一个 html 文件,从命令行生成一个具有透明背景的 (png) 图像
Using Chrome headless (version 74.0.3729.157 as of this response), it is actually easy:
使用 Chrome headless(截至本回复的版本为 74.0.3729.157),实际上很容易:
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --headless --screenshot --window-size=256,256 --default-background-color=0 button.html
Explanation of the command:
命令的解释:
- you run Chrome from the command line (here shown for the Mac, but assuming similar on Windows or Linux)
--headless
runs Chrome without opening it and exits after the command completes--screenshot
will capture a screenshot (note that it generates a file calledscreenshot.png
in the folder where the command is run)--window-size
allow to only capture a portion of the screen (format is--window-size=width,height
)--default-background-color=0
is the magic trick that tells Chrome to use a transparentbackground, not the default white color- finally you provide the html file (as a url either local or remote...)
- 你从命令行运行 Chrome(这里显示的是 Mac,但假设在 Windows 或 Linux 上类似)
--headless
运行 Chrome 而不打开它并在命令完成后退出--screenshot
将捕获屏幕截图(请注意,它会生成一个screenshot.png
在运行命令的文件夹中调用的文件)--window-size
只允许捕获屏幕的一部分(格式为--window-size=width,height
)--default-background-color=0
是告诉 Chrome 使用透明背景的魔术,而不是默认的白色- 最后你提供 html 文件(作为本地或远程的 url...)
回答by AKX
Yes. HTML2Canvasexists to render HTML onto <canvas>
(which you can then use as an image).
是的。HTML2Canvas 的存在是为了在<canvas>
其上呈现 HTML (然后您可以将其用作图像)。
NOTE: There is a known issue, that this will not work with SVG
注意:有一个已知问题,这不适用于 SVG
回答by tsayen
May I recommend dom-to-imagelibrary, that was written solely to address this problem (I'm the maintainer).
Here is how you use it (some more here):
我可以推荐dom-to-image库,它是专门为解决这个问题而编写的(我是维护者)。
这是你如何使用它(这里还有一些):
var node = document.getElementById('my-node');
domtoimage.toPng(node)
.then (function (dataUrl) {
var img = new Image();
img.src = dataUrl;
document.appendChild(img);
})
.catch(function (error) {
console.error('oops, something went wrong!', error);
});
回答by Timothée Jeannin
There is a lot of options and they all have their pro and cons.
有很多选择,它们都有其优点和缺点。
Option 1: Use one of the many available libraries
选项 1:使用众多可用库之一
- dom-to-image
- wkhtmltoimage(included in the wkhtmltopdf tool)
- IMGKit(for ruby and based on wkhtmltoimage)
- imgkit(for python and based on wkhtmltoimage)
- python-webkit2png
- ...
- dom-to-image
- wkhtmltoimage(包含在 wkhtmltopdf 工具中)
- IMGKit(用于 ruby 并基于 wkhtmltoimage)
- imgkit(用于 python 和基于 wkhtmltoimage)
- python-webkit2png
- ...
Pros
优点
- Conversion is quite fast most of the time
- 大多数时候转换速度相当快
Cons
缺点
- Bad rendering
- Does not execute javascript
- No support for recent web features (FlexBox, Advanced Selectors, Webfonts, Box Sizing, Media Queries, ...)
- Sometimes not so easy to install
- Complicated to scale
- 糟糕的渲染
- 不执行javascript
- 不支持最近的 Web 功能(FlexBox、高级选择器、Webfonts、Box Sizing、媒体查询等)
- 有时不是那么容易安装
- 规模复杂
Option 2: Use PhantomJs and maybe a wrapper library
选项 2:使用 PhantomJs 和包装库
- PhantomJs
- node-webshot(javascript wrapper library for PhantomJs)
- ...
- PhantomJs
- node-webshot(PhantomJs 的 JavaScript 包装库)
- ...
Pros
优点
- Execute Javascript
- Quite fast
- 执行Javascript
- 蛮快
Cons
缺点
- Bad rendering
- No support for recent web features (FlexBox, Advanced Selectors, Webfonts, Box Sizing, Media Queries, ...)
- Complicated to scale
- Not so easy to make it work if there is images to be loaded ...
- 糟糕的渲染
- 不支持最近的 Web 功能(FlexBox、高级选择器、Webfonts、Box Sizing、媒体查询等)
- 规模复杂
- 如果要加载图像,则不太容易使其工作......
Option 3: Use Chrome Headless and maybe a wrapper library
选项 3:使用 Chrome Headless 和一个包装库
- Chrome Headless
- chrome-devtools-protocol
- Puppeteer(javascript wrapper library for Chrome headless)
- ...
Pros
优点
- Execute Javascript
- Near perfect rendering
- 执行Javascript
- 近乎完美的渲染
Cons
缺点
- Not so easy to have exactly the wanted result regarding:
- page load timing
- viewport dimensions
- Complicated to scale
- Quite slow and even slower if the html contains external links
- 在以下方面获得完全想要的结果并不那么容易:
- 页面加载时间
- 视口尺寸
- 规模复杂
- 如果 html 包含外部链接,速度会很慢甚至更慢
Option 4: Use an API
选项 4:使用 API
- ApiFlash(based on chrome)
- EvoPDF(has an option for html)
- Grabzit
- HTML/CSS to Image API
- ...
- ApiFlash(基于chrome)
- EvoPDF(有一个 html 选项)
- 抓斗
- HTML/CSS 到图像 API
- ...
Pros
优点
- Execute Javascript
- Near perfect rendering
- Fast when caching options are correctly used
- Scale is handled by the APIs
- Precise timing, viewport, ...
- Most of the time they offer a free plan
- 执行Javascript
- 近乎完美的渲染
- 正确使用缓存选项时速度快
- 规模由 API 处理
- 精确计时、视口、...
- 大多数时候他们提供免费计划
Cons
缺点
- Not free if you plan to use them a lot
- 如果您打算大量使用它们,则不是免费的
Disclosure: I'm the founder of ApiFlash. I did my best to provide an honest and useful answer.
披露:我是 ApiFlash 的创始人。我已尽力提供诚实而有用的答案。
回答by Sjeiti
All the answers here use third party libraries while rendering HTML to an image can be relatively simple in pure Javascript. There iswas even an article about iton the canvas section on MDN.
这里的所有答案都使用第三方库,而在纯 Javascript 中将 HTML 呈现为图像可能相对简单。还有的甚至一个关于它的文章上MDN画布部分。
The trick is this:
诀窍是这样的:
- create an SVG with a foreignObject node containing your XHTML
- set the src of an image to the data url of that SVG
drawImage
onto the canvas- set canvas data to target image.src
- 使用包含 XHTML 的 foreignObject 节点创建一个 SVG
- 将图像的 src 设置为该 SVG 的数据 url
drawImage
在画布上- 将画布数据设置为目标 image.src
const {body} = document
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
canvas.width = canvas.height = 100
const tempImg = document.createElement('img')
tempImg.addEventListener('load', onTempImageLoad)
tempImg.src = 'data:image/svg+xml,' + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><foreignObject width="100%" height="100%"><div xmlns="http://www.w3.org/1999/xhtml"><style>em{color:red;}</style><em>I</em> lick <span>cheese</span></div></foreignObject></svg>')
const targetImg = document.createElement('img')
body.appendChild(targetImg)
function onTempImageLoad(e){
ctx.drawImage(e.target, 0, 0)
targetImg.src = canvas.toDataURL()
}
Some things to note
一些注意事项
- The HTML inside the SVG has to be XHTML
- For security reasons the SVG as data url of an image acts as an isolated CSS scope for the HTML since no external sources can be loaded. So a Google font for instance has to be inlined using a tool like this one.
- Even when the HTML inside the SVG exceeds the size of the image it wil draw onto the canvas correctly. But the actual height cannot be measured from that image. A fixed height solution will work just fine but dynamic height will require a bit more work. The best is to render the SVG data into an iframe (for isolated CSS scope) and use the resulting size for the canvas.
- SVG 内的 HTML 必须是 XHTML
- 出于安全原因,SVG 作为图像的数据 url 充当 HTML 的独立 CSS 范围,因为无法加载外部源。因此,谷歌的字体,例如有使用类似工具内联这一个。
- 即使 SVG 中的 HTML 超过图像的大小,它也会正确地绘制到画布上。但是无法从该图像中测量实际高度。固定高度的解决方案可以很好地工作,但动态高度需要更多的工作。最好的方法是将 SVG 数据渲染到 iframe(用于隔离的 CSS 范围)并使用画布的结果大小。
回答by TheContrarian
回答by PinnyM
You can use an HTML to PDF tool like wkhtmltopdf. And then you can use a PDF to image tool like imagemagick. Admittedly this is server side and a very convoluted process...
您可以使用像 wkhtmltopdf 这样的 HTML 转 PDF 工具。然后你可以使用像 imagemagick 这样的 PDF 图像工具。不可否认,这是服务器端和一个非常复杂的过程......
回答by vabanagas
The only library that I got to work for Chrome, Firefox and MS Edge was rasterizeHTML. It outputs better quality that HTML2Canvas and is still supported unlike HTML2Canvas.
我为 Chrome、Firefox 和 MS Edge 工作的唯一库是rasterizeHTML。它输出的质量比 HTML2Canvas 更好,并且与 HTML2Canvas 不同,它仍然受支持。
Getting Element and Downloading as PNG
获取元素并下载为 PNG
var node= document.getElementById("elementId");
var canvas = document.createElement("canvas");
canvas.height = node.offsetHeight;
canvas.width = node.offsetWidth;
var name = "test.png"
rasterizeHTML.drawHTML(node.outerHTML, canvas)
.then(function (renderResult) {
if (navigator.msSaveBlob) {
window.navigator.msSaveBlob(canvas.msToBlob(), name);
} else {
const a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
a.href = canvas.toDataURL();
a.download = name;
a.click();
document.body.removeChild(a);
}
});
回答by Code Spy
Use html2canvasjust include plugin and call method to convert HTML to Canvas then download as image PNG
使用html2canvas只包含插件和调用方法将 HTML 转换为 Canvas 然后下载为图像 PNG
html2canvas(document.getElementById("image-wrap")).then(function(canvas) {
var link = document.createElement("a");
document.body.appendChild(link);
link.download = "manpower_efficiency.jpg";
link.href = canvas.toDataURL();
link.target = '_blank';
link.click();
});
Source: http://www.freakyjolly.com/convert-html-document-into-image-jpg-png-from-canvas/
来源:http: //www.freakyjolly.com/convert-html-document-into-image-jpg-png-from-canvas/
回答by Mohit Kulkarni
Use this code, it will surely work:
使用此代码,它肯定会起作用:
<script type="text/javascript">
$(document).ready(function () {
setTimeout(function(){
downloadImage();
},1000)
});
function downloadImage(){
html2canvas(document.querySelector("#dvContainer")).then(canvas => {
a = document.createElement('a');
document.body.appendChild(a);
a.download = "test.png";
a.href = canvas.toDataURL();
a.click();
});
}
</script>
Just do not forget to include Html2CanvasJS file in your program. https://html2canvas.hertzen.com/dist/html2canvas.js
只是不要忘记在您的程序中包含 Html2CanvasJS 文件。 https://html2canvas.hertzen.com/dist/html2canvas.js