Screendrop截屏实现揭秘:为什么全屏捕获放弃ScreenCaptureKit回归screencapture CLI
【免费下载链接】ScreendropA beautiful screenshot + screen recording + Loom alternative - all native, self hostable and free.项目地址: https://gitcode.com/gh_mirrors/sc/Screendrop
Screendrop 是一款完全原生的 macOS 截屏与录屏工具,也是免费的 Loom 替代品。最近它的截屏模块做了一个耐人寻味的技术决策:全屏捕获放弃了系统新 API ScreenCaptureKit,回归了最朴素的 screencapture 命令行工具。原因藏在几行注释里——窗口阴影会"消失"。本文带你用 5 分钟看懂这个取舍背后的工程智慧。
一、先认识 Screendrop 的截屏能力
Screendrop 的截屏路径由统一协调器驱动:快捷键(如Option + 1全屏、Option + 3区域)触发后,倒计时、捕获、预览卡片、历史记录入库一条龙走完。
整个流程的调度逻辑在 CaptureCoordinator.swift:全屏捕获先解析当前活动显示器,再交给截屏管理器执行真正的抓取。
captureFullscreen() ├─ 解析当前显示器 displayID ├─ 运行可选的倒计时 ├─ ScreenshotManager.captureFullscreen() ← 本文主角 └─ finishCapture():导入历史 + 弹出预览卡片二、ScreenCaptureKit 的坑:窗口阴影为什么"消失"
按惯例,新写 macOS 截屏工具自然会选 Apple 力推的ScreenCaptureKit(Screendrop 的录屏功能确实在用它,见 ScreenRecordingManager.swift)。但全屏截图用它抓出来的图,细看会发现一个致命缺陷:
窗口与窗口之间的投影(drop shadow)丢了。
原因写在 ScreenshotManager.swift 的注释里:
- ScreenCaptureKit 的显示器捕获是自己重新合成(re-compose)窗口的,它并不直接读取 WindowServer 的最终合成画面;
- 合成过程中,窗口之间那层淡淡的投影被丢掉了;
- 结果是浅色背景上的窗口"贴"在背景上,边缘发白、层次尽失,截图看起来"脏脏的"。
而截图工具的底线是"你屏幕上看到什么,图里就该有什么"。
三、回归 screencapture CLI:用最土的办法抓住真实屏幕
macOS 自带了一个命令行工具/usr/sbin/screencapture,系统自带的"截屏"应用本质上就是它的图形壳。它读取的是 WindowServer 合成的真实屏幕画面,阴影、半透明、动态效果一个不少。
Screendrop 的解法干脆利落:Process拉起 CLI,主线程不阻塞,静默执行(见 ScreenshotManager.swift):
| 参数 | 作用 |
|---|---|
-D <n> | 指定第 n 块显示器(1 为主屏) |
-w | 交互式点选窗口 |
-s | 交互式拖框选区域 |
-o | 窗口捕获时不带阴影(可配置) |
-T <秒> | 选定目标之后再倒计时触发 |
-x | 不播放快门音效(由应用自己控制提示音) |
-t png | 无损 PNG 输出 |
三种捕获模式共享同一个 CLI 执行器,全屏用-D、窗口用-w(captureWindow)、区域用-s(captureArea),行为天然一致——这也是"回归 CLI"的第二重红利:全屏、窗口、区域三条路径的画质完全对齐。
四、细节打磨:显示器映射、刘海黑条与延时快门
回归 CLI 不是"一行了事",几个边角问题被逐一处理:
1. 显示器 ID → 索引映射
screencapture -D用的是 1 基序号,而系统 API 给的是CGDirectDisplayID。screencaptureDisplayIndex 用CGGetActiveDisplayList取出显示器列表(主屏排第一),把 ID 翻译成-D认识的序号,多屏外接显示器也能精确命中。
2. 刘海屏的黑条裁剪
带刘海的 Mac 在隐藏菜单栏全屏时,顶部会留下一条纯黑带子。NotchBarTrimmer 检测并裁掉这条空黑带,非黑色内容则原样放行,且保留原始 DPI 等图片属性(trimEmptyMenuBarIfNeeded)。
3. 延时快门时机
窗口/区域捕获的 3/5/10 秒倒计时,直接复用 CLI 的-T参数——在选定窗口/画完框之后才开始倒数,而不是之前。这个细节连系统"截屏"应用都做得很巧妙,见 performCaptureWindow 的注释。
五、给开发者的 3 点启发
- 新 API ≠ 总是更好:ScreenCaptureKit 适合录屏这类流式场景,但"像素级还原所见"的截图场景,老牌 CLI 反而更对味;
- 系统 CLI 是可以依赖的基础设施:
screencapture随系统分发、参数文档完整、零权限申请,比自研合成管线稳定得多; - 好注释胜过好代码:这个决策的全部理由浓缩在 ScreenshotManager.swift 四行注释里,后来的维护者一眼就懂"为什么不用那个更先进的 API"。
六、动手看完整代码
想深入研究 Screendrop 的截屏实现,可以直接克隆仓库(git clone https://gitcode.com/gh_mirrors/sc/Screendrop),重点文件清单:
- 截屏核心:ScreenshotManager.swift
- 捕获流程调度:CaptureCoordinator.swift
- 刘海裁剪:NotchBarTrimmer.swift
- 功能与快捷键全览:README.md
一句话总结:当 ScreenCaptureKit 合成画面丢掉了窗口阴影,Screendrop 选择了"向传统致敬"——用最原生的 screencapture CLI 抓住屏幕本来的样子。有时,最老的工具才是最对的选择。🖥️
【免费下载链接】ScreendropA beautiful screenshot + screen recording + Loom alternative - all native, self hostable and free.项目地址: https://gitcode.com/gh_mirrors/sc/Screendrop
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考