FileReader readAsDataURL 创建大型 base64 图像

FileReader readAsDataURL creating large base64 images

我需要将输入图像 (blob) 转换为 base64 图像。我知道大小会增加大约 1.37。

但是我注意到在使用 firereader.readAsDataUrl 时,与 macOS 上的内置 base64 命令行工具相比,图像的大小非常大。

https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL

重现步骤:

  1. 下载此免费示例图像 https://wall.alphacoders.com/big.php?i=685897 请确保单击“下载”按钮(下载原始 8000x600)。不要用右键另存为因为图片会被压缩

  2. 使用 jsfiddle 选择上面下载的图像并检查控制台日志以获取 base 64 的大小。https://jsfiddle.net/b7nkw8j9/ 您可以看到大小为 11.2mb .

  3. 现在,如果您在 mac 使用 base64 命令行工具将上面下载的图像转换为 base64 并在那里检查文件大小。您将在此处看到 base64 大小。 5.9mbbase64 -w 0 downloaded_image.jpg > downloaded_image.base64

这是我在代码中使用的将输入文件图像转换为 base64 的函数。

async convertToBase64(file) {

  if (file === undefined) {
    throw new Error("File could not be found");
  }

  const fileReader = new FileReader();

  return new Promise((resolve, reject) => {
    fileReader.readAsDataURL(file);

    fileReader.onerror = (error) => {
      reject("Input: File could not be read:" + error);
    };

    fileReader.onloadend = () => {
      resolve(fileReader.result);
    };
  });

}

为什么filereader.readAsDataURL 使图像base64 输出非常大。

我怎样才能使它更有效率?

FileReader 有 5,882,455 个字节,base64 输出有 5,882,433 个字节,如果你从 data:image/png;base64, 中添加 22 个字节,我们就不会太远了。

但是对于问题 我怎样才能使它更有效率?,只是不要在这里使用数据 URL。无论你被告知你也需要它,那都是谎言(我有 99% 的把握)。

相反,您应该始终更喜欢直接使用 Blob。

要显示它,请使用 blob URL:

inp.onchange = e => {
  img.src = URL.createObjectURL(inp.files[0]);
};
<input type="file" id="inp">
<img id="img" src="" height="200" alt="Image preview..." accept="image/*">

要将其发送到您的服务器,send the Blob directly,可以通过 FormData 或直接来自 xhr.send() 或作为获取请求的主体。

唯一可以想到在前端需要数据 URL 版本的二进制文件的情况是生成需要嵌入该二进制文件的独立文档。对于我在职业生涯中遇到的所有其他用例,Blob 更适合。


对于在 Chrome 的工具提示中打印的消息,这是浏览器必须保存在内存中的 USVString 的大小。它是磁盘上文件大小的两倍,因为 USVStrings 是用 UTF-16 编码的,即使这个字符串只包含 ASCII 字符。
但是,要发送到您的服务器,或保存为文本文件,通常会重新编码为 8 位编码,并恢复为正常大小。

所以不要将此工具提示作为告诉您数据有多大的意思,它只是它在浏览器分配的内存中占用的大小,但在外部,它根本不一样。

如果你想检查生成的二进制数据的大小,这里更好fiddle,它会将 USVStrings 转换为 UTF-8 并将二进制保持为二进制(例如,如果你将 ArrayBuffer 传递给它):

function previewFile() {
  var preview = document.querySelector('img');
  var file    = document.querySelector('input[type=file]').files[0];
  var reader  = new FileReader();

  reader.addEventListener("load", function () {
    console.log(new Blob([reader.result]).size);
    preview.src = reader.result;
  }, false);

  if (file) {
    reader.readAsDataURL(file);
  }
}
<!-- Learn about this code on MDN: https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL -->

<input type="file" onchange="previewFile()"><br>
<img src="" height="200" alt="Image preview...">