将HTML渲染为图像

是否有一种方法将html渲染成PNG那样的图像?我知道这是可能的与画布,但我想渲染标准的html元素,如div为例。

502135 次浏览

你可以使用像wkhtmltopdf这样的HTML转PDF工具。然后你可以使用像imagemagick这样的PDF图像工具。不可否认,这是服务器端,一个非常复杂的过程…

我不认为这是最好的答案,但它似乎很有趣,可以发布。

编写一个应用程序,打开您最喜欢的浏览器到所需的HTML文档,适当大小的窗口,并采取屏幕截图。然后,删除图像的边界。

是的。HTML2Canvas的存在是为了将HTML呈现到<canvas>上(然后你可以将其用作图像)。

注意:有一个已知的问题,这将不适用于SVG

仅用JavaScript无法100%准确地做到这一点。

这里有Qt Webkit 工具出python版本。如果你想自己做,我已经成功地用可可:

[self startTraverse:pagesArray performBlock:^(int collectionIndex, int pageIndex) {


NSString *locale = [self selectedLocale];


NSRect offscreenRect = NSMakeRect(0.0, 0.0, webView.frame.size.width, webView.frame.size.height);
NSBitmapImageRep* offscreenRep = nil;


offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
pixelsWide:offscreenRect.size.width
pixelsHigh:offscreenRect.size.height
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
colorSpaceName:NSCalibratedRGBColorSpace
bitmapFormat:0
bytesPerRow:(4 * offscreenRect.size.width)
bitsPerPixel:32];


[NSGraphicsContext saveGraphicsState];


NSGraphicsContext *bitmapContext = [NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep];
[NSGraphicsContext setCurrentContext:bitmapContext];
[webView displayRectIgnoringOpacity:offscreenRect inContext:bitmapContext];
[NSGraphicsContext restoreGraphicsState];


// Create a small + large thumbs
NSImage *smallThumbImage = [[NSImage alloc] initWithSize:thumbSizeSmall];
NSImage *largeThumbImage = [[NSImage alloc] initWithSize:thumbSizeLarge];


[smallThumbImage lockFocus];
[[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];
[offscreenRep drawInRect:CGRectMake(0, 0, thumbSizeSmall.width, thumbSizeSmall.height)];
NSBitmapImageRep *smallThumbOutput = [[NSBitmapImageRep alloc] initWithFocusedViewRect:CGRectMake(0, 0, thumbSizeSmall.width, thumbSizeSmall.height)];
[smallThumbImage unlockFocus];


[largeThumbImage lockFocus];
[[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];
[offscreenRep drawInRect:CGRectMake(0, 0, thumbSizeLarge.width, thumbSizeLarge.height)];
NSBitmapImageRep *largeThumbOutput = [[NSBitmapImageRep alloc] initWithFocusedViewRect:CGRectMake(0, 0, thumbSizeLarge.width, thumbSizeLarge.height)];
[largeThumbImage unlockFocus];


// Write out small
NSString *writePathSmall = [issueProvider.imageDestinationPath stringByAppendingPathComponent:[NSString stringWithFormat:@"/%@-collection-%03d-page-%03d_small.png", locale, collectionIndex, pageIndex]];
NSData *dataSmall = [smallThumbOutput representationUsingType:NSPNGFileType properties: nil];
[dataSmall writeToFile:writePathSmall atomically: NO];


// Write out lage
NSString *writePathLarge = [issueProvider.imageDestinationPath stringByAppendingPathComponent:[NSString stringWithFormat:@"/%@-collection-%03d-page-%03d_large.png", locale, collectionIndex, pageIndex]];
NSData *dataLarge = [largeThumbOutput representationUsingType:NSPNGFileType properties: nil];
[dataLarge writeToFile:writePathLarge atomically: NO];
}];

希望这能有所帮助!

你可以使用PhantomJS,这是一个无头webkit (safari中的渲染引擎和(直到最近)chrome)驱动程序。你可以学习如何截取页面在这里的屏幕。希望有帮助!

我可以推荐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);
});

你可以添加引用 HtmlRenderer到你的项目并执行以下操作,

