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

@zouchengxin/pdf-engine

v1.0.7

Published

A library that supports parsing and editing PDF files

Readme

Features

  • Zero dependencies - The wasm file used is embedded in the package.
  • Type-safe - TypeScript definitions are included.
  • Works in browser and Node.js
  • Powerful features - supports parsing and editing

Installation

# yarn add @zouchengxin/pdfium-engine
# pnpm install @zouchengxin/pdfium-engine
npm install @zouchengxin/pdfium-engine

Demo

pdf-engine-demo

Usage

Initialization

import { PdfEngine } from '@zouchengxin/pdfium-engine';

const pdfEngine = new PdfEngine();
// API_KEY not provided, validity period until 2026-01-01, You can adjust the system time for testing.
// Or contact the developer to obtain the API key.
await pdfEngine.init(API_KEY);

Parse

// Select PDF file and return uint8Array data
const selectPdfFile = async () => {
  const [fileHandle] = await window.showOpenFilePicker({
    types: [
      {
        description: 'Pdf Files',
        accept: {
          'application/pdf': ['.pdf'],
        },
      },
    ],
    excludeAcceptAllOption: true,
    multiple: false,
  });
  const file = await fileHandle.getFile();
  const buf = await file.arrayBuffer();
  const bytes = new Uint8Array(buf);
  return bytes;
}
const data = await selectPdfFile();
// Load PDF documents, parameter Uint8Array
const pdfDoc = pdfEngine.loadPdf(data);
// Get the number of pages
const count = pdfDoc.getPageCount();
// Retrieves PDF metadata.
// returning the fields Title, Author, Subject, Keywords, Creator, Producer, CreationDate, and ModDate.
const meta = pdfDoc.getMetaData();
console.log('Page Count:', count);
console.log('Pdf Meta:', meta);
for (let i = 0; i < count; i++) {
  // Obtain the page proxy object and perform operations such as parsing and editing.
  const page = pdfDoc.getPageProxy(i);
  // Get page width
  const width = page.getPageWidth();
  // Get page height
  const height = page.getPageHeight();
  // Retrieves all xobject objects on the page.
  // including those of type TEXT, PATH, IMAGE, SHADING, and FORM.
  const objs = page.getObjects();
  // Retrieves all annotation objects on the page.
  // including those of type TEXT, LINK, FREETEXT, LINE, SQUARE, CIRCLE, HIGHLIGHT, UNDERLINE, STAMP, INK etc.
  const annots = page.getAnnotions();
  console.log('Page Size:', width, height);
  console.log('Page Objects:', objs);
  console.log('Page Annotions:', annots);
}

Rendering

// Retrieve the bitmap after page rendering; render only the xobject object, excluding annotations.
// Return value: ImageData object
const data = page.getBitmap();
// Retrieve page thumbnail; return empty if not stored.
// Return value: ImageData object
const data = page.getThumbnail();

Create

Annotations
// Select Image file and return uint8Array data
const selectImageFile = async () => {
  const [fileHandle] = await window.showOpenFilePicker({
    types: [
      {
        description: 'Image Files',
        accept: {
          'image/*': ['.png','.jpeg','.jpg','.webp'],
        },
      },
    ],
    excludeAcceptAllOption: true,
    multiple: false,
  });
  const file = await fileHandle.getFile();
  return file;
}
// get ImageData data
const getImageDataFromFile = async (file) =>{
  const {promise,resolve} = Promise.withResolvers();
  const img = new Image();
  const url = URL.createObjectURL(file);
  img.onload = () => {
    const canvas = document.createElement('canvas');
    canvas.width = img.width;
    canvas.height = img.height;
    const ctx = canvas.getContext('2d');
    if (!ctx) return null;
    ctx.drawImage(img, 0, 0);
    const data = ctx.getImageData(0, 0, img.width, img.height);
    resolve(data);
    URL.revokeObjectURL(url);
  };
  img.src = url;
  return promise;
}

// Create a link annotation.
// rect: a rectangular area.
// url: the redirect link.
page.createLinkAnno({
  rect: [100, 100, 100, 40],
  url: 'https://www.baidu.com',
});

