news 2026/8/30 19:42:44

macOS原生OCR文字复制工具:利用Vision框架实现屏幕取词

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
macOS原生OCR文字复制工具:利用Vision框架实现屏幕取词

开发 macOS 应用时,把屏幕上的文字“抓”下来复制到剪贴板,是一个很常见的自动化需求。之前我一直用第三方 OCR 服务或者 Tesseract,但配置麻烦、识别中文效果也不理想。后来发现 macOS 系统本身自带了 OCR 能力,通过 Vision 框架就能调用,不需要联网,也不依赖任何第三方 SDK。看到有人分享了一个叫 “Monkey see, monkey do” 的小项目,思路就是“眼睛看到什么,就能复制什么”,本质上就是屏幕截取 + 原生 OCR。这篇文章我就把这条链路完整拆解一遍,带你从零实现一个 macOS 原生 OCR 文字复制工具,代码可以直接跑。

本文适合 macOS 开发者、自动化脚本爱好者,也适合想了解 Vision 框架文本识别的大前端和 AI 方向读者。学完你可以掌握如何调用 macOS 原生 OCR 识别图片,如何截取屏幕区域,如何把识别结果写入剪贴板,并了解权限配置、性能优化和常见坑点。

1. 背景:macOS 上实现 OCR 有哪些方案

1.1 什么是 OCR

OCR(Optical Character Recognition,光学字符识别)的目的是从图像中提取文字。比如一张截图、一张扫描件、甚至摄像头拍到的画面,只要里面有文字,OCR 就能把它们变成可编辑、可复制的文本。

在 macOS 上做文字识别,常见方案有:

方案类型优缺点
Tesseract开源本地引擎免费,但需要安装语言包,中文识别精度一般
百度 OCR / 腾讯 OCR云端 API精度高,但要联网、有调用配额,涉及隐私
macOS Vision系统原生框架免费、离线、集成度高,支持中文,无需额外依赖

从工程角度看,如果你的工具只在 macOS 上跑,且不想把用户截图上传到云端,Vision 框架是最合适的选择。它内置在系统里,性能和识别率都经过苹果优化,尤其是 macOS 12 之后对中文、日文、韩文的支持已经比较完善。

1.2 “Monkey see, monkey do” 想表达什么

“Monkey see, monkey do” 是一个英文俗语,意思是“看到什么就模仿什么”。放到 OCR 工具里,就是一个很形象的产品逻辑:屏幕上出现什么文字,工具就把它识别并复现出来。

你可以想象这样的使用场景:

  • 看视频时发现字幕里有想要保存的句子,直接一框选就复制;
  • 阅读加密 PDF 或图片型 PDF 时,无法选中文字,用 OCR 工具提取;
  • 软件界面上的报错信息无法复制,直接截屏识别;
  • 开会时想把幻灯片里的文字快速做成笔记。

这些需求都可以用 macOS 原生能力实现,不需要购买专业软件。

1.3 为什么推荐使用系统原生 OCR

使用 Vision 框架的好处很明显:

  1. 离线可用:不依赖网络,不把数据上传到第三方服务器;
  2. 免费无限量:本地计算,没有 API 配额和费用;
  3. 隐私安全:截图留在本机,适合处理敏感文档;
  4. 中文支持好:系统语言包已经内置,开箱即用;
  5. 与 macOS 系统深度集成:可以配合快捷键、Automator、Shortcuts 使用。

如果你的应用只面向 macOS,优先用系统能力往往是性价比最高的方案。

2. 环境准备与版本说明

在开始写代码之前,先确认你的开发环境和运行环境。

2.1 操作系统版本

Vision 框架从 macOS 10.15 开始引入文本识别能力,但早期的VNRecognizeTextRequest仅支持英文。如果你需要识别中文,建议使用 macOS 12 Monterey 及之后版本,此时 Live Text 已内置,识别质量和语言丰富度提升明显。

本文示例基于 macOS 13/14 实测,理论兼容 macOS 12+。如果你的系统是 macOS 10.15 或 11,代码大部分可用,但中文识别可能受限。

2.2 开发工具

  • Xcode:可以使用 Xcode 14 或更高版本,命令行工具也可以单独安装;
  • Swift:示例代码基于 Swift 5;
  • Command Line Tools:如果你不想建完整 Xcode 工程,直接用swift命令编译运行也可以。

检查 Command Line Tools 是否安装:

xcode-select --install

查看 Swift 版本:

swift --version

2.3 运行权限

如果你的 OCR 工具只识别图片文件,不需要额外权限。但如果你要实现屏幕实时取词,需要给终端或 App 授权“屏幕录制”权限:

  • 系统设置 → 隐私与安全性 → 屏幕录制;
  • 把你运行工具所在的终端 App(比如 Terminal、iTerm)勾选上。