string htmlCode ="<p>This is a sample html.</p>";
Image image = HtmlRender.RenderToImage(htmlCode ,new Size(500,300));

安装phantomjs

$ npm install phantomjs

用以下代码创建一个文件github.js

var page = require('webpage').create();
//viewportSize being the actual size of the headless browser
page.viewportSize = { width: 1024, height: 768 };
page.open('http://github.com/', function() {
page.render('github.png');
phantom.exit();
});

将文件作为参数传递给phantomjs

$ phantomjs github.js

我为Chrome, Firefox和MS Edge工作的唯一库是rasterizeHTML。它输出比HTML2Canvas更好的质量,并且仍然受支持,不像HTML2Canvas。

获取元素和下载为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);
}
});

有很多选择,它们都有各自的优点和缺点。

选项1:使用API

优点

  • 执行Javascript
  • 近乎完美渲染
  • 正确使用缓存选项时快速
  • 缩放由api处理
  • 精确计时,视口,…
  • 大多数时候,他们提供的是免费方案

缺点

  • 如果你打算经常使用它们,就不是免费的

选项2:使用众多可用库中的一个

优点

  • 大多数时候,转换是相当快的

缺点

  • 坏的呈现
  • 不执行javascript
  • 不支持最近的网页功能(FlexBox,高级选择器,网页字体,盒子大小,媒体查询,…)
  • 有时不容易安装
  • 缩放复杂

选项3:使用PhantomJs和包装器库

优点

  • 执行Javascript
  • 很快

缺点

  • 坏的呈现
  • 不支持最近的网页功能(FlexBox,高级选择器,网页字体,盒子大小,媒体查询,…)
  • 缩放复杂
  • 不那么容易使它工作,如果有图像要加载…

选项4:使用Chrome Headless和一个包装器库

  • Chrome Headless
  • < a href = " https://chromedevtools.github。io / devtools-protocol noreferrer“rel = > chrome-devtools-protocol < / >
  • 傀儡师 (Chrome无头浏览器的javascript包装库)
  • ...

优点

  • 执行Javascript
  • 近乎完美渲染

缺点

  • 要得到想要的结果并不容易:
    • 页面加载时间
    • 视窗尺寸
  • 缩放复杂
  • 相当慢,甚至更慢,如果html包含外部链接

披露:我是ApiFlash的创始人。我尽力提供了一个诚实而有用的答案。

使用html2canvas只包含插件和调用方法将HTML转换为画布,然后下载为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();
});

: http://www.freakyjolly.com/convert-html-document-into-image-jpg-png-from-canvas/

使用这段代码,它一定会工作:

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

不要忘记在你的程序中包含Html2CanvasJS文件。 https://html2canvas.hertzen.com/dist/html2canvas.js < / p >

这里所有的答案都使用第三方库,而在纯Javascript中将HTML渲染为图像可以相对简单。在MDN上的canvas部分中,甚至是一篇关于它的文章

诀窍是这样的:

  • 使用包含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()
}

需要注意的一些事情

  • SVG内的HTML必须是XHTML
  • 出于安全原因,SVG作为图像的数据url充当HTML的独立CSS范围,因为没有外部源可以加载。例如,谷歌字体必须使用这一个这样的工具进行内联。
  • 即使SVG内的HTML超过了图像的大小,它也会正确地绘制到画布上。但实际高度无法从图像中测量出来。 固定高度的解决方案可以很好地工作,但动态高度将需要更多的工作。最好的方法是将SVG数据呈现为iframe(用于孤立的CSS范围),并使用画布的结果大小

我知道这是一个已经有很多答案的老问题,但我仍然花了很多时间去做我想做的事情:

  • 给定一个html文件,从命令行生成一个带有透明的背景的(png)图像

使用Chrome headless (version 74.0.3729.157),实际上很容易:

"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --headless --screenshot --window-size=256,256 --default-background-color=0 button.html

