Skip to content

Instantly share code, notes, and snippets.

@Foadsf
Created October 22, 2024 06:29
Show Gist options
  • Select an option

  • Save Foadsf/6e7db7504b7a90a44fef4f23fe36765d to your computer and use it in GitHub Desktop.

Select an option

Save Foadsf/6e7db7504b7a90a44fef4f23fe36765d to your computer and use it in GitHub Desktop.
Node.js script to convert SVGs to PDFs using Puppeteer, with support for Mermaid CLI's foreignObject elements and robust dimension handling
const puppeteer = require('puppeteer');
const fs = require('fs');
const path = require('path');
async function convertSVGtoPDF(inputPath, outputPath) {
// Validate input file exists and is SVG
if (!fs.existsSync(inputPath)) {
throw new Error('Input file does not exist');
}
if (path.extname(inputPath).toLowerCase() !== '.svg') {
throw new Error('Input file must be an SVG');
}
// Read SVG content
const svgContent = fs.readFileSync(inputPath, 'utf8');
// Launch browser
const browser = await puppeteer.launch();
const page = await browser.newPage();
// Create HTML with SVG content and add viewBox if not present
await page.setContent(`
<!DOCTYPE html>
<html>
<head>
<style>
body { margin: 0; }
svg {
width: 100%;
height: 100%;
max-width: 16384px; /* Chrome's max dimension */
max-height: 16384px;
}
</style>
</head>
<body>
${svgContent}
</body>
</html>
`);
// Get and validate SVG dimensions
const dimensions = await page.evaluate(() => {
const svg = document.querySelector('svg');
let width = svg.width.baseVal.value;
let height = svg.height.baseVal.value;
// If dimensions are 0 or not set, try to get them from viewBox
if (!width || !height) {
const viewBox = svg.viewBox.baseVal;
if (viewBox) {
width = viewBox.width;
height = viewBox.height;
}
}
// If still no dimensions, try to get from bounding box
if (!width || !height) {
const bbox = svg.getBBox();
width = bbox.width;
height = bbox.height;
}
// Ensure dimensions are valid numbers and within reasonable limits
width = Math.min(Math.max(width, 1), 14400); // Max 14400 to be safe
height = Math.min(Math.max(height, 1), 14400);
return { width, height };
});
// Apply a scale factor if dimensions are too large
const maxDimension = 14400; // Maximum safe dimension
let scale = 1;
if (dimensions.width > maxDimension || dimensions.height > maxDimension) {
scale = Math.min(
maxDimension / dimensions.width,
maxDimension / dimensions.height
);
}
const finalDimensions = {
width: Math.round(dimensions.width * scale),
height: Math.round(dimensions.height * scale)
};
// Log dimensions for debugging
console.log('Original dimensions:', dimensions);
console.log('Final dimensions:', finalDimensions);
console.log('Scale factor:', scale);
try {
// Set viewport
await page.setViewport({
width: finalDimensions.width,
height: finalDimensions.height
});
// Generate PDF
await page.pdf({
path: outputPath,
width: finalDimensions.width,
height: finalDimensions.height,
printBackground: true
});
} catch (error) {
console.error('Detailed error:', error);
// Fallback to default dimensions if still getting errors
const fallbackDimensions = {
width: 800,
height: 600
};
console.log('Falling back to default dimensions:', fallbackDimensions);
await page.setViewport(fallbackDimensions);
await page.pdf({
path: outputPath,
...fallbackDimensions,
printBackground: true
});
}
await browser.close();
}
// Command line interface
if (require.main === module) {
const args = process.argv.slice(2);
if (args.length !== 2) {
console.log('Usage: node script.js <input.svg> <output.pdf>');
process.exit(1);
}
const [inputPath, outputPath] = args;
convertSVGtoPDF(inputPath, outputPath)
.then(() => {
console.log(`Successfully converted ${inputPath} to ${outputPath}`);
})
.catch(error => {
console.error('Error:', error.message);
process.exit(1);
});
}
module.exports = convertSVGtoPDF;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment