2011-10-10 30 views
7

我必須爲未來的項目(無閃光,IE10 +,FF7 +等)創建圖像上傳器,該圖像上傳器在客戶端而不是服務器上進行圖像大小調整/轉換/裁剪。如何上傳/張貼多個畫布元素

所以我做了一個javascript界面​​,用戶可以'上傳'他們的文件,並在瀏覽器中直接調整大小/裁剪,而無需聯繫服務器。表現還算不錯,但效果不錯。

endresult是一個畫布元素的數組。用戶可以在圖像調整大小後編輯/裁剪圖像,所以我將它們保留爲畫布而不是將它們轉換爲jpeg。 (這會惡化最初的性能)

現在,這工作正常,但我不知道什麼是最好的方式實際上傳完成的畫布元素到服務器現在。 (在服務器上使用asp.net 4通用處理程序)

我試圖從包含每個畫布的dataurl的所有元素創建一個json對象。

問題是,當我得到10-40張照片時,瀏覽器在創建數據傳輸時開始凍結,特別是對於大於2兆字節的圖像。

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

也將它們轉換爲json對象(我​​使用json2.js)通常會崩潰我的瀏覽器。 (FF7)

我的目標

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

上傳程序

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

什麼是送畫布元素添加到服務器的最佳途徑?

我應該一次或一次發送它們嗎?

+2

這是一個非常有趣的問題。不知道爲什麼2 downvotes沒有任何意見,+1 –

+1

爲什麼在這個世界上這個問題downvoted? – Pointy

+0

生成數據url並一次發送一個。這將減少內存使用量。它還使您能夠顯示進度(不支持xhr2)。另一個好處是服務器邏輯會稍微簡單一些,服務器上的內存使用量會更少。 – Gerben

回答

5

一個一個上傳文件比較好。需要更少的內存,只要一個文件準備上傳,就可以開始上傳,而不用等待所有文件準備好。

使用FormData發送文件。允許以二進制格式上傳文件而不是base64編碼。

var formData = new FormData; 

如果Firefox使用canvas.mozGetAsFile('image.jpg')而不是canvas.toDataUrl()。允許避免從base64到二進制的不必要的轉換。

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

在Chrome中使用BlobBuilder爲base64轉換成二進制大對象(見dataURItoBlob功能

接受 有幾件事情打轉轉後,我設法弄清楚這一點我自己。

首先,這會dataURI轉換成斑點:

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

this question):

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

,然後發送formData對象。我不知道該怎麼做jQuery的,但與普通的XHR對象它像這樣:

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

在服務器,你可以從文件中收集得到的文件:

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

這工作正常,謝謝。 – elch