【问题标题】:JNI: Bitmap from unsigned char* always nullJNI:来自 unsigned char* 的位图始终为空
【发布时间】:2015-07-01 16:10:55
【问题描述】:

我想将图像(通过 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?

【问题讨论】:

  • 可能你得到的是空数据。一旦检查出来。

标签: java android c++ bitmap java-native-interface


【解决方案1】:

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

如果您的字节数组包含未压缩的 RGB 数据,那么您可以 create a mutable Bitmap 设置正确的宽度和高度,然后使用 Bitmap.setPixels 设置像素。但是,setPixels 采用具有 32 位 ARGB 值的整数数组,从您的日志中看起来您的字节数组包含每像素 3 字节的 RGB 数据。

因此您需要创建一个 int 数组,然后处理您的字节数组并为每个字节三元组写入一个 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。

【讨论】:

  • 感谢您的回答,这解决了我 80% 的问题。你是对的,我有一组未压缩的 RGB 数据。我听从了您的建议(此处为代码pastebin.com/SespEigv),但现在我遇到了两个问题: 1 每次运行此代码时,320x240 图像需要大约 1 秒。有没有办法加快这个过程?我想尽可能接近,比如说,30fps,尽可能 2 图像在那里,但它的颜色被弄乱了。我很确定 jni 字节数组是用 RGB 编码的;那么,为什么我的颜色这么奇怪?
  • 如果颜色混乱,可能是由于 RGB 顺序。我不知道您的数据的顺序,但请尝试 intArray[i] = 0xff000000 | ((int)数据[i*3+2]
  • 可能是每次分配字节数组都会减慢速度。您可以尝试在 Java 端分配一次,然后将其传递给 JNI,JNI 将其填满,每次都重用它。同样不要每次都创建位图,创建一次并重复使用。
  • 还有一件事,尝试用 & 255 屏蔽字节(参见修订后的答案)。 Java 字节已签名
  • 您的最后修改(即屏蔽字节)是正确的方法。我什至设法稍微优化了我的代码,而且速度更快(即使我想改进它 - 仍然必须尝试在 Java 端分配位图一次)。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多