命令使用说明:

  • 你从命令行运行Chrome(这里显示的是Mac,但假设在Windows或Linux上类似)
  • --headless运行Chrome而不打开它,并在命令完成后退出
  • --screenshot将捕获一个屏幕截图(注意,它会在运行命令的文件夹中生成一个名为screenshot.png的文件)
  • --window-size只允许捕获屏幕的一部分(格式为--window-size=width,height)
  • --default-background-color=0是一个魔术,告诉Chrome使用透明的背景,而不是默认的白色
  • 最后提供HTML文件(作为本地或远程url…)

HtmlToImage.jar是将html转换为图像的最简单方法

使用java将HTML转换为图像

我读了Sjeiti的答案,我觉得很有趣,在那里你只需要几行简单的JavaScript就可以在图像中呈现HTML。

当然,我们必须意识到这种方法的局限性(请在他的回答中阅读其中的一些)。

在这里,我进一步使用了他的代码。

svg图像原则上具有无限分辨率,因为它是矢量图形。但您可能已经注意到,Sjeiti的代码生成的图像分辨率并不高。在将SVG-image转移到canvas-element之前,可以通过缩放SVG-image来解决这个问题,我在下面给出的两个(可运行的)示例代码中的最后一个代码中已经做到了这一点。我在该代码中实现的另一件事是最后一步,即将其保存为png文件。只是为了完成整个过程。

因此,我给出了两个可运行的代码片段:

第一个演示了SVG的无限分辨率。运行它并使用浏览器放大,以查看分辨率是否随着放大而减小。

在您可以运行的代码片段中,我已经使用反勾号指定了一个带有换行符的所谓模板字符串,以便您可以更清楚地看到呈现的HTML。但是,如果HTML在一行之内,那么代码就会非常短,就像这样。

const body = document.getElementsByTagName('BODY')[0];
const img = document.createElement('img')
img.src = 'data:image/svg+xml,' + encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200"><foreignObject width="100%" height="100%"><div xmlns="http://www.w3.org/1999/xhtml" style="border:1px solid red;padding:20px;"><style>em {color:red;}.test {color:blue;}</style>What you see here is only an image, nothing else.<br /><br /><em>I</em> really like <span class="test">cheese.</span><br /><br />Zoom in to check the resolution!</div></foreignObject></svg>`);
body.appendChild(img);

这里是一个可运行的代码片段。

const body = document.getElementsByTagName('BODY')[0];
const img = document.createElement('img')
img.src = 'data:image/svg+xml,' + encodeURIComponent(`
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
<foreignObject width="100%" height="100%">
<div xmlns="http://www.w3.org/1999/xhtml" style="border:1px solid red;padding:20px;">
<style>
em {
color:red;
}
.test {
color:blue;
}
</style>
What you see here is only an image, nothing
else.<br />
<br />
<em>I</em> really like <span class="test">cheese.</span><br />
<br />
Zoom in to check the resolution!
</div>
</foreignObject>
</svg>
`);
body.appendChild(img);

放大并检查SVG的无限分辨率。

下面的下一个可运行文件实现了我上面提到的两个额外步骤,即通过缩放SVG来提高分辨率,然后将其保存为png图像。

