tesseract-ocr 0.0.2 → 0.0.3

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.
@@ -0,0 +1,282 @@
1
+ #--
2
+ # Copyright 2011 meh. All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without modification, are
5
+ # permitted provided that the following conditions are met:
6
+ #
7
+ # 1. Redistributions of source code must retain the above copyright notice, this list of
8
+ # conditions and the following disclaimer.
9
+ #
10
+ # THIS SOFTWARE IS PROVIDED BY meh ''AS IS'' AND ANY EXPRESS OR IMPLIED
11
+ # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
12
+ # FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL meh OR
13
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
14
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
15
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
16
+ # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
17
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
18
+ # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19
+ #
20
+ # The views and conclusions contained in the software and documentation are those of the
21
+ # authors and should not be interpreted as representing official policies, either expressed
22
+ # or implied, of meh.
23
+ #++
24
+
25
+ module Tesseract; module C
26
+
27
+ module Iterator
28
+ extend FFI::Inliner
29
+
30
+ inline 'C++' do |cpp|
31
+ cpp.include 'tesseract/resultiterator.h'
32
+ cpp.libraries 'tesseract'
33
+
34
+ cpp.raw 'using namespace tesseract;'
35
+
36
+ cpp.eval {
37
+ enum :PolyBlockType, [
38
+ :UNKNOWN,
39
+ :FLOWING_TEXT, :HEADING_TEXT, :PULLOUT_TEXT, :TABLE, :VERTICAL_TEXT, :CAPTION_TEXT,
40
+ :FLOWING_IMAGE, :HEADING_IMAGE, :PULLOUT_IMAGE,
41
+ :HORZ_LINE, :VERT_LINE, :NOISE, :COUNT
42
+ ]
43
+
44
+ enum :PageIteratorLevel, [
45
+ :BLOCK, :PARAGRAPH, :LINE, :WORD, :SYMBOL
46
+ ]
47
+
48
+ orientation = enum :UP, :RIGHT, :DOWN, :LEFT
49
+ direction = enum :LEFT_TO_RIGHT, :RIGHT_TO_LEFT, :TOP_TO_BOTTOM
50
+
51
+ BoundingBox = Class.new(FFI::Struct) {
52
+ layout \
53
+ :left, :int,
54
+ :top, :int,
55
+ :right, :int,
56
+ :bottom, :int
57
+ }
58
+
59
+ Image = Class.new(FFI::Struct) {
60
+ layout \
61
+ :pix, :pointer,
62
+ :x, :int,
63
+ :y, :int
64
+ }
65
+
66
+ Baseline = Class.new(FFI::Struct) {
67
+ layout \
68
+ :x1, :int,
69
+ :y1, :int,
70
+ :x2, :int,
71
+ :y2, :int
72
+ }
73
+
74
+ Orientation = Class.new(FFI::Struct) {
75
+ layout \
76
+ :orientation, orientation,
77
+ :writing_direction, direction,
78
+ :textline_order, direction,
79
+ :deskew_angle, :float
80
+ }
81
+
82
+ FontAttributes = Class.new(FFI::Struct) {
83
+ layout \
84
+ :id, :int,
85
+ :name, :string,
86
+ :pointsize, :int,
87
+
88
+ :is_bold, :bool,
89
+ :is_italic, :bool,
90
+ :is_underlined, :bool,
91
+ :is_monospace, :bool,
92
+ :is_serif, :bool,
93
+ :is_smallcaps, :bool
94
+ }
95
+
96
+ typedef BoundingBox.by_value, :BoundingBox
97
+ typedef Image.by_value, :Image
98
+ typedef Baseline.by_value, :Baseline
99
+ typedef Orientation.by_value, :OrientationResult
100
+ typedef FontAttributes.by_value, :FontAttributes
101
+ }
102
+
103
+ cpp.raw %{
104
+ typedef struct BoundingBox {
105
+ int left;
106
+ int top;
107
+ int right;
108
+ int bottom;
109
+ } BoundingBox;
110
+
111
+ typedef struct Image {
112
+ Pix* pix;
113
+ int x;
114
+ int y;
115
+ } Image;
116
+
117
+ typedef struct Baseline {
118
+ int x1;
119
+ int y1;
120
+ int x2;
121
+ int y2;
122
+ } Baseline;
123
+
124
+ typedef struct OrientationResult {
125
+ Orientation orientation;
126
+ WritingDirection writing_direction;
127
+ TextlineOrder textline_order;
128
+ float deskew_angle;
129
+ } OrientationResult;
130
+
131
+ typedef struct FontAttributes {
132
+ int id;
133
+ const char* name;
134
+ int pointsize;
135
+
136
+ bool is_bold;
137
+ bool is_italic;
138
+ bool is_underlined;
139
+ bool is_monospace;
140
+ bool is_serif;
141
+ bool is_smallcaps;
142
+ } FontAttributes;
143
+ }
144
+
145
+ cpp.function %{
146
+ void destroy (PageIterator* it) {
147
+ delete it;
148
+ }
149
+ }
150
+
151
+ cpp.function %{
152
+ void begin (PageIterator* it) {
153
+ it->Begin();
154
+ }
155
+ }
156
+
157
+ cpp.function %{
158
+ bool next (PageIterator* it, PageIteratorLevel level) {
159
+ return it->Next(level);
160
+ }
161
+ }
162
+
163
+ cpp.function %{
164
+ bool is_at_beginning_of (PageIterator* it, PageIteratorLevel level) {
165
+ return it->IsAtBeginningOf(level);
166
+ }
167
+ }
168
+
169
+ cpp.function %{
170
+ bool is_at_final_element (PageIterator* it, PageIteratorLevel level, PageIteratorLevel element) {
171
+ return it->IsAtFinalElement(level, element);
172
+ }
173
+ }
174
+
175
+ cpp.function %{
176
+ BoundingBox bounding_box (PageIterator* it, PageIteratorLevel level) {
177
+ BoundingBox result;
178
+
179
+ it->BoundingBox(level, &result.left, &result.top, &result.right, &result.bottom);
180
+
181
+ return result;
182
+ }
183
+ }
184
+
185
+ cpp.function %{
186
+ PolyBlockType block_type (PageIterator* it) {
187
+ return it->BlockType();
188
+ }
189
+ }
190
+
191
+ cpp.function %{
192
+ Pix* get_binary_image (PageIterator* it, PageIteratorLevel level) {
193
+ return it->GetBinaryImage(level);
194
+ }
195
+ }
196
+
197
+ cpp.function %{
198
+ Image get_image (PageIterator* it, PageIteratorLevel level, int padding) {
199
+ Image result;
200
+
201
+ result.pix = it->GetImage(level, padding, &result.x, &result.y);
202
+
203
+ return result;
204
+ }
205
+ }
206
+
207
+ cpp.function %{
208
+ Baseline baseline (PageIterator* it, PageIteratorLevel level) {
209
+ Baseline result;
210
+
211
+ it->Baseline(level, &result.x1, &result.y1, &result.x2, &result.y2);
212
+
213
+ return result;
214
+ }
215
+ }
216
+
217
+ cpp.function %{
218
+ OrientationResult orientation (PageIterator* it) {
219
+ OrientationResult result;
220
+
221
+ it->Orientation(&result.orientation, &result.writing_direction, &result.textline_order, &result.deskew_angle);
222
+
223
+ return result;
224
+ }
225
+ }
226
+
227
+ cpp.function %{
228
+ char* get_utf8_text (ResultIterator* it, PageIteratorLevel level) {
229
+ return it->GetUTF8Text(level);
230
+ }
231
+ }
232
+
233
+ cpp.function %{
234
+ float confidence (ResultIterator* it, PageIteratorLevel level) {
235
+ return it->Confidence(level);
236
+ }
237
+ }
238
+
239
+ cpp.function %{
240
+ FontAttributes word_font_attributes (ResultIterator* it) {
241
+ FontAttributes result;
242
+
243
+ result.name = it->WordFontAttributes(&result.is_bold, &result.is_italic, &result.is_underlined,
244
+ &result.is_monospace, &result.is_serif, &result.is_smallcaps, &result.pointsize, &result.id);
245
+
246
+ return result;
247
+ }
248
+ }
249
+
250
+ cpp.function %{
251
+ bool word_is_from_dictionary (ResultIterator* it) {
252
+ return it->WordIsFromDictionary();
253
+ }
254
+ }
255
+
256
+ cpp.function %{
257
+ bool word_is_numeric (ResultIterator* it) {
258
+ return it->WordIsNumeric();
259
+ }
260
+ }
261
+
262
+ cpp.function %{
263
+ bool symbol_is_superscript (ResultIterator* it) {
264
+ return it->SymbolIsSuperscript();
265
+ }
266
+ }
267
+
268
+ cpp.function %{
269
+ bool symbol_is_subscript (ResultIterator* it) {
270
+ return it->SymbolIsSubscript();
271
+ }
272
+ }
273
+
274
+ cpp.function %{
275
+ bool symbol_is_dropcap (ResultIterator* it) {
276
+ return it->SymbolIsDropcap();
277
+ }
278
+ }
279
+ end
280
+ end
281
+
282
+ end; end
@@ -0,0 +1,88 @@
1
+ #--
2
+ # Copyright 2011 meh. All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without modification, are
5
+ # permitted provided that the following conditions are met:
6
+ #
7
+ # 1. Redistributions of source code must retain the above copyright notice, this list of
8
+ # conditions and the following disclaimer.
9
+ #
10
+ # THIS SOFTWARE IS PROVIDED BY meh ''AS IS'' AND ANY EXPRESS OR IMPLIED
11
+ # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
12
+ # FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL meh OR
13
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
14
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
15
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
16
+ # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
17
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
18
+ # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19
+ #
20
+ # The views and conclusions contained in the software and documentation are those of the
21
+ # authors and should not be interpreted as representing official policies, either expressed
22
+ # or implied, of meh.
23
+ #++
24
+
25
+ module Tesseract; module C
26
+
27
+ module Leptonica
28
+ extend FFI::Inliner
29
+
30
+ inline 'C++' do |cpp|
31
+ cpp.include 'leptonica/allheaders.h'
32
+ cpp.libraries 'lept'
33
+
34
+ cpp.eval {
35
+ enum :Format, [
36
+ :UNKNOWN, :BMP, :JFIF_JPEG, :PNG,
37
+ :TIFF, :TIFF_PACKBITS, :TIFF_RLE, :TIFF_G3, :TIFF_G4, :TIFF_LZW, :TIFF_ZIP,
38
+ :PNM, :PS, :GIF, :JP2, :WEBP, :LPDF, :DEFAULT, :SPIX
39
+ ]
40
+ }
41
+
42
+ cpp.typedef 'int32_t', 'Format'
43
+
44
+ cpp.function %{
45
+ Pix* pix_read (const char* path) {
46
+ return pixRead(path);
47
+ }
48
+ }
49
+
50
+ cpp.function %{
51
+ Pix* pix_read_fd (int fd) {
52
+ return pixReadStream(fdopen(fd, "rb"), 0);
53
+ }
54
+ }
55
+
56
+ cpp.function %{
57
+ Pix* pix_read_mem (const l_uint8* data, size_t size) {
58
+ return pixReadMem(data, size);
59
+ }
60
+ }
61
+
62
+ cpp.function %{
63
+ bool pix_write_mem (Pix* pix, uint8_t** data, size_t* size, Format format) {
64
+ return pixWriteMem(data, size, pix, format);
65
+ }
66
+ }
67
+
68
+ cpp.function %{
69
+ void pix_destroy (Pix* pix) {
70
+ pixDestroy(&pix);
71
+ }
72
+ }
73
+
74
+ cpp.function %{
75
+ int32_t pix_get_width (Pix* pix) {
76
+ return pixGetWidth(pix);
77
+ }
78
+ }
79
+
80
+ cpp.function %{
81
+ int32_t pix_get_height (Pix* pix) {
82
+ return pixGetHeight(pix);
83
+ }
84
+ }
85
+ end
86
+ end
87
+
88
+ end; end
@@ -24,6 +24,8 @@
24
24
 
