rtesseract 2.1.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +5 -5
  2. data/.document +1 -2
  3. data/.gitignore +12 -0
  4. data/.rspec +3 -0
  5. data/.travis.yml +13 -11
  6. data/CODE_OF_CONDUCT.md +74 -0
  7. data/Gemfile +4 -16
  8. data/Gemfile.lock +42 -82
  9. data/LICENSE.txt +18 -17
  10. data/README.md +137 -0
  11. data/Rakefile +4 -48
  12. data/bin/console +14 -0
  13. data/bin/setup +8 -0
  14. data/lib/rtesseract/box.rb +15 -60
  15. data/lib/rtesseract/check.rb +14 -0
  16. data/lib/rtesseract/command.rb +41 -0
  17. data/lib/rtesseract/configuration.rb +15 -64
  18. data/lib/rtesseract/pdf.rb +18 -0
  19. data/lib/rtesseract/text.rb +9 -0
  20. data/lib/rtesseract/tsv.rb +18 -0
  21. data/lib/rtesseract/version.rb +3 -0
  22. data/lib/rtesseract.rb +22 -214
  23. data/rtesseract.gemspec +27 -93
  24. metadata +38 -71
  25. data/README.rdoc +0 -156
  26. data/VERSION +0 -1
  27. data/lib/processors/mini_magick.rb +0 -43
  28. data/lib/processors/none.rb +0 -34
  29. data/lib/processors/rmagick.rb +0 -46
  30. data/lib/rtesseract/blob.rb +0 -34
  31. data/lib/rtesseract/box_char.rb +0 -31
  32. data/lib/rtesseract/errors.rb +0 -21
  33. data/lib/rtesseract/mixed.rb +0 -54
  34. data/lib/rtesseract/processor.rb +0 -19
  35. data/lib/rtesseract/utils.rb +0 -44
  36. data/spec/configs/eng.user-words.txt +0 -13
  37. data/spec/images/README.pdf +0 -0
  38. data/spec/images/blank.tif +0 -0
  39. data/spec/images/mixed.tif +0 -0
  40. data/spec/images/orientation_reverse.png +0 -0
  41. data/spec/images/test with spaces.tif +0 -0
  42. data/spec/images/test-pdf.png +0 -0
  43. data/spec/images/test.bmp +0 -0
  44. data/spec/images/test.jpg +0 -0
  45. data/spec/images/test.png +0 -0
  46. data/spec/images/test.tif +0 -0
  47. data/spec/images/test1.tif +0 -0
  48. data/spec/images/test_words.png +0 -0
  49. data/spec/rtesseract_box_char_spec.rb +0 -82
  50. data/spec/rtesseract_box_spec.rb +0 -36
  51. data/spec/rtesseract_mixed_spec.rb +0 -49
  52. data/spec/rtesseract_spec.rb +0 -274
  53. data/spec/spec_helper.rb +0 -18
@@ -0,0 +1,41 @@
1
+ require 'tmpdir'
2
+
3
+ class RTesseract
4
+ class Command
5
+ FIXED = [:command, :psm, :oem, :lang, :tessdata_dir, :user_words, :user_patterns, :config_file]
6
+
7
+ attr_reader :options
8
+
9
+ def initialize(source, output, options)
10
+ @source = source
11
+ @output = output
12
+ @options = options
13
+ end
14
+
15
+ def configs
16
+ @options.to_h.map { |key, value| ['-c', "#{key}=#{value}"] unless FIXED.include?(key) }.compact
17
+ end
18
+
19
+ def full_command
20
+ command = [options.command, @source, @output]
21
+
22
+ command << ['--psm', options.psm.to_s] if options.psm
23
+ command << ['--oem', options.oem.to_s] if options.oem
24
+ command << ['-l', options.lang] if options.lang
25
+
26
+ command << ['--tessdata_dir', options.tessdata_dir] if options.tessdata_dir
27
+ command << ['--user_words', options.user_words] if options.user_words
28
+ command << ['--user_patterns', options.user_patterns] if options.user_patterns
29
+
30
+ command << configs
31
+
32
+ command << options.config_file.to_s if options.config_file
33
+
34
+ command.flatten
35
+ end
36
+
37
+ def run
38
+ Open3.capture2e(*full_command)
39
+ end
40
+ end
41
+ end
@@ -1,75 +1,26 @@
1
- # RTesseract
2
- class RTesseract
3
- # Aliases to languages names
4
- LANGUAGES = {
5
- 'en' => 'eng',
6
- 'en-us' => 'eng',
7
- 'english' => 'eng',
8
- 'pt' => 'por',
9
- 'pt-br' => 'por',
10
- 'portuguese' => 'por',
11
- 'it' => 'ita',
12
- 'sp' => 'spa'
13
- }.freeze
14
-
15
- # Configuration class
16
- class Configuration
17
- attr_accessor :processor, :lang, :psm, :tessdata_dir, :user_words, :user_patterns, :command, :debug, :options_cmd
18
-
19
- def initialize
20
- @processor = 'rmagick'
21
- end
22
-
23
- # Global configuration
24
- def parent
25
- @parent ||= RTesseract.configuration || RTesseract::Configuration.new
26
- end
27
-
28
- # Set value of option
29
- def option(options, name, default = nil)
30
- self.instance_variable_set("@#{name}", options.option(name, parent.send(name)) || default)
31
- end
1
+ require 'ostruct'
32
2
 
