更新记录

1.0.0(2026-10-03) 下载此版本

  • 生成固定版式 PDF,支持文字、图片、矩形和线段。
  • 多张图片按顺序生成统一尺寸 PDF,并处理图片方向。
  • 查询 PDF 页数、页面尺寸、元数据和加密状态。
  • 渲染页面图片、提取文字和关键词检索。
  • 合并、拆分、抽取、复制、重排、旋转和裁剪页面。
  • 批量文字水印,支持平铺/单枚、字体、颜色、透明度、角度、间距和前后图层。
  • 阅读密码、所有者密码、打印/复制权限和授权解密。
  • 元数据、书签、表单、批注和栅格化处理。
  • HTTPS 下载、进度回调、下载取消和插件缓存文件清理。

平台兼容性

uni-app x(5.26)

Chrome Safari Android iOS 鸿蒙 微信小程序
× × 5.0 13 × ×

其他

多语言 暗黑模式 宽屏模式 蒸汽模式
× × × √

lf-pdfkit

lf-pdfkit 是面向 uni-app x 的 UTS API 插件,用于在 Android 和 iOS 设备本地生成、读取、编辑和保护 PDF。插件不上传文档内容,也不依赖 WebView 或 Office/HTML 渲染引擎。

版本与支持范围

  • 插件版本:1.0.0
  • HBuilderX:5.26 及以上
  • uni-app x:5.26 及以上
  • Android:最低 API 21
  • iOS:最低 13.0
  • 支持平台:Android、iOS
  • 不支持平台:Web、鸿蒙、小程序和普通 uni-app Vue 工程

这是 API 插件,所有能力均通过 script 中的 UTS 方法调用。插件不提供可直接嵌入页面的 PDF 阅读组件;如需预览,可使用 renderPdf 得到图片后由宿主页面展示,或自行实现页面组件。

插件包含 Kotlin、Swift 原生实现以及 Android Maven 依赖。使用前必须制作包含插件依赖的自定义调试基座,或直接使用云打包。仅复制源码而继续使用不包含 PDFBox 依赖的旧基座,无法运行 Android 功能。

安装与导入

将 uni_modules/lf-pdfkit 放入 uni-app x 工程,在 UTS 页面中从插件根目录导入:

import { createPdf, getPdfInfo, renderPdf } from '@/uni_modules/lf-pdfkit'

不要直接导入 utssdk 内部文件。插件对外类型和函数均从根入口导出,直接导入根目录可以保证平台实现和类型提示一致。

能力总览

能力 说明 主要接口
业务文档生成 将文字、图片、矩形和线段写入多页 PDF createPdf
图片成册 将照片或扫描图按顺序排成统一尺寸的 PDF,并处理方向 imagesToPdf
文档查询 查询页数、尺寸、元数据、加密状态和文件大小 getPdfInfo
页面渲染 将 PDF 页面渲染为 PNG/JPEG 图片 renderPdf
文字提取与检索 提取页面文字,按关键词查找位置和上下文 extractText、searchPdf
页面编排 合并、拆分、抽取、复制、重排和旋转页面 mergePdf、splitPdf、selectPages、rotatePdf
页面裁剪 修改页面可视区域 cropPdf
批量水印 写入平铺或单枚文字水印,支持字体、角度、图层和透明度 watermarkPdf
文档保护 设置密码和打印/复制权限,使用所有者密码解密 encryptPdf、decryptPdf
文档结构 读写元数据和书签 setMetadata、getOutlines、setOutlines
表单处理 查询字段、填写字段并按需固化 getFormFields、fillForms
批注与栅格化 添加便签/高亮/矩形/图片盖章,或生成视觉副本 annotatePdf、rasterizePdf
文件管理 下载 HTTPS 文件、清理插件缓存文件 downloadPdf、releaseFiles

基本数据类型

PdfSource

所有读取和编辑接口都使用 PdfSource:

type PdfSource = { path: string, password?: string }

path 必须是本地文件路径,也可以是 Android content:// 输入地址或 file:// 地址。网络地址不能直接交给 PDF 接口,应先使用 downloadPdf 下载。password 只在本次调用期间使用,不写入文件元数据或日志。

PdfFile

写文件接口返回:

type PdfFile = { path: string, pageCount: number, fileSize: number }

fileSize 的单位是字节。未指定 outputPath 时,文件会写入插件私有缓存目录;需要长期保存时,请由宿主应用复制到自己的持久目录。

