# Devlog · H7:打磨篮子(HTML charset + CMYK JPEG)

> 2026-06-12 · 里程碑 H7(见 [hardening-iteration.md](../plans/hardening-iteration.md))· 状态:🟡 4 项中 3 项落地(含 H2a 的 MediaBox),2 项阻塞留待

## 落地两项

### HTML charset(真实 bug)
html 后端原先 `std::fs::read_to_string(path)` 强制 UTF-8——任何非 UTF-8 页面
(legacy GBK/Shift-JIS/Windows-1252)直接读取失败。新增
[`textio::decode_html`](../../crates/docparse-core/src/textio.rs):前 1024 字节
嗅探 `<meta charset>`(`charset=` 标签 + `http-equiv` Content-Type 两种形式,
HTML5 算法),解析到 label 用 `encoding_rs` 精确解码;无声明回退既有
`decode_text`(UTF-8 快路 + chardetng)。**声明的 charset 比统计检测更可靠**。
- e2e:造 GBK HTML(`<meta charset="gbk">` + GBK 正文)→ 正确出"中文标题/
  正文段落";Python 默认 UTF-8 读同文件报错,印证旧路径会丢内容。
- +3 单测(meta charset / http-equiv / UTF-8 无声明)。

### CMYK JPEG(避免输出偏色)
PDF 可嵌 4 通道 CMYK/YCCK JPEG;原 DCTDecode 透传把它当 RGB JPEG 原样导出,
下游(PNG 转换 / base64)解成 RGB 会**偏色**(且 Adobe APP14 常反相)。新增
`jpeg_components`(扫 SOF marker 读组件数,跳过 APP/RST 段),4 通道 → 记
`ImageKind::None` 位置占位(不输出错色图),TODO 留 APP14-aware CMYK→RGB。
- 正常 3(YCbCr)/1(灰度)通道透传不变(三件套 + JBIG2 OCR 回归通过)。
- +1 单测(SOF 组件数 4/3/1、APP0 跳过、空输入)。

## 两项留待(诚实标注阻塞)

- **转写区域重叠去重**:transcribe.rs 整页转写相邻区域无去重;改动可加,但
  验证需 `models/unirec`(~700MB)实跑整页转写。留下轮带模型验证。
- **v5-mobile 自转**:⛔ 外部环境阻塞。核实 `models/ppocr-v5/` 现存是
  **server 模型**(det 84MB + rec 81MB ≈ 172MB),非 mobile;mobile(~20MB)
  需 `paddle2onnx` 离线 Python+paddle 环境自转,**本环境无法执行**。现役
  v4-mobile(16MB,2s/页)+ 可选 v5-server 已覆盖需求,非阻塞性缺口。

## 经验

- **打磨项也要分"能干净做" vs "有外部阻塞"**:HTML charset/CMYK 是纯 Rust、
  可造样例自验的,干净做掉;v5-mobile 卡在离线 paddle 工具链,诚实标注阻塞
  而非硬凑,比假装完成有用。
- **CMYK JPEG 的正确退路是占位而非透传**:透传 4 通道当 RGB 是静默输出错误
  数据;改占位是"宁缺毋滥",符合不静默吞错的红线。完整转换(APP14)留 TODO。
