如何将 Base64 解码为 PDF
- 把字符串粘贴到 Base64 或 data URI。完整的
data:application/pdf;base64,…URI 可以直接用,换行、两侧的引号、URL 安全的 Base64(-和_)以及缺失的=填充也都没问题。如果长字符串保存在文件里,请使用 打开 .txt 文件 或把文件拖到输入框上;超过 4 MB 的内容会直接解码,不在文本框中显示。 - 预览会出现在按钮下方。粘贴后立即开始解码;如果想自己点击 解码,取消勾选 实时 即可。
- 检查 文件名。默认是
decoded,但如果 data URI 中有name=参数,或者你打开的是文本文件,就会沿用那个名字:invoice.pdf.b64.txt会变成invoice.pdf。 - 点击 下载文件。预览下方的 在新标签页中打开 链接会以全尺寸显示同一个 PDF。
页面打开时会加载一个示例 PDF,在粘贴自己的数据之前,你可以先看看正常的结果是什么样子。
Base64 PDF 从哪里来
JSON 无法直接承载原始字节,所以通过 JSON API 返回文档的服务会把文档作为 Base64 字符串发送,字段名通常类似 content、document、file 或 label。
- 面单和物流 API 会把可打印的快递面单作为 Base64 PDF 返回。同一个请求往往也可以根据格式参数返回 ZPL 或 PNG,所以名为“PDF”的字段不一定真的是 PDF(见下文的表格)。
- 电子签名服务会在完成响应或 webhook 中以 Base64 返回已签署的文档,常常还附带一份单独的审计证书。
- UBL XML 格式的电子发票会在
<cbc:EmbeddedDocumentBinaryObject mimeCode="application/pdf" filename="INV-1001.pdf">这样的元素中嵌入一份便于阅读的 PDF 副本。复制标签之间的文本即可;filename属性告诉你 文件名 里该填什么。 - 在电子邮件的原始源码中,PDF 附件是一个带
Content-Transfer-Encoding: base64的 MIME 部分,每行 76 个字符。只粘贴编码块就行,或者用 EML 解码器 打开整封邮件,它会列出所有附件。邮件中的 Base64 讲解了邮件结构。 - 存放在数据库 BLOB 列中的文档经常被导出为文本。PostgreSQL 的
encode(data, 'base64')以及 MySQL 或 MariaDB 的TO_BASE64()都会每 76 个字符插入一个换行;解码器会跳过它们。
如果一个 JSON 响应里有多个编码字段,解码 JSON 中的 Base64 可以一次性找到并全部解码。反方向操作,即把 PDF 文件转成字符串,请使用 PDF 转 Base64。
预览会显示什么
| 字段 | 来源 |
|---|---|
| PDF 版本 | 文件头行,例如 %PDF-1.7 |
| 页数 | 根据文件中的页面对象统计(见下文) |
| 标题 | 文档信息中的标题,前提是以纯文本存储 |
| 已加密 | 文件含有加密字典时出现:可能是打开密码,也可能只是权限限制 |
| SHA-256 | 解码后字节的哈希。让发送方对比 sha256sum invoice.pdf 的结果,就能证明文件完好送达 |
预览本身就是浏览器的 PDF 查看器,它通过本地 blob: URL 显示解码后的字节。Chrome、Edge、Firefox 和桌面版 Safari 会直接内嵌显示。如果浏览器被设置为下载 PDF 而不是打开(Chrome:设置、隐私和安全、网站设置、更多内容设置、PDF 文档;Firefox:设置、常规、应用程序、Portable Document Format),预览会保持空白;很多移动浏览器根本无法在页面内渲染 PDF。这些情况下,在新标签页中打开 和 下载文件 仍然可用,预览上方的信息列表也照样会填好。
页数是怎么统计的
工具不会为了统计页数而渲染 PDF。它会在文件的前 32 MB 中统计页面对象(/Type /Page)。如果一个都找不到,就读取页面树的 /Count 条目;如果这个也看不到,就显示 未知。有两种情况会让这个数字和查看器显示的不一致:
- 页数偏多。 创建后又经过编辑、批注或签名的 PDF 通常采用增量保存:修改过的页面作为新对象追加到文件末尾,旧版本仍留在文件中。在一个有 2 页、其中一页被重写过的测试文件中,统计结果是 3。
- 未知。 从 PDF 1.5 开始,对象可以打包进压缩的对象流,这时不解压就既读不到页面对象,也读不到页面树。
两者不一致时,以查看器显示的页数为准。
结果不是 PDF 时
如果解码后的字节是其他内容,字段上方会有一条提示说明检测到了什么,例如“这看起来是 HTML,而不是 PDF。”,并附带 下载为 .html 按钮。Base64 的开头通常就能说明问题所在:
| Base64 开头 | 实际内容 |
|---|---|
JVBERi0 | PDF(%PDF-) |
SlZCRVJpMH | 被编码了两次的 PDF:JVBERi0… 的 Base64 |
H4sI | gzip 压缩的数据 |
PCFET0NUWVBF、PCFkb2N0eXBl、PGh0bWw | HTML 页面,通常是错误页或登录页 |
eyJ | JSON,常常是 {"error":… 这样的错误消息 |
XlhB | 热敏打印机用的 ZPL 面单(^XA) |
iVBORw0KGgo | PNG 图片 |
对于双重编码的字符串或 gzip 数据,工具会再显示一条提示,带有 再次解码 按钮,它会把输入替换为内层数据;返回 可以回到你粘贴的原始内容。对于损坏或无法识别的文件,提示会写着“这看起来不像 PDF”,并给出检测到的类型;扩展名保持 .pdf,你仍然可以下载这些字节,换个阅读器试试。
解码之前出现的错误另有原因:
- 原始 JSON 中的转义,例如
\/(PHP 的json_encode会这样写斜杠)或行与行之间的字面\n,会被自动去除。如果其他\转义仍然触发 无效字符\,请使用 修复 Base64,或者先解析 JSON 再复制值。 - 无效字符
%说明字符串经过了 URL 编码。+、/和=的转义(%2B、%2F、%3D)会被自动修正;其他情况请先用 URL 解码器 处理一遍。 - 能识别为 PDF 却什么也不显示,通常是数据被截断了。文件头还在,所以检测能通过,但文件末尾存放交叉引用表的部分丢失了。其他常见原因见 Base64 常见错误。
在代码中将 Base64 解码为 PDF
Python,从 JSON 响应中读取:
import base64, json
with open("response.json") as f:
b64 = json.load(f)["document"]
if b64.startswith("data:"):
b64 = b64.split(",", 1)[1]
pdf = base64.b64decode(b64)
if not pdf.startswith(b"%PDF-"):
raise ValueError(f"not a PDF, starts with {pdf[:16]!r}")
with open("document.pdf", "wb") as f:
f.write(pdf)
b64decode 会悄悄丢弃标准字母表以外的字符,所以含 - 和 _ 的 URL 安全字符串会解码成乱码,而且不报错。这类字符串请使用 base64.urlsafe_b64decode。Node.js 一次调用就能同时接受两种字母表:
import { readFile, writeFile } from "node:fs/promises";
const { document } = JSON.parse(await readFile("response.json", "utf8"));
const pdf = Buffer.from(document.replace(/^data:[^,]*,/, ""), "base64");
if (pdf.toString("latin1", 0, 5) !== "%PDF-") throw new Error("not a PDF");
await writeFile("document.pdf", pdf);
在 shell 中,jq -r 很关键:不加 -r,值会带着引号,base64 -d 会报错“invalid input”并停止。
jq -r '.document' response.json | base64 -d > document.pdf
键名 document 只是占位符,换成你的 API 实际使用的字段名即可。更多写法见 Python 中的 Base64、Node.js 中的 Base64 和 Bash 中的 Base64。
常见问题
怎么把 Base64 字符串转换成 PDF 文件?
把字符串粘贴到上方的输入框,确认预览无误后点击 下载文件。如果来自 JSON,只复制引号之间的值;data:application/pdf;base64, 前缀和换行可以保留。
为什么解码出来的 PDF 打不开或是一片空白?
几乎都是因为字符串被截断了:日志的单行长度限制、数据库字段长度或复制粘贴的上限都会切掉文件末尾。完整的 PDF 以 %%EOF 结尾;可以把解码后的大小和发送方给出的大小对比一下。
能查看有密码保护的 PDF 吗?
可以。信息列表会显示 已加密:是,Chrome 和 Firefox 的内置查看器会在预览中要求输入密码。下载的文件保持原样,用同一个密码即可打开。
为什么工具提示我的 Base64 不是 PDF?
解码后的字节不是以 %PDF- 开头。最常见的原因是 API 返回的是错误页面或 JSON 消息,而不是文档;警告会说明检测到了什么,并提供按该扩展名保存的选项,方便你查看内容。
在这里解码机密 PDF 安全吗?
PDF 在你的浏览器内解码和显示,页面的内容安全策略会阻止它发出除 Cloudflare 的浏览量统计以外的网络请求。页面加载完成后,你甚至可以断网继续使用。