Logo Search packages:      
Sourcecode: ocrad version File versions  Download package

main.cc

/*  GNU Ocrad - Optical Character Recognition program
    Copyright (C) 2003, 2004, 2005 Antonio Diaz Diaz.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
    Return values: 0 for a normal exit, 1 for environmental problems
    (file not found, invalid flags, I/O errors, etc), 2 to indicate a
    corrupt or invalid input file, 3 for an internal consistency error
    (eg, bug) which caused ocrad to panic.
*/

#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <getopt.h>

#include "common.h"
#include "rational.h"
#include "rectangle.h"
#include "bitmap.h"
#include "textpage.h"


namespace {

// Date of this version: 2005-10-10

const char * invocation_name = 0;
const char * const Program_name    = "GNU Ocrad";
const char * const program_name    = "ocrad";
const char * const program_version = "0.13";
const char * const program_year    = "2005";

struct Input_control
  {
  Transformation transformation;
  int rindex, layout_level, scale;
  Rational threshold;
  char specialtype;
  bool copy, invert;

  Input_control() throw()
    : rindex( -1 ), layout_level( 0 ), scale( 0 ), threshold( -1 ),
      specialtype( 0 ), copy( false ), invert( false ) {}

  bool set_threshold( const char * ptr ) throw();
  };


void show_error( const char * msg, int errcode = 0, bool help = false ) throw()
  {
  if( msg && msg[0] != 0 )
    {
    std::fprintf( stderr, "%s: %s", program_name, msg );
    if( errcode > 0 ) std::fprintf( stderr, ": %s", strerror( errcode ) );
    std::fprintf( stderr, "\n" );
    }
  if( help && invocation_name && invocation_name[0] != 0 )
    std::fprintf( stderr, "Try `%s --help' for more information.\n", invocation_name );
  }


bool Input_control::set_threshold( const char * ptr ) throw()
  {
  if( threshold.parse( ptr, threshold ) && threshold >= 0 && threshold <= 1 )
    return true;
  show_error( "threshold out of limits (0.0 - 1.0)", 0, true );
  return false;
  }


void show_help( bool verbose ) throw()
  {
  std::printf( "%s - Optical Character Recognition program.\n", Program_name );
  std::printf( "Reads pgm/pbm file(s), or standard input, and sends text to standard output.\n" );
  std::printf( "\nUsage: %s [options] [files]\n", invocation_name );
  std::printf( "Options:\n" );
  std::printf( "  -h, --help               display this help and exit\n" );
  std::printf( "  -V, --version            output version information and exit\n" );
  std::printf( "  -a, --append             append text to output file\n" );
  std::printf( "  -b, --block=<n>          process only the specified text block\n" );
  std::printf( "  -c, --charset=<name>     try `--charset=help' for a list of names\n" );
  std::printf( "  -f, --force              force overwrite of output file\n" );
  std::printf( "  -F, --format=<fmt>       output format (byte, utf8)\n" );
  std::printf( "  -i, --invert             invert image levels (white on black)\n" );
  std::printf( "  -l, --layout=<n>         layout analysis, 0=none, 1=column, 2=full\n" );
  std::printf( "  -o <file>                place the output into <file>\n" );
  std::printf( "  -s, --scale=[-]<n>       scale input image by [1/]<n>\n" );
  std::printf( "  -t, --transform=<name>   try `--transform=help' for a list of names\n" );
  std::printf( "  -T, --threshold=<n%%>     threshold for -s option or pgm file (0-100%%)\n" );
  std::printf( "  -v, --verbose            be verbose\n" );
  std::printf( "  -x <file>                export OCR Results File to <file>\n" );
  if( verbose )
    {
    std::printf( "  -1, -4                   pbm output file type (debug)\n" );
    std::printf( "  -C, --copy               'copy' input to output (debug)\n" );
    std::printf( "  -D, --debug=<level>      (0-100) output intermediate data (debug)\n" );
    std::printf( "  -S <type>                make a 'special file' (debug)\n" );
    }
  std::printf( "\nReport bugs to bug-ocrad@gnu.org\n" );
  }


void show_version() throw()
  {
  std::printf( "%s version %s\n", Program_name, program_version );
  std::printf( "Copyright (C) %s Antonio Diaz Diaz.\n", program_year );
  std::printf( "This program is free software; you may redistribute it under the terms of\n" );
  std::printf( "the GNU General Public License.  This program has absolutely no warranty.\n" );
  }


const char * my_basename( const char * filename ) throw()
  {
  const char * c = filename;
  while( *c ) { if( *c == '/' ) filename = c + 1; ++c; }
  return filename;
  }


int process_file( FILE *infile, const char * infile_name,
                  const Input_control & input_control,
                  const Control & control ) throw()
  {
  try
    {
    std::vector< Rectangle > rv;
    Bitmap page_image( infile, input_control.threshold, input_control.invert );

    page_image.transform( input_control.transformation );
    page_image.scale( input_control.scale, input_control.threshold );
    page_image.analyse_layout( rv, input_control.layout_level );
    if( control.verbose )
      std::fprintf( stderr, "number of text blocks %d\n", (int)rv.size() );

    if( input_control.rindex >= (int)rv.size() )
      {
      std::fprintf( stderr,"This page has only %d text block(s)\n", (int)rv.size() );
      return 1;
      }
    if( input_control.rindex >= 0 )
      {
      Rectangle re = rv[input_control.rindex];
      rv.clear(); rv.push_back( re );
      }

    if( input_control.specialtype != 0 )
      {
      if( control.outfile )
        {
        const char & t = input_control.specialtype;
        if( t == 'v' || t == 'h' ) page_image.histogramize( t == 'v' );
        else { show_error( "bad special type" ); return 1; }
        page_image.save( control.outfile, control.filetype );
        }
      return 0;
      }
    if( input_control.copy )
      {
      if( control.outfile )
        {
        if( input_control.layout_level == 0 && rv.size() == 1 )
          page_image.save( control.outfile, control.filetype );
        else for( unsigned int c = 0; c < rv.size(); ++c )
          {
          Bitmap bitmap( page_image, rv[c] );
          bitmap.save( control.outfile, control.filetype );
          }
        }
      return 0;
      }

    Textpage textpage( page_image, rv, my_basename( infile_name ), control );
    }
  catch( Bitmap::Error e ) { show_error( e.s ); return 2; }
  return 0;
  }

} // end namespace


