2009-07-11 10:03:09 +08:00
|
|
|
/**********************************************************************
|
2010-11-24 02:34:14 +08:00
|
|
|
* File: tessedit.cpp (Formerly tessedit.c)
|
|
|
|
* Description: Main program for merge of tess and editor.
|
|
|
|
* Author: Ray Smith
|
|
|
|
* Created: Tue Jan 07 15:21:46 GMT 1992
|
|
|
|
*
|
|
|
|
* (C) Copyright 1992, Hewlett-Packard Ltd.
|
|
|
|
** Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
** you may not use this file except in compliance with the License.
|
|
|
|
** You may obtain a copy of the License at
|
|
|
|
** http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
** Unless required by applicable law or agreed to in writing, software
|
|
|
|
** distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
** See the License for the specific language governing permissions and
|
|
|
|
** limitations under the License.
|
|
|
|
*
|
|
|
|
**********************************************************************/
|
2009-07-11 10:03:09 +08:00
|
|
|
|
|
|
|
// Include automatically generated configuration file if running autoconf
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config_auto.h"
|
|
|
|
#endif
|
2011-08-30 14:34:41 +08:00
|
|
|
|
2014-01-10 09:38:00 +08:00
|
|
|
#ifdef _WIN32
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <io.h>
|
|
|
|
#endif // _WIN32
|
|
|
|
#include <iostream>
|
|
|
|
|
2009-07-11 10:03:09 +08:00
|
|
|
#include "allheaders.h"
|
2010-11-30 08:58:30 +08:00
|
|
|
#include "baseapi.h"
|
2014-01-10 01:58:55 +08:00
|
|
|
#include "basedir.h"
|
2013-09-21 03:39:59 +08:00
|
|
|
#include "renderer.h"
|
2010-11-30 08:58:30 +08:00
|
|
|
#include "strngs.h"
|
2012-03-05 06:27:16 +08:00
|
|
|
#include "tprintf.h"
|
2013-12-10 18:52:54 +08:00
|
|
|
#include "openclwrapper.h"
|
2009-07-11 10:03:09 +08:00
|
|
|
|
|
|
|
/**********************************************************************
|
2010-11-30 08:58:30 +08:00
|
|
|
* main()
|
|
|
|
*
|
|
|
|
**********************************************************************/
|
2009-07-11 10:03:09 +08:00
|
|
|
|
|
|
|
int main(int argc, char **argv) {
|
2011-08-19 00:41:51 +08:00
|
|
|
if ((argc == 2 && strcmp(argv[1], "-v") == 0) ||
|
|
|
|
(argc == 2 && strcmp(argv[1], "--version") == 0)) {
|
2012-03-05 06:27:16 +08:00
|
|
|
char *versionStrP;
|
|
|
|
|
2011-08-09 04:33:18 +08:00
|
|
|
fprintf(stderr, "tesseract %s\n", tesseract::TessBaseAPI::Version());
|
2012-09-27 16:24:46 +08:00
|
|
|
|
2012-03-05 06:27:16 +08:00
|
|
|
versionStrP = getLeptonicaVersion();
|
|
|
|
fprintf(stderr, " %s\n", versionStrP);
|
|
|
|
lept_free(versionStrP);
|
2012-09-27 16:24:46 +08:00
|
|
|
|
2012-03-05 06:27:16 +08:00
|
|
|
versionStrP = getImagelibVersions();
|
|
|
|
fprintf(stderr, " %s\n", versionStrP);
|
|
|
|
lept_free(versionStrP);
|
|
|
|
|
2013-12-14 16:35:14 +08:00
|
|
|
#ifdef USE_OPENCL
|
|
|
|
cl_platform_id platform;
|
|
|
|
cl_uint num_platforms;
|
|
|
|
cl_device_id devices[2];
|
|
|
|
cl_uint num_devices;
|
|
|
|
char info[256];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
fprintf(stderr, " OpenCL info:\n");
|
|
|
|
clGetPlatformIDs(1, &platform, &num_platforms);
|
|
|
|
fprintf(stderr, " Found %d platforms.\n", num_platforms);
|
|
|
|
clGetPlatformInfo(platform, CL_PLATFORM_NAME, 256, info, 0);
|
|
|
|
fprintf(stderr, " Platform name: %s.\n", info);
|
|
|
|
clGetPlatformInfo(platform, CL_PLATFORM_VERSION, 256, info, 0);
|
|
|
|
fprintf(stderr, " Version: %s.\n", info);
|
|
|
|
clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 2, devices, &num_devices);
|
|
|
|
fprintf(stderr, " Found %d devices.\n", num_devices);
|
|
|
|
for (i = 0; i < num_devices; ++i) {
|
|
|
|
clGetDeviceInfo(devices[i], CL_DEVICE_NAME, 256, info, 0);
|
|
|
|
fprintf(stderr, " Device %d name: %s.\n", i+1, info);
|
|
|
|
}
|
|
|
|
#endif
|
2011-07-30 05:55:49 +08:00
|
|
|
exit(0);
|
2010-11-30 08:58:30 +08:00
|
|
|
}
|
2012-09-27 16:24:46 +08:00
|
|
|
|
2010-11-30 08:58:30 +08:00
|
|
|
// Make the order of args a bit more forgiving than it used to be.
|
|
|
|
const char* lang = "eng";
|
|
|
|
const char* image = NULL;
|
|
|
|
const char* output = NULL;
|
2013-11-11 04:59:11 +08:00
|
|
|
const char* datapath = NULL;
|
2012-12-24 01:47:06 +08:00
|
|
|
bool noocr = false;
|
|
|
|
bool list_langs = false;
|
2012-12-24 01:54:14 +08:00
|
|
|
bool print_parameters = false;
|
2012-12-24 01:47:06 +08:00
|
|
|
|
2010-11-30 08:58:30 +08:00
|
|
|
tesseract::PageSegMode pagesegmode = tesseract::PSM_AUTO;
|
|
|
|
int arg = 1;
|
|
|
|
while (arg < argc && (output == NULL || argv[arg][0] == '-')) {
|
|
|
|
if (strcmp(argv[arg], "-l") == 0 && arg + 1 < argc) {
|
|
|
|
lang = argv[arg + 1];
|
|
|
|
++arg;
|
2013-11-11 04:59:11 +08:00
|
|
|
} else if (strcmp(argv[arg], "--tessdata-dir") == 0 && arg + 1 < argc) {
|
|
|
|
datapath = argv[arg + 1];
|
|
|
|
++arg;
|
|
|
|
} else if (strcmp(argv[arg], "--list-langs") == 0) {
|
|
|
|
noocr = true;
|
|
|
|
list_langs = true;
|
2010-11-30 08:58:30 +08:00
|
|
|
} else if (strcmp(argv[arg], "-psm") == 0 && arg + 1 < argc) {
|
|
|
|
pagesegmode = static_cast<tesseract::PageSegMode>(atoi(argv[arg + 1]));
|
|
|
|
++arg;
|
2012-12-24 01:54:14 +08:00
|
|
|
} else if (strcmp(argv[arg], "--print-parameters") == 0) {
|
|
|
|
noocr = true;
|
|
|
|
print_parameters = true;
|
2013-05-03 01:06:14 +08:00
|
|
|
} else if (strcmp(argv[arg], "-c") == 0 && arg + 1 < argc) {
|
2013-04-30 04:43:14 +08:00
|
|
|
// handled properly after api init
|
|
|
|
++arg;
|
2010-11-30 08:58:30 +08:00
|
|
|
} else if (image == NULL) {
|
|
|
|
image = argv[arg];
|
|
|
|
} else if (output == NULL) {
|
|
|
|
output = argv[arg];
|
|
|
|
}
|
|
|
|
++arg;
|
|
|
|
}
|
2012-12-24 01:47:06 +08:00
|
|
|
|
|
|
|
if (argc == 2 && strcmp(argv[1], "--list-langs") == 0) {
|
|
|
|
list_langs = true;
|
|
|
|
noocr = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (output == NULL && noocr == false) {
|
2014-01-10 09:38:00 +08:00
|
|
|
fprintf(stderr, "Usage:\n %s imagename|stdin outputbase|stdout "
|
|
|
|
"[options...] [configfile...]\n\n", argv[0]);
|
2013-11-11 04:59:11 +08:00
|
|
|
|
|
|
|
fprintf(stderr, "OCR options:\n");
|
|
|
|
fprintf(stderr, " --tessdata-dir /path\tspecify location of tessdata"
|
|
|
|
" path\n");
|
|
|
|
fprintf(stderr, " -l lang[+lang]\tspecify language(s) used for OCR\n");
|
|
|
|
fprintf(stderr, " -c configvar=value\tset value for control parameter.\n"
|
|
|
|
"\t\t\tMultiple -c arguments are allowed.\n");
|
|
|
|
fprintf(stderr, " -psm pagesegmode\tspecify page segmentation mode.\n");
|
|
|
|
fprintf(stderr, "These options must occur before any configfile.\n\n");
|
2010-11-30 08:58:30 +08:00
|
|
|
fprintf(stderr,
|
2014-01-10 01:58:55 +08:00
|
|
|
"pagesegmode values are:\n"
|
|
|
|
" 0 = Orientation and script detection (OSD) only.\n"
|
|
|
|
" 1 = Automatic page segmentation with OSD.\n"
|
|
|
|
" 2 = Automatic page segmentation, but no OSD, or OCR\n"
|
|
|
|
" 3 = Fully automatic page segmentation, but no OSD. (Default)\n"
|
|
|
|
" 4 = Assume a single column of text of variable sizes.\n"
|
|
|
|
" 5 = Assume a single uniform block of vertically aligned text.\n"
|
|
|
|
" 6 = Assume a single uniform block of text.\n"
|
|
|
|
" 7 = Treat the image as a single text line.\n"
|
|
|
|
" 8 = Treat the image as a single word.\n"
|
|
|
|
" 9 = Treat the image as a single word in a circle.\n"
|
|
|
|
" 10 = Treat the image as a single character.\n\n");
|
2013-07-08 00:39:13 +08:00
|
|
|
fprintf(stderr, "Single options:\n");
|
|
|
|
fprintf(stderr, " -v --version: version info\n");
|
|
|
|
fprintf(stderr, " --list-langs: list available languages for tesseract "
|
2013-11-11 04:59:11 +08:00
|
|
|
"engine. Can be used with --tessdata-dir.\n");
|
2013-07-08 00:39:13 +08:00
|
|
|
fprintf(stderr, " --print-parameters: print tesseract parameters to the "
|
2013-11-11 04:59:11 +08:00
|
|
|
"stdout.\n");
|
2010-11-30 08:58:30 +08:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2014-01-23 05:32:20 +08:00
|
|
|
if (output != NULL && strcmp(output, "-") && strcmp(output, "stdout")) {
|
2014-01-22 16:17:37 +08:00
|
|
|
tprintf("Tesseract Open Source OCR Engine v%s with Leptonica\n",
|
2013-12-23 05:58:52 +08:00
|
|
|
tesseract::TessBaseAPI::Version());
|
2014-01-22 16:17:37 +08:00
|
|
|
}
|
2013-12-23 05:58:52 +08:00
|
|
|
PERF_COUNT_START("Tesseract:main")
|
2012-12-24 01:47:06 +08:00
|
|
|
tesseract::TessBaseAPI api;
|
2010-11-30 08:58:30 +08:00
|
|
|
|
|
|
|
api.SetOutputName(output);
|
2013-11-11 04:59:11 +08:00
|
|
|
int rc = api.Init(datapath, lang, tesseract::OEM_DEFAULT,
|
2012-10-09 08:41:08 +08:00
|
|
|
&(argv[arg]), argc - arg, NULL, NULL, false);
|
2012-12-24 01:47:06 +08:00
|
|
|
|
2012-02-26 22:48:35 +08:00
|
|
|
if (rc) {
|
2013-07-08 00:39:13 +08:00
|
|
|
fprintf(stderr, "Could not initialize tesseract.\n");
|
2012-02-26 22:48:35 +08:00
|
|
|
exit(1);
|
|
|
|
}
|
2012-09-27 16:24:46 +08:00
|
|
|
|
2013-04-30 04:43:14 +08:00
|
|
|
char opt1[255], opt2[255];
|
|
|
|
for (arg = 0; arg < argc; arg++) {
|
2013-05-03 01:06:14 +08:00
|
|
|
if (strcmp(argv[arg], "-c") == 0 && arg + 1 < argc) {
|
2013-04-30 04:43:14 +08:00
|
|
|
strncpy(opt1, argv[arg + 1], 255);
|
|
|
|
*(strchr(opt1, '=')) = 0;
|
|
|
|
strncpy(opt2, strchr(argv[arg + 1], '=') + 1, 255);
|
|
|
|
opt2[254] = 0;
|
|
|
|
++arg;
|
|
|
|
|
2013-09-21 03:39:59 +08:00
|
|
|
if (!api.SetVariable(opt1, opt2)) {
|
2013-07-08 00:39:13 +08:00
|
|
|
fprintf(stderr, "Could not set option: %s=%s\n", opt1, opt2);
|
2013-04-30 04:43:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-24 01:47:06 +08:00
|
|
|
if (list_langs) {
|
|
|
|
GenericVector<STRING> languages;
|
|
|
|
api.GetAvailableLanguagesAsVector(&languages);
|
2013-07-08 00:39:13 +08:00
|
|
|
fprintf(stderr, "List of available languages (%d):\n",
|
2012-12-24 01:47:06 +08:00
|
|
|
languages.size());
|
|
|
|
for (int index = 0; index < languages.size(); ++index) {
|
|
|
|
STRING& string = languages[index];
|
|
|
|
fprintf(stderr, "%s\n", string.string());
|
|
|
|
}
|
|
|
|
api.End();
|
|
|
|
exit(0);
|
|
|
|
}
|
2012-12-24 01:54:14 +08:00
|
|
|
|
|
|
|
if (print_parameters) {
|
|
|
|
FILE* fout = stdout;
|
2013-07-08 00:39:13 +08:00
|
|
|
fprintf(stdout, "Tesseract parameters:\n");
|
2012-12-24 01:54:14 +08:00
|
|
|
api.PrintVariables(fout);
|
|
|
|
api.End();
|
|
|
|
exit(0);
|
|
|
|
}
|
2012-12-24 01:47:06 +08:00
|
|
|
|
2011-08-19 00:41:51 +08:00
|
|
|
// We have 2 possible sources of pagesegmode: a config file and
|
|
|
|
// the command line. For backwards compatability reasons, the
|
|
|
|
// default in tesseract is tesseract::PSM_SINGLE_BLOCK, but the
|
|
|
|
// default for this program is tesseract::PSM_AUTO. We will let
|
|
|
|
// the config file take priority, so the command-line default
|
|
|
|
// can take priority over the tesseract default, so we use the
|
|
|
|
// value from the command line only if the retrieved mode
|
|
|
|
// is still tesseract::PSM_SINGLE_BLOCK, indicating no change
|
|
|
|
// in any config file. Therefore the only way to force
|
|
|
|
// tesseract::PSM_SINGLE_BLOCK is from the command line.
|
|
|
|
// It would be simpler if we could set the value before Init,
|
|
|
|
// but that doesn't work.
|
|
|
|
if (api.GetPageSegMode() == tesseract::PSM_SINGLE_BLOCK)
|
2014-01-08 00:48:52 +08:00
|
|
|
api.SetPageSegMode(pagesegmode);
|
2011-08-19 00:41:51 +08:00
|
|
|
|
2014-01-10 02:48:43 +08:00
|
|
|
bool stdInput = !strcmp(image, "stdin") || !strcmp(image, "-");
|
2014-01-12 22:47:15 +08:00
|
|
|
Pix* pixs = NULL;
|
2014-01-08 00:48:52 +08:00
|
|
|
if (stdInput) {
|
2014-01-10 02:48:43 +08:00
|
|
|
char byt;
|
|
|
|
GenericVector<l_uint8> ch_data;
|
2014-01-08 00:48:52 +08:00
|
|
|
std::istream file(std::cin.rdbuf());
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
if (_setmode(_fileno(stdin), _O_BINARY) == -1)
|
|
|
|
tprintf("ERROR: cin to binary: %s", strerror(errno));
|
|
|
|
#endif // WIN32
|
|
|
|
|
|
|
|
while (file.get(byt)) {
|
|
|
|
ch_data.push_back(byt);
|
|
|
|
}
|
|
|
|
std::cin.ignore(std::cin.rdbuf()->in_avail() + 1);
|
|
|
|
|
2014-01-12 22:47:15 +08:00
|
|
|
pixs = pixReadMem(&ch_data[0], ch_data.size());
|
|
|
|
}
|
|
|
|
|
2014-01-25 10:28:51 +08:00
|
|
|
if (pagesegmode == tesseract::PSM_AUTO_ONLY ||
|
|
|
|
pagesegmode == tesseract::PSM_OSD_ONLY) {
|
2014-01-12 22:47:15 +08:00
|
|
|
tesseract::Orientation orientation;
|
|
|
|
tesseract::WritingDirection direction;
|
|
|
|
tesseract::TextlineOrder order;
|
|
|
|
float deskew_angle;
|
|
|
|
int ret_val = 0;
|
|
|
|
|
|
|
|
if (!pixs)
|
|
|
|
pixs = pixRead(image);
|
|
|
|
api.SetImage(pixs);
|
|
|
|
tesseract::PageIterator* it = api.AnalyseLayout();
|
|
|
|
if (it) {
|
|
|
|
it->Orientation(&orientation, &direction, &order, &deskew_angle);
|
|
|
|
tprintf("Orientation: %d\nWritingDirection: %d\nTextlineOrder: %d\n" \
|
|
|
|
"Deskew angle: %.4f\n",
|
|
|
|
orientation, direction, order, deskew_angle);
|
|
|
|
} else {
|
|
|
|
ret_val = 1;
|
|
|
|
}
|
|
|
|
pixDestroy(&pixs);
|
|
|
|
delete it;
|
|
|
|
exit(ret_val);
|
|
|
|
}
|
|
|
|
|
|
|
|
tesseract::TessResultRenderer* renderer = NULL;
|
|
|
|
bool b;
|
|
|
|
api.GetBoolVariable("tessedit_create_hocr", &b);
|
|
|
|
if (b && renderer == NULL) renderer = new tesseract::TessHOcrRenderer();
|
|
|
|
|
|
|
|
api.GetBoolVariable("tessedit_create_pdf", &b);
|
|
|
|
if (b && renderer == NULL)
|
|
|
|
renderer = new tesseract::TessPDFRenderer(api.GetDatapath());
|
|
|
|
|
|
|
|
api.GetBoolVariable("tessedit_create_boxfile", &b);
|
|
|
|
if (b && renderer == NULL) renderer = new tesseract::TessBoxTextRenderer();
|
|
|
|
|
|
|
|
if (renderer == NULL) renderer = new tesseract::TessTextRenderer();
|
|
|
|
|
|
|
|
if (pixs) {
|
2014-01-10 02:48:43 +08:00
|
|
|
api.ProcessPage(pixs, 0, NULL, NULL, 0, renderer);
|
|
|
|
pixDestroy(&pixs);
|
2014-01-08 00:48:52 +08:00
|
|
|
} else {
|
|
|
|
FILE* fin = fopen(image, "rb");
|
|
|
|
if (fin == NULL) {
|
|
|
|
fprintf(stderr, "Cannot open input file: %s\n", image);
|
|
|
|
exit(2);
|
|
|
|
}
|
|
|
|
fclose(fin);
|
2014-01-10 02:48:43 +08:00
|
|
|
if (!api.ProcessPages(image, NULL, 0, renderer)) {
|
|
|
|
fprintf(stderr, "Error during processing.\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2014-01-08 00:48:52 +08:00
|
|
|
}
|
|
|
|
|
2014-01-10 02:48:43 +08:00
|
|
|
FILE* fout = stdout;
|
|
|
|
if (strcmp(output, "-") && strcmp(output, "stdout")) {
|
|
|
|
STRING outfile = STRING(output)
|
|
|
|
+ STRING(".")
|
|
|
|
+ STRING(renderer->file_extension());
|
|
|
|
fout = fopen(outfile.string(), "wb");
|
|
|
|
if (fout == NULL) {
|
|
|
|
fprintf(stderr, "Cannot create output file %s\n", outfile.string());
|
|
|
|
exit(1);
|
2013-09-21 03:39:59 +08:00
|
|
|
}
|
|
|
|
}
|
2014-01-10 02:48:43 +08:00
|
|
|
|
|
|
|
const char* data;
|
|
|
|
inT32 data_len;
|
|
|
|
if (renderer->GetOutput(&data, &data_len)) {
|
|
|
|
fwrite(data, 1, data_len, fout);
|
|
|
|
if (fout != stdout)
|
|
|
|
fclose(fout);
|
|
|
|
else
|
|
|
|
clearerr(fout);
|
|
|
|
}
|
2013-12-10 18:52:54 +08:00
|
|
|
PERF_COUNT_END
|
2010-11-30 08:58:30 +08:00
|
|
|
return 0; // Normal exit
|
2009-07-11 10:03:09 +08:00
|
|
|
}
|