jkunz 83642b9084
Default (tags) / security (push) Failing after 3s
Default (tags) / test (push) Failing after 1s
Default (tags) / metadata (push) Skipped
v6.5.1
2026-10-12 20:28:05 +00:00
…
…
…
…

@push.rocks/smartpdf 📄✨

Transform HTML, websites, and PDFs into beautiful documents and images with just a few lines of code.

npm version TypeScript License: MIT

Issue Reporting and Security

For reporting bugs, issues, or security vulnerabilities, please visit community.foss.global/. This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a code.foss.global/ account to submit Pull Requests directly.

🚀 Why SmartPDF?

SmartPDF is your Swiss Army knife for PDF operations in Node.js. Whether you're generating invoices from HTML, snapshotting web pages, merging documents, or converting PDF pages to images — SmartPDF handles it all through a clean, async-first TypeScript API backed by headless Chromium.

✨ Features at a Glance

Feature Description
📝 HTML → PDF Render any HTML string (with full CSS) into an A4-sized PDF
🌐 Website → PDF Capture a live URL as a PDF — one page the size of its document, or the full-page scroll
🔀 PDF Merging Combine multiple PDF buffers into a single document
🖼️ PDF → Images Convert PDF pages to PNG, WebP, or progressive JPEG
🧮 PDF → Pixels Render pages to raw RGB or gray pixels at an exact DPI, one page at a time, without a browser (for raster printers)
📑 Text Extraction Pull raw text content from any PDF buffer
🔍 OCR Add a searchable text layer to scanned PDFs with the system's ocrmypdf
🔌 Smart Port Management Automatic port allocation so multiple instances never collide
🎛️ DPI Control Built-in scale constants for screen, high-quality, and print resolutions
🌐 BYO Browser Optionally pass your own Puppeteer Browser instance

📦 Installation

pnpm add @push.rocks/smartpdf

Prerequisites: SmartPDF requires Node.js 22.13 or newer and uses headless Chromium through SmartBrowser 5's automation entry and Puppeteer 25. On most systems Chromium is handled automatically. If you run into browser-launch issues (CI, Docker, etc.), make sure the required system libraries are installed and review the Puppeteer troubleshooting guide.

Installed with it: PDF → image rendering uses PDF.js from pdfjs-dist (Apache-2.0). pdfjs-dist declares @napi-rs/canvas (MIT; its native binary bundles Google Skia, BSD-3-Clause) as an optional dependency, so a package manager that installs optional dependencies (the default) also fetches that binary for your platform. Rendering does not use it (PDF.js renders in the headless browser); text extraction runs PDF.js in Node.js, which loads it to define DOMMatrix and Path2D when present (see Extract Text).

Optional system tools for OCR: ocrPdfBytes() runs OCRmyPDF (MPL-2.0), which drives Tesseract (Apache-2.0) and Ghostscript (AGPL-3.0 or commercial). They are not npm dependencies: install them with the system package manager (e.g. apt install ocrmypdf tesseract-ocr-eng ghostscript) together with the Tesseract language packs you need. SmartPDF only starts them as separate processes; nothing of them is linked into or shipped with this package. Every other feature works without them.

🎯 Quick Start

import { SmartPdf } from '@push.rocks/smartpdf';
import * as fs from 'fs';

// 1. Create and start
const smartPdf = await SmartPdf.create();
await smartPdf.start();

// 2. Generate a PDF from HTML
const pdf = await smartPdf.getA4PdfResultForHtmlString(`
  <h1>Hello, PDF World! 🌍</h1>
  <p>Generated with SmartPDF.</p>
`);

// 3. Write to disk
fs.writeFileSync('my-first.pdf', pdf.buffer);

// 4. Clean up
await smartPdf.stop();

Every method returns an IPdf object:

interface IPdf {
  id: string | null;        // Unique identifier
  name: string;             // Filename
  buffer: Buffer;           // Raw PDF bytes
  metadata?: {
    textExtraction?: string; // Extracted text (when available)
  };
}

