将HTML渲染为图像

2020/10/24 13:42 · javascript ·  · 0评论

有没有一种方法可以将html渲染为PNG图片?我知道画布是可能的,但我想呈现例如div之类的标准html元素。

我知道这是一个很老的问题,已经有了很多答案,但是我仍然花了几个小时来尝试做自己想做的事情:

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

使用无头的Chrome(此响应的版本为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)。

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

注意:存在一个已知问题,该问题不适用于SVG

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

有很多选择,它们各有利弊。

选项1:使用许多可用的库之一

优点

  • 大多数情况下转换速度都非常快

缺点

  • 渲染效果不好
  • 不执行JavaScript
  • 不支持最新的Web功能(FlexBox,高级选择器,Webfonts,Box大小调整,媒体查询等)
  • 有时安装起来不太容易
  • 规模复杂

选项2:使用PhantomJs以及包装器库

优点

  • 执行JavaScript
  • 蛮快

缺点

  • 渲染效果不好
  • 不支持最新的Web功能(FlexBox,高级选择器,Webfonts,Box大小调整,媒体查询等)
  • 规模复杂
  • 如果要加载图像,使其工作起来并不容易...

选项3:使用Chrome Headless,并可能使用包装器库

优点

  • 执行JavaScript
  • 接近完美的渲染

缺点

  • 要获得关于以下内容的所需结果并不容易:

    • 页面加载时间
    • 视口尺寸
  • 规模复杂
  • 如果html包含外部链接,则相当慢,甚至更慢

选项4:使用API

优点

  • 执行JavaScript
  • 接近完美的渲染
  • 正确使用缓存选项时快速
  • 规模由API处理
  • 精确的时间,视口,...
  • 大多数时候,他们提供免费计划

缺点

  • 如果您打算大量使用它们,它不是免费的

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

这里的所有答案都使用第三方库,而用纯Javascript渲染HTML到图像可能相对简单。还有甚至一个关于它的文章上MDN画布部分。

诀窍是这样的:

  • 使用包含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作用域。因此,例如,必须使用此类工具内联Google字体
  • 即使SVG中的HTML超出了图像的大小,它也会正确地绘制到画布上。但是实际高度无法从该图像测量。固定高度的解决方案可以很好地工作,但动态高度需要更多的工作。最好的方法是将SVG数据渲染到iframe中(用于隔离的CSS范围),然后将结果尺寸用于画布。

您可以使用PhantomJS,它是一个无头Webkit(Safari中的渲染引擎和(直到最近)chrome)驱动程序。您可以在此处了解如何进行页面的屏幕截图希望有帮助!

您可以使用HTML到PDF的工具,例如wkhtmltopdf。然后,您可以使用PDF图像工具,例如imagemagick。诚然,这是服务器端的过程,而且过程非常复杂。

我必须为Chrome,Firefox和MS Edge使用的唯一库是rasterizeHTML与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);
            }
     });

使用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();
        });

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

我不希望这是最好的答案,但看起来足够有趣了。

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

使用此代码,它肯定可以工作:

<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

仅靠JavaScript不能100%准确地做到这一点。

有一个Qt Webkit工具和一个python版本如果您想自己做,那么我在Cocoa上取得了成功:

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

希望这可以帮助!

我读了Sjeiti的答案,发现非常有趣,在那里,您只需几个普通的JavaScript行就可以在图像中呈现HTML。

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

在这里,我已经采取了他的代码进一步的步骤。

SVG图像原则上具有无限分辨率,因为它是矢量图形。但是您可能已经注意到Sjeiti的代码生成的图像没有高分辨率。可以通过在将SVG图像传输到画布元素之前缩放SVG图像来解决此问题,我在下面给出的两个(可运行)示例代码的最后一个中完成了此操作。我在该代码中实现的另一件事是最后一步,即将其另存为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/上,适用于那些浏览器。

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

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

使用Java将HTML转换为图像

您可以将参考 HtmlRenderer添加到您的项目中,然后执行以下操作:

string htmlCode ="<p>This is a sample html.</p>";
Image image = HtmlRender.RenderToImage(htmlCode ,new Size(500,300));
本文地址:http://javascript.askforanswer.com/jianghtmlxuanranweituxiang.html
文章标签: ,   ,   ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!