簡單的網頁截圖功能 - DOM to Image
本篇要解決的問題
去年九月時,August 有寫了一篇〈簡單的網頁截圖功能 – html2canvas、Canvas2image〉,當時寫完後,以為這就是前端在網頁截圖這塊的終極套件(咦?)。結果最近工作上真的要使用這套截圖、下載的功能時,才發現真實的情形下,因為網頁會比 Demo 中的複雜,所以存下來的圖,圖片裡的網頁有些部份是跑版的!
傻眼,還得另外調一版 CSS 給截圖狀態下的網頁,多耗了一點時間。
最近又有另一個案子要使用截圖並下載的功能,發現一樣會有跑版的情形,August 眉頭一皺,覺得案情並不單純,所以就問了 ChatGPT 看有沒有替代的工具,對話如下圖:
立刻試了一下裡面提到的 dom-to-image,發現不會跑版耶,而且下載下來的圖片,檔案大小少很多。
但中間過程中還是有踩到坑,就決定為這個套件再寫一篇截圖的功能,讓大家要使用時可以拿來當速成避坑指南。
本篇最後有一個彩蛋,是關於最近被生成式 AI 給影響的部份,可以看到最後喔。
本篇最後完成的 Demo:
https://letswritetw.github.io/letswrite-dom-to-image/
安裝 DOM to Image
DOM to Image:https://github.com/tsayen/dom-to-image
安裝方式就跟一般要使用 JavaScript 的套件一樣,可以直接 CDN 引用或是用 npm package。
CDN
<script src="https://cdnjs.cloudflare.com/ajax/libs/dom-to-image/2.6.0/dom-to-image.min.js"></script>
npm package
先安裝 package:
$ npm install dom-to-image 或 $ yarn add dom-to-image
JS 中 import:
import domtoimage from 'dom-to-image';
使用 Dom to Image
DOM to Image 可以指定存成 JPEG、PNG、SVG。
SVG 因為 August 沒實際上用到,這邊就不會使用。
以下示範存成 PNG 的圖檔。
// 抓取指定的 div,產生 base64 格式圖片 // 之所以重複二次,下一段的注意事項會解釋 const el = document.getElementById('xxx'); const config = { quality: 1, style: { "filter": "grayscale(100%)" } }; const dataUriTemp = await domtoimage.toPng(el, captureConfig).then(dataUrl => dataUrl); const dataUri = await domtoimage.toPng(el, captureConfig).then(dataUrl => dataUrl); // 下載圖片 const link = document.createElement('a'); const filename = 'Demo.png'; link.download = filename; link.href = dataUri; link.click();
如果想存成 JPEG,就是把 toPng 改成 toJpeg,然後檔案的部份副檔名也要記得改成 *.jpeg。
程式碼中的 config 是可傳入的參數,這邊示範的是改 quality、style。
因為 style 寫了 filter: grayscale(100%),所以下載下來的圖片都會變成灰階。
如果是活動性質的頁面,截圖前加上 `style` 會是很有趣的作法。
可用的參數如下:
- filter:可以濾掉指定的 tag。官方文件是用在濾掉 SVG 的 tag。
- bgcolor:指定背景色。
- width、height:指定寬、高。
- style:可以加上額外的 style。
- quality:圖片的品質,數值是 0 - 1,1 為最高,預設是 1。
- cacheBust:要不要清除緩存,true 是要、false 是否,預設是 false。
- imagePlaceholder:如果抓不到 div 的圖片,要給什麼墊檔圖,看文件是要填 Base64。
注意事項
以下是 August 踩了一上午的坑後,終於發現在手機操作時有 2 個要注意的地方,不注意的話會讓 Dom-to-Image 產生的圖檔,div 中的圖片變一片空白:
- 圖片有 position: relative。
- 執行 domtoimage.toJpeg(targetId, [config]) 時,第一次圖片的地方會是空白,但第二次以後就會正常,所以……雖然很蠢,但為了維持手機世界的和平,請執行二次,這就是為什麼範例程式碼會先寫一次 dataUriTemp,接著又寫了一次 dataUri。
另外,還有一種情形會讓下載的圖片不完整,就是抓取的 div 本身有寫 max-width: xxx; margin: 0 auto;,寫了 max-width,會讓 DOM to Image 在抓圖時寫上限定的寬,但因為抓圖不會跟著置中,就變成抓下來的位置會從最左邊開始,造成抓下來的圖右邊會被裁切掉。
本篇 Demo 及原始碼
本篇的程式碼有放上 GitHub 上,也用 GitHub Pages 產生了 Demo,請自行取用,但希望在取用前能分享本篇,或在 GitHub 上點個星星,你的一個小小動作對本站都是大大的鼓勵。
原始碼:https://github.com/letswritetw/letswrite-dom-to-image
Demo:https://letswritetw.github.io/letswrite-dom-to-image/
Notion AI 生成的文章
其實在開始要寫這篇時,August 就被生成式 AI 驚呆了。
August 前幾天才通過 Notion 加上 AI 的功能申請,所以當今天打開 Notion,才打完本篇的標題後,就跳出一個「Ask AI to write」的選項,好奇了按了一下……AI 就把本篇幾百字關於 DOM to Image 的介紹及應用文章寫完了,雖然給的是英文。
好啊,都給 AI 寫就好啊~~~
其實在開始用了 ChatGPT 後,就在想是不是還要繼續堅持寫學習的筆記文?
因為未來大家會愈來愈來常先問 AI,問不到才 Google。
那,即便堅持寫,也是寫給 AI 拿去學習用的吧?來網站的人,真實的人類會愈來愈少。
這樣,還有經營的必要嗎?現在除了「之後面試時可以當作品集」的理由,想不到其它繼續寫下去的理由了。
Anyway,以下是 Notion AI 所編寫的文章,有經過 August 修改,把文字從英文轉成中文,並調整了詞句。
大家可以對比一下上面幾段出自 August 的真人文字,跟下面幾段 AI 所生成的文字,未來 August 撰文,為了省時間跟心力,會陸續使用 AI 提供的文字了。
DOM to Image 是一個非常有用的工具,用於建立網頁的螢幕截圖。它允許用戶通過點擊一個按鈕快速輕鬆地抓取網頁的快照然後保存,可以共享結果給朋友或同事。
本篇筆記文將提供一個使用 DOM to Image 建立一個簡單的網頁截圖功能的簡單教學。
第一步是在 HTML 頁面中引用 DOM to Image 的 JS。這可以在 HTML 引用 CDN 來快速輕鬆完成:
<script src="https://unpkg.com/[email protected]/dist/dom-to-image.min.js"></script>
引用了 CDN 後,還需要建立一個函數,這個函數可以讓我們抓取螢幕截圖。
此函數接受 HTML 元素作為參數,並返回一個解析為圖像的 Promise。
以下是使用 domtoimage.toPng() 的方法完成的:
function captureScreenshot(element) { return new Promise((resolve, reject) => { domtoimage.toPng(element) .then((dataUrl) => { resolve(dataUrl); }) .catch((error) => { reject(error); }); }); }
建立函數後,執行函數便可從 HTML 中輕鬆獲取螢幕截圖:
captureScreenshot(document.getElementById('element-id'));
這是這樣!只需幾行代碼,您現在就可以使用強大的 DOM to Image 建立一個簡單的網頁截圖功能。
當我們需要快速抓取網頁的螢幕截圖時,此明件可以節省時間和麻煩,對於任何使用網頁的人來說,它都是一個不可多得的工具。