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 1 commit
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.
104 changes: 103 additions & 1 deletion card.io/src/main/java/io/card/payment/CardIOActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,18 @@
import io.card.payment.ui.Appearance;
import io.card.payment.ui.ViewUtil;


/* Tesseract Imports */
import android.os.Environment;
Copy link
Member

Choose a reason for hiding this comment

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

Imports should follow the standard sorting.

Copy link
Author

Choose a reason for hiding this comment

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

Will do.

import android.content.Context;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;



/**
* This is the entry point {@link android.app.Activity} for a card.io client to use <a
* href="https://card.io">card.io</a>.
Expand Down Expand Up @@ -327,7 +339,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 +1123,94 @@ 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/";//getFilesDir()+ "/Tesseract/";//getExternalFilesDir(null) + "/Tesseract/";//Environment.getExternalStorageDirectory().toString() + "/Tesseract/";
Copy link
Member

Choose a reason for hiding this comment

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

Why can't you load the data from the assets themselves, without having to copy to another location?

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 complicated issue for both android itself and tesseract. In iOS this can be read directly from the bundle, the same is not true for android assets. In order to read for tesseract it must be copied to external storage. Having said that in order to read the file as a stream, which should be doable directly from assets the tesseract input / engine might need to be modified. I suspect this is non-trivial. I suspect it can be done if that is a requirement.

See refs below for more detail
http://stackoverflow.com/questions/24129719/android-cant-find-file-in-assets-folder
http://stackoverflow.com/questions/33220378/tesseract-tessdata-folder-not-found-when-put-in-assets-folder

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) {

Copy link
Member

Choose a reason for hiding this comment

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

Extra newline

Copy link
Author

Choose a reason for hiding this comment

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

It will be removed.

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 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());
}
}

}
12 changes: 6 additions & 6 deletions card.io/src/main/java/io/card/payment/CardScanner.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,26 +121,26 @@ private native void nScanFrame(byte[] data, int frameWidth, int frameHeight, int
Log.i(Util.PUBLIC_LOG_TAG, "card.io " + BuildConfig.PRODUCT_VERSION + " " + BuildConfig.BUILD_TIME);

try {
loadLibrary("cardioDecider");
System.loadLibrary("cardioDecider");
Copy link
Member

Choose a reason for hiding this comment

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

You should probably rebase to the latest master. This change should not be here.

Copy link
Author

Choose a reason for hiding this comment

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

This appears to have slipped through FileMerge. Easy fix.

Log.d(Util.PUBLIC_LOG_TAG, "Loaded card.io decider library.");
Log.d(Util.PUBLIC_LOG_TAG, " nUseNeon(): " + nUseNeon());
Log.d(Util.PUBLIC_LOG_TAG, " nUseTegra():" + nUseTegra());
Log.d(Util.PUBLIC_LOG_TAG, " nUseX86(): " + nUseX86());

if (usesSupportedProcessorArch()) {
loadLibrary("opencv_core");
System.loadLibrary("opencv_core");
Log.d(Util.PUBLIC_LOG_TAG, "Loaded opencv core library");
loadLibrary("opencv_imgproc");
System.loadLibrary("opencv_imgproc");
Log.d(Util.PUBLIC_LOG_TAG, "Loaded opencv imgproc library");
}
if (nUseNeon()) {
loadLibrary("cardioRecognizer");
System.loadLibrary("cardioRecognizer");
Log.i(Util.PUBLIC_LOG_TAG, "Loaded card.io NEON library");
} else if (nUseX86()) {
loadLibrary("cardioRecognizer");
System.loadLibrary("cardioRecognizer");
Log.i(Util.PUBLIC_LOG_TAG, "Loaded card.io x86 library");
} else if (nUseTegra()) {
loadLibrary("cardioRecognizer_tegra2");
System.loadLibrary("cardioRecognizer_tegra2");
Log.i(Util.PUBLIC_LOG_TAG, "Loaded card.io Tegra2 library");
} else {
Log.w(Util.PUBLIC_LOG_TAG,
Expand Down
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