How to get pdf meta-data using MuPdf in Android ? I'm using MuPdf V1.7.
I can get Author & PDF name but I cannot get creation date, creator and etc. I used below function to get information:
fz_lookup_metadata(ctx, glo->doc, FZ_META_INFO_TITLE, info, sizeof(info));
fz_lookup_metadata(ctx, glo->doc, FZ_META_INFO_AUTHOR, info, sizeof(info));
Can anybody help?
hi all i can get creation date from pdf by the below code.
add this into document.h
#define FZ_META_INFO_CREATIONDATE "info:CreationDate"
paste the below code into mupdf.c
JNIEXPORT jstring
JNICALL JNI_FN(MuPDFCore_metaPublishDate)(JNIEnv * env, jobject thiz)
{
char info[64];
globals *glo = get_globals(env, thiz);
fz_context *ctx = glo->ctx;
pdf_document *idoc = pdf_specifics(ctx, glo->doc);
fz_lookup_metadata(ctx, glo->doc, FZ_META_INFO_CREATIONDATE, info, sizeof(info));
return (*env)->NewStringUTF(env, info);
}
then we can able to get this by core.metaPublishDate().
you can easily do this with mupdf library.This function returns a string array which contains metadata information, respectively to keys in keys array. If there is no such info for a key, it returns an empty string
JNIEXPORT jobjectArray JNICALL
JNI_FN(MuPDFCore_metadataInternal)(JNIEnv * env, jobject thiz)
{
char info[64];
globals *glo = get_globals(env, thiz);
jobjectArray arr;
jclass stringClass;
const int nkeys = 4;
const char *keys[nkeys];
int i;
keys[0] = "Title";
keys[1] = "Author";
keys[2] = "Subject";
keys[3] = "Keywords";
stringClass = (*env)->FindClass(env, "java/lang/String");
arr = (*env)->NewObjectArray(env, nkeys, stringClass, NULL);
LOGI("Getting metadata");
for(i=0; idoc, FZ_META_INFO, info, sizeof(info));
LOGI("%s : %s", keys[i], info);
jstring s = (*env)->NewStringUTF(env, info);
if (s != NULL) {
(*env)->SetObjectArrayElement(env, arr, i, s);
}
(*env)->DeleteLocalRef(env, s);
}
return arr;
}
Related
i'm trying to access getPackageManager.getApplicationInfo in jni.
const char* getNativeLibPath(JNIEnv* env, jobject thiz, const char* libraryName, const char* packageName) {
jclass contextClass = env->GetObjectClass(thiz);
jmethodID getPackageManager = env->GetMethodID(contextClass, "getPackageManager", "()Landroid/content/pm/PackageManager;");
jobject instantiatePackageManager = env->CallObjectMethod(thiz, getPackageManager);
jclass packageManagerClass = env->GetObjectClass(instantiatePackageManager);
jmethodID getApplicationInfo = env->GetMethodID(packageManagerClass, "getApplicationInfo", "(Ljava/lang/String;I)Landroid/content/pm/ApplicationInfo;");
jobject instantiateApplicationInfo = env->CallObjectMethod(thiz, getApplicationInfo, packageName, 0);
jclass applicationInfoClass = env->GetObjectClass(instantiateApplicationInfo);
jfieldID nativeLibraryDir = env->GetFieldID(applicationInfoClass, "nativeLibraryDir", "Ljava/lang/String;");
auto string = (jstring) env->GetObjectField(instantiateApplicationInfo, nativeLibraryDir);
const char* returnValue = env->GetStringUTFChars(string, nullptr);
std::string appendedResult = std::string(returnValue) + std::string("/") + std::string(libraryName);
return appendedResult.c_str();
}
This is my code for it. However for some reason i'm getting this error: JNI ERROR (app bug): accessed stale WeakGlobal 0x74eecd21ff (index 1324143135 in a table of size 38) JNI DETECTED ERROR IN APPLICATION: use of deleted weak global reference 0x74eecd21ff
Any help is appreciated!
Your code has at least three problems:
You call getApplicationInfo with a const char * which expects a Java string:
jobject instantiateApplicationInfo = env->CallObjectMethod(instantiatePackageManager, getApplicationInfo, env->NewStringUTF(packageName), 0);
You need to call env->ReleaseStringUTF(returnValue) to release the string on the Java side
You cannot return a const char * like that. Either return the std::string directly, or allocate memory with new char[] and let the caller free it.
I'm following an online course. It's about JNI. And this code below is in my test.cpp file.
__android_log_print(ANDROID_LOG_ERROR,"testjni JNI: c_str1 = %s", c_str1);
Then it shows "error: format string is not a string literal (potentially insecure) [-Werror,-Wformat-security]"
How should I change it? Thanks!
The full method and implementation
JNIEXPORT jstring JNICALL Java_com_example_carapp_OBOJNI_test_1jni_1api3
(JNIEnv *env, jobject obj, jstring j_str1, jstring j_str2){
const char *c_str1 = NULL;
const char *c_str2 = NULL;
c_str1 = env->GetStringUTFChars(j_str1,0);
__android_log_print(ANDROID_LOG_ERROR,"testjni JNI: c_str1 = %s", c_str1);
env->ReleaseStringUTFChars(j_str1,c_str1);
jstring ret_j_string = env->NewStringUTF("JNI return String");
return ret_j_string;
I need get byte array from jni to Java.
Ex: I have a byte array byte[] a = {1,2,3,4,5,6}
JNIEXPORT jbyteArray JNICALL Java_com_vn_getArray (JNIEnv *env, jobject obj) {
jbyte[] a = {1,2,3,4,5,6};
return a;
}
I do not know how to return a byte array from jni.
Can someone help me? Please!
In Java, an array is an object. So to hand a byte array from C or C++ over to java you will need to instantiate a jbyteArray, and return that. Instead of a C array. To solve that, see the following code:
JNIEXPORT jbyteArray JNICALL Java_Test_returnArray
(JNIEnv *env, jobject This)
{
jbyte a[] = {1,2,3,4,5,6};
jbyteArray ret = env->NewByteArray(6);
env->SetByteArrayRegion (ret, 0, 6, a);
return ret;
}
Based on this link
I do like that and it's working
JNIEXPORT jbyteArray JNICALL Java_com_vn_getArray(JNIEnv *env, jobject obj) {
jbyte byteUrl[] = {1,2,3,3,4};
int sizeByteUrl = 5;
jbyteArray data = (*env)->NewByteArray(env, sizeByteUrl);
if (data == NULL) {
return NULL; // out of memory error thrown
}
// creat bytes from byteUrl
jbyte *bytes = (*env)->GetByteArrayElements(env, data, 0);
int i;
for (i = 0; i < sizeByteUrl; i++) {
bytes[i] = byteUrl[i];
}
// move from the temp structure to the java structure
(*env)->SetByteArrayRegion(env, data, 0, sizeByteUrl, bytes);
return data;
}
The program should take an Image from the SD card and adjust its brightness. And the image is taken from the SD card via the NDK C-code. It is to be noted that the string depicting the path to the image is passed to the NDK via JNI.
Java code:
private void adjustBrightness() {
imagePath = (Environment.getExternalStorageDirectory().getPath()+"earthglobe.jpeg").toCharArray();
brightness(imagePath, brightness);
}
public native void brightness(char[] imagePath, float brightness);
NDK code:
JNIEXPORT void JNICALL Java_com_example_ImageActivity_brightness(JNIEnv * env,char[] bitmappath, jfloat brightnessValue)
{
string bmpath = bitmappath+'\0';
jobject obj = fopen( bitmappath , "rb" );
}
You cannot pass char[] this way.
In Java use:
public static native void brightness(String imagePath, float brightness);
In native use:
std::string ConvertJString(JNIEnv* env, jstring str)
{
if ( !str ) std::string();
const jsize len = env->GetStringUTFLength(str);
const char* strChars = env->GetStringUTFChars(str, (jboolean *)0);
std::string Result(strChars, len);
env->ReleaseStringUTFChars(str, strChars);
return Result;
}
JNIEXPORT void JNICALL Java_com_example_ImageActivity_brightness(JNIEnv * env, jobject obj, jstring bitmappath, jfloat brightnessValue)
{
std::string bmpath = ConvertJString( env, bitmappath );
FILE* f = fopen( bmpath.c_str(), "rb" );
// do something useful here
fclose( f );
}
OK, so I have the native code below.
I'm trying to return an array of FilePermissionInfo from it, populated with some data returned by stat().
The problem is that I get the following error when NewObject is called the first time:
06-15 20:25:17.621: W/dalvikvm(2287): Invalid indirect reference
0x40005820 in decodeIndirectRef 06-15 20:25:17.621: E/dalvikvm(2287):
VM aborting
It's odd, because the only reference object I have is the jclass (for FilePermissionInfo) and I turn it to a global reference.
The code is:
JNIEXPORT jobjectArray JNICALL
Java_com_mn_rootscape_utils_NativeMethods_getFilesPermissions( JNIEnv* env, jobject thizz, jobjectArray filePathsArray )
{
jobjectArray result;
int size = (*env)->GetArrayLength(env, filePathsArray);
jboolean isCopy;
jclass filePermInfoCls = (*env)->FindClass(env, kFilePermissionInfoPath);
if(!filePermInfoCls)
{
LOGE("getFilesPermissions: failed to get class reference.");
return NULL;
}
gFilePermInfoClass = (jclass)(*env)->NewGlobalRef(env, filePermInfoCls);
LOGI("got gFilePermInfoClass");
jmethodID filePermInfoClsConstructor = (*env)->GetMethodID(env, gFilePermInfoClass, "<init>", kFilePermInfoConstructorSig);
if(!filePermInfoClsConstructor)
{
LOGE("getFilesPermissions: failed to get method reference.");
return NULL;
}
struct stat sb;
LOGI("starting...");
result = (jobjectArray)(*env)->NewObjectArray(env, size, gFilePermInfoClass, NULL);
for(int i = 0; i != size; ++i)
{
jstring string = (jstring) (*env)->GetObjectArrayElement(env, filePathsArray, i);
const char *rawString = (*env)->GetStringUTFChars(env, string, &isCopy);
if(stat(rawString, &sb) == -1)
{
LOGE("stat error for: %s", rawString);
}
LOGI("%ld %ld %ld %ld %ld %ld %ld %ld", sb.st_dev, sb.st_mode, sb.st_nlink, sb.st_uid, sb.st_gid, sb.st_atime, sb.st_mtime, sb.st_ctime);
jobject permInfo = (*env)->NewObject(env,
gFilePermInfoClass,
filePermInfoClsConstructor,
(long)sb.st_dev,
(long)sb.st_mode,
(long)sb.st_nlink,
(long)sb.st_uid,
(long)sb.st_gid,
(long)sb.st_atime,
(long)sb.st_mtime,
(long)sb.st_ctime,
"",
"",
1,
"");
LOGI("xxx1");
(*env)->SetObjectArrayElement(env, result, i, permInfo);
LOGI("xxx2");
(*env)->ReleaseStringUTFChars(env, string, rawString);
LOGI("xxx3");
}
(*env)->DeleteLocalRef(env, filePermInfoCls);
return result;
}
The Java class constructor signature and path are:
const char* kFilePermissionInfoPath = "com/mn/rootscape/utils/FilePermissionInfo";
const char* kFilePermInfoConstructorSig = "(JJJJJJJJLjava/lang/String;Ljava/lang/String;ZLjava/lang/String;)V";
Please note that if I call NewObject on the default constructor then it works fine.
OK, found it.
It was a problem with the jstring parameters. It turns out you cannot pass empty strings (or even NULL for that matter) as a jstring.
Instead I used (*env)->NewStringUTF(env, NULL) to create a NULL jstring.
Seems to work OK now.
Since this question generated somewhat a high activity, I'm posting the final solution below. Note that the nullString variable is being deallocated at the end of its scope (or when you're done using it):
jstring nullString = (*env)->NewStringUTF(env, NULL);
...
jobject permInfo = (*env)->NewObject(env,
gFilePermInfoClass,
filePermInfoClsConstructor,
(jbyte)permsOwner,
(jbyte)permsGroup,
(jbyte)permsOthers,
(jlong)sb.st_uid,
(jlong)sb.st_gid,
(jlong)sb.st_atime,
(jlong)sb.st_mtime,
(jlong)sb.st_ctime,
nullString,
nullString,
(jboolean)1,
nullString);
...
(*env)->DeleteLocalRef(env, nullString);