經常在微博上看到很多內容使用的什么長微博截圖,並且截圖上還附加了很多其他的信息。之前對純前端截圖有些研究,正好本博客有這個需求,今天就把這東西實現了下。
需要聲明的是,JavaScript 目前還不能實現網頁截屏,就算以后能夠實現,也一定是瀏覽器提供了相關接口,JS 去調用這些接口。既然不能截屏,那我們能做的只有通過拿到像素點的信息來”拼湊”圖片。
先說說我們看到的截屏方式
用過 phantomJS 的同學都知道,它提供了一個截屏函數,通過它可以整屏獲取頁面截圖,而且他支持的格式也比較多:JPG/PNG/GIF/PDF。通過簡單的兩句命令就可以把一個網頁截取下來:
// render.js var webPage = require('webpage'); var page = webPage.create(); page.viewportSize = { width: 1920, height: 1080 }; page.open("http://www.taobao.com", function start(status) { page.render('taobao_home.jpeg', {format: 'jpeg', quality: '100'}); phantom.exit(); });
安裝 phantomjs 之后執行下上面的文件:
phantomjs render.js
你會發現,一張寬度很窄的淘寶首頁圖就保存到了同目錄下的 taobao_home.jpeg
中。也有同學使用 phantomjs 做了很多有意思的東西,比如每隔 100ms 截圖,然后對比圖像之間的差異,分析網頁的加載情況和性能問題,甚至做網頁的監控。好吧,話題收回來,繼續說說其他的截屏方式,關於 phantomjs 可以移步到官網學習。
前端截屏方案
能夠導出圖片的,目前只有 canvas。頁面上的元素,除了圖片、視音頻、SVG等,其他都是文字,都可以使用 css 樣式變換出來。我們知道,在 canvas 中是可以繪制圖片和文字的,那么問題就很好解決了。
- 遍歷頁面的所有元素,提取DOM數
- 獲取渲染之后的每個 DOM 節點的內聯、外鏈 CSS 屬性
- 將樣式轉換成 canvas 的屬性,利用 offset 等屬性輔助擺放位置,將節點對應到 canvas 上
這個方案比較粗糙,但是對於簡單的頁面,以上操作就能導出一張幾乎與原狀一模一樣的圖片。當然,我們想到的,也有人實現出來了,html2canvas
就是一個關注度很高的 js 截屏庫,它考慮的內容會更多更全面。比如:
我博客左側的微博小圖標,hover 上去有一個微博分享,這里我就使用了這個庫截取博客全文視圖(考慮小屏手機,我把寬度設置成 480,比較窄),其實現是很簡單的:
html2canvas(document.body).then(function(canvas) { canvas.id = 'screenshotCanvas'; document.body.appendChild(canvas); });
此時,頁面的截圖已經 append 到了 body 中。canvas 提供了導出圖片的函數:
var can = documeng.getElementById("screenshotCanvas"); var imgDataURI = can.toDataURL('image/png');
我們也可以將到處的內容轉化成一個 blob 流,這樣就能直接通過 URI 地址來訪問了。
原始需求是將圖片分享出去
無論是 dataURI 還是還是 blob 流,他們都沒辦法當做一個 URL 在網絡上訪問,所以當我使用微博分享(附加圖片分享)的時候,圖片總是拿不到。
var shareUrl = "http://service.weibo.com/share/share.php?appkey=YOUR_APP_KEY&title="
+ title + "&url=" + url + "&searchPic=false&style=simple&pic="
+ picUrl;
這里的 picUrl 必須是一個 http 可請求到的地址,實在是無奈呀,在 coding.net 寫了一個小應用,用來臨時儲存圖片(10分鍾之后刪除上傳圖片),有需要的可以試用下:
JQuery 用戶可以這樣搞:
var fd = new FormData(); fd.append("img", imgBlob); $.ajax({ type: "POST", url: "http://tmpfile.coding.io/img", dataType: 'json', data: fd, crossDomain: true, processData: false, contentType: false, success: function(data){ if(data && data.path) { console.log("http://tmpfile.coding.io/tmp" + data.path); } } });
小結
只要能拿到原始圖,之后的加工處理都是比較簡單的。比如如何實現畫框截取某個區域的圖形,思路就是截取整圖,記住鼠標按下和抬起的兩個點,然后從整圖中摳出來就搞定了。在 QQ 空間發表說說的地方有提供截屏工具,這是因為騰訊在電腦上安裝了插件,並且提供了對應的 JS 接口,JS 是沒有能力直接截屏的。
好吧,了解原理就好,人家有現成的庫可以用,咱們不要動不動就造輪子,不好玩。
引用https://www.barretlee.com/blog/2015/09/24/screenshot-with-javascript/