Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • pagedjs/pagedjs-cli
  • math712b/pagedjs-cli
  • valentin.schabschneider/pagedjs-cli
3 results
Show changes
Showing
with 8397 additions and 428 deletions
File added
File added
File added
File added
File added
File added
1.c52c62a7c50daf7d3f73ec16977cd4b0ea401710807d5dbe3850941dd1b73a70
\ No newline at end of file
{
"manifest_version": 2,
"name": "hyphens-data",
"version": "120.0.6050.0"
}
\ No newline at end of file
This diff is collapsed.
{
"name": "pagedjs-cli",
"version": "0.0.2",
"version": "0.4.3",
"author": "Fred Chasen",
"license": "MIT",
"homepage": "https://pagedmedia.org",
"homepage": "https://pagedjs.org",
"repository": {
"type": "git",
"url": "https://gitlab.pagedmedia.org/polyfills/pagedjs-cli.git"
"url": "https://gitlab.coko.foundation/pagedjs/pagedjs.git"
},
"type": "module",
"main": "./src/index.js",
"exports": {
"import": "./src/index.js",
"require": "./src/index.js",
"default": "./src/index.js"
},
"bin": "./src/cli.js",
"scripts": {
"start": "./bin/paged"
"start": "./src/cli.js",
"build": "rollup -c",
"lint": "eslint src",
"test": "npm run lint",
"prepare": "npm run build"
},
"dependencies": {
"commander": "^2.15.1",
"express": "^4.16.3",
"pagedjs": "latest",
"puppeteer": "^1.5.0",
"replace-ext": "^1.0.0"
}
"commander": "^11.1.0",
"express": "^4.18.2",
"html-entities": "^2.4.0",
"katex": "^0.16.9",
"lodash": "^4.17.21",
"mathjax": "^3.2.2",
"node-fetch": "^3.3.2",
"ora": "^8.0.1",
"pagedjs": "^0.4.3",
"pdf-lib": "1.17.1",
"puppeteer": "^21.9.0",
"replace-ext": "^2.0.0"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.2.3",
"eslint": "^8.56.0",
"rollup": "^4.9.6",
"rollup-plugin-license": "^3.2.0",
"rollup-plugin-serve": "^2.0.2"
},
"files": [
"dist",
"src"
]
}
import { nodeResolve } from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import json from "@rollup/plugin-json";
import license from "rollup-plugin-license";
const plugins = [
nodeResolve({
extensions: ['.cjs','.mjs', '.js']
}),
commonjs({
include: ["node_modules/**", "../../node_modules/**"]
}),
json(),
license({
banner: "@license Paged.js v<%= pkg.version %> | MIT | https://pagedjs.org",
})
];
export default [
{
input: "./src/browser.js",
output: {
name: "PagedPolyfill",
file: "./dist/browser.js",
format: "umd"
},
plugins: plugins
}
];
{
"defaultAction": "SCMP_ACT_ERRNO",
"archMap": [
{
"architecture": "SCMP_ARCH_X86_64",
"subArchitectures": [
"SCMP_ARCH_X86",
"SCMP_ARCH_X32"
]
},
{
"architecture": "SCMP_ARCH_AARCH64",
"subArchitectures": [
"SCMP_ARCH_ARM"
]
},
{
"architecture": "SCMP_ARCH_MIPS64",
"subArchitectures": [
"SCMP_ARCH_MIPS",
"SCMP_ARCH_MIPS64N32"
]
},
{
"architecture": "SCMP_ARCH_MIPS64N32",
"subArchitectures": [
"SCMP_ARCH_MIPS",
"SCMP_ARCH_MIPS64"
]
},
{
"architecture": "SCMP_ARCH_MIPSEL64",
"subArchitectures": [
"SCMP_ARCH_MIPSEL",
"SCMP_ARCH_MIPSEL64N32"
]
},
{
"architecture": "SCMP_ARCH_MIPSEL64N32",
"subArchitectures": [
"SCMP_ARCH_MIPSEL",
"SCMP_ARCH_MIPSEL64"
]
},
{
"architecture": "SCMP_ARCH_S390X",
"subArchitectures": [
"SCMP_ARCH_S390"
]
}
],
"syscalls": [
{
"comment": "Allow create user namespaces",
"names": [
"clone",
"setns",
"unshare"
],
"action": "SCMP_ACT_ALLOW",
"args": [],
"includes": {},
"excludes": {}
},
{
"names": [
"accept",
"accept4",
"access",
"adjtimex",
"alarm",
"bind",
"brk",
"capget",
"capset",
"chdir",
"chmod",
"chown",
"chown32",
"clock_adjtime",
"clock_adjtime64",
"clock_getres",
"clock_getres_time64",
"clock_gettime",
"clock_gettime64",
"clock_nanosleep",
"clock_nanosleep_time64",
"close",
"connect",
"copy_file_range",
"creat",
"dup",
"dup2",
"dup3",
"epoll_create",
"epoll_create1",
"epoll_ctl",
"epoll_ctl_old",
"epoll_pwait",
"epoll_wait",
"epoll_wait_old",
"eventfd",
"eventfd2",
"execve",
"execveat",
"exit",
"exit_group",
"faccessat",
"fadvise64",
"fadvise64_64",
"fallocate",
"fanotify_mark",
"fchdir",
"fchmod",
"fchmodat",
"fchown",
"fchown32",
"fchownat",
"fcntl",
"fcntl64",
"fdatasync",
"fgetxattr",
"flistxattr",
"flock",
"fork",
"fremovexattr",
"fsetxattr",
"fstat",
"fstat64",
"fstatat64",
"fstatfs",
"fstatfs64",
"fsync",
"ftruncate",
"ftruncate64",
"futex",
"futex_time64",
"futimesat",
"getcpu",
"getcwd",
"getdents",
"getdents64",
"getegid",
"getegid32",
"geteuid",
"geteuid32",
"getgid",
"getgid32",
"getgroups",
"getgroups32",
"getitimer",
"getpeername",
"getpgid",
"getpgrp",
"getpid",
"getppid",
"getpriority",
"getrandom",
"getresgid",
"getresgid32",
"getresuid",
"getresuid32",
"getrlimit",
"get_robust_list",
"getrusage",
"getsid",
"getsockname",
"getsockopt",
"get_thread_area",
"gettid",
"gettimeofday",
"getuid",
"getuid32",
"getxattr",
"inotify_add_watch",
"inotify_init",
"inotify_init1",
"inotify_rm_watch",
"io_cancel",
"ioctl",
"io_destroy",
"io_getevents",
"io_pgetevents",
"io_pgetevents_time64",
"ioprio_get",
"ioprio_set",
"io_setup",
"io_submit",
"io_uring_enter",
"io_uring_register",
"io_uring_setup",
"ipc",
"kill",
"lchown",
"lchown32",
"lgetxattr",
"link",
"linkat",
"listen",
"listxattr",
"llistxattr",
"_llseek",
"lremovexattr",
"lseek",
"lsetxattr",
"lstat",
"lstat64",
"madvise",
"membarrier",
"memfd_create",
"mincore",
"mkdir",
"mkdirat",
"mknod",
"mknodat",
"mlock",
"mlock2",
"mlockall",
"mmap",
"mmap2",
"mprotect",
"mq_getsetattr",
"mq_notify",
"mq_open",
"mq_timedreceive",
"mq_timedreceive_time64",
"mq_timedsend",
"mq_timedsend_time64",
"mq_unlink",
"mremap",
"msgctl",
"msgget",
"msgrcv",
"msgsnd",
"msync",
"munlock",
"munlockall",
"munmap",
"nanosleep",
"newfstatat",
"_newselect",
"open",
"openat",
"pause",
"pipe",
"pipe2",
"poll",
"ppoll",
"ppoll_time64",
"prctl",
"pread64",
"preadv",
"preadv2",
"prlimit64",
"pselect6",
"pselect6_time64",
"pwrite64",
"pwritev",
"pwritev2",
"read",
"readahead",
"readlink",
"readlinkat",
"readv",
"recv",
"recvfrom",
"recvmmsg",
"recvmmsg_time64",
"recvmsg",
"remap_file_pages",
"removexattr",
"rename",
"renameat",
"renameat2",
"restart_syscall",
"rmdir",
"rseq",
"rt_sigaction",
"rt_sigpending",
"rt_sigprocmask",
"rt_sigqueueinfo",
"rt_sigreturn",
"rt_sigsuspend",
"rt_sigtimedwait",
"rt_sigtimedwait_time64",
"rt_tgsigqueueinfo",
"sched_getaffinity",
"sched_getattr",
"sched_getparam",
"sched_get_priority_max",
"sched_get_priority_min",
"sched_getscheduler",
"sched_rr_get_interval",
"sched_rr_get_interval_time64",
"sched_setaffinity",
"sched_setattr",
"sched_setparam",
"sched_setscheduler",
"sched_yield",
"seccomp",
"select",
"semctl",
"semget",
"semop",
"semtimedop",
"semtimedop_time64",
"send",
"sendfile",
"sendfile64",
"sendmmsg",
"sendmsg",
"sendto",
"setfsgid",
"setfsgid32",
"setfsuid",
"setfsuid32",
"setgid",
"setgid32",
"setgroups",
"setgroups32",
"setitimer",
"setpgid",
"setpriority",
"setregid",
"setregid32",
"setresgid",
"setresgid32",
"setresuid",
"setresuid32",
"setreuid",
"setreuid32",
"setrlimit",
"set_robust_list",
"setsid",
"setsockopt",
"set_thread_area",
"set_tid_address",
"setuid",
"setuid32",
"setxattr",
"shmat",
"shmctl",
"shmdt",
"shmget",
"shutdown",
"sigaltstack",
"signalfd",
"signalfd4",
"sigprocmask",
"sigreturn",
"socket",
"socketcall",
"socketpair",
"splice",
"stat",
"stat64",
"statfs",
"statfs64",
"statx",
"symlink",
"symlinkat",
"sync",
"sync_file_range",
"syncfs",
"sysinfo",
"tee",
"tgkill",
"time",
"timer_create",
"timer_delete",
"timer_getoverrun",
"timer_gettime",
"timer_gettime64",
"timer_settime",
"timer_settime64",
"timerfd_create",
"timerfd_gettime",
"timerfd_gettime64",
"timerfd_settime",
"timerfd_settime64",
"times",
"tkill",
"truncate",
"truncate64",
"ugetrlimit",
"umask",
"uname",
"unlink",
"unlinkat",
"utime",
"utimensat",
"utimensat_time64",
"utimes",
"vfork",
"vmsplice",
"wait4",
"waitid",
"waitpid",
"write",
"writev"
],
"action": "SCMP_ACT_ALLOW",
"args": [],
"comment": "",
"includes": {},
"excludes": {}
},
{
"names": [
"ptrace"
],
"action": "SCMP_ACT_ALLOW",
"args": null,
"comment": "",
"includes": {
"minKernel": "4.8"
},
"excludes": {}
},
{
"names": [
"personality"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 0,
"valueTwo": 0,
"op": "SCMP_CMP_EQ"
}
],
"comment": "",
"includes": {},
"excludes": {}
},
{
"names": [
"personality"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 8,
"valueTwo": 0,
"op": "SCMP_CMP_EQ"
}
],
"comment": "",
"includes": {},
"excludes": {}
},
{
"names": [
"personality"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 131072,
"valueTwo": 0,
"op": "SCMP_CMP_EQ"
}
],
"comment": "",
"includes": {},
"excludes": {}
},
{
"names": [
"personality"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 131080,
"valueTwo": 0,
"op": "SCMP_CMP_EQ"
}
],
"comment": "",
"includes": {},
"excludes": {}
},
{
"names": [
"personality"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 4294967295,
"valueTwo": 0,
"op": "SCMP_CMP_EQ"
}
],
"comment": "",
"includes": {},
"excludes": {}
},
{
"names": [
"sync_file_range2"
],
"action": "SCMP_ACT_ALLOW",
"args": [],
"comment": "",
"includes": {
"arches": [
"ppc64le"
]
},
"excludes": {}
},
{
"names": [
"arm_fadvise64_64",
"arm_sync_file_range",
"sync_file_range2",
"breakpoint",
"cacheflush",
"set_tls"
],
"action": "SCMP_ACT_ALLOW",
"args": [],
"comment": "",
"includes": {
"arches": [
"arm",
"arm64"
]
},
"excludes": {}
},
{
"names": [
"arch_prctl"
],
"action": "SCMP_ACT_ALLOW",
"args": [],
"comment": "",
"includes": {
"arches": [
"amd64",
"x32"
]
},
"excludes": {}
},
{
"names": [
"modify_ldt"
],
"action": "SCMP_ACT_ALLOW",
"args": [],
"comment": "",
"includes": {
"arches": [
"amd64",
"x32",
"x86"
]
},
"excludes": {}
},
{
"names": [
"s390_pci_mmio_read",
"s390_pci_mmio_write",
"s390_runtime_instr"
],
"action": "SCMP_ACT_ALLOW",
"args": [],
"comment": "",
"includes": {
"arches": [
"s390",
"s390x"
]
},
"excludes": {}
},
{
"names": [
"open_by_handle_at"
],
"action": "SCMP_ACT_ALLOW",
"args": [],
"comment": "",
"includes": {
"caps": [
"CAP_DAC_READ_SEARCH"
]
},
"excludes": {}
},
{
"names": [
"bpf",
"clone",
"fanotify_init",
"lookup_dcookie",
"mount",
"name_to_handle_at",
"perf_event_open",
"quotactl",
"setdomainname",
"sethostname",
"setns",
"syslog",
"umount",
"umount2",
"unshare"
],
"action": "SCMP_ACT_ALLOW",
"args": [],
"comment": "",
"includes": {
"caps": [
"CAP_SYS_ADMIN"
]
},
"excludes": {}
},
{
"names": [
"clone"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 2114060288,
"valueTwo": 0,
"op": "SCMP_CMP_MASKED_EQ"
}
],
"comment": "",
"includes": {},
"excludes": {
"caps": [
"CAP_SYS_ADMIN"
],
"arches": [
"s390",
"s390x"
]
}
},
{
"names": [
"clone"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 1,
"value": 2114060288,
"valueTwo": 0,
"op": "SCMP_CMP_MASKED_EQ"
}
],
"comment": "s390 parameter ordering for clone is different",
"includes": {
"arches": [
"s390",
"s390x"
]
},
"excludes": {
"caps": [
"CAP_SYS_ADMIN"
]
}
},
{
"names": [
"reboot"
],
"action": "SCMP_ACT_ALLOW",
"args": [],
"comment": "",
"includes": {
"caps": [
"CAP_SYS_BOOT"
]
},
"excludes": {}
},
{
"names": [
"chroot"
],
"action": "SCMP_ACT_ALLOW",
"args": [],
"comment": "",
"includes": {
"caps": [
"CAP_SYS_CHROOT"
]
},
"excludes": {}
},
{
"names": [
"delete_module",
"init_module",
"finit_module"
],
"action": "SCMP_ACT_ALLOW",
"args": [],
"comment": "",
"includes": {
"caps": [
"CAP_SYS_MODULE"
]
},
"excludes": {}
},
{
"names": [
"acct"
],
"action": "SCMP_ACT_ALLOW",
"args": [],
"comment": "",
"includes": {
"caps": [
"CAP_SYS_PACCT"
]
},
"excludes": {}
},
{
"names": [
"kcmp",
"process_vm_readv",
"process_vm_writev",
"ptrace"
],
"action": "SCMP_ACT_ALLOW",
"args": [],
"comment": "",
"includes": {
"caps": [
"CAP_SYS_PTRACE"
]
},
"excludes": {}
},
{
"names": [
"iopl",
"ioperm"
],
"action": "SCMP_ACT_ALLOW",
"args": [],
"comment": "",
"includes": {
"caps": [
"CAP_SYS_RAWIO"
]
},
"excludes": {}
},
{
"names": [
"settimeofday",
"stime",
"clock_settime"
],
"action": "SCMP_ACT_ALLOW",
"args": [],
"comment": "",
"includes": {
"caps": [
"CAP_SYS_TIME"
]
},
"excludes": {}
},
{
"names": [
"vhangup"
],
"action": "SCMP_ACT_ALLOW",
"args": [],
"comment": "",
"includes": {
"caps": [
"CAP_SYS_TTY_CONFIG"
]
},
"excludes": {}
},
{
"names": [
"get_mempolicy",
"mbind",
"set_mempolicy"
],
"action": "SCMP_ACT_ALLOW",
"args": [],
"comment": "",
"includes": {
"caps": [
"CAP_SYS_NICE"
]
},
"excludes": {}
},
{
"names": [
"syslog"
],
"action": "SCMP_ACT_ALLOW",
"args": [],
"comment": "",
"includes": {
"caps": [
"CAP_SYSLOG"
]
},
"excludes": {}
}
]
}
\ No newline at end of file
import * as Paged from "pagedjs";
window.Paged = Paged;
let ready = new Promise(function(resolve, reject){
if (document.readyState === "interactive" || document.readyState === "complete") {
resolve(document.readyState);
return;
}
document.onreadystatechange = function ($) {
if (document.readyState === "interactive") {
resolve(document.readyState);
}
};
});
let config = window.PagedConfig || {
auto: true,
before: undefined,
after: undefined,
content: undefined,
stylesheets: undefined,
renderTo: undefined,
settings: undefined
};
let previewer = new Paged.Previewer(config.settings);
ready.then(async function () {
let done;
if (config.before) {
await config.before();
}
if(config.auto !== false) {
done = await previewer.preview(config.content, config.stylesheets, config.renderTo);
}
if (config.after) {
await config.after(done);
}
});
export default previewer;
\ No newline at end of file
#!/usr/bin/env node
import { program } from "commander";
import ora from "ora";
import path from "path";
import fs from "fs";
import replaceExt from "replace-ext";
import Printer from "./printer.js";
// import pkg from "../package.json" assert { type: "json" };
function commaSeparatedList(value) {
return value.split(",");
}
program
// .version(pkg.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")
.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, [])
.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)
.option("--media [media]", "Emulate \"print\" or \"screen\" media, defaults to print.")
.option("--style <style>", "Path to CSS stylesheets to be added before rendering", collect, [])
.option("--warn", "Enable warning logs")
.option("--disable-script-injection", "Disable in injection of the polyphill script.")
.option("--extra-header <header:value>", "Header to be added to the page request.", collect, [])
.parse(process.argv);
function collect(value, previous) {
return previous.concat(value);
}
const options = program.opts();
let input = options.inputs || program.args[0];
let dir = process.cwd();
let relativePath;
let allowLocal;
try {
new URL(input);
allowLocal = false;
} catch (error) {
relativePath = path.resolve(dir, input);
allowLocal = !options.blockLocal;
}
const extraHTTPHeaders = options.extraHeader.reduce((acc, header) => {
const [name, ...value] = header.split(":");
return [ ...acc, { [name]: value.join(":") } ];
}, []);
let output;
if (!input) {
console.error("You must include an input path");
process.exit(1);
}
if (relativePath) {
if ([".html", ".xhtml"].indexOf(path.extname(relativePath)) === -1) {
console.error("Must pass a html or xhtml file as input");
process.exit(1);
}
try {
fs.accessSync(relativePath, fs.F_OK);
} catch (e) {
console.error("Input cannot be found", e);
process.exit(1);
}
}
if (typeof(options.output) === "string") {
output = path.resolve(dir, options.output);
} else if (typeof(options.output) !== "undefined") {
output = "./" + replaceExt(path.basename(input), ".pdf");
}
const spinner = ora({
spinner: "circleQuarters"
});
if (typeof input === "string") {
spinner.start("Loading: " + input);
} else {
spinner.start("Loading");
}
(async () => {
const printerOptions = {
debug: options.debug,
headless: options.headless,
allowLocal: allowLocal,
allowRemote: !options.blockRemote,
allowedPaths: options.allowedPaths,
allowedDomains: options.allowedDomains,
additionalScripts: options.additionalScript,
styles: options.style,
browserEndpoint: options.browserEndpoint,
timeout: options.timeout,
browserArgs: options.browserArgs,
emulateMedia: options.media,
enableWarnings: options.warn,
disableScriptInjection: options.disableScriptInjection,
extraHTTPHeaders: extraHTTPHeaders
};
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);
printer.on("page", (page) => {
if (page.position === 0) {
spinner.succeed("Loaded");
spinner.start("Rendering: Page " + (page.position + 1));
} else {
spinner.text = "Rendering: Page " + (page.position + 1);
}
});
printer.on("rendered", (msg) => {
spinner.succeed(msg);
spinner.start("Generating");
});
printer.on("postprocessing", (msg) => {
spinner.succeed("Generated");
spinner.start("Processing");
});
options.outlineTags = !options.outlineTags ? ["h1","h2","h3"] : options.outlineTags.split(",");
let file;
if (options.html) {
file = await printer.html(input, options)
.catch((e) => {
console.error(e);
process.exit(1);
});
output = replaceExt(output, ".html");
} else if (options.debug === true) {
await printer.preview(input);
} else {
file = await printer.pdf(input, options)
.catch((e) => {
console.error(e);
process.exit(1);
});
}
spinner.succeed("Processed");
if (file && output) {
fs.writeFile(output, file, (err) => {
if (err) throw err;
spinner.succeed("Saved to " + output);
process.exit(0);
});
} else if (file) {
process.stdout.write(file);
}
})();
import Printer from "./printer.js";
export default Printer;
// Adapted from asciidoctor-web-pdf for HTML documents
// https://github.com/Mogztter/asciidoctor-web-pdf/blob/0a27de7423f12fe1f8b5ff7bcb720b786fb63e5b/lib/outline.js
import { PDFDict, PDFName, PDFNumber, PDFHexString } from "pdf-lib";
import { decode as htmlEntitiesDecode } from "html-entities";
const SanitizeXMLRx = /<[^>]+>/g;
function sanitize (string) {
if (string.includes("<")) {
string = string.replace(SanitizeXMLRx, "");
}
return htmlEntitiesDecode(string);
}
async function parseOutline(page, tags, enableWarnings) {
return await page.evaluate((tags) => {
const tagsToProcess = [];
for (const node of document.querySelectorAll(tags.join(","))) {
tagsToProcess.push(node);
}
tagsToProcess.reverse();
const root = {children: [], depth: -1};
let currentOutlineNode = root;
const linkHolder = document.createElement("div");
const body = document.querySelector("body");
linkHolder.style.display = "none";
body.insertBefore(linkHolder, body.firstChild);
while (tagsToProcess.length > 0) {
const tag = tagsToProcess.pop();
const orderDepth = tags.indexOf(tag.tagName.toLowerCase());
const dest = encodeURIComponent(tag.id).replace(/%/g, "#25");
// Add to link holder to register a destination
const hiddenLink = document.createElement("a");
hiddenLink.href = "#"+dest;
linkHolder.appendChild(hiddenLink);
if (orderDepth < currentOutlineNode.depth) {
currentOutlineNode = currentOutlineNode.parent;
tagsToProcess.push(tag);
} else {
const newNode = {
title: tag.innerText.trim(),
// encode section ID until https://bugs.chromium.org/p/chromium/issues/detail?id=985254 is fixed
destination: dest,
children: [],
depth: orderDepth,
};
if (orderDepth == currentOutlineNode.depth) {
if (currentOutlineNode.parent) {
newNode.parent = currentOutlineNode.parent;
currentOutlineNode.parent.children.push(newNode);
} else {
newNode.parent = currentOutlineNode;
currentOutlineNode.children.push(newNode);
}
currentOutlineNode = newNode;
} else if (orderDepth > currentOutlineNode.depth) {
newNode.parent = currentOutlineNode;
currentOutlineNode.children.push(newNode);
currentOutlineNode = newNode;
}
}
}
const stripParentProperty = (node) => {
node.parent = undefined;
for (const child of node.children) {
stripParentProperty(child);
}
};
stripParentProperty(root);
return root.children;
}, tags);
}
function setRefsForOutlineItems (layer, context, parentRef) {
for (const item of layer) {
item.ref = context.nextRef();
item.parentRef = parentRef;
setRefsForOutlineItems(item.children, context, item.ref);
}
}
function countChildrenOfOutline (layer) {
let count = 0;
for (const item of layer) {
++count;
count += countChildrenOfOutline(item.children);
}
return count;
}
function buildPdfObjectsForOutline (layer, context) {
for (const [i, item] of layer.entries()) {
const prev = layer[i - 1];
const next = layer[i + 1];
const pdfObject = new Map([
[PDFName.of("Title"), PDFHexString.fromText(sanitize(item.title))],
[PDFName.of("Dest"), PDFName.of(item.destination)],
[PDFName.of("Parent"), item.parentRef]
]);
if (prev) {
pdfObject.set(PDFName.of("Prev"), prev.ref);
}
if (next) {
pdfObject.set(PDFName.of("Next"), next.ref);
}
if (item.children.length > 0) {
pdfObject.set(PDFName.of("First"), item.children[0].ref);
pdfObject.set(PDFName.of("Last"), item.children[item.children.length - 1].ref);
pdfObject.set(PDFName.of("Count"), PDFNumber.of(countChildrenOfOutline(item.children)));
}
context.assign(item.ref, PDFDict.fromMapWithContext(pdfObject, context));
buildPdfObjectsForOutline(item.children, context);
}
}
function generateWarningsAboutMissingDestinations (layer, pdfDoc) {
const dests = pdfDoc.context.lookup(pdfDoc.catalog.get(PDFName.of("Dests")));
// Dests can be undefined if the PDF wasn't successfully generated (for instance if Paged.js threw an exception)
if (dests) {
const validDestinationTargets = dests.entries().map(([key, _]) => key.value());
for (const item of layer) {
if (item.destination && !validDestinationTargets.includes("/" + item.destination)) {
console.warn(`Unable to find destination "${item.destination}" while generating PDF outline.`);
}
generateWarningsAboutMissingDestinations(item.children, pdfDoc);
}
}
}
async function setOutline (pdfDoc, outline, enableWarnings=false) {
const context = pdfDoc.context;
const outlineRef = context.nextRef();
if (outline.length === 0) {
return pdfDoc;
}
if (enableWarnings) {
generateWarningsAboutMissingDestinations(outline, pdfDoc);
}
setRefsForOutlineItems(outline, context, outlineRef);
buildPdfObjectsForOutline(outline, context);
const outlineObject = PDFDict.fromMapWithContext(new Map([
[PDFName.of("First"), outline[0].ref],
[PDFName.of("Last"), outline[outline.length - 1].ref],
[PDFName.of("Count"), PDFNumber.of(countChildrenOfOutline(outline))]
]), context);
context.assign(outlineRef, outlineObject);
pdfDoc.catalog.set(PDFName.of("Outlines"), outlineRef);
return pdfDoc;
}
export {
parseOutline,
setOutline
};
\ No newline at end of file
export function setTrimBoxes(pdfDoc, pages) {
const pdfPages = pdfDoc.getPages();
pdfPages.forEach((pdfPage, index) => {
const page = pages[index];
if (!page) {
return; // page was not rendered
}
let { boxes } = page;
if (Object.is(boxes.media, boxes.crop)) {
return; // No bleed set
}
pdfPage.setTrimBox(boxes.crop.x,
boxes.crop.y,
boxes.crop.width + boxes.crop.x,
boxes.crop.height + boxes.crop.y);
});
}
export function setMetadata(pdfDoc, meta) {
if (meta.keywords && typeof meta.keywords === "string") {
meta.keywords = meta.keywords.split(",");
}
if (!meta.keywords) {
meta.keywords = [];
}
// Overwrite Dates
if (!(meta.creationDate instanceof Date)) {
meta.creationDate = new Date();
}
meta.modDate = new Date();
meta.metadataDate = new Date();
// Get the existing Info
if (!meta.creator) {
let creator = pdfDoc.getCreator();
meta.creator = creator + " + Paged.js";
}
if (!meta.producer) {
let producer = pdfDoc.getProducer();
meta.producer = producer;
}
if (meta.title) {
pdfDoc.setTitle(meta.title);
}
if (meta.subject) {
pdfDoc.setSubject(meta.subject);
}
if (meta.keywords && meta.keywords.length) {
pdfDoc.setKeywords(meta.keywords);
}
if (meta.author) {
pdfDoc.setAuthor(meta.author);
}
if (meta.creationDate) {
pdfDoc.setCreationDate(meta.creationDate);
}
if (meta.modDate) {
pdfDoc.setModificationDate(meta.modDate);
}
if (meta.creator) {
pdfDoc.setCreator(meta.creator);
}
if (meta.producer) {
pdfDoc.setProducer(meta.producer);
}
}
\ No newline at end of file
import EventEmitter from "events";
import puppeteer from "puppeteer";
import path from "path";
import fs from "fs";
import { mkdtemp, cp } from "fs/promises";
import { tmpdir } from "os";
import { join } from "node:path";
import { fileURLToPath } from "url";
import { PDFDocument } from "pdf-lib";
import { setTrimBoxes, setMetadata } from "./postprocesser.js";
import { parseOutline, setOutline } from "./outline.js";
const currentPath = fileURLToPath(import.meta.url);
const dir = process.cwd();
const scriptPath = path.resolve(path.dirname(currentPath), "../dist/browser.js");
class Printer extends EventEmitter {
constructor(options = {}) {
super();
this.debug = typeof options.debug !== "undefined" ? options.debug : false;
this.headless = options.headless !== false ? "new" : false;
this.allowLocal = options.allowLocal || false;
this.allowRemote = typeof options.allowRemote !== "undefined" ? options.allowRemote : true;
this.additionalScripts = options.additionalScripts || [];
this.allowedPaths = options.allowedPaths || [];
this.allowedDomains = options.allowedDomains || [];
this.ignoreHTTPSErrors = options.ignoreHTTPSErrors || false;
this.browserWSEndpoint = options.browserEndpoint;
this.browserArgs = options.browserArgs;
this.overrideDefaultBackgroundColor = options.overrideDefaultBackgroundColor || false;
this.timeout = options.timeout || 0;
this.closeAfter = typeof options.closeAfter !== "undefined" ? options.closeAfter : true;
this.emulateMedia = options.emulateMedia || "print";
this.styles = options.styles || [];
this.enableWarnings = options.enableWarnings || false;
this.disableScriptInjection = options.disableScriptInjection || false;
this.extraHTTPHeaders = options.extraHTTPHeaders || {};
this.pages = [];
if (this.debug) {
this.headless = false;
this.closeAfter = false;
}
}
async setup() {
let tmpDir = await mkdtemp(join(tmpdir(), "pagedjs-"));
let puppeteerOptions = {
headless: this.headless,
args: [],
ignoreHTTPSErrors: this.ignoreHTTPSErrors,
userDataDir: tmpDir
};
if (process.platform === "linux") {
cp(path.resolve(path.dirname(currentPath), "../docker-userdata"), tmpDir, { recursive: true });
puppeteerOptions.ignoreDefaultArgs = ["--disable-component-update"];
}
if (this.allowLocal) {
puppeteerOptions.args.push("--allow-file-access-from-files");
}
if (this.browserArgs) {
puppeteerOptions.args.push(...this.browserArgs);
}
if (this.browserWSEndpoint) {
puppeteerOptions.browserWSEndpoint = this.browserWSEndpoint;
this.browser = await puppeteer.connect(puppeteerOptions);
} else {
this.browser = await puppeteer.launch(puppeteerOptions);
}
return this.browser;
}
async render(input) {
let resolver;
let rendered = new Promise(function(resolve, reject) {
resolver = resolve;
});
if (!this.browser) {
await this.setup();
}
try {
const page = await this.browser.newPage();
page.setDefaultTimeout(this.timeout);
page.setExtraHTTPHeaders(this.extraHTTPHeaders);
await page.emulateMediaType(this.emulateMedia);
if (this.overrideDefaultBackgroundColor) {
page._client.send("Emulation.setDefaultBackgroundColorOverride", { color: this.overrideDefaultBackgroundColor });
}
let url, relativePath, html;
if (typeof input === "string") {
try {
new URL(input);
url = input;
} catch (error) {
relativePath = path.resolve(dir, input);
if (this.browserWSEndpoint) {
html = fs.readFileSync(relativePath, "utf-8");
} else {
url = "file://" + relativePath;
}
}
} else {
url = input.url;
html = input.html;
}
if (this.needsAllowedRules()) {
await page.setRequestInterception(true);
page.on("request", (request) => {
let uri = new URL(request.url());
let { host, protocol, pathname } = uri;
let local = protocol === "file:";
if (local && this.withinAllowedPath(pathname) === false) {
request.abort();
return;
}
if (local && !this.allowLocal) {
request.abort();
return;
}
if (host && this.isAllowedDomain(host) === false) {
request.abort();
return;
}
if (host && !this.allowRemote) {
request.abort();
return;
}
request.continue();
});
}
if (this.disableScriptInjection) {
await page.evaluateOnNewDocument(() => {
window.PagedConfig = { auto: false };
});
}
if (html) {
await page.setContent(html);
if (url) {
await page.evaluate((url) => {
let base = document.querySelector("base");
if (!base) {
base = document.createElement("base");
document.querySelector("head").appendChild(base);
}
base.setAttribute("href", url);
}, url);
}
} else {
await page.goto(url);
}
this.content = await page.content();
if (!this.disableScriptInjection) {
await page.evaluate(() => {
window.PagedConfig = window.PagedConfig || {};
window.PagedConfig.auto = false;
});
await page.addScriptTag({
path: scriptPath
});
}
for (const style of this.styles) {
await page.addStyleTag({
[this.isUrl(style) ? "url" : "path"]: style
});
}
for (const script of this.additionalScripts) {
await page.addScriptTag({
[this.isUrl(script) ? "url" : "path"]: script
});
}
await page.exposeFunction("onSize", (size) => {
this.emit("size", size);
});
await page.exposeFunction("onPage", (page) => {
this.pages.push(page);
this.emit("page", page);
});
await page.exposeFunction("onRendered", (msg, width, height, orientation) => {
this.emit("rendered", msg, width, height, orientation);
resolver({msg, width, height, orientation});
});
await page.evaluate(async () => {
let done;
window.PagedPolyfill.on("page", (page) => {
const { id, width, height, startToken, endToken, breakAfter, breakBefore, position } = page;
const mediabox = page.element.getBoundingClientRect();
const cropbox = page.pagebox.getBoundingClientRect();
function getPointsValue(value) {
return (Math.round(CSS.px(value).to("pt").value * 100) / 100);
}
let boxes = {
media: {
width: getPointsValue(mediabox.width),
height: getPointsValue(mediabox.height),
x: 0,
y: 0
},
crop: {
width: getPointsValue(cropbox.width),
height: getPointsValue(cropbox.height),
x: getPointsValue(cropbox.x) - getPointsValue(mediabox.x),
y: getPointsValue(cropbox.y) - getPointsValue(mediabox.y)
}
};
window.onPage({ id, width, height, startToken, endToken, breakAfter, breakBefore, position, boxes });
});
window.PagedPolyfill.on("size", (size) => {
window.onSize(size);
});
window.PagedPolyfill.on("rendered", (flow) => {
let msg = "Rendering " + flow.total + " pages took " + flow.performance + " milliseconds.";
window.onRendered(msg, flow.width, flow.height, flow.orientation);
});
if (window.PagedConfig.before) {
await window.PagedConfig.before();
}
done = await window.PagedPolyfill.preview();
if (window.PagedConfig.after) {
await window.PagedConfig.after(done);
}
}).catch((error) => {
throw error;
});
await page.waitForNetworkIdle({
timeout: this.timeout
});
await rendered;
await page.waitForSelector(".pagedjs_pages");
return page;
} catch (error) {
this.closeAfter && this.close();
throw error;
}
}
async pdf(input, options={}) {
let page = await this.render(input)
.catch((e) => {
throw e;
});
try {
// Get metatags
const meta = await page.evaluate(() => {
let meta = {};
let title = document.querySelector("title");
if (title) {
meta.title = title.textContent.trim();
}
let lang = document.querySelector("html").getAttribute("lang");
if (lang) {
meta.lang = lang;
}
let metaTags = document.querySelectorAll("meta");
[...metaTags].forEach((tag) => {
if (tag.name) {
meta[tag.name] = tag.content;
}
});
return meta;
});
const outline = await parseOutline(page, options.outlineTags);
let settings = {
timeout: this.timeout,
printBackground: true,
displayHeaderFooter: false,
preferCSSPageSize: options.width ? false : true,
width: options.width,
height: options.height,
orientation: options.orientation,
margin: {
top: 0,
right: 0,
bottom: 0,
left: 0,
}
};
let pdf = await page.pdf(settings)
.catch((e) => {
throw e;
});
this.closeAfter && page.close();
this.emit("postprocessing");
let pdfDoc = await PDFDocument.load(pdf);
setMetadata(pdfDoc, meta);
setTrimBoxes(pdfDoc, this.pages);
setOutline(pdfDoc, outline, this.enableWarnings);
pdf = await pdfDoc.save();
return pdf;
} catch (error) {
this.closeAfter && this.close();
throw error;
}
}
async html(input, stayopen) {
let page = await this.render(input);
let content = await page.content();
if (this.closeAfter) {
page.close();
this.close();
}
return content;
}
async preview(input) {
let page = await this.render(input);
this.closeAfter && this.close();
return page;
}
async close() {
return this.browser && this.browser.close();
}
needsAllowedRules() {
if (this.allowedPaths && this.allowedPaths.length !== 0) {
return true;
}
if (this.allowedDomains && this.allowedDomains.length !== 0) {
return true;
}
}
withinAllowedPath(pathname) {
if (!this.allowedPaths || this.allowedPaths.length === 0) {
return true;
}
for (let parent of this.allowedPaths) {
const relative = path.relative(parent, pathname);
if (relative && !relative.startsWith("..") && !path.isAbsolute(relative)) {
return true;
}
}
return false;
}
isAllowedDomain(domain) {
if (!this.allowedDomains || this.allowedDomains.length === 0) {
return true;
}
return this.allowedDomains.includes(domain);
}
isUrl(resource) {
try {
new URL(resource);
return true;
} catch {
return false;
}
}
}
export default Printer;
......@@ -10,16 +10,9 @@ html{
}
@page {
size: 148mm 210mm portait
size: A5;
}
@media screen {
.baseline .pagedjs_page {
background-image: repeating-linear-gradient(180deg, transparent 0, transparent 14px , rgba(0,255,0,0.7) var(--baseline)) ;
background-size: cover;
background-position: 0 -3px , 0 0
}
}
@page cover {
margin: 0;
......
......@@ -4,8 +4,10 @@
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<title>
The Project Gutenberg eBook of Auroræ: Their Characters and Spectra, by J. Rand Capron.
Auroræ: Their Characters and Spectra.
</title>
<meta name="author" content="J. Rand Capron"/>
<meta name="subject" content="Project Gutenberg eBook"/>
 
<link rel="coverpage" href="images/cover.jpg" />
 
......@@ -24,7 +26,7 @@
<!-- Prince XML-->
<!-- <link href="prince/layout-prince.css" rel="stylesheet"/> -->
 
<!-- <script src="http://localhost:9090/dist/paged.polyfill.js"></script> -->
 
<!-- Typos -->
<link rel="stylesheet" href="fonts/spectral/stylesheet.css" />
......