2013-04-13 42 views
2

我試圖讓用戶保存已經呈現到畫布的圖像。可能有多個圖像,我希望用戶能夠將所有圖像一次下載爲一個tar文件。我試圖編寫代碼來生成這個tar文件。我大部分工作正常,但是當最終將tar文件下載到我的計算機時,我發現組成png文件的一些二進制數據已損壞。下面是相關的代碼:將數據URL轉換爲有效字節字符串

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

    } 

我把先前渲染的幀到非渲染畫布以及使用所述畫布toDataURL()方法與Base64編碼的幀的經編碼版本的PNG。接下來,我使用atob將其轉換爲一個字節字符串,以便將其附加到我生成的tar文件的內容中。

當我在十六進制編輯器中查看文件時,我的tar頭是正確的,但是png的內容不太正確。 ASCII內容看起來很正常,但二進制數據被加密。

提供的任何幫助將不勝感激。謝謝。

PS

我附上的鏈接,我看了相關的帖子。他們有幫助,但我還沒有看到任何能夠完全解決我的問題的東西。謝謝。

Convert Data URI to File then append to FormData,並Data URI to Object URL with createObjectURL in chrome/ff

+0

你有沒有嘗試發送一個參數'圖像/ PNG'就像在http://stackoverflow.com/questions/923885/capture-html-canvas-as-gif-jpg-png-pdf – akonsu

+0

我沒有,因爲PNG是應該是默認的,如上所述window.location.href = dataURI;保存一個有效的PNG文件。只是要確定;不過,我只是試了一下。沒有運氣。謝謝。 –

+0

你的意思是'canvas.toDataURL'有一個錯誤,並返回一個損壞的圖像,或者你是什麼意思?如果我正確理解代碼,第一行設置canvas元素的寬度和高度。完成後,畫布將被刪除。 – akonsu

回答

0

OK,我已經解決了這個問題。問題在於toTar結束時的Blob構造函數。傳遞給它一個字符串導致blob將我的數據視爲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文件並刪除需要在年底進行轉換,但是這足以回答我的問題,希望能幫助別人。謝謝。