一、再战高亮
前文已提及文本高亮需要将分散的选区矩形一行行合并起来。单是如此生成的高亮方块会显得很瘦,不利于点选。可通过混合使用FPDFText_GetCharBox、FPDFText_GetLooseCharBox这两个API使每行高亮矩形拥有合适的高度。效果如下:

同样的算法可运用于选区方框本身,不过比较懒就省去了。
另一个困扰我的是高亮标记的形状问题。专业的 PDF SDK 可以生成如下形状的高亮标记:

但是 PDFium 只能生成普通矩形,而非“圆边”矩形。
通过仔细对比,发现“圆边”的关键在于Appearance String(AP)。
262 0 obj
<</AP<</N 461 0 R >>/C[ 1 1 0]/Contents(Maron)/CreationDate(D:20201114175217+09'00')/F 0/M(D:20201114175217+09'00')/NM(e6a504cd-943a-4297-b93b-6abd7a264c01)/P 57 0 R /PDFIUM_HasGeneratedAP true/Popup 263 0 R /QuadPoints[ 278.424 457.676 316.68 457.676 278.424 441.662 316.68 441.662]/RC(<?xml version="1.0"?><body xmlns="http://www.w3.org/1999/xhtml" xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/" xfa:APIVersion="Acrobat:11.0.13" xfa:spec="2.0.2" ><p><span style="font-size:13.8pt">Maron</span></p></body>)/Rect[ 274.149 441.162 320.955 458.176]/Subj(Highlight)/Subtype/Highlight/T(TEST)/Type/Annot>>
endobj
461 0 obj
<</BBox[ 0 0 46.806 17.0149]/Filter/FlateDecode/FormType 1/Length 28/Resources
<<
/ExtGState <</R0 <</AIS false/BM/Multiply/Type/ExtGState>>>>
/XObject <</MWFOForm 445 0 R>>
>>
>>stream
x���2PH/���
w�w�/�Up��� 8���
endstream
可见 262 0 obj
定义了高亮标注对象,并且包含了AP对象461 0 obj
。后者是个stream对象,关键词有ExtGState、XObject 、Form这样的字眼,同样具有包围框BBox。其 stream 流(乱码部分)可解出字符串:
FPDF_WCHAR buffer[512]={0};
char buffer_c[512]={0};
auto ap = FPDFAnnot_GetAP(aI, 0, buffer, 512);
// /MWFOForm D
WideCharToMultiByte(CP_ACP, 0, (WCHAR*)buffer, ap, buffer_c, 512, 0, 0);
std::cout << "Annot AP = " << ap << " = " << buffer_c << ".\n";
结果是:
/R0 gs
/R1 gs
/MWFOForm Do
意义不明。太过复杂也省去,“圆边”没有就没有吧。
二、再战保存
已知,PDFium 无法增量保存。不过保存6MB左右的文件是很快的,可以配合实现一些选项以弥补不足。
保存机制:
- onPause 时保存
- onDestroy 时保存
- 根据文件大小自动选择保存时机( onPause 或 onDestroy )
- 不保存
数据库使用:
- 保存至数据库
静读天下也会在数据库中记录新添加的高亮标注,然后一一列出。
这里就诞生了一种可能性:不将高亮标注等保存至 PDF,而是保存至数据库。
网友评论