├── .gitignore
├── README.md
├── assets
├── demo.gif
├── open-variables-panel.jpg
└── set-variables.jpg
├── icon.png
├── info.plist.example
├── ocr.rb
└── pngpaste
├── LICENSE
└── pngpaste
/.gitignore:
--------------------------------------------------------------------------------
1 | info.plist
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Alfred Clipboard OCR
2 |
3 | 一个对剪贴板中的图片内容调用百度云 API 做 OCR 识别的 Alfred 工作流。不喜欢百度?试试[基于有道的同类工作流](https://github.com/baker221/alfred-clipboard-ocr-youdao)。
4 |
5 | 
6 |
7 |
感谢:V2EX, Firefox, Snipaste, CotEditor 在上图中的出场(排名不分先后)
8 |
9 | ## 安装方法
10 |
11 | 1. [下载 workflow](https://github.com/oott123/alfred-clipboard-ocr/releases) 并使用 Alfred 安装
12 | 2. 去 [百度云控制台](https://console.bce.baidu.com/ai/#/ai/ocr/overview/index) 申请一个文字识别的应用,并记下 API Key 和 API Secret
13 | 在这里需要顺便[领取免费资源](https://console.bce.baidu.com/ai/#/ai/ocr/overview/resource/getFree),否则会遇到 API 额度不足的问题
14 | 3. 打开 Alfred 设置,找到这个 workflow 并打开变量控制面板
15 | 
16 | 4. 将第二步中获得的 API Key 和 API Secret 填入对应的变量中
17 | 
18 |
19 | ## 使用说明
20 |
21 | 首先,使用任意一个截图软件将想要识别的区域截取下来。你也可以复制图片内容(而非图片文件)到剪贴板中。
22 |
23 | 在 Alfred 中输入 `ocr` 并回车,稍等片刻,即可获得识别的文字。
24 |
25 | 识别后的文字会自动复制到你的剪贴板中。识别并复制成功后,Alfred 会弹出桌面通知提醒你。
26 |
27 | ## 常见问题
28 |
29 | ### 开了代理就报错
30 |
31 | 常见的错误有:
32 |
33 | * Bad URI
34 | * Method Not Allowed
35 | * Request Failed
36 |
37 | 遇到此类问题请先尝试关闭代理确认是否为代理问题。若确认是代理问题而又不希望关闭代理软件的,可以在 Workflow Environment Variables 一栏增加两个变量如下:
38 |
39 | | Name | Value | Don't Export |
40 | | ------------ | ----- | ------------ |
41 | | `HTTP_PROXY` | 空字符串 | NO |
42 | | `http_proxy` | 空字符串 | NO |
43 |
44 | 重试即可。
45 |
46 | ## 授权协议
47 |
48 | AGPLv3
49 |
50 | #### 开源软件使用许可
51 |
52 | [pngpaste](./pngpaste/LICENSE)
53 |
54 | #### 图标授权 (Icon Credit)
55 |
56 | Icon made by [Freepik](http://www.freepik.com) from [www.flaticon.com](https://www.flaticon.com/).
57 |
--------------------------------------------------------------------------------
/assets/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oott123/alfred-clipboard-ocr/4a83ccc53e6bf8df294cf3c17029d4fcd0f21e13/assets/demo.gif
--------------------------------------------------------------------------------
/assets/open-variables-panel.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oott123/alfred-clipboard-ocr/4a83ccc53e6bf8df294cf3c17029d4fcd0f21e13/assets/open-variables-panel.jpg
--------------------------------------------------------------------------------
/assets/set-variables.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oott123/alfred-clipboard-ocr/4a83ccc53e6bf8df294cf3c17029d4fcd0f21e13/assets/set-variables.jpg
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oott123/alfred-clipboard-ocr/4a83ccc53e6bf8df294cf3c17029d4fcd0f21e13/icon.png
--------------------------------------------------------------------------------
/info.plist.example:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | bundleid
6 | com.oott123.alfred.clipboard.ocr
7 | category
8 | Productivity
9 | connections
10 |
11 | 22CAE27E-42AE-447B-BE53-6C897CD8AD1C
12 |
13 |
14 | destinationuid
15 | F257A671-46A1-49AA-A430-8D73E8E628B9
16 | modifiers
17 | 0
18 | modifiersubtext
19 |
20 | vitoclose
21 |
22 |
23 |
24 | 40AEA484-9716-45C2-B627-35208FA951E0
25 |
26 |
27 | destinationuid
28 | 22CAE27E-42AE-447B-BE53-6C897CD8AD1C
29 | modifiers
30 | 0
31 | modifiersubtext
32 |
33 | vitoclose
34 |
35 |
36 |
37 |
38 | createdby
39 | oott123
40 | description
41 | Use Baidu OCR API to covert your clipboard image to text.
42 | disabled
43 |
44 | name
45 | OCR Clipboard
46 | objects
47 |
48 |
49 | config
50 |
51 | lastpathcomponent
52 |
53 | onlyshowifquerypopulated
54 |
55 | removeextension
56 |
57 | text
58 | {var:content}
59 | title
60 | {var:title}
61 |
62 | type
63 | alfred.workflow.output.notification
64 | uid
65 | F257A671-46A1-49AA-A430-8D73E8E628B9
66 | version
67 | 1
68 |
69 |
70 | config
71 |
72 | concurrently
73 |
74 | escaping
75 | 102
76 | script
77 | ruby ocr.rb
78 | scriptargtype
79 | 1
80 | scriptfile
81 | ./ocr.rb
82 | type
83 | 8
84 |
85 | type
86 | alfred.workflow.action.script
87 | uid
88 | 22CAE27E-42AE-447B-BE53-6C897CD8AD1C
89 | version
90 | 2
91 |
92 |
93 | config
94 |
95 | argumenttype
96 | 2
97 | keyword
98 | ocr
99 | subtext
100 |
101 | text
102 | OCR Clipboard
103 | withspace
104 |
105 |
106 | type
107 | alfred.workflow.input.keyword
108 | uid
109 | 40AEA484-9716-45C2-B627-35208FA951E0
110 | version
111 | 1
112 |
113 |
114 | readme
115 | This workflow use Baidu Cloud OCR API convert images on your clipboard to text.
116 |
117 | Grab a api key and secret from https://console.bce.baidu.com/ai/#/ai/ocr/overview/index , and then fill it in `Workflow Enviornment Variables`.
118 | Take a screenshot and/or copy an image to clipboard. Use keyword `ocr` to get it by text.
119 |
120 | Icon made by FreePik from www.flaticon.com.
121 | uidata
122 |
123 | 22CAE27E-42AE-447B-BE53-6C897CD8AD1C
124 |
125 | xpos
126 | 230
127 | ypos
128 | 150
129 |
130 | 40AEA484-9716-45C2-B627-35208FA951E0
131 |
132 | xpos
133 | 70
134 | ypos
135 | 150
136 |
137 | F257A671-46A1-49AA-A430-8D73E8E628B9
138 |
139 | xpos
140 | 380
141 | ypos
142 | 150
143 |
144 |
145 | variables
146 |
147 | bce_api_key
148 |
149 | bce_api_secret
150 |
151 |
152 | variablesdontexport
153 |
154 | bce_api_secret
155 | bce_api_key
156 |
157 | version
158 | 0.1.0
159 | webaddress
160 | https://oott123.github.io/alfred-clipboard-ocr
161 |
162 |
163 |
--------------------------------------------------------------------------------
/ocr.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | %w|tempfile base64 uri net/http openssl json cgi fileutils open3|.each(&method(:require))
3 |
4 | def dump_clipboard_image
5 | file = Tempfile.new ['alfred_ocr', '.jpg']
6 | file.close
7 |
8 | `./pngpaste/pngpaste #{file.path}`
9 | raise 'No image found in your clipboard.' unless $?.success?
10 |
11 | content = Base64.encode64 file.open.read
12 | raise 'Image should be smaller than 4M' if content.length > 4*1024*1024
13 |
14 | content
15 | ensure
16 | file.close
17 | file.unlink
18 | end
19 |
20 | CREDENTIALS_FOLDER = (ENV['alfred_workflow_data'] or ENV['HOME'])
21 | CREDENTIALS_PATH = CREDENTIALS_FOLDER + '/.alfred_ocr_credentials'
22 |
23 | def get_credentials
24 | credentials = {}
25 | FileUtils.mkdir_p CREDENTIALS_FOLDER
26 | api_key = ENV['bce_api_key']
27 | api_secret = ENV['bce_api_secret']
28 | begin
29 | credentials = Marshal.load IO.binread CREDENTIALS_PATH
30 | raise 'Your credentials has expired' if credentials['expires_at'] < Time.now
31 | rescue
32 | raise 'bce_api_key is not defined' unless api_key
33 | raise 'bce_api_secret is not defined' unless api_secret
34 | url = URI("https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=#{api_key}&client_secret=#{api_secret}")
35 |
36 | http = Net::HTTP.new(url.host, url.port)
37 | http.use_ssl = true
38 | http.verify_mode = OpenSSL::SSL::VERIFY_NONE
39 |
40 | request = Net::HTTP::Post.new(url)
41 |
42 | response = http.request(request)
43 | credentials = JSON.load response.read_body
44 | raise (credentials['error_msg'] or 'Credentials incorrect') unless credentials['expires_in']
45 | credentials['expires_at'] = Time.now + credentials['expires_in']
46 | IO.binwrite CREDENTIALS_PATH, Marshal.dump(credentials)
47 | end
48 | credentials
49 | end
50 |
51 | def clear_credentials
52 | FileUtils.rm CREDENTIALS_PATH rescue nil
53 | end
54 |
55 | def ocr_text(image_base64, credentials)
56 | image_base64_encoded = CGI::escape image_base64
57 | access_token = credentials['access_token']
58 |
59 | url = URI("https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic?access_token=#{access_token}")
60 |
61 | http = Net::HTTP.new(url.host, url.port)
62 | http.use_ssl = true
63 | http.verify_mode = OpenSSL::SSL::VERIFY_NONE
64 |
65 | request = Net::HTTP::Post.new(url)
66 | request['content-type'] = 'application/x-www-form-urlencoded'
67 | request.body = "language_type=auto_detect&image=#{image_base64_encoded}"
68 |
69 | response = http.request(request)
70 | data = JSON.load response.read_body
71 | raise (data['error_msg'] or 'Request failed') unless data['words_result']
72 | data['words_result'].map{|x| x['words']}.join "\n"
73 | end
74 |
75 | def copy(str)
76 | Open3.popen3( 'pbcopy' ){ |input, _, _| input << str }
77 | end
78 |
79 | def alfred_output(variables)
80 | obj = {
81 | 'alfredworkflow' => {
82 | 'arg' => 'something',
83 | 'config' => {},
84 | 'variables' => variables
85 | }
86 | }
87 | puts(JSON.dump obj)
88 | end
89 |
90 | begin
91 | image_base64 = dump_clipboard_image
92 | credentials = get_credentials
93 | result = ''
94 | times = 0
95 | a = proc{redo}
96 | begin
97 | result = ocr_text image_base64, credentials
98 | rescue
99 | STDERR.puts 'request failed, clear credentials cache and try again'
100 | STDERR.puts $!
101 | STDERR.puts $!.stack
102 | # clear credentials cache and redo the entire workflow
103 | clear_credentials
104 | a.call
105 | times += 1
106 | retry if times <= 1
107 | end
108 | copy result
109 | alfred_output({
110 | 'title' => 'Text Copied',
111 | 'content' => result
112 | })
113 | rescue
114 | alfred_output({
115 | 'title' => 'OCR Clipboard Error',
116 | 'content' => "#{$!.message}"
117 | })
118 | STDERR.puts $!
119 | STDERR.puts $!.stack
120 | end
121 |
--------------------------------------------------------------------------------
/pngpaste/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2010 Jerry Chen. All rights reserved.
2 |
3 | Redistribution and use in source and binary forms, with or without
4 | modification, are permitted provided that the following conditions are
5 | met:
6 |
7 | 1. Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above
11 | copyright notice, this list of conditions and the following
12 | disclaimer in the documentation and/or other materials provided
13 | with the distribution.
14 |
15 | THIS SOFTWARE IS PROVIDED BY JERRY CHEN ``AS IS'' AND ANY EXPRESS OR
16 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 | DISCLAIMED. IN NO EVENT SHALL JERRY CHEN OR CONTRIBUTORS BE LIABLE FOR
19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 |
27 | The views and conclusions contained in the software and documentation
28 | are those of the authors and should not be interpreted as representing
29 | official policies, either expressed or implied, of Jerry Chen.
30 |
--------------------------------------------------------------------------------
/pngpaste/pngpaste:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oott123/alfred-clipboard-ocr/4a83ccc53e6bf8df294cf3c17029d4fcd0f21e13/pngpaste/pngpaste
--------------------------------------------------------------------------------