33
- # Return the values of options
34
- def load_options(options, names = [])
35
- names.each { |name| option(options, name, nil) }
3
+ class RTesseract
4
+ class Configuration < OpenStruct
5
+ def merge(options)
6
+ RTesseract::Configuration.new(self.to_h.merge(options))
36
7
  end
37
8
  end
38
9
 
39
10
  class << self
40
- attr_accessor :configuration
41
- end
42
-
43
- def self.configure
44
- self.configuration ||= Configuration.new
45
- yield(configuration)
46
- self.clear_pdf_option
47
- end
48
-
49
- # Clear pdf option
50
- def self.clear_pdf_option
51
- if self.configuration.options_cmd
52
- self.configuration.options_cmd.delete('pdf')
53
- self.configuration.options_cmd.delete(:pdf)
11
+ def config
12
+ @config ||= RTesseract::Configuration.new(
13
+ command: 'tesseract',
14
+ debug_file: '/dev/null'
15
+ )
54
16
  end
55
- end
56
17
 
57
- # Default command
58
- def self.default_command
59
- TesseractBin::Executables[:tesseract] || 'tesseract'
60
- rescue
61
- 'tesseract'
62
- end
18
+ def configure
19
+ yield(config) if block_given?
20
+ end
63
21
 
64
- # Local config to instance
65
- def self.local_config(options = {})
66
- RTesseract::Configuration.new.tap do |config|
67
- config.command = config.option(options, :command, RTesseract.default_command)
68
- config.processor = config.option(options, :processor, 'rmagick')
69
- config.load_options(options, [:lang, :psm, :tessdata_dir, :user_words, :user_patterns])
70
- config.debug = config.option(options, :debug, false)
71
- pdf_opts = lambda { |o| o == 'pdf' || o == :pdf }
72
- config.options_cmd = [options.option(:options, nil)].delete_if(&pdf_opts).flatten.compact
22
+ def reset_config!
23
+ @config = nil
73
24
  end
74
25
  end
75
26
  end
@@ -0,0 +1,18 @@
1
+ require 'tmpdir'
2
+
3
+ class RTesseract
4
+ module Pdf
5
+ def self.temp_dir
6
+ @file_path = Pathname.new(Dir.tmpdir)
7
+ end
8
+
9
+ def self.run(source, options)
10
+ name = "rtesseract_#{SecureRandom.uuid}"
11
+ options.tessedit_create_pdf = 1
12
+
13
+ RTesseract::Command.new(source, temp_dir.join(name).to_s, options).run
14
+
15
+ File.open(temp_dir.join("#{name}.pdf").to_s, 'r')
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,9 @@
1
+ require 'open3'
2
+
3
+ class RTesseract
4
+ module Text
5
+ def self.run(source, options)
6
+ RTesseract::Command.new(source, 'stdout', options).run.first
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,18 @@
1
+ require 'tmpdir'
2
+
3
+ class RTesseract
4
+ module Tsv
5
+ def self.temp_dir
6
+ @file_path = Pathname.new(Dir.tmpdir)
7
+ end
8
+
9
+ def self.run(source, options)
10
+ name = "rtesseract_#{SecureRandom.uuid}"
11
+ options.tessedit_create_tsv = 1
12
+
13
+ RTesseract::Command.new(source, temp_dir.join(name).to_s, options).run
14
+
15
+ File.open(temp_dir.join("#{name}.tsv").to_s, 'r')
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ class RTesseract
2
+ VERSION = '3.0.0'.freeze
3
+ end
data/lib/rtesseract.rb CHANGED
@@ -1,238 +1,46 @@
1
- # encoding: UTF-8
2
- require 'pathname'
3
- require 'tempfile'
1
+ require "rtesseract/check"
2
+ require "rtesseract/configuration"
3
+ require "rtesseract/command"
4
+ require "rtesseract/text"
5
+ require "rtesseract/pdf"
6
+ require "rtesseract/box"
7
+ require "rtesseract/tsv"
4
8
 