如果你要把工具打包成独立 App,还需在 App 的Info.plist中声明:

<key>NSScreenCaptureUsageDescription</key> <string>需要截取屏幕内容以进行 OCR 文字识别</string>

如果是命令行工具,没有 Info.plist,但系统仍会在第一次调用截屏 API 时弹出授权提示。

2.4 示例项目结构

为了让示例尽量简单,我们不建 Xcode 工程,直接用 Swift 脚本。项目结构如下:

monkey-see/ ├── main.swift ├── Package.swift # 可选,如果使用 SwiftPM └── images/ └── sample.png

你可以把main.swift当成独立命令行工具运行。

3. 核心原理:Vision 框架如何做文字识别

Vision 是苹果提供的计算机视觉框架。它并不直接对外暴露 UI,而是通过 request-handler 模式工作。

3.1 核心概念

  • VNRecognizeTextRequest:文本识别请求对象,负责配置识别参数;
  • VNImageRequestHandler:图像请求处理器,负责把图片数据交给 Vision 分析;
  • VNRecognizedTextObservation:识别结果,包含文字内容和坐标位置。

一个完整的识别流程是:

  1. 把图片转换为CGImage
  2. 创建VNRecognizeTextRequest
  3. 创建VNImageRequestHandler并执行请求;
  4. 遍历VNRecognizedTextObservation提取文本。

3.2 识别精度设置

recognitionLevel有两个选项:

  • .fast:速度快,适合实时截屏;
  • .accurate:精度高,适合从图片中提取文字。

对于截图场景,建议先用.accurate提高准确率,如果性能不够再改为.fast

3.3 语言支持

通过recognitionLanguages可以指定识别语言。常用语言代码:

  • zh-Hans:简体中文;
  • en-US:英文;
  • ja-JP:日文;
  • ko-KR:韩文。

如果希望同时识别中英文,可以传入多个语言:

request.recognitionLanguages = ["zh-Hans", "en-US"]

注意:并非所有语言在所有系统版本上都可用,建议做一次可用语言查询。

3.4 坐标系统

Vision 的坐标系统与 UIKit/AppKit 不同。Vision 使用归一化坐标,原点在图片左下角,y 轴向上。如果你需要把文字框画在截图原图上,需要做坐标转换。

3.5 核心代码示例

下面是一个最小可用的 Swift 函数,用来识别一张 PNG 图片中的所有文字:

import Vision import AppKit func recognizeText(from image: NSImage) -> String { guard let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil) else { return "" } var resultText = "" let request = VNRecognizeTextRequest { request, error in guard let observations = request.results as? [VNRecognizedTextObservation] else { return } for observation in observations { if let candidate = observation.topCandidates(1).first { resultText += candidate.string + "\n" } } } request.recognitionLevel = .accurate request.recognitionLanguages = ["zh-Hans", "en-US"] request.usesLanguageCorrection = true let handler = VNImageRequestHandler(cgImage: cgImage, options: [:]) try? handler.perform([request]) return resultText }

这段代码中:

  • topCandidates(1)返回置信度最高的一个候选文本;
  • usesLanguageCorrection会利用语言模型修正识别结果,默认开启;
  • try? handler.perform忽略错误,实际项目中建议用do-catch处理。

4. 完整实战:从屏幕截取到复制文字

接下来我们实现一个完整的命令行工具:用户启动程序后,截取当前屏幕,自动识别屏幕上的所有文字,并复制到剪贴板。

4.1 创建 Swift 脚本

先创建一个文件夹:

mkdir monkey-see && cd monkey-see touch main.swift

用文本编辑器打开main.swift

4.2 获取屏幕截图

macOS 截取主屏幕可以使用 Core Graphics 的CGDisplayCreateImage。这个 API 会返回一个CGImage,可以直接交给 Vision 处理。

import CoreGraphics func captureScreen() -> CGImage? { let screenRect = CGMainDisplayBounds() guard let image = CGDisplayCreateImage(CGMainDisplayID()) else { return nil } return image }

CGMainDisplayID()返回主显示器 ID,CGDisplayCreateImage会生成该显示器的图像。如果你想截取某个区域,可以在生成图片后使用cropping(to:)裁剪。

4.3 对截图进行 OCR 识别

我们复用上一节的recognizeText函数,但输入变成CGImage,避免 NSImage 转换开销:

import Vision func recognizeText(from cgImage: CGImage) -> String { var resultText = "" let request = VNRecognizeTextRequest { request, error in guard error == nil else { print("识别错误: \(error!.localizedDescription)") return } guard let observations = request.results as? [VNRecognizedTextObservation] else { return } for observation in observations { if let candidate = observation.topCandidates(1).first { resultText += candidate.string + "\n" } } } request.recognitionLevel = .accurate request.recognitionLanguages = ["zh-Hans", "en-US"] request.usesLanguageCorrection = true let handler = VNImageRequestHandler(cgImage: cgImage, options: [:]) do { try handler.perform([request]) } catch { print("执行失败: \(error.localizedDescription)") } return resultText }

4.4 写入剪贴板

macOS 里写入剪贴板最简单的方式是使用NSPasteboard

import AppKit func copyToPasteboard(_ text: String) { let pasteboard = NSPasteboard.general pasteboard.clearContents() pasteboard.setString(text, forType: .string) }

注意:命令行工具使用 AppKit 需要保证有图形会话,普通终端运行没有问题。

4.5 主程序组装

main.swift里把这三步串起来:

import Foundation import AppKit import Vision import CoreGraphics // ... 上面定义的函数 ... @main struct MonkeySee { static func main() { print("正在截取屏幕...") guard let screenImage = captureScreen() else { print("截屏失败") exit(1) } print("正在进行 OCR 识别...") let text = recognizeText(from: screenImage) guard !text.isEmpty else { print("没有识别到文字") exit(0) } copyToPasteboard(text) print("识别完成,已复制以下内容到剪贴板:") print("-----------------------------") print(text) } }

如果你不想用@main,也可以直接把顶层代码写在main.swift中。

4.6 编译运行

由于 Swift 命令行工具可以直接从源文件编译,执行:

swiftc -o monkey-see main.swift -framework Vision -framework AppKit -framework CoreGraphics

然后运行:

./monkey-see

首次运行可能会弹出“终端想要截取屏幕图像”的授权提示,点击允许后需要重新运行。

4.7 测试效果

准备一张包含中英文文字的图片,或者打开任意网页,运行工具后:

正在截取屏幕... 正在进行 OCR 识别... 识别完成,已复制以下内容到剪贴板: ----------------------------- 这个网站使用 Cookie 来增强您的浏览体验。 Hello, welcome to my blog!

打开文本编辑器粘贴,就能看到完整内容。

5. 进阶:实现矩形区域 OCR 和快捷键唤起

整屏识别虽然简单,但实际使用时往往只需要识别某一块区域。比如弹窗中的错误信息、视频字幕、表格中的某一列。下面我们增加区域选择能力。

5.1 使用screencapture命令配合区域截图

最简单的方式是调用系统自带的screencapture命令行工具。它可以让你手动框选区域。

screencapture -i /tmp/ocr_selection.png

如果希望截取后光标变成十字准线,并允许用户拖动选择区域,使用-i交互模式。截图成功后,生成的 PNG 文件再交给 OCR 识别。

5.2 Swift 调用screencapture

在 Swift 中可以用Process执行系统命令:

import Foundation func captureSelection() -> URL? { let url = URL(fileURLWithPath: "/tmp/ocr_selection.png") let process = Process() process.executableURL = URL(fileURLWithPath: "/usr/sbin/screencapture") process.arguments = ["-i", url.path] do { try process.run() process.waitUntilExit() if FileManager.default.fileExists(atPath: url.path) { return url } } catch { print("截屏失败: \(error)") } return nil }

注意screencapture在较新的 macOS 中路径通常是/usr/sbin/screencapture,也可能位于/sbin,建议用xcrun --find screencapture查找。

5.3 从文件加载图片并识别

拿到截图文件后,用 NSImage 加载:

if let url = captureSelection() { guard let image = NSImage(contentsOf: url), let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil) else { print("无法加载截图") exit(1) } let text = recognizeText(from: cgImage) copyToPasteboard(text) print(text) }

5.4 绑定快捷键

如果你希望按下某个快捷键就启动“区域 OCR”流程,可以使用全局热键库,比如:

  • Carbon 的RegisterEventHotKey
  • 第三方库HotKey(SwiftPM);
  • macOS 自带 Shortcuts 快捷指令。

用 Carbon 实现全局快捷键比较繁琐,这里给出思路。更推荐使用HotKey这个开源库,它封装了事件监听,使用起来更现代。

