Страницы

Поиск по вопросам

понедельник, 23 декабря 2019 г.

Передача изображения из нативной библиотеки в Android

#java #android #cpp #android_ndk


Подскажите, как передать изображение из библиотеки на C++ в приложение под андроидом.

Пишу простой html рендер: https://www.livecoding.tv/video/simple-html-render-c/ .
Во второй части хочу запустить его под андроидом.

Самый простой вариант передачи изображения:

String img = Render("index.html"); 
Bitmap bitmap = getBitmap(img);


Через файл. Но это костыль и так делать не надо.

Как реализовать передачу изображения?

На мой взгляд самым простым способом будет возвращать само изображение, а не ссылку
на него. Как его загрузить в Bitmap?

Не самым простым способом будет формирование изображение из C++.
Есть пример вызова Bitmap.createBitmap() - https://stackoverflow.com/questions/7677092/creating-an-android-graphics-bitmap-from-c
, но это недостаточно для решения.
    


Ответы

Ответ 1



Верните из JNI массив байтов, а потом грузите на стороне Java картинку из этого массива, как хотите. JNIEXPORT jbyteArray JNICALL get_bitmap(JNIEnv *env, jobject obj, jstring str) { const char *nativeString = env->GetStringUTFChars(str, 0); // "index.html" char* data = ;//указатель на данные, берите их откуда хотите size_t size = ; // размер данных jbyteArray result = env->NewByteArray(size); if (result == NULL) { return NULL; // out of memory error thrown } env->SetByteArrayRegion(result, 0, size, data); return result; } // Регистрация нативных методов в JVM static JNINativeMethod methods[] = { {"getBitmap", "(Ljava/lang/String;)[B", (void *)get_bitmap}, }; jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { JNIEnv *env; if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_4) != JNI_OK) return JNI_FALSE; jclass clazz = env->FindClass("com/example/MyCoolClass"); if (clazz ) { if (env->RegisterNatives(clazz, methods, sizeof(methods)/sizeof(methods[0])) < 0) return JNI_FALSE; } return JNI_VERSION_1_4; } На стороне Java: package com.example; class MyCoolClass { public static void main(String[] args) { String img = Render("index.html"); byte[] bytes = getBitmap(img); Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); } private static native byte[] getBitmap(String arg); } Надеюсь, идея вам понятна. Если вопрос производительности для вас критичен, почитайте это.

Ответ 2



По моему опыту несмотря на одно копирование данных, самый быстрый способ (если C-функция работает с форматом raw). К сожалению я не нашёл способа совсем без копирования. Часть класса java: native ByteBuffer newBitmap(int width, int height, int bpp); native void freeBitmap(ByteBuffer buf); public static final Config[] colormode= new Config[]{null, Config.ALPHA_8, Config.RGB_565, null, Config.ARGB_8888}; public Bitmap getBitmap(int width, height, bytePerPixel) { Bitmap b=Bitmap.createBitmap(width, height, colormode[bytePerPixel]); // подготавливаем место под картинку ByteBuffer bbuf= newBitmap(width, height, bytePerPixel); // получаем данные из C if(bbuf!=null) { if(bbuf.remaining() > bitmap.getRowBytes()*bitmap.getHeight()) // если картинка оказалась длиннее bbuf.limit(bitmap.getRowBytes()*bitmap.getHeight()); bitmap.copyPixelsFromBuffer(bbuf); // копируем буфер в картинку freeBitmap(bbuf); // освобождаем буфер return bitmap; }else return null; } C++: #include #include extern "C" JNIEXPORT jobject JNICALL Java_org_myclass_newBitmap(JNIEnv * env, jobject _this, jint width, jint height, jint bpp) { unsigned char *pix = malloc(width*height*bpp); if(!pix) return 0; for(int i=0; i< width; i++) for(int j=0; j< height; i++) for(int k=0; k< bpp; k++) { // как-то заполняем pix[j*bpp*width+i*bpp+k]= k==3? 255 : i*k+j*(2-k); } return env->NewDirectByteBuffer(pix, width*height*bpp); } extern "C" JNIEXPORT void JNICALL Java_org_myclass_freeBitmap(JNIEnv * env, jobject _this, jobject bbuf) { free(env->GetDirectBufferAddress(bbuf)); } jint JNI_OnLoad(JavaVM* vm, void* reserved) { return JNI_VERSION_1_6; }

Комментариев нет:

Отправить комментарий