window.addEventListener("load", doit, false)
var canvas;
var ctx;
var tempImg;
function doit() {
const body = document.getElementsByTagName('BODY')[0];
const scale = document.getElementById('scale').value;
let trans = document.getElementById('trans').checked;
if (trans) {
trans = '';
} else {
trans = 'background-color:white;';
}
let source = `
<div xmlns="http://www.w3.org/1999/xhtml" style="border:1px solid red;padding:20px;${trans}">
<style>
em {
color:red;
}
.test {
color:blue;
}
</style>
What you see here is only an image, nothing
else.<br />
<br />
<em>I</em> really like <span class="test">cheese.</span><br />
<br />
<div style="text-align:center;">
Scaling:
<br />
${scale} times!
</div>
</div>`
document.getElementById('source').innerHTML = source;
canvas = document.createElement('canvas');
ctx = canvas.getContext('2d');
canvas.width = 200*scale;
canvas.height = 200*scale;
tempImg = document.createElement('img');
tempImg.src = 'data:image/svg+xml,' + encodeURIComponent(`
<svg xmlns="http://www.w3.org/2000/svg" width="${200*scale}" height="${200*scale}">
<foreignObject
style="
width:200px;
height:200px;
transform:scale(${scale});
"
>` + source + `
</foreignObject>
</svg>
`);
}
function saveAsPng(){
ctx.drawImage(tempImg, 0, 0);
var a  = document.createElement('a');
a.href = canvas.toDataURL('image/png');
a.download = 'image.png';
a.click();
}
<table border="0">
<tr>
<td colspan="2">
The claims in the HTML-text is only true for the image created when you click the button.
</td>
</tr>
<tr>
<td width="250">
<div id="source" style="width:200px;height:200px;">
</div>
</td>
<td valign="top">
<div>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;In this example the PNG-image will be squarish even if the HTML here on the left is not exactly squarish. That can be fixed.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;To increase the resolution of the image you can change the scaling with this slider.
<div style="text-align:right;margin:5px 0px;">
<label style="background-color:#FDD;border:1px solid #F77;padding:0px 10px;"><input id="trans" type="checkbox" onchange="doit();" />&nbsp;&nbsp;Make it transparent</label>
</div>
<span style="white-space:nowrap;">1<input id="scale" type="range" min="1" max="10" step="0.25" value="2" oninput="doit();" style="width:150px;vertical-align:-8px;" />10&nbsp;&nbsp;<button onclick="saveAsPng();">Save as PNG-image</button></span>
</div>
            

</td>
</tr>
</table>

尝试不同的比例。例如,如果您将缩放设置为10,那么您将在生成的png图像中获得非常好的分辨率。我增加了一点额外的功能:一个复选框,如果你喜欢,你可以使png图像透明。

注意:

当这个脚本在Stack Overflow运行时,保存按钮在Chrome和Edge中不工作。原因是https://www.chromestatus.com/feature/5706745674465280

因此,我也把这个片段放在https://jsfiddle.net/7gozdq5v/上,它适用于这些浏览器。

这就是我所做的。

注意:请检查App.js的代码。

源代码链接

如果你喜欢它,你可以掉一颗星。✌️

更新:

import * as htmlToImage from 'html-to-image';
import download from 'downloadjs';


import logo from './logo.svg';
import './App.css';


const App = () => {
const onButtonClick = () => {
var domElement = document.getElementById('my-node');
htmlToImage.toJpeg(domElement)
.then(function (dataUrl) {
console.log(dataUrl);
download(dataUrl, 'image.jpeg');
})
.catch(function (error) {
console.error('oops, something went wrong!', error);
});
};
return (
<div className="App" id="my-node">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a><br></br>
<button onClick={onButtonClick}>Download as JPEG</button>
</header>
</div>
);
}


export default App;
我也在思考这个问题。 我发现这是你问题的最佳解决方案

我们可以使用javascript的html-to-image库将HTML代码转换为图像

NPM安装html-to-image

HTML代码

<div>
<div id="capture">
<p>
<span>Heading Of Image</span><br></br>
<span>This is color Image</span><br></br>
<img src="Your/ImagePath/ifany.jpg" width="100%" />
<span>Footer Of the Image</span>
</p>
</div>
<h2>Generated Image</h2>
<div id="real">
</div></div>

Javascript代码

var htmlToImage = require('html-to-image');
var node = document.getElementById('capture');
htmlToImage.toJpeg(node, { quality: 1, backgroundColor: "#FFFFFF", height: node.clientHeight, width: node.clientWidth })
.then(function (dataUrl) {
var img = new Image();
img.src = dataUrl;
var div = document.getElementById("real")
div.appendChild(img)
})
.catch(function (error) {
console.error('oops, something went wrong!', error);
});
通过这个例子,你现在可以在<div>标签中看到你的图像。 您现在可以在代码中添加保存和下载或上传图像选项

使用剧作家的page.screenshot (),它是超级容易采取截图。例如使用Python(但它也适用于Node.js, Java和.NET):

from playwright.async_api import async_playwright


async with async_playwright() as p:
browser = await p.chromium.launch()
page = await browser.new_page()
await page.goto('https://google.com')
await page.screenshot(path=f'screenshot.png')
await browser.close()