add more JNI bindings
Signed-off-by: Iliyan Malchev <malchev@google.com>
diff --git a/ccmain/jni.cpp b/ccmain/jni.cpp
index 294bf66..37a2403 100644
--- a/ccmain/jni.cpp
+++ b/ccmain/jni.cpp
@@ -17,7 +17,6 @@
#include <nativehelper/jni.h>
#include <assert.h>
-#include <stdio.h> // debug
#include "baseapi.h"
#include "varable.h"
@@ -26,6 +25,7 @@
#define DEBUG 1
#if DEBUG
+#include <stdio.h>
BOOL_VAR (tessedit_write_images, TRUE,
"Capture the image from the IPE");
#endif
@@ -34,6 +34,8 @@
#include <utils/Log.h>
static tesseract::TessBaseAPI api;
+static jbyteArray image_obj;
+static jbyte* image_buffer;
jboolean
ocr_open(JNIEnv *env, jobject thiz, jstring lang)
@@ -56,39 +58,23 @@
LOGE("could not initialize tesseract!");
res = JNI_FALSE;
}
+#if DEBUG
else if (!api.ReadConfigFile("/sdcard/tessdata/ratings")) {
LOGE("could not read config file, using defaults!");
// This is not a fatal error.
}
- LOGI("lang %s initialization complete\n", c_lang);
+#endif
+ else
+ LOGI("lang %s initialization complete\n", c_lang);
env->ReleaseStringUTFChars(lang, c_lang);
LOGI("successfully initialized tesseract!");
return res;
}
-jstring
-ocr_recognize(JNIEnv *env, jobject thiz,
- jbyteArray image,
- jint width, jint height,
- jint bpp,
- jint rowWidth)
-{
- LOGI("recognize image x=%d, y=%d, rw=%d\n", width, height, rowWidth);
-
- if (env->GetArrayLength(image) < width * height) {
- LOGE("image length = %ld is less than width * height = %ld!",
- env->GetArrayLength(image),
- width * height);
- }
-
- jbyte* buffer = env->GetByteArrayElements(image, NULL);
- api.SetImage((const unsigned char *)buffer,
- width, height, bpp, rowWidth);
- char * text = api.GetUTF8Text();
- env->ReleaseByteArrayElements(image, buffer, JNI_ABORT);
-
#if DEBUG
+static void dump_debug_data(char *text)
+{
if (tessedit_write_images) {
page_image.write("/data/tessinput.tif");
}
@@ -102,22 +88,194 @@
fclose(fp);
}
}
+}
+#else
+static void dump_debug_data(char *text __attribute__((unused)))
+{
+}
#endif
+jstring
+ocr_recognize_image(JNIEnv *env, jobject thiz,
+ jbyteArray image,
+ jint width, jint height,
+ jint bpp,
+ jint rowWidth)
+{
+ LOGI("recognize image x=%d, y=%d, rw=%d\n", width, height, rowWidth);
+
+ if (env->GetArrayLength(image) < width * height) {
+ LOGE("image length = %d is less than width * height = %d!",
+ env->GetArrayLength(image),
+ width * height);
+ }
+
+ jbyte* buffer = env->GetByteArrayElements(image, NULL);
+ api.SetImage((const unsigned char *)buffer,
+ width, height, bpp, rowWidth);
+ char * text = api.GetUTF8Text();
+ env->ReleaseByteArrayElements(image, buffer, JNI_ABORT);
+
+ dump_debug_data(text);
+
// Will that work on a NULL?
return env->NewStringUTF(text);
}
+void
+ocr_set_image(JNIEnv *env, jobject thiz,
+ jbyteArray image,
+ jint width, jint height,
+ jint bpp,
+ jint rowWidth)
+{
+ LOG_ASSERT(image_obj == NULL && image_buffer == NULL,
+ "image and/or image_buffer are not NULL!");
+ image_obj = (jbyteArray)env->NewGlobalRef(image);
+ image_buffer = env->GetByteArrayElements(image_obj, NULL);
+ api.SetImage((const unsigned char *)image_buffer,
+ width, height, bpp, rowWidth);
+}
+
+void
+ocr_set_rectangle(JNIEnv *env, jobject thiz,
+ jint left, jint top,
+ jint width, jint height)
+{
+ // Restrict recognition to a sub-rectangle of the image. Call after SetImage.
+ // Each SetRectangle clears the recogntion results so multiple rectangles
+ // can be recognized with the same image.
+ LOG_ASSERT(image_obj != NULL && image_buffer != NULL,
+ "image and/or image_buffer are NULL!");
+ api.SetRectangle(left, top, width, height);
+}
+
+jstring
+ocr_recognize(JNIEnv *env, jobject thiz,
+ jint width, jint height,
+ jint bpp,
+ jint rowWidth)
+{
+ LOG_ASSERT(image_obj != NULL && image_buffer != NULL,
+ "image and/or image_buffer are NULL!");
+
+ char * text = api.GetUTF8Text();
+
+ dump_debug_data(text);
+
+ // Will that work on a NULL?
+ return env->NewStringUTF(text);
+}
+
+static jint
+ocr_mean_confidence(JNIEnv *env, jobject thiz)
+{
+ // Returns the (average) confidence value between 0 and 100.
+ return api.MeanTextConf();
+}
+
+static jintArray
+ocr_word_confidences(JNIEnv *env, jobject thiz)
+{
+ // Returns all word confidences (between 0 and 100) in an array, terminated
+ // by -1. The calling function must delete [] after use.
+ // The number of confidences should correspond to the number of space-
+ // delimited words in GetUTF8Text.
+ int* confs = api.AllWordConfidences();
+ LOG_ASSERT(confs != NULL, "Could not get word-confidence values!");
+
+ int len, *trav;
+ for (len = 0, trav = confs; *trav != -1; trav++, len++);
+
+ LOG_ASSERT(confs != NULL, "Confidence array has %d elements",
+ len);
+
+ jintArray ret = env->NewIntArray(len);
+ LOG_ASSERT(ret != NULL,
+ "Could not create Java confidence array!");
+
+ env->SetIntArrayRegion(ret, 0, len, confs);
+ delete [] confs;
+ return ret;
+}
+
+static void
+ocr_set_variable(JNIEnv *env, jobject thiz,
+ jstring var, jstring value)
+{
+ // Set the value of an internal "variable" (of either old or new types).
+ // Supply the name of the variable and the value as a string, just as
+ // you would in a config file.
+ // Returns false if the name lookup failed.
+ // Eg SetVariable("tessedit_char_blacklist", "xyz"); to ignore x, y and z.
+ // Or SetVariable("bln_numericmode", "1"); to set numeric-only mode.
+ // SetVariable may be used before Init, but settings will revert to
+ // defaults on End().
+
+ const char *c_var = env->GetStringUTFChars(var, NULL);
+ const char *c_value = env->GetStringUTFChars(value, NULL);
+
+ api.SetVariable(c_var, c_value);
+
+ env->ReleaseStringUTFChars(var, c_var);
+ env->ReleaseStringUTFChars(value, c_value);
+}
+
+static void
+ocr_clear_results(JNIEnv *env, jobject thiz)
+{
+ // Free up recognition results and any stored image data, without actually
+ // freeing any recognition data that would be time-consuming to reload.
+ // Afterwards, you must call SetImage or TesseractRect before doing
+ // any Recognize or Get* operation.
+ LOGI("releasing all memory");
+ api.Clear();
+
+ // Call between pages or documents etc to free up memory and forget
+ // adaptive data.
+ LOGI("clearing adaptive classifier");
+ api.ClearAdaptiveClassifier();
+
+ if (image_buffer != NULL) {
+ LOGI("releasing image buffer");
+ env->ReleaseByteArrayElements(image_obj, image_buffer, JNI_ABORT);
+ env->DeleteGlobalRef(image_obj);
+ image_obj = NULL;
+ image_buffer = NULL;
+ }
+}
+
static void
ocr_close(JNIEnv *env, jobject thiz)
{
LOGI("quit");
+
+ // Close down tesseract and free up all memory. End() is equivalent to
+ // destructing and reconstructing your TessBaseAPI. Once End() has been
+ // used, none of the other API functions may be used other than Init and
+ // anything declared above it in the class definition.
+// api.End(); --> causes a crash
+}
+
+static void
+ocr_set_page_seg_mode(JNIEnv *env, jobject thiz, jint mode)
+{
+ // Set the current page segmentation mode. Defaults to PSM_AUTO.
+ api.SetPageSegMode((tesseract::PageSegMode)mode);
}
static JNINativeMethod methods[] = {
- {"open", "(Ljava/lang/String;)Z", (void*)ocr_open},
- {"recognize", "([BIIII)Ljava/lang/String;", (void*)ocr_recognize},
- {"close", "()V", (void*)ocr_close},
+ {"openNative", "(Ljava/lang/String;)Z", (void*)ocr_open},
+ {"setImageNative", "([BIIII)V", (void*)ocr_set_image},
+ {"setRectangleNative", "(IIII)V", (void*)ocr_set_rectangle},
+ {"recognizeNative", "()Ljava/lang/String;", (void*)ocr_recognize},
+ {"recognizeNative", "([BIIII)Ljava/lang/String;", (void*)ocr_recognize_image},
+ {"clearResultsNative", "()V", (void*)ocr_clear_results},
+ {"closeNative", "()V", (void*)ocr_close},
+ {"meanConfidenceNative", "()I", (void*)ocr_mean_confidence},
+ {"wordConfidencesNative", "()[I", (void*)ocr_word_confidences},
+ {"setVariableNative", "(Ljava/lang/String;Ljava/lang/String;)V", (void*)ocr_set_variable},
+ {"setPageSegModeNative", "(I)V", (void*)ocr_set_page_seg_mode},
};
/*