Render HTML to an image
Asked Answered
G

21

319

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.

Gadfly answered 23/5, 2012 at 14:19 Comment(6)
To create some sort of user assistance, for example. Sadly, that's not possible (for security reasons?). You have to ask the user to press PrintScreen in order to do something.Phytography
possible duplicate of How to convert HTML of a website to an image?Ailssa
I want to use HTML/CSS to design a logo.Gadfly
@ErnestFriedman-Hill not a duplicate: the question you mentioned is specific to java.Gadfly
Everyone will know it's possible on the server side. It's the equivalent of answering "What's 2+2?" with "5 is close to what you are looking for, but it's somewhat convoluted."Cheyenne
Canvas > dataURL > Image example freakyjolly.com/…Permalloy
A
214

There is a lot of options and they all have their pro and cons.

Option 1: Use an 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

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

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

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.

Almandine answered 15/9, 2017 at 15:44 Comment(4)
wkhtmltoimage/pdf does support javascript rendering. You can set a javascript delay or let wkhtml check for a specifc window.status (which you can set with javascript when you know your js stuff is done)Crifasi
PhantomJS supports dynamic stuff like Google Maps. It's really a full web browser, just without a display attached. However you have to wait a bit for Google Map to load the tiles with the geography (I wait 500ms and allow people to change the delay - if it's not enough, running again without increasing the time is fine, because those tiles are cached).Illassorted
API Flash able to grab the entire webpage if &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
A gotcha with many of these techniques is system and monitor dependent font rendering. Ideally you do not want hinting or subpixel antialiasing. I understand OSX has both disabled out of the box. These are often enabled on Linux systems but can be disabled. Windows also has them enabled but I found no clear way to disable them. But, this might not matter at all for you application.Bacchus
S
133

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);
    });
