雲計算

H5分享截圖方案優化

作者:閒魚技術-苑振一

背景

分享是傳播活動,吸引用戶最重要的一環。現有分享手段多是題目配合單張圖片,利用點擊的方式跳轉到目標頁面。在信息越來越豐富的今天,單個題目和圖片對用戶的吸引力是有限的。而在對推廣要求更高的營銷場景和裂變過程中,我們往往需要將頁面內容一部分作為圖片整體分享出去。直接利用手機原生的截屏功能會有幾個問題:1)內容格式無法自定義。2)翻頁情況無法處理。3)視窗區域不可控。本文通過討論現有截屏的方案和閒魚內部截屏方案,介紹如何利用web實現移動端高還原度富圖文分享。

現有方案

Html2Canvas

介紹

html2canvas是一種基於canvas,將DOM結構繪製在canvas上面產生圖片的第三方庫。通過如下的方式可以將對應的DOM結構繪製成圖片保存出來。優勢在於上手簡單,使用方便。
20200721115513.jpg

繪製原理

原理如下圖所示。核心邏輯是克隆對應節點DOM結構,利用parse解析成數據,構建canvas進行內容繪製,返回對應的canvas。
20200715205138.jpg

實際使用過程中發現大概有如下幾個問題
  1. 圖片跨域不支持。生成的圖片存在跨域限制問題。
  2. 繪製清晰度低。即使使用apiscale放大後繪製,又會由於生成base64格式圖片內容過長導致無法傳輸。
  3. 圓弧計算精度低。由於html2canvas是計算像素後繪製到canvas上,而canvas展示又會經過瀏覽器繪製,導致像素精度降低。
  4. 深度節點出現黑色情況。由於DOM結構過深,經過像素計算後,會偶爾出現像素丟失情況。

SVG

介紹

該方案是利用svg可以包裹DOM結構的特性,將對應目標裝載進去,之後將svg導出成base64格式的圖片。使用方式如下。通過xmlns指定命名空間,防止多集合下元素和屬性的衝突。後綴中的svgxhtml分別表示解析方式。利用不同的解析方式,實現了svg內部嵌入html的方式。
20200721115524.jpg
之後只要通過encodeURIComponent(svg)將對應的svg轉換成base64就可以。優勢是容易上手且不依賴第三方庫。

實際使用過程中發現大概有如下幾個問題
  1. SVG無法連接到外部的資源。比如通過cdn引入的css以及html中的圖片連接都會被限制。
  2. 不支持js執行。現如今SPA頁面都需要執行JS後才會渲染對應的DOM節點,而SVG卻不支持JS的執行。
  3. SVG位置和大小不確定。遇到需要及時展示的情況,需要實時計算位置才行。

解決方案

思路

從上面可以看到,現有的兩種主流移動端截屏方案都有自己的不足。相比之下,利用canvas繪製的方法更適合SPA應用。那麼我們需要解決的是html2canvas對應的幾個問題:圖片跨域清晰度低圓弧計算精度差深層節點解析出錯。

圖片跨域

通過new Image()的方式生成圖片,在image.onload階段使用canvas繪製圖片。此時會產生跨域限制,需要通過crossOrigin = 'Anonymous'設置來解決這個問題。
20200721115534.jpg

提高清晰度

在繪製中發現,如果採用寬度375px的canvas將圖片導出,會出現圖片模糊的情況。一種方案是提高原圖片清晰度,但是加載速度會大大提高,用戶體驗不友好。另一種方式是放大canvas,利用drawImage中的參數控制圖片座標和canvas中的繪製座標。drawImage中包含幾個參數:控制圖片的sx, sy, sWidth, sHeight和控制canvas繪製的x, y, width, height。參數具體含義如圖中所示。
1.jpg
將方法中width和height乘上ratio,放大圖片,控制繪製座標,就能在canvas特定位置上繪製出想要的內容。考慮到小canvas在展示階段清晰度足夠,僅保存階段需要放大三倍繪製的特性,採用第二種方法在幾乎沒有提高性能開銷的前提下,提高清晰度。我們以實際繪製截圖來看一下效果。下圖左邊是一倍結果,右圖是三倍結果。
20200714092948.jpg

圓弧精度提升和深層DOM解析

圓弧精度低和深層DOM解析出錯問題本質上還是由於DOM結構過於複雜,當採用通用方案處理時,難免無法覆蓋。考慮到移動端內容有限,結構簡單的特點。決定採用特定DOM節點針對性繪製的方案解決深層DOM解析出錯的問題。好處如下:1)方法原子化,維護簡單。2)繪製高度自定義化,自由組織界面結構。3)拓展性強。在同事胖仔的幫助下實現特定DOM節點繪製方案。方案構建過程中主要有如下幾個難點:圓角矩形文字自動換行

  • 圓角矩形:通過截斷的方式繪製特定背景的圓角矩形。原理是通過createPattern的方式在canvas上獲取圖片內容,再利用Path的方式,繪製對應的路線,利用canvas.arc繪製圓弧部分,利用canvas.lineTo繪製直線部分,截取想要的內容,實現圓角矩形。

    1. 圖片內容獲取。

      `context.createPattern(imgUrl, "no-repeat")`
    2. 圓角矩形區域繪製

      ![20200721115559.jpg](https://intranetproxy.alipay.com/skylark/lark/0/2020/jpeg/288128/1595303835739-f4f3bea5-562a-472a-9f45-f4599ed74997.jpeg) 
    3. 繪製內容

      ![20200721115612.jpg](https://intranetproxy.alipay.com/skylark/lark/0/2020/jpeg/288128/1595303848154-c0c9fe64-b092-47c5-b82c-20d6c10c5417.jpeg) 
  • 文本自動換行:思路是通過measureText獲得當前文本寬度,每次添加一個字,比對此時文本寬度和行寬,超過時候繪製當前行,進行換行,y增加行高,重複這個過程。
    20200721115630.jpg

效果

  • 實現了一套移動端截屏方法。解決了現有第三方庫html2canvas繪製清晰度低,圓弧計算精度低,深層DOM解析出錯的問題。
  • 採用原子化實現方法。支持截屏自定義繪製,而不是如html2canvas和svg只能通過複數次繪製不同DOM節點,來拼湊目標的方式。

總結

在互聯網時代,尤其是5G馬上要來臨的今天。傳統的分享模式,標題+單圖片,逐漸難以滿足越來越豐富的活動宣傳要求。而流量的廉價化和短視頻火熱的時下,富圖文傳播無疑能傳遞更多的信息。目前我們已經實現了基本DOM節點繪製方案,並在站內活動中使用富圖文分享。相信在不久的將來,我們能夠利用移動端截屏分享功能幫助更多閒魚用戶高效率分享內容,讓用戶樂在閒魚,玩在閒魚。

Leave a Reply

Your email address will not be published. Required fields are marked *