Android Open Source - BCC O C R






From Project

Back to project page BCC.

License

The source code is released under:

MIT License

If you think the Android project BCC listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright (C) 2009 IT Wizard.// w  w  w.j  av a  2  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 String m_sOCRResult = null;
  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, 
    Log.v(TAG, "mConfig.m_asLanguages = " + mConfig.m_asLanguages);
    // 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();
    if(mConfig.m_asLanguages == null) {
      mConfig.m_asLanguages = new String[]{};
    }
  }

  /**
   * 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
          Log.v(TAG,"m_asWords[i].m_sBody = " + m_asWords[i].m_sBody + " m_asWords[i].m_iConfidence = " + m_asWords[i].m_iConfidence + " mConfig.m_iMinWordConfidence = " + mConfig.m_iMinWordConfidence);
          //if (m_asWords[i].m_iConfidence > mConfig.m_iMinWordConfidence)
          if (m_asWords[i].m_iConfidence > 20)
          {   
            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)
    {
      ex.printStackTrace();
      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;
      }
    }
    m_sOCRResult = text_ret;
    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");
  }
}




Java Source Code List

com.bcc.AddBCCManage.java
com.bcc.AddBCC.java
com.bcc.BCCActivity.java
com.bcc.ImportExportBCC.java
com.bcc.ImportExportManage.java
com.bcc.OCRResult.java
com.bcc.SetPrefs.java
com.bcc.util.BCCUtil.java
com.bcc.util.Facade.java
com.bcc.util.adaptor.ManageBCCListAdaptor.java
com.bcc.util.adaptor.ManageListAdaptor.java
com.itwizard.mezzofanti.AssetsManager.java
com.itwizard.mezzofanti.CameraManager.java
com.itwizard.mezzofanti.CaptureLayout.java
com.itwizard.mezzofanti.CustomImageButton.java
com.itwizard.mezzofanti.DownloadManager.java
com.itwizard.mezzofanti.InstallActivity.java
com.itwizard.mezzofanti.Mezzofanti.java
com.itwizard.mezzofanti.OCR.java
com.itwizard.mezzofanti.OnScreenHint.java
com.sdsu.bcc.BCCConstants.java
com.sdsu.bcc.database.DatabaseImpl.java
com.sdsu.bcc.database.DatabaseOperation.java
com.sdsu.bcc.database.data.CardInformation.java
com.sdsu.bcc.database.data.CategoryInformation.java
com.sdsu.bcc.database.data.ContactInformation.java
com.sdsu.bcc.database.data.FilesInformation.java
com.sdsu.bcc.database.data.ImageInformation.java
com.sdsu.bcc.database.impl.BCCDataStore.java
com.sdsu.bcc.database.impl.CategoryDataStore.java
com.sdsu.bcc.database.impl.ContactDataStore.java
com.sdsu.bcc.database.impl.FilesDataStore.java
com.sdsu.bcc.database.impl.ImageDataStore.java
com.sdsu.bcc.file.FileDataStoreFactory.java
com.sdsu.bcc.file.FileDataStoreOperations.java
com.sdsu.bcc.file.impl.CSVDataStore.java