2012-12-19 12 views
18

Sto tentando di eseguire il rendering di un'immagine PNG archiviata in un javascript Uint8Array. Il codice che ho inizialmente provato era il seguente:Javascript: Renderizza PNG memorizzato come Uint8Array su elemento Canvas senza URI dati

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()); 

Tuttavia, ho trovato che per qualche motivo la funzione onload non è mai stato in esecuzione (ho avuto punti di interruzione impostati in cromo ed è semplicemente mai colpito). Ho scoperto che se imposto src su un URL anziché su URI dati, ha funzionato correttamente. Tuttavia, a causa di alcuni vincoli, non posso direttamente fare riferimento all'URL dell'immagine, cioè, deve essere caricato dallo UInt8Array.

Inoltre, per complicare leggermente le cose, queste immagini possono avere dimensioni di megabyte. Da quello che ho letto, ci sono problemi di compatibilità con il tentativo di utilizzare gli URI di dati per immagini molto grandi. Per questo motivo, sono estremamente titubante nell'utilizzarli.

La domanda, quindi, è come si esegue il rendering di questo array di byte come PNG su un contesto di canvas senza utilizzare URI di dati o riferimento direttamente all'URL dell'immagine?


Ho anche provato usando qualcosa come il seguente per manipolare i dati di immagine direttamente mediante la funzione putImageData. Tenete a mente che non al 100% capisco come questa funzione

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); 

E 'stato sollevato da un blog il cui scheda allora ho chiuso, quindi mi scuso per l'ispirazione per non dare credito appropriato.


Inoltre, mentre lentamente martellare via a questa cosa, mi sono imbattuto in un errore in Chrome SECURITY_ERR: DOM Exception 18. Si scopre che, non appena un'immagine viene caricata su una tela usando drawImage, non può essere recuperata senza alcuni accorgimenti aggiuntivi. Uno Chromium Blog post sull'argomento era particolarmente utile

+0

Hai esaminato 'putImageData()'? – David

+0

Solo per curiosità: come sono arrivati ​​i dati dell'immagine nell'array? – closure

+1

@David: L'ho esaminato un po ', ma la mia comprensione è che si tratta di dati di immagini non elaborati, non di dati di immagine codificati PNG. Lo proverò – zashu

risposta

15

Se si dispone dei dati PNG in memoria (che penso sia quello che si sta descrivendo), è possibile creare un'immagine da esso. In HTML sarebbe simile:

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

In JavaScript si può fare lo stesso:

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

Si noti che è possibile modificare il tipo MIME se non si dispone di dati PNG.

È quindi possibile disegnare il image sulla tela utilizzando context.drawImage(image, 0, 0) o simile.

Quindi la parte restante del puzzle è quella di codificare il contenuto del tuo Uint8Array in dati Base 64.

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

La funzione btoa non è standard, in modo da alcuni browser potrebbe non supportare esso. Tuttavia sembra che most do. Altrimenti potresti trovare utile some code I use.

Non ho provato nulla di tutto ciò!

+0

btoa è sicuramente un'ottima alternativa alla libreria di terze parti che sto usando come un modo per codificare utilizzando le funzioni native. La mia più grande paura con gli URI di dati (che è il metodo consigliato) è la dimensione, in particolare, sui browser mobili per i quali è stato progettato, una preoccupazione che ho avuto dopo aver esaminato [questa domanda] (http://stackoverflow.com/questions/ 695.151 /-url-size-limitazioni dei dati-protocollo). – zashu

+2

Ho raggiunto un limite in Chrome prima quando provavo a visualizzare un'immagine tramite un URL di dati. Se è superiore a 2 MB, Chrome non funziona correttamente. Altri browser hanno limiti più alti. Ho utilizzato una soluzione alternativa che ho trovato in questo rapporto bug di Chromium: http://code.google.com/p/chromium/issues/detail?id=69227 –

+0

Alla fine, ho optato per andare con gli URI di dati poiché non sembrava nessun altro soluzione adatta alla necessità. Dovevo solo assicurarmi che le immagini stesse fossero abbastanza piccole. – zashu

16

Se si dispone già di un UInt8Array, è necessario considerare l'utilizzo di Blob e createObjectURL; createObjectURL alloca un URL speciale che consente al browser di accedere a un blob creato internamente di dati binari come se fosse un file che viene caricato esternamente.

Where it is supported, createObjectURL è un'ottima alternativa agli enormi URI di dati. Potrebbe comunque essere necessario ricorrere all'URI dei dati in Opera, IE < 10 e tutte tranne le versioni più recenti dei browser mobili.

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. 
+0

ottenendo errore 'createObjectURL() di indefinito' – adi

Problemi correlati