Seiter answered 25/9, 2015 at 7:20 Comment(27)
This is great! Any way to double the output size?Temperament
Thanks! But what exactly do you mean by "doubling the size"?Seiter
My image is created nicely, but I want to be able to print it out at high-resolution, so I need the outputted png to be 2 or 3 times bigger than the DOM element it was rendered from. Is this possible?Temperament
First thing that comes to my mind - try to render your image to SVG (using 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
Thanks, I've added an issue on github. The easiest way would be to add CSS zoom:2 on the element before rendering which does work, but it unfortunately crops the image to the original dimensions rather than the new dimensionsTemperament
This is MUCH better than html2canvas. Thanks.Unbending
I found this much better and easy to work with compared to IMGKit on my Rails 4 app.Aristophanes
trying to use this library but its printing the textarea and not an image of the HTML. Little confused with how to do this...Nagoya
what is the dataUrl here?Necolenecro
@Necolenecro it's a String containing the URL with base64-encoded dataSeiter
I didn't find this one to be better than html2canvas. The output I kept receiving was nowhere near the actual page visuals.Dewy
For me (I am using angularJS) dom-to-image library worked better than html2canvas, because both were able to "catch" the div, but only this was able to catch the image inside the div (such an image was within a directive, I don't know whether this is the reason or not).Tautology
Is it possible to use this library, node js server side itself to generate image before it comes to browser?Recusant
@Seiter I know this an old thread, but I'm using your amazing lib on a mobile project, but the phone keep showing the rendered images on low resolution. I open them on my pc, but they're perfect. Just on the phone. Is there's anything I'm making wrong? The quality attribute is already on 100... :'(Kiel
Found this to work well. Also see github.com/eligrey/FileSaver.js and stuk.github.io/jszip for downloading/zipping.Alluring
Hi would you mind commenting on the robustness of inlining images in SVG docs? Articles seem to indicate it's not very robust because even new browsers have limits on data URIs. If you cap images at 2 MB, could you rely on a client solution to generate PNGs from SVG docs? Or do you have to go server side? Thanks for any insight you can offer!Needlepoint
I was looking for everywhere for a solution with transparent background. This is much better!Denning
@Seiter this library works great in chrome but didn't work in IE 10+.Quanta
This not support proxy so can not capture cross origin image.Bony
@Seiter - the project/repo is currently dead? Because on github I see many nice pull requests but nobody merge itWoodenware
@KamilKiełczewski I'm not developing this project currently. But the code is open, anyone can fork it and merge all those pull requestsSeiter
i have a responsive html element which spreads and shrinks with window size. can I download it to an image at its original size?Decrypt
Can you support taking screenshots of video tags?Eared
@Kiran, I was also interested in creating images on the node side. Would you be able to solve this? Thank You!Smallsword
Anyway to download the rendered image?Hosanna
@Smallsword no luck we change requirement itself :-(Recusant
@Recusant Thanks for the feedback. I used node-canvas moduleSmallsword
L
119

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

Lynching answered 23/5, 2012 at 14:26 Comment(9)
It seems interesting but I didn't manage to make it work so I choose John Fisher solution. Thanks for the info, I'll watch this project in the future!Gadfly
dom-to-image (see tsayen's answer) does a much better job to render an accurate picture.Masque
If you are dealing with SVGs at all, dom-to-image works much better.Unbending
This solution is very slowChough
another issue, if the element is hidden or behind another element this will not workGrueling
Worked perfectly for meMagalymagan
This is a good demo for anyone dealing with SVG to image codepen.io/samthor/pen/jpPJZP?editors=0010Arctogaea
I've tried dom-to-image, it did not work at all. Had to screenshot HTML with WebGL content in it (Mapbox map), Tried dom-to-image and rasterizeHTML, neither worked. html2canvas worked perfectlyHailstone
It doesn't take the image URLCarmencarmena
B
92

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.
Breathy answered 30/10, 2018 at 15:3 Comment(8)
Nice! Removing external library dependency is indeed the good way to go. I changed my accepted answer :-)Gadfly
That article is no longer there.Rios
Strange, does't look moved but simply deleted. I'll try and replace it with a waybackmachine url when I find a computer.Breathy
Great answer, but commenting on the state of art of HTML and Web APIs, which as usual looks like something pulled out someones behind -- all the functionality is technically there but exposed behind an array (no pun intended) of weird code paths that resemble nothing of the kind of clarity you would expect from a well designed APIs. In plainspeak: it is most likely trivial for a browser to allow a 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
Could you comment on the robustness of inlining images in a SVG doc? Articles seem to indicate it's not very robust because even new browsers have limits on data URIs. If you cap images at 2 MB, could you rely on a client solution to generate PNGs from SVG docs? Or do you have to go server side? Thanks for any insight you can offer!Needlepoint
This answer #12637895 seems to indicate you can go quite far. Mozilla and Chrome have unlimited data uri lenght and even current IE allows 4GB, which boils down to about 3GB images (due to base64). But this would be a good thing to test.Breathy
- some quick and dirty tests later - jsfiddle.net/Sjeiti/pcwudrmc/75965 Chrome, Edge and Firefox go up to a width height of at least 10,000 pixels which (in this case) is a character count of about 10,000,000 and a png filesize of 8MB. Haven't tested rigourously but it's enough for most use cases.Breathy
@Breathy I know the question is very old. But I am currently trying to do some thing similar to add an SVG to Canvas. As Below Can you please look at this question. May be you can help me out here. #77471968Latonialatoniah
P
63

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 called screenshot.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...)
Pate answered 17/5, 2019 at 22:25 Comment(6)
Very nice! It works with SVG also! I switched to your solution in the end! ;-)Gadfly
--screenshot='absolute\path\of\screenshot.png' worked for meShun
comman line worked. if i want to run this programatically from express js how to run it?Agalloch
FYI this also works with chromium even though it doesn't mention the option in the man page.Aframe
The svg isn't an svg for me ... it's just a PNG with an SVG extension ... so watch out.Parahydrogen
@Parahydrogen I don't believe ths is wat Martin Delille is suggesting. You can use Crhome to convert an SVG to a PNG. But not to render a webppage as SVG.Asymptomatic
P
14

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!

Phyla answered 16/10, 2013 at 23:25 Comment(2)
This technique works well. However, 2 years have passed since your comment. Have you come across anything that operates faster than PhantomJS? Image Generation typically takes 2-5 seconds in Phantom, in my experience.Lammergeier
Headless Chrome is now possible. I don't know if it's faster, but if you want accurate screenshots, this is a good way to go.Walczak
S
14

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);
            }
     });
