如何进行 Ascii85 编码和解码
- 在 输入 · 文本 中输入或粘贴文本。Ascii85 会显示在 输出 · Ascii85(Adobe) 中。
- 在输出下方,勾选 添加 <~ ~> 定界符 可得到 PostScript/PDF 的包裹格式;如果你的解码器不支持这个简写,取消勾选 全零组用 z 表示。
- 要使用其他 Base85 字母表,把 到 改为 Base85(Git / Python b85)、Z85(ZeroMQ) 或 RFC 1924(IPv6 Base85)。
- 要解码,在方向切换中点击 Ascii85(Adobe)→ 文本。解码器接受
<~ ~>定界符、z、y和任意空白,因此从文件中复制的带换行的数据可以直接粘贴。 - 如果结果是二进制数据,把 到 设为 Hex,或点击 保存字节。
Ascii85 的工作原理
Ascii85 每次取 4 个字节,把它们读作一个 32 位大端序整数,再写成 5 位 85 进制数。每一位都是 !(值 0)到 u(值 84)之间的一个字符。四个字节用五个字符表示,额外开销为 25%,而 Base64 是 33%。
经典示例是 Man (末尾带空格):字节 4d 61 6e 20 变成 9jqo^。最后一组不足 4 个字节时,编码器会用零字节补齐,但对 n 个字节只写出 n + 1 个字符,所以 Hello(5 个字节)变成 87cURDZ:五个字符表示 Hell,两个字符表示 o。
两种简写可以缩短常见的模式。z 代替四个零字节组成的组,完整写出来就是 !!!!!。在 btoa 变体中,y 代替四个空格。本解码器两者都能读取,编码器会写出 z(可关闭),但从不写出 y。
Base85 各变体对比
| 变体 | 字母表 | Hello | 使用场景 |
|---|---|---|---|
| Ascii85(Adobe) | 按 ASCII 顺序从 ! 到 u | 87cURDZ | PostScript、PDF /ASCII85Decode |
| Base85(Git / Python) | 0-9 A-Z a-z !#$%&()*+-;<=>?@^_`{|}~ | NM&qnZv | Git 二进制补丁、Python base64.b85encode |
| Z85 | 0-9 a-z A-Z .-:+=^!/*?&<>()[]{}@%$# | nm=QNzV | ZeroMQ 和 CurveZMQ 密钥,参见 Z85 |
| RFC 1924 | 与 Git 相同 | 一个 IPv6 地址编码为 4)+k&C#VzJ4br>0wv%Yp | IPv6 地址,一个玩笑 |
Git 和 RFC 1924 的字母表相同,但 RFC 1924 把整个 16 字节地址当作一个 128 位数字处理,而不是分成四个 4 字节组。RFC 1924 发布于 1996 年 4 月 1 日,提议把 1080::8:800:200c:417a 写成 4)+k&C#VzJ4br>0wv%Yp。把 从 设为 IPv6 地址、到 设为 RFC 1924(IPv6 Base85),转换器就能复现这个结果。
PDF 和 PostScript 中的 Ascii85
PostScript Level 2 引入了 Ascii85,用于在文本文件中嵌入图片、字体等二进制数据。数据用 <~ … ~> 包裹。在 PDF 中,带有 /Filter /ASCII85Decode 的流使用同样的编码,并以 ~> 结尾。这里的解码器无论有没有开头的 <~ 都能找到结束标记。
Ascii85 常常是过滤器链中的最外层,例如 /Filter [/ASCII85Decode /FlateDecode]。这时解码 Ascii85 得到的是经过 zlib 压缩的字节,而不是可读的内容。
Git 使用 Base85 的方式不同。在 GIT binary patch 中,每行以一个长度字符开头(A–Z 表示 1–26 个字节,a–z 表示 27–52 个字节),后面是经过 zlib 压缩的数据的 Base85。解码前要去掉每行的第一个字符,然后再解压结果。
Python 中的 Ascii85 和 Base85
标准库中两种字母表都有:
import base64
base64.a85encode(b"Hello") # b'87cURDZ'
base64.a85encode(b"Hello", adobe=True) # b'<~87cURDZ~>'
base64.a85encode(b" ", foldspaces=True) # b'y'
base64.b85encode(b"Hello") # b'NM&qnZv'
base64.a85decode(b"<~9jqo^~>", adobe=True) # b'Man '
a85decode 需要 adobe=True 才能接受定界符。更多编码用法见 Python 页面。
常见问题
- “位置 … 处的 z 只允许出现在 5 字符组之间”。 组内部出现了
z。数据已损坏,或者它根本不是 Ascii85;Z85 和 Git 的 Base85 把z当作普通数字使用。 - “从位置 … 开始的组超出范围”。 五个字符编码出的值大于 2^32 − 1。把 Git Base85 或 Z85 当作 Ascii85 解码时就会这样;请切换 从。
- 出现
v、{或|之类的意外字符。 除了y和z两个简写,u之后的所有字符都在 Ascii85 字母表之外,这同样说明数据是另一种变体。 - 输出末尾多了几个零字节。 你的编码器补齐了最后一组,并写出了全部 5 个字符。对于只有 n 个字节的最后一组,Ascii85 只写 n + 1 个字符。
常见问题
Base85 和 Ascii85 有什么区别?
Base85 是一种通用思路:用 85 个字符的字符集,把 4 个字节写成 5 个字符。Ascii85 是 Adobe 的版本,使用 ! 到 u 的字符,并带有 z 简写和 <~ ~> 定界符。Git、Python 的 b85encode、Z85 和 RFC 1924 使用同样的算法,只是字母表不同。
Ascii85 中的 z 是什么意思?
单个 z 代表四个零字节,否则要写成 !!!!!。它只允许出现在一个完整的 5 字符组本该开始的位置;出现在组内部的 z 属于错误。
怎么解码 PDF 中的 Ascii85?
复制 stream 和 endstream 之间的流数据,一直到 ~>(包括它),然后在方向设为 Ascii85(Adobe)→ 文本 时粘贴。如果该流还列出了 /FlateDecode,结果是 zlib 数据;把 到 设为 Base64,再用 gzip 和 zlib 解码器 解压。
Base85 比 Base64 更好吗?
它大约短 6%:额外开销是 25%,而 Base64 是 33%。但根据变体不同,它的字母表包含引号、反斜杠或 < 和 &,因此在 JSON、XML 或 shell 中需要转义,而 Base64 不需要。只在这些字符安全的场合使用它。