分享一个Chrome插件 滚动截屏功能

paullooo 2024-09-01 10:33:01 阅读 58

引言

在当今信息时代,我们经常需要保存和分享网页内容。然而,传统的截图工具往往只能捕捉可见区域,无法完整保存长页面。本文将介绍如何开发一个Chrome扩展来实现网页的滚动截图功能,让您轻松捕获整个网页内容。

背景

在上周分享了chrome插件倒计时功能后,我在一次面试中发现准备的"八股文"知识没有用上。这促使我思考如何更好地分享有用的信息。虽然习惯使用微信的截屏功能,但它只能局部截屏或当前屏幕截屏,无法截取整个页面。因此,开发一个滚动截屏功能成为了我的下一个项目。

市场调研

首先,我浏览了Chrome应用商店,发现了一个名为Awesome Screenshot的应用。它提供了强大的截图和编辑功能,为我们的项目提供了很好的参考。

在这里插入图片描述

技术原理

在ChatGPT的协助下,我了解了滚动截屏的基本原理:

使用<code>chrome.tabs.captureVisibleTab API截取当前窗口图片滚动到下一屏并重复截图过程使用Canvas将所有截取的图片拼接成一张完整的长图

这个过程看似简单,但实际实现中遇到了不少挑战。

在这里插入图片描述

开发过程

项目搭建

我使用了之前的Plasmo框架快速搭建了一个简易版本的Chrome扩展。

在这里插入图片描述

主要挑战

开发过程中主要遇到以下困难:

Content、Background和Popup脚本之间的数据传递功能在不同脚本块中的合理分配Chrome API的使用限制(如在Content脚本中无法使用<code>chrome.downloads)使用Storage传递数据时遇到的容量限制(解决方案:使用area:"local")

核心代码实现

以下是一些关键代码片段:

Popup脚本触发Content脚本中的截图功能:

const tabs = await chrome.tabs.query({ -- -->

active: true,

currentWindow: true

})

const tabId = tabs[0].id

chrome.tabs.sendMessage(tabId, { action: "captureFullPage", tabId }, (response) => {

if (chrome.runtime.lastError || !response) {

console.log("Failed to get page info.")

} else {

console.log('captureFullPage cb: ', response)

}

})

Content脚本中实现滚动截图:

while (totalHeight < height) {

window.scrollTo(0, totalHeight)

if (totalHeight > 0) {

removeFixedAndStickyElements() // 移除固定和粘性元素

}

await sleep(600)

const { screenshotUrl } = await sendToBackground({

name: "capture",

body: { }

})

const compressedDataUrl = await compressImage(screenshotUrl, 0.6, 0.8)

screenShorts.push({

dataUrl: compressedDataUrl,

y: totalHeight

})

totalHeight += windowHeight

}

使用Canvas拼接图片(这是最具挑战性的部分):

const canvas = document.createElement("canvas")

canvas.width = images[0].img.width

canvas.height = totalHeightCanvas

const ctx = canvas.getContext("2d")

let currentY = 0

images.forEach(({ img, y }, index) => {

const sourceY = index === images.length - 1 ? height - y : 0

const imgHeight = index === images.length - 1

? img.height + (windowHeight - (height - y))

: img.height

const destY = currentY

currentY += imgHeight

ctx.drawImage(

img,

0,

sourceY,

img.width,

imgHeight,

0,

destY,

img.width,

imgHeight

)

})

遇到的问题和解决方案

固定元素和粘性元素的处理:

为避免这些元素在每一屏中重复出现,我们尝试在滚动时临时隐藏它们:

function removeFixedAndStickyElements() {

const fixedElements = [...document.querySelectorAll("*")].filter(

(el) =>

getComputedStyle(el).position === "fixed" ||

getComputedStyle(el).position === "sticky"

)

fixedElements.forEach((el) => {

hiddenElements.push({

element: el,

originalVisibility: el.style.visibility

})

el.style.visibility = "hidden"

})

}

图片拼接:

最后一屏的高度和拼接起始位置需要特殊处理,这部分耗费了大量时间进行调试。

在这里插入图片描述

已实现功能

滚动截屏 跳转tabs页面展示图片

待实现功能

滚动区域检测(支持局部滚动区域的截取) 优化浮动元素处理,截图完成后恢复页面状态 改进popup界面设计 添加滚动截屏进度条 实现图片压缩保存,使用IndexedDB缓存链接记录

经验总结

Chrome扩展开发中,了解不同脚本(Content、Background、Popup)的职责和限制非常重要。处理大量图片数据时,需要考虑性能和内存问题,适当使用压缩和异步处理。对于复杂的UI操作(如滚动截屏),需要考虑各种边界情况和特殊元素的处理。

结论

开发这个滚动截图Chrome扩展是一次有趣而富有挑战性的经历。虽然还有改进空间,但它已经能够满足基本的长页面截图需求。我们期待在未来的版本中加入更多功能,提升用户体验。

开源地址

欢迎访问项目源码并提供宝贵意见:

https://github.com/paulloo/chromePlugin_screenshot

感谢Awesome Screenshot为本项目提供了实现思路和界面参考。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。