FileReader readAsDataURL создание больших изображений base64 - PullRequest
1 голос
/ 04 июля 2019

У меня есть требование преобразовать входное изображение (блоб) в изображение base64.Я знаю, что размер увеличится примерно на 1,37.

Однако я заметил, что при использовании firereader.readAsDataUrl размер изображения очень велик по сравнению со встроенным инструментом командной строки base64, который есть в macOS.

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

Шаги для воспроизведения:

  1. Загрузить этот бесплатный образец изображения https://wall.alphacoders.com/big.php?i=685897 обязательно нажмите кнопку Загрузить (Загрузить)Оригинал 8000x600).Не используйте правый клик для сохранения, так как изображение будет сжато

  2. Используйте jsfiddle, чтобы выбрать вышеуказанный загруженный образ и проверить в журнале консоли размер базы 64. https://jsfiddle.net/b7nkw8j9/ Вы можете видеть размер 11.2 МБ .

  3. Теперь, если у вас на Mac используется инструмент командной строки base64, чтобы преобразовать вышеуказанный загруженный образ в base64 ипроверьте размер файла там.Вы увидите размер base64 здесь. 5.9MB .base64 -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 чрезвычайно велик.

Как я могу сделать это более эффективным?

enter image description here

1 Ответ

1 голос
/ 04 июля 2019

У меня 5,882,455 байтов для FileReader против 5,882,433 байтов для base64 вывода, если вы добавите 22 байта из data:image/png;base64,, мы не слишком далеко.

Однако на вопрос Как я могу сделать это более эффективным? , просто не используйте URL данных здесь. Что бы вам ни говорили, вам это тоже нужно, это была ложь (я уверен на 99%).

Вместо этого вы всегда должны предпочитать работать с Blob напрямую.

Чтобы отобразить его, используйте URL-адрес BLOB-объекта:

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/*">

Чтобы отправить его на ваш сервер, отправьте BLOB-объект напрямую , либо через FormData, либо напрямую из xhr.send () или в качестве тела запроса на выборку.

Единственный случай, когда вы можете подумать о том, где вам понадобится версия двоичного файла с URL-адресом данных на внешнем интерфейсе, - это создать отдельный документ, в который нужно будет встроить этот двоичный файл. Для всех других случаев использования, которые я встречал в своей карьере, Blob, где гораздо лучше.


Для сообщения, которое выводится во всплывающей подсказке Chrome, это размер USVString , который браузер должен хранить в памяти. Это в два раза больше файла, который вы имеете на диске, потому что USVStrings кодируются в UTF-16, хотя эта строка содержит только символы ASCII.
Однако для отправки на сервер или для сохранения в виде текстового файла его обычно перекодируют в 8-битную кодировку и получают его нормальный размер.

Так что не принимайте эту подсказку как средство, чтобы сказать вам, насколько велики ваши данные, это только размер, который он принимает в выделенной памяти браузера, но снаружи он не будет таким же.

Если вы хотите проверить размер сгенерированных здесь двоичных данных, лучше воспользоваться скриптом, который преобразует 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...">
...