witcher
witcher

Reputation: 135

Convert Bitmap from array of bytes (byte[]) - Bitmap is still null

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

Answers (1)

samgak
samgak

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

Related Questions