是否有一种方法将html渲染成PNG那样的图像?我知道这是可能的与画布,但我想渲染标准的html元素,如div为例。
当前回答
仅用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];
}];
希望这能有所帮助!
其他回答
使用剧作家的page.screen()可以非常容易地截取屏幕截图。例如使用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()
我读了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> 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> 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();" /> 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 <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/上,它适用于这些浏览器。
你可以使用像wkhtmltopdf这样的HTML转PDF工具。然后你可以使用像imagemagick这样的PDF图像工具。不可否认,这是服务器端,一个非常复杂的过程…
我不认为这是最好的答案,但它似乎很有趣,可以发布。
编写一个应用程序,打开您最喜欢的浏览器到所需的HTML文档,适当大小的窗口,并采取屏幕截图。然后,删除图像的边界。
这里所有的答案都使用第三方库,而在纯Javascript中将HTML渲染为图像可以相对简单。在MDN的画布部分甚至有一篇关于它的文章。
诀窍是这样的:
使用包含XHTML的foreignObject节点创建SVG 将图像的src设置为该SVG的数据url 将图像绘制到画布上 将画布数据设置为目标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() }
需要注意的一些事情
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.
推荐文章
- 截断字符串直接JavaScript
- 我如何使用可选的链接与数组和函数?
- EINVRES请求https://bower.herokuapp.com/packages/失败,提示502
- 使用fetch进行基本身份验证?
- 如何从子组件内部更新React上下文?
- 如何将一个普通对象转换为ES6映射?
- scrollIntoView卷轴太远了
- Angular ng-repeat反过来
- 如何获得请求路径与表达请求对象
- 使用Handlebars 'each'循环访问父对象的属性
- 盎格鲁- ngcloak / ngg展示blink元素
- 禁用表单自动提交按钮单击
- 节点和错误:EMFILE,打开的文件太多
- 链接重新加载当前页面
- JavaScript函数中的默认参数值