tesseract-ocr 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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