Bitmap是Android中一个很重要都类,是一个图片信息类,图片都会封装成一个Bitmap的对象后,才能在Android中使用。
那么Bitmap究竟包含了什么东西呢?
就看几个比较重要的属性吧
//jni分配的native空间地址
// Convenience for JNI access
private final long mNativePtr;
private final boolean mIsMutable;
/**
* Represents whether the Bitmap's content is requested to be pre-multiplied.
* Note that isPremultiplied() does not directly return this value, because
* isPremultiplied() may never return true for a 565 Bitmap or a bitmap
* without alpha.
*
* setPremultiplied() does directly set the value so that setConfig() and
* setPremultiplied() aren't order dependent, despite being setters.
*
* The native bitmap's premultiplication state is kept up to date by
* pushing down this preference for every config change.
*/
private boolean mRequestPremultiplied;
//标志点9图的数据
private byte[] mNinePatchChunk; // may be null
private NinePatch.InsetStruct mNinePatchInsets; // may be null
//宽
private int mWidth;
//高
private int mHeight;
//是否回收
private boolean mRecycled;
我们基本构造Bitmap都是使用BitmapFactory来进行构造的,其内部最终会调用这些native的方法
private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
Rect padding, Options opts);
private static native Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
Rect padding, Options opts);
private static native Bitmap nativeDecodeAsset(long nativeAsset, Rect padding, Options opts);
private static native Bitmap nativeDecodeByteArray(byte[] data, int offset,
int length, Options opts);
会调用nativeDecodeStream来解析文件流
nativeDecodeStream.png
配置完成后会调用Bitmap.cpp
createBitmap.png
可以看出是使用gBitmap_class的构造方法来创建对象
createBitmap.png
其实际还是会反射到framework 层的Bitmap层去创建一个java层表象,实际对象还是通过c++来分配内存地址的
反射Framework层Bitmap创建.png
Mat对象,是Opencv解析图片和图片处理的对象,以下是native层的bitmap转为Mat对象的逻辑
void bitmap_to_mat(JNIEnv *env, jobject &srcBitmap, Mat &srcMat) {
void *srcPixels = 0;
//native层的Bitmap对象信息
AndroidBitmapInfo srcBitmapInfo;
try {
//转换层native层对象
AndroidBitmap_getInfo(env, srcBitmap, &srcBitmapInfo);
//加锁
AndroidBitmap_lockPixels(env, srcBitmap, &srcPixels);
uint32_t srcHeight = srcBitmapInfo.height;
uint32_t srcWidth = srcBitmapInfo.width;
//通道分解
srcMat.create(srcHeight, srcWidth, CV_8UC4);
if (srcBitmapInfo.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
//转为4通道的Mat图
Mat tmp(srcHeight, srcWidth, CV_8UC4, srcPixels);
tmp.copyTo(srcMat);
} else {
//转为2通道的Mat灰度图
Mat tmp = Mat(srcHeight, srcWidth, CV_8UC2, srcPixels);
cvtColor(tmp, srcMat, COLOR_BGR5652RGBA);
}
//解锁
AndroidBitmap_unlockPixels(env, srcBitmap);
return;
} catch (cv::Exception &e) {
AndroidBitmap_unlockPixels(env, srcBitmap);
jclass je = env->FindClass("java/lang/Exception");
env -> ThrowNew(je, e.what());
return;
} catch (...) {
AndroidBitmap_unlockPixels(env, srcBitmap);
jclass je = env->FindClass("java/lang/Exception");
env -> ThrowNew(je, "unknown");
return;
}
}
当然经过处理后还需要从Mat对象转换为bitmap对象,这种方式是外部传递了bitmap对象了。
void mat_to_bitmap(JNIEnv *env, Mat &srcMat, jobject &dstBitmap) {
void *dstPixels = 0;
AndroidBitmapInfo dstBitmapInfo;
try {
AndroidBitmap_getInfo(env, dstBitmap, &dstBitmapInfo);
AndroidBitmap_lockPixels(env, dstBitmap, &dstPixels);
uint32_t dstHeight = dstBitmapInfo.height;
uint32_t dstWidth = dstBitmapInfo.width;
//通道选择
if (dstBitmapInfo.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
Mat tmp(dstHeight, dstWidth, CV_8UC4, dstPixels);
if(srcMat.type() == CV_8UC1) {
//灰度图转为RGBA
cvtColor(srcMat, tmp, COLOR_GRAY2RGBA);
} else if (srcMat.type() == CV_8UC3) {
cvtColor(srcMat, tmp, COLOR_BGR2RGBA);
} else if (srcMat.type() == CV_8UC4) {
srcMat.copyTo(tmp);
}
} else {
Mat tmp = Mat(dstHeight, dstWidth, CV_8UC2, dstPixels);
if(srcMat.type() == CV_8UC1) {
cvtColor(srcMat, tmp, COLOR_GRAY2RGB);
} else if (srcMat.type() == CV_8UC3) {
cvtColor(srcMat, tmp, COLOR_BGR5652RGB);
} else if (srcMat.type() == CV_8UC4) {
cvtColor(srcMat, tmp, COLOR_BGRA2RGB);
}
}
AndroidBitmap_unlockPixels(env, dstBitmap);
}catch (cv::Exception &e) {
AndroidBitmap_unlockPixels(env, dstBitmap);
jclass je = env->FindClass("java/lang/Exception");
env -> ThrowNew(je, e.what());
return;
} catch (...) {
AndroidBitmap_unlockPixels(env, dstBitmap);
jclass je = env->FindClass("java/lang/Exception");
env -> ThrowNew(je, "unknown");
return;
}
}
下面这种是自身构成通过反射来构成好bitmap对象,这里仲带你是在反射构成bitmap对象并且拥有反射缓存,需要使用GlobalRef
jclass clazz;
jclass configCls;
jobject config;
jobject mat_to_bitmap_object(JNIEnv *env,Mat &srcMat){
if(clazz == nullptr) {
jclass jclazz = env->FindClass("android/graphics/Bitmap");
clazz = (jclass)env->NewGlobalRef(jclazz);
}
jmethodID createBitmap = env->GetStaticMethodID(clazz, "createBitmap",
"(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
if(configCls == nullptr) {
jclass jconfigCls = env->FindClass("android/graphics/Bitmap$Config");
configCls = (jclass)env->NewGlobalRef(jconfigCls);
}
jfieldID fid = env->GetStaticFieldID(configCls, "ARGB_8888", "Landroid/graphics/Bitmap$Config;");
if (config == nullptr) {
jobject jconfig = env->GetStaticObjectField(configCls, fid);
config = env->NewGlobalRef(jconfig);
}
jobject jbitmap = env->CallStaticObjectMethod(clazz,createBitmap,srcMat.cols,srcMat.rows,config);
AndroidBitmapInfo info;
void *pixels = 0;
try {
AndroidBitmap_getInfo(env, jbitmap, &info);
AndroidBitmap_lockPixels(env,jbitmap, &pixels);
Mat tmp(info.height,info.width,CV_8UC4,pixels);
cvtColor(srcMat,tmp,COLOR_BGR2RGBA);
AndroidBitmap_unlockPixels(env,jbitmap);
return jbitmap;
}catch (cv::Exception &e) {
AndroidBitmap_unlockPixels(env, jbitmap);
return NULL;
} catch (...) {
AndroidBitmap_unlockPixels(env, jbitmap);
return NULL;
}
}
两个群号都可以加入,群2群号763094035,我在这里期待你们的加入!!!
Android组件化群2群1号是316556016。
Android组件化群1