📚 How It Works

SmartPDF spins up a lightweight HTTP server (via @push.rocks/smartserve) bound to localhost and a headless Chromium browser. When you call a generation method:

  1. Your HTML is registered internally and served at http://localhost:{port}/{id}
  2. Puppeteer navigates to that URL, waits for the page to fully render, and captures a PDF
  3. A header-based security check ensures only the correct content is captured
  4. The server and browser are torn down when you call stop()

This architecture means you get pixel-perfect CSS rendering, web font support, and full JavaScript execution — the same rendering engine that powers Chrome.

🏗️ Instance Management

const smartPdf = await SmartPdf.create();
await smartPdf.start();

// ... your operations ...

await smartPdf.stop();

For production use, wrap in try/finally:

const smartPdf = await SmartPdf.create();
try {
  await smartPdf.start();
  // ... generate PDFs ...
} finally {
  await smartPdf.stop();
}

SmartPDF leaves SIGINT, SIGTERM and SIGHUP to your program: the browser it launches keeps running when the process receives one of them, so a shutdown handler can finish the PDFs in flight and then call stop(). A program without such a handler ends as Node.js does on these signals, and the browser ends with it.

🔌 Smart Port Allocation

Run multiple instances without conflicts:

// Each instance auto-selects a free port (default range: 20000–30000)
const instance1 = new SmartPdf();
const instance2 = new SmartPdf();
await instance1.start(); // e.g. port 20000
await instance2.start(); // e.g. port 20001

console.log(instance1.serverPort); // 20000
console.log(instance2.serverPort); // 20001

// Custom range
const custom = new SmartPdf({ portRangeStart: 4000, portRangeEnd: 5000 });

// Or pin a specific port
const pinned = new SmartPdf({ port: 3000 });

start() takes a port by listening on it and moves on to the next port of the range when it is in use, so instances that start at the same time, in one process or in several, each get a port of their own. If a specific port is already in use, start() throws an error immediately instead of silently failing.

🌐 Bring Your Own Browser

Pass an existing Puppeteer Browser instance — SmartPDF won't close it when you call stop().

The browser must reach http://localhost:<serverPort> of the process running SmartPDF: HTML → PDF loads your HTML from there, and PDF → image loads the render page, PDF.js and its assets from there too. A browser that runs elsewhere (another host, or a container with its own network) cannot render.

pnpm add @push.rocks/smartpdf @push.rocks/smartbrowser
import { SmartPdf } from '@push.rocks/smartpdf';
import { getEnvAwareBrowserInstance } from '@push.rocks/smartbrowser/automation';

const browser = await getEnvAwareBrowserInstance();

const smartPdf = await SmartPdf.create();
await smartPdf.start(browser); // uses your browser

await smartPdf.stop();      // server stops, browser stays open
await browser.close();       // you manage browser lifecycle

🎨 PDF Generation

📝 HTML → A4 PDF

Renders at a 794×1122 viewport (A4 at 96 DPI) with full CSS support:

const pdf = await smartPdf.getA4PdfResultForHtmlString(`
  <style>
    body { font-family: 'Helvetica', sans-serif; margin: 40px; }
    .header {
      background: linear-gradient(135deg, #667eea, #764ba2);
      color: white; padding: 30px; border-radius: 10px; text-align: center;
    }
    table { width: 100%; border-collapse: collapse; margin-top: 20px; }
    th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
    th { background: #f5f5f5; }
  </style>

  <div class="header">
    <h1>Invoice #2024-001</h1>
  </div>

  <table>
    <tr><th>Item</th><th>Qty</th><th>Price</th></tr>
    <tr><td>Widget Pro</td><td>5</td><td>$49.99</td></tr>
    <tr><td>Gizmo Ultra</td><td>2</td><td>$129.99</td></tr>
  </table>
`);

