Skip to content

更新日志

记录 Officia 文档与产品的更新节点。文档基线(机器可读事实快照)见仓库 .docmeta/baseline-*.json,用于后续更新时对比"哪些能力 / API 变了"。

2026-09-04 · v1.1.3 Excel 转 PDF 补齐表格边框、行高与垂直对齐

Maven 坐标plus.ruoyi:officia-all:1.1.3。无破坏性变更;含一处呈现行为变化,见文末。

修复:xlsx 转出来的表格只剩文字,框线全丢

一份满是框线的报表转成 PDF 后,文字都在、线一条没有。根因在解析而非渲染: 样式表解析读了数字格式、填充、字体与水平对齐,唯独跳过 <borders>(ECMA-376 §18.8.4), xf/@borderId 也没记录。IR 与排版层的边框能力一直是齐备的(Word 表格一直在用), 只是 Excel 这条链从没往里喂过数据。

叠加第二处:样式此前只在读到单元格 <v> 时才记录,而报表右侧成片的空列, 框线恰恰挂在无值的空单元格上(<c r="D99" s="62"/>)——那半张表即使解析了边框也仍然没有线。

本版补齐说明
单元格边框ST_BorderStyle 全部线型(hair/thin/medium/thick/double 及各式虚线,§18.18.3),<color auto="1"/> 归一为黑
边框冲突相邻单元格各自声明共享边时按「粗线压细线、双线最高」决胜,合并区的 medium 外框不会被相邻格的 thin 内线吃掉
合并区外框上/左取左上角、右取右上角、下取左下角合成,跨列表头的右、下外框不再缺失
跨行合并下方各行改为 vMerge 占位格,横线不再穿过「备注」这类跨行表头
行高<row @ht> 进入排版,按下限约束,内容更高时仍可撑开不裁字

修复:表格跨页后,续页第一行顶上缺一条线

共享横边在消解阶段一律归上一行的底边持有;上一行留在上一页时,续页表格顶部就少一条线。 本版在页顶按同一套冲突规则就地重算补回,行在页中时仍沿用消解结果、不重复描边。 该修复位于通用排版层,所有格式的跨页表格(含 Word)都受益。

行为变化:Excel 单元格垂直对齐改按规范默认底对齐

此前未声明 vertical 的单元格一律按顶部绘制,本版改为 ECMA-376 §18.8.1 规定的默认值 bottom——这与 Excel 中的实际呈现一致。带行高的表格,文字位置会比 1.1.2 更贴近原表。 API 未变,无需改代码。

2026-09-04 · v1.1.2 修复间接引用解析 + 元数据写入改为强类型

Maven 坐标plus.ruoyi:officia-all:1.1.2含一处破坏性变更,见文末。

修复:PDF 编辑侧没有统一解引用,撞上真实文件就出错

使用方在 1.1.1 上给真实 PDF 加平铺水印时报 class ...PdfObjectParser$Ref cannot be cast to class java.util.Map

根因是 PDF32000 §7.3.10 允许任何对象写成间接引用(7 0 R),而条目是不是引用 取决于生成文件的程序、与文档复杂度无关;编辑侧却在几个读取点各写了一份 instanceof Ref 判断,漏掉的那处就成了裸强转。本版改为唯一的解引用入口, 并顺带修掉同一根因下另外四处——它们都不抛异常,只静默出错,比崩溃更难发现:

条目是间接引用时旧行为影响的操作
/Font抛 ClassCastException平铺文字水印
/Contents 指向数组拼出嵌套数组,整页正文丢失水印、页码
/Annots 指向数组(签名路径)走「当没有」分支,页面原有注解全被清空(链接、表单域、批注)数字签名
/Annots 指向数组(注解水印)拼出嵌套数组,注解整块失效注解模式水印
/Rotate当成 0,旋转基准算错页面旋转

内容读取侧(PdfReader)的强转全部有类型守卫,不受此缺陷影响。

变更:setMetadataPdfMetadata,不再收 Map

此前读元数据返回 PdfMetadata、写元数据却要自己拼 Map<String, String>, 同一组数据两套类型。更实际的代价是键名全靠调用方记——写成 "author" 而不是 "Author" 不会报错,只是静默不生效

java
// 1.1.1 及更早
byte[] out = OfficiaPdf.setMetadata(pdf, Map.of("Title", "合同", "Author", "Officia"));

// 1.1.2
byte[] out = OfficiaPdf.setMetadata(pdf, new PdfMetadata().title("合同").author("Officia"));

// 读出来改几项再写回
byte[] patched = OfficiaPdf.setMetadata(pdf,
        new PdfMetadata(OfficiaPdf.metadata(pdf).all()).subject("补充主题"));

// 自定义 Info 键(§14.3.3 允许)
byte[] custom = OfficiaPdf.setMetadata(pdf, new PdfMetadata().set("Company", "若依科技"));

链式编辑器同步:edit(pdf).metadata(new PdfMetadata().title("季度报告"))

