From 4a3caefd92e2a15a384249735f09a3cd58bdb0e7 Mon Sep 17 00:00:00 2001 From: Ray Smith Date: Tue, 12 May 2015 15:41:15 -0700 Subject: [PATCH] Add ability to build under android (without cube or scrollview). --- android/AndroidManifest.xml | 4 +++ android/Makefile.am | 1 + android/jni/Android.mk | 57 +++++++++++++++++++++++++++++++++++++ android/jni/Application.mk | 13 +++++++++ api/baseapi.cpp | 14 +++++++++ ccmain/control.cpp | 4 +++ ccmain/paramsd.h | 2 ++ ccmain/tessedit.cpp | 9 ++++-- ccmain/tesseractclass.cpp | 8 ++++++ ccmain/tesseractclass.h | 14 +++++++-- ccstruct/imagedata.cpp | 4 +++ textord/drawedg.h | 2 ++ 12 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 android/AndroidManifest.xml create mode 100644 android/Makefile.am create mode 100644 android/jni/Android.mk create mode 100644 android/jni/Application.mk diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml new file mode 100644 index 00000000..d5bf0998 --- /dev/null +++ b/android/AndroidManifest.xml @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/android/Makefile.am b/android/Makefile.am new file mode 100644 index 00000000..9b822f6b --- /dev/null +++ b/android/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = AndroidManifest.xml jni/Android.mk jni/Application.mk diff --git a/android/jni/Android.mk b/android/jni/Android.mk new file mode 100644 index 00000000..d8f557e6 --- /dev/null +++ b/android/jni/Android.mk @@ -0,0 +1,57 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE := tesseract-$(APP_ABI) + +LOCAL_STATIC_LIBRARIES := \ + mobile_base \ + leptonica-$(APP_ABI) + +LOCAL_C_INCLUDES := $(APP_C_INCLUDES) + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/../../api \ + $(LOCAL_PATH)/../../ccmain\ + $(LOCAL_PATH)/../../ccstruct\ + $(LOCAL_PATH)/../../ccutil\ + $(LOCAL_PATH)/../../classify\ + $(LOCAL_PATH)/../../cutil\ + $(LOCAL_PATH)/../../dict\ + $(LOCAL_PATH)/../../image\ + $(LOCAL_PATH)/../../textord\ + $(LOCAL_PATH)/../../third_party\ + $(LOCAL_PATH)/../../wordrec\ + $(LOCAL_PATH)/../../opencl\ + $(LOCAL_PATH)/../../viewer\ + $(LOCAL_PATH)/../../../leptonica/include + +$(info local c includes=$(LOCAL_C_INCLUDES)) +$(info local path=$(LOCAL_PATH)) +LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/../../api/*.cpp $(LOCAL_PATH)/../../ccmain/*.cpp $(LOCAL_PATH)/../../ccstruct/*.cpp $(LOCAL_PATH)/../../ccutil/*.cpp $(LOCAL_PATH)/../../classify/*.cpp $(LOCAL_PATH)/../../cutil/*.cpp $(LOCAL_PATH)/../../dict/*.cpp $(LOCAL_PATH)/../../image/*.cpp $(LOCAL_PATH)/../../textord/*.cpp $(LOCAL_PATH)/../../viewer/*.cpp $(LOCAL_PATH)/../../wordrec/*.cpp) + +EXPLICIT_SRC_EXCLUDES := \ + $(LOCAL_PATH)/../../ccmain/cubeclassifier.cpp \ + $(LOCAL_PATH)/../../ccmain/cubeclassifier.h \ + $(LOCAL_PATH)/../../ccmain/cube_control.cpp \ + $(LOCAL_PATH)/../../ccmain/cube_reco_context.cpp \ + $(LOCAL_PATH)/../../ccmain/cube_reco_context.h \ + $(LOCAL_PATH)/../../ccmain/tesseract_cube_combiner.cpp \ + $(LOCAL_PATH)/../../ccmain/tesseract_cube_combiner.h \ + $(LOCAL_PATH)/../../api/pdfrenderer.cpp \ + $(LOCAL_PATH)/../../api/tesseractmain.cpp \ + +LOCAL_SRC_FILES := $(filter-out $(EXPLICIT_SRC_EXCLUDES), $(LOCAL_SRC_FILES)) + +LOCAL_SRC_FILES := $(LOCAL_SRC_FILES:$(LOCAL_PATH)/%=%) + +$(info local src files = $(LOCAL_SRC_FILES)) + +LOCAL_LDLIBS := -ldl -llog -ljnigraphics +LOCAL_CFLAGS := -DANDROID_BUILD -DGRAPHICS_DISABLED + +include $(BUILD_SHARED_LIBRARY) + +$(call import-module,mobile/base) +$(call import-module,mobile/base) +$(call import-module,mobile/util/hash) +$(call import-module,third_party/leptonica/android/jni) diff --git a/android/jni/Application.mk b/android/jni/Application.mk new file mode 100644 index 00000000..ef8a2153 --- /dev/null +++ b/android/jni/Application.mk @@ -0,0 +1,13 @@ +# Include common.mk for building google3 native code. +DEPOT_PATH := $(firstword $(subst /google3, ,$(abspath $(call my-dir)))) +ifneq ($(wildcard $(DEPOT_PATH)/google3/mobile/build/common.mk),) + include $(DEPOT_PATH)/google3/mobile/build/common.mk +else + include $(DEPOT_PATH)/READONLY/google3/mobile/build/common.mk +endif + +# Specify the hash namespace that we're using, based on the APP_STL we're using. +APP_CFLAGS += -Werror -DHASH_NAMESPACE=__gnu_cxx -Wno-error=deprecated-register +APP_PLATFORM := android-16 +APP_STL := gnustl_static +NDK_TOOLCHAIN_VERSION := clang diff --git a/api/baseapi.cpp b/api/baseapi.cpp index f502d24f..26398491 100644 --- a/api/baseapi.cpp +++ b/api/baseapi.cpp @@ -742,6 +742,7 @@ void TessBaseAPI::DumpPGM(const char* filename) { fclose(fp); } +#ifndef ANDROID_BUILD /** * Placeholder for call to Cube and test that the input data is correct. * reskew is the direction of baselines in the skewed image in @@ -786,6 +787,7 @@ int CubeAPITest(Boxa* boxa_blocks, Pixa* pixa_blocks, ASSERT_HOST(pr_word == word_count); return 0; } +#endif /** * Runs page layout analysis in the mode set by SetPageSegMode. @@ -1022,6 +1024,7 @@ bool TessBaseAPI::ProcessPagesMultipageTiff(const l_uint8 *data, int timeout_millisec, TessResultRenderer* renderer, int tessedit_page_number) { +#ifndef ANDROID_BUILD Pix *pix = NULL; #ifdef USE_OPENCL OpenclDevice od; @@ -1052,6 +1055,9 @@ bool TessBaseAPI::ProcessPagesMultipageTiff(const l_uint8 *data, if (tessedit_page_number >= 0) break; } return true; +#else + return false; +#endif } // Master ProcessPages calls ProcessPagesInternal and then does any post- @@ -1087,6 +1093,7 @@ bool TessBaseAPI::ProcessPagesInternal(const char* filename, const char* retry_config, int timeout_millisec, TessResultRenderer* renderer) { +#ifndef ANDROID_BUILD PERF_COUNT_START("ProcessPages") bool stdInput = !strcmp(filename, "stdin") || !strcmp(filename, "-"); if (stdInput) { @@ -1174,6 +1181,9 @@ bool TessBaseAPI::ProcessPagesInternal(const char* filename, } PERF_COUNT_END return true; +#else + return false; +#endif } bool TessBaseAPI::ProcessPage(Pix* pix, int page_index, const char* filename, @@ -1207,8 +1217,10 @@ bool TessBaseAPI::ProcessPage(Pix* pix, int page_index, const char* filename, failed = Recognize(NULL) < 0; } if (tesseract_->tessedit_write_images) { +#ifndef ANDROID_BUILD Pix* page_pix = GetThresholdedImage(); pixWrite("tessinput.tif", page_pix, IFF_TIFF_G4); +#endif } if (failed && retry_config != NULL && retry_config[0] != '\0') { // Save current config variables before switching modes. @@ -2613,10 +2625,12 @@ int TessBaseAPI::NumDawgs() const { return tesseract_ == NULL ? 0 : tesseract_->getDict().NumDawgs(); } +#ifndef ANDROID_BUILD /** Return a pointer to underlying CubeRecoContext object if present. */ CubeRecoContext *TessBaseAPI::GetCubeRecoContext() const { return (tesseract_ == NULL) ? NULL : tesseract_->GetCubeRecoContext(); } +#endif /** Escape a char string - remove <>&"' with HTML codes. */ STRING HOcrEscape(const char* text) { diff --git a/ccmain/control.cpp b/ccmain/control.cpp index 0dbc3fa3..28f6c824 100644 --- a/ccmain/control.cpp +++ b/ccmain/control.cpp @@ -387,12 +387,14 @@ bool Tesseract::recog_all_words(PAGE_RES* page_res, // ****************** Pass 5,6 ******************* rejection_passes(page_res, monitor, target_word_box, word_config); +#ifndef ANDROID_BUILD // ****************** Pass 7 ******************* // Cube combiner. // If cube is loaded and its combiner is present, run it. if (tessedit_ocr_engine_mode == OEM_TESSERACT_CUBE_COMBINED) { run_cube_combiner(page_res); } +#endif // ****************** Pass 8 ******************* font_recognition_pass(page_res); @@ -986,11 +988,13 @@ void Tesseract::classify_word_pass1(const WordData& word_data, BLOCK* block = word_data.block; prev_word_best_choice_ = word_data.prev_word != NULL ? word_data.prev_word->word->best_choice : NULL; +#ifndef ANDROID_BUILD // If we only intend to run cube - run it and return. if (tessedit_ocr_engine_mode == OEM_CUBE_ONLY) { cube_word_pass1(block, row, *in_word); return; } +#endif WERD_RES* word = *in_word; match_word_pass_n(1, word, row, block); if (!word->tess_failed && !word->word->flag(W_REP_CHAR)) { diff --git a/ccmain/paramsd.h b/ccmain/paramsd.h index 164b1463..0214652e 100644 --- a/ccmain/paramsd.h +++ b/ccmain/paramsd.h @@ -24,7 +24,9 @@ #define VARABLED_H #include "elst.h" +#ifndef ANDROID_BUILD #include "scrollview.h" +#endif #include "params.h" #include "tesseractclass.h" diff --git a/ccmain/tessedit.cpp b/ccmain/tessedit.cpp index e8566050..f5fb0379 100644 --- a/ccmain/tessedit.cpp +++ b/ccmain/tessedit.cpp @@ -194,7 +194,11 @@ bool Tesseract::init_tesseract_lang_data( if (tessdata_manager_debug_level) tprintf("Loaded ambigs\n"); } - // Load Cube objects if necessary. + // The various OcrEngineMode settings (see publictypes.h) determine which + // engine-specific data files need to be loaded. Currently everything needs + // the base tesseract data, which supplies other useful information, but + // alternative engines, such as cube and LSTM are optional. +#ifndef ANDROID_BUILD if (tessedit_ocr_engine_mode == OEM_CUBE_ONLY) { ASSERT_HOST(init_cube_objects(false, &tessdata_manager)); if (tessdata_manager_debug_level) @@ -204,7 +208,7 @@ bool Tesseract::init_tesseract_lang_data( if (tessdata_manager_debug_level) tprintf("Loaded Cube with combiner\n"); } - +#endif // Init ParamsModel. // Load pass1 and pass2 weights (for now these two sets are the same, but in // the future separate sets of weights can be generated). @@ -475,5 +479,4 @@ enum CMD_EVENTS RECOG_PSEUDO, ACTION_2_CMD_EVENT }; - } // namespace tesseract diff --git a/ccmain/tesseractclass.cpp b/ccmain/tesseractclass.cpp index e50699b5..c262bbc9 100644 --- a/ccmain/tesseractclass.cpp +++ b/ccmain/tesseractclass.cpp @@ -37,11 +37,15 @@ #include "tesseractclass.h" #include "allheaders.h" +#ifndef ANDROID_BUILD #include "cube_reco_context.h" +#endif #include "edgblob.h" #include "equationdetect.h" #include "globals.h" +#ifndef ANDROID_BUILD #include "tesseract_cube_combiner.h" +#endif // Include automatically generated configuration file if running autoconf. #ifdef HAVE_CONFIG_H @@ -547,8 +551,10 @@ Tesseract::Tesseract() reskew_(1.0f, 0.0f), most_recently_used_(this), font_table_size_(0), +#ifndef ANDROID_BUILD cube_cntxt_(NULL), tess_cube_combiner_(NULL), +#endif equ_detect_(NULL) { } @@ -556,6 +562,7 @@ Tesseract::~Tesseract() { Clear(); end_tesseract(); sub_langs_.delete_data_pointers(); +#ifndef ANDROID_BUILD // Delete cube objects. if (cube_cntxt_ != NULL) { delete cube_cntxt_; @@ -565,6 +572,7 @@ Tesseract::~Tesseract() { delete tess_cube_combiner_; tess_cube_combiner_ = NULL; } +#endif } void Tesseract::Clear() { diff --git a/ccmain/tesseractclass.h b/ccmain/tesseractclass.h index c3fe50e0..087e995e 100644 --- a/ccmain/tesseractclass.h +++ b/ccmain/tesseractclass.h @@ -97,12 +97,16 @@ class WERD_RES; namespace tesseract { class ColumnFinder; +#ifndef ANDROID_BUILD class CubeLineObject; class CubeObject; class CubeRecoContext; +#endif class EquationDetect; class Tesseract; +#ifndef ANDROID_BUILD class TesseractCubeCombiner; +#endif // A collection of various variables for statistics and debugging. struct TesseractStats { @@ -382,6 +386,7 @@ class Tesseract : public Wordrec { int *right_ok) const; //// cube_control.cpp /////////////////////////////////////////////////// +#ifndef ANDROID_BUILD bool init_cube_objects(bool load_combiner, TessdataManager *tessdata_manager); // Iterates through tesseract's results and calls cube on each word, @@ -407,6 +412,7 @@ class Tesseract : public Wordrec { Boxa** char_boxes, CharSamp*** char_samples); bool create_cube_box_word(Boxa *char_boxes, int num_chars, TBOX word_box, BoxWord* box_word); +#endif //// output.h ////////////////////////////////////////////////////////// void output_pass(PAGE_RES_IT &page_res_it, const TBOX *target_word_box); @@ -713,8 +719,8 @@ class Tesseract : public Wordrec { // Creates a fake best_choice entry in each WERD_RES with the correct text. void CorrectClassifyWords(PAGE_RES* page_res); // Call LearnWord to extract features for labelled blobs within each word. - // Features are written to the given filename. - void ApplyBoxTraining(const STRING& filename, PAGE_RES* page_res); + // Features are stored in an internal buffer. + void ApplyBoxTraining(const STRING& fontname, PAGE_RES* page_res); //// fixxht.cpp /////////////////////////////////////////////////////// // Returns the number of misfit blob tops in this word. @@ -1089,7 +1095,9 @@ class Tesseract : public Wordrec { PAGE_RES_IT* pr_it, FILE *output_file); +#ifndef ANDROID_BUILD inline CubeRecoContext *GetCubeRecoContext() { return cube_cntxt_; } +#endif private: // The filename of a backup config file. If not null, then we currently @@ -1129,9 +1137,11 @@ class Tesseract : public Wordrec { Tesseract* most_recently_used_; // The size of the font table, ie max possible font id + 1. int font_table_size_; +#ifndef ANDROID_BUILD // Cube objects. CubeRecoContext* cube_cntxt_; TesseractCubeCombiner *tess_cube_combiner_; +#endif // Equation detector. Note: this pointer is NOT owned by the class. EquationDetect* equ_detect_; }; diff --git a/ccstruct/imagedata.cpp b/ccstruct/imagedata.cpp index 0186cd09..4016a92b 100644 --- a/ccstruct/imagedata.cpp +++ b/ccstruct/imagedata.cpp @@ -51,6 +51,7 @@ void WordFeature::ComputeSize(const GenericVector& features, // Draws the features in the given window. void WordFeature::Draw(const GenericVector& features, ScrollView* window) { +#ifndef GRAPHICS_DISABLED for (int f = 0; f < features.size(); ++f) { FCOORD pos(features[f].x_, features[f].y_); FCOORD dir; @@ -61,6 +62,7 @@ void WordFeature::Draw(const GenericVector& features, window->DrawTo(IntCastRounded(pos.x() + dir.x()), IntCastRounded(pos.y() + dir.y())); } +#endif } // Writes to the given file. Returns false in case of error. @@ -244,6 +246,7 @@ int ImageData::MemoryUsed() const { // Draws the data in a new window. void ImageData::Display() const { +#ifndef GRAPHICS_DISABLED const int kTextSize = 64; // Draw the image. Pix* pix = GetPix(); @@ -274,6 +277,7 @@ void ImageData::Display() const { win->Pen(ScrollView::GREEN); win->Update(); window_wait(win); +#endif } // Adds the supplied boxes and transcriptions that correspond to the correct diff --git a/textord/drawedg.h b/textord/drawedg.h index 339432fd..0d4903ba 100644 --- a/textord/drawedg.h +++ b/textord/drawedg.h @@ -19,6 +19,7 @@ #ifndef DRAWEDG_H #define DRAWEDG_H +#ifndef ANDROID_BUILD #include "scrollview.h" #include "crakedge.h" @@ -32,3 +33,4 @@ void draw_raw_edge( //draw the cracks ScrollView::Color colour //colour to draw in ); #endif +#endif