Chrome / Edge 的 Manifest V3 擴充功能,把整頁網頁擷取成一張長圖或一份 PDF。
純本機執行,零執行期依賴,無建置步驟。
| 模式 | 說明 |
|---|---|
| 整頁 | 從頁面頂端捲動到底部,逐幀拼接成一張長圖 |
| 可視 | 只擷取目前視窗可見的區域,不捲動 |
| 框選 | 在頁面上拖曳出矩形範圍,可跨越多個視窗高度 |
| 元素 | 選取單一元素並擷取,包含高於視窗的元素 |
| 手動 | 由使用者自行捲動,擴充功能以固定間隔取樣拼接 |
- PNG — 無損。抓幀時同樣使用 PNG,不做二次壓縮。
- JPEG / WebP — 品質可調(30–100)。抓幀時即壓縮,記憶體用量較低。
- PDF — 紙張 A4 / A3 / Letter / Legal / Tabloid,直式或橫式,頁邊距 0–144pt。
PDF 分頁方式:
- 依紙寬縮放後分頁(預設)
- 單頁長圖(超過 PDF 單頁 14400pt 上限時自動改為分頁)
- 整張縮進一頁
| 選項 | 說明 |
|---|---|
| 隱藏固定元素 | 擷取時隱藏 position: fixed / sticky 元素 |
| 隱藏捲軸 | 擷取時隱藏頁面捲軸 |
| 等待懶擷載入 | 頁面高度變動時延長等待 |
| 每屏等待 | 每幀之間的等待時間(0–1200ms) |
| 起始延遲 | 開始擷取前的延遲(0–60000ms) |
| 頁面高度上限 | 超過此高度的內容不擷取(1000–1000000px) |
| 抓幀格式 | 自動 / PNG / JPEG |
| 重試次數 | 單幀擷取失敗的重試上限 |
| 檔名模板 | 支援 {date} {time} {datetime} {host} {title} {mode} {format} {width} {height} {index} |
| 下載子資料夾 | 指定檔案存放的相對路徑 |
| 完成後開啟結果頁 | 擷取完成後開啟預覽頁 |
| 保留歷史筆數 | 本機歷史紀錄的上限 |
- 測試滾動 — 對目前頁面執行一次完整捲動(至底部再返回原位),回報可捲動性判定結果。
- 複製診斷 — 輸出目前頁面的量測資料與判定結果文字。
- 常駐顯示 — 捲動方式、頁面高度上限、內容高度(
document/body/ 視口)。
可捲動性判定分為五類:可捲動、有可捲動範圍但實際無法捲動、非原生捲動、頁面僅一屏、PDF 檢視器。
- 預覽產出的圖片或 PDF
- 拖曳裁剪並另存為 PNG
- 轉存為 PNG / JPEG / WebP
- 存放於瀏覽器本機 IndexedDB
- 可設定保留筆數、可清空
- 右鍵選單 — 整頁 / 可視區域 / 框選範圍 / 點選元素
- 鍵盤快捷鍵 —
Alt+Shift+S開啟面板,Alt+Shift+F直接擷取整頁(可於chrome://extensions/shortcuts修改) - 介面語言 — 簡體中文 / 繁體中文 / 英文(跟隨瀏覽器語言)
- 下載
snapscroll-1.0.0.zip並解壓縮 - 開啟
chrome://extensions(Edge 為edge://extensions) - 開啟右上角「開發人員模式」
- 點「載入未封裝項目」,選擇解壓縮後的資料夾
git clone https://github.com/just-lum/snapscroll.git
cd snapscroll
node tools/make-icons.mjs圖示由程式碼生成,需先執行一次。接著依上述步驟 2–4 載入該資料夾。
- 開啟任意網頁
- 點擊工具列上的 SnapScroll 圖示
- 選擇擷取模式與輸出格式
- 點「開始擷取」
擷取期間頁面底部會顯示進度條(可於選項中關閉),工具列圖示同時顯示進度百分比。
只申請 activeTab。擴充功能在使用者點擊圖示時,才取得當前分頁的臨時存取權;安裝時不取得任何網站的存取權。
| 權限 | 用途 |
|---|---|
activeTab |
存取使用者當前操作的分頁 |
scripting |
注入頁面代理腳本 |
downloads |
儲存產出的檔案 |
storage |
儲存設定 |
offscreen |
影像拼接與編碼 |
contextMenus |
右鍵選單 |
engine/ 純函式模組(UMD):捲動計劃、座標換算、PDF 分頁與生成、
檔名處理、畫布上限、可捲動性判定
background/ Service worker(classic worker + importScripts)、擷取控制器、下載
injected/ 注入頁面的代理:量測、捲動、進度條、框選與元素拾取
offscreen/ Offscreen document:畫布拼接、編碼、PDF 組裝
ui/ popup / options / result 三個頁面
同一份 engine/ 模組同時被 Node 測試(require)、service worker(importScripts)與擴充頁面(<script>)載入,無建置步驟。
- 注入頁面代理,量測視窗與文件尺寸
- 探測頁面的捲動機制(實際捲動 1 像素後復位)
- 預先捲動至底部再回到頂端(可選),使延遲載入內容就位
- 逐幀捲動、擷取,送至 offscreen document 拼接
- 編碼,並透過 downloads API 儲存
每一幀比對「要求捲動位置」與「實際捲動位置」;連續兩幀沒有位移時中止並回報錯誤。
頁面的捲動可能由不同元素驅動。擴充功能依序實測 window、頁面內可捲動容器、body,並於每次捲動後驗證位置是否如預期;若某種方式無效則切換下一種。捲動方式一經確定,讀取位置、計算範圍與下達指令皆依該方式執行。
拼接採用分段畫布:輸出按 y 軸切分為多條,逐幀繪入相交的分段,分段填滿後編碼並釋放。記憶體用量取決於單一分段的高度,而非整張圖的高度。
PDF 輸出時分段高度等於頁面高度,每頁僅進行一次 JPEG 編碼,並以 /DCTDecode 直接嵌入 PDF,無二次解碼。
engine/pdf-writer.js 產生 PDF 物件表與 xref 表。位元組偏移以實際寫入長度計算;非 ASCII 字串以 UTF-16BE 十六進位字串編碼。產出後執行結構自檢(檢查 xref 偏移是否指向對應物件)。
擷取期間對頁面的變更皆記錄於還原清單,結束後(含失敗與取消)復原:固定元素的可見性、捲軸樣式、注入的樣式表、以及使用者原本的捲動位置。
- 虛擬捲動清單 — 僅存在於 DOM 的可見項目可被擷取,此類清單無法取得完整內容。可使用「手動」模式。
- 跨網域 iframe — 內容會出現在擷取結果中(畫面合成),但無法驅動其內部捲動。
- 擷取頻率限制 —
chrome.tabs.captureVisibleTab有呼叫頻率上限。「手動」模式的取樣間隔約 500ms。 - 畫布尺寸上限 — 超過上限時,PNG / JPEG / WebP 會輸出為多個檔案(
_part-01、_part-02…)。PDF 不受影響。 - 受限頁面 —
chrome://、擴充功能頁面與file://無法擷取。 - PDF 檢視器 — 內容由瀏覽器外掛繪製,不在 DOM 中,無法捲動擷取。可改用「可視」模式。
- 非原生捲動 — 以
transform或 canvas 驅動捲動的頁面,原生捲動 API 無法取得後續內容。 - 擷取期間請勿切換分頁 —
captureVisibleTab只能擷取視窗目前顯示的分頁。
node --test # 單元測試(136 項)
node tools/make-icons.mjs # 從程式碼生成圖示
node tools/package.mjs # 打包為 dist/snapscroll-<version>.zip
node tools/serve-fixtures.mjs --open # 測試頁伺服器(http://127.0.0.1:8788)
node tools/e2e/run.mjs # 端對端測試(需 Playwright)fixtures/ 包含各類測試頁面:
long-page.html— 20000px 長頁面,每 100px 一條刻度、每 500px 一段編號fixed-header.html— 上/下/右各一個固定元素lazy-images.html— 捲動時才載入內容,頁面高度會變動scroll-body.html/scroll-inner.html/scroll-js-container.html/scroll-hidden-overflow.html— 捲動由body、內層容器或overflow:hidden容器驅動scroll-locked.html— 捲動被腳本接管scroll-transform.html— 以transform驅動的非原生捲動pdf-embed.html— 模擬 PDF 檢視器
tools/e2e/run.mjs 啟動瀏覽器、載入擴充功能、執行實際擷取,並驗證產出檔案。測試時將擴充功能複製至暫存目錄,並在該副本的 manifest 加入 <all_urls> 權限(自動化環境沒有使用者手勢,activeTab 不會生效)。
Playwright 非必要依賴;未安裝時會顯示安裝指令。
MIT