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

@ycsx/ofdjs

v1.0.6

Published

A Javascript class for reading and rendering ofd files

Downloads

1,097

Readme

@ycsx/ofdjs

一个用于读取和渲染OFD(开放式文档格式)文件的JavaScript库。

License npm version

功能特性

  • 📄 OFD 文档解析 - 完整支持OFD格式文件的解析和加载
  • 🎨 文档渲染 - 支持多种渲染模式(Template、PathContent)
  • 📐 缩放控制 - 灵活的页面缩放功能
  • ✍️ 签名验证 - 支持OFD电子签名的验证
  • 🖼️ JBIG2支持 - 支持JBIG2压缩图像
  • 🔧 丰富的API - 提供灵活的编程接口

安装

使用npm安装:

npm install @ycsx/ofdjs

或使用yarn:

yarn add @ycsx/ofdjs

快速开始

基础使用

import { parseOfdDocument, renderOfd } from '@ycsx/ofdjs';

// 1. 解析OFD文件
parseOfdDocument({
  ofd: 'path/to/file.ofd',  // 文件路径、File对象或ArrayBuffer
  success: (ofdDocument) => {
    console.log('解析成功', ofdDocument);
    
    // 2. 渲染文档到页面
    const screenWidth = window.innerWidth;
    const pages = renderOfd(screenWidth, ofdDocument[0]);
    
    // 3. 添加到DOM
    pages.forEach(pageDiv => {
      document.getElementById('container').appendChild(pageDiv);
    });
  },
  fail: (error) => {
    console.error('解析失败', error);
  }
});

使用缩放功能

import { parseOfdDocument, renderOfdByScale, setPageScale, getPageScale } from '@ycsx/ofdjs';

// 设置缩放比例(1.0 = 100%)
setPageScale(1.2);

parseOfdDocument({
  ofd: file,
  success: (ofdDocument) => {
    // 根据设置的缩放比例渲染
    const pages = renderOfdByScale(ofdDocument[0]);
    document.getElementById('container').appendChild(...pages);
  }
});

// 获取当前缩放比例
console.log('Current scale:', getPageScale());

原生 HTML 中使用

仓库里的 examples/basic.html 就是一个完整的原生浏览器示例。它演示了:

  • 选择本地 OFD 文件
  • 调用 parseOfdDocument() 解析文档
  • 使用 renderPage() 渲染当前页
  • 使用 calPageBox() 计算页面尺寸
  • 手动实现分页与缩放

如果你是直接引用源码入口,推荐这样写:

<script type="module">
  import { parseOfdDocument, renderPage, calPageBox } from '../index.js';

  let currentDocument = null;
  let currentPageIndex = 0;
  let currentScale = 1;

  function getOFDDocument() {
    return currentDocument?.document || currentDocument;
  }

  function getRenderWidth() {
    const container = document.getElementById('ofdContainer');
    return Math.max((container.clientWidth || 1024) * currentScale, 320);
  }

  function renderCurrentPage() {
    const container = document.getElementById('ofdContainer');
    container.innerHTML = '';

    if (!currentDocument?.pages?.length) return;

    const doc = getOFDDocument();
    const page = currentDocument.pages[currentPageIndex];
    const box = calPageBox(getRenderWidth(), doc, page);

    const pageDiv = document.createElement('div');
    pageDiv.style.cssText = `
      position: relative;
      width: ${box.w}px;
      height: ${box.h}px;
      background: white;
    `;

    renderPage(
      pageDiv,
      page,
      currentDocument.tpls,
      currentDocument.fontResObj,
      currentDocument.drawParamResObj,
      currentDocument.multiMediaResObj
    );

    container.appendChild(pageDiv);
  }

  document.getElementById('ofdInput').addEventListener('change', (event) => {
    const file = event.target.files?.[0];
    if (!file) return;

    parseOfdDocument({
      ofd: file,
      success: (ofdDocument) => {
        currentDocument = ofdDocument;
        currentPageIndex = 0;
        currentScale = 1;
        renderCurrentPage();
      },
      fail: (error) => {
        console.error('文件解析失败', error);
      }
    });
  });

  document.getElementById('scaleInput').addEventListener('input', (event) => {
    currentScale = Number(event.target.value) / 100;
    if (currentDocument) renderCurrentPage();
  });
</script>

如果你想直接使用打包后的 dist/ofd.min.js,则不要用 import,而是用普通 <script> 引入后从全局对象取 API:

<script src="../dist/ofd.min.js"></script>
<script>
  const { parseOfdDocument, renderPage, calPageBox } = window.OFD;
</script>

在 Vue 3 中使用

