之前一直在考慮一個在浏覽器上實作截屏的問題,搜尋了一下了解了些情況。
在初期想到的是如何通過JS把網頁變為圖檔,網上有相應的開源項目,例如https://github.com/niklasvh/html2canvas. 這個元件試了一下在本機上還是有些問題。
除了這個以外,還有一個東西是PhantomJS
PhantomJS is a headless WebKit with JavaScript API. It has fast and native support for various web standards: DOM handling, CSS selector, JSON, Canvas, and SVG.
它本生就能用來做Screen Capture
使用phantomjs存在兩個問題,一是它需要伺服器的支援,而是經我測試中文有問題(我是用它提供的DEMO來測試的,沒有自己裝環境試),而我們想做的事在浏覽器上實作截圖,這些方案都和預先想的有所偏離,關于截屏這個問題也就擱置了一段時間。
前幾天裝了個花瓣的插件,發現它可以網頁裡面實作截屏,研究了一下他壓縮過的代碼,注意到了其中使用到了Chrome擴充開發中使用的方法參與截屏(它實際截屏的代碼沒找到)。
然後又在Chrome擴充開發頁面上找到了一個實作頁面截屏的執行個體screenshot,其中最關鍵的方法就是captureVisibleTab,captureVisibleTab的用法如下:
chrome.tabs.captureVisibleTab(null, function(img) {
// callback of captureVisibleTab,img a string start with data://
var my_img = new Image();
my_img.onload = function(){
// execute after the img was loaded
};
my_img.src = img;
});
上面的代碼中my_img把captureVisibleTab獲得的資料作為自己的src,但是captureVisibleTab隻能截取目前可見區域的圖像。沒法完成整頁截圖,是以我們不得不拼圖。我們血要在截取一塊可視區域以後滾動滾動條到下一塊可視區域再截圖,如此反複。于是我使用了如下流程進行操作:
- 截取第一塊
- background發送消息到内容頁面,通知滾動,滾動完成回調scrollPageDone
- 滾動完成調用scrollPageDone,其中調用截屏
- 截屏完畢繼續滾動,反複
上述流程有一個問題,就是滾動頁面是需要時間的,為了解決這個問題,我在scrollPageDone中使用setTimeout 500ms之後再調用截屏函數。現在我們已經順利的擷取了整頁的很多小塊。是時候把他們拼成完整的頁面截圖了。我的思路是把這些小塊繪制到一塊canvas上,然後把canvas.getDataUrl()擷取的值設定為img.src,如此圖像即可拼裝出來。把此圖像另存為即可得到截圖。下面是拼接圖檔的一段代碼:
my_img.onload = function() {
var ctx = canvas.getContext("2d");
ctx.drawImage(blockImg, 0, 0, width, height, 0, Capturer.yPos, width, height);
Capturer.yPos += Capturer.clientHeight;
self.scrollPage(self.tabId, 0, Capturer.clientHeight);
};
其中的yPos用來記錄圖像從上到下已經拼接了多長,以便接着上次拼完的地方繼續拼接。這裡最關鍵的方法應為:
ctx.drawImage(my_img, 0, 0, width, height,
, Capturer.yPos, width, height);
其方法說明為:
drawImage(image, sourceX, sourceY, sourceWidth, sourceHeight,
destX, destY, destWidth, destHeight)
上面所述基本說明了用chrome擴充實作截屏的基本原理,剩下的就是如何滾動,拼接圖像如何處理邊界塊的問題了。我的代碼在https://github.com/erichua23/prj/tree/master/screenshot