PdfMetadata 的链式方法值传 null 表示不写该项,而不是清空既有值—— 与「保留既有项、给定项覆盖」的写入语义一致。all() 现在返回只读视图。

🔴 破坏性变更与迁移

以下两个方法的 Map 版本已删除,不是废弃:

旧签名新签名
OfficiaPdf.setMetadata(byte[], Map<String, String>)OfficiaPdf.setMetadata(byte[], PdfMetadata)
PdfEditor.metadata(Map<String, String>)PdfEditor.metadata(PdfMetadata)

用到它们的代码升级后编译不过,按上面的例子改即可;标准键都有同名链式方法, 自定义键用 set(key, value)。其余 API 一律未变。

2026-09-04 · v1.1.1 修复:发布包漏了两个包的防混淆配置

请从 1.1.0 升级到 plus.ruoyi:officia-all:1.1.1

问题

1.1.0(及更早的 1.0.0)的发布包在混淆时漏配了 render.imageocr 两个包, 导致以下类在 jar 里被改名,客户 import 会直接报「找不到符号」:

受累的 API
WatermarkOptionsOfficiaPdf.watermark(pdf, WatermarkOptions[, ttf])(1.1.0 新增)
ImageRenderOptionsOfficiaPdf / OfficiaWordstoImages(..., ImageRenderOptions)
OfficiaOcrOcrOptions整个 OCR 门面

OfficiaPdf.watermark(pdf, text) 等不带这些类型的 API 不受影响,一直可用。

影响范围

1.0.0 就带此缺陷,只是当时少有人用带选项的重载。1.1.1 起四个类全部恢复正常。 授权门控与验票逻辑的混淆不受此修复影响(那部分本就该混淆,也确实仍是混淆的)。

我们改了什么

防混淆的判据从「这个模块算不算能力包」改成「有没有类型出现在公开门面的签名里」, 并新增一道发版前的关口:拿 release 包当 classpath 真编译一段客户代码, 凡出现在公开签名里的类型都在其中被 import 使用——被误混淆的类会在编译期立刻暴露。 此前的验证(单测、测试台、线上部署)走的都是未混淆的开发构建,结构上发现不了这类问题。

2026-09-04 · v1.1.0 发布:参数化水印 + Word 转 PDF 还原度提升

Maven 坐标plus.ruoyi:officia-all:1.1.0(从 1.0.0 升级无需改代码,旧 API 全部保留)

新增:水印可自定义了

此前 OfficiaPdf.watermark(pdf, text) 的样式是写死的(页心、45°、半透明灰),做不出 「姓名 + 时间戳整页平铺」这类防泄密溯源水印。新增 WatermarkOptions 重载:

java
byte[] out = OfficiaPdf.watermark(pdf,
        WatermarkOptions.text("张三 {datetime}")
                .tile(true).fontSizePt(13).opacity(0.13f)
                .rotationDegrees(-30f).tileGapRatio(1.5f),
        simsunTtf);
  • 样式全可调:字号 / 颜色 / 不透明度 / 旋转角 / 平铺间距 / 画在正文上或下
  • 整页平铺走 PDF 规范的平铺图案(PDF32000 §8.7.3),一页铺几十个水印的体积与铺一个相当
  • 动态变量{page} {pages} {date} {time} {datetime},逐页替换
  • 图片水印WatermarkOptions.image(sealPng),PNG 透明通道保留(走 /SMask),印章不带白底
  • 注解模式annotation(true) 改用水印注解(§12.5.6.22)承载。注意它可被阅读器隐藏、 编辑器删除,只适合「草稿」「待审」这类提示性水印;溯源水印请用默认的内容流模式

旧的 watermark(pdf, text) 行为一字未动。

修复:Word → PDF 内容不再静默丢失

用 124 份新抓取的真实 doc/docx(未针对性调优)与 WPS 输出逐页比对:

指标1.0.01.1.0
转换成功率116 / 124124 / 124
平均字符召回0.98540.9944
最低字符召回0.53400.8941
目录点线密度(vs 基准)0.6280.971

其中两类是静默丢内容——不报错、转换还显示成功,拿到 PDF 才发现少了整段:

  • 表格单元格内的浮动文本框整块丢失:一份流程图文档 397 字丢掉 185 字
  • 内容控件 w:sdt 只穿透了内联一级:单元格级 / 行级 / 块级的 sdt 连同内容一起跳过

另修复目录前导符取字(按所属 run 的字号与西文族)、PAGEREF 域按书签所在页重算、 w:caps / w:smallCapsw:sym 私用区映射、西文字体缺失时的回退口径等。

其他

  • extractImagesDetailed() 补进文档:extractImages 遇到 JBIG2Decode / CCITTFaxDecode / JPXDecode 会跳过,用它的 hasSkipped() / describeSkipped() 才知道结果是否完整
  • 签名选项补充 contactInfofieldName 的说明

