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.
There is a lot of options and they all have their pro and cons.
Option 1: Use an API
- ApiFlash (based on chrome)
- EvoPDF (has an option for html)
- Grabzit
- HTML/CSS to Image 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
Cons
- Not free if you plan to use them a lot
Option 2: Use one of the many available libraries
- 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
- ...
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
Option 3: Use PhantomJs and maybe a wrapper library
- PhantomJs
- node-webshot (javascript wrapper library for PhantomJs)
- ...
Pros
- Execute Javascript
- Quite fast
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 ...
Option 4: Use Chrome Headless and maybe a wrapper library
- Chrome Headless
- chrome-devtools-protocol
- Puppeteer (javascript wrapper library for Chrome headless)
- ...
Pros
- Execute Javascript
- Near perfect rendering
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
Disclosure: I'm the founder of ApiFlash. I did my best to provide an honest and useful answer.
&full_page=true
is added to the url. Retains its clarity better than many other options I have tried and renders fairly complicated pages well. –
Catalectic May I recommend dom-to-image library, that was written solely to address this problem (I'm the maintainer).
Here is how you use it (some more here):
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);
});
domtoimage.toSvg
), then render it yourself on canvas and try to play with that canvas' resolution somehow. It's probably possible to implement such feature as some kind of rendering option in the lib itself, so you can pass image dimensions in pixels. If you need it, I'd appreciate you creating an issue on github. –
Seiter zoom:2
on the element before rendering which does work, but it unfortunately crops the image to the original dimensions rather than the new dimensions –
Temperament Yes. HTML2Canvas exists to render HTML onto <canvas>
(which you can then use as an image).
NOTE: There is a known issue, that this will not work with SVG
All the answers here use third party libraries while rendering HTML to an image can be relatively simple in pure Javascript. There is was even an article about it on the canvas section on 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
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.
Document
to be rendered into a raster (e.g. a Canvas
), but because noone bothered to standardize it, we have to resort to insanity like illustrated above (no offense at the author of this code). –
Elderly 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 transparent background from the command line
Using Chrome headless (version 74.0.3729.157 as of this response), it is actually easy:
"/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 transparent background, not the default white color- finally you provide the html file (as a url either local or remote...)
--screenshot='absolute\path\of\screenshot.png'
worked for me –
Shun You could use PhantomJS, which is a headless webkit (the rendering engine in safari and (up until recently) chrome) driver. You can learn how to do screen capture of pages here. Hope that helps!
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.
Getting Element and Downloading as 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);
}
});
rasterizeHTML.drawHTML(node.innerHTML, canvas)
Note that Im calling innerHTML on the node –
Pichardo 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...
Node.js
. How about simple frontend? –
Valuator I read the answer by Sjeiti which I found very interesting, where you with just a few plain JavaScript lines can render HTML in an image.
We of course have to be aware of the limitations of this method (please read about some of them in his answer).
Here I have taken his code a couple of steps further.
An SVG-image has in principle infinite resolution, since it is vector graphics. But you might have noticed that the image that Sjeiti's code generated did not have a high resolution. This can be fixed by scaling the SVG-image before transferring it to the canvas-element, which I have done in the last one of the two (runnable) example codes i give below. The other thing I have implemented in that code is the last step, namely saving it as a PNG-file. Just to complete the whole thing.
So, I give two runnable snippets of code:
The first one demonstrates the infinite resolution of an SVG. Run it and zoom in with your browser to see that the resolution does not diminish as you zoom in.
In the snippet that you can run I have used backticks to specify a so called template string with line breaks so that you can more clearly see the HTML that is rendered. But otherwise, if that HTML is within one line, then the code will be very short, like this.
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);
Here it comes as a runnable snippet.
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);
Zoom in and check the infinite resolution of the SVG.
The next runnable, below, is the one that implements the two extra steps which I mentioned above, namely improving resolution by first scaling the SVG, and then the saving as a PNG-image.
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>
Try with different scalings. If you for example set scaling to 10, then you get a very good resolution in the generated PNG-image. And I added a little extra feature: a checkbox so that you can make the PNG-image transparent if you like.
Notice:
The Save-button does not work in Chrome and Edge when this script is run here at Stack Overflow. The reason is this https://www.chromestatus.com/feature/5706745674465280 .
Therefore I have also put this snippet on https://jsfiddle.net/7gozdq5v/ where it works for those browsers.
<div xmlns="http://www.w3.org/1999/xhtml" style="border:1px solid red;padding:20px;${trans};background-image: url('https://i.ibb.co/9Zvz58h/star.png')">
–
Everyway Use html2canvas just include plugin and call method to convert HTML to Canvas then download as image 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/
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
I don't expect this to be the best answer, but it seemed interesting enough to post.
Write an app that opens up your favorite browser to the desired HTML document, sizes the window properly, and takes a screen shot. Then, remove the borders of the image.
You can't do this 100% accurately with JavaScript alone.
There's a Qt Webkit tool out there, and a python version. If you want to do it yourself, I've had success with 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];
}];
Hope this helps!
This is what I did.
Note: Please check App.js for the code.
If you liked it, you can drop a star.✌️
Update:
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;
I also put my head around this issue. And I found this as the best solution for your problem
We can use html-to-image
library of javascript to convert HTML code to image
npm install html-to-image
HTML Code
<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 Code
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);
});
By this example, you can now see your image in <div>
tag where id = 'real'
.
You can now add the save and download or upload image option in code.
<foreignObject>
tag. –
Vanatta Install phantomjs
$ npm install phantomjs
Create a file github.js with following code
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();
});
Pass the file as argument to phantomjs
$ phantomjs github.js
I will suggest this npm package "html-to-image"
Description: ✂️ Generates an image from a DOM node using HTML5 canvas and SVG.
How to use:
Install
npm install --save html-to-image
Usage
/* ES6 */
import * as htmlToImage from 'html-to-image';
import { toPng, toJpeg, toBlob, toPixelData, toSvg } from 'html-to-image';
Get a PNG image base64-encoded data URL and download it (using download):
htmlToImage.toPng(document.getElementById('my-node'))
.then(function (dataUrl) {
download(dataUrl, 'my-node.png');
});
With Playwright's page.screenshot() it's super easy to take a screenshot. For example using Python (but it's also available for Node.js, Java and .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()
HtmlToImage.jar will be the simplest way to convert a html into an image
Yes, You can do it with HTML2Canvas library it renders your HTML code to canvas. It gives the option to convert html to an image from a specific div then use canvas2image to download the image locally to your filesystem.
Link the Source Code
html2canvas(document.querySelector('#screenscoot'), {
onrendered: function(canvas) {
// document.body.appendChild(canvas);
return Canvas2Image.saveAsPNG(canvas);
}
});
You can add reference HtmlRenderer to your project and do the following,
string htmlCode ="<p>This is a sample html.</p>";
Image image = HtmlRender.RenderToImage(htmlCode ,new Size(500,300));
© 2022 - 2024 — McMap. All rights reserved.