Reputation: 135
I have a byte array retrieved from JNI part of my application. The input to JNI was also a byte array of bitmap picture from camera in ARGB8888 format. C++ has modified my bitmap to grayscale, using FastCV function. Here is my code:
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;
}
The documentation for FastCV function fcvColorRGB888ToGrayu8 can be seen here: fcvColorRGB888ToGrayu8 doc
As you can see in the title, I am not able to set my new bitmap grayScaledPic from JNI. Log cat gives me this usual statement:
SkImageDecoder::Factory returned null
It seems like bytes in my new array grayBuffer are not proper or I am overlooking some issue, for example setting the right format of bitmap via BitmapFactory.Options. Or input array even can be wrong, because fcvColorRGB888ToGrayu8 is expecting RGB888 as an input, but Android does not support this format. Does I have to remove alpha channel first?
Does anybody know, what else could be the point?
SOLVED >> see accepted answer
Problem was in decoding byte array by BitmapFactory.decodeByteArray - only works with compressed bitmaps (JPEG,PNG)
Upvotes: 1
Views: 3877
Reputation: 24417
The problem is in your Java code:
Bitmap grayScaledPic = BitmapFactory.decodeByteArray(grayBuffer, 0, grayBuffer.length);
BitmapFactor.decodeByteArray() decodes a compressed image such as a JPG or PNG file that has been loaded into a byte array. It doesn't work on raw uncompressed data.
To set from a grey scale byte array you would have to use a different method. You can convert to an int array and then create the bitmap using Bitmap.createBitmap() e.g:
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);
Another way would be to return an int array from your JNI code instead of a byte array and then create the bitmap from it in Java directly.
Upvotes: 1