Android上需要生成图片首先想到的是 createBitmap API,看了一下之后,实现了第一种方法
纯Java实现
private Bitmap createBitmap(int[][] dataArray) {
// 转一维数组
byte[] newArray = new byte[dataArray.length * dataArray[0].length];
int index = 0;
for (int row = 0; row < dataArray.length; row++) {
for (int column = 0; column < dataArray[0].length; column++) {
newArray[index++] = (byte)dataArray[row][column];
}
}
// 注意 width,height 与 二维数组 row,colume 的对应关系
Bitmap bitmap = Bitmap.createBitmap(dataArray[0].length, dataArray.length, Bitmap.Config.ARGB_8888);
int pixels[] = new int[dataArray[0].length * dataArray.length];
for (int i = 0; i < pixels.length; ++i) {
//关键代码,生产灰度图
pixels[i] = newArray[i] * 256 * 256 + newArray[i] * 256 + newArray[i] + 0xFF000000;
}
// 设置像素值
bitmap.setPixels(pixels, 0, 128, 0, 0, 128, 19500);
if (bitmap != null) {
// 只是做图片缩放
bitmap = zoomBitmap(bitmap, 440, 590);
}
return bitmap;
}
/**
* 图片缩放
* @param
* @param bitmap 对象
* @param w 要缩放的宽度
* @param h 要缩放的高度
* @return newBmp 新 Bitmap对象
*/
public static Bitmap zoomBitmap (Bitmap bitmap,int w, int h){
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Matrix matrix = new Matrix();
float scaleWidth = ((float) w / width);
float scaleHeight = ((float) h / height);
matrix.postScale(scaleWidth, scaleHeight);
Bitmap newBmp = Bitmap.createBitmap(bitmap, 0, 0, width, height,
matrix, true);
return newBmp;
}
这里的二维数组是直接拿来用的,像素数组我是拿到的一个 csv文件解析出来的,这里就不赘述了,用的是 jxl 库。
完成之后发现实在是太慢了,出去解析 csv 的时间,光生成图片的时间都是以 秒 来计算的。
然后就换成了 OpenCV 来实现。结合 在现有AS项目中新增OpenCV c++库的支持,现在缺少的就只有 实现 转换图片的函数就可以了。
OpenCV Jni实现
public static native Bitmap array2Bitmap(int width, int height, int[][] original_data, Bitmap bitmap);
现在的 AS 都已经支持可以根据提示 自动在 cpp 文件生成对应的函数了
extern "C"
JNIEXPORT jobject JNICALL
Java_xyz_jimbray_healthydemo_JNITools_array2Bitmap(JNIEnv *env, jclass type, jint width, jint height,
jobjectArray original_data, jobject bitmap) {
jint rows = env->GetArrayLength(original_data);
jarray array = (jintArray)(env->GetObjectArrayElement(original_data, 0));
jint cols = env->GetArrayLength(array);
// 转换二维数组
vector<vector<int>> swp(rows, vector<int>(cols));
for (jint i = 0; i < rows; i++) {
array = (jintArray)(env->GetObjectArrayElement(original_data, i));
// 获取指针
jint *col_data = env->GetIntArrayElements((jintArray)array, 0);
for (jint j = 0; j < cols; j++) {
swp[i][j] = col_data[j];
}
// 释放指针
env->ReleaseIntArrayElements((jintArray)array, col_data, 0);
}
// 注意 width,height 的参数位置
cv::Mat mat = cv::Mat(height, width, CV_8U);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
mat.at<uchar>(i, j) = swp[i][j];
}
}
// 缩放图片以方便展示
cv::resize(mat, mat, cv::Size(440, 590), 0, 0, CV_INTER_LINEAR);
//get source bitmap's config
jclass java_bitmap_class = (jclass)env->FindClass("android/graphics/Bitmap");
jmethodID mid = env->GetMethodID(java_bitmap_class, "getConfig", "()Landroid/graphics/Bitmap$Config;");
jobject bitmap_config = env->CallObjectMethod(bitmap, mid);
jobject _bitmap = mat_to_bitmap(env, mat, false, bitmap_config);
AndroidBitmap_unlockPixels(env, bitmap);
return _bitmap;
}
// 不要忘记定义哦
jobject mat_to_bitmap(JNIEnv * env, cv::Mat& src, bool needPremultiplyAlpha, jobject bitmap_config){
jclass java_bitmap_class = (jclass)env->FindClass("android/graphics/Bitmap");
jmethodID mid = env->GetStaticMethodID(java_bitmap_class,
"createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
jobject bitmap = env->CallStaticObjectMethod(java_bitmap_class,
mid, src.size().width, src.size().height, bitmap_config);
AndroidBitmapInfo info;
void* pixels = 0;
try {
//validate
CV_Assert(AndroidBitmap_getInfo(env, bitmap, &info) >= 0);
CV_Assert(src.type() == CV_8UC1 || src.type() == CV_8UC3 || src.type() == CV_8UC4);
CV_Assert(AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0);
CV_Assert(pixels);
//type mat
if(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888){
cv::Mat tmp(info.height, info.width, CV_8UC4, pixels);
if(src.type() == CV_8UC1){
cvtColor(src, tmp, CV_GRAY2RGBA);
} else if(src.type() == CV_8UC3){
cvtColor(src, tmp, CV_RGB2RGBA);
} else if(src.type() == CV_8UC4){
if(needPremultiplyAlpha){
cvtColor(src, tmp, COLOR_RGBA2mRGBA);
}else{
src.copyTo(tmp);
}
}
} else{
cv::Mat tmp(info.height, info.width, CV_8UC2, pixels);
if(src.type() == CV_8UC1){
cvtColor(src, tmp, CV_GRAY2BGR565);
} else if(src.type() == CV_8UC3){
cvtColor(src, tmp, CV_RGB2BGR565);
} else if(src.type() == CV_8UC4){
cvtColor(src, tmp, CV_RGBA2BGR565);
}
}
AndroidBitmap_unlockPixels(env, bitmap);
return bitmap;
} catch(cv::Exception e){
AndroidBitmap_unlockPixels(env, bitmap);
jclass je = env->FindClass("org/opencv/core/CvException");
if(!je) je = env->FindClass("java/lang/Exception");
env->ThrowNew(je, e.what());
return bitmap;
} catch (...){
AndroidBitmap_unlockPixels(env, bitmap);
jclass je = env->FindClass("java/lang/Exception");
env->ThrowNew(je, "Unknown exception in JNI code {nMatToBitmap}");
return bitmap;
}
}
在 Java 层调用
private Bitmap createBitmap(int[][] dataArray) {
Bitmap src = Bitmap.createBitmap(dataArray[0].length, dataArray.length, Bitmap.Config.ARGB_8888);
Bitmap bitmap = JNITools.array2Bitmap(dataArray[0].length, dataArray.length, dataArray, src);
return bitmap;
}
完成。
相对前面的 纯Java版本,速度现在是以 毫秒 计,根本没有对比的资格。
comments powered by Disqus