void Ocrad::internal_error( const char * msg ) throw()
  {
  char buf[80];
  std::snprintf( buf, sizeof( buf ), "internal error: %s.\n", msg );
  show_error( buf );
  exit( 3 );
  }


// 'infile' contains the scanned image (in pbm format) to be converted
// to text.
// 'outfile' is the destination for the text version of the scanned
// image. (or for a pbm file if debugging).
// 'exportfile' is the Ocr Results File.
//
int main( int argc, char * argv[] ) throw()
  {
  Input_control input_control;
  Control control;
  const char *outfile_name = 0, *exportfile_name = 0;
  bool append = false, force = false;
  invocation_name = argv[0];

  // scan arguments

  while( true )               // process options
    {
    static const struct option long_options[] =
      {
      {"append", no_argument, 0, 'a'},
      {"block", required_argument, 0, 'b'},
      {"charset", required_argument, 0, 'c'},
      {"copy", no_argument, 0, 'C'},
      {"debug", required_argument, 0, 'D'},
      {"force", no_argument, 0, 'f'},
      {"format", required_argument, 0, 'F'},
      {"help", no_argument, 0, 'h'},
      {"invert", no_argument, 0, 'i'},
      {"layout", required_argument, 0, 'l'},
      {"scale", required_argument, 0, 's'},
      {"transform", required_argument, 0, 't'},
      {"threshold", required_argument, 0, 'T'},
      {"verbose", no_argument, 0, 'v'},
      {"version", no_argument, 0, 'V'},
      {0, 0, 0, 0}
      };

    int c = getopt_long( argc, argv, "14CD:F:S:T:Vab:c:fhil:o:s:t:vx:",
                         long_options, 0 );
    if( c == -1 ) break;            // all options processed

    switch( c )
      {
      case '1':
      case '4': control.filetype = c; break;
      case 'C': input_control.copy = true; break;
      case 'D': control.debug_level = std::strtol( optarg, 0, 0 ); break;
      case 'F': if( !control.set_format( optarg ) )
                  { show_error( "bad output format", 0, true ); return 1; }
                break;
      case 'S': input_control.specialtype = optarg[0]; break;
      case 'T': if( !input_control.set_threshold( optarg ) ) return 1; break;
      case 'V':   show_version(); return 0;
      case 'a': append = true; break;
      case 'b': input_control.rindex = std::strtol( optarg, 0, 0 ) - 1; break;
      case 'c': if( !control.charset.enable( optarg ) )
                  { control.charset.show_error( program_name, optarg ); return 1; }
                break;
      case 'f': force = true; break;
      case 'h': show_help( control.verbose ); return 0;
      case 'i': input_control.invert = true; break;
      case 'l': input_control.layout_level = std::strtol( optarg, 0, 0 ); break;
      case 'o':   outfile_name = optarg; break;
      case 's': input_control.scale = std::strtol( optarg, 0, 0 ); break;
      case 't': if( !input_control.transformation.set( optarg ) )
                  { input_control.transformation.show_error( program_name, optarg );
                  return 1; }
                break;
      case 'v': control.verbose = true; break;
      case 'x':   exportfile_name = optarg; break;
      case '?': show_error( 0, 0, true ); return 1;   // bad option
      default: return 1;
      }
    } // end process options

  if( outfile_name && std::strcmp( outfile_name, "-" ) != 0 )
    {
    if( append ) control.outfile = std::fopen( outfile_name, "a" );
    else if( force ) control.outfile = std::fopen( outfile_name, "w" );
    else if( ( control.outfile = std::fopen( outfile_name, "wx" ) ) == 0 )
      {
      std::fprintf( stderr, "Output file %s already exists.\n", outfile_name );
      return 1;
      }
    if( !control.outfile )
      { std::fprintf( stderr, "Cannot open %s\n", outfile_name ); return 1; }
    }

  if( exportfile_name && control.debug_level == 0 &&
      input_control.scale == 0 && input_control.specialtype == 0 &&
      !input_control.copy )
    {
    if( std::strcmp( exportfile_name, "-" ) == 0 )
      { control.exportfile = stdout; if( !outfile_name ) control.outfile = 0; }
    else
      {
      control.exportfile = std::fopen( exportfile_name, "w" );
      if( !control.exportfile )
        {
        std::fprintf( stderr, "Cannot open %s\n", exportfile_name );
        return 1;
        }
      }
    std::fprintf( control.exportfile,
                  "# Ocr Results File. Created by %s version %s\n",
                  Program_name, program_version );
    }

  // process any remaining command line arguments (input files)
  FILE *infile = (optind < argc) ? 0 : stdin;
  const char *infile_name = "-";
  int retval = 0;
  while( true )
    {
    while( infile != stdin )
      {
      if( infile ) std::fclose( infile );
      if( optind >= argc ) { infile = 0; break; }
      infile_name = argv[optind++];
      if( std::strcmp( infile_name, "-" ) == 0 ) infile = stdin;
      else infile = std::fopen( infile_name, "r" );
      if( infile ) break;
      std::fprintf( stderr, "Cannot open %s\n", infile_name );
      if( retval == 0 ) retval = 1;
      }
    if( !infile ) break;

    int tmp = process_file( infile, infile_name, input_control, control );
    if( infile == stdin )
      {
      if( tmp <= 1 )
        {
        int ch;
        do ch = std::fgetc( infile ); while( std::isspace( ch ) );
        std::ungetc( ch, infile );
        }
      if( tmp > 1 || std::feof( infile ) || std::ferror( infile ) ) infile = 0;
      }
    if( tmp > retval ) retval = tmp;
    if( control.outfile ) std::fflush( control.outfile );
    if( control.exportfile ) std::fflush( control.exportfile );
    }
  if( control.outfile ) std::fclose( control.outfile );
  if( control.exportfile ) std::fclose( control.exportfile );
  return retval;
  }

Generated by  Doxygen 1.6.0   Back to index