@cocalc/project
Version:
CoCalc: project daemon
66 lines (56 loc) • 1.77 kB
text/typescript
/*
Note that this doesn't actually use upstream nbconvert itself at all!
- pdf: takes html, then uses headless chrome via
chromium-browser or google-chrome, if installed to convert to pdf
NOTE: Firefox does *not* support printing to pdf in headless mode according to
https://stackoverflow.com/questions/48358556/firefox-headless-print-to-pdf-option
*/
import which from "which";
import { join, parse } from "path";
// time google-chrome --headless --disable-gpu --no-sandbox --print-to-pdf=a.pdf --run-all-compositor-stages-before-draw --virtual-time-budget=10000 a.html
const { execute_code } = require("@cocalc/backend/misc_node");
import { callback_opts } from "@cocalc/util/async-utils";
export default async function htmlToPDF(
path: string,
timeout: number = 30
): Promise<string> {
const { dir, name } = parse(path);
const outfile = join(dir, name + ".pdf");
const command = await getCommand();
const args = [
"--headless",
"--disable-gpu",
"--no-sandbox",
`--print-to-pdf=${outfile}`,
"--run-all-compositor-stages-before-draw",
`--virtual-time-budget=${timeout * 1000}`,
path,
];
const output = await callback_opts(execute_code)({
command,
args,
err_on_exit: false,
timeout,
ulimit_timeout: true,
bash: true,
});
if (output.exit_code != 0) {
throw Error(output.stderr);
}
return outfile;
}
const COMMANDS = ["google-chrome", "chromium-browser"];
let cache: string = "";
async function getCommand(): Promise<string> {
if (cache) return cache;
for (const cmd of COMMANDS) {
try {
await which(cmd);
cache = cmd;
return cmd;
} catch (_err) {}
}
throw Error(
`one of ${COMMANDS.join(" or ")} must be installed to convert to PDF`
);
}