更新於 2023/11/07閱讀時間約 9 分鐘

簡單的網頁截圖功能 – DOM to Image

本篇要解決的問題

去年九月時,August 有寫了一篇〈簡單的網頁截圖功能 – html2canvas、Canvas2image〉,當時寫完後,以為這就是前端在網頁截圖這塊的終極套件(咦?)。結果最近工作上真的要使用這套截圖、下載的功能時,才發現真實的情形下,因為網頁會比 Demo 中的複雜,所以存下來的圖,圖片裡的網頁有些部份是跑版的!
傻眼,還得另外調一版 CSS 給截圖狀態下的網頁,多耗了一點時間。
最近又有另一個案子要使用截圖並下載的功能,發現一樣會有跑版的情形,August 眉頭一皺,覺得案情並不單純,所以就問了 ChatGPT 看有沒有替代的工具,對話如下圖:
ChatGPT 提供網頁截圖的套件
ChatGPT 提供網頁截圖的套件
立刻試了一下裡面提到的 dom-to-image,發現不會跑版耶,而且下載下來的圖片,檔案大小少很多。
但中間過程中還是有踩到坑,就決定為這個套件再寫一篇截圖的功能,讓大家要使用時可以拿來當速成避坑指南。
本篇最後有一個彩蛋,是關於最近被生成式 AI 給影響的部份,可以看到最後喔。
本篇最後完成的 Demo:

安裝 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 上點個星星,你的一個小小動作對本站都是大大的鼓勵。

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/dom-to-image@2.6.0/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 建立一個簡單的網頁截圖功能。
當我們需要快速抓取網頁的螢幕截圖時,此明件可以節省時間和麻煩,對於任何使用網頁的人來說,它都是一個不可多得的工具。
分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.