loading...
Cover image for Generate images from HTML in Node.js

Generate images from HTML in Node.js

yvonnickfrin profile image 🦁 Yvonnick FRIN Originally published at yvonnickfrin.dev ・2 min read

As developers, we don't have great skills with image manipulation softwares, but we still need it. In my case I had to generate Twitter cards for social media and flyers for the meetup I co-organize. An important point for use is automation. So I wanted a solution that let me make a template and generates a lot of images without extra work.

That is why I created node-html-to-image. A Node.js module that generates images from HTML.

Here is the simplest example, you provide an output path and a HTML string. That's all!

const nodeHtmlToImage = require('node-html-to-image')

nodeHtmlToImage({
  output: './image.png',
  html: '<html><body>Hello world!</body></html>'
})
  .then(() => console.log('The image was created successfully!'))

I talked about automation earlier. It comes with a templating engine, Handlebars. It enables creating multiple images using the same template.

In the following example, we changed world by a placeholder and inject its value with the content option.

const nodeHtmlToImage = require('node-html-to-image')

nodeHtmlToImage({
  output: './image.png',
  html: '<html><body>Hello {{name}}!</body></html>',
  content: { name: 'you' }
})
  .then(() => console.log('The image was created successfully!'))

You want to generate images from HTML without writing a line of code? No problem, I also made a cli that use node-html-to-image underneath called node-html-to-image-cli.

npx node-html-to-image-cli index.html image.png

Generated image:

Demonstration of node-html-to-image-cli

Feel free check out the GitHub repositories if you are interested:

Want to support ? Don't forget to leave a ⭐️


Feedback or ideas are appreciated 🙏 Please tweet me if you have questions @YvonnickFrin!

Posted on by:

yvonnickfrin profile

🦁 Yvonnick FRIN

@yvonnickfrin

Open source advocate at @ZenikaIT. I'm a @NantesJS meetup co-organizer on my spare time.

Discussion

markdown guide
 

¡Amazing!

Just tried it out, loving it! Just one question. If I use px to set the width of my elements, the image looks good:

But if I use % to set the width, then:

Why could this happen?

However, amazing project, thank you!

 

Thank you Desiré!

Basically the module takes a screenshot of the body tag's content. So you need to fix the size of you image on this tag using CSS then you can use percent on body's children.

Maybe I should add this in the documentation?

 

Not sure, my code is as follows:

<body>
    <div class="card">
       [ ... ] (lots of subdivs)
    </div>
</body>

and my css:

        .card{
            width: 20%; /** if it's % then the image's width doesn't display properly **/
            box-shadow: 1px 3px 15px lightgray;
            height: 250px;
        }

I guess if it's a % then it won't work properly and you must set a fixed width for your elements before taking the screenshot!

I think it would be useful to add this as a sidenote, in case someone is setting all the components with %!

Also, it works perfectly fine with rem and em too.

EDIT: I'm using the CLI version just in case that matters!

Percentage are relative to your parent dimensions So it will be 20 percent of body. If you don't fix body size it will be relative to the browser's viewport I guess. I don't set any viewport. So I recommend fixing body size to the resolution you want for the output file.

In the example below I fix the size to A4 format in high resolution. The output file resolution will be 2480x3508. So the card size will be 20% of 2480px. You see what I mean?

<html>
  <head>
    <style>
       body {
         width: 2480px;
         height: 3508px;
       }
       .card{
         width: 20%; /** if it's % then the image's width doesn't display properly **/
         box-shadow: 1px 3px 15px lightgray;
         height: 250px;
        }
    </style>
  </head>
  <body>
    <div class="card">
       [ ... ] (lots of subdivs)
    </div>
  </body>
</html>

Sure! I usually never set any size for the body, it should be nice to have it in mind so the image looks good, thank you!

Désiré I added a section about this in the documentation. What do you think of it?

Clear as a sunny day, I think there can't be any risk now! Thank you!

 

This won't work on Docker, need to install anything other that npm install?

 

You have to follow this for Docker github.com/puppeteer/puppeteer/blo... (tehere is specifict instructiosn for alpine also) and send this in puppeteerArgs when you call nodeHtmlToImage:

puppeteerArgs: {
headless: true,
args: [
"--no-sandbox",
"--remote-debugging-address=0.0.0.0",
"--remote-debugging-port=9222",
],
}

 
 

Super cool stuff

Is there any way to use custom font? I got a HTML like this but the output image is not using the font specified (it's good to show in browser)



<br>
body {<br>
width: 1000px;<br>
height: 500px;<br>
}</p>
<div class="highlight"><pre class="highlight plaintext"><code> @font-face {
font-family: JuneBug;
src: url('JUNEBUG.TTF');
}
h1 {
    font-family: JuneBug
}

&lt;/style&gt;
</code></pre></div>
<p></head></p>

<p><body>Hello world!<br>
<h1>Hey, June</h1><br>
</body></p>

<p></html></p>

 

Hi Nathaniel,

TTF format is made for Safari, Android and iOS. The image is generated in a chromium browser. So you can only use WOFF format.

 

Is it possible to generate a GIF from animated HTML?

 

node-html-to-images don't handle this use case. It is an awesome idea!

 
 

Looks so cool! It's interesting that I can use HTML and CSS to generate an image.

 

Thank you Nihar! Sure, as a developper I'm used to HTML and CSS which are great tools to make nice graphical stuff 🙌

 
 

Wow, Thank you for this great work!

I have a question though, Does it work with react Native? Thank you.