在 Typescript 中对嵌入的 PDF 进行 Base64 解码

Posted

技术标签:

【中文标题】在 Typescript 中对嵌入的 PDF 进行 Base64 解码【英文标题】:Base64 Decode embedded PDF in Typescript 【发布时间】:2021-01-14 03:24:00 【问题描述】:

在 XML 文件中,我们有一个表示 PDF 文件的 base64 编码字符串,其中包含一些表格表示,即类似于this example。在解码该 PDF 文档的 base64 字符串(即such as this)时,我们最终得到一个大小为 66 kB 的 PDF 文档,可以在任何 PDF 查看器中正确打开。

尝试在 TypeScript 中使用 Buffer 解码相同的 base64 编码字符串(在 VSCode 扩展中),即使用以下函数:

function decodeBase64(base64String: string): string 
    const buf: Buffer = Buffer.from(base64String, "base64");
    return buf.toString();


// the base64 encoded string is usually extracted from an XML file directly
// for testing purposes we load that base64 encoded string from a local file
const base64Enc: string = fs.readFileSync(".../base64Enc.txt", "ascii");
const base64Decoded: string = decodeBase64(base64Enc);

fs.writeFileSync(".../table.pdf", base64Decoded);

我们最终得到一个 109 kB 大小的 PDF 和一个无法使用 PDF 查看器打开的文档。

对于一个简单的 PDF,例如 this one,使用 base64 编码的字符串表示,例如 this,上面的代码可以工作,并且可以在任何 PDF 查看器中阅读 PDF。

我还尝试使用

直接读取本地存储的 PDF 文件的 base64 编码表示
const buffer: string | Buffer = fs.readFileSync(".../base64Enc.txt", "base64");

虽然也没有产生有用的东西。

即使对this suggestion 稍作修改,由于atob(...) 不存在(suggestions 将atob 替换为缓冲区),最终代码如下:

const buffer: string = fs.readFileSync(".../base64Enc.txt", "ascii");

// atob(...) is not present, other answers suggest to use Buffer for conversion
const binary: string = Buffer.from(buffer, 'base64').toString();
const arrayBuffer: ArrayBuffer = new ArrayBuffer(binary.length);
const uintArray: Uint8Array = new Uint8Array(arrayBuffer);

for (let i: number = 0; i < binary.length; i++) 
    uintArray[i] = binary.charCodeAt(i);

const decoded: string = Buffer.from(uintArray.buffer).toString();

fs.writeFileSync(".../table.pdf", decoded);

我最终不会得到可读的 PDF。 “解码”table.pdf 样本最终大小为 109 kB。

我在这里做错了什么?怎样才能像 Notepad++ 提供的功能一样,对 table.pdf 样本等 PDF 进行解码以获得可读的 PDF 文档?

【问题讨论】:

我认为你可以通过 new Uint8Array(Buffer.from(buffer, 'base64')) 获得 uintArray 以避免字符串转换和所有 charCodeAt 的东西。然后只需将数组写入文件而不转换为字符串。 @HereticMonkey 将 Uint8Array 直接写入文件会生成可读的 PDF 文件。我现在面临的问题是,这些更改需要应用于文档,而 vscode WorkspaceEdit() 对象仅适用于替换字符串表示,但我想这是后续问题的关注点。如果您将您的建议添加为答案,我很高兴接受它,以便与我有类似问题的其他人能够更快地找到您的解决方案 【参考方案1】:

从How to get an array from ArrayBuffer? 的答案中大量借用,如果您使用Uint8Array 构造函数从Buffer 获得Uint8Array

const buffer: string = fs.readFileSync(".../base64Enc.txt", "ascii");
const uintArray: Uint8Array = new Uint8Array(Buffer.from(buffer, 'base64'));
fs.writeFileSync(".../table.pdf", uintArray);

Uint8Array 直接写入文件可确保不会因移入和移出字符串的编码更改而导致损坏。

请注意:Uint8Array 指向与Buffer 相同的内部字节数组。在这种情况下并不重要,因为这段代码没有在构造函数之外引用Buffer,但如果有人决定为Buffer.from(buffer, 'base64')的输出创建一个新变量。

【讨论】:

以上是关于在 Typescript 中对嵌入的 PDF 进行 Base64 解码的主要内容,如果未能解决你的问题,请参考以下文章

如何在Typescript中对私有方法进行单元测试

如何在 Python 中对 PDF 文件进行 base64 编码

仅在 typescript React 中对数组的最后一个索引进行样式设置?

如何在 Web 应用程序中对 PDF 文档进行数字签名?

在 Cognos PDF 报告中对超链接列进行分组

如何在 netsuite/freemarker 的高级 pdf/html 工作表中对列表进行分组?