将HTML渲染为图像

Mar*_*lle 139 html javascript css image render

有没有办法将html呈现为像PNG一样的图像?我知道它可以用canvas,但我想渲染像div这样的标准html元素.

AKX*_*AKX 95

是.存在HTML2Canvas以将HTML呈现<canvas>(您可以将其用作图像).

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

  • dom-to-image(参见tsayen的回答)可以更好地呈现准确的图片. (3认同)
  • 这个解决方案非常慢 (3认同)
  • 另一个问题,如果元素被隐藏或在另一个元素后面,这将无法工作 (2认同)

tsa*_*yen 85

我是否可以推荐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);
    });
Run Code Online (Sandbox Code Playgroud)

  • 这比html2canvas好多了.谢谢. (8认同)
  • 这很棒!有什么方法可以将输出大小加倍? (2认同)
  • 我想到的第一件事 - 尝试将您的图像渲染为SVG(使用`domtoimage.toSvg`),然后在画布上自己渲染它并尝试以某种方式使用该画布的分辨率.可能可以在lib本身中实现某种渲染选项等功能,因此您可以以像素为单位传递图像尺寸.如果你需要它,我很感激你在github上创建一个问题. (2认同)
  • 是否可以使用这个库,节点js服务器端本身在浏览器之前生成图像? (2认同)

Tim*_*nin 48

有很多选择,他们都有自己的利弊.

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

优点

  • 大多数时候转换速度非常快

缺点

  • 糟糕的渲染
  • 不执行javascript
  • 不支持最近的Web功能(FlexBox,高级选择器,Webfonts,Box大小,媒体查询,...)
  • 有时不太容易安装
  • 复杂到规模

选项2:使用PhantomJs和可能的包装库

优点

  • 执行Javascript
  • 蛮快

缺点

  • 糟糕的渲染
  • 不支持最近的Web功能(FlexBox,高级选择器,Webfonts,Box大小,媒体查询,...)
  • 复杂到规模
  • 如果有要加载的图像,就不那么容易了

选项3:使用Chrome Headless和可能的包装库

优点

  • 执行Javascript
  • 近乎完美的渲染

缺点

  • 获得完全想要的结果并不容易:
    • 页面加载时间
    • 视口尺寸
  • 复杂到规模
  • 如果html包含外部链接,那么速度甚至更慢

选项4:使用API

优点

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

缺点

  • 如果您计划使用它们,则不是免费的

免责声明:我是ApiFlash的创始人.我尽力提供诚实和有用的答案.

  • 感谢您提供许多可能的解决方案的详细解答 (2认同)

Sje*_*iti 42

这里的所有答案都使用第三方库,而在纯Javascript中将HTML呈现给图像可能相对简单.还有甚至一个关于它的文章上MDN画布部分.

诀窍是:

  • 使用包含XHTML的foreignObject节点创建SVG
  • 将图像的src设置为该SVG的数据URL
  • drawImage 在画布上
  • 将画布数据设置为target.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()
}
Run Code Online (Sandbox Code Playgroud)

有些事情需要注意

  • SVG中的HTML必须是XHTML
  • 出于安全原因,SVG作为图像的数据URL充当HTML的隔离CSS范围,因为不能加载外部源.因此,必须使用像这样的工具来内联Google字体.
  • 即使SVG内的HTML超出了图像的大小,它也会正确地绘制到画布上.但是无法从该图像测量实际高度.固定高度的解决方案可以很好地工作,但动态高度将需要更多的工作.最好的方法是将SVG数据呈现为iframe(对于隔离的CSS范围),并使用画布的结果大小.

  • 很好的答案,但要评论 HTML 和 Web API 的最新技术水平,这与往常一样看起来像是将某些人拉到了后面——所有功能在技术上都存在,但暴露在一个奇怪的代码路径数组(无双关语)后面,类似于设计良好的 API 不会像您期望的那样清晰。简单地说:浏览器允许将“文档”呈现为光栅(例如“画布”)很可能是微不足道的,但是因为没有人愿意对其进行标准化,我们不得不像上面说明的那样疯狂(不冒犯此代码的作者)。 (4认同)
  • - 稍后的一些快速和肮脏的测试 - http://jsfiddle.net/Sjeiti/pcwudrmc/75965/ Chrome,Edge和Firefox的宽度高度至少为10,000像素(在这种情况下)是一个字符数约为10,000,000和8MB的png文件大小.没有严格测试,但对大多数用例来说已经足够了. (2认同)

yan*_*yan 16

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

  • 给定一个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
Run Code Online (Sandbox Code Playgroud)

命令说明:

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

  • 很不错!它也适用于 SVG!我最终改用了你的解决方案!;-) (2认同)
  • `--screenshot='absolute\path\of\screenshot.png'` 对我有用 (2认同)
  • 命令行有效。如果我想从express js 以编程方式运行它如何运行它? (2认同)

小智 13

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


Pin*_*nyM 11

您可以使用HTML到PDF工具,如wkhtmltopdf.然后你可以使用PDF来成像imagemagick这样的工具.不可否认,这是服务器端和一个非常复杂的过程......

  • 或者你可以运行wkhtmltopdf的图像兄弟,wkhtmltoimage. (12认同)

vab*_*gas 8

我为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);
            }
     });
Run Code Online (Sandbox Code Playgroud)

  • 但它不适用于IE。[rasterizeHTML的局限性](https://github.com/cburgmer/rasterizeHTML.js/wiki/Limitations) (2认同)

Cod*_*Spy 6

使用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();
        });
Run Code Online (Sandbox Code Playgroud)

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


Joh*_*her 5

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

编写一个应用程序,打开您喜欢的浏览器到所需的HTML文档,正确调整窗口大小,并拍摄屏幕截图.然后,删除图像的边框.


Mat*_*ton 5

仅使用 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];
}];
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!


Moh*_*rni 5

使用此代码,它肯定会起作用:

<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>
Run Code Online (Sandbox Code Playgroud)

只是不要忘记在您的程序中包含 Html2CanvasJS 文件。 https://html2canvas.hertzen.com/dist/html2canvas.js


Mag*_*nus 5

我阅读了 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);
Run Code Online (Sandbox Code Playgroud)

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

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);
Run Code Online (Sandbox Code Playgroud)

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

下面的下一个 runnable 是实现我上面提到的两个额外步骤的一个,即通过首先缩放 SVG 来提高分辨率,然后保存为 PNG 图像。

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);
Run Code Online (Sandbox Code Playgroud)
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();
}
Run Code Online (Sandbox Code Playgroud)

尝试不同的缩放比例。例如,如果您将缩放比例设置为 10,那么您将在生成的 PNG 图像中获得非常好的分辨率。我添加了一些额外的功能:一个复选框,以便您可以根据需要使 PNG 图像透明。

注意:

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

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


Vij*_*wad 5

这就是我所做的。

\n

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

\n

链接到源代码

\n

如果你喜欢它,你可以给它一颗星。\xe2\x9c\x8c\xef\xb8\x8f

\n

更新

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

  • 请[避免仅链接答案](http://meta.stackoverflow.com/tags/link-only-answers/info)。“只不过是指向外部站点的链接”的答案[可能会被删除](http://stackoverflow.com/help/deleted-answers)。 (2认同)

小智 5

我也思考过这个问题。我发现这是解决您问题的最佳方案

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

npm 安装 html 到图像

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>
Run Code Online (Sandbox Code Playgroud)

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);
    });
Run Code Online (Sandbox Code Playgroud)

通过此示例,您现在可以在<div>标签 where中看到您的图像id = 'real'。您现在可以在代码中添加保存并下载或上传图像选项。