页码、坐标和尺寸

  • 所有页码从 1 开始。
  • 页面尺寸和坐标使用 PDF point,1 point = 1/72 英寸。
  • A4 页面约为 595 × 842 point。
  • createPdf 的文字、图片、矩形和线段坐标以未旋转页面左上角为原点,x 向右、y 向下。
  • cropPdf 的裁剪矩形遵循同样的左上角坐标约定。
  • rotatePdf 的角度必须是 90 的整数倍。
  • 颜色统一使用 #RRGGBB,不依赖 CSS 颜色名解析。

所有写操作都会生成新文件,不覆盖输入文件,也不覆盖已存在的输出文件。显式传入的 outputPath 必须指向不存在的文件,且父目录必须已经存在。

生成 PDF

createPdf 适合生成业务单据、报价单、报告、清单和固定版式文档。插件负责 PDF 页面、文字和矢量元素的写入;分页规则、金额计算和业务排版由调用方准备。

支持的元素类型:

kind 必填字段 说明
text x、y、text 文字;可选 width、height、fontSize、fontPath、fontFamily、color
image x、y、path 图片;必须提供 width、height
rect x、y、width、height lineWidth 为 0 时填充,大于 0 时描边
line x、y、width、height 绘制线段,长度不能为 0
import { createPdf, getPdfInfo, PdfPage, PdfText } from '@/uni_modules/lf-pdfkit'

const elements: PdfText[] = [
  { kind: 'text', x: 36, y: 36, width: 523, height: 36,
    text: '项目交付报告', fontSize: 24, color: '#173454',
    fontPath: '/static/fonts/your-font.ttf' } as PdfText,
  { kind: 'rect', x: 36, y: 100, width: 523, height: 64,
    color: '#E8F1F5', lineWidth: 0 } as PdfText,
  { kind: 'line', x: 36, y: 188, width: 523, height: 0,
    color: '#173454', lineWidth: 1 } as PdfText
]

const file = await createPdf({
  pages: [{ width: 595, height: 842, elements: elements } as PdfPage],
  metadata: { title: '项目交付报告', author: '业务系统' }
})
const info = await getPdfInfo({ path: file.path })
console.log(info.pageCount, file.path)

文字不会自动创建下一页。文字超出 width 或 height 时,接口会返回参数或内容错误;调用方应提前分行、分页或扩大文本框。Android 使用自定义 TTF 时,字体必须包含文字所需字形,并且调用方必须拥有字体授权。

图片成册

import { imagesToPdf } from '@/uni_modules/lf-pdfkit'

const file = await imagesToPdf({
  paths: photoPaths,
  width: 595,
  height: 842,
  margin: 28,
  fit: 'contain'
})

参数说明:

  • paths:图片路径数组,顺序就是 PDF 页序。
  • width、height:输出页面尺寸,默认接近 A4。
  • margin:图片区域边距,单位为 point。
  • fit:contain 保持完整图片并留白;cover 填满区域并裁剪;fill 拉伸填满。
  • Android 会读取图片 EXIF 方向并完成方向校正。

查询、渲染和文字处理

import { getPdfInfo, renderPdf, extractText, searchPdf } from '@/uni_modules/lf-pdfkit'

const source = { path: file.path }
const info = await getPdfInfo(source)
const images = await renderPdf({ source: source, pages: [1], scale: 1.5, format: 'png' })
const texts = await extractText({ source: source, pages: [1, 2] })
const hits = await searchPdf({ source: source, query: '验收', maxResults: 20 })

renderPdf 返回插件缓存中的图片路径。使用完毕后,可把这些图片路径传给 releaseFiles 清理。渲染图片不等于修改原 PDF。扫描 PDF 只有图像,没有文字层,因此 extractText 和 searchPdf 无法识别扫描图中的文字;插件不提供 OCR。

页面编排

import { mergePdf, splitPdf, selectPages, rotatePdf, cropPdf } from '@/uni_modules/lf-pdfkit'

const merged = await mergePdf({
  sources: [{ path: firstPath }, { path: secondPath, password: ownerPassword }]
})
const split = await splitPdf({ source: { path: merged.path }, groups: [[1], [2, 3]] })
const reordered = await selectPages({ source: { path: merged.path }, pages: [3, 1, 1] })
const rotated = await rotatePdf({ source: { path: merged.path }, pages: [1], degrees: 90 })
const cropped = await cropPdf({ source: { path: merged.path }, pages: [1], rect: { x: 20, y: 20, width: 555, height: 802 } })

页面编排主要保留页面内容,不保证完整合并不同文件的文档级表单、名称树、附件、标签、JavaScript、全部书签和数字签名。包含复杂交互结构的生产合同,应在目标阅读器中验收输出结果。重写已签名 PDF 通常会使原数字签名失效。

