JNI:从unsigned char*创建Bitmap始终为null

3
我希望您可以将一个图像(通过JNI)从C++传递到Android应用程序。我有一个未被破坏的unsigned char*数组,甚至可以将其保存到ppm文件中,并在我的笔记本电脑上正确显示它。然后,我使用以下函数将其转换为jByteArray:
jbyteArray imgByte=as_byte_array(env,imgRaw,img.getRawImageSize());
...
jbyteArray as_byte_array(JNIEnv *env, unsigned char* buf, int len) {
    jbyteArray array = env->NewByteArray (len);
    env->SetByteArrayRegion (array, 0, len, reinterpret_cast<jbyte*>(buf));
    return array;
}

接下来,我将这个jByteArray发送到Java端。这个变量已经被正确填充,我可以通过在LogCat上打印它的十六进制值来验证:

07-01 18:02:45.941    7017-8238/com.myapp.myapp W/C++ side﹕  798a95798b9677889371838d6b7d8664757e5d6e7860717b5e...
07-01 18:02:46.941    7017-8238/com.myapp.myapp W/Java side﹕ 798a95798b9677889371838d6b7d8664757e5d6e7860717b5e...

最后一步是在ImageView上展示它。为此,我执行以下代码(从SO上的另一个问题中获取):
public void setImageViewWithByteArray(final ImageView view, byte[] data) {
    final Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);

    getActivity().runOnUiThread(new Runnable() {
        @Override
        public void run() {
            if (bitmap==null) {
                Log.e(TAG,"Bitmap is NULL!");
                view.setImageResource(R.drawable.abc_btn_radio_material);
            }
            else {
                view.setImageBitmap(bitmap);
            }
        }
    });
}

但是 bitmap 变量总是为 null。我做错了什么?有没有办法调试 decodeByteArray


可能你正在获取空数据,请检查一下。 - Saritha G
1个回答

4

BitmapFactor.decodeByteArray 用于解码压缩的图像数据,例如PNG文件的内容。

如果您的字节数组包含未压缩的RGB数据,则可以使用create a mutable Bitmap创建正确宽度和高度的位图,然后使用Bitmap.setPixels设置像素。但是,setPixels需要一个带有32位ARGB值的int数组,而从您的日志中看,您的字节数组包含每像素3个字节的RGB数据。

因此,您需要创建一个int数组,然后处理您的字节数组,并为每个字节三元组写入一个int值,例如:

intArray[i] = 0xff000000 |
    (((int)data[i*3] & 255) << 16) | (((int)data[i*3+1] & 255) << 8) | ((int)data[i*3+2] & 255);

然后将其传递给setPixels。或者你可以在JNI端完成并返回jintArray。

1
谢谢您的答案,解决了我80%的问题。您是对的,我有一个未压缩的RGB数据数组。我按照您的建议进行了操作(代码在此http://pastebin.com/SespEigv),但现在我有两个问题:1 每次运行此代码,对于320x240的图像,需要大约1秒的时间。有没有方法可以加快这个过程?我希望尽可能接近比如说30fps;2 图像在那里,但颜色很混乱。我非常确定jni字节数组是以RGB编码的,那么为什么我的颜色会变得那么奇怪呢? - alecive
如果颜色混乱,可能是由于RGB顺序。我不知道你的数据是什么顺序,但尝试intArray [i] = 0xff000000 | ((int)data [i * 3 + 2] << 16) | ((int)data [i * 3 + 1] << 8) | (int)data [i * 3];至于速度问题,我不认为颜色转换会花费1秒钟来处理320x240的图像,你在JNI端之前是否进行了其他处理,这可能解释了这个问题? - samgak
可能是每次分配字节数组都在减慢速度。您可以尝试在Java端一次性分配它,并将其传递给JNI,以填充它,每次重复使用它。同样,不要每次创建位图,创建一次并重复使用它。 - samgak
还有一件事,请尝试使用“&255”对字节进行掩码处理(请参见修订后的答案)。Java中的字节是带符号的。 - samgak
你的最后修改(即掩码字节)是正确的方法。我甚至设法优化了我的代码,它运行得更快了(尽管我仍然想改进它 - 还需要尝试在Java端一次性分配位图)。感谢你的帮助! - alecive

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接