如何在使用大图像时使用JNI位图操作来帮助避免OOM?

如何在使用大图像时使用JNI位图操作来帮助避免OOM?

背景

大多数时候,在Android上获取OOM是由于使用了太多位图和/或创建大位图。

最近我决定试用JNI,以便通过将数据本身存储在JNI端来避免OOM。

在与JNI搞砸了一段时间后,我在SO上创建了一些帖子,寻求帮助并分享我的知识,现在我决定与你分享更多代码。如果有人有兴趣阅读调查结果或做出贡献,这里有帖子:

这一次,我添加了存储,恢复,裁剪和旋转位图的功能。它应该很容易添加更多选项,如果其他人在这里将自己的代码添加到更有用的功能我会很高兴

所以我要展示的代码实际上是合并了我创造的所有东西。

示例使用代码:

Bitmap bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);final int width=bitmap.getWidth(),height=bitmap.getHeight();// store the bitmap in the JNI "world"final JniBitmapHolder bitmapHolder=new JniBitmapHolder(bitmap);// no need for the bitmap on the java "world", since the operations are done on the JNI "world"bitmap.recycle();// crop a center square from the bitmap, from (0.25,0.25) to (0.75,0.75) of the bitmap.bitmapHolder.cropBitmap(width/4,height/4,width*3/4,height*3/4);//rotate the bitmap:bitmapHolder.rotateBitmapCcw90();//get the output java bitmap , and free the one on the JNI "world"bitmap=bitmapHolder.getBitmapAndFree();

该项目可在github上获得

  • 项目页面可在github上找到

  • 随时提供建议和贡献。

重要笔记

此处显示的相同的注释,加上:

  • 此处编写的当前功能(在项目页面上更新):

    • 商店

    • 恢复

    • 逆时针旋转90度

    • 作物。

  • 我为这段代码采用的方法是内存效率(仅使用我需要的内存,并在不需要时释放它)和CPU效率(我尽可能使用指针和CPU内存缓存优化)。

  • 为了获得最佳性能,我做了很少的验证,特别是在JNI部分。最好管理java“world”上的验证。

  • 我认为应该添加许多缺失的功能,我希望我有时间添加它们。如果有人愿意贡献,我也很乐意添加他们的代码。以下是我认为可能有用的功能:

    • 获取当前位图信息

    • 缩放位图,包括选择使用哪种算法(最近邻和双线性插值应该足够)。

    • 使用不同的位图格式

    • 在JNI中进行解码,以避免从一开始就创建java位图(而不是在java世界中使用堆),只是在完成所有操作时才结束。

    • 面部检测

    • 任何角度的旋转,或至少是明显的旋转。目前我只增加了90度逆时针旋转。


POPMUISE
浏览 376回答 1
1回答

白衣非少年

