从字节数组 (byte[]) 转换位图 - 位图仍然为空
Convert Bitmap from array of bytes (byte[]) - Bitmap is still null
我从应用程序的 JNI 部分检索了一个字节数组。 JNI 的输入也是来自相机的 ARGB8888 格式位图图片的字节数组。 C++ 使用 FastCV 函数将我的位图修改为灰度。这是我的代码:
Java:
private void fcvTest(String fileName) { //path to stored image
Bitmap bmp = BitmapFactory.decodeFile(fileName);
//we are going from 32bit integer (ARGB8888) to 8bit byte (grayscale) => 4 * number of pixels:
ByteBuffer argbBuf = ByteBuffer.allocate(bmp.getWidth() * bmp.getHeight() * 4);
bmp.copyPixelsToBuffer(argbBuf);
byte[] grayBuffer = new byte[]{};
grayBuffer = fcvGrayScale(argbBuf.array(), bmp.getWidth(), bmp.getHeight());
Bitmap grayScaledPic = BitmapFactory.decodeByteArray(grayBuffer, 0, grayBuffer.length);
}
private native byte[] fcvGrayScale(byte[] data, int w, int h);
C++:
JNIEXPORT jbyteArray JNICALL Java_com_qualcomm_loadjpeg_LoadJpeg_fcvGrayScale(JNIEnv* env, jobject obj, jbyteArray img, uint32_t w, uint32_t h) {
jbyte* jImg;
jboolean isCopy;
jbyteArray grayToJava;
jbyte* jbyteGray;
jImg = env->GetByteArrayElements(img, &isCopy);
uint8_t* uint8Gray = (uint8_t*) fcvMemAlloc(w*h*4, 16);
fcvColorRGB888ToGrayu8((uint8_t*) jImg, w, h, 0, uint8Gray, 0);
jbyteGray = (jbyte*) uint8Gray;
grayToJava = env->NewByteArray(w*h); //no need for 4-more space for grayscale
env->SetByteArrayRegion(grayToJava, 0, w*h, jbyteGray);
env->ReleaseByteArrayElements(img, jImg, JNI_ABORT);
fcvMemFree(uint8Gray);
return grayToJava;
}
可以在此处查看 FastCV 函数 fcvColorRGB888ToGrayu8 的文档:
fcvColorRGB888ToGrayu8 doc
正如您在标题中所见,我无法从 JNI 设置新位图 grayScaledPic。 Log cat 给了我这个通常的语句:
SkImageDecoder::Factory returned null
我的新数组 grayBuffer 中的字节似乎不正确,或者我忽略了一些问题,例如通过 BitmapFactory.Options 设置正确的位图格式。或者输入数组甚至可能是错误的,因为 fcvColorRGB888ToGrayu8 期望 RGB888 作为输入,但 Android 不支持这种格式。我必须先删除 alpha 通道吗?
有人知道吗,还有什么意义?
已解决 >> 查看已接受的答案
BitmapFactory.decodeByteArray 解码字节数组时出现问题 - 仅适用于压缩位图(JPEG、PNG)
问题出在您的 Java 代码中:
Bitmap grayScaledPic = BitmapFactory.decodeByteArray(grayBuffer, 0, grayBuffer.length);
BitmapFactor.decodeByteArray() 解码已加载到字节数组中的压缩图像,例如 JPG 或 PNG 文件。它不适用于未压缩的原始数据。
要从灰度字节数组进行设置,您必须使用不同的方法。您可以转换为 int 数组,然后使用 Bitmap.createBitmap() 创建位图,例如:
final int pixCount = bmp.getWidth() * bmp.getHeight();
int[] intGreyBuffer = new int[pixCount];
for(int i=0; i < pixCount; i++)
{
int greyValue = (int)greyBuffer[i] & 0xff;
intGreyBuffer[i] = 0xff000000 | (greyValue << 16) | (greyValue << 8) | greyValue;
}
Bitmap grayScaledPic = Bitmap.createBitmap(intGreyBuffer, bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888);
另一种方法是从您的 JNI 代码中 return 一个 int 数组而不是字节数组,然后直接在 Java 中从中创建位图。
我从应用程序的 JNI 部分检索了一个字节数组。 JNI 的输入也是来自相机的 ARGB8888 格式位图图片的字节数组。 C++ 使用 FastCV 函数将我的位图修改为灰度。这是我的代码:
Java:
private void fcvTest(String fileName) { //path to stored image
Bitmap bmp = BitmapFactory.decodeFile(fileName);
//we are going from 32bit integer (ARGB8888) to 8bit byte (grayscale) => 4 * number of pixels:
ByteBuffer argbBuf = ByteBuffer.allocate(bmp.getWidth() * bmp.getHeight() * 4);
bmp.copyPixelsToBuffer(argbBuf);
byte[] grayBuffer = new byte[]{};
grayBuffer = fcvGrayScale(argbBuf.array(), bmp.getWidth(), bmp.getHeight());
Bitmap grayScaledPic = BitmapFactory.decodeByteArray(grayBuffer, 0, grayBuffer.length);
}
private native byte[] fcvGrayScale(byte[] data, int w, int h);
C++:
JNIEXPORT jbyteArray JNICALL Java_com_qualcomm_loadjpeg_LoadJpeg_fcvGrayScale(JNIEnv* env, jobject obj, jbyteArray img, uint32_t w, uint32_t h) {
jbyte* jImg;
jboolean isCopy;
jbyteArray grayToJava;
jbyte* jbyteGray;
jImg = env->GetByteArrayElements(img, &isCopy);
uint8_t* uint8Gray = (uint8_t*) fcvMemAlloc(w*h*4, 16);
fcvColorRGB888ToGrayu8((uint8_t*) jImg, w, h, 0, uint8Gray, 0);
jbyteGray = (jbyte*) uint8Gray;
grayToJava = env->NewByteArray(w*h); //no need for 4-more space for grayscale
env->SetByteArrayRegion(grayToJava, 0, w*h, jbyteGray);
env->ReleaseByteArrayElements(img, jImg, JNI_ABORT);
fcvMemFree(uint8Gray);
return grayToJava;
}
可以在此处查看 FastCV 函数 fcvColorRGB888ToGrayu8 的文档: fcvColorRGB888ToGrayu8 doc
正如您在标题中所见,我无法从 JNI 设置新位图 grayScaledPic。 Log cat 给了我这个通常的语句:
SkImageDecoder::Factory returned null
我的新数组 grayBuffer 中的字节似乎不正确,或者我忽略了一些问题,例如通过 BitmapFactory.Options 设置正确的位图格式。或者输入数组甚至可能是错误的,因为 fcvColorRGB888ToGrayu8 期望 RGB888 作为输入,但 Android 不支持这种格式。我必须先删除 alpha 通道吗?
有人知道吗,还有什么意义?
已解决 >> 查看已接受的答案
BitmapFactory.decodeByteArray 解码字节数组时出现问题 - 仅适用于压缩位图(JPEG、PNG)
问题出在您的 Java 代码中:
Bitmap grayScaledPic = BitmapFactory.decodeByteArray(grayBuffer, 0, grayBuffer.length);
BitmapFactor.decodeByteArray() 解码已加载到字节数组中的压缩图像,例如 JPG 或 PNG 文件。它不适用于未压缩的原始数据。
要从灰度字节数组进行设置,您必须使用不同的方法。您可以转换为 int 数组,然后使用 Bitmap.createBitmap() 创建位图,例如:
final int pixCount = bmp.getWidth() * bmp.getHeight();
int[] intGreyBuffer = new int[pixCount];
for(int i=0; i < pixCount; i++)
{
int greyValue = (int)greyBuffer[i] & 0xff;
intGreyBuffer[i] = 0xff000000 | (greyValue << 16) | (greyValue << 8) | greyValue;
}
Bitmap grayScaledPic = Bitmap.createBitmap(intGreyBuffer, bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888);
另一种方法是从您的 JNI 代码中 return 一个 int 数组而不是字节数组,然后直接在 Java 中从中创建位图。