25
25
  require 'tesseract/api'
26
26
 
27
+ require 'tesseract/engine/iterator'
28
+
27
29
  module Tesseract
28
30
 
29
31
  class Engine
@@ -32,16 +34,18 @@ class Engine
32
34
  namedic :path, :language, :mode, :variables,
33
35
  :optional => { :path => '.', :language => :eng, :mode => :DEFAULT, :variables => {}, :config => [] },
34
36
  :alias => { :data => :path, :lang => :language }
35
- def initialize (path = '.', language = :eng, mode = :DEFAULT, variables = {}, config = []) # :yields: self
37
+ def initialize (path = '.', language = :eng, mode = :DEFAULT, variables = {}, config = [], &block) # :yields: self
36
38
  @api = API.new
37
39
 
38
40
  @initializing = true
39
41
 
42
+ @init = block
40
43
  @path = path
41
44
  @language = language
42
45
  @mode = mode
43
46
  @variables = variables
44
47
  @config = config
48
+ @rectangle = []
45
49
 
46
50
  yield self if block_given?
47
51
 
@@ -65,7 +69,10 @@ class Engine
65
69
  end
66
70
 
67
71
  def with (&block) # :yields: self
68
- self.class.new(@path, @language, @mode, @variables.clone, &block)
72
+ self.class.new(@path, @language, @mode, @variables.clone, @config.clone) {|e|
73
+ @init.call(e) if @init
74
+ block.call(e) if block
75
+ }
69
76
  end
