1

I'm making a simple app in Android. I'm using NDK to make JNI calls. I have a file in a resource subfolder (raw), which I need to access from native c++ code. I want to read it from native using for example "ifstream" function but I don't get to do that.

That's my Java code:

Algorithm algorithm = new Algorithm();

    InputStream isModel = getResources().openRawResource(R.raw.model);

    String model = algorithm.ReadResourceFile(isModel);

    if(imgInput != null && txtResults != null)
    {
        Bitmap bmp = ((BitmapDrawable)imgInput.getDrawable()).getBitmap();

        //Convert Bitmap to Mat
        Mat image = new Mat(bmp.getHeight(), bmp.getWidth(), CvType.CV_8U);

        //Print results on txtResults
        String results = algorithm.DetectEmotionByImage(image.nativeObj, model);
        txtResults.setText(results);
    }

That's my C++ code:

JNIEXPORT jstring JNICALL
Java_org_ctic_emoplay_1android_algorithm_Algorithm_DetectEmotionByImage(JNIEnv *env,
                                                                        jobject instance,
                                                                        jlong image,
                                                                        jstring fileModel_,
                                                                        jstring fileRange_,
                                                                        jstring fileModelFlandmarks_,
                                                                        jstring fileHaarCascade_)
{
    const char *fileModel = env->GetStringUTFChars(fileModel_, NULL);

    SVM_testing testing;

    Mat* imageInput= (Mat*)image;
    Mat& inImageInput = *(Mat*) imageInput;

    string results = testing.TestModel(inImageInput, fileModel);

    const char* final_results = results.c_str();

    env->ReleaseStringUTFChars(fileModel_, fileModel);

    return env->NewStringUTF(final_results);
}

Anyone can help me? I'm desperated. Thanks!

  • you can use file descriptor ... but i'm not sure if you can get `std::istream` from it – Selvin Aug 17 '16 at 08:41
  • The raw folder is inside your apk, which is a zip file, which is not unpacked. So normal file read methods will not work. The Java AssetManager classes may help, or you could extract the file from raw on the Java side and save it, or you could use a message passing protocol to transfer the bytes of the file from Java to the C++ side. Another method would be to use zlib to open your apk. – Richard Critten Aug 17 '16 at 09:08

1 Answers1

0

The file will be stored inside the APK, but if you rename the file extension to something like .PNG then it will not be compressed. Put the file in the assets folder, not res/raw.

You can get the APK file path like this:

public static String getAPKFilepath(Context context) {
    // Get the path
    String apkFilePath = null;
    ApplicationInfo appInfo = null;
    PackageManager packMgmr = context.getPackageManager();
    String packageName = context.getApplicationContext().getPackageName();
    try {
        appInfo = packMgmr.getApplicationInfo(packageName, 0);
        apkFilePath = appInfo.sourceDir;
    } catch (NameNotFoundException e) {
    }
    return apkFilePath;
}

Then find the offset of your resource inside the APK:

public static void findAPKFile(String filepath, Context context) {
    String apkFilepath = getAPKFilepath(context);

    // Get the offset and length for the file: theUrl, that is in your
    // assets folder
    AssetManager assetManager = context.getAssets();
    try {

        AssetFileDescriptor assFD = assetManager.openFd(filepath);
        if (assFD != null) {
            long offset = assFD.getStartOffset();
            long fileSize = assFD.getLength();
            assFD.close(); 

            // **** offset and fileSize are the offset and size
            // **** in bytes of the asset inside the APK
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Call like this:

findAPKFile("model.png", MyActivity.this);

You can call your C++ and pass offset, fileSize and apkFilepath via JNI. Open the file, seek past offset bytes and then read out fileSize bytes of data.

The accepted answer to this question shows an alternative method but I haven't tried doing it that way so I can't vouch for it.

Community
  • 1
  • 1
samgak
  • 23,944
  • 4
  • 60
  • 82