Pdf-Engine发布

5,908 阅读3分钟

npm地址: @zouchengxin/pdf-engine - npm
demo地址: pdf-engine

介绍

pdf-engine内部使用pdfium编译的Webassembly二进制文件。
目前已支持功能:

  • 解析XObject和Annotation对象
  • 页面预览
  • 编辑保存(创建Link)

安装

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

使用

初始化

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);

解析

// 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);
}

渲染

// 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();

编辑

// 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.

// Save the PDF data and return a Uint8Array.
const uint8Arr = pdfDoc.savePdf();

注意

  • color: [r, g, b, a], 红绿蓝透明通道组成的数组。
  • rect: [x, y, w, h], 矩形区域左下角x/y坐标,w/h代表宽度高度。
  • 坐标系: 页面左下角为原点,水平方向为x轴。
  • API_KEY: 联系开发者获取,或者修改系统时间至2026/01/01之前进行测试。

联系

QQ 群: 877673376
爱发电: ifdian.net/a/zouchengx…