gocr-ruby 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +49 -0
- data/ext/gocr/Makefile +141 -0
- data/ext/gocr/Makefile.in +140 -0
- data/ext/gocr/amiga.h +31 -0
- data/ext/gocr/barcode.c +2108 -0
- data/ext/gocr/barcode.h +11 -0
- data/ext/gocr/box.c +496 -0
- data/ext/gocr/config.h +37 -0
- data/ext/gocr/config.h.in +36 -0
- data/ext/gocr/database.c +468 -0
- data/ext/gocr/detect.c +1003 -0
- data/ext/gocr/extconf.rb +6 -0
- data/ext/gocr/gocr.c +436 -0
- data/ext/gocr/gocr.h +290 -0
- data/ext/gocr/jconv.c +168 -0
- data/ext/gocr/job.c +92 -0
- data/ext/gocr/lines.c +364 -0
- data/ext/gocr/list.c +334 -0
- data/ext/gocr/list.h +91 -0
- data/ext/gocr/ocr0.c +7312 -0
- data/ext/gocr/ocr0.h +63 -0
- data/ext/gocr/ocr0n.c +1527 -0
- data/ext/gocr/ocr1.c +85 -0
- data/ext/gocr/ocr1.h +3 -0
- data/ext/gocr/otsu.c +310 -0
- data/ext/gocr/otsu.h +23 -0
- data/ext/gocr/output.c +291 -0
- data/ext/gocr/output.h +37 -0
- data/ext/gocr/pcx.c +153 -0
- data/ext/gocr/pcx.h +9 -0
- data/ext/gocr/pgm2asc.c +3259 -0
- data/ext/gocr/pgm2asc.h +105 -0
- data/ext/gocr/pixel.c +538 -0
- data/ext/gocr/pnm.c +538 -0
- data/ext/gocr/pnm.h +35 -0
- data/ext/gocr/progress.c +87 -0
- data/ext/gocr/progress.h +42 -0
- data/ext/gocr/remove.c +715 -0
- data/ext/gocr/tga.c +87 -0
- data/ext/gocr/tga.h +6 -0
- data/ext/gocr/unicode.c +1318 -0
- data/ext/gocr/unicode.h +62 -0
- data/ext/gocr/unicode_defs.h +1245 -0
- data/ext/gocr/version.h +2 -0
- data/gocr-ruby.gemspec +28 -0
- data/image.png +0 -0
- data/lib/gocr.rb +6 -0
- data/lib/gocr/image.rb +8 -0
- data/lib/gocr/version.rb +3 -0
- metadata +156 -0
data/ext/gocr/extconf.rb
ADDED
data/ext/gocr/gocr.c
ADDED
@@ -0,0 +1,436 @@
|
|
1
|
+
/*
|
2
|
+
This is a Optical-Character-Recognition program
|
3
|
+
Copyright (C) GPLv2 2000-2013 Joerg Schulenburg
|
4
|
+
|
5
|
+
This program is free software; you can redistribute it and/or
|
6
|
+
modify it under the terms of the GNU General Public License
|
7
|
+
as published by the Free Software Foundation; either version 2
|
8
|
+
of the License, or (at your option) any later version.
|
9
|
+
|
10
|
+
This program is distributed in the hope that it will be useful,
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
GNU General Public License for more details.
|
14
|
+
|
15
|
+
You should have received a copy of the GNU General Public License
|
16
|
+
along with this program; if not, write to the Free Software
|
17
|
+
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
18
|
+
|
19
|
+
see README for EMAIL-address
|
20
|
+
|
21
|
+
sometimes I have written comments in german language, sorry for that
|
22
|
+
|
23
|
+
This file was retrieved from pgm2asc.cc of Joerg, in order to have
|
24
|
+
a library of the ocr-engine from Klaas Freitag
|
25
|
+
|
26
|
+
*/
|
27
|
+
#include "config.h"
|
28
|
+
#include <stdlib.h>
|
29
|
+
#include <stdio.h>
|
30
|
+
#include <assert.h>
|
31
|
+
#include <string.h>
|
32
|
+
#ifdef HAVE_GETTIMEOFDAY
|
33
|
+
#include <sys/time.h>
|
34
|
+
#endif
|
35
|
+
#ifdef HAVE_UNISTD_H
|
36
|
+
#include <unistd.h>
|
37
|
+
#endif
|
38
|
+
|
39
|
+
#include "pnm.h"
|
40
|
+
#include "pgm2asc.h"
|
41
|
+
#include "pcx.h"
|
42
|
+
#include "ocr0.h" /* only_numbers */
|
43
|
+
#include "progress.h"
|
44
|
+
#include "version.h"
|
45
|
+
#include "ruby.h"
|
46
|
+
|
47
|
+
/*
|
48
|
+
#ifndef RSTRING_PTR
|
49
|
+
#define RSTRING_PTR(s) (RSTRING(s))
|
50
|
+
#endif
|
51
|
+
#ifndef RSTRING_LEN
|
52
|
+
#define RSTRING_LEN(s) (RSTRING(s))
|
53
|
+
#endif
|
54
|
+
*/
|
55
|
+
static void out_version(int v) {
|
56
|
+
fprintf(stderr, " Optical Character Recognition --- gocr "
|
57
|
+
version_string " " release_string "\n"
|
58
|
+
" Copyright (C) 2001-2010 Joerg Schulenburg GPG=1024D/53BDFBE3\n"
|
59
|
+
" released under the GNU General Public License\n");
|
60
|
+
/* as recommended, (c) and license should be part of the binary */
|
61
|
+
/* no email because of SPAM, see README for contacting the author */
|
62
|
+
if (v)
|
63
|
+
fprintf(stderr, " use option -h for help\n");
|
64
|
+
if (v & 2)
|
65
|
+
exit(1);
|
66
|
+
return;
|
67
|
+
}
|
68
|
+
|
69
|
+
static void help(void) {
|
70
|
+
out_version(0);
|
71
|
+
/* output is shortened to essentials, see manual page for details */
|
72
|
+
fprintf(stderr,
|
73
|
+
" using: gocr [options] pnm_file_name # use - for stdin\n"
|
74
|
+
" options (see gocr manual pages for more details):\n"
|
75
|
+
" -h, --help\n"
|
76
|
+
" -i name - input image file (pnm,pgm,pbm,ppm,pcx,...)\n"
|
77
|
+
" -o name - output file (redirection of stdout)\n"
|
78
|
+
" -e name - logging file (redirection of stderr)\n"
|
79
|
+
" -x name - progress output to fifo (see manual)\n"
|
80
|
+
" -p name - database path including final slash (default is ./db/)\n");
|
81
|
+
fprintf(stderr, /* string length less than 509 bytes for ISO C89 */
|
82
|
+
" -f fmt - output format (ISO8859_1 TeX HTML XML UTF8 ASCII)\n"
|
83
|
+
" -l num - threshold grey level 0<160<=255 (0 = autodetect)\n"
|
84
|
+
" -d num - dust_size (remove small clusters, -1 = autodetect)\n"
|
85
|
+
" -s num - spacewidth/dots (0 = autodetect)\n"
|
86
|
+
" -v num - verbose (see manual page)\n"
|
87
|
+
" -c string - list of chars (debugging, see manual)\n"
|
88
|
+
" -C string - char filter (ex. hexdigits: ""0-9A-Fx"", only ASCII)\n"
|
89
|
+
" -m num - operation modes (bitpattern, see manual)\n");
|
90
|
+
fprintf(stderr, /* string length less than 509 bytes for ISO C89 */
|
91
|
+
" -a num - value of certainty (in percent, 0..100, default=95)\n"
|
92
|
+
" -u string - output this string for every unrecognized character\n");
|
93
|
+
fprintf(stderr, /* string length less than 509 bytes for ISO C89 */
|
94
|
+
" examples:\n"
|
95
|
+
"\tgocr -m 4 text1.pbm # do layout analyzis\n"
|
96
|
+
"\tgocr -m 130 -p ./database/ text1.pbm # extend database\n"
|
97
|
+
"\tdjpeg -pnm -gray text.jpg | gocr - # use jpeg-file via pipe\n"
|
98
|
+
"\n");
|
99
|
+
fprintf(stderr, " webpage: http://jocr.sourceforge.net/ (may out of date)\n");
|
100
|
+
fprintf(stderr, " mirror: http://www-e.uni-magdeburg.de/jschulen/ocr/\n");
|
101
|
+
exit(0);
|
102
|
+
}
|
103
|
+
|
104
|
+
#ifdef HAVE_GETTIMEOFDAY
|
105
|
+
/* from the glibc documentation */
|
106
|
+
static int timeval_subtract (struct timeval *result, struct timeval *x,
|
107
|
+
struct timeval *y) {
|
108
|
+
|
109
|
+
/* Perform the carry for the later subtraction by updating Y. */
|
110
|
+
if (x->tv_usec < y->tv_usec) {
|
111
|
+
int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
|
112
|
+
y->tv_usec -= 1000000 * nsec;
|
113
|
+
y->tv_sec += nsec;
|
114
|
+
}
|
115
|
+
if (x->tv_usec - y->tv_usec > 1000000) {
|
116
|
+
int nsec = (x->tv_usec - y->tv_usec) / 1000000;
|
117
|
+
y->tv_usec += 1000000 * nsec;
|
118
|
+
y->tv_sec -= nsec;
|
119
|
+
}
|
120
|
+
|
121
|
+
/* Compute the time remaining to wait.
|
122
|
+
`tv_usec' is certainly positive. */
|
123
|
+
result->tv_sec = x->tv_sec - y->tv_sec;
|
124
|
+
result->tv_usec = x->tv_usec - y->tv_usec;
|
125
|
+
|
126
|
+
/* Return 1 if result is negative. */
|
127
|
+
return x->tv_sec < y->tv_sec;
|
128
|
+
}
|
129
|
+
#endif
|
130
|
+
|
131
|
+
static void process_arguments(job_t *job, int argn, char *argv[])
|
132
|
+
{
|
133
|
+
int i;
|
134
|
+
char *s1;
|
135
|
+
|
136
|
+
assert(job);
|
137
|
+
|
138
|
+
if (argn <= 1) {
|
139
|
+
out_version(1);
|
140
|
+
exit(0);
|
141
|
+
}
|
142
|
+
#ifdef HAVE_PGM_H
|
143
|
+
pnm_init(&argn, &argv);
|
144
|
+
#endif
|
145
|
+
|
146
|
+
/* process arguments */
|
147
|
+
for (i = 1; i < argn; i++) {
|
148
|
+
if (strcmp(argv[i], "--help") == 0)
|
149
|
+
help(); /* and quits */
|
150
|
+
if (argv[i][0] == '-' && argv[i][1] != 0) {
|
151
|
+
s1 = "";
|
152
|
+
if (i + 1 < argn)
|
153
|
+
s1 = argv[i + 1];
|
154
|
+
switch (argv[i][1]) {
|
155
|
+
case 'h': /* help */
|
156
|
+
help();
|
157
|
+
break;
|
158
|
+
case 'i': /* input image file */
|
159
|
+
job->src.fname = s1;
|
160
|
+
i++;
|
161
|
+
break;
|
162
|
+
case 'e': /* logging file */
|
163
|
+
if (s1[0] == '-' && s1[1] == '\0') {
|
164
|
+
#ifdef HAVE_UNISTD_H
|
165
|
+
dup2(STDOUT_FILENO, STDERR_FILENO); /* -e /dev/stdout works */
|
166
|
+
#else
|
167
|
+
fprintf(stderr, "stderr redirection not possible without unistd.h\n");
|
168
|
+
#endif
|
169
|
+
}
|
170
|
+
else if (!freopen(s1, "w", stderr)) {
|
171
|
+
fprintf(stderr, "stderr redirection to %s failed\n", s1);
|
172
|
+
}
|
173
|
+
i++;
|
174
|
+
break;
|
175
|
+
case 'p': /* database path */
|
176
|
+
job->cfg.db_path=s1;
|
177
|
+
i++;
|
178
|
+
break;
|
179
|
+
case 'o': /* output file */
|
180
|
+
if (s1[0] == '-' && s1[1] == '\0') { /* default */
|
181
|
+
}
|
182
|
+
else if (!freopen(s1, "w", stdout)) {
|
183
|
+
fprintf(stderr, "stdout redirection to %s failed\n", s1);
|
184
|
+
};
|
185
|
+
i++;
|
186
|
+
break;
|
187
|
+
case 'f': /* output format */
|
188
|
+
if (strcmp(s1, "ISO8859_1") == 0) job->cfg.out_format=ISO8859_1; else
|
189
|
+
if (strcmp(s1, "TeX") == 0) job->cfg.out_format=TeX; else
|
190
|
+
if (strcmp(s1, "HTML") == 0) job->cfg.out_format=HTML; else
|
191
|
+
if (strcmp(s1, "XML") == 0) job->cfg.out_format=XML; else
|
192
|
+
if (strcmp(s1, "SGML") == 0) job->cfg.out_format=SGML; else
|
193
|
+
if (strcmp(s1, "UTF8") == 0) job->cfg.out_format=UTF8; else
|
194
|
+
if (strcmp(s1, "ASCII") == 0) job->cfg.out_format=ASCII; else
|
195
|
+
fprintf(stderr,"Warning: unknown format (-f %s)\n",s1);
|
196
|
+
i++;
|
197
|
+
break;
|
198
|
+
case 'c': /* list of chars (_ = not recognized chars) */
|
199
|
+
job->cfg.lc = s1;
|
200
|
+
i++;
|
201
|
+
break;
|
202
|
+
case 'C': /* char filter, default: NULL (all chars) */
|
203
|
+
/* ToDo: UTF8 input, wchar */
|
204
|
+
job->cfg.cfilter = s1;
|
205
|
+
i++;
|
206
|
+
break;
|
207
|
+
case 'd': /* dust size */
|
208
|
+
job->cfg.dust_size = atoi(s1);
|
209
|
+
i++;
|
210
|
+
break;
|
211
|
+
case 'l': /* grey level 0<160<=255, 0 for autodetect */
|
212
|
+
job->cfg.cs = atoi(s1);
|
213
|
+
i++;
|
214
|
+
break;
|
215
|
+
case 's': /* spacewidth/dots (0 = autodetect) */
|
216
|
+
job->cfg.spc = atoi(s1);
|
217
|
+
i++;
|
218
|
+
break;
|
219
|
+
case 'v': /* verbose mode */
|
220
|
+
job->cfg.verbose |= atoi(s1);
|
221
|
+
i++;
|
222
|
+
break;
|
223
|
+
case 'm': /* operation modes */
|
224
|
+
job->cfg.mode |= atoi(s1);
|
225
|
+
i++;
|
226
|
+
break;
|
227
|
+
case 'n': /* numbers only */
|
228
|
+
job->cfg.only_numbers = atoi(s1);
|
229
|
+
i++;
|
230
|
+
break;
|
231
|
+
case 'x': /* initialize progress output s1=fname */
|
232
|
+
ini_progress(s1);
|
233
|
+
i++;
|
234
|
+
break;
|
235
|
+
case 'a': /* set certainty */
|
236
|
+
job->cfg.certainty = atoi(s1);;
|
237
|
+
i++;
|
238
|
+
break;
|
239
|
+
case 'u': /* output marker for unrecognized chars */
|
240
|
+
job->cfg.unrec_marker = s1;
|
241
|
+
i++;
|
242
|
+
break;
|
243
|
+
default:
|
244
|
+
fprintf(stderr, "# unknown option use -h for help\n");
|
245
|
+
}
|
246
|
+
continue;
|
247
|
+
}
|
248
|
+
else /* argument can be filename v0.2.5 */ if (argv[i][0] != '-'
|
249
|
+
|| argv[i][1] == '\0' ) {
|
250
|
+
job->src.fname = argv[i];
|
251
|
+
}
|
252
|
+
}
|
253
|
+
}
|
254
|
+
|
255
|
+
static void mark_start(job_t *job) {
|
256
|
+
assert(job);
|
257
|
+
|
258
|
+
if (job->cfg.verbose) {
|
259
|
+
out_version(0);
|
260
|
+
/* insert some helpful info for support */
|
261
|
+
fprintf(stderr, "# compiled: " __DATE__ );
|
262
|
+
#if defined(__GNUC__)
|
263
|
+
fprintf(stderr, " GNUC-%d", __GNUC__ );
|
264
|
+
#endif
|
265
|
+
#ifdef __GNUC_MINOR__
|
266
|
+
fprintf(stderr, ".%d", __GNUC_MINOR__ );
|
267
|
+
#endif
|
268
|
+
#if defined(__linux)
|
269
|
+
fprintf(stderr, " linux");
|
270
|
+
#elif defined(__unix)
|
271
|
+
fprintf(stderr, " unix");
|
272
|
+
#endif
|
273
|
+
#if defined(__WIN32) || defined(__WIN32__)
|
274
|
+
fprintf(stderr, " WIN32");
|
275
|
+
#endif
|
276
|
+
#if defined(__WIN64) || defined(__WIN64__)
|
277
|
+
fprintf(stderr, " WIN64");
|
278
|
+
#endif
|
279
|
+
#if defined(__VERSION__)
|
280
|
+
fprintf(stderr, " version " __VERSION__ );
|
281
|
+
#endif
|
282
|
+
fprintf(stderr, "\n");
|
283
|
+
fprintf(stderr,
|
284
|
+
"# options are: -l %d -s %d -v %d -c %s -m %d -d %d -n %d -a %d -C \"%s\"\n",
|
285
|
+
job->cfg.cs, job->cfg.spc, job->cfg.verbose, job->cfg.lc, job->cfg.mode,
|
286
|
+
job->cfg.dust_size, job->cfg.only_numbers, job->cfg.certainty,
|
287
|
+
job->cfg.cfilter);
|
288
|
+
fprintf(stderr, "# file: %s\n", job->src.fname);
|
289
|
+
#ifdef USE_UNICODE
|
290
|
+
fprintf(stderr,"# using unicode\n");
|
291
|
+
#endif
|
292
|
+
#ifdef HAVE_GETTIMEOFDAY
|
293
|
+
gettimeofday(&job->tmp.init_time, NULL);
|
294
|
+
#endif
|
295
|
+
}
|
296
|
+
}
|
297
|
+
|
298
|
+
static void mark_end(job_t *job) {
|
299
|
+
assert(job);
|
300
|
+
|
301
|
+
#ifdef HAVE_GETTIMEOFDAY
|
302
|
+
/* show elapsed time */
|
303
|
+
if (job->cfg.verbose) {
|
304
|
+
struct timeval end, result;
|
305
|
+
gettimeofday(&end, NULL);
|
306
|
+
timeval_subtract(&result, &end, &job->tmp.init_time);
|
307
|
+
fprintf(stderr,"Elapsed time: %d:%02d:%3.3f.\n", (int)result.tv_sec/60,
|
308
|
+
(int)result.tv_sec%60, (float)result.tv_usec/1000);
|
309
|
+
}
|
310
|
+
#endif
|
311
|
+
}
|
312
|
+
|
313
|
+
static int read_picture(job_t *job) {
|
314
|
+
int rc=0;
|
315
|
+
assert(job);
|
316
|
+
|
317
|
+
if (strstr(job->src.fname, ".pcx"))
|
318
|
+
readpcx(job->src.fname, &job->src.p, job->cfg.verbose);
|
319
|
+
else
|
320
|
+
rc=readpgm(job->src.fname, &job->src.p, job->cfg.verbose);
|
321
|
+
return rc; /* 1 for multiple images, -1 on error, 0 else */
|
322
|
+
}
|
323
|
+
|
324
|
+
/* subject of change, we need more output for XML (ToDo) */
|
325
|
+
void print_output(job_t *job) {
|
326
|
+
int linecounter = 0;
|
327
|
+
const char *line;
|
328
|
+
|
329
|
+
assert(job);
|
330
|
+
|
331
|
+
/* TODO: replace getTextLine-loop(line) by output_text() (libs have to use pipes)
|
332
|
+
simplify code 2010-09-26
|
333
|
+
*/
|
334
|
+
linecounter = 0;
|
335
|
+
line = getTextLine(&(job->res.linelist), linecounter++);
|
336
|
+
while (line) {
|
337
|
+
/* notice: decode() is shiftet to getTextLine since 0.38 */
|
338
|
+
fputs(line, stdout);
|
339
|
+
if (job->cfg.out_format==HTML) fputs("<br />",stdout);
|
340
|
+
if (job->cfg.out_format!=XML) fputc('\n', stdout);
|
341
|
+
line = getTextLine(&(job->res.linelist), linecounter++);
|
342
|
+
}
|
343
|
+
free_textlines(&(job->res.linelist));
|
344
|
+
}
|
345
|
+
|
346
|
+
/* FIXME jb: remove JOB; renamed to OCR_JOB 2010-09-26 */
|
347
|
+
job_t *OCR_JOB;
|
348
|
+
|
349
|
+
|
350
|
+
char* gocr_recognize(char* filename) {
|
351
|
+
char* line;
|
352
|
+
int multipnm=1;
|
353
|
+
job_t job1, *job; /* fixme, dont want global variables for lib */
|
354
|
+
job=OCR_JOB=&job1;
|
355
|
+
|
356
|
+
setvbuf(stdout, (char *) NULL, _IONBF, 0); /* not buffered */
|
357
|
+
|
358
|
+
job_init(job); /* init cfg and db */
|
359
|
+
job->src.fname = filename;
|
360
|
+
/* load character data base (JS1002: now outside pgm2asc) */
|
361
|
+
if ( job->cfg.mode & 2 ) /* check for db-option flag */
|
362
|
+
load_db(job);
|
363
|
+
/* load_db uses readpnm() and would conflict with multi images */
|
364
|
+
|
365
|
+
job_init_image(job); /* single image */
|
366
|
+
mark_start(job);
|
367
|
+
read_picture(job);
|
368
|
+
|
369
|
+
pgm2asc(job);
|
370
|
+
mark_end(job);
|
371
|
+
line = getTextLine(&(job->res.linelist), 0);
|
372
|
+
job_free_image(job);
|
373
|
+
return line;
|
374
|
+
}
|
375
|
+
|
376
|
+
|
377
|
+
static VALUE image_recognize(VALUE self, VALUE arg) {
|
378
|
+
char* filename = StringValuePtr(arg);
|
379
|
+
return rb_str_new2( gocr_recognize(filename) );
|
380
|
+
}
|
381
|
+
|
382
|
+
/*
|
383
|
+
* @brief define ruby class GOCR::Image and method recognize
|
384
|
+
*
|
385
|
+
*/
|
386
|
+
void Init_gocr() {
|
387
|
+
VALUE mGocr = rb_define_module("GOCR");
|
388
|
+
VALUE mImage = rb_define_class_under(mGocr, "Image", rb_cObject);
|
389
|
+
rb_define_singleton_method(mImage, "recognize", image_recognize, 1);
|
390
|
+
}
|
391
|
+
|
392
|
+
|
393
|
+
/* -------------------------------------------------------------
|
394
|
+
// ------ MAIN - replace this by your own aplication!
|
395
|
+
// ------------------------------------------------------------- */
|
396
|
+
//int main(int argn, char *argv[]) {
|
397
|
+
// int multipnm=1;
|
398
|
+
// job_t job1, *job; /* fixme, dont want global variables for lib */
|
399
|
+
// job=OCR_JOB=&job1;
|
400
|
+
//
|
401
|
+
// setvbuf(stdout, (char *) NULL, _IONBF, 0); /* not buffered */
|
402
|
+
//
|
403
|
+
// job_init(job); /* init cfg and db */
|
404
|
+
//
|
405
|
+
// process_arguments(job, argn, argv);
|
406
|
+
//
|
407
|
+
// /* load character data base (JS1002: now outside pgm2asc) */
|
408
|
+
// if ( job->cfg.mode & 2 ) /* check for db-option flag */
|
409
|
+
// load_db(job);
|
410
|
+
// /* load_db uses readpnm() and would conflict with multi images */
|
411
|
+
//
|
412
|
+
// while (multipnm==1) { /* multi-image loop */
|
413
|
+
//
|
414
|
+
// job_init_image(job); /* single image */
|
415
|
+
//
|
416
|
+
// mark_start(job);
|
417
|
+
//
|
418
|
+
// multipnm = read_picture(job);
|
419
|
+
// /* separation of main and rest for using as lib
|
420
|
+
// this will be changed later => introduction of set_option()
|
421
|
+
// for better communication to the engine */
|
422
|
+
// if (multipnm<0) break; /* read error */
|
423
|
+
//
|
424
|
+
// /* call main loop */
|
425
|
+
// pgm2asc(job);
|
426
|
+
//
|
427
|
+
// mark_end(job);
|
428
|
+
//
|
429
|
+
// print_output(job);
|
430
|
+
//
|
431
|
+
// job_free_image(job);
|
432
|
+
//
|
433
|
+
// }
|
434
|
+
//
|
435
|
+
// return ((multipnm<0)?multipnm:0); /* -1=255 on error, 0 ok */
|
436
|
+
//}
|
data/ext/gocr/gocr.h
ADDED
@@ -0,0 +1,290 @@
|
|
1
|
+
/*
|
2
|
+
This is a Optical-Character-Recognition program
|
3
|
+
Copyright (C) 2000-2010 Joerg Schulenburg
|
4
|
+
|
5
|
+
This program is free software; you can redistribute it and/or
|
6
|
+
modify it under the terms of the GNU General Public License
|
7
|
+
as published by the Free Software Foundation; either version 2
|
8
|
+
of the License, or (at your option) any later version.
|
9
|
+
|
10
|
+
This program is distributed in the hope that it will be useful,
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
GNU General Public License for more details.
|
14
|
+
|
15
|
+
You should have received a copy of the GNU General Public License
|
16
|
+
along with this program; if not, write to the Free Software
|
17
|
+
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
18
|
+
|
19
|
+
see README for EMAIL-address
|
20
|
+
|
21
|
+
sometimes I have written comments in german language, sorry for that
|
22
|
+
|
23
|
+
- look for ??? for preliminary code
|
24
|
+
*/
|
25
|
+
|
26
|
+
/* General headerfile with gocr-definitions */
|
27
|
+
|
28
|
+
#ifndef __GOCR_H__
|
29
|
+
#define __GOCR_H__
|
30
|
+
|
31
|
+
#include "pnm.h"
|
32
|
+
#include "unicode.h" /* FORMAT definition */
|
33
|
+
#include "list.h"
|
34
|
+
#include <stddef.h>
|
35
|
+
#ifdef HAVE_GETTIMEOFDAY
|
36
|
+
#include <sys/time.h>
|
37
|
+
#endif
|
38
|
+
|
39
|
+
/*
|
40
|
+
* wchar_t should always exist (ANSI), but WCHAR.H is sometimes missing
|
41
|
+
* USE_UNICODE should be removed or replaced by HAVE_WCHAR_H in future
|
42
|
+
*/
|
43
|
+
#ifdef HAVE_WCHAR_H
|
44
|
+
#define USE_UNICODE 1
|
45
|
+
#endif
|
46
|
+
|
47
|
+
/* extern "C"{ */
|
48
|
+
/* ------------------------ feature extraction ----------------- */
|
49
|
+
#define AT 7 /* mark */
|
50
|
+
#define M1 1 /* mark */
|
51
|
+
enum direction {
|
52
|
+
UP=1, DO, RI, LE
|
53
|
+
};
|
54
|
+
typedef enum direction DIRECTION;
|
55
|
+
#define ST 7 /* stop */
|
56
|
+
/* ------------------------------------------------------------- */
|
57
|
+
/* detect maximas in of line overlapps (return in %) and line koord */
|
58
|
+
#define HOR 1 /* horizontal */
|
59
|
+
#define VER 2 /* vertikal */
|
60
|
+
#define RIS 3 /* rising=steigend */
|
61
|
+
#define FAL 4 /* falling=fallend */
|
62
|
+
|
63
|
+
#define MAXlines 1024
|
64
|
+
|
65
|
+
/* ToDo: if we have a tree instead of a list, a line could be a node object */
|
66
|
+
struct tlines {
|
67
|
+
int num;
|
68
|
+
int dx, dy; /* direction of text lines (straight/skew) */
|
69
|
+
int m1[MAXlines], /* start of line = upper bound of 'A' */
|
70
|
+
m2[MAXlines], /* upper bound of 'e' */
|
71
|
+
m3[MAXlines], /* lower bound of 'e' = baseline */
|
72
|
+
m4[MAXlines]; /* stop of line = lower bound of 'q' */
|
73
|
+
/* ToDo: add sureness per m1,m2 etc? */
|
74
|
+
int x0[MAXlines],
|
75
|
+
x1[MAXlines]; /* left and right border */
|
76
|
+
int wt[MAXlines]; /* weight, how sure thats correct in percent, v0.41 */
|
77
|
+
int pitch[MAXlines]; /* word pitch (later per box?), v0.41 */
|
78
|
+
int mono[MAXlines]; /* spacing type, 0=proportional, 1=monospaced */
|
79
|
+
};
|
80
|
+
|
81
|
+
#define NumAlt 10 /* maximal number of alternative chars (table length) */
|
82
|
+
#define MaxNumFrames 8 /* maximum number of frames per char/box */
|
83
|
+
#define MaxFrameVectors 128 /* maximum vectors per frame (*8=1KB/box) */
|
84
|
+
/* ToDo: use only malloc_box(),free_box(),copybox() for creation, destroy etc.
|
85
|
+
* adding reference_counter to avoid pointer pointing to freed box
|
86
|
+
*/
|
87
|
+
struct box { /* this structure should contain all pixel infos of a letter */
|
88
|
+
int x0,x1,y0,y1,x,y,dots; /* xmin,xmax,ymin,ymax,reference-pixel,i-dots */
|
89
|
+
int num_boxes, /* 1 "abc", 2 "!i?", 3 "ä" (composed objects) 0.41 */
|
90
|
+
num_subboxes; /* 1 for "abdegopqADOPQR", 2 for "B" (holes) 0.41 */
|
91
|
+
wchar_t c; /* detected char (same as tac[0], obsolete?) */
|
92
|
+
wchar_t modifier; /* default=0, see compose() in unicode.c */
|
93
|
+
int num; /* same number = same char */
|
94
|
+
int line; /* line number (points to struct tlines lines) */
|
95
|
+
int m1,m2,m3,m4; /* m2 = upper boundary, m3 = baseline */
|
96
|
+
/* planed: sizeof hole_1, hole_2, certainty (run1=100%,run2=90%,etc.) */
|
97
|
+
pix *p; /* pointer to pixmap (v0.2.5) */
|
98
|
+
/* tac, wac is used together with setac() to manage very similar chars */
|
99
|
+
int num_ac; /* length of table (alternative chars), default=0 */
|
100
|
+
wchar_t tac[NumAlt]; /* alternative chars, only used by setac(),getac() */
|
101
|
+
int wac[NumAlt]; /* weight of alternative chars */
|
102
|
+
char *tas[NumAlt]; /* alternative UTF8-strings or XML codes if tac[]=0 */
|
103
|
+
/* replacing old obj */
|
104
|
+
/* ToDo: (*obj)[NumAlt] + olen[NumAlt] ??? */
|
105
|
+
/* ToDo: bitmap for possible Picture|Object|Char ??? */
|
106
|
+
/* char *obj; */ /* pointer to text-object ... -> replaced by tas[] */
|
107
|
+
/* ... (melted chars, barcode, picture coords, ...) */
|
108
|
+
/* must be freed before box is freed! */
|
109
|
+
/* do _not_ copy only the pointer to object */
|
110
|
+
/* --------------------------------------------------------
|
111
|
+
* extension since v0.41 js05, Store frame vectors,
|
112
|
+
* which is a table of vectors sourrounding the char and its
|
113
|
+
* inner white holes. The advantage is the independence from
|
114
|
+
* resolution, handling of holes, overlap and rotation.
|
115
|
+
* --------------------------------------------------------- */
|
116
|
+
int num_frames; /* number of frames: 1 for cfhklmnrstuvwxyz */
|
117
|
+
/* 2 for abdegijopq */
|
118
|
+
int frame_vol[MaxNumFrames]; /* volume inside frame +/- (black/white) */
|
119
|
+
int frame_per[MaxNumFrames]; /* periphery, summed length of vectors */
|
120
|
+
int num_frame_vectors[MaxNumFrames]; /* index to next frame */
|
121
|
+
/* biggest frame should be stored first (outer frame) */
|
122
|
+
/* biggest has the maximum pair distance */
|
123
|
+
/* num vector loops */
|
124
|
+
int frame_vector[MaxFrameVectors][2]; /* may be 16*int=fixpoint_number */
|
125
|
+
|
126
|
+
};
|
127
|
+
typedef struct box Box;
|
128
|
+
|
129
|
+
/* true if the coordination pair (a,b) is outside the image p */
|
130
|
+
#define outbounds(p, a, b) (a < 0 || b < 0 || a >= (p)->x || b >= (p)->y)
|
131
|
+
|
132
|
+
/* ToDo: this structure seems to be obsolete, remove it */
|
133
|
+
typedef struct path {
|
134
|
+
int start; /* color at the beginning of the path, (0=white, 1=black) */
|
135
|
+
int *x; /* x coordinates of transitions */
|
136
|
+
int *y; /* y coordinates of transitions */
|
137
|
+
int num; /* current number of entries in x or y */
|
138
|
+
int max; /* maximum number of entries in x or y */
|
139
|
+
/* (if more values need to be stored, the arrays are enlarged) */
|
140
|
+
} path_t;
|
141
|
+
|
142
|
+
/* job_t contains all information needed for an OCR task */
|
143
|
+
typedef struct job_s {
|
144
|
+
struct { /* source data */
|
145
|
+
char *fname; /* input filename; default value: "-" */
|
146
|
+
pix p; /* source pixel data, pixelmap 8bit gray */
|
147
|
+
} src;
|
148
|
+
struct { /* temporary stuff, e.g. buffers */
|
149
|
+
#ifdef HAVE_GETTIMEOFDAY
|
150
|
+
struct timeval init_time; /* starting time of this job */
|
151
|
+
#endif
|
152
|
+
pix ppo; /* pixmap for visual debugging output, obsolete */
|
153
|
+
|
154
|
+
/* sometimes recognition function is called again and again, if result was 0
|
155
|
+
n_run tells the pixel function to return alternative results */
|
156
|
+
int n_run; /* num of run, if run_2 critical pattern get other results */
|
157
|
+
/* used for 2nd try, pixel uses slower filter function etc. */
|
158
|
+
List dblist; /* list of boxes loaded from the character database */
|
159
|
+
} tmp;
|
160
|
+
struct { /* results */
|
161
|
+
List boxlist; /* store every object in a box, which contains */
|
162
|
+
/* the characteristics of the object (see struct box) */
|
163
|
+
List linelist; /* recognized text lines after recognition */
|
164
|
+
|
165
|
+
struct tlines lines; /* used to access to line-data (statistics) */
|
166
|
+
/* here the positions (frames) of lines are */
|
167
|
+
/* stored for further use */
|
168
|
+
int avX,avY; /* average X,Y (avX=sumX/numC) */
|
169
|
+
int sumX,sumY,numC; /* sum of all X,Y; num chars */
|
170
|
+
} res;
|
171
|
+
struct { /* configuration */
|
172
|
+
int cs; /* critical grey value (pixel<cs => black pixel) */
|
173
|
+
/* range: 0..255, 0 means autodetection */
|
174
|
+
int spc; /* spacewidth/dots (0 = autodetect); default value: 0 */
|
175
|
+
int mode; /* operation modes; default value: 0 */
|
176
|
+
/* operation mode (see --help) */
|
177
|
+
int dust_size; /* dust size; default value: 10 */
|
178
|
+
int only_numbers; /* numbers only; default value: 0 */
|
179
|
+
int verbose; /* verbose mode; default value: 0 */
|
180
|
+
/* verbose option (see --help) */
|
181
|
+
FORMAT out_format; /* output format; default value: ISO8859_1 */
|
182
|
+
char *lc; /* debuglist of chars (_ = not recognized chars) */
|
183
|
+
/* default value: "_" */
|
184
|
+
char *db_path; /* pathname for database; default value: NULL */
|
185
|
+
char *cfilter; /* char filter; default value: NULL, ex: "A-Za-z" */
|
186
|
+
/* limit of certainty where chars are accepted as identified */
|
187
|
+
int certainty; /* in units of 100 (percent); 0..100; default 95 */
|
188
|
+
char *unrec_marker; /* output this string for every unrecognized char */
|
189
|
+
} cfg;
|
190
|
+
} job_t;
|
191
|
+
|
192
|
+
/* initialze job structure */
|
193
|
+
void job_init(job_t *job); /* once for cfg and db */
|
194
|
+
void job_init_image(job_t *job); /* for each of a multiimage */
|
195
|
+
|
196
|
+
/* free job structure */
|
197
|
+
void job_free_image(job_t *job); /* for each of a multiimage */
|
198
|
+
|
199
|
+
/* FIXME jb: remove JOB; 2010-09-25 renamed to OCR_JOB */
|
200
|
+
/* as a first step OCR_JOB will be remain in DO_DEBUG mode only */
|
201
|
+
extern job_t *OCR_JOB;
|
202
|
+
|
203
|
+
/* calculate the overlapp of the line (0-1) with black points
|
204
|
+
* by rekursiv bisection
|
205
|
+
* (evl. Fehlertoleranz mit pixel in Umgebung dx,dy suchen) (umschaltbar) ???
|
206
|
+
* MidPoint Line Algorithm (Bresenham) Foley: ComputerGraphics better?
|
207
|
+
* will be replaced by vector functions
|
208
|
+
*/
|
209
|
+
|
210
|
+
/* gerade y=dy/dx*x+b, implizit d=F(x,y)=dy*x-dx*y+b*dx=0
|
211
|
+
* incrementell y(i+1)=m*(x(i)+1)+b, F(x+1,y+1)=f(F(x,y)) */
|
212
|
+
int get_line(int x0, int y0, int x1, int y1, pix *p, int cs, int ret);
|
213
|
+
int get_line2(int x0, int y0, int x1, int y1, pix *p, int cs, int ret);
|
214
|
+
|
215
|
+
/* look for white 0x02 or black 0x01 dots (0x03 = white+black) */
|
216
|
+
char get_bw(int x0, int x1, int y0, int y1,
|
217
|
+
pix *p, int cs,int mask);
|
218
|
+
|
219
|
+
/* look for black crossing a line x0,y0,x1,y1
|
220
|
+
* follow line and count crossings ([white]-black-transitions)
|
221
|
+
*/
|
222
|
+
int num_cross(int x0, int x1, int y0, int y1,
|
223
|
+
pix *p, int cs);
|
224
|
+
|
225
|
+
/* memory allocation with error checking */
|
226
|
+
void *xrealloc(void *ptr, size_t size);
|
227
|
+
|
228
|
+
/* follow a line x0,y0,x1,y1 recording locations of transitions,
|
229
|
+
* return count of transitions
|
230
|
+
*/
|
231
|
+
int follow_path(int x0, int x1, int y0, int y1, pix *p, int cs, path_t *path);
|
232
|
+
|
233
|
+
/* -------------------------------------------------------------
|
234
|
+
* mark edge-points
|
235
|
+
* - first move forward until b/w-edge
|
236
|
+
* - more than 2 pixel?
|
237
|
+
* - loop around
|
238
|
+
* - if forward pixel : go up, rotate right
|
239
|
+
* - if forward no pixel : rotate left
|
240
|
+
* - stop if found first 2 pixel in same order
|
241
|
+
* mit an rechter-Wand-entlang-gehen strategie
|
242
|
+
* --------------------------------------------------------------
|
243
|
+
* turmite game: inp: start-x,y, regel r_black=UP,r_white=RIght until border
|
244
|
+
* out: last-position
|
245
|
+
* Zaehle dabei, Schritte,Sackgassen,xmax,ymax,ro-,ru-,lo-,lu-Ecken
|
246
|
+
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
247
|
+
*
|
248
|
+
* is this the right place for declaration?
|
249
|
+
*/
|
250
|
+
void turmite(pix *p, int *x, int *y,
|
251
|
+
int x0, int x1, int y0, int y1, int cs, int rw, int rb);
|
252
|
+
|
253
|
+
/* test if points are connected via t-pixel (rekursiv!) */
|
254
|
+
int joined(pix *p, int x0, int y0, int x1, int y1, int cs);
|
255
|
+
|
256
|
+
/* move from x,y to direction r until pixel or l steps
|
257
|
+
* return number of steps
|
258
|
+
*/
|
259
|
+
int loop(pix *p, int x, int y, int l, int cs, int col, DIRECTION r);
|
260
|
+
|
261
|
+
#define MAX_HOLES 3
|
262
|
+
typedef struct list_holes {
|
263
|
+
int num; /* numbers of holes, initialize with 0 */
|
264
|
+
struct hole_s {
|
265
|
+
int size,x,y,x0,y0,x1,y1; /* size, start point, outer rectangle */
|
266
|
+
} hole[MAX_HOLES];
|
267
|
+
} holes_t;
|
268
|
+
|
269
|
+
/* look for white holes surrounded by black points
|
270
|
+
* at moment white point with black in all four directions
|
271
|
+
*/
|
272
|
+
int num_hole(int x0, int x1, int y0, int y1, pix *p, int cs, holes_t *holes);
|
273
|
+
|
274
|
+
/* count for black nonconnected objects --- used for i,auml,ouml,etc. */
|
275
|
+
int num_obj(int x0, int x1, int y0, int y1, pix *p, int cs);
|
276
|
+
|
277
|
+
int distance( pix *p1, struct box *box1, /* box-frame */
|
278
|
+
pix *p2, struct box *box2, int cs);
|
279
|
+
|
280
|
+
/* call the OCR engine ;) */
|
281
|
+
/* char whatletter(struct box *box1,int cs); */
|
282
|
+
|
283
|
+
/* declared in pixel.c */
|
284
|
+
/* getpixel() was pixel() but it may collide with netpnm pixel declaration */
|
285
|
+
int getpixel(pix *p, int x, int y);
|
286
|
+
int marked(pix *p, int x, int y);
|
287
|
+
void put(pix * p, int x, int y, int ia, int io);
|
288
|
+
|
289
|
+
/* } */ /* extern C */
|
290
|
+
#endif /* __GOCR_H__ */
|