UNPKG

bangla-pdf-generator-temp

Version:

A powerful Node.js utility for generating richly formatted PDF documents in Bangla (Bengali) using custom fonts, tables, images, headers, footers, and multi-column layouts. Ideal for reports, certificates, and form-based documents in Bengali script. Suppo

223 lines (195 loc) 5.49 kB
// src/core/BanglaPDF.js import puppeteer from 'puppeteer'; import path from 'path'; import { generateHTML } from '../utils/htmlGenerator.js'; import { wrapHTML } from '../utils/htmlWrapper.js'; import { FONT_MAP, DEFAULT_OPTIONS } from './constants.js'; import { ImageLoader } from '../utils/imageLoader.js'; export default class BanglaPDF { constructor(options = {}) { this.content = []; this.options = { ...DEFAULT_OPTIONS, ...options, margin: { ...DEFAULT_OPTIONS.margin, ...(options.margin || {}) } }; this.currentFont = this.options.defaultFont; this.footer = null; this.pageNumberFormat = null; this.columnMode = null; this.columnBuffer = []; } flushColumnsIfNeeded() { if (this.columnBuffer.length > 0 && this.columnMode) { this.content.push({ type: 'columns', columns: [...this.columnBuffer], count: this.columnMode }); this.columnBuffer = []; } } column(count = 2) { this.flushColumnsIfNeeded(); this.columnMode = count; this.columnBuffer = []; return this; } addText(text, options = {}) { const block = { type: 'text', value: text, font: this.currentFont, ...this.options, ...options }; if (this.columnMode) { this.columnBuffer.push(block); if (this.columnBuffer.length === this.columnMode) { this.content.push({ type: 'columns', columns: [...this.columnBuffer], count: this.columnMode }); this.columnBuffer = []; } } else { this.content.push(block); } return this; } addHeader(text, options = {}) { return this.addText(text, { fontSize: 22, bold: true, align: 'center', margin: '0 0 10px 0', ...options }); } addTable({ headers, rows, ...options }) { const block = { type: 'table', headers, rows, font: this.currentFont, cellPadding: this.options.tableCellPadding, ...this.options, ...options }; if (this.columnMode) { this.columnBuffer.push(block); if (this.columnBuffer.length === this.columnMode) this.flushColumnsIfNeeded(); } else { this.content.push(block); } return this; } async addImage(source, options = {}) { try { const processedSrc = await ImageLoader.load(source); const block = { type: 'image', src: processedSrc, ...options }; if (this.columnMode) { this.columnBuffer.push(block); if (this.columnBuffer.length === this.columnMode) this.flushColumnsIfNeeded(); } else { this.content.push(block); } return this; } catch (error) { console.error('Image loading error:', error.message); this.addText(`[Image failed to load: ${error.message}]`, { color: 'red' }); return this; } } setFooter(options = {}) { this.footer = options; return this; } setPageNumberFormat(formatFunc) { this.pageNumberFormat = formatFunc; return this; } addPageBreak() { this.flushColumnsIfNeeded(); this.content.push({ type: 'pageBreak', value: '' }); return this; } selectFont(fontName) { if (!FONT_MAP[fontName]) { throw new Error(`Font ${fontName} not available. Choose from: ${Object.keys(FONT_MAP).join(', ')}`); } this.currentFont = fontName; return this; } async save(outputPath = 'output.pdf') { this.flushColumnsIfNeeded(); const fontPath = path.resolve(FONT_MAP[this.currentFont]); const contentHTML = await generateHTML(this.content, fontPath, this.options.padding); const html = wrapHTML(contentHTML, fontPath, this.options.padding, this.currentFont); const browser = await puppeteer.launch({ headless: 'new', args: [ '--font-render-hinting=none', '--no-sandbox', '--disable-setuid-sandbox', '--disable-web-security' ] }); const page = await browser.newPage(); await page.setViewport({ width: 794, height: 1123, deviceScaleFactor: 1 }); await page.setContent(html, { waitUntil: 'networkidle0', timeout: 30000 }); const footerTextHTML = this.footer?.text ? `<div style="${this.footer?.textStyle || ''}">${this.footer.text}</div>` : ''; const pageNumberHTML = this.footer?.pageNumber ? `<div style="${this.footer?.pageNumberStyle || ''}"> Page <span class="pageNumber"></span> of <span class="totalPages"></span> </div>` : ''; const footerHtml = ` <div style=" width: 100%; padding: 0 1cm; font-family: sans-serif; text-align: ${this.footer?.align || 'center'}; "> ${this.footer?.divider?.enabled ? `<hr style='border:none; border-top: ${this.footer?.divider?.thickness || '1px'} solid ${this.footer?.divider?.color || '#000'}; margin-bottom: 5px;' />` : ''} ${footerTextHTML} ${pageNumberHTML} </div> `; await page.pdf({ path: outputPath, format: 'A4', printBackground: true, displayHeaderFooter: true, margin: { top: this.options.margin.top, right: this.options.margin.right, bottom: this.options.margin.bottom, left: this.options.margin.left }, headerTemplate: `<span></span>`, footerTemplate: footerHtml }); await browser.close(); } }