HTML5 之先縮圖再上傳

This content is over 13 years old. It may be obsolete and may not reflect the current opinion of the author.


為了要實現「使用者選了檔案,先用 canvas 縮圖然後當做檔案上傳」這個 idea,後來又花了一點時間把HTML5 檔案上傳改了一下。如果聽過或是看過之前的投影片就知道之前的程式碼分成三步驟:

  1. 讀檔案
  2. 組合 multipart/form-data
  3. 上傳檔案

而要實做縮圖則是加上了步驟 1.5:

  1. 把檔案轉換成 data: URL
  2. 用 <img> 載入
  3. 把圖貼進 <canvas>
  4. 把 <canvas> 的資料讀出來

然後就可以送到步驟 2 了。但是我試了半天,發現還是只能讓 Firefox 用;因為 Firefox 3 以上可以接受且上傳 binary string 組出來的 multipart/form-data;如果是 Firefox 4 (> 20100917; beta7pre) 的話,還可以用 canvas.mozGetAsFile 直接產生在硬碟裡不存在的 File 物件,送進 FormData。

Webkit 因為上述兩種做法都不存在所以行不通。直接把 binary string 送去 xhr.send() 在 Chrome 6 會錯誤,在 Chrome 7 會把字串當成 UTF-8 轉碼再傳,整個破壞掉。Google 之後發現了 BlobBuilder 和 xhr.send(blob) 這些標準 binary data 處理方式,但是試了之後還是沒有把 binary string 正確轉換成 Blob 的方法;字串一樣會被當成 UTF-8;指定 byte code 轉換成 blob 所需的 ArrayBuffer 物件瀏覽器還沒實做。

最後自暴自棄了試了一些 hack 的方法:因為 Blob 可以切割,故只要想辦法把某個長度為 255 bytes 的 ascii.bin 轉成 Blob,就可以拿來拼湊任何資料。XMLHttpRequest level 2 有定義 responseBlob,不過試了才發現瀏覽器沒實做。FileReader 和 File 物件的 hack 變成要要求使用者下載某個檔案再選。UTF-8 無法用到所有的 byte 位置,所以不能拿來湊有所有 byte 碼位的 blob。

所以啦,感想就是如果瀏覽器要實做 HTML5 要把所有功能都實做完呀,不然要做的事情拼不出來。

關於 Blob 無法表現任意資料的問題,這邊有一篇抱怨

Update: 後來發現 ArrayBuffer 在 Chrome 9 (dev) 和 Firefox 有實做,所以還是把功能加上去了。就看 Chrome 9 什麼時候變正式版?