htmlpdfs / puppeteer_pdf.js
ABDALLALSWAITI's picture
Upload 2 files
dd229d4 verified
#!/usr/bin/env node
const puppeteer = require('puppeteer');
const path = require('path');
const fs = require('fs');
// Get command line arguments
const args = process.argv.slice(2);
if (args.length < 2) {
console.error('Usage: node puppeteer_pdf.js <html_file_path> <aspect_ratio>');
process.exit(1);
}
const htmlFilePath = args[0];
const aspectRatio = args[1];
// Check if HTML file exists
if (!fs.existsSync(htmlFilePath)) {
console.error(`Error: HTML file not found at ${htmlFilePath}`);
process.exit(1);
}
// Main conversion function
async function convertToPDF() {
let browser;
try {
console.log('Starting PDF conversion...');
console.log(`HTML File: ${htmlFilePath}`);
console.log(`Aspect Ratio: ${aspectRatio}`);
// Get absolute paths
const absoluteHtmlPath = path.resolve(htmlFilePath);
const htmlDir = path.dirname(absoluteHtmlPath);
console.log(`HTML Directory: ${htmlDir}`);
// Read HTML content
let htmlContent = fs.readFileSync(absoluteHtmlPath, 'utf8');
// List image files in the directory
const imageFiles = fs.readdirSync(htmlDir).filter(file =>
/\.(jpg|jpeg|png|gif|svg|webp|bmp)$/i.test(file)
);
console.log(`Found ${imageFiles.length} image file(s) in directory:`, imageFiles);
// Launch browser with system Chromium
const browserOptions = {
headless: true,
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-web-security',
'--disable-features=IsolateOrigins',
'--disable-site-isolation-trials',
'--disable-accelerated-2d-canvas',
'--disable-gpu',
'--disable-software-rasterizer',
'--disable-dev-tools',
'--no-first-run',
'--no-default-browser-check',
'--disable-breakpad',
'--disable-crash-reporter',
'--no-crashpad',
'--disable-features=Crashpad',
'--crash-dumps-dir=/tmp',
'--disable-component-update'
]
};
browserOptions.env = {
...process.env,
CHROME_CRASHPAD_PIPE_NAME: 'NONE'
};
// Try to use system Chromium if available
const chromiumPaths = [
'/usr/bin/chromium',
'/usr/bin/chromium-browser',
'/usr/bin/google-chrome',
'/usr/bin/google-chrome-stable'
];
for (const chromiumPath of chromiumPaths) {
if (fs.existsSync(chromiumPath)) {
browserOptions.executablePath = chromiumPath;
console.log(`Using Chromium at: ${chromiumPath}`);
break;
}
}
browser = await puppeteer.launch(browserOptions);
const page = await browser.newPage();
// Set viewport for better rendering based on aspect ratio
let viewportWidth = 1920;
let viewportHeight = 1080;
if (aspectRatio === '9:16') {
viewportWidth = 1080;
viewportHeight = 1920;
} else if (aspectRatio === '1:1') {
viewportWidth = 1080;
viewportHeight = 1080;
}
await page.setViewport({
width: viewportWidth,
height: viewportHeight,
deviceScaleFactor: 1 // Changed from 2 to 1 to preserve original sizing
});
console.log(`Viewport set to: ${viewportWidth}x${viewportHeight}`);
// Construct file:// URL for the HTML directory
const baseUrl = 'file://' + htmlDir + '/';
console.log(`Base URL: ${baseUrl}`);
// Load HTML content with file:// protocol
console.log('Loading HTML content...');
await page.goto(baseUrl + path.basename(absoluteHtmlPath), {
waitUntil: ['networkidle0', 'domcontentloaded'],
timeout: 30000
});
// Wait for all images and fonts to load
console.log('Waiting for images and fonts...');
await page.evaluate(async () => {
const selectors = Array.from(document.querySelectorAll("img"));
console.log('Found', selectors.length, 'img tags');
await Promise.all([
document.fonts.ready,
...selectors.map((img) => {
console.log('Image src:', img.src, 'Complete:', img.complete);
if (img.complete) return Promise.resolve();
return new Promise((resolve) => {
img.addEventListener("load", () => {
console.log('Loaded:', img.src);
resolve();
});
img.addEventListener("error", () => {
console.log('Error loading:', img.src);
resolve();
});
setTimeout(() => {
console.log('Timeout:', img.src);
resolve();
}, 5000);
});
}),
]);
});
// Check which images loaded successfully
const imageStatus = await page.evaluate(() => {
const images = Array.from(document.querySelectorAll('img'));
return images.map(img => ({
src: img.src,
complete: img.complete,
naturalWidth: img.naturalWidth,
naturalHeight: img.naturalHeight,
width: img.width,
height: img.height
}));
});
console.log('Image loading status:', JSON.stringify(imageStatus, null, 2));
// Count pages for logging
const pageCount = await page.evaluate(() => {
const pages = document.querySelectorAll('.page, .slide, section.page, article.page');
return pages.length || 'unknown';
});
console.log(`Detected ${pageCount} page element(s) in HTML`);
// Emulate screen media (not print) to preserve CSS
await page.emulateMediaType('screen');
// Additional wait for rendering and animations
console.log('Waiting for final render...');
await new Promise(resolve => setTimeout(resolve, 2000));
// Generate PDF path
const pdfPath = htmlFilePath.replace('.html', '.pdf');
// Configure PDF options based on aspect ratio
let pdfOptions = {
path: pdfPath,
printBackground: true,
preferCSSPageSize: true,
margin: {
top: '0mm',
right: '0mm',
bottom: '0mm',
left: '0mm'
},
displayHeaderFooter: false,
scale: 1.0
};
// Set dimensions based on aspect ratio
if (aspectRatio === '16:9') {
pdfOptions.width = '288mm';
pdfOptions.height = '162mm';
pdfOptions.landscape = false;
console.log('PDF format: Custom 16:9 (288mm x 162mm)');
} else if (aspectRatio === '1:1') {
pdfOptions.width = '210mm';
pdfOptions.height = '210mm';
pdfOptions.landscape = false;
console.log('PDF format: Square (210mm x 210mm)');
} else if (aspectRatio === '9:16') {
pdfOptions.width = '162mm';
pdfOptions.height = '288mm';
pdfOptions.landscape = false;
console.log('PDF format: Custom 9:16 (162mm x 288mm)');
} else {
pdfOptions.width = '297mm';
pdfOptions.height = '210mm';
pdfOptions.landscape = true;
console.log('PDF format: A4 Landscape (default)');
}
// Generate the PDF
console.log('Generating PDF...');
await page.pdf(pdfOptions);
// Verify PDF was created
if (fs.existsSync(pdfPath)) {
const stats = fs.statSync(pdfPath);
console.log(`Successfully converted ${htmlFilePath} to ${pdfPath}`);
console.log(`PDF size: ${(stats.size / 1024).toFixed(2)} KB`);
process.exit(0);
} else {
console.error('PDF file was not created');
process.exit(1);
}
} catch (error) {
console.error(`PDF conversion failed: ${error.message}`);
console.error(error.stack);
process.exit(1);
} finally {
if (browser) {
await browser.close();
}
}
}
// Run conversion
convertToPDF().catch(error => {
console.error('Unhandled error:', error);
process.exit(1);
});