Pro 版本
Projection — 深度参考
本页是 Pro Projection 模块的深度参考,记录公开的 tokenize、emit 与往返(round-trip)接口、意图门(intent gate)以及内容流往返语义。ContentProjectionWriter 将一个 PDF 内容流词法解析(lex)为一个扁平、有序的 token 列表,然后再把一个 token 列表重新序列化为一个新的内容流。该模型是单向的:写出(emission)产生一个新的流,绝不是对原件的原地编辑。
注意。 此处的 “Projection” 指内容流 token 投影,而非坐标投影或地理空间投影。
可用性与许可
标题为“可用性与许可”的章节此能力随 NextPDF Pro(nextpdf/pro)交付,并通过 Pro 层级的许可信封(license envelope)激活。没有该授权的部署不会加载此能力的类。比较版本并获取许可。
不存在单项功能许可标志。这是一项 Pro 版本能力。写出还额外要求一个由类型系统强制、而非许可开关的显式 ProjectionIntent 参数。
公开 API 范围
标题为“公开 API 范围”的章节composer require nextpdf/pro:^3该模块位于 NextPDF\Pro\Projection 命名空间。ContentProjectionWriter 上的所有操作均为静态方法。
| 符号 | 参数 | 默认行为 | 返回 | 抛出或失败于 | 备注 |
|---|---|---|---|---|---|
ContentProjectionWriter::tokenize | string $contentStream | 将流词法解析为一个扁平、有序的 token 列表;规范化空白、丢弃注释、跳过无法识别的字节 | list<ContentToken> | 无;畸形或控制字节被跳过,而非被拒绝 | 只读;不需要意图。 |
ContentProjectionWriter::emit | list<ContentToken> $tokens、ProjectionIntent $intent | 将 token 序列化为一个新的内容流;输出与意图取值无关 | string | 方法体内无;缺失或非 ProjectionIntent 的参数在类型边界处失败 | 意图是调用点门(call-site gate),而非运行时开关。 |
ContentProjectionWriter::roundTrip | string $contentStream | 先 tokenize,再原样重新 emit,不作修改;即验证门 | string | 无 | 输出并非字节一致;运算符序列与操作数值被保留。 |
ContentToken::__construct | ContentTokenType $type、string|int|float|bool|null $value = null | 构造一个不可变 token;不执行任何校验 | ContentToken | 无;类型不兼容的 $value 在类型边界处失败 | readonly;type 与 value 为 public。 |
ContentToken::isTextOperator | — | 报告该 token 是否为文本运算符(BT、ET、Tj、TJ、Td、TD、Tm、T*、Tf、Tc、Tw、Tz、TL、Tr、Ts、'、") | bool | 无;对非运算符 token 返回 false | — |
ContentToken::isTextShowingOperator | — | 报告该 token 是否为文本显示运算符(Tj、TJ、'、") | bool | 无;对非运算符 token 返回 false | 文本运算符的子集。 |
ContentTokenType | —(string 支撑的枚举) | 枚举 token 判别值:LiteralString、HexString、Number、Name、Operator、ArrayBegin、ArrayEnd、DictBegin、DictEnd、Boolean、Null | — | — | 支撑值是稳定标识符。 |
ProjectionIntent | —(纯枚举) | 枚举两种被允许的写出意图:Sanitization、SteganographicEmbedding | — | — | 无通用取值,因此静态分析会标记未声明的使用。 |
public static function tokenize(string $contentStream): arraypublic static function emit(array $tokens, ProjectionIntent $intent): stringpublic static function roundTrip(string $contentStream): stringenum ProjectionIntent{ case Sanitization; case SteganographicEmbedding;}public function __construct( public ContentTokenType $type, public string|int|float|bool|null $value = null,) {}
public function isTextOperator(): boolpublic function isTextShowingOperator(): bool行为契约
标题为“行为契约”的章节ContentProjectionWriter::tokenize($contentStream) 将流词法解析为一个扁平、有序的 list<ContentToken>。它涵盖字面字符串、十六进制字符串、name、数字、数组与字典定界符、布尔值、null 以及运算符。空白与注释被消费并丢弃;无法识别的字节推进游标而不产生 token。该遍是只读的,且不需要意图。
emit($tokens, $intent) 将一个 token 列表序列化回内容流字节,并要求一个 ProjectionIntent。意图仅是一个调用点声明:无论传入哪种取值,写出的字节都是相同的。数字保留其整数/浮点数的区分——整数按原样写出,浮点数以最多六位小数写出并去除末尾零。字面字符串被重新转义,十六进制字符串以大写十六进制写出,name 带有其前导 solidus。每个运算符后跟一个换行符;数组与字典定界符会抑制相邻的分隔符。
roundTrip($contentStream) 先 tokenize,再原样重新 emit,不作改动。它是验证门:在信任任何“修改并写出”的序列之前,先确认一个干净的结果。输出与输入并非字节一致——空白被规范化、注释已消失——但运算符序列与操作数值被保留。
ProjectionIntent 恰好有两种取值:Sanitization(破坏性、不可逆的 redaction)与 SteganographicEmbedding(隐藏载荷嵌入)。没有通用取值,因此静态分析可以标记任何缺少声明的、已知目的的写出。ContentToken 是一个不可变的 readonly 值,携带一个 type 判别值与一个已解码的 value;isTextOperator() 与 isTextShowingOperator() 对运算符 token 进行分类,并对每个非运算符 token 返回 false。
边界情况与失败模式
标题为“边界情况与失败模式”的章节- 在任何“修改并写出”的序列之前,先确认一次干净的往返。请把往返失败视为一个停止条件。
Sanitization意图是不可逆的。被移除的 token 在输出中不存在,也无法从中恢复。- 意图不改变输出。
emit()对两种取值都产生相同的字节;该参数是一个调用点门。redaction 与隐写编辑由调用方在写出前对 token 列表进行修改来施加。 - 写出器会规范化空白并丢弃注释,因此即便是未经修改的往返,与原件的字节级比较也会出现差异。
- 浮点操作数以最多六位小数格式化,然后去零。需要更高精度的值在写出时被舍入;整数是精确的。
- 输入的字面字符串转义解码包括
\n、\r、\t、\b、\f、被转义的定界符,以及被钳制为一个字节的至多三位八进制转义。 - 十六进制字符串若位数为奇数,则在输入时以一个末尾零填充,符合 ISO 十六进制字符串规则。
- 畸形或控制字节被跳过,而非被拒绝;
tokenize()对意外输入不抛出任何异常。 - 本模块不执行任何密码学操作,也未定义任何 FIPS 特定行为。
一致性
标题为“一致性”的章节Tokenization 将流视为标准 PDF 对象语法中的运算符与操作数序列,依据 ISO 32000-2:2020, 8.2。字节到 token 的分组遵循 ISO 32000-2:2020, 7.2 的词法字符类。奇数长度的十六进制字符串将末尾数字填充为零,依据 ISO 32000-2:2020, 7.3.4.3。这些条款记录在本页的引用记录中。
这些陈述描述的是相对于所引条款的能力。NextPDF 未持有任何一致性认证,对某一条款的支持并非认证主张。
开发说明
标题为“开发说明”的章节- 自该模块的 1.10.0 发行版起可用;三个操作均为
ContentProjectionWriter上的静态入口点。 - Tokenize 与 emit 在内容流长度上是线性的。没有公布的吞吐量数字;请以有代表性的流进行测量。
- 扁平 token 模型——每个词法元素一个 token,而非按运算符分组——正是它使诸如调整一个 TJ 数组内某个数字这样的外科式编辑成为可能。按运算符分组的表示存在于 Pro 树的其他位置,不在本页范围内。
ContentToken是不可变的。请通过构造新 token、而非修改已有 token 来构建一个修改后的列表。- 请在你的流水线中保留往返门:一个通过的
roundTrip()是该模块在任何破坏性编辑之前所围绕设计的前置条件。
发布边界
标题为“发布边界”的章节本页仅记录外部可观察的行为与受支持的公开 API 范围。内部命名空间路径、辅助类、机制表、运维手册文件名以及工单前缀均不在范围内。