Dynamically generated thumbnails!
Thats right, its a blog update.
I now generate og/meta images using satori + Resvg based on a html template, in node!
Setup
(this is using ESM, not commonjs - I recently ported my project to ESM as part of this so thought i should mention)
install the modules
npm i satori npm i satori-html npm i @resvg/resvg-js
we create our main file and import our modules
import satori from "satori";
import { html } from "satori-html";
import { Resvg } from "@resvg/resvg-js";
import {fileURLToPath} from 'url';
import path from 'path';
basically, I take a template from a html template existing in the filesystem, and replace certain tags.
make template.html in the root of your project (or wherever you want it- really)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
width: 1200px;
height: 628px;
display: flex;
align-items: center;
justify-content: center;
background-color: black;
background-image: radial-gradient(circle, #ffffff 1px, black 1px);
background-size: 40px 40px;
color: white;
font-family: sans-serif;
margin: 0 auto;
}
.container {
display: flex;
width: 100%;
height: 100%;
padding: 50px;
}
.container img {
width: 500px;
height: 500px;
flex-shrink: 0;
}
.text {
display: flex;
flex-direction: column;
padding-left: 50px;
flex-grow: 1;
justify-content: center;
}
.text h1 {
font-size: 48px;
margin-bottom: 20px;
}
.text p {
font-size: 24px;
}
</style>
</head>
<body>
<div class="container">
<img src="https://cataas.com/cat?type=square" alt="Random Cat">
<div class="text">
<h1>{{title}}</h1>
<hr>
<p>{{headline}}</p>
</div>
</div>
</body>
</html>
Fonts: you need a font to render text. I used Victor Mono, but as long as its a .ttf or .otf it should work
and finally, some code in our main file.
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
async function generateImage(title, headline){
const templatePath = path.join(__dirname, 'template.html');
let template = await fs.readFile(templatePath, 'utf8');
template = template
.replaceAll('{{title}}', title)
.replaceAll('{{headline}}', headline)
const markup = html(template);
const fontData = await fs.readFile(
"VictorMono-Regular.ttf"
);
const svg = await satori(markup, {
width: 1200,
height: 628,
fonts: [
{
name: "Arial",
data: fontData,
weight: "auto",
style: "normal",
},
],
});
const resvg = new Resvg(svg, {
background: "rgba(255, 255, 255, 1)",
});
const pngData = resvg.render();
const pngBuffer = pngData.asPng();
fs.writeFile("./generated/" + title + ".png", pngBuffer)
}
finally, we can generate images with a simple function call
generateImage('awesome', 'sauce');
Conclusion
Satori + resvg is a powerful combination, with the code I provided, you should be able to make any type of image you want from html!
I really need to make a comment section, but if you need anything / just want to tell me something, feel free to email me
vesania at exonauto.me
Thanks for reading, have a wonderful day :)