批量水印

水印写入 PDF 页面内容层,不会把整页栅格化:

import { watermarkPdf } from '@/uni_modules/lf-pdfkit'

const marked = await watermarkPdf({
  source: { path: file.path },
  text: '内部资料', mode: 'tile', angle: 45,
  fontPath: '/static/fonts/your-font.ttf', fontSize: 24,
  color: '#64748B', opacity: 0.18,
  spacingX: 72, spacingY: 56, layer: 'foreground'
})
参数 默认值 范围或说明
mode tile tile 多行平铺;single 单枚居中
angle 45 -180 至 180 度,正值在视觉上逆时针旋转
fontFamily sans-serif sans-serif、serif 或 monospace
fontPath 不指定 自定义 TTF,优先级高于 fontFamily
fontSize 24 1 至 256 point
color #808080 必须是 #RRGGBB
opacity 0.18 0 至 1,0 为透明,1 为不透明
spacingX / spacingY 72 / 56 0 至 1440 point
layer foreground foreground 在原内容上方;background 在下方

水印不是安全涂黑,不会删除底层文字,也不能作为 DRM。背景水印可能被不透明底色或扫描图片遮挡,扫描 PDF 通常应使用前景层。单枚水平水印可以显式设置 mode: 'single', angle: 0。

加密、权限与解密

import { encryptPdf, decryptPdf } from '@/uni_modules/lf-pdfkit'

const locked = await encryptPdf({
  source: { path: file.path },
  userPassword: 'reader-secret', ownerPassword: 'owner-secret',
  allowPrinting: true, allowCopying: false
})
const plain = await decryptPdf({
  source: { path: locked.path, password: 'owner-secret' }
})

ownerPassword 必须非空,并且不能与 userPassword 相同。普通编辑接口不会悄悄解除原文档加密;处理受保护 PDF 前,应先使用所有者密码显式解密到新文件。权限位不是 DRM,其他软件可能不遵守,但插件会在需要复制、修改或解密时执行权限检查。

元数据、书签、表单和批注

import { setMetadata, getOutlines, setOutlines, getFormFields, fillForms, annotatePdf } from '@/uni_modules/lf-pdfkit'

const updated = await setMetadata({
  source: { path: file.path },
  metadata: { title: '归档报告', author: '档案系统', keywords: '归档,报告' }
})
const outlines = await getOutlines({ path: updated.path })
const withOutlines = await setOutlines({
  source: { path: updated.path },
  items: [{ title: '首页', page: 1, depth: 0 }]
})
const fields = await getFormFields({ path: withOutlines.path })
const filled = await fillForms({
  source: { path: withOutlines.path },
  values: [{ name: 'customerName', value: '示例客户' }], flatten: false
})
const annotated = await annotatePdf({
  source: { path: filled.path },
  annotations: [{ page: 1, kind: 'note', rect: { x: 40, y: 40, width: 80, height: 40 }, text: '需要复核' }]
})

书签 depth 从 0 开始,层级不能跳级。表单字段能否填写取决于原文档字段类型、只读状态和平台能力。图片盖章只是视觉批注,不属于数字签名。

临时文件与下载

import { downloadPdf, releaseFiles } from '@/uni_modules/lf-pdfkit'

const task = downloadPdf({
  url: 'https://example.com/report.pdf',
  headers: { Authorization: 'Bearer token' }, timeout: 60000
}, (event) => { console.log(event.progress) })
const downloaded = await task.promise
await releaseFiles([downloaded.path])

downloadPdf 只接受 HTTPS 地址,返回 promise 和 cancel()。下载成功只代表 HTTP 状态为 2xx,服务器仍可能返回登录页或其他非 PDF 内容;交给 PDF 接口打开时才会验证格式。普通 PDF 操作没有硬取消保证。

插件输出默认位于应用缓存目录,系统可能在空间不足时清理缓存。宿主应用需要长期保存文件时,应在 Promise 成功后复制到自己的持久目录,并在确认不再使用预览图片后调用 releaseFiles。不要释放仍被页面使用的文件。

平台差异与限制