70
77
 
71
78
  def set (name, value)
@@ -111,35 +118,25 @@ class Engine
111
118
  end
112
119
 
113
120
  def page_segmentation_mode= (value)
114
- @api.page_seg_mode = if value.to_i >= 1 && value.to_i <= 10
115
- value.to_i
116
- else
117
- value.to_s.upcase.to_sym
118
- end
121
+ @api.set_page_seg_mode C.for_enum(value)
119
122
  end
120
123
 
121
124
  def image= (image)
122
125
  @image = image
123
126
  end
124
127
 
128
+ namedic :x, :y, :width, :height,
129
+ :optional => 0 .. -1,
130
+ :alias => { :w => :width, :h => :height }
131
+ def select (x = nil, y = nil, width = nil, height = nil)
132
+ @rectangle = [x, y, width, height]
133
+ end
134
+
125
135
  namedic :image, :x, :y, :width, :height,
126
136
  :optional => 0 .. -1,
127
137
  :alias => { :w => :width, :h => :height }
128
138
  def text_for (image = nil, x = nil, y = nil, width = nil, height = nil)
129
- image ||= @image or raise ArgumentError, 'you have to set an image first'
130
- image = API.image_for(image)
131
-
132
- x ||= 0
133
- y ||= 0
134
- width ||= image.width
135
- height ||= image.height
136
-
137
- if (x + width) > image.width || (y + height) > image.height
138
- raise IndexError, 'image access out of boundaries'
139
- end
140
-
141
- @api.set_image(image)
142
- @api.set_rectangle(x, y, width, height)
139
+ _setup(image, x, y, width, height)
143
140
 
