bpmn-to-image
Version:
Convert a BPMN 2.0 diagrams to PDF, SVG or PNG images
160 lines (124 loc) • 2.94 kB
JavaScript
import puppeteer from 'puppeteer';
import {
basename,
} from 'node:path';
import {
readFileSync,
writeFileSync
} from 'node:fs';
/** @typedef { import('puppeteer').Page } Page */
/** @typedef { PrintOptions } any */
/**
* @param { Page } page
* @param { PrintOptions } options
*
* @return {Promise<void>}
*/
async function printDiagram(page, options) {
const {
input,
outputs,
minDimensions,
footer,
title = true,
deviceScaleFactor
} = options;
const diagramXML = readFileSync(input, 'utf8');
const diagramTitle = title === false ? false : (
title.length ? title : basename(input)
);
await page.goto(new URL('./skeleton.html', import.meta.url));
const viewerScript = import.meta.resolve('bpmn-js/dist/bpmn-viewer.production.min.js');
const desiredViewport = await page.evaluate(async function(diagramXML, options) {
const {
viewerScript,
...openOptions
} = options;
await loadScript(viewerScript);
// returns desired viewport
return openDiagram(diagramXML, openOptions);
}, diagramXML, {
minDimensions,
title: diagramTitle,
viewerScript,
footer
});;
page.setViewport({
width: Math.round(desiredViewport.width),
height: Math.round(desiredViewport.height),
deviceScaleFactor
});
await page.evaluate(() => resize());
for (const output of outputs) {
console.log(`writing ${output}`);
if (output.endsWith('.pdf')) {
await page.pdf({
path: output,
width: desiredViewport.width,
height: desiredViewport.diagramHeight
});
} else
if (output.endsWith('.png')) {
await page.screenshot({
path: output,
clip: {
x: 0,
y: 0,
width: desiredViewport.width,
height: desiredViewport.diagramHeight
}
});
} else
if (output.endsWith('.svg')) {
const svg = await page.evaluate(() => toSVG());
writeFileSync(output, svg, 'utf8');
} else {
console.error(`Unknown output file format: ${output}`);
}
}
}
async function withPage(fn) {
let browser;
try {
browser = await puppeteer.launch({
headless: 'new'
});
await fn(await browser.newPage());
} finally {
if (browser) {
await browser.close();
}
}
}
export async function convertAll(conversions, options={}) {
const {
minDimensions,
footer,
title,
deviceScaleFactor
} = options;
await withPage(async function(page) {
for (const conversion of conversions) {
const {
input,
outputs
} = conversion;
await printDiagram(page, {
input,
outputs,
minDimensions,
title,
footer,
deviceScaleFactor
});
}
});
}
export async function convert(input, output) {
return await convertAll([
{
input,
outputs: [ output ]
}
]);
}