// Create a FreeText annotation.
page.createFreeTextAnno({
  rect: [100, 200, 100, 40],
  content: 'Free Text Anno',
  color: [255, 0, 0, 255],
  fontSize: 14,
});

// Create a Text annotation.
page.createTextAnno({
  rect: [100, 300, 100, 40],
  content: 'Text Anno',
  color: [255, 0, 0, 255],
  fontSize: 14,
});

// Create a Square annotation.
page.createSquareAnno({
  rect: [100, 400, 100, 60],
  strokeColor: [255, 0, 0, 255],
  fillColor: [0, 255, 0, 255],
});

// Create a Circle annotation.
page.createCircleAnno({
  rect: [200, 100, 100, 100],
  strokeColor: [255, 0, 0, 255],
  fillColor: [0, 255, 0, 255],
});

// Create a Highlight annotation.
page.createHighlightAnno({
  rect: [200, 200, 100, 60],
  strokeColor: [255, 0, 0, 255],
  fillColor: [0, 255, 0, 255],
});

// Create a Underline annotation.
page.createUnderlineAnno({
  rect: [200, 300, 100, 60],
  strokeColor: [255, 0, 0, 255],
  fillColor: [0, 255, 0, 255],
});

// Create a Stamp annotation.
const file = await selectImageFile();
const data = await getImageDataFromFile(file);
page.createStampAnno({
  rect: [200, 400, 100, 100],
  matrix: { a: 50, b: 0, c: 0, d: 50, e: 200, f: 400 },
  data,
});

// More features are under development.
XObject
  // Select Image file and return uint8Array data
  const selectFontFile = async () => {
    const [fileHandle] = await window.showOpenFilePicker({
      types: [
        {
          description: 'Font Files',
          accept: {
            'font/*': ['.ttf'],
          },
        },
      ],
      excludeAcceptAllOption: true,
      multiple: false,
    });
    const file = await fileHandle.getFile();
    const buf = await file.arrayBuffer();
    const bytes = new Uint8Array(buf);
    return bytes;
  }

  // Add Text XObject(system font)
  // system font: Helvetica, Helvetica-Bold, Helvetica-Oblique, Helvetica-BoldOblique,
  // Times-Roman, Times-Bold, Times-Italic, Times-BoldItalic,
  // Courier, Courier-Bold, Courier-Oblique, Courier-BoldOblique,
  // Symbol, ZapfDingbats ( not supported for now )
  // Note: system fonts only support English
  page.addTextObj({
    x: 300,
    y: 100,
    text: 'hello word!',
    fontFamily: 'Helvetica-Bold',
    strokeColor: [255, 0, 0, 255],
    color: [0, 255, 0, 255],
  });

  // Add external fonts, such as Chinese fonts
  // Note: Currently supports ttf files only
  const data = await selectFontFile()
  pdfDoc.addCustomFont('custom-font', data);

 // Get registered external fonts
  const fonts = pdfDoc.getCustomFonts();
  console.log('custom fonts:', fonts);

  // Add Text XObject(custom font)
  page.addTextObj({
    x: 300,
    y: 200,
    text: '你好世界',
    fontFamily: 'custom-font',
  });

  // Add Image XObject
  const file = await selectImageFile();
  const data = await getImageDataFromFile(file);
  page.addImageOBJ({
    rect: [300, 300, 100, 100],
    matrix: { a: 80, b: 0, c: 0, d: 80, e: 300, f: 300 },
    data,
  });
Save
// Save the PDF data and return a Uint8Array.
const uint8Arr = pdfDoc.savePdf();

Note

  • color: [r, g, b, a], An array of red, green, blue, and blue
  • rect: [x, y, w, h], An array consisting of the x-coordinate of the bottom left corner of the rectangular region, the y-coordinate of the bottom left corner of the rectangular region, the width of the rectangular region, and the height of the rectangular region.
  • Coordinate: The origin is at the bottom left corner of the page, the horizontal direction is the x-axis, and the vertical direction is the y-axis.
  • API_KEY: Contact the developer for details, or change your system time to before January 1, 2026 for testing purposes.

Contact

QQ 群: 877673376

爱发电: https://ifdian.net/a/zouchengxin