npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

docs-companion-kit

v0.1.17

Published

Zero-runtime-dependency PDF and image workflows for Node.js and browsers, authored in TypeScript.

Downloads

2,361

Readme

docs-companion-kit

Zero-dependency TypeScript library for PDF and image processing across Node.js and browsers.

Ships PDF authoring, parsing and rendering, multi-format image codecs (PNG/JPEG/GIF/TIFF/WebP), CLI tools, batch processing, and layout helpers.

Runs in Node.js >= 18 and modern browsers. No native bindings, no WASM, no runtime dependencies.


Platform and Build

  • Source: src/**/*.ts (TypeScript ES2022, strict)
  • Output: dist/ (ESM + .d.ts)
  • Zero runtime dependencies
  • Conditional exports: ".", "./browser", "./node"
  • Primary binary type: Uint8Array

Features

PDF Creation

  • Documents and pages: new PDFDocument(), addPage(), deletePage(), reorderPages()
  • Text and shapes: drawText(), drawLine(), drawRect(), drawPath()
  • Image embedding: drawImage() for PNG/JPEG/GIF/TIFF inputs
  • Links and forms: drawLink(), drawTextField(), drawCheckbox()
  • Embedded fonts (TrueType / OpenType):
    • doc.embedFont(fontBytes: Uint8Array): EmbeddedFont — parse + register a TTF or OTF font (whole-font embedding, no subsetting); returns an EmbeddedFont handle
    • page.drawEmbeddedText(text, { font, x, y, size?, color? }) — draw text using an embedded font; the font is automatically added to the page's /Font resource dict
    • font.measureText(text, size): number — measure advance width in points
    • font.width1000(charCode): number — advance width in 1/1000 em units (matches /Widths array)
    • doc.getEmbeddedFonts(): EmbeddedFont[] — list all embedded fonts in the document
    • Encoding: WinAnsiEncoding (char codes 32–255); /FontFile2 for TTF, /FontFile3 for CFF/OTF
    • parseTtfMetrics(bytes): TtfMetrics — low-level font parser (head, hhea, hmtx, cmap, OS/2, name, post)
  • AcroForm extensions:
    • page.drawDropdown({ name, x, y, width, height, options, value?, fontSize? }) — combobox field with /Ff 131072
    • page.drawListBox({ name, x, y, width, height, options, value?, fontSize?, multiSelect? }) — list box; multiSelect adds /Ff 2097152
    • page.drawRadioGroup({ name, options: [{exportValue, rect}], value? }) — radio button group; serialised as one /Btn parent field + one /Widget annotation per option
  • Document review annotations (ISO 32000-1 §12.5):
    • page.drawHighlight(x, y, w, h, opts?) — yellow highlight overlay with /QuadPoints and /CA opacity; opts: color [0–1], opacity
    • page.drawUnderline(x, y, w, h, opts?) — underline; opts: color, opacity
    • page.drawSquiggly(x, y, w, h, opts?) — squiggly underline (default red); opts: color, opacity
    • page.drawStrikeOut(x, y, w, h, opts?) — strikethrough (default red); opts: color, opacity
    • page.drawFreeText(text, x, y, width, height, opts?) — floating text box with /DA appearance string; opts: font, fontSize, textColor, bgColor, borderColor (all colors 0–1)
    • page.drawStamp(name, x, y, width, height, opts?) — rubber stamp with 15 predefined names: Approved, Draft, Confidential, Experimental, NotApproved, AsIs, Expired, NotForPublicRelease, Final, Sold, Departmental, ForComment, TopSecret, ForPublicRelease, Void; opts: color, opacity
  • Internal navigation links:
    • page.drawGoToLink(pageIndex, x, y, w, h, targetY?) — clickable in-document page jump
    • page.drawNamedLink(destName, x, y, w, h) — jump to a named destination
    • doc.addNamedDestination({ name, pageIndex, y? }) — register /Names /Dests in the catalog
  • Bookmarks (document outline):
    • doc.addBookmark({ title, pageIndex, y?, children?, bold?, italic?, color?, collapsed? })
    • doc.setBookmarks(list) / doc.getBookmarks() / doc.clearBookmarks()
    • Nested hierarchies with /First, /Last, /Next, /Prev linkage
    • Collapsed parent bookmarks encoded with negative /Count
  • Page labels:
    • doc.setPageLabels(ranges) — styles D (Arabic), r/R (Roman), a/A (alpha), with optional prefix and startValue
    • buildPageLabelsEntry(ranges) — utility to preview the /PageLabels literal
  • Layout APIs:
    • page.drawWrappedText()
    • page.drawTable()
    • drawParagraph(page, text, options)
    • drawTextColumns(page, text, options)
  • Color authoring:
    • RGB via color
    • Grayscale via gray (PDF g/G)
    • CMYK via cmyk (PDF k/K)
    • ICC output intent embedding via doc.setOutputIntentICC(...)
    • Supported across drawText, drawWrappedText, drawRect/drawPath/drawLine, and drawTable
  • Metadata: doc.metadata = { title, author, subject, keywords, creator, producer }
  • Deterministic output: doc.save({ deterministic: true })
  • Watermarks:
    • drawTextWatermark(page, text, { opacity?, angle?, font?, size?, color?, x?, y? }) — semi-transparent rotated text overlay using PDF ExtGState
    • applyWatermark(doc, text, opts) — apply the same watermark to every page in the document
    • drawImageWatermark(page, image, { opacity?, angle?, width?, height?, x?, y? }) — RGBA image overlay; width/height preserve aspect ratio if only one is given
    • applyImageWatermark(doc, image, opts) — apply image watermark to every page
    • Default: 18% opacity, 45° angle, 72pt Helvetica-Bold, medium gray; viewers render the transparency natively
  • Page rotation:
    • page.setRotation(0 | 90 | 180 | 270) — sets /Rotate in the page dict
    • page.rotation getter; preserved on clone(); 0° never written to PDF (viewer default)
  • Viewer preferences:
    • doc.setViewerPreferences(prefs) — serializes /ViewerPreferences, /PageMode, /PageLayout in the catalog
    • prefs.PageMode'UseNone' | 'UseOutlines' | 'UseThumbs' | 'FullScreen' | 'UseOC' | 'UseAttachments'
    • prefs.PageLayout'SinglePage' | 'OneColumn' | 'TwoColumnLeft' | 'TwoColumnRight' | 'TwoPageLeft' | 'TwoPageRight'
    • Inner prefs: HideToolbar, HideMenubar, HideWindowUI, FitWindow, CenterWindow, DisplayDocTitle, Duplex, PrintScaling, NumCopies, Direction, NonFullScreenPageMode