注意:这是一个有点旧的代码。对于最新的,请查看github上的项目页面。JNI / Android.mkLOCAL_PATH&nbsp;:=&nbsp;$(call&nbsp;my-dir)#bitmap&nbsp;operations&nbsp;moduleinclude&nbsp;$(CLEAR_VARS)LOCAL_MODULE&nbsp;&nbsp;&nbsp;&nbsp;:=&nbsp;JniBitmapOperationsLOCAL_SRC_FILES&nbsp;:=&nbsp;JniBitmapOperations.cpp LOCAL_LDLIBS&nbsp;:=&nbsp;-llog LOCAL_LDFLAGS&nbsp;+=&nbsp;-ljnigraphics include&nbsp;$(BUILD_SHARED_LIBRARY)APP_OPTIM&nbsp;:=&nbsp;debug LOCAL_CFLAGS&nbsp;:=&nbsp;-g#if&nbsp;you&nbsp;need&nbsp;to&nbsp;add&nbsp;more&nbsp;module,&nbsp;do&nbsp;the&nbsp;same&nbsp;as&nbsp;the&nbsp;one&nbsp;we&nbsp;started&nbsp;with&nbsp;(the&nbsp;one&nbsp;with&nbsp;the&nbsp;CLEAR_VARS)JNI / JniBitmapOperations.cpp#include&nbsp;<jni.h>#include&nbsp;<jni.h>#include&nbsp;<android/log.h>#include&nbsp;<stdio.h>#include&nbsp;<android/bitmap.h>#include&nbsp;<cstring>#include&nbsp;<unistd.h>#define&nbsp;&nbsp;LOG_TAG&nbsp;&nbsp;&nbsp;&nbsp;"DEBUG"#define&nbsp;&nbsp;LOGD(...)&nbsp;&nbsp;__android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)#define&nbsp;&nbsp;LOGE(...)&nbsp;&nbsp;__android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)extern&nbsp;"C" &nbsp;&nbsp;{ &nbsp;&nbsp;JNIEXPORT&nbsp;jobject&nbsp;JNICALL&nbsp;Java_com_jni_bitmap_1operations_JniBitmapHolder_jniStoreBitmapData(JNIEnv&nbsp;*&nbsp;env,&nbsp;jobject&nbsp;obj,&nbsp;jobject&nbsp;bitmap); &nbsp;&nbsp;JNIEXPORT&nbsp;jobject&nbsp;JNICALL&nbsp;Java_com_jni_bitmap_1operations_JniBitmapHolder_jniGetBitmapFromStoredBitmapData(JNIEnv&nbsp;*&nbsp;env,&nbsp;jobject&nbsp;obj,&nbsp;jobject&nbsp;handle); &nbsp;&nbsp;JNIEXPORT&nbsp;void&nbsp;JNICALL&nbsp;Java_com_jni_bitmap_1operations_JniBitmapHolder_jniFreeBitmapData(JNIEnv&nbsp;*&nbsp;env,&nbsp;jobject&nbsp;obj,&nbsp;jobject&nbsp;handle); &nbsp;&nbsp;JNIEXPORT&nbsp;void&nbsp;JNICALL&nbsp;Java_com_jni_bitmap_1operations_JniBitmapHolder_jniRotateBitmapCcw90(JNIEnv&nbsp;*&nbsp;env,&nbsp;jobject&nbsp;obj,&nbsp;jobject&nbsp;handle); &nbsp;&nbsp;JNIEXPORT&nbsp;void&nbsp;JNICALL&nbsp;Java_com_jni_bitmap_1operations_JniBitmapHolder_jniCropBitmap(JNIEnv&nbsp;*&nbsp;env,&nbsp;jobject&nbsp;obj,&nbsp;jobject&nbsp;handle,&nbsp;uint32_t&nbsp;left,&nbsp;uint32_t&nbsp;top,&nbsp;uint32_t&nbsp;right,&nbsp;uint32_t&nbsp;bottom); &nbsp;&nbsp;}class&nbsp;JniBitmap &nbsp;&nbsp;{ &nbsp;&nbsp;public: &nbsp;&nbsp;&nbsp;&nbsp;uint32_t*&nbsp;_storedBitmapPixels; &nbsp;&nbsp;&nbsp;&nbsp;AndroidBitmapInfo&nbsp;_bitmapInfo; &nbsp;&nbsp;&nbsp;&nbsp;JniBitmap() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_storedBitmapPixels&nbsp;=&nbsp;NULL; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;};/**crops&nbsp;the&nbsp;bitmap&nbsp;within&nbsp;to&nbsp;be&nbsp;smaller.&nbsp;note&nbsp;that&nbsp;no&nbsp;validations&nbsp;are&nbsp;done*/&nbsp;//JNIEXPORT&nbsp;void&nbsp;JNICALL&nbsp;Java_com_jni_bitmap_1operations_JniBitmapHolder_jniCropBitmap(JNIEnv&nbsp;*&nbsp;env,&nbsp;jobject&nbsp;obj,&nbsp;jobject&nbsp;handle,&nbsp;uint32_t&nbsp;left,&nbsp;uint32_t&nbsp;top,&nbsp;uint32_t&nbsp;right,&nbsp;uint32_t&nbsp;bottom) &nbsp;&nbsp;{ &nbsp;&nbsp;JniBitmap*&nbsp;jniBitmap&nbsp;=&nbsp;(JniBitmap*)&nbsp;env->GetDirectBufferAddress(handle); &nbsp;&nbsp;if&nbsp;(jniBitmap->_storedBitmapPixels&nbsp;==&nbsp;NULL) &nbsp;&nbsp;&nbsp;&nbsp;return; &nbsp;&nbsp;uint32_t*&nbsp;previousData&nbsp;=&nbsp;jniBitmap->_storedBitmapPixels; &nbsp;&nbsp;uint32_t&nbsp;oldWidth&nbsp;=&nbsp;jniBitmap->_bitmapInfo.width; &nbsp;&nbsp;uint32_t&nbsp;newWidth&nbsp;=&nbsp;right&nbsp;-&nbsp;left,&nbsp;newHeight&nbsp;=&nbsp;bottom&nbsp;-&nbsp;top; &nbsp;&nbsp;uint32_t*&nbsp;newBitmapPixels&nbsp;=&nbsp;new&nbsp;uint32_t[newWidth&nbsp;*&nbsp;newHeight]; &nbsp;&nbsp;uint32_t*&nbsp;whereToGet&nbsp;=&nbsp;previousData&nbsp;+&nbsp;left&nbsp;+&nbsp;top&nbsp;*&nbsp;oldWidth; &nbsp;&nbsp;uint32_t*&nbsp;whereToPut&nbsp;=&nbsp;newBitmapPixels; &nbsp;&nbsp;for&nbsp;(int&nbsp;y&nbsp;=&nbsp;top;&nbsp;y&nbsp;<&nbsp;bottom;&nbsp;++y) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;memcpy(whereToPut,&nbsp;whereToGet,&nbsp;sizeof(uint32_t)&nbsp;*&nbsp;newWidth); &nbsp;&nbsp;&nbsp;&nbsp;whereToGet&nbsp;+=&nbsp;oldWidth; &nbsp;&nbsp;&nbsp;&nbsp;whereToPut&nbsp;+=&nbsp;newWidth; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;//done&nbsp;copying&nbsp;,&nbsp;so&nbsp;replace&nbsp;old&nbsp;data&nbsp;with&nbsp;new&nbsp;one &nbsp;&nbsp;delete[]&nbsp;previousData; &nbsp;&nbsp;jniBitmap->_storedBitmapPixels&nbsp;=&nbsp;newBitmapPixels; &nbsp;&nbsp;jniBitmap->_bitmapInfo.width&nbsp;=&nbsp;newWidth; &nbsp;&nbsp;jniBitmap->_bitmapInfo.height&nbsp;=&nbsp;newHeight; &nbsp;&nbsp;}/**rotates&nbsp;the&nbsp;inner&nbsp;bitmap&nbsp;data&nbsp;by&nbsp;90&nbsp;degress&nbsp;counter&nbsp;clock&nbsp;wise*/&nbsp;//JNIEXPORT&nbsp;void&nbsp;JNICALL&nbsp;Java_com_jni_bitmap_1operations_JniBitmapHolder_jniRotateBitmapCcw90(JNIEnv&nbsp;*&nbsp;env,&nbsp;jobject&nbsp;obj,&nbsp;jobject&nbsp;handle) &nbsp;&nbsp;{ &nbsp;&nbsp;JniBitmap*&nbsp;jniBitmap&nbsp;=&nbsp;(JniBitmap*)&nbsp;env->GetDirectBufferAddress(handle); &nbsp;&nbsp;if&nbsp;(jniBitmap->_storedBitmapPixels&nbsp;==&nbsp;NULL) &nbsp;&nbsp;&nbsp;&nbsp;return; &nbsp;&nbsp;uint32_t*&nbsp;previousData&nbsp;=&nbsp;jniBitmap->_storedBitmapPixels; &nbsp;&nbsp;AndroidBitmapInfo&nbsp;bitmapInfo&nbsp;=&nbsp;jniBitmap->_bitmapInfo; &nbsp;&nbsp;uint32_t*&nbsp;newBitmapPixels&nbsp;=&nbsp;new&nbsp;uint32_t[bitmapInfo.height&nbsp;*&nbsp;bitmapInfo.width]; &nbsp;&nbsp;int&nbsp;whereToPut&nbsp;=&nbsp;0; &nbsp;&nbsp;//&nbsp;A.D&nbsp;D.C &nbsp;&nbsp;//&nbsp;...>... &nbsp;&nbsp;//&nbsp;B.C&nbsp;A.B &nbsp;&nbsp;for&nbsp;(int&nbsp;x&nbsp;=&nbsp;bitmapInfo.width&nbsp;-&nbsp;1;&nbsp;x&nbsp;>=&nbsp;0;&nbsp;--x) &nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;y&nbsp;=&nbsp;0;&nbsp;y&nbsp;<&nbsp;bitmapInfo.height;&nbsp;++y) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uint32_t&nbsp;pixel&nbsp;=&nbsp;previousData[bitmapInfo.width&nbsp;*&nbsp;y&nbsp;+&nbsp;x]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newBitmapPixels[whereToPut++]&nbsp;=&nbsp;pixel; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;delete[]&nbsp;previousData; &nbsp;&nbsp;jniBitmap->_storedBitmapPixels&nbsp;=&nbsp;newBitmapPixels; &nbsp;&nbsp;uint32_t&nbsp;temp&nbsp;=&nbsp;bitmapInfo.width; &nbsp;&nbsp;bitmapInfo.width&nbsp;=&nbsp;bitmapInfo.height; &nbsp;&nbsp;bitmapInfo.height&nbsp;=&nbsp;temp; &nbsp;&nbsp;}/**free&nbsp;bitmap*/&nbsp;&nbsp;//JNIEXPORT&nbsp;void&nbsp;JNICALL&nbsp;Java_com_jni_bitmap_1operations_JniBitmapHolder_jniFreeBitmapData(JNIEnv&nbsp;*&nbsp;env,&nbsp;jobject&nbsp;obj,&nbsp;jobject&nbsp;handle) &nbsp;&nbsp;{ &nbsp;&nbsp;JniBitmap*&nbsp;jniBitmap&nbsp;=&nbsp;(JniBitmap*)&nbsp;env->GetDirectBufferAddress(handle); &nbsp;&nbsp;if&nbsp;(jniBitmap->_storedBitmapPixels&nbsp;==&nbsp;NULL) &nbsp;&nbsp;&nbsp;&nbsp;return; &nbsp;&nbsp;delete[]&nbsp;jniBitmap->_storedBitmapPixels; &nbsp;&nbsp;jniBitmap->_storedBitmapPixels&nbsp;=&nbsp;NULL; &nbsp;&nbsp;delete&nbsp;jniBitmap; &nbsp;&nbsp;}/**restore&nbsp;java&nbsp;bitmap&nbsp;(from&nbsp;JNI&nbsp;data)*/&nbsp;&nbsp;//JNIEXPORT&nbsp;jobject&nbsp;JNICALL&nbsp;Java_com_jni_bitmap_1operations_JniBitmapHolder_jniGetBitmapFromStoredBitmapData(JNIEnv&nbsp;*&nbsp;env,&nbsp;jobject&nbsp;obj,&nbsp;jobject&nbsp;handle) &nbsp;&nbsp;{ &nbsp;&nbsp;JniBitmap*&nbsp;jniBitmap&nbsp;=&nbsp;(JniBitmap*)&nbsp;env->GetDirectBufferAddress(handle); &nbsp;&nbsp;if&nbsp;(jniBitmap->_storedBitmapPixels&nbsp;==&nbsp;NULL) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;LOGD("no&nbsp;bitmap&nbsp;data&nbsp;was&nbsp;stored.&nbsp;returning&nbsp;null..."); &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;NULL; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;// &nbsp;&nbsp;//creating&nbsp;a&nbsp;new&nbsp;bitmap&nbsp;to&nbsp;put&nbsp;the&nbsp;pixels&nbsp;into&nbsp;it&nbsp;-&nbsp;using&nbsp;Bitmap&nbsp;Bitmap.createBitmap&nbsp;(int&nbsp;width,&nbsp;int&nbsp;height,&nbsp;Bitmap.Config&nbsp;config)&nbsp;: &nbsp;&nbsp;// &nbsp;&nbsp;//LOGD("creating&nbsp;new&nbsp;bitmap..."); &nbsp;&nbsp;jclass&nbsp;bitmapCls&nbsp;=&nbsp;env->FindClass("android/graphics/Bitmap"); &nbsp;&nbsp;jmethodID&nbsp;createBitmapFunction&nbsp;=&nbsp;env->GetStaticMethodID(bitmapCls,&nbsp;"createBitmap",&nbsp;"(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;"); &nbsp;&nbsp;jstring&nbsp;configName&nbsp;=&nbsp;env->NewStringUTF("ARGB_8888"); &nbsp;&nbsp;jclass&nbsp;bitmapConfigClass&nbsp;=&nbsp;env->FindClass("android/graphics/Bitmap$Config"); &nbsp;&nbsp;jmethodID&nbsp;valueOfBitmapConfigFunction&nbsp;=&nbsp;env->GetStaticMethodID(bitmapConfigClass,&nbsp;"valueOf",&nbsp;"(Ljava/lang/String;)Landroid/graphics/Bitmap$Config;"); &nbsp;&nbsp;jobject&nbsp;bitmapConfig&nbsp;=&nbsp;env->CallStaticObjectMethod(bitmapConfigClass,&nbsp;valueOfBitmapConfigFunction,&nbsp;configName); &nbsp;&nbsp;jobject&nbsp;newBitmap&nbsp;=&nbsp;env->CallStaticObjectMethod(bitmapCls,&nbsp;createBitmapFunction,&nbsp;jniBitmap->_bitmapInfo.width,&nbsp;jniBitmap->_bitmapInfo.height,&nbsp;bitmapConfig); &nbsp;&nbsp;// &nbsp;&nbsp;//&nbsp;putting&nbsp;the&nbsp;pixels&nbsp;into&nbsp;the&nbsp;new&nbsp;bitmap: &nbsp;&nbsp;// &nbsp;&nbsp;int&nbsp;ret; &nbsp;&nbsp;void*&nbsp;bitmapPixels; &nbsp;&nbsp;if&nbsp;((ret&nbsp;=&nbsp;AndroidBitmap_lockPixels(env,&nbsp;newBitmap,&nbsp;&bitmapPixels))&nbsp;<&nbsp;0) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;LOGE("AndroidBitmap_lockPixels()&nbsp;failed&nbsp;!&nbsp;error=%d",&nbsp;ret); &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;NULL; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;uint32_t*&nbsp;newBitmapPixels&nbsp;=&nbsp;(uint32_t*)&nbsp;bitmapPixels; &nbsp;&nbsp;int&nbsp;pixelsCount&nbsp;=&nbsp;jniBitmap->_bitmapInfo.height&nbsp;*&nbsp;jniBitmap->_bitmapInfo.width; &nbsp;&nbsp;memcpy(newBitmapPixels,&nbsp;jniBitmap->_storedBitmapPixels,&nbsp;sizeof(uint32_t)&nbsp;*&nbsp;pixelsCount); &nbsp;&nbsp;AndroidBitmap_unlockPixels(env,&nbsp;newBitmap); &nbsp;&nbsp;//LOGD("returning&nbsp;the&nbsp;new&nbsp;bitmap"); &nbsp;&nbsp;return&nbsp;newBitmap; &nbsp;&nbsp;}/**store&nbsp;java&nbsp;bitmap&nbsp;as&nbsp;JNI&nbsp;data*/&nbsp;&nbsp;//JNIEXPORT&nbsp;jobject&nbsp;JNICALL&nbsp;Java_com_jni_bitmap_1operations_JniBitmapHolder_jniStoreBitmapData(JNIEnv&nbsp;*&nbsp;env,&nbsp;jobject&nbsp;obj,&nbsp;jobject&nbsp;bitmap) &nbsp;&nbsp;{ &nbsp;&nbsp;AndroidBitmapInfo&nbsp;bitmapInfo; &nbsp;&nbsp;uint32_t*&nbsp;storedBitmapPixels&nbsp;=&nbsp;NULL; &nbsp;&nbsp;//LOGD("reading&nbsp;bitmap&nbsp;info..."); &nbsp;&nbsp;int&nbsp;ret; &nbsp;&nbsp;if&nbsp;((ret&nbsp;=&nbsp;AndroidBitmap_getInfo(env,&nbsp;bitmap,&nbsp;&bitmapInfo))&nbsp;<&nbsp;0) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;LOGE("AndroidBitmap_getInfo()&nbsp;failed&nbsp;!&nbsp;error=%d",&nbsp;ret); &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;NULL; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;LOGD("width:%d&nbsp;height:%d&nbsp;stride:%d",&nbsp;bitmapInfo.width,&nbsp;bitmapInfo.height,&nbsp;bitmapInfo.stride); &nbsp;&nbsp;if&nbsp;(bitmapInfo.format&nbsp;!=&nbsp;ANDROID_BITMAP_FORMAT_RGBA_8888) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;LOGE("Bitmap&nbsp;format&nbsp;is&nbsp;not&nbsp;RGBA_8888!"); &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;NULL; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;// &nbsp;&nbsp;//read&nbsp;pixels&nbsp;of&nbsp;bitmap&nbsp;into&nbsp;native&nbsp;memory&nbsp;: &nbsp;&nbsp;// &nbsp;&nbsp;//LOGD("reading&nbsp;bitmap&nbsp;pixels..."); &nbsp;&nbsp;void*&nbsp;bitmapPixels; &nbsp;&nbsp;if&nbsp;((ret&nbsp;=&nbsp;AndroidBitmap_lockPixels(env,&nbsp;bitmap,&nbsp;&bitmapPixels))&nbsp;<&nbsp;0) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;LOGE("AndroidBitmap_lockPixels()&nbsp;failed&nbsp;!&nbsp;error=%d",&nbsp;ret); &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;NULL; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;uint32_t*&nbsp;src&nbsp;=&nbsp;(uint32_t*)&nbsp;bitmapPixels; &nbsp;&nbsp;storedBitmapPixels&nbsp;=&nbsp;new&nbsp;uint32_t[bitmapInfo.height&nbsp;*&nbsp;bitmapInfo.width]; &nbsp;&nbsp;int&nbsp;pixelsCount&nbsp;=&nbsp;bitmapInfo.height&nbsp;*&nbsp;bitmapInfo.width; &nbsp;&nbsp;memcpy(storedBitmapPixels,&nbsp;src,&nbsp;sizeof(uint32_t)&nbsp;*&nbsp;pixelsCount); &nbsp;&nbsp;AndroidBitmap_unlockPixels(env,&nbsp;bitmap); &nbsp;&nbsp;JniBitmap&nbsp;*jniBitmap&nbsp;=&nbsp;new&nbsp;JniBitmap(); &nbsp;&nbsp;jniBitmap->_bitmapInfo&nbsp;=&nbsp;bitmapInfo; &nbsp;&nbsp;jniBitmap->_storedBitmapPixels&nbsp;=&nbsp;storedBitmapPixels; &nbsp;&nbsp;return&nbsp;env->NewDirectByteBuffer(jniBitmap,&nbsp;0); &nbsp;&nbsp;}SRC / COM / JNI / bitmap_operations / JniBitmapHolder.javapackage&nbsp;com.jni.bitmap_operations;import&nbsp;java.nio.ByteBuffer;import&nbsp;android.graphics.Bitmap;import&nbsp;android.util.Log;public&nbsp;class&nbsp;JniBitmapHolder &nbsp;&nbsp;{ &nbsp;&nbsp;ByteBuffer&nbsp;_handler&nbsp;=null; &nbsp;&nbsp;static &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;System.loadLibrary("JniBitmapOperations"); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;private&nbsp;native&nbsp;ByteBuffer&nbsp;jniStoreBitmapData(Bitmap&nbsp;bitmap); &nbsp;&nbsp;private&nbsp;native&nbsp;Bitmap&nbsp;jniGetBitmapFromStoredBitmapData(ByteBuffer&nbsp;handler); &nbsp;&nbsp;private&nbsp;native&nbsp;void&nbsp;jniFreeBitmapData(ByteBuffer&nbsp;handler); &nbsp;&nbsp;private&nbsp;native&nbsp;void&nbsp;jniRotateBitmapCcw90(ByteBuffer&nbsp;handler); &nbsp;&nbsp;private&nbsp;native&nbsp;void&nbsp;jniCropBitmap(ByteBuffer&nbsp;handler,final&nbsp;int&nbsp;left,final&nbsp;int&nbsp;top,final&nbsp;int&nbsp;right,final&nbsp;int&nbsp;bottom); &nbsp;&nbsp;public&nbsp;JniBitmapHolder() &nbsp;&nbsp;&nbsp;&nbsp;{} &nbsp;&nbsp;public&nbsp;JniBitmapHolder(final&nbsp;Bitmap&nbsp;bitmap) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;storeBitmap(bitmap); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;public&nbsp;void&nbsp;storeBitmap(final&nbsp;Bitmap&nbsp;bitmap) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;if(_handler!=null) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;freeBitmap(); &nbsp;&nbsp;&nbsp;&nbsp;_handler=jniStoreBitmapData(bitmap); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;public&nbsp;void&nbsp;rotateBitmapCcw90() &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;if(_handler==null) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return; &nbsp;&nbsp;&nbsp;&nbsp;jniRotateBitmapCcw90(_handler); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;public&nbsp;void&nbsp;cropBitmap(final&nbsp;int&nbsp;left,final&nbsp;int&nbsp;top,final&nbsp;int&nbsp;right,final&nbsp;int&nbsp;bottom) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;if(_handler==null) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return; &nbsp;&nbsp;&nbsp;&nbsp;jniCropBitmap(_handler,left,top,right,bottom); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;public&nbsp;Bitmap&nbsp;getBitmap() &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;if(_handler==null) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;null; &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;jniGetBitmapFromStoredBitmapData(_handler); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;public&nbsp;Bitmap&nbsp;getBitmapAndFree() &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;Bitmap&nbsp;bitmap=getBitmap(); &nbsp;&nbsp;&nbsp;&nbsp;freeBitmap(); &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;bitmap; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;public&nbsp;void&nbsp;freeBitmap() &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;if(_handler==null) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return; &nbsp;&nbsp;&nbsp;&nbsp;jniFreeBitmapData(_handler); &nbsp;&nbsp;&nbsp;&nbsp;_handler=null; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;@Override &nbsp;&nbsp;protected&nbsp;void&nbsp;finalize()&nbsp;throws&nbsp;Throwable &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;super.finalize(); &nbsp;&nbsp;&nbsp;&nbsp;if(_handler==null) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return; &nbsp;&nbsp;&nbsp;&nbsp;Log.w("DEBUG","JNI&nbsp;bitmap&nbsp;wasn't&nbsp;freed&nbsp;nicely.please&nbsp;rememeber&nbsp;to&nbsp;free&nbsp;the&nbsp;bitmap&nbsp;as&nbsp;soon&nbsp;as&nbsp;you&nbsp;can"); &nbsp;&nbsp;&nbsp;&nbsp;freeBitmap(); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Android