144
141
  @api.get_text.tap {|text|
145
142
  text.instance_exec(@api) {|api|
@@ -160,61 +157,40 @@ class Engine
160
157
  text_for(nil, x, y, width, height)
161
158
  end
162
159
 
163
- def words_for (*args)
164
- _confidences(text_for(*args).split(/\s+/))
160
+ def text
161
+ text_at
165
162
  end
166
163
 
167
- def words_at (*args)
168
- _confidences(text_at(*args).split(/\s+/))
169
- end
164
+ %w(block paragraph line word symbol).each {|level|
165
+ define_method "each_#{level}" do |&block|
166
+ raise ArgumentError, 'you have to pass a block' unless block
170
167
 
171
- namedic :image, :page, :x, :y, :width, :height,
172
- :optional => 0 .. -1,
173
- :alias => { :w => :width, :h => :height }
174
- def chars_for (image = nil, page = nil, x = nil, y = nil, width = nil, height = nil)
175
- image ||= @image or raise ArgumentError, 'you have to set an image first'
176
- image = API.image_for(image)
177
-
178
- page ||= 0
179
- x ||= 0
180
- y ||= 0
181
- width ||= image.width
182
- height ||= image.height
183
-
184
- if (x + width) > image.width || (y + height) > image.height
185
- raise IndexError, 'image access out of boundaries'
168
+ _iterator.__send__ "each_#{level}", &block
186
169
  end
187
170
 
188
- @api.set_image(image)
189
- @api.set_rectangle(x, y, width, height)
190
-
191
- @api.get_box(page).lines.map {|line|
192
- char, x, y, width, height, page = line.chomp.split ' '
193
-
194
- char.instance_eval {
195
- @x = x.to_i
196
- @y = y.to_i
197
- @width = width.to_i
198
- @height = height.to_i
199
- @page = page.to_i
171
+ define_method "#{level}s" do
172
+ _iterator.__send__ "#{level}s"
173
+ end
200
174
 
201
- class << self
202
- attr_reader :x, :y, :width, :height, :page
203
- end
204
- }
175
+ namedic :image, :x, :y, :width, :height,
176
+ :optional => 0 .. -1,
177
+ :alias => { :w => :width, :h => :height }
178
+ define_method "#{level}s_for" do |image = nil, x = nil, y = nil, width = nil, height = nil|
179
+ self.image = image if image
180
+ select x, y, width, height
205
181
 
206
- char
207
- }
208
- end
182
+ __send__("#{level}s")
183
+ end
209
184
 
210
- namedic :page, :x, :y, :width, :height,
211
- :optional => 0 .. -1,
212
- :alias => { :w => :width, :h => :height }
213
- def chars_at (page = nil, x = nil, y = nil, width = nil, height = nil)
214
- chars_for(nil, page, x, y, width, height)
215
- end
185
+ namedic :x, :y, :width, :height,
186
+ :optional => 0 .. -1,
187
+ :alias => { :w => :width, :h => :height }
188
+ define_method "#{level}s_at" do |x = nil, y = nil, width = nil, height = nil|
189
+ __send__("#{level}s_for", nil, x, y, width, height)
190
+ end
191
+ }
216
192
 
217
- private
193
+ protected
218
194
  def _init
219
195
  @api.end
220
196
 
@@ -229,27 +205,41 @@ private
229
205
  }
230
206
  end
231
207
 
232
- def _confidences (words)
233
- pointer = @api.all_word_confidences
234
- current = 0
208
+ def _setup (image = nil, x = nil, y = nil, width = nil, height = nil)
209
+ image ||= @image or raise ArgumentError, 'you have to set an image first'
210
+ image = API.image_for(image)
235
211
 
236
- while (tmp = pointer.get_int(current)) != -1
237
- break unless words[current]
212
+ if !width && x
213
+ width = image.width - x
214
+ end
238
215
 
239
- words[current].instance_eval {
240
- @confidence = tmp
216
+ if !height && y
217
+ height = image.height - y
218
+ end
241
219
 
242
- class << self
243
- attr_reader :confidence
244
- end
245
- }
220
+ x ||= @rectangle[0] || 0
221
+ y ||= @rectangle[1] || 0
222
+ width ||= @rectangle[2] || image.width
223
+ height ||= @rectangle[3] || image.height
246
224
 
247
- current += 1
225
+ if (x + width) > image.width || (y + height) > image.height
226
+ raise IndexError, 'image access out of boundaries'
248
227
  end
249
228
 
250
- C::free_array_of_int(pointer)
229
+ @api.set_image(image)
230
+ @api.set_rectangle(x, y, width, height)
231
+ end
232
+
233
+ def _recognize
234
+ _setup
235
+
236
+ @api.get_text
237
+ end
238
+
239
+ def _iterator
240
+ _recognize
251
241
 
252
- words
242
+ Iterator.new(@api.get_iterator)
253
243
  end
254
244
  end
255
245