Back to project page mezzofanti.
The source code is released under:
Apache License
If you think the Android project mezzofanti listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
/* * Copyright (C) 2009 IT Wizard.//from w ww . ja v a2 s . c o m * http://www.itwizard.ro * * 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. */ package com.itwizard.mezzofanti; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.Typeface; import android.text.SpannableString; import android.text.Spanned; import android.text.style.StyleSpan; import android.util.Log; /** * The wrapper for the JNI-OCR library */ public final class OCR { public static OCRConfig mConfig = new OCRConfig(); private static OCR m_OCRinstance = null; // there is only one ocr instance, publicly access it with get() private static final String TAG = "MLOG: OCR.java: "; // Java-lib variables public final static int PSM_AUTO = 0; // Fully automatic page segmentation. (Default.) public final static int PSM_SINGLE_COLUMN = 1; // Assume a single column of text of variable sizes. public final static int PSM_SINGLE_BLOCK = 2; // Assume a single uniform block of text. public final static int PSM_SINGLE_LINE = 3; // Treat the image as a single text line. public final static int PSM_SINGLE_WORD = 4; // Treat the image as a single word. public final static int PSM_SINGLE_CHAR = 5; // Treat the image as a single character. public final static int PSM_COUNT = 6; // Number of enum entries. public static Word[] m_asWords = null; // vector to keep all info about each word in the results public static SpannableString m_ssOCRResult = null; // the parsed result (all errors are changed to '#', all non-dictionary words become 'italic') public static int m_iMeanConfidence = 0; // the mean overall confidence private boolean m_bLineMode = false; public boolean m_bIsLibraryInitialized = false; // is the library initialized /** * Class to keep info about each OCRed word. */ public final class Word { String m_sBody; // the word body int m_iConfidence; // the ocr confidence for the word boolean m_bIsValidWord; // is a valid dictionary word boolean m_bNewLine; // hold an endline after it int m_iEnd; // the last position in the overall result /** * constructor */ public Word() { m_sBody = ""; m_iConfidence = 0; m_bIsValidWord = false; m_bNewLine = false; m_iEnd = 0; } /** * 2nd constructor * @param body the word-body * @param conf the confidence */ public Word(String body, int conf) { if (!mConfig.m_bReplaceUnknownChars) m_sBody = body; else { m_sBody = body.replaceAll("[\n\r]+", ""); m_sBody = m_sBody.replaceAll("[^A-Za-z0-9!?.,%$@&*(){}<>:;'\"-]+", "#"); } m_iConfidence = conf; if (m_sBody.contains("#")) m_bIsValidWord = false; else m_bIsValidWord = MyIsValidDictionaryWord(body); m_bNewLine = body.contains("\n"); Log.v(TAG, "Word("+m_sBody+","+conf+")"); } } // end class Word // ------------------------------------------------------------------- /** * stores the OCR configuration, load/store the config */ public final static class OCRConfig { public int m_iMinOveralConfidence; // the overall confidence for all decoded text public int m_iMinWordConfidence; // the confidence per each word public int m_iPSMMode = PSM_AUTO; // the OCR scanning mode public boolean m_bUseBWFilter; // enable or not the BW filter public boolean m_bShowValidWordsOnly; // if enabled, we will display only the dictionary-valid words after OCR public boolean m_bReplaceUnknownChars; // replace strange characters with '#' private byte m_bImgDivisor = 2; // the image divisor factor private String m_sLanguage = "eng"; // current language public String m_asLanguages[] = null; // all available languages /** * constructor */ public OCRConfig() { LoadFabricDefaults(); } /** * load fabric default values for the config */ public void LoadFabricDefaults() { m_iMinOveralConfidence = 60; m_iMinWordConfidence = 50; m_iPSMMode = OCR.PSM_AUTO; SetImgDivisor(2); m_bUseBWFilter = false; m_bShowValidWordsOnly = false; m_bReplaceUnknownChars = true; m_sLanguage = "eng"; Log.v(TAG, "LoadFabricDefaults(): " + m_sLanguage); } /** * get setings from the shared preferences * @param prefs the shared preferences * @return success/fail */ public boolean GetSettings(SharedPreferences prefs) { Log.v(TAG, "GetSettings() -----------------------------------------------"); try { OCR.mConfig.m_iMinOveralConfidence = Integer.parseInt(prefs.getString(PreferencesActivity.KEY_MIN_OVERALL_CONFIDENCE, "60")); OCR.mConfig.m_iMinWordConfidence = Integer.parseInt(prefs.getString(PreferencesActivity.KEY_MIN_WORD_CONFIDENCE, "50")); OCR.mConfig.SetImgDivisor(Integer.parseInt(prefs.getString(PreferencesActivity.KEY_SPEED_QUALITY, "2"))); OCR.mConfig.m_bUseBWFilter = prefs.getBoolean(PreferencesActivity.KEY_USE_IMAGE_LIGHT_FILTER, false); OCR.mConfig.m_sLanguage = prefs.getString(PreferencesActivity.KEY_SET_OCR_LANGUAGE, "eng"); } catch (Exception ex) { Log.v(TAG, "exception: GetSettings()" + ex.toString()); return false; } Log.v(TAG, "GetSettings: [" + OCR.mConfig.m_iMinOveralConfidence +","+ OCR.mConfig.m_iMinWordConfidence +","+ OCR.mConfig.GetImgDivisor() +","+ OCR.mConfig.m_bUseBWFilter +","+ OCR.mConfig.m_sLanguage +"]" ); return true; } /** * set the image divisor for the OCR * @param d 2/4 */ public void SetImgDivisor(int d) { if (d!=2 && d!=4) return; m_bImgDivisor = (byte)d; } /** * @return the image divisor */ public byte GetImgDivisor() { return m_bImgDivisor; } /** * @return OCR dictionary language */ public String GetLanguage() { Log.v(TAG, "GetLanguage(): " + m_sLanguage); return m_sLanguage; } /** * @return a string containing all available OCR dictionaries */ public String GetLanguages() { String ret = ""; for (int i=0; i<m_asLanguages.length; i++) { ret += m_asLanguages[i]; if (i!=m_asLanguages.length-1) ret += ","; } return ret; } /** * @return a vector of strings, each string is a valid OCR-dictionary language */ public String[] GetvLanguages() { if (m_asLanguages == null) return null; String ret[] = new String[m_asLanguages.length]; for (int i=0; i<m_asLanguages.length; i++) ret[i] = LanguageMore(m_asLanguages[i]); return ret; } /** * Check if a language is installed. * @param lang the language to check for * @return if language is installed or not */ public boolean IsLanguageInstalled(String lang) { if (m_asLanguages == null) return false; for (int i=0; i<m_asLanguages.length; i++) { if (m_asLanguages[i].compareTo(lang) == 0) return true; if (LanguageMore(m_asLanguages[i]).compareTo(lang) == 0) return true; } return false; } /** * @param lang the language in short format * @return the language in long-string format */ public String LanguageMore(String lang) { if ( lang.compareTo("eng") == 0 ) return "English"; if ( lang.compareTo("spa") == 0 ) return "Spanish"; if ( lang.compareTo("fra") == 0 ) return "French"; if ( lang.compareTo("ita") == 0 ) return "Italian"; if ( lang.compareTo("deu") == 0 ) return "German"; return "error"; } /** * @return the current OCR language in long-string format */ public String GetLanguageMore() { return LanguageMore(m_sLanguage); } } // end class OCRConfig // ------------------------------------------------------------------- /** * constructor */ private OCR() { String text = libVer(); classInitNative(); initializeNativeDataNative(); mConfig.m_asLanguages = getLanguagesNative(); // this should be called at the beginning, // such a way nobody calls without a valid language // if not called, the recognizeNative will not work Log.v(TAG, "OCR Initialize() done - libver "+ text + " no-langs-installed=" + mConfig.m_asLanguages.length); } public static void Initialize() { if (m_OCRinstance == null) { m_OCRinstance = new OCR(); } } /** * @return the ocr instance */ public static OCR get() { return m_OCRinstance; } /** * cleanup function */ public void Destructor() { Log.v(TAG, "OCR - finalize"); if (m_bIsLibraryInitialized) OCRClean(); m_bIsLibraryInitialized = false; } /** * read the available OCR languages in the local vector */ public static void ReadAvailableLanguages() { mConfig.m_asLanguages = getLanguagesNative(); } /** * Set the OCR-dictionary language * @param lang the language to be set * @return true if language exists and was installed properly */ public boolean SetLanguage(String lang) { Log.v(TAG, "setLanguage to "+lang); if (mConfig.m_asLanguages == null) return false; Log.v(TAG, "noLangs=" + mConfig.m_asLanguages.length); for (int i=0; i<mConfig.m_asLanguages.length; i++) if (mConfig.m_asLanguages[i].compareTo(lang) == 0) { mConfig.m_sLanguage = lang; openNative(lang); Log.v(TAG, "setLang succeded"); return true; } Log.v(TAG, "setLang failed"); return false; } /** * clear the API and the buffers used by the last OCR execution */ public void OCRClean() { clearResultsNative(); // api clear releaseImageNative(); // free the image buffers //cleanupNativeDataNative(); // free internal buffers (test for crash if image not allocated) //closeNative(); // end api - called by the destructor itself closeDebug(); // clean close debug } /** * Local store of mean confidence */ public void SaveMeanConfidence() { m_iMeanConfidence = meanConfidenceNative(); } /** * Add a user word to the OCR-dictionary. * @param newword * @return */ public boolean AddUserWord(String newword) { if (!isValidWord(newword)) { BufferedWriter writer; try { writer = new BufferedWriter(new FileWriter(Mezzofanti.DATA_PATH + mConfig.GetLanguage() +".user-words",true)); writer.write(newword+"\n"); writer.close(); closeNative(); openNative(mConfig.GetLanguage()); // change the validity in the local structure for (int i=0; i<m_asWords.length; i++) { if (m_asWords[i].m_sBody.compareTo(newword) == 0) m_asWords[i].m_bIsValidWord = true; } return true; } catch (Exception e) { Log.v(TAG, e.toString()); return false; } } return false; } /** * Get the internal picture that was used during the OCR. The OCR engine uses a filtered image, and not the original. * Using this function, one can see why there were problems during OCR. * * @param pic_width the picture width * @param pic_height the picture height * @return the internal image as a bitmap */ public Bitmap GetInternImage(int pic_width, int pic_height) { // from disk file Log.v(TAG, "getInternImage w=" + pic_width + " h=" + pic_height); byte[] tif = null; try { tif = GetBytesFromFile(new File(Mezzofanti.RESULTS_PATH + "tessinput.tif"), pic_width, pic_height, 1); } catch (Exception ex) { Log.v(TAG, "exception: " + ex.toString()); } if (tif == null) { Log.v(TAG, "warning: tif is null"); return null; } Bitmap bmp2 = null; try { bmp2 = Bitmap.createBitmap(pic_width, pic_height, Bitmap.Config.RGB_565); } catch (Throwable th) { Log.v(TAG, "throwable: " + th.toString()); return null; } int [] pixbuf = new int[8]; for (int h=0; h<pic_height; h++) for (int w=0; w<pic_width; w++) { if (w%8 == 0) { // read 8b -> 8pixels int pix = tif[258 + (h*pic_width + w)/8]; // store them in a buffer for (int i=0; i<8; i++) { pix = pix >> i; pixbuf[7-i] = pix & 0x00000001; if (pixbuf[7-i] != 0) pixbuf[7-i] = 0x00ffffff; } } bmp2.setPixel(w, h, pixbuf[w%8]); } return bmp2; } /** * from unsigned byte to int value * @param b value to be converted * @return the according int value */ public int unsignedByte2Int(byte b) { return (int) b & 0xFF; } /** * read bytes from file into a byte buffer * @param file the image-file to be read * @param width the image width * @param height the image height * @param bpp bytes per pixel * @return a vector with the image, no compression * @throws IOException */ public byte[] GetBytesFromFile(File file, int width, int height, int bpp) throws IOException { InputStream is = new FileInputStream(file); // Get the size of the file long length = file.length(); if (length < width*height*bpp) { // file is too small Log.v(TAG, "warning: file len is too small "+length); //return null; //bpp in the tif case is fractional 1b per pixel, meaning 1/8B per pixel, so this warning is wrong } // You cannot create an array using a long type. // It needs to be an int type. // Before converting to an int type, check // to ensure that file is not larger than Integer.MAX_VALUE. if (length > Integer.MAX_VALUE) { // File is too large Log.v(TAG, "warning: length more than max allowed value"); return null; } // Create the byte array to hold the data byte[] bytes = new byte[(int)length]; // Read in the bytes int offset = 0; int numRead = 0; while (offset < bytes.length && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) { offset += numRead; } // Ensure all the bytes have been read in if (offset < bytes.length) { throw new IOException("Could not completely read file "+file.getName()); } // Close the input stream and return bytes is.close(); return bytes; } /* * ---------------------------------------------------------------------------------------- * OCR functions * ---------------------------------------------------------------------------------------- */ /** * Transforms an image to bw 1bpp. * @param bw_img the image * @param width image width * @param height image height * @param bpp bytes per pixel * @return the new bpp */ public int bwFilterImage(byte[] bw_img, int width, int height, int bpp) { //!! TBD if bpp=1 final int THOLD_WHITE = 0x70; final int THOLD_BLACK = 0x30; final int BLK_SZ = width/16; //=128 (this should be an int, otherwise we will get noise at the margins) final int RED_P = 3; final int GREEN_P = 6; final int BLUE_P = 1; if (bpp != 1) { int local_min = THOLD_WHITE; int local_max = THOLD_BLACK; int local = 0; for (int i=0; i<width * height; i++) { // compute the intensity of the pixel int red = unsignedByte2Int(bw_img[i*3+0]); int green = unsignedByte2Int(bw_img[i*3+1]); int blue = unsignedByte2Int(bw_img[i*3+2]); int intensity = red*RED_P + green*GREEN_P + blue*BLUE_P; intensity /= 10; // rarely: compute in advance the local min and max (for one BLK_SZ line) if ( local == 0 ) { local_min = THOLD_WHITE; local_max = THOLD_BLACK; for (int k=i; k<i+BLK_SZ && k<width*height; k++) { int lred = unsignedByte2Int(bw_img[k*3+0]); int lgreen = unsignedByte2Int(bw_img[k*3+1]); int lblue = unsignedByte2Int(bw_img[k*3+2]); int lintensity = lred*RED_P + lgreen*GREEN_P + lblue*BLUE_P; lintensity /= 10; if ( lintensity > local_max ) local_max = lintensity; if ( lintensity < local_min ) local_min = lintensity; } local = BLK_SZ; } local --; // compare current pixel with local min and max if ( (local_max - intensity) < 0x15 ) { bw_img[i] = -1; // =0xff =white } else { bw_img[i] = 0x00; // black } } // -------------------------------------------------------------- } // we give up 3Bpp, and replace them with 1Bpp (Bpp = Byte Per Pixel) return 1; // return the new bpp } /** * Apply OCR to a byte[] image * @param bw_img the image as a vector (no compresion) * @param width image width * @param height image height * @param bpp bytes per pixel * @return the OCR result */ public String ImgOCRAndFilter(byte[] bw_img, int width, int height, int bpp) { String text = ""; try { // the filter modifies the img-buffer itself //bpp = bwFilterImage(bw_img, width, height, bpp); setImageNative(bw_img, width, height, bpp); // copy the image in the internal OCR buffers setRectangleNative(0, 0, width, height); // set rectangle to be OCRized setPageSegModeNative(mConfig.m_iPSMMode); // set the page segmentation mode text = recognizeNative(); // OCR the buffered image //text = recognizeNative(); // OCR the buffered image //text = recognizeNative(bw_img, width, height, bpp); // may be used instead of the 4 steps above // do next - process the results } catch (Exception ex) { text = ex.getMessage(); } return text; } /** * OCR an int[] image * @param bw_img the image, no compression * @param width image width * @param height image height * @param bHorizontalDisp if image is horizontal or vertical * @return */ public String ImgOCRAndFilter(int[] bw_img, int width, int height, boolean bHorizontalDisp, boolean bLineMode) { String text_ret = ""; m_bLineMode = bLineMode; try { setImageNative(bw_img, width, height, mConfig.m_bUseBWFilter, bLineMode ? true : bHorizontalDisp); // copy the image in the internal OCR buffers if (bHorizontalDisp || bLineMode) setRectangleNative(0, 0, width, height); // set rectangle to be OCRized else setRectangleNative(0, 0, height, width); setPageSegModeNative(mConfig.m_iPSMMode); // set the page segmentation mode String bulk_text = recognizeNative(); // OCR the buffered image text_ret = bulk_text; Log.v(TAG, "OCR brute text is ["+bulk_text+"]"); int wconf[] = wordConfidencesNative(); // get the confidence for each word Log.v(TAG, "no confidences="+wconf.length); String st[] = bulk_text.split("/"); // get the list of words decoded Log.v(TAG, "no words=" + st.length); boolean bLenMatch = true; int len = st.length-1; if (wconf.length != st.length-1) { Log.v(TAG, "errror: the word len do not match --------------------------"); bLenMatch = false; } // create the list of words and attributes m_asWords = new Word[len]; for (int i=0; i<len; i++) m_asWords[i] = new Word( st[i], bLenMatch ? wconf[i] : 0 ); Log.v(TAG, "allocated memory, linemode=" + m_bLineMode); String debug_text = ""; // in line-mode we keep only valid dictionary words and words with a large OCR trust if (m_bLineMode) { text_ret = ""; for (int i=0; i<m_asWords.length; i++) { debug_text += "\t[" + m_asWords[i].m_sBody + "/" + m_asWords[i].m_bIsValidWord +"/"+ m_asWords[i].m_iConfidence +"]"; // show the valid dictionary words if ( m_asWords[i].m_sBody.length() >= 3 && m_asWords[i].m_iConfidence > 80 ) { text_ret += m_asWords[i].m_sBody + " "; continue; } // this is a void word (in line mode we do not display anything for it) if ( m_asWords[i].m_sBody.length() < 3 || !IsValidLineModeWord(m_asWords[i].m_sBody) // this checks if the word contains signs or numbers ) { continue; } // show the valid dictionary words if ( m_asWords[i].m_bIsValidWord || m_asWords[i].m_iConfidence > mConfig.m_iMinWordConfidence ) { text_ret += m_asWords[i].m_sBody + " "; continue; } } Log.v(TAG, "polished text is ["+ text_ret +"]"); Log.v(TAG, "debug text is ["+ debug_text +"]"); } // polish the results according to the configuration, if not in line-mode if (mConfig.m_iMinWordConfidence > 0 && !m_bLineMode) { text_ret = ""; for (int i=0; i<m_asWords.length; i++) { debug_text += "\t[" + m_asWords[i].m_sBody + "/" + m_asWords[i].m_bIsValidWord +"/"+ m_asWords[i].m_iConfidence +"]"; // this is a void word (in line mode we do not display anything for it) if ( m_asWords[i].m_sBody.compareTo(" ") == 0 || m_asWords[i].m_sBody.contains("#") || m_asWords[i].m_sBody.length() == 0) { Log.v(TAG, "1: [" + m_asWords[i].m_sBody + "]"); text_ret += "... "; if (m_asWords[i].m_bNewLine) text_ret += "\n"; m_asWords[i].m_iEnd = text_ret.length(); continue; } // show the valid dictionary words if (m_asWords[i].m_bIsValidWord) { Log.v(TAG, "2: ["+m_asWords[i].m_sBody+"]"); text_ret += m_asWords[i].m_sBody + " "; if (m_asWords[i].m_bNewLine) text_ret += "\n"; m_asWords[i].m_iEnd = text_ret.length(); continue; } // invalid dictionary word, but preaty good confidence - show them if (m_asWords[i].m_iConfidence > mConfig.m_iMinWordConfidence) { Log.v(TAG, "3: ["+m_asWords[i].m_sBody+"]"); text_ret += m_asWords[i].m_sBody; text_ret += " "; } else { text_ret += "... "; } if (m_asWords[i].m_bNewLine) text_ret += "\n"; m_asWords[i].m_iEnd = text_ret.length(); } Log.v(TAG, "polished text is ["+ text_ret +"]"); Log.v(TAG, "debug text is ["+ debug_text +"]"); } } catch (Exception ex) { text_ret = ex.toString(); Log.v(TAG, "Exception (ImgOCRAndFilter): " + ex.toString()); } // create the spannable string, to be displayed m_ssOCRResult = new SpannableString(text_ret); if (!m_bLineMode) { int start = 0; int end = 0; for (int i=0; i<m_asWords.length; i++) { end = m_asWords[i].m_iEnd; if ( m_asWords[i].m_bIsValidWord == false || (m_asWords[i].m_iConfidence!=0 && m_asWords[i].m_iConfidence < mConfig.m_iMinWordConfidence) ) { m_ssOCRResult.setSpan(new StyleSpan(Typeface.ITALIC), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); Log.v(TAG, "ss: "+start+"-"+end); } start = end; } } return text_ret; } /** * Get the index of one word, given the position in the decoded text. * @param iPosInString the position in the string * @return returns -1 if iPosInString is longer than the string itself */ public static int GetWordIndex(int iPosInString) { int i=0; int prev = 0; for (; i<m_asWords.length; i++) { if (iPosInString >= prev && iPosInString < m_asWords[i].m_iEnd) break; prev = m_asWords[i].m_iEnd; } if (i == m_asWords.length) return -1; return i; } /** * OCR a non-coded image from a file, 1 pixel = bpp bytes * @param filename the image-file * @param width image width * @param height image height * @param bpp bytes per pixel * @return the OCR result */ public String FileOCR(String filename, int width, int height, int bpp) { String text = ""; try { byte[] bw_img = null; // -------------- step 1 bw_img = GetBytesFromFile(new File(filename), width, height, bpp); // 1 if (bw_img == null) { return "could not load file\n"; } text = ImgOCRAndFilter(bw_img, width, height, bpp); // do next - process the results } catch (Exception ex) { text = ex.getMessage(); } return text; } /** * Verifies if the provided word is valid for line-mode, where we have more constrains than full-mode * @param s - the word * @return validity */ private boolean IsValidLineModeWord(String s) { // if only letters if (s.matches("[a-zA-Z]+")) return true; if (s.contains("#")) return false; return IsValidComposedWord(s); } /** * This is used in 'word' constructor, we do not want single-letters and signs to be valid dictionary words * @param text the word to be searched * @return validity of the word, according to the dictionary */ public static boolean MyIsValidDictionaryWord(String text) { // this is for numbers, signs and alphabet letters if (text.length() < 2) return false; return IsValidComposedWord(text); } /** * Wrapper for JNI-IsValidWord - all chars converted to lower case, check for composed-words (ex: white-grey) * @param word the word to be searched * @return validity of the word, according to the dictionary */ public static boolean IsValidComposedWord(String word) { String lWord = word.toLowerCase(); // this checks for composed words, ex: well-equiped, grey-white, Montenegro's String ss = lWord.replaceAll("[^a-zA-Z]", " "); String [] vect = ss.split(" "); for (int i=0; i<vect.length; i++) if ( vect[i].length()>0 && !get().isValidWord(vect[i]) ) // even if one word is not valid, return { Log.v(TAG, "word: ["+vect[i] +"] is not valid"); return false; } return true; } /* * ---------------------------------------------------------------------------------------- * Java-lib variables * ---------------------------------------------------------------------------------------- */ /* The methods implemented by the 'ocr' native library, which is packaged * with this application. */ // general initialization/cleanup/setup functions public native void classInitNative(); // init the lib (1st to be called at startup) public native void initializeNativeDataNative(); // init allocate lib buffers (2nd to be called) public native boolean openNative(String sLanguage); // init the api with a language public native void cleanupNativeDataNative(); // delete the lib buffers public native void clearResultsNative(); // api clear public native void closeNative(); // api.end, called by the destructor automatically public native void setVariableNative( // set a lib variable String var, String value); // language functions public static native String[] getLanguagesNative(); // get the language list public native int getShardsNative( // get the shard of the language String lang); public native boolean isValidWord(String word); // is the word valid according to the installed language // aux functions before OCR public native void setImageNative( // copy the image to the internal api buffers byte[] image, int width, int height, int bpp); public native void setImageNative( // copy the image to the internal api buffers int[] image, int width, int height, boolean bBWFilter, boolean bHorizDisp); public native void releaseImageNative(); // release the internal api buffers public native void setRectangleNative( // set the rectangle where OCR will focus int left, int top, int width, int height); public native void setPageSegModeNative( // set the page segmentation mode int mode); // OCR public native String recognizeNative( // do OCR over the parameter image byte[] image, int width, int height, int bpp); public native String recognizeNative(); // do OCR over the image in the api buffers (all ocr) public native String recognizeNative(int nopass); // do OCR over the image in the api buffers // (options: 0=all, 1 or 2 passes) // aux functions, to be run after OCR public native int meanConfidenceNative(); // mean confidence (last OCR) public native int[] wordConfidencesNative(); // confidence for each word (last OCR) public native String getBoxText(); // get the box for each letter // debug functions public native void closeDebug(); // clean close the debug (if any) public native String libVer(); // get the lib version public int mNativeData; // storage space for the library's internal buffers /* this is used to load the 'ocr' library on application * startup. The library has already been unpacked into * /data/data/com.../lib/libocr.so at installation time by the package manager. */ static { System.loadLibrary("ocr"); } }