PDF Parsing and Analysis

  • parsePDF(bytes, { strict? })
  • Streaming parse: parsePDFStream(), parsePDFAsyncStream()
  • Text extraction: extractPdfText(parsed)
  • Text search: searchPdfText(parsed, query, { caseSensitive?, maxMatches?, pageIndices? }) → { totalMatches, matches: [{ pageIndex, matchText, x, y, font, size }] }
  • Image extraction: extractPdfImages(parsed)
  • Diagnostics: parsed.diagnostics[]

PDF Rendering

  • renderPageToPng(parsed, index, { scale })
  • renderPdfToPngs(parsed, { scale })
  • renderPageToRGBA(parsed, index, opts)
  • convertPdfToImages(input, { format?, pageNumbers?, scale?, width?, height?, base64?, quality?, concurrency?, strict?, maxInputBytes?, maxPagePixels? })
  • Custom operator hooks via render options
  • Corpus compatibility matrix demo for local PDF fixtures

Corpus Compatibility API

  • analyzePdfCorpus(entries, { renderScale? }) for parse/render matrix reporting

Image Processing

  • Codecs:
    • readPng(), writePng()
    • readJpeg(), writeJpeg()
    • readGif(), writeGif()
    • readTiff(), readTiffPages(), writeTiff(), writeTiffMultiPage()
    • writeWebp() (lossless encoder)
  • Transform and color: resize/crop/rotate/flip/grayscale/brightness/contrast
  • Blend and alpha: blendImages(), applyAlphaMask(), composite()
  • Analysis: imageHistogram(), adjustLevels()
  • Convolution: blur(), sharpen(), edgeDetect(), emboss(), convolve()
  • Format conversion: detectImageFormat(), convertImage(), convertImageDirect()

PDF and TIFF Interchange

  • renderPdfToTiff(parsed, options)
  • embedTiffInPdf(doc, tiffBytes, options)
  • createPdfFromTiff(tiffBytes, options)

Node Utilities

  • readFile(), writeFile()
  • batchConvert(files, outputDir, options)
  • batchExtractPdfImages(pdfFile, outputDir, options)
  • convertPdfToImages(input, options) from docs-companion-kit/node (data URI/path/Buffer/Uint8Array, plus opt-in URL support via allowRemote)

CLI

  • doc-kit convert -o [--format png|jpeg|gif|tiff|webp] [--quality 1-100] [--compression none|lzw|deflate|packbits] [--scale n] [--pages 1,3-5]
  • doc-kit extract <input.pdf> -o [--format jpeg|png|tiff] [--quality 1-100]
  • doc-kit batch-convert -o [--format ...] [--pattern ...]

