Skip to content

Latest commit

 

History

History
475 lines (348 loc) · 12.2 KB

File metadata and controls

475 lines (348 loc) · 12.2 KB

HTML to PDF with Bangla Fonts - Express.js Example

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.

🎯 Project Overview

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

✨ Features

  • 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

📋 Requirements

  • Node.js v14+ (v16+ recommended)
  • npm or yarn
  • Modern system with adequate RAM for Puppeteer (requires ~150MB)

🚀 Installation

1. Clone or download the project

git clone <repository-url>
cd html-to-pdf-bangla-example

2. Install dependencies

npm install

3. Start the server

Development mode (with auto-reload):

npm run dev

Production mode:

npm start

The server will start on http://localhost:3000

📁 Project Structure

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

🔌 API Documentation

Health Check Endpoint

GET /health

Verify that the server is running.

Response:

{
  "status": "ok"
}

PDF Generation Endpoint

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 language
  • message (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

💻 Usage Examples

Using cURL

curl -X POST http://localhost:3000/generate-html-to-pdf \
  -H "Content-Type: application/json" \
  -d '{
    "name": "আপনার নাম",
    "message": "আপনার বার্তা এখানে লিখুন"
  }' \
  --output invoice.pdf

Using Fetch (JavaScript/Frontend)

const 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);
  }
};

Using Axios (Node.js)

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();

🎨 Available Fonts

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.

How to Switch Fonts

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
});

🔧 How It Works

Architecture Flow

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 Embedding Process

  1. Font File Reading: The TTF font file is read from disk
  2. Base64 Encoding: Font is converted to Base64 format
  3. Data URI Creation: Base64 string is wrapped as a Data URI
  4. CSS @font-face: Font is embedded in the HTML's @font-face declaration
  5. Puppeteer Rendering: Puppeteer renders the HTML with embedded font
  6. 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

📝 Customizing the Template

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 the name value from request
  • {{message}} - Will be replaced with the message value from request

You can add more placeholders and handle them in server.js.


🐛 Troubleshooting

Issue: PDF doesn't display Bangla text

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

Issue: "Cannot find module 'puppeteer'"

Solution:

npm install puppeteer

Issue: "Port 3000 is already in use"

Solution: Change the port in server.js:

const port = 3001; // or any available port

Issue: Puppeteer launch fails

Solution: Ensure you have system dependencies installed:

# Ubuntu/Debian
sudo apt-get install -y libgbm-dev libpango-1.0-0

# macOS
brew install chromium

Issue: Fonts not embedding properly

Solution:

  • Ensure proper UTF-8 encoding in HTML: <meta charset="UTF-8" />
  • Use !important in CSS to force font-family
  • Check browser console for font loading errors
  • Verify the font format matches the src: declaration in CSS

📊 Sample Outputs

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.


🚀 Production Considerations

Performance Optimization

  1. 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];
    }
  2. PDF Queue: For high-volume scenarios, implement a job queue (Bull, RabbitMQ)

  3. Timeout Handling: Add timeout limits for PDF generation

  4. Error Logging: Implement proper logging system (Winston, Bunyan)

  5. Database Storage: Store PDF metadata in a database instead of filesystem

Deployment

  • 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

📚 Resources


🤝 Contributing

Feel free to fork this project and submit improvements!


💡 Use Cases

This project is perfect for:

  • 📄 Invoice generation
  • 🧾 Receipt printing
  • 📋 Report generation
  • 🎓 Certificate printing
  • 📰 Newsletter generation
  • 📔 Document automation
  • 🎫 Ticket generation

⚙️ System Information

  • Node.js: v14+ (tested with v18+)
  • NPM: v6+
  • Puppeteer: v24.40.0
  • Express: v5.2.1
  • Platform: Linux, macOS, Windows

🎓 Learning Outcomes

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