JosephM JosephM - 4 months ago 17
Java Question

Unable to display the results of OCR

I have this mainActivity java file which I would like to display back the results of the OCR.


  1. ERROR: Creation of directory /storage/emulated/0/TesseractSample/tessdata failed, check does Android Manifest have permission to write to external storage.

  2. Unable to copy files to tessdata java.io.FileNotFoundException: /storage/emulated/0/TesseractSample/tessdata/eng.traineddata: open failed: ENOENT (No such file or directory)



3.Unable to decode stream: java.io.FileNotFoundException: /storage/emulated/0/TesseractSample/imgs/ocr.jpg: open failed: EACCES (Permission denied)


  1. Data path must contain subfolder tessdata!

    import android.app.Activity;
    import android.content.Intent;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.net.Uri;
    import android.os.Environment;
    import android.os.Bundle;
    import android.provider.MediaStore;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.TextView;
    import android.widget.Toast;

    import com.googlecode.tesseract.android.TessBaseAPI;

    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;

    public class MainActivity extends Activity {

    private static final String TAG = MainActivity.class.getSimpleName();
    static final int PHOTO_REQUEST_CODE = 1;
    private TessBaseAPI tessBaseApi;
    TextView textView;
    Uri outputFileUri;
    private static final String lang = "eng";
    String result = "empty";

    private static final String DATA_PATH = Environment.getExternalStorageDirectory().toString() + "/TesseractSample/";
    private static final String TESSDATA = "tessdata";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Button captureImg = (Button) findViewById(R.id.action_btn);
    if (captureImg != null) {
    captureImg.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    startCameraActivity();
    }
    });
    }
    textView = (TextView) findViewById(R.id.textResult);
    }


    /**
    * to get high resolution image from camera
    */
    private void startCameraActivity() {
    try {
    String IMGS_PATH = Environment.getExternalStorageDirectory().toString() + "/TesseractSample/imgs";
    prepareDirectory(IMGS_PATH);

    String img_path = IMGS_PATH + "/ocr.jpg";

    outputFileUri = Uri.fromFile(new File(img_path));

    final Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);

    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
    startActivityForResult(takePictureIntent, PHOTO_REQUEST_CODE);
    }
    } catch (Exception e) {
    Log.e(TAG, e.getMessage());
    }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode,
    Intent data) {
    //making photo
    if (requestCode == PHOTO_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
    prepareTesseract();
    startOCR(outputFileUri);
    } else {
    Toast.makeText(this, "ERROR: Image was not obtained.", Toast.LENGTH_SHORT).show();
    }
    }

    /**
    * Prepare directory on external storage
    *
    * @param path
    * @throws Exception
    */
    private void prepareDirectory(String path) {

    File dir = new File(path);
    if (!dir.exists()) {
    if (!dir.mkdirs()) {
    Log.e(TAG, "ERROR: Creation of directory " + path + " failed, check does Android Manifest have permission to write to external storage.");
    }
    } else {
    Log.i(TAG, "Created directory " + path);
    }
    }


    private void prepareTesseract() {
    try {
    prepareDirectory(DATA_PATH + TESSDATA);
    } catch (Exception e) {
    e.printStackTrace();
    }

    copyTessDataFiles(TESSDATA);
    }

    /**
    * Copy tessdata files (located on assets/tessdata) to destination directory
    *
    * @param path - name of directory with .traineddata files
    */
    private void copyTessDataFiles(String path) {
    try {
    String fileList[] = getAssets().list(path);

    for (String fileName : fileList) {

    // open file within the assets folder
    // if it is not already there copy it to the sdcard
    String pathToDataFile = DATA_PATH + path + "/" + fileName;
    if (!(new File(pathToDataFile)).exists()) {

    InputStream in = getAssets().open(path + "/" + fileName);

    OutputStream out = new FileOutputStream(pathToDataFile);

    // Transfer bytes from in to out
    byte[] buf = new byte[1024];
    int len;

    while ((len = in.read(buf)) > 0) {
    out.write(buf, 0, len);
    }
    in.close();
    out.close();

    Log.d(TAG, "Copied " + fileName + "to tessdata");
    }
    }
    } catch (IOException e) {
    Log.e(TAG, "Unable to copy files to tessdata " + e.toString());
    }
    }


    /**
    * don't run this code in main thread - it stops UI thread. Create AsyncTask instead.
    * https://developer.android.com/reference/android/os/AsyncTask.html
    *
    * @param imgUri
    */
    private void startOCR(Uri imgUri) {
    try {
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inSampleSize = 4; // 1 - means max size. 4 - means maxsize/4 size. Don't use value <4, because you need more memory in the heap to store your data.
    Bitmap bitmap = BitmapFactory.decodeFile(imgUri.getPath(), options);

    result = extractText(bitmap);

    textView.setText(result);

    } catch (Exception e) {
    Log.e(TAG, e.getMessage());
    }
    }


    private String extractText(Bitmap bitmap) {
    try {
    tessBaseApi = new TessBaseAPI();
    } catch (Exception e) {
    Log.e(TAG, e.getMessage());
    if (tessBaseApi == null) {
    Log.e(TAG, "TessBaseAPI is null. TessFactory not returning tess object.");
    }
    }

    tessBaseApi.init(DATA_PATH, lang);

    // //EXTRA SETTINGS
    // //For example if we only want to detect numbers
    // tessBaseApi.setVariable(TessBaseAPI.VAR_CHAR_WHITELIST, "1234567890");
    //
    // //blackList Example
    // tessBaseApi.setVariable(TessBaseAPI.VAR_CHAR_BLACKLIST, "!@#$%^&*()_+=-qwertyuiop[]}{POIU" +
    // "YTRWQasdASDfghFGHjklJKLl;L:'\"\\|~`xcvXCVbnmBNM,./<>?");

    Log.d(TAG, "Training file loaded");
    tessBaseApi.setImage(bitmap);
    String extractedText = "empty result";
    try {
    extractedText = tessBaseApi.getUTF8Text();
    } catch (Exception e) {
    Log.e(TAG, "Error in recognizing text.");
    }
    tessBaseApi.end();
    return extractedText;
    }
    }


Answer Source

If you're targeting Android SDK 23 or higher, you have to request permissions from the user at run time in addition to requesting permission in the Android manifest file.

Alternatively, you can target SDK 22 or lower by changing the targetSdkVersion value in your build.gradle.