乌市泽哥 发表于 2024-9-1 16:22:48

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

弁言

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

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

首先,我浏览了Chrome应用商店,发现了一个名为Awesome Screenshot的应用。它提供了强大的截图和编辑功能,为我们的项目提供了很好的参考。
https://i-blog.csdnimg.cn/direct/26461de026df4454a3fb0d5737e87b99.png
技术原理

在ChatGPT的帮忙下,我相识了滚动截屏的根本原理:

[*]利用chrome.tabs.captureVisibleTab API截取当前窗口图片
[*]滚动到下一屏并重复截图过程
[*]利用Canvas将所有截取的图片拼接成一张完整的长图
这个过程看似简单,但现实实现中遇到了不少挑战。
https://i-blog.csdnimg.cn/direct/fc7de4af51844333b9a6a87e232b9c2a.png
开发过程

项目搭建

我利用了之前的Plasmo框架快速搭建了一个简易版本的Chrome扩展。
https://i-blog.csdnimg.cn/direct/b053dc872d20483ab2eb5208fc4678b3.png
重要挑战

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

[*]Content、Background和Popup脚本之间的数据通报
[*]功能在不同脚本块中的合理分配
[*]Chrome API的利用限制(如在Content脚本中无法利用chrome.downloads)
[*]利用Storage通报数据时遇到的容量限制(解决方案:利用area:"local")
核心代码实现

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

[*]Popup脚本触发Content脚本中的截图功能:
const tabs = await chrome.tabs.query({
active: true,
currentWindow: true
})
const tabId = tabs.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.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"
})
}

[*]图片拼接:
末了一屏的高度和拼接起始位置需要特殊处理,这部分耗费了大量时间进行调试。
https://i-blog.csdnimg.cn/direct/6ce6e6c39c294b639c360f01f871fe74.gif#pic_center
已实现功能



[*] 滚动截屏
[*] 跳转tabs页面展示图片
待实现功能



[*] 滚动地区检测(支持局部滚动地区的截取)
[*] 优化浮动元素处理,截图完成后规复页面状态
[*] 改进popup界面设计
[*] 添加滚动截屏进度条
[*] 实现图片压缩保存,利用IndexedDB缓存链接记载
经验总结


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

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

接待访问项目源码并提供宝贵意见:
https://github.com/paulloo/chromePlugin_screenshot
感谢Awesome Screenshot为本项目提供了实现思路和界面参考。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 分享一个Chrome插件 滚动截屏功能