Skip to content
Snippets Groups Projects
paged 5.86 KiB
Newer Older
Fred Chasen's avatar
Fred Chasen committed
#!/usr/bin/env node
Fred Chasen's avatar
Fred Chasen committed
const program = require("commander");
const ora = require("ora");
Fred Chasen's avatar
Fred Chasen committed
const Printer = require("../");
Fred Chasen's avatar
Fred Chasen committed
const path = require("path");
const fs = require("fs");
// const { promisify } = require("util");
// const writeFileAsync = promisify(fs.writeFile);
const replaceExt = require("replace-ext");
Fred Chasen's avatar
Fred Chasen committed

function commaSeparatedList(value) {
  return value.split(',');
}

Fred Chasen's avatar
Fred Chasen committed
program
Fred Chasen's avatar
Fred Chasen committed
  .version(require("../package.json").version)
  .arguments("[inputPath]")
  .option("-i, --inputs [inputs]", "Inputs")
  .option("-o, --output [output]", "Output")
  .option("-d, --debug", "Debug")
  .option("-l, --landscape", "Landscape printing", false)
  .option("-s, --page-size [size]", "Print to Page Size [size]")
  .option("-w, --width [size]", "Print to Page Width [width] in MM")
  .option("-h --height [size]", "Print to Page Height [weight] in MM")
  .option("--forceTransparentBackground", "Print with transparent background")
Fred Chasen's avatar
Fred Chasen committed
  // .option("-m, --page-margin [margin]", "Print with margin [margin]")
  // .option("-n, --hyphenate [lang]", "Hyphenate with language [language], defaults to "en-us"")
  // .option("-hi, --hypher_ignore [str]", "Ignore passed element selectors, such as ".class_to_ignore, h1"")
  // .option("-ho, --hypher_only [str]", "Only hyphenate passed elements selector, such as ".hyphenate, aside"")
  // .option("-e, --encoding [type]", "Set the encoding of the input html, defaults to "utf-8"")
  .option("-t, --timeout [ms]", "Set a max timeout of [ms]")
  .option("-x, --html", "output html file")
  .option("-b, --blockLocal", "Disallow access to filesystem for local files")
  .option("-r, --blockRemote", "Disallow requests to remote servers")
  .option("--allowedPath [allowedPaths]", "Only allow access to given filesystem paths, repeatable.", collect, [])
  .option("--allowedDomain [allowedDomains]", "Only allow access to given remote domains, repeatable", collect, [])
Fred Chasen's avatar
Fred Chasen committed
  .option("--outline-tags [tags]", "Specifies that an outline should be " +
          "generated for the resulting PDF document. [tags] specifies which " +
          "HTML tags should be considered for that outline. " +
          "\"h1,h2\" will trigger an outline with \"h1\" tags as root elements " +
          "and \"h2\" elements as their childs.")
  .option("--additional-script <script>", "Additional script tags which are " +
          "added to the HTML document before rendering. This is useful for " +
          "adding custom pagedjs handlers. The option can be repeated.",
          collect, [])
  .option("--browserEndpoint <browserEndpoint>", "Use a remote Chrome server with browserWSEndpoint")
  .option("--browserArgs <browserArgs>", "Launch Chrome with comma separated args", commaSeparatedList)
Fred Chasen's avatar
Fred Chasen committed
  .parse(process.argv);

function collect(value, previous) {
  return previous.concat(value);
}

const options = program.opts();

let input = options.inputs || program.args[0];
Fred Chasen's avatar
Fred Chasen committed

let dir = process.cwd();

