
BentoPDF 是一个强大、以隐私为先、客户端运行的 PDF 工具套件,支持自托管。它允许您直接在浏览器中操作、编辑、合并和处理 PDF 文件,无需服务器端处理,确保您的文件始终保持安全和私密。
项目的核心目标是提供一个完全免费、无需注册、无限使用且尊重用户隐私的 PDF 处理解决方案。所有工具都 100% 在浏览器中运行,文件永不离开您的设备,结合开源(AGPL-3.0)和商业双重许可模式,适合个人和企业使用。
基于对项目代码的分析,BentoPDF 提供了极其丰富的功能,主要特性包括:
BentoPDF 提供了多种安装和部署方式,以适应不同的使用场景。
从 Docker Hub 拉取预构建的镜像并运行:
# 标准模式(包含完整品牌和营销内容)
docker run -p 3000:8080 bentopdf/bentopdf:latest
# 简洁模式(仅显示工具界面,适合内网部署)
docker run -p 3001:8080 bentopdf/bentopdf-simple:latest访问 http://localhost:3000 或 http://localhost:3001 即可使用。
创建 docker-compose.yml 文件:
version: '3.8'
services:
bentopdf:
image: bentopdf/bentopdf:latest # 或 bentopdf/bentopdf-simple:latest
container_name: bentopdf
restart: unless-stopped
ports:
- '8080:8080'
security_opt:
- no-new-privileges:true然后运行 docker-compose up -d。
BentoPDF 可以部署在任何静态网站托管服务上:
dist-{version}.zip 文件,下载解压后即可上传至静态主机。# 克隆仓库
git clone https://github.com/alam00000/bentopdf.git
cd bentopdf
# 安装依赖
npm install
# 开发模式运行(标准模式)
npm run dev
# 开发模式运行(简洁模式)
npm run serve:simple
# 构建生产版本
npm run buildBentoPDF 支持多语言。页脚区域内置了语言切换器,点击后可以从下拉列表中选择您偏好的语言。语言设置会保存在本地。
BentoPDF 提供了便捷的键盘快捷键以提升效率:
Escape:返回工具网格视图。Ctrl/Cmd + K:聚焦工具搜索框。Ctrl/Cmd + /:显示/隐藏快捷键帮助面板。BentoPDF 是一个前端应用,没有传统后端 API。其核心功能通过集成多个 WebAssembly 库(如 pdf.js, pymupdf-wasm, gs-wasm)在浏览器中实现。对于数字签名等需要网络请求的功能,项目提供了一个可选的 Cloudflare Worker 代理 (cors-proxy-worker.js) 来处理跨域请求。
项目的构建和配置基于 Vite,并使用了多个插件:
@tailwindcss/vite: 用于 Tailwind CSS。vite-plugin-handlebars: 用于 HTML 模板和局部组件(如导航栏、页脚)。vite-plugin-static-copy: 用于复制静态资源。languageRouterPlugin: 用于开发环境下的多语言路由重写。以下是项目中一些核心模块的代码示例,展示了其关键实现。
src/js/state.js)此模块集中管理了应用的核心状态,确保在不同工具间切换时状态清晰。
// src/js/state.js
export const state = {
activeTool: null, // 当前激活的工具ID
files: [], // 用户上传的文件列表
pdfDoc: null, // 当前加载的PDF.js文档对象
pdfPages: [], // 文档的页面代理对象数组
currentPdfUrl: null, // 当前PDF文件的Blob URL
};
// 重置状态,通常在切换工具或完成操作时调用
export function resetState() {
state.activeTool = null;
state.files = [];
state.pdfDoc = null;
state.pdfPages = [];
state.currentPdfUrl = null;
document.getElementById('tool-content').innerHTML = '';
}src/js/i18n/i18n.js)此函数根据URL路径或本地存储来确定当前应使用的语言。
// src/js/i18n/i18n.js (节选)
export const getLanguageFromUrl = () => {
const basePath = import.meta.env.BASE_URL.replace(/\/$/, '');
let path = window.location.pathname;
// 处理基础路径(如部署在子目录时)
if (basePath && basePath !== '/' && path.startsWith(basePath)) {
path = path.slice(basePath.length) || '/';
}
// 从URL路径匹配语言代码
const langMatch = path.match(
/^\/(en|fr|es|de|zh|zh-TW|vi|tr|id|it|pt)(?:\/|$)/
);
if (langMatch && supportedLanguages.includes(langMatch[1])) {
return langMatch[1];
}
// 回退到本地存储的语言设置
const storedLang = localStorage.getItem('i18nextLng');
if (storedLang && supportedLanguages.includes(storedLang)) {
return storedLang;
}
// 默认返回英语
return 'en';
};vite.config.ts)在开发服务器中,此中间件负责将类似 /de/tools 的请求重写为 /tools.html,并注入语言上下文,实现无刷新语言切换。
// vite.config.ts (节选)
function createLanguageMiddleware(isDev: boolean) {
return (req, res, next) => {
const basePath = getBasePath();
let pathname = req.url.split('?')[0];
// 剥离基础路径
if (basePath && basePath !== '/' && pathname.startsWith(basePath)) {
pathname = pathname.slice(basePath.length) || '/';
}
const langMatch = pathname.match(LANG_REGEX);
if (langMatch) {
const [, lang, rest] = langMatch;
// 重写请求到对应的 .html 文件
req.url = `${basePath}/${rest || 'index'}.html`;
// 将语言信息附加到请求对象,供后续插件使用
(req as any).language = lang;
} else if (PAGES.has(pathname.slice(1).replace(/\.html$/, ''))) {
// 处理无语言前缀的页面请求,附加默认语言
(req as any).language = 'en';
}
next();
};
}scripts/release.js)此脚本自动化了项目的版本发布流程,包括更新版本号、创建 Git 标签、构建和打包。
#!/usr/bin/env node
// scripts/release.js (节选)
function main() {
const type = process.argv[2] || 'patch'; // 接受 major, minor, patch 参数
console.log(`🚀 Releasing ${type} version...`);
// 1. 更新 package.json 中的版本号
const newVersion = updateVersion(type);
// 2. 更新 HTML 文件中的版本号显示
execSync('npm run update-version', { stdio: 'inherit' });
// 3. 提交版本变更
execSync('git add package.json *.html src/pages/*.html', { stdio: 'inherit' });
execSync(`git commit -m "Release v${newVersion}"`, { stdio: 'inherit' });
// 4. 创建 Git 标签
const tagName = createGitTag(newVersion);
// 5. 构建并打包发行文件
execSync('npm run package', { stdio: 'inherit' }); // 这会生成 dist-{version}.zip
// 6. 推送代码和标签到远程仓库
execSync('git push origin main', { stdio: 'inherit' });
execSync(`git push origin ${tagName}`, { stdio: 'inherit' });
console.log(`🎉 Release v${newVersion} complete!`);
console.log(`📦 Docker image: bentopdf/bentopdf:${newVersion}`);
console.log(`📦 Distribution: dist-${newVersion}.zip`);
}gqq1IFjQTrOralpsd4SvLFV2TeMkbWkR3xz9WAatxU0=
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。