Installation

npm install docs-companion-kit

CLI usage:

npx doc-kit --help

Quick Start

Create a PDF

import { PDFDocument } from 'docs-companion-kit';

const doc = new PDFDocument();
const page = doc.addPage({ width: 420, height: 300 });
page.drawText('Hello PDF', { x: 40, y: 240, size: 18 });
const bytes = doc.save({ deterministic: true });

Paragraph and Column Layout

import { PDFDocument, drawParagraph, drawTextColumns } from 'docs-companion-kit';

const doc = new PDFDocument();
const page = doc.addPage({ width: 500, height: 700 });

const y = drawParagraph(page, 'Paragraph one...\n\nParagraph two...', {
  x: 40,
  y: 660,
  width: 420,
  firstLineIndent: 14,
  paragraphSpacing: 8,
  lineHeight: 14
});

const cols = drawTextColumns(page, 'Long body text ...', {
  x: 40,
  y: y - 10,
  width: 420,
  height: 120,
  columns: 2,
  gutter: 18
});

console.log(cols.overflowText.length);

Convert Image Format

import { convertImage } from 'docs-companion-kit';

const output = convertImage(inputBytes, { format: 'png' });

Convert PDF to TIFF

import { parsePDF, renderPdfToTiff } from 'docs-companion-kit';

const parsed = parsePDF(pdfBytes);
const tiff = renderPdfToTiff(parsed, { scale: 2, compression: 'lzw' });

Convert PDF to Images (Multi-Format)

import { convertPdfToImages } from 'docs-companion-kit';

const pages = await convertPdfToImages(pdfBytes, {
  format: 'webp',       // png | jpeg | gif | tiff | webp
  pageNumbers: [1, 3],  // 1-based
  width: 1600,
  concurrency: 4
});

Node URL Input (Security Opt-In)

import { convertPdfToImages } from 'docs-companion-kit/node';

const pages = await convertPdfToImages('https://example.com/file.pdf', {
  format: 'png',
  allowRemote: true,
  // Off by default. Needed for localhost/private-network targets.
  allowPrivateNetwork: false,
  requestTimeoutMs: 10_000,
  maxRemoteBytes: 50 * 1024 * 1024
});

High-Fidelity Native PDF Rendering (Node)

For shipping labels, barcodes, and PDFs with embedded/special fonts, use the Node native renderer. It delegates the actual page painting to a system PDF renderer, so the output matches what a PDF viewer renders much more closely than the dependency-free fallback.

import { convertPdfToImages } from 'docs-companion-kit/node';

const pages = await convertPdfToImages('./label.pdf', {
  renderEngine: 'native',
  // "auto" prefers Poppler's pdftoppm and falls back to macOS Quick Look
  // for single-page PDFs when Poppler is not installed.
  nativeRenderer: 'auto',
  format: 'png',
  scale: 4
});

Poppler (pdftoppm) is recommended for multi-page/high-volume conversion. On macOS without Poppler, Quick Look supports single-page PDFs.

Author Grayscale and CMYK PDF Content

import { PDFDocument } from 'docs-companion-kit';

const doc = new PDFDocument();
const page = doc.addPage({ width: 320, height: 220 });

page.drawRect({ x: 20, y: 140, width: 60, height: 40, fill: true, cmyk: [0, 1, 1, 0] });
page.drawRect({ x: 100, y: 140, width: 60, height: 40, fill: true, gray: 0.5 });
page.drawText('CMYK + Gray', { x: 20, y: 110, cmyk: [1, 0, 0, 0], size: 12 });

const bytes = doc.save({ deterministic: true });

Attach an ICC Output Intent Profile

import { PDFDocument } from 'docs-companion-kit';

const doc = new PDFDocument();
doc.setOutputIntentICC({
  profile: new Uint8Array([73, 67, 67, 80, 82, 79, 70, 73, 76, 69]),
  components: 3,
  outputConditionIdentifier: 'sRGB IEC61966-2.1',
  info: 'Demo RGB Profile'
});

const page = doc.addPage({ width: 200, height: 200 });
page.drawText('ICC output intent attached', { x: 20, y: 140, size: 12 });

const bytes = doc.save({ deterministic: true });

Analyze a PDF Corpus Matrix

import { analyzePdfCorpus } from 'docs-companion-kit';

const report = analyzePdfCorpus([
  { name: 'sample-1.pdf', bytes: pdf1 },
  { name: 'sample-2.pdf', bytes: pdf2 }
], { renderScale: 1 });

console.log(report.summary.passed, report.summary.total);

Scripts

npm run build   # compile TypeScript → dist/
npm test        # run test suite (requires a prior build)
npm run typecheck

License

MIT