@ycsx/ofdjs
v1.0.6
Published
A Javascript class for reading and rendering ofd files
Downloads
1,097
Maintainers
Readme
@ycsx/ofdjs
一个用于读取和渲染OFD(开放式文档格式)文件的JavaScript库。
功能特性
- 📄 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!
在贡献前,请:
- Fork 本项目
- 创建特性分支 (
git checkout -b feature/AmazingFeature) - 提交更改 (
git commit -m 'Add some AmazingFeature') - 推送到分支 (
git push origin feature/AmazingFeature) - 创建Pull Request
相关资源
联系方式
如有问题或建议,欢迎:
- 提交 GitHub Issues
- 发送邮件至: 4081360972qq.com
最后更新: 2026年6月26日