5
- require 'rtesseract/utils'
6
- require 'rtesseract/configuration'
7
- require 'rtesseract/errors'
8
-
9
- # Ruby wrapper for Tesseract OCR
10
9
  class RTesseract
11
- attr_accessor :configuration
12
- attr_reader :processor
13
- attr_reader :source
14
-
15
- def initialize(src = '', options = {})
16
- self.configuration = RTesseract.local_config(options)
17
- @options = options || {}
18
- @points = {}
19
- @processor = RTesseract::Processor.choose_processor!(configuration.processor)
20
- self.source = src
21
- initialize_hook
22
- end
23
-
24
- # Hook to end of initialize method
25
- def initialize_hook
26
- end
27
-
28
- # Define the source
29
- def source=(src)
30
- @value = nil
31
- @pdf_path = nil
32
- @source = @processor.image?(src) ? src : Pathname.new(src)
33
- end
34
-
35
- # Crop image to convert
36
- def crop!(points = {})
37
- @value = nil
38
- @points = points
39
- self
40
- end
41
-
42
- # Select the language
43
- # ===Languages
44
- ## * eng - English
45
- ## * deu - German
46
- ## * deu-f - German fraktur
47
- ## * fra - French
48
- ## * ita - Italian
49
- ## * nld - Dutch
50
- ## * por - Portuguese
51
- ## * spa - Spanish
52
- ## * vie - Vietnamese
53
- ## Note: Make sure you have installed the language to tesseract
54
- def lang
55
- language = (configuration.lang || 'eng').to_s.strip.downcase
56
- " -l #{LANGUAGES[language] || language} "
57
- rescue
58
- ''
59
- end
60
-
61
- # Convert option to command
62
- def option_to_string(prefix, value = nil)
63
- (value.nil? ? '' : " #{prefix} #{value} ")
64
- rescue
65
- ''
66
- end
67
-
68
- # Page Segment Mode
69
- def psm
70
- option_to_string('-psm', configuration.psm)
71
- end
72
-
73
- # Tessdata Dir
74
- def tessdata_dir
75
- option_to_string('--tessdata-dir', configuration.tessdata_dir)
76
- end
77
-
78
- # User Words
79
- def user_words
80
- option_to_string('--user-words', configuration.user_words)
81
- end
82
-
83
- # User Patterns
84
- def user_patterns
85
- option_to_string('--user-patterns', configuration.user_patterns)
86
- end
87
-
88
- # Options on line
89
- def options_cmd
90
- configuration.options_cmd
91
- end
92
-
93
- # Hook to before config
94
- def config_hook
95
- end
96
-
97
- # Convert configurations
98
- def config
99
- @options ||= {}
100
- config_hook
101
- @options.map { |k, v| "#{k} #{v}" }.join("\n")
102
- end
103
-
104
- # Write config to file
105
- def config_file
106
- config_hook
107
- return '' if @options == {}
108
- conf = Tempfile.new('config')
109
- conf.write(config)
110
- conf.flush
111
- conf.path
112
- end
113
-
114
- # TODO: Clear console for MacOS or Windows
115
- def clear_console_output
116
- return '' if configuration.debug
117
- return '2>/dev/null' if File.exist?('/dev/null') # Linux console clear
118
- end
119
-
120
- # Get image
121
- def image
122
- (@image = @processor.image_to_tif(@source, @points)).path
123
- end
124
-
125
- # Extension of file
126
- def file_ext
127
- '.txt'
128
- end
10
+ class Error < StandardError; end
129
11
 
130
- # Detect version number
131
- def tesseract_version
132
- RTesseract::Utils.version_number
133
- end
12
+ check_version!
134
13
 
14
+ attr_reader :config, :source
135
15
 
