2013-02-13 51 views
1

我有點Javascript運行在Android平板電腦上,運行Opera Mobile 12。平板電腦被連接到辦公室的牆上,所以在辦公室工作的每個人都使用它作爲計時系統(即他們使用它來計時/不工作)。當某個事件發生時,這個JavaScript會爲用戶拍照,然後將這張照片轉換爲數據URL,以便將其發送到服務器。這一切都在後臺運行,但 - videocanvas元素都設置爲display:none;上下文drawImage/canvas toDataURL在歌劇手機上顯着滯後

下面是處理網絡攝像頭交互代碼:

var Webcam = function() { 
    var video = document.getElementById('video'); 
    var stream_webcam = function(stream) { 
    video.addEventListener('loadedmetadata', function(){ 
     video.play(); 
    }, false); 
    video.src = window.URL.createObjectURL(stream); 
    } 

    // start recording 
    if (navigator.getUserMedia) 
    navigator.getUserMedia({video: true}, stream_webcam); 
    else 
    _error("No navigator.getUserMedia support detected!"); 

    var w = {}; 

    w.snap = function(callback) { 
    var canvas = document.getElementById('canvas'); 
    canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height); 
    // delay is incurred in writing to canvas on opera mobile 
    setTimeout(function() { 
     callback(canvas.toDataURL()); 
    }, 1); 
    }; 

    return w; 
} 

w.snap(callback)當用戶按下某個按鈕被調用。問題是在調用drawImage和實際繪製到畫布上的圖像之間存在顯着的延遲。 下面是發生問題:

  • 用戶1個用戶的平板電腦,按下按鈕,有他們的照片「啪」,併發送到服務器。服務器收到一張空白的透明圖像。 (它與html5 canvas toDataURL returns blank image不同 - 第一張圖像發送到服務器的數據量大大減少,因爲它是空白的)
  • 幾分鐘後,用戶2使用平板電腦並按下按鈕,並將其照片「啪」。服務器接收用戶的照片1.
  • 後來,用戶3做同樣的事情,和服務器得到的用戶的照片,2

所以我猜調用toDataURL()將返回舊數據因爲drawImage()沒有。 (我讀的地方,它是異步的,但我無法證實,並不能找到一個事件附加當它完成繪製的任何方式)

我已經試過:

  • 改變超時在snap()到各種值。我試過的最高是2000年,但同樣的問題發生。 (如果有人提出更高的數字,我很樂意嘗試,但我不想高得多,因爲如果我太高,用戶3有可能在我處理用戶2之前拍攝他們的照片照片,這意味着我可能會完全失去它!)
  • 當頁面第一次加載時,畫布繪製了一些東西,但沒有修復它 - 當用戶1被拍攝時,服務器接收到頁面加載時拍攝的任何照片,而不是用戶1的照片。
  • 在調用toDataURL之前,再次使用getElementById「獲取」畫布元素。

一些更多的注意事項:

  • 這工作我在Chrome和Opera電腦(MacBook Air的)上的罰款。
  • 我無法可靠地使用調試器複製它(使用Opera Dragonfly鏈接到平板電腦)。
  • AFAIK Opera Mobile是唯一支持getUserMedia的Android瀏覽器,因此可以拍照。
  • 如果我從videocanvas中刪除display:none;,它可以正常工作(在平板電腦上)。 僅當視頻和畫布已設置display:none;時纔會出現此問題。

因爲頁是一個單頁的應用程式無需滾動或縮放,一個可能的解決方法是將下面的頁面摺疊視頻和帆布,然後禁用與JavaScript滾動(即滾動到頂部每當用戶滾動)。

但是如果可能的話,我寧願採取適當的解決方案而不是解決方法!

回答

4

我沒有一個很好的解決方案,但我建議不要通過將dom設置爲不可見來處理隱形畫布。

而不是

var canvas = document.getElementById('canvas'); 

嘗試

var canvas = document.createElement('canvas'); 
canvas.width = video.width; 
canvas.height = video.height; 
canvas.getContext('2d').drawImage(video, 0, 0) 

這種方式是從DOM分開。

而且爲什麼不使用

canvas.toDataURL("image/jpg")? 

編輯:另外,如果你在設計它,你有沒有嘗試過其他瀏覽器了嗎?有什麼限制您通過其他可用的瀏覽器或使用phonegap的Opera?編輯2:思考它,帆布還有兩個其他的選項,讓你的照片到位,你想看看兩個。這兩個之中:

var imgData = canvas.getContext('2d').getImageData(0,0,canvas.width,canvas.height); 

- 或 -

canvas.getContext('2d').putImageData(imgData,0,0); 

這兩個忽略任何縮放你對我所做的上下文,但我發現,他們更直接和常增快。它們是toDataURL和drawImage的可靠替代品,但是您輸入並從中獲取的圖像數據以下列格式編碼爲數組:

[r1,b1,g1,a1,r2,b2,g2,a2 .. ..]

你能爲他們在這裏找到文檔:

http://www.w3schools.com/tags/canvas_putimagedata.asp http://www.w3schools.com/tags/canvas_getimagedata.asp

+0

Opera的Android手機上的瀏覽器只支持'getUserMedia',這就是爲什麼它被使用。出於商業原因,不能使用Phonegap。 – 2013-02-25 11:58:17

+0

感謝您的建議,但會給他們一個鏡頭。 – 2013-02-25 12:28:50

+0

只是想知道,它工作? – 2013-03-03 23:01:11

2

一些版本的Android有toDataUrl();問題,也許這就是解決方案?

http://code.google.com/p/todataurl-png-js/wiki/FirstSteps

腳本:http://todataurl-png-js.googlecode.com/svn/trunk/todataurl.js

head粘貼此:

<script src="todataurl.js"></script> 
+0

謝謝,我會研究它。它似乎更傾向於默認的Android瀏覽器;我正在使用Opera。 – 2013-05-09 22:02:10

+0

這看起來不錯。如果你稍微修改一下代碼,你可以在Web Worker中創建數據管理而不掛上主UI線程。可轉移對象允許將畫布圖像數據超快速傳輸給工作人員。內部工作者可以更高效地將數據壓縮應用於IDAT塊的PNG,使用例如。快速zlib端口https://github.com/nodeca/pako/。使用https://github.com/SheetJS/js-crc32可以高效地創建crc32。編輯:但是,我不知道如何支持目標移動瀏覽器的工作人員和可轉移的。 – 2015-09-07 20:36:34