let relativePath;
let allowLocal;
try {
  let uri = new URL(input);
Fred Chasen's avatar
Fred Chasen committed
} catch (error) {
  relativePath = path.resolve(dir, input);
  allowLocal = !options.blockLocal;
Fred Chasen's avatar
Fred Chasen committed
let output;

let headless = typeof options.debug === "undefined";
Fred Chasen's avatar
Fred Chasen committed
// var hyphenator;
// var hyphenateOptions;

if (!input) {
  console.error("You must include an input path");
  return process.exit(1);
}

Fred Chasen's avatar
Fred Chasen committed

Fred Chasen's avatar
Fred Chasen committed
  if ([".html", ".xhtml"].indexOf(path.extname(relativePath)) === -1) {
    console.error("Must pass a html or xhtml file as input");
Fred Chasen's avatar
Fred Chasen committed
    return process.exit(1);
  }

  try {
      fs.accessSync(relativePath, fs.F_OK);
  } catch (e) {
      console.error("Input cannot be found", e);
      return process.exit(1);
  }
Fred Chasen's avatar
Fred Chasen committed
}

if (typeof(options.output) === "string") {
  output = path.resolve(dir, options.output);
} else if (typeof(options.output) !== "undefined") {
Fred Chasen's avatar
Fred Chasen committed
  output = "./" + replaceExt(path.basename(input), ".pdf");
Fred Chasen's avatar
Fred Chasen committed
} else {
  output = "output.pdf";
}


const spinner = ora({
  spinner: "circleQuarters"
Fred Chasen's avatar
Fred Chasen committed
});
if (typeof input === "string") {
  spinner.start("Loading: " + input);
} else {
  spinner.start("Loading");
}
Fred Chasen's avatar
Fred Chasen committed

  const printerOptions = {
    headless: headless,
    allowLocal: allowLocal,
    allowRemote: !options.blockRemote,
    allowedPaths: options.allowedPaths,
    allowedDomains: options.allowedDomains,
    additionalScripts: options.additionalScript,
    browserEndpoint: options.browserEndpoint,
    timeout: options.timeout,
    browserArgs: options.browserArgs
  if (options.forceTransparentBackground) {
    printerOptions.overrideDefaultBackgroundColor = { r: 0, g: 0, b: 0, a: 0 }; // Workaround to get a transparent background in the resulting PDF. See https://bugs.chromium.org/p/chromium/issues/detail?id=498892 for more information.
  }

  let printer = new Printer(printerOptions);
Fred Chasen's avatar
Fred Chasen committed

  printer.on("page", (page) => {
    if (page.position === 0) {
      spinner.succeed("Loaded");
Fred Chasen's avatar
Fred Chasen committed

      spinner.start("Rendering: Page " + (page.position + 1));
    } else {
Fred Chasen's avatar
Fred Chasen committed
      spinner.text = "Rendering: Page " + (page.position + 1);
Fred Chasen's avatar
Fred Chasen committed

  printer.on("rendered", (msg) => {
    spinner.succeed(msg);
    spinner.start("Generating");
  });

  printer.on("postprocessing", (msg) => {
    spinner.succeed("Generated");
    spinner.start("Processing");
  });
Fred Chasen's avatar
Fred Chasen committed

  let file;
  if (headless) {
    let options = {};
    if (options.html) {
      file = await printer.html(input, options)
        .catch((e) => {
          console.error(e);
          process.exit(1);
        });
Fred Chasen's avatar
Fred Chasen committed
      output = replaceExt(output, ".html");
Fred Chasen's avatar
Fred Chasen committed
    } else {
      options.outlineTags = !options.outlineTags ? [] : options.outlineTags.split(",");
      file = await printer.pdf(input, options)
        .catch((e) => {
          console.error(e);
          process.exit(1);
        });
Fred Chasen's avatar
Fred Chasen committed
    }
  } else {
    printer.preview(input);
  }
Fred Chasen's avatar
Fred Chasen committed

  spinner.succeed("Processed");

Fred Chasen's avatar
Fred Chasen committed
  if (file) {
    fs.writeFile(output, file, (err) => {
      if (err) throw err;
      spinner.succeed("Saved to " + output);
Fred Chasen's avatar
Fred Chasen committed
      process.exit(0);
    });
  }
Fred Chasen's avatar
Fred Chasen committed
})();