Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass a bitmap from Java to C++ with JNI in Android Development?

I would like to pass a bitmap from Android to C++ using JNI for Android Development.

In Java, I call this function to send a Bitmap from Java to C++:

public native int sendMyBitmap(Bitmap bitmap);

in JNI, I have done it like this:

JNIEXPORT void JNICALL sendMyBitmap(JNIEnv * env,
        jobject obj, jobject bitmap) 
{
    AndroidBitmapInfo androidBitmapInfo ;
    void* pixels;
    AndroidBitmap_getInfo(env, bitmap, &androidBitmapInfo);
    AndroidBitmap_lockPixels(env, bitmap, &pixels);
    unsigned char* pixelsChar = (unsigned char*) pixels;
    saveImage(pixelsChar);
}

void saveImage(unsigned char* img)
{
    FILE *f;
    int w = 640, h = 480;

    int filesize = 54 + 3*w*h;  //w is your image width, h is image height, both int

    unsigned char bmpfileheader[14] = {'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0};
    unsigned char bmpinfoheader[40] = {40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0};
    unsigned char bmppad[3] = {0,0,0};

    bmpfileheader[ 2] = (unsigned char)(filesize    );
    bmpfileheader[ 3] = (unsigned char)(filesize>> 8);
    bmpfileheader[ 4] = (unsigned char)(filesize>>16);
    bmpfileheader[ 5] = (unsigned char)(filesize>>24);

    bmpinfoheader[ 4] = (unsigned char)(       w    );
    bmpinfoheader[ 5] = (unsigned char)(       w>> 8);
    bmpinfoheader[ 6] = (unsigned char)(       w>>16);
    bmpinfoheader[ 7] = (unsigned char)(       w>>24);
    bmpinfoheader[ 8] = (unsigned char)(       h    );
    bmpinfoheader[ 9] = (unsigned char)(       h>> 8);
    bmpinfoheader[10] = (unsigned char)(       h>>16);
    bmpinfoheader[11] = (unsigned char)(       h>>24);

    f = fopen("/storage/test.png","wb");
    fwrite(bmpfileheader,1,14,f);
    fwrite(bmpinfoheader,1,40,f);
    for(int i=0; i<h; i++)
    {
        fwrite(img+(w*(h-i-1)*3),3,w,f);
        fwrite(bmppad,1,(4-(w*3)%4)%4,f);
    }
    fflush(f);
    fclose(f);
}

After saving the bitmap in C++ JNI, the bitmaps in Java and in C++ are different. I am struggling to find out what is the problem and how can I find the problem.

like image 987
olidev Avatar asked Aug 27 '13 09:08

olidev


1 Answers

This line:

fwrite(img + (w * (h - i - 1)*3), 3, w, f);

You are assuming the input BITMAP has 24 bites (3 bytes) per pixel. But there is no such pixel format in android.

You also are assuming the width is exactly 640 pixels and the height is exactly 480 pixels. This can be truth in your case, but you should read this information, not hardcode the values.

All these values are provided by the function AndroidBitmap_getInfo(). Why are you not using them? Just check the structure AndroidBitmapInfo:

typedef struct {
    uint32_t    width;
    uint32_t    height;
    uint32_t    stride;
    int32_t     format;
    uint32_t    flags;      // 0 for now
} AndroidBitmapInfo;

You can directly read the dimensions of your bitmap. Additionally you should check the parameter format, which can be one of these values:

enum AndroidBitmapFormat {
    ANDROID_BITMAP_FORMAT_NONE      = 0,
    ANDROID_BITMAP_FORMAT_RGBA_8888 = 1,
    ANDROID_BITMAP_FORMAT_RGB_565   = 4,
    ANDROID_BITMAP_FORMAT_RGBA_4444 = 7,
    ANDROID_BITMAP_FORMAT_A_8       = 8,
};

You see? There is no RGB_888 format. You should ensure you are sending the bitmap in RGBA_8888 pixel format from Java co C++ and modify your algorithm accordingly. I think it would be easier to change the output pixel format to 32 bits (instead of 24 bits).

like image 68
Robert H. Avatar answered Nov 16 '22 17:11

Robert H.