仓库里的 examples/vue/3/src/vue-viewer.vue 是一个 Vue 3 的集成示例。组件方式的核心思路是:

  • ref 保存加载状态、错误信息、文件信息和页面容器
  • change 事件里调用 parseOfdDocument()
  • 解析成功后使用 renderOfd() 生成页面 DOM
  • 把生成的页面元素挂到 ref 容器里

示例代码如下:

<template>
  <div class="ofd-viewer">
    <div class="controls">
      <input
        type="file"
        accept=".ofd"
        @change="handleFileChange"
        :disabled="loading"
      />
      <button v-if="fileInfo" @click="handleClear">清空文档</button>
    </div>

    <div v-if="loading">正在加载...</div>
    <div v-if="error">{{ error }}</div>

    <div v-if="fileInfo">
      <p><strong>文件名:</strong> {{ fileInfo.name }}</p>
      <p><strong>页数:</strong> {{ fileInfo.pageCount }}</p>
      <p><strong>大小:</strong> {{ formatSize(fileInfo.size) }}</p>
    </div>

    <div ref="containerRef" class="viewer">
      <div ref="pageRef"></div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { parseOfdDocument, renderOfd } from '@ycsx/ofdjs';

const loading = ref(false);
const error = ref(null);
const fileInfo = ref(null);
const containerRef = ref(null);
const pageRef = ref(null);
const pageElements = ref([]);

