2011-10-10 1 views
7

Devo creare un uploader di immagini per un progetto futuro (senza flash, IE10 +, FF7 + ecc.) Che ridimensiona/converte/ritaglia immagine sul client e non sul server.Come caricare/caricare più elementi di canvas

Così ho creato un'interfaccia javascript in cui l'utente può "caricare" i propri file e ridimensionarli/croppare direttamente nel browser, senza mai contattare il server. La performance è OK, non così buona, ma funziona.

Il risultato finale è un array di elementi canvas. L'utente può modificare/ritagliare le immagini dopo che sono state ridimensionate, quindi le tengo come canvas invece di convertirle in jpeg. (Che peggiorerebbe la prestazione iniziale)

Ora funziona correttamente, ma non so quale sia il modo migliore per caricare effettivamente gli elementi di tela finiti sul server ora. (Utilizzo di un gestore generico asp.net 4 sul server)

Ho provato a creare un oggetto JSON da tutti gli elementi contenenti il ​​dataurl di ciascun canvas.

Il problema è che quando ho 10-40 immagini, il browser inizia a congelarsi durante la creazione dei dataurl, specialmente per le immagini che superano i 2 megabyte.

  //images = array of UploadImage 
      for (var i = 0; i < images.length; i++) { 
       var data = document.getElementById('cv_' + i).toDataURL('image/jpg'); 
       images[i].data = data.substr(data.indexOf('base64') + 7); 
      } 

convertendoli anche a un oggetto JSON (sto usando json2.js) di solito si blocca il mio browser. (FF7)

Il mio scopo

var UploadImage = function (pFileName, pName, pDescription) { 
     this.FileName = pFileName; 
     this.Name = pName; 
     this.Description = pDescription; 
     this.data = null; 
    } 

Il caricamento di routine

  //images = array of UploadImage 
      for (var i = 0; i < images.length; i++) { 
       var data = document.getElementById('cv_' + i).toDataURL('image/jpg'); 
       images[i].data = data.substr(data.indexOf('base64') + 7); 
      } 

      var xhr, provider; 
      xhr = jQuery.ajaxSettings.xhr(); 
      if (xhr.upload) { 
       xhr.upload.addEventListener('progress', function (e) { 
        console.log(Math.round((e.loaded * 100)/e.total) + '% done'); 
       }, false); 
      } 
      provider = function() { 
       return xhr; 
      }; 
      var ddd = JSON.stringify(images); //usually crash here 
      $.ajax({ 
       type: 'POST', 
       url: 'upload.ashx', 
       xhr: provider, 
       dataType: 'json', 
       success: function (data) { 
        alert('ajax success: data = ' + data); 
       }, 
       error: function() { 
        alert('ajax error'); 
       }, 
       data: ddd 
      }); 

Quale sarebbe il modo migliore per inviare gli elementi di tela al server?

Devo inviarli tutti in una volta o uno per uno?

+2

Questa è una domanda piuttosto interessante . Non sei sicuro del perché 2 downvotes senza commenti, +1 –

+1

Perché nel mondo questa domanda è stata downvoted? – Pointy

+0

Genera l'url di dati e lo invia uno alla volta. Ciò ridurrà l'utilizzo della memoria. Permette anche di mostrare il progresso (xhr2 non è supportato). L'altro lato positivo è che la logica del server sarà leggermente più semplice e l'utilizzo della memoria sul server sarà inferiore. – Gerben

risposta

5

Il caricamento dei file uno ad uno è migliore. Richiede meno memoria e non appena un file è pronto per essere caricato, il caricamento può essere avviato anziché attendere mentre tutti i file verranno preparati.

Utilizzare FormData per inviare file. Permette di caricare file in formato binario invece di base64 codificati.

var formData = new FormData; 

Se Firefox usa canvas.mozGetAsFile ('image.jpg') al posto di canvas.toDataUrl(). Consentire di evitare conversioni non necessarie da base64 a binario.

var file = canvas.mozGetAsFile('image.jpg'); 
formData.append(file); 

In Chrome utilizzano per convertire BlobBuilder base64 in blob (vedi dataURItoBlob funzione

accettati Dopo aver suonato in giro con un paio di cose, sono riuscito a calcolare questo fuori me stesso.

Prima di tutto, questo convertirà un dataURI ad un Blob:

//added for quick reference 
function dataURItoBlob(dataURI) { 
    // convert base64/URLEncoded data component to raw binary data held in a string 
    var byteString; 
    if (dataURI.split(',')[0].indexOf('base64') >= 0) 
     byteString = atob(dataURI.split(',')[1]); 
    else 
     byteString = unescape(dataURI.split(',')[1]); 

    // separate out the mime component 
    var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; 

    // write the bytes of the string to a typed array 
    var ia = new Uint8Array(byteString.length); 
    for (var i = 0; i < byteString.length; i++) { 
     ia[i] = byteString.charCodeAt(i); 
    } 

    return new Blob([ia], {type:mimeString}); 
} 

Da this question):

var blob = dataURItoBlob(canvas.toDataURL('image/jpg')); 
formData.append(blob); 

E poi inviare l'oggetto formData. Non sono sicuro di come farlo in jQuery, ma con XHR semplice oggetto a cui in questo modo:

var xhr = new XMLHttpRequest; 
xhr.open('POST', 'upload.ashx', false); 
xhr.send(formData); 

Nel server è possibile ottenere i file da File collezione:

context.Request.Files[0].SaveAs(...); 
+0

Funziona bene, grazie. – elch