2026-08-08 · 在线测试台上线

  • demo.officia.ruoyi.plus 开放访问——免安装的 Officia 能力测试台: 浏览器上传 doc/docx/xlsx/pptx/pdf/图片/eml 当场实测转换、模板填充、PDF 工具箱、图像滤镜、 条码二维码、邮件归档,并可一键跑批量回归。每步显示页数 / 耗时 / 体积,产物可预览下载。
  • 站点跑评估版(水印 + 限 30 页),可现场加载自己的 officia.lic 对比解锁前后效果。
  • 入口已加到文档站导航栏、首页与快速开始页。

站点上传件与产物只存在内存、重启即清、不落盘不入库;定位是能力测试台而非生产级服务 (未做大文档与高并发压测),请勿上传涉密文档。

2026-08-08 · 公式函数清单公开 + DOC 图片边界澄清

  • Cells 模块页新增「支持的函数(35 个)」清单表(数学 13 / 统计 7 / 逻辑 6 / 文本 8 / 查找 1), 并说明清单外函数(SUMIFS / INDEX / MATCH / 日期函数)会求值失败。此前只写"支持一批常用函数", 客户无法自查自己的表能不能算。
  • 澄清 DOC 内 WMF / EMF / PICT / CMYK JPEG 图片的真实行为:自 2026-07-31 起,这类无法洁净室解码的 图片负载不再否决整份文档——该图位置退化为保留版面尺寸的空白占位,后文不上移、环绕仍成立, 整篇照常转出。此前文档描述为"明确不支持",会让客户误以为整份文件转不了。

本条只更正描述、不含 API 变更;产品侧该行为 2026-07-31 已生效。

2026-08-04 · Slides 门面精简为单一保真语义

  • OfficiaSlides.toPdf 现在就是版式几何保真:形状按 a:xfrm 绝对定位、占位符 layout/master 继承、 每张幻灯片一页。此前它是"只取文字"的内容提取式,不输出图片与样式。
  • 移除 toPdfLayoutAware——其能力已成为 toPdf 的默认行为,无需再选模式。
  • 补齐重载矩阵:保真路径现支持 byte[] / InputStream / File / ConvertOptions 四种入参, 并可用 convert(...)ConvertResult(页数 = 幻灯片数、耗时)。
  • 移除内容提取式转换链。只要纯文本时对产物再抽一次即可,且文字比原内容提取式更全: OfficiaPdf.extractText(OfficiaSlides.toPdf(pptx))

变更原因:内容提取式自建成起未再演进,而保真链已迭代 30 余次(渐变透明度、组合填充继承、 图片旋转与裁剪、内嵌字体、3D 场景、图表等)。同一门面里 toPdf 语义与 Words/Cells 不一致, 且文档首页推荐的恰是效果最差的一条,故收敛为单一语义。

2026-07-30 · 模块页深化 + API 校准

  • 深化 5 个能力模块页(Cells / Slides / Pdf / Email / Imaging)到完整用法度,均对照 officia 真实门面签名逐一校准。
  • 修正 3 处 API 描述(真相源=代码):
    • OfficiaPdf.edit() 链式方法是 pageNumbers() 而非 addPageNumbers()extractPages/removePagesint... 页索引(0-based)。
    • OfficiaCells.evaluateFormula(sheet, formula) 首参为"单元格→值"数据表。
    • OfficiaImaging.textWatermark(src, text, x, y, fontSize, rgb, opacity) 参数为坐标/字号/颜色/不透明度。

2026-07-29 · 文档站首建(基线 v1)

节点快照.docmeta/baseline-2026-07-29.json

  • 建立官方文档站(VitePress),含 SEO(JSON-LD / sitemap / canonical)与 GEO(llms.txt / robots.txt 放行 AI 爬虫)。
  • 覆盖八大能力门面文档:Words / Cells / Slides / Pdf / Email / Imaging / BarCode + 授权模块 License。
  • 授权定价上线:个人版 ¥1288 / 企业版 ¥2999。
  • 授权体系:席位签名授权、零代码自动加载 officia.lic、未授权评估态(水印 + 限页)。

本节点的产品事实(截至 2026-07-29)

  • Officia 版本:1.0.0,Java 17 基线,运行时零第三方依赖。
  • 能力模块:Words / Cells / Slides / Pdf / Email / Imaging / BarCode(7 大门面)+ License。
  • Cells 公式引擎:35 个函数。
  • PDF 加密:RC4 与 AES-256(AESV3)。
  • BarCode:Code128/39/93 · EAN-13/8 · UPC-A · ITF-14 · QR(全 40 版本)。
  • 测试:全模块单测绿(详见基线快照 testFiles 字段)。

如何维护更新节点:每次文档 / 产品有实质变化时,在此新增一条,并生成一份新的 .docmeta/baseline-YYYY-MM-DD.json(重新提取当前门面 API、模块清单、版本、测试数),与上一份 diff 即可定位改动、精准更新对应文档页。