├── .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 | ![演示动画](./assets/demo.gif) 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 | ![变量控制面板的位置](./assets/open-variables-panel.jpg) 16 | 4. 将第二步中获得的 API Key 和 API Secret 填入对应的变量中 17 | ![添加变量的示意图](./assets/set-variables.jpg) 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 --------------------------------------------------------------------------------