Подтвердить что ты не робот

Javascript: Render PNG хранится как Uint8Array на элемент Canvas без URI данных

Я пытаюсь отобразить изображение PNG, которое хранится в javascript Uint8Array. Код, который я изначально пытался, был следующим:

var imgByteStr = String.fromCharCode.apply(null, this.imgBytes);

var pageImg = new Image();
pageImg.onload = function(e) {

    // Draw onto the canvas
    canvasContext.drawImage(pageImg, 0, 0);

};

// Attempt to generate the Data URI from the binary
// 3rd-party library adds toBase64() as a string function
pageImg.src="data:image/png;base64,"+encodeURIComponent(imgByteStr.toBase64());

Однако я обнаружил, что по какой-либо причине функция onload никогда не запускалась (у меня были точки останова, установленные в хроме, и это просто никогда не удавалось). Я обнаружил, что если я установил src в URL вместо URI данных, он работал правильно. Однако из-за некоторых ограничений я не могу напрямую ссылаться на URL-адрес изображения, т.е. Он должен быть загружен из Uint8Array.

Кроме того, чтобы усложнить ситуацию чуть больше, эти изображения могут быть мегабайтами в размере. Из того, что я прочитал, возникают проблемы совместимости с попыткой использовать URI данных для очень больших изображений. Из-за этого я крайне не решаюсь использовать их.

Таким образом, возникает вопрос, как сделать этот массив байтов как PNG в контексте canvas без использования URI данных или ссылаться непосредственно на URL-адрес изображения?


Я также попытался использовать что-то вроде следующего, чтобы напрямую манипулировать данными изображения, используя функцию putImageData. Имейте в виду, что я не понимаю на 100%, как работает эта функция.

var imgdata = canvasContext.createImageData(this.baseHeight, this.baseWidth);
var imgdatalen = imgdata.data.length;
for(var i=0; i<imgdatalen; i++) {
    imgdata.data[i] = _this.imgBytes[i];
}
canvasContext.putImageData(imgdata, 0, 0);

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


Кроме того, медленно выбирая эту вещь, я столкнулся с ошибкой в ​​Chrome SECURITY_ERR: DOM Exception 18. Оказывается, что, как только изображение загружается в холст с помощью drawImage, его невозможно извлечь без дополнительных обходных решений. A Сообщение Chromium Blog по теме было особенно полезно

4b9b3361

Ответ 1

Если у вас есть данные PNG в памяти (я думаю, это то, что вы описываете), вы можете создать изображение из него. В HTML это будет выглядеть так:

 <img src="data:image/png;base64,KSjs9JdldhAlisflAkshf==" />

В JavaScript вы можете сделать то же самое:

var image = document.createElement('img');
    image.src = 'data:image/png;base64,' + base64Data;

Обратите внимание, что вы можете изменить тип MIME, если у вас нет данных PNG.

Затем вы можете нарисовать image на вашем холсте с помощью context.drawImage(image, 0, 0) или аналогичного.

Таким образом, оставшаяся часть головоломки состоит в том, чтобы кодировать содержимое вашего Uint8Array в данные базы 64.

var array = new Uint8Array(),
    base64Data = btoa(String.fromCharCode.apply(null, array));

Функция btoa не является стандартной, поэтому некоторые браузеры могут ее не поддерживать. Однако кажется, что больше всего. В противном случае вы можете найти некоторый код, который я использую.

Я сам этого не испытывал!

Ответ 2

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

Где он поддерживается, createObjectURL - отличная альтернатива огромным URI данных. Вам все равно придется вернуться к использованию URI данных в Opera, IE и 10, и все, кроме последних версий мобильных браузеров.

var myArray; //= your data in a UInt8Array
var blob = new Blob([myArray], {'type': 'image/png'});
var URL = URL.createObjectURL(blob); //possibly `webkitURL` or another vendor prefix for old browsers.