fs.writeFileSync('invoice.pdf', pdf.buffer);

⏱️ HTML its scripts render: readySelector

By default the page is printed once its network has been idle for half a second (networkidle2). That is no sign that the page's scripts have finished, and for a page that renders itself (a web component that lays out a document) it is often later than needed or earlier than right. Let the page say when it is ready instead: its scripts make a selector match, and the page is printed as soon as it has loaded and the selector matches:

const pdf = await smartPdf.getA4PdfResultForHtmlString(
  `<my-invoice data="..."></my-invoice><script type="module">/* sets the attribute "rendered" when done */</script>`,
  { readySelector: 'my-invoice[rendered]' },
);
  • The page's own network does not hold the print back: a request that stays open after the page is ready does not delay it.
  • A page that does not match the selector within readyTimeoutMs (default 30,000) fails the render with an error that names the selector and the errors the page threw.
  • Not with network: 'blocked', which runs no JavaScript: the combination is refused.

🔒 HTML with text nobody vouches for: network: 'blocked'

By default the page loads what it references, as a browser would. When the HTML carries text a person or a program wrote (a note, a comment, an address), render it with its network blocked, so an image or a stylesheet in that text cannot make the server fetch an address:

const pdf = await smartPdf.getA4PdfResultForHtmlString(reportHtml, { network: 'blocked' });
  • Every request but a data: URI is refused before it leaves the browser: images, stylesheets, fonts, frames and prefetches, and the page is offline. Embed the images, stylesheets and fonts the PDF needs as data: URIs; a remote reference is not loaded.
  • The page renders in a browser context of its own whose connections go to a proxy of the render's own that closes them. Chrome opens a connection ahead of every frame navigation (<iframe>, <object>, <embed>) before request interception, network emulation or a content security policy apply; through that proxy none of them reaches a host the HTML names.
  • The document is sandboxed (Content-Security-Policy: sandbox) and runs no JavaScript: no <meta http-equiv="refresh"> replaces it, no form is submitted, and no script opens a channel requests do not cover (a WebSocket, a WebRTC connection). Frames stay empty instead of showing the browser's error page.

🌐 Website → PDF

Two methods depending on your needs:

// Standard capture — uses the document's own dimensions
const pdf = await smartPdf.getPdfResultForWebsite('https://example.com');

// Full-page capture — scrolls to bottom, captures everything as a single page
const fullPdf = await smartPdf.getFullWebsiteAsSinglePdf('https://example.com');

getPdfResultForWebsite uses a 1980×1200 viewport and prints one page the size of the document (the larger of the root's and the body's scroll width and height). getFullWebsiteAsSinglePdf uses a 1920px-wide viewport, grows it to the document's scroll height and prints a single tall page.

Both print the page a website settles on. They wait for it to load (networkidle2) and then for one more second; a navigation of its own in that time — a script's redirect once the page has loaded — is followed to the page it leads to, up to five times. A navigation that leads to no document (no content, a download, a failed request) leaves the page as it is. A navigation that starts later still, while the page is measured, is followed once as well. An HTTP redirect or a navigation while the page loads lands where it leads, as before.

🔀 Merge Multiple PDFs

Combine any number of PDF buffers into one document using pdf-lib:

const invoice = await smartPdf.readFileToPdfObject('./invoice.pdf');
const terms = await smartPdf.readFileToPdfObject('./terms.pdf');
const appendix = await smartPdf.getA4PdfResultForHtmlString('<h1>Appendix</h1>...');

const merged = await smartPdf.mergePdfs([
  invoice.buffer,
  terms.buffer,
  appendix.buffer,
]);

fs.writeFileSync('complete-package.pdf', merged);

📑 Read a PDF from Disk

const pdfObject = await smartPdf.readFileToPdfObject('./document.pdf');
console.log(pdfObject.name);   // "document.pdf"
console.log(pdfObject.buffer); // <Buffer ...>