import HotKey let hotKey = HotKey(key: .space, modifiers: [.control]) hotKey.keyDownHandler = { // 执行区域截图和 OCR startRegionCaptureAndRecognize() }

注意:第三方库需要额外集成,如果是个人学习,完全可以用 Automator 或者 BetterTouchTool 去绑定快捷键。

5.5 权限补充

使用screencapture -i时,系统同样会要求屏幕录制权限。如果出现黑屏或无法截图,请检查权限设置。

6. 常见问题与排查思路

6.1 问题对照表

问题现象常见原因解决思路
截屏返回空图没有屏幕录制权限系统设置中勾选终端的屏幕录制权限
识别不到任何文字图片中没有文字 / 识别语言未配置换测试图片;添加语言参数
中文识别乱码recognitionLanguages只设置了en-US添加zh-Hans
坐标错位Vision 坐标系与 AppKit 不一致转换坐标:y = 1 - normalizedY
运行效率低使用.accurate且图片过大调整为.fast,或缩小图片尺寸
命令行工具无法使用 AppKit未导入AppKit框架编译时加-framework AppKit
弹出安全提示系统首次请求屏幕录制权限点击允许后重启终端

6.2 识别不了中文怎么办

首先确认系统版本。macOS 12 以下对中文支持有限,建议升级系统。其次在请求中明确指定中文:

request.recognitionLanguages = ["zh-Hans"]

如果仍无效,用下面代码查询当前可用的识别语言:

let supported = try? VNRecognizeTextRequest.supportedRecognitionLanguages(for: .accurate, revision: VNRecognizeTextRequestRevision3) print(supported ?? [])

输出结果会列出所有支持的语言代码。

6.3 截屏权限出现“系统数据占用过大”或无法截取

这和 OCR 本身无关,但很多用户会遇到。如果你的 macOS 系统提示“系统数据占用过大”,可以检查“屏幕录制”权限列表是否有残留的已卸载 App。清理方法:重置终端权限或重启系统。

如果鼠标光标在screencapture -i交互模式下不显示,可能是全屏截图权限未开启,或者正在使用虚拟机。虚拟机环境下屏幕捕获行为与真实 macOS 不同,请参考虚拟机的显示驱动配置。

6.4 OCR 识别结果顺序不对

Vision 返回的观察结果并不是绝对按阅读顺序排列的。解决办法是手动排序:

let sortedObservations = observations.sorted { a, b in if abs(a.boundingBox.midY - b.boundingBox.midY) > 0.01 { return a.boundingBox.midY > b.boundingBox.midY } else { return a.boundingBox.minX < b.boundingBox.minX } }

由于 Vision 坐标原点在左下角,midY越大表示位置越靠上。按从下到上?不,这里我们是要按阅读顺序:先按 y 降序(上到下),同一行内按 x 升序(左到右)。

6.5 编译时找不到 Vision 框架

确保命令行编译时添加了-framework Vision

swiftc -o monkey-see main.swift -framework Vision -framework AppKit -framework CoreGraphics

如果你使用 SwiftPM,则需要在Package.swift中链接系统框架。

7. 最佳实践与工程建议

7.1 合理选择识别精度

如果你的应用需要实时处理视频帧,建议使用.fast,并在每帧之间做节流。对于静态截图,.accurate更合适。

7.2 提高识别准确率

  • 识别前对图片做二值化或增强对比度;
  • 将图片缩放至合适大小,过大或过小都会影响效果;
  • 对旋转的文字设置recognitionLevel = .accurate,但仍有限度;
  • 对结果做后处理,例如去掉多余空格、修正标点。

7.3 隐私与安全

  • 不要把截屏图片明文保存在磁盘上,用完即删;
  • 如果网络传输 OCR 结果,务必加密;
  • 如果你的 App 会处理敏感数据,在隐私政策中明确说明;
  • 在用户授权前不要触发截图,否则可能被系统拒绝。

7.4 处理多语言

建议根据用户系统语言动态设置识别语言,而不是写死。可以通过Locale.preferredLanguages获取当前语言,映射到 Vision 的语言代码。

7.5 内存管理

Vision 处理大图时会占用较多内存。在命令行工具中,识别完成后及时释放对象。如果是 iOS/macOS App,建议将识别任务放到后台队列:

DispatchQueue.global(qos: .userInitiated).async { let text = recognizeText(from: cgImage) DispatchQueue.main.async { self.textView.string = text } }

7.6 日志与错误处理

生产工具一定要有完整的错误日志。可以把每次识别耗时、识别语言、候选文字数量记录下来,方便后续调优。

7.7 打包成 App

如果你把工具分发给同事使用,可以打包成.app,并在Info.plist声明权限。使用osascript或 Automator 也能快速做成“服务”菜单项,无需 Xcode。

7.8 与最新系统兼容

macOS Sequoia 发布后,很多用户遇到“若要打开此 App,你需要从 macOS 恢复启动,并将安全策略更改为完整安全”的问题。这本质上是自定义内核扩展或未签名 App 的安全策略设置。对普通 OCR 工具来说,建议使用 Developer ID 签名,避免用户被安全策略卡住。

7.9 性能优化方向

如果你要做“全局 OCR 搜索”这类工具,可以考虑:

  • 监听屏幕变化,增量识别;
  • 使用VNImageRequestHandlerregionOfInterest只识别变化区域;
  • 使用 GPU 加速,但 Vision 默认已经使用系统加速能力;
  • 建立文字缓存,避免重复识别。

8. 总结与下一步学习方向

通过本文的实战,你已经掌握了 macOS 原生 OCR 的核心链路:

  • 使用VNRecognizeTextRequest识别图片文字;
  • 使用CGDisplayCreateImagescreencapture截取屏幕;
  • 使用NSPasteboard写入剪贴板;
  • 处理屏幕录制权限;
  • 通过识别语言参数解决中文支持问题。

这套方案非常适合做个人效率工具,比如“截图 OCR”“屏幕取词”“离线文字提取”。如果想继续深入,可以尝试:

  • 在 iOS 上使用同样的 Vision API 实现拍照取词;
  • 结合 Core ML 做自定义文字分类;
  • 利用 Live Text 的底层能力做更聪明的 OCR 应用;
  • 把 Swift 代码封装成命令行工具,通过 Python 调用,形成更灵活的自动化脚本。

关于 Python 调用,可以借助PyObjC框架,但需要安装对应 macOS 版本支持的 pyobjc-framework-Vision 包。环境配置时要注意 Python 版本与 PyObjC 的兼容性,建议在虚拟环境中安装。

最后提醒一点:屏幕录制权限在开发调试阶段经常被忽略,一旦发现截屏全黑,优先检查“隐私与安全性”里的授权列表。调试完成后,把权限限定在最小范围,保障用户隐私。

如果你也打算做一个类似的“看到什么就复制什么”的小工具,不妨先从今天的示例改造起。加上一个快捷键,再配合区域截图,就是一个相当顺手的日常效率工具了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/30 19:38:12

Spotify 推出 AI 音乐标签:AI 生成与 AI 辅助作品如何区分?

先说一个判断&#xff1a;Spotify 为 AI 生成的艺术家身份加上新的标签&#xff0c;这件事看起来像是一个平台功能更新&#xff0c;实际上是一个信号——AI 音乐已经不再只是短视频背景音或实验性玩法&#xff0c;而是正式进入了流媒体平台的内容治理和推荐体系。这个标签要解决…

作者头像 李华
网站建设 2026/8/30 19:37:28

2026内容运营故障分级处理全流程:容错不追责、复盘根治反复出错问题

内容运营的核心竞争力&#xff0c;从来不是零出错&#xff0c;而是快速控损、合理容错、根治复发的故障处理能力。成熟的内容团队都会建立标准化故障管控体系&#xff0c;通过三级故障分级判定、单次故障免追责机制、深度无自我复盘流程&#xff0c;既能极速修复用户体验问题、…

作者头像 李华
网站建设 2026/8/30 19:35:45

Mistral托管GLM-5.2:模型分发进入多平台互嵌时代

Mistral 的模型列表里增加了一个名字&#xff1a;GLM-5.2。如果你长期做大模型应用开发&#xff0c;第一次看到这条消息时可能会觉得有点微妙——Mistral 是总部在巴黎、以自研模型起家的欧洲 AI 公司&#xff0c;而 Z.ai 是智谱团队面向国际市场的品牌&#xff0c;GLM 系列则是…

作者头像 李华
网站建设 2026/8/30 19:29:36

VC++6.0英文安装包:工业遗留系统确定性编译的唯一基线

简介&#xff1a;本资源为微软经典开发工具VC 6.0的原生英文安装包&#xff0c;面向Windows平台下C/C初学者、高校教学人员、遗留系统维护工程师及嵌入式/工业软件兼容性开发者&#xff0c;解决老旧项目编译环境缺失、MFC程序调试复现及跨语言开发兼容性问题。压缩包共2000个文…

作者头像 李华
网站建设 2026/8/30 19:26:49

STM32裸机开发进阶:FreeRTOS从入门到实战排查

铁头山羊的 FreeRTOS 教程更新了。先给结论&#xff1a;如果你是使用 STM32 做嵌入式开发&#xff0c;之前一直在裸机里靠主循环和定时器硬撑&#xff0c;任务一多就发现逻辑乱、外设冲突、响应不及时&#xff0c;那这套教程值得你从头跟一遍。这次更新的重点&#xff0c;不是把…

作者头像 李华