#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; }
Комментариев нет:
Отправить комментарий