📖 Extract Text

Pull the text of every page from a PDF buffer. No browser is needed, so start() is not required:

const text = await smartPdf.extractTextFromPdfBuffer(pdf.buffer, {
  maxPages: 50, // refuse longer documents before any text is read
  signal: AbortSignal.timeout(30_000), // stop the work
});
console.log(text);
  • Format: the text items of each page in the order PDF.js reports them (the order of the page's content stream), a line break (\n) where PDF.js ends a line, and a blank line (\n\n, exported as PDF_TEXT_PAGE_SEPARATOR) between pages. Works best with text-based PDFs; scanned documents have no text to read.
  • Safety: the text is read with the bundled PDF.js 6 (pdfjs-dist), running in Node.js. It has no eval sink reachable from document data (its Node.js build keeps one constant Function('return this')() fallback that finds the global object, and compiles nothing from a PDF), so a malicious font cannot run code while its text is read (CVE-2024-4367); only the text layer is read, no page is rendered.
  • Limits: maxPages refuses a document with more pages with a SmartPdfPageLimitError before any text is read; an aborted signal rejects with the signal's reason.
  • Errors: if the buffer cannot be read as a PDF, the promise rejects with an Error whose cause is the PDF.js error.
  • Process: the first extraction loads PDF.js. In Node.js, PDF.js defines globalThis.DOMMatrix and globalThis.Path2D from @napi-rs/canvas when they are missing; without that optional package it prints a warning for each and text extraction still works.

🔍 OCR Scanned PDFs

Add a searchable text layer to a scanned PDF. No browser is needed, so start() is not required, but ocrmypdf, tesseract and Ghostscript must be installed (see Installation):

const searchablePdf = await smartPdf.ocrPdfBytes(scannedPdfBytes, {
  languages: ['eng', 'deu'], // tesseract language packs (default: ocrmypdf's default, eng)
  rotatePages: true, // rotate pages to the detected text orientation (default: true)
  signal: AbortSignal.timeout(120_000), // stop the run
});
const text = await smartPdf.extractTextFromPdfBuffer(searchablePdf);
  • Process: the PDF is piped to ocrmypdf - - and the result read from its stdout. No shell is involved and SmartPDF writes no files; ocrmypdf keeps its working files in the system temp directory (TMPDIR) and removes them. On POSIX, ocrmypdf and the tesseract and Ghostscript processes it starts run in their own, detached process group: a terminal Ctrl+C or the death of your process does not reach them. Stop a run through signal; after your process has died, ocrmypdf ends once it tries to write its output to the closed pipe (EPIPE). On Windows, which has no process groups, ocrmypdf runs as a plain child process. The output is ocrmypdf's default, a PDF/A-2b.
  • Abort: on POSIX an aborted signal interrupts the whole process group (SIGINT, so ocrmypdf removes its working files; SIGKILL if it has not exited after 5 seconds) and rejects with the signal's reason once the group has exited. On Windows only the ocrmypdf process is signalled: Node.js terminates it at once (Windows has no SIGINT for it, so it cannot remove its working files), and the tesseract worker processes it started may continue until their current page completes. If a signal cannot be delivered (e.g. EPERM), the call rejects with that error once ocrmypdf has exited.
  • Errors: an executable that is missing or not executable (ENOENT, EACCES) rejects with a SmartPdfOcrUnavailableError. A process that cannot be created for another reason, such as exhausted file descriptors (EMFILE) or process limits (EAGAIN), rejects with a SmartPdfOcrError whose exitCode and exitSignal are null and whose cause is the spawn error with its code. A failed run rejects with a SmartPdfOcrError carrying exitCode (ocrmypdf's exit codes, e.g. 6 for a PDF that already has text, 2 for input that is no PDF), exitSignal and stderrTail, the end of ocrmypdf's stderr. Language codes are validated before the run (RangeError).
  • Executable: ocrmypdfPath selects another ocrmypdf executable than the one found in PATH.

🖼️ PDF → Image Conversion

Convert PDF pages to raster images using Puppeteer + PDF.js. Each page becomes a separate image buffer.

Rendering and untrusted PDFs. SmartPDF bundles PDF.js 6 (pdfjs-dist), which has no eval sink: neither the library nor its worker calls eval or new Function, the path CVE-2024-4367 used to run JavaScript from a malicious font. The isEvalSupported: false setting that protected older PDF.js versions is gone from PDF.js 6 together with that path, so there is nothing to switch off. PDF.js and all of its assets (worker, WebAssembly image decoders, CMaps, standard fonts, ICC profiles) are read from pdfjs-dist and served from SmartPDF's own loopback HTTP server, so nothing is fetched from the internet at render time. The render page and every PDF.js asset are served with a Content-Security-Policy without unsafe-eval, so the browser blocks eval and new Function in the page and in the PDF.js worker; wasm-unsafe-eval lets PDF.js compile the WebAssembly that decodes JBIG2 and JPEG 2000 images and PostScript functions.

This protects against script execution from a PDF. It does not bound the work a PDF causes: apart from maxPages and the 30-second limit on the in-browser render, there is no memory or CPU limit, so a hostile document can still make a render slow or memory-hungry.

The image methods need a headless Chromium (via start()). PDF.js 6 runs in that browser for them, and in Node.js for text extraction and for page rasters (rasterizePdfPages); the Node.js floor of >=22.13.0 is the one pdfjs-dist declares.

All image methods accept two guard options in addition to scale, maxWidth and maxHeight:

  • maxPages — refuse a document with more pages than this before any page is rendered (throws SmartPdfPageLimitError).
  • signal — an AbortSignal that stops the rendering.
const pages = await smartPdf.convertPDFToPngBytes(untrustedPdf, {
  maxPages: 50,
  signal: controller.signal,
});

PNG — Lossless Quality

const pngPages = await smartPdf.convertPDFToPngBytes(pdf.buffer, {
  scale: SmartPdf.SCALE_HIGH, // 3.0 = ~216 DPI (default)
});

pngPages.forEach((png, i) => {
  fs.writeFileSync(`page-${i + 1}.png`, Buffer.from(png));
});

WebP — Modern & Efficient

25–60% smaller than PNG at similar visual quality:

const webpPages = await smartPdf.convertPDFToWebpBytes(pdf.buffer, {
  scale: 2.0,     // ~144 DPI
  quality: 90,    // 0–100 (default: 85)
});

JPEG — Progressive Loading

Generates true progressive JPEGs (multi-pass rendering) via sharp:

const jpegPages = await smartPdf.convertPDFToJpegBytes(pdf.buffer, {
  scale: SmartPdf.SCALE_HIGH,
  quality: 85,       // 0–100 (default: 85)
  maxWidth: 1920,    // optional dimension constraints
  maxHeight: 1080,
});

📏 DPI & Scale Reference

All image methods accept a scale parameter. PDF.js renders at 72 DPI by default, so scale is a multiplier:

Constant Value DPI Use Case
SmartPdf.SCALE_SCREEN 2.0 ~144 Web display, thumbnails
SmartPdf.SCALE_HIGH 3.0 ~216 General purpose (default)
SmartPdf.SCALE_PRINT 6.0 ~432 Print-quality output

Or calculate a custom scale:

const scale = SmartPdf.getScaleForDPI(300); // → 4.167

🖼️ Dimension Constraints

All image methods support maxWidth and maxHeight to cap output size while preserving aspect ratio:

// High-res render, but capped at 800×1000 px
const constrained = await smartPdf.convertPDFToWebpBytes(pdf.buffer, {
  scale: SmartPdf.SCALE_HIGH,
  quality: 90,
  maxWidth: 800,
  maxHeight: 1000,
});

🧮 Raw Pixels at an Exact DPI

rasterizePdfPages renders each page to raw pixels at the resolution you ask for: what a printer that takes raster pages (PWG Raster, Apple URF) needs, or anything else that works on a page's pixels. A page of w × h points becomes round(w · dpi / 72) × round(h · dpi / 72) pixels as the page shows (its /Rotate applied), in RGB (three bytes a pixel) or gray (one byte, luma), row by row from the top left without padding. Transparent parts are white.

PDF.js renders the pages in Node.js on @napi-rs/canvas, the optional dependency pdfjs-dist renders with in Node.js, so no browser runs and the instance need not be started. PDF.js 6 has no eval sink reachable from document data (see the note above), glyphs are drawn as paths and fonts are never handed to the canvas; JBIG2 and JPEG 2000 images are decoded by PDF.js's WebAssembly decoders from the bundled pdfjs-dist. Rendering runs in your process: an A4 page at 300 dpi takes about 150–300 ms, during which the event loop waits, and the first call in a process also loads PDF.js (about one to two seconds). Without @napi-rs/canvas (optional dependencies skipped, or a platform it has no build for) the first page fails with PDF.js's canvas error. Pass intent: 'print' for pages that go to a printer: annotations are then drawn as they print (one marked not to be printed is left out, one marked not to be viewed but printed is drawn).

The pages come one at a time as they render, so a loop that handles each page before it asks for the next holds one page's pixels at a time (an A4 page at 300 dpi is 2480 × 3508 pixels, 26 MB in RGB). Leaving the loop early ends the rendering. maxPages refuses a longer document before any page renders, a page whose raster would be larger than 32,767 pixels a side or 268,435,456 in all (MAX_RASTER_SIDE, MAX_RASTER_AREA) is refused, and an aborted signal stops the work with its reason.

for await (const page of smartPdf.rasterizePdfPages(pdf.buffer, { dpi: 300, colorSpace: 'gray' })) {
  // page.pageNumber, page.pageCount, page.width, page.height, page.dpi, page.colorSpace
  // page.pixels: Uint8Array of width × height bytes (gray) or width × height × 3 (rgb)
  await sendToPrinter(page);
}

📊 Format Comparison

Format Typical Size vs PNG Lossy? Transparency Progressive Best For
PNG baseline No ✅ — Screenshots, diagrams, text-heavy docs
WebP 40–75% Yes ✅ — Modern web apps, thumbnails
JPEG 50–70% Yes ❌ ✅ Photos, complex graphics, email

⚡ Parallel Processing

Process multiple URLs concurrently with separate instances:

const urls = [
  'https://example.com/page1',
  'https://example.com/page2',
  'https://example.com/page3',
];

// Spin up parallel instances
const instances = await Promise.all(
  urls.map(() => SmartPdf.create())
);
await Promise.all(instances.map(i => i.start()));

// Generate in parallel
const pdfs = await Promise.all(
  urls.map((url, i) => instances[i].getFullWebsiteAsSinglePdf(url))
);

// Merge all results
const merged = await instances[0].mergePdfs(pdfs.map(p => p.buffer));
fs.writeFileSync('all-pages.pdf', merged);

// Clean up
await Promise.all(instances.map(i => i.stop()));

📝 Full API Reference

SmartPdf Class

Static Properties

Property Type Value Description
SCALE_SCREEN number 2.0 ~144 DPI scale factor
SCALE_HIGH number 3.0 ~216 DPI scale factor (default)
SCALE_PRINT number 6.0 ~432 DPI scale factor

Static Methods

Method Returns Description
create(options?) Promise<SmartPdf> Factory method to create an instance
getScaleForDPI(dpi) number Converts a DPI value to a scale factor (dpi / 72)

Instance Properties

Property Type Description
serverPort number The port the internal HTTP server is listening on

Instance Methods

Method Returns Description
start(browser?) Promise<void> Starts internal server + browser. Optionally accepts an existing Puppeteer Browser.
stop() Promise<void> Shuts down server and browser (unless external browser was provided).
getA4PdfResultForHtmlString(html, options?) Promise<IPdf> Renders HTML at 794×1122 viewport → A4 PDF; { network: 'blocked' } reaches nothing beyond the string; { readySelector, readyTimeoutMs? } prints once the page's scripts make the selector match
getPdfResultForWebsite(url) Promise<IPdf> Captures website at 1980×1200 viewport → PDF
getFullWebsiteAsSinglePdf(url) Promise<IPdf> Captures full scrollable page at 1920px wide → single-page PDF
mergePdfs(buffers) Promise<Uint8Array> Merges an array of PDF Uint8Array buffers
readFileToPdfObject(path) Promise<IPdf> Reads a PDF file from disk into an IPdf object
extractTextFromPdfBuffer(buffer, opts?) Promise<string> Extracts the text of every page (options: maxPages, signal)
ocrPdfBytes(buffer, opts?) Promise<Uint8Array> Adds a text layer to a scanned PDF with ocrmypdf (options: languages, rotatePages, signal, ocrmypdfPath)
convertPDFToPngBytes(buffer, opts?) Promise<Uint8Array[]> Converts each PDF page to a PNG buffer
convertPDFToWebpBytes(buffer, opts?) Promise<Uint8Array[]> Converts each PDF page to a WebP buffer
convertPDFToJpegBytes(buffer, opts?) Promise<Uint8Array[]> Converts each PDF page to a progressive JPEG buffer
rasterizePdfPages(buffer, opts) AsyncGenerator<IPdfPageRaster> Renders each page to raw pixels at an exact DPI, one page at a time, in Node.js without a browser (options: dpi, colorSpace 'rgb'/'gray', intent 'display'/'print', maxPages, signal)

Image Conversion Options

{
  scale?: number;      // DPI multiplier (default: 3.0)
  quality?: number;    // 0–100, WebP/JPEG only (default: 85)
  maxWidth?: number;   // Max output width in pixels
  maxHeight?: number;  // Max output height in pixels
  maxPages?: number;   // Refuse longer documents before rendering (SmartPdfPageLimitError)
  signal?: AbortSignal; // Stops the rendering
}

ISmartPdfOptions Interface

{
  port?: number;           // Use a specific port
  portRangeStart?: number; // Auto-allocation range start (default: 20000)
  portRangeEnd?: number;   // Auto-allocation range end (default: 30000)
}

Migration from @push.rocks/smartocr

@push.rocks/smartocr is deprecated; its OCR now ships with SmartPDF.

@push.rocks/smartocr @push.rocks/smartpdf
const ocr = await SmartOcr.createAndInit() const smartPdf = await SmartPdf.create() (no start() needed for OCR)
await ocr.processPdfBuffer(pdfBuffer) → Buffer await smartPdf.ocrPdfBytes(pdfBytes) → Uint8Array (wrap with Buffer.from() where a Buffer is needed)
always --rotate-pages rotatePages option, default true
— languages, signal and ocrmypdfPath options
ran ocrmypdf through a bash command line with temp files in the package's .nogit folder runs ocrmypdf without a shell over stdin/stdout
init() (and so createAndInit()) rejected with not found: ocrmypdf when it was missing; a failed run surfaced as a file-read error SmartPdfOcrUnavailableError / SmartPdfOcrError with exit code and stderr tail

This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the license file.

Please note: The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.

Trademarks

This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.

Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.

Company Information

Task Venture Capital GmbH Registered at District Court Bremen HRB 35230 HB, Germany

For any legal inquiries or further information, please contact us via email at hello@task.vc.

By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.

S
Description
A library for creating PDFs dynamically from HTML or websites with additional features like merging PDFs.
Readme
7.6 MiB
Languages
TypeScript 100%