PageRenderTime 153ms CodeModel.GetById 100ms RepoModel.GetById 0ms app.codeStats 0ms

/Spikes/GocrDemo/gocr.c

http://stp-iphone.googlecode.com/
C | 472 lines | 336 code | 42 blank | 94 comment | 57 complexity | 5eb2200631e10423d7ca780958af28b8 MD5 | raw file
Possible License(s): Apache-2.0
  1. /*
  2. This is a Optical-Character-Recognition program
  3. Copyright (C) 2000-2009 Joerg Schulenburg
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  15. see README for EMAIL-address
  16. sometimes I have written comments in german language, sorry for that
  17. This file was retrieved from pgm2asc.cc of Joerg, in order to have
  18. a library of the ocr-engine from Klaas Freitag
  19. */
  20. #include "config.h"
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <assert.h>
  24. #include <string.h>
  25. #ifdef HAVE_GETTIMEOFDAY
  26. #include <sys/time.h>
  27. #endif
  28. #ifdef HAVE_UNISTD_H
  29. #include <unistd.h>
  30. #endif
  31. #include "pnm.h"
  32. #include "pgm2asc.h"
  33. #include "pcx.h"
  34. #include "ocr0.h" /* only_numbers */
  35. #include "progress.h"
  36. #include "version.h"
  37. static void out_version(int v) {
  38. fprintf(stderr, " Optical Character Recognition --- gocr "
  39. version_string " " release_string "\n"
  40. " Copyright (C) 2001-2009 Joerg Schulenburg GPG=1024D/53BDFBE3\n"
  41. " released under the GNU General Public License\n");
  42. /* as recommended, (c) and license should be part of the binary */
  43. /* no email because of SPAM, see README for contacting the author */
  44. if (v)
  45. fprintf(stderr, " use option -h for help\n");
  46. if (v & 2)
  47. exit(1);
  48. return;
  49. }
  50. static void help(void) {
  51. out_version(0);
  52. /* output is shortened to essentials, see manual page for details */
  53. fprintf(stderr,
  54. " using: gocr [options] pnm_file_name # use - for stdin\n"
  55. " options (see gocr manual pages for more details):\n"
  56. " -h, --help\n"
  57. " -i name - input image file (pnm,pgm,pbm,ppm,pcx,...)\n"
  58. " -o name - output file (redirection of stdout)\n"
  59. " -e name - logging file (redirection of stderr)\n"
  60. " -x name - progress output to fifo (see manual)\n"
  61. " -p name - database path including final slash (default is ./db/)\n");
  62. fprintf(stderr, /* string length less than 509 bytes for ISO C89 */
  63. " -f fmt - output format (ISO8859_1 TeX HTML XML UTF8 ASCII)\n"
  64. " -l num - threshold grey level 0<160<=255 (0 = autodetect)\n"
  65. " -d num - dust_size (remove small clusters, -1 = autodetect)\n"
  66. " -s num - spacewidth/dots (0 = autodetect)\n"
  67. " -v num - verbose (see manual page)\n"
  68. " -c string - list of chars (debugging, see manual)\n"
  69. " -C string - char filter (ex. hexdigits: ""0-9A-Fx"", only ASCII)\n"
  70. " -m num - operation modes (bitpattern, see manual)\n");
  71. fprintf(stderr, /* string length less than 509 bytes for ISO C89 */
  72. " -a num - value of certainty (in percent, 0..100, default=95)\n"
  73. " -u string - output this string for every unrecognized character\n");
  74. fprintf(stderr, /* string length less than 509 bytes for ISO C89 */
  75. " examples:\n"
  76. "\tgocr -m 4 text1.pbm # do layout analyzis\n"
  77. "\tgocr -m 130 -p ./database/ text1.pbm # extend database\n"
  78. "\tdjpeg -pnm -gray text.jpg | gocr - # use jpeg-file via pipe\n"
  79. "\n");
  80. fprintf(stderr, " webpage: http://jocr.sourceforge.net/\n");
  81. exit(0);
  82. }
  83. #ifdef HAVE_GETTIMEOFDAY
  84. /* from the glibc documentation */
  85. static int timeval_subtract (struct timeval *result, struct timeval *x,
  86. struct timeval *y) {
  87. /* Perform the carry for the later subtraction by updating Y. */
  88. if (x->tv_usec < y->tv_usec) {
  89. int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
  90. y->tv_usec -= 1000000 * nsec;
  91. y->tv_sec += nsec;
  92. }
  93. if (x->tv_usec - y->tv_usec > 1000000) {
  94. int nsec = (x->tv_usec - y->tv_usec) / 1000000;
  95. y->tv_usec += 1000000 * nsec;
  96. y->tv_sec -= nsec;
  97. }
  98. /* Compute the time remaining to wait.
  99. `tv_usec' is certainly positive. */
  100. result->tv_sec = x->tv_sec - y->tv_sec;
  101. result->tv_usec = x->tv_usec - y->tv_usec;
  102. /* Return 1 if result is negative. */
  103. return x->tv_sec < y->tv_sec;
  104. }
  105. #endif
  106. static void process_arguments(job_t *job, int argn, char *argv[])
  107. {
  108. int i;
  109. char *s1;
  110. assert(job);
  111. if (argn <= 1) {
  112. out_version(1);
  113. exit(0);
  114. }
  115. #ifdef HAVE_PGM_H
  116. pnm_init(&argn, &argv);
  117. #endif
  118. /* process arguments */
  119. for (i = 1; i < argn; i++) {
  120. if (strcmp(argv[i], "--help") == 0)
  121. help(); /* and quits */
  122. if (argv[i][0] == '-' && argv[i][1] != 0) {
  123. s1 = "";
  124. if (i + 1 < argn)
  125. s1 = argv[i + 1];
  126. switch (argv[i][1]) {
  127. case 'h': /* help */
  128. help();
  129. break;
  130. case 'i': /* input image file */
  131. job->src.fname = s1;
  132. i++;
  133. break;
  134. case 'e': /* logging file */
  135. if (s1[0] == '-' && s1[1] == '\0') {
  136. #ifdef HAVE_UNISTD_H
  137. dup2(STDOUT_FILENO, STDERR_FILENO); /* -e /dev/stdout works */
  138. #else
  139. fprintf(stderr, "stderr redirection not possible without unistd.h\n");
  140. #endif
  141. }
  142. else if (!freopen(s1, "w", stderr)) {
  143. fprintf(stderr, "stderr redirection to %s failed\n", s1);
  144. }
  145. i++;
  146. break;
  147. case 'p': /* database path */
  148. job->cfg.db_path=s1;
  149. i++;
  150. break;
  151. case 'o': /* output file */
  152. if (s1[0] == '-' && s1[1] == '\0') { /* default */
  153. }
  154. else if (!freopen(s1, "w", stdout)) {
  155. fprintf(stderr, "stdout redirection to %s failed\n", s1);
  156. };
  157. i++;
  158. break;
  159. case 'f': /* output format */
  160. if (strcmp(s1, "ISO8859_1") == 0) job->cfg.out_format=ISO8859_1; else
  161. if (strcmp(s1, "TeX") == 0) job->cfg.out_format=TeX; else
  162. if (strcmp(s1, "HTML") == 0) job->cfg.out_format=HTML; else
  163. if (strcmp(s1, "XML") == 0) job->cfg.out_format=XML; else
  164. if (strcmp(s1, "SGML") == 0) job->cfg.out_format=SGML; else
  165. if (strcmp(s1, "UTF8") == 0) job->cfg.out_format=UTF8; else
  166. if (strcmp(s1, "ASCII") == 0) job->cfg.out_format=ASCII; else
  167. fprintf(stderr,"Warning: unknown format (-f %s)\n",s1);
  168. i++;
  169. break;
  170. case 'c': /* list of chars (_ = not recognized chars) */
  171. job->cfg.lc = s1;
  172. i++;
  173. break;
  174. case 'C': /* char filter, default: NULL (all chars) */
  175. /* ToDo: UTF8 input, wchar */
  176. job->cfg.cfilter = s1;
  177. i++;
  178. break;
  179. case 'd': /* dust size */
  180. job->cfg.dust_size = atoi(s1);
  181. i++;
  182. break;
  183. case 'l': /* grey level 0<160<=255, 0 for autodetect */
  184. job->cfg.cs = atoi(s1);
  185. i++;
  186. break;
  187. case 's': /* spacewidth/dots (0 = autodetect) */
  188. job->cfg.spc = atoi(s1);
  189. i++;
  190. break;
  191. case 'v': /* verbose mode */
  192. job->cfg.verbose |= atoi(s1);
  193. i++;
  194. break;
  195. case 'm': /* operation modes */
  196. job->cfg.mode |= atoi(s1);
  197. i++;
  198. break;
  199. case 'n': /* numbers only */
  200. job->cfg.only_numbers = atoi(s1);
  201. i++;
  202. break;
  203. case 'x': /* initialize progress output s1=fname */
  204. ini_progress(s1);
  205. i++;
  206. break;
  207. case 'a': /* set certainty */
  208. job->cfg.certainty = atoi(s1);;
  209. i++;
  210. break;
  211. case 'u': /* output marker for unrecognized chars */
  212. job->cfg.unrec_marker = s1;
  213. i++;
  214. break;
  215. default:
  216. fprintf(stderr, "# unknown option use -h for help\n");
  217. }
  218. continue;
  219. }
  220. else /* argument can be filename v0.2.5 */ if (argv[i][0] != '-'
  221. || argv[i][1] == '\0' ) {
  222. job->src.fname = argv[i];
  223. }
  224. }
  225. }
  226. static void mark_start(job_t *job) {
  227. assert(job);
  228. if (job->cfg.verbose) {
  229. out_version(0);
  230. /* insert some helpful info for support */
  231. fprintf(stderr, "# compiled: " __DATE__ );
  232. #if defined(__GNUC__)
  233. fprintf(stderr, " GNUC-%d", __GNUC__ );
  234. #endif
  235. #ifdef __GNUC_MINOR__
  236. fprintf(stderr, ".%d", __GNUC_MINOR__ );
  237. #endif
  238. #if defined(__linux)
  239. fprintf(stderr, " linux");
  240. #elif defined(__unix)
  241. fprintf(stderr, " unix");
  242. #endif
  243. #if defined(__WIN32) || defined(__WIN32__)
  244. fprintf(stderr, " WIN32");
  245. #endif
  246. #if defined(__WIN64) || defined(__WIN64__)
  247. fprintf(stderr, " WIN64");
  248. #endif
  249. #if defined(__VERSION__)
  250. fprintf(stderr, " version " __VERSION__ );
  251. #endif
  252. fprintf(stderr, "\n");
  253. fprintf(stderr,
  254. "# options are: -l %d -s %d -v %d -c %s -m %d -d %d -n %d -a %d -C \"%s\"\n",
  255. job->cfg.cs, job->cfg.spc, job->cfg.verbose, job->cfg.lc, job->cfg.mode,
  256. job->cfg.dust_size, job->cfg.only_numbers, job->cfg.certainty,
  257. job->cfg.cfilter);
  258. fprintf(stderr, "# file: %s\n", job->src.fname);
  259. #ifdef USE_UNICODE
  260. fprintf(stderr,"# using unicode\n");
  261. #endif
  262. #ifdef HAVE_GETTIMEOFDAY
  263. gettimeofday(&job->tmp.init_time, NULL);
  264. #endif
  265. }
  266. }
  267. static void mark_end(job_t *job) {
  268. assert(job);
  269. #ifdef HAVE_GETTIMEOFDAY
  270. /* show elapsed time */
  271. if (job->cfg.verbose) {
  272. struct timeval end, result;
  273. gettimeofday(&end, NULL);
  274. timeval_subtract(&result, &end, &job->tmp.init_time);
  275. fprintf(stderr,"Elapsed time: %d:%02d:%3.3f.\n", (int)result.tv_sec/60,
  276. (int)result.tv_sec%60, (float)result.tv_usec/1000);
  277. }
  278. #endif
  279. }
  280. static int read_picture(job_t *job) {
  281. int rc=0;
  282. assert(job);
  283. if (strstr(job->src.fname, ".pcx"))
  284. readpcx(job->src.fname, &job->src.p, job->cfg.verbose);
  285. else
  286. rc=readpgm(job->src.fname, &job->src.p, job->cfg.verbose);
  287. return rc; /* 1 for multiple images, 0 else */
  288. }
  289. /* subject of change, we need more output for XML (ToDo) */
  290. void print_output(job_t *job) {
  291. int linecounter = 0;
  292. const char *line;
  293. assert(job);
  294. linecounter = 0;
  295. line = getTextLine(linecounter++);
  296. while (line) {
  297. /* notice: decode() is shiftet to getTextLine since 0.38 */
  298. fputs(line, stdout);
  299. if (job->cfg.out_format==HTML) fputs("<br />",stdout);
  300. if (job->cfg.out_format!=XML) fputc('\n', stdout);
  301. line = getTextLine(linecounter++);
  302. }
  303. free_textlines();
  304. }
  305. char* safeConcat(char *source, const char *appendThis)
  306. {
  307. char *temp = malloc(strlen(source) + 1);
  308. strcpy(temp, source);
  309. int newSize = strlen(temp) + strlen(appendThis) + 2;
  310. source = malloc(newSize);
  311. strcpy(source, temp);
  312. strcat(source, appendThis);
  313. return source;
  314. }
  315. /**
  316. * Generates the output of the OCR as a string.
  317. * @param job the input job.
  318. * @return the OCR output
  319. */
  320. char* generate_output_string(job_t *job, char *finalOutput) {
  321. int linecounter = 0;
  322. const char *line;
  323. finalOutput = malloc(2);
  324. finalOutput = "";
  325. assert(job);
  326. linecounter = 0;
  327. line = getTextLine(linecounter++);
  328. while (line)
  329. {
  330. if (linecounter > 1) finalOutput = safeConcat(finalOutput, "\n");
  331. finalOutput = safeConcat(finalOutput, line);
  332. //if (job->cfg.out_format==HTML) strcat(finalOutput, "<br />");
  333. line = getTextLine(linecounter++);
  334. }
  335. free_textlines();
  336. return finalOutput;
  337. }
  338. /* FIXME jb: remove JOB; */
  339. job_t *JOB;
  340. /* -------------------------------------------------------------
  341. // ------ MAIN - replace this by your own aplication!
  342. // ------------------------------------------------------------- */
  343. //int main(int argn, char *argv[]) {
  344. // int multipnm=1;
  345. // job_t job;
  346. //
  347. // JOB = &job;
  348. // setvbuf(stdout, (char *) NULL, _IONBF, 0); /* not buffered */
  349. //
  350. // while (multipnm==1) {
  351. //
  352. // job_init(&job);
  353. //
  354. // process_arguments(&job, argn, argv);
  355. //
  356. // mark_start(&job);
  357. //
  358. // multipnm = read_picture(&job);
  359. // /* separation of main and rest for using as lib
  360. // this will be changed later => introduction of set_option()
  361. // for better communication to the engine */
  362. // if (multipnm<0) break; /* read error */
  363. //
  364. // /* call main loop */
  365. // pgm2asc(&job);
  366. //
  367. // mark_end(&job);
  368. //
  369. // print_output(&job);
  370. //
  371. // job_free(&job);
  372. //
  373. // }
  374. //
  375. // return 0;
  376. //}
  377. /**
  378. * Runs GOCR and returns the output.
  379. * @param fileName the name of the input file.
  380. * @return the output text from GOCR.
  381. */
  382. char* rungocr(const char *fileName, char* output)
  383. {
  384. int multipnm=1;
  385. job_t job;
  386. JOB = &job;
  387. setvbuf(stdout, (char *) NULL, _IONBF, 0); /* not buffered */
  388. int argn = 2;
  389. char *argv[2];
  390. argv[0] = "gocr";
  391. argv[1] = malloc(strlen(fileName) + 1);
  392. strcpy(argv[1],fileName);
  393. output = malloc(2);
  394. output = "";
  395. while (multipnm==1) {
  396. job_init(&job);
  397. process_arguments(&job, argn, argv);
  398. mark_start(&job);
  399. multipnm = read_picture(&job);
  400. /* separation of main and rest for using as lib
  401. this will be changed later => introduction of set_option()
  402. for better communication to the engine */
  403. if (multipnm<0) break; /* read error */
  404. /* call main loop */
  405. pgm2asc(&job);
  406. mark_end(&job);
  407. char *returnString;
  408. returnString = generate_output_string(&job, returnString);
  409. //strcat(output, generate_output_string(&job));
  410. output = safeConcat(output, returnString);
  411. job_free(&job);
  412. }
  413. return output;
  414. }
  415. int main()
  416. {
  417. char* fileName = "../image.ppm";
  418. printf("Performing OCR on %s\n", fileName);
  419. char* output;
  420. output = rungocr(fileName, output);
  421. printf("OCR Output is:\n%s\n\n\n\n", output);
  422. return 0;
  423. }