Преобразовать Data-URL в правильную строку байтов

Я пытаюсь разрешить пользователю сохранять изображения, которые были представлены на холсте. Может быть несколько изображений, и я хочу, чтобы пользователь мог загрузить все изображения одновременно в виде одного tar-файла. Я пытаюсь написать код для создания этого файла tar. У меня большая часть этого работает, но когда файл tar загружается на мой компьютер в конце, я обнаруживаю, что некоторые двоичные данные, составляющие файлы png, были повреждены. Вот соответствующий код:

var canvBuffer = $('<canvas>').attr('width', canvasWidth).attr('height', canvasHeight);
var ctxBuffer = canvBuffer[0].getContext('2d');

imgData.data.set(renderedFrames[0]);
ctxBuffer.putImageData(imgData,0,0);

var strURI = canvBuffer[0].toDataURL();
var byteString = atob(decodeURIComponent(strURI.substring(strURI.indexOf(',')+1)));

toTar([byteString]);

function toTar(files /* array of blobs to convert */){
        var tar = '';

        for (var i = 0, f = false, chkSumString, totalChkSum, out; i < files.length; i++) {

            f = files[i];
            chkSumString = '';

            var content  = f;


            var name = 'p1.png'.padRight('\0', 100);
            var mode = '0000664'.padRight('\0', 8);
            var uid = (1000).toString(8).padLeft('0', 7).padRight('\0',8);
            var gid = (1000).toString(8).padLeft('0', 7).padRight('\0',8);
            var size = (f.length).toString(8).padLeft('0', 11).padRight('\0',12);

            var mtime = '12123623701'.padRight('\0', 12); // modification time
            var chksum = '        '; // enter all spaces to calculate chksum
            var typeflag = '0';
            var linkname = ''.padRight('\0',100);
            var ustar = 'ustar  \0';
            var uname = 'chris'.padRight('\0', 32);
            var gname = 'chris'.padRight('\0', 32);

            // Construct header with spaces filling in for chksum value
            chkSumString = (name + mode + uid + gid + size + mtime + chksum + typeflag + linkname + ustar + uname + gname).padRight('\0', 512);


            // Calculate chksum for header
            totalChkSum = 0;
            for (var i = 0, ch; i < chkSumString.length; i++){
                ch =  chkSumString.charCodeAt(i);
                totalChkSum += ch;
            }

            // reconstruct header plus content with chksum inserted
            chksum = (totalChkSum).toString(8).padLeft('0', 6) + '\0 ';
            out = (name + mode + uid + gid + size + mtime + chksum + typeflag + linkname + ustar + uname + gname).padRight('\0', 512);
            out += content.padRight('\0', (512 + Math.floor(content.length/512) * 512)); // pad out to a multiple of 512
            out += ''.padRight('\0', 1024); // two 512 blocks to terminate the file
            tar += out;
        }

        var b = new Blob([tar], {'type': 'application/tar'});
        window.location.href =  window.URL.createObjectURL(b);

    }

Я помещаю ранее визуализированный кадр на не визуализированный холст и использую метод canDase toDataURL() для кодированной png-версии кадра с кодировкой Base64. Затем я использую atob, чтобы преобразовать это в байтовую строку, чтобы ее можно было добавить к содержимому файла tar, который я генерирую.

Когда я просматриваю файл в шестнадцатеричном редакторе, мой заголовок tar корректен, но содержимое png не совсем верно. Содержимое ASCII выглядит нормально, но двоичные данные шифруются.

Любая предложенная помощь будет принята с благодарностью. Благодарю.

PS

Я приложил ссылки на похожие посты, на которые смотрел. Они были полезны, но я еще не видел там ничего, что полностью решало бы мои проблемы. Благодарю.

Преобразуйте URI данных в файл, затем добавьте в FormData, а URI данных в URL объекта с помощью createObjectURL в chrome/ff

1 ответ

Решение

ОК, я решил проблему. Проблема была в конструкторе Blob в конце toTar. передача этой строки заставляла большой двоичный объект обрабатывать мои данные как UTF-8 вместо двоичных, вместо этого я должен передать ему arrayBuffer для массива целых чисел без знака. Ниже мое решение

  var byteArray = new Uint8Array(tar.length);
  for (var b = 0; b < tar.length; b++) {
       byteArray[b] = tar.charCodeAt(b);
  }

  var b = new Blob([byteArray.buffer], {'type': 'application/tar'});
  window.location.href =  window.URL.createObjectURL(b);

Я должен переписать toTar, чтобы построить файл в Uint8Array и убрать необходимость конвертации в конце, но это адекватно отвечает на мой вопрос и, надеюсь, поможет кому-то еще. Благодарю.

Другие вопросы по тегам