136
- # Rand file path
137
- def file_dest
138
- @file_dest = Pathname.new(Dir.tmpdir).join("#{Time.now.to_f}#{rand(1500)}").to_s
139
- end
140
-
141
- # Full path of file with txt extension
142
- def file_with_ext(ext = nil)
143
- [@file_dest, ext || file_ext].join('')
144
- end
145
-
146
- # Run command
147
- def convert_command
148
- `#{configuration.command} "#{image}" "#{file_dest}" #{lang} #{psm} #{tessdata_dir} #{user_words} #{user_patterns} #{config_file} #{clear_console_output} #{options_cmd.join(' ')}`
149
- end
150
-
151
- # Is pdf output?
152
- def pdf?
153
- options_cmd.include? 'pdf'
154
- end
155
-
156
- # Read result file
157
- def convert_text
158
- @value = File.read(file_with_ext).to_s
16
+ def initialize(src = '', options = {})
17
+ @source = src
18
+ @config = RTesseract.config.merge(options)
159
19
  end
160
20
 
161
- # Store pdf result path
162
- def convert_pdf
163
- @pdf_path = file_with_ext('.pdf')
21
+ def to_box
22
+ Box.run(@source, config)
164
23
  end
165
24
 
166
- # Convert result to proper type
167
- def convert_result
168
- if pdf?
169
- convert_pdf
170
- else
171
- convert_text
172
- RTesseract::Utils.remove_files([@image, file_with_ext])
173
- end
25
+ def words
26
+ to_box.map { |word| word[:word] }
174
27
  end
175
28
 
176
- # Hook to convert
177
- def after_convert_hook
29
+ def to_pdf
30
+ Pdf.run(@source, config)
178
31
  end
179
32
 
180
- # Convert image to string
181
- def convert
182
- convert_command
183
- after_convert_hook
184
- convert_result
185
- rescue => error
186
- raise RTesseract::ConversionError.new(error), error, caller
33
+ def to_tsv
34
+ Tsv.run(@source, config)
187
35
  end
188
36
 
189
37
  # Output value
190
38
  def to_s
191
- return @value if @value
192
-
193
- if @processor.image?(@source) || @source.file?
194
- convert
195
- @value
196
- else
197
- fail RTesseract::ImageNotSelectedError.new(@source)
198
- end
39
+ Text.run(@source, config)
199
40
  end
200
41
 
201
42
  # Remove spaces and break-lines
202
43
  def to_s_without_spaces
203
44
  to_s.gsub(/\s/, '')
204
45
  end
205
-
206
- # Output pdf path
207
- def to_pdf
208
- return @pdf_path if @pdf_path
209
-
210
- fail TesseractVersionError.new if tesseract_version.nil? || tesseract_version < 3.03
211
-
212
- if @processor.image?(@source) || @source.file?
213
- options_cmd << 'pdf'
214
- convert
215
- options_cmd.delete('pdf')
216
- @pdf_path
217
- else
218
- fail RTesseract::ImageNotSelectedError.new(@source)
219
- end
220
- end
221
-
222
- # Destroy pdf file
223
- def clean
224
- RTesseract::Utils.remove_files([@pdf_path])
225
- end
226
-
227
46
  end
228
-
229
- require 'rtesseract/mixed'
230
- require 'rtesseract/box'
231
- require 'rtesseract/box_char'
232
- require 'rtesseract/blob'
233
- require 'rtesseract/processor'
234
-
235
- # Processors
236
- require 'processors/rmagick.rb'
237
- require 'processors/mini_magick.rb'
238
- require 'processors/none.rb'
data/rtesseract.gemspec CHANGED
@@ -1,99 +1,33 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
- # -*- encoding: utf-8 -*-
5
- # stub: rtesseract 2.1.0 ruby lib
6
1
 
7
- Gem::Specification.new do |s|
8
- s.name = "rtesseract"
9
- s.version = "2.1.0"
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "rtesseract/version"
10
5
 