const formatSize = (bytes) => {
  if (bytes === 0) return '0 B';
  const k = 1024;
  const sizes = ['B', 'KB', 'MB', 'GB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
};

const handleFileChange = (event) => {
  const file = event.target.files?.[0];
  if (!file) return;

  pageElements.value = [];
  pageRef.value.innerHTML = '';
  loading.value = true;
  error.value = null;

  parseOfdDocument({
    ofd: file,
    success: (ofdDoc) => {
      const screenWidth = containerRef.value?.offsetWidth || 1024;
      pageElements.value = renderOfd(screenWidth, ofdDoc[0]);
      pageElements.value.forEach((element) => pageRef.value.appendChild(element));
      fileInfo.value = {
        name: file.name,
        pageCount: ofdDoc[0]?.pages?.length || 0,
        size: file.size,
      };
      loading.value = false;
    },
    fail: (err) => {
      error.value = err.message || '文件加载失败';
      loading.value = false;
    },
  });
};

const handleClear = () => {
  pageElements.value = [];
  fileInfo.value = null;
  error.value = null;
  pageRef.value.innerHTML = '';
};
</script>

说明:Vue 3 示例目前以“加载后一次渲染页面”为主,后续如果需要分页、缩放、单页预览等交互,可以在这个模板基础上继续扩展。

React 和 Vue 2 的示例会在后续补充。

API 文档

parseOfdDocument(options)

解析OFD文档文件。

参数:

| 参数 | 类型 | 描述 | |------|------|------| | options | Object | 配置对象 | | options.ofd | string | File | ArrayBuffer | OFD文件源(文件路径、File对象或二进制数据) | | options.success | Function | 成功回调,接收解析后的文档对象 | | options.fail | Function | 失败回调,接收错误对象 |

返回值:

示例:

parseOfdDocument({
  ofd: fileInput.files[0],
  success: (document) => {
    console.log('页数:', document.pages.length);
  },
  fail: (error) => {
    console.error('错误:', error);
  }
});

renderOfd(screenWidth, ofdDocument)

根据指定宽度渲染OFD文档,返回DOM页面数组。

参数:

| 参数 | 类型 | 描述 | |------|------|------| | screenWidth | number | 页面显示宽度(像素) | | ofdDocument | Object | 通过 parseOfdDocument 获得的文档对象 |

返回值: Array<HTMLDivElement> - 页面DOM元素数组

示例:

const pages = renderOfd(1024, ofdDocument);
pages.forEach(pageDiv => {
  // 每个pageDiv包含一个页面
  console.log('页面ID:', pageDiv.id);
  container.appendChild(pageDiv);
});

renderOfdByScale(ofdDocument)

根据设置的缩放比例渲染OFD文档。需先使用 setPageScale() 设置缩放值。

参数:

| 参数 | 类型 | 描述 | |------|------|------| | ofdDocument | Object | 通过 parseOfdDocument 获得的文档对象 |

返回值: Array<HTMLDivElement> - 页面DOM元素数组

示例:

setPageScale(1.5);  // 150%
const pages = renderOfdByScale(ofdDocument);

setPageScale(scale)

设置全局页面缩放比例。

参数:

| 参数 | 类型 | 描述 | |------|------|------| | scale | number | 缩放比例(1.0 = 100%,可设置0.5-2.0之间的值) |

返回值:

示例:

setPageScale(0.8);   // 80%
setPageScale(1.2);   // 120%

getPageScale()

获取当前设置的缩放比例。

参数:

返回值: number - 当前缩放比例

示例:

const currentScale = getPageScale();
console.log(`当前缩放: ${currentScale * 100}%`);

calPageBox(screenWidth, document, page)

计算页面在指定屏幕宽度下的尺寸。

参数:

| 参数 | 类型 | 描述 | |------|------|------| | screenWidth | number | 屏幕宽度(像素) | | document | Object | OFD文档对象 | | page | Object | 页面对象 |

返回值: Object - 包含 w(宽度)和 h(高度)的对象

示例:

const box = calPageBox(1024, ofdDocument.document, ofdDocument.pages[0]);
console.log(`页面尺寸: ${box.w}x${box.h}`);

calPageBoxScale(document, page)

根据设置的缩放比例计算页面尺寸。

参数:

| 参数 | 类型 | 描述 | |------|------|------| | document | Object | OFD文档对象 | | page | Object | 页面对象 |

返回值: Object - 包含 w(宽度)和 h(高度)的对象

示例:

setPageScale(1.2);
const box = calPageBoxScale(ofdDocument.document, ofdDocument.pages[0]);
console.log(`缩放后页面尺寸: ${box.w}x${box.h}`);

renderPage(pageDiv, page, templates, fonts, drawParams, multiMedia)

在指定的DOM元素中渲染单个页面。(高级API,通常无需直接调用)

参数:

| 参数 | 类型 | 描述 | |------|------|------| | pageDiv | HTMLDivElement | 页面容器DOM元素 | | page | Object | 页面对象 | | templates | Object | 页面模板资源 | | fonts | Object | 字体资源 | | drawParams | Object | 绘制参数 | | multiMedia | Object | 多媒体资源 |

返回值:


错误处理

parseOfdDocument({
  ofd: file,
  success: (document) => {
    console.log('解析成功');
  },
  fail: (error) => {
    // 常见错误类型
    if (error.message.includes('not a valid zip')) {
      console.error('不是有效的OFD文件');
    } else if (error.message.includes('XML parse')) {
      console.error('文档结构错误');
    } else {
      console.error('未知错误:', error);
    }
  }
});

支持的OFD版本

  • OFD 1.0
  • OFD 1.2

浏览器兼容性

| 浏览器 | 最低版本 | 备注 | |--------|---------|------| | Chrome | 50+ | ✅ 完全支持 | | Firefox | 45+ | ✅ 完全支持 | | Safari | 10+ | ✅ 完全支持 | | Edge | 15+ | ✅ 完全支持 | | IE | 不支持 | ❌ 需要使用polyfills |

注: 需要支持 ES6 Module 和 Promise。如需支持IE11,请使用相应的polyfills。

依赖项

  • jszip - ZIP文件解析
  • @xmldom/xmldom - XML解析
  • jsrsasign - 数字签名验证
  • js-sha1 - SHA1哈希算法
  • js-md5 - MD5哈希算法
  • @lapo/asn1js - ASN.1编码/解码
  • ofd-xml-parser - OFD XML解析
  • @sharp9/ofdjs - OFD格式处理
  • web-streams-polyfill - Stream API polyfill

常见问题

Q: 如何在Node.js中使用?

A: 由于该库依赖于浏览器DOM API,暂不支持Node.js环境。未来可能提供Headless实现。

Q: 支持大文件吗?

A: 支持,但建议文件不超过100MB。对于特别大的文件,可能需要分页加载。

Q: 可以修改渲染样式吗?

A: 可以。通过CSS修改返回的页面DOM元素的样式。

Q: 支持导出功能吗?

A: 当前版本仅支持渲染和查看。导出功能建议使用html2pdf等库。

Q: 可以获取文本内容吗?

A: 可以通过遍历文档对象的内容节点获取。具体方法请参考源代码或提出Issue。

版本历史

请查看 CHANGELOG.md 了解版本更新信息。

许可证

本项目采用 Apache License 2.0 许可证。

原始项目: DLTech21/ofd.js © 2020 DLTech21

修改版本: 2026 Ycsx

详情请见 LICENSE 文件。

贡献

欢迎提交Issue和Pull Request!

在贡献前,请:

  1. Fork 本项目
  2. 创建特性分支 (git checkout -b feature/AmazingFeature)
  3. 提交更改 (git commit -m 'Add some AmazingFeature')
  4. 推送到分支 (git push origin feature/AmazingFeature)
  5. 创建Pull Request

相关资源

联系方式

如有问题或建议,欢迎:


最后更新: 2026年6月26日