A simple and practical example demonstrating how to convert HTML templates to PDF with proper Bangla font support using Express.js and Puppeteer. Perfect for generating invoices, receipts, documents, and other PDFs that require Bangla text rendering.
This project showcases the complete workflow for:
- Converting HTML templates to PDF using Puppeteer
- Embedding Bangla fonts directly in the PDF generation process
- Generating invoices and documents dynamically from an Express.js backend
- Returning generated PDFs to clients as downloads
- Storing PDF copies on the server for archival purposes
- Bangla Font Support: Properly renders Bangla/Bengali text in PDFs
- Dynamic Content: Replace template placeholders with dynamic data
- Base64 Font Embedding: Fonts embedded as data URIs for portability
- PDF Generation: Fast, reliable PDF generation using Puppeteer (Chrome headless browser)
- Flexible Output: Download PDF directly or save to server
- Multiple Font Options: 3 example Bangla fonts included for testing
- Simple API: Easy-to-use REST endpoint for PDF generation
- Node.js v14+ (v16+ recommended)
- npm or yarn
- Modern system with adequate RAM for Puppeteer (requires ~150MB)
git clone <repository-url>
cd html-to-pdf-bangla-examplenpm installDevelopment mode (with auto-reload):
npm run devProduction mode:
npm startThe server will start on http://localhost:3000
html-to-pdf-bangla-example/
├── package.json # Project dependencies and scripts
├── server.js # Express.js backend with PDF generation endpoint
├── README.md # This file
├── fonts/ # Bangla font files
│ ├── Atma-Bold.ttf # Atma font (default)
│ ├── AnekBangla-Bold.ttf # Anek Bangla font
│ └── NotoSansBengali-Bold.ttf # Noto Sans Bengali font
├── templates/ # HTML templates for PDF generation
│ └── invoice.html # Invoice template with dynamic placeholders
└── outputs/ # Generated PDF files
├── AtmaFont.pdf # Sample output with Atma font
├── AnekBanglaFont.pdf # Sample output with Anek Bangla font
└── NotoSansFont.pdf # Sample output with Noto Sans Bengali font
GET /health
Verify that the server is running.
Response:
{
"status": "ok"
}POST /generate-html-to-pdf
Generates a PDF from the invoice template with dynamic content.
Request Body:
{
"name": "মাহমুদ হাসান রামীম",
"message": "আসসালামু আলাইকুম, এই একটি উদাহরণ পিডিএফ যা বাংলা ফন্ট ব্যবহার করে তৈরি করা হয়েছে।"
}Query Parameters:
name(required): Name/title text in Bangla or any languagemessage(required): Message content in Bangla or any language
Response:
- Returns a PDF file as a downloadable attachment
- PDF is also saved to the
outputs/directory with a timestamp filename
Example Response Headers:
Content-Type: application/pdf
Content-Disposition: attachment; filename=1712345678900.pdf
curl -X POST http://localhost:3000/generate-html-to-pdf \
-H "Content-Type: application/json" \
-d '{
"name": "আপনার নাম",
"message": "আপনার বার্তা এখানে লিখুন"
}' \
--output invoice.pdfconst generatePDF = async () => {
try {
const response = await fetch("http://localhost:3000/generate-html-to-pdf", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "মাহমুদ হাসান রামীম",
message: "আমার প্রথম বাংলা পিডিএফ তৈরি হয়েছে!",
}),
});
// Download the PDF
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "invoice.pdf";
a.click();
} catch (error) {
console.error("Error generating PDF:", error);
}
};const axios = require("axios");
const fs = require("fs");
const generatePDF = async () => {
try {
const response = await axios.post(
"http://localhost:3000/generate-html-to-pdf",
{
name: "মাহমুদ হাসান রামীম",
message: "নোড.জেএস এর মাধ্যমে পিডিএফ তৈরি করা হচ্ছে",
},
{ responseType: "arraybuffer" },
);
fs.writeFileSync("invoice.pdf", response.data);
console.log("PDF saved successfully!");
} catch (error) {
console.error("Error generating PDF:", error);
}
};
generatePDF();The project includes 3 Bangla font options:
| Font | File | Description |
|---|---|---|
| Atma | Atma-Bold.ttf |
Default font. Clean, modern, and highly readable. Great for invoices and formal documents. |
| Anek Bangla | AnekBangla-Bold.ttf |
Beautiful, calligraphic Bangla font. Excellent for titles and decorative use. |
| Noto Sans Bengali | NotoSansBengali-Bold.ttf |
Google's professional sans-serif font. Recommended for web and print. |
Edit server.js line 17 to change the default font:
// Current (Atma font)
const fontFilePath = path.join(__dirname, "fonts", "Atma-Bold.ttf");
// Switch to Anek Bangla
// const fontFilePath = path.join(__dirname, "fonts", "AnekBangla-Bold.ttf");
// Switch to Noto Sans Bengali
// const fontFilePath = path.join(__dirname, "fonts", "NotoSansBengali-Bold.ttf");Or make it dynamic by adding it as a parameter to the API:
app.post("/generate-html-to-pdf", async (req, res) => {
const { name, message, font = "Atma-Bold.ttf" } = req.body;
const fontFilePath = path.join(__dirname, "fonts", font);
// ... rest of the code
});User Request
↓
POST /generate-html-to-pdf
↓
Load HTML Template
↓
Read Font File & Convert to Base64
↓
Replace {{name}} and {{message}} placeholders
↓
Embed Font as Data URI in CSS @font-face
↓
Launch Puppeteer (Headless Chrome)
↓
Render HTML with Bangla Fonts
↓
Generate PDF from Rendered Page
↓
Save PDF to outputs/ folder
↓
Return PDF to Client
- Font File Reading: The TTF font file is read from disk
- Base64 Encoding: Font is converted to Base64 format
- Data URI Creation: Base64 string is wrapped as a Data URI
- CSS @font-face: Font is embedded in the HTML's
@font-facedeclaration - Puppeteer Rendering: Puppeteer renders the HTML with embedded font
- PDF Generation: The rendered page with fonts is converted to PDF
This approach ensures:
- ✅ Fonts are embedded in the PDF
- ✅ No external font dependencies
- ✅ Portable and shareable PDFs
- ✅ Works offline
Edit templates/invoice.html to customize your PDF layout:
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<style>
@font-face {
font-family: "Bangla";
src: url("{{FONT_PATH}}") format("truetype");
}
body {
font-family: "Bangla";
padding: 40px;
}
/* Add your custom styles here */
</style>
</head>
<body>
<h1>ইনভয়েস</h1>
<p>নাম: {{name}}</p>
<p>বার্তা: {{message}}</p>
<!-- Add more content here -->
</body>
</html>Available Placeholders:
{{FONT_PATH}}- Will be replaced with embedded font data URI (auto-handled){{name}}- Will be replaced with thenamevalue from request{{message}}- Will be replaced with themessagevalue from request
You can add more placeholders and handle them in server.js.
Solution:
- Ensure the font file exists in the
fonts/directory - Check that the font path in code is correct
- Verify the font is a valid TTF file
- Try a different font from the options provided
Solution:
npm install puppeteerSolution:
Change the port in server.js:
const port = 3001; // or any available portSolution: Ensure you have system dependencies installed:
# Ubuntu/Debian
sudo apt-get install -y libgbm-dev libpango-1.0-0
# macOS
brew install chromiumSolution:
- Ensure proper UTF-8 encoding in HTML:
<meta charset="UTF-8" /> - Use
!importantin CSS to force font-family - Check browser console for font loading errors
- Verify the font format matches the
src:declaration in CSS
Three sample PDFs are included in the outputs/ directory:
- AtmaFont.pdf - Generated using Atma font
- AnekBanglaFont.pdf - Generated using Anek Bangla font
- NotoSansFont.pdf - Generated using Noto Sans Bengali font
These demonstrate the PDF output quality with different Bangla fonts.
-
Font Caching: Cache the base64-encoded fonts to avoid repeated file reads
const fontCache = {}; function getCachedFont(fontPath) { if (!fontCache[fontPath]) { fontCache[fontPath] = fs.readFileSync(fontPath).toString("base64"); } return fontCache[fontPath]; }
-
PDF Queue: For high-volume scenarios, implement a job queue (Bull, RabbitMQ)
-
Timeout Handling: Add timeout limits for PDF generation
-
Error Logging: Implement proper logging system (Winston, Bunyan)
-
Database Storage: Store PDF metadata in a database instead of filesystem
- Docker: Container deployment recommended
- Memory: Allocate 2GB+ RAM for Puppeteer
- Cleanup: Implement periodic cleanup of old PDFs in
outputs/ - HTTPS: Always use HTTPS in production
- Rate Limiting: Add rate limiting to prevent abuse
Feel free to fork this project and submit improvements!
This project is perfect for:
- 📄 Invoice generation
- 🧾 Receipt printing
- 📋 Report generation
- 🎓 Certificate printing
- 📰 Newsletter generation
- 📔 Document automation
- 🎫 Ticket generation
- Node.js: v14+ (tested with v18+)
- NPM: v6+
- Puppeteer: v24.40.0
- Express: v5.2.1
- Platform: Linux, macOS, Windows
By studying this project, you'll learn:
- ✅ How to use Puppeteer for PDF generation
- ✅ How to work with custom fonts in PDFs
- ✅ How to handle file I/O in Node.js
- ✅ How to build REST APIs with Express.js
- ✅ How to embed resources (fonts) in web documents
- ✅ How to handle Bangla/Unicode text in Node.js
Created with ❤️ for Bangla web developers