Android

  • 使用 PDFBox-Android 2.0.27.0 和 AndroidX ExifInterface 1.3.7。
  • 单个输入或输出 PDF 不超过 128 MiB;一次请求的输入输出总量不超过 512 MiB。
  • 单个输入和一次批量输出最多 100 页。
  • 单次位图处理上限约为 1200 万像素,并会检查页面尺寸、PDF 对象数量和绘制复杂度。
  • 中文及其他非拉丁文字必须使用包含对应字形的 TTF fontPath。
  • 页面抽取、拆分和合并会拒绝无法安全重建的 AcroForm、Widget、Link、Popup/Reply 等交互结构。
  • fillForms 支持文本、复选框、单选按钮和部分选择字段;不支持 XFA,多选字段不能按数组契约填写。
  • 输出文件使用排他创建,不覆盖已有文件;复制期间不要提前读取尚未成功返回的路径。

iOS

  • 使用系统 PDFKit、UIKit、CoreGraphics、ImageIO 和 CoreText。
  • 输入和输出 PDF 最大 256 MiB,单个输入和一次输出最多 100 页,后台任务队列最多 8 个。
  • 加密密码最多 32 个可打印 ASCII 字符,具体加密算法由系统 PDFKit 决定。
  • 表单填写主要支持文本和复选框;flatten: true 需要 iOS 16 或更高版本。
  • 水印和图片盖印遇到包含大纲、Widget、Link、标签、图层或签名的复杂 PDF 时可能拒绝处理,以避免悄悄损坏文档结构。
  • 系统字体度量与 Android 不完全一致。跨端要求版式一致时,请两端使用同一授权 TTF 并分别验收。

不提供的能力

  • OCR 和扫描图片文字识别。
  • HTML、Word、Excel 或网页转 PDF。
  • PKI/PAdES 证书数字签名、签名验证和 PDF/A、PDF/UA 合规校验。
  • 安全涂黑、不可恢复的敏感信息删除和 DRM。
  • 原生连续滚动 PDF 阅读器、原生文字选择、双指缩放和批注编辑工具栏。
  • 富文本排版、Emoji 复杂塑形、竖排文字和 Office 级分页引擎。

错误处理

所有 Promise 失败都会返回 LfPdfError,包含 errSubject: 'lf-pdfkit'、errCode 和 errMsg。业务代码应优先按错误码分流,不要只匹配错误文本。

错误码 含义 常见原因
9020001 参数错误 页码、坐标、颜色、密码或输出路径无效
9020002 文件错误 文件不存在、无权读取、输出目录不存在
9020003 密码错误 未提供密码或密码不正确
9020004 PDF 处理失败 PDF 损坏、解析失败、渲染失败或写入失败
9020005 不支持 平台、文档结构或系统版本不支持
9020006 资源超限 页数、文件大小、像素、对象数量或队列超限
9020007 网络失败 HTTPS 请求失败或 HTTP 状态不是 2xx
9020008 主动取消 downloadPdf().cancel() 被调用
9020009 权限不足 PDF 不允许复制、修改、填写或装配

发布包说明

DCloud UTS 插件的发布包必须保留插件根目录和 package.json。本 API 插件的核心文件是 utssdk/interface.uts、utssdk/index.uts、utssdk/app-android 和 utssdk/app-ios。发布包不应包含 unpackage、node_modules、.git、示例工程、构建缓存或与插件无关的文档。

本插件通过 utssdk/app-android/config.json 声明 PDFBox Maven 依赖,不在压缩包内重复携带 jar/aar。发布前应使用 HBuilderX 自定义基座和云打包分别验证 Android、iOS 的生成、渲染、水印、密码、页面编排和临时文件清理流程。

许可证

插件自有代码采用 MIT 许可证,详见 LICENSE。Android 依赖 PDFBox-Android 和 AndroidX ExifInterface,iOS 使用系统框架。分发应用或二次打包时,请同时遵守这些依赖的许可证和 NOTICE 要求。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

### Android - `android.permission.INTERNET`:仅在调用 `downloadPdf` 下载调用方指定的 HTTPS 文件时使用;本地 PDF 处理不需要网络。 - 存储读写权限:插件不主动申请。插件使用应用私有缓存,并处理宿主明确传入的文件路径。 - `content://` 临时读取授权:由宿主文件选择器提供,宿主负责取得授权后再传入插件。 ### iOS - 网络访问:仅在调用 `downloadPdf` 时访问调用方指定的 HTTPS 地址。 - 照片库权限:由宿主调用 `uni.chooseImage` 时按业务需要申请,插件自身不主动弹出照片权限申请。 - 本地文件:插件只访问宿主明确传入的文件,不申请额外文件权限。 插件不申请定位、通讯录、麦克风、相机、蓝牙、日历或通知权限。

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

无

许可协议

MIT License

Copyright (c) 2026 lf-pdfkit contributors

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

暂无用户评论。