Sheasheaf answered 22/11, 2016 at 23:5 Comment(4)
but it doesn't work with IE. rasterizeHTML LimitationsVest
@Sheasheaf is there any single file javascript for this?Pompeii
This change helped me a lot: rasterizeHTML.drawHTML(node.innerHTML, canvas) Note that Im calling innerHTML on the nodePichardo
@MahdiKhalili - cburgmer.github.io/rasterizeHTML.js/rasterizeHTML.allinone.jsSurbased
B
12

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

Bichromate answered 23/5, 2012 at 14:23 Comment(2)
Or you could just run wkhtmltopdf's image brother, wkhtmltoimage.Quinquefid
This library is for Node.js. How about simple frontend?Valuator
V
10

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

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.

Vanillin answered 24/8, 2020 at 11:57 Comment(5)
You just omitted the main part of the task: converting to PNG! Your image is an SVG, a vector graphics format which is zoomable infinitely. But that is not the question.Leitman
MGM, You are right. It seems I totally missed that important aspect of the question. I will try to fix my answer so that it covers that part also. Give me some time for that.Vanillin
MGM, so, I have fixed it now.Vanillin
@Vanillin I really love this solution. I was testing on my own and tried adding a background image to the html that's being transformed but found that the image itself doesn't render as the background when being transformed. Any ideas on how that can be fixed? Here's what I tried <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
@ZakDeBrine I am not able to dive into that problem now, unfortunately. I suggest that you formulate it into a new question to see if you can get some help with it. Good luck!Vanillin
P
6

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/

Permalloy answered 8/6, 2018 at 9:37 Comment(1)
Please note that html2canvas is having an issue with Shadow dom elements. if your application is using the shadow dom elements and you want it in generated snapshots then html2-canvas is not good choice for you go with html-to-imageGowrie
F
6

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

Forestforestage answered 5/7, 2018 at 4:59 Comment(0)
E
5

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.

Ericerica answered 23/5, 2012 at 14:25 Comment(5)
Same as the Headless Chrome Screenshot solution, with the exception of considerable contribution to global warming.Bernie
If only the current options had been available 9 years ago...Ericerica
When an answer is such fundamentally correct and relevant after 9 years that you omit the date (:Bernie
@BahramArdalan: The date is provided by StackOverflow. Look at the bottom-right area of the answer. It says "answered May 23 2012".Ericerica
Read it again. It was a compliment to you. 'you' was metaphorically meant to be 'me' omitting the date (not looking for it hence not seeing it) because after all these times passed by your perfect answer still seemed so relevant that I didn't think once to check the date.Bernie
T
5

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!

Temporal answered 9/6, 2012 at 19:46 Comment(2)
Do you have swift version of the above? or if possible can you please re-write it?Actinium
Would you mind sharing the code you use to load the webView that you're rendering? This seems like a promising approach for my thumbnail renderer. Thanks!Bureau
J
5

This is what I did.

Note: Please check App.js for the code.

Link to source 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;
Jotham answered 9/11, 2020 at 12:10 Comment(2)
Please avoid link only answers. Answers that are "barely more than a link to an external site” may be deleted.Curvilinear
Sure @Quentin, thank you for pointing it out.Jotham
E
5

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.

Eulalie answered 8/6, 2021 at 8:16 Comment(3)
I got better and faster results using this library than the others recommended here, thanks. It also avoids the extra step of creating a canvas since it uses an SVG solution with the <foreignObject> tag.Vanatta
link to library pleaseSuave
Here it is npmjs.com/package/html-to-imageEulalie
A
2

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
Articulator answered 31/8, 2016 at 20:24 Comment(0)
M
2

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');
  });
Metamer answered 16/1, 2023 at 10:41 Comment(1)
npmjs.com/package/html-to-imageMetamer
C
1

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()
Custodian answered 19/11, 2022 at 17:21 Comment(0)
D
0

HtmlToImage.jar will be the simplest way to convert a html into an image

Converting HTML to image using java

Dilator answered 8/7, 2019 at 10:27 Comment(1)
Please avoid link only answers. Answers that are "barely more than a link to an external site” may be deleted.Curvilinear
L
0

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);
        }
    });
Lyallpur answered 5/2, 2023 at 6:27 Comment(1)
There are so many problems with this library. I have to say it simply just does not work. It will render very basic things . i get border lines and basically no text or css gets rendered at all.Suave
M
-5

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));
Mob answered 11/11, 2015 at 6:47 Comment(1)
It's a C# library. The request is for JavaScript.Leitman

© 2022 - 2024 — McMap. All rights reserved.