先看blob介紹

    demo

    原始碼: html js

    <!DOCTYPE html>
    <html>
    <body>
      <h1>Create an image/png blob, then fetch it with XHR</h1>
      <pre id="display"></pre>
      <script src="blob_xhr_1.js"></script>
    </body>
    </html>
    (function () {
      'use strict';
    
      // From http://stackoverflow.com/questions/14967647/ (continues on next line)
      // encode-decode-image-with-base64-breaks-image (2013-04-21)
      function fixBinary(bin) {
        var length = bin.length;
        var buf = new ArrayBuffer(length);
        var arr = new Uint8Array(buf);
        for (var i = 0; i < length; i++) {
          arr[i] = bin.charCodeAt(i);
        }
        return buf;
      }
    
      var display = document.getElementById('display');
      display.innerHTML = (display.innerHTML || '');
    
      function log(text) {
        display.innerHTML += "\n" + text;
      }
      var base64 =
        "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAB1klEQVR42n2TzytEURTHv3e8N1joRhZG" +
        "zJsoCjsLhcw0jClKWbHwY2GnLGUlIfIP2IjyY2djZTHSMJNQSilFNkz24z0/Ms2MrnvfvMu8mcfZvPvu" +
        "Pfdzz/mecwgKLNYKb0cFEgXbRvwV2s2HuWazCbzKA5LvNecDXayBjv9NL7tEpSNgbYzQ5kZmAlSXgsGG" +
        "XmS+MjhKxDHgC+quyaPKQtoPYMQPOh5U9H6tBxF+Icy/aolqAqLP5wjWd5r/Ip3YXVILrF4ZRYAxDhCO" +
        "J/yCwiMI+/xgjOEzmzIhAio04GeGayIXjQ0wGoAuQ5cmIjh8jNo0GF78QwNhpyvV1O9tdxSSR6PLl51F" +
        "nIK3uQ4JJQME4sCxCIRxQbMwPNSjqaobsfskm9l4Ky6jvCzWEnDKU1ayQPe5BbN64vYJ2vwO7CIeLIi3" +
        "ciYAoby0M4oNYBrXgdgAbC/MhGCRhyhCZwrcEz1Ib3KKO7f+2I4iFvoVmIxHigGiZHhPIb0bL1bQApFS" +
        "9U/AC0ulSXrrhMotka/lQy0Ic08FDeIiAmDvA2HX01W05TopS2j2/H4T6FBVbj4YgV5+AecyLk+Ctvms" +
        "QWK8WZZ+Hdf7QGu7fobMuZHyq1DoJLvUqQrfM966EU/qYGwAAAAASUVORK5CYII=";
    
      var binary = fixBinary(atob(base64));
      var blob = new Blob([binary], {
        type: 'image/png'
      });
      var url = URL.createObjectURL(blob);
      log('Created a png blob of size: ' + blob.size);
      log('Inserting an img...');
      var img = document.createElement('img');
      img.src = url;
      document.body.appendChild(img);
      log('Blob URL is: ' + url);
      log('Fetching with ajax...');
    
      var xhr = new XMLHttpRequest();
      xhr.open('GET', url);
      xhr.responseType = 'arraybuffer';
      xhr.onreadystatechange = function () {
    	  //xhr.send() 以後,如果狀態改變,就執行這個函數
        if (xhr.readyState !== 4) {
          return;
        }
        log('xhr.status is: ' + xhr.status);
        log('returned content-type is: ' + xhr.getResponseHeader('Content-Type'));
        log('returned content-length is: ' + xhr.getResponseHeader('Content-Length'));
    
        var returnedBlob = new Blob([xhr.response], {
          type: 'image/png'
        });
        var reader = new FileReader();
        reader.onload = function (e) {
          var returnedURL = e.target.result;
          //e.g.: returnedURL = "data:image/png;base64,iVBORw0KGgoA....
          var returnedBase64 = returnedURL.replace(/^[^,]+,/, ''); 
          log('xhr.response (in base64) is: ' + returnedBase64);
          log('is this the expected base64? ' + (returnedBase64 === base64));
        };
        //reader.readAsDataURL(blob); // 原來是這行,但是應該不對。改成下面
    	reader.readAsDataURL(returnedBlob); //Convert the blob from clipboard to base64
      };
      xhr.send(); //送出request=> line 47, xhr.open('GET',url)
    })();

    xxxx

    (function () {
      'use strict';
    
      // From http://stackoverflow.com/questions/14967647/ (continues on next line)
      // encode-decode-image-with-base64-breaks-image (2013-04-21)
      function fixBinary(bin) {
        var length = bin.length;
        var buf = new ArrayBuffer(length);
        var arr = new Uint8Array(buf);
        for (var i = 0; i < length; i++) {
          arr[i] = bin.charCodeAt(i);
        }
        return buf;
      }
    

    blob_xhr_note.files/blob_xhr_1.js
    (function () {
      'use strict';
    
      // From http://stackoverflow.com/questions/14967647/ (continues on next line)
      // encode-decode-image-with-base64-breaks-image (2013-04-21)
      function fixBinary(bin) {
        var length = bin.length;
        var buf = new ArrayBuffer(length);
        var arr = new Uint8Array(buf);
        for (var i = 0; i < length; i++) {
          arr[i] = bin.charCodeAt(i);
        }
        return buf;
      }
    
      var display = document.getElementById('display');
      display.innerHTML = (display.innerHTML || '');
    
      function log(text) {
        display.innerHTML += "\n" + text;
      }
      var base64 =
        "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAB1klEQVR42n2TzytEURTHv3e8N1joRhZG" +
        "zJsoCjsLhcw0jClKWbHwY2GnLGUlIfIP2IjyY2djZTHSMJNQSilFNkz24z0/Ms2MrnvfvMu8mcfZvPvu" +
        "Pfdzz/mecwgKLNYKb0cFEgXbRvwV2s2HuWazCbzKA5LvNecDXayBjv9NL7tEpSNgbYzQ5kZmAlSXgsGG" +
        "XmS+MjhKxDHgC+quyaPKQtoPYMQPOh5U9H6tBxF+Icy/aolqAqLP5wjWd5r/Ip3YXVILrF4ZRYAxDhCO" +
        "J/yCwiMI+/xgjOEzmzIhAio04GeGayIXjQ0wGoAuQ5cmIjh8jNo0GF78QwNhpyvV1O9tdxSSR6PLl51F" +
        "nIK3uQ4JJQME4sCxCIRxQbMwPNSjqaobsfskm9l4Ky6jvCzWEnDKU1ayQPe5BbN64vYJ2vwO7CIeLIi3" +
        "ciYAoby0M4oNYBrXgdgAbC/MhGCRhyhCZwrcEz1Ib3KKO7f+2I4iFvoVmIxHigGiZHhPIb0bL1bQApFS" +
        "9U/AC0ulSXrrhMotka/lQy0Ic08FDeIiAmDvA2HX01W05TopS2j2/H4T6FBVbj4YgV5+AecyLk+Ctvms" +
        "QWK8WZZ+Hdf7QGu7fobMuZHyq1DoJLvUqQrfM966EU/qYGwAAAAASUVORK5CYII=";
    
      var binary = fixBinary(atob(base64));
      var blob = new Blob([binary], {
        type: 'image/png'
      });
      var url = URL.createObjectURL(blob);
      log('Created a png blob of size: ' + blob.size);
      log('Inserting an img...');
      var img = document.createElement('img');
      img.src = url;
      document.body.appendChild(img);
      log('Blob URL is: ' + url);
      log('Fetching with ajax...');
    
      var xhr = new XMLHttpRequest();
      xhr.open('GET', url);
      xhr.responseType = 'arraybuffer';
      xhr.onreadystatechange = function () {
    	  //xhr.send() 以後,如果狀態改變,就執行這個函數
        if (xhr.readyState !== 4) {
          return;
        }
        log('xhr.status is: ' + xhr.status);
        log('returned content-type is: ' + xhr.getResponseHeader('Content-Type'));
        log('returned content-length is: ' + xhr.getResponseHeader('Content-Length'));
    
        var returnedBlob = new Blob([xhr.response], {
          type: 'image/png'
        });
        var reader = new FileReader();
        reader.onload = function (e) {
          var returnedURL = e.target.result;
          //e.g.: returnedURL = "data:image/png;base64,iVBORw0KGgoA....
          var returnedBase64 = returnedURL.replace(/^[^,]+,/, ''); 
          log('xhr.response (in base64) is: ' + returnedBase64);
          log('is this the expected base64? ' + (returnedBase64 === base64));
        };
        //reader.readAsDataURL(blob); // 原來是這行,但是應該不對。改成下面
    	reader.readAsDataURL(returnedBlob); //Convert the blob from clipboard to base64
      };
      xhr.send(); //送出request=> line 47, xhr.open('GET',url)
    })();

    @import "blobXhr_1.html" {code_block=true,"class=line-numbers"}

    <pre id=display>顯示訊息用

    blobXhr_1.js

    @import "blobXhr_1.js" {code_block=true,"class=line-numbers"}

    想要測試讀取URL時的影像轉換。看看能不能拿到一樣的base64

    L33: 利用binary = fixBinary(atob(base64)) 將base64轉成矩陣(raw data)。

    L34: 從binary建立一個blob。

    L37: url <- createObjectURL()建立blob url。將二進位陣列轉為 blob 型態的url(url=URL.createObjectURL(blob))

    L46-L72的流程:

    1. 利用XMLHttpRequest()要求從L37建立的 url 要求ArrayBuffer(L48),
    2. 然後利用xhr.reponse建立 returnedBlob
    3. L63-67 從 returnedBlob 建立base64

    最後比較 returnBlob的base64 和原始base64 一不一樣。

    line 48 : 因為指定`reponseType='arraybuffer'所以line 57 的debug結果是ArrayBuffer 在 XMLHttpRequest Level 1 規範中,responseType,用來指定回應的類型(預設值為空字串),可設定的數值有 'arraybuffer'、'blob'、'document'、'json' 與 'text'。

    line 57: xhr.response 的內容如下(F12),是陣列,直接拿來建立Blob

    
    ArrayBuffer(527) {}
    [[Int8Array]]: Int8Array(527) [-119, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 16, 0, 0, 0, 16, 8, 6, 0, 0, 0, 31, -13, -1, 97, 0, 0, 1, -42, 73, 68, 65, 84, 120, -38, 125, -109, -49, 43, 68, 81, 20, -57, -65, 119, -68, 55, 88, -24, 70, 22, 70, -52, -101, 40, 10, 59, 11, -123, -52, 52, -116, 41, 74, 89, -79, -16, 99, 97, -89, 44, 101, 37, 33, -14, 15, -40, -120, -14, 99, 103, 99, 101, 49, -46, 48, -109, 80, 74, 41, 69, 54, …]
    [[Uint8Array]]: Uint8Array(527) [137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 16, 0, 0, 0, 16, 8, 6, 0, 0, 0, 31, 243, 255, 97, 0, 0, 1, 214, 73, 68, 65, 84, 120, 218, 125, 147, 207, 43, 68, 81, 20, 199, 191, 119, 188, 55, 88, 232, 70, 22, 70, 204, 155, 40, 10, 59, 11, 133, 204, 52, 140, 41, 74, 89, 177, 240, 99, 97, 167, 44, 101, 37, 33, 242, 15, 216, 136, 242, 99, 103, 99, 101, 49, 210, 48, 147, 80, 74, 41, 69, 54, …]
    byteLength: (...)__proto__: ArrayBuffer
    

    L63: returnedURL = "data:image/png;base64,iVBORw0KGgoA....

    var returnedBase64 = returnedURL.replace(/^[^,]+,/, ''); 從字串頭開始(第1個^) [^,]+,:除了,這個字元以外,至少一個以上,一直到, 結束,都殺掉。

    分部解說

    atob(),btoa()

    兩個函數分別是 base64 的編碼、解碼,都是字串。

    charCodeAt

    charCodeAt() 方法可返回指定位置的字符的 Unicode 編碼。

    範例

    var sentence = 'The quick brown fox jumped over the lazy dog.';
    var index = 4;
    console.log('The character code ' + sentence.charCodeAt(index) + ' is equal to ' + sentence.charAt(index));
    // expected output: "The character code 113 is equal to q"
    

    範例: Convert a base64 string into a binary Uint8 Array

    var BASE64_MARKER = ';base64,';
    
    function convertDataURIToBinary(dataURI) {
      var base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length;
      var base64 = dataURI.substring(base64Index);
      var raw = window.atob(base64);
      var rawLength = raw.length;
      var array = new Uint8Array(new ArrayBuffer(rawLength));
    
      for(i = 0; i < rawLength; i++) {
        array[i] = raw.charCodeAt(i);
      }
      return array;
    }
    

    主程式碼中的fixBinary

    function fixBinary(bin) {
        var length = bin.length;
        var buf = new ArrayBuffer(length);
        var arr = new Uint8Array(buf);
        for (var i = 0; i < length; i++) {
          arr[i] = bin.charCodeAt(i);
        }
        return buf;
      }
    

    bin 雖然是二進位,但是typeof(bin)=string; charCodeAt()將裡面的每一元素以code 方式讀取。

    更進一步的說明,參見base64編碼問題這裡

    ArrayBuffer

    語意上 ArrayBuffer 就只是一個陣列。但是要存取內容,必須經由unit8array 或 unit16array 。 這也是為甚麼後綴buffer的原因。

    例如,如果ArrayBuffer 是一個16位元的unsigned 整數,那麼我們可以利用 Uint16Array 來解釋裡面的數字,並且利用[]存取:

    假定 buf 的內容以如下的 bytes [0x02, 0x01, 0x03, 0x07](注意, multibyte 的值會根據CPU而不同,例如在X86中為little-endian )

    var bufView = new Uint16Array(buf);
    if (bufView[0]===258) {   // 258 === 0x0102
      console.log("ok");
    }
    bufView[0] = 255;    // buf now contains the bytes [0xFF, 0x00, 0x03, 0x07]
    bufView[0] = 0xff05; // buf now contains the bytes [0x05, 0xFF, 0x03, 0x07]
    bufView[1] = 0x0210; // buf now contains the bytes [0x05, 0xFF, 0x10, 0x02]