Skip to content
This repository was archived by the owner on Jan 12, 2019. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions card.io/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<!-- We need this for tessdata-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does tessdata need these extra permissions? Is the data not stored within the SDK itself?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tessdata is an external directory read in by Tesseract. It needs to be included with the app/assets/bundle. With android the only way to do this is have it on the sd card or emulated storage build into most devices. Read/write external in this case does not mean external storage but rather the external emulated storage.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be no need to write it to external storage, the internal private storage for the app should be fine. I've had to do something similar with an OpenVPN binary that needs to read a configuration file from disk, it does need to be written to storage instead of the assets directory so it can be accessed as a file, but from the point of view of the app, internal storage should be ok.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an issue with tesseract, not an inability to read from assets. C/C++ can do what you described. However to my knowledge Tesseract specifically does not. It is platform agnostic so it cannot use AssetManager/NDK without referencing android specific apis. I will look into adding this functionality with some flags/magic if that is the desired. It should also be noted that this is not writing to external storage. It is internal to the phone, not the apk. The write permission is required to do that. It may require code changes to tesseract. The current solution is the agreed method outside of changing the tesseract source. Having said that I am in agreement that this is sort of a stupid solution to something you would think would be more straight forward as it is with ios version.

Some relevant discussion on the topic: http://stackoverflow.com/questions/23174318/how-to-get-a-full-path-for-an-android-resource-file-init-tesseract-ocr-in-andro

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<uses-feature android:name="android.hardware.camera" android:required="false"/>
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
Expand Down
Binary file added card.io/src/main/assets/tessdata/co.traineddata
Binary file not shown.
101 changes: 97 additions & 4 deletions card.io/src/main/java/io/card/payment/CardIOActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
* See the file "LICENSE.md" for the full license governing this code.
*/

import android.Manifest;
import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
Expand All @@ -18,11 +18,15 @@
import android.graphics.Matrix;
import android.graphics.Rect;
import android.hardware.SensorManager;
import android.Manifest;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Vibrator;
import android.util.Log;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.OrientationEventListener;
Expand All @@ -32,15 +36,18 @@
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Toast;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.util.Date;

Expand Down Expand Up @@ -327,7 +334,7 @@ public final class CardIOActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate()");

tessSetup();
numActivityAllocations++;
// NOTE: java native asserts are disabled by default on Android.
if (numActivityAllocations != 1) {
Expand Down Expand Up @@ -1111,4 +1118,90 @@ public Rect getTorchRect() {
return mOverlay.getTorchRect();
}

/*************************** TESSERACT Entry Point **************************/


private String DATA_PATH = "";
private final String TESSDATA = "tessdata";
private final String TESSCONFIG = "tessconfigs";

/*
* Entry point for tessdata adapted from TessTwo
*/
private void tessSetup() {
DATA_PATH = getExternalFilesDir(null) + "/Tesseract/";
Log.i(TAG, "Attempting to copy tessdata");
Log.i(TAG, "Accessing: "+ DATA_PATH);
prepareTesseract();
}

/**
* 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);
prepareDirectory(DATA_PATH + TESSDATA + "/" + TESSCONFIG);
}
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
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());
}
}

}
28 changes: 26 additions & 2 deletions card.io/src/main/jni/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,30 @@ LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libopencv_imgproc.so
LOCAL_SHARED_LIBRARIES := opencv_core
include $(PREBUILT_SHARED_LIBRARY)


# --- declare tesseract prebuilt static libs ---------------------------------

include $(CLEAR_VARS)
LOCAL_MODULE := leptonica_core
LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/liblept.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := jpg_lib
LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libjpgt.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := png_lib
LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libpngt.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := tesseract_core
LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libtess.so
LOCAL_SHARED_LIBRARIES := leptonica_core jpg_lib png_lib
include $(PREBUILT_SHARED_LIBRARY)

endif

# --- libcardioRecognizer.so --------------------------------------------------------
Expand All @@ -36,7 +60,7 @@ ifneq (,$(filter $(TARGET_ARCH_ABI),armeabi-v7a x86 arm64-v8a x86_64))

LOCAL_MODULE := cardioRecognizer
LOCAL_LDLIBS := -llog -L$(SYSROOT)/usr/lib -lz -ljnigraphics
LOCAL_SHARED_LIBRARIES := cpufeatures opencv_imgproc opencv_core
LOCAL_SHARED_LIBRARIES := cpufeatures opencv_imgproc opencv_core tesseract_core

LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(LOCAL_DMZ_DIR) $(LOCAL_PATH)/$(LOCAL_DMZ_DIR)/cv
LOCAL_SRC_FILES := $(LOCAL_DMZ_DIR)/dmz_all.cpp nativeRecognizer.cpp
Expand Down Expand Up @@ -67,7 +91,7 @@ ifneq (,$(filter $(TARGET_ARCH_ABI),armeabi-v7a x86 arm64-v8a x86_64))

LOCAL_MODULE := cardioRecognizer_tegra2
LOCAL_LDLIBS := -llog -L$(SYSROOT)/usr/lib -lz -ljnigraphics
LOCAL_SHARED_LIBRARIES := cpufeatures opencv_imgproc opencv_core
LOCAL_SHARED_LIBRARIES := cpufeatures opencv_imgproc opencv_core tesseract_core

LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(LOCAL_DMZ_DIR) $(LOCAL_PATH)/$(LOCAL_DMZ_DIR)/cv
LOCAL_SRC_FILES := $(LOCAL_DMZ_DIR)/dmz_all.cpp nativeRecognizer.cpp
Expand Down
Loading