11
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
- s.require_paths = ["lib"]
13
- s.authors = ["Danilo Jeremias da Silva"]
14
- s.date = "2016-09-08"
15
- s.description = "Ruby library for working with the Tesseract OCR."
16
- s.email = "dannnylo@gmail.com"
17
- s.extra_rdoc_files = [
18
- "LICENSE.txt",
19
- "README.rdoc"
20
- ]
21
- s.files = [
22
- ".document",
23
- ".rspec",
24
- ".travis.yml",
25
- "CHANGELOG.md",
26
- "Gemfile",
27
- "Gemfile.lock",
28
- "LICENSE.txt",
29
- "README.rdoc",
30
- "Rakefile",
31
- "VERSION",
32
- "lib/processors/mini_magick.rb",
33
- "lib/processors/none.rb",
34
- "lib/processors/rmagick.rb",
35
- "lib/rtesseract.rb",
36
- "lib/rtesseract/blob.rb",
37
- "lib/rtesseract/box.rb",
38
- "lib/rtesseract/box_char.rb",
39
- "lib/rtesseract/configuration.rb",
40
- "lib/rtesseract/errors.rb",
41
- "lib/rtesseract/mixed.rb",
42
- "lib/rtesseract/processor.rb",
43
- "lib/rtesseract/utils.rb",
44
- "rtesseract.gemspec",
45
- "spec/configs/eng.user-words.txt",
46
- "spec/images/README.pdf",
47
- "spec/images/blank.tif",
48
- "spec/images/mixed.tif",
49
- "spec/images/orientation_reverse.png",
50
- "spec/images/test with spaces.tif",
51
- "spec/images/test-pdf.png",
52
- "spec/images/test.bmp",
53
- "spec/images/test.jpg",
54
- "spec/images/test.png",
55
- "spec/images/test.tif",
56
- "spec/images/test1.tif",
57
- "spec/images/test_words.png",
58
- "spec/rtesseract_box_char_spec.rb",
59
- "spec/rtesseract_box_spec.rb",
60
- "spec/rtesseract_mixed_spec.rb",
61
- "spec/rtesseract_spec.rb",
62
- "spec/spec_helper.rb"
63
- ]
64
- s.homepage = "http://github.com/dannnylo/rtesseract"
65
- s.licenses = ["MIT"]
66
- s.rubygems_version = "2.4.8"
67
- s.summary = "Ruby library for working with the Tesseract OCR."
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rtesseract"
8
+ spec.version = RTesseract::VERSION
9
+ spec.authors = ["Danilo Jeremias da Silva"]
10
+ spec.email = ["dannnylo@gmail.com"]
68
11
 
69
- if s.respond_to? :specification_version then
70
- s.specification_version = 4
12
+ spec.summary = "Ruby library for working with the Tesseract OCR.".freeze
13
+ spec.description = "Ruby library for working with the Tesseract OCR.".freeze
14
+ spec.homepage = "http://github.com/dannnylo/rtesseract".freeze
15
+ spec.license = "MIT"
71
16
 
72
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
73
- s.add_runtime_dependency(%q<nokogiri>, [">= 0"])
74
- s.add_development_dependency(%q<rspec>, [">= 0"])
75
- s.add_development_dependency(%q<rdoc>, [">= 0"])
76
- s.add_development_dependency(%q<bundler>, [">= 0"])
77
- s.add_development_dependency(%q<jeweler>, ["~> 2.1.1"])
78
- s.add_development_dependency(%q<simplecov>, [">= 0"])
79
- s.add_development_dependency(%q<coveralls>, [">= 0"])
80
- else
81
- s.add_dependency(%q<nokogiri>, [">= 0"])
82
- s.add_dependency(%q<rspec>, [">= 0"])
83
- s.add_dependency(%q<rdoc>, [">= 0"])
84
- s.add_dependency(%q<bundler>, [">= 0"])
85
- s.add_dependency(%q<jeweler>, ["~> 2.1.1"])
86
- s.add_dependency(%q<simplecov>, [">= 0"])
87
- s.add_dependency(%q<coveralls>, [">= 0"])
88
- end
89
- else
90
- s.add_dependency(%q<nokogiri>, [">= 0"])
91
- s.add_dependency(%q<rspec>, [">= 0"])
92
- s.add_dependency(%q<rdoc>, [">= 0"])
93
- s.add_dependency(%q<bundler>, [">= 0"])
94
- s.add_dependency(%q<jeweler>, ["~> 2.1.1"])
95
- s.add_dependency(%q<simplecov>, [">= 0"])
96
- s.add_dependency(%q<coveralls>, [">= 0"])
17
+ # Specify which files should be added to the gem when it is released.
18
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
20
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
97
21
  end
98
- end
22
+ spec.bindir = "exe"
23
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.17"
27
+ spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency "rspec", "~> 3.0"
29
+ spec.add_development_dependency "simplecov"
30
+ spec.add_development_dependency "coveralls"
99
31
 
32
+ spec.add_dependency "nokogiri"
33
+ end